Skip to content

Commit bd4f67c

Browse files
authored
Rollup merge of #123699 - jieyouxu:rmake-refactor, r=Mark-Simulacrum
run-make-support: tidy up support library - Make `handle_failed_output` take `&Command` instead of having the caller keep doing `format!("{:#?}", s)`. - Introduce a helper macro for implementing common command wrappers, such as `arg`, `args`, `run`, `run_fail`. - Use the helper macro on existing command wrappers and remove manual copy-pasta'd implementations.
2 parents 7c8c2f0 + a67a119 commit bd4f67c

File tree

5 files changed

+146
-121
lines changed

5 files changed

+146
-121
lines changed

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

+3-36
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::env;
22
use std::path::Path;
3-
use std::process::{Command, Output};
3+
use std::process::Command;
44

55
use crate::{bin_name, cygpath_windows, handle_failed_output, is_msvc, is_windows, tmp_dir, uname};
66

@@ -19,6 +19,8 @@ pub struct Cc {
1919
cmd: Command,
2020
}
2121

22+
crate::impl_common_helpers!(Cc);
23+
2224
impl Cc {
2325
/// Construct a new platform-specific C compiler invocation.
2426
///
@@ -43,22 +45,6 @@ impl Cc {
4345
self
4446
}
4547

46-
/// Add a *platform-and-compiler-specific* argument. Please consult the docs for the various
47-
/// possible C compilers on the various platforms to check which arguments are legal for
48-
/// which compiler.
49-
pub fn arg(&mut self, flag: &str) -> &mut Self {
50-
self.cmd.arg(flag);
51-
self
52-
}
53-
54-
/// Add multiple *platform-and-compiler-specific* arguments. Please consult the docs for the
55-
/// various possible C compilers on the various platforms to check which arguments are legal
56-
/// for which compiler.
57-
pub fn args(&mut self, args: &[&str]) -> &mut Self {
58-
self.cmd.args(args);
59-
self
60-
}
61-
6248
/// Specify `-o` or `-Fe`/`-Fo` depending on platform/compiler. This assumes that the executable
6349
/// is under `$TMPDIR`.
6450
pub fn out_exe(&mut self, name: &str) -> &mut Self {
@@ -85,25 +71,6 @@ impl Cc {
8571

8672
self
8773
}
88-
89-
/// Run the constructed C invocation command and assert that it is successfully run.
90-
#[track_caller]
91-
pub fn run(&mut self) -> Output {
92-
let caller_location = std::panic::Location::caller();
93-
let caller_line_number = caller_location.line();
94-
95-
let output = self.cmd.output().unwrap();
96-
if !output.status.success() {
97-
handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number);
98-
}
99-
output
100-
}
101-
102-
/// Inspect what the underlying [`Command`] is up to the current construction.
103-
pub fn inspect(&mut self, f: impl FnOnce(&Command)) -> &mut Self {
104-
f(&self.cmd);
105-
self
106-
}
10774
}
10875

10976
/// `EXTRACFLAGS`

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

