diff --git a/Cargo.lock b/Cargo.lock index d9f4e2dc..c0f34b73 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3942,6 +3942,7 @@ dependencies = [ "bincode", "bstr", "clap", + "ctrlc", "derive_more", "fspy", "futures-util", diff --git a/crates/vite_task/Cargo.toml b/crates/vite_task/Cargo.toml index 6f6dc571..7f0bebb3 100644 --- a/crates/vite_task/Cargo.toml +++ b/crates/vite_task/Cargo.toml @@ -17,6 +17,7 @@ async-trait = { workspace = true } bincode = { workspace = true, features = ["derive"] } bstr = { workspace = true } clap = { workspace = true, features = ["derive"] } +ctrlc = { workspace = true } derive_more = { workspace = true, features = ["from"] } fspy = { workspace = true } futures-util = { workspace = true } diff --git a/crates/vite_task/src/session/mod.rs b/crates/vite_task/src/session/mod.rs index 3588faa5..add1633a 100644 --- a/crates/vite_task/src/session/mod.rs +++ b/crates/vite_task/src/session/mod.rs @@ -327,6 +327,13 @@ impl<'a> Session<'a> { Some(self.make_summary_writer()), self.program_name.clone(), )); + // Ignore SIGINT/CTRL_C before executing tasks. Child tasks + // receive the signal directly from the terminal driver and handle + // it themselves. This lets the runner wait for tasks to exit and + // report their actual exit status rather than being killed + // mid-flight. + let _ = ctrlc::set_handler(|| {}); + self.execute_graph(graph, builder).await.map_err(SessionError::EarlyExit) } } diff --git a/crates/vite_task_bin/src/main.rs b/crates/vite_task_bin/src/main.rs index 2fe73c00..d627e2c3 100644 --- a/crates/vite_task_bin/src/main.rs +++ b/crates/vite_task_bin/src/main.rs @@ -3,12 +3,6 @@ use vite_task::{Command, ExitStatus, Session}; use vite_task_bin::OwnedSessionConfig; fn main() -> ! { - // Ignore SIGINT/CTRL_C before the tokio runtime starts. Child tasks - // receive the signal directly from the terminal driver and handle it - // themselves. This lets the runner wait for tasks to exit and report - // their actual exit status rather than being killed mid-flight. - let _ = ctrlc::set_handler(|| {}); - let exit_code: i32 = tokio::runtime::Builder::new_multi_thread().enable_all().build().unwrap().block_on(async { match run().await { diff --git a/crates/vite_task_bin/src/vtt/exit_on_ctrlc.rs b/crates/vite_task_bin/src/vtt/exit_on_ctrlc.rs index 3eed75e8..6c26d582 100644 --- a/crates/vite_task_bin/src/vtt/exit_on_ctrlc.rs +++ b/crates/vite_task_bin/src/vtt/exit_on_ctrlc.rs @@ -33,6 +33,9 @@ pub fn run() -> Result<(), Box> { })?; pty_terminal_test_client::mark_milestone("ready"); + // Print a newline so the milestone bytes get flushed through line-buffered + // writers (labeled/grouped log modes). + println!(); loop { std::thread::park(); diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/ctrl-c/snapshots.toml b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/ctrl-c/snapshots.toml index db217d6d..637c2bee 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/ctrl-c/snapshots.toml +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/ctrl-c/snapshots.toml @@ -12,3 +12,30 @@ steps = [ { "write-key" = "ctrl-c" }, ] }, ] + +[[e2e]] +name = "ctrl-c terminates running tasks (labeled)" +steps = [ + { argv = [ + "vt", + "run", + "--log=labeled", + "dev", + ], interactions = [ + { "expect-milestone" = "ready" }, + { "write-key" = "ctrl-c" }, + ] }, +] + +[[e2e]] +name = "ctrl-c terminates running tasks (cached)" +steps = [ + { argv = [ + "vt", + "run", + "dev-cached", + ], interactions = [ + { "expect-milestone" = "ready" }, + { "write-key" = "ctrl-c" }, + ] }, +] diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/ctrl-c/snapshots/ctrl-c terminates running tasks (cached).snap b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/ctrl-c/snapshots/ctrl-c terminates running tasks (cached).snap new file mode 100644 index 00000000..4fe99bae --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/ctrl-c/snapshots/ctrl-c terminates running tasks (cached).snap @@ -0,0 +1,11 @@ +--- +source: crates/vite_task_bin/tests/e2e_snapshots/main.rs +expression: e2e_outputs +--- +> vt run dev-cached +@ expect-milestone: ready +$ vtt exit-on-ctrlc +@ write-key: ctrl-c +$ vtt exit-on-ctrlc + +ctrl-c received diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/ctrl-c/snapshots/ctrl-c terminates running tasks (labeled).snap b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/ctrl-c/snapshots/ctrl-c terminates running tasks (labeled).snap new file mode 100644 index 00000000..ec161535 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/ctrl-c/snapshots/ctrl-c terminates running tasks (labeled).snap @@ -0,0 +1,13 @@ +--- +source: crates/vite_task_bin/tests/e2e_snapshots/main.rs +expression: e2e_outputs +--- +> vt run --log=labeled dev +@ expect-milestone: ready +[ctrl-c-test#dev] $ vtt exit-on-ctrlc ⊘ cache disabled +[ctrl-c-test#dev] +@ write-key: ctrl-c +[ctrl-c-test#dev] $ vtt exit-on-ctrlc ⊘ cache disabled +[ctrl-c-test#dev] + +[ctrl-c-test#dev] ctrl-c received diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/ctrl-c/snapshots/ctrl-c terminates running tasks.snap b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/ctrl-c/snapshots/ctrl-c terminates running tasks.snap index b19a6308..84c6c210 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/ctrl-c/snapshots/ctrl-c terminates running tasks.snap +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/ctrl-c/snapshots/ctrl-c terminates running tasks.snap @@ -7,4 +7,5 @@ expression: e2e_outputs $ vtt exit-on-ctrlc ⊘ cache disabled @ write-key: ctrl-c $ vtt exit-on-ctrlc ⊘ cache disabled + ctrl-c received diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/ctrl-c/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/ctrl-c/vite-task.json index f66089b1..ed631d53 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/ctrl-c/vite-task.json +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/ctrl-c/vite-task.json @@ -1,8 +1,13 @@ { - "cache": false, + "cache": true, "tasks": { "dev": { - "command": "vtt exit-on-ctrlc" + "command": "vtt exit-on-ctrlc", + "cache": false + }, + "dev-cached": { + "command": "vtt exit-on-ctrlc", + "cache": true } } }