Skip to content

Commit

Permalink
Switch to yauzl for variant analysis results
Browse files Browse the repository at this point in the history
  • Loading branch information
koesie10 committed Dec 18, 2023
1 parent 6cfa0a9 commit 7708347
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 19 deletions.
16 changes: 12 additions & 4 deletions extensions/ql-vscode/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions extensions/ql-vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1946,6 +1946,7 @@
"vscode-languageclient": "^8.0.2",
"vscode-test-adapter-api": "^1.7.0",
"vscode-test-adapter-util": "^0.7.0",
"yauzl": "^2.10.0",
"zip-a-folder": "^3.1.3"
},
"devDependencies": {
Expand Down Expand Up @@ -1997,6 +1998,7 @@
"@types/vscode": "^1.82.0",
"@types/webpack": "^5.28.0",
"@types/webpack-env": "^1.18.0",
"@types/yauzl": "^2.10.3",
"@typescript-eslint/eslint-plugin": "^6.2.1",
"@typescript-eslint/parser": "^6.14.0",
"@vscode/test-electron": "^2.2.0",
Expand Down
121 changes: 121 additions & 0 deletions extensions/ql-vscode/src/common/unzip.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
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.
function openZip(path: string, options: ZipOptions = {}): Promise<ZipFile> {
return new Promise((resolve, reject) => {
open(path, options, (err, zipFile) => {
if (err) {
reject(err);
return;
}

resolve(zipFile);
});
});
}

function readZipEntries(zipFile: ZipFile): Promise<ZipEntry[]> {
return new Promise((resolve, reject) => {
const files: ZipEntry[] = [];

zipFile.readEntry();
zipFile.on("entry", (entry: ZipEntry) => {
if (/\/$/.test(entry.fileName)) {
// Directory file names end with '/'
// We don't need to do anything for directories.
} else {
files.push(entry);
}

zipFile.readEntry();
});

zipFile.on("end", () => {
resolve(files);
});

zipFile.on("error", (err) => {
reject(err);
});
});
}

function openZipReadStream(
zipFile: ZipFile,
entry: ZipEntry,
): Promise<Readable> {
return new Promise((resolve, reject) => {
zipFile.openReadStream(entry, (err, readStream) => {
if (err) {
reject(err);
return;
}

resolve(readStream);
});
});
}

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();
}
}
11 changes: 0 additions & 11 deletions extensions/ql-vscode/src/common/zip.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
} from "./shared/variant-analysis";
import { DisposableObject, DisposeHandler } from "../common/disposable-object";
import { EventEmitter } from "vscode";
import { unzipFile } from "../common/zip";
import { unzipToDirectory } from "../common/unzip";
import { readRepoTask, writeRepoTask } from "./repo-tasks-store";

type CacheKey = `${number}/${string}`;
Expand Down Expand Up @@ -106,7 +106,7 @@ export class VariantAnalysisResultsManager extends DisposableObject {
VariantAnalysisResultsManager.RESULTS_DIRECTORY,
);

await unzipFile(zipFilePath, unzippedFilesDirectory);
await unzipToDirectory(zipFilePath, unzippedFilesDirectory);

this._onResultDownloaded.fire({
variantAnalysisId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ describe(VariantAnalysisResultsManager.name, () => {
});

afterEach(async () => {
if (fs.existsSync(variantAnalysisStoragePath)) {
fs.rmSync(variantAnalysisStoragePath, { recursive: true });
if (await fs.pathExists(variantAnalysisStoragePath)) {
await fs.remove(variantAnalysisStoragePath);
}
});

Expand Down

0 comments on commit 7708347

Please sign in to comment.