Start bridge abstraction

Summary: This is just an early start of centralising some ad-hoc logic we've got all over the place right now. Memoised do-we-have-idb calls with concatenated shell invocations. This gives us the opportunity to do a bit of testing, too.

Reviewed By: mweststrate

Differential Revision: D26694863

fbshipit-source-id: cd2b9883f90397802bbaae6030f7cb3881c565c2
This commit is contained in:
Pascal Hartig
2021-03-02 09:51:16 -08:00
committed by Facebook GitHub Bot
parent 43242557aa
commit 390f27a137
4 changed files with 183 additions and 61 deletions

View File

@@ -0,0 +1,78 @@
/**
* 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 fs from 'fs';
import child_process from 'child_process';
export interface IOSBridge {
startLogListener: (
udid: string,
) => child_process.ChildProcessWithoutNullStreams;
}
async function isAvailable(idbPath: string): Promise<boolean> {
if (!idbPath) {
return false;
}
return fs.promises
.access(idbPath, fs.constants.X_OK)
.then((_) => true)
.catch((_) => false);
}
const LOG_EXTRA_ARGS = [
'--style',
'json',
'--predicate',
'senderImagePath contains "Containers"',
'--debug',
'--info',
];
function idbStartLogListener(
idbPath: string,
udid: string,
): child_process.ChildProcessWithoutNullStreams {
return child_process.spawn(
idbPath,
['log', '--udid', udid, '--', ...LOG_EXTRA_ARGS],
{},
);
}
function xcrunStartLogListener(udid: string) {
const deviceSetPath = process.env.DEVICE_SET_PATH
? ['--set', process.env.DEVICE_SET_PATH]
: [];
return child_process.spawn(
'xcrun',
[
'simctl',
...deviceSetPath,
'spawn',
udid,
'log',
'stream',
...LOG_EXTRA_ARGS,
],
{},
);
}
export async function makeIOSBridge(idbPath: string): Promise<IOSBridge> {
if (await isAvailable(idbPath)) {
return {
startLogListener: idbStartLogListener.bind(null, idbPath),
};
}
return {
startLogListener: xcrunStartLogListener,
};
}

View File

@@ -0,0 +1,60 @@
/**
* 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 {makeIOSBridge} from '../IOSBridge';
import childProcess from 'child_process';
import {mocked} from 'ts-jest/utils';
jest.mock('child_process');
const spawn = mocked(childProcess.spawn);
test('uses xcrun with no idb', async () => {
const ib = await makeIOSBridge('');
ib.startLogListener('deadbeef');
expect(spawn).toHaveBeenCalledWith(
'xcrun',
[
'simctl',
'spawn',
'deadbeef',
'log',
'stream',
'--style',
'json',
'--predicate',
'senderImagePath contains "Containers"',
'--debug',
'--info',
],
{},
);
});
test('uses idb when present', async () => {
const ib = await makeIOSBridge('/usr/local/bin/idb');
ib.startLogListener('deadbeef');
expect(spawn).toHaveBeenCalledWith(
'/usr/local/bin/idb',
[
'log',
'--udid',
'deadbeef',
'--',
'--style',
'json',
'--predicate',
'senderImagePath contains "Containers"',
'--debug',
'--info',
],
{},
);
});