Files
fitness_walk_nwnu/node_modules/node-simctl/lib/subcommands/bootstatus.js
T
2026-09-08 20:28:54 +08:00

114 lines
3.4 KiB
JavaScript

import log from '../logger';
import { waitForCondition } from 'asyncbox';
const commands = {};
/**
* @typedef {Object} BootMonitorOptions
* @property {?number} timeout [240000] - Simulator booting timeout in ms.
* @property {?Function} onWaitingDataMigration - This event is fired when data migration stage starts.
* @property {?Function} onWaitingSystemApp - This event is fired when system app wait stage starts.
* @property {?Function} onFinished - This event is fired when Simulator is fully booted.
* @property {?Function} onError - This event is fired when there was an error while monitoring the booting process
* or when the timeout has expired.
* @property {?boolean} shouldPreboot [false] Whether to preboot the Simulator
* if this command is called and it is not already in booted or booting state.
*/
/**
* Start monitoring for boot status of the particular Simulator.
* If onFinished property is not set then the method will block
* until Simulator booting is completed.
* The method is only available since Xcode8.
*
* @param {?BootMonitorOptions} opts - Monitoring options.
* @returns {SubProcess} The instance of the corresponding monitoring process.
* @throws {Error} If the Simulator fails to finish booting within the given timeout and onFinished
* property is not set.
* @throws {Error} If the `udid` instance property is unset
*/
commands.startBootMonitor = async function startBootMonitor (opts = {}) {
const {
timeout = 240000,
onWaitingDataMigration,
onWaitingSystemApp,
onFinished,
onError,
shouldPreboot,
} = opts;
const udid = this.requireUdid('bootstatus');
let status = '';
let isBootingFinished = false;
let error = null;
let timeoutHandler = null;
const args = [udid];
if (shouldPreboot) {
args.push('-b');
}
const bootMonitor = await this.exec('bootstatus', {
args,
asynchronous: true,
});
bootMonitor.on('output', (stdout, stderr) => {
status += stdout || stderr;
if (stdout) {
if (stdout.includes('Waiting on Data Migration') && onWaitingDataMigration) {
onWaitingDataMigration();
} else if (stdout.includes('Waiting on System App') && onWaitingSystemApp) {
onWaitingSystemApp();
}
}
});
bootMonitor.on('exit', (code, signal) => {
if (timeoutHandler) {
clearTimeout(timeoutHandler);
}
if (code === 0) {
if (onFinished) {
onFinished();
}
isBootingFinished = true;
} else {
status = status || signal;
error = new Error(status);
if (onError) {
onError(error);
}
}
});
await bootMonitor.start(0);
const stopMonitor = async () => {
if (bootMonitor.isRunning) {
try {
await bootMonitor.stop();
} catch (e) {
log.warn(e.message);
}
}
};
const start = process.hrtime();
if (onFinished) {
timeoutHandler = setTimeout(stopMonitor, timeout);
} else {
try {
await waitForCondition(() => {
if (error) {
throw error;
}
return isBootingFinished;
}, {waitMs: timeout, intervalMs: 500});
} catch (err) {
await stopMonitor();
const [seconds] = process.hrtime(start);
throw new Error(
`The simulator ${udid} has failed to finish booting after ${seconds}s. ` +
`Original status: ${status}`);
}
}
return bootMonitor;
};
export default commands;