diff --git a/src/cargo/core/manifest.rs b/src/cargo/core/manifest.rs index a2cac38f7..f4513b94b 100644 --- a/src/cargo/core/manifest.rs +++ b/src/cargo/core/manifest.rs @@ -10,7 +10,7 @@ use core::{ Summary }; use core::dependency::SerializedDependency; -use util::{CargoResult, box_error}; +use util::{CargoResult, human}; #[deriving(PartialEq,Clone)] pub struct Manifest { @@ -65,7 +65,7 @@ impl LibKind { "rlib" => Ok(Rlib), "dylib" => Ok(Dylib), "staticlib" => Ok(StaticLib), - _ => Err(box_error(format!("{} was not one of lib|rlib|dylib|staticlib", string))) + _ => Err(human(format!("{} was not one of lib|rlib|dylib|staticlib", string))) } } diff --git a/src/cargo/lib.rs b/src/cargo/lib.rs index b23b6ce33..4952bd7eb 100644 --- a/src/cargo/lib.rs +++ b/src/cargo/lib.rs @@ -30,6 +30,13 @@ macro_rules! some( } )) +macro_rules! cargo_try ( + ($expr:expr) => ({ + use util::BoxError; + try!($expr.box_error()) + }) +) + pub mod core; pub mod ops; pub mod sources; diff --git a/src/cargo/ops/cargo_read_manifest.rs b/src/cargo/ops/cargo_read_manifest.rs index f5524618e..258b1cd11 100644 --- a/src/cargo/ops/cargo_read_manifest.rs +++ b/src/cargo/ops/cargo_read_manifest.rs @@ -1,7 +1,7 @@ use std::io::File; use util; use core::{Package,Manifest,SourceId}; -use util::{CargoResult, box_error, human}; +use util::{CargoResult, human}; pub fn read_manifest(contents: &[u8], source_id: &SourceId) -> CargoResult<(Manifest, Vec)> { util::toml::to_manifest(contents, source_id).map_err(human) @@ -9,9 +9,9 @@ pub fn read_manifest(contents: &[u8], source_id: &SourceId) -> CargoResult<(Mani pub fn read_package(path: &Path, source_id: &SourceId) -> CargoResult<(Package, Vec)> { log!(5, "read_package; path={}; source-id={}", path.display(), source_id); - let mut file = try!(File::open(path).map_err(box_error)); - let data = try!(file.read_to_end().map_err(box_error)); - let (manifest, nested) = try!(read_manifest(data.as_slice(), source_id)); + let mut file = cargo_try!(File::open(path)); + let data = cargo_try!(file.read_to_end()); + let (manifest, nested) = cargo_try!(read_manifest(data.as_slice(), source_id)); Ok((Package::new(manifest, path), nested)) } diff --git a/src/cargo/sources/git/utils.rs b/src/cargo/sources/git/utils.rs index c1fbc4edf..d3e3ae852 100644 --- a/src/cargo/sources/git/utils.rs +++ b/src/cargo/sources/git/utils.rs @@ -1,5 +1,5 @@ use url::Url; -use util::{CargoResult, ProcessBuilder, process, box_error}; +use util::{CargoResult, ChainError, ProcessBuilder, process}; use std::fmt; use std::fmt::{Show,Formatter}; use std::str; @@ -41,21 +41,21 @@ impl Show for GitReference { macro_rules! git( ($config:expr, $str:expr, $($rest:expr),*) => ( - try!(git_inherit(&$config, format!($str, $($rest),*))) + cargo_try!(git_inherit(&$config, format!($str, $($rest),*))) ); ($config:expr, $str:expr) => ( - try!(git_inherit(&$config, format!($str))) + cargo_try!(git_inherit(&$config, format!($str))) ); ) macro_rules! git_output( ($config:expr, $str:expr, $($rest:expr),*) => ( - try!(git_output(&$config, format!($str, $($rest),*))) + cargo_try!(git_output(&$config, format!($str, $($rest),*))) ); ($config:expr, $str:expr) => ( - try!(git_output(&$config, format!($str))) + cargo_try!(git_output(&$config, format!($str))) ); ) @@ -158,9 +158,9 @@ impl GitRemote { pub fn checkout(&self, into: &Path) -> CargoResult { if into.exists() { - try!(self.fetch_into(into)); + cargo_try!(self.fetch_into(into)); } else { - try!(self.clone_into(into)); + cargo_try!(self.clone_into(into)); } Ok(GitDatabase { remote: self.clone(), path: into.clone() }) @@ -173,7 +173,7 @@ impl GitRemote { fn clone_into(&self, path: &Path) -> CargoResult<()> { let dirname = Path::new(path.dirname()); - try!(mkdir_recursive(path, UserDir).map_err(box_error)); + cargo_try!(mkdir_recursive(path, UserDir)); Ok(git!(dirname, "clone {} {} --bare --no-hardlinks --quiet", self.fetch_location(), path.display())) } @@ -192,10 +192,10 @@ impl GitDatabase { } pub fn copy_to(&self, reference: S, dest: &Path) -> CargoResult { - let checkout = try!(GitCheckout::clone_into(dest, self.clone(), GitReference::for_str(reference.as_slice()))); + let checkout = cargo_try!(GitCheckout::clone_into(dest, self.clone(), GitReference::for_str(reference.as_slice()))); - try!(checkout.fetch()); - try!(checkout.update_submodules()); + cargo_try!(checkout.fetch()); + cargo_try!(checkout.update_submodules()); Ok(checkout) } @@ -208,12 +208,12 @@ impl GitDatabase { impl GitCheckout { fn clone_into(into: &Path, database: GitDatabase, reference: GitReference) -> CargoResult { - let revision = try!(database.rev_for(reference.as_slice())); + let revision = cargo_try!(database.rev_for(reference.as_slice())); let checkout = GitCheckout { location: into.clone(), database: database, reference: reference, revision: revision }; // If the git checkout already exists, we don't need to clone it again if !checkout.location.join(".git").exists() { - try!(checkout.clone_repo()); + cargo_try!(checkout.clone_repo()); } Ok(checkout) @@ -226,23 +226,23 @@ impl GitCheckout { fn clone_repo(&self) -> CargoResult<()> { let dirname = Path::new(self.location.dirname()); - try!(mkdir_recursive(&dirname, UserDir).map_err(|_| - box_error(format!("Couldn't mkdir {}", Path::new(self.location.dirname()).display())))); + cargo_try!(mkdir_recursive(&dirname, UserDir).chain_error(|| + format!("Couldn't mkdir {}", Path::new(self.location.dirname()).display()))); if self.location.exists() { - try!(rmdir_recursive(&self.location).map_err(|_| - box_error(format!("Couldn't rmdir {}", Path::new(&self.location).display())))); + cargo_try!(rmdir_recursive(&self.location).chain_error(|| + format!("Couldn't rmdir {}", Path::new(&self.location).display()))); } git!(dirname, "clone --no-checkout --quiet {} {}", self.get_source().display(), self.location.display()); - try!(chmod(&self.location, AllPermissions).map_err(box_error)); + cargo_try!(chmod(&self.location, AllPermissions)); Ok(()) } fn fetch(&self) -> CargoResult<()> { git!(self.location, "fetch --force --quiet --tags {}", self.get_source().display()); - try!(self.reset(self.revision.as_slice())); + cargo_try!(self.reset(self.revision.as_slice())); Ok(()) } @@ -262,13 +262,12 @@ fn git(path: &Path, str: &str) -> ProcessBuilder { } fn git_inherit(path: &Path, str: String) -> CargoResult<()> { - git(path, str.as_slice()).exec().map_err(|err| - box_error(format!("Executing `git {}` failed: {}", str, err))) + git(path, str.as_slice()).exec().chain_error(|| format!("Executing `git {}` failed", str)) } fn git_output(path: &Path, str: String) -> CargoResult { - let output = try!(git(path, str.as_slice()).exec_with_output().map_err(|_| - box_error(format!("Executing `git {}` failed", str)))); + let output = cargo_try!(git(path, str.as_slice()).exec_with_output().chain_error(|| + format!("Executing `git {}` failed", str))); Ok(to_str(output.output.as_slice()).as_slice().trim_right().to_str()) } diff --git a/src/cargo/sources/path.rs b/src/cargo/sources/path.rs index 7aa292f18..d60a5fa06 100644 --- a/src/cargo/sources/path.rs +++ b/src/cargo/sources/path.rs @@ -2,7 +2,7 @@ use std::fmt; use std::fmt::{Show,Formatter}; use core::{Package,PackageId,Summary,SourceId,Source}; use ops; -use util::{CargoResult, box_error}; +use util::{CargoResult, error}; pub struct PathSource { id: SourceId, @@ -40,12 +40,12 @@ impl PathSource { log!(5, "get_root_package; source={}", self); if !self.updated { - return Err(box_error("source has not been updated")) + return Err(error("source has not been updated")) } match self.packages.as_slice().head() { Some(pkg) => Ok(pkg.clone()), - None => Err(box_error("no package found in source")) + None => Err(error("no package found in source")) } } } diff --git a/src/cargo/util/errors.rs b/src/cargo/util/errors.rs index 8c9187d4f..707c9aa30 100644 --- a/src/cargo/util/errors.rs +++ b/src/cargo/util/errors.rs @@ -11,6 +11,10 @@ pub trait CargoError { fn cause<'a>(&'a self) -> Option<&'a CargoError> { None } fn is_human(&self) -> bool { false } + fn box_error(self) -> Box { + box self as Box + } + fn concrete(&self) -> ConcreteCargoError { ConcreteCargoError { description: self.description(), @@ -45,10 +49,38 @@ impl CargoError for Box { fn is_human(&self) -> bool { (*self).is_human() } + + fn box_error(self) -> Box { + self + } } pub type CargoResult = Result>; +pub trait BoxError { + fn box_error(self) -> CargoResult; +} + +pub trait ChainError { + fn chain_error(self, callback: || -> E) -> CargoResult ; +} + +impl BoxError for Result { + fn box_error(self) -> CargoResult { + self.map_err(|err| err.box_error()) + } +} + +impl ChainError for Result { + fn chain_error(self, callback: || -> E) -> CargoResult { + self.map_err(|err| { + let mut update = callback().concrete(); + update.cause = Some(err.box_error()); + box update as Box + }) + } +} + impl CargoError for &'static str { fn description(&self) -> String { self.to_str() } fn is_human(&self) -> bool { true } @@ -200,7 +232,3 @@ pub fn chain(original: Box, update: E) -> Box } - -pub fn box_error(err: S) -> Box { - box err as Box -} diff --git a/src/cargo/util/mod.rs b/src/cargo/util/mod.rs index 8957948c9..1de113644 100644 --- a/src/cargo/util/mod.rs +++ b/src/cargo/util/mod.rs @@ -1,8 +1,8 @@ pub use self::config::Config; pub use self::process_builder::{process,ProcessBuilder}; pub use self::result::{Wrap, Require}; -pub use self::errors::{CargoResult, CargoError, CliResult, CliError, ProcessError}; -pub use self::errors::{process_error, box_error, internal_error, error, human, chain}; +pub use self::errors::{CargoResult, CargoError, BoxError, ChainError, CliResult, CliError, ProcessError}; +pub use self::errors::{process_error, internal_error, error, human, chain}; pub use self::paths::realpath; pub mod graph; diff --git a/src/cargo/util/toml.rs b/src/cargo/util/toml.rs index 261b9413b..22898713f 100644 --- a/src/cargo/util/toml.rs +++ b/src/cargo/util/toml.rs @@ -7,7 +7,7 @@ use serialize::Decodable; use core::{SourceId,GitKind}; use core::manifest::{LibKind,Lib}; use core::{Summary,Manifest,Target,Dependency,PackageId}; -use util::{CargoResult, Require, error, box_error}; +use util::{CargoResult, Require, error}; pub fn to_manifest(contents: &[u8], source_id: &SourceId) -> CargoResult<(Manifest, Vec)> { let root = try!(toml::parse_from_bytes(contents).map_err(|_| error("Cargo.toml is not valid Toml"))); @@ -25,7 +25,7 @@ fn toml_to_manifest(root: toml::Value) -> CargoResult { toml::from_toml(root.clone()) } - let project = try!(decode(&root, "project").map_err(box_error)); + let project = cargo_try!(decode(&root, "project")); let lib = decode(&root, "lib").ok(); let bin = decode(&root, "bin").ok();