diff --git a/Cargo.lock b/Cargo.lock index 31f480c8c9..4acf811087 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2315,7 +2315,7 @@ dependencies = [ [[package]] name = "fspy" version = "0.1.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "allocator-api2", "anyhow", @@ -2342,6 +2342,7 @@ dependencies = [ "thiserror 2.0.20", "tokio", "tokio-util", + "vt_casefold", "which", "winapi", "wincode", @@ -2351,7 +2352,7 @@ dependencies = [ [[package]] name = "fspy_client_unix" version = "0.0.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "allocator-api2", "anyhow", @@ -2368,7 +2369,7 @@ dependencies = [ [[package]] name = "fspy_detours_sys" version = "0.0.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "cc", "winapi", @@ -2377,7 +2378,7 @@ dependencies = [ [[package]] name = "fspy_ipc_str" version = "0.0.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "allocator-api2", "bumpalo", @@ -2390,7 +2391,7 @@ dependencies = [ [[package]] name = "fspy_nostd" version = "0.0.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "atoi", "bitflags 2.13.2", @@ -2404,7 +2405,7 @@ dependencies = [ [[package]] name = "fspy_nostd_alloc" version = "0.0.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "allocator-api2", "bump-scope", @@ -2414,7 +2415,7 @@ dependencies = [ [[package]] name = "fspy_preload_unix" version = "0.0.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "allocator-api2", "ctor", @@ -2431,7 +2432,7 @@ dependencies = [ [[package]] name = "fspy_preload_windows" version = "0.1.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "allocator-api2", "constcat", @@ -2451,7 +2452,7 @@ dependencies = [ [[package]] name = "fspy_seccomp_unotify" version = "0.1.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "futures-util", "libc", @@ -2468,7 +2469,7 @@ dependencies = [ [[package]] name = "fspy_shared" version = "0.0.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "allocator-api2", "bitflags 2.13.2", @@ -2490,7 +2491,7 @@ dependencies = [ [[package]] name = "fspy_shared_unix" version = "0.0.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "allocator-api2", "anyhow", @@ -2510,7 +2511,7 @@ dependencies = [ [[package]] name = "fspy_shm" version = "0.0.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "fspy_nostd", "windows-sys 0.61.2", @@ -3789,7 +3790,7 @@ dependencies = [ [[package]] name = "materialized_artifact" version = "0.0.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "materialized_artifact_macros", "tempfile", @@ -3798,7 +3799,7 @@ dependencies = [ [[package]] name = "materialized_artifact_macros" version = "0.0.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "proc-macro2", "quote", @@ -3920,28 +3921,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "monostate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc4dfdf312bb1b22fce127237589f4ee31652bc479f3d208332f32132aaccc9" -dependencies = [ - "monostate-impl", - "serde", - "serde_core", -] - -[[package]] -name = "monostate-impl" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a656449eeb444c77364a3033f013c51869eee320c0dff805eb53024c0dfd435b" -dependencies = [ - "proc-macro2", - "quote", - "syn 3.0.5", -] - [[package]] name = "napi" version = "3.12.6" @@ -5739,7 +5718,7 @@ dependencies = [ [[package]] name = "pty_terminal" version = "0.0.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "anyhow", "portable-pty", @@ -5749,7 +5728,7 @@ dependencies = [ [[package]] name = "pty_terminal_test" version = "0.0.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "anyhow", "portable-pty", @@ -5760,7 +5739,7 @@ dependencies = [ [[package]] name = "pty_terminal_test_client" version = "0.0.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "base64 0.22.1", "getrandom 0.4.3", @@ -7631,7 +7610,7 @@ dependencies = [ [[package]] name = "snapshot_test" version = "0.1.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "serde", "serde_json", @@ -7661,7 +7640,7 @@ dependencies = [ [[package]] name = "socket_ipc" version = "0.0.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "nix 0.31.3", "tempfile", @@ -8555,6 +8534,7 @@ dependencies = [ "idna", "percent-encoding", "serde", + "serde_derive", ] [[package]] @@ -8701,6 +8681,7 @@ dependencies = [ "vp_static_config", "vp_toolchain", "vt", + "vt_casefold", "vt_path", "vt_select", "vt_str", @@ -9017,7 +8998,7 @@ checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" [[package]] name = "vt" version = "0.0.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "anstream", "anyhow", @@ -9046,6 +9027,7 @@ dependencies = [ "tracing", "twox-hash", "uuid", + "vt_casefold", "vt_client_napi", "vt_glob", "vt_graph", @@ -9073,14 +9055,24 @@ dependencies = [ "vte", ] +[[package]] +name = "vt_casefold" +version = "0.0.0" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" +dependencies = [ + "ref-cast", + "serde", +] + [[package]] name = "vt_client" version = "0.0.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "fspy_ipc_str", "rustc-hash", "socket_ipc", + "vt_casefold", "vt_ipc_shared", "vt_path", "wincode", @@ -9089,7 +9081,7 @@ dependencies = [ [[package]] name = "vt_client_napi" version = "0.1.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "napi", "napi-build", @@ -9101,7 +9093,7 @@ dependencies = [ [[package]] name = "vt_glob" version = "0.0.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "globset", "thiserror 2.0.20", @@ -9111,11 +9103,10 @@ dependencies = [ [[package]] name = "vt_graph" version = "0.1.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "anyhow", "async-trait", - "monostate", "petgraph 0.8.3", "rustc-hash", "serde", @@ -9133,7 +9124,7 @@ dependencies = [ [[package]] name = "vt_graph_ser" version = "0.1.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "petgraph 0.8.3", "serde", @@ -9142,7 +9133,7 @@ dependencies = [ [[package]] name = "vt_ipc_shared" version = "0.0.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "fspy_ipc_str", "rustc-hash", @@ -9152,7 +9143,7 @@ dependencies = [ [[package]] name = "vt_path" version = "0.1.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "diff-struct", "os_str_bytes", @@ -9167,7 +9158,7 @@ dependencies = [ [[package]] name = "vt_plan" version = "0.1.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "anyhow", "async-trait", @@ -9181,6 +9172,8 @@ dependencies = [ "shell-escape", "thiserror 2.0.20", "tracing", + "url", + "vt_casefold", "vt_glob", "vt_graph", "vt_graph_ser", @@ -9195,7 +9188,7 @@ dependencies = [ [[package]] name = "vt_powershell" version = "0.1.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "vt_path", "which", @@ -9204,7 +9197,7 @@ dependencies = [ [[package]] name = "vt_select" version = "0.0.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "anyhow", "crossterm", @@ -9215,7 +9208,7 @@ dependencies = [ [[package]] name = "vt_server" version = "0.0.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "fspy_ipc_str", "futures", @@ -9225,6 +9218,7 @@ dependencies = [ "tokio", "tokio-util", "tracing", + "vt_casefold", "vt_glob", "vt_ipc_shared", "vt_path", @@ -9234,20 +9228,19 @@ dependencies = [ [[package]] name = "vt_shell" version = "0.0.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "brush-parser 0.4.0", - "diff-struct", "serde", "shell-escape", + "vt_casefold", "vt_str", - "wincode", ] [[package]] name = "vt_str" version = "0.1.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "compact_str 0.9.1", "diff-struct", @@ -9258,7 +9251,7 @@ dependencies = [ [[package]] name = "vt_workspace" version = "0.0.0" -source = "git+https://github.com/voidzero-dev/vite-task.git?rev=790b15282344e00f508e74bc0e10ad0feffcbbf2#790b15282344e00f508e74bc0e10ad0feffcbbf2" +source = "git+https://github.com/voidzero-dev/vite-task.git?rev=7d69d6577ecf6bd83deee32186de59918a712873#7d69d6577ecf6bd83deee32186de59918a712873" dependencies = [ "clap", "petgraph 0.8.3", diff --git a/Cargo.toml b/Cargo.toml index 81fb8f0fb4..5140f49c25 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -189,7 +189,7 @@ dunce = "1.0.5" fast-glob = "1.0.0" flate2 = { version = "=1.1.9", features = ["zlib-rs"] } form_urlencoded = "1.2.1" -fspy = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "790b15282344e00f508e74bc0e10ad0feffcbbf2" } +fspy = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "7d69d6577ecf6bd83deee32186de59918a712873" } futures = "0.3.31" futures-util = "0.3.31" glob = "0.3.2" @@ -246,8 +246,8 @@ pretty_assertions = "1.4.1" phf = "0.14.0" prettyplease = "0.2.32" proc-macro2 = "1" -pty_terminal_test = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "790b15282344e00f508e74bc0e10ad0feffcbbf2" } -pty_terminal_test_client = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "790b15282344e00f508e74bc0e10ad0feffcbbf2" } +pty_terminal_test = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "7d69d6577ecf6bd83deee32186de59918a712873" } +pty_terminal_test_client = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "7d69d6577ecf6bd83deee32186de59918a712873" } quote = "1" rayon = "1.10.0" regex = "1.11.1" @@ -271,7 +271,7 @@ sha2 = "0.10.9" shell-escape = "0.1.5" simdutf8 = "0.1.5" smallvec = { version = "1.16.0", features = ["union"] } -snapshot_test = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "790b15282344e00f508e74bc0e10ad0feffcbbf2" } +snapshot_test = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "7d69d6577ecf6bd83deee32186de59918a712873" } string_cache = "0.9.0" sugar_path = { version = "3", features = ["cached_current_dir"] } supports-color = "3" @@ -305,12 +305,13 @@ vp_setup = { path = "crates/vp_setup" } vp_shared = { path = "crates/vp_shared" } vp_static_config = { path = "crates/vp_static_config" } vp_toolchain = { path = "crates/vp_toolchain" } -vt = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "790b15282344e00f508e74bc0e10ad0feffcbbf2" } -vt_path = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "790b15282344e00f508e74bc0e10ad0feffcbbf2" } -vt_powershell = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "790b15282344e00f508e74bc0e10ad0feffcbbf2" } -vt_select = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "790b15282344e00f508e74bc0e10ad0feffcbbf2" } -vt_str = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "790b15282344e00f508e74bc0e10ad0feffcbbf2" } -vt_workspace = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "790b15282344e00f508e74bc0e10ad0feffcbbf2" } +vt = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "7d69d6577ecf6bd83deee32186de59918a712873" } +vt_casefold = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "7d69d6577ecf6bd83deee32186de59918a712873" } +vt_path = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "7d69d6577ecf6bd83deee32186de59918a712873" } +vt_powershell = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "7d69d6577ecf6bd83deee32186de59918a712873" } +vt_select = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "7d69d6577ecf6bd83deee32186de59918a712873" } +vt_str = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "7d69d6577ecf6bd83deee32186de59918a712873" } +vt_workspace = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "7d69d6577ecf6bd83deee32186de59918a712873" } walkdir = "2.5.0" webpki-root-certs = "1.0.9" which = "8.0.6" @@ -416,6 +417,7 @@ string_wizard = { path = "./rolldown/crates/string_wizard", features = ["serde"] # pty_terminal_test_client = { path = "../vite-task/crates/pty_terminal_test_client" } # snapshot_test = { path = "../vite-task/crates/snapshot_test" } # vt = { path = "../vite-task/crates/vt" } +# vt_casefold = { path = "../vite-task/crates/vt_casefold" } # vt_path = { path = "../vite-task/crates/vt_path" } # vt_powershell = { path = "../vite-task/crates/vt_powershell" } # vt_select = { path = "../vite-task/crates/vt_select" } diff --git a/README.md b/README.md index 139fdf4d08..ad4b16bf8a 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,9 @@ export default defineConfig({ tasks: { 'generate:icons': { command: 'node scripts/generate-icons.js', - env: ['ICON_THEME'], + cache: { + env: ['ICON_THEME'], + }, }, }, }, diff --git a/bench/benches/workspace_load.rs b/bench/benches/workspace_load.rs index 859ed9281a..1c6ba44c60 100644 --- a/bench/benches/workspace_load.rs +++ b/bench/benches/workspace_load.rs @@ -1,6 +1,6 @@ #![allow(clippy::allow_attributes, clippy::disallowed_types)] -use std::{ffi::OsStr, hint::black_box, path::PathBuf, sync::Arc}; +use std::{hint::black_box, path::PathBuf}; use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main}; use rustc_hash::FxHashMap; @@ -70,9 +70,8 @@ fn bench_workspace_load(c: &mut Criterion) { b.iter(|| { runtime.block_on(async { let mut owned_callbacks = BenchSessionConfig::default(); - let envs: FxHashMap, Arc> = FxHashMap::default(); let mut session = Session::init_with( - envs, + FxHashMap::default(), fixture_path.clone().into(), owned_callbacks.as_callbacks(), ) @@ -88,10 +87,12 @@ fn bench_workspace_load(c: &mut Criterion) { b.iter(|| { runtime.block_on(async { let mut owned_callbacks = BenchSessionConfig::default(); - let envs: FxHashMap, Arc> = FxHashMap::default(); - let mut session = - Session::init_with(envs, path.clone().into(), owned_callbacks.as_callbacks()) - .expect("Failed to create session"); + let mut session = Session::init_with( + FxHashMap::default(), + path.clone().into(), + owned_callbacks.as_callbacks(), + ) + .expect("Failed to create session"); black_box( session.ensure_task_graph_loaded().await.expect("Failed to load task graph"), ); diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/change_passthrough_env_config/vite.config.ts b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/change_passthrough_env_config/vite.config.ts index 5079c3e5af..9bfe2d1575 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/change_passthrough_env_config/vite.config.ts +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/change_passthrough_env_config/vite.config.ts @@ -5,8 +5,7 @@ export default { tasks: { hello: { command: 'node -p process.env.MY_ENV', - untrackedEnv, - cache: true, + cache: { untrackedEnv }, }, }, }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/npm_install_with_options/vite.config.ts b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/npm_install_with_options/vite.config.ts index 03ba99dcd3..990cd43d97 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/npm_install_with_options/vite.config.ts +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/npm_install_with_options/vite.config.ts @@ -4,7 +4,9 @@ export default { tasks: { install: { command: 'vp install --prod --silent', - input: [{ auto: true }, '!node_modules/**', '!package-lock.json'], + cache: { + input: [{ auto: true }, '!node_modules/**', '!package-lock.json'], + }, }, }, }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/plain_terminal_ui/vite.config.ts b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/plain_terminal_ui/vite.config.ts index e715214f39..a4eac20e45 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/plain_terminal_ui/vite.config.ts +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/plain_terminal_ui/vite.config.ts @@ -6,9 +6,10 @@ export default { tasks: { hello: { command: 'node hello.mjs', - env: ['FOO', 'BAR'], - cache: true, - ...(untrackedEnv && { untrackedEnv }), + cache: { + env: ['FOO', 'BAR'], + ...(untrackedEnv && { untrackedEnv }), + }, ...(cwd && { cwd }), }, }, diff --git a/crates/vp_static_config/src/lib.rs b/crates/vp_static_config/src/lib.rs index 2af9103163..eb8eaa611b 100644 --- a/crates/vp_static_config/src/lib.rs +++ b/crates/vp_static_config/src/lib.rs @@ -1371,8 +1371,9 @@ mod tests { tasks: { hello: { command: 'node hello.mjs', - envs: ['FOO', 'BAR'], - cache: true, + cache: { + env: ['FOO', 'BAR'], + }, }, }, }, @@ -1385,8 +1386,9 @@ mod tests { "tasks": { "hello": { "command": "node hello.mjs", - "envs": ["FOO", "BAR"], - "cache": true, + "cache": { + "env": ["FOO", "BAR"], + }, } } }), diff --git a/docs/config/run.md b/docs/config/run.md index ccddfb4520..fa3c43034e 100644 --- a/docs/config/run.md +++ b/docs/config/run.md @@ -80,7 +80,7 @@ tasks: { } ``` -Use the object form when a task needs other fields like `cache`, `dependsOn`, `env`, or `input`. +Use the object form when a task needs other fields like `cache`, `dependsOn`, or `cwd`. ### `command` @@ -156,10 +156,26 @@ See [Task Dependencies](/guide/run#task-dependencies) for details on how explici ### `cache` -- **Type:** `boolean` +- **Type:** `boolean | { env?: string[], untrackedEnv?: string[], input?: Array<...>, output?: Array<...> }` - **Default:** `true` -Whether to cache this task's output. Set to `false` for tasks that should never be cached, like dev servers: +Whether and how to cache this task. Caching is enabled with default settings when `cache` is omitted, `true`, or `{}`. + +Use an object to configure how the task is cached with [`cache.env`](#cache-env), [`cache.untrackedEnv`](#cache-untrackedenv), [`cache.input`](#cache-input), and [`cache.output`](#cache-output): + +```ts [vite.config.ts] +tasks: { + build: { + command: 'node build.mjs', + cache: { + env: ['NODE_ENV'], + input: [{ auto: true }, '!dist/**'], + }, + }, +} +``` + +Set `cache` to `false` for tasks that should never be cached, like dev servers: ```ts [vite.config.ts] tasks: { @@ -170,7 +186,7 @@ tasks: { } ``` -### `env` +### `cache.env` - **Type:** `string[]` - **Default:** `[]` @@ -181,7 +197,9 @@ Environment variables included in the cache fingerprint. When any listed variabl tasks: { build: { command: 'node build.mjs', - env: ['NODE_ENV'], + cache: { + env: ['NODE_ENV'], + }, }, } ``` @@ -195,7 +213,7 @@ $ NODE_ENV=development vp run build # first run $ NODE_ENV=production vp run build # cache miss: env 'NODE_ENV' changed ``` -### `untrackedEnv` +### `cache.untrackedEnv` - **Type:** `string[]` - **Default:** see below @@ -206,12 +224,14 @@ Environment variables passed to the task process but **not** included in the cac tasks: { build: { command: 'node build.mjs', - untrackedEnv: ['CI', 'GITHUB_ACTIONS'], + cache: { + untrackedEnv: ['CI', 'GITHUB_ACTIONS'], + }, }, } ``` -`untrackedEnv` accepts the same wildcard and `!` exclusion patterns as [`env`](#env). +`untrackedEnv` accepts the same wildcard and `!` exclusion patterns as [`env`](#cache-env). Do not put a variable in `untrackedEnv` if its value changes the task result. If a cache-reporting tool covers the variable through [automatic tracking](/guide/automatic-data-tracking#cooperative-tracking), leave it out of both `env` and `untrackedEnv`. @@ -222,7 +242,7 @@ Vite Task passes a set of common environment variables to all tasks: - **CI/CD:** `CI`, `VERCEL_*`, `NEXT_*`, `GITHUB_*`, `RUNNER_*`, `ACTIONS_ID_TOKEN_REQUEST_URL`, `ACTIONS_ID_TOKEN_REQUEST_TOKEN` - **Terminal:** Color variables (`FORCE_COLOR`, `NO_COLOR`, `COLORTERM`, `TERM`, `TERM_PROGRAM`) aren't passed to tasks unless you list them under `env` (the value gets fingerprinted, so changing it invalidates the cache) or `untrackedEnv` (passed without fingerprinting). If `FORCE_COLOR` isn't in either list, the child gets `FORCE_COLOR=1` so cached logs stay colored. Colors get stripped on display when the terminal can't render them. -### `input` +### `cache.input` - **Type:** `Array` - **Default:** `[{ auto: true }]` (auto-inferred) @@ -235,8 +255,10 @@ Vite Task automatically detects which files a command uses. See [Automatic Data tasks: { build: { command: 'vp build', - // Use `{ auto: true }` to use automatic fingerprinting (default). - input: [{ auto: true }, '!**/*.tsbuildinfo', '!dist/**'], + cache: { + // Use `{ auto: true }` to use automatic fingerprinting (default). + input: [{ auto: true }, '!**/*.tsbuildinfo', '!dist/**'], + }, }, } ``` @@ -247,7 +269,9 @@ tasks: { tasks: { build: { command: 'vp build', - input: ['src/**/*.ts', 'vite.config.ts'], + cache: { + input: ['src/**/*.ts', 'vite.config.ts'], + }, }, } ``` @@ -258,10 +282,12 @@ tasks: { tasks: { build: { command: 'vp build', - input: [ - { auto: true }, - { pattern: 'shared-config/**', base: 'workspace' }, - ], + cache: { + input: [ + { auto: true }, + { pattern: 'shared-config/**', base: 'workspace' }, + ], + }, }, } ``` @@ -277,7 +303,9 @@ The `base` field is required and controls how the glob pattern is resolved: tasks: { greet: { command: 'node greet.mjs', - input: [], + cache: { + input: [], + }, }, } ``` @@ -286,7 +314,7 @@ tasks: { String glob patterns are resolved relative to the package directory by default. Use the object form with `base: "workspace"` to resolve relative to the workspace root. ::: -### `output` +### `cache.output` - **Type:** `Array` - **Default:** automatic write tracking @@ -299,7 +327,9 @@ If you omit `output`, Vite Task uses automatic write tracking to choose those fi tasks: { build: { command: 'node build.mjs', - output: ['dist/**', '!dist/cache/**'], + cache: { + output: ['dist/**', '!dist/cache/**'], + }, }, } ``` @@ -312,7 +342,9 @@ This is useful when a task writes files that should not be restored from the cac tasks: { typecheck: { command: 'tsc --build', - output: [{ auto: true }, '!*.tsbuildinfo'], + cache: { + output: [{ auto: true }, '!*.tsbuildinfo'], + }, }, } ``` @@ -323,10 +355,12 @@ If a task writes outside its own package, use the object form with `base: "works tasks: { build: { command: 'node build.mjs', - output: [ - 'dist/**', - { pattern: 'shared-artifacts/**', base: 'workspace' }, - ], + cache: { + output: [ + 'dist/**', + { pattern: 'shared-artifacts/**', base: 'workspace' }, + ], + }, }, } ``` @@ -337,7 +371,9 @@ Set `output: []` to disable output restoration for a cached task: tasks: { report: { command: 'node scripts/report.mjs', - output: [], + cache: { + output: [], + }, }, } ``` diff --git a/docs/guide/automatic-data-tracking.md b/docs/guide/automatic-data-tracking.md index 6ab679951e..32fe2061ac 100644 --- a/docs/guide/automatic-data-tracking.md +++ b/docs/guide/automatic-data-tracking.md @@ -4,7 +4,7 @@ Automatic data tracking is how Vite Task learns what inputs a task needs for cac When you run a cache-enabled task, Vite Task observes the task's execution and records what files were read and written, as well as any metadata reported by the task. On the next run, Vite Task uses the recorded fingerprint to decide whether to replay the cache or run the task. -Use this page when you need to understand why a task hits or misses the cache, or when you need to decide whether to add `input`, `output`, `env`, or `untrackedEnv` config. +Use this page when you need to understand why a task hits or misses the cache, or when you need to decide whether to add `cache.input`, `cache.output`, `cache.env`, or `cache.untrackedEnv` config. ## Tracking Tiers @@ -19,7 +19,7 @@ Vite Task starts with file system tracking for any command. A cache-reporting to ## File System Tracking -File system tracking applies to every cache-enabled task. If you omit [`input`](/config/run#input), Vite Task tracks the files a command reads while it runs: +File system tracking applies to every cache-enabled task. If you omit [`cache.input`](/config/run#cache-input), Vite Task tracks the files a command reads while it runs: ```ts [vite.config.ts] import { defineConfig } from 'vite-plus'; @@ -37,7 +37,7 @@ export default defineConfig({ For this task, Vite Task records source files, config files, missing files the command checked, and directories the command scanned. Subsequent runs re-run the task when one of those tracked inputs changes. -File system tracking also tracks outputs. If you omit [`output`](/config/run#output), Vite Task archives files the command writes after a successful run and restores them on a cache hit. +File system tracking also tracks outputs. If you omit [`cache.output`](/config/run#cache-output), Vite Task archives files the command writes after a successful run and restores them on a cache hit. ### Limitations @@ -45,13 +45,13 @@ Vite Task cannot track environment variable reads, and it cannot always tell whi Use [Override Inputs And Outputs](#override-inputs-and-outputs) when file system tracking includes files that should not affect the cache, misses files that should, or restores the wrong outputs. -Use [`env`](/config/run#env) when a command needs an environment variable and the value should affect the cache, or [`untrackedEnv`](/config/run#untrackedenv) when the value should not affect the cache. +Use [`cache.env`](/config/run#cache-env) when a command needs an environment variable and the value should affect the cache, or [`cache.untrackedEnv`](/config/run#cache-untrackedenv) when the value should not affect the cache. These limitations do not apply to `vp build`: Vite reports [Cooperative Tracking](#cooperative-tracking) metadata automatically, including `VITE_*`, `NODE_ENV`, and Vite-managed cache paths that should not become inputs or outputs. A standard `vp build` task does not need manual `input`, `output`, or `env`. ### Override Inputs And Outputs -[`input`](/config/run#input) controls what invalidates the cache. [`output`](/config/run#output) controls which files Vite Task restores on a cache hit. +[`cache.input`](/config/run#cache-input) controls what invalidates the cache. [`cache.output`](/config/run#cache-output) controls which files Vite Task restores on a cache hit. Both options use the same syntax and can be configured separately. @@ -65,12 +65,13 @@ Both options use the same syntax and can be configured separately. tasks: { build: { command: 'node build.mjs', + cache: { + // Keep automatic input tracking, but exclude `dist` from inputs. + input: [{ auto: true }, '!dist/**'], - // Keep automatic input tracking, but exclude `dist` from inputs. - input: [{ auto: true }, '!dist/**'], - - // Disable automatic output tracking and restore only `dist/**` on a cache hit. - output: ['dist/**'], + // Disable automatic output tracking and restore only `dist/**` on a cache hit. + output: ['dist/**'], + }, }, } ``` @@ -81,8 +82,10 @@ Use explicit `input` globs only when you know the command's full input set. This tasks: { lint: { command: 'vp lint', - // Disable automatic input tracking and fingerprint only these files. - input: ['src/**', 'vite.config.ts'], + cache: { + // Disable automatic input tracking and fingerprint only these files. + input: ['src/**', 'vite.config.ts'], + }, }, } ``` @@ -93,7 +96,9 @@ Set `input: []` when no files should affect the cache fingerprint. This is rarel tasks: { downloadSchema: { command: 'curl -O https://example.com/schema.json', - input: [], + cache: { + input: [], + }, }, } ``` @@ -128,13 +133,13 @@ export default defineConfig({ Run this task with `vpr frontendBuild` or `vp run frontendBuild`. -Manual config overrides reported metadata. Add `input`, `output`, `env`, or `untrackedEnv` when your project has behavior that Vite cannot report. +Manual config overrides reported metadata. Add `cache.input`, `cache.output`, `cache.env`, or `cache.untrackedEnv` when your project has behavior that Vite cannot report. Vite+ supports cooperative tracking for `vp build` today. It will extend this support to more first-party tools in the future. Third-party tools can report cache metadata with [`@voidzero-dev/vite-task-client`](https://npmx.dev/package/@voidzero-dev/vite-task-client). ## When To Add Manual Config -Add config when your project has behavior the command or tool cannot know. +Add config when your project has behavior the command or tool cannot know. These options go under the task's [`cache`](/config/run#cache) object. | Case | Example | | ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | diff --git a/docs/guide/cache.md b/docs/guide/cache.md index 0ef8735f5b..29af69e599 100644 --- a/docs/guide/cache.md +++ b/docs/guide/cache.md @@ -7,7 +7,7 @@ Vite Task can automatically track dependencies and cache tasks run through `vp r When a task runs successfully (exit code 0), its terminal output (stdout/stderr) and all written files (output files) are saved. On the next run, Vite Task checks if anything changed: 1. **Arguments:** did the [additional arguments](/guide/run#additional-arguments) passed to the task change? -2. **Environment variables:** did any [fingerprinted env vars](/config/run#env) change? +2. **Environment variables:** did any [fingerprinted env vars](/config/run#cache-env) change? 3. **Inputs:** did any input file that the command reads change? When all checks match, Vite Task replays the cached terminal output, restores saved output files, and skips the command. @@ -50,14 +50,16 @@ Vite Task uses [automatic data tracking](/guide/automatic-data-tracking) to lear - **File system tracking:** Vite Task records file reads, missing-file probes, directory listings, and written output files for every task with cache enabled. - **Cooperative tracking:** cache-reporting tools can report metadata that file system tracking cannot infer. Vite+ supports this for `vp build` today. -Use [`input`](/config/run#input) or [`output`](/config/run#output) when a task needs manual tracking rules. `input` controls what invalidates the cache. `output` controls which files Vite Task restores on a cache hit. +Use [`cache.input`](/config/run#cache-input) or [`cache.output`](/config/run#cache-output) when a task needs manual tracking rules. `input` controls what invalidates the cache. `output` controls which files Vite Task restores on a cache hit. ```ts [vite.config.ts] tasks: { build: { command: 'node build.mjs', - input: [{ auto: true }, '!dist/**'], - output: ['dist/**'], + cache: { + input: [{ auto: true }, '!dist/**'], + output: ['dist/**'], + }, }, } ``` @@ -66,20 +68,22 @@ tasks: { By default, tasks run in a clean environment. Only a small set of common variables, such as `PATH`, `HOME`, and `CI`, are passed through. Other environment variables are neither visible to the task nor included in the cache fingerprint. -To add an environment variable to the cache key, add it to [`env`](/config/run#env). Changing its value then invalidates the cache: +To add an environment variable to the cache key, add it to [`cache.env`](/config/run#cache-env). Changing its value then invalidates the cache: ```ts [vite.config.ts] tasks: { build: { command: 'webpack --mode production', - env: ['NODE_ENV'], + cache: { + env: ['NODE_ENV'], + }, }, } ``` -To pass a variable to the task **without** affecting cache behavior, use [`untrackedEnv`](/config/run#untrackedenv). This is useful for variables like `CI` or `GITHUB_ACTIONS` that should be available in the task, but do not affect caching behavior. +To pass a variable to the task **without** affecting cache behavior, use [`cache.untrackedEnv`](/config/run#cache-untrackedenv). This is useful for variables like `CI` or `GITHUB_ACTIONS` that should be available in the task, but do not affect caching behavior. -See [Run Config](/config/run#env) for details on wildcard patterns and the full list of automatically passed-through variables. +See [Run Config](/config/run#cache-env) for details on wildcard patterns and the full list of automatically passed-through variables. ## Cache Sharing diff --git a/docs/guide/run.md b/docs/guide/run.md index b1570eb0ca..b02776d06c 100644 --- a/docs/guide/run.md +++ b/docs/guide/run.md @@ -95,7 +95,9 @@ export default defineConfig({ build: { command: 'vp build', dependsOn: ['lint'], - env: ['NODE_ENV'], + cache: { + env: ['NODE_ENV'], + }, }, deploy: { command: 'deploy-script --prod', diff --git a/docs/vite.config.ts b/docs/vite.config.ts index 365e29530a..ab261a2e66 100644 --- a/docs/vite.config.ts +++ b/docs/vite.config.ts @@ -1,6 +1,8 @@ export default { run: { tasks: { + // Docs deploys build with the released `vp` from setup-vp. Keep the cache + // settings at the top level until a release requires them under `cache`. 'build:site': { command: 'vitepress build', // The docs and installer URLs depend on the explicit origin or Workers diff --git a/packages/cli/README.md b/packages/cli/README.md index 18b488b07d..7fe5ff62db 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -73,7 +73,9 @@ export default defineConfig({ tasks: { 'generate:icons': { command: 'node scripts/generate-icons.js', - env: ['ICON_THEME'], + cache: { + env: ['ICON_THEME'], + }, }, }, }, diff --git a/packages/cli/binding/Cargo.toml b/packages/cli/binding/Cargo.toml index 7099e4cfa5..2042f39c36 100644 --- a/packages/cli/binding/Cargo.toml +++ b/packages/cli/binding/Cargo.toml @@ -39,6 +39,7 @@ vp_static_config = { workspace = true } vp_toolchain = { workspace = true } vt_str = { workspace = true } vt = { workspace = true } +vt_casefold = { workspace = true } vt_workspace = { workspace = true } rolldown_binding = { workspace = true, optional = true, features = ["disable_panic_hook"] } diff --git a/packages/cli/binding/src/check/mod.rs b/packages/cli/binding/src/check/mod.rs index 3eb6505ff0..bad28e26cd 100644 --- a/packages/cli/binding/src/check/mod.rs +++ b/packages/cli/binding/src/check/mod.rs @@ -1,8 +1,7 @@ mod analysis; -use std::{ffi::OsStr, sync::Arc, time::Instant}; +use std::{sync::Arc, time::Instant}; -use rustc_hash::FxHashMap; use vp_error::Error; use vp_shared::output; use vt::ExitStatus; @@ -14,7 +13,8 @@ use self::analysis::{ print_stdout_block, print_summary_line, }; use crate::cli::{ - CapturedCommandOutput, SubcommandResolver, SynthesizableSubcommand, resolve_and_capture_output, + CapturedCommandOutput, EnvMap, SubcommandResolver, SynthesizableSubcommand, + resolve_and_capture_output, }; /// Execute the `vp check` composite command (fmt + lint + optional type checks). @@ -26,7 +26,7 @@ pub(crate) async fn execute_check( no_lint_flag: bool, no_error_on_unmatched_pattern: bool, paths: Vec, - envs: &Arc, Arc>>, + envs: &Arc, cwd: &AbsolutePathBuf, ) -> Result { let mut status = ExitStatus::SUCCESS; diff --git a/packages/cli/binding/src/cli/execution.rs b/packages/cli/binding/src/cli/execution.rs index 7d4b19991f..58772c1899 100644 --- a/packages/cli/binding/src/cli/execution.rs +++ b/packages/cli/binding/src/cli/execution.rs @@ -1,45 +1,34 @@ -use std::{borrow::Cow, ffi::OsStr, process::Stdio, sync::Arc}; +use std::{borrow::Cow, process::Stdio, sync::Arc}; -use rustc_hash::FxHashMap; use vp_error::Error; use vt::ExitStatus; use vt_path::AbsolutePathBuf; use super::{ resolver::SubcommandResolver, - types::{CapturedCommandOutput, SynthesizableSubcommand, exit_status_from}, + types::{CapturedCommandOutput, EnvMap, SynthesizableSubcommand, exit_status_from}, }; /// Resolve a subcommand into a prepared `tokio::process::Command`. async fn resolve_and_build_command( resolver: &SubcommandResolver, subcommand: SynthesizableSubcommand, - envs: &Arc, Arc>>, + envs: &Arc, cwd: &AbsolutePathBuf, ) -> Result { let resolved = resolver.resolve(subcommand, envs, cwd).await.map_err(Error::Anyhow)?; // Resolve the program path using `which` to handle Windows .cmd/.bat files (PATHEXT) - let program_path = { - let paths = resolved.envs.iter().find_map(|(k, v)| { - let is_path = if cfg!(windows) { - k.as_ref().eq_ignore_ascii_case("PATH") - } else { - k.as_ref() == "PATH" - }; - if is_path { Some(v.as_ref().to_os_string()) } else { None } - }); - vp_command::resolve_bin( - resolved.program.as_ref().to_str().unwrap_or_default(), - paths.as_deref(), - cwd, - )? - }; + let program_path = vp_command::resolve_bin( + resolved.program.as_ref().to_str().unwrap_or_default(), + vt::get_path_env(&resolved.envs).map(AsRef::as_ref), + cwd, + )?; let mut cmd = vp_command::build_command(&program_path, cwd); cmd.args(resolved.args.iter().map(|s| s.as_str())) .env_clear() - .envs(resolved.envs.iter().map(|(k, v)| (k.as_ref(), v.as_ref()))); + .envs(resolved.envs.iter().map(|(k, v)| (k.inner(), v))); Ok(cmd) } @@ -47,7 +36,7 @@ async fn resolve_and_build_command( pub(super) async fn resolve_and_execute( resolver: &SubcommandResolver, subcommand: SynthesizableSubcommand, - envs: &Arc, Arc>>, + envs: &Arc, cwd: &AbsolutePathBuf, ) -> Result { let is_interactive = matches!( @@ -77,7 +66,7 @@ pub(super) enum FilterStream { pub(super) async fn resolve_and_execute_with_filter( resolver: &SubcommandResolver, subcommand: SynthesizableSubcommand, - envs: &Arc, Arc>>, + envs: &Arc, cwd: &AbsolutePathBuf, stream: FilterStream, filter: impl Fn(&str) -> Cow<'_, str>, @@ -109,7 +98,7 @@ pub(super) async fn resolve_and_execute_with_filter( pub(crate) async fn resolve_and_capture_output( resolver: &SubcommandResolver, subcommand: SynthesizableSubcommand, - envs: &Arc, Arc>>, + envs: &Arc, cwd: &AbsolutePathBuf, force_color_if_terminal: bool, ) -> Result { diff --git a/packages/cli/binding/src/cli/mod.rs b/packages/cli/binding/src/cli/mod.rs index 778da0886f..b03fb65426 100644 --- a/packages/cli/binding/src/cli/mod.rs +++ b/packages/cli/binding/src/cli/mod.rs @@ -18,16 +18,16 @@ use cow_utils::CowUtils; pub(crate) use execution::resolve_and_capture_output; // Re-exports for lib.rs and check/mod.rs pub use resolver::SubcommandResolver; -use rustc_hash::FxHashMap; -pub(crate) use types::CapturedCommandOutput; pub use types::{ BoxedResolverFn, CliOptions, ResolveCommandResult, SynthesizableSubcommand, ToolchainArgs, ViteConfigResolverFn, }; +pub(crate) use types::{CapturedCommandOutput, EnvMap}; use vp_error::Error; pub use vp_shared::init_tracing; use vp_shared::{PrependOptions, env_vars, prepend_tools_to_path_env}; use vt::{ExitStatus, Session, SessionConfig}; +use vt_casefold::EnvName; use vt_path::{AbsolutePath, AbsolutePathBuf}; use vt_str::Str; @@ -76,16 +76,19 @@ async fn execute_direct_subcommand( SubcommandResolver::new(Arc::clone(&workspace_path)) }; - let envs: Arc, Arc>> = Arc::new({ - let mut envs: FxHashMap, Arc> = std::env::vars_os() - .map(|(k, v)| (Arc::from(k.as_os_str()), Arc::from(v.as_os_str()))) + let envs: Arc = Arc::new({ + let mut envs: EnvMap = std::env::vars_os() + .map(|(k, v)| (EnvName::new(Arc::from(k.as_os_str())), Arc::from(v.as_os_str()))) .collect(); // When elicitation retargeted the command, the tool runs with the // target as its working directory: keep the POSIX PWD consistent, // like a real `cd`. Untargeted runs keep the caller's PWD verbatim // (it may legitimately differ from cwd through shell symlinks). if cfg!(unix) && retargeted { - envs.insert(Arc::from(OsStr::new("PWD")), Arc::from(cwd.as_path().as_os_str())); + envs.insert( + EnvName::new(Arc::from(OsStr::new("PWD"))), + Arc::from(cwd.as_path().as_os_str()), + ); } envs }); @@ -143,21 +146,12 @@ async fn execute_direct_subcommand( Ok(status) } -fn is_path_env_key(key: &OsStr) -> bool { - if cfg!(windows) { key.eq_ignore_ascii_case("PATH") } else { key == "PATH" } -} - fn try_prepend_to_env_path( - envs: &Arc, Arc>>, + envs: &Arc, bin_prefix: &AbsolutePath, -) -> Result, Arc>>, Error> { - let path_key = envs - .keys() - .find(|key| is_path_env_key(key.as_ref())) - .cloned() - .unwrap_or_else(|| Arc::from(OsStr::new("PATH"))); +) -> Result, Error> { let current_path = - envs.get(&path_key).map_or_else(Default::default, |path| path.to_os_string()); + vt::get_path_env(envs).map_or_else(Default::default, |path| path.to_os_string()); let paths = if current_path.is_empty() { Vec::new() } else { @@ -173,15 +167,13 @@ fn try_prepend_to_env_path( ) .map_err(|error| Error::Anyhow(anyhow::Error::new(error)))?; - let mut envs = FxHashMap::clone(envs); - envs.insert(path_key, Arc::from(new_path.as_os_str())); + let mut envs = EnvMap::clone(envs); + // An existing PATH keeps its spelling (Windows commonly uses `Path`). + envs.insert(EnvName::new(Arc::from(OsStr::new("PATH"))), Arc::from(new_path.as_os_str())); Ok(Arc::new(envs)) } -fn prepend_to_env_path( - envs: &Arc, Arc>>, - bin_prefix: &AbsolutePath, -) -> Arc, Arc>> { +fn prepend_to_env_path(envs: &Arc, bin_prefix: &AbsolutePath) -> Arc { match try_prepend_to_env_path(envs, bin_prefix) { Ok(updated_envs) => updated_envs, Err(error) => { @@ -196,8 +188,8 @@ fn prepend_to_env_path( async fn envs_with_explicit_package_manager_path( cwd: &AbsolutePath, - envs: Arc, Arc>>, -) -> Result, Arc>>, Error> { + envs: Arc, +) -> Result, Error> { let Some(resolution) = (match vp_pm_cli::resolve_package_manager_from_package_json(cwd) { Ok(resolution) => resolution, Err(error) => { @@ -451,14 +443,17 @@ mod tests { time::{SystemTime, UNIX_EPOCH}, }; - use rustc_hash::FxHashMap; use vt::config::UserRunConfig; + use vt_casefold::EnvName; use vt_path::AbsolutePathBuf; - use super::{Error, envs_with_explicit_package_manager_path, prepend_to_env_path}; + use super::{EnvMap, Error, envs_with_explicit_package_manager_path, prepend_to_env_path}; - fn envs_with_path(path: &std::ffi::OsStr) -> Arc, Arc>> { - Arc::new(FxHashMap::from_iter([(Arc::from(OsStr::new("PATH")), Arc::from(path))])) + fn envs_with_path(path: &std::ffi::OsStr) -> Arc { + Arc::new(EnvMap::from_iter([( + EnvName::new(Arc::from(OsStr::new("PATH"))), + Arc::from(path), + )])) } #[test] @@ -470,7 +465,7 @@ mod tests { let envs = envs_with_path(original_path.as_os_str()); let updated = prepend_to_env_path(&envs, &pm_bin); - let path_value = updated.get(OsStr::new("PATH")).expect("PATH should exist"); + let path_value = vt::get_path_env(&updated).expect("PATH should exist"); let paths = std::env::split_paths(path_value).collect::>(); assert_eq!(paths.first().map(std::path::PathBuf::as_path), Some(pm_bin.as_path())); @@ -485,7 +480,7 @@ mod tests { let envs = envs_with_path(original_path.as_os_str()); let updated = prepend_to_env_path(&envs, &pm_bin); - let path_value = updated.get(OsStr::new("PATH")).expect("PATH should exist"); + let path_value = vt::get_path_env(&updated).expect("PATH should exist"); let paths = std::env::split_paths(path_value).collect::>(); assert_eq!(paths, vec![pm_bin.as_path().to_path_buf()]); @@ -495,10 +490,10 @@ mod tests { fn creates_path_when_env_map_has_no_path() { let cwd = std::env::current_dir().expect("current_dir should exist"); let pm_bin = AbsolutePathBuf::new(cwd.join("pm-bin")).expect("pm bin should be absolute"); - let envs = Arc::new(FxHashMap::default()); + let envs = Arc::new(EnvMap::default()); let updated = prepend_to_env_path(&envs, &pm_bin); - let path_value = updated.get(OsStr::new("PATH")).expect("PATH should be created"); + let path_value = vt::get_path_env(&updated).expect("PATH should be created"); let paths = std::env::split_paths(path_value).collect::>(); assert_eq!(paths, vec![pm_bin.as_path().to_path_buf()]); @@ -511,13 +506,16 @@ mod tests { let pm_bin = AbsolutePathBuf::new(cwd.join("pm-bin")).expect("pm bin should be absolute"); let original_path = std::env::join_paths([old_bin.as_path()]).expect("valid PATH"); let key = if cfg!(windows) { "Path" } else { "PATH" }; - let envs = Arc::new(FxHashMap::from_iter([( - Arc::from(OsStr::new(key)), + let envs = Arc::new(EnvMap::from_iter([( + EnvName::new(Arc::from(OsStr::new(key))), Arc::from(original_path.as_os_str()), )])); let updated = prepend_to_env_path(&envs, &pm_bin); - let path_value = updated.get(OsStr::new(key)).expect("existing PATH key should be updated"); + let [(path_key, path_value)] = updated.iter().collect::>()[..] else { + panic!("the existing PATH entry should be updated in place: {updated:?}"); + }; + assert_eq!(path_key.inner().as_ref(), OsStr::new(key)); let paths = std::env::split_paths(path_value).collect::>(); assert_eq!(paths.first().map(std::path::PathBuf::as_path), Some(pm_bin.as_path())); @@ -543,7 +541,7 @@ mod tests { .await .expect("package manager preflight errors should not fail direct commands"); - assert_eq!(updated.get(OsStr::new("PATH")), envs.get(OsStr::new("PATH"))); + assert_eq!(vt::get_path_env(&updated), vt::get_path_env(&envs)); fs::remove_dir_all(temp_dir).expect("temp dir should be removed"); } @@ -602,7 +600,7 @@ mod tests { .await .expect("missing packageManager should not error"); - assert_eq!(updated.get(OsStr::new("PATH")), envs.get(OsStr::new("PATH"))); + assert_eq!(vt::get_path_env(&updated), vt::get_path_env(&envs)); assert_eq!( fs::read_to_string(temp_dir.join("package.json")).expect("package.json should exist"), r#"{"name":"fixture"}"# diff --git a/packages/cli/binding/src/cli/resolver.rs b/packages/cli/binding/src/cli/resolver.rs index 7eccaf25b8..12255f7b5e 100644 --- a/packages/cli/binding/src/cli/resolver.rs +++ b/packages/cli/binding/src/cli/resolver.rs @@ -1,15 +1,18 @@ use std::{env, ffi::OsStr, iter, sync::Arc}; -use rustc_hash::FxHashMap; use vt::config::user::{ AutoTracking, EnabledCacheConfig, GlobWithBase, InputBase, UserCacheConfig, UserInputEntry, }; +use vt_casefold::EnvName; use vt_path::AbsolutePath; use vt_str::Str; use super::{ help::should_prepend_vitest_run, - types::{CliOptions, ResolvedSubcommand, ResolvedUniversalViteConfig, SynthesizableSubcommand}, + types::{ + CliOptions, EnvMap, ResolvedSubcommand, ResolvedUniversalViteConfig, + SynthesizableSubcommand, + }, }; /// Resolves synthesizable subcommands to concrete programs and arguments. @@ -81,7 +84,7 @@ impl SubcommandResolver { pub(super) async fn resolve( &self, subcommand: SynthesizableSubcommand, - envs: &Arc, Arc>>, + envs: &Arc, cwd: &AbsolutePath, ) -> anyhow::Result { match subcommand { @@ -327,25 +330,23 @@ pub(super) fn check_cache_inputs() -> Vec { ] } -fn merge_resolved_envs( - envs: &Arc, Arc>>, - resolved_envs: Vec<(String, String)>, -) -> Arc, Arc>> { - let mut envs = FxHashMap::clone(envs); +fn merge_resolved_envs(envs: &Arc, resolved_envs: Vec<(String, String)>) -> Arc { + let mut envs = EnvMap::clone(envs); for (k, v) in resolved_envs { - envs.entry(Arc::from(OsStr::new(&k))).or_insert_with(|| Arc::from(OsStr::new(&v))); + envs.entry(EnvName::new(Arc::from(OsStr::new(&k)))) + .or_insert_with(|| Arc::from(OsStr::new(&v))); } Arc::new(envs) } /// Merge resolved envs and inject VP_VERSION for rolldown-vite branding. fn merge_resolved_envs_with_version( - envs: &Arc, Arc>>, + envs: &Arc, resolved_envs: Vec<(String, String)>, -) -> Arc, Arc>> { +) -> Arc { let mut merged = merge_resolved_envs(envs, resolved_envs); let map = Arc::make_mut(&mut merged); - map.entry(Arc::from(OsStr::new("VP_VERSION"))) + map.entry(EnvName::new(Arc::from(OsStr::new("VP_VERSION")))) .or_insert_with(|| Arc::from(OsStr::new(env!("CARGO_PKG_VERSION")))); merged } @@ -392,7 +393,7 @@ mod tests { let runtime: Arc = Arc::from(cwd.join("custom runtime").as_path().as_os_str()); let resolver = SubcommandResolver::new(cwd.clone().into()) .with_cli_options(cli_options(Arc::clone(&runtime))); - let envs = Arc::new(FxHashMap::default()); + let envs = Arc::new(EnvMap::default()); for command in [ SynthesizableSubcommand::Lint { args: vec![] }, SynthesizableSubcommand::Fmt { args: vec![] }, @@ -414,7 +415,7 @@ mod tests { let cwd = AbsolutePathBuf::new(temp.path().to_path_buf()).unwrap(); let resolver = SubcommandResolver::new(cwd.clone().into()) .with_cli_options(cli_options(Arc::from(OsStr::new("node")))); - let envs = Arc::new(FxHashMap::default()); + let envs = Arc::new(EnvMap::default()); for args in [ &["src"][..], @@ -445,7 +446,7 @@ mod tests { let root = AbsolutePathBuf::new(temp.path().to_path_buf()).unwrap(); let cwd = root.join("packages/app"); let config_file = root.join("vite config.mts").as_path().to_str().unwrap().to_string(); - let envs = Arc::new(FxHashMap::default()); + let envs = Arc::new(EnvMap::default()); for (mut config, has_lint, has_fmt) in [ (serde_json::json!({}), false, false), @@ -496,7 +497,7 @@ mod tests { let cwd = root.join("packages/app"); let resolver = SubcommandResolver::new(root.into()) .with_cli_options(cli_options(Arc::from(OsStr::new("node")))); - let envs = Arc::new(FxHashMap::default()); + let envs = Arc::new(EnvMap::default()); for args in [ &["-c", "custom.json", "index.ts"][..], diff --git a/packages/cli/binding/src/cli/types.rs b/packages/cli/binding/src/cli/types.rs index 612ae29339..1f17529436 100644 --- a/packages/cli/binding/src/cli/types.rs +++ b/packages/cli/binding/src/cli/types.rs @@ -4,9 +4,14 @@ use clap::{Parser, Subcommand}; use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; use vt::{Command, ExitStatus, config::user::UserCacheConfig, plan_request::SyntheticPlanRequest}; +use vt_casefold::EnvName; use vt_path::AbsolutePath; use vt_str::Str; +/// Environment variables for a spawned command. Names compare by the platform's +/// rules (ASCII case-insensitive on Windows), the same as vite-task's session envs. +pub(crate) type EnvMap = FxHashMap>, Arc>; + /// Resolved configuration from vite.config.ts #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub(crate) struct ResolvedUniversalViteConfig { @@ -173,7 +178,7 @@ pub(super) struct ResolvedSubcommand { pub(super) program: Arc, pub(super) args: Arc<[Str]>, pub(super) cache_config: UserCacheConfig, - pub(super) envs: Arc, Arc>>, + pub(super) envs: Arc, } impl ResolvedSubcommand { diff --git a/packages/cli/src/run-config.ts b/packages/cli/src/run-config.ts index cd780fce5b..b32282aefa 100644 --- a/packages/cli/src/run-config.ts +++ b/packages/cli/src/run-config.ts @@ -45,11 +45,19 @@ cwd?: string, * `{ "task": "build", "from": "dependencies" }` runs `build` in each * direct workspace dependency that defines a `build` task. */ -dependsOn?: Array, } & ({ +dependsOn?: Array, /** - * Whether to cache the task + * Whether and how to cache the task. + * + * - Omitted or `true`: caching enabled with default settings (same as `{}`) + * - `false`: caching disabled + * - Object: caching enabled with the given settings */ -cache?: true, +cache?: TaskCache, }; + +export type TaskCache = boolean | TaskCacheConfig; + +export type TaskCacheConfig = { /** * Environment variable names to be fingerprinted and passed to the task. */ @@ -79,11 +87,7 @@ input?: Array, * - `{auto: true}` enables automatic output tracking * - Negative patterns (e.g. `"!dist/cache/**"`) exclude matched files */ -output?: Array, } | { -/** - * Whether to cache the task - */ -cache: false, }); +output?: Array, }; export type TaskDefinition = Task | Command; @@ -100,7 +104,8 @@ scripts?: boolean, /** * Global cache kill switch for task entries. * - * When `false`, overrides all tasks to disable caching, even tasks with `cache: true`. + * When `false`, overrides all tasks to disable caching, even tasks with `cache: true` + * or a `cache` object. * When `true`, respects each task's individual `cache` setting * (each task's `cache` defaults to `true` if omitted). *