wok_dev/
config.rs

1use anyhow::*;
2use serde::{Deserialize, Serialize};
3use std::{fs, path};
4
5const CONFIG_CURRENT_VERSION: &str = "1.0-experimental";
6
7#[derive(Serialize, Deserialize, Debug, Clone)]
8#[serde(deny_unknown_fields)]
9pub struct Repo {
10    pub path: path::PathBuf,
11    pub head: String,
12}
13
14/// Config schema for `wok.toml`
15///
16/// A repository containing `wok.toml` file serves as an "umbrella" repo for a
17/// workspace containing several repos.
18#[derive(Serialize, Deserialize, Debug)]
19#[serde(deny_unknown_fields)]
20pub struct Config {
21    pub version: String,
22    #[serde(rename = "repo")]
23    pub repos: Vec<Repo>,
24}
25
26impl Config {
27    pub fn new() -> Self {
28        Config {
29            version: String::from(CONFIG_CURRENT_VERSION),
30            repos: vec![],
31        }
32    }
33
34    pub fn add_repo(&mut self, path: &path::Path, head: &str) -> bool {
35        assert!(!path.is_absolute());
36
37        if self.has_repo_path(path) {
38            return false;
39        }
40
41        self.repos.push(Repo {
42            path: path::PathBuf::from(path),
43            head: String::from(head),
44        });
45        true
46    }
47
48    pub fn remove_repo(&mut self, path: &path::Path) -> bool {
49        assert!(!path.is_absolute());
50
51        let mut removed = false;
52        self.repos.retain(|r| {
53            if r.path != path {
54                return true;
55            }
56            removed = true;
57            false
58        });
59        removed
60    }
61
62    pub fn set_repo_head(&mut self, path: &path::Path, head: &String) -> bool {
63        assert!(!path.is_absolute());
64
65        let mut updated = false;
66        self.repos = self
67            .repos
68            .iter()
69            .map(|r| -> Repo {
70                let mut r = r.to_owned();
71                if r.path != path {
72                    return r;
73                }
74                r.head = head.to_owned();
75                updated = true;
76                r
77            })
78            .collect();
79        updated
80    }
81
82    /// Loads the workspace config from a file at the `config_path`.
83    pub fn load(config_path: &path::Path) -> Result<Config> {
84        let config = toml::from_str(&Self::read(config_path)?)
85            .context("Cannot parse the wok file")?;
86        Ok(config)
87    }
88
89    /// Reads the config file into a string (useful mainly for testing).
90    pub fn read(config_path: &path::Path) -> Result<String> {
91        fs::read_to_string(config_path).context("Cannot read the wok file")
92    }
93
94    /// Saves the workspace config to a file.
95    pub fn save(&self, config_path: &path::Path) -> Result<()> {
96        fs::write(config_path, self.dump()?).context("Cannot save the wok file")?;
97        Ok(())
98    }
99
100    /// Returns config as TOML string (useful mainly for testing).
101    pub fn dump(&self) -> Result<String> {
102        Ok(toml::to_string(self).context("Cannot serialize config")?)
103    }
104
105    fn has_repo_path(&self, path: &path::Path) -> bool {
106        assert!(!path.is_absolute());
107        self.repos.iter().any(|r| r.path == path)
108    }
109}
110
111impl Default for Config {
112    fn default() -> Self {
113        Config::new()
114    }
115}