microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
0.6.17

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/extension/commandPaletteHandler.ts

362lines · 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";
db6fd42aRuslan Bikkinin7 years ago10import {TargetType, GeneralMobilePlatform} 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 {
db6fd42aRuslan Bikkinin7 years ago38this.logger.debug(`Command palette: added folder ${workspaceFolder.uri.fsPath}`);
4edcda70Artem Egorov8 years ago39this.projectsCache[workspaceFolder.uri.fsPath] = {
40...stuff,
2e432a9eArtem Egorov8 years ago41workspaceFolder,
42};
43}
bef522ffMeena Kunnathur Balakrishnan10 years ago44
4edcda70Artem Egorov8 years ago45public static getFolder(workspaceFolder: vscode.WorkspaceFolder): IReactNativeProject {
46return this.projectsCache[workspaceFolder.uri.fsPath];
2e432a9eArtem Egorov8 years ago47}
48
4edcda70Artem Egorov8 years ago49public static delFolder(workspaceFolder: vscode.WorkspaceFolder): void {
50delete this.projectsCache[workspaceFolder.uri.fsPath];
bef522ffMeena Kunnathur Balakrishnan10 years ago51}
52
0904a0d7Meena Kunnathur Balakrishnan10 years ago53/**
54* Starts the React Native packager
55*/
2e432a9eArtem Egorov8 years ago56public static startPackager(): Q.Promise<void> {
57return this.selectProject()
58.then((project: IReactNativeProject) => {
4787ec09Artem Egorov8 years ago59return this.executeCommandInContext("startPackager", project.workspaceFolder, () => {
60return project.packager.isRunning()
2e432a9eArtem Egorov8 years ago61.then((running) => {
4edcda70Artem Egorov8 years ago62return running ? project.packager.stop() : Q.resolve(void 0);
4787ec09Artem Egorov8 years ago63});
64})
65.then(() => project.packager.start());
2e432a9eArtem Egorov8 years ago66});
bef522ffMeena Kunnathur Balakrishnan10 years ago67}
68
0904a0d7Meena Kunnathur Balakrishnan10 years ago69/**
70* Kills the React Native packager invoked by the extension's packager
71*/
2e432a9eArtem Egorov8 years ago72public static stopPackager(): Q.Promise<void> {
73return this.selectProject()
74.then((project: IReactNativeProject) => {
4787ec09Artem Egorov8 years ago75return this.executeCommandInContext("stopPackager", project.workspaceFolder, () => project.packager.stop());
2e432a9eArtem Egorov8 years ago76});
3194e9afMeena Kunnathur Balakrishnan10 years ago77}
78
4edcda70Artem Egorov8 years ago79public static stopAllPackagers(): Q.Promise<void> {
80let keys = Object.keys(this.projectsCache);
81let promises: Q.Promise<void>[] = [];
82keys.forEach((key) => {
83let project = this.projectsCache[key];
4787ec09Artem Egorov8 years ago84promises.push(this.executeCommandInContext("stopPackager", project.workspaceFolder, () => project.packager.stop()));
4edcda70Artem Egorov8 years ago85});
86
87return Q.all(promises).then(() => {});
88}
89
f2a58eefBret Johnson9 years ago90/**
91* Restarts the React Native packager
92*/
2e432a9eArtem Egorov8 years ago93public static restartPackager(): Q.Promise<void> {
94return this.selectProject()
95.then((project: IReactNativeProject) => {
96return this.executeCommandInContext("restartPackager", project.workspaceFolder, () =>
97this.runRestartPackagerCommandAndUpdateStatus(project));
98});
f2a58eefBret Johnson9 years ago99}
100
7893fb7eJimmy Thomson9 years ago101/**
102* Execute command to publish to exponent host.
103*/
2e432a9eArtem Egorov8 years ago104public static publishToExpHost(): Q.Promise<void> {
105return this.selectProject()
106.then((project: IReactNativeProject) => {
107return this.executeCommandInContext("publishToExpHost", project.workspaceFolder, () => {
108return this.executePublishToExpHost(project).then((didPublish) => {
109if (!didPublish) {
110CommandPaletteHandler.logger.warning("Publishing was unsuccessful. Please make sure you are logged in Exponent and your project is a valid Exponentjs project");
111}
112});
113});
7893fb7eJimmy Thomson9 years ago114});
115}
116
3194e9afMeena Kunnathur Balakrishnan10 years ago117/**
118* Executes the 'react-native run-android' command
119*/
d1fc7f8aArtem Egorov8 years ago120public static runAndroid(target: TargetType = "simulator"): Q.Promise<void> {
2e432a9eArtem Egorov8 years ago121return this.selectProject()
122.then((project: IReactNativeProject) => {
0611729dRuslan Bikkinin7 years ago123TargetPlatformHelper.checkTargetPlatformSupport("android");
4787ec09Artem Egorov8 years ago124return this.executeCommandInContext("runAndroid", project.workspaceFolder, () => {
db6fd42aRuslan Bikkinin7 years ago125const platform = <AndroidPlatform>this.createPlatform(project, "android", AndroidPlatform, target);
4787ec09Artem Egorov8 years ago126return platform.beforeStartPackager()
127.then(() => {
128return platform.startPackager();
129})
130.then(() => {
131return platform.runApp(/*shouldLaunchInAllDevices*/true);
132})
2e432a9eArtem Egorov8 years ago133.then(() => {
134return platform.disableJSDebuggingMode();
135});
4787ec09Artem Egorov8 years ago136});
0a68f8dbArtem Egorov8 years ago137});
3194e9afMeena Kunnathur Balakrishnan10 years ago138}
139
140/**
141* Executes the 'react-native run-ios' command
142*/
d1fc7f8aArtem Egorov8 years ago143public static runIos(target: TargetType = "simulator"): Q.Promise<void> {
2e432a9eArtem Egorov8 years ago144return this.selectProject()
145.then((project: IReactNativeProject) => {
0611729dRuslan Bikkinin7 years ago146TargetPlatformHelper.checkTargetPlatformSupport("ios");
4787ec09Artem Egorov8 years ago147return this.executeCommandInContext("runIos", project.workspaceFolder, () => {
db6fd42aRuslan Bikkinin7 years ago148const platform = <IOSPlatform>this.createPlatform(project, "ios", IOSPlatform, target);
4787ec09Artem Egorov8 years ago149return platform.beforeStartPackager()
150.then(() => {
151return platform.startPackager();
152})
153.then(() => {
154// Set the Debugging setting to disabled, because in iOS it's persisted across runs of the app
155return platform.disableJSDebuggingMode();
156})
2e432a9eArtem Egorov8 years ago157.catch(() => { }) // If setting the debugging mode fails, we ignore the error and we run the run ios command anyways
158.then(() => {
159return platform.runApp();
160});
4787ec09Artem Egorov8 years ago161});
162});
163}
164
165/**
166* Starts the Exponent packager
167*/
168public static runExponent(): Q.Promise<void> {
169return this.selectProject()
170.then((project: IReactNativeProject) => {
171return this.loginToExponent(project)
172.then(() => {
031832ffArtem Egorov8 years ago173return this.executeCommandInContext("runExponent", project.workspaceFolder, () => {
db6fd42aRuslan Bikkinin7 years ago174const platform = <ExponentPlatform>this.createPlatform(project, "exponent", ExponentPlatform);
4787ec09Artem Egorov8 years ago175return platform.beforeStartPackager()
176.then(() => {
177return platform.startPackager();
178})
179.then(() => {
180return platform.runApp();
181});
182});
183});
2e432a9eArtem Egorov8 years ago184});
3194e9afMeena Kunnathur Balakrishnan10 years ago185}
186
2e432a9eArtem Egorov8 years ago187public static showDevMenu(): Q.Promise<void> {
a41f5c68Artem Egorov8 years ago188return this.selectProject()
189.then((project: IReactNativeProject) => {
db6fd42aRuslan Bikkinin7 years ago190const androidPlatform = <AndroidPlatform>this.createPlatform(project, "android", AndroidPlatform);
191androidPlatform.showDevMenu()
a41f5c68Artem Egorov8 years ago192.catch(() => { }); // Ignore any errors
db6fd42aRuslan Bikkinin7 years ago193const iosPlatform = <IOSPlatform>this.createPlatform(project, "ios", IOSPlatform);
194iosPlatform.showDevMenu()
a41f5c68Artem Egorov8 years ago195.catch(() => { }); // Ignore any errors
196return Q.resolve(void 0);
197});
7daed3fcArtem Egorov8 years ago198}
199
2e432a9eArtem Egorov8 years ago200public static reloadApp(): Q.Promise<void> {
a41f5c68Artem Egorov8 years ago201return this.selectProject()
202.then((project: IReactNativeProject) => {
db6fd42aRuslan Bikkinin7 years ago203const androidPlatform = <AndroidPlatform>this.createPlatform(project, "android", AndroidPlatform);
204androidPlatform.reloadApp()
a41f5c68Artem Egorov8 years ago205.catch(() => { }); // Ignore any errors
db6fd42aRuslan Bikkinin7 years ago206const iosPlatform = <IOSPlatform>this.createPlatform(project, "ios", IOSPlatform);
207iosPlatform.reloadApp()
a41f5c68Artem Egorov8 years ago208.catch(() => { }); // Ignore any errors
209return Q.resolve(void 0);
210});
7daed3fcArtem Egorov8 years ago211}
212
031832ffArtem Egorov8 years ago213public static getPlatformByCommandName(commandName: string): string {
214commandName = commandName.toLocaleLowerCase();
215
216if (commandName.indexOf("android") > -1) {
217return "android";
218}
219
220if (commandName.indexOf("ios") > -1) {
221return "ios";
222}
223
224if (commandName.indexOf("exponent") > -1) {
225return "exponent";
226}
227
228return "";
229}
230
db6fd42aRuslan Bikkinin7 years ago231private static createPlatform(project: IReactNativeProject, platform: "ios" | "android" | "exponent", platformClass: typeof GeneralMobilePlatform, target?: TargetType): GeneralMobilePlatform {
232const runOptions = CommandPaletteHandler.getRunOptions(project, platform, target);
233return new platformClass(runOptions, {
234packager: project.packager,
235});
236}
237
2e432a9eArtem Egorov8 years ago238private static runRestartPackagerCommandAndUpdateStatus(project: IReactNativeProject): Q.Promise<void> {
4787ec09Artem Egorov8 years ago239return project.packager.restart(SettingsHelper.getPackagerPort(project.workspaceFolder.uri.fsPath));
3194e9afMeena Kunnathur Balakrishnan10 years ago240}
b3a793eeNisheet Jain10 years ago241
242/**
243* Ensures that we are in a React Native project and then executes the operation
244* Otherwise, displays an error message banner
245* {operation} - a function that performs the expected operation
246*/
2e432a9eArtem Egorov8 years ago247private static executeCommandInContext(rnCommand: string, workspaceFolder: vscode.WorkspaceFolder, operation: () => Q.Promise<void>): Q.Promise<void> {
031832ffArtem Egorov8 years ago248const extProps = {
249platform: {
250value: CommandPaletteHandler.getPlatformByCommandName(rnCommand),
251isPii: false,
252},
253};
254
255return TelemetryHelper.generate("RNCommand", extProps, (generator) => {
8512ccfeMeena Kunnathur Balakrishnan10 years ago256generator.add("command", rnCommand, false);
e4dd9aa4Serge Svekolnikov8 years ago257const projectRoot = SettingsHelper.getReactNativeProjectRoot(workspaceFolder.uri.fsPath);
db6fd42aRuslan Bikkinin7 years ago258this.logger.debug(`Command palette: run project ${projectRoot} in context`);
259return ReactNativeProjectHelper.isReactNativeProject(projectRoot)
260.then(isRNProject => {
261generator.add("isRNProject", isRNProject, false);
262if (isRNProject) {
263// Bring the log channel to focus
264this.logger.setFocusOnLogChannel();
265
266// Execute the operation
267return operation();
268} else {
269vscode.window.showErrorMessage(`${projectRoot} workspace is not a React Native project.`);
270return;
271}
272});
10873e11digeff10 years ago273});
b3a793eeNisheet Jain10 years ago274}
7893fb7eJimmy Thomson9 years ago275
276/**
277* 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.
278*/
2e432a9eArtem Egorov8 years ago279private static executePublishToExpHost(project: IReactNativeProject): Q.Promise<boolean> {
280CommandPaletteHandler.logger.info("Publishing app to Exponent server. This might take a moment.");
281return this.loginToExponent(project)
7059d307Patricio Beltran9 years ago282.then(user => {
2e432a9eArtem Egorov8 years ago283CommandPaletteHandler.logger.debug(`Publishing as ${user.username}...`);
4787ec09Artem Egorov8 years ago284return this.runExponent()
7059d307Patricio Beltran9 years ago285.then(() =>
a41f5c68Artem Egorov8 years ago286XDL.publish(project.workspaceFolder.uri.fsPath))
7059d307Patricio Beltran9 years ago287.then(response => {
288if (response.err || !response.url) {
289return false;
290}
291const publishedOutput = `App successfully published to ${response.url}`;
2e432a9eArtem Egorov8 years ago292CommandPaletteHandler.logger.info(publishedOutput);
7059d307Patricio Beltran9 years ago293vscode.window.showInformationMessage(publishedOutput);
294return true;
295});
296});
297}
298
2e432a9eArtem Egorov8 years ago299private static loginToExponent(project: IReactNativeProject): Q.Promise<XDL.IUser> {
300return project.exponentHelper.loginToExponent(
5c8365a6Artem Egorov8 years ago301(message, password) => {
302return Q.Promise((resolve, reject) => {
303vscode.window.showInputBox({ placeHolder: message, password: password })
2e432a9eArtem Egorov8 years ago304.then(login => {
305resolve(login || "");
306}, reject);
5c8365a6Artem Egorov8 years ago307});
308},
309(message) => {
310return Q.Promise((resolve, reject) => {
311vscode.window.showInformationMessage(message)
2e432a9eArtem Egorov8 years ago312.then(password => {
313resolve(password || "");
314}, reject);
5c8365a6Artem Egorov8 years ago315});
316}
4787ec09Artem Egorov8 years ago317)
318.catch((err) => {
319CommandPaletteHandler.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.");
320throw err;
321});
7893fb7eJimmy Thomson9 years ago322}
2e432a9eArtem Egorov8 years ago323
324private static selectProject(): Q.Promise<IReactNativeProject> {
325let keys = Object.keys(this.projectsCache);
326if (keys.length > 1) {
327return Q.Promise((resolve, reject) => {
328vscode.window.showQuickPick(keys)
329.then((selected) => {
330if (selected) {
db6fd42aRuslan Bikkinin7 years ago331this.logger.debug(`Command palette: selected project ${selected}`);
2e432a9eArtem Egorov8 years ago332resolve(this.projectsCache[selected]);
333}
334}, reject);
335});
336} else if (keys.length === 1) {
db6fd42aRuslan Bikkinin7 years ago337this.logger.debug(`Command palette: once project ${keys[0]}`);
2e432a9eArtem Egorov8 years ago338return Q.resolve(this.projectsCache[keys[0]]);
339} else {
db6fd42aRuslan Bikkinin7 years ago340return Q.reject(new Error("Current workspace does not contain React Native projects."));
2e432a9eArtem Egorov8 years ago341}
342}
d1fc7f8aArtem Egorov8 years ago343
4787ec09Artem Egorov8 years ago344private static getRunOptions(project: IReactNativeProject, platform: "ios" | "android" | "exponent", target: TargetType = "simulator"): IAndroidRunOptions | IIOSRunOptions {
d1fc7f8aArtem Egorov8 years ago345const packagerPort = SettingsHelper.getPackagerPort(project.workspaceFolder.uri.fsPath);
346const runArgs = SettingsHelper.getRunArgs(platform, target, project.workspaceFolder.uri);
347const envArgs = SettingsHelper.getEnvArgs(platform, target, project.workspaceFolder.uri);
348const envFile = SettingsHelper.getEnvFile(platform, target, project.workspaceFolder.uri);
349const projectRoot = SettingsHelper.getReactNativeProjectRoot(project.workspaceFolder.uri.fsPath);
350const runOptions: IAndroidRunOptions | IIOSRunOptions = {
351platform: platform,
352workspaceRoot: project.workspaceFolder.uri.fsPath,
353projectRoot: projectRoot,
354packagerPort: packagerPort,
355runArguments: runArgs,
356env: envArgs,
357envFile: envFile,
358};
359
360return runOptions;
361}
0a283547Anna Kocheshkova8 years ago362}