microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
align-android-launch-command

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/extension/ios/iOSTargetManager.ts

291lines · modeblame

4cd25962JiglioNero4 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
09f6024fHeniker4 years ago4import * as nls from "vscode-nls";
5import { QuickPickOptions, window } from "vscode";
4cd25962JiglioNero4 years ago6import { ChildProcess } from "../../common/node/childProcess";
ab0238b7RedMickey4 years ago7import { PromiseUtil } from "../../common/node/promise";
176f99c8ConnorQi013 months ago8import { IDebuggableMobileTarget, IMobileTarget, MobileTarget } from "../mobileTarget";
4cd25962JiglioNero4 years ago9import { MobileTargetManager } from "../mobileTargetManager";
10import { OutputChannelLogger } from "../log/OutputChannelLogger";
11import { TargetType } from "../generalPlatform";
09f6024fHeniker4 years ago12
4cd25962JiglioNero4 years ago13nls.config({
14messageFormat: nls.MessageFormat.bundle,
15bundleFormat: nls.BundleFormat.standalone,
16})();
17const localize = nls.loadMessageBundle();
18
19export interface IDebuggableIOSTarget extends IDebuggableMobileTarget {
20name: string;
21system: string;
22}
23
24export class IOSTarget extends MobileTarget implements IDebuggableIOSTarget {
25protected _system: string;
176f99c8ConnorQi013 months ago26protected _name!: string;
4cd25962JiglioNero4 years ago27
28public static fromInterface(obj: IDebuggableIOSTarget): IOSTarget {
29return new IOSTarget(obj.isOnline, obj.isVirtualTarget, obj.id, obj.name, obj.system);
30}
31
32constructor(
33isOnline: boolean,
34isVirtualTarget: boolean,
35id: string,
36name: string,
37system: string,
38) {
39super(isOnline, isVirtualTarget, id, name);
40this._system = system;
41}
42
43get system(): string {
44return this._system;
45}
46
47get name(): string {
48return this._name;
49}
50
51set name(value: string) {
52this._name = value;
53}
54}
55
56export class IOSTargetManager extends MobileTargetManager {
57private static readonly XCRUN_COMMAND = "xcrun";
58private static readonly SIMCTL_COMMAND = "simctl";
59private static readonly BOOT_COMMAND = `boot`;
60private static readonly SIMULATORS_LIST_COMMAND = `${IOSTargetManager.XCRUN_COMMAND} ${IOSTargetManager.SIMCTL_COMMAND} list devices available --json`;
61private static readonly ALL_DEVICES_LIST_COMMAND = `${IOSTargetManager.XCRUN_COMMAND} xctrace list devices`;
62private static readonly BOOTED_STATE = "Booted";
63private static readonly SIMULATOR_START_TIMEOUT = 120;
64private static readonly ANY_SYSTEM = "AnySystem";
65
66private childProcess: ChildProcess = new ChildProcess();
67private logger: OutputChannelLogger = OutputChannelLogger.getChannel(
68OutputChannelLogger.MAIN_CHANNEL_NAME,
69true,
70);
71protected targets?: IDebuggableIOSTarget[];
72
73public async collectTargets(targetType?: TargetType): Promise<void> {
74this.targets = [];
75if (targetType === undefined || targetType === TargetType.Simulator) {
76const simulators = JSON.parse(
77await this.childProcess.execToString(`${IOSTargetManager.SIMULATORS_LIST_COMMAND}`),
78);
79Object.keys(simulators.devices).forEach(rawSystem => {
80const temp = rawSystem.split(".").slice(-1)[0].split("-"); // "com.apple.CoreSimulator.SimRuntime.iOS-11-4" -> ["iOS", "11", "4"]
81const system = `${temp[0]} ${temp.slice(1).join(".")}`; // ["iOS", "11", "4"] -> iOS 11.4
82simulators.devices[rawSystem].forEach((device: any) => {
83// Now we support selection only for iOS system
84if (system.includes("iOS")) {
85this.targets?.push({
86id: device.udid,
87name: device.name,
88system,
89isVirtualTarget: true,
90isOnline: device.state === IOSTargetManager.BOOTED_STATE,
91});
92}
93});
94});
95}
96
97if (targetType === undefined || targetType === TargetType.Device) {
98const allDevicesOutput = await this.childProcess.execToString(
99`${IOSTargetManager.ALL_DEVICES_LIST_COMMAND}`,
100);
09f6024fHeniker4 years ago101// Output example:
4cd25962JiglioNero4 years ago102// == Devices ==
103// sierra (EFDAAD01-E1A3-5F00-A357-665B501D5520)
104// My iPhone (14.4.2) (33n546e591e707bd64c718bfc1bf3e8b7c16bfc9)
105//
106// == Simulators ==
107// Apple TV (14.5) (417BDFD8-6E22-4F87-BCAA-19C241AC9548)
108// Apple TV 4K (2nd generation) (14.5) (925E6E38-0D7B-45E9-ADE0-89C20779D467)
09f6024fHeniker4 years ago109// ...
4cd25962JiglioNero4 years ago110const lines = allDevicesOutput
111.split("\n")
112.map(line => line.trim())
113.filter(line => !!line);
09f6024fHeniker4 years ago114const firstDevicesIndex = lines.indexOf("== Devices ==") + 1;
115const lastDevicesIndex = lines.indexOf("== Simulators ==") - 1;
4cd25962JiglioNero4 years ago116for (let i = firstDevicesIndex; i <= lastDevicesIndex; i++) {
117const line = lines[i];
118const params = line
119.split(" ")
120.map(el => el.trim())
121.filter(el => !!el);
122// Add only devices with system version
123if (
124params[params.length - 1].match(/\(.+\)/) &&
125params[params.length - 2].match(/\(.+\)/)
126) {
127this.targets.push({
128id: params[params.length - 1].replace(/\(|\)/g, "").trim(),
129name: params.slice(0, params.length - 2).join(" "),
130system: params[params.length - 2].replace(/\(|\)/g, "").trim(),
131isVirtualTarget: false,
132isOnline: true,
133});
134}
135}
136}
137}
138
139public async selectAndPrepareTarget(
140filter?: (el: IDebuggableIOSTarget) => boolean,
141): Promise<IOSTarget | undefined> {
142const selectedTarget = await this.startSelection(filter);
143if (selectedTarget) {
09f6024fHeniker4 years ago144return !selectedTarget.isOnline && selectedTarget.isVirtualTarget
145? this.launchSimulator(selectedTarget)
146: IOSTarget.fromInterface(selectedTarget);
4cd25962JiglioNero4 years ago147}
148return undefined;
149}
150
151public async isVirtualTarget(targetString: string): Promise<boolean> {
152try {
153if (targetString === TargetType.Device) {
154return false;
155} else if (targetString === TargetType.Simulator) {
156return true;
157}
09f6024fHeniker4 years ago158const target = (
159await this.getTargetList(
160target => target.id === targetString || target.name === targetString,
161)
162)[0];
163if (target) {
164return target.isVirtualTarget;
165}
166throw Error("There is no any target with specified target string");
4cd25962JiglioNero4 years ago167} catch {
168throw new Error(
169localize(
170"CouldNotRecognizeTargetType",
171"Could not recognize type of the target {0}",
172targetString,
173),
174);
175}
176}
177
178protected async startSelection(
179filter?: (el: IDebuggableIOSTarget) => boolean,
180): Promise<IDebuggableIOSTarget | undefined> {
181const system = await this.selectSystem(filter);
182if (system) {
183return (await this.selectTarget(
176f99c8ConnorQi013 months ago184(el: IMobileTarget) =>
185(filter ? filter(el as IDebuggableIOSTarget) : true) &&
186(system === IOSTargetManager.ANY_SYSTEM
187? true
188: (el as IDebuggableIOSTarget).system === system),
4cd25962JiglioNero4 years ago189)) as IDebuggableIOSTarget | undefined;
190}
191return;
192}
193
194protected async selectSystem(
195filter?: (el: IDebuggableIOSTarget) => boolean,
196): Promise<string | undefined> {
176f99c8ConnorQi013 months ago197const targets = (await this.getTargetList(
198filter as ((el: IMobileTarget) => boolean) | undefined,
199)) as IDebuggableIOSTarget[];
4cd25962JiglioNero4 years ago200// If we select only from devices, we should not select system
201if (!targets.find(target => target.isVirtualTarget)) {
202return IOSTargetManager.ANY_SYSTEM;
203}
204const names: Set<string> = new Set(targets.map(target => target.system));
205const systemsList = Array.from(names);
206let result: string | undefined = systemsList[0];
207if (systemsList.length > 1) {
208const quickPickOptions: QuickPickOptions = {
209ignoreFocusOut: true,
210canPickMany: false,
211placeHolder: localize(
212"SelectIOSSystemVersion",
213"Select system version of iOS target",
214),
215};
216result = await window.showQuickPick(systemsList, quickPickOptions);
217}
218return result?.toString();
219}
220
221protected async launchSimulator(
222virtualTarget: IDebuggableIOSTarget,
223): Promise<IOSTarget | undefined> {
224return new Promise<IOSTarget | undefined>((resolve, reject) => {
8df9830bSamriel4 years ago225let emulatorLaunchFailed = false;
4cd25962JiglioNero4 years ago226const emulatorProcess = this.childProcess.spawn(
227IOSTargetManager.XCRUN_COMMAND,
228[IOSTargetManager.SIMCTL_COMMAND, IOSTargetManager.BOOT_COMMAND, virtualTarget.id],
229{
230detached: true,
231},
232true,
233);
234emulatorProcess.spawnedProcess.unref();
235emulatorProcess.outcome.catch(e => {
8df9830bSamriel4 years ago236emulatorLaunchFailed = true;
4cd25962JiglioNero4 years ago237this.logger.error(
238localize(
239"ErrorWhileLaunchingSimulator",
240"Error while launching simulator {0} : {1}",
241`${virtualTarget.name}(${virtualTarget.id})`,
242e,
243),
244);
245reject(e);
246});
247
248const condition = async () => {
8df9830bSamriel4 years ago249if (emulatorLaunchFailed)
250throw new Error("iOS simulator launch failed unexpectedly");
4cd25962JiglioNero4 years ago251await this.collectTargets(TargetType.Simulator);
252const onlineTarget = (await this.getTargetList()).find(
253target => target.id === virtualTarget.id && target.isOnline,
254);
255return onlineTarget ? true : null;
256};
257
09f6024fHeniker4 years ago258void PromiseUtil.waitUntil<boolean>(
4cd25962JiglioNero4 years ago259condition,
2601000,
261IOSTargetManager.SIMULATOR_START_TIMEOUT * 1000,
8df9830bSamriel4 years ago262).then(
263isBooted => {
264if (isBooted) {
265virtualTarget.isOnline = true;
266this.logger.info(
267localize(
268"SimulatorLaunched",
269"Launched simulator {0}",
4cd25962JiglioNero4 years ago270virtualTarget.name,
8df9830bSamriel4 years ago271),
272);
273resolve(IOSTarget.fromInterface(virtualTarget));
274} else {
275reject(
276new Error(
277`Virtual device launch finished with an exception: ${localize(
278"SimulatorStartWarning",
279"Could not start the simulator {0} within {1} seconds.",
280virtualTarget.name,
281IOSTargetManager.SIMULATOR_START_TIMEOUT,
282)}`,
283),
284);
285}
286},
287() => {},
288);
4cd25962JiglioNero4 years ago289});
290}
291}