Rollup merge of #124612 - Urgau:run-make-stdin, r=jieyouxu
Add support for inputing via stdin with run-make-support This PR adds the facility to set a input bytes that will be passed via the standard input. This is useful for testing `rustc -` (and soon `rustdoc -`). In #124611 took the approach of having a dedicated `run` method but it is not very convenient to use and would necessitate many functions, one for success, one for fail, ... Instead this PR takes a different approach and allows setting the input bytes as if it were a parameter and when calling the (now custom) `output` function, we write the input bytes into stdin. I think this gives us maximum flexibility in the implementation and a simple interface for users. To test this new logic I ported `tests/run-make/stdin-non-utf8/` to an `rmake.rs` one. r? `@jieyouxu`
This commit is contained in:
commit
c27d3d5d2a
@ -71,6 +71,11 @@ impl Cc {
|
|||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the [`Output`][::std::process::Output] of the finished process.
|
||||||
|
pub fn output(&mut self) -> ::std::process::Output {
|
||||||
|
self.cmd.output().expect("failed to get output of finished process")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `EXTRACFLAGS`
|
/// `EXTRACFLAGS`
|
||||||
|
@ -70,4 +70,9 @@ impl Clang {
|
|||||||
self.cmd.arg(format!("-fuse-ld={ld}"));
|
self.cmd.arg(format!("-fuse-ld={ld}"));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the [`Output`][::std::process::Output] of the finished process.
|
||||||
|
pub fn output(&mut self) -> ::std::process::Output {
|
||||||
|
self.cmd.output().expect("failed to get output of finished process")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -144,7 +144,7 @@ pub fn set_host_rpath(cmd: &mut Command) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Implement common helpers for command wrappers. This assumes that the command wrapper is a struct
|
/// Implement common helpers for command wrappers. This assumes that the command wrapper is a struct
|
||||||
/// containing a `cmd: Command` field. The provided helpers are:
|
/// containing a `cmd: Command` field and a `output` function. The provided helpers are:
|
||||||
///
|
///
|
||||||
/// 1. Generic argument acceptors: `arg` and `args` (delegated to [`Command`]). These are intended
|
/// 1. Generic argument acceptors: `arg` and `args` (delegated to [`Command`]). These are intended
|
||||||
/// to be *fallback* argument acceptors, when specific helpers don't make sense. Prefer to add
|
/// to be *fallback* argument acceptors, when specific helpers don't make sense. Prefer to add
|
||||||
@ -160,7 +160,12 @@ pub fn set_host_rpath(cmd: &mut Command) {
|
|||||||
/// Example usage:
|
/// Example usage:
|
||||||
///
|
///
|
||||||
/// ```ignore (illustrative)
|
/// ```ignore (illustrative)
|
||||||
/// struct CommandWrapper { cmd: Command }
|
/// struct CommandWrapper { cmd: Command } // <- required `cmd` field
|
||||||
|
///
|
||||||
|
/// impl CommandWrapper {
|
||||||
|
/// /// Get the [`Output`][::std::process::Output] of the finished process.
|
||||||
|
/// pub fn output(&mut self) -> Output { /* ... */ } // <- required `output()` method
|
||||||
|
/// }
|
||||||
///
|
///
|
||||||
/// crate::impl_common_helpers!(CommandWrapper);
|
/// crate::impl_common_helpers!(CommandWrapper);
|
||||||
///
|
///
|
||||||
@ -231,18 +236,13 @@ macro_rules! impl_common_helpers {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the [`Output`][::std::process::Output] of the finished process.
|
|
||||||
pub fn output(&mut self) -> ::std::process::Output {
|
|
||||||
self.cmd.output().expect("failed to get output of finished process")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Run the constructed command and assert that it is successfully run.
|
/// Run the constructed command and assert that it is successfully run.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn run(&mut self) -> ::std::process::Output {
|
pub fn run(&mut self) -> ::std::process::Output {
|
||||||
let caller_location = ::std::panic::Location::caller();
|
let caller_location = ::std::panic::Location::caller();
|
||||||
let caller_line_number = caller_location.line();
|
let caller_line_number = caller_location.line();
|
||||||
|
|
||||||
let output = self.cmd.output().unwrap();
|
let output = self.output();
|
||||||
if !output.status.success() {
|
if !output.status.success() {
|
||||||
handle_failed_output(&self.cmd, output, caller_line_number);
|
handle_failed_output(&self.cmd, output, caller_line_number);
|
||||||
}
|
}
|
||||||
@ -255,7 +255,7 @@ macro_rules! impl_common_helpers {
|
|||||||
let caller_location = ::std::panic::Location::caller();
|
let caller_location = ::std::panic::Location::caller();
|
||||||
let caller_line_number = caller_location.line();
|
let caller_line_number = caller_location.line();
|
||||||
|
|
||||||
let output = self.cmd.output().unwrap();
|
let output = self.output();
|
||||||
if output.status.success() {
|
if output.status.success() {
|
||||||
handle_failed_output(&self.cmd, output, caller_line_number);
|
handle_failed_output(&self.cmd, output, caller_line_number);
|
||||||
}
|
}
|
||||||
|
@ -41,4 +41,10 @@ impl LlvmReadobj {
|
|||||||
self.cmd.arg("--file-header");
|
self.cmd.arg("--file-header");
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the [`Output`][::std::process::Output] of the finished process.
|
||||||
|
#[track_caller]
|
||||||
|
pub fn output(&mut self) -> ::std::process::Output {
|
||||||
|
self.cmd.output().expect("failed to get output of finished process")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
use std::env;
|
use std::env;
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
|
use std::io::Write;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process::{Command, Output};
|
use std::process::{Command, Output, Stdio};
|
||||||
|
|
||||||
use crate::{handle_failed_output, set_host_rpath, tmp_dir};
|
use crate::{handle_failed_output, set_host_rpath, tmp_dir};
|
||||||
|
|
||||||
@ -19,6 +20,7 @@ pub fn aux_build() -> Rustc {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Rustc {
|
pub struct Rustc {
|
||||||
cmd: Command,
|
cmd: Command,
|
||||||
|
stdin: Option<Box<[u8]>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::impl_common_helpers!(Rustc);
|
crate::impl_common_helpers!(Rustc);
|
||||||
@ -37,14 +39,14 @@ impl Rustc {
|
|||||||
/// Construct a new `rustc` invocation.
|
/// Construct a new `rustc` invocation.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let cmd = setup_common();
|
let cmd = setup_common();
|
||||||
Self { cmd }
|
Self { cmd, stdin: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a new `rustc` invocation with `aux_build` preset (setting `--crate-type=lib`).
|
/// Construct a new `rustc` invocation with `aux_build` preset (setting `--crate-type=lib`).
|
||||||
pub fn new_aux_build() -> Self {
|
pub fn new_aux_build() -> Self {
|
||||||
let mut cmd = setup_common();
|
let mut cmd = setup_common();
|
||||||
cmd.arg("--crate-type=lib");
|
cmd.arg("--crate-type=lib");
|
||||||
Self { cmd }
|
Self { cmd, stdin: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Argument provider methods
|
// Argument provider methods
|
||||||
@ -161,12 +163,40 @@ impl Rustc {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Specify a stdin input
|
||||||
|
pub fn stdin<I: AsRef<[u8]>>(&mut self, input: I) -> &mut Self {
|
||||||
|
self.stdin = Some(input.as_ref().to_vec().into_boxed_slice());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the [`Output`][::std::process::Output] of the finished process.
|
||||||
|
#[track_caller]
|
||||||
|
pub fn output(&mut self) -> ::std::process::Output {
|
||||||
|
// let's make sure we piped all the input and outputs
|
||||||
|
self.cmd.stdin(Stdio::piped());
|
||||||
|
self.cmd.stdout(Stdio::piped());
|
||||||
|
self.cmd.stderr(Stdio::piped());
|
||||||
|
|
||||||
|
if let Some(input) = &self.stdin {
|
||||||
|
let mut child = self.cmd.spawn().unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut stdin = child.stdin.take().unwrap();
|
||||||
|
stdin.write_all(input.as_ref()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
child.wait_with_output().expect("failed to get output of finished process")
|
||||||
|
} else {
|
||||||
|
self.cmd.output().expect("failed to get output of finished process")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn run_fail_assert_exit_code(&mut self, code: i32) -> Output {
|
pub fn run_fail_assert_exit_code(&mut self, code: i32) -> Output {
|
||||||
let caller_location = std::panic::Location::caller();
|
let caller_location = std::panic::Location::caller();
|
||||||
let caller_line_number = caller_location.line();
|
let caller_line_number = caller_location.line();
|
||||||
|
|
||||||
let output = self.cmd.output().unwrap();
|
let output = self.output();
|
||||||
if output.status.code().unwrap() != code {
|
if output.status.code().unwrap() != code {
|
||||||
handle_failed_output(&self.cmd, output, caller_line_number);
|
handle_failed_output(&self.cmd, output, caller_line_number);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use std::env;
|
use std::env;
|
||||||
|
use std::io::Write;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process::{Command, Output};
|
use std::process::{Command, Output, Stdio};
|
||||||
|
|
||||||
use crate::{handle_failed_output, set_host_rpath};
|
use crate::{handle_failed_output, set_host_rpath};
|
||||||
|
|
||||||
@ -17,6 +18,7 @@ pub fn rustdoc() -> Rustdoc {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Rustdoc {
|
pub struct Rustdoc {
|
||||||
cmd: Command,
|
cmd: Command,
|
||||||
|
stdin: Option<Box<[u8]>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::impl_common_helpers!(Rustdoc);
|
crate::impl_common_helpers!(Rustdoc);
|
||||||
@ -32,7 +34,7 @@ impl Rustdoc {
|
|||||||
/// Construct a bare `rustdoc` invocation.
|
/// Construct a bare `rustdoc` invocation.
|
||||||
pub fn bare() -> Self {
|
pub fn bare() -> Self {
|
||||||
let cmd = setup_common();
|
let cmd = setup_common();
|
||||||
Self { cmd }
|
Self { cmd, stdin: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a `rustdoc` invocation with `-L $(TARGET_RPATH_DIR)` set.
|
/// Construct a `rustdoc` invocation with `-L $(TARGET_RPATH_DIR)` set.
|
||||||
@ -40,7 +42,7 @@ impl Rustdoc {
|
|||||||
let mut cmd = setup_common();
|
let mut cmd = setup_common();
|
||||||
let target_rpath_dir = env::var_os("TARGET_RPATH_DIR").unwrap();
|
let target_rpath_dir = env::var_os("TARGET_RPATH_DIR").unwrap();
|
||||||
cmd.arg(format!("-L{}", target_rpath_dir.to_string_lossy()));
|
cmd.arg(format!("-L{}", target_rpath_dir.to_string_lossy()));
|
||||||
Self { cmd }
|
Self { cmd, stdin: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specify path to the input file.
|
/// Specify path to the input file.
|
||||||
@ -62,12 +64,41 @@ impl Rustdoc {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Specify a stdin input
|
||||||
|
pub fn stdin<I: AsRef<[u8]>>(&mut self, input: I) -> &mut Self {
|
||||||
|
self.cmd.stdin(Stdio::piped());
|
||||||
|
self.stdin = Some(input.as_ref().to_vec().into_boxed_slice());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the [`Output`][::std::process::Output] of the finished process.
|
||||||
|
#[track_caller]
|
||||||
|
pub fn output(&mut self) -> ::std::process::Output {
|
||||||
|
// let's make sure we piped all the input and outputs
|
||||||
|
self.cmd.stdin(Stdio::piped());
|
||||||
|
self.cmd.stdout(Stdio::piped());
|
||||||
|
self.cmd.stderr(Stdio::piped());
|
||||||
|
|
||||||
|
if let Some(input) = &self.stdin {
|
||||||
|
let mut child = self.cmd.spawn().unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut stdin = child.stdin.take().unwrap();
|
||||||
|
stdin.write_all(input.as_ref()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
child.wait_with_output().expect("failed to get output of finished process")
|
||||||
|
} else {
|
||||||
|
self.cmd.output().expect("failed to get output of finished process")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn run_fail_assert_exit_code(&mut self, code: i32) -> Output {
|
pub fn run_fail_assert_exit_code(&mut self, code: i32) -> Output {
|
||||||
let caller_location = std::panic::Location::caller();
|
let caller_location = std::panic::Location::caller();
|
||||||
let caller_line_number = caller_location.line();
|
let caller_line_number = caller_location.line();
|
||||||
|
|
||||||
let output = self.cmd.output().unwrap();
|
let output = self.output();
|
||||||
if output.status.code().unwrap() != code {
|
if output.status.code().unwrap() != code {
|
||||||
handle_failed_output(&self.cmd, output, caller_line_number);
|
handle_failed_output(&self.cmd, output, caller_line_number);
|
||||||
}
|
}
|
||||||
|
@ -288,7 +288,6 @@ run-make/static-unwinding/Makefile
|
|||||||
run-make/staticlib-blank-lib/Makefile
|
run-make/staticlib-blank-lib/Makefile
|
||||||
run-make/staticlib-dylib-linkage/Makefile
|
run-make/staticlib-dylib-linkage/Makefile
|
||||||
run-make/std-core-cycle/Makefile
|
run-make/std-core-cycle/Makefile
|
||||||
run-make/stdin-non-utf8/Makefile
|
|
||||||
run-make/suspicious-library/Makefile
|
run-make/suspicious-library/Makefile
|
||||||
run-make/symbol-mangling-hashed/Makefile
|
run-make/symbol-mangling-hashed/Makefile
|
||||||
run-make/symbol-visibility/Makefile
|
run-make/symbol-visibility/Makefile
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
include ../tools.mk
|
|
||||||
|
|
||||||
all:
|
|
||||||
cp non-utf8 $(TMPDIR)/non-utf.rs
|
|
||||||
cat $(TMPDIR)/non-utf.rs | $(RUSTC) - 2>&1 \
|
|
||||||
| $(CGREP) "error: couldn't read from stdin, as it did not contain valid UTF-8"
|
|
@ -1 +0,0 @@
|
|||||||
<EFBFBD>
|
|
26
tests/run-make/stdin-rustc/rmake.rs
Normal file
26
tests/run-make/stdin-rustc/rmake.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
//! This test checks rustc `-` (stdin) support
|
||||||
|
|
||||||
|
use run_make_support::{is_windows, rustc, tmp_dir};
|
||||||
|
|
||||||
|
const HELLO_WORLD: &str = r#"
|
||||||
|
fn main() {
|
||||||
|
println!("Hello world!");
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
const NOT_UTF8: &[u8] = &[0xff, 0xff, 0xff];
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let out_dir = tmp_dir();
|
||||||
|
|
||||||
|
// echo $HELLO_WORLD | rustc -
|
||||||
|
rustc().arg("-").stdin(HELLO_WORLD).run();
|
||||||
|
assert!(
|
||||||
|
out_dir.join(if !is_windows() { "rust_out" } else { "rust_out.exe" }).try_exists().unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
|
// echo $NOT_UTF8 | rustc -
|
||||||
|
let output = rustc().arg("-").stdin(NOT_UTF8).run_fail();
|
||||||
|
let stderr = String::from_utf8(output.stderr).unwrap();
|
||||||
|
assert!(stderr.contains("error: couldn't read from stdin, as it did not contain valid UTF-8"));
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user