Skip to content

Commit 091ca23

Browse files
committed
fix: Propagate signals in project run
1 parent 9db785b commit 091ca23

File tree

1 file changed

+23
-2
lines changed
  • crates/uv/src/commands/project

1 file changed

+23
-2
lines changed

crates/uv/src/commands/project/run.rs

+23-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ use futures::StreamExt;
1111
use itertools::Itertools;
1212
use owo_colors::OwoColorize;
1313
use tokio::process::Command;
14+
use tokio::select;
15+
use tokio::signal::unix::{signal, SignalKind};
1416
use tracing::{debug, warn};
1517
use url::Url;
1618
use uv_cache::Cache;
@@ -994,9 +996,28 @@ pub(crate) async fn run(
994996
// Ignore signals in the parent process, deferring them to the child. This is safe as long as
995997
// the command is the last thing that runs in this process; otherwise, we'd need to restore the
996998
// signal handlers after the command completes.
997-
let _handler = tokio::spawn(async { while tokio::signal::ctrl_c().await.is_ok() {} });
999+
let mut term_signal = signal(SignalKind::terminate())?;
1000+
let mut int_signal = signal(SignalKind::interrupt())?;
9981001

999-
let status = handle.wait().await.context("Child process disappeared")?;
1002+
let status = select! {
1003+
status = handle.wait() => status,
1004+
1005+
// `SIGTERM`
1006+
_ = term_signal.recv() => {
1007+
handle.kill().await?;
1008+
handle.wait().await.context("Child process disappeared")?;
1009+
return Ok(ExitStatus::Failure);
1010+
}
1011+
1012+
// `SIGINT`
1013+
_ = int_signal.recv() => {
1014+
handle.kill().await?;
1015+
handle.wait().await.context("Child process disappeared")?;
1016+
return Ok(ExitStatus::Failure);
1017+
}
1018+
};
1019+
1020+
let status = status.context("Child process disappeared")?;
10001021

10011022
// Exit based on the result of the command
10021023
if let Some(code) = status.code() {

0 commit comments

Comments
 (0)