Auto merge of #125752 - jieyouxu:kaboom, r=Kobzol
run-make: arm command wrappers with drop bombs This PR is one in a series of cleanups to run-make tests and the run-make-support library. ### Summary It's easy to forget to actually executed constructed command wrappers, e.g. `rustc().input("foo.rs")` but forget the `run()`, so to help catch these mistakes, we arm command wrappers with drop bombs on construction to force them to be executed by test code. This PR also removes the `Deref`/`DerefMut` impl for our custom `Command` which derefs to `std::process::Command` because it can cause issues when trying to use a custom command: ```rs htmldocck().arg().run() ``` fails to compile because the `arg()` is resolved to `std::process::Command::arg`, which returns `&mut std::process::Command` that doesn't have a `run()` command. This PR also: - Removes `env_var` on the `impl_common_helper` macro that was wrongly named and is a footgun (no users). - Bumps the run-make-support library to version `0.1.0`. - Adds a changelog to the support library. ### Details Especially for command wrappers like `Rustc`, it's very easy to build up a command invocation but forget to actually execute it, e.g. by using `run()`. This commit adds "drop bombs" to command wrappers, which are armed on command wrapper construction, and only defused if the command is executed (through `run`, `run_fail`). If the test writer forgets to execute the command, the drop bomb will "explode" and panic with an error message. This is so that tests don't silently pass with constructed-but-not-executed command wrappers. This PR is best reviewed commit-by-commit. try-job: x86_64-msvc
This commit is contained in:
commit
20ba13c38e
@ -3452,7 +3452,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "run_make_support"
|
||||
version = "0.0.0"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"gimli 0.28.1",
|
||||
"object 0.34.0",
|
||||
|
67
src/tools/run-make-support/CHANGELOG.md
Normal file
67
src/tools/run-make-support/CHANGELOG.md
Normal file
@ -0,0 +1,67 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to the `run_make_support` library should be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the support
|
||||
library should adhere to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) even if it's
|
||||
not intended for public consumption (it's moreso to help internally, to help test writers track
|
||||
changes to the support library).
|
||||
|
||||
This support library will probably never reach 1.0. Please bump the minor version in `Cargo.toml` if
|
||||
you make any breaking changes or other significant changes, or bump the patch version for bug fixes.
|
||||
|
||||
## [0.1.0] - 2024-06-09
|
||||
|
||||
### Changed
|
||||
|
||||
- Use *drop bombs* to enforce that commands are executed; a command invocation will panic if it is
|
||||
constructed but never executed. Execution methods `Command::{run, run_fail}` will defuse the drop
|
||||
bomb.
|
||||
- Added `Command` helpers that forward to `std::process::Command` counterparts.
|
||||
|
||||
### Removed
|
||||
|
||||
- The `env_var` method which was incorrectly named and is `env_clear` underneath and is a footgun
|
||||
from `impl_common_helpers`. For example, removing `TMPDIR` on Unix and `TMP`/`TEMP` breaks
|
||||
`std::env::temp_dir` and wrecks anything using that, such as rustc's codgen.
|
||||
- Removed `Deref`/`DerefMut` for `run_make_support::Command` -> `std::process::Command` because it
|
||||
causes a method chain like `htmldocck().arg().run()` to fail, because `arg()` resolves to
|
||||
`std::process::Command` which also returns a `&mut std::process::Command`, causing the `run()` to
|
||||
be not found.
|
||||
|
||||
## [0.0.0] - 2024-06-09
|
||||
|
||||
Consider this version to contain all changes made to the support library before we started to track
|
||||
changes in this changelog.
|
||||
|
||||
### Added
|
||||
|
||||
- Custom command wrappers around `std::process::Command` (`run_make_support::Command`) and custom
|
||||
wrapper around `std::process::Output` (`CompletedProcess`) to make it more convenient to work with
|
||||
commands and their output, and help avoid forgetting to check for exit status.
|
||||
- `Command`: `set_stdin`, `run`, `run_fail`.
|
||||
- `CompletedProcess`: `std{err,out}_utf8`, `status`, `assert_std{err,out}_{equals, contains,
|
||||
not_contains}`, `assert_exit_code`.
|
||||
- `impl_common_helpers` macro to avoid repeating adding common convenience methods, including:
|
||||
- Environment manipulation methods: `env`, `env_remove`
|
||||
- Command argument providers: `arg`, `args`
|
||||
- Common invocation inspection (of the command invocation up until `inspect` is called):
|
||||
`inspect`
|
||||
- Execution methods: `run` (for commands expected to succeed execution, exit status `0`) and
|
||||
`run_fail` (for commands expected to fail execution, exit status non-zero).
|
||||
- Command wrappers around: `rustc`, `clang`, `cc`, `rustc`, `rustdoc`, `llvm-readobj`.
|
||||
- Thin helpers to construct `python` and `htmldocck` commands.
|
||||
- `run` and `run_fail` (like `Command::{run, run_fail}`) for running binaries, which sets suitable
|
||||
env vars (like `LD_LIB_PATH` or equivalent, `TARGET_RPATH_ENV`, `PATH` on Windows).
|
||||
- Pseudo command `diff` which has similar functionality as the cli util but not the same API.
|
||||
- Convenience panic-on-fail helpers `env_var`, `env_var_os`, `cwd` for their `std::env` conterparts.
|
||||
- Convenience panic-on-fail helpers for reading respective env vars: `target`, `source_root`.
|
||||
- Platform check helpers: `is_windows`, `is_msvc`, `cygpath_windows`, `uname`.
|
||||
- fs helpers: `copy_dir_all`.
|
||||
- `recursive_diff` helper.
|
||||
- Generic `assert_not_contains` helper.
|
||||
- Scoped run-with-teardown helper `run_in_tmpdir` which is designed to run commands in a temporary
|
||||
directory that is cleared when closure returns.
|
||||
- Helpers for constructing the name of binaries and libraries: `rust_lib_name`, `static_lib_name`,
|
||||
`bin_name`, `dynamic_lib_name`.
|
||||
- Re-export libraries: `gimli`, `object`, `regex`, `wasmparsmer`.
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "run_make_support"
|
||||
version = "0.0.0"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
@ -7,6 +7,7 @@
|
||||
///
|
||||
/// WARNING: This means that what flags are accepted by the underlying C compiler is
|
||||
/// platform- AND compiler-specific. Consult the relevant docs for `gcc`, `clang` and `mvsc`.
|
||||
#[track_caller]
|
||||
pub fn cc() -> Cc {
|
||||
Cc::new()
|
||||
}
|
||||
@ -25,6 +26,7 @@ impl Cc {
|
||||
///
|
||||
/// WARNING: This means that what flags are accepted by the underlying C compile is
|
||||
/// platform- AND compiler-specific. Consult the relevant docs for `gcc`, `clang` and `mvsc`.
|
||||
#[track_caller]
|
||||
pub fn new() -> Self {
|
||||
let compiler = env_var("CC");
|
||||
|
||||
@ -84,11 +86,6 @@ pub fn output<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
|
||||
self.cmd.arg(path.as_ref());
|
||||
self
|
||||
}
|
||||
|
||||
/// Get the [`Output`][::std::process::Output] of the finished process.
|
||||
pub fn command_output(&mut self) -> ::std::process::Output {
|
||||
self.cmd.output().expect("failed to get output of finished process")
|
||||
}
|
||||
}
|
||||
|
||||
/// `EXTRACFLAGS`
|
||||
|
@ -4,6 +4,7 @@
|
||||
use crate::{bin_name, env_var};
|
||||
|
||||
/// Construct a new `clang` invocation. `clang` is not always available for all targets.
|
||||
#[track_caller]
|
||||
pub fn clang() -> Clang {
|
||||
Clang::new()
|
||||
}
|
||||
@ -18,6 +19,7 @@ pub struct Clang {
|
||||
|
||||
impl Clang {
|
||||
/// Construct a new `clang` invocation. `clang` is not always available for all targets.
|
||||
#[track_caller]
|
||||
pub fn new() -> Self {
|
||||
let clang = env_var("CLANG");
|
||||
let cmd = Command::new(clang);
|
||||
|
@ -1,36 +1,107 @@
|
||||
use crate::{assert_not_contains, handle_failed_output};
|
||||
use std::ffi;
|
||||
use std::ffi::OsStr;
|
||||
use std::io::Write;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::panic;
|
||||
use std::path::Path;
|
||||
use std::process::{Command as StdCommand, ExitStatus, Output, Stdio};
|
||||
|
||||
/// This is a custom command wrapper that simplifies working with commands
|
||||
/// and makes it easier to ensure that we check the exit status of executed
|
||||
/// processes.
|
||||
use crate::drop_bomb::DropBomb;
|
||||
use crate::{assert_not_contains, handle_failed_output};
|
||||
|
||||
/// This is a custom command wrapper that simplifies working with commands and makes it easier to
|
||||
/// ensure that we check the exit status of executed processes.
|
||||
///
|
||||
/// # A [`Command`] must be executed
|
||||
///
|
||||
/// A [`Command`] is armed by a [`DropBomb`] on construction to enforce that it will be executed. If
|
||||
/// a [`Command`] is constructed but never executed, the drop bomb will explode and cause the test
|
||||
/// to panic. Execution methods [`run`] and [`run_fail`] will defuse the drop bomb. A test
|
||||
/// containing constructed but never executed commands is dangerous because it can give a false
|
||||
/// sense of confidence.
|
||||
///
|
||||
/// [`run`]: Self::run
|
||||
/// [`run_fail`]: Self::run_fail
|
||||
#[derive(Debug)]
|
||||
pub struct Command {
|
||||
cmd: StdCommand,
|
||||
stdin: Option<Box<[u8]>>,
|
||||
drop_bomb: DropBomb,
|
||||
}
|
||||
|
||||
impl Command {
|
||||
pub fn new<S: AsRef<OsStr>>(program: S) -> Self {
|
||||
Self { cmd: StdCommand::new(program), stdin: None }
|
||||
#[track_caller]
|
||||
pub fn new<P: AsRef<OsStr>>(program: P) -> Self {
|
||||
let program = program.as_ref();
|
||||
Self { cmd: StdCommand::new(program), stdin: None, drop_bomb: DropBomb::arm(program) }
|
||||
}
|
||||
|
||||
pub fn set_stdin(&mut self, stdin: Box<[u8]>) {
|
||||
self.stdin = Some(stdin);
|
||||
}
|
||||
|
||||
/// Specify an environment variable.
|
||||
pub fn env<K, V>(&mut self, key: K, value: V) -> &mut Self
|
||||
where
|
||||
K: AsRef<ffi::OsStr>,
|
||||
V: AsRef<ffi::OsStr>,
|
||||
{
|
||||
self.cmd.env(key, value);
|
||||
self
|
||||
}
|
||||
|
||||
/// Remove an environmental variable.
|
||||
pub fn env_remove<K>(&mut self, key: K) -> &mut Self
|
||||
where
|
||||
K: AsRef<ffi::OsStr>,
|
||||
{
|
||||
self.cmd.env_remove(key);
|
||||
self
|
||||
}
|
||||
|
||||
/// Generic command argument provider. Prefer specific helper methods if possible.
|
||||
/// Note that for some executables, arguments might be platform specific. For C/C++
|
||||
/// compilers, arguments might be platform *and* compiler specific.
|
||||
pub fn arg<S>(&mut self, arg: S) -> &mut Self
|
||||
where
|
||||
S: AsRef<ffi::OsStr>,
|
||||
{
|
||||
self.cmd.arg(arg);
|
||||
self
|
||||
}
|
||||
|
||||
/// Generic command arguments provider. Prefer specific helper methods if possible.
|
||||
/// Note that for some executables, arguments might be platform specific. For C/C++
|
||||
/// compilers, arguments might be platform *and* compiler specific.
|
||||
pub fn args<S>(&mut self, args: &[S]) -> &mut Self
|
||||
where
|
||||
S: AsRef<ffi::OsStr>,
|
||||
{
|
||||
self.cmd.args(args);
|
||||
self
|
||||
}
|
||||
|
||||
/// Inspect what the underlying [`std::process::Command`] is up to the
|
||||
/// current construction.
|
||||
pub fn inspect<I>(&mut self, inspector: I) -> &mut Self
|
||||
where
|
||||
I: FnOnce(&StdCommand),
|
||||
{
|
||||
inspector(&self.cmd);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the path where the command will be run.
|
||||
pub fn current_dir<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
|
||||
self.cmd.current_dir(path);
|
||||
self
|
||||
}
|
||||
|
||||
/// Run the constructed command and assert that it is successfully run.
|
||||
#[track_caller]
|
||||
pub fn run(&mut self) -> CompletedProcess {
|
||||
let caller_location = std::panic::Location::caller();
|
||||
let caller_line_number = caller_location.line();
|
||||
|
||||
let output = self.command_output();
|
||||
if !output.status().success() {
|
||||
handle_failed_output(&self, output, caller_line_number);
|
||||
handle_failed_output(&self, output, panic::Location::caller().line());
|
||||
}
|
||||
output
|
||||
}
|
||||
@ -38,18 +109,16 @@ pub fn run(&mut self) -> CompletedProcess {
|
||||
/// Run the constructed command and assert that it does not successfully run.
|
||||
#[track_caller]
|
||||
pub fn run_fail(&mut self) -> CompletedProcess {
|
||||
let caller_location = std::panic::Location::caller();
|
||||
let caller_line_number = caller_location.line();
|
||||
|
||||
let output = self.command_output();
|
||||
if output.status().success() {
|
||||
handle_failed_output(&self, output, caller_line_number);
|
||||
handle_failed_output(&self, output, panic::Location::caller().line());
|
||||
}
|
||||
output
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub(crate) fn command_output(&mut self) -> CompletedProcess {
|
||||
fn command_output(&mut self) -> CompletedProcess {
|
||||
self.drop_bomb.defuse();
|
||||
// let's make sure we piped all the input and outputs
|
||||
self.cmd.stdin(Stdio::piped());
|
||||
self.cmd.stdout(Stdio::piped());
|
||||
@ -71,20 +140,6 @@ pub(crate) fn command_output(&mut self) -> CompletedProcess {
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Command {
|
||||
type Target = StdCommand;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.cmd
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Command {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.cmd
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the result of an executed process.
|
||||
/// The various `assert_` helper methods should preferably be used for
|
||||
/// checking the contents of stdout/stderr.
|
||||
|
@ -2,9 +2,12 @@
|
||||
use similar::TextDiff;
|
||||
use std::path::Path;
|
||||
|
||||
use crate::drop_bomb::DropBomb;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
#[track_caller]
|
||||
pub fn diff() -> Diff {
|
||||
Diff::new()
|
||||
}
|
||||
@ -16,10 +19,12 @@ pub struct Diff {
|
||||
actual: Option<String>,
|
||||
actual_name: Option<String>,
|
||||
normalizers: Vec<(String, String)>,
|
||||
drop_bomb: DropBomb,
|
||||
}
|
||||
|
||||
impl Diff {
|
||||
/// Construct a bare `diff` invocation.
|
||||
#[track_caller]
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
expected: None,
|
||||
@ -27,6 +32,7 @@ pub fn new() -> Self {
|
||||
actual: None,
|
||||
actual_name: None,
|
||||
normalizers: Vec::new(),
|
||||
drop_bomb: DropBomb::arm("diff"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,9 +85,9 @@ pub fn normalize<R: Into<String>, I: Into<String>>(
|
||||
self
|
||||
}
|
||||
|
||||
/// Executes the diff process, prints any differences to the standard error.
|
||||
#[track_caller]
|
||||
pub fn run(&self) {
|
||||
pub fn run(&mut self) {
|
||||
self.drop_bomb.defuse();
|
||||
let expected = self.expected.as_ref().expect("expected text not set");
|
||||
let mut actual = self.actual.as_ref().expect("actual text not set").to_string();
|
||||
let expected_name = self.expected_name.as_ref().unwrap();
|
||||
|
50
src/tools/run-make-support/src/drop_bomb/mod.rs
Normal file
50
src/tools/run-make-support/src/drop_bomb/mod.rs
Normal file
@ -0,0 +1,50 @@
|
||||
//! This module implements "drop bombs" intended for use by command wrappers to ensure that the
|
||||
//! constructed commands are *eventually* executed. This is exactly like `rustc_errors::Diag` where
|
||||
//! we force every `Diag` to be consumed or we emit a bug, but we panic instead.
|
||||
//!
|
||||
//! This is adapted from <https://docs.rs/drop_bomb/latest/drop_bomb/> and simplified for our
|
||||
//! purposes.
|
||||
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::panic;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct DropBomb {
|
||||
command: OsString,
|
||||
defused: bool,
|
||||
armed_line: u32,
|
||||
}
|
||||
|
||||
impl DropBomb {
|
||||
/// Arm a [`DropBomb`]. If the value is dropped without being [`defused`][Self::defused], then
|
||||
/// it will panic. It is expected that the command wrapper uses `#[track_caller]` to help
|
||||
/// propagate the caller info from rmake.rs.
|
||||
#[track_caller]
|
||||
pub(crate) fn arm<S: AsRef<OsStr>>(command: S) -> DropBomb {
|
||||
DropBomb {
|
||||
command: command.as_ref().into(),
|
||||
defused: false,
|
||||
armed_line: panic::Location::caller().line(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Defuse the [`DropBomb`]. This will prevent the drop bomb from panicking when dropped.
|
||||
pub(crate) fn defuse(&mut self) {
|
||||
self.defused = true;
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DropBomb {
|
||||
fn drop(&mut self) {
|
||||
if !self.defused && !std::thread::panicking() {
|
||||
panic!(
|
||||
"command constructed but not executed at line {}: `{}`",
|
||||
self.armed_line,
|
||||
self.command.to_string_lossy()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
15
src/tools/run-make-support/src/drop_bomb/tests.rs
Normal file
15
src/tools/run-make-support/src/drop_bomb/tests.rs
Normal file
@ -0,0 +1,15 @@
|
||||
use super::DropBomb;
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_arm() {
|
||||
let bomb = DropBomb::arm("hi :3");
|
||||
drop(bomb); // <- armed bomb should explode when not defused
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_defuse() {
|
||||
let mut bomb = DropBomb::arm("hi :3");
|
||||
bomb.defuse();
|
||||
drop(bomb); // <- defused bomb should not explode
|
||||
}
|
@ -7,6 +7,7 @@
|
||||
pub mod clang;
|
||||
mod command;
|
||||
pub mod diff;
|
||||
mod drop_bomb;
|
||||
pub mod llvm_readobj;
|
||||
pub mod run;
|
||||
pub mod rustc;
|
||||
@ -16,6 +17,7 @@
|
||||
use std::ffi::OsString;
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::panic;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub use gimli;
|
||||
@ -31,6 +33,7 @@
|
||||
pub use rustc::{aux_build, rustc, Rustc};
|
||||
pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc};
|
||||
|
||||
#[track_caller]
|
||||
pub fn env_var(name: &str) -> String {
|
||||
match env::var(name) {
|
||||
Ok(v) => v,
|
||||
@ -38,6 +41,7 @@ pub fn env_var(name: &str) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn env_var_os(name: &str) -> OsString {
|
||||
match env::var_os(name) {
|
||||
Some(v) => v,
|
||||
@ -65,11 +69,13 @@ pub fn is_darwin() -> bool {
|
||||
target().contains("darwin")
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn python_command() -> Command {
|
||||
let python_path = env_var("PYTHON");
|
||||
Command::new(python_path)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn htmldocck() -> Command {
|
||||
let mut python = python_command();
|
||||
python.arg(source_root().join("src/etc/htmldocck.py"));
|
||||
@ -161,15 +167,13 @@ pub fn cwd() -> PathBuf {
|
||||
/// available on the platform!
|
||||
#[track_caller]
|
||||
pub fn cygpath_windows<P: AsRef<Path>>(path: P) -> String {
|
||||
let caller_location = std::panic::Location::caller();
|
||||
let caller_line_number = caller_location.line();
|
||||
|
||||
let caller = panic::Location::caller();
|
||||
let mut cygpath = Command::new("cygpath");
|
||||
cygpath.arg("-w");
|
||||
cygpath.arg(path.as_ref());
|
||||
let output = cygpath.command_output();
|
||||
let output = cygpath.run();
|
||||
if !output.status().success() {
|
||||
handle_failed_output(&cygpath, output, caller_line_number);
|
||||
handle_failed_output(&cygpath, output, caller.line());
|
||||
}
|
||||
// cygpath -w can attach a newline
|
||||
output.stdout_utf8().trim().to_string()
|
||||
@ -178,13 +182,11 @@ pub fn cygpath_windows<P: AsRef<Path>>(path: P) -> String {
|
||||
/// Run `uname`. This assumes that `uname` is available on the platform!
|
||||
#[track_caller]
|
||||
pub fn uname() -> String {
|
||||
let caller_location = std::panic::Location::caller();
|
||||
let caller_line_number = caller_location.line();
|
||||
|
||||
let caller = panic::Location::caller();
|
||||
let mut uname = Command::new("uname");
|
||||
let output = uname.command_output();
|
||||
let output = uname.run();
|
||||
if !output.status().success() {
|
||||
handle_failed_output(&uname, output, caller_line_number);
|
||||
handle_failed_output(&uname, output, caller.line());
|
||||
}
|
||||
output.stdout_utf8()
|
||||
}
|
||||
@ -364,12 +366,6 @@ pub fn env_remove<K>(&mut self, key: K) -> &mut Self
|
||||
self
|
||||
}
|
||||
|
||||
/// Clear all environmental variables.
|
||||
pub fn env_var(&mut self) -> &mut Self {
|
||||
self.cmd.env_clear();
|
||||
self
|
||||
}
|
||||
|
||||
/// Generic command argument provider. Prefer specific helper methods if possible.
|
||||
/// Note that for some executables, arguments might be platform specific. For C/C++
|
||||
/// compilers, arguments might be platform *and* compiler specific.
|
||||
@ -398,7 +394,7 @@ pub fn inspect<I>(&mut self, inspector: I) -> &mut Self
|
||||
where
|
||||
I: FnOnce(&::std::process::Command),
|
||||
{
|
||||
inspector(&self.cmd);
|
||||
self.cmd.inspect(inspector);
|
||||
self
|
||||
}
|
||||
|
||||
@ -415,7 +411,7 @@ pub fn run_fail(&mut self) -> crate::command::CompletedProcess {
|
||||
}
|
||||
|
||||
/// Set the path where the command will be run.
|
||||
pub fn current_dir<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
|
||||
pub fn current_dir<P: AsRef<::std::path::Path>>(&mut self, path: P) -> &mut Self {
|
||||
self.cmd.current_dir(path);
|
||||
self
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
/// Construct a new `llvm-readobj` invocation. This assumes that `llvm-readobj` is available
|
||||
/// at `$LLVM_BIN_DIR/llvm-readobj`.
|
||||
#[track_caller]
|
||||
pub fn llvm_readobj() -> LlvmReadobj {
|
||||
LlvmReadobj::new()
|
||||
}
|
||||
@ -20,6 +21,7 @@ pub struct LlvmReadobj {
|
||||
impl LlvmReadobj {
|
||||
/// Construct a new `llvm-readobj` invocation. This assumes that `llvm-readobj` is available
|
||||
/// at `$LLVM_BIN_DIR/llvm-readobj`.
|
||||
#[track_caller]
|
||||
pub fn new() -> Self {
|
||||
let llvm_bin_dir = env_var("LLVM_BIN_DIR");
|
||||
let llvm_bin_dir = PathBuf::from(llvm_bin_dir);
|
||||
|
@ -1,5 +1,6 @@
|
||||
use std::env;
|
||||
use std::ffi::OsStr;
|
||||
use std::panic;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use crate::command::{Command, CompletedProcess};
|
||||
@ -7,7 +8,8 @@
|
||||
|
||||
use super::handle_failed_output;
|
||||
|
||||
fn run_common(name: &str) -> (Command, CompletedProcess) {
|
||||
#[track_caller]
|
||||
fn run_common(name: &str) -> Command {
|
||||
let mut bin_path = PathBuf::new();
|
||||
bin_path.push(cwd());
|
||||
bin_path.push(name);
|
||||
@ -34,19 +36,17 @@ fn run_common(name: &str) -> (Command, CompletedProcess) {
|
||||
cmd.env("PATH", env::join_paths(paths.iter()).unwrap());
|
||||
}
|
||||
|
||||
let output = cmd.command_output();
|
||||
(cmd, output)
|
||||
cmd
|
||||
}
|
||||
|
||||
/// Run a built binary and make sure it succeeds.
|
||||
#[track_caller]
|
||||
pub fn run(name: &str) -> CompletedProcess {
|
||||
let caller_location = std::panic::Location::caller();
|
||||
let caller_line_number = caller_location.line();
|
||||
|
||||
let (cmd, output) = run_common(name);
|
||||
let caller = panic::Location::caller();
|
||||
let mut cmd = run_common(name);
|
||||
let output = cmd.run();
|
||||
if !output.status().success() {
|
||||
handle_failed_output(&cmd, output, caller_line_number);
|
||||
handle_failed_output(&cmd, output, caller.line());
|
||||
}
|
||||
output
|
||||
}
|
||||
@ -54,18 +54,18 @@ pub fn run(name: &str) -> CompletedProcess {
|
||||
/// Run a built binary and make sure it fails.
|
||||
#[track_caller]
|
||||
pub fn run_fail(name: &str) -> CompletedProcess {
|
||||
let caller_location = std::panic::Location::caller();
|
||||
let caller_line_number = caller_location.line();
|
||||
|
||||
let (cmd, output) = run_common(name);
|
||||
let caller = panic::Location::caller();
|
||||
let mut cmd = run_common(name);
|
||||
let output = cmd.run_fail();
|
||||
if output.status().success() {
|
||||
handle_failed_output(&cmd, output, caller_line_number);
|
||||
handle_failed_output(&cmd, output, caller.line());
|
||||
}
|
||||
output
|
||||
}
|
||||
|
||||
/// Create a new custom Command.
|
||||
/// This should be preferred to creating `std::process::Command` directly.
|
||||
/// Create a new custom [`Command`]. This should be preferred to creating [`std::process::Command`]
|
||||
/// directly.
|
||||
#[track_caller]
|
||||
pub fn cmd<S: AsRef<OsStr>>(program: S) -> Command {
|
||||
let mut command = Command::new(program);
|
||||
set_host_rpath(&mut command);
|
||||
|
@ -5,11 +5,13 @@
|
||||
use crate::{command, cwd, env_var, set_host_rpath};
|
||||
|
||||
/// Construct a new `rustc` invocation.
|
||||
#[track_caller]
|
||||
pub fn rustc() -> Rustc {
|
||||
Rustc::new()
|
||||
}
|
||||
|
||||
/// Construct a new `rustc` aux-build invocation.
|
||||
#[track_caller]
|
||||
pub fn aux_build() -> Rustc {
|
||||
Rustc::new_aux_build()
|
||||
}
|
||||
@ -22,6 +24,7 @@ pub struct Rustc {
|
||||
|
||||
crate::impl_common_helpers!(Rustc);
|
||||
|
||||
#[track_caller]
|
||||
fn setup_common() -> Command {
|
||||
let rustc = env_var("RUSTC");
|
||||
let mut cmd = Command::new(rustc);
|
||||
@ -34,12 +37,14 @@ impl Rustc {
|
||||
// `rustc` invocation constructor methods
|
||||
|
||||
/// Construct a new `rustc` invocation.
|
||||
#[track_caller]
|
||||
pub fn new() -> Self {
|
||||
let cmd = setup_common();
|
||||
Self { cmd }
|
||||
}
|
||||
|
||||
/// Construct a new `rustc` invocation with `aux_build` preset (setting `--crate-type=lib`).
|
||||
#[track_caller]
|
||||
pub fn new_aux_build() -> Self {
|
||||
let mut cmd = setup_common();
|
||||
cmd.arg("--crate-type=lib");
|
||||
|
@ -5,11 +5,13 @@
|
||||
use crate::{env_var, env_var_os, set_host_rpath};
|
||||
|
||||
/// Construct a plain `rustdoc` invocation with no flags set.
|
||||
#[track_caller]
|
||||
pub fn bare_rustdoc() -> Rustdoc {
|
||||
Rustdoc::bare()
|
||||
}
|
||||
|
||||
/// Construct a new `rustdoc` invocation with `-L $(TARGET_RPATH_DIR)` set.
|
||||
#[track_caller]
|
||||
pub fn rustdoc() -> Rustdoc {
|
||||
Rustdoc::new()
|
||||
}
|
||||
@ -21,6 +23,7 @@ pub struct Rustdoc {
|
||||
|
||||
crate::impl_common_helpers!(Rustdoc);
|
||||
|
||||
#[track_caller]
|
||||
fn setup_common() -> Command {
|
||||
let rustdoc = env_var("RUSTDOC");
|
||||
let mut cmd = Command::new(rustdoc);
|
||||
@ -30,12 +33,14 @@ fn setup_common() -> Command {
|
||||
|
||||
impl Rustdoc {
|
||||
/// Construct a bare `rustdoc` invocation.
|
||||
#[track_caller]
|
||||
pub fn bare() -> Self {
|
||||
let cmd = setup_common();
|
||||
Self { cmd }
|
||||
}
|
||||
|
||||
/// Construct a `rustdoc` invocation with `-L $(TARGET_RPATH_DIR)` set.
|
||||
#[track_caller]
|
||||
pub fn new() -> Self {
|
||||
let mut cmd = setup_common();
|
||||
let target_rpath_dir = env_var_os("TARGET_RPATH_DIR");
|
||||
|
@ -35,7 +35,7 @@ fn main() {
|
||||
let rustc = env_var("RUSTC");
|
||||
let bootstrap_cargo = env_var("BOOTSTRAP_CARGO");
|
||||
let mut cmd = cmd(bootstrap_cargo);
|
||||
cmd.args([
|
||||
cmd.args(&[
|
||||
"build",
|
||||
"--manifest-path",
|
||||
manifest_path.to_str().unwrap(),
|
||||
|
@ -9,5 +9,5 @@ fn main() {
|
||||
.output(&out_dir)
|
||||
.run();
|
||||
// FIXME (GuillaumeGomez): Port the python script to Rust as well.
|
||||
assert!(python_command().arg("validate_json.py").arg(&out_dir).status().unwrap().success());
|
||||
python_command().arg("validate_json.py").arg(&out_dir).run();
|
||||
}
|
||||
|
@ -56,5 +56,5 @@ fn main() {
|
||||
.arg(&ex_dir)
|
||||
.run();
|
||||
|
||||
assert!(htmldocck().arg(out_dir).arg("src/lib.rs").status().unwrap().success());
|
||||
htmldocck().arg(out_dir).arg("src/lib.rs").run();
|
||||
}
|
||||
|
@ -45,5 +45,5 @@ pub fn scrape(extra_args: &[&str]) {
|
||||
}
|
||||
rustdoc.run();
|
||||
|
||||
assert!(htmldocck().arg(out_dir).arg("src/lib.rs").status().unwrap().success());
|
||||
htmldocck().arg(out_dir).arg("src/lib.rs").run();
|
||||
}
|
||||
|
@ -28,5 +28,5 @@ fn main() {
|
||||
std::fs::write(&test_css, test_content).unwrap();
|
||||
|
||||
rustdoc().output(&out_dir).input("foo.rs").arg("--theme").arg(&test_css).run();
|
||||
assert!(htmldocck().arg(out_dir).arg("foo.rs").status().unwrap().success());
|
||||
htmldocck().arg(out_dir).arg("foo.rs").run();
|
||||
}
|
||||
|
@ -3,5 +3,5 @@
|
||||
fn main() {
|
||||
let out_dir = "rustdoc";
|
||||
rustdoc().input("src/lib.rs").crate_name("foobar").crate_type("lib").output(&out_dir).run();
|
||||
assert!(htmldocck().arg(out_dir).arg("src/lib.rs").status().unwrap().success());
|
||||
htmldocck().arg(out_dir).arg("src/lib.rs").run();
|
||||
}
|
||||
|
@ -12,5 +12,5 @@ fn main() {
|
||||
.arg(&out_dir)
|
||||
.run();
|
||||
|
||||
assert!(htmldocck().arg(out_dir).arg("src/lib.rs").status().unwrap().success());
|
||||
htmldocck().arg(out_dir).arg("src/lib.rs").run();
|
||||
}
|
||||
|
@ -12,5 +12,5 @@ fn main() {
|
||||
.arg(&out_dir)
|
||||
.run();
|
||||
|
||||
assert!(htmldocck().arg(out_dir).arg("src/lib.rs").status().unwrap().success());
|
||||
htmldocck().arg(out_dir).arg("src/lib.rs").run();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user