microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
3c2eeb5c9c12252cabd328afa31e79f80b5dd394

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/common/commandExecutor.ts

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