Add --verbose cause chain support

This commit is contained in:
Yehuda Katz 2014-06-19 14:13:39 -07:00
parent bee480e465
commit fce9983203
3 changed files with 51 additions and 19 deletions

@ -1 +1 @@
Subproject commit 673bbd95858fc0e6eae39d0d30a2781ba4c8d87e
Subproject commit 9af78f5b1fdfd09580758ec3b559c7704e6a5382

View File

@ -34,7 +34,7 @@ fn execute() {
let (cmd, args) = match process(os::args()) {
Ok((cmd, args)) => (cmd, args),
Err(err) => return handle_error(err)
Err(err) => return handle_error(err, false)
};
if cmd == "config-for-key".to_str() {
@ -59,8 +59,8 @@ fn execute() {
match command {
Ok(ExitStatus(0)) => (),
Ok(ExitStatus(i)) | Ok(ExitSignal(i)) => handle_error(CliError::new("", i as uint)),
Err(_) => handle_error(CliError::new("No such subcommand", 127))
Ok(ExitStatus(i)) | Ok(ExitSignal(i)) => handle_error(CliError::new("", i as uint), false),
Err(_) => handle_error(CliError::new("No such subcommand", 127), false)
}
}
}

View File

@ -19,8 +19,8 @@ extern crate hamcrest;
use serialize::{Decoder,Encoder,Decodable,Encodable,json};
use std::io;
use hammer::{FlagDecoder,FlagConfig,HammerError};
pub use util::{CliError, CliResult, human};
use hammer::{FlagDecoder, FlagConfig, HammerError, FlagConfiguration};
pub use util::{CargoError, CliError, CliResult, human};
macro_rules! some(
($e:expr) => (
@ -53,30 +53,48 @@ pub struct NoFlags;
impl FlagConfig for NoFlags {}
#[deriving(Decodable)]
pub struct GlobalFlags {
verbose: bool,
rest: Vec<String>
}
impl FlagConfig for GlobalFlags {
fn config(_: Option<GlobalFlags>, c: FlagConfiguration) -> FlagConfiguration {
c.short("verbose", '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>());
fn call<'a, T: RepresentsFlags, U: RepresentsJSON, V: Encodable<json::Encoder<'a>, io::IoError>>(exec: fn(T, U) -> CliResult<Option<V>>, args: &[String]) -> CliResult<Option<V>> {
let flags = try!(flags_from_args::<T>(args));
let json = try!(json_from_stdin::<U>());
exec(flags, json)
}
process_executed(call(exec))
match global_flags() {
Err(e) => handle_error(e, true),
Ok(val) => process_executed(call(exec, val.rest.as_slice()), val)
}
}
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>());
fn call<'a, T: RepresentsFlags, V: Encodable<json::Encoder<'a>, io::IoError>>(exec: fn(T) -> CliResult<Option<V>>, args: &[String]) -> CliResult<Option<V>> {
let flags = try!(flags_from_args::<T>(args));
exec(flags)
}
process_executed(call(exec));
match global_flags() {
Err(e) => handle_error(e, true),
Ok(val) => process_executed(call(exec, val.rest.as_slice()), val)
}
}
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>>, flags: GlobalFlags) {
match result {
Err(e) => handle_error(e),
Err(e) => handle_error(e, flags.verbose),
Ok(encodable) => {
encodable.map(|encodable| {
let encoded = json::Encoder::str_encode(&encodable);
@ -86,23 +104,37 @@ pub fn process_executed<'a, T: Encodable<json::Encoder<'a>, io::IoError>>(result
}
}
pub fn handle_error(err: CliError) {
pub fn handle_error(err: CliError, verbose: bool) {
log!(4, "handle_error; err={}", err);
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));
if verbose {
error.cause().map(handle_cause);
}
std::os::set_exit_status(exit_code as int);
}
fn handle_cause(err: &CargoError) {
println!("\nCaused by:");
println!(" {}", err.description());
err.cause().map(handle_cause);
}
fn args() -> Vec<String> {
std::os::args()
}
fn flags_from_args<T: RepresentsFlags>() -> CliResult<T> {
let mut decoder = FlagDecoder::new::<T>(args().tail());
fn flags_from_args<T: RepresentsFlags>(args: &[String]) -> CliResult<T> {
let mut decoder = FlagDecoder::new::<T>(args);
Decodable::decode(&mut decoder).map_err(|e: HammerError| CliError::new(e.message, 1))
}
fn global_flags() -> CliResult<GlobalFlags> {
let mut decoder = FlagDecoder::new::<GlobalFlags>(args().tail());
Decodable::decode(&mut decoder).map_err(|e: HammerError| CliError::new(e.message, 1))
}