storing information about failed plugins
Summary: If a plugin was not loaded we used to ignore it. This diff still ignores the plugins that weren't loaded, but adds some information about them to the redux store. This information is used in the PluginDebugger. These are the three reasons, why a plugin might not be loaded. * `gatekeepedPlugins`: Plugin was ignored because of a GK * `failedPlugins`: Plugin could not be requried/failed to parse * `disabledPlugins`: Plugin disabled in `~/.flipper/config.json` Information for each them is added to the redux store. Reviewed By: passy Differential Revision: D13516986 fbshipit-source-id: b7a55a159cb586d1a88fbb976248131c52a909c5
This commit is contained in:
committed by
Facebook Github Bot
parent
9ec04d33e2
commit
6827515329
@@ -26,7 +26,7 @@ const logger = new Logger();
|
|||||||
test('dispatcher dispatches REGISTER_PLUGINS', () => {
|
test('dispatcher dispatches REGISTER_PLUGINS', () => {
|
||||||
dispatcher(mockStore, logger);
|
dispatcher(mockStore, logger);
|
||||||
const actions = mockStore.getActions();
|
const actions = mockStore.getActions();
|
||||||
expect(actions[0].type).toBe('REGISTER_PLUGINS');
|
expect(actions.map(a => a.type)).toContain('REGISTER_PLUGINS');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('getDynamicPlugins returns empty array', () => {
|
test('getDynamicPlugins returns empty array', () => {
|
||||||
@@ -56,7 +56,7 @@ test('checkDisabled', () => {
|
|||||||
const config = {disabledPlugins: [disabledPlugin]};
|
const config = {disabledPlugins: [disabledPlugin]};
|
||||||
// $FlowFixMe process.env not defined in electron API spec
|
// $FlowFixMe process.env not defined in electron API spec
|
||||||
remote.process.env.CONFIG = JSON.stringify(config);
|
remote.process.env.CONFIG = JSON.stringify(config);
|
||||||
const disabled = checkDisabled();
|
const disabled = checkDisabled([]);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
disabled({
|
disabled({
|
||||||
@@ -75,7 +75,7 @@ test('checkDisabled', () => {
|
|||||||
|
|
||||||
test('checkGK for plugin without GK', () => {
|
test('checkGK for plugin without GK', () => {
|
||||||
expect(
|
expect(
|
||||||
checkGK({
|
checkGK([])({
|
||||||
name: 'pluginID',
|
name: 'pluginID',
|
||||||
out: './test/index.js',
|
out: './test/index.js',
|
||||||
}),
|
}),
|
||||||
@@ -84,7 +84,7 @@ test('checkGK for plugin without GK', () => {
|
|||||||
|
|
||||||
test('checkGK for passing plugin', () => {
|
test('checkGK for passing plugin', () => {
|
||||||
expect(
|
expect(
|
||||||
checkGK({
|
checkGK([])({
|
||||||
name: 'pluginID',
|
name: 'pluginID',
|
||||||
gatekeeper: TEST_PASSING_GK,
|
gatekeeper: TEST_PASSING_GK,
|
||||||
out: './test/index.js',
|
out: './test/index.js',
|
||||||
@@ -93,17 +93,20 @@ test('checkGK for passing plugin', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('checkGK for failing plugin', () => {
|
test('checkGK for failing plugin', () => {
|
||||||
expect(
|
const gatekeepedPlugins = [];
|
||||||
checkGK({
|
const name = 'pluginID';
|
||||||
name: 'pluginID',
|
const plugins = checkGK(gatekeepedPlugins)({
|
||||||
gatekeeper: TEST_FAILING_GK,
|
name,
|
||||||
out: './test/index.js',
|
gatekeeper: TEST_FAILING_GK,
|
||||||
}),
|
out: './test/index.js',
|
||||||
).toBeFalsy();
|
});
|
||||||
|
|
||||||
|
expect(plugins).toBeFalsy();
|
||||||
|
expect(gatekeepedPlugins[0].name).toEqual(name);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('requirePlugin returns null for invalid requires', () => {
|
test('requirePlugin returns null for invalid requires', () => {
|
||||||
const plugin = requirePlugin(require)({
|
const plugin = requirePlugin([], require)({
|
||||||
name: 'pluginID',
|
name: 'pluginID',
|
||||||
out: 'this/path/does not/exist',
|
out: 'this/path/does not/exist',
|
||||||
});
|
});
|
||||||
@@ -114,7 +117,7 @@ test('requirePlugin returns null for invalid requires', () => {
|
|||||||
test('requirePlugin loads plugin', () => {
|
test('requirePlugin loads plugin', () => {
|
||||||
const name = 'pluginID';
|
const name = 'pluginID';
|
||||||
const homepage = 'https://fb.workplace.com/groups/230455004101832/';
|
const homepage = 'https://fb.workplace.com/groups/230455004101832/';
|
||||||
const plugin = requirePlugin(require)({
|
const plugin = requirePlugin([], require)({
|
||||||
name,
|
name,
|
||||||
homepage,
|
homepage,
|
||||||
out: path.join(__dirname, 'TestPlugin.js'),
|
out: path.join(__dirname, 'TestPlugin.js'),
|
||||||
|
|||||||
@@ -13,16 +13,22 @@ import type {State} from '../reducers/plugins';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import * as Flipper from 'flipper';
|
import * as Flipper from 'flipper';
|
||||||
import {registerPlugins} from '../reducers/plugins';
|
import {
|
||||||
|
registerPlugins,
|
||||||
|
addGatekeepedPlugins,
|
||||||
|
addDisabledPlugins,
|
||||||
|
addFailedPlugins,
|
||||||
|
} from '../reducers/plugins';
|
||||||
import {remote} from 'electron';
|
import {remote} from 'electron';
|
||||||
import {GK} from 'flipper';
|
import {GK} from 'flipper';
|
||||||
import {FlipperBasePlugin} from '../plugin.js';
|
import {FlipperBasePlugin} from '../plugin.js';
|
||||||
import {setupMenuBar} from '../MenuBar.js';
|
import {setupMenuBar} from '../MenuBar.js';
|
||||||
|
|
||||||
type PluginDefinition = {
|
export type PluginDefinition = {
|
||||||
name: string,
|
name: string,
|
||||||
out: string,
|
out: string,
|
||||||
gatekeeper?: string,
|
gatekeeper?: string,
|
||||||
|
entry?: string,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default (store: Store, logger: Logger) => {
|
export default (store: Store, logger: Logger) => {
|
||||||
@@ -31,16 +37,21 @@ export default (store: Store, logger: Logger) => {
|
|||||||
window.ReactDOM = ReactDOM;
|
window.ReactDOM = ReactDOM;
|
||||||
window.Flipper = Flipper;
|
window.Flipper = Flipper;
|
||||||
|
|
||||||
const disabled = checkDisabled();
|
const gatekeepedPlugins: Array<PluginDefinition> = [];
|
||||||
|
const disabledPlugins: Array<PluginDefinition> = [];
|
||||||
|
const failedPlugins: Array<[PluginDefinition, string]> = [];
|
||||||
|
|
||||||
const initialPlugins: Array<
|
const initialPlugins: Array<
|
||||||
Class<FlipperPlugin<> | FlipperDevicePlugin<>>,
|
Class<FlipperPlugin<> | FlipperDevicePlugin<>>,
|
||||||
> = [...getBundledPlugins(), ...getDynamicPlugins()]
|
> = [...getBundledPlugins(), ...getDynamicPlugins()]
|
||||||
.filter(disabled)
|
.filter(checkDisabled(disabledPlugins))
|
||||||
.filter(checkGK)
|
.filter(checkGK(gatekeepedPlugins))
|
||||||
.map(requirePlugin())
|
.map(requirePlugin(failedPlugins))
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
|
|
||||||
|
store.dispatch(addGatekeepedPlugins(gatekeepedPlugins));
|
||||||
|
store.dispatch(addDisabledPlugins(disabledPlugins));
|
||||||
|
store.dispatch(addFailedPlugins(failedPlugins));
|
||||||
store.dispatch(registerPlugins(initialPlugins));
|
store.dispatch(registerPlugins(initialPlugins));
|
||||||
|
|
||||||
let state: ?State = null;
|
let state: ?State = null;
|
||||||
@@ -81,22 +92,30 @@ export function getDynamicPlugins() {
|
|||||||
return dynamicPlugins;
|
return dynamicPlugins;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function checkGK(plugin: PluginDefinition): boolean {
|
export const checkGK = (gatekeepedPlugins: Array<PluginDefinition>) => (
|
||||||
const result = plugin.gatekeeper && !GK.get(plugin.gatekeeper);
|
plugin: PluginDefinition,
|
||||||
if (plugin.gatekeeper && !result) {
|
): boolean => {
|
||||||
|
if (!plugin.gatekeeper) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const result = GK.get(plugin.gatekeeper);
|
||||||
|
if (!result) {
|
||||||
|
gatekeepedPlugins.push(plugin);
|
||||||
console.warn(
|
console.warn(
|
||||||
'Plugin %s will be ignored as user is not part of the gatekeeper "%s".',
|
'Plugin %s will be ignored as user is not part of the gatekeeper "%s".',
|
||||||
plugin.name,
|
plugin.name,
|
||||||
plugin.gatekeeper,
|
plugin.gatekeeper,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return !result;
|
return result;
|
||||||
}
|
};
|
||||||
|
|
||||||
export function checkDisabled(): (plugin: PluginDefinition) => boolean {
|
export const checkDisabled = (disabledPlugins: Array<PluginDefinition>) => (
|
||||||
let disabledPlugins: Set<string> = new Set();
|
plugin: PluginDefinition,
|
||||||
|
): boolean => {
|
||||||
|
let disabledList: Set<string> = new Set();
|
||||||
try {
|
try {
|
||||||
disabledPlugins = new Set(
|
disabledList = new Set(
|
||||||
// $FlowFixMe process.env not defined in electron API spec
|
// $FlowFixMe process.env not defined in electron API spec
|
||||||
JSON.parse(remote?.process.env.CONFIG || '{}').disabledPlugins || [],
|
JSON.parse(remote?.process.env.CONFIG || '{}').disabledPlugins || [],
|
||||||
);
|
);
|
||||||
@@ -104,12 +123,17 @@ export function checkDisabled(): (plugin: PluginDefinition) => boolean {
|
|||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (plugin: PluginDefinition) => !disabledPlugins.has(plugin.name);
|
if (disabledList.has(plugin.name)) {
|
||||||
}
|
disabledPlugins.push(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
export function requirePlugin(
|
return !disabledList.has(plugin.name);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const requirePlugin = (
|
||||||
|
failedPlugins: Array<[PluginDefinition, string]>,
|
||||||
requireFunction: Function = window.electronRequire,
|
requireFunction: Function = window.electronRequire,
|
||||||
) {
|
) => {
|
||||||
return (
|
return (
|
||||||
pluginDefinition: PluginDefinition,
|
pluginDefinition: PluginDefinition,
|
||||||
): ?Class<FlipperPlugin<> | FlipperDevicePlugin<>> => {
|
): ?Class<FlipperPlugin<> | FlipperDevicePlugin<>> => {
|
||||||
@@ -137,8 +161,9 @@ export function requirePlugin(
|
|||||||
|
|
||||||
return plugin;
|
return plugin;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
failedPlugins.push([pluginDefinition, e.message]);
|
||||||
console.error(pluginDefinition, e);
|
console.error(pluginDefinition, e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ export class FlipperBasePlugin<
|
|||||||
static title: ?string = null;
|
static title: ?string = null;
|
||||||
static id: string = '';
|
static id: string = '';
|
||||||
static icon: ?string = null;
|
static icon: ?string = null;
|
||||||
|
static gatekeeper: ?string = null;
|
||||||
|
static entry: ?string = null;
|
||||||
static bugs: ?{
|
static bugs: ?{
|
||||||
email?: string,
|
email?: string,
|
||||||
url?: string,
|
url?: string,
|
||||||
|
|||||||
@@ -5,7 +5,11 @@
|
|||||||
* @format
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {default as reducer, registerPlugins} from '../plugins';
|
import {
|
||||||
|
default as reducer,
|
||||||
|
registerPlugins,
|
||||||
|
addGatekeepedPlugins,
|
||||||
|
} from '../plugins';
|
||||||
import {
|
import {
|
||||||
FlipperBasePlugin,
|
FlipperBasePlugin,
|
||||||
FlipperPlugin,
|
FlipperPlugin,
|
||||||
@@ -29,6 +33,9 @@ test('add clientPlugin', () => {
|
|||||||
{
|
{
|
||||||
devicePlugins: new Map(),
|
devicePlugins: new Map(),
|
||||||
clientPlugins: new Map(),
|
clientPlugins: new Map(),
|
||||||
|
gatekeepedPlugins: [],
|
||||||
|
failedPlugins: [],
|
||||||
|
disabledPlugins: [],
|
||||||
},
|
},
|
||||||
registerPlugins([testPlugin]),
|
registerPlugins([testPlugin]),
|
||||||
);
|
);
|
||||||
@@ -40,6 +47,9 @@ test('add devicePlugin', () => {
|
|||||||
{
|
{
|
||||||
devicePlugins: new Map(),
|
devicePlugins: new Map(),
|
||||||
clientPlugins: new Map(),
|
clientPlugins: new Map(),
|
||||||
|
gatekeepedPlugins: [],
|
||||||
|
failedPlugins: [],
|
||||||
|
disabledPlugins: [],
|
||||||
},
|
},
|
||||||
registerPlugins([testDevicePlugin]),
|
registerPlugins([testDevicePlugin]),
|
||||||
);
|
);
|
||||||
@@ -51,6 +61,9 @@ test('do not add plugin twice', () => {
|
|||||||
{
|
{
|
||||||
devicePlugins: new Map(),
|
devicePlugins: new Map(),
|
||||||
clientPlugins: new Map(),
|
clientPlugins: new Map(),
|
||||||
|
gatekeepedPlugins: [],
|
||||||
|
failedPlugins: [],
|
||||||
|
disabledPlugins: [],
|
||||||
},
|
},
|
||||||
registerPlugins([testPlugin, testPlugin]),
|
registerPlugins([testPlugin, testPlugin]),
|
||||||
);
|
);
|
||||||
@@ -62,6 +75,9 @@ test('do not add other classes', () => {
|
|||||||
{
|
{
|
||||||
devicePlugins: new Map(),
|
devicePlugins: new Map(),
|
||||||
clientPlugins: new Map(),
|
clientPlugins: new Map(),
|
||||||
|
gatekeepedPlugins: [],
|
||||||
|
failedPlugins: [],
|
||||||
|
disabledPlugins: [],
|
||||||
},
|
},
|
||||||
// $FlowFixMe testing wrong classes on purpose here
|
// $FlowFixMe testing wrong classes on purpose here
|
||||||
registerPlugins([testBasePlugin]),
|
registerPlugins([testBasePlugin]),
|
||||||
@@ -69,3 +85,18 @@ test('do not add other classes', () => {
|
|||||||
expect(res.devicePlugins.size).toEqual(0);
|
expect(res.devicePlugins.size).toEqual(0);
|
||||||
expect(res.devicePlugins.size).toEqual(0);
|
expect(res.devicePlugins.size).toEqual(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('add gatekeeped plugin', () => {
|
||||||
|
const gatekeepedPlugins = [{name: 'plugin', out: 'out.js'}];
|
||||||
|
const res = reducer(
|
||||||
|
{
|
||||||
|
devicePlugins: new Map(),
|
||||||
|
clientPlugins: new Map(),
|
||||||
|
gatekeepedPlugins: [],
|
||||||
|
failedPlugins: [],
|
||||||
|
disabledPlugins: [],
|
||||||
|
},
|
||||||
|
addGatekeepedPlugins(gatekeepedPlugins),
|
||||||
|
);
|
||||||
|
expect(res.gatekeepedPlugins).toEqual(gatekeepedPlugins);
|
||||||
|
});
|
||||||
|
|||||||
@@ -7,21 +7,42 @@
|
|||||||
|
|
||||||
import {FlipperPlugin, FlipperDevicePlugin} from '../plugin.js';
|
import {FlipperPlugin, FlipperDevicePlugin} from '../plugin.js';
|
||||||
|
|
||||||
|
import type {PluginDefinition} from '../dispatcher/plugins';
|
||||||
|
|
||||||
export type State = {
|
export type State = {
|
||||||
devicePlugins: Map<string, Class<FlipperDevicePlugin<>>>,
|
devicePlugins: Map<string, Class<FlipperDevicePlugin<>>>,
|
||||||
clientPlugins: Map<string, Class<FlipperPlugin<>>>,
|
clientPlugins: Map<string, Class<FlipperPlugin<>>>,
|
||||||
|
gatekeepedPlugins: Array<PluginDefinition>,
|
||||||
|
disabledPlugins: Array<PluginDefinition>,
|
||||||
|
failedPlugins: Array<[PluginDefinition, string]>,
|
||||||
};
|
};
|
||||||
|
|
||||||
type P = Class<FlipperPlugin<> | FlipperDevicePlugin<>>;
|
type P = Class<FlipperPlugin<> | FlipperDevicePlugin<>>;
|
||||||
|
|
||||||
export type Action = {
|
export type Action =
|
||||||
type: 'REGISTER_PLUGINS',
|
| {
|
||||||
payload: Array<P>,
|
type: 'REGISTER_PLUGINS',
|
||||||
};
|
payload: Array<P>,
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'GATEKEEPED_PLUGINS',
|
||||||
|
payload: Array<PluginDefinition>,
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'DISABLED_PLUGINS',
|
||||||
|
payload: Array<PluginDefinition>,
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'FAILED_PLUGINS',
|
||||||
|
payload: Array<[PluginDefinition, string]>,
|
||||||
|
};
|
||||||
|
|
||||||
const INITIAL_STATE: State = {
|
const INITIAL_STATE: State = {
|
||||||
devicePlugins: new Map(),
|
devicePlugins: new Map(),
|
||||||
clientPlugins: new Map(),
|
clientPlugins: new Map(),
|
||||||
|
gatekeepedPlugins: [],
|
||||||
|
disabledPlugins: [],
|
||||||
|
failedPlugins: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function reducer(
|
export default function reducer(
|
||||||
@@ -51,6 +72,21 @@ export default function reducer(
|
|||||||
devicePlugins,
|
devicePlugins,
|
||||||
clientPlugins,
|
clientPlugins,
|
||||||
};
|
};
|
||||||
|
} else if (action.type === 'GATEKEEPED_PLUGINS') {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
gatekeepedPlugins: state.gatekeepedPlugins.concat(action.payload),
|
||||||
|
};
|
||||||
|
} else if (action.type === 'DISABLED_PLUGINS') {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
disabledPlugins: state.disabledPlugins.concat(action.payload),
|
||||||
|
};
|
||||||
|
} else if (action.type === 'FAILED_PLUGINS') {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
failedPlugins: state.failedPlugins.concat(action.payload),
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
@@ -60,3 +96,24 @@ export const registerPlugins = (payload: Array<P>): Action => ({
|
|||||||
type: 'REGISTER_PLUGINS',
|
type: 'REGISTER_PLUGINS',
|
||||||
payload,
|
payload,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const addGatekeepedPlugins = (
|
||||||
|
payload: Array<PluginDefinition>,
|
||||||
|
): Action => ({
|
||||||
|
type: 'GATEKEEPED_PLUGINS',
|
||||||
|
payload,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const addDisabledPlugins = (
|
||||||
|
payload: Array<PluginDefinition>,
|
||||||
|
): Action => ({
|
||||||
|
type: 'DISABLED_PLUGINS',
|
||||||
|
payload,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const addFailedPlugins = (
|
||||||
|
payload: Array<[PluginDefinition, string]>,
|
||||||
|
): Action => ({
|
||||||
|
type: 'FAILED_PLUGINS',
|
||||||
|
payload,
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user