Skip to content

Commit cc5e9df

Browse files
committed
Cache failures in the rustc info cache
This commit updates the rustc info cache to cache failures to execute rustc as well as successes. This fixes a weird issue where if you're probing for flags the `rustc_info_cache` test fails on channels which don't have the flag since previously a failure to execute rustc resulted in never caching the result.
1 parent ed4568e commit cc5e9df

File tree

10 files changed

+157
-120
lines changed

10 files changed

+157
-120
lines changed

crates/cargo-test-support/src/lib.rs

Lines changed: 46 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -798,13 +798,17 @@ impl Execs {
798798
match res {
799799
Ok(out) => self.match_output(&out),
800800
Err(e) => {
801-
let err = e.downcast_ref::<ProcessError>();
802-
if let Some(&ProcessError {
803-
output: Some(ref out),
801+
if let Some(ProcessError {
802+
stdout: Some(stdout),
803+
stderr: Some(stderr),
804+
code,
804805
..
805-
}) = err
806+
}) = e.downcast_ref::<ProcessError>()
806807
{
807-
return self.match_output(out);
808+
return self
809+
.match_status(*code, stdout, stderr)
810+
.and(self.match_stdout(stdout, stderr))
811+
.and(self.match_stderr(stdout, stderr));
808812
}
809813
Err(format!("could not exec process {}: {:?}", process, e))
810814
}
@@ -813,119 +817,91 @@ impl Execs {
813817

814818
fn match_output(&self, actual: &Output) -> MatchResult {
815819
self.verify_checks_output(actual);
816-
self.match_status(actual)
817-
.and(self.match_stdout(actual))
818-
.and(self.match_stderr(actual))
820+
self.match_status(actual.status.code(), &actual.stdout, &actual.stderr)
821+
.and(self.match_stdout(&actual.stdout, &actual.stderr))
822+
.and(self.match_stderr(&actual.stdout, &actual.stderr))
819823
}
820824

821-
fn match_status(&self, actual: &Output) -> MatchResult {
825+
fn match_status(&self, code: Option<i32>, stdout: &[u8], stderr: &[u8]) -> MatchResult {
822826
match self.expect_exit_code {
823827
None => Ok(()),
824-
Some(code) if actual.status.code() == Some(code) => Ok(()),
828+
Some(expected) if code == Some(expected) => Ok(()),
825829
Some(_) => Err(format!(
826-
"exited with {}\n--- stdout\n{}\n--- stderr\n{}",
827-
actual.status,
828-
String::from_utf8_lossy(&actual.stdout),
829-
String::from_utf8_lossy(&actual.stderr)
830+
"exited with {:?}\n--- stdout\n{}\n--- stderr\n{}",
831+
code,
832+
String::from_utf8_lossy(&stdout),
833+
String::from_utf8_lossy(&stderr)
830834
)),
831835
}
832836
}
833837

834-
fn match_stdout(&self, actual: &Output) -> MatchResult {
838+
fn match_stdout(&self, stdout: &[u8], stderr: &[u8]) -> MatchResult {
835839
self.match_std(
836840
self.expect_stdout.as_ref(),
837-
&actual.stdout,
841+
stdout,
838842
"stdout",
839-
&actual.stderr,
843+
stderr,
840844
MatchKind::Exact,
841845
)?;
842846
for expect in self.expect_stdout_contains.iter() {
843-
self.match_std(
844-
Some(expect),
845-
&actual.stdout,
846-
"stdout",
847-
&actual.stderr,
848-
MatchKind::Partial,
849-
)?;
847+
self.match_std(Some(expect), stdout, "stdout", stderr, MatchKind::Partial)?;
850848
}
851849
for expect in self.expect_stderr_contains.iter() {
852-
self.match_std(
853-
Some(expect),
854-
&actual.stderr,
855-
"stderr",
856-
&actual.stdout,
857-
MatchKind::Partial,
858-
)?;
850+
self.match_std(Some(expect), stderr, "stderr", stdout, MatchKind::Partial)?;
859851
}
860852
for &(ref expect, number) in self.expect_stdout_contains_n.iter() {
861853
self.match_std(
862854
Some(expect),
863-
&actual.stdout,
855+
stdout,
864856
"stdout",
865-
&actual.stderr,
857+
stderr,
866858
MatchKind::PartialN(number),
867859
)?;
868860
}
869861
for expect in self.expect_stdout_not_contains.iter() {
870862
self.match_std(
871863
Some(expect),
872-
&actual.stdout,
864+
stdout,
873865
"stdout",
874-
&actual.stderr,
866+
stderr,
875867
MatchKind::NotPresent,
876868
)?;
877869
}
878870
for expect in self.expect_stderr_not_contains.iter() {
879871
self.match_std(
880872
Some(expect),
881-
&actual.stderr,
873+
stderr,
882874
"stderr",
883-
&actual.stdout,
875+
stdout,
884876
MatchKind::NotPresent,
885877
)?;
886878
}
887879
for expect in self.expect_stderr_unordered.iter() {
888-
self.match_std(
889-
Some(expect),
890-
&actual.stderr,
891-
"stderr",
892-
&actual.stdout,
893-
MatchKind::Unordered,
894-
)?;
880+
self.match_std(Some(expect), stderr, "stderr", stdout, MatchKind::Unordered)?;
895881
}
896882
for expect in self.expect_neither_contains.iter() {
897883
self.match_std(
898884
Some(expect),
899-
&actual.stdout,
885+
stdout,
900886
"stdout",
901-
&actual.stdout,
887+
stdout,
902888
MatchKind::NotPresent,
903889
)?;
904890

905891
self.match_std(
906892
Some(expect),
907-
&actual.stderr,
893+
stderr,
908894
"stderr",
909-
&actual.stderr,
895+
stderr,
910896
MatchKind::NotPresent,
911897
)?;
912898
}
913899

914900
for expect in self.expect_either_contains.iter() {
915-
let match_std = self.match_std(
916-
Some(expect),
917-
&actual.stdout,
918-
"stdout",
919-
&actual.stdout,
920-
MatchKind::Partial,
921-
);
922-
let match_err = self.match_std(
923-
Some(expect),
924-
&actual.stderr,
925-
"stderr",
926-
&actual.stderr,
927-
MatchKind::Partial,
928-
);
901+
let match_std =
902+
self.match_std(Some(expect), stdout, "stdout", stdout, MatchKind::Partial);
903+
let match_err =
904+
self.match_std(Some(expect), stderr, "stderr", stderr, MatchKind::Partial);
929905

930906
if let (Err(_), Err(_)) = (match_std, match_err) {
931907
return Err(format!(
@@ -938,12 +914,12 @@ impl Execs {
938914
}
939915

940916
for (with, without) in self.expect_stderr_with_without.iter() {
941-
self.match_with_without(&actual.stderr, with, without)?;
917+
self.match_with_without(stderr, with, without)?;
942918
}
943919

944920
if let Some(ref objects) = self.expect_json {
945-
let stdout = str::from_utf8(&actual.stdout)
946-
.map_err(|_| "stdout was not utf8 encoded".to_owned())?;
921+
let stdout =
922+
str::from_utf8(stdout).map_err(|_| "stdout was not utf8 encoded".to_owned())?;
947923
let lines = stdout
948924
.lines()
949925
.filter(|line| line.starts_with('{'))
@@ -962,8 +938,8 @@ impl Execs {
962938
}
963939

964940
if !self.expect_json_contains_unordered.is_empty() {
965-
let stdout = str::from_utf8(&actual.stdout)
966-
.map_err(|_| "stdout was not utf8 encoded".to_owned())?;
941+
let stdout =
942+
str::from_utf8(stdout).map_err(|_| "stdout was not utf8 encoded".to_owned())?;
967943
let mut lines = stdout
968944
.lines()
969945
.filter(|line| line.starts_with('{'))
@@ -990,12 +966,12 @@ impl Execs {
990966
Ok(())
991967
}
992968

993-
fn match_stderr(&self, actual: &Output) -> MatchResult {
969+
fn match_stderr(&self, stdout: &[u8], stderr: &[u8]) -> MatchResult {
994970
self.match_std(
995971
self.expect_stderr.as_ref(),
996-
&actual.stderr,
972+
stderr,
997973
"stderr",
998-
&actual.stdout,
974+
stdout,
999975
MatchKind::Exact,
1000976
)
1001977
}

src/bin/cargo/commands/bench.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
7474
let err = ops::run_benches(&ws, &ops, &bench_args)?;
7575
match err {
7676
None => Ok(()),
77-
Some(err) => Err(match err.exit.as_ref().and_then(|e| e.code()) {
77+
Some(err) => Err(match err.code {
7878
Some(i) => CliError::new(anyhow::format_err!("bench failed"), i),
7979
None => CliError::new(err.into(), 101),
8080
}),

src/bin/cargo/commands/run.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,15 +90,14 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
9090

9191
// If we never actually spawned the process then that sounds pretty
9292
// bad and we always want to forward that up.
93-
let exit = match proc_err.exit {
93+
let exit_code = match proc_err.code {
9494
Some(exit) => exit,
9595
None => return CliError::new(err, 101),
9696
};
9797

9898
// If `-q` was passed then we suppress extra error information about
9999
// a failed process, we assume the process itself printed out enough
100100
// information about why it failed so we don't do so as well
101-
let exit_code = exit.code().unwrap_or(101);
102101
let is_quiet = config.shell().verbosity() == Verbosity::Quiet;
103102
if is_quiet {
104103
CliError::code(exit_code)

src/bin/cargo/commands/test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
125125
None => Ok(()),
126126
Some(err) => {
127127
let context = anyhow::format_err!("{}", err.hint(&ws, &ops.compile_opts));
128-
let e = match err.exit.as_ref().and_then(|e| e.code()) {
128+
let e = match err.code {
129129
// Don't show "process didn't exit successfully" for simple errors.
130130
Some(i) if errors::is_simple_exit_code(i) => CliError::new(context, i),
131131
Some(i) => CliError::new(Error::from(err).context(context), i),

src/bin/cargo/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ fn execute_external_subcommand(config: &Config, cmd: &str, args: &[&str]) -> Cli
171171
};
172172

173173
if let Some(perr) = err.downcast_ref::<ProcessError>() {
174-
if let Some(code) = perr.exit.as_ref().and_then(|c| c.code()) {
174+
if let Some(code) = perr.code {
175175
return Err(CliError::code(code));
176176
}
177177
}

src/cargo/core/compiler/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ fn rustc(cx: &mut Context<'_, '_>, unit: &Unit, exec: &Arc<dyn Executor>) -> Car
297297
match err
298298
.downcast_ref::<ProcessError>()
299299
.as_ref()
300-
.and_then(|perr| perr.exit.and_then(|e| e.code()))
300+
.and_then(|perr| perr.code)
301301
{
302302
Some(n) if errors::is_simple_exit_code(n) => VerboseError::new(err).into(),
303303
_ => err,

src/cargo/util/errors.rs

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -192,14 +192,25 @@ impl<'a> ::std::iter::FusedIterator for ManifestCauses<'a> {}
192192
pub struct ProcessError {
193193
/// A detailed description to show to the user why the process failed.
194194
pub desc: String,
195+
195196
/// The exit status of the process.
196197
///
197-
/// This can be `None` if the process failed to launch (like process not found).
198-
pub exit: Option<ExitStatus>,
199-
/// The output from the process.
198+
/// This can be `None` if the process failed to launch (like process not
199+
/// found) or if the exit status wasn't a code but was instead something
200+
/// like termination via a signal.
201+
pub code: Option<i32>,
202+
203+
/// The stdout from the process.
204+
///
205+
/// This can be `None` if the process failed to launch, or the output was
206+
/// not captured.
207+
pub stdout: Option<Vec<u8>>,
208+
209+
/// The stderr from the process.
200210
///
201-
/// This can be `None` if the process failed to launch, or the output was not captured.
202-
pub output: Option<Output>,
211+
/// This can be `None` if the process failed to launch, or the output was
212+
/// not captured.
213+
pub stderr: Option<Vec<u8>>,
203214
}
204215

205216
impl fmt::Display for ProcessError {
@@ -218,7 +229,7 @@ impl std::error::Error for ProcessError {}
218229
pub struct CargoTestError {
219230
pub test: Test,
220231
pub desc: String,
221-
pub exit: Option<ExitStatus>,
232+
pub code: Option<i32>,
222233
pub causes: Vec<ProcessError>,
223234
}
224235

@@ -254,7 +265,7 @@ impl CargoTestError {
254265
CargoTestError {
255266
test,
256267
desc,
257-
exit: errors[0].exit,
268+
code: errors[0].code,
258269
causes: errors,
259270
}
260271
}
@@ -359,20 +370,39 @@ pub fn process_error(
359370
output: Option<&Output>,
360371
) -> ProcessError {
361372
let exit = match status {
362-
Some(s) => status_to_string(s),
373+
Some(s) => exit_status_to_string(s),
363374
None => "never executed".to_string(),
364375
};
365-
let mut desc = format!("{} ({})", &msg, exit);
366376

367-
if let Some(out) = output {
368-
match str::from_utf8(&out.stdout) {
377+
process_error_raw(
378+
msg,
379+
status.and_then(|s| s.code()),
380+
&exit,
381+
output.map(|s| s.stdout.as_slice()),
382+
output.map(|s| s.stderr.as_slice()),
383+
)
384+
}
385+
386+
pub fn process_error_raw(
387+
msg: &str,
388+
code: Option<i32>,
389+
status: &str,
390+
stdout: Option<&[u8]>,
391+
stderr: Option<&[u8]>,
392+
) -> ProcessError {
393+
let mut desc = format!("{} ({})", msg, status);
394+
395+
if let Some(out) = stdout {
396+
match str::from_utf8(out) {
369397
Ok(s) if !s.trim().is_empty() => {
370398
desc.push_str("\n--- stdout\n");
371399
desc.push_str(s);
372400
}
373401
Ok(..) | Err(..) => {}
374402
}
375-
match str::from_utf8(&out.stderr) {
403+
}
404+
if let Some(out) = stderr {
405+
match str::from_utf8(out) {
376406
Ok(s) if !s.trim().is_empty() => {
377407
desc.push_str("\n--- stderr\n");
378408
desc.push_str(s);
@@ -381,11 +411,16 @@ pub fn process_error(
381411
}
382412
}
383413

384-
return ProcessError {
414+
ProcessError {
385415
desc,
386-
exit: status,
387-
output: output.cloned(),
388-
};
416+
code,
417+
stdout: stdout.map(|s| s.to_vec()),
418+
stderr: stderr.map(|s| s.to_vec()),
419+
}
420+
}
421+
422+
pub fn exit_status_to_string(status: ExitStatus) -> String {
423+
return status_to_string(status);
389424

390425
#[cfg(unix)]
391426
fn status_to_string(status: ExitStatus) -> String {

src/cargo/util/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ pub use self::canonical_url::CanonicalUrl;
44
pub use self::config::{homedir, Config, ConfigValue};
55
pub use self::dependency_queue::DependencyQueue;
66
pub use self::diagnostic_server::RustfixDiagnosticServer;
7-
pub use self::errors::{internal, process_error};
7+
pub use self::errors::{exit_status_to_string, internal, process_error, process_error_raw};
88
pub use self::errors::{CargoResult, CargoResultExt, CliResult, Test};
99
pub use self::errors::{CargoTestError, CliError, ProcessError};
1010
pub use self::flock::{FileLock, Filesystem};

0 commit comments

Comments
 (0)