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#[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 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 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 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 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}