about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
author许杰友 Jieyou Xu (Joe) <jieyouxu@outlook.com>2024-09-05 09:14:08 +0000
committer许杰友 Jieyou Xu (Joe) <jieyouxu@outlook.com>2024-09-05 09:14:08 +0000
commit8871ce0e1f4bc9dbca91d567ab0332746f7facaa (patch)
treec1302472325627b0eede21460d8a6b33ef4e3f6c /src
parentafed862b26335b37539ec2cd295e34ef3fb844be (diff)
downloadrust-8871ce0e1f4bc9dbca91d567ab0332746f7facaa.tar.gz
rust-8871ce0e1f4bc9dbca91d567ab0332746f7facaa.zip
run_make_support: make each command invocation only-run-once
Diffstat (limited to 'src')
-rw-r--r--src/tools/run-make-support/src/command.rs17
1 files changed, 16 insertions, 1 deletions
diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs
index 3f2ae078229..6b58173b343 100644
--- a/src/tools/run-make-support/src/command.rs
+++ b/src/tools/run-make-support/src/command.rs
@@ -15,7 +15,7 @@ use crate::{
 /// 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`] must be executed exactly once
 ///
 /// 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
@@ -23,6 +23,12 @@ use crate::{
 /// containing constructed but never executed commands is dangerous because it can give a false
 /// sense of confidence.
 ///
+/// Each [`Command`] invocation can also only be executed once, because we want to enforce
+/// `std{in,out,err}` config via [`std::process::Stdio`] but [`std::process::Stdio`] is not
+/// cloneable.
+///
+/// In this sense, [`Command`] exhibits linear type semantics but enforced at run-time.
+///
 /// [`run`]: Self::run
 /// [`run_fail`]: Self::run_fail
 /// [`run_unchecked`]: Self::run_unchecked
@@ -37,7 +43,9 @@ pub struct Command {
     stdout: Option<Stdio>,
     stderr: Option<Stdio>,
 
+    // Emulate linear type semantics.
     drop_bomb: DropBomb,
+    already_executed: bool,
 }
 
 impl Command {
@@ -51,6 +59,7 @@ impl Command {
             stdin: None,
             stdout: None,
             stderr: None,
+            already_executed: false,
         }
     }
 
@@ -177,6 +186,12 @@ impl Command {
 
     #[track_caller]
     fn command_output(&mut self) -> CompletedProcess {
+        if self.already_executed {
+            panic!("command was already executed");
+        } else {
+            self.already_executed = true;
+        }
+
         self.drop_bomb.defuse();
         // let's make sure we piped all the input and outputs
         self.cmd.stdin(self.stdin.take().unwrap_or(Stdio::piped()));