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.

This also avoids extracting anything other than the clangd binary.
  • Loading branch information
tamird committed Feb 21, 2025
1 parent e801a88 commit b9ced16
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 38 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
80 changes: 64 additions & 16 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,23 +315,70 @@ 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}`);
}
await ui.slow(
ui.localize('Extracting {0}', asset.name),
new Promise((resolve) => {
zip.extractAllToAsync(extractRoot, true, false, resolve);
}),
);
const clangdPath = path.join(extractRoot, executable.entryName);
await fs.promises.chmod(clangdPath, 0o755);
await fs.promises.unlink(zipFile);
return clangdPath;

// Can't use promisify because yauzl.open is overloaded.
const zip = await new Promise<yauzl.ZipFile>((resolve, reject) => {
yauzl.open(zipFile, {lazyEntries: true}, (err, zip) => {
if (err) return reject(err);

resolve(zip);
});
});

return await new Promise((resolve, reject) => {
zip.on('entry', (entry) => {
if (path.basename(entry.fileName) !== clangdFilename) {
// Keep reading.
zip.readEntry();
return;
}

// We found the clangd binary, extract it.
(async () => {
try {
await ui.slow(
ui.localize('Extracting {0}', asset.name),
(async () => {
const readStream = await promisify(
zip.openReadStream.bind(zip),
)(entry);

const clangdPath = path.join(extractRoot, entry.fileName);

await fs.promises.mkdir(path.dirname(clangdPath), {
recursive: true,
});

await stream.promises.pipeline(
readStream,
fs.createWriteStream(clangdPath),
);
await fs.promises.chmod(clangdPath, 0o755);
await fs.promises.unlink(zipFile);

resolve(clangdPath);
})(),
);
} catch (e) {
reject(e);
} finally {
zip.close();
}
})();
});

zip.on('error', reject);

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

// Start reading.
zip.readEntry();
});
}

// Create the 'install' and 'download' directories, and return absolute paths.
Expand Down

0 comments on commit b9ced16

Please sign in to comment.