about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-05-03 15:26:10 +0200
committerGitHub <noreply@github.com>2024-05-03 15:26:10 +0200
commitc27d3d5d2a8e65d91f32f5b30510655863238e2d (patch)
tree992ed04e1d5183207b59326b70c24c7612754b0d
parent08d99928121f4a22b1e6e5aea8e84efc025f9484 (diff)
parent2c4214e0a00287be39c2b8d5331b4fa4f88b1390 (diff)
downloadrust-c27d3d5d2a8e65d91f32f5b30510655863238e2d.tar.gz
rust-c27d3d5d2a8e65d91f32f5b30510655863238e2d.zip
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`
-rw-r--r--src/tools/run-make-support/src/cc.rs5
-rw-r--r--src/tools/run-make-support/src/clang.rs5
-rw-r--r--src/tools/run-make-support/src/lib.rs18
-rw-r--r--src/tools/run-make-support/src/llvm_readobj.rs6
-rw-r--r--src/tools/run-make-support/src/rustc.rs38
-rw-r--r--src/tools/run-make-support/src/rustdoc.rs39
-rw-r--r--src/tools/tidy/src/allowed_run_make_makefiles.txt1
-rw-r--r--tests/run-make/stdin-non-utf8/Makefile6
-rw-r--r--tests/run-make/stdin-non-utf8/non-utf81
-rw-r--r--tests/run-make/stdin-rustc/rmake.rs26
10 files changed, 120 insertions, 25 deletions
diff --git a/src/tools/run-make-support/src/cc.rs b/src/tools/run-make-support/src/cc.rs
index 146123793be..4082639f618 100644
--- a/src/tools/run-make-support/src/cc.rs
+++ b/src/tools/run-make-support/src/cc.rs
@@ -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`
diff --git a/src/tools/run-make-support/src/clang.rs b/src/tools/run-make-support/src/clang.rs
index ed9f8383dc3..c30ba29ed76 100644
--- a/src/tools/run-make-support/src/clang.rs
+++ b/src/tools/run-make-support/src/clang.rs
@@ -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")
+    }
 }
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index a874c1313b5..239f90b23c9 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -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
@@ -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);
 ///
@@ -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);
                 }
@@ -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);
                 }
diff --git a/src/tools/run-make-support/src/llvm_readobj.rs b/src/tools/run-make-support/src/llvm_readobj.rs
index 32ea07e932e..4e1f2b002f3 100644
--- a/src/tools/run-make-support/src/llvm_readobj.rs
+++ b/src/tools/run-make-support/src/llvm_readobj.rs
@@ -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")
+    }
 }
diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs
index ddaae3236c2..37539528ab3 100644
--- a/src/tools/run-make-support/src/rustc.rs
+++ b/src/tools/run-make-support/src/rustc.rs
@@ -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};
 
@@ -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);
@@ -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
@@ -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);
         }
diff --git a/src/tools/run-make-support/src/rustdoc.rs b/src/tools/run-make-support/src/rustdoc.rs
index 1054ac83c10..c2c4f2e68e2 100644
--- a/src/tools/run-make-support/src/rustdoc.rs
+++ b/src/tools/run-make-support/src/rustdoc.rs
@@ -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};
 
@@ -17,6 +18,7 @@ pub fn rustdoc() -> Rustdoc {
 #[derive(Debug)]
 pub struct Rustdoc {
     cmd: Command,
+    stdin: Option<Box<[u8]>>,
 }
 
 crate::impl_common_helpers!(Rustdoc);
@@ -32,7 +34,7 @@ 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.
@@ -40,7 +42,7 @@ impl Rustdoc {
         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.
@@ -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);
         }
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index 69c6dda4b19..4b79b910ec3 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -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
diff --git a/tests/run-make/stdin-non-utf8/Makefile b/tests/run-make/stdin-non-utf8/Makefile
deleted file mode 100644
index 709d4cf1408..00000000000
--- a/tests/run-make/stdin-non-utf8/Makefile
+++ /dev/null
@@ -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"
diff --git a/tests/run-make/stdin-non-utf8/non-utf8 b/tests/run-make/stdin-non-utf8/non-utf8
deleted file mode 100644
index bc87051a852..00000000000
--- a/tests/run-make/stdin-non-utf8/non-utf8
+++ /dev/null
@@ -1 +0,0 @@

diff --git a/tests/run-make/stdin-rustc/rmake.rs b/tests/run-make/stdin-rustc/rmake.rs
new file mode 100644
index 00000000000..c07a6df4d84
--- /dev/null
+++ b/tests/run-make/stdin-rustc/rmake.rs
@@ -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"));
+}