about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorJakub Beránek <jakub.beranek@vsb.cz>2024-07-04 16:15:59 +0200
committerJakub Beránek <berykubik@gmail.com>2024-07-12 20:15:19 +0200
commitcefd5b38348d129f657597f741dcb45cf2ca44b8 (patch)
tree80c12eb58b5daf8ad0fb9ae80e445b8281c250a5 /src
parenta1626d709cba2ff9508fe4fccba04110e5a87c7b (diff)
downloadrust-cefd5b38348d129f657597f741dcb45cf2ca44b8.tar.gz
rust-cefd5b38348d129f657597f741dcb45cf2ca44b8.zip
Add `DropBomb` to `BootstrapCommand`
This makes it harder to accidentally forget to execute a created command in bootstrap.
Diffstat (limited to 'src')
-rw-r--r--src/bootstrap/src/lib.rs1
-rw-r--r--src/bootstrap/src/utils/exec.rs18
-rw-r--r--src/bootstrap/src/utils/helpers.rs1
3 files changed, 20 insertions, 0 deletions
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index b79e1badb2a..4a69068b51e 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -938,6 +938,7 @@ impl Build {
     /// Execute a command and return its output.
     /// This method should be used for all command executions in bootstrap.
     fn run(&self, command: &mut BootstrapCommand) -> CommandOutput {
+        command.mark_as_executed();
         if self.config.dry_run() && !command.run_always {
             return CommandOutput::default();
         }
diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs
index 09801a05fa3..a9291d45f21 100644
--- a/src/bootstrap/src/utils/exec.rs
+++ b/src/bootstrap/src/utils/exec.rs
@@ -1,4 +1,5 @@
 use crate::Build;
+use build_helper::drop_bomb::DropBomb;
 use std::ffi::OsStr;
 use std::path::Path;
 use std::process::{Command, CommandArgs, CommandEnvs, ExitStatus, Output, Stdio};
@@ -61,9 +62,13 @@ pub struct BootstrapCommand {
     pub stderr: OutputMode,
     // Run the command even during dry run
     pub run_always: bool,
+    // This field makes sure that each command is executed (or disarmed) before it is dropped,
+    // to avoid forgetting to execute a command.
+    drop_bomb: DropBomb,
 }
 
 impl BootstrapCommand {
+    #[track_caller]
     pub fn new<S: AsRef<OsStr>>(program: S) -> Self {
         Command::new(program).into()
     }
@@ -149,18 +154,30 @@ impl BootstrapCommand {
     /// Provides access to the stdlib Command inside.
     /// All usages of this function should be eventually removed from bootstrap.
     pub fn as_command_mut(&mut self) -> &mut Command {
+        // We don't know what will happen with the returned command, so we need to mark this
+        // command as executed proactively.
+        self.mark_as_executed();
         &mut self.command
     }
+
+    /// Mark the command as being executd, disarming the drop bomb.
+    /// If this method is not called before the command is dropped, its drop will panic.
+    pub fn mark_as_executed(&mut self) {
+        self.drop_bomb.defuse();
+    }
 }
 
 impl From<Command> for BootstrapCommand {
+    #[track_caller]
     fn from(command: Command) -> Self {
+        let program = command.get_program().to_owned();
         Self {
             command,
             failure_behavior: BehaviorOnFailure::Exit,
             stdout: OutputMode::Print,
             stderr: OutputMode::Print,
             run_always: false,
+            drop_bomb: DropBomb::arm(program),
         }
     }
 }
@@ -175,6 +192,7 @@ enum CommandStatus {
 
 /// Create a new BootstrapCommand. This is a helper function to make command creation
 /// shorter than `BootstrapCommand::new`.
+#[track_caller]
 #[must_use]
 pub fn command<S: AsRef<OsStr>>(program: S) -> BootstrapCommand {
     BootstrapCommand::new(program)
diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs
index fd8aee37d90..f695b3229fe 100644
--- a/src/bootstrap/src/utils/helpers.rs
+++ b/src/bootstrap/src/utils/helpers.rs
@@ -501,6 +501,7 @@ pub fn check_cfg_arg(name: &str, values: Option<&[&str]>) -> String {
 /// bootstrap-specific needs/hacks from a single source, rather than applying them on next to every
 /// git command creation, which is painful to ensure that the required change is applied
 /// on each one of them correctly.
+#[track_caller]
 pub fn git(source_dir: Option<&Path>) -> BootstrapCommand {
     let mut git = command("git");