Add idb check to doctor

Summary:
Adds a check for idb to flipper-doctor.

This depends on the flipper settings, to know where to look for idb, so I've made it so you can pass settings into the doctor when running it. When run from the command line, you don't get the settings. This is because settings loading currently depends on redux so I haven't extracted it into its own package.

Not that this will notify ALL open source iOS users with a doctor warning because they don't have idb installed. The error message says you can disable it in settings, which will silence this warning.

CHANGELOG: The open source version now works with physical iOS devices.

Reviewed By: passy

Differential Revision: D21883086

fbshipit-source-id: f28c43487e88a6c07ef3cc3da2764026726c9f18
This commit is contained in:
John Knox
2020-06-09 06:53:42 -07:00
committed by Facebook GitHub Bot
parent bf62c8cbe4
commit 21a926232e
8 changed files with 85 additions and 26 deletions

View File

@@ -141,13 +141,9 @@ class DoctorBar extends Component<Props, State> {
} }
export default connect<StateFromProps, DispatchFromProps, {}, Store>( export default connect<StateFromProps, DispatchFromProps, {}, Store>(
({ ({settingsState, healthchecks: {healthcheckReport}}) => ({
settingsState: {enableAndroid, enableIOS},
healthchecks: {healthcheckReport},
}) => ({
enableAndroid,
enableIOS,
healthcheckReport, healthcheckReport,
settings: settingsState,
}), }),
{ {
setActiveSheet, setActiveSheet,

View File

@@ -406,13 +406,9 @@ class DoctorSheet extends Component<Props, State> {
} }
export default connect<StateFromProps, DispatchFromProps, OwnProps, Store>( export default connect<StateFromProps, DispatchFromProps, OwnProps, Store>(
({ ({healthchecks: {healthcheckReport}, settingsState}) => ({
healthchecks: {healthcheckReport},
settingsState: {enableAndroid, enableIOS},
}) => ({
healthcheckReport, healthcheckReport,
enableAndroid, settings: settingsState,
enableIOS,
}), }),
{ {
startHealthchecks, startHealthchecks,

View File

@@ -85,6 +85,7 @@ class SettingsSheet extends Component<Props, State> {
enableAndroid, enableAndroid,
androidHome, androidHome,
enableIOS, enableIOS,
enablePhysicalIOS,
enablePrefetching, enablePrefetching,
idbPath, idbPath,
reactNative, reactNative,
@@ -138,6 +139,18 @@ class SettingsSheet extends Component<Props, State> {
content={'iOS development is only supported on MacOS'} content={'iOS development is only supported on MacOS'}
/> />
)} )}
<ToggledSection
label="Enable physical iOS devices"
toggled={enablePhysicalIOS}
frozen={false}
onChange={(v) => {
this.setState({
updatedSettings: {
...this.state.updatedSettings,
enablePhysicalIOS: v,
},
});
}}>
<FilePathConfigField <FilePathConfigField
label="IDB binary location" label="IDB binary location"
defaultValue={idbPath} defaultValue={idbPath}
@@ -149,6 +162,7 @@ class SettingsSheet extends Component<Props, State> {
}} }}
/> />
</ToggledSection> </ToggledSection>
</ToggledSection>
<LauncherSettingsPanel <LauncherSettingsPanel
isPrefetchingEnabled={enablePrefetching} isPrefetchingEnabled={enablePrefetching}
onEnablePrefetchingChange={(v) => { onEnablePrefetchingChange={(v) => {

View File

@@ -17,6 +17,8 @@ import path from 'path';
const ConfigFieldContainer = styled(FlexRow)({ const ConfigFieldContainer = styled(FlexRow)({
paddingLeft: 10, paddingLeft: 10,
paddingRight: 10, paddingRight: 10,
marginBottom: 5,
paddingTop: 5,
}); });
const InfoText = styled(Text)({ const InfoText = styled(Text)({

View File

@@ -258,7 +258,9 @@ export default (store: Store, logger: Logger) => {
isXcodeDetected().then((isDetected) => { isXcodeDetected().then((isDetected) => {
store.dispatch(setXcodeDetected(isDetected)); store.dispatch(setXcodeDetected(isDetected));
if (isDetected) { if (isDetected) {
if (store.getState().settingsState.enablePhysicalIOS) {
startDevicePortForwarders(); startDevicePortForwarders();
}
return queryDevicesForever(store, logger); return queryDevicesForever(store, logger);
} }
}); });

View File

@@ -21,6 +21,7 @@ export type Settings = {
androidHome: string; androidHome: string;
enableAndroid: boolean; enableAndroid: boolean;
enableIOS: boolean; enableIOS: boolean;
enablePhysicalIOS: boolean;
/** /**
* If unset, this will assume the value of the GK setting. * If unset, this will assume the value of the GK setting.
* Note that this setting has no effect in the open source version * Note that this setting has no effect in the open source version
@@ -57,6 +58,7 @@ const initialState: Settings = {
androidHome: getDefaultAndroidSdkPath(), androidHome: getDefaultAndroidSdkPath(),
enableAndroid: true, enableAndroid: true,
enableIOS: os.platform() === 'darwin', enableIOS: os.platform() === 'darwin',
enablePhysicalIOS: os.platform() === 'darwin',
enablePrefetching: Tristate.Unset, enablePrefetching: Tristate.Unset,
idbPath: '/usr/local/bin/idb', idbPath: '/usr/local/bin/idb',
jsApps: { jsApps: {

View File

@@ -25,15 +25,19 @@ export type HealthcheckEventsHandler = {
}; };
export type HealthcheckSettings = { export type HealthcheckSettings = {
settings: {
enableAndroid: boolean; enableAndroid: boolean;
enableIOS: boolean; enableIOS: boolean;
enablePhysicalIOS: boolean;
idbPath: string;
};
}; };
export type HealthcheckOptions = HealthcheckEventsHandler & HealthcheckSettings; export type HealthcheckOptions = HealthcheckEventsHandler & HealthcheckSettings;
async function launchHealthchecks(options: HealthcheckOptions): Promise<void> { async function launchHealthchecks(options: HealthcheckOptions): Promise<void> {
const healthchecks = getHealthchecks(); const healthchecks = getHealthchecks();
if (!options.enableAndroid) { if (!options.settings.enableAndroid) {
healthchecks.android = { healthchecks.android = {
label: healthchecks.android.label, label: healthchecks.android.label,
isSkipped: true, isSkipped: true,
@@ -41,7 +45,7 @@ async function launchHealthchecks(options: HealthcheckOptions): Promise<void> {
'Healthcheck is skipped, because "Android Development" option is disabled in the Flipper settings', 'Healthcheck is skipped, because "Android Development" option is disabled in the Flipper settings',
}; };
} }
if (!options.enableIOS) { if (!options.settings.enableIOS) {
healthchecks.ios = { healthchecks.ios = {
label: healthchecks.ios.label, label: healthchecks.ios.label,
isSkipped: true, isSkipped: true,
@@ -57,7 +61,7 @@ async function launchHealthchecks(options: HealthcheckOptions): Promise<void> {
continue; continue;
} }
for (const h of category.healthchecks) { for (const h of category.healthchecks) {
const checkResult = await h.run(environmentInfo); const checkResult = await h.run(environmentInfo, options.settings);
const metricName = `doctor:${h.key.replace('.', ':')}.healthcheck`; // e.g. "doctor:ios:xcode-select.healthcheck" const metricName = `doctor:${h.key.replace('.', ':')}.healthcheck`; // e.g. "doctor:ios:xcode-select.healthcheck"
if (checkResult.hasProblem) { if (checkResult.hasProblem) {
hasProblems = true; hasProblems = true;

View File

@@ -34,11 +34,19 @@ export type Healthchecks = {
ios: HealthcheckCategory | SkippedHealthcheckCategory; ios: HealthcheckCategory | SkippedHealthcheckCategory;
}; };
export type Settings = {
idbPath: string;
enablePhysicalIOS: boolean;
};
export type Healthcheck = { export type Healthcheck = {
key: string; key: string;
label: string; label: string;
isRequired?: boolean; isRequired?: boolean;
run: (env: EnvironmentInfo) => Promise<HealthchecRunResult>; run: (
env: EnvironmentInfo,
settings?: Settings,
) => Promise<HealthchecRunResult>;
}; };
export type HealthchecRunResult = { export type HealthchecRunResult = {
@@ -204,6 +212,41 @@ export function getHealthchecks(): Healthchecks {
}; };
}, },
}, },
{
key: 'ios.idb',
label: 'IDB installed',
isRequired: false,
run: async (
_: EnvironmentInfo,
settings?: {enablePhysicalIOS: boolean; idbPath: string},
) => {
if (!settings) {
return {
hasProblem: false,
message:
'Not enough context to check IDB installation. Needs to be run through Flipper UI.',
};
}
if (!settings.enablePhysicalIOS) {
return {
hasProblem: false,
message:
'Using physical iOS devices is disabled in settings. So IDB is not required.',
};
}
const result = await tryExecuteCommand(
`${settings?.idbPath} --help`,
);
const hasProblem = result.hasProblem;
const message = hasProblem
? `IDB is required to use Flipper with iOS devices. It can be installed from https://github.com/facebook/idb and configured in Flipper settings. You can also disable physical iOS device support in settings. Current setting: ${settings.idbPath} isn't a valid IDB installation.`
: 'Flipper is configured to use your IDB installation.';
return {
hasProblem,
message,
};
},
},
], ],
} }
: { : {