diff options
| 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 |
| commit | 8871ce0e1f4bc9dbca91d567ab0332746f7facaa (patch) | |
| tree | c1302472325627b0eede21460d8a6b33ef4e3f6c /src | |
| parent | afed862b26335b37539ec2cd295e34ef3fb844be (diff) | |
| download | rust-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.rs | 17 |
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())); |
