Skip to content

Commit 2b1ee61

Browse files
committed
feat(key-shortcuts): r/R/B restart ladder, hint reprint, session scoping
r restarts the app of the running session without preparing, building or syncing; R prepares again first and rebuilds the native app only if needed; B always rebuilds it. The help hint is repeated once a burst of syncs settles, and a restart stays on the devices the session was given instead of every device attached to the platform.
1 parent 53551c7 commit 2b1ee61

12 files changed

Lines changed: 771 additions & 61 deletions

File tree

lib/commands/debug.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,13 @@ export async function runDebugCommand(
180180
return;
181181
}
182182

183-
// The device map is what keeps the debugger attached across a restart, so
184-
// the shared restart — which knows nothing of it — cannot stand in here.
185-
const restartDebugSession = (forceRebuildNativeApp: boolean): Promise<void> =>
183+
// The device map is what keeps the debugger attached across a re-prepare,
184+
// so the shared restart — which knows nothing of it — cannot stand in here.
185+
// The plain app restart needs no stand-in: it goes through the run
186+
// controller, whose persisted descriptor already has debugging enabled.
187+
const restartDebugSession = (
188+
forceRebuildNativeApp: boolean = false,
189+
): Promise<void> =>
186190
services.$liveSyncCommandHelper.executeLiveSyncOperation(
187191
[selectedDeviceForDebug],
188192
services.platform,
@@ -193,10 +197,11 @@ export async function runDebugCommand(
193197
);
194198

195199
context.injector.get(KeyShortcutRegistry).add(
196-
restartShortcut({ restart: restartDebugSession }),
200+
restartShortcut(),
201+
restartShortcut({ full: true, restart: () => restartDebugSession() }),
197202
restartShortcut({
198203
forceRebuildNativeApp: true,
199-
restart: restartDebugSession,
204+
restart: () => restartDebugSession(true),
200205
}),
201206
watcherShortcut(),
202207
);

lib/commands/run.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ export function runCommandShortcuts(
159159

160160
return [
161161
restartShortcut({ platform }),
162+
restartShortcut({ platform, full: true }),
162163
restartShortcut({ platform, forceRebuildNativeApp: true }),
163164
watcherShortcut(),
164165
];

lib/controllers/run-controller.ts

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ export class RunController extends EventEmitter implements IRunController {
8484
projectDir,
8585
deviceDescriptors,
8686
platforms,
87+
liveSyncInfo,
8788
);
8889

8990
const shouldStartWatcher =
@@ -233,6 +234,112 @@ export class RunController extends EventEmitter implements IRunController {
233234
);
234235
}
235236

237+
/**
238+
* Restarts the application of a running session without preparing,
239+
* building or syncing anything. Queued on the session's action chain so it
240+
* cannot overtake a sync that is already under way, and routed through
241+
* `refreshApplication` so a debug session gets its debugger back.
242+
*/
243+
public async restartApplication(
244+
data: IRestartApplicationData,
245+
): Promise<void> {
246+
const { projectDir, deviceIdentifiers } = data;
247+
const liveSyncProcessInfo =
248+
this.$liveSyncProcessDataService.getPersistedData(projectDir);
249+
250+
if (!liveSyncProcessInfo || liveSyncProcessInfo.isStopped) {
251+
this.$logger.info(
252+
"There is no running application to restart. Start a run or debug session first.",
253+
);
254+
return;
255+
}
256+
257+
const deviceDescriptors = (
258+
liveSyncProcessInfo.deviceDescriptors || []
259+
).filter(
260+
(descriptor) =>
261+
!deviceIdentifiers ||
262+
!deviceIdentifiers.length ||
263+
_.includes(deviceIdentifiers, descriptor.identifier),
264+
);
265+
266+
if (!deviceDescriptors.length) {
267+
this.$logger.info("There is no device to restart the application on.");
268+
return;
269+
}
270+
271+
const projectData = this.$projectDataService.getProjectData(projectDir);
272+
const useHotModuleReload =
273+
!!liveSyncProcessInfo.liveSyncInfo?.useHotModuleReload;
274+
275+
const deviceAction = async (device: Mobile.IDevice) => {
276+
const deviceDescriptor = _.find(
277+
deviceDescriptors,
278+
(dd) => dd.identifier === device.deviceInfo.identifier,
279+
);
280+
281+
try {
282+
const platformLiveSyncService =
283+
this.$liveSyncServiceResolver.resolveLiveSyncService(
284+
device.deviceInfo.platform,
285+
);
286+
const deviceAppData = await platformLiveSyncService.getAppData({
287+
device,
288+
watch: true,
289+
projectData,
290+
liveSyncDeviceData: deviceDescriptor,
291+
useHotModuleReload,
292+
});
293+
294+
await this.refreshApplication(
295+
projectData,
296+
{
297+
deviceAppData,
298+
modifiedFilesData: [],
299+
isFullSync: false,
300+
useHotModuleReload,
301+
},
302+
// Neither a hot update nor a native change, which is what
303+
// `refreshApplicationWithoutDebug` reads as "restart".
304+
{
305+
files: [],
306+
staleFiles: [],
307+
hasOnlyHotUpdateFiles: false,
308+
hasNativeChanges: false,
309+
hmrData: null,
310+
platform: device.deviceInfo.platform.toLowerCase(),
311+
},
312+
deviceDescriptor,
313+
);
314+
} catch (err) {
315+
this.$logger.warn(
316+
`Unable to restart the application on device: ${device.deviceInfo.identifier}. Error is: ${err.message || err}.`,
317+
);
318+
this.$logger.trace(err);
319+
320+
this.emitCore(RunOnDeviceEvents.runOnDeviceError, {
321+
projectDir: projectData.projectDir,
322+
deviceIdentifier: device.deviceInfo.identifier,
323+
applicationIdentifier:
324+
projectData.projectIdentifiers[
325+
device.deviceInfo.platform.toLowerCase()
326+
],
327+
error: err,
328+
});
329+
}
330+
};
331+
332+
await this.addActionToChain(projectDir, () =>
333+
this.$devicesService.execute(deviceAction, (device: Mobile.IDevice) =>
334+
_.some(
335+
deviceDescriptors,
336+
(deviceDescriptor) =>
337+
deviceDescriptor.identifier === device.deviceInfo.identifier,
338+
),
339+
),
340+
);
341+
}
342+
236343
protected async refreshApplication(
237344
projectData: IProjectData,
238345
liveSyncResultInfo: ILiveSyncResultInfo,

0 commit comments

Comments
 (0)