Skip to content

Commit c318ec9

Browse files
committed
fix(env): use rename-before-copy for all Windows shims on refresh
On Windows, .exe files may be locked by antivirus, search indexer, or still-running processes. The remove_file call fails with "Access denied" (os error 5), preventing npm/npx/vpx shims from being refreshed. Apply the same rename-to-.old pattern used for vp.exe to all tool shims during --refresh. Cleanup of .old files runs after all shims are created.
1 parent 5fb8073 commit c318ec9

1 file changed

Lines changed: 21 additions & 2 deletions

File tree

  • crates/vite_global_cli/src/commands/env

crates/vite_global_cli/src/commands/env/setup.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ pub async fn execute(refresh: bool, env_only: bool) -> Result<ExitStatus, Error>
7979
}
8080
}
8181

82+
// Best-effort cleanup of .old files from rename-before-copy on Windows
83+
#[cfg(windows)]
84+
cleanup_old_files(&bin_dir).await;
85+
8286
// Print results
8387
if !created.is_empty() {
8488
println!("{}", help::render_heading("Created Shims"));
@@ -194,8 +198,23 @@ async fn create_shim(
194198
if !refresh {
195199
return Ok(false);
196200
}
197-
// Remove existing shim for refresh
198-
tokio::fs::remove_file(&shim_path).await?;
201+
// Remove existing shim for refresh.
202+
// On Windows, .exe files may be locked (by antivirus, indexer, or
203+
// still-running processes), so rename to .old first instead of deleting.
204+
#[cfg(windows)]
205+
{
206+
let timestamp = std::time::SystemTime::now()
207+
.duration_since(std::time::UNIX_EPOCH)
208+
.unwrap_or_default()
209+
.as_secs();
210+
let old_name = format!("{}.{timestamp}.old", shim_filename(tool));
211+
let old_path = bin_dir.join(&old_name);
212+
let _ = tokio::fs::rename(&shim_path, &old_path).await;
213+
}
214+
#[cfg(not(windows))]
215+
{
216+
tokio::fs::remove_file(&shim_path).await?;
217+
}
199218
}
200219

201220
#[cfg(unix)]

0 commit comments

Comments
 (0)