Now can get all configs

This commit is contained in:
Yehuda Katz 2014-04-06 20:31:50 -07:00
parent 3a15f5b786
commit 739b130975
3 changed files with 101 additions and 26 deletions

View File

@ -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<ConfigFlags>, c: FlagConfiguration) -> FlagConfiguration {
c.short("human", 'h')
}
}
#[deriving(Encodable)]
struct ConfigOut {
values: collections::HashMap<~str, config::ConfigValue>
}
fn config(args: ConfigFlags) -> CargoResult<Option<ConfigOut>> {
#[deriving(Decodable)]
struct ConfigForKeyFlags {
key: ~str,
human: bool
}
impl FlagConfig for ConfigForKeyFlags {
fn config(_: Option<ConfigForKeyFlags>, config: FlagConfiguration) -> FlagConfiguration {
config.short("human", 'h')
}
}
fn config_for_key(args: ConfigForKeyFlags) -> CargoResult<Option<ConfigOut>> {
let value = try!(config::get_config(os::getcwd(), args.key.as_slice()));
if args.human {
@ -69,7 +74,31 @@ fn config(args: ConfigFlags) -> CargoResult<Option<ConfigOut>> {
}
}
fn locate_project(args: NoFlags) -> CargoResult<Option<ProjectLocation>> {
#[deriving(Decodable)]
struct ConfigListFlags {
human: bool
}
impl FlagConfig for ConfigListFlags {
fn config(_: Option<ConfigListFlags>, config: FlagConfiguration) -> FlagConfiguration {
config.short("human", 'h')
}
}
fn config_list(args: ConfigListFlags) -> CargoResult<Option<ConfigOut>> {
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<Option<ProjectLocation>> {
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() }))

View File

@ -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<ConfigValue> {
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<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);
}
});
});
Ok(map)
}
#[allow(unused_variable)]
pub fn set_config(key: ~str, value: ~str, location: Location) -> CargoResult<()> {
Ok(())
}
fn walk_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>) -> Option<T> {
let mut current = pwd.clone();
loop {
@ -49,6 +65,19 @@ fn walk_tree<T>(pwd: &Path, walk: |io::fs::File| -> CargoResult<T>) -> Option<T>
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<ConfigValue> {
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<ConfigValue> {
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<collections::HashMap<~str, ConfigValue>> {
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)
}

View File

@ -1,4 +1,3 @@
use std::os;
use super::super::{CargoResult,CargoError};
pub fn find_project(pwd: Path, file: ~str) -> CargoResult<Path> {