Implement new command execution logic
This function both handles error printing and early/late failures, but it also always returns the actual output of the command
This commit is contained in:
parent
894f7a4ba6
commit
a12f541a18
2 changed files with 104 additions and 2 deletions
|
@ -41,7 +41,7 @@ use crate::core::builder::Kind;
|
|||
use crate::core::config::{flags, LldMode};
|
||||
use crate::core::config::{DryRun, Target};
|
||||
use crate::core::config::{LlvmLibunwind, TargetSelection};
|
||||
use crate::utils::exec::{BehaviorOnFailure, BootstrapCommand, OutputMode};
|
||||
use crate::utils::exec::{BehaviorOnFailure, BootstrapCommand, CommandOutput, OutputMode};
|
||||
use crate::utils::helpers::{self, dir_is_empty, exe, libdir, mtime, output, symlink_dir};
|
||||
|
||||
mod core;
|
||||
|
@ -958,6 +958,65 @@ impl Build {
|
|||
})
|
||||
}
|
||||
|
||||
fn run_tracked(&self, command: BootstrapCommand) -> CommandOutput {
|
||||
if self.config.dry_run() {
|
||||
return CommandOutput::default();
|
||||
}
|
||||
|
||||
self.verbose(|| println!("running: {command:?}"));
|
||||
|
||||
let (output, print_error): (io::Result<CommandOutput>, bool) = match command.output_mode {
|
||||
mode @ (OutputMode::PrintAll | OutputMode::PrintOutput) => (
|
||||
command.command.status().map(|status| status.into()),
|
||||
matches!(mode, OutputMode::PrintAll),
|
||||
),
|
||||
OutputMode::SuppressOnSuccess => (command.command.output().map(|o| o.into()), true),
|
||||
};
|
||||
|
||||
let output = match output {
|
||||
Ok(output) => output,
|
||||
Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", command, e)),
|
||||
};
|
||||
if !output.is_success() {
|
||||
if print_error {
|
||||
println!(
|
||||
"\n\nCommand did not execute successfully.\
|
||||
\nExpected success, got: {}",
|
||||
output.status(),
|
||||
);
|
||||
|
||||
if !self.is_verbose() {
|
||||
println!("Add `-v` to see more details.\n");
|
||||
}
|
||||
|
||||
self.verbose(|| {
|
||||
println!(
|
||||
"\nSTDOUT ----\n{}\n\
|
||||
STDERR ----\n{}\n",
|
||||
output.stdout(),
|
||||
output.stderr(),
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
match command.failure_behavior {
|
||||
BehaviorOnFailure::DelayFail => {
|
||||
if self.fail_fast {
|
||||
exit!(1);
|
||||
}
|
||||
|
||||
let mut failures = self.delayed_failures.borrow_mut();
|
||||
failures.push(format!("{command:?}"));
|
||||
}
|
||||
BehaviorOnFailure::Exit => {
|
||||
exit!(1);
|
||||
}
|
||||
BehaviorOnFailure::Ignore => {}
|
||||
}
|
||||
}
|
||||
output
|
||||
}
|
||||
|
||||
/// Runs a command, printing out nice contextual information if it fails.
|
||||
fn run(&self, cmd: &mut Command) {
|
||||
self.run_cmd(BootstrapCommand::from(cmd).fail_fast().output_mode(
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::process::Command;
|
||||
use std::process::{Command, ExitStatus, Output};
|
||||
|
||||
/// What should be done when the command fails.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
|
@ -58,3 +58,46 @@ impl<'a> From<&'a mut Command> for BootstrapCommand<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the output of an executed process.
|
||||
#[allow(unused)]
|
||||
#[derive(Default)]
|
||||
pub struct CommandOutput {
|
||||
status: ExitStatus,
|
||||
stdout: Vec<u8>,
|
||||
stderr: Vec<u8>,
|
||||
}
|
||||
|
||||
impl CommandOutput {
|
||||
pub fn is_success(&self) -> bool {
|
||||
self.status.success()
|
||||
}
|
||||
|
||||
pub fn is_failure(&self) -> bool {
|
||||
!self.is_success()
|
||||
}
|
||||
|
||||
pub fn status(&self) -> ExitStatus {
|
||||
self.status
|
||||
}
|
||||
|
||||
pub fn stdout(&self) -> String {
|
||||
String::from_utf8(self.stdout.clone()).expect("Cannot parse process stdout as UTF-8")
|
||||
}
|
||||
|
||||
pub fn stderr(&self) -> String {
|
||||
String::from_utf8(self.stderr.clone()).expect("Cannot parse process stderr as UTF-8")
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Output> for CommandOutput {
|
||||
fn from(output: Output) -> Self {
|
||||
Self { status: output.status, stdout: output.stdout, stderr: output.stderr }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExitStatus> for CommandOutput {
|
||||
fn from(status: ExitStatus) -> Self {
|
||||
Self { status, stdout: Default::default(), stderr: Default::default() }
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue