fix: streamline the cache exploration (#135)

If a large number of versions are cached on the host system, trying to
read the whole cache at once can be quite memory intensive. Instead, we
can use an iterative approach that doesn't hold the whole directory
content in memory.
This commit is contained in:
Antoine du Hamel 2022-07-08 19:21:38 +02:00 committed by GitHub
parent 29da06c515
commit 185da44078
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 19 additions and 14 deletions

View File

@ -1,4 +1,6 @@
import {once} from 'events';
import fs from 'fs';
import type {Dir} from 'fs';
import path from 'path';
import semver from 'semver';
@ -45,30 +47,35 @@ export async function fetchAvailableVersions(spec: RegistrySpec): Promise<Array<
export async function findInstalledVersion(installTarget: string, descriptor: Descriptor) {
const installFolder = path.join(installTarget, descriptor.name);
let folderContent: Array<string>;
let cacheDirectory: Dir;
try {
folderContent = await fs.promises.readdir(installFolder);
cacheDirectory = await fs.promises.opendir(installFolder);
} catch (error) {
if ((error as nodeUtils.NodeError).code === `ENOENT`) {
folderContent = [];
return null;
} else {
throw error;
}
}
const candidateVersions: Array<string> = [];
for (const entry of folderContent) {
const range = new semver.Range(descriptor.range);
let bestMatch: string | null = null;
let maxSV: semver.SemVer | undefined = undefined;
for await (const {name} of cacheDirectory) {
// Some dot-folders tend to pop inside directories, especially on OSX
if (entry.startsWith(`.`))
if (name.startsWith(`.`))
continue;
candidateVersions.push(entry);
// If the dirname correspond to an in-range version and is not lower than
// the previous best match (or if there is not yet a previous best match),
// it's our new best match.
if (range.test(name) && maxSV?.compare(name) !== 1) {
bestMatch = name;
maxSV = new semver.SemVer(bestMatch);
}
}
const bestMatch = semver.maxSatisfying(candidateVersions, descriptor.range);
if (bestMatch === null)
return null;
return bestMatch;
}
@ -106,9 +113,7 @@ export async function installVersion(installTarget: string, locator: Locator, {s
stream.pipe(sendTo);
await new Promise(resolve => {
sendTo.on(`finish`, resolve);
});
await once(sendTo, `finish`);
await fs.promises.mkdir(path.dirname(installFolder), {recursive: true});
try {