1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! Sup config
use crate::Result;
use etc::{Etc, FileSystem, Meta, Read, Write};
use serde::{Deserialize, Serialize};
use std::process::Command;

/// Get value from equation
fn get(src: &str, key: &str) -> String {
    if let Some(mut begin) = src.find(key) {
        begin = src[begin..].find('=').unwrap_or(0) + begin + 1;
        let end = src[begin..].find('\n').unwrap_or(0) + begin;
        src[begin..end].trim().to_string()
    } else {
        String::new()
    }
}

/// MetaData Config
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct MetaData {
    /// Node authors
    pub authors: Vec<String>,
    /// Node version
    pub version: String,
    /// Node license
    pub license: String,
}

impl MetaData {
    /// Generate the metadata tuples
    pub fn tuple(&self) -> Vec<(&str, String, Option<&str>)> {
        vec![
            (
                "authors =",
                format!("authors = {:?}", self.authors),
                Some("]\n"),
            ),
            // ("version =", format!("version = \"{}\"", self.version), None),
            ("license =", format!("license = \"{}\"", self.license), None),
        ]
    }
}

impl Default for MetaData {
    fn default() -> MetaData {
        let git_config = Command::new("git")
            .args(vec!["config", "--global", "--list"])
            .output()
            .expect("Failed to execute git command")
            .stdout;
        let git_config_str = String::from_utf8_lossy(&git_config);
        let author = get(&git_config_str, "user.name");
        let mail = get(&git_config_str, "user.email");
        MetaData {
            authors: vec![format!("{} <{}>", author, mail)],
            version: "0.1.0".to_string(),
            license: "MIT".to_string(),
        }
    }
}

/// Node Config
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct Node {
    /// Node Registry
    pub registry: String,
}

impl Node {
    /// The name space of the registry node
    pub fn name_space(&self) -> String {
        let name = self.name();
        let end = self.registry.find(&name).unwrap_or(0);
        let begin = (&self.registry[..end - 1]).rfind('/').unwrap_or(0) + 1;
        self.registry[begin..end].to_string()
    }

    /// Get the name of registry
    pub fn name(&self) -> String {
        let begin = self.registry.rfind('/').unwrap_or(0) + 1;
        let end = self.registry.rfind(".git").unwrap_or(0);
        if begin - 1 == end {
            "substrate"
        } else {
            &self.registry[begin..end]
        }
        .to_string()
    }
}

impl Default for Node {
    fn default() -> Node {
        Node {
            registry: "https://github.com/paritytech/substrate.git".to_string(),
        }
    }
}

/// Sup Config
#[derive(Default, Deserialize, Serialize, Debug, Clone)]
pub struct Config {
    /// Node Metadata
    pub metadata: MetaData,
    /// Node Config
    pub node: Node,
}

impl Config {
    /// Inject default config to path
    pub fn gen_default(config: &Etc) -> Result<Config> {
        let default = Config::default();
        config.write(toml::to_string(&default)?)?;
        Ok(default)
    }

    /// New config
    pub fn new() -> Result<Config> {
        let mut home = dirs::home_dir().expect("Could not find home dir");
        home.push(".sup");

        let etc = Etc::from(&home);
        let config = etc.open("config.toml")?;
        if config.real_path()?.exists() {
            let bytes = config.read()?;
            if let Ok(cur) = toml::from_slice::<Config>(&bytes) {
                Ok(cur)
            } else {
                Self::gen_default(&config)
            }
        } else {
            Self::gen_default(&config)
        }
    }
}