From e1bc696bc0b2b0eeaa608eca613df666f28b9670 Mon Sep 17 00:00:00 2001 From: Wolf Vollprecht Date: Thu, 31 Jul 2025 11:46:46 +0200 Subject: [PATCH 01/10] forward CTRL+C signal to deno_task_shell --- Cargo.lock | 389 +++++++++++++++++++++++++++---------------------- Cargo.toml | 2 +- src/cli/run.rs | 43 +++++- 3 files changed, 257 insertions(+), 177 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fa4c82b656..78880fa055 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -273,7 +273,7 @@ dependencies = [ "futures-lite", "parking", "polling", - "rustix 1.0.7", + "rustix 1.0.8", "slab", "windows-sys 0.60.2", ] @@ -310,7 +310,7 @@ dependencies = [ "cfg-if", "event-listener", "futures-lite", - "rustix 1.0.7", + "rustix 1.0.8", ] [[package]] @@ -336,7 +336,7 @@ dependencies = [ "cfg-if", "futures-core", "futures-io", - "rustix 1.0.7", + "rustix 1.0.8", "signal-hook-registry", "slab", "windows-sys 0.60.2", @@ -391,7 +391,7 @@ dependencies = [ "futures", "http-content-range", "itertools 0.13.0", - "memmap2 0.9.5", + "memmap2 0.9.7", "reqwest", "reqwest-middleware", "thiserror 1.0.69", @@ -459,9 +459,9 @@ dependencies = [ [[package]] name = "aws-credential-types" -version = "1.2.3" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "687bc16bc431a8533fe0097c7f0182874767f920989d7260950172ae8e3c4465" +checksum = "b68c2194a190e1efc999612792e25b1ab3abfefe4306494efaaabc25933c0cbe" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", @@ -471,15 +471,15 @@ dependencies = [ [[package]] name = "aws-runtime" -version = "1.5.8" +version = "1.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f6c68419d8ba16d9a7463671593c54f81ba58cab466e9b759418da606dcc2e2" +checksum = "b2090e664216c78e766b6bac10fe74d2f451c02441d43484cd76ac9a295075f7" dependencies = [ "aws-credential-types", "aws-sigv4", "aws-smithy-async", "aws-smithy-eventstream", - "aws-smithy-http 0.62.1", + "aws-smithy-http 0.62.2", "aws-smithy-runtime", "aws-smithy-runtime-api", "aws-smithy-types", @@ -496,9 +496,9 @@ dependencies = [ [[package]] name = "aws-sdk-s3" -version = "1.96.0" +version = "1.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e25d24de44b34dcdd5182ac4e4c6f07bcec2661c505acef94c0d293b65505fe" +checksum = "8c5eafbdcd898114b839ba68ac628e31c4cfc3e11dfca38dc1b2de2f35bb6270" dependencies = [ "aws-credential-types", "aws-runtime", @@ -506,7 +506,7 @@ dependencies = [ "aws-smithy-async", "aws-smithy-checksums", "aws-smithy-eventstream", - "aws-smithy-http 0.62.1", + "aws-smithy-http 0.62.2", "aws-smithy-json", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -530,14 +530,14 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.74.0" +version = "1.78.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a69de9c1b9272da2872af60c7402683e7f45c06267735b4332deacb203239b" +checksum = "dbd7bc4bd34303733bded362c4c997a39130eac4310257c79aae8484b1c4b724" dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", - "aws-smithy-http 0.62.1", + "aws-smithy-http 0.62.2", "aws-smithy-json", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -552,14 +552,14 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.75.0" +version = "1.79.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0b161d836fac72bdd5ac1a4cd1cdc38ab888c7af26cfd95f661be4409505e63" +checksum = "77358d25f781bb106c1a69531231d4fd12c6be904edb0c47198c604df5a2dbca" dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", - "aws-smithy-http 0.62.1", + "aws-smithy-http 0.62.2", "aws-smithy-json", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -574,14 +574,14 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.76.0" +version = "1.80.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb1cd79a3412751a341a28e2cd0d6fa4345241976da427b075a0c0cd5409f886" +checksum = "06e3ed2a9b828ae7763ddaed41d51724d2661a50c45f845b08967e52f4939cfc" dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", - "aws-smithy-http 0.62.1", + "aws-smithy-http 0.62.2", "aws-smithy-json", "aws-smithy-query", "aws-smithy-runtime", @@ -603,7 +603,7 @@ checksum = "ddfb9021f581b71870a17eac25b52335b82211cdc092e02b6876b2bcefa61666" dependencies = [ "aws-credential-types", "aws-smithy-eventstream", - "aws-smithy-http 0.62.1", + "aws-smithy-http 0.62.2", "aws-smithy-runtime-api", "aws-smithy-types", "bytes", @@ -636,11 +636,11 @@ dependencies = [ [[package]] name = "aws-smithy-checksums" -version = "0.63.4" +version = "0.63.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "244f00666380d35c1c76b90f7b88a11935d11b84076ac22a4c014ea0939627af" +checksum = "5ab9472f7a8ec259ddb5681d2ef1cb1cf16c0411890063e67cdc7b62562cc496" dependencies = [ - "aws-smithy-http 0.62.1", + "aws-smithy-http 0.62.2", "aws-smithy-types", "bytes", "crc-fast", @@ -656,9 +656,9 @@ dependencies = [ [[package]] name = "aws-smithy-eventstream" -version = "0.60.9" +version = "0.60.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "338a3642c399c0a5d157648426110e199ca7fd1c689cc395676b81aa563700c4" +checksum = "604c7aec361252b8f1c871a7641d5e0ba3a7f5a586e51b66bc9510a5519594d9" dependencies = [ "aws-smithy-types", "bytes", @@ -687,9 +687,9 @@ dependencies = [ [[package]] name = "aws-smithy-http" -version = "0.62.1" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99335bec6cdc50a346fda1437f9fefe33abf8c99060739a546a16457f2862ca9" +checksum = "43c82ba4cab184ea61f6edaafc1072aad3c2a17dcf4c0fce19ac5694b90d8b5f" dependencies = [ "aws-smithy-eventstream", "aws-smithy-runtime-api", @@ -715,7 +715,7 @@ dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", "aws-smithy-types", - "h2 0.3.26", + "h2 0.3.27", "h2 0.4.11", "http 0.2.12", "http-body 0.4.6", @@ -757,12 +757,12 @@ dependencies = [ [[package]] name = "aws-smithy-runtime" -version = "1.8.4" +version = "1.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3aaec682eb189e43c8a19c3dab2fe54590ad5f2cc2d26ab27608a20f2acf81c" +checksum = "660f70d9d8af6876b4c9aa8dcb0dbaf0f89b04ee9a4455bea1b4ba03b15f26f6" dependencies = [ "aws-smithy-async", - "aws-smithy-http 0.62.1", + "aws-smithy-http 0.62.2", "aws-smithy-http-client", "aws-smithy-observability", "aws-smithy-runtime-api", @@ -781,9 +781,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime-api" -version = "1.8.3" +version = "1.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9852b9226cb60b78ce9369022c0df678af1cac231c882d5da97a0c4e03be6e67" +checksum = "937a49ecf061895fca4a6dd8e864208ed9be7546c0527d04bc07d502ec5fba1c" dependencies = [ "aws-smithy-async", "aws-smithy-types", @@ -833,9 +833,9 @@ dependencies = [ [[package]] name = "aws-types" -version = "1.3.7" +version = "1.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a322fec39e4df22777ed3ad8ea868ac2f94cd15e1a55f6ee8d8d6305057689a" +checksum = "b069d19bf01e46298eaedd7c6f283fe565a59263e53eebec945f3e6398f42390" dependencies = [ "aws-credential-types", "aws-smithy-async", @@ -894,9 +894,9 @@ dependencies = [ [[package]] name = "backon" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302eaff5357a264a2c42f127ecb8bac761cf99749fc3dc95677e2743991f99e7" +checksum = "592277618714fbcecda9a02ba7a8781f319d26532a88553bbacc77ba5d2b3a8d" dependencies = [ "fastrand", "gloo-timers 0.3.0", @@ -1051,9 +1051,9 @@ dependencies = [ [[package]] name = "bon" -version = "3.6.4" +version = "3.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f61138465baf186c63e8d9b6b613b508cd832cba4ce93cf37ce5f096f91ac1a6" +checksum = "33d9ef19ae5263a138da9a86871eca537478ab0332a7770bac7e3f08b801f89f" dependencies = [ "bon-macros", "rustversion", @@ -1061,11 +1061,11 @@ dependencies = [ [[package]] name = "bon-macros" -version = "3.6.4" +version = "3.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40d1dad34aa19bf02295382f08d9bc40651585bd497266831d40ee6296fb49ca" +checksum = "577ae008f2ca11ca7641bd44601002ee5ab49ef0af64846ce1ab6057218a5cc1" dependencies = [ - "darling", + "darling 0.21.0", "ident_case", "prettyplease", "proc-macro2", @@ -1240,9 +1240,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.29" +version = "1.2.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362" +checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" dependencies = [ "jobserver", "libc", @@ -1304,9 +1304,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.41" +version = "4.5.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be92d32e80243a54711e5d7ce823c35c41c9d929dc4ab58e1276f625841aadf9" +checksum = "ed87a9d530bb41a67537289bafcac159cb3ee28460e0a4571123d2a778a6a882" dependencies = [ "clap_builder", "clap_derive", @@ -1314,9 +1314,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.41" +version = "4.5.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707eab41e9622f9139419d573eca0900137718000c517d47da73045f54331c3d" +checksum = "64f4f3f3c77c94aff3c7e9aac9a2ca1974a5adf392a8bb751e827d6d127ab966" dependencies = [ "anstream", "anstyle", @@ -1543,15 +1543,15 @@ dependencies = [ "crc", "digest", "libc", - "rand 0.9.1", + "rand 0.9.2", "regex", ] [[package]] name = "crc32fast" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] @@ -1659,8 +1659,18 @@ version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.20.11", + "darling_macro 0.20.11", +] + +[[package]] +name = "darling" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a79c4acb1fd5fa3d9304be4c76e031c54d2e92d172a393e24b19a14fe8532fe9" +dependencies = [ + "darling_core 0.21.0", + "darling_macro 0.21.0", ] [[package]] @@ -1677,13 +1687,38 @@ dependencies = [ "syn", ] +[[package]] +name = "darling_core" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74875de90daf30eb59609910b84d4d368103aaec4c924824c6799b28f77d6a1d" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + [[package]] name = "darling_macro" version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ - "darling_core", + "darling_core 0.20.11", + "quote", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79f8e61677d5df9167cd85265f8e5f64b215cdea3fb55eebc3e622e44c7a146" +dependencies = [ + "darling_core 0.21.0", "quote", "syn", ] @@ -1739,9 +1774,9 @@ dependencies = [ [[package]] name = "deno_error" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "612ec3fc481fea759141b0c57810889b0a4fb6fee8f10748677bfe492fd30486" +checksum = "dde60bd153886964234c5012d3d9caf788287f28d81fb24a884436904101ef10" dependencies = [ "deno_error_macro", "libc", @@ -1750,9 +1785,9 @@ dependencies = [ [[package]] name = "deno_error_macro" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8380a4224d5d2c3f84da4d764c4326cac62e9a1e3d4960442d29136fc07be863" +checksum = "409f265785bd946d3006756955aaf40b0e4deb25752eae6a990afe54a31cfd83" dependencies = [ "proc-macro2", "quote", @@ -1761,9 +1796,9 @@ dependencies = [ [[package]] name = "deno_path_util" -version = "0.4.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "516f813389095889776b81cc9108ff6f336fd9409b4b12fc0138aea23d2708e1" +checksum = "bfe02936964b2910719bd488841f6e884349360113c7abf6f4c6b28ca9cd7a19" dependencies = [ "deno_error", "percent-encoding", @@ -1774,9 +1809,9 @@ dependencies = [ [[package]] name = "deno_task_shell" -version = "0.24.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71ebb5abcf453e2a2eb19d316706fd06b9f79688e6aedc4bda1f1767f53ec8c7" +checksum = "8ec9c589f733da0f5dfdf475d44cd01e2087425839a55162538d9898e94556e8" dependencies = [ "anyhow", "deno_path_util", @@ -1789,6 +1824,7 @@ dependencies = [ "sys_traits", "thiserror 2.0.12", "tokio", + "which", "windows-sys 0.59.0", ] @@ -1913,9 +1949,9 @@ checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "dyn-clone" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" [[package]] name = "ecdsa" @@ -2110,7 +2146,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f5f203b70a419cb8880d1cfe6bebe488add0a0307d404e9f24021e5fd864b80" dependencies = [ "deunicode", - "rand 0.9.1", + "rand 0.9.2", ] [[package]] @@ -2250,7 +2286,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8640e34b88f7652208ce9e88b1a37a2ae95227d84abec377ccd3c5cfeb141ed4" dependencies = [ "fs-err", - "rustix 1.0.7", + "rustix 1.0.8", "tokio", "windows-sys 0.59.0", ] @@ -2543,7 +2579,7 @@ dependencies = [ "google-cloud-gax", "http 1.3.1", "reqwest", - "rustls 0.23.28", + "rustls 0.23.31", "rustls-pemfile 2.2.0", "serde", "serde_json", @@ -2554,9 +2590,9 @@ dependencies = [ [[package]] name = "google-cloud-gax" -version = "0.23.0" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d88f66b6fccca3449ad9f0366ec3d1b74a004fa1100d98353a201dabc3203bd2" +checksum = "5560b3cedeea7041862717175d98733ac81f7bedfdd0c7949bf06d761bf4094f" dependencies = [ "base64 0.22.1", "bytes", @@ -2565,7 +2601,7 @@ dependencies = [ "google-cloud-wkt", "http 1.3.1", "pin-project", - "rand 0.9.1", + "rand 0.9.2", "serde", "serde_json", "thiserror 2.0.12", @@ -2574,9 +2610,9 @@ dependencies = [ [[package]] name = "google-cloud-rpc" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1b4b7867ab6e94e56944116f2b1bdcdbac522eea794743a9884d84db7728470" +checksum = "949f5858642f68efbd836a82400d04f2572e6d18a612c1144d0868832f40996e" dependencies = [ "bytes", "google-cloud-wkt", @@ -2587,9 +2623,9 @@ dependencies = [ [[package]] name = "google-cloud-wkt" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4b1dbeb30ab8bde2423081b76f9c302d82fea1b99f8ca750f223d32065d3c6c" +checksum = "8e2916ee3f086766d6989abd8a0b1c3910322af60d72352f6cdf5cb8eb951464" dependencies = [ "base64 0.22.1", "bytes", @@ -2614,9 +2650,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" dependencies = [ "bytes", "fnv", @@ -2914,14 +2950,14 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2 0.3.26", + "h2 0.3.27", "http 0.2.12", "http-body 0.4.6", "httparse", "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.5.10", "tokio", "tower-service", "tracing", @@ -2975,7 +3011,7 @@ dependencies = [ "hyper 1.6.0", "hyper-util", "log", - "rustls 0.23.28", + "rustls 0.23.31", "rustls-native-certs 0.8.1", "rustls-pki-types", "tokio", @@ -3015,9 +3051,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f66d5bd4c6f02bf0542fad85d626775bab9258cf795a4256dcaf3161114d1df" +checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e" dependencies = [ "base64 0.22.1", "bytes", @@ -3031,7 +3067,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2", + "socket2 0.6.0", "system-configuration", "tokio", "tower-service", @@ -3262,9 +3298,9 @@ dependencies = [ [[package]] name = "io-uring" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013" +checksum = "d93587f37623a1a17d94ef2bc9ada592f5465fe7732084ab7beefabe5c77c0c4" dependencies = [ "bitflags", "cfg-if", @@ -3482,7 +3518,7 @@ dependencies = [ "http 1.3.1", "jsonrpsee-core", "pin-project", - "rustls 0.23.28", + "rustls 0.23.31", "rustls-pki-types", "rustls-platform-verifier", "soketto", @@ -3533,7 +3569,7 @@ dependencies = [ "hyper-util", "jsonrpsee-core", "jsonrpsee-types", - "rustls 0.23.28", + "rustls 0.23.31", "rustls-platform-verifier", "serde", "serde_json", @@ -3592,9 +3628,9 @@ dependencies = [ [[package]] name = "keyring" -version = "3.6.2" +version = "3.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1961983669d57bdfe6c0f3ef8e4c229b5ef751afcc7d87e4271d2f71f6ccfa8b" +checksum = "eebcc3aff044e5944a8fbaf69eb277d11986064cba30c468730e8b9909fb551c" dependencies = [ "byteorder", "dbus-secret-service", @@ -3602,17 +3638,18 @@ dependencies = [ "secret-service", "security-framework 2.11.1", "security-framework 3.2.0", - "windows-sys 0.59.0", + "windows-sys 0.60.2", "zbus", + "zeroize", ] [[package]] name = "known-folders" -version = "1.2.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7d9a1740cc8b46e259a0eb787d79d855e79ff10b9855a5eba58868d5da7927c" +checksum = "c644f4623d1c55eb60a9dac35e0858a59f982fb87db6ce34c872372b0a5b728f" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -3672,7 +3709,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.53.2", + "windows-targets 0.53.3", ] [[package]] @@ -3693,9 +3730,9 @@ dependencies = [ [[package]] name = "libredox" -version = "0.1.4" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1580801010e535496706ba011c15f8532df6b42297d2e471fec38ceadd8c0638" +checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" dependencies = [ "bitflags", "libc", @@ -3834,9 +3871,9 @@ dependencies = [ [[package]] name = "memmap2" -version = "0.9.5" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" +checksum = "483758ad303d734cec05e5c12b41d7e93e6a6390c5e9dae6bdeb7c1259012d28" dependencies = [ "libc", ] @@ -3979,18 +4016,18 @@ checksum = "b52c1b33ff98142aecea13138bd399b68aa7ab5d9546c300988c345004001eea" [[package]] name = "munge" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cce144fab80fbb74ec5b89d1ca9d41ddf6b644ab7e986f7d3ed0aab31625cb1" +checksum = "d7feb0b48aa0a25f9fe0899482c6e1379ee7a11b24a53073eacdecb9adb6dc60" dependencies = [ "munge_macro", ] [[package]] name = "munge_macro" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "574af9cd5b9971cbfdf535d6a8d533778481b241c447826d976101e0149392a1" +checksum = "f2e3795a5d2da581a8b252fec6022eee01aea10161a4d1bf237d4cbe47f7e988" dependencies = [ "proc-macro2", "quote", @@ -4870,7 +4907,7 @@ dependencies = [ "pixi_spec_containers", "pixi_test_utils", "pixi_utils", - "rand 0.9.1", + "rand 0.9.2", "rattler", "rattler_conda_types", "rattler_digest", @@ -5258,7 +5295,7 @@ dependencies = [ "concurrent-queue", "hermit-abi", "pin-project-lite", - "rustix 1.0.7", + "rustix 1.0.8", "windows-sys 0.60.2", ] @@ -5312,9 +5349,9 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.35" +version = "0.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "061c1221631e079b26479d25bbf2275bfe5917ae8419cd7e34f13bfc2aa7539a" +checksum = "ff24dfcda44452b9816fff4cd4227e1bb73ff5a2f1bc1105aa92fb8565ce44d2" dependencies = [ "proc-macro2", "syn", @@ -5383,7 +5420,7 @@ dependencies = [ "bitflags", "lazy_static", "num-traits", - "rand 0.9.1", + "rand 0.9.2", "rand_chacha 0.9.0", "rand_xorshift", "regex-syntax 0.8.5", @@ -5566,8 +5603,8 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.23.28", - "socket2", + "rustls 0.23.31", + "socket2 0.5.10", "thiserror 2.0.12", "tokio", "tracing", @@ -5583,10 +5620,10 @@ dependencies = [ "bytes", "getrandom 0.3.3", "lru-slab", - "rand 0.9.1", + "rand 0.9.2", "ring", "rustc-hash", - "rustls 0.23.28", + "rustls 0.23.31", "rustls-pki-types", "slab", "thiserror 2.0.12", @@ -5604,7 +5641,7 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2", + "socket2 0.5.10", "tracing", "windows-sys 0.59.0", ] @@ -5658,9 +5695,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", @@ -5731,7 +5768,7 @@ dependencies = [ "indicatif", "itertools 0.14.0", "memchr", - "memmap2 0.9.5", + "memmap2 0.9.7", "once_cell", "parking_lot", "path_resolver", @@ -6025,7 +6062,7 @@ dependencies = [ "itertools 0.14.0", "json-patch", "libc", - "memmap2 0.9.5", + "memmap2 0.9.7", "parking_lot", "pin-project-lite", "rattler_cache", @@ -6135,18 +6172,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.13" +version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" +checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" dependencies = [ "bitflags", ] [[package]] name = "redox_users" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" +checksum = "78eaea1f52c56d57821be178b2d47e09ff26481a6042e8e042fcb0ced068b470" dependencies = [ "getrandom 0.2.16", "libredox", @@ -6181,7 +6218,7 @@ checksum = "78c81d000a2c524133cc00d2f92f019d399e57906c3b7119271a2495354fe895" dependencies = [ "cfg-if", "libc", - "rustix 1.0.7", + "rustix 1.0.8", "windows 0.61.3", ] @@ -6277,7 +6314,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.28", + "rustls 0.23.31", "rustls-native-certs 0.8.1", "rustls-pki-types", "serde", @@ -6386,9 +6423,9 @@ dependencies = [ [[package]] name = "rkyv" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e147371c75553e1e2fcdb483944a8540b8438c31426279553b9a8182a9b7b65" +checksum = "19f5c3e5da784cd8c69d32cdc84673f3204536ca56e1fa01be31a74b92c932ac" dependencies = [ "bytecheck", "bytes", @@ -6406,9 +6443,9 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "246b40ac189af6c675d124b802e8ef6d5246c53e17367ce9501f8f66a81abb7a" +checksum = "4270433626cffc9c4c1d3707dd681f2a2718d3d7b09ad754bec137acecda8d22" dependencies = [ "proc-macro2", "quote", @@ -6488,9 +6525,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" [[package]] name = "rustc-hash" @@ -6522,15 +6559,15 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys 0.9.4", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -6547,9 +6584,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.28" +version = "0.23.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7160e3e10bf4535308537f3c4e1641468cd0e485175d6163087c0393c7d46643" +checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" dependencies = [ "log", "once_cell", @@ -6623,7 +6660,7 @@ dependencies = [ "jni", "log", "once_cell", - "rustls 0.23.28", + "rustls 0.23.31", "rustls-native-certs 0.8.1", "rustls-platform-verifier-android", "rustls-webpki 0.103.4", @@ -6943,9 +6980,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.141" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3" dependencies = [ "indexmap 2.10.0", "itoa", @@ -7012,7 +7049,7 @@ version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de90945e6565ce0d9a25098082ed4ee4002e047cb59892c318d66821e14bb30f" dependencies = [ - "darling", + "darling 0.20.11", "proc-macro2", "quote", "syn", @@ -7240,6 +7277,16 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "socket2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + [[package]] name = "soketto" version = "0.8.1" @@ -7257,9 +7304,9 @@ dependencies = [ [[package]] name = "spdx" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58b69356da67e2fc1f542c71ea7e654a361a79c938e4424392ecf4fa065d2193" +checksum = "c3e17e880bafaeb362a7b751ec46bdc5b61445a188f80e0606e68167cd540fa3" dependencies = [ "smallvec", ] @@ -7311,23 +7358,22 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" -version = "0.27.1" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" -version = "0.27.1" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" dependencies = [ "heck", "proc-macro2", "quote", - "rustversion", "syn", ] @@ -7407,9 +7453,9 @@ dependencies = [ [[package]] name = "sys_traits" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc4707edf3196e8037ee45018d1bb1bfb233b0e4fc440fa3d3f25bc69bfdaf26" +checksum = "4f74a2c95f72e36fa6bd04a40d15623a9904bab1cc2fa6c6135b09d774a65088" dependencies = [ "junction", "libc", @@ -7528,7 +7574,7 @@ dependencies = [ "fastrand", "getrandom 0.3.3", "once_cell", - "rustix 1.0.7", + "rustix 1.0.8", "windows-sys 0.59.0", ] @@ -7538,7 +7584,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45c6481c4829e4cc63825e62c49186a34538b7b2750b73b266581ffb612fb5ed" dependencies = [ - "rustix 1.0.7", + "rustix 1.0.8", "windows-sys 0.59.0", ] @@ -7691,9 +7737,9 @@ source = "git+https://github.com/astral-sh/tl.git?rev=6e25b2ee2513d75385101a8ff9 [[package]] name = "tokio" -version = "1.46.1" +version = "1.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17" +checksum = "43864ed400b6043a4757a25c7a64a8efde741aed79a056a2fb348a406701bb35" dependencies = [ "backtrace", "bytes", @@ -7703,10 +7749,10 @@ dependencies = [ "pin-project-lite", "signal-hook-registry", "slab", - "socket2", + "socket2 0.6.0", "tokio-macros", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -7746,7 +7792,7 @@ version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" dependencies = [ - "rustls 0.23.28", + "rustls 0.23.31", "tokio", ] @@ -7848,7 +7894,7 @@ dependencies = [ "percent-encoding", "pin-project", "prost", - "socket2", + "socket2 0.5.10", "tokio", "tokio-stream", "tower 0.4.13", @@ -8144,7 +8190,7 @@ checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" dependencies = [ "getrandom 0.3.3", "js-sys", - "rand 0.9.1", + "rand 0.9.2", "wasm-bindgen", ] @@ -8574,7 +8620,7 @@ dependencies = [ "junction", "path-slash", "percent-encoding", - "rustix 1.0.7", + "rustix 1.0.8", "same-file", "schemars 1.0.4", "serde", @@ -9424,23 +9470,23 @@ version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75c7f0ef91146ebfb530314f5f1d24528d7f0767efbfd31dce919275413e393e" dependencies = [ - "webpki-root-certs 1.0.1", + "webpki-root-certs 1.0.2", ] [[package]] name = "webpki-root-certs" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86138b15b2b7d561bc4469e77027b8dd005a43dc502e9031d1f5afc8ce1f280e" +checksum = "4e4ffd8df1c57e87c325000a3d6ef93db75279dc3a231125aac571650f22b12a" dependencies = [ "rustls-pki-types", ] [[package]] name = "webpki-roots" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8782dd5a41a24eed3a4f40b606249b3e236ca61adf1f25ea4d45c73de122b502" +checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2" dependencies = [ "rustls-pki-types", ] @@ -9453,7 +9499,7 @@ checksum = "d3fabb953106c3c8eea8306e4393700d7657561cb43122571b172bbfb7c7ba1d" dependencies = [ "env_home", "regex", - "rustix 1.0.7", + "rustix 1.0.8", "winsafe", ] @@ -9504,7 +9550,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f919aee0a93304be7f62e8e5027811bbba96bcb1de84d6618be56e43f8a32a1" dependencies = [ "windows-core 0.59.0", - "windows-targets 0.53.2", + "windows-targets 0.53.3", ] [[package]] @@ -9539,7 +9585,7 @@ dependencies = [ "windows-interface", "windows-result", "windows-strings 0.3.1", - "windows-targets 0.53.2", + "windows-targets 0.53.3", ] [[package]] @@ -9695,7 +9741,7 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.2", + "windows-targets 0.53.3", ] [[package]] @@ -9746,10 +9792,11 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.2" +version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ + "windows-link", "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", @@ -9951,9 +9998,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winnow" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" +checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95" dependencies = [ "memchr", ] @@ -10004,7 +10051,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af3a19837351dc82ba89f8a125e22a3c475f05aba604acc023d62b2739ae2909" dependencies = [ "libc", - "rustix 1.0.7", + "rustix 1.0.8", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 177a3e2f66..da69ecb130 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ crossbeam-channel = "0.5.14" csv = "1.3.1" ctrlc = "3.4.5" dashmap = "6.1.0" -deno_task_shell = "0.24.0" +deno_task_shell = "0.26.0" derive_more = "2.0.1" dialoguer = "0.11.0" digest = "0.10" diff --git a/src/cli/run.rs b/src/cli/run.rs index bc32c32dd0..d86dc6969f 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -10,6 +10,7 @@ use std::{ }; use clap::Parser; +use deno_task_shell::{KillSignal, SignalKind}; use dialoguer::theme::ColorfulTheme; use fancy_display::FancyDisplay; use itertools::Itertools; @@ -33,6 +34,8 @@ use crate::{ workspace::{Environment, errors::UnsupportedPlatformError}, }; +static SIGNAL_NOTIFY: tokio::sync::Notify = tokio::sync::Notify::const_new(); + /// Runs task in the pixi environment. /// /// This command is used to run tasks in the pixi environment. @@ -137,10 +140,17 @@ pub async fn execute(args: Args) -> miette::Result<()> { let ctrlc_should_exit_process = Arc::new(AtomicBool::new(true)); let ctrlc_should_exit_process_clone = Arc::clone(&ctrlc_should_exit_process); + // Store the signal that was received for forwarding + let received_signal = Arc::new(std::sync::atomic::AtomicI32::new(0)); + let received_signal_clone = Arc::clone(&received_signal); + ctrlc::set_handler(move || { reset_cursor(); if ctrlc_should_exit_process_clone.load(Ordering::Relaxed) { exit_process_on_sigint(); + } else { + received_signal_clone.store(SignalKind::SIGINT.into(), Ordering::Relaxed); + SIGNAL_NOTIFY.notify_waiters(); } }) .into_diagnostic()?; @@ -289,7 +299,7 @@ pub async fn execute(args: Args) -> miette::Result<()> { // Execute the task itself within the command environment. If one of the tasks // failed with a non-zero exit code, we exit this parent process with // the same code. - match execute_task(&executable_task, &task_env).await { + match execute_task(&executable_task, &task_env, received_signal.clone()).await { Ok(_) => { task_idx += 1; } @@ -377,20 +387,43 @@ enum TaskExecutionError { async fn execute_task( task: &ExecutableTask<'_>, command_env: &HashMap, + received_signal: Arc, ) -> Result<(), TaskExecutionError> { let Some(script) = task.as_deno_script()? else { return Ok(()); }; let cwd = task.working_directory()?; + let kill_signal = KillSignal::default(); - let status_code = deno_task_shell::execute( + let execute_future = deno_task_shell::execute( script, command_env.clone(), cwd, Default::default(), - Default::default(), - ) - .await; + kill_signal.clone(), + ); + + // Pin the future so we can reference it in both select arms + let mut execute_future = std::pin::pin!(execute_future); + + // Create a notifier that triggers when signal is received + let signal_notifier = async { + SIGNAL_NOTIFY.notified().await; + let signal_code = received_signal.load(Ordering::Relaxed); + if signal_code != 0 { + let signal_kind = SignalKind::from(signal_code); + tracing::debug!("Abort signal detected during task execution, forwarding {:?}...", signal_kind); + kill_signal.send(signal_kind); + } + }; + + let status_code = tokio::select! { + code = &mut execute_future => code, + _ = signal_notifier => { + // Wait for the task to complete after signal forwarding + execute_future.await + }, + }; if status_code != 0 { return Err(TaskExecutionError::NonZeroExitCode(status_code)); From fd8ed34922ebcac7f90a067bf5cbf608da3b168e Mon Sep 17 00:00:00 2001 From: Wolf Vollprecht Date: Thu, 31 Jul 2025 14:31:56 +0200 Subject: [PATCH 02/10] add a ctrl c test --- pixi.toml | 2 +- src/cli/run.rs | 5 ++- tests/data/run_signals/pixi.toml | 12 ++++++ tests/data/run_signals/test.py | 23 +++++++++++ tests/integration_python/test_run_cli.py | 51 ++++++++++++++++++++++++ 5 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 tests/data/run_signals/pixi.toml create mode 100644 tests/data/run_signals/test.py diff --git a/pixi.toml b/pixi.toml index ff9e487d02..e929740409 100644 --- a/pixi.toml +++ b/pixi.toml @@ -70,7 +70,7 @@ test-integration-extra-slow-ci = "pytest --numprocesses=auto --durations=0 --tim test-integration-fast = { cmd = "pytest --pixi-build=debug --numprocesses=auto --durations=0 --timeout=100 -m 'not slow and not extra_slow' tests/integration_python", depends-on = [ "build-debug", ] } -test-integration-slow = { cmd = "pytest --numprocesses=auto --durations=0 --timeout=100 -m 'not extra_slow' tests/integration_python", depends-on = [ +test-integration-slow = { cmd = "pytest -s --numprocesses=1 --durations=0 --timeout=100 -m 'not extra_slow' tests/integration_python", depends-on = [ "build-release", ] } # pass the file to run as an argument to the task diff --git a/src/cli/run.rs b/src/cli/run.rs index d86dc6969f..168f14dedb 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -412,7 +412,10 @@ async fn execute_task( let signal_code = received_signal.load(Ordering::Relaxed); if signal_code != 0 { let signal_kind = SignalKind::from(signal_code); - tracing::debug!("Abort signal detected during task execution, forwarding {:?}...", signal_kind); + tracing::debug!( + "Abort signal detected during task execution, forwarding {:?}...", + signal_kind + ); kill_signal.send(signal_kind); } }; diff --git a/tests/data/run_signals/pixi.toml b/tests/data/run_signals/pixi.toml new file mode 100644 index 0000000000..c70e090fac --- /dev/null +++ b/tests/data/run_signals/pixi.toml @@ -0,0 +1,12 @@ +[workspace] +authors = ["Wolf Vollprecht "] +channels = ["conda-forge"] +name = "ctrlc" +platforms = ["osx-arm64"] +version = "0.1.0" + +[tasks] +start = "python ./test.py" + +[dependencies] +python = "3.12.*" diff --git a/tests/data/run_signals/test.py b/tests/data/run_signals/test.py new file mode 100644 index 0000000000..754248488d --- /dev/null +++ b/tests/data/run_signals/test.py @@ -0,0 +1,23 @@ +# type: ignore +import signal +import time + +file = open("./output.txt", "w") + + +def signal_handler(signum, frame): + file.write(f"Signal handler called with signal {signum}\n") + if signum == signal.SIGINT: + file.write("SIGINT received, exiting gracefully...\n") + exit(12) + elif signum == signal.SIGHUP: + file.write("HUP HUP HUP\n") + return + + +signal.signal(signal.SIGINT, signal_handler) +signal.signal(signal.SIGHUP, signal_handler) + +while True: + file.write("Running...\n") + time.sleep(1) diff --git a/tests/integration_python/test_run_cli.py b/tests/integration_python/test_run_cli.py index 9a2e14cfe3..f9cd3f23d1 100644 --- a/tests/integration_python/test_run_cli.py +++ b/tests/integration_python/test_run_cli.py @@ -1,4 +1,8 @@ import json +import shutil +import signal +import time +import subprocess import tomli_w from pathlib import Path @@ -1355,3 +1359,50 @@ def test_task_caching_with_multiple_inputs_args(pixi: Path, tmp_pixi_workspace: "cache hit", ], ) + + +def test_signal_forwarding(pixi: Path, tmp_pixi_workspace: Path) -> None: + """Test that signals are forwarded correctly to the task. + We copy the data from the ../data/run_signals folder to the tmp workspace + """ + + # copy the folder from ../data/run_signals to the tmp workspace + data_path = Path(__file__).parent.parent.joinpath("data", "run_signals") + tmp_data_path = tmp_pixi_workspace.joinpath("run_signals") + + shutil.copytree(data_path, tmp_data_path) + + # Use the manifest from the copied run_signals directory + manifest = tmp_data_path.joinpath("pixi.toml") + + # run the `start` task in the background and send some signals to it + # with `pixi run start` + process = subprocess.Popen( + [pixi, "run", "--no-progress", "--manifest-path", manifest, "start"], cwd=tmp_data_path + ) + + time.sleep(5) # wait for the process to start + + # send a SIGINT to the process + # process.send_signal(signal.SIGHUP) + # process.send_signal(signal.SIGHUP) + process.send_signal(signal.SIGINT) + + # check exit code + exit_code = process.wait(timeout=5) + + assert exit_code == 12, f"Process exited with code {exit_code}" + + output_file = tmp_data_path.joinpath("output.txt") + print(f"Output file exists: {output_file.exists()}") + + if output_file.exists(): + # check if we can read "SIGINT received, exiting gracefully" + with open(output_file, "r") as f: + output = f.read() + # assert "HUPHUPHUP" in output, "HUP signals were not handled correctly" + assert "SIGINT received, exiting gracefully" in output, ( + "SIGINT signal was not handled correctly" + ) + else: + raise AssertionError("Output file was not created") From 0735dd654e0cf48cdbbc55bda0cd11402887f93e Mon Sep 17 00:00:00 2001 From: Bas Zalmstra <4995967+baszalmstra@users.noreply.github.com> Date: Thu, 31 Jul 2025 14:41:12 +0200 Subject: [PATCH 03/10] signal handling --- src/cli/run.rs | 182 +++++++++++++++++++++++++++-------------------- src/lib.rs | 1 + src/signals.rs | 187 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 294 insertions(+), 76 deletions(-) create mode 100644 src/signals.rs diff --git a/src/cli/run.rs b/src/cli/run.rs index 168f14dedb..5d5fc78c83 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -3,14 +3,11 @@ use std::{ convert::identity, ffi::OsString, string::String, - sync::{ - Arc, - atomic::{AtomicBool, Ordering}, - }, + sync::atomic::Ordering, }; use clap::Parser; -use deno_task_shell::{KillSignal, SignalKind}; +use deno_task_shell::KillSignal; use dialoguer::theme::ColorfulTheme; use fancy_display::FancyDisplay; use itertools::Itertools; @@ -19,6 +16,7 @@ use pixi_config::{ConfigCli, ConfigCliActivation}; use pixi_manifest::{FeaturesExt, TaskName}; use rattler_conda_types::Platform; use thiserror::Error; +use tokio_util::sync::CancellationToken; use tracing::Level; use super::cli_config::LockFileUpdateConfig; @@ -34,8 +32,6 @@ use crate::{ workspace::{Environment, errors::UnsupportedPlatformError}, }; -static SIGNAL_NOTIFY: tokio::sync::Notify = tokio::sync::Notify::const_new(); - /// Runs task in the pixi environment. /// /// This command is used to run tasks in the pixi environment. @@ -137,24 +133,6 @@ pub async fn execute(args: Args) -> miette::Result<()> { }) .await?; - let ctrlc_should_exit_process = Arc::new(AtomicBool::new(true)); - let ctrlc_should_exit_process_clone = Arc::clone(&ctrlc_should_exit_process); - - // Store the signal that was received for forwarding - let received_signal = Arc::new(std::sync::atomic::AtomicI32::new(0)); - let received_signal_clone = Arc::clone(&received_signal); - - ctrlc::set_handler(move || { - reset_cursor(); - if ctrlc_should_exit_process_clone.load(Ordering::Relaxed) { - exit_process_on_sigint(); - } else { - received_signal_clone.store(SignalKind::SIGINT.into(), Ordering::Relaxed); - SIGNAL_NOTIFY.notify_waiters(); - } - }) - .into_diagnostic()?; - // Construct a task graph from the input arguments let search_environment = SearchEnvironments::from_opt_env( &workspace, @@ -179,10 +157,18 @@ pub async fn execute(args: Args) -> miette::Result<()> { ); } + // Spawn a task that listens for ctrl+c and resets the cursor. + tokio::spawn(async { + if let Ok(_) = tokio::signal::ctrl_c().await { + reset_cursor(); + } + }); + // Traverse the task graph in topological order and execute each individual // task. let mut task_idx = 0; let mut task_envs = HashMap::new(); + let signal = KillSignal::default(); for task_id in task_graph.topological_order() { let executable_task = ExecutableTask::from_task_graph(&task_graph, task_id); @@ -289,8 +275,6 @@ pub async fn execute(args: Args) -> miette::Result<()> { } }; - ctrlc_should_exit_process.store(false, Ordering::Relaxed); - let task_env = task_env .iter() .map(|(k, v)| (OsString::from(k), OsString::from(v))) @@ -299,7 +283,7 @@ pub async fn execute(args: Args) -> miette::Result<()> { // Execute the task itself within the command environment. If one of the tasks // failed with a non-zero exit code, we exit this parent process with // the same code. - match execute_task(&executable_task, &task_env, received_signal.clone()).await { + match execute_task(&executable_task, &task_env, signal.clone()).await { Ok(_) => { task_idx += 1; } @@ -312,9 +296,6 @@ pub async fn execute(args: Args) -> miette::Result<()> { Err(err) => return Err(err.into()), } - // Handle CTRL-C ourselves again - ctrlc_should_exit_process.store(true, Ordering::Relaxed); - // Update the task cache with the new hash executable_task .save_cache(lock_file.as_lock_file(), task_cache) @@ -387,14 +368,12 @@ enum TaskExecutionError { async fn execute_task( task: &ExecutableTask<'_>, command_env: &HashMap, - received_signal: Arc, + kill_signal: KillSignal, ) -> Result<(), TaskExecutionError> { let Some(script) = task.as_deno_script()? else { return Ok(()); }; let cwd = task.working_directory()?; - let kill_signal = KillSignal::default(); - let execute_future = deno_task_shell::execute( script, command_env.clone(), @@ -403,31 +382,8 @@ async fn execute_task( kill_signal.clone(), ); - // Pin the future so we can reference it in both select arms - let mut execute_future = std::pin::pin!(execute_future); - - // Create a notifier that triggers when signal is received - let signal_notifier = async { - SIGNAL_NOTIFY.notified().await; - let signal_code = received_signal.load(Ordering::Relaxed); - if signal_code != 0 { - let signal_kind = SignalKind::from(signal_code); - tracing::debug!( - "Abort signal detected during task execution, forwarding {:?}...", - signal_kind - ); - kill_signal.send(signal_kind); - } - }; - - let status_code = tokio::select! { - code = &mut execute_future => code, - _ = signal_notifier => { - // Wait for the task to complete after signal forwarding - execute_future.await - }, - }; - + // Execute the process and forward signals. + let status_code = run_future_forwarding_signals(kill_signal, execute_future).await; if status_code != 0 { return Err(TaskExecutionError::NonZeroExitCode(status_code)); } @@ -467,25 +423,99 @@ fn disambiguate_task_interactive<'p>( .map(|idx| problem.environments[idx].clone()) } -/// `dialoguer` doesn't clean up your term if it's aborted via e.g. `SIGINT` or -/// other exceptions: https://github.com/console-rs/dialoguer/issues/188. +// /// `dialoguer` doesn't clean up your term if it's aborted via e.g. `SIGINT` or +// /// other exceptions: https://github.com/console-rs/dialoguer/issues/188. +// /// +// /// `dialoguer`, as a library, doesn't want to mess with signal handlers, +// /// but we, as an application, are free to mess with signal handlers if we feel +// /// like it, since we own the process. +// /// This function was taken from https://github.com/dnjstrom/git-select-branch/blob/16c454624354040bc32d7943b9cb2e715a5dab92/src/main.rs#L119 +// fn reset_cursor() { +// let term = console::Term::stdout(); +// let _ = term.show_cursor(); +// } +// +// /// Exit the process with the appropriate exit code for a SIGINT. +// fn exit_process_on_sigint() { +// // https://learn.microsoft.com/en-us/cpp/c-runtime-library/signal-constants +// #[cfg(target_os = "windows")] +// std::process::exit(3); +// +// // POSIX compliant OSs: 128 + SIGINT (2) +// #[cfg(not(target_os = "windows"))] +// std::process::exit(130); +// } + +/// Runs a task future forwarding any signals received to the process. /// -/// `dialoguer`, as a library, doesn't want to mess with signal handlers, -/// but we, as an application, are free to mess with signal handlers if we feel -/// like it, since we own the process. -/// This function was taken from https://github.com/dnjstrom/git-select-branch/blob/16c454624354040bc32d7943b9cb2e715a5dab92/src/main.rs#L119 -fn reset_cursor() { - let term = console::Term::stdout(); - let _ = term.show_cursor(); +/// Signal listeners and ctrl+c listening will be setup. +pub async fn run_future_forwarding_signals( + kill_signal: KillSignal, + future: impl std::future::Future, +) -> TOutput { + fn spawn_future_with_cancellation( + future: impl std::future::Future + 'static, + token: CancellationToken, + ) { + tokio::task::spawn_local(async move { + tokio::select! { + _ = future => {} + _ = token.cancelled() => {} + } + }); + } + + let token = CancellationToken::new(); + let _token_drop_guard = token.clone().drop_guard(); + let _drop_guard = kill_signal.clone().drop_guard(); + + spawn_future_with_cancellation(listen_ctrl_c(kill_signal.clone()), token.clone()); + #[cfg(unix)] + spawn_future_with_cancellation(listen_and_forward_all_signals(kill_signal), token); + + let local_set = tokio::task::LocalSet::new(); + local_set.run_until(future).await } -/// Exit the process with the appropriate exit code for a SIGINT. -fn exit_process_on_sigint() { - // https://learn.microsoft.com/en-us/cpp/c-runtime-library/signal-constants - #[cfg(target_os = "windows")] - std::process::exit(3); +async fn listen_ctrl_c(kill_signal: KillSignal) { + while let Ok(()) = tokio::signal::ctrl_c().await { + // On windows, ctrl+c is sent to the process group, so the signal would + // have already been sent to the child process. We still want to listen + // for ctrl+c here to keep the process alive when receiving it, but no + // need to forward the signal because it's already been sent. + if !cfg!(windows) { + kill_signal.send(deno_task_shell::SignalKind::SIGINT) + } + } +} - // POSIX compliant OSs: 128 + SIGINT (2) - #[cfg(not(target_os = "windows"))] - std::process::exit(130); +#[cfg(unix)] +async fn listen_and_forward_all_signals(kill_signal: KillSignal) { + use futures::FutureExt; + use tokio::signal::unix::{SignalKind, signal}; + + use crate::signals::SIGNALS; + + // listen and forward every signal we support + let mut futures = Vec::with_capacity(SIGNALS.len()); + for signo in SIGNALS.iter().copied() { + if signo == libc::SIGKILL || signo == libc::SIGSTOP { + continue; // skip, can't listen to these + } + + let kill_signal = kill_signal.clone(); + futures.push( + async move { + let Ok(mut stream) = tokio::signal::unix::signal(signo) else { + return; + }; + let signal_kind: tokio::signal::unix::SignalKind = signo.into(); + while let Some(()) = stream.recv().await { + kill_signal.send(signal_kind); + } + } + .boxed_local(), + ) + } + futures::future::join_all(futures).await; } diff --git a/src/lib.rs b/src/lib.rs index f8c7d545cc..cad84fc472 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,6 +16,7 @@ pub mod workspace; mod reporters; mod rlimit; +mod signals; mod uv_reporter; pub mod variants; diff --git a/src/signals.rs b/src/signals.rs new file mode 100644 index 0000000000..dca0fc4640 --- /dev/null +++ b/src/signals.rs @@ -0,0 +1,187 @@ +//! For each operating system, list the signals that can be caught. + +#[cfg(target_os = "freebsd")] +pub const SIGNALS: &'static [libc::c_int] = &[ + libc::SIGHUP, + libc::SIGINT, + libc::SIGQUIT, + libc::SIGILL, + libc::SIGTRAP, + libc::SIGABRT, + libc::SIGEMT, + libc::SIGFPE, + libc::SIGKILL, + libc::SIGBUS, + libc::SIGSEGV, + libc::SIGSYS, + libc::SIGPIPE, + libc::SIGALRM, + libc::SIGTERM, + libc::SIGURG, + libc::SIGSTOP, + libc::SIGTSTP, + libc::SIGCONT, + libc::SIGCHLD, + libc::SIGTTIN, + libc::SIGTTOU, + libc::SIGIO, + libc::SIGXCPU, + libc::SIGXFSZ, + libc::SIGVTALRM, + libc::SIGPROF, + libc::SIGWINCH, + libc::SIGINFO, + libc::SIGUSR1, + libc::SIGUSR2, + libc::SIGTHR, + libc::SIGLIBRT, +]; + +#[cfg(target_os = "openbsd")] +pub const SIGNALS: &'static [libc::c_int] = &[ + libc::SIGHUP, + libc::SIGINT, + libc::SIGQUIT, + libc::SIGILL, + libc::SIGTRAP, + libc::SIGABRT, + libc::SIGEMT, + libc::SIGKILL, + libc::SIGBUS, + libc::SIGSEGV, + libc::SIGSYS, + libc::SIGPIPE, + libc::SIGALRM, + libc::SIGTERM, + libc::SIGURG, + libc::SIGSTOP, + libc::SIGTSTP, + libc::SIGCONT, + libc::SIGCHLD, + libc::SIGTTIN, + libc::SIGTTOU, + libc::SIGIO, + libc::SIGXCPU, + libc::SIGXFSZ, + libc::SIGVTALRM, + libc::SIGPROF, + libc::SIGWINCH, + libc::SIGINFO, + libc::SIGUSR1, + libc::SIGUSR2, + libc::SIGTHR, +]; + +#[cfg(any(target_os = "android", target_os = "linux"))] +pub const SIGNALS: &'static [libc::c_int] = &[ + libc::SIGHUP, + libc::SIGINT, + libc::SIGQUIT, + libc::SIGILL, + libc::SIGTRAP, + libc::SIGABRT, + libc::SIGBUS, + libc::SIGFPE, + libc::SIGKILL, + libc::SIGUSR1, + libc::SIGSEGV, + libc::SIGUSR2, + libc::SIGPIPE, + libc::SIGALRM, + libc::SIGTERM, + libc::SIGSTKFLT, + libc::SIGCHLD, + libc::SIGCONT, + libc::SIGSTOP, + libc::SIGTSTP, + libc::SIGTTIN, + libc::SIGTTOU, + libc::SIGURG, + libc::SIGXCPU, + libc::SIGXFSZ, + libc::SIGVTALRM, + libc::SIGPROF, + libc::SIGWINCH, + libc::SIGIO, + libc::SIGPWR, + libc::SIGSYS, +]; + +#[cfg(target_os = "macos")] +pub const SIGNALS: &'static [libc::c_int] = &[ + libc::SIGHUP, + libc::SIGINT, + libc::SIGQUIT, + libc::SIGILL, + libc::SIGTRAP, + libc::SIGABRT, + libc::SIGEMT, + libc::SIGFPE, + libc::SIGKILL, + libc::SIGBUS, + libc::SIGSEGV, + libc::SIGSYS, + libc::SIGPIPE, + libc::SIGALRM, + libc::SIGTERM, + libc::SIGURG, + libc::SIGSTOP, + libc::SIGTSTP, + libc::SIGCONT, + libc::SIGCHLD, + libc::SIGTTIN, + libc::SIGTTOU, + libc::SIGIO, + libc::SIGXCPU, + libc::SIGXFSZ, + libc::SIGVTALRM, + libc::SIGPROF, + libc::SIGWINCH, + libc::SIGINFO, + libc::SIGUSR1, + libc::SIGUSR2, +]; + +#[cfg(any(target_os = "solaris", target_os = "illumos"))] +pub const SIGNALS: &'static [libc::c_int] = &[ + libc::SIGHUP, + libc::SIGINT, + libc::SIGQUIT, + libc::SIGILL, + libc::SIGTRAP, + libc::SIGABRT, + libc::SIGEMT, + libc::SIGFPE, + libc::SIGKILL, + libc::SIGBUS, + libc::SIGSEGV, + libc::SIGSYS, + libc::SIGPIPE, + libc::SIGALRM, + libc::SIGTERM, + libc::SIGUSR1, + libc::SIGUSR2, + libc::SIGCHLD, + libc::SIGPWR, + libc::SIGWINCH, + libc::SIGURG, + libc::SIGPOLL, + libc::SIGSTOP, + libc::SIGTSTP, + libc::SIGCONT, + libc::SIGTTIN, + libc::SIGTTOU, + libc::SIGVTALRM, + libc::SIGPROF, + libc::SIGXCPU, + libc::SIGXFSZ, + libc::SIGWAITING, + libc::SIGLWP, + libc::SIGFREEZE, + libc::SIGTHAW, + libc::SIGCANCEL, + libc::SIGLOST, + libc::SIGXRES, + libc::SIGJVM1, + libc::SIGJVM2, +]; \ No newline at end of file From c36aacc8c0342b6ebde522b77cee79e0cc2ac28e Mon Sep 17 00:00:00 2001 From: Bas Zalmstra <4995967+baszalmstra@users.noreply.github.com> Date: Thu, 31 Jul 2025 14:41:48 +0200 Subject: [PATCH 04/10] fix line endings --- src/signals.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/signals.rs b/src/signals.rs index dca0fc4640..9dad7b3da4 100644 --- a/src/signals.rs +++ b/src/signals.rs @@ -184,4 +184,4 @@ pub const SIGNALS: &'static [libc::c_int] = &[ libc::SIGXRES, libc::SIGJVM1, libc::SIGJVM2, -]; \ No newline at end of file +]; From 36533ebd442a1fdc83e1aa87b9a6e5a76ee8f2de Mon Sep 17 00:00:00 2001 From: Bas Zalmstra <4995967+baszalmstra@users.noreply.github.com> Date: Thu, 31 Jul 2025 14:45:04 +0200 Subject: [PATCH 05/10] fix merge --- src/cli/run.rs | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/cli/run.rs b/src/cli/run.rs index 5d5fc78c83..e9a442bf73 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -3,7 +3,6 @@ use std::{ convert::identity, ffi::OsString, string::String, - sync::atomic::Ordering, }; use clap::Parser; @@ -423,18 +422,18 @@ fn disambiguate_task_interactive<'p>( .map(|idx| problem.environments[idx].clone()) } -// /// `dialoguer` doesn't clean up your term if it's aborted via e.g. `SIGINT` or -// /// other exceptions: https://github.com/console-rs/dialoguer/issues/188. -// /// -// /// `dialoguer`, as a library, doesn't want to mess with signal handlers, -// /// but we, as an application, are free to mess with signal handlers if we feel -// /// like it, since we own the process. -// /// This function was taken from https://github.com/dnjstrom/git-select-branch/blob/16c454624354040bc32d7943b9cb2e715a5dab92/src/main.rs#L119 -// fn reset_cursor() { -// let term = console::Term::stdout(); -// let _ = term.show_cursor(); -// } -// +/// `dialoguer` doesn't clean up your term if it's aborted via e.g. `SIGINT` or +/// other exceptions: https://github.com/console-rs/dialoguer/issues/188. +/// +/// `dialoguer`, as a library, doesn't want to mess with signal handlers, +/// but we, as an application, are free to mess with signal handlers if we feel +/// like it, since we own the process. +/// This function was taken from https://github.com/dnjstrom/git-select-branch/blob/16c454624354040bc32d7943b9cb2e715a5dab92/src/main.rs#L119 +fn reset_cursor() { + let term = console::Term::stdout(); + let _ = term.show_cursor(); +} + // /// Exit the process with the appropriate exit code for a SIGINT. // fn exit_process_on_sigint() { // // https://learn.microsoft.com/en-us/cpp/c-runtime-library/signal-constants From 381402255127eedfe92c68e2136b0d1f3a05fa3c Mon Sep 17 00:00:00 2001 From: Wolf Vollprecht Date: Thu, 31 Jul 2025 14:50:14 +0200 Subject: [PATCH 06/10] fix unix --- src/cli/run.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cli/run.rs b/src/cli/run.rs index e9a442bf73..ebebffcc96 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -468,11 +468,12 @@ pub async fn run_future_forwarding_signals( let _token_drop_guard = token.clone().drop_guard(); let _drop_guard = kill_signal.clone().drop_guard(); + let local_set = tokio::task::LocalSet::new(); + spawn_future_with_cancellation(listen_ctrl_c(kill_signal.clone()), token.clone()); #[cfg(unix)] spawn_future_with_cancellation(listen_and_forward_all_signals(kill_signal), token); - let local_set = tokio::task::LocalSet::new(); local_set.run_until(future).await } @@ -491,7 +492,6 @@ async fn listen_ctrl_c(kill_signal: KillSignal) { #[cfg(unix)] async fn listen_and_forward_all_signals(kill_signal: KillSignal) { use futures::FutureExt; - use tokio::signal::unix::{SignalKind, signal}; use crate::signals::SIGNALS; @@ -505,10 +505,10 @@ async fn listen_and_forward_all_signals(kill_signal: KillSignal) { let kill_signal = kill_signal.clone(); futures.push( async move { - let Ok(mut stream) = tokio::signal::unix::signal(signo) else { + let Ok(mut stream) = tokio::signal::unix::signal(signo.into()) else { return; }; - let signal_kind: tokio::signal::unix::SignalKind = signo.into(); + let signal_kind = signo.into(); while let Some(()) = stream.recv().await { kill_signal.send(signal_kind); } From 61e6ab6f5daf01d991f92772631b9daa2b1f6e55 Mon Sep 17 00:00:00 2001 From: Bas Zalmstra <4995967+baszalmstra@users.noreply.github.com> Date: Thu, 31 Jul 2025 14:53:17 +0200 Subject: [PATCH 07/10] local set in the right place --- src/cli/run.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/cli/run.rs b/src/cli/run.rs index ebebffcc96..0f16989565 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -467,14 +467,17 @@ pub async fn run_future_forwarding_signals( let token = CancellationToken::new(); let _token_drop_guard = token.clone().drop_guard(); let _drop_guard = kill_signal.clone().drop_guard(); - let local_set = tokio::task::LocalSet::new(); - spawn_future_with_cancellation(listen_ctrl_c(kill_signal.clone()), token.clone()); - #[cfg(unix)] - spawn_future_with_cancellation(listen_and_forward_all_signals(kill_signal), token); + local_set + .run_until(async move { + spawn_future_with_cancellation(listen_ctrl_c(kill_signal.clone()), token.clone()); + #[cfg(unix)] + spawn_future_with_cancellation(listen_and_forward_all_signals(kill_signal), token); - local_set.run_until(future).await + future.await + }) + .await } async fn listen_ctrl_c(kill_signal: KillSignal) { From dd96e84073bc262189c0411ed8861fb548739b60 Mon Sep 17 00:00:00 2001 From: Wolf Vollprecht Date: Thu, 31 Jul 2025 15:12:01 +0200 Subject: [PATCH 08/10] fix remaining issues --- src/cli/run.rs | 18 ++++++++++-------- src/signals.rs | 10 +++++----- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/cli/run.rs b/src/cli/run.rs index 0f16989565..bf907d1216 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -132,6 +132,13 @@ pub async fn execute(args: Args) -> miette::Result<()> { }) .await?; + // Spawn a task that listens for ctrl+c and resets the cursor. + tokio::spawn(async { + if tokio::signal::ctrl_c().await.is_ok() { + reset_cursor(); + } + }); + // Construct a task graph from the input arguments let search_environment = SearchEnvironments::from_opt_env( &workspace, @@ -156,18 +163,14 @@ pub async fn execute(args: Args) -> miette::Result<()> { ); } - // Spawn a task that listens for ctrl+c and resets the cursor. - tokio::spawn(async { - if let Ok(_) = tokio::signal::ctrl_c().await { - reset_cursor(); - } - }); - // Traverse the task graph in topological order and execute each individual // task. let mut task_idx = 0; let mut task_envs = HashMap::new(); let signal = KillSignal::default(); + // make sure that child processes are killed when pixi stops + let _drop_guard = signal.clone().drop_guard(); + for task_id in task_graph.topological_order() { let executable_task = ExecutableTask::from_task_graph(&task_graph, task_id); @@ -466,7 +469,6 @@ pub async fn run_future_forwarding_signals( let token = CancellationToken::new(); let _token_drop_guard = token.clone().drop_guard(); - let _drop_guard = kill_signal.clone().drop_guard(); let local_set = tokio::task::LocalSet::new(); local_set diff --git a/src/signals.rs b/src/signals.rs index 9dad7b3da4..9b4a1b1209 100644 --- a/src/signals.rs +++ b/src/signals.rs @@ -1,7 +1,7 @@ //! For each operating system, list the signals that can be caught. #[cfg(target_os = "freebsd")] -pub const SIGNALS: &'static [libc::c_int] = &[ +pub const SIGNALS: &[libc::c_int] = &[ libc::SIGHUP, libc::SIGINT, libc::SIGQUIT, @@ -38,7 +38,7 @@ pub const SIGNALS: &'static [libc::c_int] = &[ ]; #[cfg(target_os = "openbsd")] -pub const SIGNALS: &'static [libc::c_int] = &[ +pub const SIGNALS: &[libc::c_int] = &[ libc::SIGHUP, libc::SIGINT, libc::SIGQUIT, @@ -73,7 +73,7 @@ pub const SIGNALS: &'static [libc::c_int] = &[ ]; #[cfg(any(target_os = "android", target_os = "linux"))] -pub const SIGNALS: &'static [libc::c_int] = &[ +pub const SIGNALS: &[libc::c_int] = &[ libc::SIGHUP, libc::SIGINT, libc::SIGQUIT, @@ -108,7 +108,7 @@ pub const SIGNALS: &'static [libc::c_int] = &[ ]; #[cfg(target_os = "macos")] -pub const SIGNALS: &'static [libc::c_int] = &[ +pub const SIGNALS: &[libc::c_int] = &[ libc::SIGHUP, libc::SIGINT, libc::SIGQUIT, @@ -143,7 +143,7 @@ pub const SIGNALS: &'static [libc::c_int] = &[ ]; #[cfg(any(target_os = "solaris", target_os = "illumos"))] -pub const SIGNALS: &'static [libc::c_int] = &[ +pub const SIGNALS: &[libc::c_int] = &[ libc::SIGHUP, libc::SIGINT, libc::SIGQUIT, From b7955f7dfe2cb2d41fb73291a658a58f03ce6991 Mon Sep 17 00:00:00 2001 From: Wolf Vollprecht Date: Fri, 1 Aug 2025 11:31:44 +0200 Subject: [PATCH 09/10] try to fix test --- pixi.toml | 2 +- tests/data/run_signals/pixi.toml | 3 ++- tests/data/run_signals/test.py | 23 +++++++++++----------- tests/integration_python/test_run_cli.py | 25 ++++++++++++------------ 4 files changed, 27 insertions(+), 26 deletions(-) diff --git a/pixi.toml b/pixi.toml index e929740409..ff9e487d02 100644 --- a/pixi.toml +++ b/pixi.toml @@ -70,7 +70,7 @@ test-integration-extra-slow-ci = "pytest --numprocesses=auto --durations=0 --tim test-integration-fast = { cmd = "pytest --pixi-build=debug --numprocesses=auto --durations=0 --timeout=100 -m 'not slow and not extra_slow' tests/integration_python", depends-on = [ "build-debug", ] } -test-integration-slow = { cmd = "pytest -s --numprocesses=1 --durations=0 --timeout=100 -m 'not extra_slow' tests/integration_python", depends-on = [ +test-integration-slow = { cmd = "pytest --numprocesses=auto --durations=0 --timeout=100 -m 'not extra_slow' tests/integration_python", depends-on = [ "build-release", ] } # pass the file to run as an argument to the task diff --git a/tests/data/run_signals/pixi.toml b/tests/data/run_signals/pixi.toml index c70e090fac..d39fb26056 100644 --- a/tests/data/run_signals/pixi.toml +++ b/tests/data/run_signals/pixi.toml @@ -2,10 +2,11 @@ authors = ["Wolf Vollprecht "] channels = ["conda-forge"] name = "ctrlc" -platforms = ["osx-arm64"] +platforms = ["osx-arm64", "linux-64", "win-64"] version = "0.1.0" [tasks] +print = "cat ./test.py" start = "python ./test.py" [dependencies] diff --git a/tests/data/run_signals/test.py b/tests/data/run_signals/test.py index 754248488d..5d90bc6e43 100644 --- a/tests/data/run_signals/test.py +++ b/tests/data/run_signals/test.py @@ -1,23 +1,22 @@ # type: ignore +import sys import signal import time +from pathlib import Path -file = open("./output.txt", "w") - +output_file = Path("output.txt") +if output_file.exists(): + output_file.unlink() def signal_handler(signum, frame): - file.write(f"Signal handler called with signal {signum}\n") + output_file.write_text(f"Signal handler called with signal {signum}\n") if signum == signal.SIGINT: - file.write("SIGINT received, exiting gracefully...\n") - exit(12) - elif signum == signal.SIGHUP: - file.write("HUP HUP HUP\n") - return - + print("SIGINT received, exiting gracefully...") + output_file.write_text("SIGINT received, exiting gracefully...\n") + sys.exit(12) signal.signal(signal.SIGINT, signal_handler) -signal.signal(signal.SIGHUP, signal_handler) while True: - file.write("Running...\n") - time.sleep(1) + print("Running...\n") + time.sleep(1) \ No newline at end of file diff --git a/tests/integration_python/test_run_cli.py b/tests/integration_python/test_run_cli.py index f9cd3f23d1..93bf94d049 100644 --- a/tests/integration_python/test_run_cli.py +++ b/tests/integration_python/test_run_cli.py @@ -1,9 +1,11 @@ import json import shutil +import sys import signal import time import subprocess import tomli_w +import pytest from pathlib import Path from .common import ( @@ -1361,10 +1363,12 @@ def test_task_caching_with_multiple_inputs_args(pixi: Path, tmp_pixi_workspace: ) +@pytest.mark.skipif( + sys.platform == "win32", + reason="Signal handling is different on Windows", +) def test_signal_forwarding(pixi: Path, tmp_pixi_workspace: Path) -> None: - """Test that signals are forwarded correctly to the task. - We copy the data from the ../data/run_signals folder to the tmp workspace - """ + """Test that signals are forwarded correctly to the task.""" # copy the folder from ../data/run_signals to the tmp workspace data_path = Path(__file__).parent.parent.joinpath("data", "run_signals") @@ -1375,34 +1379,31 @@ def test_signal_forwarding(pixi: Path, tmp_pixi_workspace: Path) -> None: # Use the manifest from the copied run_signals directory manifest = tmp_data_path.joinpath("pixi.toml") + # install the dependencies + subprocess.check_call([pixi, "install", "--manifest-path", manifest], cwd=tmp_data_path) # run the `start` task in the background and send some signals to it - # with `pixi run start` process = subprocess.Popen( - [pixi, "run", "--no-progress", "--manifest-path", manifest, "start"], cwd=tmp_data_path + [pixi, "run", "--manifest-path", manifest, "start"], cwd=tmp_data_path ) - time.sleep(5) # wait for the process to start + time.sleep(1) # wait for the process to start # send a SIGINT to the process - # process.send_signal(signal.SIGHUP) - # process.send_signal(signal.SIGHUP) process.send_signal(signal.SIGINT) # check exit code - exit_code = process.wait(timeout=5) - + exit_code = process.wait(timeout=10) assert exit_code == 12, f"Process exited with code {exit_code}" output_file = tmp_data_path.joinpath("output.txt") - print(f"Output file exists: {output_file.exists()}") if output_file.exists(): # check if we can read "SIGINT received, exiting gracefully" with open(output_file, "r") as f: output = f.read() - # assert "HUPHUPHUP" in output, "HUP signals were not handled correctly" assert "SIGINT received, exiting gracefully" in output, ( "SIGINT signal was not handled correctly" ) else: raise AssertionError("Output file was not created") + From 9bdaafffbfab2255a3d4682bd8f135ebf3de7e1b Mon Sep 17 00:00:00 2001 From: Wolf Vollprecht Date: Fri, 1 Aug 2025 11:32:12 +0200 Subject: [PATCH 10/10] add lockfile --- tests/data/run_signals/pixi.lock | 586 +++++++++++++++++++++++ tests/data/run_signals/test.py | 4 +- tests/integration_python/test_run_cli.py | 1 - 3 files changed, 589 insertions(+), 2 deletions(-) create mode 100644 tests/data/run_signals/pixi.lock diff --git a/tests/data/run_signals/pixi.lock b/tests/data/run_signals/pixi.lock new file mode 100644 index 0000000000..c1824cfb67 --- /dev/null +++ b/tests/data/run_signals/pixi.lock @@ -0,0 +1,586 @@ +version: 6 +environments: + default: + channels: + - url: https://conda.anaconda.org/conda-forge/ + packages: + linux-64: + - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.7.14-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.44-h1423503_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.7.1-hecca717_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.6-h2dba641_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.1.0-h767d61c_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.1.0-h69a702a_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.1.0-h767d61c_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.1-hb9d3cd8_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.50.4-h0c1763c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.5.1-h7b32b05_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.11-h9e4cc4f_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8c095d6_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_hd72426e_102.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025b-h78e105d_0.conda + osx-arm64: + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h99b78c6_7.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.7.14-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-75.1-hfee45f7_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.7.1-hec049ff_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.4.6-h1da3d7d_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.1-h39f12f2_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.50.4-h4237e3c_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.1-h8359307_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.5.1-h81ee809_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.12.11-hc22306f_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.2-h1d1bf99_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h892fb3f_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025b-h78e105d_0.conda + win-64: + - conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h2466b09_7.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.7.14-h4c7d964_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libexpat-2.7.1-hac47afa_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libffi-3.4.6-h537db12_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/liblzma-5.8.1-h2466b09_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.50.4-hf5d6505_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.1-h2466b09_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.5.1-h725018a_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/python-3.12.11-h3f84c4b_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/tk-8.6.13-h2c6b04d_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025b-h78e105d_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/ucrt-10.0.22621.0-h57928b3_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vc-14.3-h41ae7f8_31.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vc14_runtime-14.44.35208-h818238b_31.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vcomp14-14.44.35208-h818238b_31.conda +packages: +- conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 + sha256: fe51de6107f9edc7aa4f786a70f4a883943bc9d39b3bb7307c04c41410990726 + md5: d7c89558ba9fa0495403155b64376d81 + license: None + size: 2562 + timestamp: 1578324546067 +- conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 + build_number: 16 + sha256: fbe2c5e56a653bebb982eda4876a9178aedfc2b545f25d0ce9c4c0b508253d22 + md5: 73aaf86a425cc6e73fcf236a5a46396d + depends: + - _libgcc_mutex 0.1 conda_forge + - libgomp >=7.5.0 + constrains: + - openmp_impl 9999 + license: BSD-3-Clause + license_family: BSD + size: 23621 + timestamp: 1650670423406 +- conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda + sha256: 5ced96500d945fb286c9c838e54fa759aa04a7129c59800f0846b4335cee770d + md5: 62ee74e96c5ebb0af99386de58cf9553 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc-ng >=12 + license: bzip2-1.0.6 + license_family: BSD + size: 252783 + timestamp: 1720974456583 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h99b78c6_7.conda + sha256: adfa71f158cbd872a36394c56c3568e6034aa55c623634b37a4836bd036e6b91 + md5: fc6948412dbbbe9a4c9ddbbcfe0a79ab + depends: + - __osx >=11.0 + license: bzip2-1.0.6 + license_family: BSD + size: 122909 + timestamp: 1720974522888 +- conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h2466b09_7.conda + sha256: 35a5dad92e88fdd7fc405e864ec239486f4f31eec229e31686e61a140a8e573b + md5: 276e7ffe9ffe39688abc665ef0f45596 + depends: + - ucrt >=10.0.20348.0 + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 + license: bzip2-1.0.6 + license_family: BSD + size: 54927 + timestamp: 1720974860185 +- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.7.14-h4c7d964_0.conda + sha256: a7fe9bce8a0f9f985d44940ec13a297df571ee70fb2264b339c62fa190b2c437 + md5: 40334594f5916bc4c0a0313d64bfe046 + depends: + - __win + license: ISC + size: 155882 + timestamp: 1752482396143 +- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.7.14-hbd8a1cb_0.conda + sha256: 29defbd83c7829788358678ec996adeee252fa4d4274b7cd386c1ed73d2b201e + md5: d16c90324aef024877d8713c0b7fea5b + depends: + - __unix + license: ISC + size: 155658 + timestamp: 1752482350666 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-75.1-hfee45f7_0.conda + sha256: 9ba12c93406f3df5ab0a43db8a4b4ef67a5871dfd401010fbe29b218b2cbe620 + md5: 5eb22c1d7b3fc4abb50d92d621583137 + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + size: 11857802 + timestamp: 1720853997952 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.44-h1423503_1.conda + sha256: 1a620f27d79217c1295049ba214c2f80372062fd251b569e9873d4a953d27554 + md5: 0be7c6e070c19105f966d3758448d018 + depends: + - __glibc >=2.17,<3.0.a0 + constrains: + - binutils_impl_linux-64 2.44 + license: GPL-3.0-only + license_family: GPL + size: 676044 + timestamp: 1752032747103 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.7.1-hecca717_0.conda + sha256: da2080da8f0288b95dd86765c801c6e166c4619b910b11f9a8446fb852438dc2 + md5: 4211416ecba1866fab0c6470986c22d6 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + constrains: + - expat 2.7.1.* + license: MIT + license_family: MIT + size: 74811 + timestamp: 1752719572741 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.7.1-hec049ff_0.conda + sha256: 8fbb17a56f51e7113ed511c5787e0dec0d4b10ef9df921c4fd1cccca0458f648 + md5: b1ca5f21335782f71a8bd69bdc093f67 + depends: + - __osx >=11.0 + constrains: + - expat 2.7.1.* + license: MIT + license_family: MIT + size: 65971 + timestamp: 1752719657566 +- conda: https://conda.anaconda.org/conda-forge/win-64/libexpat-2.7.1-hac47afa_0.conda + sha256: 8432ca842bdf8073ccecf016ccc9140c41c7114dc4ec77ca754551c01f780845 + md5: 3608ffde260281fa641e70d6e34b1b96 + depends: + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + constrains: + - expat 2.7.1.* + license: MIT + license_family: MIT + size: 141322 + timestamp: 1752719767870 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.6-h2dba641_1.conda + sha256: 764432d32db45466e87f10621db5b74363a9f847d2b8b1f9743746cd160f06ab + md5: ede4673863426c0883c0063d853bbd85 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: MIT + license_family: MIT + size: 57433 + timestamp: 1743434498161 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.4.6-h1da3d7d_1.conda + sha256: c6a530924a9b14e193ea9adfe92843de2a806d1b7dbfd341546ece9653129e60 + md5: c215a60c2935b517dcda8cad4705734d + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + size: 39839 + timestamp: 1743434670405 +- conda: https://conda.anaconda.org/conda-forge/win-64/libffi-3.4.6-h537db12_1.conda + sha256: d3b0b8812eab553d3464bbd68204f007f1ebadf96ce30eb0cbc5159f72e353f5 + md5: 85d8fa5e55ed8f93f874b3b23ed54ec6 + depends: + - ucrt >=10.0.20348.0 + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 + license: MIT + license_family: MIT + size: 44978 + timestamp: 1743435053850 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.1.0-h767d61c_4.conda + sha256: 144e35c1c2840f2dc202f6915fc41879c19eddbb8fa524e3ca4aa0d14018b26f + md5: f406dcbb2e7bef90d793e50e79a2882b + depends: + - __glibc >=2.17,<3.0.a0 + - _openmp_mutex >=4.5 + constrains: + - libgcc-ng ==15.1.0=*_4 + - libgomp 15.1.0 h767d61c_4 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 824153 + timestamp: 1753903866511 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.1.0-h69a702a_4.conda + sha256: 76ceac93ed98f208363d6e9c75011b0ff7b97b20f003f06461a619557e726637 + md5: 28771437ffcd9f3417c66012dc49a3be + depends: + - libgcc 15.1.0 h767d61c_4 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 29249 + timestamp: 1753903872571 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.1.0-h767d61c_4.conda + sha256: e0487a8fec78802ac04da0ac1139c3510992bc58a58cde66619dde3b363c2933 + md5: 3baf8976c96134738bba224e9ef6b1e5 + depends: + - __glibc >=2.17,<3.0.a0 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 447289 + timestamp: 1753903801049 +- conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.1-hb9d3cd8_2.conda + sha256: f2591c0069447bbe28d4d696b7fcb0c5bd0b4ac582769b89addbcf26fb3430d8 + md5: 1a580f7796c7bf6393fddb8bbbde58dc + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + constrains: + - xz 5.8.1.* + license: 0BSD + size: 112894 + timestamp: 1749230047870 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.1-h39f12f2_2.conda + sha256: 0cb92a9e026e7bd4842f410a5c5c665c89b2eb97794ffddba519a626b8ce7285 + md5: d6df911d4564d77c4374b02552cb17d1 + depends: + - __osx >=11.0 + constrains: + - xz 5.8.1.* + license: 0BSD + size: 92286 + timestamp: 1749230283517 +- conda: https://conda.anaconda.org/conda-forge/win-64/liblzma-5.8.1-h2466b09_2.conda + sha256: 55764956eb9179b98de7cc0e55696f2eff8f7b83fc3ebff5e696ca358bca28cc + md5: c15148b2e18da456f5108ccb5e411446 + depends: + - ucrt >=10.0.20348.0 + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 + constrains: + - xz 5.8.1.* + license: 0BSD + size: 104935 + timestamp: 1749230611612 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda + sha256: 927fe72b054277cde6cb82597d0fcf6baf127dcbce2e0a9d8925a68f1265eef5 + md5: d864d34357c3b65a4b731f78c0801dc4 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: LGPL-2.1-only + license_family: GPL + size: 33731 + timestamp: 1750274110928 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.50.4-h0c1763c_0.conda + sha256: 6d9c32fc369af5a84875725f7ddfbfc2ace795c28f246dc70055a79f9b2003da + md5: 0b367fad34931cb79e0d6b7e5c06bb1c + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libzlib >=1.3.1,<2.0a0 + license: blessing + size: 932581 + timestamp: 1753948484112 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.50.4-h4237e3c_0.conda + sha256: 802ebe62e6bc59fc26b26276b793e0542cfff2d03c086440aeaf72fb8bbcec44 + md5: 1dcb0468f5146e38fae99aef9656034b + depends: + - __osx >=11.0 + - icu >=75.1,<76.0a0 + - libzlib >=1.3.1,<2.0a0 + license: blessing + size: 902645 + timestamp: 1753948599139 +- conda: https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.50.4-hf5d6505_0.conda + sha256: 5dc4f07b2d6270ac0c874caec53c6984caaaa84bc0d3eb593b0edf3dc8492efa + md5: ccb20d946040f86f0c05b644d5eadeca + depends: + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: blessing + size: 1288499 + timestamp: 1753948889360 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda + sha256: 787eb542f055a2b3de553614b25f09eefb0a0931b0c87dbcce6efdfd92f04f18 + md5: 40b61aab5c7ba9ff276c41cfffe6b80b + depends: + - libgcc-ng >=12 + license: BSD-3-Clause + license_family: BSD + size: 33601 + timestamp: 1680112270483 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda + sha256: 6ae68e0b86423ef188196fff6207ed0c8195dd84273cb5623b85aa08033a410c + md5: 5aa797f8787fe7a17d1b0821485b5adc + depends: + - libgcc-ng >=12 + license: LGPL-2.1-or-later + size: 100393 + timestamp: 1702724383534 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda + sha256: d4bfe88d7cb447768e31650f06257995601f89076080e76df55e3112d4e47dc4 + md5: edb0dca6bc32e4f4789199455a1dbeb8 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + constrains: + - zlib 1.3.1 *_2 + license: Zlib + license_family: Other + size: 60963 + timestamp: 1727963148474 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.1-h8359307_2.conda + sha256: ce34669eadaba351cd54910743e6a2261b67009624dbc7daeeafdef93616711b + md5: 369964e85dc26bfe78f41399b366c435 + depends: + - __osx >=11.0 + constrains: + - zlib 1.3.1 *_2 + license: Zlib + license_family: Other + size: 46438 + timestamp: 1727963202283 +- conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.1-h2466b09_2.conda + sha256: ba945c6493449bed0e6e29883c4943817f7c79cbff52b83360f7b341277c6402 + md5: 41fbfac52c601159df6c01f875de31b9 + depends: + - ucrt >=10.0.20348.0 + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 + constrains: + - zlib 1.3.1 *_2 + license: Zlib + license_family: Other + size: 55476 + timestamp: 1727963768015 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda + sha256: 3fde293232fa3fca98635e1167de6b7c7fda83caf24b9d6c91ec9eefb4f4d586 + md5: 47e340acb35de30501a76c7c799c41d7 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: X11 AND BSD-3-Clause + size: 891641 + timestamp: 1738195959188 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda + sha256: 2827ada40e8d9ca69a153a45f7fd14f32b2ead7045d3bbb5d10964898fe65733 + md5: 068d497125e4bf8a66bf707254fff5ae + depends: + - __osx >=11.0 + license: X11 AND BSD-3-Clause + size: 797030 + timestamp: 1738196177597 +- conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.5.1-h7b32b05_0.conda + sha256: 942347492164190559e995930adcdf84e2fea05307ec8012c02a505f5be87462 + md5: c87df2ab1448ba69169652ab9547082d + depends: + - __glibc >=2.17,<3.0.a0 + - ca-certificates + - libgcc >=13 + license: Apache-2.0 + license_family: Apache + size: 3131002 + timestamp: 1751390382076 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.5.1-h81ee809_0.conda + sha256: f94fde0f096fa79794c8aa0a2665630bbf9026cc6438e8253f6555fc7281e5a8 + md5: a8ac77e7c7e58d43fa34d60bd4361062 + depends: + - __osx >=11.0 + - ca-certificates + license: Apache-2.0 + license_family: Apache + size: 3071649 + timestamp: 1751390309393 +- conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.5.1-h725018a_0.conda + sha256: 2b2eb73b0661ff1aed55576a3d38614852b5d857c2fa9205ac115820c523306c + md5: d124fc2fd7070177b5e2450627f8fc1a + depends: + - ca-certificates + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: Apache-2.0 + license_family: Apache + size: 9327033 + timestamp: 1751392489008 +- conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.11-h9e4cc4f_0_cpython.conda + sha256: 6cca004806ceceea9585d4d655059e951152fc774a471593d4f5138e6a54c81d + md5: 94206474a5608243a10c92cefbe0908f + depends: + - __glibc >=2.17,<3.0.a0 + - bzip2 >=1.0.8,<2.0a0 + - ld_impl_linux-64 >=2.36.1 + - libexpat >=2.7.0,<3.0a0 + - libffi >=3.4.6,<3.5.0a0 + - libgcc >=13 + - liblzma >=5.8.1,<6.0a0 + - libnsl >=2.0.1,<2.1.0a0 + - libsqlite >=3.50.0,<4.0a0 + - libuuid >=2.38.1,<3.0a0 + - libxcrypt >=4.4.36 + - libzlib >=1.3.1,<2.0a0 + - ncurses >=6.5,<7.0a0 + - openssl >=3.5.0,<4.0a0 + - readline >=8.2,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + constrains: + - python_abi 3.12.* *_cp312 + license: Python-2.0 + size: 31445023 + timestamp: 1749050216615 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.12.11-hc22306f_0_cpython.conda + sha256: cde8b944c2dc378a5afbc48028d0843583fd215493d5885a80f1b41de085552f + md5: 9207ebad7cfbe2a4af0702c92fd031c4 + depends: + - __osx >=11.0 + - bzip2 >=1.0.8,<2.0a0 + - libexpat >=2.7.0,<3.0a0 + - libffi >=3.4.6,<3.5.0a0 + - liblzma >=5.8.1,<6.0a0 + - libsqlite >=3.50.0,<4.0a0 + - libzlib >=1.3.1,<2.0a0 + - ncurses >=6.5,<7.0a0 + - openssl >=3.5.0,<4.0a0 + - readline >=8.2,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + constrains: + - python_abi 3.12.* *_cp312 + license: Python-2.0 + size: 13009234 + timestamp: 1749048134449 +- conda: https://conda.anaconda.org/conda-forge/win-64/python-3.12.11-h3f84c4b_0_cpython.conda + sha256: b69412e64971b5da3ced0fc36f05d0eacc9393f2084c6f92b8f28ee068d83e2e + md5: 6aa5e62df29efa6319542ae5025f4376 + depends: + - bzip2 >=1.0.8,<2.0a0 + - libexpat >=2.7.0,<3.0a0 + - libffi >=3.4.6,<3.5.0a0 + - liblzma >=5.8.1,<6.0a0 + - libsqlite >=3.50.0,<4.0a0 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.0,<4.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + - ucrt >=10.0.20348.0 + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 + constrains: + - python_abi 3.12.* *_cp312 + license: Python-2.0 + size: 15829289 + timestamp: 1749047682640 +- conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8c095d6_2.conda + sha256: 2d6d0c026902561ed77cd646b5021aef2d4db22e57a5b0178dfc669231e06d2c + md5: 283b96675859b20a825f8fa30f311446 + depends: + - libgcc >=13 + - ncurses >=6.5,<7.0a0 + license: GPL-3.0-only + license_family: GPL + size: 282480 + timestamp: 1740379431762 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.2-h1d1bf99_2.conda + sha256: 7db04684d3904f6151eff8673270922d31da1eea7fa73254d01c437f49702e34 + md5: 63ef3f6e6d6d5c589e64f11263dc5676 + depends: + - ncurses >=6.5,<7.0a0 + license: GPL-3.0-only + license_family: GPL + size: 252359 + timestamp: 1740379663071 +- conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_hd72426e_102.conda + sha256: a84ff687119e6d8752346d1d408d5cf360dee0badd487a472aa8ddedfdc219e1 + md5: a0116df4f4ed05c303811a837d5b39d8 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libzlib >=1.3.1,<2.0a0 + license: TCL + license_family: BSD + size: 3285204 + timestamp: 1748387766691 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h892fb3f_2.conda + sha256: cb86c522576fa95c6db4c878849af0bccfd3264daf0cc40dd18e7f4a7bfced0e + md5: 7362396c170252e7b7b0c8fb37fe9c78 + depends: + - __osx >=11.0 + - libzlib >=1.3.1,<2.0a0 + license: TCL + license_family: BSD + size: 3125538 + timestamp: 1748388189063 +- conda: https://conda.anaconda.org/conda-forge/win-64/tk-8.6.13-h2c6b04d_2.conda + sha256: e3614b0eb4abcc70d98eae159db59d9b4059ed743ef402081151a948dce95896 + md5: ebd0e761de9aa879a51d22cc721bd095 + depends: + - ucrt >=10.0.20348.0 + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 + license: TCL + license_family: BSD + size: 3466348 + timestamp: 1748388121356 +- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025b-h78e105d_0.conda + sha256: 5aaa366385d716557e365f0a4e9c3fca43ba196872abbbe3d56bb610d131e192 + md5: 4222072737ccff51314b5ece9c7d6f5a + license: LicenseRef-Public-Domain + size: 122968 + timestamp: 1742727099393 +- conda: https://conda.anaconda.org/conda-forge/win-64/ucrt-10.0.22621.0-h57928b3_1.conda + sha256: db8dead3dd30fb1a032737554ce91e2819b43496a0db09927edf01c32b577450 + md5: 6797b005cd0f439c4c5c9ac565783700 + constrains: + - vs2015_runtime >=14.29.30037 + license: LicenseRef-MicrosoftWindowsSDK10 + size: 559710 + timestamp: 1728377334097 +- conda: https://conda.anaconda.org/conda-forge/win-64/vc-14.3-h41ae7f8_31.conda + sha256: cb357591d069a1e6cb74199a8a43a7e3611f72a6caed9faa49dbb3d7a0a98e0b + md5: 28f4ca1e0337d0f27afb8602663c5723 + depends: + - vc14_runtime >=14.44.35208 + track_features: + - vc14 + license: BSD-3-Clause + license_family: BSD + size: 18249 + timestamp: 1753739241465 +- conda: https://conda.anaconda.org/conda-forge/win-64/vc14_runtime-14.44.35208-h818238b_31.conda + sha256: af4b4b354b87a9a8d05b8064ff1ea0b47083274f7c30b4eb96bc2312c9b5f08f + md5: 603e41da40a765fd47995faa021da946 + depends: + - ucrt >=10.0.20348.0 + - vcomp14 14.44.35208 h818238b_31 + constrains: + - vs2015_runtime 14.44.35208.* *_31 + license: LicenseRef-MicrosoftVisualCpp2015-2022Runtime + license_family: Proprietary + size: 682424 + timestamp: 1753739239305 +- conda: https://conda.anaconda.org/conda-forge/win-64/vcomp14-14.44.35208-h818238b_31.conda + sha256: 67b317b64f47635415776718d25170a9a6f9a1218c0f5a6202bfd687e07b6ea4 + md5: a6b1d5c1fc3cb89f88f7179ee6a9afe3 + depends: + - ucrt >=10.0.20348.0 + constrains: + - vs2015_runtime 14.44.35208.* *_31 + license: LicenseRef-MicrosoftVisualCpp2015-2022Runtime + license_family: Proprietary + size: 113963 + timestamp: 1753739198723 diff --git a/tests/data/run_signals/test.py b/tests/data/run_signals/test.py index 5d90bc6e43..e418b4f7ca 100644 --- a/tests/data/run_signals/test.py +++ b/tests/data/run_signals/test.py @@ -8,6 +8,7 @@ if output_file.exists(): output_file.unlink() + def signal_handler(signum, frame): output_file.write_text(f"Signal handler called with signal {signum}\n") if signum == signal.SIGINT: @@ -15,8 +16,9 @@ def signal_handler(signum, frame): output_file.write_text("SIGINT received, exiting gracefully...\n") sys.exit(12) + signal.signal(signal.SIGINT, signal_handler) while True: print("Running...\n") - time.sleep(1) \ No newline at end of file + time.sleep(1) diff --git a/tests/integration_python/test_run_cli.py b/tests/integration_python/test_run_cli.py index 93bf94d049..6c56058cd6 100644 --- a/tests/integration_python/test_run_cli.py +++ b/tests/integration_python/test_run_cli.py @@ -1406,4 +1406,3 @@ def test_signal_forwarding(pixi: Path, tmp_pixi_workspace: Path) -> None: ) else: raise AssertionError("Output file was not created") -