From cc208f1c28b3cc985076cd94e8b2c72a04f4b568 Mon Sep 17 00:00:00 2001 From: branchseer Date: Wed, 22 Apr 2026 23:52:34 +0800 Subject: [PATCH 1/2] feat(vite_task): gate fspy behind cfg for non-supported OSes Introduces a custom cfg(fspy) (set by vite_task's build.rs when target_os is windows/macos/linux) and moves the fspy dep into a matching target block. Tasks still run on any target (e.g. android, freebsd); auto-inferred caching is refused with a new CacheNotUpdatedReason::FspyUnsupported that prints "Configure `input` manually to enable caching." in the summary. - spawn() always builds tokio::process::Command directly; fspy::Command is only constructed inside spawn_fspy (cfg(fspy) only) - fspy::Command::into_tokio_command is now pub(crate) - PathRead moves from tracked_accesses.rs (fspy-gated) to fingerprint.rs - Off-path verification: `mise check-android` clippy-checks the full codebase against aarch64-linux-android Co-Authored-By: Claude Opus 4.7 (1M context) --- CHANGELOG.md | 1 + crates/fspy/src/command.rs | 2 +- crates/vite_task/Cargo.toml | 17 +++- crates/vite_task/build.rs | 18 +++++ crates/vite_task/src/session/event.rs | 4 + .../src/session/execute/fingerprint.rs | 7 +- crates/vite_task/src/session/execute/mod.rs | 78 ++++++++++++------- crates/vite_task/src/session/execute/spawn.rs | 73 +++++++++++++---- .../src/session/execute/tracked_accesses.rs | 8 +- .../vite_task/src/session/reporter/summary.rs | 35 ++++++++- 10 files changed, 185 insertions(+), 58 deletions(-) create mode 100644 crates/vite_task/build.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 380ce3ee..b28d58db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # Changelog +- **Added** Platform support for targets without `input` auto-inference (e.g. Android). Tasks still run; those relying on auto-inference run uncached, with the summary noting that `input` must be configured manually to enable caching ([#352](https://github.com/voidzero-dev/vite-task/pull/352)) - **Fixed** `vp run` no longer aborts with `failed to prepare the command for injection: Invalid argument` when the user environment already has `LD_PRELOAD` (Linux) or `DYLD_INSERT_LIBRARIES` (macOS) set. The tracer shim is now appended to any existing value and placed last, so user preloads keep their symbol-interposition precedence ([#340](https://github.com/voidzero-dev/vite-task/issues/340)) - **Changed** Arguments passed after a task name (e.g. `vp run test some-filter`) are now forwarded only to that task. Tasks pulled in via `dependsOn` no longer receive them ([#324](https://github.com/voidzero-dev/vite-task/issues/324)) - **Fixed** Windows file access tracking no longer panics when a task touches malformed paths that cannot be represented as workspace-relative inputs ([#330](https://github.com/voidzero-dev/vite-task/pull/330)) diff --git a/crates/fspy/src/command.rs b/crates/fspy/src/command.rs index 2a72c67d..fb150b26 100644 --- a/crates/fspy/src/command.rs +++ b/crates/fspy/src/command.rs @@ -228,7 +228,7 @@ impl Command { /// Convert to a `tokio::process::Command` without tracking. #[must_use] - pub fn into_tokio_command(self) -> TokioCommand { + pub(crate) fn into_tokio_command(self) -> TokioCommand { let mut tokio_cmd = TokioCommand::new(self.program); if let Some(cwd) = &self.cwd { tokio_cmd.current_dir(cwd); diff --git a/crates/vite_task/Cargo.toml b/crates/vite_task/Cargo.toml index 7ba8f2ff..2286b9dc 100644 --- a/crates/vite_task/Cargo.toml +++ b/crates/vite_task/Cargo.toml @@ -2,7 +2,7 @@ name = "vite_task" version = "0.0.0" edition.workspace = true -include = ["/src"] +include = ["/src", "/build.rs"] license.workspace = true publish = false readme = "README.md" @@ -17,8 +17,7 @@ async-trait = { workspace = true } wincode = { workspace = true, features = ["derive"] } clap = { workspace = true, features = ["derive"] } ctrlc = { workspace = true } -derive_more = { workspace = true, features = ["from"] } -fspy = { workspace = true } +derive_more = { workspace = true, features = ["debug", "from"] } futures-util = { workspace = true } once_cell = { workspace = true } owo-colors = { workspace = true } @@ -30,7 +29,14 @@ rustc-hash = { workspace = true } serde = { workspace = true, features = ["derive", "rc"] } serde_json = { workspace = true } thiserror = { workspace = true } -tokio = { workspace = true, features = ["rt-multi-thread", "io-std", "io-util", "macros", "sync"] } +tokio = { workspace = true, features = [ + "rt-multi-thread", + "io-std", + "io-util", + "macros", + "process", + "sync", +] } tokio-util = { workspace = true } tracing = { workspace = true } twox-hash = { workspace = true } @@ -45,6 +51,9 @@ wax = { workspace = true } [dev-dependencies] tempfile = { workspace = true } +[target.'cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))'.dependencies] +fspy = { workspace = true } + [target.'cfg(unix)'.dependencies] nix = { workspace = true } diff --git a/crates/vite_task/build.rs b/crates/vite_task/build.rs new file mode 100644 index 00000000..6acc864e --- /dev/null +++ b/crates/vite_task/build.rs @@ -0,0 +1,18 @@ +// Why `cfg(fspy)` instead of matching on `target_os` directly at each use site: +// "fspy is available" is a single semantic predicate, but the underlying reason +// (the `fspy` crate builds on windows/macos/linux) is a three-OS list that +// would otherwise have to be repeated — as `any(target_os = "windows", "macos", +// "linux")` — everywhere `fspy::*` is touched. Naming it `fspy` keeps the +// source self-documenting: code reads `#[cfg(fspy)]` instead of a disjunction +// over OSes. The OS allowlist lives in two spots that must stay in sync: this +// file (for the rustc cfg) and the target-scoped dep block in Cargo.toml +// (which Cargo resolves before build.rs runs, so it can't reuse this cfg). +fn main() { + println!("cargo::rustc-check-cfg=cfg(fspy)"); + println!("cargo::rerun-if-changed=build.rs"); + + let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap(); + if matches!(target_os.as_str(), "windows" | "macos" | "linux") { + println!("cargo::rustc-cfg=fspy"); + } +} diff --git a/crates/vite_task/src/session/event.rs b/crates/vite_task/src/session/event.rs index 57aec779..a0ca481c 100644 --- a/crates/vite_task/src/session/event.rs +++ b/crates/vite_task/src/session/event.rs @@ -72,6 +72,10 @@ pub enum CacheNotUpdatedReason { /// First path that was both read and written during execution. path: RelativePathBuf, }, + /// fspy isn't compiled in on this build and the task requires fspy + /// (its `input` config includes auto-inference). Task ran but cannot + /// be cached without tracked path accesses. + FspyUnsupported, } #[derive(Debug)] diff --git a/crates/vite_task/src/session/execute/fingerprint.rs b/crates/vite_task/src/session/execute/fingerprint.rs index d73a7f61..7b7103d7 100644 --- a/crates/vite_task/src/session/execute/fingerprint.rs +++ b/crates/vite_task/src/session/execute/fingerprint.rs @@ -16,9 +16,14 @@ use vite_path::{AbsolutePath, RelativePathBuf}; use vite_str::Str; use wincode::{SchemaRead, SchemaWrite}; -use super::tracked_accesses::PathRead; use crate::{collections::HashMap, session::cache::InputChangeKind}; +/// Path read access info +#[derive(Debug, Clone, Copy)] +pub struct PathRead { + pub read_dir_entries: bool, +} + /// Post-run fingerprint capturing file state after execution. /// Used to validate whether cached outputs are still valid. #[derive(SchemaWrite, SchemaRead, Debug, Serialize)] diff --git a/crates/vite_task/src/session/execute/mod.rs b/crates/vite_task/src/session/execute/mod.rs index 8af09888..812de5f6 100644 --- a/crates/vite_task/src/session/execute/mod.rs +++ b/crates/vite_task/src/session/execute/mod.rs @@ -3,6 +3,7 @@ pub mod glob_inputs; mod hash; pub mod pipe; pub mod spawn; +#[cfg(fspy)] pub mod tracked_accesses; #[cfg(windows)] mod win_job; @@ -20,12 +21,13 @@ use vite_task_plan::{ cache_metadata::CacheMetadata, execution_graph::ExecutionNodeIndex, }; +#[cfg(fspy)] +use self::tracked_accesses::TrackedPathAccesses; use self::{ - fingerprint::PostRunFingerprint, + fingerprint::{PathRead, PostRunFingerprint}, glob_inputs::compute_globbed_inputs, pipe::{PipeSinks, StdOutput, pipe_stdio}, spawn::{SpawnStdio, spawn}, - tracked_accesses::TrackedPathAccesses, }; use super::{ cache::{CacheEntryValue, ExecutionCache}, @@ -291,6 +293,17 @@ struct CacheState<'a> { fspy_negatives: Option>>, } +/// Post-execution summary of what fspy observed for a single task. Used in the +/// cache-update step. Fields are cfg-agnostic so the downstream match logic +/// doesn't need `cfg(fspy)` — the value is only ever `Some` when tracking +/// happened (see the `let tracking = ...` fork in `execute_spawn`). +struct TrackingOutcome { + path_reads: HashMap, + /// First path that was both read and written during execution, if any. + /// A non-empty value means caching this task is unsound. + read_write_overlap: Option, +} + /// Execute a spawned process with cache-aware lifecycle. /// /// This is a free function (not tied to `ExecutionContext`) so it can be reused @@ -539,44 +552,57 @@ pub async fn execute_spawn( let (cache_update_status, cache_error) = if let ExecutionMode::Cached { state, .. } = mode { let CacheState { metadata, globbed_inputs, std_outputs, fspy_negatives } = state; - // Normalize fspy accesses. `zip` gives `Some` iff fspy was enabled - // (both outcome.path_accesses and fspy_negatives are Some together). - let path_accesses = outcome - .path_accesses - .as_ref() - .zip(fspy_negatives.as_deref()) - .map(|(raw, negs)| TrackedPathAccesses::from_raw(raw, cache_base_path, negs)); + // Post-execution summary of what fspy observed. `Some` iff tracking was + // both requested (`fspy_negatives.is_some()`) and compiled in (`cfg(fspy)`). + // On a `cfg(not(fspy))` build this is always `None`, and the match below + // short-circuits to `FspyUnsupported` when tracking was needed. + let tracking: Option = { + #[cfg(fspy)] + { + outcome.path_accesses.as_ref().zip(fspy_negatives.as_deref()).map(|(raw, negs)| { + let tracked = TrackedPathAccesses::from_raw(raw, cache_base_path, negs); + let read_write_overlap = tracked + .path_reads + .keys() + .find(|p| tracked.path_writes.contains(*p)) + .cloned(); + TrackingOutcome { path_reads: tracked.path_reads, read_write_overlap } + }) + } + #[cfg(not(fspy))] + { + None + } + }; let cancelled = fast_fail_token.is_cancelled() || interrupt_token.is_cancelled(); if cancelled { // Cancelled (Ctrl-C or sibling failure) — result is untrustworthy (CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::Cancelled), None) } else if outcome.exit_status.success() { - // Check for read-write overlap: if the task wrote to any file it also - // read, the inputs were modified during execution — don't cache. - // Note: this only checks fspy-inferred reads, not globbed_inputs keys. - // A task that writes to a glob-matched file without reading it causes - // perpetual cache misses (glob detects the hash change) but not a - // correctness bug, so we don't handle that case here. - if let Some(path) = path_accesses - .as_ref() - .and_then(|pa| pa.path_reads.keys().find(|p| pa.path_writes.contains(*p))) - { + // fspy-inferred read-write overlap: the task wrote to a file it also + // read, so the prerun input hashes are stale and caching is unsound. + // (We only check fspy-inferred reads, not globbed_inputs. A task that + // writes to a glob-matched file without reading it produces perpetual + // cache misses but not a correctness bug.) + if let Some(TrackingOutcome { read_write_overlap: Some(path), .. }) = &tracking { ( CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::InputModified { path: path.clone(), }), None, ) + } else if tracking.is_none() && fspy_negatives.is_some() { + // Task requested fspy auto-inference but this binary was built + // without `cfg(fspy)`. Task ran, but we can't compute a valid + // cache entry without tracked path accesses. + (CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::FspyUnsupported), None) } else { - // path_reads is empty when inference is disabled (path_accesses is None) + // Paths already in globbed_inputs are skipped: the overlap check + // above guarantees no input modification, so the prerun hash is + // the correct post-exec hash. let empty_path_reads = HashMap::default(); - let path_reads = - path_accesses.as_ref().map_or(&empty_path_reads, |pa| &pa.path_reads); - - // Execution succeeded — attempt to create fingerprint and update cache. - // Paths already in globbed_inputs are skipped: Rule 1 (above) guarantees - // no input modification, so the prerun hash is the correct post-exec hash. + let path_reads = tracking.as_ref().map_or(&empty_path_reads, |t| &t.path_reads); match PostRunFingerprint::create(path_reads, cache_base_path, &globbed_inputs) { Ok(post_run_fingerprint) => { let new_cache_value = CacheEntryValue { diff --git a/crates/vite_task/src/session/execute/spawn.rs b/crates/vite_task/src/session/execute/spawn.rs index 0f29926b..2ed64fc8 100644 --- a/crates/vite_task/src/session/execute/spawn.rs +++ b/crates/vite_task/src/session/execute/spawn.rs @@ -2,10 +2,12 @@ //! //! [`spawn`] does one thing: hand back the child's stdio pipes plus a //! cancellation-aware `wait` future. Draining the pipes is [`super::pipe`]'s -//! job; normalizing fspy path accesses is [`super::tracked_accesses`]'s. +//! job; normalizing fspy path accesses is [`super::tracked_accesses`]'s (only +//! compiled when `cfg(fspy)` is on). use std::{io, process::Stdio}; +#[cfg(fspy)] use fspy::PathAccessIterable; use futures_util::{FutureExt, future::LocalBoxFuture}; use tokio::process::{ChildStderr, ChildStdout}; @@ -40,6 +42,7 @@ pub struct ChildHandle { pub struct ChildOutcome { pub exit_status: std::process::ExitStatus, /// Raw fspy accesses. `Some` iff `fspy` was `true` at spawn time. + #[cfg(fspy)] pub path_accesses: Option, } @@ -47,12 +50,37 @@ pub struct ChildOutcome { /// /// Cancellation is unified: whether fspy is enabled or not, the returned `wait` /// future observes `cancellation_token` and kills the child before resolving. +/// +/// On builds without `cfg(fspy)`, the `fspy` argument is ignored and the tokio +/// path is always taken. #[tracing::instrument(level = "debug", skip_all)] pub async fn spawn( cmd: &SpawnCommand, fspy: bool, stdio: SpawnStdio, cancellation_token: CancellationToken, +) -> anyhow::Result { + #[cfg(fspy)] + if fspy { + return spawn_fspy(cmd, stdio, cancellation_token).await; + } + #[cfg(not(fspy))] + let _ = fspy; + + let mut tokio_cmd = tokio::process::Command::new(cmd.program_path.as_path()); + tokio_cmd.args(cmd.args.iter().map(vite_str::Str::as_str)); + tokio_cmd.env_clear(); + tokio_cmd.envs(cmd.all_envs.iter()); + tokio_cmd.current_dir(&*cmd.cwd); + apply_stdio(&mut tokio_cmd, stdio); + spawn_tokio(tokio_cmd, cancellation_token) +} + +#[cfg(fspy)] +async fn spawn_fspy( + cmd: &SpawnCommand, + stdio: SpawnStdio, + cancellation_token: CancellationToken, ) -> anyhow::Result { let mut fspy_cmd = fspy::Command::new(cmd.program_path.as_path()); fspy_cmd.args(cmd.args.iter().map(vite_str::Str::as_str)); @@ -77,18 +105,7 @@ pub async fn spawn( } } - if fspy { - spawn_fspy(fspy_cmd, cancellation_token).await - } else { - spawn_tokio(fspy_cmd, cancellation_token) - } -} - -async fn spawn_fspy( - cmd: fspy::Command, - cancellation_token: CancellationToken, -) -> anyhow::Result { - let mut tracked = cmd.spawn(cancellation_token).await?; + let mut tracked = fspy_cmd.spawn(cancellation_token).await?; // On Windows, assign the child to a Job Object so that killing the child // also kills all descendant processes (e.g., node.exe via a .cmd shim). @@ -120,10 +137,10 @@ async fn spawn_fspy( } fn spawn_tokio( - cmd: fspy::Command, + mut cmd: tokio::process::Command, cancellation_token: CancellationToken, ) -> anyhow::Result { - let mut child = cmd.into_tokio_command().spawn()?; + let mut child = cmd.spawn()?; #[cfg(windows)] let job = { @@ -152,13 +169,37 @@ fn spawn_tokio( // `job` drops here on Windows, terminating any stragglers. #[cfg(windows)] drop(job); - Ok(ChildOutcome { exit_status, path_accesses: None }) + Ok(ChildOutcome { + exit_status, + #[cfg(fspy)] + path_accesses: None, + }) } .boxed_local(); Ok(ChildHandle { stdout, stderr, wait }) } +fn apply_stdio(cmd: &mut tokio::process::Command, stdio: SpawnStdio) { + match stdio { + SpawnStdio::Inherited => { + cmd.stdin(Stdio::inherit()).stdout(Stdio::inherit()).stderr(Stdio::inherit()); + // libuv (used by Node.js) marks stdin/stdout/stderr as close-on-exec; + // without this fix the child reopens fds 0-2 as /dev/null after exec. + // See: https://github.com/libuv/libuv/issues/2062 + // SAFETY: the pre_exec closure only performs fcntl operations on + // stdio fds, which is safe in a post-fork context. + #[cfg(unix)] + unsafe { + cmd.pre_exec(clear_stdio_cloexec); + } + } + SpawnStdio::Piped => { + cmd.stdin(Stdio::null()).stdout(Stdio::piped()).stderr(Stdio::piped()); + } + } +} + #[cfg(unix)] #[expect( clippy::unnecessary_wraps, diff --git a/crates/vite_task/src/session/execute/tracked_accesses.rs b/crates/vite_task/src/session/execute/tracked_accesses.rs index 79c77f10..83596cc7 100644 --- a/crates/vite_task/src/session/execute/tracked_accesses.rs +++ b/crates/vite_task/src/session/execute/tracked_accesses.rs @@ -1,4 +1,5 @@ //! Normalize raw fspy path accesses into workspace-relative, filtered form. +#![cfg(fspy)] use std::collections::hash_map::Entry; @@ -6,14 +7,9 @@ use fspy::{AccessMode, PathAccessIterable}; use rustc_hash::FxHashSet; use vite_path::{AbsolutePath, RelativePathBuf}; +use super::fingerprint::PathRead; use crate::collections::HashMap; -/// Path read access info -#[derive(Debug, Clone, Copy)] -pub struct PathRead { - pub read_dir_entries: bool, -} - /// Tracked file accesses from fspy, normalized to workspace-relative paths. #[derive(Default, Debug)] pub struct TrackedPathAccesses { diff --git a/crates/vite_task/src/session/reporter/summary.rs b/crates/vite_task/src/session/reporter/summary.rs index 81c314b1..4eeceb68 100644 --- a/crates/vite_task/src/session/reporter/summary.rs +++ b/crates/vite_task/src/session/reporter/summary.rs @@ -102,6 +102,11 @@ pub enum SpawnOutcome { /// First path that was both read and written, causing cache to be skipped. /// Only set when fspy detected a read-write overlap. input_modified_path: Option, + /// `true` when the task required fspy auto-inference but the binary was + /// built without `cfg(fspy)` (e.g., cross-compiled to an unsupported OS). + /// Task ran successfully but cache was not updated. + #[serde(default)] + fspy_unsupported: bool, }, /// Process exited with non-zero status. @@ -282,6 +287,10 @@ impl TaskResult { } _ => None, }; + let fspy_unsupported = matches!( + cache_update_status, + CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::FspyUnsupported) + ); match cache_status { CacheStatus::Hit { replayed_duration } => { @@ -294,6 +303,7 @@ impl TaskResult { exit_status, saved_error, input_modified_path, + fspy_unsupported, ), }, CacheStatus::Miss(cache_miss) => Self::Spawned { @@ -304,6 +314,7 @@ impl TaskResult { exit_status, saved_error, input_modified_path, + fspy_unsupported, ), }, } @@ -315,14 +326,17 @@ fn spawn_outcome_from_execution( exit_status: Option, saved_error: Option<&SavedExecutionError>, input_modified_path: Option, + fspy_unsupported: bool, ) -> SpawnOutcome { match (exit_status, saved_error) { // Spawn error — process never ran (None, Some(err)) => SpawnOutcome::SpawnError(err.clone()), // Process exited successfully, possible infra error - (Some(status), _) if status.success() => { - SpawnOutcome::Success { infra_error: saved_error.cloned(), input_modified_path } - } + (Some(status), _) if status.success() => SpawnOutcome::Success { + infra_error: saved_error.cloned(), + input_modified_path, + fspy_unsupported, + }, // Process exited with non-zero code (Some(status), _) => { let code = crate::session::event::exit_status_to_code(status); @@ -336,7 +350,11 @@ fn spawn_outcome_from_execution( // No exit status, no error — this is the cache hit / in-process path, // handled by TaskResult::CacheHit / InProcess before reaching here. // If we somehow get here, treat as success. - (None, None) => SpawnOutcome::Success { infra_error: None, input_modified_path: None }, + (None, None) => SpawnOutcome::Success { + infra_error: None, + input_modified_path: None, + fspy_unsupported: false, + }, } } @@ -455,6 +473,15 @@ impl TaskResult { { return vite_str::format!("→ Not cached: read and wrote '{path}'"); } + // fspy-unsupported-on-this-OS message — same overrides precedence as above + if let Self::Spawned { + outcome: SpawnOutcome::Success { fspy_unsupported: true, .. }, .. + } = self + { + return Str::from( + "→ Not cached: `input` auto-inference isn't supported on this OS. Configure `input` manually to enable caching.", + ); + } match self { Self::CacheHit { saved_duration_ms } => { From 86258138c7e4e10cf6718e7e429c15601819b26e Mon Sep 17 00:00:00 2001 From: branchseer Date: Wed, 22 Apr 2026 23:53:14 +0800 Subject: [PATCH 2/2] chore(deps): bump libc to 0.2.185 and nix to 0.31.2 Consolidates the two nix versions in the dep graph (0.30.1 and 0.31.1) onto 0.31.2, matching the version already pulled in transitively by dispatch2. Co-Authored-By: Claude Opus 4.7 (1M context) --- Cargo.lock | 36 ++++++++++++------------------------ Cargo.toml | 4 ++-- 2 files changed, 14 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 387e4263..602b4241 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -737,7 +737,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0b1fab2ae45819af2d0731d60f2afe17227ebb1a1538a236da84c93e9a60162" dependencies = [ "dispatch2", - "nix 0.31.1", + "nix 0.31.2", "windows-sys 0.61.2", ] @@ -1198,7 +1198,7 @@ dependencies = [ "libc", "materialized_artifact", "materialized_artifact_build", - "nix 0.30.1", + "nix 0.31.2", "ouroboros", "rustc-hash", "sha2", @@ -1247,7 +1247,7 @@ dependencies = [ "fspy_shared", "fspy_shared_unix", "libc", - "nix 0.30.1", + "nix 0.31.2", "wincode", ] @@ -1274,7 +1274,7 @@ dependencies = [ "assertables", "futures-util", "libc", - "nix 0.30.1", + "nix 0.31.2", "passfd", "seccompiler", "syscalls", @@ -1318,7 +1318,7 @@ dependencies = [ "fspy_seccomp_unotify", "fspy_shared", "memmap2", - "nix 0.30.1", + "nix 0.31.2", "phf", "stackalloc", "wincode", @@ -1328,7 +1328,7 @@ dependencies = [ name = "fspy_test_bin" version = "0.0.0" dependencies = [ - "nix 0.30.1", + "nix 0.31.2", ] [[package]] @@ -1722,9 +1722,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.180" +version = "0.2.185" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" +checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" [[package]] name = "libloading" @@ -1996,9 +1996,9 @@ dependencies = [ [[package]] name = "nix" -version = "0.30.1" +version = "0.31.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" +checksum = "5d6d0705320c1e6ba1d912b5e37cf18071b6c2e9b7fa8215a1e8a7651966f5d3" dependencies = [ "bitflags 2.10.0", "cfg-if", @@ -2007,18 +2007,6 @@ dependencies = [ "memoffset 0.9.1", ] -[[package]] -name = "nix" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225e7cfe711e0ba79a68baeddb2982723e4235247aefce1482f2f16c27865b66" -dependencies = [ - "bitflags 2.10.0", - "cfg-if", - "cfg_aliases 0.2.1", - "libc", -] - [[package]] name = "nom" version = "7.1.3" @@ -2630,7 +2618,7 @@ dependencies = [ "anyhow", "ctor", "ctrlc", - "nix 0.30.1", + "nix 0.31.2", "ntest", "portable-pty", "signal-hook", @@ -3952,7 +3940,7 @@ dependencies = [ "derive_more", "fspy", "futures-util", - "nix 0.30.1", + "nix 0.31.2", "once_cell", "owo-colors", "petgraph", diff --git a/Cargo.toml b/Cargo.toml index 28e3e250..dcff7d4a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -83,12 +83,12 @@ fspy_shared_unix = { path = "crates/fspy_shared_unix" } futures = "0.3.31" futures-util = "0.3.31" jsonc-parser = { version = "0.29.0", features = ["serde"] } -libc = "0.2.172" +libc = "0.2.185" libtest-mimic = "0.8.2" memmap2 = "0.9.7" monostate = "1.0.2" native_str = { path = "crates/native_str" } -nix = { version = "0.30.1", features = ["dir", "signal"] } +nix = { version = "0.31.2", features = ["dir", "signal"] } ntapi = "0.4.1" nucleo-matcher = "0.3.1" once_cell = "1.19"