diff --git a/package.json b/package.json index b399f85..533d087 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "fs-extra": "^10.0.0", "getos": "^3.2.1", "node-fetch": "^2.6.1", + "rimraf": "^4.4.1", "semver": "^7.3.5", "simple-git": "^3.5.0" }, @@ -62,5 +63,8 @@ "prettier": "^2.5.1", "ts-jest": "^29.0.0", "typescript": "^4.9.5" + }, + "engines": { + "node": ">=14" } } diff --git a/src/installer.ts b/src/installer.ts index 7fd20a3..4e8727b 100644 --- a/src/installer.ts +++ b/src/installer.ts @@ -4,6 +4,7 @@ import semver from 'semver'; import debug from 'debug'; import extract from 'extract-zip'; import { EventEmitter } from 'events'; +import { rimraf } from 'rimraf'; import { download as electronDownload } from '@electron/get'; import { inspect } from 'util'; @@ -114,7 +115,7 @@ export class Installer extends EventEmitter { // currently installed... try { const versionFile = path.join(this.paths.electronInstall, 'version'); - const version = fs.readFileSync(versionFile, 'utf8'); + const version = fs.readFileSync(versionFile, 'utf8').trim(); this.setState(version, InstallState.installed); } catch { // no current version @@ -141,7 +142,7 @@ export class Installer extends EventEmitter { ); if (fs.existsSync(versionFile)) { - const version = fs.readFileSync(versionFile, 'utf8'); + const version = fs.readFileSync(versionFile, 'utf8').trim(); if (semver.valid(version)) { this.setState(version, InstallState.downloaded); } @@ -339,27 +340,27 @@ export class Installer extends EventEmitter { if (installedVersion === version) { d(`already installed`); } else { - const { path: zipFile, alreadyExtracted } = await this.ensureDownloaded( + const { path: source, alreadyExtracted } = await this.ensureDownloaded( version, opts, ); // An unzipped version already exists at `electronDownload` path if (alreadyExtracted) { - await this.installVersionImpl(version, zipFile, () => { + await this.installVersionImpl(version, source, () => { // Simply copy over the files from preinstalled version to `electronInstall` const { noAsar } = process; process.noAsar = true; - fs.copySync(zipFile, electronInstall); + fs.copySync(source, electronInstall); process.noAsar = noAsar; }); } else { - await this.installVersionImpl(version, zipFile, async () => { + await this.installVersionImpl(version, source, async () => { // FIXME(anyone) is there a less awful way to wrangle asar const { noAsar } = process; try { process.noAsar = true; - await extract(zipFile, { dir: electronInstall }); + await extract(source, { dir: electronInstall }); } finally { process.noAsar = noAsar; } @@ -377,7 +378,7 @@ export class Installer extends EventEmitter { private async installVersionImpl( version: string, - zipFile: string, + source: string, installCallback: () => Promise | void, ): Promise { const { @@ -387,8 +388,8 @@ export class Installer extends EventEmitter { const d = debug(`fiddle-core:Installer:${version}:install`); this.setState(version, InstallState.installing); - d(`installing from "${zipFile}"`); - await fs.emptyDir(electronInstall); + d(`installing from "${source}"`); + await rimraf(electronInstall); // Call the user defined callback which unzips/copies files content if (installCallback) { diff --git a/tests/installer.test.ts b/tests/installer.test.ts index 4b451e1..bbfc214 100644 --- a/tests/installer.test.ts +++ b/tests/installer.test.ts @@ -14,7 +14,7 @@ import { describe('Installer', () => { let tmpdir: string; - let paths: Partial; + let paths: Pick; let nockScope: Scope; let installer: Installer; const { missing, downloading, downloaded, installing, installed } = @@ -94,9 +94,14 @@ describe('Installer', () => { const { events, result } = await listenWhile(installer, func); const exec = result as string; + const installedVersion = fs + .readFileSync(path.join(paths.electronInstall, 'version'), 'utf-8') + .trim(); + expect(isDownloaded).toBe(true); expect(installer.state(version)).toBe(installed); expect(installer.installedVersion).toBe(version); + expect(installedVersion).toBe(version); return { events, exec }; } @@ -127,10 +132,8 @@ describe('Installer', () => { } async function unZipBinary(): Promise { - const extractDir = path.join(tmpdir, 'downloads', version); - fs.mkdirSync(path.join(tmpdir, 'downloads', version), { - recursive: true, - }); + const extractDir = path.join(paths.electronDownloads, version); + fs.mkdirSync(extractDir, { recursive: true }); await extract(fixture('electron-v13.1.7.zip'), { dir: extractDir, @@ -326,15 +329,10 @@ describe('Installer', () => { fs.removeSync(zipFile); expect(installer.state(version)).toBe(downloaded); const { events } = await doInstall(installer, version); - const installedVersion = fs.readFileSync( - path.join(path.join(tmpdir, 'install', 'version')), - 'utf-8', - ); expect(events).toStrictEqual([ { version: '13.1.7', state: 'installing' }, { version: '13.1.7', state: 'installed' }, ]); - expect(installedVersion).toBe(version); }); it('throws error if already installing', async () => { diff --git a/yarn.lock b/yarn.lock index 67c2170..996f2e9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2841,6 +2841,16 @@ glob@^8.0.1: minimatch "^5.0.1" once "^1.3.0" +glob@^9.2.0: + version "9.3.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-9.3.5.tgz#ca2ed8ca452781a3009685607fdf025a899dfe21" + integrity sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q== + dependencies: + fs.realpath "^1.0.0" + minimatch "^8.0.2" + minipass "^4.2.4" + path-scurry "^1.6.1" + global-agent@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/global-agent/-/global-agent-3.0.0.tgz#ae7cd31bd3583b93c5a16437a1afe27cc33a1ab6" @@ -3977,6 +3987,11 @@ lru-cache@^7.4.4, lru-cache@^7.5.1, lru-cache@^7.7.1: resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.14.0.tgz#21be64954a4680e303a09e9468f880b98a0b3c7f" integrity sha512-EIRtP1GrSJny0dqb50QXRUNBxHJhcpxHC++M5tD7RYbvLLn5KVWKsbyswSSqDuU15UFi3bgTQIY8nhDMeF6aDQ== +lru-cache@^9.0.0: + version "9.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-9.1.1.tgz#c58a93de58630b688de39ad04ef02ef26f1902f1" + integrity sha512-65/Jky17UwSb0BuB9V+MyDpsOtXKmYwzhyl+cOa9XUiI4uV2Ouy/2voFP3+al0BjZbJgMBD8FojMpAf+Z+qn4A== + make-dir@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" @@ -4089,6 +4104,13 @@ minimatch@^5.0.1, minimatch@^5.1.0: dependencies: brace-expansion "^2.0.1" +minimatch@^8.0.2: + version "8.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-8.0.4.tgz#847c1b25c014d4e9a7f68aaf63dedd668a626229" + integrity sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA== + dependencies: + brace-expansion "^2.0.1" + minimist@^1.2.0: version "1.2.7" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" @@ -4148,6 +4170,16 @@ minipass@^3.0.0, minipass@^3.1.1, minipass@^3.1.6: dependencies: yallist "^4.0.0" +minipass@^4.2.4: + version "4.2.8" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.2.8.tgz#f0010f64393ecfc1d1ccb5f582bcaf45f48e1a3a" + integrity sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ== + +minipass@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" + integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== + minizlib@^2.1.1, minizlib@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" @@ -4688,6 +4720,14 @@ path-parse@^1.0.6: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-scurry@^1.6.1: + version "1.7.0" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.7.0.tgz#99c741a2cfbce782294a39994d63748b5a24f6db" + integrity sha512-UkZUeDjczjYRE495+9thsgcVgsaCPkaw80slmfVFgllxY+IO8ubTsOpFVjDPROBqJdHfVPUFRHPBV/WciOVfWg== + dependencies: + lru-cache "^9.0.0" + minipass "^5.0.0" + path-type@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" @@ -5031,6 +5071,13 @@ rimraf@^3.0.0, rimraf@^3.0.2: dependencies: glob "^7.1.3" +rimraf@^4.4.1: + version "4.4.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-4.4.1.tgz#bd33364f67021c5b79e93d7f4fa0568c7c21b755" + integrity sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og== + dependencies: + glob "^9.2.0" + roarr@^2.15.3: version "2.15.4" resolved "https://registry.yarnpkg.com/roarr/-/roarr-2.15.4.tgz#f5fe795b7b838ccfe35dc608e0282b9eba2e7afd"