Skip to content

Commit f98bfb1

Browse files
committed
parse compiler messages to detect error codes and faulty deps
1 parent 2f05bb4 commit f98bfb1

File tree

1 file changed

+76
-13
lines changed

1 file changed

+76
-13
lines changed

src/runner/test.rs

Lines changed: 76 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1+
use crate::crates::Crate;
12
use crate::prelude::*;
3+
use crate::results::DiagnosticCode;
24
use crate::results::{BrokenReason, EncodingType, FailureReason, TestResult, WriteResults};
35
use crate::runner::tasks::TaskCtx;
46
use crate::runner::OverrideResult;
7+
use cargo_metadata::diagnostic::DiagnosticLevel;
8+
use cargo_metadata::Message;
59
use failure::Error;
610
use remove_dir_all::remove_dir_all;
7-
use rustwide::cmd::{CommandError, SandboxBuilder};
11+
use rustwide::cmd::{CommandError, ProcessLinesActions, SandboxBuilder};
812
use rustwide::{Build, PrepareError};
13+
use std::collections::BTreeSet;
14+
use std::convert::TryFrom;
915

1016
fn failure_reason(err: &Error) -> FailureReason {
1117
for cause in err.iter_chain() {
@@ -16,7 +22,7 @@ fn failure_reason(err: &Error) -> FailureReason {
1622
} else if let Some(&CommandError::Timeout(_)) = cause.downcast_ctx() {
1723
return FailureReason::Timeout;
1824
} else if let Some(reason) = cause.downcast_ctx::<FailureReason>() {
19-
return *reason;
25+
return reason.clone();
2026
}
2127
}
2228

@@ -73,31 +79,76 @@ fn run_cargo<DB: WriteResults>(
7379
};
7480

7581
let mut did_ice = false;
76-
let mut tracker = |line: &str| {
77-
did_ice |= line.contains("error: internal compiler error");
82+
let mut error_codes = BTreeSet::new();
83+
let mut deps = BTreeSet::new();
84+
85+
let mut detect_error = |line: &str, actions: &mut ProcessLinesActions| {
86+
// Avoid trying to deserialize non JSON output
87+
if line.starts_with('{') {
88+
let message = serde_json::from_str(line);
89+
if let Ok(message) = message {
90+
match message {
91+
Message::CompilerMessage(compiler_message) => {
92+
let inner_message = compiler_message.message;
93+
match (
94+
inner_message.level,
95+
Crate::try_from(&compiler_message.package_id),
96+
) {
97+
// the only local crate in a well defined job is the crate currently being tested
98+
(DiagnosticLevel::Error, Ok(Crate::Local(_))) => {
99+
if let Some(code) = inner_message.code {
100+
error_codes.insert(DiagnosticCode::from(code.code));
101+
}
102+
}
103+
(DiagnosticLevel::Ice, Ok(Crate::Local(_))) => did_ice = true,
104+
// If the error is in a crate that is not local then it's referred to a dependency
105+
// of the current crate
106+
(DiagnosticLevel::Error, Ok(krate)) => {
107+
deps.insert(krate);
108+
}
109+
(DiagnosticLevel::Ice, Ok(krate)) => {
110+
deps.insert(krate);
111+
}
112+
113+
_ => (),
114+
}
115+
116+
actions.replace_with_lines(
117+
inner_message.rendered.unwrap_or_default().split('\n'),
118+
);
119+
}
120+
_ => actions.remove_line(),
121+
}
122+
}
123+
}
78124
};
125+
79126
let mut command = build_env
80127
.cargo()
81128
.args(args)
82129
.env("CARGO_INCREMENTAL", "0")
83130
.env("RUST_BACKTRACE", "full")
84131
.env(rustflags_env, rustflags)
85-
.process_lines(&mut tracker);
132+
.process_lines(&mut detect_error);
133+
86134
if ctx.quiet {
87135
command = command.no_output_timeout(None);
88136
}
137+
89138
match command.run() {
90-
Ok(()) => {}
139+
Ok(()) => Ok(()),
91140
Err(e) => {
92141
if did_ice {
93-
return Err(e.context(FailureReason::ICE).into());
142+
Err(e.context(FailureReason::ICE).into())
143+
} else if !deps.is_empty() {
144+
Err(e.context(FailureReason::DependsOn(deps)).into())
145+
} else if !error_codes.is_empty() {
146+
Err(e.context(FailureReason::CompilerError(error_codes)).into())
94147
} else {
95-
return Err(e);
148+
Err(e)
96149
}
97150
}
98151
}
99-
100-
Ok(())
101152
}
102153

103154
pub(super) fn run_test<DB: WriteResults>(
@@ -152,13 +203,25 @@ pub(super) fn run_test<DB: WriteResults>(
152203
}
153204

154205
fn build<DB: WriteResults>(ctx: &TaskCtx<DB>, build_env: &Build) -> Fallible<()> {
155-
run_cargo(ctx, build_env, &["build", "--frozen"])?;
156-
run_cargo(ctx, build_env, &["test", "--frozen", "--no-run"])?;
206+
run_cargo(
207+
ctx,
208+
build_env,
209+
&["build", "--frozen", "--message-format=json"],
210+
)?;
211+
run_cargo(
212+
ctx,
213+
build_env,
214+
&["test", "--frozen", "--no-run", "--message-format=json"],
215+
)?;
157216
Ok(())
158217
}
159218

160219
fn test<DB: WriteResults>(ctx: &TaskCtx<DB>, build_env: &Build) -> Fallible<()> {
161-
run_cargo(ctx, build_env, &["test", "--frozen"])
220+
run_cargo(
221+
ctx,
222+
build_env,
223+
&["test", "--frozen", "--message-format=json"],
224+
)
162225
}
163226

164227
pub(super) fn test_build_and_test<DB: WriteResults>(

0 commit comments

Comments
 (0)