+134-5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
//! `run-make-support` is a support library for run-make tests. It provides command wrappers and
2+
//! convenience utility functions to help test writers reduce duplication. The support library
3+
//! notably is built via cargo: this means that if your test wants some non-trivial utility, such
4+
//! as `object` or `wasmparser`, they can be re-exported and be made available through this library.
5+
16
pub mod cc;
27
pub mod run;
38
pub mod rustc;
@@ -82,7 +87,7 @@ pub fn cygpath_windows<P: AsRef<Path>>(path: P) -> String {
8287
cygpath.arg(path.as_ref());
8388
let output = cygpath.output().unwrap();
8489
if !output.status.success() {
85-
handle_failed_output(&format!("{:#?}", cygpath), output, caller_line_number);
90+
handle_failed_output(&cygpath, output, caller_line_number);
8691
}
8792
let s = String::from_utf8(output.stdout).unwrap();
8893
// cygpath -w can attach a newline
@@ -98,18 +103,18 @@ pub fn uname() -> String {
98103
let mut uname = Command::new("uname");
99104
let output = uname.output().unwrap();
100105
if !output.status.success() {
101-
handle_failed_output(&format!("{:#?}", uname), output, caller_line_number);
106+
handle_failed_output(&uname, output, caller_line_number);
102107
}
103108
String::from_utf8(output.stdout).unwrap()
104109
}
105110

106-
fn handle_failed_output(cmd: &str, output: Output, caller_line_number: u32) -> ! {
111+
fn handle_failed_output(cmd: &Command, output: Output, caller_line_number: u32) -> ! {
107112
if output.status.success() {
108-
eprintln!("command incorrectly succeeded at line {caller_line_number}");
113+
eprintln!("command unexpectedly succeeded at line {caller_line_number}");
109114
} else {
110115
eprintln!("command failed at line {caller_line_number}");
111116
}
112-
eprintln!("{cmd}");
117+
eprintln!("{cmd:?}");
113118
eprintln!("output status: `{}`", output.status);
114119
eprintln!("=== STDOUT ===\n{}\n\n", String::from_utf8(output.stdout).unwrap());
115120
eprintln!("=== STDERR ===\n{}\n\n", String::from_utf8(output.stderr).unwrap());
@@ -129,3 +134,127 @@ pub fn set_host_rpath(cmd: &mut Command) {
129134
env::join_paths(paths.iter()).unwrap()
130135
});
131136
}
137+
138+
/// Implement common helpers for command wrappers. This assumes that the command wrapper is a struct
139+
/// containing a `cmd: Command` field. The provided helpers are:
140+
///
141+
/// 1. Generic argument acceptors: `arg` and `args` (delegated to [`Command`]). These are intended
142+
/// to be *fallback* argument acceptors, when specific helpers don't make sense. Prefer to add
143+
/// new specific helper methods over relying on these generic argument providers.
144+
/// 2. Environment manipulation methods: `env`, `env_remove` and `env_clear`: these delegate to
145+
/// methods of the same name on [`Command`].
146+
/// 3. Output and execution: `output`, `run` and `run_fail` are provided. `output` waits for the
147+
/// command to finish running and returns the process's [`Output`]. `run` and `run_fail` are
148+
/// higher-level convenience methods which waits for the command to finish running and assert
149+
/// that the command successfully ran or failed as expected. Prefer `run` and `run_fail` when
150+
/// possible.
151+
///
152+
/// Example usage:
153+
///
154+
/// ```ignore (illustrative)
155+
/// struct CommandWrapper { cmd: Command }
156+
///
157+
/// crate::impl_common_helpers!(CommandWrapper);
158+
///
159+
/// impl CommandWrapper {
160+
/// // ... additional specific helper methods
161+
/// }
162+
/// ```
163+
///
164+
/// [`Command`]: ::std::process::Command
165+
/// [`Output`]: ::std::process::Output
166+
macro_rules! impl_common_helpers {
167+
($wrapper: ident) => {
168+
impl $wrapper {
169+
/// Specify an environment variable.
170+
pub fn env<K, V>(&mut self, key: K, value: V) -> &mut Self
171+
where
172+
K: AsRef<::std::ffi::OsStr>,
173+
V: AsRef<::std::ffi::OsStr>,
174+
{
175+
self.cmd.env(key, value);
176+
self
177+
}
178+
179+
/// Remove an environmental variable.
180+
pub fn env_remove<K>(&mut self, key: K) -> &mut Self
181+
where
182+
K: AsRef<::std::ffi::OsStr>,
183+
{
184+
self.cmd.env_remove(key);
185+
self
186+
}
187+
188+
/// Clear all environmental variables.
189+
pub fn env_var(&mut self) -> &mut Self {
190+
self.cmd.env_clear();
191+
self
192+
}
193+
194+
/// Generic command argument provider. Prefer specific helper methods if possible.
195+
/// Note that for some executables, arguments might be platform specific. For C/C++
196+
/// compilers, arguments might be platform *and* compiler specific.
197+
pub fn arg<S>(&mut self, arg: S) -> &mut Self
198+
where
199+
S: AsRef<::std::ffi::OsStr>,
200+
{
201+
self.cmd.arg(arg);
202+
self
203+
}
204+
205+
/// Generic command arguments provider. Prefer specific helper methods if possible.
206+
/// Note that for some executables, arguments might be platform specific. For C/C++
207+
/// compilers, arguments might be platform *and* compiler specific.
208+
pub fn args<S>(&mut self, args: &[S]) -> &mut Self
209+
where
210+
S: AsRef<::std::ffi::OsStr>,
211+
{
212+
self.cmd.args(args);
213+
self
214+
}
215+
216+
/// Inspect what the underlying [`Command`][::std::process::Command] is up to the
217+
/// current construction.
218+
pub fn inspect<I>(&mut self, inspector: I) -> &mut Self
219+
where
220+
I: FnOnce(&::std::process::Command),
221+
{
222+
inspector(&self.cmd);
223+
self
224+
}
225+
226+
/// Get the [`Output`][::std::process::Output] of the finished process.
227+
pub fn output(&mut self) -> ::std::process::Output {
228+
self.cmd.output().expect("failed to get output of finished process")
229+
}
230+
231+
/// Run the constructed command and assert that it is successfully run.
232+
#[track_caller]
233+
pub fn run(&mut self) -> ::std::process::Output {
234+
let caller_location = ::std::panic::Location::caller();
235+
let caller_line_number = caller_location.line();
236+
237+
let output = self.cmd.output().unwrap();
238+
if !output.status.success() {
239+
handle_failed_output(&self.cmd, output, caller_line_number);
240+
}
241+
output
242+
}
243+
244+
/// Run the constructed command and assert that it does not successfully run.
245+
#[track_caller]
246+
pub fn run_fail(&mut self) -> ::std::process::Output {
247+
let caller_location = ::std::panic::Location::caller();
248+
let caller_line_number = caller_location.line();
249+
250+
let output = self.cmd.output().unwrap();
251+
if output.status.success() {
252+
handle_failed_output(&self.cmd, output, caller_line_number);
253+
}
254+
output
255+
}
256+
}
257+
};
258+
}
259+
260+
pub(crate) use impl_common_helpers;

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ pub fn run(name: &str) -> Output {
4545

4646
let (cmd, output) = run_common(name);
4747
if !output.status.success() {
48-
handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number);
48+
handle_failed_output(&cmd, output, caller_line_number);
4949
}
5050
output
5151
}
@@ -58,7 +58,7 @@ pub fn run_fail(name: &str) -> Output {
5858

5959
let (cmd, output) = run_common(name);
6060
if output.status.success() {
61-
handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number);
61+
handle_failed_output(&cmd, output, caller_line_number);
6262
}
6363
output
6464
}

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

