mercur 0.1.2

mercur - junolang package manager
use crate::registry::compile::parse::{
    AuthorityDefinition as AuthorityTomlDefinition, NamespaceDefinition as NamespaceTomlDefinition,
    PkgDefinition as PkgTomlDefinition, PkgVersion, RegistryDefinition as RegistryTomlDefinition,
    RegistryHistoryDefinition as RegistryHistoryTomlDefinition,
};

use crate::registry::schema::registry::{Registry, RegistryDefinition, RegistryHistoryDefinition};
use crate::registry::schema::registry_generated::registry::{
    AuthorityDefinition, AuthorityDefinitionArgs, RegistryArgs, RegistryDefinitionArgs,
    RegistryHistoryDefinitionArgs, RegistryRefType,
};

use crate::registry::schema::registry_generated::registry::RegistryRefType as RegistryRefType2;

use flatbuffers::{FlatBufferBuilder, WIPOffset};

pub fn compile_registry(
    authorities: Vec<&AuthorityTomlDefinition>,
    namespaces: Vec<&NamespaceTomlDefinition>,
    pkgs: Vec<&PkgTomlDefinition>,
) -> Vec<u8> {
    let mut builder = FlatBufferBuilder::new();

    //
    // Authorities
    //
    let authority_offsets = authorities
        .into_iter()
        .map(|a| compile_authority(&mut builder, a))
        .collect::<Vec<_>>();

    let authorities = builder.create_vector(&authority_offsets);

    //
    // Namespaces
    //
    let namespace_offsets = namespaces
        .into_iter()
        .map(|n| compile_namespace(&mut builder, n))
        .collect::<Vec<_>>();

    let namespaces = builder.create_vector(&namespace_offsets);

    //
    // Packages
    //
    let package_offsets = pkgs
        .into_iter()
        .map(|p| compile_pkg_registry_entry(&mut builder, p))
        .collect::<Vec<_>>();

    let packages = builder.create_vector(&package_offsets);

    //
    // Root
    //
    let root = Registry::create(
        &mut builder,
        &RegistryArgs {
            authorities: Some(authorities),
            namespaces: Some(namespaces),
            packages: Some(packages),
        },
    );

    builder.finish(root, None);

    builder.finished_data().to_vec()
}
use crate::registry::schema::registry::{Namespace, NamespaceArgs};

use crate::registry::schema::registry::{PkgRegistryEntry, PkgRegistryEntryArgs};

fn compile_pkg_registry_entry<'a>(
    builder: &mut FlatBufferBuilder<'a>,
    pkg: &PkgTomlDefinition,
) -> WIPOffset<PkgRegistryEntry<'a>> {
    let name = builder.create_string(&pkg.metadata.name);
    let authority = builder.create_string(&pkg.metadata.authority);

    let reference = builder.create_string(&pkg.metadata.reference);

    let versions = pkg
        .versions
        .iter()
        .map(|v| compile_version(builder, v))
        .collect::<Vec<_>>();

    let versions = builder.create_vector(&versions);

    PkgRegistryEntry::create(
        builder,
        &PkgRegistryEntryArgs {
            name: Some(name),
            authority: Some(authority),
            ref_type: RegistryRefType::NoRef,
            ref_: Some(reference),
            use_ref: !pkg.metadata.reference.is_empty(),
            versions: Some(versions),
        },
    )
}

use crate::registry::schema::registry::{Hash, Version, VersionArgs};

fn compile_version<'a>(
    builder: &mut FlatBufferBuilder<'a>,
    version: &PkgVersion,
) -> WIPOffset<Version<'a>> {
    let tag = builder.create_string("");

    let (major, minor, patch, tag_name) = parse_version(&version.version);

    let tag = if tag_name.is_empty() {
        None
    } else {
        Some(builder.create_string(&tag_name))
    };

    let hash = compile_hash(builder, &version.hash);

    Version::create(
        builder,
        &VersionArgs {
            major,
            minor,
            patch,
            tag,
            hash: Some(&hash),
            date: parse_date(&version.date),
        },
    )
}

fn parse_version(version: &str) -> (u16, u8, u8, String) {
    let mut tag = String::new();

    let mut split = version.splitn(2, '-');
    let numbers = split.next().unwrap_or("0.0.0");

    if let Some(t) = split.next() {
        tag = t.to_string();
    }

    let mut nums = numbers.split('.');

    let major = nums.next().unwrap_or("0").parse().unwrap_or(0);
    let minor = nums.next().unwrap_or("0").parse().unwrap_or(0);
    let patch = nums.next().unwrap_or("0").parse().unwrap_or(0);

    (major, minor, patch, tag)
}

