RUSTC_FLAGS ?=
# Link flags to pull in dependencies
-BINS = cargo-compile \
- cargo-read-manifest \
- cargo-rustc \
- cargo-verify-project
+BINS = cargo \
+ cargo-compile \
+ cargo-read-manifest \
+ cargo-rustc \
+ cargo-verify-project
SRC = $(shell find src -name '*.rs')
-Subproject commit 49290aedf236c365c08fbc01eb70127eb5ab4a60
+Subproject commit a7c9ead90b7eb51521f3578307fe44ca8f087b9a
--- /dev/null
+extern crate cargo;
+extern crate toml;
+extern crate hammer;
+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 cargo::util::important_paths::find_project;
+use cargo::util::config;
+
+fn main() {
+ execute();
+}
+
+#[deriving(Encodable)]
+struct ProjectLocation {
+ root: ~str
+}
+
+fn execute() {
+ let (cmd, args) = match process(os::args()) {
+ Ok((cmd, args)) => (cmd, args),
+ Err(err) => return handle_error(err)
+ };
+
+ if cmd == ~"config" { execute_main_without_stdin(config) }
+ else if cmd == ~"locate-project" { execute_main_without_stdin(locate_project) }
+}
+
+fn process(mut args: ~[~str]) -> CargoResult<(~str, ~[~str])> {
+ args = args.tail().to_owned();
+ let head = try!(args.head().to_cargo_error(~"No subcommand found", 1)).to_owned();
+ let tail = args.tail().to_owned();
+
+ 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>> {
+ let value = try!(config::get_config(os::getcwd(), args.key.as_slice()));
+
+ if args.human {
+ println!("{}", value);
+ Ok(None)
+ } else {
+ let mut map = collections::HashMap::new();
+ map.insert(args.key.clone(), value);
+ Ok(Some(ConfigOut { values: map }))
+ }
+}
+
+fn locate_project(args: 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() }))
+}
process_executed(call(exec))
}
-fn process_executed<'a, T: Encodable<json::Encoder<'a>, io::IoError>>(result: CargoResult<Option<T>>) {
+pub fn process_executed<'a, T: Encodable<json::Encoder<'a>, io::IoError>>(result: CargoResult<Option<T>>) {
match result {
- Err(e) => {
- let _ = write!(&mut std::io::stderr(), "{}", e.message);
- std::os::set_exit_status(e.exit_code as int);
- },
+ Err(e) => handle_error(e),
Ok(encodable) => {
encodable.map(|encodable| {
let encoded: ~str = json::Encoder::str_encode(&encodable);
}
}
+pub fn handle_error(err: CargoError) {
+ let _ = write!(&mut std::io::stderr(), "{}", err.message);
+ std::os::set_exit_status(err.exit_code as int);
+}
+
fn flags_from_args<T: RepresentsFlags>() -> CargoResult<T> {
let mut decoder = FlagDecoder::new::<T>(std::os::args().tail());
Decodable::decode(&mut decoder).to_cargo_error(|e: HammerError| e.message, 1)
--- /dev/null
+extern crate toml;
+
+use super::super::{CargoResult,CargoError,ToCargoError};
+use std::{io,fmt};
+
+#[deriving(Eq,Clone,Encodable,Decodable)]
+pub enum Location {
+ Project,
+ Global
+}
+
+#[deriving(Eq,Clone,Encodable,Decodable)]
+pub struct ConfigValue {
+ value: ~str,
+ path: ~str
+}
+
+impl fmt::Show for ConfigValue {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f.buf, "{} (from {})", self.value, self.path)
+ }
+}
+
+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)
+}
+
+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> {
+ 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),
+ _ => ()
+ }
+ }
+
+ if !current.pop() { break; }
+ }
+
+ None
+}
+
+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);
+ let root = try!(toml::parse_from_buffer(&mut buf).to_cargo_error(~"", 1));
+ 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 })
+}
--- /dev/null
+use std::os;
+use super::super::{CargoResult,CargoError};
+
+pub fn find_project(pwd: Path, file: ~str) -> CargoResult<Path> {
+ let mut current = pwd.clone();
+
+ loop {
+ if current.join(file.clone()).exists() {
+ return Ok(current)
+ }
+
+ if !current.pop() { break; }
+ }
+
+ Err(CargoError::new(format!("Could not find a Cargo manifest ({}) in your current directory or any parent directory", file), 1))
+}
pub use self::process_builder::{process,ProcessBuilder};
pub mod process_builder;
+pub mod config;
+pub mod important_paths;