Skip to content

Commit 5e7d2c1

Browse files
dsanders11ckerr
andauthored
refactor: move more of start fiddle flow to main process (#1935)
* chore: add new IPC to get fiddle start params from renderer * chore: remove unneeded // eslint-disable-next-line * chore: refactor to start fiddle in main process * fix: change run button state to installing modules correctly * refactor: move plural-maybe.ts to common utils * chore: drop dead code * refactor: remove runner.stop wrapper method * chore: move push output helpers to utils * refactor: move bisect.ts to common utils * chore: move autobisect to main process * refactor(renderer): consolidate run and runFiddle * chore: fixup starting fiddle during autobisect * refactor(renderer): do not call startFiddle from runFiddle * test: update test coverage * chore: handle error case with getStartFiddleOptions * fix: prevent simultaneous runs * chore: dead code cleanup * fix: restore security check in deleteUserData * fix: send fiddle stopped event on error * fix: restore getFiles options * fix: start fiddle directly from context menu * test: fix path checking on Windows --------- Co-authored-by: Charles Kerr <charles@charleskerr.com>
1 parent 448991d commit 5e7d2c1

33 files changed

Lines changed: 1292 additions & 825 deletions

src/ambient.d.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import {
2222
RunnableVersion,
2323
SelectedLocalVersion,
2424
SemVer,
25-
StartFiddleParams,
25+
StartFiddleOptions,
2626
Version,
2727
} from './interfaces';
2828
import { App } from './renderer/app';
@@ -51,6 +51,10 @@ declare global {
5151
type: 'fiddle-stopped',
5252
listener: (code: number | null, signal: string | null) => void,
5353
): void;
54+
addEventListener(
55+
type: 'is-auto-bisecting',
56+
listener: (isAutoBisecting: boolean) => void,
57+
): void;
5458
addEventListener(
5559
type: 'load-example',
5660
listener: (exampleInfo: { path: string; tag: string }) => void,
@@ -93,14 +97,13 @@ declare global {
9397
...names: Array<string>
9498
): Promise<string>;
9599
arch: string;
100+
autobisectFiddle(versions: Array<RunnableVersion>): void;
96101
blockAccelerators(acceleratorsToBlock: BlockableAccelerator[]): void;
97-
cleanupDirectory(dir: string): Promise<boolean>;
98102
confirmQuit(): void;
99103
createThemeFile(
100104
newTheme: FiddleTheme,
101105
name?: string,
102106
): Promise<LoadedFiddleTheme>;
103-
deleteUserData(name: string): Promise<void>;
104107
downloadVersion(
105108
version: string,
106109
opts?: Partial<DownloadVersionParams>,
@@ -143,6 +146,10 @@ declare global {
143146
transforms: Array<FileTransformOperation>,
144147
) => Promise<{ localPath?: string; files: Files }>,
145148
);
149+
onGetStartFiddleOptions(
150+
callback: () => Promise<StartFiddleOptions>,
151+
): void;
152+
onSetVersion(callback: (version: string) => Promise<void>): void;
146153
openThemeFolder(): Promise<void>;
147154
packageRun(
148155
{ dir, packageManager }: PMOperationOptions,
@@ -160,7 +167,7 @@ declare global {
160167
setShowMeTemplate(template?: string): void;
161168
showWarningDialog(messageOptions: MessageOptions): void;
162169
showWindow(): void;
163-
startFiddle(params: StartFiddleParams): Promise<void>;
170+
startFiddle(): Promise<void>;
164171
stopFiddle(): void;
165172
themePath: string;
166173
uncacheTypes(ver: RunnableVersion): Promise<void>;

src/interfaces.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,9 @@ export type FiddleEvent =
169169
| 'electron-types-changed'
170170
| 'execute-monaco-command'
171171
| 'fiddle-runner-output'
172+
| 'fiddle-modules-installed'
172173
| 'fiddle-stopped'
174+
| 'is-auto-bisecting'
173175
| 'load-example'
174176
| 'load-gist'
175177
| 'make-fiddle'
@@ -288,14 +290,15 @@ export interface PackageJsonOptions {
288290
includeDependencies?: boolean;
289291
}
290292

291-
export interface StartFiddleParams {
292-
localPath: string | undefined;
293+
export interface StartFiddleOptions {
294+
version: string;
293295
enableElectronLogging: boolean;
294-
isValidBuild: boolean; // If the localPath is a valid Electron build
295-
version: string; // The user selected version
296-
dir: string;
297-
options: string[];
296+
executionFlags: string[];
298297
env: { [x: string]: string | undefined };
298+
modules: Array<[string, string]>;
299+
packageManager: IPackageManager;
300+
useSocketFirewall: boolean;
301+
isKeepingUserDataDirs: boolean;
299302
}
300303

301304
export interface DownloadVersionParams {

src/ipc-events.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,17 +60,20 @@ export enum IpcEvents {
6060
GET_ELECTRON_TYPES = 'GET_ELECTRON_TYPES',
6161
UNWATCH_ELECTRON_TYPES = 'UNWATCH_ELECTRON_TYPES',
6262
GET_NODE_TYPES = 'GET_NODE_TYPES',
63-
CLEANUP_DIRECTORY = 'CLEANUP_DIRECTORY',
64-
DELETE_USER_DATA = 'DELETE_USER_DATA',
6563
SAVE_FILES_TO_TEMP = 'SAVE_FILES_TO_TEMP',
6664
SAVED_LOCAL_FIDDLE = 'SAVED_LOCAL_FIDDLE',
6765
GET_FILES = 'GET_FILES',
66+
GET_START_FIDDLE_OPTIONS = 'GET_START_FIDDLE_OPTIONS',
67+
SET_VERSION = 'SET_VERSION',
6868
START_FIDDLE = 'START_FIDDLE',
6969
STOP_FIDDLE = 'STOP_FIDDLE',
70+
AUTOBISECT_FIDDLE = 'AUTOBISECT_FIDDLE',
71+
IS_AUTO_BISECTING = 'IS_AUTO_BISECTING',
7072
GET_VERSION_STATE = 'GET_VERSION_STATE',
7173
DOWNLOAD_VERSION = 'DOWNLOAD_VERSION',
7274
REMOVE_VERSION = 'REMOVE_VERSION',
7375
FIDDLE_RUNNER_OUTPUT = 'FIDDLE_RUNNER_OUTPUT',
76+
FIDDLE_MODULES_INSTALLED = 'FIDDLE_MODULES_INSTALLED',
7477
FIDDLE_STOPPED = 'FIDDLE_STOPPED',
7578
VERSION_DOWNLOAD_PROGRESS = 'VERSION_DOWNLOAD_PROGRESS',
7679
VERSION_STATE_CHANGED = 'VERSION_STATE_CHANGED',
@@ -107,6 +110,7 @@ export const ipcMainEvents = [
107110
IpcEvents.GET_RELEASED_VERSIONS,
108111
IpcEvents.GET_USERNAME,
109112
IpcEvents.STOP_FIDDLE,
113+
IpcEvents.AUTOBISECT_FIDDLE,
110114
IpcEvents.GET_VERSION_STATE,
111115
] as const;
112116

src/main/autobisect.ts

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import type { IpcMainEvent, WebContents } from 'electron';
2+
3+
import { startFiddle } from './fiddle-core';
4+
import { ipcMainManager } from './ipc';
5+
import { pushOutputLine } from './utils/push-output';
6+
import { setVersion } from './utils/set-version';
7+
import { RunResult, RunnableVersion } from '../interfaces';
8+
import { IpcEvents } from '../ipc-events';
9+
import { Bisector } from '../utils/bisect';
10+
11+
const resultString: Record<RunResult, string> = Object.freeze({
12+
[RunResult.FAILURE]: '❌ failed',
13+
[RunResult.INVALID]: '❓ invalid',
14+
[RunResult.SUCCESS]: '✅ passed',
15+
});
16+
17+
/**
18+
* Bisect the current fiddle across the specified versions.
19+
*
20+
* @param versions - versions to bisect
21+
*/
22+
async function autobisect(
23+
webContents: WebContents,
24+
versions: Array<RunnableVersion>,
25+
) {
26+
try {
27+
ipcMainManager.send(IpcEvents.IS_AUTO_BISECTING, [true], webContents);
28+
await autobisectImpl(webContents, versions);
29+
} finally {
30+
ipcMainManager.send(IpcEvents.IS_AUTO_BISECTING, [false], webContents);
31+
}
32+
}
33+
34+
async function autobisectImpl(
35+
webContents: WebContents,
36+
versions: Array<RunnableVersion>,
37+
) {
38+
const prefix = `Runner: autobisect`;
39+
40+
// precondition: can't bisect unless we have >= 2 versions
41+
if (versions.length < 2) {
42+
pushOutputLine(
43+
webContents,
44+
`${prefix} needs at least two Electron versions`,
45+
);
46+
return;
47+
}
48+
49+
const results: Map<string, RunResult> = new Map();
50+
51+
const runVersion = async (version: string) => {
52+
let result = results.get(version);
53+
if (result === undefined) {
54+
const pre = `${prefix} Electron ${version} -`;
55+
pushOutputLine(webContents, `${pre} setting version`);
56+
await setVersion(webContents, version);
57+
pushOutputLine(webContents, `${pre} starting test`);
58+
result = await startFiddle(webContents);
59+
results.set(version, result);
60+
pushOutputLine(
61+
webContents,
62+
`${pre} finished test ${resultString[result]}`,
63+
);
64+
}
65+
return result;
66+
};
67+
68+
const bisector = new Bisector(versions);
69+
let targetVersion = bisector.getCurrentVersion();
70+
let next;
71+
while (true) {
72+
const { version } = targetVersion;
73+
74+
const result = await runVersion(version);
75+
if (result === RunResult.INVALID) {
76+
return result;
77+
}
78+
79+
next = bisector.continue(result === RunResult.SUCCESS);
80+
if (Array.isArray(next)) {
81+
break;
82+
}
83+
84+
targetVersion = next;
85+
}
86+
87+
const [good, bad] = next.map((v) => v.version);
88+
const resultGood = await runVersion(good);
89+
const resultBad = await runVersion(bad);
90+
if (resultGood === resultBad) {
91+
pushOutputLine(
92+
webContents,
93+
`${prefix} 'good' ${good} and 'bad' ${bad} both returned ${resultString[resultGood]}`,
94+
);
95+
return;
96+
}
97+
98+
const msgs = [
99+
`${prefix} complete`,
100+
`${prefix} ${resultString[RunResult.SUCCESS]} ${good}`,
101+
`${prefix} ${resultString[RunResult.FAILURE]} ${bad}`,
102+
`${prefix} Commits between versions:`,
103+
`https://github.com/electron/electron/compare/v${good}...v${bad}`,
104+
];
105+
msgs.forEach((msg) => pushOutputLine(webContents, msg));
106+
}
107+
108+
/**
109+
* Wire up the IPC handler so the renderer can trigger an autobisect.
110+
*/
111+
export function setupAutobisect(): void {
112+
ipcMainManager.on(
113+
IpcEvents.AUTOBISECT_FIDDLE,
114+
(event: IpcMainEvent, versions: Array<RunnableVersion>) => {
115+
autobisect(event.sender, versions).catch(console.error);
116+
},
117+
);
118+
}

src/main/context-menu.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
MenuItemConstructorOptions,
66
} from 'electron';
77

8+
import { isRunFiddleEnabled, startFiddle } from './fiddle-core';
89
import { ipcMainManager } from './ipc';
910
import { isDevMode } from './utils/devmode';
1011
import { IpcEvents } from '../ipc-events';
@@ -17,7 +18,13 @@ export function getRunItems(): Array<MenuItemConstructorOptions> {
1718
{
1819
id: 'run',
1920
label: 'Run Fiddle',
20-
click: () => ipcMainManager.send(IpcEvents.FIDDLE_RUN),
21+
enabled: isRunFiddleEnabled(),
22+
click: (_, focusedWindow) => {
23+
if (focusedWindow)
24+
startFiddle((focusedWindow as BrowserWindow).webContents).catch(
25+
console.error,
26+
);
27+
},
2128
},
2229
{
2330
id: 'clear_console',

0 commit comments

Comments
 (0)