Add cargo_try!

This commit is contained in:
Yehuda Katz 2014-06-19 08:13:58 -07:00
parent 8c72add4f5
commit 2c2652526d
8 changed files with 74 additions and 40 deletions

View File

@ -10,7 +10,7 @@ use core::{
Summary Summary
}; };
use core::dependency::SerializedDependency; use core::dependency::SerializedDependency;
use util::{CargoResult, box_error}; use util::{CargoResult, human};
#[deriving(PartialEq,Clone)] #[deriving(PartialEq,Clone)]
pub struct Manifest { pub struct Manifest {
@ -65,7 +65,7 @@ impl LibKind {
"rlib" => Ok(Rlib), "rlib" => Ok(Rlib),
"dylib" => Ok(Dylib), "dylib" => Ok(Dylib),
"staticlib" => Ok(StaticLib), "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)))
} }
} }

View File

@ -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 core;
pub mod ops; pub mod ops;
pub mod sources; pub mod sources;

View File

@ -1,7 +1,7 @@
use std::io::File; use std::io::File;
use util; use util;
use core::{Package,Manifest,SourceId}; 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<Path>)> { pub fn read_manifest(contents: &[u8], source_id: &SourceId) -> CargoResult<(Manifest, Vec<Path>)> {
util::toml::to_manifest(contents, source_id).map_err(human) 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<Path>)> { pub fn read_package(path: &Path, source_id: &SourceId) -> CargoResult<(Package, Vec<Path>)> {
log!(5, "read_package; path={}; source-id={}", path.display(), source_id); log!(5, "read_package; path={}; source-id={}", path.display(), source_id);
let mut file = try!(File::open(path).map_err(box_error)); let mut file = cargo_try!(File::open(path));
let data = try!(file.read_to_end().map_err(box_error)); let data = cargo_try!(file.read_to_end());
let (manifest, nested) = try!(read_manifest(data.as_slice(), source_id)); let (manifest, nested) = cargo_try!(read_manifest(data.as_slice(), source_id));
Ok((Package::new(manifest, path), nested)) Ok((Package::new(manifest, path), nested))
} }

View File

@ -1,5 +1,5 @@
use url::Url; use url::Url;
use util::{CargoResult, ProcessBuilder, process, box_error}; use util::{CargoResult, ChainError, ProcessBuilder, process};
use std::fmt; use std::fmt;
use std::fmt::{Show,Formatter}; use std::fmt::{Show,Formatter};
use std::str; use std::str;
@ -41,21 +41,21 @@ impl Show for GitReference {
macro_rules! git( macro_rules! git(
($config:expr, $str:expr, $($rest:expr),*) => ( ($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) => ( ($config:expr, $str:expr) => (
try!(git_inherit(&$config, format!($str))) cargo_try!(git_inherit(&$config, format!($str)))
); );
) )
macro_rules! git_output( macro_rules! git_output(
($config:expr, $str:expr, $($rest:expr),*) => ( ($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) => ( ($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<GitDatabase> { pub fn checkout(&self, into: &Path) -> CargoResult<GitDatabase> {
if into.exists() { if into.exists() {
try!(self.fetch_into(into)); cargo_try!(self.fetch_into(into));
} else { } else {
try!(self.clone_into(into)); cargo_try!(self.clone_into(into));
} }
Ok(GitDatabase { remote: self.clone(), path: into.clone() }) Ok(GitDatabase { remote: self.clone(), path: into.clone() })
@ -173,7 +173,7 @@ impl GitRemote {
fn clone_into(&self, path: &Path) -> CargoResult<()> { fn clone_into(&self, path: &Path) -> CargoResult<()> {
let dirname = Path::new(path.dirname()); 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())) Ok(git!(dirname, "clone {} {} --bare --no-hardlinks --quiet", self.fetch_location(), path.display()))
} }
@ -192,10 +192,10 @@ impl GitDatabase {
} }
pub fn copy_to<S: Str>(&self, reference: S, dest: &Path) -> CargoResult<GitCheckout> { pub fn copy_to<S: Str>(&self, reference: S, dest: &Path) -> CargoResult<GitCheckout> {
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()); cargo_try!(checkout.fetch());
try!(checkout.update_submodules()); cargo_try!(checkout.update_submodules());
Ok(checkout) Ok(checkout)
} }
@ -208,12 +208,12 @@ impl GitDatabase {
impl GitCheckout { impl GitCheckout {
fn clone_into(into: &Path, database: GitDatabase, reference: GitReference) -> CargoResult<GitCheckout> { fn clone_into(into: &Path, database: GitDatabase, reference: GitReference) -> CargoResult<GitCheckout> {
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 }; 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 the git checkout already exists, we don't need to clone it again
if !checkout.location.join(".git").exists() { if !checkout.location.join(".git").exists() {
try!(checkout.clone_repo()); cargo_try!(checkout.clone_repo());
} }
Ok(checkout) Ok(checkout)
@ -226,23 +226,23 @@ impl GitCheckout {
fn clone_repo(&self) -> CargoResult<()> { fn clone_repo(&self) -> CargoResult<()> {
let dirname = Path::new(self.location.dirname()); let dirname = Path::new(self.location.dirname());
try!(mkdir_recursive(&dirname, UserDir).map_err(|_| cargo_try!(mkdir_recursive(&dirname, UserDir).chain_error(||
box_error(format!("Couldn't mkdir {}", Path::new(self.location.dirname()).display())))); format!("Couldn't mkdir {}", Path::new(self.location.dirname()).display())));
if self.location.exists() { if self.location.exists() {
try!(rmdir_recursive(&self.location).map_err(|_| cargo_try!(rmdir_recursive(&self.location).chain_error(||
box_error(format!("Couldn't rmdir {}", Path::new(&self.location).display())))); format!("Couldn't rmdir {}", Path::new(&self.location).display())));
} }
git!(dirname, "clone --no-checkout --quiet {} {}", self.get_source().display(), 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(()) Ok(())
} }
fn fetch(&self) -> CargoResult<()> { fn fetch(&self) -> CargoResult<()> {
git!(self.location, "fetch --force --quiet --tags {}", self.get_source().display()); 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(()) Ok(())
} }
@ -262,13 +262,12 @@ fn git(path: &Path, str: &str) -> ProcessBuilder {
} }
fn git_inherit(path: &Path, str: String) -> CargoResult<()> { fn git_inherit(path: &Path, str: String) -> CargoResult<()> {
git(path, str.as_slice()).exec().map_err(|err| git(path, str.as_slice()).exec().chain_error(|| format!("Executing `git {}` failed", str))
box_error(format!("Executing `git {}` failed: {}", str, err)))
} }
fn git_output(path: &Path, str: String) -> CargoResult<String> { fn git_output(path: &Path, str: String) -> CargoResult<String> {
let output = try!(git(path, str.as_slice()).exec_with_output().map_err(|_| let output = cargo_try!(git(path, str.as_slice()).exec_with_output().chain_error(||
box_error(format!("Executing `git {}` failed", str)))); format!("Executing `git {}` failed", str)));
Ok(to_str(output.output.as_slice()).as_slice().trim_right().to_str()) Ok(to_str(output.output.as_slice()).as_slice().trim_right().to_str())
} }

View File

@ -2,7 +2,7 @@ use std::fmt;
use std::fmt::{Show,Formatter}; use std::fmt::{Show,Formatter};
use core::{Package,PackageId,Summary,SourceId,Source}; use core::{Package,PackageId,Summary,SourceId,Source};
use ops; use ops;
use util::{CargoResult, box_error}; use util::{CargoResult, error};
pub struct PathSource { pub struct PathSource {
id: SourceId, id: SourceId,
@ -40,12 +40,12 @@ impl PathSource {
log!(5, "get_root_package; source={}", self); log!(5, "get_root_package; source={}", self);
if !self.updated { 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() { match self.packages.as_slice().head() {
Some(pkg) => Ok(pkg.clone()), Some(pkg) => Ok(pkg.clone()),
None => Err(box_error("no package found in source")) None => Err(error("no package found in source"))
} }
} }
} }

View File

@ -11,6 +11,10 @@ pub trait CargoError {
fn cause<'a>(&'a self) -> Option<&'a CargoError> { None } fn cause<'a>(&'a self) -> Option<&'a CargoError> { None }
fn is_human(&self) -> bool { false } fn is_human(&self) -> bool { false }
fn box_error(self) -> Box<CargoError> {
box self as Box<CargoError>
}
fn concrete(&self) -> ConcreteCargoError { fn concrete(&self) -> ConcreteCargoError {
ConcreteCargoError { ConcreteCargoError {
description: self.description(), description: self.description(),
@ -45,10 +49,38 @@ impl CargoError for Box<CargoError> {
fn is_human(&self) -> bool { fn is_human(&self) -> bool {
(*self).is_human() (*self).is_human()
} }
fn box_error(self) -> Box<CargoError> {
self
}
} }
pub type CargoResult<T> = Result<T, Box<CargoError>>; pub type CargoResult<T> = Result<T, Box<CargoError>>;
pub trait BoxError<T> {
fn box_error(self) -> CargoResult<T>;
}
pub trait ChainError<T> {
fn chain_error<E: CargoError>(self, callback: || -> E) -> CargoResult<T> ;
}
impl<T, E: CargoError> BoxError<T> for Result<T, E> {
fn box_error(self) -> CargoResult<T> {
self.map_err(|err| err.box_error())
}
}
impl<T, E: CargoError> ChainError<T> for Result<T, E> {
fn chain_error<E: CargoError>(self, callback: || -> E) -> CargoResult<T> {
self.map_err(|err| {
let mut update = callback().concrete();
update.cause = Some(err.box_error());
box update as Box<CargoError>
})
}
}
impl CargoError for &'static str { impl CargoError for &'static str {
fn description(&self) -> String { self.to_str() } fn description(&self) -> String { self.to_str() }
fn is_human(&self) -> bool { true } fn is_human(&self) -> bool { true }
@ -200,7 +232,3 @@ pub fn chain<E: CargoError>(original: Box<CargoError>, update: E) -> Box<CargoEr
concrete.cause = Some(original); concrete.cause = Some(original);
box concrete as Box<CargoError> box concrete as Box<CargoError>
} }
pub fn box_error<S: CargoError + 'static>(err: S) -> Box<CargoError> {
box err as Box<CargoError>
}

View File

@ -1,8 +1,8 @@
pub use self::config::Config; pub use self::config::Config;
pub use self::process_builder::{process,ProcessBuilder}; pub use self::process_builder::{process,ProcessBuilder};
pub use self::result::{Wrap, Require}; pub use self::result::{Wrap, Require};
pub use self::errors::{CargoResult, CargoError, CliResult, CliError, ProcessError}; pub use self::errors::{CargoResult, CargoError, BoxError, ChainError, CliResult, CliError, ProcessError};
pub use self::errors::{process_error, box_error, internal_error, error, human, chain}; pub use self::errors::{process_error, internal_error, error, human, chain};
pub use self::paths::realpath; pub use self::paths::realpath;
pub mod graph; pub mod graph;

View File

@ -7,7 +7,7 @@ use serialize::Decodable;
use core::{SourceId,GitKind}; use core::{SourceId,GitKind};
use core::manifest::{LibKind,Lib}; use core::manifest::{LibKind,Lib};
use core::{Summary,Manifest,Target,Dependency,PackageId}; 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<Path>)> { pub fn to_manifest(contents: &[u8], source_id: &SourceId) -> CargoResult<(Manifest, Vec<Path>)> {
let root = try!(toml::parse_from_bytes(contents).map_err(|_| error("Cargo.toml is not valid Toml"))); 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<TomlManifest> {
toml::from_toml(root.clone()) 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 lib = decode(&root, "lib").ok();
let bin = decode(&root, "bin").ok(); let bin = decode(&root, "bin").ok();