+4-57
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::env;
2-
use std::ffi::{OsStr, OsString};
2+
use std::ffi::OsString;
33
use std::path::Path;
44
use std::process::{Command, Output};
55

@@ -21,6 +21,8 @@ pub struct Rustc {
2121
cmd: Command,
2222
}
2323

24+
crate::impl_common_helpers!(Rustc);
25+
2426
fn setup_common() -> Command {
2527
let rustc = env::var("RUSTC").unwrap();
2628
let mut cmd = Command::new(rustc);
@@ -133,12 +135,6 @@ impl Rustc {
133135
self
134136
}
135137

136-
/// Generic command argument provider. Use `.arg("-Zname")` over `.arg("-Z").arg("arg")`.
137-
pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Self {
138-
self.cmd.arg(arg);
139-
self
140-
}
141-
142138
/// Specify the crate type.
143139
pub fn crate_type(&mut self, crate_type: &str) -> &mut Self {
144140
self.cmd.arg("--crate-type");
@@ -153,64 +149,15 @@ impl Rustc {
153149
self
154150
}
155151

156-
/// Generic command arguments provider. Use `.arg("-Zname")` over `.arg("-Z").arg("arg")`.
157-
pub fn args<S: AsRef<OsStr>>(&mut self, args: &[S]) -> &mut Self {
158-
self.cmd.args(args);
159-
self
160-
}
161-
162-
pub fn env(&mut self, name: impl AsRef<OsStr>, value: impl AsRef<OsStr>) -> &mut Self {
163-
self.cmd.env(name, value);
164-
self
165-
}
166-
167-
// Command inspection, output and running helper methods
168-
169-
/// Get the [`Output`][std::process::Output] of the finished `rustc` process.
170-
pub fn output(&mut self) -> Output {
171-
self.cmd.output().unwrap()
172-
}
173-
174-
/// Run the constructed `rustc` command and assert that it is successfully run.
175-
#[track_caller]
176-
pub fn run(&mut self) -> Output {
177-
let caller_location = std::panic::Location::caller();
178-
let caller_line_number = caller_location.line();
179-
180-
let output = self.cmd.output().unwrap();
181-
if !output.status.success() {
182-
handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number);
183-
}
184-
output
185-
}
186-
187-
#[track_caller]
188-
pub fn run_fail(&mut self) -> Output {
189-
let caller_location = std::panic::Location::caller();
190-
let caller_line_number = caller_location.line();
191-
192-
let output = self.cmd.output().unwrap();
193-
if output.status.success() {
194-
handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number);
195-
}
196-
output
197-
}
198-
199152
#[track_caller]
200153
pub fn run_fail_assert_exit_code(&mut self, code: i32) -> Output {
201154
let caller_location = std::panic::Location::caller();
202155
let caller_line_number = caller_location.line();
203156

204157
let output = self.cmd.output().unwrap();
205158
if output.status.code().unwrap() != code {
206-
handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number);
159+
handle_failed_output(&self.cmd, output, caller_line_number);
207160
}
208161
output
209162
}
210-
211-
/// Inspect what the underlying [`Command`] is up to the current construction.
212-
pub fn inspect(&mut self, f: impl FnOnce(&Command)) -> &mut Self {
213-
f(&self.cmd);
214-
self
215-
}
216163
}

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

