diff --git a/src/bin/cargo.rs b/src/bin/cargo.rs index bfc3b1e32..36c620cc7 100644 --- a/src/bin/cargo.rs +++ b/src/bin/cargo.rs @@ -5,9 +5,9 @@ extern crate serialize; extern crate collections; use hammer::{FlagConfig,FlagConfiguration}; -use std::{os,io}; -use serialize::{Decodable,Encodable,json}; -use cargo::{CargoResult,ToCargoError,NoFlags,execute_main_without_stdin,process_executed,handle_error}; +use std::os; +use serialize::Encodable; +use cargo::{CargoResult,ToCargoError,NoFlags,execute_main_without_stdin,handle_error}; use cargo::util::important_paths::find_project; use cargo::util::config; @@ -20,13 +20,19 @@ struct ProjectLocation { root: ~str } +/** + The top-level `cargo` command handles configuration and project location + because they are fundamental (and intertwined). Other commands can rely + on this top-level information. +*/ fn execute() { - let (cmd, args) = match process(os::args()) { + let (cmd, _) = match process(os::args()) { Ok((cmd, args)) => (cmd, args), Err(err) => return handle_error(err) }; - if cmd == ~"config" { execute_main_without_stdin(config) } + if cmd == ~"config-for-key" { execute_main_without_stdin(config_for_key) } + else if cmd == ~"config-list" { execute_main_without_stdin(config_list) } else if cmd == ~"locate-project" { execute_main_without_stdin(locate_project) } } @@ -38,25 +44,24 @@ fn process(mut args: ~[~str]) -> CargoResult<(~str, ~[~str])> { Ok((head, tail)) } -#[deriving(Decodable)] -struct ConfigFlags { - key: ~str, - value: Option<~str>, - human: bool -} - -impl FlagConfig for ConfigFlags { - fn config(_: Option, c: FlagConfiguration) -> FlagConfiguration { - c.short("human", 'h') - } -} - #[deriving(Encodable)] struct ConfigOut { values: collections::HashMap<~str, config::ConfigValue> } -fn config(args: ConfigFlags) -> CargoResult> { +#[deriving(Decodable)] +struct ConfigForKeyFlags { + key: ~str, + human: bool +} + +impl FlagConfig for ConfigForKeyFlags { + fn config(_: Option, config: FlagConfiguration) -> FlagConfiguration { + config.short("human", 'h') + } +} + +fn config_for_key(args: ConfigForKeyFlags) -> CargoResult> { let value = try!(config::get_config(os::getcwd(), args.key.as_slice())); if args.human { @@ -69,7 +74,31 @@ fn config(args: ConfigFlags) -> CargoResult> { } } -fn locate_project(args: NoFlags) -> CargoResult> { +#[deriving(Decodable)] +struct ConfigListFlags { + human: bool +} + +impl FlagConfig for ConfigListFlags { + fn config(_: Option, config: FlagConfiguration) -> FlagConfiguration { + config.short("human", 'h') + } +} + +fn config_list(args: ConfigListFlags) -> CargoResult> { + let configs = try!(config::all_configs(os::getcwd())); + + if args.human { + for (key, value) in configs.iter() { + println!("{} = {}", key, value); + } + Ok(None) + } else { + Ok(Some(ConfigOut { values: configs })) + } +} + +fn locate_project(_: NoFlags) -> CargoResult> { let root = try!(find_project(os::getcwd(), ~"Cargo.toml")); let string = try!(root.as_str().to_cargo_error(format!("Your project path contains characters not representable in Unicode: {}", os::getcwd().display()), 1)); Ok(Some(ProjectLocation { root: string.to_owned() })) diff --git a/src/cargo/util/config.rs b/src/cargo/util/config.rs index 087a7b3a7..9f579fb7a 100644 --- a/src/cargo/util/config.rs +++ b/src/cargo/util/config.rs @@ -1,15 +1,16 @@ +extern crate collections; extern crate toml; -use super::super::{CargoResult,CargoError,ToCargoError}; +use super::super::{CargoResult,ToCargoError}; use std::{io,fmt}; -#[deriving(Eq,Clone,Encodable,Decodable)] +#[deriving(Eq,TotalEq,Clone,Encodable,Decodable)] pub enum Location { Project, Global } -#[deriving(Eq,Clone,Encodable,Decodable)] +#[deriving(Eq,TotalEq,Clone,Encodable,Decodable)] pub struct ConfigValue { value: ~str, path: ~str @@ -22,14 +23,29 @@ impl fmt::Show for ConfigValue { } pub fn get_config(pwd: Path, key: &str) -> CargoResult { - walk_tree(&pwd, |file| extract_config(file, key)).to_cargo_error(format!("Config key not found: {}", key), 1) + find_in_tree(&pwd, |file| extract_config(file, key)).to_cargo_error(format!("Config key not found: {}", key), 1) } +pub fn all_configs(pwd: Path) -> CargoResult> { + 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); + } + }); + }); + + Ok(map) +} + +#[allow(unused_variable)] pub fn set_config(key: ~str, value: ~str, location: Location) -> CargoResult<()> { Ok(()) } -fn walk_tree(pwd: &Path, walk: |io::fs::File| -> CargoResult) -> Option { +fn find_in_tree(pwd: &Path, walk: |io::fs::File| -> CargoResult) -> Option { let mut current = pwd.clone(); loop { @@ -49,6 +65,19 @@ fn walk_tree(pwd: &Path, walk: |io::fs::File| -> CargoResult) -> Option None } +fn walk_tree(pwd: &Path, walk: |io::fs::File| -> ()) { + let mut current = pwd.clone(); + + loop { + let possible = current.join(".cargo").join("config"); + if possible.exists() { + let _ = io::fs::File::open(&possible).map(|file| walk(file)); + } + + if !current.pop() { break; } + } +} + fn extract_config(file: io::fs::File, key: &str) -> CargoResult { let path = try!(file.path().as_str().to_cargo_error(~"", 1)).to_owned(); let mut buf = io::BufferedReader::new(file); @@ -56,3 +85,21 @@ fn extract_config(file: io::fs::File, key: &str) -> CargoResult { let val = try!(try!(root.lookup(key).to_cargo_error(~"", 1)).get_str().to_cargo_error(~"", 1)); Ok(ConfigValue{ value: val.to_owned(), path: path }) } + +fn extract_all_configs(file: io::fs::File) -> CargoResult> { + let mut map = collections::HashMap::new(); + + 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)); + let table = try!(root.get_table().to_cargo_error(~"", 1)); + + for (key, value) in table.iter() { + match value { + &toml::String(ref val) => { map.insert(key.to_owned(), ConfigValue { value: val.to_owned(), path: path.clone() }); } + _ => () + } + } + + Ok(map) +} diff --git a/src/cargo/util/important_paths.rs b/src/cargo/util/important_paths.rs index 231aca678..a428f825c 100644 --- a/src/cargo/util/important_paths.rs +++ b/src/cargo/util/important_paths.rs @@ -1,4 +1,3 @@ -use std::os; use super::super::{CargoResult,CargoError}; pub fn find_project(pwd: Path, file: ~str) -> CargoResult {