Device plugin management (1/n): use static metadata for checking plugin compatibility with devices
Summary: *Stack summary*: this stack adds ability to manage device plugins in the same way as client plugins: install, update, uninstall, enable (star) and disable (unstar) them. *Diff summary*: changed the way how plugin compatibility with devices is checked from dynamic call to "supportsDevice" to static checks of "supportedDevices" metadata property which make it possible to check compatibility without even downloading plugin from Marketplace. Changelog: plugin compatibility with devices is now checked according to metadata in property "supportedDevices" in package.json Reviewed By: mweststrate Differential Revision: D26315848 fbshipit-source-id: 6e4b052c4ea0507ee185fc17999b6211cdb11093
This commit is contained in:
committed by
Facebook GitHub Bot
parent
19f2fccc79
commit
899fcd0783
@@ -17,9 +17,13 @@ import {
|
||||
Idler,
|
||||
createState,
|
||||
} from 'flipper-plugin';
|
||||
import type {DevicePluginDefinition, DevicePluginMap} from '../plugin';
|
||||
import {
|
||||
DevicePluginDefinition,
|
||||
DevicePluginMap,
|
||||
FlipperDevicePlugin,
|
||||
} from '../plugin';
|
||||
import {getFlipperLibImplementation} from '../utils/flipperLibImplementation';
|
||||
import {DeviceSpec, OS as PluginOS} from 'flipper-plugin-lib';
|
||||
import {DeviceSpec, OS as PluginOS, PluginDetails} from 'flipper-plugin-lib';
|
||||
|
||||
export type DeviceShell = {
|
||||
stdout: stream.Readable;
|
||||
@@ -175,6 +179,38 @@ export default class BaseDevice {
|
||||
return null;
|
||||
}
|
||||
|
||||
supportsPlugin(plugin: DevicePluginDefinition | PluginDetails) {
|
||||
let pluginDetails: PluginDetails;
|
||||
if (isDevicePluginDefinition(plugin)) {
|
||||
pluginDetails = plugin.details;
|
||||
if (!pluginDetails.pluginType && !pluginDetails.supportedDevices) {
|
||||
// TODO T84453692: this branch is to support plugins defined with the legacy approach. Need to remove this branch after some transition period when
|
||||
// all the plugins will be migrated to the new approach with static compatibility metadata in package.json.
|
||||
if (plugin instanceof _SandyPluginDefinition) {
|
||||
return (
|
||||
plugin.isDevicePlugin &&
|
||||
plugin.asDevicePluginModule().supportsDevice(this as any)
|
||||
);
|
||||
} else {
|
||||
return plugin.supportsDevice(this);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pluginDetails = plugin;
|
||||
}
|
||||
return (
|
||||
pluginDetails.pluginType === 'device' &&
|
||||
(!pluginDetails.supportedDevices ||
|
||||
pluginDetails.supportedDevices?.some(
|
||||
(d) =>
|
||||
(!d.os || d.os === this.os) &&
|
||||
(!d.type || d.type === this.deviceType) &&
|
||||
(d.archived === undefined || d.archived === this.isArchived) &&
|
||||
(!d.specs || d.specs.every((spec) => this.specs.includes(spec))),
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
loadDevicePlugins(
|
||||
devicePlugins?: DevicePluginMap,
|
||||
pluginStates?: Record<string, any>,
|
||||
@@ -189,23 +225,20 @@ export default class BaseDevice {
|
||||
}
|
||||
|
||||
loadDevicePlugin(plugin: DevicePluginDefinition, initialState?: any) {
|
||||
if (!this.supportsPlugin(plugin)) {
|
||||
return;
|
||||
}
|
||||
this.devicePlugins.push(plugin.id);
|
||||
if (plugin instanceof _SandyPluginDefinition) {
|
||||
if (plugin.asDevicePluginModule().supportsDevice(this as any)) {
|
||||
this.devicePlugins.push(plugin.id);
|
||||
this.sandyPluginStates.set(
|
||||
plugin.id,
|
||||
new _SandyDevicePluginInstance(
|
||||
getFlipperLibImplementation(),
|
||||
plugin,
|
||||
this,
|
||||
initialState,
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (plugin.supportsDevice(this)) {
|
||||
this.devicePlugins.push(plugin.id);
|
||||
}
|
||||
this.sandyPluginStates.set(
|
||||
plugin.id,
|
||||
new _SandyDevicePluginInstance(
|
||||
getFlipperLibImplementation(),
|
||||
plugin,
|
||||
this,
|
||||
initialState,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,3 +264,12 @@ export default class BaseDevice {
|
||||
this.sandyPluginStates.clear();
|
||||
}
|
||||
}
|
||||
|
||||
function isDevicePluginDefinition(
|
||||
definition: any,
|
||||
): definition is DevicePluginDefinition {
|
||||
return (
|
||||
(definition as any).prototype instanceof FlipperDevicePlugin ||
|
||||
(definition instanceof _SandyPluginDefinition && definition.isDevicePlugin)
|
||||
);
|
||||
}
|
||||
|
||||
152
desktop/app/src/devices/__tests__/BaseDevice.node.tsx
Normal file
152
desktop/app/src/devices/__tests__/BaseDevice.node.tsx
Normal file
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
import BaseDevice from '../BaseDevice';
|
||||
import * as DeviceTestPluginModule from '../../test-utils/DeviceTestPlugin';
|
||||
import {TestUtils, _SandyPluginDefinition} from 'flipper-plugin';
|
||||
import ArchivedDevice from '../ArchivedDevice';
|
||||
|
||||
const physicalDevicePluginDetails = TestUtils.createMockPluginDetails({
|
||||
id: 'physicalDevicePlugin',
|
||||
name: 'flipper-plugin-physical-device',
|
||||
version: '0.0.1',
|
||||
pluginType: 'device',
|
||||
supportedDevices: [
|
||||
{
|
||||
os: 'iOS',
|
||||
type: 'physical',
|
||||
archived: false,
|
||||
},
|
||||
{
|
||||
os: 'Android',
|
||||
type: 'physical',
|
||||
},
|
||||
],
|
||||
});
|
||||
const physicalDevicePlugin = new _SandyPluginDefinition(
|
||||
physicalDevicePluginDetails,
|
||||
DeviceTestPluginModule,
|
||||
);
|
||||
|
||||
const iosPhysicalDevicePluginDetails = TestUtils.createMockPluginDetails({
|
||||
id: 'iosPhysicalDevicePlugin',
|
||||
name: 'flipper-plugin-ios-physical-device',
|
||||
version: '0.0.1',
|
||||
pluginType: 'device',
|
||||
supportedDevices: [
|
||||
{
|
||||
os: 'iOS',
|
||||
type: 'physical',
|
||||
},
|
||||
],
|
||||
});
|
||||
const iosPhysicalDevicePlugin = new _SandyPluginDefinition(
|
||||
iosPhysicalDevicePluginDetails,
|
||||
DeviceTestPluginModule,
|
||||
);
|
||||
|
||||
const iosEmulatorlDevicePluginDetails = TestUtils.createMockPluginDetails({
|
||||
id: 'iosEmulatorDevicePlugin',
|
||||
name: 'flipper-plugin-ios-emulator-device',
|
||||
version: '0.0.1',
|
||||
pluginType: 'device',
|
||||
supportedDevices: [
|
||||
{
|
||||
os: 'iOS',
|
||||
type: 'emulator',
|
||||
},
|
||||
],
|
||||
});
|
||||
const iosEmulatorDevicePlugin = new _SandyPluginDefinition(
|
||||
iosEmulatorlDevicePluginDetails,
|
||||
DeviceTestPluginModule,
|
||||
);
|
||||
const androiKaiosPhysicalDevicePluginDetails = TestUtils.createMockPluginDetails(
|
||||
{
|
||||
id: 'androidPhysicalDevicePlugin',
|
||||
name: 'flipper-plugin-android-physical-device',
|
||||
version: '0.0.1',
|
||||
pluginType: 'device',
|
||||
supportedDevices: [
|
||||
{
|
||||
os: 'Android',
|
||||
type: 'physical',
|
||||
specs: ['KaiOS'],
|
||||
},
|
||||
],
|
||||
},
|
||||
);
|
||||
const androidKaiosPhysicalDevicePlugin = new _SandyPluginDefinition(
|
||||
androiKaiosPhysicalDevicePluginDetails,
|
||||
DeviceTestPluginModule,
|
||||
);
|
||||
|
||||
const androidEmulatorlDevicePluginDetails = TestUtils.createMockPluginDetails({
|
||||
id: 'androidEmulatorDevicePlugin',
|
||||
name: 'flipper-plugin-android-emulator-device',
|
||||
version: '0.0.1',
|
||||
pluginType: 'device',
|
||||
supportedDevices: [
|
||||
{
|
||||
os: 'Android',
|
||||
type: 'emulator',
|
||||
},
|
||||
],
|
||||
});
|
||||
const androidEmulatorDevicePlugin = new _SandyPluginDefinition(
|
||||
androidEmulatorlDevicePluginDetails,
|
||||
DeviceTestPluginModule,
|
||||
);
|
||||
test('ios physical device compatibility', () => {
|
||||
const device = new BaseDevice('serial', 'physical', 'test device', 'iOS');
|
||||
expect(device.supportsPlugin(physicalDevicePlugin)).toBeTruthy();
|
||||
expect(device.supportsPlugin(iosPhysicalDevicePlugin)).toBeTruthy();
|
||||
expect(device.supportsPlugin(iosEmulatorDevicePlugin)).toBeFalsy();
|
||||
expect(device.supportsPlugin(androidKaiosPhysicalDevicePlugin)).toBeFalsy();
|
||||
expect(device.supportsPlugin(androidEmulatorDevicePlugin)).toBeFalsy();
|
||||
});
|
||||
|
||||
test('archived device compatibility', () => {
|
||||
const device = new ArchivedDevice({
|
||||
serial: 'serial',
|
||||
deviceType: 'physical',
|
||||
title: 'test device',
|
||||
os: 'iOS',
|
||||
screenshotHandle: null,
|
||||
});
|
||||
expect(device.supportsPlugin(physicalDevicePlugin)).toBeFalsy();
|
||||
expect(device.supportsPlugin(iosPhysicalDevicePlugin)).toBeTruthy();
|
||||
expect(device.supportsPlugin(iosEmulatorDevicePlugin)).toBeFalsy();
|
||||
expect(device.supportsPlugin(androidKaiosPhysicalDevicePlugin)).toBeFalsy();
|
||||
expect(device.supportsPlugin(androidEmulatorDevicePlugin)).toBeFalsy();
|
||||
});
|
||||
|
||||
test('android emulator device compatibility', () => {
|
||||
const device = new BaseDevice('serial', 'emulator', 'test device', 'Android');
|
||||
expect(device.supportsPlugin(physicalDevicePlugin)).toBeFalsy();
|
||||
expect(device.supportsPlugin(iosPhysicalDevicePlugin)).toBeFalsy();
|
||||
expect(device.supportsPlugin(iosEmulatorDevicePlugin)).toBeFalsy();
|
||||
expect(device.supportsPlugin(androidKaiosPhysicalDevicePlugin)).toBeFalsy();
|
||||
expect(device.supportsPlugin(androidEmulatorDevicePlugin)).toBeTruthy();
|
||||
});
|
||||
|
||||
test('android KaiOS device compatibility', () => {
|
||||
const device = new BaseDevice(
|
||||
'serial',
|
||||
'physical',
|
||||
'test device',
|
||||
'Android',
|
||||
['KaiOS'],
|
||||
);
|
||||
expect(device.supportsPlugin(physicalDevicePlugin)).toBeTruthy();
|
||||
expect(device.supportsPlugin(iosPhysicalDevicePlugin)).toBeFalsy();
|
||||
expect(device.supportsPlugin(iosEmulatorDevicePlugin)).toBeFalsy();
|
||||
expect(device.supportsPlugin(androidKaiosPhysicalDevicePlugin)).toBeTruthy();
|
||||
expect(device.supportsPlugin(androidEmulatorDevicePlugin)).toBeFalsy();
|
||||
});
|
||||
Reference in New Issue
Block a user