+3-21
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use std::env;
2-
use std::ffi::OsStr;
32
use std::path::Path;
43
use std::process::{Command, Output};
54

@@ -20,6 +19,8 @@ pub struct Rustdoc {
2019
cmd: Command,
2120
}
2221

22+
crate::impl_common_helpers!(Rustdoc);
23+
2324
fn setup_common() -> Command {
2425
let rustdoc = env::var("RUSTDOC").unwrap();
2526
let mut cmd = Command::new(rustdoc);
@@ -61,33 +62,14 @@ impl Rustdoc {
6162
self
6263
}
6364

64-
/// Generic command argument provider. Use `.arg("-Zname")` over `.arg("-Z").arg("arg")`.
65-
pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Self {
66-
self.cmd.arg(arg);
67-
self
68-
}
69-
70-
/// Run the build `rustdoc` command and assert that the run is successful.
71-
#[track_caller]
72-
pub fn run(&mut self) -> Output {
73-
let caller_location = std::panic::Location::caller();
74-
let caller_line_number = caller_location.line();
75-
76-
let output = self.cmd.output().unwrap();
77-
if !output.status.success() {
78-
handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number);
79-
}
80-
output
81-
}
82-
8365
#[track_caller]
8466
pub fn run_fail_assert_exit_code(&mut self, code: i32) -> Output {
8567
let caller_location = std::panic::Location::caller();
8668
let caller_line_number = caller_location.line();
8769

8870
let output = self.cmd.output().unwrap();
8971
if output.status.code().unwrap() != code {
90-
handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number);
72+
handle_failed_output(&self.cmd, output, caller_line_number);
9173
}
9274
output
9375
}

0 commit comments

Comments
 (0)