From 091ca23754c6fa244347546a7574155610cb6baa Mon Sep 17 00:00:00 2001 From: Shane Kennedy Date: Fri, 8 Nov 2024 12:26:47 +0100 Subject: [PATCH] fix: Propagate signals in project run --- crates/uv/src/commands/project/run.rs | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/crates/uv/src/commands/project/run.rs b/crates/uv/src/commands/project/run.rs index fc8651a915074..b8310af272304 100644 --- a/crates/uv/src/commands/project/run.rs +++ b/crates/uv/src/commands/project/run.rs @@ -11,6 +11,8 @@ use futures::StreamExt; use itertools::Itertools; use owo_colors::OwoColorize; use tokio::process::Command; +use tokio::select; +use tokio::signal::unix::{signal, SignalKind}; use tracing::{debug, warn}; use url::Url; use uv_cache::Cache; @@ -994,9 +996,28 @@ pub(crate) async fn run( // Ignore signals in the parent process, deferring them to the child. This is safe as long as // the command is the last thing that runs in this process; otherwise, we'd need to restore the // signal handlers after the command completes. - let _handler = tokio::spawn(async { while tokio::signal::ctrl_c().await.is_ok() {} }); + let mut term_signal = signal(SignalKind::terminate())?; + let mut int_signal = signal(SignalKind::interrupt())?; - let status = handle.wait().await.context("Child process disappeared")?; + let status = select! { + status = handle.wait() => status, + + // `SIGTERM` + _ = term_signal.recv() => { + handle.kill().await?; + handle.wait().await.context("Child process disappeared")?; + return Ok(ExitStatus::Failure); + } + + // `SIGINT` + _ = int_signal.recv() => { + handle.kill().await?; + handle.wait().await.context("Child process disappeared")?; + return Ok(ExitStatus::Failure); + } + }; + + let status = status.context("Child process disappeared")?; // Exit based on the result of the command if let Some(code) = status.code() {