extern crate collections;
+extern crate serialize;
extern crate toml;
use super::super::{CargoResult,ToCargoError,CargoError};
+use serialize::{Encodable,Encoder};
use std::{io,fmt};
#[deriving(Eq,TotalEq,Clone,Encodable,Decodable)]
Global
}
-#[deriving(Eq,TotalEq,Clone,Encodable,Decodable,Show)]
+#[deriving(Eq,TotalEq,Clone,Decodable)]
enum ConfigValueValue {
String(~str),
- List(~[~str])
+ List(Vec<~str>)
}
-#[deriving(Eq,TotalEq,Clone,Encodable,Decodable)]
+impl fmt::Show for ConfigValueValue {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ &String(ref string) => write!(f.buf, "{}", string),
+ &List(ref list) => write!(f.buf, "{}", list)
+ }
+ }
+}
+
+impl<E, S: Encoder<E>> Encodable<S, E> for ConfigValueValue {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ match self {
+ &String(ref string) => {
+ try!(string.encode(s));
+ },
+ &List(ref list) => {
+ try!(list.encode(s));
+ }
+ }
+
+ Ok(())
+ }
+}
+
+#[deriving(Eq,TotalEq,Clone,Decodable)]
pub struct ConfigValue {
value: ConfigValueValue,
- path: ~str
+ path: Vec<~str>
+}
+
+impl<E, S: Encoder<E>> Encodable<S, E> for ConfigValue {
+ fn encode(&self, s: &mut S) -> Result<(), E> {
+ s.emit_map(2, |s| {
+ try!(s.emit_map_elt_key(0, |s| "value".encode(s)));
+ try!(s.emit_map_elt_val(0, |s| self.value.encode(s)));
+ Ok(())
+ })
+ }
}
impl fmt::Show for ConfigValue {
pub fn all_configs(pwd: Path) -> CargoResult<collections::HashMap<~str, ConfigValue>> {
let mut map = collections::HashMap::new();
- walk_tree(&pwd, |file| {
- let _ = extract_all_configs(file).map(|configs| {
- for (key, value) in configs.move_iter() {
- map.find_or_insert(key, value);
- }
- });
- });
+ try!(walk_tree(&pwd, |file| {
+ extract_all_configs(file, &mut map)
+ }));
Ok(map)
}
Ok(())
}
-fn find_in_tree<T>(pwd: &Path, walk: |io::fs::File| -> CargoResult<T>) -> Option<T> {
+fn find_in_tree<T>(pwd: &Path, walk: |io::fs::File| -> CargoResult<T>) -> CargoResult<T> {
let mut current = pwd.clone();
loop {
let possible = current.join(".cargo").join("config");
if possible.exists() {
- let res = io::fs::File::open(&possible).map(|file| walk(file));
-
- match res {
- Ok(Ok(res)) => return Some(res),
+ let file = try!(io::fs::File::open(&possible).to_cargo_error(~"", 1));
+ match walk(file) {
+ Ok(res) => return Ok(res),
_ => ()
}
}
if !current.pop() { break; }
}
- None
+ Err(CargoError::new(~"", 1))
}
-fn walk_tree(pwd: &Path, walk: |io::fs::File| -> ()) {
+fn walk_tree(pwd: &Path, walk: |io::fs::File| -> CargoResult<()>) -> CargoResult<()> {
let mut current = pwd.clone();
+ let mut err = false;
loop {
let possible = current.join(".cargo").join("config");
if possible.exists() {
- let _ = io::fs::File::open(&possible).map(|file| walk(file));
+ let file = try!(io::fs::File::open(&possible).to_cargo_error(~"", 1));
+ match walk(file) {
+ Err(_) => err = false,
+ _ => ()
+ }
}
+ if err { return Err(CargoError::new(~"", 1)); }
if !current.pop() { break; }
}
+
+ Ok(())
}
fn extract_config(file: io::fs::File, key: &str) -> CargoResult<ConfigValue> {
_ => return Err(CargoError::new(~"", 1))
};
- Ok(ConfigValue{ value: v, path: path })
+ Ok(ConfigValue{ value: v, path: vec!(path) })
}
-fn extract_all_configs(file: io::fs::File) -> CargoResult<collections::HashMap<~str, ConfigValue>> {
- let mut map = collections::HashMap::new();
-
+fn extract_all_configs(file: io::fs::File, map: &mut collections::HashMap<~str, ConfigValue>) -> CargoResult<()> {
let path = try!(file.path().as_str().to_cargo_error(~"", 1)).to_owned();
let mut buf = io::BufferedReader::new(file);
let root = try!(toml::parse_from_buffer(&mut buf).to_cargo_error(~"", 1));
for (key, value) in table.iter() {
match value {
- &toml::String(ref val) => { map.insert(key.to_owned(), ConfigValue { value: String(val.to_owned()), path: path.clone() }); }
- &toml::Array(ref val) => { map.insert(key.to_owned(), ConfigValue { value: List(val.iter().map(|s: &toml::Value| s.to_str()).collect()), path: path.clone() }); }
+ &toml::String(ref val) => { map.insert(key.to_owned(), ConfigValue { value: String(val.to_owned()), path: vec!(path.clone()) }); }
+ &toml::Array(ref val) => {
+ let config = map.find_or_insert_with(key.to_owned(), |_| {
+ ConfigValue { path: vec!(), value: List(vec!()) }
+ });
+
+ try!(merge_array(config, val.as_slice(), path.as_slice()));
+ },
_ => ()
}
}
- Ok(map)
+ Ok(())
+}
+
+fn merge_array(existing: &mut ConfigValue, val: &[toml::Value], path: &str) -> CargoResult<()> {
+ match existing.value {
+ String(_) => return Err(CargoError::new(~"", 1)),
+ List(ref mut list) => {
+ let new_list: Vec<CargoResult<~str>> = val.iter().map(|s: &toml::Value| toml_string(s)).collect();
+ if new_list.iter().any(|v| v.is_err()) {
+ return Err(CargoError::new(~"", 1));
+ } else {
+ let new_list: Vec<~str> = new_list.move_iter().map(|v| v.unwrap()).collect();
+ list.push_all(new_list.as_slice());
+ existing.path.push(path.to_owned());
+ Ok(())
+ }
+ }
+ }
+}
+
+fn toml_string(val: &toml::Value) -> CargoResult<~str> {
+ match val {
+ &toml::String(ref str) => Ok(str.to_owned()),
+ _ => Err(CargoError::new(~"", 1))
+ }
}