Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion packages/core/src/shared/lsp/baseLspInstaller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,11 @@ export abstract class BaseLspInstaller<T extends ResourcePaths = ResourcePaths,

await this.postInstall(assetDirectory)

const deletedVersions = await cleanLspDownloads(manifest.versions, nodePath.dirname(assetDirectory))
const deletedVersions = await cleanLspDownloads(
installationResult.version,
manifest.versions,
nodePath.dirname(assetDirectory)
)
this.logger.debug(`cleaning old LSP versions deleted ${deletedVersions.length} versions`)

return {
Expand Down
15 changes: 14 additions & 1 deletion packages/core/src/shared/lsp/utils/cleanup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ function isDelisted(manifestVersions: LspVersion[], targetVersion: string): bool
* @param downloadDirectory
* @returns array of deleted versions.
*/
export async function cleanLspDownloads(manifestVersions: LspVersion[], downloadDirectory: string): Promise<string[]> {
export async function cleanLspDownloads(
latestInstalledVersion: string,
manifestVersions: LspVersion[],
downloadDirectory: string
): Promise<string[]> {
const downloadedVersions = await getDownloadedVersions(downloadDirectory)
const [delistedVersions, remainingVersions] = partition(downloadedVersions, (v: string) =>
isDelisted(manifestVersions, v)
Expand All @@ -40,6 +44,15 @@ export async function cleanLspDownloads(manifestVersions: LspVersion[], download
}

for (const v of sort(remainingVersions).slice(0, -2)) {
/**
* When switching between different manifests, the following edge case can occur:
* A newly downloaded version might chronologically be older than all previously downloaded versions,
* even though it's marked as the latest version in its own manifest.
* In such cases, we skip the cleanup process to preserve this version. Otherwise we will get an EPIPE error
*/
if (v === latestInstalledVersion) {
continue
}
await fs.delete(path.join(downloadDirectory, v), { force: true, recursive: true })
deletedVersions.push(v)
}
Expand Down
8 changes: 6 additions & 2 deletions packages/core/src/test/shared/lsp/utils/cleanup.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe('cleanLSPDownloads', function () {

it('keeps two newest versions', async function () {
await fakeInstallVersions(['1.0.0', '1.0.1', '1.1.1', '2.1.1'], installationDir.fsPath)
const deleted = await cleanLspDownloads([], installationDir.fsPath)
const deleted = await cleanLspDownloads('2.1.1', [], installationDir.fsPath)

const result = (await fs.readdir(installationDir.fsPath)).map(([filename, _filetype], _index) => filename)
assert.strictEqual(result.length, 2)
Expand All @@ -53,6 +53,7 @@ describe('cleanLSPDownloads', function () {
it('deletes delisted versions', async function () {
await fakeInstallVersions(['1.0.0', '1.0.1', '1.1.1', '2.1.1'], installationDir.fsPath)
const deleted = await cleanLspDownloads(
'2.1.1',
[{ serverVersion: '1.1.1', isDelisted: true, targets: [] }],
installationDir.fsPath
)
Expand All @@ -67,6 +68,7 @@ describe('cleanLSPDownloads', function () {
it('handles case where less than 2 versions are not delisted', async function () {
await fakeInstallVersions(['1.0.0', '1.0.1', '1.1.1', '2.1.1'], installationDir.fsPath)
const deleted = await cleanLspDownloads(
'1.0.1',
[
{ serverVersion: '1.1.1', isDelisted: true, targets: [] },
{ serverVersion: '2.1.1', isDelisted: true, targets: [] },
Expand All @@ -83,7 +85,7 @@ describe('cleanLSPDownloads', function () {

it('handles case where less than 2 versions exist', async function () {
await fakeInstallVersions(['1.0.0'], installationDir.fsPath)
const deleted = await cleanLspDownloads([], installationDir.fsPath)
const deleted = await cleanLspDownloads('1.0.0', [], installationDir.fsPath)

const result = (await fs.readdir(installationDir.fsPath)).map(([filename, _filetype], _index) => filename)
assert.strictEqual(result.length, 1)
Expand All @@ -93,6 +95,7 @@ describe('cleanLSPDownloads', function () {
it('does not install delisted version when no other option exists', async function () {
await fakeInstallVersions(['1.0.0'], installationDir.fsPath)
const deleted = await cleanLspDownloads(
'1.0.0',
[{ serverVersion: '1.0.0', isDelisted: true, targets: [] }],
installationDir.fsPath
)
Expand All @@ -105,6 +108,7 @@ describe('cleanLSPDownloads', function () {
it('ignores invalid versions', async function () {
await fakeInstallVersions(['1.0.0', '.DS_STORE'], installationDir.fsPath)
const deleted = await cleanLspDownloads(
'1.0.0',
[{ serverVersion: '1.0.0', isDelisted: true, targets: [] }],
installationDir.fsPath
)
Expand Down
Loading