microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
0.6.16

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/extension/commandPaletteHandler.ts

356lines · modeblame

bef522ffMeena Kunnathur Balakrishnan10 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
6e179583digeff10 years ago4import * as vscode from "vscode";
5import * as Q from "q";
0a68f8dbArtem Egorov8 years ago6import * as XDL from "./exponent/xdlInterface";
df4bce40digeff10 years ago7import {SettingsHelper} from "./settingsHelper";
0a68f8dbArtem Egorov8 years ago8import {OutputChannelLogger} from "./log/OutputChannelLogger";
4787ec09Artem Egorov8 years ago9import {Packager} from "../common/packager";
634e3ecaRuslan Bikkinin7 years ago10import {TargetType} from "./generalMobilePlatform";
0a68f8dbArtem Egorov8 years ago11import {AndroidPlatform} from "./android/androidPlatform";
12import {IOSPlatform} from "./ios/iOSPlatform";
b0061ac6Meena Kunnathur Balakrishnan10 years ago13import {ReactNativeProjectHelper} from "../common/reactNativeProjectHelper";
aeaf46bcMeena Kunnathur Balakrishnan10 years ago14import {TargetPlatformHelper} from "../common/targetPlatformHelper";
d976d077Meena Kunnathur Balakrishnan10 years ago15import {TelemetryHelper} from "../common/telemetryHelper";
0a68f8dbArtem Egorov8 years ago16import {ExponentHelper} from "./exponent/exponentHelper";
4edcda70Artem Egorov8 years ago17import {ReactDirManager} from "./reactDirManager";
18import {ExtensionServer} from "./extensionServer";
d1fc7f8aArtem Egorov8 years ago19import {IAndroidRunOptions, IIOSRunOptions} from "./launchArgs";
4787ec09Artem Egorov8 years ago20import { ExponentPlatform } from "./exponent/exponentPlatform";
4b37483dmax-mironov8 years ago21
4edcda70Artem Egorov8 years ago22interface IReactNativeStuff {
23packager: Packager;
2e432a9eArtem Egorov8 years ago24exponentHelper: ExponentHelper;
4edcda70Artem Egorov8 years ago25reactDirManager: ReactDirManager;
26extensionServer: ExtensionServer;
27}
640e6e98max-mironov8 years ago28
4edcda70Artem Egorov8 years ago29interface IReactNativeProject extends IReactNativeStuff {
2e432a9eArtem Egorov8 years ago30workspaceFolder: vscode.WorkspaceFolder;
31}
32
e1c05e69dlebu10 years ago33export class CommandPaletteHandler {
4edcda70Artem Egorov8 years ago34private static projectsCache: {[key: string]: IReactNativeProject} = {};
2e432a9eArtem Egorov8 years ago35private static logger: OutputChannelLogger = OutputChannelLogger.getMainChannel();
6a465861max-mironov8 years ago36
4edcda70Artem Egorov8 years ago37public static addFolder(workspaceFolder: vscode.WorkspaceFolder, stuff: IReactNativeStuff): void {
38this.projectsCache[workspaceFolder.uri.fsPath] = {
39...stuff,
2e432a9eArtem Egorov8 years ago40workspaceFolder,
41};
42}
bef522ffMeena Kunnathur Balakrishnan10 years ago43
4edcda70Artem Egorov8 years ago44public static getFolder(workspaceFolder: vscode.WorkspaceFolder): IReactNativeProject {
45return this.projectsCache[workspaceFolder.uri.fsPath];
2e432a9eArtem Egorov8 years ago46}
47
4edcda70Artem Egorov8 years ago48public static delFolder(workspaceFolder: vscode.WorkspaceFolder): void {
49delete this.projectsCache[workspaceFolder.uri.fsPath];
bef522ffMeena Kunnathur Balakrishnan10 years ago50}
51
0904a0d7Meena Kunnathur Balakrishnan10 years ago52/**
53* Starts the React Native packager
54*/
2e432a9eArtem Egorov8 years ago55public static startPackager(): Q.Promise<void> {
56return this.selectProject()
57.then((project: IReactNativeProject) => {
4787ec09Artem Egorov8 years ago58return this.executeCommandInContext("startPackager", project.workspaceFolder, () => {
59return project.packager.isRunning()
2e432a9eArtem Egorov8 years ago60.then((running) => {
4edcda70Artem Egorov8 years ago61return running ? project.packager.stop() : Q.resolve(void 0);
4787ec09Artem Egorov8 years ago62});
63})
64.then(() => project.packager.start());
2e432a9eArtem Egorov8 years ago65});
bef522ffMeena Kunnathur Balakrishnan10 years ago66}
67
0904a0d7Meena Kunnathur Balakrishnan10 years ago68/**
69* Kills the React Native packager invoked by the extension's packager
70*/
2e432a9eArtem Egorov8 years ago71public static stopPackager(): Q.Promise<void> {
72return this.selectProject()
73.then((project: IReactNativeProject) => {
4787ec09Artem Egorov8 years ago74return this.executeCommandInContext("stopPackager", project.workspaceFolder, () => project.packager.stop());
2e432a9eArtem Egorov8 years ago75});
3194e9afMeena Kunnathur Balakrishnan10 years ago76}
77
4edcda70Artem Egorov8 years ago78public static stopAllPackagers(): Q.Promise<void> {
79let keys = Object.keys(this.projectsCache);
80let promises: Q.Promise<void>[] = [];
81keys.forEach((key) => {
82let project = this.projectsCache[key];
4787ec09Artem Egorov8 years ago83promises.push(this.executeCommandInContext("stopPackager", project.workspaceFolder, () => project.packager.stop()));
4edcda70Artem Egorov8 years ago84});
85
86return Q.all(promises).then(() => {});
87}
88
f2a58eefBret Johnson9 years ago89/**
90* Restarts the React Native packager
91*/
2e432a9eArtem Egorov8 years ago92public static restartPackager(): Q.Promise<void> {
93return this.selectProject()
94.then((project: IReactNativeProject) => {
95return this.executeCommandInContext("restartPackager", project.workspaceFolder, () =>
96this.runRestartPackagerCommandAndUpdateStatus(project));
97});
f2a58eefBret Johnson9 years ago98}
99
7893fb7eJimmy Thomson9 years ago100/**
101* Execute command to publish to exponent host.
102*/
2e432a9eArtem Egorov8 years ago103public static publishToExpHost(): Q.Promise<void> {
104return this.selectProject()
105.then((project: IReactNativeProject) => {
106return this.executeCommandInContext("publishToExpHost", project.workspaceFolder, () => {
107return this.executePublishToExpHost(project).then((didPublish) => {
108if (!didPublish) {
109CommandPaletteHandler.logger.warning("Publishing was unsuccessful. Please make sure you are logged in Exponent and your project is a valid Exponentjs project");
110}
111});
112});
7893fb7eJimmy Thomson9 years ago113});
114}
115
3194e9afMeena Kunnathur Balakrishnan10 years ago116/**
117* Executes the 'react-native run-android' command
118*/
d1fc7f8aArtem Egorov8 years ago119public static runAndroid(target: TargetType = "simulator"): Q.Promise<void> {
2e432a9eArtem Egorov8 years ago120return this.selectProject()
121.then((project: IReactNativeProject) => {
0611729dRuslan Bikkinin7 years ago122TargetPlatformHelper.checkTargetPlatformSupport("android");
4787ec09Artem Egorov8 years ago123return this.executeCommandInContext("runAndroid", project.workspaceFolder, () => {
634e3ecaRuslan Bikkinin7 years ago124const runOptions = CommandPaletteHandler.getRunOptions(project, "android", target);
125const platform = new AndroidPlatform(runOptions, {
126packager: project.packager,
127});
4787ec09Artem Egorov8 years ago128return platform.beforeStartPackager()
129.then(() => {
130return platform.startPackager();
131})
132.then(() => {
133return platform.runApp(/*shouldLaunchInAllDevices*/true);
134})
2e432a9eArtem Egorov8 years ago135.then(() => {
136return platform.disableJSDebuggingMode();
137});
4787ec09Artem Egorov8 years ago138});
0a68f8dbArtem Egorov8 years ago139});
3194e9afMeena Kunnathur Balakrishnan10 years ago140}
141
142/**
143* Executes the 'react-native run-ios' command
144*/
d1fc7f8aArtem Egorov8 years ago145public static runIos(target: TargetType = "simulator"): Q.Promise<void> {
2e432a9eArtem Egorov8 years ago146return this.selectProject()
147.then((project: IReactNativeProject) => {
0611729dRuslan Bikkinin7 years ago148TargetPlatformHelper.checkTargetPlatformSupport("ios");
4787ec09Artem Egorov8 years ago149return this.executeCommandInContext("runIos", project.workspaceFolder, () => {
634e3ecaRuslan Bikkinin7 years ago150const runOptions = CommandPaletteHandler.getRunOptions(project, "ios", target);
151const platform = new IOSPlatform(runOptions, {
152packager: project.packager,
153});
154
4787ec09Artem Egorov8 years ago155return platform.beforeStartPackager()
156.then(() => {
157return platform.startPackager();
158})
159.then(() => {
160// Set the Debugging setting to disabled, because in iOS it's persisted across runs of the app
161return platform.disableJSDebuggingMode();
162})
2e432a9eArtem Egorov8 years ago163.catch(() => { }) // If setting the debugging mode fails, we ignore the error and we run the run ios command anyways
164.then(() => {
165return platform.runApp();
166});
4787ec09Artem Egorov8 years ago167});
168});
169}
170
171/**
172* Starts the Exponent packager
173*/
174public static runExponent(): Q.Promise<void> {
175return this.selectProject()
176.then((project: IReactNativeProject) => {
177return this.loginToExponent(project)
178.then(() => {
031832ffArtem Egorov8 years ago179return this.executeCommandInContext("runExponent", project.workspaceFolder, () => {
634e3ecaRuslan Bikkinin7 years ago180const runOptions = CommandPaletteHandler.getRunOptions(project, "exponent");
181const platform = new ExponentPlatform(runOptions, {
182packager: project.packager,
183});
4787ec09Artem Egorov8 years ago184return platform.beforeStartPackager()
185.then(() => {
186return platform.startPackager();
187})
188.then(() => {
189return platform.runApp();
190});
191});
192});
2e432a9eArtem Egorov8 years ago193});
3194e9afMeena Kunnathur Balakrishnan10 years ago194}
195
2e432a9eArtem Egorov8 years ago196public static showDevMenu(): Q.Promise<void> {
a41f5c68Artem Egorov8 years ago197return this.selectProject()
198.then((project: IReactNativeProject) => {
634e3ecaRuslan Bikkinin7 years ago199AndroidPlatform.showDevMenu()
a41f5c68Artem Egorov8 years ago200.catch(() => { }); // Ignore any errors
634e3ecaRuslan Bikkinin7 years ago201IOSPlatform.showDevMenu(project.workspaceFolder.uri.fsPath)
a41f5c68Artem Egorov8 years ago202.catch(() => { }); // Ignore any errors
203return Q.resolve(void 0);
204});
7daed3fcArtem Egorov8 years ago205}
206
2e432a9eArtem Egorov8 years ago207public static reloadApp(): Q.Promise<void> {
a41f5c68Artem Egorov8 years ago208return this.selectProject()
209.then((project: IReactNativeProject) => {
634e3ecaRuslan Bikkinin7 years ago210AndroidPlatform.reloadApp()
a41f5c68Artem Egorov8 years ago211.catch(() => { }); // Ignore any errors
634e3ecaRuslan Bikkinin7 years ago212IOSPlatform.reloadApp(project.workspaceFolder.uri.fsPath)
a41f5c68Artem Egorov8 years ago213.catch(() => { }); // Ignore any errors
214return Q.resolve(void 0);
215});
7daed3fcArtem Egorov8 years ago216}
217
031832ffArtem Egorov8 years ago218public static getPlatformByCommandName(commandName: string): string {
219commandName = commandName.toLocaleLowerCase();
220
221if (commandName.indexOf("android") > -1) {
222return "android";
223}
224
225if (commandName.indexOf("ios") > -1) {
226return "ios";
227}
228
229if (commandName.indexOf("exponent") > -1) {
230return "exponent";
231}
232
233return "";
234}
235
2e432a9eArtem Egorov8 years ago236private static runRestartPackagerCommandAndUpdateStatus(project: IReactNativeProject): Q.Promise<void> {
4787ec09Artem Egorov8 years ago237return project.packager.restart(SettingsHelper.getPackagerPort(project.workspaceFolder.uri.fsPath));
3194e9afMeena Kunnathur Balakrishnan10 years ago238}
b3a793eeNisheet Jain10 years ago239
240/**
241* Ensures that we are in a React Native project and then executes the operation
242* Otherwise, displays an error message banner
243* {operation} - a function that performs the expected operation
244*/
2e432a9eArtem Egorov8 years ago245private static executeCommandInContext(rnCommand: string, workspaceFolder: vscode.WorkspaceFolder, operation: () => Q.Promise<void>): Q.Promise<void> {
031832ffArtem Egorov8 years ago246const extProps = {
247platform: {
248value: CommandPaletteHandler.getPlatformByCommandName(rnCommand),
249isPii: false,
250},
251};
252
253return TelemetryHelper.generate("RNCommand", extProps, (generator) => {
8512ccfeMeena Kunnathur Balakrishnan10 years ago254generator.add("command", rnCommand, false);
e4dd9aa4Serge Svekolnikov8 years ago255const projectRoot = SettingsHelper.getReactNativeProjectRoot(workspaceFolder.uri.fsPath);
634e3ecaRuslan Bikkinin7 years ago256return ReactNativeProjectHelper.isReactNativeProject(projectRoot).then(isRNProject => {
257generator.add("isRNProject", isRNProject, false);
258if (isRNProject) {
259// Bring the log channel to focus
260CommandPaletteHandler.logger.setFocusOnLogChannel();
261
262// Execute the operation
263return operation();
264} else {
265vscode.window.showErrorMessage("Current workspace is not a React Native project.");
266return;
267}
268});
10873e11digeff10 years ago269});
b3a793eeNisheet Jain10 years ago270}
7893fb7eJimmy Thomson9 years ago271
272/**
273* 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.
274*/
2e432a9eArtem Egorov8 years ago275private static executePublishToExpHost(project: IReactNativeProject): Q.Promise<boolean> {
276CommandPaletteHandler.logger.info("Publishing app to Exponent server. This might take a moment.");
277return this.loginToExponent(project)
7059d307Patricio Beltran9 years ago278.then(user => {
2e432a9eArtem Egorov8 years ago279CommandPaletteHandler.logger.debug(`Publishing as ${user.username}...`);
4787ec09Artem Egorov8 years ago280return this.runExponent()
7059d307Patricio Beltran9 years ago281.then(() =>
a41f5c68Artem Egorov8 years ago282XDL.publish(project.workspaceFolder.uri.fsPath))
7059d307Patricio Beltran9 years ago283.then(response => {
284if (response.err || !response.url) {
285return false;
286}
287const publishedOutput = `App successfully published to ${response.url}`;
2e432a9eArtem Egorov8 years ago288CommandPaletteHandler.logger.info(publishedOutput);
7059d307Patricio Beltran9 years ago289vscode.window.showInformationMessage(publishedOutput);
290return true;
291});
292});
293}
294
2e432a9eArtem Egorov8 years ago295private static loginToExponent(project: IReactNativeProject): Q.Promise<XDL.IUser> {
296return project.exponentHelper.loginToExponent(
5c8365a6Artem Egorov8 years ago297(message, password) => {
298return Q.Promise((resolve, reject) => {
299vscode.window.showInputBox({ placeHolder: message, password: password })
2e432a9eArtem Egorov8 years ago300.then(login => {
301resolve(login || "");
302}, reject);
5c8365a6Artem Egorov8 years ago303});
304},
305(message) => {
306return Q.Promise((resolve, reject) => {
307vscode.window.showInformationMessage(message)
2e432a9eArtem Egorov8 years ago308.then(password => {
309resolve(password || "");
310}, reject);
5c8365a6Artem Egorov8 years ago311});
312}
4787ec09Artem Egorov8 years ago313)
314.catch((err) => {
315CommandPaletteHandler.logger.warning("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.");
316throw err;
317});
7893fb7eJimmy Thomson9 years ago318}
2e432a9eArtem Egorov8 years ago319
320private static selectProject(): Q.Promise<IReactNativeProject> {
321let keys = Object.keys(this.projectsCache);
322if (keys.length > 1) {
323return Q.Promise((resolve, reject) => {
324vscode.window.showQuickPick(keys)
325.then((selected) => {
326if (selected) {
327resolve(this.projectsCache[selected]);
328}
329}, reject);
330});
331} else if (keys.length === 1) {
332return Q.resolve(this.projectsCache[keys[0]]);
333} else {
634e3ecaRuslan Bikkinin7 years ago334return Q.reject(new Error("Current workspace is not a React Native project."));
2e432a9eArtem Egorov8 years ago335}
336}
d1fc7f8aArtem Egorov8 years ago337
4787ec09Artem Egorov8 years ago338private static getRunOptions(project: IReactNativeProject, platform: "ios" | "android" | "exponent", target: TargetType = "simulator"): IAndroidRunOptions | IIOSRunOptions {
d1fc7f8aArtem Egorov8 years ago339const packagerPort = SettingsHelper.getPackagerPort(project.workspaceFolder.uri.fsPath);
340const runArgs = SettingsHelper.getRunArgs(platform, target, project.workspaceFolder.uri);
341const envArgs = SettingsHelper.getEnvArgs(platform, target, project.workspaceFolder.uri);
342const envFile = SettingsHelper.getEnvFile(platform, target, project.workspaceFolder.uri);
343const projectRoot = SettingsHelper.getReactNativeProjectRoot(project.workspaceFolder.uri.fsPath);
344const runOptions: IAndroidRunOptions | IIOSRunOptions = {
345platform: platform,
346workspaceRoot: project.workspaceFolder.uri.fsPath,
347projectRoot: projectRoot,
348packagerPort: packagerPort,
349runArguments: runArgs,
350env: envArgs,
351envFile: envFile,
352};
353
354return runOptions;
355}
0a283547Anna Kocheshkova8 years ago356}