Skip to content

Commit

Permalink
Open-source idb interaction code
Browse files Browse the repository at this point in the history
Summary:
I've outlined the tasks required to get iOS device support working for open source users [here](#262).

This is the first step. It publishes the same code we use internally to GitHub, but in a state where it is only "available" for non-public builds. This will not change any behavior, but means that together with the community, we can start adapting it to suit everyone, and then eventually flip "available" to true for everyone.

Reviewed By: passy

Differential Revision: D21740193

fbshipit-source-id: 586c79ad850f67da330c10a007605ff25a187544
  • Loading branch information
jknoxville authored and facebook-github-bot committed May 29, 2020
1 parent bd50f60 commit 5723553
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 74 deletions.
2 changes: 1 addition & 1 deletion desktop/app/src/dispatcher/iOSDevice.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {promisify} from 'util';
import path from 'path';
import child_process from 'child_process';
const execFile = child_process.execFile;
import iosUtil from '../fb-stubs/iOSContainerUtility';
import iosUtil from '../utils/iOSContainerUtility';
import IOSDevice from '../devices/IOSDevice';
import isProduction from '../utils/isProduction';
import GK from '../fb-stubs/GK';
Expand Down
71 changes: 0 additions & 71 deletions desktop/app/src/fb-stubs/iOSContainerUtility.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion desktop/app/src/reducers/connections.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import MacDevice from '../devices/MacDevice';
import Client from '../Client';
import {UninitializedClient} from '../UninitializedClient';
import {isEqual} from 'lodash';
import iosUtil from '../fb-stubs/iOSContainerUtility';
import iosUtil from '../utils/iOSContainerUtility';
import {performance} from 'perf_hooks';
import isHeadless from '../utils/isHeadless';
import {Actions} from '.';
Expand Down
2 changes: 1 addition & 1 deletion desktop/app/src/utils/CertificateProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
} from './openssl-wrapper-with-promises';
import path from 'path';
import tmp, {DirOptions, FileOptions} from 'tmp';
import iosUtil from '../fb-stubs/iOSContainerUtility';
import iosUtil from './iOSContainerUtility';
import {reportPlatformFailures} from './metrics';
import {getAdbClient} from './adbClient';
import * as androidUtil from './androidContainerUtility';
Expand Down
133 changes: 133 additions & 0 deletions desktop/app/src/utils/iOSContainerUtility.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/**
* 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 child_process from 'child_process';
import {promisify} from 'util';
import {Mutex} from 'async-mutex';
import {notNull} from './typeUtils';
const unsafeExec = promisify(child_process.exec);
import {killOrphanedInstrumentsProcesses} from './processCleanup';
import {reportPlatformFailures} from './metrics';
import config from '../fb-stubs/config';

const idbPath = '/usr/local/bin/idb';
// Use debug to get helpful logs when idb fails
const idbLogLevel = 'DEBUG';
const operationPrefix = 'iosContainerUtility';

const mutex = new Mutex();

export type DeviceTarget = {
udid: string;
type: 'physical' | 'emulator';
name: string;
};

function isAvailable(): boolean {
return config.isFBBuild;
}

function safeExec(command: string): Promise<{stdout: string; stderr: string}> {
return mutex.acquire().then((release) => {
return unsafeExec(command).finally(release);
});
}

async function targets(): Promise<Array<DeviceTarget>> {
if (process.platform !== 'darwin') {
return [];
}
await killOrphanedInstrumentsProcesses();
return safeExec('instruments -s devices').then(({stdout}) =>
stdout
.toString()
.split('\n')
.map((line) => line.trim())
.map((line) => /(.+) \([^(]+\) \[(.*)\]( \(Simulator\))?/.exec(line))
.filter(notNull)
.filter(
([_match, name, _udid, isSim]) =>
!isSim && (name.includes('iPhone') || name.includes('iPad')),
)
.map(([_match, name, udid]) => {
return {udid: udid, type: 'physical', name: name};
}),
);
}

function push(
udid: string,
src: string,
bundleId: string,
dst: string,
): Promise<void> {
return wrapWithErrorMessage(
reportPlatformFailures(
safeExec(
`${idbPath} --log ${idbLogLevel} file push --udid ${udid} --bundle-id ${bundleId} '${src}' '${dst}'`,
)
.then(() => {
return;
})
.catch(handleMissingIdb),
`${operationPrefix}:push`,
),
);
}

function pull(
udid: string,
src: string,
bundleId: string,
dst: string,
): Promise<void> {
return wrapWithErrorMessage(
reportPlatformFailures(
safeExec(
`${idbPath} --log ${idbLogLevel} file pull --udid ${udid} --bundle-id ${bundleId} '${src}' '${dst}'`,
)
.then(() => {
return;
})
.catch(handleMissingIdb),
`${operationPrefix}:pull`,
),
);
}

// The idb binary is a shim that downloads the proper one on first run. It requires sudo to do so.
// If we detect this, Tell the user how to fix it.
function handleMissingIdb(e: Error): void {
if (
e.message &&
e.message.includes('sudo: no tty present and no askpass program specified')
) {
throw new Error(
`idb doesn't appear to be installed. Run "${idbPath} list-targets" to fix this.`,
);
}
throw e;
}

function wrapWithErrorMessage<T>(p: Promise<T>): Promise<T> {
return p.catch((e: Error) => {
console.error(e);
// Give the user instructions. Don't embed the error because it's unique per invocation so won't be deduped.
throw new Error(
"A problem with idb has ocurred. Please run `sudo rm -rf /tmp/idb*` and `sudo yum install -y fb-idb` to update it, if that doesn't fix it, post in Flipper Support.",
);
});
}

export default {
isAvailable: isAvailable,
targets: targets,
push: push,
pull: pull,
};

0 comments on commit 5723553

Please sign in to comment.