Switch to yauzl for CodeQL CLI

This switches the CodeQL CLI download to `yauzl` instead of `unzipper`.
There should be no changes in behavior. I tested this manually on
Insiders by removing the distribution directory and this successfully
downloaded and extracted the CLI.
This commit is contained in:
Koen Vlaswinkel
2023-12-19 13:07:31 +01:00
parent b833591d1e
commit fdc36ad36b
4 changed files with 67 additions and 32 deletions

View File

@@ -15,7 +15,6 @@ import {
import {
codeQlLauncherName,
deprecatedCodeQlLauncherName,
extractZipArchive,
getRequiredAssetName,
} from "../common/distribution";
import {
@@ -26,6 +25,7 @@ import {
showAndLogErrorMessage,
showAndLogWarningMessage,
} from "../common/logging";
import { unzipToDirectory } from "../common/unzip";
/**
* distribution.ts
@@ -420,7 +420,7 @@ class ExtensionSpecificDistributionManager {
void extLogger.log(
`Extracting CodeQL CLI to ${this.getDistributionStoragePath()}`,
);
await extractZipArchive(archivePath, this.getDistributionStoragePath());
await unzipToDirectory(archivePath, this.getDistributionStoragePath());
} finally {
await remove(tmpDirectory);
}

View File

@@ -1,7 +1,4 @@
import { platform } from "os";
import { Open } from "unzipper";
import { join } from "path";
import { pathExists, chmod } from "fs-extra";
/**
* Get the name of the codeql cli installation we prefer to install, based on our current platform.
@@ -19,31 +16,6 @@ export function getRequiredAssetName(): string {
}
}
export async function extractZipArchive(
archivePath: string,
outPath: string,
): Promise<void> {
const archive = await Open.file(archivePath);
await archive.extract({
concurrency: 4,
path: outPath,
});
// Set file permissions for extracted files
await Promise.all(
archive.files.map(async (file) => {
// Only change file permissions if within outPath (path.join normalises the path)
const extractedPath = join(outPath, file.path);
if (
extractedPath.indexOf(outPath) !== 0 ||
!(await pathExists(extractedPath))
) {
return Promise.resolve();
}
return chmod(extractedPath, file.externalFileAttributes >>> 16);
}),
);
}
export function codeQlLauncherName(): string {
return platform() === "win32" ? "codeql.exe" : "codeql";
}

View File

@@ -1,5 +1,8 @@
import { Entry as ZipEntry, open, Options as ZipOptions, ZipFile } from "yauzl";
import { Readable } from "stream";
import { dirname, join } from "path";
import { WriteStream } from "fs";
import { createWriteStream, ensureDir } from "fs-extra";
// We can't use promisify because it picks up the wrong overload.
export function openZip(
@@ -82,3 +85,63 @@ export async function openZipBuffer(
});
});
}
async function copyStream(
readable: Readable,
writeStream: WriteStream,
): Promise<void> {
return new Promise((resolve, reject) => {
readable.on("error", (err) => {
reject(err);
});
readable.on("end", () => {
resolve();
});
readable.pipe(writeStream);
});
}
export async function unzipToDirectory(
archivePath: string,
destinationPath: string,
): Promise<void> {
const zipFile = await openZip(archivePath, {
autoClose: false,
strictFileNames: true,
lazyEntries: true,
});
try {
const entries = await readZipEntries(zipFile);
for (const entry of entries) {
const path = join(destinationPath, entry.fileName);
if (/\/$/.test(entry.fileName)) {
// Directory file names end with '/'
await ensureDir(path);
} else {
// Ensure the directory exists
await ensureDir(dirname(path));
const readable = await openZipReadStream(zipFile, entry);
let mode: number | undefined = entry.externalFileAttributes >>> 16;
if (mode <= 0) {
mode = undefined;
}
const writeStream = createWriteStream(path, {
autoClose: true,
mode,
});
await copyStream(readable, writeStream);
}
}
} finally {
zipFile.close();
}
}

View File

@@ -2,9 +2,9 @@ import { existsSync, createWriteStream, mkdirpSync } from "fs-extra";
import { normalize, join } from "path";
import {
getRequiredAssetName,
extractZipArchive,
codeQlLauncherName,
} from "../../src/common/distribution";
import { unzipToDirectory } from "../../src/common/unzip";
import fetch from "node-fetch";
import supportedCliVersions from "../../supported_cli_versions.json";
@@ -126,7 +126,7 @@ export async function ensureCli(useCli: boolean) {
console.log(`Unzipping into '${unzipDir}'`);
mkdirpSync(unzipDir);
await extractZipArchive(downloadedFilePath, unzipDir);
await unzipToDirectory(downloadedFilePath, unzipDir);
console.log("Done.");
} catch (e) {
console.error("Failed to download CLI.");