microsoft/vscode-react-native

Public

mirrored fromhttps://github.com/microsoft/vscode-react-nativeAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
dev/v-peq/add-expo-packager-command-tests

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/extension/macos/macOSPlatform.ts

225lines · modecode

1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for details.
3
4import * as path from "path";
5import * as semver from "semver";
6import { GeneralPlatform, MobilePlatformDeps, TargetType } from "../generalPlatform";
7import { ImacOSRunOptions, PlatformType } from "../launchArgs";
8import { OutputVerifier, PatternToFailure } from "../../common/outputVerifier";
9import { TelemetryHelper } from "../../common/telemetryHelper";
10import { CommandExecutor } from "../../common/commandExecutor";
11import { InternalErrorCode } from "../../common/error/internalErrorCode";
12import { PlistBuddy } from "../ios/plistBuddy";
13import { ChildProcess } from "../../common/node/childProcess";
14import { ProjectVersionHelper } from "../../common/projectVersionHelper";
15import { MacOSDebugModeManager } from "./macOSDebugModeManager";
16
17/**
18 * macOS specific platform implementation for debugging RN applications.
19 */
20export class MacOSPlatform extends GeneralPlatform {
21 private static SUCCESS_PATTERNS = ["Launching app"];
22 private static FAILURE_PATTERNS: PatternToFailure[] = [
23 {
24 pattern: "Unrecognized command 'run-macos'",
25 errorCode: InternalErrorCode.ReactNativemacOSIsNotInstalled,
26 },
27 ];
28
29 public static DEFAULT_MACOS_PROJECT_RELATIVE_PATH = "macos";
30
31 private macosProjectRoot: string;
32 private plistBuddy: PlistBuddy;
33 private macOSDebugModeManager: MacOSDebugModeManager;
34
35 constructor(protected runOptions: ImacOSRunOptions, platformDeps: MobilePlatformDeps = {}) {
36 super(runOptions, platformDeps);
37
38 const macosProjectFolderPath = MacOSPlatform.getOptFromRunArgs(
39 this.runArguments,
40 "--project-path",
41 false,
42 );
43 this.macosProjectRoot = path.join(
44 this.projectPath,
45 macosProjectFolderPath || MacOSPlatform.DEFAULT_MACOS_PROJECT_RELATIVE_PATH,
46 );
47 this.plistBuddy = new PlistBuddy();
48
49 const schemeFromArgs = MacOSPlatform.getOptFromRunArgs(
50 this.runArguments,
51 "--scheme",
52 false,
53 );
54 this.macOSDebugModeManager = new MacOSDebugModeManager(
55 this.macosProjectRoot,
56 this.projectPath,
57 schemeFromArgs ? schemeFromArgs : this.runOptions.scheme,
58 );
59 }
60
61 public async runApp(): Promise<void> {
62 let extProps: any = {
63 platform: {
64 value: PlatformType.macOS,
65 isPii: false,
66 },
67 };
68
69 this.projectObserver?.updateRNMacosProjectState(true);
70 if (this.runOptions.isDirect) {
71 extProps.isDirect = {
72 value: true,
73 isPii: false,
74 };
75 this.projectObserver?.updateRNMacosHermesProjectState(true);
76 }
77
78 extProps = TelemetryHelper.addPlatformPropertiesToTelemetryProperties(
79 this.runOptions,
80 this.runOptions.reactNativeVersions,
81 extProps,
82 );
83
84 await TelemetryHelper.generate("MacOSPlatform.runApp", extProps, async () => {
85 const env = GeneralPlatform.getEnvArgument(
86 process.env,
87 this.runOptions.env,
88 this.runOptions.envFile,
89 );
90
91 if (
92 !semver.valid(
93 this.runOptions.reactNativeVersions.reactNativeVersion,
94 ) /* Custom RN implementations should support this flag*/ ||
95 semver.gte(
96 this.runOptions.reactNativeVersions.reactNativeVersion,
97 MacOSPlatform.NO_PACKAGER_VERSION,
98 ) ||
99 ProjectVersionHelper.isCanaryVersion(
100 this.runOptions.reactNativeVersions.reactNativeVersion,
101 )
102 ) {
103 this.runArguments.push("--no-packager");
104 }
105
106 const runmacOSSpawn = new CommandExecutor(
107 this.runOptions.nodeModulesRoot,
108 this.projectPath,
109 this.logger,
110 ).spawnReactCommand(`run-${this.platformName}`, this.runArguments, { env });
111 await new OutputVerifier(
112 () => Promise.resolve(MacOSPlatform.SUCCESS_PATTERNS),
113 () => Promise.resolve(MacOSPlatform.FAILURE_PATTERNS),
114 this.platformName,
115 ).process(runmacOSSpawn);
116 });
117 }
118
119 public async prewarmBundleCache(): Promise<void> {
120 return this.packager.prewarmBundleCache(PlatformType.macOS);
121 }
122
123 public getRunArguments(): string[] {
124 const runArguments: string[] = [];
125
126 if (this.runOptions.runArguments && this.runOptions.runArguments.length > 0) {
127 runArguments.push(...this.runOptions.runArguments);
128 } else {
129 const target =
130 this.runOptions.target === TargetType.Simulator ? "" : this.runOptions.target;
131 if (target) {
132 runArguments.push(`--${target}`);
133 }
134 }
135
136 return runArguments;
137 }
138
139 public async enableJSDebuggingMode(): Promise<void> {
140 // Configure the app for debugging
141 // Wait until the configuration file exists, and check to see if debugging is enabled
142 const [debugModeEnabled, appName] = await Promise.all<boolean | string>([
143 this.macOSDebugModeManager.getAppRemoteDebuggingSetting(
144 this.runOptions.configuration,
145 this.runOptions.productName,
146 ),
147 this.getApplicationName(),
148 ]);
149 if (debugModeEnabled) {
150 return;
151 }
152
153 // Debugging must still be enabled
154 // We enable debugging by writing to a plist file that backs a NSUserDefaults object,
155 // but that file is written to by the app on occasion. To avoid races, we shut the app
156 // down before writing to the file.
157 await this.terminateMacOSapp(<string>appName);
158 // Write to the settings file while the app is not running to avoid races
159 await this.macOSDebugModeManager.setAppRemoteDebuggingSetting(
160 /* enable=*/ true,
161 this.runOptions.configuration,
162 this.runOptions.productName,
163 );
164 // Relaunch the app
165 await this.runApp();
166 }
167
168 public disableJSDebuggingMode(): Promise<void> {
169 return this.macOSDebugModeManager.setAppRemoteDebuggingSetting(
170 /* enable=*/ false,
171 this.runOptions.configuration,
172 this.runOptions.productName,
173 );
174 }
175
176 private async getApplicationName(): Promise<string> {
177 const iOSBuildLocationData = await this.plistBuddy.getExecutableAndConfigurationFolder(
178 this.macosProjectRoot,
179 this.projectPath,
180 PlatformType.macOS,
181 false,
182 this.runOptions.configuration,
183 this.runOptions.productName,
184 this.getSchemeFromDebuggingParameters(),
185 );
186 return iOSBuildLocationData.executable;
187 }
188
189 private getSchemeFromDebuggingParameters(): string | undefined {
190 let scheme = this.runOptions.scheme;
191 if (!scheme) {
192 const schemeFromArgs = MacOSPlatform.getOptFromRunArgs(
193 this.runArguments,
194 "--scheme",
195 false,
196 );
197 if (schemeFromArgs) {
198 scheme = schemeFromArgs;
199 }
200 }
201 return scheme;
202 }
203
204 private async terminateMacOSapp(appName: string): Promise<void> {
205 const childProcess = new ChildProcess();
206 // An example of the output from the command above:
207 // 40943 ?? 4:13.97 node /Users/user/Documents/rn_for_mac_proj/node_modules/.bin/react-native start --port 8081
208 // 40959 ?? 0:10.36 /Users/user/.nvm/versions/node/v10.19.0/bin/node /Users/user/Documents/rn_for_mac_proj/node_modules/metro/node_modules/jest-worker/build/workers/processChild.js
209 // 41004 ?? 0:21.34 /Users/user/Library/Developer/Xcode/DerivedData/rn_for_mac_proj-ghuavabiztosiqfqkrityjoxqfmv/Build/Products/Debug/rn_for_mac_proj.app/Contents/MacOS/rn_for_mac_proj
210 // 75514 ttys007 0:00.00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn rn_for_mac_proj
211 const searchResults = await childProcess.execFileToString("ps", ["-ax"]);
212 if (searchResults) {
213 const processIdRgx = /(^\d*)\s\?\?/g;
214 // We are looking for a process whose path contains the "appName.app" part
215 const processData = searchResults.split("\n").find(str => str.includes(appName));
216
217 if (processData) {
218 const match = processIdRgx.exec(processData.trim());
219 if (match && match[1]) {
220 await childProcess.execFileToString("kill", [match[1]]);
221 }
222 }
223 }
224 }
225}
226