1use std::collections::HashMap;
4
5use toml_edit::{self, Document};
6use failure::Error;
7
8use errors::*;
9
10const REGISTRIES_ENTRY: &str = "registries";
11
12pub type Registries = HashMap<String, String>;
14
15#[derive(Debug)]
19pub struct Config {
20 data: Document,
21}
22
23impl Config {
24 pub fn new(data: String) -> Result<Config, Error> {
26 match data.parse() {
27 Ok(data) => Ok(Config { data }),
28 Err(_) => Err(RegistryError::BrokenConfig.into())
29 }
30 }
31
32 pub fn data(&self) -> String {
34 self.data.to_string()
35 }
36
37 pub fn add(&mut self, name: &str, url: &str) -> Result<(), Error> {
39 match self.check_table() {
40 Ok(_) => {
41 if !self.data[REGISTRIES_ENTRY][name].is_none() {
42 return Err(RegistryError::AlreadyExist { name: name.into() }.into());
43 }
44 },
45 Err(_) => { self.data[REGISTRIES_ENTRY] = toml_edit::table(); }
46 }
47
48 self.data[REGISTRIES_ENTRY][name] = toml_edit::value(url);
49 Ok(())
50 }
51
52 pub fn remove(&mut self, name: &str) -> Result<String, Error> {
54 self.check_table()?;
55
56 let registries = &mut self.data[REGISTRIES_ENTRY];
57 if registries[name].is_none() {
58 return Err(RegistryError::NoSuchRegistry { name: name.into() }.into());
59 }
60
61 let url = registries[name].as_str().unwrap().to_string();
62 registries[name] = toml_edit::Item::None;
63
64 if registries.as_table_like().unwrap().is_empty() {
66 *registries = toml_edit::Item::None;
67 }
68
69 Ok(url)
70 }
71
72 pub fn rename(&mut self, old: &str, new: &str) -> Result<(), Error> {
74 let url = self.get(old)?;
75 self.add(new, &url)?;
76 let _ = self.remove(old)?;
77 Ok(())
78 }
79
80 pub fn get(&self, name: &str) -> Result<String, Error> {
82 self.check_table()?;
83
84 let registry = &self.data[REGISTRIES_ENTRY][name];
85 if registry.is_none() {
86 return Err(RegistryError::NoSuchRegistry { name: name.into() }.into());
87 }
88
89 Ok(registry.as_str().unwrap().to_string())
90 }
91
92 pub fn set(&mut self, name: &str, url: &str) -> Result<String, Error> {
94 self.check_table()?;
95
96 let registry = &mut self.data[REGISTRIES_ENTRY][name];
97 if registry.is_none() {
98 return Err(RegistryError::NoSuchRegistry { name: name.into() }.into());
99 }
100
101 let old = registry.as_str().unwrap().to_string();
102 *registry = toml_edit::value(url);
103
104 Ok(old)
105 }
106
107 pub fn list(&self) -> Result<Registries, Error> {
114 let mut result = HashMap::new();
115 let registries = match &self.data[REGISTRIES_ENTRY].as_table() {
116 &Some(r) => r,
117 &None => return Ok(result),
118 };
119
120 for (s, v) in registries.iter() {
121 if let Some(v) = v.as_str() {
122 result.insert(s.to_string(), v.to_string());
123 }
124 }
125
126 Ok(result)
127 }
128
129 fn check_table(&self) -> Result<(), Error> {
131 let reg = &self.data[REGISTRIES_ENTRY];
132 if !reg.is_table_like() {
133 return Err(RegistryError::TableAbsent.into());
134 }
135
136 Ok(())
137 }
138}