microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
unified-deduplication-logic-afterEach

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/common/node/childProcess.ts

231lines · modeblame

a31b007cunknown10 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
6f8b71fedigeff10 years ago4import * as nodeChildProcess from "child_process";
09f6024fHeniker4 years ago5import { kill } from "process";
ce5e88eeYuri Skorokhodov5 years ago6import { ErrorHelper } from "../error/errorHelper";
7import { InternalErrorCode } from "../error/internalErrorCode";
4bb0956eRedMickey5 years ago8import { notNullOrUndefined } from "../utils";
3fb37ad5unknown10 years ago9
c7f1165cdigeff10 years ago10// Uncomment the following lines to record all spawned processes executions
3c172a05Artem Egorov8 years ago11// import {Recorder} from "../../../test/resources/processExecution/recorder";
c7f1165cdigeff10 years ago12// Recorder.installGlobalRecorder();
13
3fb37ad5unknown10 years ago14export interface IExecResult {
6f8b71fedigeff10 years ago15process: nodeChildProcess.ChildProcess;
ce5e88eeYuri Skorokhodov5 years ago16outcome: Promise<string>;
3fb37ad5unknown10 years ago17}
18
45944d15Meena Kunnathur Balakrishnan10 years ago19export interface ISpawnResult {
6f8b71fedigeff10 years ago20spawnedProcess: nodeChildProcess.ChildProcess;
5b0582f3digeff10 years ago21stdin: NodeJS.WritableStream;
22stdout: NodeJS.ReadableStream;
23stderr: NodeJS.ReadableStream;
ce5e88eeYuri Skorokhodov5 years ago24outcome: Promise<void>;
45944d15Meena Kunnathur Balakrishnan10 years ago25}
26
3fb37ad5unknown10 years ago27interface IExecOptions {
28cwd?: string;
29stdio?: any;
30env?: any;
31encoding?: string;
32timeout?: number;
33maxBuffer?: number;
34killSignal?: string;
35}
36
37interface ISpawnOptions {
38cwd?: string;
39stdio?: any;
40env?: any;
41detached?: boolean;
77e86943lexie0111 years ago42shell?: boolean;
3fb37ad5unknown10 years ago43}
44
45export class ChildProcess {
88246fe9Meena Kunnathur Balakrishnan10 years ago46public static ERROR_TIMEOUT_MILLISECONDS = 300;
6f8b71fedigeff10 years ago47private childProcess: typeof nodeChildProcess;
aab2095edigeff10 years ago48
ce5e88eeYuri Skorokhodov5 years ago49constructor({ childProcess = nodeChildProcess } = {}) {
aab2095edigeff10 years ago50this.childProcess = childProcess;
51}
52
ce5e88eeYuri Skorokhodov5 years ago53public exec(command: string, options: IExecOptions = {}): Promise<IExecResult> {
54let outcome: Promise<string>;
55let process: nodeChildProcess.ChildProcess;
34472878RedMickey5 years ago56return new Promise<IExecResult>(resolveRes => {
ce5e88eeYuri Skorokhodov5 years ago57outcome = new Promise<string>((resolve, reject) => {
34472878RedMickey5 years ago58process = this.childProcess.exec(
59command,
60options,
61// eslint-disable-next-line @typescript-eslint/no-unused-vars
176f99c8ConnorQi013 months ago62(
63error: nodeChildProcess.ExecException | null,
64stdout: string | Buffer,
65stderr: string | Buffer,
66) => {
ce5e88eeYuri Skorokhodov5 years ago67if (error) {
34472878RedMickey5 years ago68reject(
69ErrorHelper.getNestedError(
70error,
71InternalErrorCode.CommandFailed,
72command,
73),
74);
ce5e88eeYuri Skorokhodov5 years ago75} else {
176f99c8ConnorQi013 months ago76resolve(stdout.toString());
ce5e88eeYuri Skorokhodov5 years ago77}
34472878RedMickey5 years ago78},
79);
80});
09f6024fHeniker4 years ago81resolveRes({ process, outcome });
3fb37ad5unknown10 years ago82});
83}
84
0d77292aJiglioNero4 years ago85public async execToString(command: string, options: IExecOptions = {}): Promise<string> {
86const execResult = await this.exec(command, options);
87const stdout = await execResult.outcome;
88return stdout.toString();
3fb37ad5unknown10 years ago89}
90
8aef7548ConnorQi013 months ago91public async execFileToString(
92command: string,
93args: string[] = [],
94options: IExecOptions = {},
95): Promise<string> {
96return new Promise<string>((resolve, reject) => {
97this.childProcess.execFile(
98command,
99args,
100options,
101(
102error: nodeChildProcess.ExecException | null,
103stdout: string | Buffer,
104stderr: string | Buffer,
105) => {
106if (error) {
107reject(
108ErrorHelper.getNestedError(
109error,
110InternalErrorCode.CommandFailed,
111command,
112),
113);
114} else {
115resolve(stdout.toString());
116}
117},
118);
119});
120}
121
34472878RedMickey5 years ago122public execFileSync(
123command: string,
124args: string[] = [],
125options: IExecOptions = {},
126): Buffer | string {
b3753d4eRedMickey6 years ago127return this.childProcess.execFileSync(command, args, options);
128}
129
34472878RedMickey5 years ago130public spawn(
131command: string,
132args: string[] = [],
133options: ISpawnOptions = {},
134showStdOutputsOnError: boolean = false,
135): ISpawnResult {
77e86943lexie0111 years ago136const spawnedProcess = this.childProcess.spawn(
137command,
138args,
139Object.assign({}, options, { shell: true }),
140);
09f6024fHeniker4 years ago141const outcome: Promise<void> = new Promise((resolve, reject) => {
ce5e88eeYuri Skorokhodov5 years ago142spawnedProcess.once("error", (error: any) => {
143reject(error);
144});
145
dd8375caJiglioNero5 years ago146const stderrChunks: string[] = [];
147const stdoutChunks: string[] = [];
148
34472878RedMickey5 years ago149spawnedProcess.stderr.on("data", data => {
dd8375caJiglioNero5 years ago150stderrChunks.push(data.toString());
151});
152
34472878RedMickey5 years ago153spawnedProcess.stdout.on("data", data => {
dd8375caJiglioNero5 years ago154stdoutChunks.push(data.toString());
155});
156
ce5e88eeYuri Skorokhodov5 years ago157spawnedProcess.once("exit", (code: number) => {
158if (code === 0) {
159resolve();
160} else {
09f6024fHeniker4 years ago161const commandWithArgs = `${command} ${args.join(" ")}`;
dd8375caJiglioNero5 years ago162if (showStdOutputsOnError) {
163let details = "";
164if (stdoutChunks.length > 0) {
34472878RedMickey5 years ago165details = details.concat(
166`\n\tSTDOUT: ${stdoutChunks[stdoutChunks.length - 1]}`,
167);
dd8375caJiglioNero5 years ago168}
169if (stderrChunks.length > 0) {
170details = details.concat(`\n\tSTDERR: ${stderrChunks.join("\n\t")}`);
171}
172if (details === "") {
173details = "STDOUT and STDERR are empty!";
174}
34472878RedMickey5 years ago175reject(
176ErrorHelper.getInternalError(
177InternalErrorCode.CommandFailedWithDetails,
178commandWithArgs,
179details,
180),
181);
182} else {
183reject(
184ErrorHelper.getInternalError(
185InternalErrorCode.CommandFailed,
186commandWithArgs,
187code,
188),
189);
dd8375caJiglioNero5 years ago190}
ce5e88eeYuri Skorokhodov5 years ago191}
192});
3fb37ad5unknown10 years ago193});
c3a987a7Meena Kunnathur Balakrishnan10 years ago194return {
09f6024fHeniker4 years ago195spawnedProcess,
ce5e88eeYuri Skorokhodov5 years ago196stdin: spawnedProcess.stdin,
197stdout: spawnedProcess.stdout,
198stderr: spawnedProcess.stderr,
09f6024fHeniker4 years ago199outcome,
34472878RedMickey5 years ago200};
c3a987a7Meena Kunnathur Balakrishnan10 years ago201}
4bb0956eRedMickey5 years ago202
203// Kills any orphaned Instruments processes belonging to the user.
204//
205// In some cases, we've seen interactions between Instruments and the iOS
206// simulator that cause hung instruments and DTServiceHub processes. If
207// enough instances pile up, the host machine eventually becomes
208// unresponsive. Until the underlying issue is resolved, manually kill any
209// orphaned instances (where the parent process has died and PPID is 1)
210// before launching another instruments run.
211public async killOrphanedInstrumentsProcesses(): Promise<void> {
212const result = await this.execToString("ps -e -o user,ppid,pid,comm");
213if (result) {
214result
215.split("\n")
216.filter(notNullOrUndefined)
217.map(a => /^(\S+)\s+1\s+(\d+)\s+(.+)$/.exec(a))
218.filter(notNullOrUndefined)
219.filter(m => m[1] === process.env.USER)
220.filter(
221m =>
222m[3] && ["/instruments", "/DTServiceHub"].some(name => m[3].endsWith(name)),
223)
224.forEach(m => {
225const pid = m[2];
226console.debug(`Killing orphaned Instruments process: ${pid}`);
227kill(parseInt(pid, 10), "SIGKILL");
228});
229}
230}
3fb37ad5unknown10 years ago231}