Unwind stack for cli errors
authorAleksey Kladov <aleksey.kladov@gmail.com>
Fri, 9 Mar 2018 07:43:00 +0000 (10:43 +0300)
committerAleksey Kladov <aleksey.kladov@gmail.com>
Fri, 9 Mar 2018 07:43:00 +0000 (10:43 +0300)
src/bin/cargo.rs
src/bin/cli/mod.rs
src/cargo/lib.rs
src/cargo/util/errors.rs
tests/testsuite/install.rs

index 59ff6bb9169008a1218b7daa08c838563118894f..27c751d3addd780d796101cb1f9ca91e89e48413 100644 (file)
@@ -31,18 +31,18 @@ fn main() {
         }
     };
 
-    match main_inner(&mut config) {
+    let result = {
+        init_git_transports(&mut config);
+        let _token = cargo::util::job::setup();
+        cli::do_main(&mut config)
+    };
+
+    match result {
         Err(e) => cargo::exit_with_error(e, &mut *config.shell()),
         Ok(()) => {}
     }
 }
 
-fn main_inner(config: &mut Config) -> CliResult {
-    init_git_transports(config);
-    let _token = cargo::util::job::setup();
-    cli::do_main(config)
-}
-
 fn aliased_command(config: &Config, command: &str) -> CargoResult<Option<Vec<String>>> {
     let alias_name = format!("alias.{}", command);
     let mut result = Ok(None);
index 0b18d0a8b191bc20c3260ce2c13f6d3a809dfbd6..561b204f2ff229633d63b70cef591bb5dd443c2a 100644 (file)
@@ -29,7 +29,7 @@ use search_directories;
 use is_executable;
 
 pub fn do_main(config: &mut Config) -> CliResult {
-    let args = cli().get_matches();
+    let args = cli().get_matches_safe()?;
     let is_verbose = args.occurrences_of("verbose") > 0;
     if args.is_present("version") {
         let version = cargo::version();
@@ -547,7 +547,7 @@ fn execute_subcommand(config: &mut Config, args: ArgMatches) -> CliResult {
                 alias.extend(args.values_of("").unwrap_or_default().map(|s| s.to_string()));
                 let args = cli()
                     .setting(AppSettings::NoBinaryName)
-                    .get_matches_from(alias);
+                    .get_matches_from_safe(alias)?;
                 return execute_subcommand(config, args);
             }
             let mut ext_args: Vec<&str> = vec![cmd];
index 271e6fce9bb09c69ce570ea9f44deb5f6331e06e..01a61ab6b7c717c9a1e9d652648832d09f9a91ec 100644 (file)
@@ -13,6 +13,7 @@
 #[macro_use] extern crate serde_derive;
 #[macro_use] extern crate serde_json;
 extern crate atty;
+extern crate clap;
 extern crate crates_io as registry;
 extern crate crossbeam;
 extern crate curl;
@@ -113,6 +114,11 @@ pub fn print_json<T: ser::Serialize>(obj: &T) {
 
 pub fn exit_with_error(err: CliError, shell: &mut Shell) -> ! {
     debug!("exit_with_error; err={:?}", err);
+    if let Some(ref err) = err.error {
+        if let Some(clap_err) = err.downcast_ref::<clap::Error>() {
+            clap_err.exit()
+        }
+    }
 
     let CliError { error, exit_code, unknown } = err;
     // exit_code == 0 is non-fatal error, e.g. docopt version info
index e552069d034ba0ed9a8c40c4acc264bb03929ead..e5bc2bad8fd98bf2464ed24e9c63418e200f016a 100644 (file)
@@ -6,6 +6,7 @@ use std::str;
 
 use core::{TargetKind, Workspace};
 use failure::{Context, Error, Fail};
+use clap;
 
 pub use failure::Error as CargoError;
 pub type CargoResult<T> = Result<T, Error>;
@@ -169,6 +170,13 @@ impl From<CargoError> for CliError {
     }
 }
 
+impl From<clap::Error> for CliError {
+    fn from(err: clap::Error) -> CliError {
+        let code = if err.use_stderr() { 1 } else { 0 };
+        CliError::new(err.into(), code)
+    }
+}
+
 
 // =============================================================================
 // Construction helpers
index f7272b1cb5f51de2cc965367b4ebf39f499c3217..ad5f3d60f101736da70a31cb5d21c85042465c20 100644 (file)
@@ -3,7 +3,6 @@ use std::fs::{self, File, OpenOptions};
 use std::io::prelude::*;
 
 use cargo::util::ProcessBuilder;
-use cargotest::ChannelChanger;
 use cargotest::install::{cargo_home, has_installed_exe};
 use cargotest::support::git;
 use cargotest::support::paths;