Skip to content

Commit 18ae9af

Browse files
committed
Introduce a custom Command wrapper in run-make-support
1 parent cfdb617 commit 18ae9af

File tree

8 files changed

+129
-122
lines changed

8 files changed

+129
-122
lines changed

src/tools/run-make-support/src/cc.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::path::Path;
2-
use std::process::Command;
32

43
use crate::{bin_name, cygpath_windows, env_var, handle_failed_output, is_msvc, is_windows, uname};
4+
use crate::command::Command;
55

66
/// Construct a new platform-specific C compiler invocation.
77
///

src/tools/run-make-support/src/clang.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::path::Path;
2-
use std::process::Command;
32

43
use crate::{bin_name, env_var, handle_failed_output};
4+
use crate::command::Command;
55

66
/// Construct a new `clang` invocation. `clang` is not always available for all targets.
77
pub fn clang() -> Clang {
@@ -68,9 +68,4 @@ impl Clang {
6868
self.cmd.arg(format!("-fuse-ld={ld}"));
6969
self
7070
}
71-
72-
/// Get the [`Output`][::std::process::Output] of the finished process.
73-
pub fn command_output(&mut self) -> ::std::process::Output {
74-
self.cmd.output().expect("failed to get output of finished process")
75-
}
7671
}
+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
use std::ffi::OsStr;
2+
use std::io::Write;
3+
use std::ops::{Deref, DerefMut};
4+
use std::process::{Command as StdCommand, ExitStatus, Output, Stdio};
5+
6+
#[derive(Debug)]
7+
pub struct Command {
8+
cmd: StdCommand,
9+
stdin: Option<Box<[u8]>>,
10+
}
11+
12+
impl Command {
13+
pub fn new<S: AsRef<OsStr>>(program: S) -> Self {
14+
Self {
15+
cmd: StdCommand::new(program),
16+
stdin: None,
17+
}
18+
}
19+
20+
pub fn set_stdin(&mut self, stdin: Box<[u8]>) {
21+
self.stdin = Some(stdin);
22+
}
23+
24+
#[track_caller]
25+
pub(crate) fn command_output(&mut self) -> CompletedProcess {
26+
// let's make sure we piped all the input and outputs
27+
self.cmd.stdin(Stdio::piped());
28+
self.cmd.stdout(Stdio::piped());
29+
self.cmd.stderr(Stdio::piped());
30+
31+
let output = if let Some(input) = &self.stdin {
32+
let mut child = self.cmd.spawn().unwrap();
33+
34+
{
35+
let mut stdin = child.stdin.take().unwrap();
36+
stdin.write_all(input.as_ref()).unwrap();
37+
}
38+
39+
child.wait_with_output().expect("failed to get output of finished process")
40+
} else {
41+
self.cmd.output().expect("failed to get output of finished process")
42+
};
43+
output.into()
44+
}
45+
}
46+
47+
impl Deref for Command {
48+
type Target = StdCommand;
49+
50+
fn deref(&self) -> &Self::Target {
51+
&self.cmd
52+
}
53+
}
54+
55+
impl DerefMut for Command {
56+
fn deref_mut(&mut self) -> &mut Self::Target {
57+
&mut self.cmd
58+
}
59+
}
60+
61+
/// Represents the result of an executed process.
62+
pub struct CompletedProcess {
63+
output: Output,
64+
}
65+
66+
impl CompletedProcess {
67+
pub fn stdout_utf8(&self) -> String {
68+
String::from_utf8(self.output.stdout.clone()).expect("stdout is not valid UTF-8")
69+
}
70+
71+
pub fn stderr_utf8(&self) -> String {
72+
String::from_utf8(self.output.stderr.clone()).expect("stderr is not valid UTF-8")
73+
}
74+
75+
pub fn status(&self) -> ExitStatus {
76+
self.output.status
77+
}
78+
79+
#[track_caller]
80+
pub fn assert_exit_code(&self, code: i32) {
81+
assert!(self.output.status.code() == Some(code));
82+
}
83+
}
84+
85+
impl From<Output> for CompletedProcess {
86+
fn from(output: Output) -> Self {
87+
Self {
88+
output
89+
}
90+
}
91+
}

src/tools/run-make-support/src/lib.rs

+19-19
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ pub mod llvm_readobj;
1010
pub mod run;
1111
pub mod rustc;
1212
pub mod rustdoc;
13+
mod command;
1314

1415
use std::env;
1516
use std::ffi::OsString;
1617
use std::fs;
1718
use std::io;
1819
use std::path::{Path, PathBuf};
19-
use std::process::{Command, Output};
2020

