@@ -92,6 +92,7 @@ export async function download(opts: DownloadOpts) {
9292 // This also avoids overwriting running executables
9393 const randomHex = crypto . randomBytes ( 5 ) . toString ( "hex" ) ;
9494 const rawDest = path . parse ( opts . dest . fsPath ) ;
95+ const oldServerPath = vscode . Uri . joinPath ( vscode . Uri . file ( rawDest . dir ) , `${ rawDest . name } -stale-${ randomHex } ${ rawDest . ext } ` ) ;
9596 const tempFilePath = vscode . Uri . joinPath ( vscode . Uri . file ( rawDest . dir ) , `${ rawDest . name } ${ randomHex } ` ) ;
9697
9798 await vscode . window . withProgress (
@@ -116,7 +117,46 @@ export async function download(opts: DownloadOpts) {
116117 }
117118 ) ;
118119
119- await vscode . workspace . fs . rename ( tempFilePath , opts . dest , { overwrite : true } ) ;
120+ // Try to rename a running server to avoid EPERM on Windows
121+ // NB: this can lead to issues if a running Code instance tries to restart the server.
122+ try {
123+ await vscode . workspace . fs . rename ( opts . dest , oldServerPath , { overwrite : true } ) ;
124+ log . info ( `Renamed old server binary ${ opts . dest . fsPath } to ${ oldServerPath . fsPath } ` ) ;
125+ } catch ( err ) {
126+ const fsErr = err as vscode . FileSystemError ;
127+ // This is supposed to return `FileNotFound`, alas...
128+ if ( ! fsErr . code || fsErr . code !== "FileNotFound" && fsErr . code !== "EntryNotFound" ) {
129+ log . error ( `Cannot rename existing server instance: ${ err } ` ) ;
130+ }
131+ }
132+ try {
133+ await vscode . workspace . fs . rename ( tempFilePath , opts . dest , { overwrite : true } ) ;
134+ } catch ( err ) {
135+ log . error ( `Cannot update server binary: ${ err } ` ) ;
136+ }
137+
138+ // Now try to remove any stale server binaries
139+ const serverDir = vscode . Uri . file ( rawDest . dir ) ;
140+ try {
141+ const entries = await vscode . workspace . fs . readDirectory ( serverDir ) ;
142+ for ( const [ entry , _ ] of entries ) {
143+ try {
144+ if ( entry . includes ( `${ rawDest . name } -stale-` ) ) {
145+ const uri = vscode . Uri . joinPath ( serverDir , entry ) ;
146+ try {
147+ await vscode . workspace . fs . delete ( uri ) ;
148+ log . info ( `Removed old server binary ${ uri . fsPath } ` ) ;
149+ } catch ( err ) {
150+ log . error ( `Unable to remove old server binary ${ uri . fsPath } ` ) ;
151+ }
152+ }
153+ } catch ( err ) {
154+ log . error ( `Unable to parse ${ entry } ` ) ;
155+ }
156+ }
157+ } catch ( err ) {
158+ log . error ( `Unable to enumerate contents of ${ serverDir . fsPath } ` ) ;
159+ }
120160}
121161
122162async function downloadFile (
0 commit comments