11use std:: {
22 cell:: RefCell ,
33 ffi:: OsStr ,
4- io:: { self , Read , Write } ,
5- sync:: Arc ,
4+ io:: { self , Write } ,
65} ;
76
8- use native_str:: NativeStr ;
9- use rustc_hash:: FxHashMap ;
10- use vite_path:: { self , AbsolutePath } ;
11- use vite_task_ipc_shared:: { GetEnvResponse , GetEnvsResponse , IPC_ENV_NAME , Request } ;
7+ use vite_task_ipc_shared:: { IPC_ENV_NAME , Request } ;
128
139#[ cfg( unix) ]
1410type Stream = std:: os:: unix:: net:: UnixStream ;
@@ -17,7 +13,6 @@ type Stream = std::fs::File;
1713
1814pub struct Client {
1915 stream : RefCell < Stream > ,
20- scratch : RefCell < Vec < u8 > > ,
2116}
2217
2318impl Client {
@@ -43,104 +38,22 @@ impl Client {
4338 }
4439
4540 const fn from_stream ( stream : Stream ) -> Self {
46- Self { stream : RefCell :: new ( stream) , scratch : RefCell :: new ( Vec :: new ( ) ) }
41+ Self { stream : RefCell :: new ( stream) }
4742 }
4843
49- /// `path` can be a file or a directory; for a directory, all files inside
50- /// it are ignored. Relative paths are resolved against the current working
51- /// directory before being sent to the runner.
52- ///
5344 /// Fire-and-forget: the call returns once the request is flushed to the
5445 /// kernel pipe buffer; the runner processes it during its drain phase
5546 /// after this process exits. See the `Request` type in the IPC protocol
5647 /// crate for why this is safe.
5748 ///
5849 /// # Errors
5950 ///
60- /// Returns an error if the request fails to send, or (for a relative
61- /// `path`) if the current working directory cannot be read.
62- pub fn ignore_input ( & self , path : & OsStr ) -> io:: Result < ( ) > {
63- let ns = resolve_path ( path) ?;
64- self . send ( & Request :: IgnoreInput ( & ns) )
65- }
66-
67- /// `path` can be a file or a directory; for a directory, all files inside
68- /// it are ignored. Relative paths are resolved against the current working
69- /// directory before being sent to the runner.
70- ///
71- /// Fire-and-forget — see [`Self::ignore_input`].
72- ///
73- /// # Errors
74- ///
75- /// Returns an error if the request fails to send, or (for a relative
76- /// `path`) if the current working directory cannot be read.
77- pub fn ignore_output ( & self , path : & OsStr ) -> io:: Result < ( ) > {
78- let ns = resolve_path ( path) ?;
79- self . send ( & Request :: IgnoreOutput ( & ns) )
80- }
81-
82- /// Fire-and-forget — see [`Self::ignore_input`].
83- ///
84- /// # Errors
85- ///
8651 /// Returns an error if the request fails to send.
8752 pub fn disable_cache ( & self ) -> io:: Result < ( ) > {
8853 self . send ( & Request :: DisableCache )
8954 }
9055
91- /// Requests an env value from the runner. Returns `None` if the runner reports
92- /// the env is not available.
93- ///
94- /// # Errors
95- ///
96- /// Returns an error if the request or response fails.
97- pub fn get_env ( & self , name : & OsStr , tracked : bool ) -> io:: Result < Option < Arc < OsStr > > > {
98- let name = Box :: < NativeStr > :: from ( name) ;
99-
100- self . send ( & Request :: GetEnv { name : & name, tracked } ) ?;
101- self . recv_with ( |bytes| {
102- let response: GetEnvResponse < ' _ > = wincode:: deserialize_exact ( bytes)
103- . map_err ( |err| io:: Error :: new ( io:: ErrorKind :: InvalidData , err) ) ?;
104- Ok ( response
105- . env_value
106- . map ( |env_value| Arc :: < OsStr > :: from ( env_value. to_cow_os_str ( ) . as_ref ( ) ) ) )
107- } )
108- }
109-
110- /// Requests every env whose name matches `pattern` from the runner. The
111- /// returned map is keyed by env name with its value.
112- ///
113- /// Unlike [`Self::get_env`], this always round-trips to the server — the
114- /// client has no way to know in advance which names the pattern matches.
115- /// Env names that aren't valid UTF-8 are silently dropped at the server.
116- ///
117- /// # Errors
118- ///
119- /// Returns an error if the request or response fails, or if the server
120- /// rejected the pattern as an invalid glob.
121- pub fn get_envs (
122- & self ,
123- pattern : & str ,
124- tracked : bool ,
125- ) -> io:: Result < FxHashMap < Arc < OsStr > , Arc < OsStr > > > {
126- self . send ( & Request :: GetEnvs { pattern, tracked } ) ?;
127- self . recv_with ( |bytes| {
128- let response: GetEnvsResponse < ' _ > = wincode:: deserialize_exact ( bytes)
129- . map_err ( |err| io:: Error :: new ( io:: ErrorKind :: InvalidData , err) ) ?;
130- Ok ( response
131- . entries
132- . iter ( )
133- . map ( |( name, value) | {
134- (
135- Arc :: < OsStr > :: from ( name. to_cow_os_str ( ) . as_ref ( ) ) ,
136- Arc :: < OsStr > :: from ( value. to_cow_os_str ( ) . as_ref ( ) ) ,
137- )
138- } )
139- . collect ( ) )
140- } )
141- }
142-
143- fn send ( & self , request : & Request < ' _ > ) -> io:: Result < ( ) > {
56+ fn send ( & self , request : & Request ) -> io:: Result < ( ) > {
14457 let bytes = wincode:: serialize ( request)
14558 . map_err ( |err| io:: Error :: new ( io:: ErrorKind :: InvalidData , err) ) ?;
14659 let len = u32:: try_from ( bytes. len ( ) )
@@ -151,18 +64,6 @@ impl Client {
15164 stream. flush ( ) ?;
15265 Ok ( ( ) )
15366 }
154-
155- fn recv_with < T > ( & self , extract : impl FnOnce ( & [ u8 ] ) -> io:: Result < T > ) -> io:: Result < T > {
156- let mut stream = self . stream . borrow_mut ( ) ;
157- let mut scratch = self . scratch . borrow_mut ( ) ;
158- let mut len_bytes = [ 0u8 ; 4 ] ;
159- stream. read_exact ( & mut len_bytes) ?;
160- let len = u32:: from_le_bytes ( len_bytes) as usize ;
161- scratch. clear ( ) ;
162- scratch. resize ( len, 0 ) ;
163- stream. read_exact ( & mut scratch) ?;
164- extract ( & scratch)
165- }
16667}
16768
16869#[ cfg( unix) ]
@@ -216,49 +117,3 @@ fn connect(name: &OsStr) -> io::Result<Stream> {
216117 }
217118 }
218119}
219-
220- #[ expect(
221- clippy:: disallowed_types,
222- reason = "std::path::PathBuf is needed to round-trip through std::fs::canonicalize on Windows below"
223- ) ]
224- fn resolve_path ( path : & OsStr ) -> io:: Result < Box < NativeStr > > {
225- let absolute: std:: path:: PathBuf = if let Some ( abs) = AbsolutePath :: new ( path) {
226- abs. as_path ( ) . to_path_buf ( )
227- } else {
228- let mut buf = vite_path:: current_dir ( ) ?;
229- buf. push ( path) ;
230- buf. as_path ( ) . to_path_buf ( )
231- } ;
232-
233- // On Windows, canonicalize so the path uses the exact on-disk casing
234- // and resolves substitute drives / junctions the same way `fspy`'s
235- // `GetFinalPathNameByHandleW`-reported paths do. Without this, an
236- // `ignoreInput("cache_like")` whose `current_dir()` prefix differs in
237- // case or symlink shape from the fspy-reported reads won't filter
238- // them out, and the runner sees a read/write overlap. Strip the
239- // `\\?\` namespace prefix because `fspy_shared::NativePath::
240- // strip_path_prefix` does the same on the runner side; if the
241- // canonical form starts with `\\?\UNC\`, fall back to the
242- // non-canonical form so we don't accidentally rewrite a UNC path
243- // (where dropping `\\?\` would change meaning).
244- #[ cfg( windows) ]
245- let absolute = std:: fs:: canonicalize ( & absolute) . map_or ( absolute, |canonical| {
246- use std:: {
247- ffi:: OsString ,
248- os:: windows:: ffi:: { OsStrExt , OsStringExt } ,
249- } ;
250- let wide: Vec < u16 > = canonical. as_os_str ( ) . encode_wide ( ) . collect ( ) ;
251- let unc_prefix: Vec < u16 > = r"\\?\UNC\" . encode_utf16 ( ) . collect ( ) ;
252- let nt_prefix: Vec < u16 > = r"\\?\" . encode_utf16 ( ) . collect ( ) ;
253- if wide. starts_with ( & unc_prefix) {
254- // UNC path — keep canonical form (still has \\?\UNC\ for fspy parity).
255- canonical
256- } else if let Some ( rest) = wide. strip_prefix ( nt_prefix. as_slice ( ) ) {
257- std:: path:: PathBuf :: from ( OsString :: from_wide ( rest) )
258- } else {
259- canonical
260- }
261- } ) ;
262-
263- Ok ( Box :: < NativeStr > :: from ( absolute. as_os_str ( ) ) )
264- }
0 commit comments