Refactor headless start function

Summary: Refactors the headless to have a list of closures instead of the `if` conditions. This will make addition of new arguments easy as it will be just adding a new closure to the list. One can change the order of the execution of the closures by inserting it at whatever index the user wants.

Reviewed By: passy

Differential Revision: D15965142

fbshipit-source-id: e9f348fe9d9011adcd47d140713d6187eab3b3d3
This commit is contained in:
Pritesh Nandgaonkar
2019-06-25 04:54:03 -07:00
committed by Facebook Github Bot
parent 4aafc49aaf
commit cad26c9319
2 changed files with 122 additions and 46 deletions

View File

@@ -23,6 +23,9 @@ import setup from '../static/setup.js';
import type {Store} from '../src/reducers'; import type {Store} from '../src/reducers';
import {getActivePluginNames} from '../src/utils/pluginUtils.js'; import {getActivePluginNames} from '../src/utils/pluginUtils.js';
import {serialize} from '../src/utils/serialization'; import {serialize} from '../src/utils/serialization';
import type BaseDevice from '../src/devices/BaseDevice';
type Action = {|exit: boolean, exitMessage?: string|};
type UserArguments = {| type UserArguments = {|
securePort: string, securePort: string,
@@ -116,37 +119,33 @@ function errorAndExit(error: string): void {
} }
async function earlyExitActions( async function earlyExitActions(
exitClosures: Array<(userArguments: UserArguments) => Promise<Action>>,
userArguments: UserArguments, userArguments: UserArguments,
originalConsole: typeof global.console, originalConsole: typeof global.console,
): Promise<void> { ): Promise<void> {
if (userArguments.listDevices) { for (const exitAction of exitClosures) {
const devices = await listDevices(); const {exit, exitMessage} = await exitAction(userArguments);
outputAndExit(devices.toString()); if (exit) {
outputAndExit(exitMessage || 'Exited through the earlyExit action');
}
} }
} }
async function exitActions( async function exitActions(
exitClosures: Array<
(userArguments: UserArguments, store: Store) => Promise<Action>,
>,
userArguments: UserArguments, userArguments: UserArguments,
originalConsole: typeof global.console,
store: Store, store: Store,
): Promise<void> { ): Promise<void> {
if (userArguments.listPlugins) {
outputAndExit(serialize(getActivePluginNames(store.getState().plugins)));
}
const {metrics, exit} = userArguments; const {metrics, exit} = userArguments;
if (shouldExportMetric(metrics) && metrics && metrics.length > 0) { for (var exitAction of exitClosures) {
try { const {exit, exitMessage} = await exitAction(userArguments, store);
const payload = await exportMetricsFromTrace( if (exit) {
metrics, outputAndExit(exitMessage || 'Exited through the exitActions function');
pluginsClassMap(store.getState().plugins),
);
outputAndExit(payload.toString());
} catch (error) {
console.error(error);
process.exit();
} }
} }
if (exit == 'sigint') { if (exit == 'sigint') {
process.on('SIGINT', async () => { process.on('SIGINT', async () => {
try { try {
@@ -170,33 +169,16 @@ async function exitActions(
} }
async function storeModifyingActions( async function storeModifyingActions(
storeModifyingClosures: Array<
(userArguments: UserArguments, store: Store) => Promise<Action>,
>,
userArguments: UserArguments, userArguments: UserArguments,
originalConsole: typeof global.console,
store: Store, store: Store,
): Promise<void> { ): Promise<void> {
const {device: selectedDeviceID} = userArguments; for (const closure of storeModifyingClosures) {
if (selectedDeviceID) { const {exit, exitMessage} = await closure(userArguments, store);
//$FlowFixMe: Checked the class name before calling reverse. if (exit) {
const devices = await listDevices(); outputAndExit(exitMessage || 'Exited through the earlyExit action');
const matchedDevice = devices.find(
device => device.serial === selectedDeviceID,
);
if (matchedDevice) {
if (matchedDevice.constructor.name === 'AndroidDevice') {
const ports = store.getState().application.serverPorts;
matchedDevice.reverse([ports.secure, ports.insecure]);
}
store.dispatch({
type: 'REGISTER_DEVICE',
payload: matchedDevice,
});
store.dispatch({
type: 'SELECT_DEVICE',
payload: matchedDevice,
});
} else {
console.error(`No device matching the serial ${selectedDeviceID}`);
process.exit();
} }
} }
} }
@@ -270,13 +252,107 @@ async function startFlipper(userArguments: UserArguments) {
); );
const logger = initLogger(store, {isHeadless: true}); const logger = initLogger(store, {isHeadless: true});
await earlyExitActions(userArguments, originalConsole); const earlyExitClosures: Array<
(userArguments: UserArguments) => Promise<Action>,
> = [
(userArguments: UserArguments) => {
if (userArguments.listDevices) {
return listDevices().then((devices: Array<BaseDevice>) => {
const mapped = devices.map(device => {
return {
os: device.os,
title: device.title,
deviceType: device.deviceType,
serial: device.serial,
};
});
return {exit: true, exitMessage: serialize(mapped)};
});
}
return Promise.resolve({exit: false});
},
];
await earlyExitActions(earlyExitClosures, userArguments);
const cleanupDispatchers = dispatcher(store, logger); const cleanupDispatchers = dispatcher(store, logger);
await storeModifyingActions(userArguments, originalConsole, store); const storeModifyingClosures: Array<
(userArguments: UserArguments, store: Store) => Promise<Action>,
> = [
(userArguments: UserArguments, store: Store) => {
const {device: selectedDeviceID} = userArguments;
if (selectedDeviceID) {
return listDevices().then(devices => {
const matchedDevice = devices.find(
device => device.serial === selectedDeviceID,
);
if (matchedDevice) {
if (matchedDevice.constructor.name === 'AndroidDevice') {
const ports = store.getState().application.serverPorts;
//$FlowFixMe: Checked the class name before calling reverse.
matchedDevice.reverse([ports.secure, ports.insecure]);
}
store.dispatch({
type: 'REGISTER_DEVICE',
payload: matchedDevice,
});
store.dispatch({
type: 'SELECT_DEVICE',
payload: matchedDevice,
});
return {exit: false};
}
return {
exit: true,
exitMessage: `No device matching the serial ${selectedDeviceID}`,
};
});
}
return Promise.resolve({
exit: false,
});
},
];
await exitActions(userArguments, originalConsole, store); const exitActionClosures: Array<
(userArguments: UserArguments, store: Store) => Promise<Action>,
> = [
(userArguments: UserArguments, store: Store) => {
const {listPlugins} = userArguments;
if (listPlugins) {
return Promise.resolve({
exit: true,
exitMessage: serialize(
getActivePluginNames(store.getState().plugins),
),
});
}
return Promise.resolve({
exit: false,
});
},
(userArguments: UserArguments, store: Store) => {
const {metrics} = userArguments;
if (shouldExportMetric(metrics) && metrics && metrics.length > 0) {
return exportMetricsFromTrace(
metrics,
pluginsClassMap(store.getState().plugins),
)
.then(payload => {
return {exit: true, exitMessage: payload ? payload.toString() : ''};
})
.catch(error => {
return {exit: true, exitMessage: error};
});
}
return Promise.resolve({exit: false});
},
];
await storeModifyingActions(storeModifyingClosures, userArguments, store);
await exitActions(exitActionClosures, userArguments, store);
await cleanupDispatchers(); await cleanupDispatchers();
} }

View File

@@ -76,7 +76,7 @@ function parseJSON(str: string): ?any {
export async function exportMetricsFromTrace( export async function exportMetricsFromTrace(
trace: string, trace: string,
pluginsMap: Map<string, Class<FlipperDevicePlugin<> | FlipperPlugin<>>>, pluginsMap: Map<string, Class<FlipperDevicePlugin<> | FlipperPlugin<>>>,
): Promise<?string> { ): Promise<string> {
const data = fs.readFileSync(trace, 'utf8'); const data = fs.readFileSync(trace, 'utf8');
const parsedJSONData = parseJSON(data); const parsedJSONData = parseJSON(data);
if (!parsedJSONData) { if (!parsedJSONData) {