repos/
metadata.rs

1use std::collections::HashMap;
2use std::fs::File;
3use std::io::prelude::*;
4use std::path::Path;
5
6use toml;
7
8use super::util;
9
10#[derive(Deserialize)]
11pub struct Metadata {
12    pub repos: HashMap<String, Repo>,
13    pub proxy: Proxy,
14}
15
16#[derive(Deserialize)]
17pub struct Repo {
18    pub vcs: String,
19    pub allow_sync: bool,
20    pub bare: bool,
21    pub use_proxy: bool,
22    pub topics: Vec<String>,
23}
24
25#[derive(Deserialize)]
26pub struct Proxy {
27    pub scheme: String,
28    pub host: String,
29    pub port: u16,
30}
31
32/// Load metadata from file path.
33pub fn load(path: &Path) -> Result<Metadata, String> {
34    let path_display = path.display();
35    let mut file = match File::open(&path) {
36        Ok(file) => file,
37        Err(err) => {
38            return Err(format!(
39                "Couldn't open {}: {}",
40                path_display,
41                err.to_string()
42            ))
43        }
44    };
45
46    let mut content = String::new();
47    match file.read_to_string(&mut content) {
48        Ok(_) => {}
49        Err(err) => {
50            return Err(format!(
51                "Couldn't read {}: {}",
52                path_display,
53                err.to_string()
54            ))
55        }
56    }
57
58    loads(&content)
59}
60
61/// Load metadata from string slices.
62pub fn loads(content: &str) -> Result<Metadata, String> {
63    let md: Metadata = match toml::from_str(&content) {
64        Ok(md) => md,
65        Err(err) => {
66            return Err(format!(
67                "Couldn't parse as toml format because of: {}",
68                err.to_string()
69            ));
70        }
71    };
72
73    // Validate repo url.
74    let mut urls_errors: HashMap<String, String> = HashMap::new();
75    for url in md.repos.keys() {
76        match util::validate_repo_url(url) {
77            Err(err) => {
78                urls_errors.insert(url.to_string(), err.to_string());
79            }
80            Ok(_) => {}
81        }
82    }
83    if !urls_errors.is_empty() {
84        for (url, error) in urls_errors {
85            println!("Url '{}' is unsupported because of: {}.", url, error);
86        }
87        Err("Unsupported repository urls found in metadata file.".to_string())
88    } else {
89        Ok(md)
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    extern crate tempfile;
96
97    use std::io::Write;
98    use std::path::Path;
99
100    use super::{load, loads};
101
102    static TEMP_CONTENT: &'static str = "
103        [repos.'https://github.com/org/repo.git']
104        vcs = 'git'
105        allow_sync = true
106        bare = false
107        use_proxy = false
108        topics = ['topic1', 'topic2']
109
110        [proxy]
111        scheme = 'socks5'
112        host = '127.0.0.1'
113        port = 1080
114    ";
115
116    #[test]
117    fn md_loads() {
118        let md = loads(&TEMP_CONTENT).unwrap();
119
120        assert_eq!(md.proxy.scheme, "socks5");
121        assert_eq!(md.proxy.host, "127.0.0.1");
122        assert_eq!(md.proxy.port, 1080);
123    }
124
125    #[test]
126    fn md_load() {
127        let mut tmpfile = tempfile::NamedTempFile::new().unwrap();
128        write!(tmpfile, "{}", &TEMP_CONTENT).unwrap();
129
130        let path = tmpfile.path();
131
132        let filepath = Path::new(path);
133        let md = load(&filepath).unwrap();
134
135        assert_eq!(md.proxy.scheme, "socks5");
136        assert_eq!(md.proxy.host, "127.0.0.1");
137        assert_eq!(md.proxy.port, 1080);
138    }
139}