2121
pub use gimli;
2222
pub use object;
@@ -167,13 +167,12 @@ pub fn cygpath_windows<P: AsRef<Path>>(path: P) -> String {
167167
let mut cygpath = Command::new("cygpath");
168168
cygpath.arg("-w");
169169
cygpath.arg(path.as_ref());
170-
let output = cygpath.output().unwrap();
171-
if !output.status.success() {
170+
let output = cygpath.command_output();
171+
if !output.status().success() {
172172
handle_failed_output(&cygpath, output, caller_line_number);
173173
}
174-
let s = String::from_utf8(output.stdout).unwrap();
175174
// cygpath -w can attach a newline
176-
s.trim().to_string()
175+
output.stdout_utf8().trim().to_string()
177176
}
178177

179178
/// Run `uname`. This assumes that `uname` is available on the platform!
@@ -183,23 +182,23 @@ pub fn uname() -> String {
183182
let caller_line_number = caller_location.line();
184183

185184
let mut uname = Command::new("uname");
186-
let output = uname.output().unwrap();
187-
if !output.status.success() {
185+
let output = uname.command_output();
186+
if !output.status().success() {
188187
handle_failed_output(&uname, output, caller_line_number);
189188
}
190-
String::from_utf8(output.stdout).unwrap()
189+
output.stdout_utf8()
191190
}
192191

193-
fn handle_failed_output(cmd: &Command, output: Output, caller_line_number: u32) -> ! {
194-
if output.status.success() {
192+
fn handle_failed_output(cmd: &Command, output: CompletedProcess, caller_line_number: u32) -> ! {
193+
if output.status().success() {
195194
eprintln!("command unexpectedly succeeded at line {caller_line_number}");
196195
} else {
197196
eprintln!("command failed at line {caller_line_number}");
198197
}
199198
eprintln!("{cmd:?}");
200-
eprintln!("output status: `{}`", output.status);
201-
eprintln!("=== STDOUT ===\n{}\n\n", String::from_utf8(output.stdout).unwrap());
202-
eprintln!("=== STDERR ===\n{}\n\n", String::from_utf8(output.stderr).unwrap());
199+
eprintln!("output status: `{}`", output.status());
200+
eprintln!("=== STDOUT ===\n{}\n\n", output.stdout_utf8());
201+
eprintln!("=== STDERR ===\n{}\n\n", output.stderr_utf8());
203202
std::process::exit(1)
204203
}
205204

@@ -412,25 +411,25 @@ macro_rules! impl_common_helpers {
412411

413412
/// Run the constructed command and assert that it is successfully run.
414413
#[track_caller]
415-
pub fn run(&mut self) -> ::std::process::Output {
414+
pub fn run(&mut self) -> crate::command::CompletedProcess {
416415
let caller_location = ::std::panic::Location::caller();
417416
let caller_line_number = caller_location.line();
418417

419-
let output = self.command_output();
420-
if !output.status.success() {
418+
let output = self.cmd.command_output();
419+
if !output.status().success() {
421420
handle_failed_output(&self.cmd, output, caller_line_number);
422421
}
423422
output
424423
}
425424

426425
/// Run the constructed command and assert that it does not successfully run.
427426
#[track_caller]
428-
pub fn run_fail(&mut self) -> ::std::process::Output {
427+
pub fn run_fail(&mut self) -> crate::command::CompletedProcess {
429428
let caller_location = ::std::panic::Location::caller();
430429
let caller_line_number = caller_location.line();
431430

432-
let output = self.command_output();
433-
if output.status.success() {
431+
let output = self.cmd.command_output();
432+
if output.status().success() {
434433
handle_failed_output(&self.cmd, output, caller_line_number);
435434
}
436435
output
@@ -446,3 +445,4 @@ macro_rules! impl_common_helpers {
446445
}
447446

448447
pub(crate) use impl_common_helpers;
448+
use crate::command::{Command, CompletedProcess};

src/tools/run-make-support/src/llvm_readobj.rs

+1-7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::path::{Path, PathBuf};
2-
use std::process::Command;
32

43
use crate::{env_var, handle_failed_output};
4+
use crate::command::Command;
55

66
/// Construct a new `llvm-readobj` invocation. This assumes that `llvm-readobj` is available
77
/// at `$LLVM_BIN_DIR/llvm-readobj`.
@@ -39,10 +39,4 @@ impl LlvmReadobj {
3939
self.cmd.arg("--file-header");
4040
self
4141
}
42-
43-
/// Get the [`Output`][::std::process::Output] of the finished process.
44-
#[track_caller]
45-
pub fn command_output(&mut self) -> ::std::process::Output {
46-
self.cmd.output().expect("failed to get output of finished process")
47-
}
4842
}

src/tools/run-make-support/src/run.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
use std::env;
22
use std::path::{Path, PathBuf};
3-
use std::process::{Command, Output};
43

54
use crate::{cwd, env_var, is_windows};
5+
use crate::command::{Command, CompletedProcess};
66

77
use super::handle_failed_output;
88

9-
fn run_common(name: &str) -> (Command, Output) {
9+
fn run_common(name: &str) -> (Command, CompletedProcess) {
1010
let mut bin_path = PathBuf::new();
1111
bin_path.push(cwd());
1212
bin_path.push(name);
@@ -33,31 +33,31 @@ fn run_common(name: &str) -> (Command, Output) {
3333
cmd.env("PATH", env::join_paths(paths.iter()).unwrap());
3434
}
3535

36-
let output = cmd.output().unwrap();
36+
let output = cmd.command_output();
3737
(cmd, output)
3838
}
3939

4040
/// Run a built binary and make sure it succeeds.
4141
#[track_caller]
42-
pub fn run(name: &str) -> Output {
42+
pub fn run(name: &str) -> CompletedProcess {
4343
let caller_location = std::panic::Location::caller();
4444
let caller_line_number = caller_location.line();
4545

4646
let (cmd, output) = run_common(name);
47-
if !output.status.success() {
47+
if !output.status().success() {
4848
handle_failed_output(&cmd, output, caller_line_number);
4949
}
5050
output
5151
}
5252

5353
/// Run a built binary and make sure it fails.
5454
#[track_caller]
55-
pub fn run_fail(name: &str) -> Output {
55+
pub fn run_fail(name: &str) -> CompletedProcess {
5656
let caller_location = std::panic::Location::caller();
5757
let caller_line_number = caller_location.line();
5858

5959
let (cmd, output) = run_common(name);
60-
if output.status.success() {
60+
if output.status().success() {
6161
handle_failed_output(&cmd, output, caller_line_number);
6262
}
6363
output

src/tools/run-make-support/src/rustc.rs

+5-41
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
use std::ffi::{OsStr, OsString};
2-
use std::io::Write;
32
use std::path::Path;
4-
use std::process::{Command, Output, Stdio};
3+
use command::Command;
54

6-
use crate::{cwd, env_var, handle_failed_output, set_host_rpath};
5+
use crate::{command, cwd, env_var, handle_failed_output, set_host_rpath};
76

87
/// Construct a new `rustc` invocation.
98
pub fn rustc() -> Rustc {
@@ -19,7 +18,6 @@ pub fn aux_build() -> Rustc {
1918
#[derive(Debug)]
2019
pub struct Rustc {
2120
cmd: Command,
22-
stdin: Option<Box<[u8]>>,
2321
}
2422

2523
crate::impl_common_helpers!(Rustc);
@@ -38,14 +36,14 @@ impl Rustc {
3836
/// Construct a new `rustc` invocation.
3937
pub fn new() -> Self {
4038
let cmd = setup_common();
41-
Self { cmd, stdin: None }
39+
Self { cmd }
4240
}
4341

4442
/// Construct a new `rustc` invocation with `aux_build` preset (setting `--crate-type=lib`).
4543
pub fn new_aux_build() -> Self {
4644
let mut cmd = setup_common();
4745
cmd.arg("--crate-type=lib");
48-
Self { cmd, stdin: None }
46+
Self { cmd }
4947
}
5048

5149
// Argument provider methods
@@ -197,7 +195,7 @@ impl Rustc {
197195

198196
/// Specify a stdin input
199197
pub fn stdin<I: AsRef<[u8]>>(&mut self, input: I) -> &mut Self {
200-
self.stdin = Some(input.as_ref().to_vec().into_boxed_slice());
198+
self.cmd.set_stdin(input.as_ref().to_vec().into_boxed_slice());
201199
self
202200
}
203201

@@ -213,38 +211,4 @@ impl Rustc {
213211
self.cmd.arg(format!("-Clinker={linker}"));
214212
self
215213
}
216-
217-
/// Get the [`Output`] of the finished process.
218-
#[track_caller]
219-
pub fn command_output(&mut self) -> Output {
220-
// let's make sure we piped all the input and outputs
221-
self.cmd.stdin(Stdio::piped());
222-
self.cmd.stdout(Stdio::piped());
223-
self.cmd.stderr(Stdio::piped());
224-
225-
if let Some(input) = &self.stdin {
226-
let mut child = self.cmd.spawn().unwrap();
227-
228-
{
229-
let mut stdin = child.stdin.take().unwrap();
230-
stdin.write_all(input.as_ref()).unwrap();
231-
}
232-
233-
child.wait_with_output().expect("failed to get output of finished process")
234-
} else {
235-
self.cmd.output().expect("failed to get output of finished process")
236-
}
237-
}
238-
239-
#[track_caller]
240-
pub fn run_fail_assert_exit_code(&mut self, code: i32) -> Output {
241-
let caller_location = std::panic::Location::caller();
242-
let caller_line_number = caller_location.line();
243-
244-
let output = self.command_output();
245-
if output.status.code().unwrap() != code {
246-
handle_failed_output(&self.cmd, output, caller_line_number);
247-
}
248-
output
249-
}
250214
}

0 commit comments

Comments
 (0)