microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
bf6ca50469e7197ca79e913dfab8ef6372097a15

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/common/commandExecutor.ts

178lines · 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 Q from "q";
5import {ChildProcess} from "child_process";
6import {Log} from "./log/log";
7import {Node} from "./node/node";
8import {ISpawnResult} from "./node/childProcess";
9import {ErrorHelper} from "./error/errorHelper";
10import {InternalErrorCode} from "./error/internalErrorCode";
11
12interface EnvironmentOptions {
13 REACT_DEBUGGER?: string;
14}
15
16interface Options {
17 env?: EnvironmentOptions;
18}
19
20export enum CommandStatus {
21 Start = 0,
22 End = 1
23}
24
25export class CommandExecutor {
26 private currentWorkingDirectory: string;
27
28 constructor(currentWorkingDirectory?: string) {
29 this.currentWorkingDirectory = currentWorkingDirectory;
30 }
31
32 public execute(command: string, options: Options = {}): Q.Promise<void> {
33 Log.logCommandStatus(command, CommandStatus.Start);
34 return new Node.ChildProcess().execToString(command, { cwd: this.currentWorkingDirectory, env: options.env })
35 .then(stdout => {
36 Log.logMessage(stdout);
37 Log.logCommandStatus(command, CommandStatus.End);
38 },
39 (reason: Error) =>
40 this.generateRejectionForCommand(command, reason));
41 }
42
43 /**
44 * Spawns a child process with the params passed and returns promise of the spawned ChildProcess
45 * This method does not wait for the spawned process to finish execution
46 * {command} - The command to be invoked in the child process
47 * {args} - Arguments to be passed to the command
48 * {options} - additional options with which the child process needs to be spawned
49 */
50 public spawn(command: string, args: string[], options: Options = {}): ChildProcess {
51 return this.spawnChildProcess(command, args, options).spawnedProcess;
52 }
53
54 /**
55 * Spawns a child process with the params passed
56 * This method waits until the spawned process finishes execution
57 * {command} - The command to be invoked in the child process
58 * {args} - Arguments to be passed to the command
59 * {options} - additional options with which the child process needs to be spawned
60 */
61 public spawnAndWaitForCompletion(command: string, args: string[], options: Options = {}): Q.Promise<void> {
62 return this.spawnChildProcess(command, args, options).outcome;
63 }
64
65 /**
66 * Spawns the React Native packager in a child process.
67 */
68 public spawnReactPackager(args?: string[], options: Options = {}): Q.Promise<ChildProcess> {
69 let deferred = Q.defer<ChildProcess>();
70 let command = this.getReactCommandName();
71 let runArguments = ["start"];
72
73 if (args) {
74 runArguments = runArguments.concat(args);
75 }
76
77 let spawnOptions = Object.assign({}, { cwd: this.currentWorkingDirectory }, options);
78
79 let result = new Node.ChildProcess().spawn(command, runArguments, spawnOptions);
80 result.spawnedProcess.once("error", (error: any) => {
81 deferred.reject(ErrorHelper.getNestedError(error, InternalErrorCode.PackagerStartFailed));
82 });
83
84 result.stderr.on("data", (data: Buffer) => {
85 Log.logMessage(data.toString(), /*formatMessage*/false);
86 });
87
88 result.stdout.on("data", (data: Buffer) => {
89 Log.logMessage(data.toString(), /*formatMessage*/false);
90 });
91
92 // TODO #83 - PROMISE: We need to consume result.outcome here
93 Q.delay(300).done(() => deferred.resolve(result.spawnedProcess));
94 return deferred.promise;
95 }
96
97 /**
98 * Kills the React Native packager in a child process.
99 */
100 public killReactPackager(packagerProcess: ChildProcess): Q.Promise<void> {
101 Log.logMessage("Stopping Packager");
102 if (packagerProcess) {
103 /* To reliably kill the child process on all versions of Windows,
104 * please use taskkill to end the packager process */
105 if (process.platform === "win32") {
106 return new Node.ChildProcess().exec("taskkill /pid " + packagerProcess.pid + " /T /F").outcome.then(() => {
107 Log.logMessage("Packager stopped");
108 });
109 } else {
110 packagerProcess.kill();
111 Log.logMessage("Packager stopped");
112 return Q.resolve<void>(void 0);
113 }
114 } else {
115 Log.logMessage("Packager not found");
116 return Q.resolve<void>(void 0);
117 }
118 }
119
120
121
122 /**
123 * Executes a react native command and waits for its completion.
124 */
125 public spawnAndWaitReactCommand(command: string, args?: string[], options: Options = {}): Q.Promise<void> {
126 return this.spawnChildReactCommandProcess(command, args, options).outcome;
127 }
128
129 public spawnChildReactCommandProcess(command: string, args?: string[], options: Options = {}): ISpawnResult {
130 let runArguments = [command];
131 if (args) {
132 runArguments = runArguments.concat(args);
133 }
134 return this.spawnChildProcess(this.getReactCommandName(), runArguments, options);
135 }
136
137 /**
138 * Resolves the dev machine, desktop platform.
139 */
140 private getReactCommandName() {
141 let platform = process.platform;
142 switch (platform) {
143 case "darwin":
144 return "react-native";
145 case "win32":
146 default:
147 return "react-native.cmd";
148 }
149 }
150
151 private spawnChildProcess(command: string, args: string[], options: Options = {}): ISpawnResult {
152 let spawnOptions = Object.assign({}, { cwd: this.currentWorkingDirectory }, options);
153 let commandWithArgs = command + " " + args.join(" ");
154
155 Log.logCommandStatus(commandWithArgs, CommandStatus.Start);
156 let result = new Node.ChildProcess().spawnWithExitHandler(command, args, spawnOptions);
157
158 result.stderr.on("data", (data: Buffer) => {
159 Log.logMessage(data.toString(), /*formatMessage*/ false);
160 });
161
162 result.stdout.on("data", (data: Buffer) => {
163 Log.logMessage(data.toString(), /*formatMessage*/ false);
164 });
165
166 result.outcome = result.outcome.then(
167 () =>
168 Log.logCommandStatus(commandWithArgs, CommandStatus.End),
169 reason =>
170 this.generateRejectionForCommand(command, reason));
171
172 return result;
173 }
174
175 private generateRejectionForCommand(command: string, reason: any): Q.Promise<void> {
176 return Q.reject<void>(ErrorHelper.getInternalError(InternalErrorCode.CommandFailed, command, reason));
177 }
178}
179