diff --git a/src/bin/cargo/commands/test.rs b/src/bin/cargo/commands/test.rs index 95981caacf2..7972aaa46ec 100644 --- a/src/bin/cargo/commands/test.rs +++ b/src/bin/cargo/commands/test.rs @@ -1,6 +1,7 @@ -use cargo::ops::{self, CompileFilter, FilterRule, LibRule}; - use crate::command_prelude::*; +use cargo::ops::{self, CompileFilter, FilterRule, LibRule}; +use cargo::util::errors; +use failure::Fail; pub fn cli() -> App { subcommand("test") @@ -164,12 +165,15 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { let err = ops::run_tests(&ws, &ops, &test_args)?; match err { None => Ok(()), - Some(err) => Err(match err.exit.as_ref().and_then(|e| e.code()) { - Some(i) => CliError::new( - failure::format_err!("{}", err.hint(&ws, &ops.compile_opts)), - i, - ), - None => CliError::new(err.into(), 101), - }), + Some(err) => { + let context = failure::format_err!("{}", err.hint(&ws, &ops.compile_opts)); + let e = match err.exit.as_ref().and_then(|e| e.code()) { + // Don't show "process didn't exit successfully" for simple errors. + Some(i) if errors::is_simple_exit_code(i) => CliError::new(context, i), + Some(i) => CliError::new(err.context(context).into(), i), + None => CliError::new(err.context(context).into(), 101), + }; + Err(e) + } } } diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 6b159b419ae..99fa9874739 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -45,7 +45,7 @@ use crate::core::manifest::TargetSourcePath; use crate::core::profiles::{Lto, PanicStrategy, Profile}; use crate::core::Feature; use crate::core::{PackageId, Target}; -use crate::util::errors::{CargoResult, CargoResultExt, Internal, ProcessError}; +use crate::util::errors::{self, CargoResult, CargoResultExt, Internal, ProcessError}; use crate::util::machine_message::Message; use crate::util::paths; use crate::util::{self, machine_message, ProcessBuilder}; @@ -271,7 +271,7 @@ fn rustc<'a, 'cfg>( .as_ref() .and_then(|perr| perr.exit.and_then(|e| e.code())) { - Some(n) if n < 128 => Internal::new(err).into(), + Some(n) if errors::is_simple_exit_code(n) => Internal::new(err).into(), _ => err, } } diff --git a/src/cargo/util/errors.rs b/src/cargo/util/errors.rs index 8ba0a5e6477..af3fd0b6cbd 100644 --- a/src/cargo/util/errors.rs +++ b/src/cargo/util/errors.rs @@ -381,6 +381,17 @@ pub fn process_error( } } +pub fn is_simple_exit_code(code: i32) -> bool { + // Typical unix exit codes are 0 to 127. + // Windows doesn't have anything "typical", and is a + // 32-bit number (which appears signed here, but is really + // unsigned). However, most of the interesting NTSTATUS + // codes are very large. This is just a rough + // approximation of which codes are "normal" and which + // ones are abnormal termination. + code >= 0 && code <= 127 +} + pub fn internal(error: S) -> failure::Error { _internal(&error) }