@travetto/exec
Advanced tools
Comparing version 0.0.15 to 0.0.16
@@ -17,3 +17,3 @@ { | ||
}, | ||
"version": "0.0.15" | ||
"version": "0.0.16" | ||
} |
@@ -7,6 +7,4 @@ travetto: Exec | ||
- Allows for running a single command | ||
- Allows for running commands through a pool of workers | ||
- Defaults to `cross-spawn` where possible. | ||
- Provides constructs for managing IPC (inter-process communication) | ||
- Allows for running docker operations with proper handling of execution | ||
- Will catch when the docker container has run away, and will terminate within timeouts |
@@ -0,15 +1,16 @@ | ||
import * as child_process from 'child_process'; | ||
import * as util from 'util'; | ||
import * as fs from 'fs'; | ||
import * as path from 'path'; | ||
import * as util from 'util'; | ||
import * as child_process from 'child_process'; | ||
import { CommonProcess, ChildOptions, ExecutionResult } from './types'; | ||
import { CommonProcess, ChildOptions } from './types'; | ||
import { spawn, WithOpts } from './util'; | ||
import { scanDir, Entry, rimraf } from '@travetto/base'; | ||
import { rimraf } from '@travetto/base'; | ||
const writeFile = util.promisify(fs.writeFile); | ||
const mkTempDir = util.promisify(fs.mkdtemp); | ||
const mkdir = util.promisify(fs.mkdir); | ||
const writeFile = util.promisify(fs.writeFile); | ||
function exec(command: string, opts?: WithOpts<child_process.SpawnOptions>) { | ||
return spawn(command, opts)[1]; | ||
return spawn(command, { shell: false, ...opts })[1]; | ||
} | ||
@@ -19,8 +20,5 @@ | ||
private tempDir: string = '/tmp'; | ||
private volume: string = '/var/workspace'; | ||
private cmd: string = 'docker'; | ||
private _proc: CommonProcess; | ||
private workspace: string; | ||
private container: string; | ||
@@ -31,7 +29,20 @@ | ||
public volumes: { [key: string]: string } = {}; | ||
private tempVolumes: { [key: string]: string } = {} | ||
public workingDir: string; | ||
constructor(private image: string, container?: string) { | ||
this.container = container || `${image}-${Date.now()}-${Math.random()}`.replace(/[^A-Z0-9a-z\-]/g, ''); | ||
this.workspace = `${this.tempDir}/${this.container}`; | ||
} | ||
async createTempVolume(volume: string) { | ||
const p = await mkTempDir(`/tmp/${this.image.replace(/[^A-Za-z0-9]/g, '_')}`); | ||
this.tempVolumes[p] = volume; | ||
return p; | ||
} | ||
mapVolume(local: string, volume: string) { | ||
this.volumes[local] = volume; | ||
} | ||
get pid() { | ||
@@ -41,3 +52,3 @@ return this._proc !== undefined ? this._proc.pid : -1; | ||
async create() { | ||
async run(...args: string[]) { | ||
// Kill existing | ||
@@ -47,13 +58,31 @@ await this.destroy(); | ||
// Make temp dirs | ||
const mkdirAll = Object.keys(this.tempVolumes).map(x => mkdir(x).catch(e => { })); | ||
await Promise.all(mkdirAll); | ||
let prom; | ||
try { | ||
await mkdir(this.workspace); | ||
} catch (e) { /* ignore */ } | ||
const finalArgs = [this.cmd, 'run', `--name=${this.container}`]; | ||
if (this.workingDir) { | ||
finalArgs.push('-w', this.workingDir); | ||
} | ||
for (const k of Object.keys(this.volumes)) { | ||
finalArgs.push('-v', `${k}:${this.volumes[k]}`) | ||
} | ||
for (const k of Object.keys(this.tempVolumes)) { | ||
finalArgs.push('-v', `${k}:${this.tempVolumes[k]}`); | ||
} | ||
try { | ||
await exec(`${this.cmd} create --name=${this.container} -it -v ${this.workspace}:${this.volume} -w ${this.volume} ${this.image}`); | ||
await exec(`${this.cmd} start ${this.container}`); | ||
console.debug('Running', [...finalArgs, this.image, ...args]); | ||
[this._proc, prom] = spawn([...finalArgs, this.image, ...args].join(' '), { shell: false }); | ||
} catch (e) { | ||
if (e.killed) { | ||
this.evict = true; | ||
} | ||
throw e; | ||
} | ||
return this; | ||
return prom; | ||
} | ||
@@ -75,22 +104,11 @@ | ||
} catch (e) { /* ignore */ } | ||
await this.cleanup(); | ||
} | ||
async exec(cmd: string, options: ChildOptions = {}) { | ||
try { | ||
const [proc, prom] = spawn(`${this.cmd} exec ${this.container} ${cmd}`, options) | ||
this._proc = proc; | ||
await prom; | ||
} catch (e) { | ||
if (e.killed) { | ||
this.evict = true; | ||
} | ||
} | ||
} | ||
async initRun(files?: { name: string, content: string }[]) { | ||
async writeFiles(dir: string, files?: { name: string, content: string }[]) { | ||
await this.cleanup(); | ||
if (files) { | ||
for (const { name, content } of files) { | ||
const f = [this.workspace, name].join(path.sep); | ||
const f = [dir, name].join(path.sep); | ||
await writeFile(f, content, { mode: '755' }); | ||
@@ -103,5 +121,4 @@ } | ||
async cleanup() { | ||
try { | ||
await rimraf(`${this.workspace}/*`); | ||
} catch (e) { /* ignore */ } | ||
const temps = Object.keys(this.tempVolumes).map(x => rimraf(x).catch(e => { })); | ||
await Promise.all(temps); | ||
} | ||
@@ -108,0 +125,0 @@ |
export * from './execution'; | ||
export * from './local'; | ||
export * from './child'; | ||
export * from './util'; | ||
export * from './util'; | ||
export * from './docker'; |
#!/usr/bin/env node | ||
require('@travetto/base/bootstrap').run() | ||
.then(x => require(process.env.SRC || './simple.parent.ts')); | ||
.then(x => require(process.env.SRC || './docker.ts')); |
@@ -33,3 +33,2 @@ import { ChildExecution } from '../src'; | ||
await pool.shutdown(); | ||
process.exit(0); | ||
}); |
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
14198
17
443
9