11import * as fs from "fs"
22import * as path from "path"
3+ import { execSync } from "child_process"
34
45import { ViewsContainer , Views , Menus , Configuration , contributesSchema } from "./types.js"
56
@@ -22,23 +23,50 @@ function copyDir(srcDir: string, dstDir: string, count: number): number {
2223 return count
2324}
2425
25- function rmDir ( dirPath : string , maxRetries : number = 3 ) : void {
26+ function rmDir ( dirPath : string , maxRetries : number = 5 ) : void {
2627 for ( let attempt = 1 ; attempt <= maxRetries ; attempt ++ ) {
2728 try {
2829 fs . rmSync ( dirPath , { recursive : true , force : true } )
2930 return
3031 } catch ( error ) {
3132 const isLastAttempt = attempt === maxRetries
3233
33- const isEnotemptyError =
34- error instanceof Error && "code" in error && ( error . code === "ENOTEMPTY" || error . code === "EBUSY" )
34+ const isRetryableError =
35+ error instanceof Error &&
36+ "code" in error &&
37+ ( error . code === "ENOTEMPTY" ||
38+ error . code === "EBUSY" ||
39+ error . code === "EPERM" ||
40+ error . code === "EACCES" )
41+
42+ if ( isLastAttempt ) {
43+ // On the last attempt, try alternative cleanup methods.
44+ try {
45+ console . warn ( `[rmDir] Final attempt using alternative cleanup for ${ dirPath } ` )
46+
47+ // Try to clear readonly flags on Windows.
48+ if ( process . platform === "win32" ) {
49+ try {
50+ execSync ( `attrib -R "${ dirPath } \\*.*" /S /D` , { stdio : "ignore" } )
51+ } catch {
52+ // Ignore attrib errors.
53+ }
54+ }
55+ fs . rmSync ( dirPath , { recursive : true , force : true , maxRetries : 3 , retryDelay : 100 } )
56+ return
57+ } catch ( finalError ) {
58+ console . error ( `[rmDir] Failed to remove ${ dirPath } after ${ maxRetries } attempts:` , finalError )
59+ throw finalError
60+ }
61+ }
3562
36- if ( isLastAttempt || ! isEnotemptyError ) {
37- throw error // Re-throw if it's the last attempt or not a locking error.
63+ if ( ! isRetryableError ) {
64+ throw error // Re-throw if it's not a retryable error.
3865 }
3966
40- // Wait with exponential backoff before retrying.
41- const delay = Math . min ( 100 * Math . pow ( 2 , attempt - 1 ) , 1000 ) // Cap at 1s.
67+ // Wait with exponential backoff before retrying, with longer delays for Windows.
68+ const baseDelay = process . platform === "win32" ? 200 : 100
69+ const delay = Math . min ( baseDelay * Math . pow ( 2 , attempt - 1 ) , 2000 ) // Cap at 2s
4270 console . warn ( `[rmDir] Attempt ${ attempt } failed for ${ dirPath } , retrying in ${ delay } ms...` )
4371
4472 // Synchronous sleep for simplicity in build scripts.
0 commit comments