Skip to content

Commit

Permalink
Replace adm-zip with yauzl
Browse files Browse the repository at this point in the history
All adm-zip versions after 0.5.10 seem to have bugs:
- 0.5.11 causes tests to fail.
- 0.5.12 causes tests to hang.
- 0.5.13 causes extracted files to be empty.
  • Loading branch information
tamird committed Feb 23, 2025
1 parent e801a88 commit 00e8d4a
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 32 deletions.
57 changes: 38 additions & 19 deletions package-lock.json

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

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,22 @@
"url": "https://github.com/clangd/node-clangd/issues"
},
"dependencies": {
"adm-zip": "^0.5.14",
"node-fetch": "^2.7.0",
"readdirp": "^4.1.1",
"rimraf": "^6.0.1",
"semver": "^7.6.3",
"which": "^5.0.0"
"which": "^5.0.0",
"yauzl": "^3.2.0"
},
"devDependencies": {
"@types/adm-zip": "^0.5.5",
"@types/node": "^22.0.2",
"@types/node-fetch": "^2.6.11",
"@types/node-static": "^0.7.11",
"@types/semver": "^7.5.8",
"@types/tape": "^5.6.4",
"@types/tmp": "^0.2.6",
"@types/which": "^3.0.4",
"@types/yauzl": "^2.10.3",
"node-static": "^0.7.11",
"prettier": "^3.3.3",
"tap-spec": "^5.0.0",
Expand Down
73 changes: 63 additions & 10 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// - checking for updates (manual or automatic)
// - no usable clangd found, try to recover
// These have different flows, but the same underlying mechanisms.
import AdmZip from 'adm-zip';
import yauzl from 'yauzl';
import * as child_process from 'child_process';
import * as fs from 'fs';
import fetch from 'node-fetch';
Expand All @@ -18,6 +18,7 @@ import {readdirpPromise} from 'readdirp';
import {rimraf} from 'rimraf';
import * as semver from 'semver';
import * as stream from 'stream';
import {promisify} from 'util';
import which from 'which';

// Abstracts the editor UI and configuration.
Expand Down Expand Up @@ -314,20 +315,72 @@ namespace Install {
// continue with installation.
}
}

const zipFile = path.join(dirs.download, asset.name);
await download(asset.browser_download_url, zipFile, abort, ui);
const zip = new AdmZip(zipFile);
const executable = zip.getEntries().find((e) => e.name == clangdFilename);
if (executable === undefined) {
throw new Error(`Didn't find ${clangdFilename} in ${zipFile}`);
}

// Can't use promisify(yauzl.open) because yauzl.open is overloaded and we
// want the second overload.
const open = promisify(
(
file: string,
callback: (err: Error | null, zipfile: yauzl.ZipFile) => void,
) => yauzl.open(file, {lazyEntries: true}, callback),
);

const clangdPath = await open(zipFile).then((zip) =>
new Promise<string>((resolve, reject) => {
zip.on('entry', (entry: yauzl.Entry) => {
if (path.basename(entry.fileName) === clangdFilename) {
return resolve(path.join(extractRoot, entry.fileName));
}
zip.readEntry();
});

zip.on('error', reject);

zip.on('end', () => {
reject(new Error(`Didn't find ${clangdFilename} in ${zipFile}`));
});

// Start reading.
zip.readEntry();
}).finally(() => zip.close()),
);

await fs.promises.mkdir(extractRoot);

await ui.slow(
ui.localize('Extracting {0}', asset.name),
new Promise((resolve) => {
zip.extractAllToAsync(extractRoot, true, false, resolve);
}),
open(zipFile).then((zip) =>
new Promise<void>((resolve, reject) => {
zip.on('entry', (entry: yauzl.Entry) => {
const entryPath = path.join(extractRoot, entry.fileName);

(entry.fileName.endsWith('/')
? fs.promises.mkdir(entryPath)
: promisify(zip.openReadStream.bind(zip))(entry).then(
(readStream) =>
stream.promises.pipeline(
readStream,
fs.createWriteStream(entryPath),
),
)
)
.then(() => zip.readEntry())
.catch(reject);
});

zip.on('error', reject);

zip.on('end', resolve);

// Start reading.
zip.readEntry();
}).finally(() => zip.close()),
),
);
const clangdPath = path.join(extractRoot, executable.entryName);

await fs.promises.chmod(clangdPath, 0o755);
await fs.promises.unlink(zipFile);
return clangdPath;
Expand Down

0 comments on commit 00e8d4a

Please sign in to comment.