mercur 0.1.5

mercur - junolang package manager
use std::{collections::HashMap, fs::File, io::Read, path::Path};

use serde::{Deserialize, Serialize};

//
// authority.toml
//

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JunoToml {
    pub schema: u8,
    pub vars: HashMap<String, String>,
    pub project: JunoPackageMetadata,
    #[serde(rename = "lib")]
    pub libs: Vec<JunoPackageLib>,
    #[serde(rename = "bin")]
    pub bins: Vec<JunoPackageBin>,

    #[serde(rename = "dep")]
    pub dependencies: HashMap<String, JunoDependency>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JunoPackageMetadata {
    pub name: String,
    pub version: String,
    pub edition: String,
    pub description: String,
    pub license: String,
    pub homepage: String,
    pub repository: String,
    pub documentation: String,
    pub authors: Vec<String>,
    pub keywords: Vec<String>,
    pub categories: Vec<String>,

    pub readme: String,
    pub publish: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JunoPackageLib {
    pub entry: String,
    pub output: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JunoPackageBin {
    pub entry: String,
    pub output: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JunoDependency {
    pub authority: String,
    pub namespace: String,
    #[serde(skip)]
    pub name: String,
    pub version: String,
    pub hash: Option<String>,
    pub sign: Option<String>,
}

pub fn parse_juno_toml(path: &Path) -> anyhow::Result<JunoToml> {
    let buf: &mut String = &mut String::new();
    File::open(path)?.read_to_string(buf)?;
    let mut juno_toml: JunoToml = toml::from_str(buf)?;
    juno_toml.resolve_vars();
    Ok(juno_toml)
}

impl JunoToml {
    pub fn resolve_vars(&mut self) {
        self.project.name = replace_vars(&self.project.name, &self.vars);
        self.project.version = replace_vars(&self.project.version, &self.vars);
        self.project.description = replace_vars(&self.project.description, &self.vars);
        self.project.license = replace_vars(&self.project.license, &self.vars);
        self.project.homepage = replace_vars(&self.project.homepage, &self.vars);
        self.project.repository = replace_vars(&self.project.repository, &self.vars);
        self.project.documentation = replace_vars(&self.project.documentation, &self.vars);
        self.project.readme = replace_vars(&self.project.readme, &self.vars);
        for lib in &mut self.libs {
            lib.entry = replace_vars(&lib.entry, &self.vars);
            lib.output = replace_vars(&lib.output, &self.vars);
        }
        for bin in &mut self.bins {
            bin.entry = replace_vars(&bin.entry, &self.vars);
            bin.output = replace_vars(&bin.output, &self.vars);
        }
        for (dep_name, dep) in &mut self.dependencies {
            dep.authority = replace_vars(&dep.authority, &self.vars);
            dep.namespace = replace_vars(&dep.namespace, &self.vars);
            dep.name = dep_name.clone();
            dep.version = replace_vars(&dep.version, &self.vars);
            if let Some(hash) = dep.hash.as_ref() {
                dep.hash = Some(replace_vars(hash, &self.vars));
            }
            if let Some(sign) = dep.sign.as_ref() {
                dep.sign = Some(replace_vars(sign, &self.vars));
            }
        }
        
        for author in &mut self.project.authors {
            *author = replace_vars(author, &self.vars);
        }

        for keyword in &mut self.project.keywords {
            *keyword = replace_vars(keyword, &self.vars);
        }

        for category in &mut self.project.categories {
            *category = replace_vars(category, &self.vars);
        }
    }
}
fn replace_vars(input: &str, vars: &HashMap<String, String>) -> String {
    let mut output = input.to_string();

    for (key, value) in vars {
        output = output.replace(&format!("${{{}}}", key), value);
    }

    output
}