Plugin name list

Summary:
Adds an argument to the headless Flipper to print the list of available plugins. Added `--list-plugins`.

Currently the startFlipper function is not scalable enough to add new arguments and its implementation. I am planning to tackle this with the list of Actions which will be closure. So adding a new argument with its implementation will be just appending a closure at the correct location in an array. Will work on that in the later diff stacked on the current one.

Reviewed By: jknoxville

Differential Revision: D15789778

fbshipit-source-id: 91ba472617d593c3490bb932590a06d83597cba7
This commit is contained in:
Pritesh Nandgaonkar
2019-06-17 06:14:49 -07:00
committed by Facebook Github Bot
parent 198841d1d7
commit e5294d34f0
5 changed files with 105 additions and 5 deletions

View File

@@ -21,6 +21,8 @@ import {listDevices} from '../src/utils/listDevices';
// $FlowFixMe this file exist, trust me, flow! // $FlowFixMe this file exist, trust me, flow!
import setup from '../static/setup.js'; 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 {serialize} from '../src/utils/serialization';
type UserArguments = {| type UserArguments = {|
securePort: string, securePort: string,
@@ -31,6 +33,7 @@ type UserArguments = {|
metrics: string, metrics: string,
listDevices: boolean, listDevices: boolean,
device: string, device: string,
listPlugins: boolean,
|}; |};
yargs yargs
@@ -76,6 +79,11 @@ yargs
describe: 'Will print the list of devices in the terminal', describe: 'Will print the list of devices in the terminal',
type: 'boolean', type: 'boolean',
}); });
yargs.option('list-plugins', {
default: false,
describe: 'Will print the list of supported plugins in the terminal',
type: 'boolean',
});
yargs.option('device', { yargs.option('device', {
default: undefined, default: undefined,
describe: describe:
@@ -122,12 +130,16 @@ async function exitActions(
originalConsole: typeof global.console, 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) { if (shouldExportMetric(metrics) && metrics && metrics.length > 0) {
try { try {
const payload = await exportMetricsFromTrace( const payload = await exportMetricsFromTrace(
metrics, metrics,
pluginsClassMap(store.getState()), pluginsClassMap(store.getState().plugins),
); );
outputAndExit(payload.toString()); outputAndExit(payload.toString());
} catch (error) { } catch (error) {

View File

@@ -0,0 +1,62 @@
/**
* Copyright 2018-present Facebook.
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
* @format
*/
import {getActivePluginNames} from '../pluginUtils';
import type {State as PluginsState} from '../../reducers/plugins.js';
import type {PluginDefinition} from '../../dispatcher/plugins';
function mockPluginState(
gatekeepedPlugins: Array<PluginDefinition>,
disabledPlugins: Array<PluginDefinition>,
failedPlugins: Array<[PluginDefinition, string]>,
): PluginsState {
return {
devicePlugins: new Map([
//$FlowFixMe: Class instance won't be used in the test
['DevicePlugin1', undefined],
//$FlowFixMe: Class instance won't be used in the test
['DevicePlugin2', undefined],
]),
clientPlugins: new Map([
//$FlowFixMe: Class instance won't be used in the test
['ClientPlugin1', undefined],
//$FlowFixMe: Class instance won't be used in the test
['ClientPlugin2', undefined],
]),
gatekeepedPlugins,
disabledPlugins,
failedPlugins,
};
}
function mockPluginDefinition(name: string): PluginDefinition {
return {
name,
out: 'out',
};
}
test('getActivePluginNames with the plugins getting excluded', () => {
let state = mockPluginState(
[mockPluginDefinition('DevicePlugin1')],
[mockPluginDefinition('ClientPlugin1')],
[[mockPluginDefinition('DevicePlugin2'), 'DevicePlugin2']],
);
let list = getActivePluginNames(state);
expect(list).toEqual(['ClientPlugin2']);
});
test('getActivePluginNames with the no plugins getting excluded', () => {
let state = mockPluginState([], [], []);
let list = getActivePluginNames(state);
expect(list).toEqual([
'ClientPlugin1',
'ClientPlugin2',
'DevicePlugin1',
'DevicePlugin2',
]);
});

View File

@@ -49,16 +49,16 @@ export function processClients(
} }
export function pluginsClassMap( export function pluginsClassMap(
state: State, plugins: PluginStates,
): Map<string, Class<FlipperDevicePlugin<> | FlipperPlugin<>>> { ): Map<string, Class<FlipperDevicePlugin<> | FlipperPlugin<>>> {
const pluginsMap: Map< const pluginsMap: Map<
string, string,
Class<FlipperDevicePlugin<> | FlipperPlugin<>>, Class<FlipperDevicePlugin<> | FlipperPlugin<>>,
> = new Map([]); > = new Map([]);
state.plugins.clientPlugins.forEach((val, key) => { plugins.clientPlugins.forEach((val, key) => {
pluginsMap.set(key, val); pluginsMap.set(key, val);
}); });
state.plugins.devicePlugins.forEach((val, key) => { plugins.devicePlugins.forEach((val, key) => {
pluginsMap.set(key, val); pluginsMap.set(key, val);
}); });
return pluginsMap; return pluginsMap;

View File

@@ -52,7 +52,7 @@ export async function exportMetricsWithoutTrace(
const pluginsMap: Map< const pluginsMap: Map<
string, string,
Class<FlipperDevicePlugin<> | FlipperPlugin<>>, Class<FlipperDevicePlugin<> | FlipperPlugin<>>,
> = pluginsClassMap(store.getState()); > = pluginsClassMap(store.getState().plugins);
const metadata = await fetchMetadata(pluginStates, pluginsMap, store); const metadata = await fetchMetadata(pluginStates, pluginsMap, store);
const newPluginStates = metadata.pluginStates; const newPluginStates = metadata.pluginStates;
const {errorArray} = metadata; const {errorArray} = metadata;

View File

@@ -7,6 +7,9 @@
import type BaseDevice from '../devices/BaseDevice.js'; import type BaseDevice from '../devices/BaseDevice.js';
import {FlipperDevicePlugin, FlipperPlugin} from '../plugin.js'; import {FlipperDevicePlugin, FlipperPlugin} from '../plugin.js';
import type {State as PluginStatesState} from '../reducers/pluginStates.js'; import type {State as PluginStatesState} from '../reducers/pluginStates.js';
import {pluginsClassMap} from './exportData.js';
import type {State as PluginsState} from '../reducers/plugins.js';
import type {PluginDefinition} from '../dispatcher/plugins';
export function getPluginKey( export function getPluginKey(
selectedApp: ?string, selectedApp: ?string,
@@ -41,3 +44,26 @@ export function getPersistedState<PersistedState>(
}; };
return persistedState; return persistedState;
} }
export function getActivePluginNames(plugins: PluginsState): Array<string> {
let pluginsMap: Map<
string,
Class<FlipperDevicePlugin<> | FlipperPlugin<>>,
> = pluginsClassMap(plugins);
let arr: Array<PluginDefinition> = plugins.disabledPlugins.concat(
plugins.gatekeepedPlugins,
);
arr.forEach((plugin: PluginDefinition) => {
if (pluginsMap.has(plugin.name)) {
pluginsMap.delete(plugin.name);
}
});
plugins.failedPlugins.forEach((plugin: [PluginDefinition, string]) => {
if (plugin[0] && plugin[0].name && pluginsMap.has(plugin[0].name)) {
pluginsMap.delete(plugin[0].name);
}
});
return [...pluginsMap.keys()];
}