fn compile_hash(_builder: &mut FlatBufferBuilder, hash: &str) -> Hash {
    let hash = hash.trim();

    let mut parts = [0u64; 4];

    for (i, chunk) in hash.as_bytes().chunks(16).take(4).enumerate() {
        let s = std::str::from_utf8(chunk).unwrap_or("0");
        parts[i] = u64::from_str_radix(s, 16).unwrap_or(0);
    }

    Hash::new(parts[0], parts[1], parts[2], parts[3])
}

use chrono::DateTime;

fn parse_date(date: &str) -> u64 {
    DateTime::parse_from_rfc3339(date)
        .map(|d| d.timestamp() as u64)
        .unwrap_or(0)
}
fn compile_namespace<'a>(
    builder: &mut FlatBufferBuilder<'a>,
    namespace: &NamespaceTomlDefinition,
) -> WIPOffset<Namespace<'a>> {
    let id = builder.create_string(&namespace.metadata.id);
    let name = builder.create_string(&namespace.metadata.name);

    let owners = namespace
        .metadata
        .owners
        .iter()
        .map(|owner| builder.create_string(owner))
        .collect::<Vec<_>>();

    let owners = builder.create_vector(&owners);

    Namespace::create(
        builder,
        &NamespaceArgs {
            id: Some(id),
            name: Some(name),
            owners: Some(owners),
        },
    )
}
pub fn compile_authority<'a>(
    builder: &mut FlatBufferBuilder<'a>,
    authority: &AuthorityTomlDefinition,
) -> WIPOffset<AuthorityDefinition<'a>> {
    let id = builder.create_string(&authority.metadata.id);
    let name = builder.create_string(&authority.metadata.name);
    let homepage = builder.create_string(&authority.metadata.homepage);
    let description = builder.create_string(&authority.metadata.description);

    let owners = authority
        .metadata
        .owners
        .iter()
        .map(|owner| builder.create_string(owner))
        .collect::<Vec<_>>();
    let owners = builder.create_vector(&owners);

    let signing_keys = authority
        .metadata
        .signing_keys
        .iter()
        .map(|key| builder.create_string(key))
        .collect::<Vec<_>>();
    let signing_keys = builder.create_vector(&signing_keys);

    let registries = authority
        .registries
        .iter()
        .enumerate()
        .map(|(id, registry)| compile_registry_definition(builder, id as u16, registry))
        .collect::<Vec<_>>();
    let registries = builder.create_vector(&registries);

    crate::registry::schema::registry::AuthorityDefinition::create(
        builder,
        &AuthorityDefinitionArgs {
            id: Some(id),
            name: Some(name),
            owners: Some(owners),
            homepage: Some(homepage),
            description: Some(description),
            registries: Some(registries),
            signing_keys: Some(signing_keys),
        },
    )
}

fn compile_registry_definition<'a>(
    builder: &mut FlatBufferBuilder<'a>,
    id: u16,
    registry: &RegistryTomlDefinition,
) -> WIPOffset<RegistryDefinition<'a>> {
    let reference = builder.create_string(&registry.reference);
    let namespace = builder.create_string(&registry.namespace);

    let history = registry
        .history
        .iter()
        .enumerate()
        .map(|(id, history)| compile_registry_history(builder, id as u16, history))
        .collect::<Vec<_>>();

    let history = builder.create_vector(&history);

    RegistryDefinition::create(
        builder,
        &RegistryDefinitionArgs {
            id,
            type_: parse_registry_ref_type(&registry.registry_type),
            ref_: Some(reference),
            namespace: Some(namespace),
            history: Some(history),
        },
    )
}

fn compile_registry_history<'a>(
    builder: &mut FlatBufferBuilder<'a>,
    id: u16,
    history: &RegistryHistoryTomlDefinition,
) -> WIPOffset<RegistryHistoryDefinition<'a>> {
    let reference = builder.create_string(&history.reference);

    RegistryHistoryDefinition::create(
        builder,
        &RegistryHistoryDefinitionArgs {
            id,
            type_: parse_registry_ref_type(&history.registry_type),
            ref_: Some(reference),
            deprecated: history.deprecated,
            until: parse_date(&history.until),
        },
    )
}

pub fn parse_registry_ref_type(ty: &str) -> RegistryRefType {
    match ty.to_ascii_lowercase().as_str() {
        "github" => RegistryRefType::Github,
        "http" => RegistryRefType::HTTP,
        "inregistry" => RegistryRefType::InRegistry,
        _ => RegistryRefType::NoRef,
    }
}