Skip to content

Commit b2b3bde

Browse files
committed
Consistently use crate::display_error on errors during drain
1 parent 86376c8 commit b2b3bde

File tree

4 files changed

+85
-54
lines changed

4 files changed

+85
-54
lines changed

src/cargo/core/compiler/job_queue.rs

+32-28
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ use crate::core::compiler::future_incompat::{
7777
use crate::core::resolver::ResolveBehavior;
7878
use crate::core::{PackageId, Shell, TargetKind};
7979
use crate::util::diagnostic_server::{self, DiagnosticPrinter};
80+
use crate::util::errors::AlreadyPrintedError;
8081
use crate::util::machine_message::{self, Message as _};
8182
use crate::util::CargoResult;
8283
use crate::util::{self, internal, profile};
@@ -169,6 +170,10 @@ struct DrainState<'cfg> {
169170
per_package_future_incompat_reports: Vec<FutureIncompatReportPackage>,
170171
}
171172

173+
pub struct ErrorsDuringDrain {
174+
pub count: usize,
175+
}
176+
172177
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
173178
pub struct JobId(pub u32);
174179

@@ -786,14 +791,14 @@ impl<'cfg> DrainState<'cfg> {
786791
// After a job has finished we update our internal state if it was
787792
// successful and otherwise wait for pending work to finish if it failed
788793
// and then immediately return.
789-
let mut error = None;
794+
let mut errors = ErrorsDuringDrain { count: 0 };
790795
// CAUTION! Do not use `?` or break out of the loop early. Every error
791796
// must be handled in such a way that the loop is still allowed to
792797
// drain event messages.
793798
loop {
794-
if error.is_none() {
799+
if errors.count == 0 {
795800
if let Err(e) = self.spawn_work_if_possible(cx, jobserver_helper, scope) {
796-
self.handle_error(&mut cx.bcx.config.shell(), &mut error, e);
801+
self.handle_error(&mut cx.bcx.config.shell(), &mut errors, e);
797802
}
798803
}
799804

@@ -804,7 +809,7 @@ impl<'cfg> DrainState<'cfg> {
804809
}
805810

806811
if let Err(e) = self.grant_rustc_token_requests() {
807-
self.handle_error(&mut cx.bcx.config.shell(), &mut error, e);
812+
self.handle_error(&mut cx.bcx.config.shell(), &mut errors, e);
808813
}
809814

810815
// And finally, before we block waiting for the next event, drop any
@@ -814,7 +819,7 @@ impl<'cfg> DrainState<'cfg> {
814819
// to the jobserver itself.
815820
for event in self.wait_for_events() {
816821
if let Err(event_err) = self.handle_event(cx, jobserver_helper, plan, event) {
817-
self.handle_error(&mut cx.bcx.config.shell(), &mut error, event_err);
822+
self.handle_error(&mut cx.bcx.config.shell(), &mut errors, event_err);
818823
}
819824
}
820825
}
@@ -839,30 +844,24 @@ impl<'cfg> DrainState<'cfg> {
839844
}
840845

841846
let time_elapsed = util::elapsed(cx.bcx.config.creation_time().elapsed());
842-
if let Err(e) = self.timings.finished(cx, &error) {
843-
if error.is_some() {
844-
crate::display_error(&e, &mut cx.bcx.config.shell());
845-
} else {
846-
return Some(e);
847-
}
847+
if let Err(e) = self.timings.finished(cx, &errors.to_error()) {
848+
self.handle_error(&mut cx.bcx.config.shell(), &mut errors, e);
848849
}
849850
if cx.bcx.build_config.emit_json() {
850851
let mut shell = cx.bcx.config.shell();
851852
let msg = machine_message::BuildFinished {
852-
success: error.is_none(),
853+
success: errors.count == 0,
853854
}
854855
.to_json_string();
855856
if let Err(e) = writeln!(shell.out(), "{}", msg) {
856-
if error.is_some() {
857-
crate::display_error(&e.into(), &mut shell);
858-
} else {
859-
return Some(e.into());
860-
}
857+
self.handle_error(&mut shell, &mut errors, e.into());
861858
}
862859
}
863860

864-
if let Some(e) = error {
865-
Some(e)
861+
if let Some(error) = errors.to_error() {
862+
// Any errors up to this point have already been printed via the
863+
// `display_error` inside `handle_error`.
864+
Some(anyhow::Error::new(AlreadyPrintedError::new(error)))
866865
} else if self.queue.is_empty() && self.pending_queue.is_empty() {
867866
let message = format!(
868867
"{} [{}] target(s) in {}",
@@ -887,19 +886,14 @@ impl<'cfg> DrainState<'cfg> {
887886
fn handle_error(
888887
&self,
889888
shell: &mut Shell,
890-
err_state: &mut Option<anyhow::Error>,
889+
err_state: &mut ErrorsDuringDrain,
891890
new_err: anyhow::Error,
892891
) {
893-
if err_state.is_some() {
894-
// Already encountered one error.
895-
log::warn!("{:?}", new_err);
896-
} else if !self.active.is_empty() {
897-
crate::display_error(&new_err, shell);
892+
crate::display_error(&new_err, shell);
893+
if !self.active.is_empty() && err_state.count == 0 {
898894
drop(shell.warn("build failed, waiting for other jobs to finish..."));
899-
*err_state = Some(anyhow::format_err!("build failed"));
900-
} else {
901-
*err_state = Some(new_err);
902895
}
896+
err_state.count += 1;
903897
}
904898

905899
// This also records CPU usage and marks concurrency; we roughly want to do
@@ -1216,3 +1210,13 @@ feature resolver. Try updating to diesel 1.4.8 to fix this error.
12161210
Ok(())
12171211
}
12181212
}
1213+
1214+
impl ErrorsDuringDrain {
1215+
fn to_error(&self) -> Option<anyhow::Error> {
1216+
match self.count {
1217+
0 => None,
1218+
1 => Some(format_err!("1 job failed")),
1219+
n => Some(format_err!("{} jobs failed", n)),
1220+
}
1221+
}
1222+
}

src/cargo/lib.rs

+19-23
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use crate::core::Shell;
1313
use anyhow::Error;
1414
use log::debug;
1515

16-
pub use crate::util::errors::{InternalError, VerboseError};
16+
pub use crate::util::errors::{AlreadyPrintedError, InternalError, VerboseError};
1717
pub use crate::util::{indented_lines, CargoResult, CliError, CliResult, Config};
1818
pub use crate::version::version;
1919

@@ -76,31 +76,27 @@ pub fn display_warning_with_error(warning: &str, err: &Error, shell: &mut Shell)
7676
}
7777

7878
fn _display_error(err: &Error, shell: &mut Shell, as_err: bool) -> bool {
79-
let verbosity = shell.verbosity();
80-
let is_verbose = |e: &(dyn std::error::Error + 'static)| -> bool {
81-
verbosity != Verbose && e.downcast_ref::<VerboseError>().is_some()
82-
};
83-
// Generally the top error shouldn't be verbose, but check it anyways.
84-
if is_verbose(err.as_ref()) {
85-
return true;
86-
}
87-
if as_err {
88-
drop(shell.error(&err));
89-
} else {
90-
drop(writeln!(shell.err(), "{}", err));
91-
}
92-
for cause in err.chain().skip(1) {
93-
// If we're not in verbose mode then print remaining errors until one
79+
for (i, err) in err.chain().enumerate() {
80+
// If we're not in verbose mode then only print cause chain until one
9481
// marked as `VerboseError` appears.
95-
if is_verbose(cause) {
82+
//
83+
// Generally the top error shouldn't be verbose, but check it anyways.
84+
if shell.verbosity() != Verbose && err.is::<VerboseError>() {
9685
return true;
9786
}
98-
drop(writeln!(shell.err(), "\nCaused by:"));
99-
drop(write!(
100-
shell.err(),
101-
"{}",
102-
indented_lines(&cause.to_string())
103-
));
87+
if err.is::<AlreadyPrintedError>() {
88+
break;
89+
}
90+
if i == 0 {
91+
if as_err {
92+
drop(shell.error(&err));
93+
} else {
94+
drop(writeln!(shell.err(), "{}", err));
95+
}
96+
} else {
97+
drop(writeln!(shell.err(), "\nCaused by:"));
98+
drop(write!(shell.err(), "{}", indented_lines(&err.to_string())));
99+
}
104100
}
105101
false
106102
}

src/cargo/util/errors.rs

+33
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,39 @@ impl fmt::Display for InternalError {
9999
}
100100
}
101101

102+
// =============================================================================
103+
// Already printed error
104+
105+
/// An error that does not need to be printed because it does not add any new
106+
/// information to what has already been printed.
107+
pub struct AlreadyPrintedError {
108+
inner: Error,
109+
}
110+
111+
impl AlreadyPrintedError {
112+
pub fn new(inner: Error) -> Self {
113+
AlreadyPrintedError { inner }
114+
}
115+
}
116+
117+
impl std::error::Error for AlreadyPrintedError {
118+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
119+
self.inner.source()
120+
}
121+
}
122+
123+
impl fmt::Debug for AlreadyPrintedError {
124+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125+
self.inner.fmt(f)
126+
}
127+
}
128+
129+
impl fmt::Display for AlreadyPrintedError {
130+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131+
self.inner.fmt(f)
132+
}
133+
}
134+
102135
// =============================================================================
103136
// Manifest error
104137

tests/testsuite/install.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -879,11 +879,9 @@ fn compile_failure() {
879879
.with_status(101)
880880
.with_stderr_contains(
881881
"\
882+
[ERROR] could not compile `foo` due to previous error
882883
[ERROR] failed to compile `foo v0.0.1 ([..])`, intermediate artifacts can be \
883884
found at `[..]target`
884-
885-
Caused by:
886-
could not compile `foo` due to previous error
887885
",
888886
)
889887
.run();

0 commit comments

Comments
 (0)