UNPKG

@ts-common/azure-js-dev-tools

Version:

Developer dependencies for TypeScript related projects

566 lines 22.6 kB
"use strict"; /** * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for * license information. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.run = exports.getChildProcessStdio = exports.logResult = exports.logEnvironmentVariables = exports.logCommand = exports.getShowResultFunction = exports.getArgsArray = exports.FakeRunner = exports.RealRunner = exports.chunkToString = exports.ensureQuoted = exports.shouldQuote = exports.quoteIfNeeded = exports.parseCommands = exports.parseCommand = exports.createCommand = exports.parseCommandTokens = exports.parseCommandToken = exports.commandToString = void 0; var tslib_1 = require("tslib"); var child_process_1 = require("child_process"); var os = tslib_1.__importStar(require("os")); var arrays_1 = require("./arrays"); var common_1 = require("./common"); var path_1 = require("./path"); /** * Get the string representation of the provided command. */ function commandToString(command) { var e_1, _a; var result = quoteIfNeeded(command.executable); if (arrays_1.any(command.args)) { try { for (var _b = tslib_1.__values(command.args), _c = _b.next(); !_c.done; _c = _b.next()) { var arg = _c.value; if (arg) { result += " " + quoteIfNeeded(arg); } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_1) throw e_1.error; } } } return result; } exports.commandToString = commandToString; function parseCommandNonWhitespaceToken(commandString, startIndex) { var commandStringLength = commandString.length; var endIndex = startIndex; var quote; var escaped = false; while (endIndex < commandStringLength) { var currentCharacter = commandString[endIndex]; ++endIndex; if (!quote) { if (currentCharacter === " ") { --endIndex; break; } else if (currentCharacter === "'" || currentCharacter === "\"") { quote = currentCharacter; } } else if (!escaped) { if (currentCharacter === "\\") { escaped = true; } else if (currentCharacter === quote) { quote = undefined; } } else { escaped = false; } } return { text: commandString.substring(startIndex, endIndex), startIndex: startIndex, endIndex: endIndex, }; } function parseCommandWhitespaceToken(commandString, startIndex) { var commandStringLength = commandString.length; var endIndex = startIndex + 1; while (endIndex < commandStringLength && commandString[endIndex] === " ") { ++endIndex; } return { text: commandString.substring(startIndex, endIndex), startIndex: startIndex, endIndex: endIndex, isWhitespace: true, }; } function parseCommandToken(commandString, startIndex) { var result; var commandStringLength = commandString.length; if (0 <= startIndex && startIndex < commandStringLength) { var firstCharacter = commandString[startIndex]; if (firstCharacter === " ") { result = parseCommandWhitespaceToken(commandString, startIndex); } else { result = parseCommandNonWhitespaceToken(commandString, startIndex); } } return result; } exports.parseCommandToken = parseCommandToken; function parseCommandTokens(commandString, startIndex) { if (startIndex === void 0) { startIndex = 0; } var result = []; var argToken = parseCommandToken(commandString, startIndex); while (argToken) { if (!argToken.isWhitespace) { result.push(argToken); } argToken = parseCommandToken(commandString, argToken.endIndex); } return result; } exports.parseCommandTokens = parseCommandTokens; function createCommand(commandTokens) { var result; if (arrays_1.any(commandTokens)) { result = { executable: commandTokens.shift().text, args: commandTokens.map(function (commandToken) { return commandToken.text; }), }; } return result; } exports.createCommand = createCommand; /** * Parse a command object from the provided command string. */ function parseCommand(commandString, startIndex) { if (startIndex === void 0) { startIndex = 0; } var commandTokens = parseCommandTokens(commandString, startIndex); return createCommand(commandTokens); } exports.parseCommand = parseCommand; function parseCommands(commandString, startIndex) { if (startIndex === void 0) { startIndex = 0; } var commandTokens = parseCommandTokens(commandString, startIndex); var commandStartIndex = 0; var result = []; for (var commandIndex = 0; commandIndex < commandTokens.length; ++commandIndex) { var command = commandTokens[commandIndex]; if (command.text === "&" || command.text === "&&") { if (commandStartIndex === commandIndex) { ++commandStartIndex; } else { result.push(createCommand(commandTokens.slice(commandStartIndex, commandIndex))); commandStartIndex = commandIndex + 1; } } } if (commandStartIndex < commandTokens.length) { result.push(createCommand(commandTokens.slice(commandStartIndex, commandTokens.length))); } return result; } exports.parseCommands = parseCommands; /** * Quote the provided value if it is needed. */ function quoteIfNeeded(value, quote) { if (quote === void 0) { quote = "\""; } return shouldQuote(value, quote) ? ensureQuoted(value, quote) : value; } exports.quoteIfNeeded = quoteIfNeeded; /** * Determine whether or not the provided value should be quoted. */ function shouldQuote(value, quote) { if (quote === void 0) { quote = "\""; } return !!value && (value.includes(" ") || value.includes(quote)); } exports.shouldQuote = shouldQuote; /** * Ensure that the provided value is surrounded by the provided quote string. */ function ensureQuoted(value, quote) { if (quote === void 0) { quote = "\""; } if (quote && value.length < quote.length * 2 || !value.startsWith(quote) || !value.endsWith(quote)) { if (quote === "\"" || quote === "'") { value = common_1.replaceAll(value, quote, "\\" + quote); } value = "" + quote + value + quote; } return value; } exports.ensureQuoted = ensureQuoted; function chunkToString(chunk) { if (Buffer.isBuffer(chunk)) { chunk = chunk.toString("utf8"); } return chunk; } exports.chunkToString = chunkToString; var captureProcessOutput = function (source, captureFn, capturePrefix) { return tslib_1.__awaiter(void 0, void 0, void 0, function () { var capturedOutput, captureOutputFn; return tslib_1.__generator(this, function (_a) { capturedOutput = ""; if (captureFn === false || source === null) { return [2 /*return*/, undefined]; } captureOutputFn = function (text) { capturedOutput += text; if (typeof captureFn === "function") { if (capturePrefix) { text = "[" + capturePrefix + "] " + text; } captureFn(text); } }; return [2 /*return*/, new Promise(function (resolve, reject) { var currentOutputLine = ""; source.addListener("data", function (chunk) { currentOutputLine += chunkToString(chunk); while (true) { var newLineIndex = currentOutputLine.indexOf("\n"); if (newLineIndex === -1) { break; } var startOfNextLine = newLineIndex + 1; captureOutputFn(currentOutputLine.substring(0, startOfNextLine)); currentOutputLine = currentOutputLine.substring(startOfNextLine); } }); source.addListener("error", function (error) { if (currentOutputLine) { captureOutputFn(currentOutputLine); currentOutputLine = ""; } reject(error); }); source.addListener("end", function () { if (currentOutputLine) { captureOutputFn(currentOutputLine); currentOutputLine = ""; } resolve(capturedOutput); }); })]; }); }); }; /** * A command runner that runs commands using a spawned process. */ var RealRunner = /** @class */ (function () { function RealRunner() { } RealRunner.prototype.run = function (command, options) { if (options === void 0) { options = {}; } var executablePath = path_1.normalizePath(command.executable, os.platform()); var childProcess = child_process_1.spawn(executablePath, command.args || [], { cwd: options.executionFolderPath, stdio: getChildProcessStdio(options), env: options.environmentVariables || process.env }); var stdoutCaptured = captureProcessOutput(childProcess.stdout, options.captureOutput, options.capturePrefix); var stderrCaptured = captureProcessOutput(childProcess.stderr, options.captureError, options.capturePrefix); var processExitCode; var processDone = new Promise(function (resolve, reject) { childProcess.addListener("exit", function (exitCode) { processExitCode = exitCode; resolve(); }); childProcess.addListener("error", reject); }); return Promise.all([processDone, stdoutCaptured, stderrCaptured]) .then(function (_a) { var _b = tslib_1.__read(_a, 3), _ = _b[0], stdout = _b[1], stderr = _b[2]; return { exitCode: processExitCode, stdout: stdout, stderr: stderr, processId: childProcess.pid, }; }) .catch(function (error) { if (typeof options.captureError === "function") { options.captureError(error.toString()); } return { error: error }; }); }; return RealRunner; }()); exports.RealRunner = RealRunner; function getExecutionFolderPath(options) { return (options && options.executionFolderPath) || process.cwd(); } /** * A fake command runner. */ var FakeRunner = /** @class */ (function () { function FakeRunner(innerRunner) { this.fakeCommands = []; this.innerRunner = innerRunner || new RealRunner(); this.unrecognizedCommand = function (command, options) { return Promise.reject(new Error("No FakeRunner result has been registered for the command \"" + commandToString(command) + "\" at \"" + getExecutionFolderPath(options) + "\".")); }; } /** * Set the function to invoke when an unrecognized command is run. * @param unrecognizedCommandHandler The function to call when an unrecognized command is run. */ FakeRunner.prototype.onUnrecognizedCommand = function (unrecognizedCommandHandler) { this.unrecognizedCommand = unrecognizedCommandHandler; }; /** * Configure this FakeRunner so that all unrecognized commands will be passed through to its * inner runner. */ FakeRunner.prototype.passthroughUnrecognized = function () { var _this = this; this.onUnrecognizedCommand(function (command, options) { return _this.innerRunner.run(command, options); }); }; /** * Set the fake result to return when the provided command is run. * @param command The command to fake. */ FakeRunner.prototype.set = function (command) { this.fakeCommands.push(command); }; /** * Indicate that when this Runner attempts to run the provided commandString it should just pass * the commandString through to the inner runner. * @param commandString The commandString to pass through to the inner runner. */ FakeRunner.prototype.passthrough = function (command, executionFolderPath) { var _this = this; this.set({ executable: command.executable, args: command.args, executionFolderPath: executionFolderPath, result: function () { return _this.innerRunner.run(command, { executionFolderPath: executionFolderPath }); } }); }; FakeRunner.prototype.run = function (command, options) { return tslib_1.__awaiter(this, void 0, void 0, function () { var commandString, executionFolderPath, fakeCommand, result, runResult; return tslib_1.__generator(this, function (_a) { commandString = commandToString(command); executionFolderPath = getExecutionFolderPath(options); fakeCommand = arrays_1.last(this.fakeCommands, function (registeredFakeCommand) { return commandString === commandToString(registeredFakeCommand) && (!registeredFakeCommand.executionFolderPath || executionFolderPath === registeredFakeCommand.executionFolderPath); }); if (!fakeCommand) { result = Promise.resolve(this.unrecognizedCommand(command, options)); } else { runResult = fakeCommand.result; if (!runResult) { runResult = { exitCode: 0 }; } else if (typeof runResult === "function") { runResult = runResult(); } result = Promise.resolve(runResult); } return [2 /*return*/, result]; }); }); }; return FakeRunner; }()); exports.FakeRunner = FakeRunner; /** * Get an array of string arguments from the provided args. * @param args The args string or array of strings. */ function getArgsArray(args) { var argsArray = []; if (typeof args === "string") { argsArray.push.apply(argsArray, tslib_1.__spread(args.split(" "))); } else if (args) { argsArray.push.apply(argsArray, tslib_1.__spread(args)); } return argsArray; } exports.getArgsArray = getArgsArray; /** * Get the showResult function that will determine whether the command's result will be logged. * @param showResult The showResult property from the command's RunOptions. */ function getShowResultFunction(showResult) { var result; if (showResult === undefined) { result = function (result) { return result.exitCode !== 0; }; } else if (typeof showResult === "boolean") { result = function () { return !!showResult; }; } else { result = showResult; } return result; } exports.getShowResultFunction = getShowResultFunction; function logCommand(command, options) { return tslib_1.__awaiter(this, void 0, void 0, function () { var commandString; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: if (!(options && options.log && (options.showCommand == undefined || options.showCommand))) return [3 /*break*/, 2]; commandString = commandToString(command); if (options.executionFolderPath) { commandString = options.executionFolderPath + ": " + commandString; } return [4 /*yield*/, Promise.resolve(options.log(commandString))]; case 1: _a.sent(); _a.label = 2; case 2: return [2 /*return*/]; } }); }); } exports.logCommand = logCommand; function logEnvironmentVariables(options) { return tslib_1.__awaiter(this, void 0, void 0, function () { var _a, _b, _c, entryName, entryValue, e_2_1; var e_2, _d; return tslib_1.__generator(this, function (_e) { switch (_e.label) { case 0: if (!(options && options.log && options.environmentVariables && options.showEnvironmentVariables)) return [3 /*break*/, 9]; return [4 /*yield*/, options.log("Environment Variables:")]; case 1: _e.sent(); _e.label = 2; case 2: _e.trys.push([2, 7, 8, 9]); _a = tslib_1.__values(Object.entries(options.environmentVariables)), _b = _a.next(); _e.label = 3; case 3: if (!!_b.done) return [3 /*break*/, 6]; _c = tslib_1.__read(_b.value, 2), entryName = _c[0], entryValue = _c[1]; return [4 /*yield*/, options.log(" \"" + entryName + "\": \"" + entryValue + "\"")]; case 4: _e.sent(); _e.label = 5; case 5: _b = _a.next(); return [3 /*break*/, 3]; case 6: return [3 /*break*/, 9]; case 7: e_2_1 = _e.sent(); e_2 = { error: e_2_1 }; return [3 /*break*/, 9]; case 8: try { if (_b && !_b.done && (_d = _a.return)) _d.call(_a); } finally { if (e_2) throw e_2.error; } return [7 /*endfinally*/]; case 9: return [2 /*return*/]; } }); }); } exports.logEnvironmentVariables = logEnvironmentVariables; function logResult(result, options) { return tslib_1.__awaiter(this, void 0, void 0, function () { var showResult; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: if (!(options && options.log)) return [3 /*break*/, 10]; showResult = getShowResultFunction(options.showResult); if (!showResult(result)) return [3 /*break*/, 10]; return [4 /*yield*/, Promise.resolve(options.log("Exit Code: " + result.exitCode))]; case 1: _a.sent(); if (!(result.stdout && (options.captureOutput === true || options.captureOutput === undefined))) return [3 /*break*/, 4]; return [4 /*yield*/, Promise.resolve(options.log("Output:"))]; case 2: _a.sent(); return [4 /*yield*/, Promise.resolve(options.log(result.stdout))]; case 3: _a.sent(); _a.label = 4; case 4: if (!(result.stderr && (options.captureError === true || options.captureError === undefined))) return [3 /*break*/, 7]; return [4 /*yield*/, Promise.resolve(options.log("Error:"))]; case 5: _a.sent(); return [4 /*yield*/, Promise.resolve(options.log(result.stderr))]; case 6: _a.sent(); _a.label = 7; case 7: if (!(result.error && (options.captureError === true || options.captureError === undefined))) return [3 /*break*/, 10]; return [4 /*yield*/, Promise.resolve(options.log("Error:"))]; case 8: _a.sent(); return [4 /*yield*/, Promise.resolve(options.log(JSON.stringify(result.error, undefined, 2)))]; case 9: _a.sent(); _a.label = 10; case 10: return [2 /*return*/]; } }); }); } exports.logResult = logResult; function getChildProcessStdio(options) { return [ "inherit", options.captureOutput === false ? "ignore" : "pipe", options.captureError === false ? "ignore" : "pipe" ]; } exports.getChildProcessStdio = getChildProcessStdio; /** * Run the provided command asynchronously. * @param command The command to run. * @param args The arguments to provide to the command. */ function run(command, args, options) { if (options === void 0) { options = {}; } return tslib_1.__awaiter(this, void 0, void 0, function () { var runner, result; var _a; return tslib_1.__generator(this, function (_b) { switch (_b.label) { case 0: if (typeof command === "string") { command = { executable: command, }; } if (!command.args) { command.args = []; } if (args) { (_a = command.args).push.apply(_a, tslib_1.__spread(args)); } runner = options.runner || new RealRunner(); return [4 /*yield*/, logCommand(command, options)]; case 1: _b.sent(); return [4 /*yield*/, logEnvironmentVariables(options)]; case 2: _b.sent(); return [4 /*yield*/, runner.run(command, options)]; case 3: result = _b.sent(); return [4 /*yield*/, logResult(result, options)]; case 4: _b.sent(); if (options.throwOnError && result.exitCode) { throw new Error(command.executable + " " + command.args.join(" ") + " " + (result.stderr || "")); } return [2 /*return*/, result]; } }); }); } exports.run = run; //# sourceMappingURL=run.js.map