Skip to content

Commit a12f541

Browse files
committed
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
1 parent 894f7a4 commit a12f541

File tree

2 files changed

+104
-2
lines changed

2 files changed

+104
-2
lines changed

src/bootstrap/src/lib.rs

+60-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ use crate::core::builder::Kind;
4141
use crate::core::config::{flags, LldMode};
4242
use crate::core::config::{DryRun, Target};
4343
use crate::core::config::{LlvmLibunwind, TargetSelection};
44-
use crate::utils::exec::{BehaviorOnFailure, BootstrapCommand, OutputMode};
44+
use crate::utils::exec::{BehaviorOnFailure, BootstrapCommand, CommandOutput, OutputMode};
4545
use crate::utils::helpers::{self, dir_is_empty, exe, libdir, mtime, output, symlink_dir};
4646

4747
mod core;
@@ -958,6 +958,65 @@ impl Build {
958958
})
959959
}
960960

961+
fn run_tracked(&self, command: BootstrapCommand) -> CommandOutput {
962+
if self.config.dry_run() {
963+
return CommandOutput::default();
964+
}
965+
966+
self.verbose(|| println!("running: {command:?}"));
967+
968+
let (output, print_error): (io::Result<CommandOutput>, bool) = match command.output_mode {
969+
mode @ (OutputMode::PrintAll | OutputMode::PrintOutput) => (
970+
command.command.status().map(|status| status.into()),
971+
matches!(mode, OutputMode::PrintAll),
972+
),
973+
OutputMode::SuppressOnSuccess => (command.command.output().map(|o| o.into()), true),
974+
};
975+
976+
let output = match output {
977+
Ok(output) => output,
978+
Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", command, e)),
979+
};
980+
if !output.is_success() {
981+
if print_error {
982+
println!(
983+
"\n\nCommand did not execute successfully.\
984+
\nExpected success, got: {}",
985+
output.status(),
986+
);
987+
988+
if !self.is_verbose() {
989+
println!("Add `-v` to see more details.\n");
990+
}
991+
992+
self.verbose(|| {
993+
println!(
994+
"\nSTDOUT ----\n{}\n\
995+
STDERR ----\n{}\n",
996+
output.stdout(),
997+
output.stderr(),
998+
)
999+
});
1000+
}
1001+
1002+
match command.failure_behavior {
1003+
BehaviorOnFailure::DelayFail => {
1004+
if self.fail_fast {
1005+
exit!(1);
1006+
}
1007+
1008+
let mut failures = self.delayed_failures.borrow_mut();
1009+
failures.push(format!("{command:?}"));
1010+
}
1011+
BehaviorOnFailure::Exit => {
1012+
exit!(1);
1013+
}
1014+
BehaviorOnFailure::Ignore => {}
1015+
}
1016+
}
1017+
output
1018+
}
1019+
9611020
/// Runs a command, printing out nice contextual information if it fails.
9621021
fn run(&self, cmd: &mut Command) {
9631022
self.run_cmd(BootstrapCommand::from(cmd).fail_fast().output_mode(

src/bootstrap/src/utils/exec.rs

+44-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::process::Command;
1+
use std::process::{Command, ExitStatus, Output};
22

33
/// What should be done when the command fails.
44
#[derive(Debug, Copy, Clone)]
@@ -58,3 +58,46 @@ impl<'a> From<&'a mut Command> for BootstrapCommand<'a> {
5858
}
5959
}
6060
}
61+
62+
/// Represents the output of an executed process.
63+
#[allow(unused)]
64+
#[derive(Default)]
65+
pub struct CommandOutput {
66+
status: ExitStatus,
67+
stdout: Vec<u8>,
68+
stderr: Vec<u8>,
69+
}
70+
71+
impl CommandOutput {
72+
pub fn is_success(&self) -> bool {
73+
self.status.success()
74+
}
75+
76+
pub fn is_failure(&self) -> bool {
77+
!self.is_success()
78+
}
79+
80+
pub fn status(&self) -> ExitStatus {
81+
self.status
82+
}
83+
84+
pub fn stdout(&self) -> String {
85+
String::from_utf8(self.stdout.clone()).expect("Cannot parse process stdout as UTF-8")
86+
}
87+
88+
pub fn stderr(&self) -> String {
89+
String::from_utf8(self.stderr.clone()).expect("Cannot parse process stderr as UTF-8")
90+
}
91+
}
92+
93+
impl From<Output> for CommandOutput {
94+
fn from(output: Output) -> Self {
95+
Self { status: output.status, stdout: output.stdout, stderr: output.stderr }
96+
}
97+
}
98+
99+
impl From<ExitStatus> for CommandOutput {
100+
fn from(status: ExitStatus) -> Self {
101+
Self { status, stdout: Default::default(), stderr: Default::default() }
102+
}
103+
}

0 commit comments

Comments
 (0)