-
Notifications
You must be signed in to change notification settings - Fork 226
Expand file tree
/
Copy pathcleaner.ts
More file actions
113 lines (96 loc) · 3.52 KB
/
cleaner.ts
File metadata and controls
113 lines (96 loc) · 3.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import type { ExtensionContext } from "vscode";
import { getDirectoryNamesInsidePath } from "../../common/files";
import { sleep } from "../../common/time";
import type { BaseLogger } from "../../common/logging";
import { join } from "path";
import { getErrorMessage } from "../../common/helpers-pure";
import { pathExists, remove } from "fs-extra";
interface ExtensionManagedDistributionManager {
folderIndex: number;
distributionFolderPrefix: string;
}
interface DistributionDirectory {
directoryName: string;
folderIndex: number;
}
/**
* This class is responsible for cleaning up old distributions that are no longer needed. In normal operation, this
* should not be necessary as the old distribution is deleted when the distribution is updated. However, in some cases
* the extension may leave behind old distribution which can result in a significant amount of space (> 100 GB) being
* taking up by unused distributions.
*/
export class ExtensionManagedDistributionCleaner {
constructor(
private readonly extensionContext: ExtensionContext,
private readonly logger: BaseLogger,
private readonly manager: ExtensionManagedDistributionManager,
) {}
public start() {
// Intentionally starting this without waiting for it
void this.cleanup().catch((e: unknown) => {
void this.logger.log(
`Failed to clean up old versions of the CLI: ${getErrorMessage(e)}`,
);
});
}
public async cleanup() {
if (!(await pathExists(this.extensionContext.globalStorageUri.fsPath))) {
return;
}
const currentFolderIndex = this.manager.folderIndex;
const distributionDirectoryRegex = new RegExp(
`^${this.manager.distributionFolderPrefix}(\\d+)$`,
);
const existingDirectories = await getDirectoryNamesInsidePath(
this.extensionContext.globalStorageUri.fsPath,
);
const distributionDirectories = existingDirectories
.map((dir): DistributionDirectory | null => {
const match = dir.match(distributionDirectoryRegex);
if (!match) {
// When the folderIndex is 0, the distributionFolderPrefix is used as the directory name
if (dir === this.manager.distributionFolderPrefix) {
return {
directoryName: dir,
folderIndex: 0,
};
}
return null;
}
return {
directoryName: dir,
folderIndex: parseInt(match[1]),
};
})
.filter((dir) => dir !== null);
// Clean up all directories that are older than the current one
const cleanableDirectories = distributionDirectories.filter(
(dir) => dir.folderIndex < currentFolderIndex,
);
if (cleanableDirectories.length === 0) {
return;
}
void this.logger.log(
`Cleaning up ${cleanableDirectories.length} old versions of the CLI.`,
);
for (const cleanableDirectory of cleanableDirectories) {
// Wait 60 seconds between each cleanup to avoid overloading the system (even though the remove call should be async)
await sleep(10_000);
const path = join(
this.extensionContext.globalStorageUri.fsPath,
cleanableDirectory.directoryName,
);
// Delete this directory
try {
await remove(path);
} catch (e) {
void this.logger.log(
`Tried to clean up an old version of the CLI at ${path} but encountered an error: ${getErrorMessage(e)}.`,
);
}
}
void this.logger.log(
`Cleaned up ${cleanableDirectories.length} old versions of the CLI.`,
);
}
}