microsoft/vscode-react-native

Public

mirrored from https://github.com/microsoft/vscode-react-nativeAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
1.8.0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

src/extension/ios/iOSContainerUtility.ts

257lines · modeblame

4bb0956eRedMickey5 years ago1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for details.
3
4import { ChildProcess } from "../../common/node/childProcess";
5import { PromiseUtil } from "../../common/node/promise";
6import { OutputChannelLogger } from "../log/OutputChannelLogger";
4cd25962JiglioNero4 years ago7import * as fs from "fs";
8import * as path from "path";
9import { IDebuggableMobileTarget } from "../mobileTarget";
10import { logger } from "vscode-debugadapter/lib/logger";
4bb0956eRedMickey5 years ago11
12/**
13* @preserve
4cd25962JiglioNero4 years ago14* Start region: the code is borrowed from https://github.com/facebook/flipper/blob/c2848df7f210c363113797c0f2e3db8c5d4fd49f/desktop/app/src/server/devices/ios/iOSContainerUtility.tsx
4bb0956eRedMickey5 years ago15*
16* Copyright (c) Facebook, Inc. and its affiliates.
17*
18* This source code is licensed under the MIT license found in the
19* LICENSE file in the root directory of this source tree.
20*
21* @format
22*/
23
24export const idbPath = "/usr/local/bin/idb";
25// Use debug to get helpful logs when idb fails
26const idbLogLevel = "DEBUG";
27
28type IdbTarget = {
29name: string;
30udid: string;
31state: string;
32type: string;
4cd25962JiglioNero4 years ago33target_type?: string;
4bb0956eRedMickey5 years ago34os_version: string;
35architecture: string;
36};
37
4cd25962JiglioNero4 years ago38export type DeviceTarget = IDebuggableMobileTarget;
4bb0956eRedMickey5 years ago39
4cd25962JiglioNero4 years ago40export const isIdbAvailable = PromiseUtil.promiseCacheDecorator<boolean>(isAvailable);
4bb0956eRedMickey5 years ago41
42function isAvailable(): Promise<boolean> {
43if (!idbPath) {
44return Promise.resolve(false);
45}
4cd25962JiglioNero4 years ago46return fs.promises
47.access(idbPath, fs.constants.X_OK)
4bb0956eRedMickey5 years ago48.then(() => true)
49.catch(() => false);
50}
51
4cd25962JiglioNero4 years ago52export async function isXcodeDetected(): Promise<boolean> {
53return new ChildProcess()
54.execToString("xcode-select -p")
55.then(stdout => {
56return fs.existsSync(stdout.trim());
57})
58.catch(_ => false);
59}
60
61async function queryTargetsWithoutXcodeDependency(
62idbCompanionPath: string,
63isAvailableFunc: (idbPath: string) => Promise<boolean>,
64): Promise<Array<DeviceTarget>> {
65if (await isAvailableFunc(idbCompanionPath)) {
66return new ChildProcess()
67.execToString(`${idbCompanionPath} --list 1 --only device`)
68.then(stdout => parseIdbTargets(stdout))
69.catch((e: Error) => {
70logger.warn(
71`Failed to query idb_companion --list 1 --only device for physical targets: ${e}`,
72);
73return [];
74});
75} else {
76logger.warn(
77`Unable to locate idb_companion in ${idbCompanionPath}. Try running sudo yum install -y fb-idb`,
78);
79return [];
80}
81}
82
83function parseIdbTargets(lines: string): Array<DeviceTarget> {
84return lines
85.trim()
86.split("\n")
87.map(line => line.trim())
88.filter(Boolean)
89.map(line => JSON.parse(line))
90.filter(({ state }: IdbTarget) => state.toLocaleLowerCase() === "booted")
91.map<IdbTarget>(({ type, target_type, ...rest }: IdbTarget) => ({
92type: (type || target_type) === "simulator" ? "emulator" : "physical",
93...rest,
94}))
95.map<DeviceTarget>((target: IdbTarget) => ({
96id: target.udid,
97isVirtualTarget: target.type === "emulator",
98name: target.name,
99isOnline: true,
100}));
101}
102
103export async function idbListTargets(idbPath: string): Promise<Array<DeviceTarget>> {
104return new ChildProcess()
105.execToString(`${idbPath} list-targets --json`)
106.then(stdout =>
107// See above.
108parseIdbTargets(stdout),
109)
110.catch((e: Error) => {
111logger.warn(`Failed to query idb for targets: ${e}`);
112return [];
113});
114}
115
4bb0956eRedMickey5 years ago116async function targets(): Promise<Array<DeviceTarget>> {
117if (process.platform !== "darwin") {
118return [];
119}
4cd25962JiglioNero4 years ago120const isXcodeInstalled = await isXcodeDetected();
121if (!isXcodeInstalled) {
122const idbCompanionPath = path.dirname(idbPath) + "/idb_companion";
123return queryTargetsWithoutXcodeDependency(idbCompanionPath, isAvailable);
124}
4bb0956eRedMickey5 years ago125
126// Not all users have idb installed because you can still use
127// Flipper with Simulators without it.
4cd25962JiglioNero4 years ago128// But idb is MUCH more CPU efficient than xcrun, so
129// when installed, use it. This still holds true
130// with the move from instruments to xcrun.
131// TODO: Move idb availability check up.
4bb0956eRedMickey5 years ago132if (await isIdbAvailable()) {
4cd25962JiglioNero4 years ago133return await idbListTargets(idbPath);
4bb0956eRedMickey5 years ago134} else {
4cd25962JiglioNero4 years ago135return new ChildProcess()
136.execToString("xcrun xctrace list devices")
137.then(stdout => {
138const targets: DeviceTarget[] = [];
139const lines = stdout
140.split("\n")
141.map(line => line.trim())
142.filter(line => !!line);
143const firstDevicesIndex = lines.findIndex(line => line === "== Devices ==") + 1;
144const lastDevicesIndex = lines.findIndex(line => line === "== Simulators ==") - 1;
145for (let i = firstDevicesIndex; i <= lastDevicesIndex; i++) {
146const line = lines[i];
147const params = line
148.split(" ")
149.map(el => el.trim())
150.filter(el => !!el);
151// Add only devices with system version
152if (
153params[params.length - 1].match(/\(.+\)/) &&
154params[params.length - 2].match(/\(.+\)/)
155) {
156targets.push({
157id: params[params.length - 1].replace(/\(|\)/g, "").trim(),
158name: params.slice(0, params.length - 2).join(" "),
159isVirtualTarget: false,
160isOnline: true,
161});
162}
163}
164return targets;
165})
166.catch(e => {
167logger.warn(`Failed to query for devices using xctrace: ${e}`);
168return [];
169});
4bb0956eRedMickey5 years ago170}
171}
172
173async function push(
174udid: string,
175src: string,
176bundleId: string,
177dst: string,
178logger?: OutputChannelLogger,
179): Promise<void> {
180const cp = new ChildProcess();
181await checkIdbIsInstalled();
182return wrapWithErrorMessage(
183cp
184.execToString(
185`${idbPath} --log ${idbLogLevel} file push --udid ${udid} --bundle-id ${bundleId} '${src}' '${dst}'`,
186)
187.then(() => {
188return;
189})
190.catch(e => handleMissingIdb(e)),
191logger,
192);
193}
194
195async function pull(
196udid: string,
197src: string,
198bundleId: string,
199dst: string,
200logger?: OutputChannelLogger,
201): Promise<void> {
202const cp = new ChildProcess();
203await checkIdbIsInstalled();
204return wrapWithErrorMessage(
205cp
206.execToString(
207`${idbPath} --log ${idbLogLevel} file pull --udid ${udid} --bundle-id ${bundleId} '${src}' '${dst}'`,
208)
209.then(() => {
210return;
211})
212.catch(e => handleMissingIdb(e)),
213logger,
214);
215}
216
217export async function checkIdbIsInstalled(): Promise<void> {
218const isInstalled = await isIdbAvailable();
219if (!isInstalled) {
220throw new Error(
221`idb is required to use iOS devices. Please install it with instructions from https://github.com/facebook/idb.`,
222);
223}
224}
225
226// The fb-internal idb binary is a shim that downloads the proper one on first run. It requires sudo to do so.
227// If we detect this, Tell the user how to fix it.
228function handleMissingIdb(e: Error): void {
229if (e.message && e.message.includes("sudo: no tty present and no askpass program specified")) {
230throw new Error(
231`idb doesn't appear to be installed. Run "${idbPath} list-targets" to fix this.`,
232);
233}
234throw e;
235}
236
237function wrapWithErrorMessage<T>(p: Promise<T>, logger?: OutputChannelLogger): Promise<T> {
238return p.catch((e: Error) => {
239logger?.error(e.message);
240// Give the user instructions. Don't embed the error because it's unique per invocation so won't be deduped.
241throw new Error(
242"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 https://github.com/microsoft/vscode-react-native.",
243);
244});
245}
246
247export default {
248isAvailable,
249targets,
250push,
251pull,
252};
253
254/**
255* @preserve
4cd25962JiglioNero4 years ago256* End region: https://github.com/facebook/flipper/blob/c2848df7f210c363113797c0f2e3db8c5d4fd49f/desktop/app/src/server/devices/ios/iOSContainerUtility.tsx
4bb0956eRedMickey5 years ago257*/