UNPKG

@sprucelabs/spruce-cli

Version:

Command line interface for building Spruce skills.

157 lines • 6.21 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const child_process_1 = require("child_process"); const error_1 = __importDefault(require("@sprucelabs/error")); const spruce_skill_utils_1 = require("@sprucelabs/spruce-skill-utils"); const escapeRegExp_1 = __importDefault(require("lodash/escapeRegExp")); const string_argv_1 = __importDefault(require("string-argv")); const tree_kill_1 = __importDefault(require("tree-kill")); const SpruceError_1 = __importDefault(require("../errors/SpruceError")); process.setMaxListeners(100); class CommandServiceImpl { cwd; activeChildProcess; ignoreCloseErrors = false; static fakeResponses = []; static commandsRunCapturedByMockResponses = []; constructor(cwd) { this.cwd = cwd; } getCwd() { return this.cwd; } setCwd(cwd) { this.cwd = cwd; } async execute(cmd, options) { const cwd = this.cwd; const args = options?.args || (0, string_argv_1.default)(cmd); const executable = options?.args ? cmd : args.shift(); const boundKill = this.kill.bind(this); if (!executable) { throw new Error('Bad params sent to command service'); } const { mockResponse, mockKey } = this.getMockResponse(executable, args); if (mockResponse) { CommandServiceImpl.commandsRunCapturedByMockResponses.push(mockKey); mockResponse.callback?.(executable, args); if (mockResponse.code !== 0) { throw new SpruceError_1.default({ code: 'EXECUTING_COMMAND_FAILED', cmd: `${executable} ${args.join(' ')}`, cwd, stdout: mockResponse.stdout, stderr: mockResponse.stderr, }); } return { stdout: mockResponse.stdout ?? '' }; } process.on('exit', boundKill); return new Promise((resolve, reject) => { let stdout = ''; let stderr = ''; const spawnOptions = options?.shouldStream ? { stdio: 'inherit', cwd, env: { PATH: process.env.PATH, IS_CLI: 'true', FORCE_COLOR: options?.forceColor ? '1' : '0', ...options?.env, }, } : { cwd, env: { PATH: process.env.PATH, IS_CLI: 'true', FORCE_COLOR: options?.forceColor ? '1' : '0', ...options?.env, }, shell: true, ...options?.spawnOptions, }; const child = (0, child_process_1.spawn)(executable, args, spawnOptions); this.activeChildProcess = child; if (options?.outStream) { child.stdout?.pipe(options.outStream); } child.stdout?.addListener('data', (data) => { options?.onData?.(data.toString()); stdout += data; }); child.stderr?.addListener('data', (data) => { options?.onError?.(data.toString()); stderr += data; }); const closeHandler = (code) => { process.off('exit', boundKill); if (!this.activeChildProcess) { return; } this.activeChildProcess = undefined; setTimeout(() => { child.stdout?.removeAllListeners(); child.stderr?.removeAllListeners(); child.removeAllListeners(); if (code === 0 || this.ignoreCloseErrors || options?.ignoreErrors) { resolve({ stdout }); this.ignoreCloseErrors = false; } else { if (stderr.search((0, escapeRegExp_1.default)(spruce_skill_utils_1.ERROR_DIVIDER)) > -1) { const stderrParts = stderr.split(spruce_skill_utils_1.ERROR_DIVIDER); const err = error_1.default.parse(stderrParts[1], SpruceError_1.default); reject(err); return; } reject(new SpruceError_1.default({ code: 'EXECUTING_COMMAND_FAILED', cmd: `${executable} ${args.join(' ')}`, cwd, stdout, stderr, })); } }, 0); }; child.addListener('close', closeHandler); child.addListener('exit', closeHandler); }); } kill = () => { if (this.activeChildProcess?.pid) { this.ignoreCloseErrors = true; (0, tree_kill_1.default)(this.activeChildProcess.pid, 'SIGTERM'); } }; pid = () => { return this.activeChildProcess?.pid; }; getMockResponse(executable, args) { const mockKey = `${executable} ${args.join(' ')}`.trim(); const commands = CommandServiceImpl.fakeResponses; const match = commands.find((r) => r.command instanceof RegExp ? mockKey.search(r.command) > -1 : r.command.replace(/ +/gis, '') === mockKey.replace(/ +/gis, '')); return { mockResponse: match?.response, mockKey }; } static fakeCommand(command, response) { this.fakeResponses.unshift({ command, response, }); } static clearFakedResponses() { this.fakeResponses = []; } } exports.default = CommandServiceImpl; //# sourceMappingURL=CommandService.js.map