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
32pub 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
61pub 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 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}