about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJakub Beránek <jakub.beranek@vsb.cz>2024-07-07 19:04:27 +0200
committerJakub Beránek <berykubik@gmail.com>2024-07-26 09:17:34 +0200
commit82d5743e0b1ecd1995d3bee1a03ec2571b3ffdad (patch)
tree6fe799b6e5347b7617eb35e3bcd8677c0cc13ae5
parentc70d63ed728ff38e397d4737d226b6f4e753e3d9 (diff)
downloadrust-82d5743e0b1ecd1995d3bee1a03ec2571b3ffdad.tar.gz
rust-82d5743e0b1ecd1995d3bee1a03ec2571b3ffdad.zip
Make it easier to detect when bootstrap tries to read uncaptured stdout/stderr
If e.g. only stdout is captured, but the caller tries to read stderr, previously
they would get back an empty string. Now the code will explicitly panic when
accessing an uncaptured output stream.
-rw-r--r--src/bootstrap/src/lib.rs6
-rw-r--r--src/bootstrap/src/utils/exec.rs46
2 files changed, 32 insertions, 20 deletions
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 1d388767d7e..899a80fa9c7 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -968,7 +968,9 @@ impl Build {
         let mut message = String::new();
         let output: CommandOutput = match output {
             // Command has succeeded
-            Ok(output) if output.status.success() => output.into(),
+            Ok(output) if output.status.success() => {
+                CommandOutput::from_output(output, stdout, stderr)
+            }
             // Command has started, but then it failed
             Ok(output) => {
                 writeln!(
@@ -982,7 +984,7 @@ Executed at: {executed_at}"#,
                 )
                 .unwrap();
 
-                let output: CommandOutput = output.into();
+                let output: CommandOutput = CommandOutput::from_output(output, stdout, stderr);
 
                 // If the output mode is OutputMode::Capture, we can now print the output.
                 // If it is OutputMode::Print, then the output has already been printed to
diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs
index 22619e674f9..d4ae8e26aaa 100644
--- a/src/bootstrap/src/utils/exec.rs
+++ b/src/bootstrap/src/utils/exec.rs
@@ -223,17 +223,31 @@ pub fn command<S: AsRef<OsStr>>(program: S) -> BootstrapCommand {
 }
 
 /// Represents the output of an executed process.
-#[allow(unused)]
 pub struct CommandOutput {
     status: CommandStatus,
-    stdout: Vec<u8>,
-    stderr: Vec<u8>,
+    stdout: Option<Vec<u8>>,
+    stderr: Option<Vec<u8>>,
 }
 
 impl CommandOutput {
     #[must_use]
     pub fn did_not_start() -> Self {
-        Self { status: CommandStatus::DidNotStart, stdout: vec![], stderr: vec![] }
+        Self { status: CommandStatus::DidNotStart, stdout: None, stderr: None }
+    }
+
+    #[must_use]
+    pub fn from_output(output: Output, stdout: OutputMode, stderr: OutputMode) -> Self {
+        Self {
+            status: CommandStatus::Finished(output.status),
+            stdout: match stdout {
+                OutputMode::Print => None,
+                OutputMode::Capture => Some(output.stdout),
+            },
+            stderr: match stderr {
+                OutputMode::Print => None,
+                OutputMode::Capture => Some(output.stderr),
+            },
+        }
     }
 
     #[must_use]
@@ -259,7 +273,10 @@ impl CommandOutput {
 
     #[must_use]
     pub fn stdout(&self) -> String {
-        String::from_utf8(self.stdout.clone()).expect("Cannot parse process stdout as UTF-8")
+        String::from_utf8(
+            self.stdout.clone().expect("Accessing stdout of a command that did not capture stdout"),
+        )
+        .expect("Cannot parse process stdout as UTF-8")
     }
 
     #[must_use]
@@ -269,7 +286,10 @@ impl CommandOutput {
 
     #[must_use]
     pub fn stderr(&self) -> String {
-        String::from_utf8(self.stderr.clone()).expect("Cannot parse process stderr as UTF-8")
+        String::from_utf8(
+            self.stderr.clone().expect("Accessing stderr of a command that did not capture stderr"),
+        )
+        .expect("Cannot parse process stderr as UTF-8")
     }
 }
 
@@ -277,18 +297,8 @@ impl Default for CommandOutput {
     fn default() -> Self {
         Self {
             status: CommandStatus::Finished(ExitStatus::default()),
-            stdout: vec![],
-            stderr: vec![],
-        }
-    }
-}
-
-impl From<Output> for CommandOutput {
-    fn from(output: Output) -> Self {
-        Self {
-            status: CommandStatus::Finished(output.status),
-            stdout: output.stdout,
-            stderr: output.stderr,
+            stdout: Some(vec![]),
+            stderr: Some(vec![]),
         }
     }
 }