@ionic/cli-utils
Version:
Ionic CLI Utils
172 lines (171 loc) • 8.39 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const cli_framework_1 = require("@ionic/cli-framework");
const process_1 = require("@ionic/cli-framework/utils/process");
const shell_1 = require("@ionic/cli-framework/utils/shell");
const streams_1 = require("@ionic/cli-framework/utils/streams");
const chalk_1 = require("chalk");
const Debug = require("debug");
const path = require("path");
const split2 = require("split2");
const guards_1 = require("../guards");
const errors_1 = require("./errors");
const debug = Debug('ionic:cli-utils:lib:shell');
class Shell {
constructor(e, options) {
this.e = e;
this.alterPath = options && options.alterPath ? options.alterPath : (p) => p;
}
run(command, args, _a) {
var { stream, killOnExit = true, showCommand = true, showError = true, fatalOnNotFound = true, fatalOnError = true, truncateErrorOutput } = _a, crossSpawnOptions = tslib_1.__rest(_a, ["stream", "killOnExit", "showCommand", "showError", "fatalOnNotFound", "fatalOnError", "truncateErrorOutput"]);
return tslib_1.__awaiter(this, void 0, void 0, function* () {
this.prepareSpawnOptions(crossSpawnOptions);
const cmd = new shell_1.ShellCommand(command, args, crossSpawnOptions);
const fullCmd = cmd.bashify();
const truncatedCmd = fullCmd.length > 80 ? fullCmd.substring(0, 80) + '...' : fullCmd;
if (showCommand && this.e.log.level >= cli_framework_1.LOGGER_LEVELS.INFO) {
this.e.log.rawmsg(`> ${chalk_1.default.green(fullCmd)}`);
}
const ws = stream ? stream : this.e.log.createWriteStream(cli_framework_1.LOGGER_LEVELS.INFO, false);
try {
const promise = cmd.run();
if (promise.p.stdout) {
const s = streams_1.combineStreams(split2(), ws);
// TODO: https://github.com/angular/angular-cli/issues/10922
s.on('error', (err) => {
debug('Error in subprocess stdout pipe: %o', err);
});
promise.p.stdout.pipe(s);
}
if (promise.p.stderr) {
const s = streams_1.combineStreams(split2(), ws);
// TODO: https://github.com/angular/angular-cli/issues/10922
s.on('error', (err) => {
debug('Error in subprocess stderr pipe: %o', err);
});
promise.p.stderr.pipe(s);
}
if (killOnExit) {
process_1.onBeforeExit(() => tslib_1.__awaiter(this, void 0, void 0, function* () {
if (promise.p.pid) {
yield process_1.killProcessTree(promise.p.pid);
}
}));
}
yield promise;
}
catch (e) {
if (e instanceof cli_framework_1.ShellCommandError && e.code === cli_framework_1.ERROR_SHELL_COMMAND_NOT_FOUND) {
if (fatalOnNotFound) {
throw new errors_1.FatalException(`Command not found: ${chalk_1.default.green(command)}`, 127);
}
else {
throw e;
}
}
if (!guards_1.isExitCodeException(e)) {
throw e;
}
let err = e.message || '';
if (truncateErrorOutput && err.length > truncateErrorOutput) {
err = `${chalk_1.default.bold('(truncated)')} ... ` + err.substring(err.length - truncateErrorOutput);
}
const publicErrorMsg = (`An error occurred while running subprocess ${chalk_1.default.green(command)}.\n` +
`${chalk_1.default.green(truncatedCmd)} exited with exit code ${e.exitCode}.\n\n` +
`Re-running this command with the ${chalk_1.default.green('--verbose')} flag may provide more information.`);
const privateErrorMsg = `Subprocess (${chalk_1.default.green(command)}) encountered an error (exit code ${e.exitCode}).`;
if (fatalOnError) {
if (showError) {
throw new errors_1.FatalException(publicErrorMsg, e.exitCode);
}
else {
throw new errors_1.FatalException(privateErrorMsg, e.exitCode);
}
}
else {
if (showError) {
this.e.log.error(publicErrorMsg);
}
}
throw e;
}
});
}
output(command, args, _a) {
var { fatalOnNotFound = true, fatalOnError = true, showError = true, showCommand = false } = _a, crossSpawnOptions = tslib_1.__rest(_a, ["fatalOnNotFound", "fatalOnError", "showError", "showCommand"]);
return tslib_1.__awaiter(this, void 0, void 0, function* () {
const cmd = new shell_1.ShellCommand(command, args, crossSpawnOptions);
const fullCmd = cmd.bashify();
const truncatedCmd = fullCmd.length > 80 ? fullCmd.substring(0, 80) + '...' : fullCmd;
if (showCommand && this.e.log.level >= cli_framework_1.LOGGER_LEVELS.INFO) {
this.e.log.rawmsg(`> ${chalk_1.default.green(fullCmd)}`);
}
try {
return yield cmd.output();
}
catch (e) {
if (e instanceof cli_framework_1.ShellCommandError && e.code === cli_framework_1.ERROR_SHELL_COMMAND_NOT_FOUND) {
if (fatalOnNotFound) {
throw new errors_1.FatalException(`Command not found: ${chalk_1.default.green(command)}`, 127);
}
else {
throw e;
}
}
if (!guards_1.isExitCodeException(e)) {
throw e;
}
const errorMsg = `An error occurred while running ${chalk_1.default.green(truncatedCmd)} (exit code ${e.exitCode})\n`;
if (fatalOnError) {
throw new errors_1.FatalException(errorMsg, e.exitCode);
}
else {
if (showError) {
this.e.log.error(errorMsg);
}
}
return '';
}
});
}
spawn(command, args, _a) {
var { showCommand = true } = _a, crossSpawnOptions = tslib_1.__rest(_a, ["showCommand"]);
this.prepareSpawnOptions(crossSpawnOptions);
const cmd = new shell_1.ShellCommand(command, args, crossSpawnOptions);
const p = cmd.spawn();
if (showCommand && this.e.log.level >= cli_framework_1.LOGGER_LEVELS.INFO) {
this.e.log.rawmsg(`> ${chalk_1.default.green(cmd.bashify())}`);
}
return p;
}
cmdinfo(command, args = []) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
const opts = {};
this.prepareSpawnOptions(opts);
const cmd = new shell_1.ShellCommand(command, args, opts);
try {
const out = yield cmd.output();
return out.split('\n').join(' ').trim();
}
catch (e) {
// no command info at this point
}
});
}
prepareSpawnOptions(options) {
// Create a `process.env`-type object from all key/values of `process.env`,
// then `options.env`, then add several key/values. PATH is supplemented
// with the `node_modules\.bin` folder in the project directory so that we
// can run binaries inside a project.
options.env = process_1.createProcessEnv(process.env, options.env, {
PATH: this.alterPath(process.env.PATH || ''),
FORCE_COLOR: chalk_1.default.enabled ? '1' : '0',
});
}
}
exports.Shell = Shell;
function prependNodeModulesBinToPath(projectDir, p) {
return path.resolve(projectDir, 'node_modules', '.bin') + path.delimiter + p;
}
exports.prependNodeModulesBinToPath = prependNodeModulesBinToPath;
;