Summary: Bumps [prettier](https://github.com/prettier/prettier) from 2.2.1 to 2.3.0. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/prettier/prettier/releases">prettier's releases</a>.</em></p> <blockquote> <h2>2.3.0</h2> <p><a href="https://github.com/prettier/prettier/compare/2.2.1...2.3.0">diff</a></p> <p>{emoji:1f517} <a href="https://prettier.io/blog/2021/05/09/2.3.0.html">Release Notes</a></p> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/prettier/prettier/blob/main/CHANGELOG.md">prettier's changelog</a>.</em></p> <blockquote> <h1>2.3.0</h1> <p><a href="https://github.com/prettier/prettier/compare/2.2.1...2.3.0">diff</a></p> <p>{emoji:1f517} <a href="https://prettier.io/blog/2021/05/09/2.3.0.html">Release Notes</a></p> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="2afc3b9ae6"><code>2afc3b9</code></a> Release 2.3.0</li> <li><a href="7cfa9aa89b"><code>7cfa9aa</code></a> Fix pre-commit hook setup command (<a href="https://github-redirect.dependabot.com/prettier/prettier/issues/10710">#10710</a>)</li> <li><a href="c8c02b4753"><code>c8c02b4</code></a> Build(deps-dev): Bump concurrently from 6.0.2 to 6.1.0 in /website (<a href="https://github-redirect.dependabot.com/prettier/prettier/issues/10834">#10834</a>)</li> <li><a href="6506e0f50e"><code>6506e0f</code></a> Build(deps-dev): Bump webpack-cli from 4.6.0 to 4.7.0 in /website (<a href="https://github-redirect.dependabot.com/prettier/prettier/issues/10836">#10836</a>)</li> <li><a href="69fae9c291"><code>69fae9c</code></a> Build(deps): Bump flow-parser from 0.150.0 to 0.150.1 (<a href="https://github-redirect.dependabot.com/prettier/prettier/issues/10839">#10839</a>)</li> <li><a href="164a6e2351"><code>164a6e2</code></a> Switch CLI to async (<a href="https://github-redirect.dependabot.com/prettier/prettier/issues/10804">#10804</a>)</li> <li><a href="d3e7e2f634"><code>d3e7e2f</code></a> Build(deps): Bump codecov/codecov-action from v1.4.1 to v1.5.0 (<a href="https://github-redirect.dependabot.com/prettier/prettier/issues/10833">#10833</a>)</li> <li><a href="9e09845da0"><code>9e09845</code></a> Build(deps): Bump <code>@angular/compiler</code> from 11.2.12 to 11.2.13 (<a href="https://github-redirect.dependabot.com/prettier/prettier/issues/10838">#10838</a>)</li> <li><a href="1bfab3d045"><code>1bfab3d</code></a> Build(deps-dev): Bump eslint from 7.25.0 to 7.26.0 (<a href="https://github-redirect.dependabot.com/prettier/prettier/issues/10840">#10840</a>)</li> <li><a href="387fce4ed8"><code>387fce4</code></a> Minor formatting tweaks (<a href="https://github-redirect.dependabot.com/prettier/prettier/issues/10807">#10807</a>)</li> <li>Additional commits viewable in <a href="https://github.com/prettier/prettier/compare/2.2.1...2.3.0">compare view</a></li> </ul> </details> <br /> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `dependabot rebase` will rebase this PR - `dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `dependabot merge` will merge this PR after your CI passes on it - `dependabot squash and merge` will squash and merge this PR after your CI passes on it - `dependabot cancel merge` will cancel a previously requested merge and block automerging - `dependabot reopen` will reopen this PR if it is closed - `dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) </details> Pull Request resolved: https://github.com/facebook/flipper/pull/2300 Reviewed By: passy Differential Revision: D28323849 Pulled By: cekkaewnumchai fbshipit-source-id: 1842877ccc9a9587af7f0d9ff9432c2075c8ee22
274 lines
8.4 KiB
TypeScript
274 lines
8.4 KiB
TypeScript
/**
|
|
* 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 AndroidDevice from '../devices/AndroidDevice';
|
|
import KaiOSDevice from '../devices/KaiOSDevice';
|
|
import child_process from 'child_process';
|
|
import {Store} from '../reducers/index';
|
|
import BaseDevice from '../devices/BaseDevice';
|
|
import {Logger} from '../fb-interfaces/Logger';
|
|
import {getAdbClient} from '../utils/adbClient';
|
|
import which from 'which';
|
|
import {promisify} from 'util';
|
|
import {ServerPorts} from '../reducers/application';
|
|
import {Client as ADBClient} from 'adbkit';
|
|
import {addErrorNotification} from '../reducers/notifications';
|
|
import {destroyDevice} from '../reducers/connections';
|
|
|
|
function createDevice(
|
|
adbClient: ADBClient,
|
|
device: any,
|
|
store: Store,
|
|
ports?: ServerPorts,
|
|
): Promise<AndroidDevice | undefined> {
|
|
return new Promise((resolve, reject) => {
|
|
const type =
|
|
device.type !== 'device' || device.id.startsWith('emulator')
|
|
? 'emulator'
|
|
: 'physical';
|
|
|
|
adbClient
|
|
.getProperties(device.id)
|
|
.then(async (props) => {
|
|
try {
|
|
let name = props['ro.product.model'];
|
|
const abiString = props['ro.product.cpu.abilist'] || '';
|
|
const sdkVersion = props['ro.build.version.sdk'] || '';
|
|
const abiList = abiString.length > 0 ? abiString.split(',') : [];
|
|
if (type === 'emulator') {
|
|
name = (await getRunningEmulatorName(device.id)) || name;
|
|
}
|
|
const isKaiOSDevice = Object.keys(props).some(
|
|
(name) => name.startsWith('kaios') || name.startsWith('ro.kaios'),
|
|
);
|
|
const androidLikeDevice = new (
|
|
isKaiOSDevice ? KaiOSDevice : AndroidDevice
|
|
)(device.id, type, name, adbClient, abiList, sdkVersion);
|
|
if (ports) {
|
|
await androidLikeDevice
|
|
.reverse([ports.secure, ports.insecure])
|
|
// We may not be able to establish a reverse connection, e.g. for old Android SDKs.
|
|
// This is *generally* fine, because we hard-code the ports on the SDK side.
|
|
.catch((e) => {
|
|
console.warn(
|
|
`Failed to reverse-proxy ports on device ${androidLikeDevice.serial}: ${e}`,
|
|
);
|
|
});
|
|
}
|
|
resolve(androidLikeDevice);
|
|
} catch (e) {
|
|
reject(e);
|
|
}
|
|
})
|
|
.catch((e) => {
|
|
if (
|
|
e &&
|
|
e.message &&
|
|
e.message === `Failure: 'device still connecting'`
|
|
) {
|
|
console.debug('Device still connecting: ' + device.id);
|
|
} else {
|
|
const isAuthorizationError = (e?.message as string)?.includes(
|
|
'device unauthorized',
|
|
);
|
|
store.dispatch(
|
|
addErrorNotification(
|
|
'Could not connect to ' + device.id,
|
|
isAuthorizationError
|
|
? 'Make sure to authorize debugging on the phone'
|
|
: 'Failed to setup connection',
|
|
e,
|
|
),
|
|
);
|
|
}
|
|
resolve(undefined); // not ready yet, we will find it in the next tick
|
|
});
|
|
});
|
|
}
|
|
|
|
export async function getActiveAndroidDevices(
|
|
store: Store,
|
|
): Promise<Array<BaseDevice>> {
|
|
const client = await getAdbClient(store);
|
|
const androidDevices = await client.listDevices();
|
|
const devices = await Promise.all(
|
|
androidDevices.map((device) => createDevice(client, device, store)),
|
|
);
|
|
return devices.filter(Boolean) as any;
|
|
}
|
|
|
|
function getRunningEmulatorName(
|
|
id: string,
|
|
): Promise<string | null | undefined> {
|
|
return new Promise((resolve, reject) => {
|
|
const port = id.replace('emulator-', '');
|
|
// The GNU version of netcat doesn't terminate after 1s when
|
|
// specifying `-w 1`, so we kill it after a timeout. Because
|
|
// of that, even in case of an error, there may still be
|
|
// relevant data for us to parse.
|
|
child_process.exec(
|
|
`echo "avd name" | nc -w 1 localhost ${port}`,
|
|
{timeout: 1000, encoding: 'utf-8'},
|
|
(error: Error | null | undefined, data) => {
|
|
if (data != null && typeof data === 'string') {
|
|
const match = data.trim().match(/(.*)\r\nOK$/);
|
|
resolve(match != null && match.length > 0 ? match[1] : null);
|
|
} else {
|
|
reject(error);
|
|
}
|
|
},
|
|
);
|
|
});
|
|
}
|
|
|
|
export default (store: Store, logger: Logger) => {
|
|
const watchAndroidDevices = () => {
|
|
// get emulators
|
|
promisify(which)('emulator')
|
|
.catch(
|
|
() =>
|
|
`${
|
|
process.env.ANDROID_HOME || process.env.ANDROID_SDK_ROOT || ''
|
|
}/tools/emulator`,
|
|
)
|
|
.then((emulatorPath) => {
|
|
child_process.exec(
|
|
`${emulatorPath} -list-avds`,
|
|
(error: Error | null, data: string | null) => {
|
|
if (error != null || data == null) {
|
|
console.warn('List AVD failed: ', error);
|
|
return;
|
|
}
|
|
const payload = data.split('\n').filter(Boolean);
|
|
store.dispatch({
|
|
type: 'REGISTER_ANDROID_EMULATORS',
|
|
payload,
|
|
});
|
|
},
|
|
);
|
|
});
|
|
|
|
getAdbClient(store)
|
|
.then((client) => {
|
|
client
|
|
.trackDevices()
|
|
.then((tracker) => {
|
|
tracker.on('error', (err) => {
|
|
if (err.message === 'Connection closed') {
|
|
// adb server has shutdown, remove all android devices
|
|
const {connections} = store.getState();
|
|
const deviceIDsToRemove: Array<string> = connections.devices
|
|
.filter(
|
|
(device: BaseDevice) => device instanceof AndroidDevice,
|
|
)
|
|
.map((device: BaseDevice) => device.serial);
|
|
|
|
unregisterDevices(deviceIDsToRemove);
|
|
console.warn('adb server was shutdown');
|
|
setTimeout(watchAndroidDevices, 500);
|
|
} else {
|
|
throw err;
|
|
}
|
|
});
|
|
|
|
tracker.on('add', async (device) => {
|
|
if (device.type !== 'offline') {
|
|
registerDevice(client, device, store);
|
|
}
|
|
});
|
|
|
|
tracker.on('change', async (device) => {
|
|
if (device.type === 'offline') {
|
|
unregisterDevices([device.id]);
|
|
} else {
|
|
registerDevice(client, device, store);
|
|
}
|
|
});
|
|
|
|
tracker.on('remove', (device) => {
|
|
unregisterDevices([device.id]);
|
|
});
|
|
})
|
|
.catch((err: {code: string}) => {
|
|
if (err.code === 'ECONNREFUSED') {
|
|
console.warn('adb server not running');
|
|
} else {
|
|
throw err;
|
|
}
|
|
});
|
|
})
|
|
.catch((e) => {
|
|
console.warn(`Failed to watch for android devices: ${e.message}`);
|
|
});
|
|
};
|
|
|
|
async function registerDevice(adbClient: any, deviceData: any, store: Store) {
|
|
const androidDevice = await createDevice(
|
|
adbClient,
|
|
deviceData,
|
|
store,
|
|
store.getState().application.serverPorts,
|
|
);
|
|
if (!androidDevice) {
|
|
return;
|
|
}
|
|
logger.track('usage', 'register-device', {
|
|
os: 'Android',
|
|
name: androidDevice.title,
|
|
serial: androidDevice.serial,
|
|
});
|
|
|
|
// remove offline devices with same serial as the connected.
|
|
const reconnectedDevices = store
|
|
.getState()
|
|
.connections.devices.filter(
|
|
(device: BaseDevice) =>
|
|
device.serial === androidDevice.serial && !device.connected.get(),
|
|
)
|
|
.map((device) => device.serial);
|
|
|
|
reconnectedDevices.forEach((serial) => {
|
|
destroyDevice(store, logger, serial);
|
|
});
|
|
|
|
androidDevice.loadDevicePlugins(
|
|
store.getState().plugins.devicePlugins,
|
|
store.getState().connections.enabledDevicePlugins,
|
|
);
|
|
store.dispatch({
|
|
type: 'REGISTER_DEVICE',
|
|
payload: androidDevice,
|
|
});
|
|
}
|
|
|
|
async function unregisterDevices(deviceIds: Array<string>) {
|
|
deviceIds.forEach((id) =>
|
|
logger.track('usage', 'unregister-device', {
|
|
os: 'Android',
|
|
serial: id,
|
|
}),
|
|
);
|
|
|
|
deviceIds.forEach((id) => {
|
|
const device = store
|
|
.getState()
|
|
.connections.devices.find((device) => device.serial === id);
|
|
device?.disconnect();
|
|
});
|
|
}
|
|
|
|
watchAndroidDevices();
|
|
|
|
// cleanup method
|
|
return () =>
|
|
getAdbClient(store).then((client) => {
|
|
client.kill();
|
|
});
|
|
};
|