From a424a6bcfb66fc2171c60fcb57282fa1160b6dce Mon Sep 17 00:00:00 2001 From: jneira Date: Wed, 8 Dec 2021 22:21:11 +0100 Subject: [PATCH] Use js which as fallback --- package-lock.json | 22 +++++-- package.json | 2 + src/utils.ts | 162 +++++++++++++++++++++++----------------------- 3 files changed, 99 insertions(+), 87 deletions(-) diff --git a/package-lock.json b/package-lock.json index a614385e..f75101be 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "request": "^2.88.2", "request-promise-native": "^1.0.8", "vscode-languageclient": "^7.0.0", + "which": "^2.0.1", "yauzl": "^2.10.0" }, "devDependencies": { @@ -29,6 +30,7 @@ "@types/node": "^14.0.3", "@types/request-promise-native": "^1.0.17", "@types/vscode": "^1.52.0", + "@types/which": "^2.0.1", "@types/yauzl": "^2.9.1", "@vscode/test-electron": "^1.6.2", "glob": "^7.1.4", @@ -221,6 +223,12 @@ "integrity": "sha512-wZt3VTmzYrgZ0l/3QmEbCq4KAJ71K3/hmMQ/nfpv84oH8e81KKwPEoQ5v8dNCxfHFVJ1JabHKmCvqdYOoVm1Ow==", "dev": true }, + "node_modules/@types/which": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/which/-/which-2.0.1.tgz", + "integrity": "sha512-Jjakcv8Roqtio6w1gr0D7y6twbhx6gGgFGF5BLwajPpnOIOxFkakFhCq+LmyyeAz7BX6ULrjBOxdKaCDy+4+dQ==", + "dev": true + }, "node_modules/@types/yauzl": { "version": "2.9.1", "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.1.tgz", @@ -1941,8 +1949,7 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" }, "node_modules/isobject": { "version": "3.0.1", @@ -3899,7 +3906,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "dependencies": { "isexe": "^2.0.0" }, @@ -4224,6 +4230,12 @@ "integrity": "sha512-wZt3VTmzYrgZ0l/3QmEbCq4KAJ71K3/hmMQ/nfpv84oH8e81KKwPEoQ5v8dNCxfHFVJ1JabHKmCvqdYOoVm1Ow==", "dev": true }, + "@types/which": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/which/-/which-2.0.1.tgz", + "integrity": "sha512-Jjakcv8Roqtio6w1gr0D7y6twbhx6gGgFGF5BLwajPpnOIOxFkakFhCq+LmyyeAz7BX6ULrjBOxdKaCDy+4+dQ==", + "dev": true + }, "@types/yauzl": { "version": "2.9.1", "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.1.tgz", @@ -5558,8 +5570,7 @@ "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" }, "isobject": { "version": "3.0.1", @@ -7034,7 +7045,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "requires": { "isexe": "^2.0.0" } diff --git a/package.json b/package.json index a7d47476..41e54693 100644 --- a/package.json +++ b/package.json @@ -398,6 +398,7 @@ "@types/node": "^14.0.3", "@types/request-promise-native": "^1.0.17", "@types/vscode": "^1.52.0", + "@types/which": "^2.0.1", "@types/yauzl": "^2.9.1", "@vscode/test-electron": "^1.6.2", "glob": "^7.1.4", @@ -425,6 +426,7 @@ "request": "^2.88.2", "request-promise-native": "^1.0.8", "vscode-languageclient": "^7.0.0", + "which": "^2.0.1", "yauzl": "^2.10.0" } } diff --git a/src/utils.ts b/src/utils.ts index 924cbaa0..c400bd2e 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -10,6 +10,7 @@ import * as url from 'url'; import { promisify } from 'util'; import { OutputChannel, ProgressLocation, window, WorkspaceFolder } from 'vscode'; import { Logger } from 'vscode-languageclient'; +import * as which from 'which'; import * as yazul from 'yauzl'; import { createGunzip } from 'zlib'; @@ -18,7 +19,7 @@ enum LogLevel { Error, Warn, Info, - Debug + Debug, } export class ExtensionLogger implements Logger { public readonly name: string; @@ -52,7 +53,7 @@ export class ExtensionLogger implements Logger { let now = new Date(); // Ugly hack to make js date iso format similar to hls one const offset = now.getTimezoneOffset(); - now = new Date(now.getTime() - (offset * 60 * 1000)); + now = new Date(now.getTime() - offset * 60 * 1000); const timedMsg = `${new Date().toISOString().replace('T', ' ').replace('Z', '0000')} ${msg}`; this.channel.appendLine(timedMsg); if (this.logFile) { @@ -161,87 +162,90 @@ export async function downloadFile(titleMsg: string, src: string, dest: string): fs.unlinkSync(downloadDest); } - const downloadTask = window.withProgress( - { - location: ProgressLocation.Notification, - title: titleMsg, - cancellable: false, - }, - async (progress) => { - const p = new Promise((resolve, reject) => { - const srcUrl = url.parse(src); - const opts: https.RequestOptions = { - host: srcUrl.host, - path: srcUrl.path, - protocol: srcUrl.protocol, - port: srcUrl.port, - headers: userAgentHeader, - }; - getWithRedirects(opts, (res) => { - const totalSize = parseInt(res.headers['content-length'] || '1', 10); - const fileStream = fs.createWriteStream(downloadDest, { mode: 0o744 }); - let curSize = 0; + const downloadTask = window + .withProgress( + { + location: ProgressLocation.Notification, + title: titleMsg, + cancellable: false, + }, + async (progress) => { + const p = new Promise((resolve, reject) => { + const srcUrl = url.parse(src); + const opts: https.RequestOptions = { + host: srcUrl.host, + path: srcUrl.path, + protocol: srcUrl.protocol, + port: srcUrl.port, + headers: userAgentHeader, + }; + getWithRedirects(opts, (res) => { + const totalSize = parseInt(res.headers['content-length'] || '1', 10); + const fileStream = fs.createWriteStream(downloadDest, { mode: 0o744 }); + let curSize = 0; - // Decompress it if it's a gzip or zip - const needsGunzip = - res.headers['content-type'] === 'application/gzip' || extname(srcUrl.path ?? '') === '.gz'; - const needsUnzip = res.headers['content-type'] === 'application/zip' || extname(srcUrl.path ?? '') === '.zip'; - if (needsGunzip) { - const gunzip = createGunzip(); - gunzip.on('error', reject); - res.pipe(gunzip).pipe(fileStream); - } else if (needsUnzip) { - const zipDest = downloadDest + '.zip'; - const zipFs = fs.createWriteStream(zipDest); - zipFs.on('error', reject); - zipFs.on('close', () => { - yazul.open(zipDest, (err, zipfile) => { - if (err) { - throw err; - } - if (!zipfile) { - throw Error("Couldn't decompress zip"); - } + // Decompress it if it's a gzip or zip + const needsGunzip = + res.headers['content-type'] === 'application/gzip' || extname(srcUrl.path ?? '') === '.gz'; + const needsUnzip = + res.headers['content-type'] === 'application/zip' || extname(srcUrl.path ?? '') === '.zip'; + if (needsGunzip) { + const gunzip = createGunzip(); + gunzip.on('error', reject); + res.pipe(gunzip).pipe(fileStream); + } else if (needsUnzip) { + const zipDest = downloadDest + '.zip'; + const zipFs = fs.createWriteStream(zipDest); + zipFs.on('error', reject); + zipFs.on('close', () => { + yazul.open(zipDest, (err, zipfile) => { + if (err) { + throw err; + } + if (!zipfile) { + throw Error("Couldn't decompress zip"); + } - // We only expect *one* file inside each zip - zipfile.on('entry', (entry: yazul.Entry) => { - zipfile.openReadStream(entry, (err2, readStream) => { - if (err2) { - throw err2; - } - readStream?.pipe(fileStream); + // We only expect *one* file inside each zip + zipfile.on('entry', (entry: yazul.Entry) => { + zipfile.openReadStream(entry, (err2, readStream) => { + if (err2) { + throw err2; + } + readStream?.pipe(fileStream); + }); }); }); }); - }); - res.pipe(zipFs); - } else { - res.pipe(fileStream); - } + res.pipe(zipFs); + } else { + res.pipe(fileStream); + } - function toMB(bytes: number) { - return bytes / (1024 * 1024); - } + function toMB(bytes: number) { + return bytes / (1024 * 1024); + } - res.on('data', (chunk: Buffer) => { - curSize += chunk.byteLength; - const msg = `${toMB(curSize).toFixed(1)}MB / ${toMB(totalSize).toFixed(1)}MB`; - progress.report({ message: msg, increment: (chunk.length / totalSize) * 100 }); - }); - res.on('error', reject); - fileStream.on('close', resolve); - }).on('error', reject); - }); - try { - await p; - // Finally rename it to the actual dest - fs.renameSync(downloadDest, dest); - } finally { - // And remember to remove it from the list of current downloads - inFlightDownloads.get(src)?.delete(dest); + res.on('data', (chunk: Buffer) => { + curSize += chunk.byteLength; + const msg = `${toMB(curSize).toFixed(1)}MB / ${toMB(totalSize).toFixed(1)}MB`; + progress.report({ message: msg, increment: (chunk.length / totalSize) * 100 }); + }); + res.on('error', reject); + fileStream.on('close', resolve); + }).on('error', reject); + }); + try { + await p; + // Finally rename it to the actual dest + fs.renameSync(downloadDest, dest); + } finally { + // And remember to remove it from the list of current downloads + inFlightDownloads.get(src)?.delete(dest); + } } - } - ).then(_ => true); + ) + .then((_) => true); try { if (inFlightDownloads.has(src)) { @@ -250,7 +254,7 @@ export async function downloadFile(titleMsg: string, src: string, dest: string): inFlightDownloads.set(src, new Map([[dest, downloadTask]])); } return await downloadTask; - } catch (e: any) { + } catch (e) { await promisify(fs.unlink)(downloadDest).catch(ignoreFileNotExists); throw new Error(`Failed to download ${src}:\n${e.message}`); } @@ -277,17 +281,13 @@ export function executableExists(exe: string): boolean { const isWindows = process.platform === 'win32'; const cmd: string = isWindows ? 'where' : 'which'; const out = child_process.spawnSync(cmd, [exe]); - return out.status === 0 || (isWindows && fileExists(exe)); + return out.status === 0 || (!isWindows && (which.sync(exe, { nothrow: true }) ?? '') !== ''); } export function directoryExists(path: string): boolean { return fs.existsSync(path) && fs.lstatSync(path).isDirectory(); } -function fileExists(path: string): boolean { - return fs.existsSync(path) && fs.lstatSync(path).isFile(); -} - export function resolvePathPlaceHolders(path: string, folder?: WorkspaceFolder) { path = path.replace('${HOME}', os.homedir).replace('${home}', os.homedir).replace(/^~/, os.homedir); if (folder) {