Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for inputing via stdin with run-make-support #124612

Merged
merged 2 commits into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/tools/run-make-support/src/cc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ impl Cc {

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`
Expand Down
5 changes: 5 additions & 0 deletions src/tools/run-make-support/src/clang.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,9 @@ impl Clang {
self.cmd.arg(format!("-fuse-ld={ld}"));
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")
}
}
18 changes: 9 additions & 9 deletions src/tools/run-make-support/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
/// 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
/// to be *fallback* argument acceptors, when specific helpers don't make sense. Prefer to add
Expand All @@ -160,7 +160,12 @@ pub fn set_host_rpath(cmd: &mut Command) {
/// Example usage:
///
/// ```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);
///
Expand Down Expand Up @@ -231,18 +236,13 @@ macro_rules! impl_common_helpers {
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.
#[track_caller]
pub fn run(&mut self) -> ::std::process::Output {
let caller_location = ::std::panic::Location::caller();
let caller_line_number = caller_location.line();

let output = self.cmd.output().unwrap();
let output = self.output();
if !output.status.success() {
handle_failed_output(&self.cmd, output, caller_line_number);
}
Expand All @@ -255,7 +255,7 @@ macro_rules! impl_common_helpers {
let caller_location = ::std::panic::Location::caller();
let caller_line_number = caller_location.line();

let output = self.cmd.output().unwrap();
let output = self.output();
if output.status.success() {
handle_failed_output(&self.cmd, output, caller_line_number);
}
Expand Down
6 changes: 6 additions & 0 deletions src/tools/run-make-support/src/llvm_readobj.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,10 @@ impl LlvmReadobj {
self.cmd.arg("--file-header");
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")
}
}
38 changes: 34 additions & 4 deletions src/tools/run-make-support/src/rustc.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use std::env;
use std::ffi::OsString;
use std::io::Write;
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};

Expand All @@ -19,6 +20,7 @@ pub fn aux_build() -> Rustc {
#[derive(Debug)]
pub struct Rustc {
cmd: Command,
stdin: Option<Box<[u8]>>,
}

crate::impl_common_helpers!(Rustc);
Expand All @@ -37,14 +39,14 @@ impl Rustc {
/// Construct a new `rustc` invocation.
pub fn new() -> Self {
let cmd = setup_common();
Self { cmd }
Self { cmd, stdin: None }
}

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

// Argument provider methods
Expand Down Expand Up @@ -161,12 +163,40 @@ impl Rustc {
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]
pub fn run_fail_assert_exit_code(&mut self, code: i32) -> Output {
let caller_location = std::panic::Location::caller();
let caller_line_number = caller_location.line();

let output = self.cmd.output().unwrap();
let output = self.output();
if output.status.code().unwrap() != code {
handle_failed_output(&self.cmd, output, caller_line_number);
}
Expand Down
39 changes: 35 additions & 4 deletions src/tools/run-make-support/src/rustdoc.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::env;
use std::io::Write;
use std::path::Path;
use std::process::{Command, Output};
use std::process::{Command, Output, Stdio};

use crate::{handle_failed_output, set_host_rpath};

Expand All @@ -17,6 +18,7 @@ pub fn rustdoc() -> Rustdoc {
#[derive(Debug)]
pub struct Rustdoc {
cmd: Command,
stdin: Option<Box<[u8]>>,
}

crate::impl_common_helpers!(Rustdoc);
Expand All @@ -32,15 +34,15 @@ impl Rustdoc {
/// Construct a bare `rustdoc` invocation.
pub fn bare() -> Self {
let cmd = setup_common();
Self { cmd }
Self { cmd, stdin: None }
}

/// Construct a `rustdoc` invocation with `-L $(TARGET_RPATH_DIR)` set.
pub fn new() -> Self {
let mut cmd = setup_common();
let target_rpath_dir = env::var_os("TARGET_RPATH_DIR").unwrap();
cmd.arg(format!("-L{}", target_rpath_dir.to_string_lossy()));
Self { cmd }
Self { cmd, stdin: None }
}

/// Specify path to the input file.
Expand All @@ -62,12 +64,41 @@ impl Rustdoc {
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]
pub fn run_fail_assert_exit_code(&mut self, code: i32) -> Output {
let caller_location = std::panic::Location::caller();
let caller_line_number = caller_location.line();

let output = self.cmd.output().unwrap();
let output = self.output();
if output.status.code().unwrap() != code {
handle_failed_output(&self.cmd, output, caller_line_number);
}
Expand Down
1 change: 0 additions & 1 deletion src/tools/tidy/src/allowed_run_make_makefiles.txt
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,6 @@ run-make/static-unwinding/Makefile
run-make/staticlib-blank-lib/Makefile
run-make/staticlib-dylib-linkage/Makefile
run-make/std-core-cycle/Makefile
run-make/stdin-non-utf8/Makefile
run-make/suspicious-library/Makefile
run-make/symbol-mangling-hashed/Makefile
run-make/symbol-visibility/Makefile
Expand Down
6 changes: 0 additions & 6 deletions tests/run-make/stdin-non-utf8/Makefile

This file was deleted.

1 change: 0 additions & 1 deletion tests/run-make/stdin-non-utf8/non-utf8

This file was deleted.

26 changes: 26 additions & 0 deletions tests/run-make/stdin-rustc/rmake.rs
Original file line number Diff line number Diff line change
@@ -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"));
}