mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-31 06:22:00 +00:00
Refactor command outcome handling
To handle the case of failing to start a `BootstrapCommand`.
This commit is contained in:
parent
e8c8860142
commit
60c20bfe0c
@ -13,7 +13,6 @@ use std::env;
|
|||||||
use std::ffi::{OsStr, OsString};
|
use std::ffi::{OsStr, OsString};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "bootstrap-self-test"))]
|
#[cfg(not(feature = "bootstrap-self-test"))]
|
||||||
use crate::builder::Builder;
|
use crate::builder::Builder;
|
||||||
@ -25,7 +24,6 @@ use std::collections::HashSet;
|
|||||||
use crate::builder::Kind;
|
use crate::builder::Kind;
|
||||||
use crate::core::config::Target;
|
use crate::core::config::Target;
|
||||||
use crate::utils::exec::BootstrapCommand;
|
use crate::utils::exec::BootstrapCommand;
|
||||||
use crate::utils::helpers::output;
|
|
||||||
use crate::Build;
|
use crate::Build;
|
||||||
|
|
||||||
pub struct Finder {
|
pub struct Finder {
|
||||||
@ -210,11 +208,14 @@ than building it.
|
|||||||
.or_else(|| cmd_finder.maybe_have("reuse"));
|
.or_else(|| cmd_finder.maybe_have("reuse"));
|
||||||
|
|
||||||
#[cfg(not(feature = "bootstrap-self-test"))]
|
#[cfg(not(feature = "bootstrap-self-test"))]
|
||||||
let stage0_supported_target_list: HashSet<String> =
|
let stage0_supported_target_list: HashSet<String> = crate::utils::helpers::output(
|
||||||
output(Command::new(&build.config.initial_rustc).args(["--print", "target-list"]))
|
&mut BootstrapCommand::new(&build.config.initial_rustc)
|
||||||
.lines()
|
.args(["--print", "target-list"])
|
||||||
.map(|s| s.to_string())
|
.command,
|
||||||
.collect();
|
)
|
||||||
|
.lines()
|
||||||
|
.map(|s| s.to_string())
|
||||||
|
.collect();
|
||||||
|
|
||||||
// We're gonna build some custom C code here and there, host triples
|
// We're gonna build some custom C code here and there, host triples
|
||||||
// also build some C++ shims for LLVM so we need a C++ compiler.
|
// also build some C++ shims for LLVM so we need a C++ compiler.
|
||||||
|
@ -23,14 +23,13 @@ use std::fmt::Display;
|
|||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::{Command, Stdio};
|
use std::process::{Command, Output, Stdio};
|
||||||
use std::str;
|
use std::str;
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
|
|
||||||
use build_helper::ci::{gha, CiEnv};
|
use build_helper::ci::{gha, CiEnv};
|
||||||
use build_helper::exit;
|
use build_helper::exit;
|
||||||
use build_helper::util::fail;
|
|
||||||
use filetime::FileTime;
|
use filetime::FileTime;
|
||||||
use sha2::digest::Digest;
|
use sha2::digest::Digest;
|
||||||
use termcolor::{ColorChoice, StandardStream, WriteColor};
|
use termcolor::{ColorChoice, StandardStream, WriteColor};
|
||||||
@ -945,43 +944,61 @@ impl Build {
|
|||||||
|
|
||||||
self.verbose(|| println!("running: {command:?}"));
|
self.verbose(|| println!("running: {command:?}"));
|
||||||
|
|
||||||
let output: io::Result<CommandOutput> = match command.output_mode {
|
let output: io::Result<Output> = match command.output_mode {
|
||||||
OutputMode::Print => command.command.status().map(|status| status.into()),
|
OutputMode::Print => command.command.status().map(|status| Output {
|
||||||
OutputMode::CaptureAll => command.command.output().map(|o| o.into()),
|
status,
|
||||||
|
stdout: vec![],
|
||||||
|
stderr: vec![],
|
||||||
|
}),
|
||||||
|
OutputMode::CaptureAll => command.command.output(),
|
||||||
OutputMode::CaptureStdout => {
|
OutputMode::CaptureStdout => {
|
||||||
command.command.stderr(Stdio::inherit());
|
command.command.stderr(Stdio::inherit());
|
||||||
command.command.output().map(|o| o.into())
|
command.command.output()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let output = match output {
|
use std::fmt::Write;
|
||||||
Ok(output) => output,
|
|
||||||
Err(e) => fail(&format!("failed to execute command: {command:?}\nerror: {e}")),
|
let mut message = String::new();
|
||||||
|
let output: CommandOutput = match output {
|
||||||
|
// Command has succeeded
|
||||||
|
Ok(output) if output.status.success() => output.into(),
|
||||||
|
// Command has started, but then it failed
|
||||||
|
Ok(output) => {
|
||||||
|
writeln!(
|
||||||
|
message,
|
||||||
|
"\n\nCommand {command:?} did not execute successfully.\
|
||||||
|
\nExpected success, got: {}",
|
||||||
|
output.status,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let output: CommandOutput = output.into();
|
||||||
|
// If the output mode is OutputMode::Print, the output has already been printed to
|
||||||
|
// stdout/stderr, and we thus don't have anything captured to print anyway.
|
||||||
|
if matches!(command.output_mode, OutputMode::CaptureAll | OutputMode::CaptureStdout)
|
||||||
|
{
|
||||||
|
writeln!(message, "\nSTDOUT ----\n{}", output.stdout().trim()).unwrap();
|
||||||
|
|
||||||
|
// Stderr is added to the message only if it was captured
|
||||||
|
if matches!(command.output_mode, OutputMode::CaptureAll) {
|
||||||
|
writeln!(message, "\nSTDERR ----\n{}", output.stderr().trim()).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output
|
||||||
|
}
|
||||||
|
// The command did not even start
|
||||||
|
Err(e) => {
|
||||||
|
writeln!(
|
||||||
|
message,
|
||||||
|
"\n\nCommand {command:?} did not execute successfully.\
|
||||||
|
\nIt was not possible to execute the command: {e:?}"
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
CommandOutput::did_not_start()
|
||||||
|
}
|
||||||
};
|
};
|
||||||
if !output.is_success() {
|
if !output.is_success() {
|
||||||
use std::fmt::Write;
|
|
||||||
|
|
||||||
// Here we build an error message, and below we decide if it should be printed or not.
|
|
||||||
let mut message = String::new();
|
|
||||||
writeln!(
|
|
||||||
message,
|
|
||||||
"\n\nCommand {command:?} did not execute successfully.\
|
|
||||||
\nExpected success, got: {}",
|
|
||||||
output.status(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// If the output mode is OutputMode::Print, the output has already been printed to
|
|
||||||
// stdout/stderr, and we thus don't have anything captured to print anyway.
|
|
||||||
if matches!(command.output_mode, OutputMode::CaptureAll | OutputMode::CaptureStdout) {
|
|
||||||
writeln!(message, "\nSTDOUT ----\n{}", output.stdout().trim()).unwrap();
|
|
||||||
|
|
||||||
// Stderr is added to the message only if it was captured
|
|
||||||
if matches!(command.output_mode, OutputMode::CaptureAll) {
|
|
||||||
writeln!(message, "\nSTDERR ----\n{}", output.stderr().trim()).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match command.failure_behavior {
|
match command.failure_behavior {
|
||||||
BehaviorOnFailure::DelayFail => {
|
BehaviorOnFailure::DelayFail => {
|
||||||
if self.fail_fast {
|
if self.fail_fast {
|
||||||
|
@ -132,25 +132,47 @@ impl From<Command> for BootstrapCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents the outcome of starting a command.
|
||||||
|
enum CommandOutcome {
|
||||||
|
/// The command has started and finished with some status.
|
||||||
|
Finished(ExitStatus),
|
||||||
|
/// It was not even possible to start the command.
|
||||||
|
DidNotStart,
|
||||||
|
}
|
||||||
|
|
||||||
/// Represents the output of an executed process.
|
/// Represents the output of an executed process.
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub struct CommandOutput(Output);
|
pub struct CommandOutput {
|
||||||
|
outcome: CommandOutcome,
|
||||||
|
stdout: Vec<u8>,
|
||||||
|
stderr: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
impl CommandOutput {
|
impl CommandOutput {
|
||||||
|
pub fn did_not_start() -> Self {
|
||||||
|
Self { outcome: CommandOutcome::DidNotStart, stdout: vec![], stderr: vec![] }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_success(&self) -> bool {
|
pub fn is_success(&self) -> bool {
|
||||||
self.0.status.success()
|
match self.outcome {
|
||||||
|
CommandOutcome::Finished(status) => status.success(),
|
||||||
|
CommandOutcome::DidNotStart => false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_failure(&self) -> bool {
|
pub fn is_failure(&self) -> bool {
|
||||||
!self.is_success()
|
!self.is_success()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn status(&self) -> ExitStatus {
|
pub fn status(&self) -> Option<ExitStatus> {
|
||||||
self.0.status
|
match self.outcome {
|
||||||
|
CommandOutcome::Finished(status) => Some(status),
|
||||||
|
CommandOutcome::DidNotStart => None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stdout(&self) -> String {
|
pub fn stdout(&self) -> String {
|
||||||
String::from_utf8(self.0.stdout.clone()).expect("Cannot parse process stdout as UTF-8")
|
String::from_utf8(self.stdout.clone()).expect("Cannot parse process stdout as UTF-8")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stdout_if_ok(&self) -> Option<String> {
|
pub fn stdout_if_ok(&self) -> Option<String> {
|
||||||
@ -158,24 +180,26 @@ impl CommandOutput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn stderr(&self) -> String {
|
pub fn stderr(&self) -> String {
|
||||||
String::from_utf8(self.0.stderr.clone()).expect("Cannot parse process stderr as UTF-8")
|
String::from_utf8(self.stderr.clone()).expect("Cannot parse process stderr as UTF-8")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for CommandOutput {
|
impl Default for CommandOutput {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self(Output { status: Default::default(), stdout: vec![], stderr: vec![] })
|
Self {
|
||||||
|
outcome: CommandOutcome::Finished(ExitStatus::default()),
|
||||||
|
stdout: vec![],
|
||||||
|
stderr: vec![],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Output> for CommandOutput {
|
impl From<Output> for CommandOutput {
|
||||||
fn from(output: Output) -> Self {
|
fn from(output: Output) -> Self {
|
||||||
Self(output)
|
Self {
|
||||||
}
|
outcome: CommandOutcome::Finished(output.status),
|
||||||
}
|
stdout: output.stdout,
|
||||||
|
stderr: output.stderr,
|
||||||
impl From<ExitStatus> for CommandOutput {
|
}
|
||||||
fn from(status: ExitStatus) -> Self {
|
|
||||||
Self(Output { status, stdout: vec![], stderr: vec![] })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user