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) => (
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);
}
}
-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))
}