diff --git a/src/bin/cargo-read-manifest.rs b/src/bin/cargo-read-manifest.rs index 2d2a36cdf..7aeaa4e42 100644 --- a/src/bin/cargo-read-manifest.rs +++ b/src/bin/cargo-read-manifest.rs @@ -6,7 +6,7 @@ extern crate serialize; extern crate hammer; use hammer::FlagConfig; -use cargo::{execute_main_without_stdin,CLIResult}; +use cargo::{execute_main_without_stdin,CLIResult,CLIError}; use cargo::core::Package; use cargo::ops::cargo_read_manifest::read_manifest; @@ -23,4 +23,9 @@ fn main() { fn execute(options: Options) -> CLIResult> { read_manifest(options.manifest_path.as_slice()).map(|m| Some(m)) + .map_err(|err| CLIError { + msg: err.get_desc().to_owned(), + detail: err.get_detail().map(|s| s.to_owned()), + exit_code: 1 + }) } diff --git a/src/cargo/core/resolver.rs b/src/cargo/core/resolver.rs index 5ec587713..7e4a747d2 100644 --- a/src/cargo/core/resolver.rs +++ b/src/cargo/core/resolver.rs @@ -5,7 +5,7 @@ use core::{ Summary, Registry }; -use core::errors::CargoResult; +use util::result::CargoResult; /* TODO: * - The correct input here is not a registry. Resolves should be performable diff --git a/src/cargo/core/source.rs b/src/cargo/core/source.rs index 1e0de7415..6bb1bee1a 100644 --- a/src/cargo/core/source.rs +++ b/src/cargo/core/source.rs @@ -1,5 +1,5 @@ use core::{Summary,NameVer,Package}; -use core::errors::CargoResult; +use util::CargoResult; /** * A Source finds and downloads remote packages based on names and diff --git a/src/cargo/core/summary.rs b/src/cargo/core/summary.rs index 5834fe34d..dd8544428 100644 --- a/src/cargo/core/summary.rs +++ b/src/cargo/core/summary.rs @@ -36,10 +36,12 @@ pub trait SummaryVec { } impl SummaryVec for Vec { + // TODO: Move to Registery fn names(&self) -> Vec<~str> { self.iter().map(|summary| summary.name_ver.get_name().to_owned()).collect() } + // TODO: Delete fn deps(&self) -> Vec { self.iter().map(|summary| Dependency::with_namever(summary.get_name_ver())).collect() } diff --git a/src/cargo/ops/cargo_compile.rs b/src/cargo/ops/cargo_compile.rs index 5c6a7b521..336368fe7 100644 --- a/src/cargo/ops/cargo_compile.rs +++ b/src/cargo/ops/cargo_compile.rs @@ -16,42 +16,37 @@ use std::os; use util::config; -use util::config::{all_configs,ConfigValue}; +use util::config::{ConfigValue}; use core::{PackageSet,Source}; use core::resolver::resolve; use sources::path::PathSource; use ops::cargo_rustc; use ops::cargo_read_manifest::read_manifest; -use core::errors::{CargoError,CLIError,CLIResult,ToResult}; +// use core::errors::{CargoError,CLIError,CLIResult,ToResult}; use core::summary::SummaryVec; +use util::{other_error, CargoError, CargoResult, Wrap}; -pub fn compile(manifest_path: &str) -> CLIResult<()> { +pub fn compile(manifest_path: &str) -> CargoResult<()> { let root_dep = try!(read_manifest(manifest_path)).to_dependency(); - let configs = try!(all_configs(os::getcwd()).to_result(|err: CargoError| - CLIError::new("Could not load configurations", Some(err.to_str()), 1))); + let configs = try!(config::all_configs(os::getcwd())); let config_paths = configs.find(&("paths".to_owned())).map(|v| v.clone()).unwrap_or_else(|| ConfigValue::new()); let mut paths: Vec = match config_paths.get_value() { - &config::String(_) => return Err(CLIError::new("The path was configured as a String instead of a List", None, 1)), + &config::String(_) => return Err(other_error("The path was configured as a String instead of a List")), &config::List(ref list) => list.iter().map(|path| Path::new(path.as_slice())).collect() }; paths.push(Path::new(manifest_path).dir_path()); let source = PathSource::new(paths); - let summaries = try!(source.list().to_result(|err| - CLIError::new(format!("Unable to list packages from {}", source), Some(err.to_str()), 1))); + let summaries = try!(source.list().wrap("unable to list packages from source")); + let resolved = try!(resolve([root_dep], &summaries).wrap("unable to resolve dependencies")); - let resolved = try!(resolve([root_dep], &summaries).to_result(|err: CargoError| - CLIError::new("Unable to resolve dependencies", Some(err.to_str()), 1))); + try!(source.download(resolved.as_slice()).wrap("unable to download packages")); - try!(source.download(resolved.as_slice()).to_result(|err| - CLIError::new(format!("Unable to download packages from {}", source), Some(err.to_str()), 1))); - - let packages = try!(source.get(resolved.as_slice()).to_result(|err| - CLIError::new(format!("Unable to get packages from {} for {}", source, summaries.names()), Some(err.to_str()), 1))); + let packages = try!(source.get(resolved.as_slice()).wrap("unable ot get packages from source")); let package_set = PackageSet::new(packages.as_slice()); diff --git a/src/cargo/ops/cargo_read_manifest.rs b/src/cargo/ops/cargo_read_manifest.rs index 817f6d0fa..5e7e622bd 100644 --- a/src/cargo/ops/cargo_read_manifest.rs +++ b/src/cargo/ops/cargo_read_manifest.rs @@ -1,16 +1,24 @@ use toml; use toml::from_toml; -use core; +use core::Package; use core::manifest::{TomlManifest}; -use core::errors::{CLIError,CLIResult,ToResult}; +use util::{other_error,CargoResult,CargoError}; -pub fn read_manifest(manifest_path: &str) -> CLIResult { - let root = try!(toml::parse_from_file(manifest_path.clone()).to_result(|err| - CLIError::new(format!("Cargo.toml was not valid Toml: {}", manifest_path), Some(err.to_str()), 1))); - - let toml_manifest = try!(from_toml::(root.clone()).to_result(|err: toml::Error| - CLIError::new(format!("Cargo.toml was not in the right format: {}", manifest_path), Some(err.to_str()), 1))); - - toml_manifest.to_package(manifest_path.as_slice()).to_result(|err| - CLIError::new(format!("Cargo.toml was not in the right format: {}", manifest_path), Some(err.to_str()), 1)) +pub fn read_manifest(path: &str) -> CargoResult { + let root = try!(parse_from_file(path)); + let toml = try!(load_toml(path, root)); + toml.to_package(path) +} + +fn parse_from_file(path: &str) -> CargoResult { + toml::parse_from_file(path.clone()).map_err(|err| to_cargo_err(path, err)) +} + +fn load_toml(path: &str, root: toml::Value) -> CargoResult { + from_toml::(root).map_err(|err| to_cargo_err(path, err)) +} + +fn to_cargo_err(path: &str, err: toml::Error) -> CargoError { + other_error("Cargo.toml is not valid Toml") + .with_detail(format!("path={}; err={}", path, err.to_str())) } diff --git a/src/cargo/ops/cargo_rustc.rs b/src/cargo/ops/cargo_rustc.rs index 750f1076b..9af537bae 100644 --- a/src/cargo/ops/cargo_rustc.rs +++ b/src/cargo/ops/cargo_rustc.rs @@ -4,13 +4,14 @@ use std::path::Path; use core::errors::{CLIError,CLIResult,ToResult}; use core; use util; +use util::{other_error,CargoResult,CargoError}; type Args = Vec<~str>; -pub fn compile(pkgs: &core::PackageSet) -> CLIResult<()> { +pub fn compile(pkgs: &core::PackageSet) -> CargoResult<()> { let sorted = match pkgs.sort() { Some(pkgs) => pkgs, - None => return Err(CLIError::new("Circular dependency detected", None, 1)) + None => return Err(other_error("circular dependency detected")) }; for pkg in sorted.iter() { @@ -21,14 +22,13 @@ pub fn compile(pkgs: &core::PackageSet) -> CLIResult<()> { Ok(()) } -fn compile_pkg(pkg: &core::Package, pkgs: &core::PackageSet) -> CLIResult<()> { +fn compile_pkg(pkg: &core::Package, pkgs: &core::PackageSet) -> CargoResult<()> { // Build up the destination // let src = pkg.get_root().join(Path::new(pkg.get_source().path.as_slice())); let target_dir = pkg.get_absolute_target_dir(); // First ensure that the directory exists - try!(mk_target(&target_dir).to_result(|err| - CLIError::new(format!("Could not create the target directory {}", target_dir.display()), Some(err.to_str()), 1))); + try!(mk_target(&target_dir).map_err(|err| other_error("could not create target directory"))); // compile for target in pkg.get_targets().iter() { @@ -42,7 +42,7 @@ fn mk_target(target: &Path) -> io::IoResult<()> { io::fs::mkdir_recursive(target, io::UserRWX) } -fn rustc(root: &Path, target: &core::Target, dest: &Path, deps: &[core::Package]) -> CLIResult<()> { +fn rustc(root: &Path, target: &core::Target, dest: &Path, deps: &[core::Package]) -> CargoResult<()> { let mut args = Vec::new(); build_base_args(&mut args, target, dest); @@ -52,8 +52,7 @@ fn rustc(root: &Path, target: &core::Target, dest: &Path, deps: &[core::Package] .cwd(root.clone()) .args(args.as_slice()) .exec() - .to_result(|err| - CLIError::new(format!("Couldn't execute `rustc {}` in `{}`", args.connect(" "), root.display()), Some(err.to_str()), 1))); + .map_err(|err| rustc_to_cargo_err(&args, root, err))); Ok(()) } @@ -74,3 +73,8 @@ fn build_deps_args(dst: &mut Args, deps: &[core::Package]) { dst.push(dir.as_str().unwrap().to_owned()); } } + +fn rustc_to_cargo_err(args: &Vec<~str>, cwd: &Path, err: io::IoError) -> CargoError { + other_error("failed to exec rustc") + .with_detail(format!("args={}; root={}; cause={}", args.connect(" "), cwd.display(), err.to_str())) +} diff --git a/src/cargo/sources/path.rs b/src/cargo/sources/path.rs index b73c5b54c..3a8737ce5 100644 --- a/src/cargo/sources/path.rs +++ b/src/cargo/sources/path.rs @@ -2,8 +2,8 @@ use std::fmt; use std::fmt::{Show,Formatter}; use core::{NameVer,Package,Summary}; use core::source::Source; -use core::errors::{CargoResult,CargoCLIError,ToResult}; use cargo_read_manifest = ops::cargo_read_manifest::read_manifest; +use util::{CargoResult}; pub struct PathSource { paths: Vec @@ -49,5 +49,5 @@ impl Source for PathSource { fn read_manifest(path: &Path) -> CargoResult { let joined = path.join("Cargo.toml"); - cargo_read_manifest(joined.as_str().unwrap()).to_result(|err| CargoCLIError(err)) + cargo_read_manifest(joined.as_str().unwrap()) } diff --git a/src/cargo/util/config.rs b/src/cargo/util/config.rs index d586a1b96..3b0343a26 100644 --- a/src/cargo/util/config.rs +++ b/src/cargo/util/config.rs @@ -1,10 +1,8 @@ -extern crate collections; -extern crate serialize; -extern crate toml; - -use core::errors::{CargoResult,CargoError,ToResult}; -use serialize::{Encodable,Encoder}; use std::{io,fmt}; +use collections::HashMap; +use serialize::{Encodable,Encoder}; +use toml; +use util::{other_error,CargoResult,Require}; #[deriving(Eq,TotalEq,Clone,Encodable,Decodable)] pub enum Location { @@ -76,12 +74,12 @@ impl fmt::Show for ConfigValue { } pub fn get_config(pwd: Path, key: &str) -> CargoResult { - find_in_tree(&pwd, |file| extract_config(file, key)).to_result(|_| - CargoError::described(format!("Config key not found: {}", key))) + find_in_tree(&pwd, |file| extract_config(file, key)) + .map_err(|_| other_error("config key not found").with_detail(format!("key={}", key))) } -pub fn all_configs(pwd: Path) -> CargoResult> { - let mut map = collections::HashMap::new(); +pub fn all_configs(pwd: Path) -> CargoResult> { + let mut map = HashMap::new(); try!(walk_tree(&pwd, |file| { extract_all_configs(file, &mut map) @@ -101,7 +99,7 @@ fn find_in_tree(pwd: &Path, walk: |io::fs::File| -> CargoResult) -> CargoR loop { let possible = current.join(".cargo").join("config"); if possible.exists() { - let file = try!(io::fs::File::open(&possible).to_result(|_| CargoError::other())); + let file = try!(io::fs::File::open(&possible).map_err(|_| other_error("could not open file"))); match walk(file) { Ok(res) => return Ok(res), _ => () @@ -111,7 +109,7 @@ fn find_in_tree(pwd: &Path, walk: |io::fs::File| -> CargoResult) -> CargoR if !current.pop() { break; } } - Err(CargoError::other()) + Err(other_error("")) } fn walk_tree(pwd: &Path, walk: |io::fs::File| -> CargoResult<()>) -> CargoResult<()> { @@ -121,14 +119,14 @@ fn walk_tree(pwd: &Path, walk: |io::fs::File| -> CargoResult<()>) -> CargoResult loop { let possible = current.join(".cargo").join("config"); if possible.exists() { - let file = try!(io::fs::File::open(&possible).to_result(|_| CargoError::other())); + let file = try!(io::fs::File::open(&possible).map_err(|_| other_error("could not open file"))); match walk(file) { Err(_) => err = false, _ => () } } - if err { return Err(CargoError::other()); } + if err { return Err(other_error("")); } if !current.pop() { break; } } @@ -138,26 +136,26 @@ fn walk_tree(pwd: &Path, walk: |io::fs::File| -> CargoResult<()>) -> CargoResult fn extract_config(file: io::fs::File, key: &str) -> CargoResult { let path = file.path().clone(); let mut buf = io::BufferedReader::new(file); - let root = try!(toml::parse_from_buffer(&mut buf).to_result(|_| CargoError::other())); - let val = try!(root.lookup(key).to_result(|_| CargoError::other())); + let root = try!(toml::parse_from_buffer(&mut buf).map_err(|_| other_error(""))); + let val = try!(root.lookup(key).require(other_error(""))); let v = match val { &toml::String(ref val) => String(val.to_owned()), &toml::Array(ref val) => List(val.iter().map(|s: &toml::Value| s.to_str()).collect()), - _ => return Err(CargoError::other()) + _ => return Err(other_error("")) }; Ok(ConfigValue{ value: v, path: vec!(path) }) } -fn extract_all_configs(file: io::fs::File, map: &mut collections::HashMap<~str, ConfigValue>) -> CargoResult<()> { +fn extract_all_configs(file: io::fs::File, map: &mut HashMap<~str, ConfigValue>) -> CargoResult<()> { let path = file.path().clone(); let mut buf = io::BufferedReader::new(file); - let root = try!(toml::parse_from_buffer(&mut buf).to_result(|err| - CargoError::described(format!("Couldn't parse Toml manifest `{}`: {}", path.display(), err)))); + let root = try!(toml::parse_from_buffer(&mut buf).map_err(|err| + other_error("could not parse Toml manifest").with_detail(format!("path={}; err={}", path.display(), err.to_str())))); - let table = try!(root.get_table().to_result(|err| - CargoError::described(format!("Couldn't parse Toml manifest `{}`: {}", path.display(), err)))); + let table = try!(root.get_table() + .require(other_error("could not parse Toml manifest").with_detail(format!("path={}", path.display())))); for (key, value) in table.iter() { match value { @@ -167,8 +165,8 @@ fn extract_all_configs(file: io::fs::File, map: &mut collections::HashMap<~str, ConfigValue { path: vec!(), value: List(vec!()) } }); - try!(merge_array(config, val.as_slice(), &path).to_result(|err| - CargoError::described(format!("The `{}` key in your config {}", key, err)))); + try!(merge_array(config, val.as_slice(), &path).map_err(|err| + other_error("missing").with_detail(format!("The `{}` key in your config {}", key, err)))); }, _ => () } @@ -179,11 +177,11 @@ fn extract_all_configs(file: io::fs::File, map: &mut collections::HashMap<~str, fn merge_array(existing: &mut ConfigValue, val: &[toml::Value], path: &Path) -> CargoResult<()> { match existing.value { - String(_) => return Err(CargoError::described("should be an Array, but it was a String")), + String(_) => return Err(other_error("should be an Array, but it was a String")), List(ref mut list) => { let new_list: Vec> = val.iter().map(|s: &toml::Value| toml_string(s)).collect(); if new_list.iter().any(|v| v.is_err()) { - return Err(CargoError::described("should be an Array of Strings, but was an Array of other values")); + return Err(other_error("should be an Array of Strings, but was an Array of other values")); } else { let new_list: Vec<~str> = new_list.move_iter().map(|v| v.unwrap()).collect(); list.push_all(new_list.as_slice()); @@ -197,6 +195,6 @@ fn merge_array(existing: &mut ConfigValue, val: &[toml::Value], path: &Path) -> fn toml_string(val: &toml::Value) -> CargoResult<~str> { match val { &toml::String(ref str) => Ok(str.to_owned()), - _ => Err(CargoError::other()) + _ => Err(other_error("")) } } diff --git a/src/cargo/util/mod.rs b/src/cargo/util/mod.rs index df596e0e8..f8b9fa906 100644 --- a/src/cargo/util/mod.rs +++ b/src/cargo/util/mod.rs @@ -1,4 +1,6 @@ pub use self::process_builder::{process,ProcessBuilder}; +pub use self::result::{CargoError,CargoResult,Wrap,Require,other_error}; + pub mod graph; pub mod process_builder; pub mod config; diff --git a/src/cargo/util/result.rs b/src/cargo/util/result.rs index 7a35d460b..f836e7371 100644 --- a/src/cargo/util/result.rs +++ b/src/cargo/util/result.rs @@ -2,14 +2,39 @@ use std::io; pub type CargoResult = Result; -#[deriving(Show)] +pub fn other_error(desc: &'static str) -> CargoError { + CargoError { + kind: OtherCargoError, + desc: desc, + detail: None, + cause: None + } +} + +#[deriving(Show,Clone)] pub struct CargoError { kind: CargoErrorKind, desc: &'static str, - detail: Option<~str> + detail: Option<~str>, + cause: Option> } -#[deriving(Show)] +impl CargoError { + pub fn get_desc(&self) -> &'static str { + self.desc + } + + pub fn get_detail<'a>(&'a self) -> Option<&'a str> { + self.detail.as_ref().map(|s| s.as_slice()) + } + + pub fn with_detail(mut self, detail: ~str) -> CargoError { + self.detail = Some(detail); + self + } +} + +#[deriving(Show,Clone)] pub enum CargoErrorKind { InternalError, IoError(io::IoError), @@ -18,7 +43,7 @@ pub enum CargoErrorKind { type CargoCliResult = Result; -#[deriving(Show)] +#[deriving(Show,Clone)] pub struct CargoCliError { kind: CargoCliErrorKind, exit_status: uint, @@ -27,7 +52,30 @@ pub struct CargoCliError { cause: Option } -#[deriving(Show)] +#[deriving(Show,Clone)] pub enum CargoCliErrorKind { OtherCargoCliError } + +pub trait Wrap { + fn wrap(self, desc: &'static str) -> Self; +} + +impl Wrap for Result { + fn wrap(self, desc: &'static str) -> Result { + self + } +} + +pub trait Require { + fn require(self, err: CargoError) -> CargoResult; +} + +impl Require for Option { + fn require(self, err: CargoError) -> CargoResult { + match self { + Some(x) => Ok(x), + None => Err(err) + } + } +}