Skip to content

Commit cefd5b3

Browse files
committed
Add DropBomb to BootstrapCommand
This makes it harder to accidentally forget to execute a created command in bootstrap.
1 parent a1626d7 commit cefd5b3

File tree

3 files changed

+20
-0
lines changed

3 files changed

+20
-0
lines changed

src/bootstrap/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -938,6 +938,7 @@ impl Build {
938938
/// Execute a command and return its output.
939939
/// This method should be used for all command executions in bootstrap.
940940
fn run(&self, command: &mut BootstrapCommand) -> CommandOutput {
941+
command.mark_as_executed();
941942
if self.config.dry_run() && !command.run_always {
942943
return CommandOutput::default();
943944
}

src/bootstrap/src/utils/exec.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::Build;
2+
use build_helper::drop_bomb::DropBomb;
23
use std::ffi::OsStr;
34
use std::path::Path;
45
use std::process::{Command, CommandArgs, CommandEnvs, ExitStatus, Output, Stdio};
@@ -61,9 +62,13 @@ pub struct BootstrapCommand {
6162
pub stderr: OutputMode,
6263
// Run the command even during dry run
6364
pub run_always: bool,
65+
// This field makes sure that each command is executed (or disarmed) before it is dropped,
66+
// to avoid forgetting to execute a command.
67+
drop_bomb: DropBomb,
6468
}
6569

6670
impl BootstrapCommand {
71+
#[track_caller]
6772
pub fn new<S: AsRef<OsStr>>(program: S) -> Self {
6873
Command::new(program).into()
6974
}
@@ -149,18 +154,30 @@ impl BootstrapCommand {
149154
/// Provides access to the stdlib Command inside.
150155
/// All usages of this function should be eventually removed from bootstrap.
151156
pub fn as_command_mut(&mut self) -> &mut Command {
157+
// We don't know what will happen with the returned command, so we need to mark this
158+
// command as executed proactively.
159+
self.mark_as_executed();
152160
&mut self.command
153161
}
162+
163+
/// Mark the command as being executd, disarming the drop bomb.
164+
/// If this method is not called before the command is dropped, its drop will panic.
165+
pub fn mark_as_executed(&mut self) {
166+
self.drop_bomb.defuse();
167+
}
154168
}
155169

156170
impl From<Command> for BootstrapCommand {
171+
#[track_caller]
157172
fn from(command: Command) -> Self {
173+
let program = command.get_program().to_owned();
158174
Self {
159175
command,
160176
failure_behavior: BehaviorOnFailure::Exit,
161177
stdout: OutputMode::Print,
162178
stderr: OutputMode::Print,
163179
run_always: false,
180+
drop_bomb: DropBomb::arm(program),
164181
}
165182
}
166183
}
@@ -175,6 +192,7 @@ enum CommandStatus {
175192

176193
/// Create a new BootstrapCommand. This is a helper function to make command creation
177194
/// shorter than `BootstrapCommand::new`.
195+
#[track_caller]
178196
#[must_use]
179197
pub fn command<S: AsRef<OsStr>>(program: S) -> BootstrapCommand {
180198
BootstrapCommand::new(program)

src/bootstrap/src/utils/helpers.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,7 @@ pub fn check_cfg_arg(name: &str, values: Option<&[&str]>) -> String {
501501
/// bootstrap-specific needs/hacks from a single source, rather than applying them on next to every
502502
/// git command creation, which is painful to ensure that the required change is applied
503503
/// on each one of them correctly.
504+
#[track_caller]
504505
pub fn git(source_dir: Option<&Path>) -> BootstrapCommand {
505506
let mut git = command("git");
506507

0 commit comments

Comments
 (0)