From 176c445817c431ec2557d2df074d97e600983b96 Mon Sep 17 00:00:00 2001 From: 0x5457 <0x5457@protonmail.com> Date: Tue, 19 Aug 2025 15:28:24 +0800 Subject: [PATCH] Avoid symlink conflicts when re-extracting `eslint-xx.tar.gz` (#36068) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #34325 **Background** When upgrading/reinstalling the ESLint language server, extracting the archive over an existing version directory that contains symlinks can fail and interrupt the installation. ``` failed to unpack .../vscode-eslint-2.4.4/.../client/src/shared File exists (os error 17) when symlinking ../../$shared/ to .../client/src/shared ``` **Root cause** Extracting into a non-empty directory conflicts with leftover files/symlinks (e.g., `client/src/shared -> ../../$shared`), causing “File exists (os error 17)”. When `fs::metadata(&server_path).await.is_err()` is true, the code falls back to cached_server_binary, but that still targets the same (potentially corrupted/half-installed) directory and does not run `npm install` or `npm run compile`, so the system cannot recover and remains broken. **Change** Before downloading and extracting, delete the target version directory (vscode-eslint-) to ensure an empty extraction destination and avoid conflicts. **Alternative approaches** temp directory + rename: extract into a clean temp directory and rename into place to avoid half-installed states [async-tar](https://github.com/dignifiedquire/async-tar) enhancement: tolerate already-existing symlinks (or add a “replace-existing” option). Release Notes: - Fixed eslint installation not clearing files after previous attempts' --- crates/languages/src/typescript.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/languages/src/typescript.rs b/crates/languages/src/typescript.rs index d477acc7f6..7937adbc09 100644 --- a/crates/languages/src/typescript.rs +++ b/crates/languages/src/typescript.rs @@ -910,7 +910,7 @@ impl LspAdapter for EsLintLspAdapter { let server_path = destination_path.join(Self::SERVER_PATH); if fs::metadata(&server_path).await.is_err() { - remove_matching(&container_dir, |entry| entry != destination_path).await; + remove_matching(&container_dir, |_| true).await; download_server_binary( delegate,