microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
7893fb7e2accec713663526fdfb9aca273210a74

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/extension/commandPaletteHandler.ts

198lines · 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 vscode from "vscode";
5import * as Q from "q";
6import * as XDL from "xdl";
7import {CommandExecutor} from "../common/commandExecutor";
8import {SettingsHelper} from "./settingsHelper";
9import {Log} from "../common/log/log";
10import {Packager, PackagerRunAs} from "../common/packager";
11import {AndroidPlatform} from "../common/android/androidPlatform";
12import {PackagerStatus, PackagerStatusIndicator} from "./packagerStatusIndicator";
13import {ReactNativeProjectHelper} from "../common/reactNativeProjectHelper";
14import {TargetPlatformHelper} from "../common/targetPlatformHelper";
15import {TelemetryHelper} from "../common/telemetryHelper";
16import {IOSDebugModeManager} from "../common/ios/iOSDebugModeManager";
17import {ExponentHelper} from "../common/exponent/exponentHelper";
18
19export class CommandPaletteHandler {
20 private reactNativePackager: Packager;
21 private reactNativePackageStatusIndicator: PackagerStatusIndicator;
22 private workspaceRoot: string;
23 private exponentHelper: ExponentHelper;
24
25 constructor(workspaceRoot: string, reactNativePackager: Packager, packagerStatusIndicator: PackagerStatusIndicator, exponentHelper: ExponentHelper) {
26 this.workspaceRoot = workspaceRoot;
27 this.reactNativePackager = reactNativePackager;
28 this.reactNativePackageStatusIndicator = packagerStatusIndicator;
29 this.exponentHelper = exponentHelper;
30 }
31
32 /**
33 * Starts the React Native packager
34 */
35 public startPackager(): Q.Promise<void> {
36 return this.exponentHelper.configureReactNativeEnvironment()
37 .then(() =>
38 this.executeCommandInContext("startPackager", () =>
39 this.runStartPackagerCommandAndUpdateStatus()));
40 }
41
42 /**
43 * Starts the Exponent packager
44 */
45 public startExponentPackager(): Q.Promise<void> {
46 return this.exponentHelper.configureExponentEnvironment()
47 .then(() =>
48 this.executeCommandInContext("startExponentPackager", () =>
49 this.runStartPackagerCommandAndUpdateStatus(PackagerRunAs.EXPONENT)));
50 }
51
52 /**
53 * Kills the React Native packager invoked by the extension's packager
54 */
55 public stopPackager(): Q.Promise<void> {
56 return this.executeCommandInContext("stopPackager", () => this.reactNativePackager.stop())
57 .then(() => this.reactNativePackageStatusIndicator.updatePackagerStatus(PackagerStatus.PACKAGER_STOPPED));
58 }
59
60 /**
61 * Restarts the React Native packager
62 */
63 public restartPackager(): Q.Promise<void> {
64 return this.executeCommandInContext("restartPackager", () =>
65 this.runRestartPackagerCommandAndUpdateStatus());
66 }
67
68 /**
69 * Execute command to publish to exponent host.
70 */
71 public publishToExpHost(): Q.Promise<void> {
72 return this.executeCommandInContext("publishToExpHost", () => {
73 this.executePublishToExpHost().then((didPublish) => {
74 if (!didPublish) {
75 Log.logMessage("Publishing was unsuccessful. Please make sure you are logged in Exponent and your project is a valid Exponentjs project");
76 }
77 });
78 });
79 }
80
81 /**
82 * Executes the 'react-native run-android' command
83 */
84 public runAndroid(): Q.Promise<void> {
85 TargetPlatformHelper.checkTargetPlatformSupport("android");
86 return this.executeCommandInContext("runAndroid", () => this.executeWithPackagerRunning(() => {
87 const packagerPort = SettingsHelper.getPackagerPort();
88 return new AndroidPlatform({ projectRoot: this.workspaceRoot, packagerPort: packagerPort }).runApp(/*shouldLaunchInAllDevices*/true);
89 }));
90 }
91
92
93 /**
94 * Executes the 'react-native run-ios' command
95 */
96 public runIos(): Q.Promise<void> {
97 TargetPlatformHelper.checkTargetPlatformSupport("ios");
98 return this.executeCommandInContext("runIos", () => {
99 // Set the Debugging setting to disabled, because in iOS it's persisted across runs of the app
100 return new IOSDebugModeManager(this.workspaceRoot).setSimulatorJSDebuggingModeSetting(/*enable=*/ false)
101 .catch(() => { }) // If setting the debugging mode fails, we ignore the error and we run the run ios command anyways
102 .then(() => this.executeReactNativeRunCommand("run-ios"));
103 });
104 }
105
106 private runRestartPackagerCommandAndUpdateStatus(): Q.Promise<void> {
107 return this.reactNativePackager.restart(SettingsHelper.getPackagerPort())
108 .then(() => this.reactNativePackageStatusIndicator.updatePackagerStatus(PackagerStatus.PACKAGER_STARTED));
109 }
110
111 /**
112 * Helper method to run packager and update appropriate configurations
113 */
114 private runStartPackagerCommandAndUpdateStatus(startAs: PackagerRunAs = PackagerRunAs.REACT_NATIVE): Q.Promise<any> {
115 if (startAs === PackagerRunAs.EXPONENT) {
116 return this.reactNativePackager.startAsExponent(SettingsHelper.getPackagerPort())
117 .then(exponentUrl => {
118 this.reactNativePackageStatusIndicator.updatePackagerStatus(PackagerStatus.EXPONENT_PACKAGER_STARTED);
119 Log.logMessage("Application is running on Exponent.");
120 Log.logMessage(`Open your exponent app at ${exponentUrl}`);
121 });
122 }
123 return this.reactNativePackager.startAsReactNative(SettingsHelper.getPackagerPort())
124 .then(() => this.reactNativePackageStatusIndicator.updatePackagerStatus(PackagerStatus.PACKAGER_STARTED));
125 }
126
127 /**
128 * Executes a react-native command passed after starting the packager
129 * {command} The command to be executed
130 * {args} The arguments to be passed to the command
131 */
132 private executeReactNativeRunCommand(command: string, args?: string[]): Q.Promise<void> {
133 return this.executeWithPackagerRunning(() => {
134 return new CommandExecutor(this.workspaceRoot).spawnReactCommand(command, args).outcome;
135 });
136 }
137
138 /**
139 * Executes a lambda function after starting the packager
140 * {lambda} The lambda function to be executed
141 */
142 private executeWithPackagerRunning(lambda: () => Q.Promise<void>): Q.Promise<void> {
143 // Start the packager before executing the React-Native command
144 Log.logMessage("Attempting to start the React Native packager");
145 return this.runStartPackagerCommandAndUpdateStatus().then(lambda);
146 }
147
148 /**
149 * Ensures that we are in a React Native project and then executes the operation
150 * Otherwise, displays an error message banner
151 * {operation} - a function that performs the expected operation
152 */
153 private executeCommandInContext(rnCommand: string, operation: () => Q.Promise<void> | void): Q.Promise<void> {
154 let reactNativeProjectHelper = new ReactNativeProjectHelper(vscode.workspace.rootPath);
155 return TelemetryHelper.generate("RNCommand", (generator) => {
156 generator.add("command", rnCommand, false);
157 return reactNativeProjectHelper.isReactNativeProject().then(isRNProject => {
158 generator.add("isRNProject", isRNProject, false);
159 if (isRNProject) {
160 // Bring the log channel to focus
161 Log.setFocusOnLogChannel();
162
163 // Execute the operation
164 return operation();
165 } else {
166 vscode.window.showErrorMessage("Current workspace is not a React Native project.");
167 }
168 });
169 });
170 }
171
172 /**
173 * Publish project to exponent server. In order to do this we need to make sure the user is logged in exponent and the packager is running.
174 */
175 private executePublishToExpHost(): Q.Promise<boolean> {
176 Log.logMessage("Publishing app to Exponent server. This might take a moment.");
177 return Q(XDL.User.getCurrentUserAsync()).then(user => {
178 if (!user) {
179 Log.logWarning("You're not logged in to exponent. Please login before trying to publish.");
180 return false;
181 }
182 Log.logMessage(`Publishing as ${user.username}...`);
183 return this.startExponentPackager()
184 .then(() =>
185 XDL.Project.publishAsync(this.workspaceRoot))
186 .then(response => {
187 if (response.err || !response.url) {
188 return false;
189 }
190 Log.logMessage(`App successfully published to ${response.url}`);
191 return true;
192 });
193 }).catch(() => {
194 Log.logWarning("An error has occured. Please make sure you are logged in to exponent, your project is setup correctly for publishing and your packager is running as exponent.");
195 return false;
196 });
197 }
198}
199