use std::os;
use hammer::FlagConfig;
-use cargo::{execute_main_without_stdin,CLIResult,CLIError,ToResult};
+use cargo::{execute_main_without_stdin};
use cargo::ops;
+use cargo::util::{CliResult, CliError};
use cargo::util::important_paths::find_project;
-use cargo::util::{ToCLI};
#[deriving(PartialEq,Clone,Decodable,Encodable)]
pub struct Options {
execute_main_without_stdin(execute);
}
-fn execute(options: Options) -> CLIResult<Option<()>> {
+fn execute(options: Options) -> CliResult<Option<()>> {
debug!("executing; cmd=cargo-compile; args={}", os::args());
let root = match options.manifest_path {
Some(path) => Path::new(path),
None => try!(find_project(os::getcwd(), "Cargo.toml")
.map(|path| path.join("Cargo.toml"))
- .to_result(|err|
- CLIError::new("Could not find Cargo.toml in this directory or any parent directory", Some(err), 102)))
+ .map_err(|_|
+ CliError::new("Could not find Cargo.toml in this directory or any parent directory", 102)))
};
- ops::compile(&root).map(|_| None).to_cli(101)
+ ops::compile(&root).map(|_| None).map_err(|err| CliError::from_boxed(err, 101))
}
extern crate url;
use hammer::FlagConfig;
-use cargo::{execute_main_without_stdin,CLIResult,CLIError,ToResult};
+use cargo::{execute_main_without_stdin};
use cargo::core::source::{Source,SourceId};
use cargo::sources::git::{GitSource};
-use cargo::util::{Config,ToCLI};
+use cargo::util::{Config, CliResult, CliError, Require};
use url::Url;
#[deriving(PartialEq,Clone,Decodable)]
execute_main_without_stdin(execute);
}
-fn execute(options: Options) -> CLIResult<Option<()>> {
+fn execute(options: Options) -> CliResult<Option<()>> {
let Options { url, reference, .. } = options;
- let url: Url = try!(from_str(url.as_slice()).to_result(|_|
- CLIError::new(format!("The URL `{}` you passed was not a valid URL", url), None::<&str>, 1)));
+ let url: Url = try!(from_str(url.as_slice())
+ .require(|| format!("The URL `{}` you passed was not a valid URL", url))
+ .map_err(|e| CliError::from_boxed(e, 1)));
let source_id = SourceId::for_git(&url, reference.as_slice());
- let mut source = GitSource::new(&source_id, &try!(Config::new().to_cli(1)));
+ let mut source = GitSource::new(&source_id, &try!(Config::new().map_err(|e| CliError::from_boxed(e, 1))));
- try!(source.update().map_err(|e| {
- CLIError::new(format!("Couldn't update {}: {}", source, e), None::<&str>, 1)
- }));
+ try!(source.update().map_err(|e| CliError::new(format!("Couldn't update {}: {}", source, e), 1)));
Ok(None)
}
extern crate hammer;
use hammer::FlagConfig;
-use cargo::{execute_main_without_stdin,CLIResult,CLIError};
-use cargo::core::{Package,Source,SourceId};
+use cargo::{execute_main_without_stdin};
+use cargo::core::{Package, Source, SourceId};
+use cargo::util::{CliResult, CliError};
use cargo::sources::{PathSource};
#[deriving(PartialEq,Clone,Decodable)]
execute_main_without_stdin(execute);
}
-fn execute(options: Options) -> CLIResult<Option<Package>> {
+fn execute(options: Options) -> CliResult<Option<Package>> {
let source_id = SourceId::for_path(&Path::new(options.manifest_path.as_slice()));
let mut source = PathSource::new(&source_id);
source
.get_root_package()
.map(|pkg| Some(pkg))
- .map_err(|err| CLIError::new(err.get_desc(), Some(err.get_detail()), 1))
+ .map_err(|err| CliError::from_boxed(err, 1))
}
use std::io::process::{Command,InheritFd,ExitStatus,ExitSignal};
use serialize::Encodable;
use cargo::{NoFlags,execute_main_without_stdin,handle_error};
-use cargo::core::errors::{CLIError,CLIResult,ToResult};
use cargo::util::important_paths::find_project;
-use cargo::util::{ToCLI,config,simple_human};
+use cargo::util::{CliError, CliResult, CargoResult, CargoError, Require, config, box_error};
fn main() {
execute();
.stderr(InheritFd(2))
.status();
- match command.map_err(|_| simple_human("No such subcommand")) {
+ match command {
Ok(ExitStatus(0)) => (),
- Ok(ExitStatus(i)) | Ok(ExitSignal(i)) => handle_error(simple_human("").to_cli(i as uint)),
- Err(err) => handle_error(err.to_cli(127))
+ Ok(ExitStatus(i)) | Ok(ExitSignal(i)) => handle_error(CliError::new("", i as uint)),
+ Err(_) => handle_error(CliError::new("No such subcommand", 127))
}
}
}
-fn process(args: Vec<String>) -> CLIResult<(String, Vec<String>)> {
+fn process(args: Vec<String>) -> CliResult<(String, Vec<String>)> {
let args: Vec<String> = Vec::from_slice(args.tail());
- let head = try!(args.iter().nth(0).to_result(|_| CLIError::new("No subcommand found", None::<&str>, 1))).to_str();
+ let head = try!(args.iter().nth(0).require(|| "No subcommand found").map_err(|err| CliError::from_boxed(err, 1))).to_str();
let tail = Vec::from_slice(args.tail());
Ok((head, tail))
}
}
-fn config_for_key(args: ConfigForKeyFlags) -> CLIResult<Option<ConfigOut>> {
- let value = try!(config::get_config(os::getcwd(), args.key.as_slice()).to_result(|err|
- CLIError::new("Couldn't load configuration", Some(err), 1)));
+fn config_for_key(args: ConfigForKeyFlags) -> CliResult<Option<ConfigOut>> {
+ let value = try!(config::get_config(os::getcwd(), args.key.as_slice()).map_err(|err|
+ CliError::new("Couldn't load configuration", 1)));
if args.human {
println!("{}", value);
}
}
-fn config_list(args: ConfigListFlags) -> CLIResult<Option<ConfigOut>> {
- let configs = try!(config::all_configs(os::getcwd()).to_result(|err|
- CLIError::new("Couldn't load conifguration", Some(err), 1)));
+fn config_list(args: ConfigListFlags) -> CliResult<Option<ConfigOut>> {
+ let configs = try!(config::all_configs(os::getcwd()).map_err(|e|
+ CliError::new("Couldn't load configuration", 1)));
if args.human {
for (key, value) in configs.iter() {
}
}
-fn locate_project(_: NoFlags) -> CLIResult<Option<ProjectLocation>> {
- let root = try!(find_project(os::getcwd(), "Cargo.toml").to_result(|err|
- CLIError::new(err.to_str(), None::<&str>, 1)));
+fn locate_project(_: NoFlags) -> CliResult<Option<ProjectLocation>> {
+ let root = try!(find_project(os::getcwd(), "Cargo.toml").map_err(|e| CliError::from_boxed(e, 1)));
- let string = try!(root.as_str().to_result(|_|
- CLIError::new(format!("Your project path contains characters not representable in Unicode: {}", os::getcwd().display()), None::<&str>, 1)));
+ let string = try!(root.as_str()
+ .require(|| "Your project path contains characters not representable in Unicode")
+ .map_err(|e| CliError::from_boxed(e, 1)));
Ok(Some(ProjectLocation { root: string.to_str() }))
}
Summary
};
use core::dependency::SerializedDependency;
-use util::{CargoResult,simple_human};
+use util::{CargoResult, CargoError, box_error};
#[deriving(PartialEq,Clone)]
pub struct Manifest {
"rlib" => Ok(Rlib),
"dylib" => Ok(Dylib),
"staticlib" => Ok(StaticLib),
- _ => Err(simple_human(format!("{} was not one of lib|rlib|dylib|staticlib", string)))
+ _ => Err(box_error(format!("{} was not one of lib|rlib|dylib|staticlib", string)))
}
}
use std::collections::HashMap;
+
use core::{
Dependency,
PackageId,
Summary,
Registry
};
-use util::result::CargoResult;
+use util::errors::CargoResult;
/* TODO:
* - The correct input here is not a registry. Resolves should be performable
use std::fmt;
use std::str::CharOffsets;
use semver::Version;
-use util::{other_error,CargoResult};
+use util::{CargoResult, error};
#[deriving(PartialEq,Clone)]
pub struct VersionReq {
}
if lexer.is_error() {
- return Err(other_error("invalid version requirement"));
+ return Err(error("invalid version requirement"));
}
predicates.push(try!(builder.build()));
fn set_sigil(&mut self, sigil: &str) -> CargoResult<()> {
if self.op.is_some() {
- return Err(other_error("op already set"));
+ return Err(error("op already set"));
}
match Op::from_sigil(sigil) {
Some(op) => self.op = Some(op),
- _ => return Err(other_error("invalid sigil"))
+ _ => return Err(error("invalid sigil"))
}
Ok(())
fn build(&self) -> CargoResult<Predicate> {
let op = match self.op {
Some(x) => x,
- None => return Err(other_error("op required"))
+ None => return Err(error("op required"))
};
let major = match self.major {
Some(x) => x,
- None => return Err(other_error("major version required"))
+ None => return Err(error("major version required"))
};
Ok(Predicate {
let n = (c as uint) - ('0' as uint);
if n > 9 {
- return Err(other_error("version components must be numeric"));
+ return Err(error("version components must be numeric"));
}
ret *= 10;
use serialize::{Decoder,Encoder,Decodable,Encodable,json};
use std::io;
use hammer::{FlagDecoder,FlagConfig,HammerError};
-pub use core::errors::{CLIError,CLIResult,ToResult};
+pub use util::{CliError, CliResult};
macro_rules! some(
($e:expr) => (
impl FlagConfig for NoFlags {}
-pub fn execute_main<'a, T: RepresentsFlags, U: RepresentsJSON, V: Encodable<json::Encoder<'a>, io::IoError>>(exec: fn(T, U) -> CLIResult<Option<V>>) {
- fn call<'a, T: RepresentsFlags, U: RepresentsJSON, V: Encodable<json::Encoder<'a>, io::IoError>>(exec: fn(T, U) -> CLIResult<Option<V>>) -> CLIResult<Option<V>> {
+pub fn execute_main<'a, T: RepresentsFlags, U: RepresentsJSON, V: Encodable<json::Encoder<'a>, io::IoError>>(exec: fn(T, U) -> CliResult<Option<V>>) {
+ fn call<'a, T: RepresentsFlags, U: RepresentsJSON, V: Encodable<json::Encoder<'a>, io::IoError>>(exec: fn(T, U) -> CliResult<Option<V>>) -> CliResult<Option<V>> {
let flags = try!(flags_from_args::<T>());
let json = try!(json_from_stdin::<U>());
process_executed(call(exec))
}
-pub fn execute_main_without_stdin<'a, T: RepresentsFlags, V: Encodable<json::Encoder<'a>, io::IoError>>(exec: fn(T) -> CLIResult<Option<V>>) {
- fn call<'a, T: RepresentsFlags, V: Encodable<json::Encoder<'a>, io::IoError>>(exec: fn(T) -> CLIResult<Option<V>>) -> CLIResult<Option<V>> {
+pub fn execute_main_without_stdin<'a, T: RepresentsFlags, V: Encodable<json::Encoder<'a>, io::IoError>>(exec: fn(T) -> CliResult<Option<V>>) {
+ fn call<'a, T: RepresentsFlags, V: Encodable<json::Encoder<'a>, io::IoError>>(exec: fn(T) -> CliResult<Option<V>>) -> CliResult<Option<V>> {
let flags = try!(flags_from_args::<T>());
exec(flags)
process_executed(call(exec));
}
-pub fn process_executed<'a, T: Encodable<json::Encoder<'a>, io::IoError>>(result: CLIResult<Option<T>>) {
+pub fn process_executed<'a, T: Encodable<json::Encoder<'a>, io::IoError>>(result: CliResult<Option<T>>) {
match result {
Err(e) => handle_error(e),
Ok(encodable) => {
}
}
-pub fn handle_error(err: CLIError) {
+pub fn handle_error(err: CliError) {
log!(4, "handle_error; err={}", err);
- let CLIError { msg, exit_code, .. } = err;
- let _ = write!(&mut std::io::stderr(), "{}", msg);
+ let CliError { error, exit_code, .. } = err;
+ let _ = write!(&mut std::io::stderr(), "{}", error);
+ // TODO: Cause chains
//detail.map(|d| write!(&mut std::io::stderr(), ":\n{}", d));
std::os::set_exit_status(exit_code as int);
std::os::args()
}
-fn flags_from_args<T: RepresentsFlags>() -> CLIResult<T> {
+fn flags_from_args<T: RepresentsFlags>() -> CliResult<T> {
let mut decoder = FlagDecoder::new::<T>(args().tail());
- Decodable::decode(&mut decoder).to_result(|e: HammerError| CLIError::new(e.message, None::<&str>, 1))
+ Decodable::decode(&mut decoder).map_err(|e: HammerError| CliError::new(e.message, 1))
}
-fn json_from_stdin<T: RepresentsJSON>() -> CLIResult<T> {
+fn json_from_stdin<T: RepresentsJSON>() -> CliResult<T> {
let mut reader = io::stdin();
- let input = try!(reader.read_to_str().to_result(|_| CLIError::new("Standard in did not exist or was not UTF-8", None::<&str>, 1)));
+ let input = try!(reader.read_to_str().map_err(|e| CliError::new("Standard in did not exist or was not UTF-8", 1)));
- let json = try!(json::from_str(input.as_slice()).to_result(|_| CLIError::new("Could not parse standard in as JSON", Some(input.clone()), 1)));
+ let json = try!(json::from_str(input.as_slice()).map_err(|e| CliError::new("Could not parse standard in as JSON", 1)));
let mut decoder = json::Decoder::new(json);
- Decodable::decode(&mut decoder).to_result(|e: json::DecoderError| CLIError::new("Could not process standard in as input", Some(e), 1))
+ Decodable::decode(&mut decoder).map_err(|e: json::DecoderError| CliError::new("Could not process standard in as input", 1))
}
use core::registry::PackageRegistry;
use ops;
use sources::{PathSource};
-use util::{CargoResult,Wrap,config,other_error};
+use util::{CargoResult, Wrap, config, error};
pub fn compile(manifest_path: &Path) -> CargoResult<()> {
log!(4, "compile; manifest-path={}", manifest_path.display());
let config_paths = configs.find_equiv(&"paths").map(|v| v.clone()).unwrap_or_else(|| ConfigValue::new());
let paths: Vec<Path> = match config_paths.get_value() {
- &config::String(_) => return Err(other_error("The path was configured as a String instead of a List")),
+ &config::String(_) => return Err(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()
};
use std::io::File;
use util;
use core::{Package,Manifest,SourceId};
-use util::{CargoResult,io_error};
+use util::{CargoResult, CargoError, box_error, human};
pub fn read_manifest(contents: &[u8], source_id: &SourceId) -> CargoResult<(Manifest, Vec<Path>)> {
- util::toml::to_manifest(contents, source_id)
+ util::toml::to_manifest(contents, source_id).map_err(human)
}
pub fn read_package(path: &Path, source_id: &SourceId) -> CargoResult<(Package, Vec<Path>)> {
log!(5, "read_package; path={}; source-id={}", path.display(), source_id);
- let mut file = try!(File::open(path).map_err(io_error));
- let data = try!(file.read_to_end().map_err(io_error));
+ 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));
Ok((Package::new(manifest, path), nested))
use std::str;
use core::{Package,PackageSet,Target};
use util;
-use util::{other_error,human_error,CargoResult,CargoError,ProcessBuilder};
-use util::result::ProcessError;
+use util::{CargoResult, CargoError, ProcessBuilder, error, human, box_error};
type Args = Vec<String>;
fn mk_target(target: &Path) -> CargoResult<()> {
io::fs::mkdir_recursive(target, io::UserRWX)
- .map_err(|_| other_error("could not create target directory"))
+ .map_err(|_| error("could not create target directory"))
}
fn rustc(root: &Path, target: &Target, dest: &Path, deps: &Path, verbose: bool) -> CargoResult<()> {
let rustc = prepare_rustc(root, target, *crate_type, dest, deps);
try!((if verbose {
- rustc.exec()
+ rustc.exec().map_err(|err| {
+ log!(5, "exec failed; error={}", err.description());
+ human(err)
+ })
} else {
- rustc.exec_with_output().and(Ok(()))
- }).map_err(|e| rustc_to_cargo_err(rustc.get_args().as_slice(), root, e)));
+ rustc.exec_with_output().and(Ok(())).map_err(|err| {
+ log!(5, "exec_with_output failed; error={}", err.description());
+ human(err)
+ })
+ }));
}
Ok(())
dst.push(deps.display().to_str());
}
-fn rustc_to_cargo_err(args: &[String], cwd: &Path, err: CargoError) -> CargoError {
- let msg = {
- let output = match err {
- CargoError { kind: ProcessError(_, ref output), .. } => output,
- _ => fail!("Bug! exec() returned an error other than a ProcessError")
- };
-
- let mut msg = format!("failed to execute: `rustc {}`", args.connect(" "));
-
- output.as_ref().map(|o| {
- let second = format!("; Error:\n{}", str::from_utf8_lossy(o.error.as_slice()));
- msg.push_str(second.as_slice());
- });
-
- msg
- };
-
- human_error(msg, format!("root={}", cwd.display()), err)
-}
-
fn topsort(deps: &PackageSet) -> CargoResult<PackageSet> {
match deps.sort() {
Some(deps) => Ok(deps),
- None => return Err(other_error("circular dependency detected"))
+ None => return Err(error("circular dependency detected"))
}
}
use url::Url;
-use util::{CargoResult,ProcessBuilder,io_error,human_error,process};
+use util::{CargoResult, ProcessBuilder, process, box_error};
use std::fmt;
use std::fmt::{Show,Formatter};
use std::str;
fn clone_into(&self, path: &Path) -> CargoResult<()> {
let dirname = Path::new(path.dirname());
- try!(mkdir_recursive(path, UserDir).map_err(|err|
- human_error(format!("Couldn't recursively create `{}`", dirname.display()), format!("path={}", dirname.display()), io_error(err))));
+ try!(mkdir_recursive(path, UserDir).map_err(box_error));
Ok(git!(dirname, "clone {} {} --bare --no-hardlinks --quiet", self.fetch_location(), path.display()))
}
let dirname = Path::new(self.location.dirname());
try!(mkdir_recursive(&dirname, UserDir).map_err(|e|
- human_error(format!("Couldn't mkdir {}", Path::new(self.location.dirname()).display()), None::<&str>, io_error(e))));
+ box_error(format!("Couldn't mkdir {}", Path::new(self.location.dirname()).display()))));
if self.location.exists() {
try!(rmdir_recursive(&self.location).map_err(|e|
- human_error(format!("Couldn't rmdir {}", Path::new(&self.location).display()), None::<&str>, io_error(e))));
+ box_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(io_error));
+ try!(chmod(&self.location, AllPermissions).map_err(box_error));
Ok(())
}
fn git_inherit(path: &Path, str: String) -> CargoResult<()> {
git(path, str.as_slice()).exec().map_err(|err|
- human_error(format!("Executing `git {}` failed: {}", str, err), None::<&str>, err))
+ box_error(format!("Executing `git {}` failed: {}", str, err)))
}
fn git_output(path: &Path, str: String) -> CargoResult<String> {
let output = try!(git(path, str.as_slice()).exec_with_output().map_err(|err|
- human_error(format!("Executing `git {}` failed", str), None::<&str>, err)));
+ box_error(format!("Executing `git {}` failed", str))));
Ok(to_str(output.output.as_slice()).as_slice().trim_right().to_str())
}
use std::fmt::{Show,Formatter};
use core::{Package,PackageId,Summary,SourceId,Source};
use ops;
-use util::{CargoResult,simple_human};
+use util::{CargoResult, box_error};
pub struct PathSource {
id: SourceId,
match self.packages.as_slice().head() {
Some(pkg) => Ok(pkg.clone()),
- None => Err(simple_human("no package found in source"))
+ None => Err(box_error("no package found in source"))
}
}
}
use std::collections::HashMap;
use serialize::{Encodable,Encoder};
use toml;
-use util::{CargoResult,Require,other_error,simple_human};
+use util::{CargoResult, Require, error, internal_error};
pub struct Config {
home_path: Path
pub fn new() -> CargoResult<Config> {
Ok(Config {
home_path: try!(os::homedir()
- .require(simple_human("Couldn't find the home directory")))
+ .require(|| "Couldn't find the home directory"))
})
}
pub fn get_config(pwd: Path, key: &str) -> CargoResult<ConfigValue> {
find_in_tree(&pwd, |file| extract_config(file, key))
- .map_err(|_| other_error("config key not found").with_detail(format!("key={}", key)))
+ .map_err(|_| internal_error("config key not found", format!("key={}", key)))
}
pub fn all_configs(pwd: Path) -> CargoResult<HashMap<String, ConfigValue>> {
loop {
let possible = current.join(".cargo").join("config");
if possible.exists() {
- let file = try!(io::fs::File::open(&possible).map_err(|_| other_error("could not open file")));
+ let file = try!(io::fs::File::open(&possible).map_err(|_| error("could not open file")));
match walk(file) {
Ok(res) => return Ok(res),
_ => ()
if !current.pop() { break; }
}
- Err(other_error(""))
+ Err(error(""))
}
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).map_err(|_| other_error("could not open file")));
+ let file = try!(io::fs::File::open(&possible).map_err(|_| error("could not open file")));
match walk(file) {
Err(_) => err = false,
_ => ()
}
}
- if err { return Err(other_error("")); }
+ if err { return Err(error("")); }
if !current.pop() { break; }
}
fn extract_config(file: io::fs::File, key: &str) -> CargoResult<ConfigValue> {
let path = file.path().clone();
let mut buf = io::BufferedReader::new(file);
- let root = try!(toml::parse_from_buffer(&mut buf).map_err(|_| other_error("")));
- let val = try!(root.lookup(key).require(other_error("")));
+ let root = try!(toml::parse_from_buffer(&mut buf).map_err(|_| error("")));
+ let val = try!(root.lookup(key).require(|| error("")));
let v = match val {
&toml::String(ref val) => String(val.clone()),
&toml::Array(ref val) => List(val.iter().map(|s: &toml::Value| s.to_str()).collect()),
- _ => return Err(other_error(""))
+ _ => return Err(error(""))
};
Ok(ConfigValue{ value: v, path: vec!(path) })
let path = file.path().clone();
let mut buf = io::BufferedReader::new(file);
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()))));
+ internal_error("could not parse Toml manifest", format!("path={}; err={}", path.display(), err.to_str()))));
let table = try!(root.get_table()
- .require(other_error("could not parse Toml manifest").with_detail(format!("path={}", path.display()))));
+ .require(|| internal_error("could not parse Toml manifest", format!("path={}", path.display()))));
for (key, value) in table.iter() {
match value {
});
try!(merge_array(config, val.as_slice(), &path).map_err(|err|
- other_error("missing").with_detail(format!("The `{}` key in your config {}", key, err))));
+ error(format!("The `{}` key in your config {}", key, err))));
},
_ => ()
}
fn merge_array(existing: &mut ConfigValue, val: &[toml::Value], path: &Path) -> CargoResult<()> {
match existing.value {
- String(_) => return Err(other_error("should be an Array, but it was a String")),
+ String(_) => return Err(error("should be an Array, but it was a String")),
List(ref mut list) => {
let new_list: Vec<CargoResult<String>> = val.iter().map(|s: &toml::Value| toml_string(s)).collect();
if new_list.iter().any(|v| v.is_err()) {
- return Err(other_error("should be an Array of Strings, but was an Array of other values"));
+ return Err(error("should be an Array of Strings, but was an Array of other values"));
} else {
let new_list: Vec<String> = new_list.move_iter().map(|v| v.unwrap()).collect();
list.push_all(new_list.as_slice());
fn toml_string(val: &toml::Value) -> CargoResult<String> {
match val {
&toml::String(ref str) => Ok(str.clone()),
- _ => Err(other_error(""))
+ _ => Err(error(""))
}
}
--- /dev/null
+use std::io::process::{Command,ProcessOutput,ProcessExit,ExitStatus,ExitSignal};
+use std::io::IoError;
+use std::fmt;
+use std::fmt::{Show, Formatter};
+
+use TomlError = toml::Error;
+
+pub trait CargoError {
+ fn description(&self) -> String;
+ fn detail(&self) -> Option<String> { None }
+ fn cause<'a>(&'a self) -> Option<&'a CargoError> { None }
+ fn is_human(&self) -> bool { false }
+
+ fn concrete(&self) -> ConcreteCargoError {
+ ConcreteCargoError {
+ description: self.description(),
+ detail: self.detail(),
+ cause: self.cause().map(|c| box c.concrete() as Box<CargoError>),
+ is_human: self.is_human()
+ }
+ }
+}
+
+impl Show for Box<CargoError> {
+ fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+ try!(write!(f, "{}", self.description()));
+ Ok(())
+ }
+}
+
+impl CargoError for Box<CargoError> {
+ fn description(&self) -> String {
+ (*self).description()
+ }
+
+ fn detail(&self) -> Option<String> {
+ (*self).detail()
+ }
+
+ fn cause<'a>(&'a self) -> Option<&'a CargoError> {
+ (*self).cause()
+ }
+
+ fn is_human(&self) -> bool {
+ (*self).is_human()
+ }
+}
+
+pub type CargoResult<T> = Result<T, Box<CargoError>>;
+
+impl CargoError for &'static str {
+ fn description(&self) -> String { self.to_str() }
+ fn is_human(&self) -> bool { true }
+}
+
+impl CargoError for String {
+ fn description(&self) -> String { self.to_str() }
+ fn is_human(&self) -> bool { true }
+}
+
+impl CargoError for IoError {
+ fn description(&self) -> String { self.to_str() }
+}
+
+impl CargoError for TomlError {
+ fn description(&self) -> String { self.to_str() }
+}
+
+pub struct ProcessError {
+ pub command: String,
+ pub exit: Option<ProcessExit>,
+ pub output: Option<ProcessOutput>,
+ pub detail: Option<String>,
+ pub cause: Option<Box<CargoError>>
+}
+
+impl Show for ProcessError {
+ fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+ let exit = match self.exit {
+ Some(ExitStatus(i)) | Some(ExitSignal(i)) => i.to_str(),
+ None => "never executed".to_str()
+ };
+ write!(f, "process failed: `{}` (status={})", self.command, exit)
+ }
+}
+
+impl CargoError for ProcessError {
+ fn description(&self) -> String {
+ let exit = match self.exit {
+ Some(ExitStatus(i)) | Some(ExitSignal(i)) => i.to_str(),
+ None => "never executed".to_str()
+ };
+ format!("Executing `{}` failed (status={})", self.command, exit)
+ }
+
+ fn detail(&self) -> Option<String> {
+ self.detail.clone()
+ }
+
+ fn cause<'a>(&'a self) -> Option<&'a CargoError> {
+ self.cause.as_ref().map(|c| { let err: &CargoError = *c; err })
+ }
+}
+
+struct ConcreteCargoError {
+ description: String,
+ detail: Option<String>,
+ cause: Option<Box<CargoError>>,
+ is_human: bool
+}
+
+impl Show for ConcreteCargoError {
+ fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+ write!(f, "{}", self.description)
+ }
+}
+
+impl CargoError for ConcreteCargoError {
+ fn description(&self) -> String {
+ self.description.clone()
+ }
+
+ fn detail(&self) -> Option<String> {
+ self.detail.clone()
+ }
+
+ fn cause<'a>(&'a self) -> Option<&'a CargoError> {
+ self.cause.as_ref().map(|c| { let err: &CargoError = *c; err })
+ }
+
+ fn is_human(&self) -> bool {
+ self.is_human
+ }
+}
+
+pub type CliResult<T> = Result<T, CliError>;
+
+#[deriving(Show)]
+pub struct CliError {
+ pub error: Box<CargoError>,
+ pub exit_code: uint
+}
+
+impl CliError {
+ pub fn new<E: CargoError + 'static>(error: E, code: uint) -> CliError {
+ let error = box error as Box<CargoError>;
+ CliError::from_boxed(error, code)
+ }
+
+ pub fn from_boxed(error: Box<CargoError>, code: uint) -> CliError {
+ let error = if error.is_human() {
+ error
+ } else {
+ chain(error, "An unknown error occurred")
+ };
+
+ CliError { error: error, exit_code: code }
+ }
+}
+
+pub fn process_error<S: Str>(msg: S, command: &Command, status: Option<&ProcessExit>, output: Option<&ProcessOutput>) -> ProcessError {
+ ProcessError {
+ command: command.to_str(),
+ exit: status.map(|o| o.clone()),
+ output: output.map(|o| o.clone()),
+ detail: None,
+ cause: None
+ }
+}
+
+pub fn internal_error<S1: Str, S2: Str>(error: S1, detail: S2) -> Box<CargoError> {
+ box ConcreteCargoError {
+ description: error.as_slice().to_str(),
+ detail: Some(detail.as_slice().to_str()),
+ cause: None,
+ is_human: false
+ } as Box<CargoError>
+}
+
+pub fn error<S1: Str>(error: S1) -> Box<CargoError> {
+ box ConcreteCargoError {
+ description: error.as_slice().to_str(),
+ detail: None,
+ cause: None,
+ is_human: false
+ } as Box<CargoError>
+}
+
+pub fn human<E: CargoError>(error: E) -> Box<CargoError> {
+ let mut concrete = error.concrete();
+ concrete.is_human = true;
+ box concrete as Box<CargoError>
+}
+
+pub fn chain<E: CargoError>(original: Box<CargoError>, update: E) -> Box<CargoError> {
+ let mut concrete = update.concrete();
+ concrete.cause = Some(original);
+ box concrete as Box<CargoError>
+}
+
+pub fn box_error<S: CargoError + 'static>(err: S) -> Box<CargoError> {
+ box err as Box<CargoError>
+}
-use util::{other_error,CargoResult,CargoError};
+use util::{CargoResult, CargoError, internal_error};
pub fn find_project(pwd: Path, file: &str) -> CargoResult<Path> {
let mut current = pwd.clone();
Err(manifest_missing_err(&pwd, file.as_slice()))
}
-fn manifest_missing_err(pwd: &Path, file: &str) -> CargoError {
- other_error("manifest not found")
- .with_detail(format!("pwd={}; file={}", pwd.display(), file))
+fn manifest_missing_err(pwd: &Path, file: &str) -> Box<CargoError> {
+ internal_error("manifest not found",
+ format!("pwd={}; file={}", pwd.display(), file))
}
pub use self::config::Config;
pub use self::process_builder::{process,ProcessBuilder};
-pub use self::result::{CargoError,CargoResult,Wrap,Require,ToCLI,other_error,human_error,simple_human,toml_error,io_error,process_error};
+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::paths::realpath;
pub mod graph;
pub mod result;
pub mod toml;
pub mod paths;
+pub mod errors;
use std::os;
use std::path::Path;
use std::io::process::{Command,ProcessOutput,InheritFd};
-use util::{CargoResult,io_error,process_error};
+use util::{CargoResult, CargoError, ProcessError, process_error, box_error};
use std::collections::HashMap;
#[deriving(Clone,PartialEq)]
}
// TODO: should InheritFd be hardcoded?
- pub fn exec(&self) -> CargoResult<()> {
+ pub fn exec(&self) -> Result<(), ProcessError> {
let mut command = self.build_command();
command
.env(self.build_env().as_slice())
.stdout(InheritFd(1))
.stderr(InheritFd(2));
- let exit = try!(command.status().map_err(io_error));
+ let msg = || format!("Could not execute process `{}`", self.debug_string());
+
+ let exit = try!(command.status().map_err(|e| process_error(msg(), &command, None, None)));
if exit.success() {
Ok(())
} else {
- let msg = format!("Could not execute process `{}`", self.debug_string());
- Err(process_error(msg, exit, None))
+ Err(process_error(msg(), &command, Some(&exit), None))
}
}
- pub fn exec_with_output(&self) -> CargoResult<ProcessOutput> {
+ pub fn exec_with_output(&self) -> Result<ProcessOutput, ProcessError> {
let mut command = self.build_command();
command.env(self.build_env().as_slice());
- let output = try!(command.output().map_err(io_error));
+ let msg = || format!("Could not execute process `{}`", self.debug_string());
+
+ let output = try!(command.output().map_err(|e| process_error(msg(), &command, None, None)));
if output.status.success() {
Ok(output)
} else {
- let msg = format!("Could not execute process `{}`", self.debug_string());
- Err(process_error(msg, output.status.clone(), Some(output)))
+ Err(process_error(msg(), &command, Some(&output.status), Some(&output)))
}
}
-use std::fmt;
-use std::fmt::{Show,Formatter};
-use std::io;
-use std::io::IoError;
-use std::io::process::{ProcessOutput,ProcessExit};
-use core::errors::{CLIError,CLIResult};
-use toml;
-
-/*
- * CargoResult should be used in libcargo. CargoCliResult should be used in the
- * various executables.
- */
-
-pub type CargoResult<T> = Result<T, CargoError>;
-
-pub fn other_error(desc: &'static str) -> CargoError {
- CargoError {
- kind: OtherCargoError,
- desc: StaticDescription(desc),
- detail: None,
- cause: None
- }
-}
-
-pub fn io_error(err: IoError) -> CargoError {
- let desc = err.desc;
-
- CargoError {
- kind: IoError(err),
- desc: StaticDescription(desc),
- detail: None,
- cause: None
- }
-}
-
-pub fn process_error(detail: String, exit: ProcessExit, output: Option<ProcessOutput>) -> CargoError {
- CargoError {
- kind: ProcessError(exit, output),
- desc: BoxedDescription(detail),
- detail: None,
- cause: None
- }
-}
-
-pub fn human_error<T: ToStr, U: ToStr>(desc: T, detail: U, cause: CargoError) -> CargoError {
- CargoError {
- kind: HumanReadableError,
- desc: BoxedDescription(desc.to_str()),
- detail: Some(detail.to_str()),
- cause: Some(box cause)
- }
-}
-
-pub fn simple_human<T: Show>(desc: T) -> CargoError {
- CargoError {
- kind: HumanReadableError,
- desc: BoxedDescription(desc.to_str()),
- detail: None,
- cause: None
- }
-}
-
-pub fn toml_error(desc: &'static str, error: toml::Error) -> CargoError {
- CargoError {
- kind: TomlError(error),
- desc: StaticDescription(desc),
- detail: None,
- cause: None
- }
-}
-
-#[deriving(PartialEq,Clone)]
-pub struct CargoError {
- pub kind: CargoErrorKind,
- desc: CargoErrorDescription,
- detail: Option<String>,
- cause: Option<Box<CargoError>>
-}
-
-impl Show for CargoError {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- match self.desc {
- StaticDescription(string) => try!(write!(f, "{}", string)),
- BoxedDescription(ref string) => try!(write!(f, "{}", string))
- };
-
- write!(f, "; kind={}", self.kind)
- }
-}
-
-#[deriving(PartialEq,Show,Clone)]
-enum CargoErrorDescription {
- StaticDescription(&'static str),
- BoxedDescription(String)
-}
-
-impl CargoError {
- pub fn get_desc<'a>(&'a self) -> &'a str {
- match self.desc {
- StaticDescription(desc) => desc,
- BoxedDescription(ref desc) => desc.as_slice()
- }
- }
-
- pub fn get_detail<'a>(&'a self) -> Option<&'a str> {
- self.detail.as_ref().map(|s| s.as_slice())
- }
-
- pub fn with_detail<T: Show>(mut self, detail: T) -> CargoError {
- self.detail = Some(detail.to_str());
- self
- }
-
- pub fn to_cli(self, exit_code: uint) -> CLIError {
- match self {
- CargoError { kind: HumanReadableError, desc: BoxedDescription(desc), detail: detail, .. } => {
- CLIError::new(desc, detail, exit_code)
- },
- ref err @ CargoError { kind: InternalError, desc: StaticDescription(desc), detail: None, .. } => {
- CLIError::new(format!("An unexpected error occurred: {}", err), Some(desc), exit_code)
- },
- ref err @ CargoError { kind: InternalError, desc: StaticDescription(desc), detail: Some(ref detail), .. } => {
- CLIError::new(format!("An unexpected error occurred: {}", err), Some(format!("{}\n{}", desc, detail)), exit_code)
- },
- ref err @ _ => {
- CLIError::new(format!("An unexpected error occurred: {}", err), None::<&str>, exit_code)
- }
- }
- }
-}
-
-#[deriving(PartialEq)]
-pub enum CargoErrorKind {
- HumanReadableError,
- InternalError,
- ProcessError(ProcessExit, Option<ProcessOutput>),
- IoError(io::IoError),
- TomlError(toml::Error),
- OtherCargoError
-}
-
-impl Show for CargoErrorKind {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- match self {
- &ProcessError(ref exit, _) => write!(f, "ProcessError({})", exit),
- &HumanReadableError => write!(f, "HumanReadableError"),
- &InternalError => write!(f, "InternalError"),
- &IoError(ref err) => write!(f, "IoError({})", err),
- &TomlError(ref err) => write!(f, "TomlError({})", err),
- &OtherCargoError => write!(f, "OtherCargoError")
- }
- }
-}
-
-impl Clone for CargoErrorKind {
- fn clone(&self) -> CargoErrorKind {
- match self {
- &ProcessError(ref exit, ref output) => {
- ProcessError(exit.clone(), output.as_ref().map(|output| ProcessOutput {
- status: output.status.clone(), output: output.output.clone(), error: output.error.clone()
- }))
- },
- &HumanReadableError => HumanReadableError,
- &InternalError => InternalError,
- &IoError(ref err) => IoError(err.clone()),
- &TomlError(ref err) => TomlError(err.clone()),
- &OtherCargoError => OtherCargoError
- }
- }
-}
-
-type CargoCliResult<T> = Result<T, CargoCliError>;
-
-#[deriving(Show,Clone)]
-pub struct CargoCliError {
- kind: CargoCliErrorKind,
- exit_status: uint,
- desc: &'static str,
- detail: Option<String>,
- cause: Option<CargoError>
-}
-
-#[deriving(Show,Clone)]
-pub enum CargoCliErrorKind {
- OtherCargoCliError
-}
+use util::errors::{CargoResult, CargoError, chain};
pub trait Wrap {
- fn wrap(self, desc: &'static str) -> Self;
+ fn wrap<E: CargoError>(self, error: E) -> Self;
}
-impl<T> Wrap for Result<T, CargoError> {
- fn wrap(self, desc: &'static str) -> Result<T, CargoError> {
+impl<T> Wrap for Result<T, Box<CargoError>> {
+ fn wrap<E: CargoError>(self, error: E) -> CargoResult<T> {
match self {
Ok(x) => Ok(x),
- Err(e) => {
- Err(CargoError {
- kind: e.kind.clone(),
- desc: StaticDescription(desc),
- detail: None,
- cause: Some(box e)
- })
- }
+ Err(e) => Err(chain(e, error))
}
}
}
pub trait Require<T> {
- fn require(self, err: CargoError) -> CargoResult<T>;
+ fn require<E: CargoError>(self, err: || -> E) -> CargoResult<T>;
}
impl<T> Require<T> for Option<T> {
- fn require(self, err: CargoError) -> CargoResult<T> {
+ fn require<E: CargoError>(self, err: || -> E) -> CargoResult<T> {
match self {
Some(x) => Ok(x),
- None => Err(err)
- }
- }
-}
-
-pub trait ToCLI<T> {
- fn to_cli(self, exit_code: uint) -> CLIResult<T>;
-}
-
-impl<T> ToCLI<T> for Result<T, CargoError> {
- fn to_cli(self, exit_code: uint) -> CLIResult<T> {
- match self {
- Ok(val) => Ok(val),
- Err(err) => Err(err.to_cli(exit_code))
+ None => Err(box err().concrete() as Box<CargoError>)
}
}
}
use core::{SourceId,GitKind};
use core::manifest::{LibKind,Lib};
use core::{Summary,Manifest,Target,Dependency,PackageId};
-use util::{CargoResult,Require,simple_human,toml_error};
+use util::{CargoResult, Require, error, box_error};
pub fn to_manifest(contents: &[u8], source_id: &SourceId) -> CargoResult<(Manifest, Vec<Path>)> {
- let root = try!(toml::parse_from_bytes(contents).map_err(|_|
- simple_human("Cargo.toml is not valid Toml")));
-
- let toml = try!(toml_to_manifest(root).map_err(|_|
- simple_human("Cargo.toml is not a valid Cargo manifest")));
+ let root = try!(toml::parse_from_bytes(contents).map_err(|_| error("Cargo.toml is not valid Toml")));
+ let toml = try!(toml_to_manifest(root).map_err(|_| error("Cargo.toml is not a valid manifest")));
toml.to_manifest(source_id)
}
toml::from_toml(root.clone())
}
- let project = try!(decode(&root, "project").map_err(|e| toml_error("ZOMG", e)));
+ let project = try!(decode(&root, "project").map_err(box_error));
let lib = decode(&root, "lib").ok();
let bin = decode(&root, "bin").ok();
let deps = match deps {
Some(deps) => {
- let table = try!(deps.get_table().require(simple_human("dependencies must be a table"))).clone();
+ let table = try!(deps.get_table().require(|| "dependencies must be a table")).clone();
let mut deps: HashMap<String, TomlDependency> = HashMap::new();
for (k, v) in table.iter() {
let v = try!(v.get_str()
- .require(simple_human("dependency values must be string")));
+ .require(|| "dependency values must be string"));
details.insert(k.clone(), v.clone());
}
let version = try!(details.find_equiv(&"version")
- .require(simple_human("dependencies must include a version"))).clone();
+ .require(|| "dependencies must include a version")).clone();
deps.insert(k.clone(), DetailedDep(DetailedTomlDependency {
version: version,
use ham = hamcrest;
use cargo::core::shell;
use cargo::util::{process,ProcessBuilder,CargoError};
-use cargo::util::result::ProcessError;
+use cargo::util::ProcessError;
pub mod paths;
match res {
Ok(out) => self.match_output(&out),
- Err(CargoError { kind: ProcessError(_, ref out), .. }) => self.match_output(out.get_ref()),
+ Err(ProcessError { output: Some(ref out), .. }) => self.match_output(out),
Err(e) => Err(format!("could not exec process {}: {}", process, e))
}
}
assert_that(p.cargo_process("cargo-compile"),
execs()
.with_status(101)
- .with_stderr("Cargo.toml is not a valid Cargo manifest"));
+ .with_stderr("Cargo.toml is not a valid manifest"));
})
test!(cargo_compile_without_manifest {
assert_that(p.cargo_process("cargo-compile"),
execs()
.with_status(101)
- .with_stderr(format!("src/foo.rs:1:1: 1:8 error: expected item but found `invalid`\nsrc/foo.rs:1 invalid rust code!\n ^~~~~~~\nfailed to execute: `rustc src/foo.rs --crate-type bin --out-dir {} -L {}`", target.display(), target.join("deps").display()).as_slice()));
+ .with_stderr(format!("src/foo.rs:1:1: 1:8 error: expected item but found `invalid`\nsrc/foo.rs:1 invalid rust code!\n ^~~~~~~\nExecuting `rustc 'src/foo.rs' '--crate-type' 'bin' '--out-dir' '{}' '-L' '{}'` failed (status=101)", target.display(), target.join("deps").display()).as_slice()));
})
test!(cargo_compile_with_warnings_in_the_root_package {
-use support::{ProjectBuilder,ResultTest,project,execs,main_file};
+use std::io::File;
+
+use support::{ProjectBuilder, ResultTest, project, execs, main_file, paths};
use hamcrest::{assert_that,existing_file};
use cargo;
-use cargo::util::{CargoResult,process};
+use cargo::util::{CargoResult, ProcessError, process};
fn setup() {
}
-fn git_repo(name: &str, callback: |ProjectBuilder| -> ProjectBuilder) -> CargoResult<ProjectBuilder> {
+fn git_repo(name: &str, callback: |ProjectBuilder| -> ProjectBuilder) -> Result<ProjectBuilder, ProcessError> {
+ let gitconfig = paths::home().join(".gitconfig");
+
+ if !gitconfig.exists() {
+ File::create(&gitconfig).write(r"
+ [user]
+
+ email = foo@bar.com
+ name = Foo Bar
+ ".as_bytes()).assert()
+ }
+
let mut git_project = project(name);
git_project = callback(git_project);
git_project.build();