Skip to content

Commit e6387a1

Browse files
feat: allow usage of already unzipped electron versions (#37)
1 parent 7d17028 commit e6387a1

File tree

4 files changed

+215
-31
lines changed

4 files changed

+215
-31
lines changed

dist/fiddle-core.d.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ export declare interface Mirrors {
4747
electronNightlyMirror: string;
4848
}
4949

50+
export declare interface ElectronBinary {
51+
path: string;
52+
alreadyExtracted: boolean;
53+
}
54+
5055
interface InstallerParams {
5156
progressCallback: (progress: ProgressObject) => void;
5257
mirror: Mirrors;
@@ -118,7 +123,7 @@ export declare class Installer extends EventEmitter {
118123
private ensureDownloadedImpl;
119124
/** map of version string to currently-running active Promise */
120125
private downloading;
121-
ensureDownloaded(version: string, opts?: Partial<InstallerParams>): Promise<string>;
126+
ensureDownloaded(version: string, opts?: Partial<InstallerParams>): Promise<ElectronBinary>;
122127
/** the currently-installing version, if any */
123128
private installing;
124129
install(version: string, opts?: Partial<InstallerParams>): Promise<string>;

src/index.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import { DefaultPaths, Paths } from './paths';
2-
import { Installer, InstallState, InstallStateEvent } from './installer';
2+
import {
3+
Installer,
4+
InstallState,
5+
InstallStateEvent,
6+
ElectronBinary,
7+
} from './installer';
38
import { Fiddle, FiddleFactory, FiddleSource } from './fiddle';
49
import { BisectResult, Runner, RunnerOptions, TestResult } from './runner';
510
import {
@@ -16,6 +21,7 @@ export {
1621
BaseVersions,
1722
BisectResult,
1823
DefaultPaths,
24+
ElectronBinary,
1925
ElectronVersions,
2026
Fiddle,
2127
FiddleFactory,

src/installer.ts

Lines changed: 103 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as fs from 'fs-extra';
22
import * as path from 'path';
3+
import semver from 'semver';
34
import debug from 'debug';
45
import extract from 'extract-zip';
56
import { EventEmitter } from 'events';
@@ -37,6 +38,11 @@ export interface Mirrors {
3738
electronNightlyMirror: string;
3839
}
3940

41+
export interface ElectronBinary {
42+
path: string;
43+
alreadyExtracted: boolean; // to check if it's kept as zipped or not
44+
}
45+
4046
interface InstallerParams {
4147
progressCallback: (progress: ProgressObject) => void;
4248
mirror: Mirrors;
@@ -124,7 +130,23 @@ export class Installer extends EventEmitter {
124130
try {
125131
for (const file of fs.readdirSync(this.paths.electronDownloads)) {
126132
const match = reg.exec(file);
127-
if (match) this.setState(match[1], InstallState.downloaded);
133+
if (match) {
134+
this.setState(match[1], InstallState.downloaded);
135+
} else {
136+
// Case when the download path already has the unzipped electron version
137+
const versionFile = path.join(
138+
this.paths.electronDownloads,
139+
file,
140+
'version',
141+
);
142+
143+
if (fs.existsSync(versionFile)) {
144+
const version = fs.readFileSync(versionFile, 'utf8');
145+
if (semver.valid(version)) {
146+
this.setState(version, InstallState.downloaded);
147+
}
148+
}
149+
}
128150
}
129151
} catch {
130152
// no download directory yet
@@ -174,7 +196,11 @@ export class Installer extends EventEmitter {
174196
this.paths.electronDownloads,
175197
getZipName(version),
176198
);
199+
// Or, maybe the version was already installed and kept in file system
200+
const preInstalledPath = path.join(this.paths.electronDownloads, version);
201+
177202
const isZipDeleted = await rerunner(zipPath, binaryCleaner);
203+
const isPathDeleted = await rerunner(preInstalledPath, binaryCleaner);
178204

179205
// maybe uninstall it
180206
if (this.installedVersion === version) {
@@ -187,7 +213,7 @@ export class Installer extends EventEmitter {
187213
isBinaryDeleted = true;
188214
}
189215

190-
if (isZipDeleted && isBinaryDeleted) {
216+
if ((isZipDeleted || isPathDeleted) && isBinaryDeleted) {
191217
this.setState(version, InstallState.missing);
192218
} else {
193219
// Ideally the execution shouldn't reach this point
@@ -235,12 +261,23 @@ export class Installer extends EventEmitter {
235261
private async ensureDownloadedImpl(
236262
version: string,
237263
opts?: Partial<InstallerParams>,
238-
): Promise<string> {
264+
): Promise<ElectronBinary> {
239265
const d = debug(`fiddle-core:Installer:${version}:ensureDownloadedImpl`);
240266
const { electronDownloads } = this.paths;
241267
const zipFile = path.join(electronDownloads, getZipName(version));
242268

243269
const state = this.state(version);
270+
271+
if (state === InstallState.downloaded) {
272+
const preInstalledPath = path.join(electronDownloads, version);
273+
if (!fs.existsSync(zipFile) && fs.existsSync(preInstalledPath)) {
274+
return {
275+
path: preInstalledPath,
276+
alreadyExtracted: true,
277+
};
278+
}
279+
}
280+
244281
if (state === InstallState.missing) {
245282
d(`"${zipFile}" does not exist; downloading now`);
246283
this.setState(version, InstallState.downloading);
@@ -253,16 +290,19 @@ export class Installer extends EventEmitter {
253290
d(`"${zipFile}" exists; no need to download`);
254291
}
255292

256-
return zipFile;
293+
return {
294+
path: zipFile,
295+
alreadyExtracted: false,
296+
};
257297
}
258298

259299
/** map of version string to currently-running active Promise */
260-
private downloading = new Map<string, Promise<string>>();
300+
private downloading = new Map<string, Promise<ElectronBinary>>();
261301

262302
public async ensureDownloaded(
263303
version: string,
264304
opts?: Partial<InstallerParams>,
265-
): Promise<string> {
305+
): Promise<ElectronBinary> {
266306
const { downloading: promises } = this;
267307
let promise = promises.get(version);
268308
if (promise) return promise;
@@ -297,24 +337,38 @@ export class Installer extends EventEmitter {
297337
if (installedVersion === version) {
298338
d(`already installed`);
299339
} else {
300-
const zipFile = await this.ensureDownloaded(version, opts);
301-
this.setState(version, InstallState.installing);
302-
d(`installing from "${zipFile}"`);
303-
await fs.emptyDir(electronInstall);
304-
// FIXME(anyone) is there a less awful way to wrangle asar
305-
// @ts-ignore: yes, I know noAsar isn't defined in process
306-
const { noAsar } = process;
307-
try {
308-
// @ts-ignore: yes, I know noAsar isn't defined in process
309-
process.noAsar = true;
310-
await extract(zipFile, { dir: electronInstall });
311-
} finally {
312-
// @ts-ignore: yes, I know noAsar isn't defined in process
313-
process.noAsar = noAsar; // eslint-disable-line
340+
const { path: zipFile, alreadyExtracted } = await this.ensureDownloaded(
341+
version,
342+
opts,
343+
);
344+
345+
// An unzipped version already exists at `electronDownload` path
346+
if (alreadyExtracted) {
347+
await this.installVersionImpl(version, zipFile, () => {
348+
// Simply copy over the files from preinstalled version to `electronInstall`
349+
// @ts-ignore
350+
const { noAsar } = process;
351+
// @ts-ignore
352+
process.noAsar = true;
353+
fs.copySync(zipFile, electronInstall);
354+
// @ts-ignore
355+
process.noAsar = noAsar; // eslint-disable-line
356+
});
357+
} else {
358+
await this.installVersionImpl(version, zipFile, async () => {
359+
// FIXME(anyone) is there a less awful way to wrangle asar
360+
// @ts-ignore: yes, I know noAsar isn't defined in process
361+
const { noAsar } = process;
362+
try {
363+
// @ts-ignore: yes, I know noAsar isn't defined in process
364+
process.noAsar = true;
365+
await extract(zipFile, { dir: electronInstall });
366+
} finally {
367+
// @ts-ignore: yes, I know noAsar isn't defined in process
368+
process.noAsar = noAsar; // eslint-disable-line
369+
}
370+
});
314371
}
315-
if (installedVersion)
316-
this.setState(installedVersion, InstallState.downloaded);
317-
this.setState(version, InstallState.installed);
318372
}
319373

320374
this.installing.delete(version);
@@ -323,4 +377,30 @@ export class Installer extends EventEmitter {
323377
d(inspect({ electronExec, version }));
324378
return electronExec;
325379
}
380+
381+
private async installVersionImpl(
382+
version: string,
383+
zipFile: string,
384+
installCallback: () => Promise<void> | void,
385+
): Promise<void> {
386+
const {
387+
paths: { electronInstall },
388+
installedVersion,
389+
} = this;
390+
const d = debug(`fiddle-core:Installer:${version}:install`);
391+
392+
this.setState(version, InstallState.installing);
393+
d(`installing from "${zipFile}"`);
394+
await fs.emptyDir(electronInstall);
395+
396+
// Call the user defined callback which unzips/copies files content
397+
if (installCallback) {
398+
await installCallback();
399+
}
400+
401+
if (installedVersion) {
402+
this.setState(installedVersion, InstallState.downloaded);
403+
}
404+
this.setState(version, InstallState.installed);
405+
}
326406
}

0 commit comments

Comments
 (0)