Skip to content

Commit 988ffee

Browse files
authored
Merge pull request #31 from aryanshridhar/Add-DownloadOptions
feat: add installing options for electron binary
2 parents 9007a90 + ada5322 commit 988ffee

File tree

4 files changed

+102
-12
lines changed

4 files changed

+102
-12
lines changed

README.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ const result = await runner.bisect('10.0.0', '13.1.7', path_or_gist_or_git_repo)
7878
### Managing Electron Installations
7979

8080
```ts
81-
import { Installer } from 'fiddle-core';
81+
import { Installer, ProgressObject } from 'fiddle-core';
8282

8383
const installer = new Installer();
8484
installer.on('state-changed', ({version, state}) => {
@@ -89,12 +89,37 @@ installer.on('state-changed', ({version, state}) => {
8989
await installer.ensureDownloaded('12.0.15');
9090
// expect(installer.state('12.0.5').toBe('downloaded');
9191

92+
// download a version with callback
93+
const callback = (progress: ProgressObject) => {
94+
const percent = progress.percent * 100;
95+
console.log(`Current download progress %: ${percent.toFixed(2)}`);
96+
};
97+
await installer.ensureDownloaded('12.0.15', {
98+
progressCallback: callback,
99+
});
100+
101+
// download a version with a specific mirror
102+
const npmMirrors = {
103+
electronMirror: 'https://npmmirror.com/mirrors/electron/',
104+
electronNightlyMirror: 'https://npmmirror.com/mirrors/electron-nightly/',
105+
},
106+
107+
await installer.ensureDownloaded('12.0.15', {
108+
mirror: npmMirrors,
109+
});
110+
92111
// remove a download
93112
await installer.remove('12.0.15');
94113
// expect(installer.state('12.0.15').toBe('not-downloaded');
95114

96115
// install a specific version for the runner to use
97116
const exec = await installer.install('11.4.10');
117+
118+
// Installing with callback and custom mirrors
119+
await installer.install('11.4.10', {
120+
progressCallback: callback,
121+
mirror: npmMirrors,
122+
});
98123
// expect(installer.state('11.4.10').toBe('installed');
99124
// expect(fs.accessSync(exec, fs.constants.X_OK)).toBe(true);
100125
```

dist/fiddle-core.d.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,18 @@ export declare function compareVersions(a: SemVer, b: SemVer): number;
4040

4141
export declare const DefaultPaths: Paths;
4242

43+
export declare type ProgressObject = { percent: number };
44+
45+
export declare interface Mirrors {
46+
electronMirror: string;
47+
electronNightlyMirror: string;
48+
}
49+
50+
interface InstallerParams {
51+
progressCallback: (progress: ProgressObject) => void;
52+
mirror: Mirrors;
53+
}
54+
4355
/**
4456
* Implementation of Versions that self-populates from release information at
4557
* https://releases.electronjs.org/releases.json .
@@ -106,10 +118,10 @@ export declare class Installer extends EventEmitter {
106118
private ensureDownloadedImpl;
107119
/** map of version string to currently-running active Promise */
108120
private downloading;
109-
ensureDownloaded(version: string): Promise<string>;
121+
ensureDownloaded(version: string, opts?: Partial<InstallerParams>): Promise<string>;
110122
/** the currently-installing version, if any */
111123
private installing;
112-
install(version: string): Promise<string>;
124+
install(version: string, opts?: Partial<InstallerParams>): Promise<string>;
113125
}
114126

