@travetto/exec
Advanced tools
Comparing version 0.0.39 to 0.1.1
@@ -7,4 +7,4 @@ { | ||
"dependencies": { | ||
"@travetto/base": "^0.0.162", | ||
"@travetto/pool": "^0.0.16" | ||
"@travetto/base": "^0.1.1", | ||
"@travetto/pool": "^0.1.1" | ||
}, | ||
@@ -27,3 +27,3 @@ "description": "Common wrapper around process execution with high level docker support.", | ||
}, | ||
"version": "0.0.39" | ||
"version": "0.1.1" | ||
} |
import * as child_process from 'child_process'; | ||
import * as exec from './util'; | ||
import { ExecUtil } from './util'; | ||
import { ChildOptions, ExecutionEvent } from './types'; | ||
@@ -13,3 +13,3 @@ import { Execution } from './execution'; | ||
_init() { | ||
const op: typeof exec.fork = (this.fork ? exec.fork : exec.spawn); | ||
const op: typeof ExecUtil.fork = (this.fork ? ExecUtil.fork : ExecUtil.spawn); | ||
@@ -16,0 +16,0 @@ const finalOpts: ChildOptions = { |
@@ -0,4 +1,4 @@ | ||
import { Env } from '@travetto/base'; | ||
import { ExecUtil } from './util'; | ||
import { DockerContainer } from './docker'; | ||
import { AppEnv } from '@travetto/base'; | ||
import { spawn } from './util'; | ||
import { ExecutionResult, CommonProcess } from './types'; | ||
@@ -22,3 +22,3 @@ | ||
async _init() { | ||
const canUseDocker = AppEnv.docker && (this.config.docker === undefined || !!this.config.docker); | ||
const canUseDocker = Env.docker && (this.config.docker === undefined || !!this.config.docker); | ||
const useDocker = canUseDocker && (!this.config.checkForLocal || !(await this.config.checkForLocal())); | ||
@@ -52,3 +52,3 @@ | ||
const cmd = this.config.processCommand ? this.config.processCommand(args) : args; | ||
exec = spawn(cmd.join(' '), { quiet: true }); | ||
exec = ExecUtil.spawn(cmd.join(' '), { quiet: true }); | ||
} | ||
@@ -55,0 +55,0 @@ return exec as [CommonProcess, Promise<ExecutionResult>]; |
@@ -7,5 +7,6 @@ import * as child_process from 'child_process'; | ||
import { Shutdown, ScanFs } from '@travetto/base'; | ||
import { CommonProcess, ExecutionResult } from './types'; | ||
import { spawn, WithOpts } from './util'; | ||
import { Shutdown, rimraf } from '@travetto/base'; | ||
import { ExecUtil, WithOpts } from './util'; | ||
@@ -16,3 +17,3 @@ const writeFile = util.promisify(fs.writeFile); | ||
function exec(command: string, opts?: WithOpts<child_process.SpawnOptions>) { | ||
return spawn(command, { shell: false, ...opts })[1]; | ||
return ExecUtil.spawn(command, { shell: false, ...opts })[1]; | ||
} | ||
@@ -81,3 +82,3 @@ | ||
]).join(' '); | ||
const [proc, prom] = spawn(cmd, { shell: false }); | ||
const [proc, prom] = ExecUtil.spawn(cmd, { shell: false }); | ||
if (op !== 'run' && op !== 'exec') { | ||
@@ -264,3 +265,3 @@ prom.catch(e => { this.evict = true; }); | ||
const temps = Object.keys(this.tempVolumes).map(x => rimraf(x).catch((e: any) => { })); | ||
const temps = Object.keys(this.tempVolumes).map(x => ScanFs.rimraf(x).catch((e: any) => { })); | ||
Promise.all(temps); | ||
@@ -287,3 +288,3 @@ | ||
console.debug('Cleaning', this.image, this.container); | ||
const temps = Object.keys(this.tempVolumes).map(x => rimraf(x).catch((e: any) => { })); | ||
const temps = Object.keys(this.tempVolumes).map(x => ScanFs.rimraf(x).catch((e: any) => { })); | ||
await Promise.all(temps); | ||
@@ -290,0 +291,0 @@ } |
@@ -0,3 +1,4 @@ | ||
import { Env } from '@travetto/base'; | ||
import { CommonProcess, ExecutionEvent } from './types'; | ||
import { AppEnv } from '@travetto/base'; | ||
@@ -36,3 +37,3 @@ export class Execution<U extends ExecutionEvent = ExecutionEvent, T extends CommonProcess = CommonProcess> { | ||
send(eventType: string, data?: any) { | ||
if (AppEnv.trace) { | ||
if (Env.trace) { | ||
console.trace(process.pid, 'SENDING', eventType, data); | ||
@@ -83,3 +84,3 @@ } | ||
const fn = (e: U) => { | ||
if (AppEnv.trace) { | ||
if (Env.trace) { | ||
console.trace(process.pid, 'RECEIVING', e.type, e); | ||
@@ -86,0 +87,0 @@ } |
175
src/util.ts
@@ -5,112 +5,115 @@ import * as cp from 'child_process'; | ||
export function enhanceProcess(p: cp.ChildProcess, options: ExecutionOptions, cmd: string) { | ||
const timeout = options.timeout; | ||
export type WithOpts<T> = T & ExecutionOptions; | ||
const prom = new Promise<ExecutionResult>((resolve, reject) => { | ||
let stdout = ''; | ||
let stderr = ''; | ||
let timer: any; | ||
let done = false; | ||
const finish = async function (result: ExecutionResult) { | ||
if (done) { | ||
return; | ||
} | ||
if (timer) { | ||
clearTimeout(timer); | ||
} | ||
done = true; | ||
export class ExecUtil { | ||
if (!result.valid) { | ||
reject(new BaseError(`Error executing ${cmd}: ${result.message || 'failed'}`, result)); | ||
} else { | ||
resolve(result); | ||
} | ||
}; | ||
private static getArgs(cmd: string) { | ||
let args: string[] = []; | ||
if (!options.quiet) { | ||
p.stdout.on('data', (d: string) => stdout += `${d}\n`); | ||
p.stderr.on('data', (d: string) => stderr += `${d}\n`); | ||
if (cmd.indexOf(' ') > 0) { | ||
[cmd, ...args] = cmd.split(' '); | ||
} | ||
p.on('error', (err: Error) => | ||
finish({ code: 1, stdout, stderr, message: err.message, valid: false })); | ||
console.debug('exec:', [cmd, ...args].join(' ')); | ||
return { cmd, args }; | ||
} | ||
p.on('close', (code: number) => | ||
finish({ code, stdout, stderr, valid: code === null || code === 0 })); | ||
static enhanceProcess(p: cp.ChildProcess, options: ExecutionOptions, cmd: string) { | ||
const timeout = options.timeout; | ||
if (timeout) { | ||
timer = setTimeout(async x => { | ||
if (options.timeoutKill) { | ||
await options.timeoutKill(p); | ||
const prom = new Promise<ExecutionResult>((resolve, reject) => { | ||
let stdout = ''; | ||
let stderr = ''; | ||
let timer: any; | ||
let done = false; | ||
const finish = async function (result: ExecutionResult) { | ||
if (done) { | ||
return; | ||
} | ||
if (timer) { | ||
clearTimeout(timer); | ||
} | ||
done = true; | ||
if (!result.valid) { | ||
reject(new BaseError(`Error executing ${cmd}: ${result.message || 'failed'}`, result)); | ||
} else { | ||
p.kill('SIGKILL'); | ||
resolve(result); | ||
} | ||
finish({ code: 1, stderr, stdout, message: `Execution timed out after: ${timeout} ms`, valid: false, killed: true }); | ||
}, timeout); | ||
} | ||
}); | ||
}; | ||
return prom; | ||
} | ||
if (!options.quiet) { | ||
p.stdout.on('data', (d: string) => stdout += `${d}\n`); | ||
p.stderr.on('data', (d: string) => stderr += `${d}\n`); | ||
} | ||
function getArgs(cmd: string) { | ||
let args: string[] = []; | ||
p.on('error', (err: Error) => | ||
finish({ code: 1, stdout, stderr, message: err.message, valid: false })); | ||
if (cmd.indexOf(' ') > 0) { | ||
[cmd, ...args] = cmd.split(' '); | ||
} | ||
p.on('close', (code: number) => | ||
finish({ code, stdout, stderr, valid: code === null || code === 0 })); | ||
console.debug('exec:', [cmd, ...args].join(' ')); | ||
return { cmd, args }; | ||
} | ||
if (timeout) { | ||
timer = setTimeout(async x => { | ||
if (options.timeoutKill) { | ||
await options.timeoutKill(p); | ||
} else { | ||
p.kill('SIGKILL'); | ||
} | ||
finish({ code: 1, stderr, stdout, message: `Execution timed out after: ${timeout} ms`, valid: false, killed: true }); | ||
}, timeout); | ||
} | ||
}); | ||
export type WithOpts<T> = T & ExecutionOptions; | ||
return prom; | ||
} | ||
export function spawn(cmdStr: string, options: WithOpts<cp.SpawnOptions> = {}): [cp.ChildProcess, Promise<ExecutionResult>] { | ||
const { cmd, args } = getArgs(cmdStr); | ||
const p = cp.spawn(cmd, args, { shell: true, ...(options as cp.SpawnOptions) }); | ||
return [p, enhanceProcess(p, options, cmdStr)]; | ||
} | ||
static spawn(cmdStr: string, options: WithOpts<cp.SpawnOptions> = {}): [cp.ChildProcess, Promise<ExecutionResult>] { | ||
const { cmd, args } = ExecUtil.getArgs(cmdStr); | ||
const p = cp.spawn(cmd, args, { shell: true, ...(options as cp.SpawnOptions) }); | ||
return [p, ExecUtil.enhanceProcess(p, options, cmdStr)]; | ||
} | ||
export function fork(cmdStr: string, options: WithOpts<cp.ForkOptions> = {}): [cp.ChildProcess, Promise<ExecutionResult>] { | ||
const { cmd, args } = getArgs(cmdStr); | ||
const p = cp.fork(cmd, args, options); | ||
return [p, enhanceProcess(p, options, cmdStr)]; | ||
} | ||
static fork(cmdStr: string, options: WithOpts<cp.ForkOptions> = {}): [cp.ChildProcess, Promise<ExecutionResult>] { | ||
const { cmd, args } = ExecUtil.getArgs(cmdStr); | ||
const p = cp.fork(cmd, args, options); | ||
return [p, ExecUtil.enhanceProcess(p, options, cmdStr)]; | ||
} | ||
export function exec(cmd: string, options: WithOpts<cp.ExecOptions> = {}): [cp.ChildProcess, Promise<ExecutionResult>] { | ||
const p = cp.exec(cmd, options); | ||
return [p, enhanceProcess(p, options, cmd)]; | ||
} | ||
static exec(cmd: string, options: WithOpts<cp.ExecOptions> = {}): [cp.ChildProcess, Promise<ExecutionResult>] { | ||
const p = cp.exec(cmd, options); | ||
return [p, ExecUtil.enhanceProcess(p, options, cmd)]; | ||
} | ||
export function serializeError(e: Error | any) { | ||
let error: any = undefined; | ||
static serializeError(e: Error | any) { | ||
let error: any = undefined; | ||
if (e) { | ||
error = {}; | ||
for (const k of Object.keys(e)) { | ||
error[k] = e[k]; | ||
if (e) { | ||
error = {}; | ||
for (const k of Object.keys(e)) { | ||
error[k] = e[k]; | ||
} | ||
error.$ = true; | ||
error.message = e.message; | ||
error.stack = e.stack; | ||
error.name = e.name; | ||
} | ||
error.$ = true; | ||
error.message = e.message; | ||
error.stack = e.stack; | ||
error.name = e.name; | ||
return error; | ||
} | ||
return error; | ||
} | ||
export function deserializeError(e: any) { | ||
if (e && e.$) { | ||
const err = new Error(); | ||
for (const k of Object.keys(e)) { | ||
(err as any)[k] = e[k]; | ||
static deserializeError(e: any) { | ||
if (e && e.$) { | ||
const err = new Error(); | ||
for (const k of Object.keys(e)) { | ||
(err as any)[k] = e[k]; | ||
} | ||
err.message = e.message; | ||
err.stack = e.stack; | ||
err.name = e.name; | ||
return err; | ||
} else if (e) { | ||
return e; | ||
} | ||
err.message = e.message; | ||
err.stack = e.stack; | ||
err.name = e.name; | ||
return err; | ||
} else if (e) { | ||
return e; | ||
} | ||
} |
@@ -1,4 +0,5 @@ | ||
import { ChildExecution } from '../src'; | ||
import { ConcurrentPool, ArrayDataSource, IteratorDataSource } from '@travetto/pool'; | ||
import { ChildExecution } from '../src'; | ||
const pool = new ConcurrentPool<ChildExecution>(async () => { | ||
@@ -5,0 +6,0 @@ console.log('Initializing child'); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
26439
730
+ Added@travetto/base@0.1.4(transitive)
+ Added@travetto/pool@0.1.4(transitive)
+ Addedtslib@1.14.1(transitive)
- Removed@travetto/base@0.0.162(transitive)
- Removed@travetto/pool@0.0.16(transitive)
Updated@travetto/base@^0.1.1
Updated@travetto/pool@^0.1.1