115127
/**

src/installer.ts

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@ export interface InstallStateEvent {
3131
state: InstallState;
3232
}
3333

34+
export interface Mirrors {
35+
electronMirror: string;
36+
electronNightlyMirror: string;
37+
}
38+
39+
interface InstallerParams {
40+
progressCallback: (progress: ProgressObject) => void;
41+
mirror: Mirrors;
42+
}
43+
3444
/**
3545
* Manage downloading and installing Electron versions.
3646
*
@@ -190,9 +200,16 @@ export class Installer extends EventEmitter {
190200
if (state === 'installed') return version;
191201
}
192202

193-
private async download(version: string): Promise<string> {
203+
private async download(
204+
version: string,
205+
opts?: Partial<InstallerParams>,
206+
): Promise<string> {
194207
let pctDone = 0;
195208
const getProgressCallback = (progress: ProgressObject) => {
209+
if (opts?.progressCallback) {
210+
// Call the user passed callback function
211+
opts.progressCallback(progress);
212+
}
196213
const pct = Math.round(progress.percent * 100);
197214
if (pctDone + 10 <= pct) {
198215
const emoji = pct >= 100 ? '🏁' : '⏳';
@@ -202,6 +219,10 @@ export class Installer extends EventEmitter {
202219
}
203220
};
204221
const zipFile = await electronDownload(version, {
222+
mirrorOptions: {
223+
mirror: opts?.mirror?.electronMirror,
224+
nightlyMirror: opts?.mirror?.electronNightlyMirror,
225+
},
205226
downloadOptions: {
206227
quiet: true,
207228
getProgressCallback,
@@ -210,7 +231,10 @@ export class Installer extends EventEmitter {
210231
return zipFile;
211232
}
212233

213-
private async ensureDownloadedImpl(version: string): Promise<string> {
234+
private async ensureDownloadedImpl(
235+
version: string,
236+
opts?: Partial<InstallerParams>,
237+
): Promise<string> {
214238
const d = debug(`fiddle-core:Installer:${version}:ensureDownloadedImpl`);
215239
const { electronDownloads } = this.paths;
216240
const zipFile = path.join(electronDownloads, getZipName(version));
@@ -219,7 +243,7 @@ export class Installer extends EventEmitter {
219243
if (state === 'missing') {
220244
d(`"${zipFile}" does not exist; downloading now`);
221245
this.setState(version, 'downloading');
222-
const tempFile = await this.download(version);
246+
const tempFile = await this.download(version, opts);
223247
await fs.ensureDir(electronDownloads);
224248
await fs.move(tempFile, zipFile);
225249
this.setState(version, 'downloaded');
@@ -234,12 +258,15 @@ export class Installer extends EventEmitter {
234258
/** map of version string to currently-running active Promise */
235259
private downloading = new Map<string, Promise<string>>();
236260

237-
public async ensureDownloaded(version: string): Promise<string> {
261+
public async ensureDownloaded(
262+
version: string,
263+
opts?: Partial<InstallerParams>,
264+
): Promise<string> {
238265
const { downloading: promises } = this;
239266
let promise = promises.get(version);
240267
if (promise) return promise;
241268

242-
promise = this.ensureDownloadedImpl(version).finally(() =>
269+
promise = this.ensureDownloadedImpl(version, opts).finally(() =>
243270
promises.delete(version),
244271
);
245272
promises.set(version, promise);
@@ -249,7 +276,10 @@ export class Installer extends EventEmitter {
249276
/** the currently-installing version, if any */
250277
private installing: string | undefined;
251278

252-
public async install(version: string): Promise<string> {
279+
public async install(
280+
version: string,
281+
opts?: Partial<InstallerParams>,
282+
): Promise<string> {
253283
const d = debug(`fiddle-core:Installer:${version}:install`);
254284
const { electronInstall } = this.paths;
255285
const electronExec = Installer.getExecPath(electronInstall);
@@ -262,7 +292,7 @@ export class Installer extends EventEmitter {
262292
if (installedVersion === version) {
263293
d(`already installed`);
264294
} else {
265-
const zipFile = await this.ensureDownloaded(version);
295+
const zipFile = await this.ensureDownloaded(version, opts);
266296
this.setState(version, 'installing');
267297
d(`installing from "${zipFile}"`);
268298
await fs.emptyDir(electronInstall);

tests/installer.test.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,21 +71,44 @@ describe('Installer', () => {
7171
}
7272

7373
async function doInstall(installer: Installer, version: string) {
74-
const func = () => installer.install(version);
74+
let isDownloaded = false;
75+
const progressCallback = () => {
76+
isDownloaded = true;
77+
};
78+
79+
// Version is already downloaded and present in local
80+
if (installer.state(version) !== 'missing') {
81+
isDownloaded = true;
82+
}
83+
const func = () => installer.install(version, { progressCallback });
7584
const { events, result } = await listenWhile(installer, func);
7685
const exec = result as string;
7786

87+
expect(isDownloaded).toBe(true);
7888
expect(installer.state(version)).toBe('installed');
7989
expect(installer.installedVersion).toBe(version);
8090

8191
return { events, exec };
8292
}
8393

8494
async function doDownload(installer: Installer, version: string) {
85-
const func = () => installer.ensureDownloaded(version);
95+
let isDownloaded = false;
96+
const progressCallback = () => {
97+
isDownloaded = true;
98+
};
99+
100+
// Version is already downloaded and present in local
101+
if (installer.state(version) !== 'missing') {
102+
isDownloaded = true;
103+
}
104+
const func = () =>
105+
installer.ensureDownloaded(version, {
106+
progressCallback,
107+
});
86108
const { events, result } = await listenWhile(installer, func);
87109
const zipfile = result as string;
88110

111+
expect(isDownloaded).toBe(true);
89112
expect(fs.existsSync(zipfile)).toBe(true);
90113
expect(installer.state(version)).toBe('downloaded');
91114

0 commit comments

Comments
 (0)