pax_global_header00006660000000000000000000000064127751346360014530gustar00rootroot0000000000000052 comment=842be7c11a33c71177ea03ff12412047f3d8bd07 execa-0.5.0/000077500000000000000000000000001277513463600126175ustar00rootroot00000000000000execa-0.5.0/.editorconfig000066400000000000000000000002761277513463600153010ustar00rootroot00000000000000root = true [*] indent_style = tab end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true [{package.json,*.yml}] indent_style = space indent_size = 2 execa-0.5.0/.gitattributes000066400000000000000000000000351277513463600155100ustar00rootroot00000000000000* text=auto *.js text eol=lf execa-0.5.0/.gitignore000066400000000000000000000000421277513463600146030ustar00rootroot00000000000000node_modules .nyc_output coverage execa-0.5.0/.travis.yml000066400000000000000000000001661277513463600147330ustar00rootroot00000000000000language: node_js node_js: - '6' - '4' after_script: - 'cat coverage/lcov.info | ./node_modules/.bin/coveralls' execa-0.5.0/appveyor.yml000066400000000000000000000006011277513463600152040ustar00rootroot00000000000000environment: matrix: - nodejs_version: '6' - nodejs_version: '4' install: - ps: Install-Product node $env:nodejs_version - set CI=true - npm -g install npm@latest - set PATH=%APPDATA%\npm;%PATH% - npm install matrix: fast_finish: true build: off version: '{build}' shallow_clone: true clone_depth: 1 test_script: - node --version - npm --version - npm test execa-0.5.0/fixtures/000077500000000000000000000000001277513463600144705ustar00rootroot00000000000000execa-0.5.0/fixtures/error-message.js000077500000000000000000000001431277513463600176020ustar00rootroot00000000000000#!/usr/bin/env node 'use strict'; console.log('stdout'); console.error('stderr'); process.exit(2); execa-0.5.0/fixtures/exit000077500000000000000000000001111277513463600153600ustar00rootroot00000000000000#!/usr/bin/env node 'use strict'; process.exit(Number(process.argv[2])); execa-0.5.0/fixtures/fail000077500000000000000000000000641277513463600153310ustar00rootroot00000000000000#!/usr/bin/env node 'use strict'; process.exit(2); execa-0.5.0/fixtures/forever000077500000000000000000000001001277513463600160550ustar00rootroot00000000000000#!/usr/bin/env node 'use strict'; setTimeout(() => {}, 20000); execa-0.5.0/fixtures/max-buffer000077500000000000000000000002371277513463600164540ustar00rootroot00000000000000#!/usr/bin/env node 'use strict'; const output = process.argv[2]; const bytes = Number(process.argv[3]); process[output].write('.'.repeat(bytes - 1) + '\n'); execa-0.5.0/fixtures/non-executable000066400000000000000000000000421277513463600173200ustar00rootroot00000000000000#!/usr/bin/env node 'use strict'; execa-0.5.0/fixtures/noop000077500000000000000000000001001277513463600153600ustar00rootroot00000000000000#!/usr/bin/env node 'use strict'; console.log(process.argv[2]); execa-0.5.0/fixtures/noop-err000077500000000000000000000001021277513463600161500ustar00rootroot00000000000000#!/usr/bin/env node 'use strict'; console.error(process.argv[2]); execa-0.5.0/fixtures/stdin000077500000000000000000000001061277513463600155340ustar00rootroot00000000000000#!/usr/bin/env node 'use strict'; process.stdin.pipe(process.stdout); execa-0.5.0/fixtures/sub-process000077500000000000000000000001341277513463600166610ustar00rootroot00000000000000#!/usr/bin/env node 'use strict'; const m = require('../'); console.log(m('forever').pid); execa-0.5.0/fixtures/sub-process-false000077500000000000000000000001561277513463600177550ustar00rootroot00000000000000#!/usr/bin/env node 'use strict'; const m = require('../'); console.log(m('forever', {cleanup: false}).pid); execa-0.5.0/index.js000066400000000000000000000122501277513463600142640ustar00rootroot00000000000000'use strict'; const childProcess = require('child_process'); const util = require('util'); const crossSpawn = require('cross-spawn'); const stripEof = require('strip-eof'); const npmRunPath = require('npm-run-path'); const isStream = require('is-stream'); const _getStream = require('get-stream'); const onExit = require('signal-exit'); const errname = require('./lib/errname'); const TEN_MEGABYTES = 1000 * 1000 * 10; function handleArgs(cmd, args, opts) { let parsed; if (opts && opts.__winShell === true) { delete opts.__winShell; parsed = { command: cmd, args, options: opts, file: cmd, original: cmd }; } else { parsed = crossSpawn._parse(cmd, args, opts); } opts = Object.assign({ maxBuffer: TEN_MEGABYTES, stripEof: true, preferLocal: true, encoding: 'utf8', reject: true, cleanup: true }, parsed.options); if (opts.preferLocal) { opts.env = npmRunPath.env(opts); } return { cmd: parsed.command, args: parsed.args, opts }; } function handleInput(spawned, opts) { const input = opts.input; if (input === null || input === undefined) { return; } if (isStream(input)) { input.pipe(spawned.stdin); } else { spawned.stdin.end(input); } } function handleOutput(opts, val) { if (val && opts.stripEof) { val = stripEof(val); } return val; } function handleShell(fn, cmd, opts) { let file = '/bin/sh'; let args = ['-c', cmd]; opts = Object.assign({}, opts); if (process.platform === 'win32') { opts.__winShell = true; file = process.env.comspec || 'cmd.exe'; args = ['/s', '/c', `"${cmd}"`]; opts.windowsVerbatimArguments = true; } if (opts.shell) { file = opts.shell; delete opts.shell; } return fn(file, args, opts); } function getStream(process, stream, encoding, maxBuffer) { if (!process[stream]) { return null; } let ret; if (encoding) { ret = _getStream(process[stream], { encoding, maxBuffer }); } else { ret = _getStream.buffer(process[stream], {maxBuffer}); } return ret.catch(err => { err.stream = stream; err.message = `${stream} ${err.message}`; throw err; }); } const processDone = spawned => new Promise(resolve => { spawned.on('exit', (code, signal) => { resolve({code, signal}); }); spawned.on('error', err => { resolve({err}); }); }); module.exports = (cmd, args, opts) => { let joinedCmd = cmd; if (Array.isArray(args) && args.length > 0) { joinedCmd += ' ' + args.join(' '); } const parsed = handleArgs(cmd, args, opts); const encoding = parsed.opts.encoding; const maxBuffer = parsed.opts.maxBuffer; let spawned; try { spawned = childProcess.spawn(parsed.cmd, parsed.args, parsed.opts); } catch (err) { return Promise.reject(err); } let removeExitHandler; if (parsed.opts.cleanup) { removeExitHandler = onExit(() => { spawned.kill(); }); } const promise = Promise.all([ processDone(spawned), getStream(spawned, 'stdout', encoding, maxBuffer), getStream(spawned, 'stderr', encoding, maxBuffer) ]).then(arr => { const result = arr[0]; const stdout = arr[1]; const stderr = arr[2]; let err = result.err; const code = result.code; const signal = result.signal; if (removeExitHandler) { removeExitHandler(); } if (err || code !== 0 || signal !== null) { if (!err) { err = new Error(`Command failed: ${joinedCmd}\n${stderr}${stdout}`); err.code = code < 0 ? errname(code) : code; } // TODO: missing some timeout logic for killed // https://github.com/nodejs/node/blob/master/lib/child_process.js#L203 // err.killed = spawned.killed || killed; err.killed = err.killed || spawned.killed; err.stdout = stdout; err.stderr = stderr; err.failed = true; err.signal = signal || null; err.cmd = joinedCmd; if (!parsed.opts.reject) { return err; } throw err; } return { stdout: handleOutput(parsed.opts, stdout), stderr: handleOutput(parsed.opts, stderr), code: 0, failed: false, killed: false, signal: null, cmd: joinedCmd }; }); crossSpawn._enoent.hookChildProcess(spawned, parsed); handleInput(spawned, parsed.opts); spawned.then = promise.then.bind(promise); spawned.catch = promise.catch.bind(promise); return spawned; }; module.exports.stdout = function () { // TODO: set `stderr: 'ignore'` when that option is implemented return module.exports.apply(null, arguments).then(x => x.stdout); }; module.exports.stderr = function () { // TODO: set `stdout: 'ignore'` when that option is implemented return module.exports.apply(null, arguments).then(x => x.stderr); }; module.exports.shell = (cmd, opts) => handleShell(module.exports, cmd, opts); module.exports.sync = (cmd, args, opts) => { const parsed = handleArgs(cmd, args, opts); if (isStream(parsed.opts.input)) { throw new TypeError('The `input` option cannot be a stream in sync mode'); } const result = childProcess.spawnSync(parsed.cmd, parsed.args, parsed.opts); result.stdout = handleOutput(parsed.opts, result.stdout); result.stderr = handleOutput(parsed.opts, result.stderr); return result; }; module.exports.shellSync = (cmd, opts) => handleShell(module.exports.sync, cmd, opts); module.exports.spawn = util.deprecate(module.exports, 'execa.spawn() is deprecated. Use execa() instead.'); execa-0.5.0/lib/000077500000000000000000000000001277513463600133655ustar00rootroot00000000000000execa-0.5.0/lib/errname.js000066400000000000000000000017141277513463600153570ustar00rootroot00000000000000'use strict'; // The Node team wants to deprecate `process.bind(...)`. // https://github.com/nodejs/node/pull/2768 // // However, we need the 'uv' binding for errname support. // This is a defensive wrapper around it so `execa` will not fail entirely if it stops working someday. // // If this ever stops working. See: https://github.com/sindresorhus/execa/issues/31#issuecomment-215939939 for another possible solution. let uv; try { uv = process.binding('uv'); if (typeof uv.errname !== 'function') { throw new Error('uv.errname is not a function'); } } catch (err) { console.error('execa/lib/errname: unable to establish process.binding(\'uv\')', err); uv = null; } function errname(uv, code) { if (uv) { return uv.errname(code); } if (!(code < 0)) { throw new Error('err >= 0'); } return `Unknown system error ${code}`; } module.exports = code => errname(uv, code); // used for testing the fallback behavior module.exports.__test__ = errname; execa-0.5.0/license000066400000000000000000000021371277513463600141670ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) Sindre Sorhus (sindresorhus.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. execa-0.5.0/package.json000066400000000000000000000024761277513463600151160ustar00rootroot00000000000000{ "name": "execa", "version": "0.5.0", "description": "A better `child_process`", "license": "MIT", "repository": "sindresorhus/execa", "author": { "name": "Sindre Sorhus", "email": "sindresorhus@gmail.com", "url": "sindresorhus.com" }, "maintainers": [ { "name": "James Talmage", "email": "james@talmage.io", "url": "github.com/jamestalmage" } ], "engines": { "node": ">=4" }, "scripts": { "test": "xo && nyc ava" }, "files": [ "index.js", "lib" ], "keywords": [ "exec", "child", "process", "execute", "fork", "execfile", "spawn", "file", "shell", "bin", "binary", "binaries", "npm", "path", "local" ], "dependencies": { "cross-spawn": "^4.0.0", "get-stream": "^2.2.0", "is-stream": "^1.1.0", "npm-run-path": "^2.0.0", "signal-exit": "^3.0.0", "strip-eof": "^1.0.0" }, "devDependencies": { "ava": "*", "cat-names": "^1.0.2", "coveralls": "^2.11.9", "delay": "^1.3.1", "is-running": "^2.0.0", "nyc": "^8.3.0", "xo": "*" }, "nyc": { "reporter": [ "text", "lcov" ], "exclude": [ "node_modules", "**/fixtures/**", "**/test.js", "**/test/**" ] }, "xo": { "esnext": true } } execa-0.5.0/readme.md000066400000000000000000000111601277513463600143750ustar00rootroot00000000000000# execa [![Build Status: Linux](https://travis-ci.org/sindresorhus/execa.svg?branch=master)](https://travis-ci.org/sindresorhus/execa) [![Build status: Windows](https://ci.appveyor.com/api/projects/status/x5ajamxtjtt93cqv/branch/master?svg=true)](https://ci.appveyor.com/project/sindresorhus/execa/branch/master) [![Coverage Status](https://coveralls.io/repos/github/sindresorhus/execa/badge.svg?branch=master)](https://coveralls.io/github/sindresorhus/execa?branch=master) > A better [`child_process`](https://nodejs.org/api/child_process.html) ## Why - Promise interface. - [Strips EOF](https://github.com/sindresorhus/strip-eof) from the output so you don't have to `stdout.trim()`. - Supports [shebang](https://en.wikipedia.org/wiki/Shebang_(Unix)) binaries cross-platform. - [Improved Windows support.](https://github.com/IndigoUnited/node-cross-spawn#why) - Higher max buffer. 10 MB instead of 200 KB. - [Executes locally installed binaries by name.](#preferlocal) - [Cleans up spawned processes when the parent process dies.](#cleanup) ## Install ``` $ npm install --save execa ``` ## Usage ```js const execa = require('execa'); execa('echo', ['unicorns']).then(result => { console.log(result.stdout); //=> 'unicorns' }); // pipe the child process stdout to the current stdout execa('echo', ['unicorns']).stdout.pipe(process.stdout); execa.shell('echo unicorns').then(result => { console.log(result.stdout); //=> 'unicorns' }); // example of catching an error execa.shell('exit 3').catch(error => { console.log(error); /* { message: 'Command failed: /bin/sh -c exit 3' killed: false, code: 3, signal: null, cmd: '/bin/sh -c exit 3', stdout: '', stderr: '' } */ }); ``` ## API ### execa(file, [arguments], [options]) Execute a file. Same options as [`child_process.execFile`](https://nodejs.org/api/child_process.html#child_process_child_process_execfile_file_args_options_callback). Think of this as a mix of `child_process.execFile` and `child_process.spawn`. Returns a [`child_process` instance](https://nodejs.org/api/child_process.html#child_process_class_childprocess), which is enhanced to also be a `Promise` for a result `Object` with `stdout` and `stderr` properties. ### execa.stdout(file, [arguments], [options]) Same as `execa()`, but returns only `stdout`. ### execa.stderr(file, [arguments], [options]) Same as `execa()`, but returns only `stderr`. ### execa.shell(command, [options]) Execute a command through the system shell. Prefer `execa()` whenever possible, as it's both faster and safer. Same options as [`child_process.exec`](https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback). Returns a [`child_process` instance](https://nodejs.org/api/child_process.html#child_process_class_childprocess). The `child_process` instance is enhanced to also be promise for a result object with `stdout` and `stderr` properties. ### execa.sync(file, [arguments], [options]) Execute a file synchronously. Same options as [`child_process.execFileSync`](https://nodejs.org/api/child_process.html#child_process_child_process_execfilesync_file_args_options), except the default encoding is `utf8` instead of `buffer`. Returns the same result object as [`child_process.spawnSync`](https://nodejs.org/api/child_process.html#child_process_child_process_spawnsync_command_args_options). ### execa.shellSync(file, [options]) Execute a command synchronously through the system shell. Same options as [`child_process.execSync`](https://nodejs.org/api/child_process.html#child_process_child_process_execsync_command_options), except the default encoding is `utf8` instead of `buffer`. Returns the same result object as [`child_process.spawnSync`](https://nodejs.org/api/child_process.html#child_process_child_process_spawnsync_command_args_options). ### options Additional options: #### stripEof Type: `boolean`
Default: `true` [Strip EOF](https://github.com/sindresorhus/strip-eof) (last newline) from the output. #### preferLocal Type: `boolean`
Default: `true` Prefer locally installed binaries when looking for a binary to execute.
If you `$ npm install foo`, you can then `execa('foo')`. #### input Type: `string` `Buffer` `ReadableStream` Write some input to the `stdin` of your binary.
Streams are not allowed when using the synchronous methods. #### reject Type: `boolean`
Default: `true` Setting this to `false` resolves the promise with the error instead of rejecting it. #### cleanup Type: `boolean`
Default: `true` Keep track of the spawned process and `kill` it when the parent process exits. ## License MIT © [Sindre Sorhus](https://sindresorhus.com) execa-0.5.0/test.js000066400000000000000000000207561277513463600141460ustar00rootroot00000000000000import path from 'path'; import stream from 'stream'; import childProcess from 'child_process'; import test from 'ava'; import getStream from 'get-stream'; import isRunning from 'is-running'; import delay from 'delay'; import m from './'; process.env.PATH = path.join(__dirname, 'fixtures') + path.delimiter + process.env.PATH; test('execa()', async t => { const {stdout} = await m('noop', ['foo']); t.is(stdout, 'foo'); }); test('buffer', async t => { const {stdout} = await m('noop', ['foo'], {encoding: null}); t.true(Buffer.isBuffer(stdout)); t.is(stdout.toString(), 'foo'); }); test('execa.stdout()', async t => { const stdout = await m.stdout('noop', ['foo']); t.is(stdout, 'foo'); }); test('execa.stderr()', async t => { const stderr = await m.stderr('noop-err', ['foo']); t.is(stderr, 'foo'); }); test('stdout/stderr available on errors', async t => { const err = await t.throws(m('exit', ['2'])); t.is(typeof err.stdout, 'string'); t.is(typeof err.stderr, 'string'); }); test('include stdout and stderr in errors for improved debugging', async t => { const err = await t.throws(m('fixtures/error-message.js')); t.regex(err.message, /stdout/); t.regex(err.message, /stderr/); }); test('execa.shell()', async t => { const {stdout} = await m.shell('node fixtures/noop foo'); t.is(stdout, 'foo'); }); test('execa.spawn()', async t => { t.is(typeof m.spawn('noop').pid, 'number'); t.is((await getStream(m.spawn('noop', ['foo']).stdout)).trim(), 'foo'); }); test('execa.sync()', t => { const {stdout} = m.sync('noop', ['foo']); t.is(stdout, 'foo'); }); test('execa.shellSync()', t => { const {stdout} = m.shellSync('node fixtures/noop foo'); t.is(stdout, 'foo'); }); test('stripEof option', async t => { const {stdout} = await m('noop', ['foo'], {stripEof: false}); t.is(stdout, 'foo\n'); }); test.serial('preferLocal option', async t => { t.true((await m('cat-names')).stdout.length > 2); if (process.platform === 'win32') { // TODO: figure out how to make the below not hang on Windows return; } // account for npm adding local binaries to the PATH const _path = process.env.PATH; process.env.PATH = ''; await t.throws(m('cat-names', {preferLocal: false}), /spawn .* ENOENT/); process.env.PATH = _path; }); test('input option can be a String', async t => { const {stdout} = await m('stdin', {input: 'foobar'}); t.is(stdout, 'foobar'); }); test('input option can be a Buffer', async t => { const {stdout} = await m('stdin', {input: 'testing12'}); t.is(stdout, 'testing12'); }); test('input can be a Stream', async t => { const s = new stream.PassThrough(); s.write('howdy'); s.end(); const {stdout} = await m('stdin', {input: s}); t.is(stdout, 'howdy'); }); test('you can write to child.stdin', async t => { const child = m('stdin'); child.stdin.end('unicorns'); t.is((await child).stdout, 'unicorns'); }); test('input option can be a String - sync', async t => { const {stdout} = m.sync('stdin', {input: 'foobar'}); t.is(stdout, 'foobar'); }); test('input option can be a Buffer - sync', async t => { const {stdout} = m.sync('stdin', {input: new Buffer('testing12', 'utf8')}); t.is(stdout, 'testing12'); }); test('opts.stdout:ignore - stdout will not collect data', async t => { const {stdout} = await m('stdin', { input: 'hello', stdio: [null, 'ignore', null] }); t.is(stdout, null); }); test('helpful error trying to provide an input stream in sync mode', t => { t.throws( () => m.sync('stdin', {input: new stream.PassThrough()}), /The `input` option cannot be a stream in sync mode/ ); }); test('execa() returns a promise with kill() and pid', t => { const promise = m('noop', ['foo']); t.is(typeof promise.kill, 'function'); t.is(typeof promise.pid, 'number'); }); test('maxBuffer affects stdout', t => { t.throws(m('max-buffer', ['stdout', '11'], {maxBuffer: 10}), /stdout maxBuffer exceeded/); t.notThrows(m('max-buffer', ['stdout', '10'], {maxBuffer: 10})); }); test('maxBuffer affects stderr', t => { t.throws(m('max-buffer', ['stderr', '13'], {maxBuffer: 12}), /stderr maxBuffer exceeded/); t.notThrows(m('max-buffer', ['stderr', '12'], {maxBuffer: 12})); }); test('skip throwing when using reject option', async t => { const err = await t.notThrows(m('exit', ['2'], {reject: false})); t.is(typeof err.stdout, 'string'); t.is(typeof err.stderr, 'string'); }); test('execa() returns code and failed properties', async t => { const {code, failed} = await m('noop', ['foo']); const err = await t.throws(m('exit', ['2'])); t.is(code, 0); t.false(failed); t.is(err.code, 2); t.true(err.failed); }); test(`use relative path with '..' chars`, async t => { const pathViaParentDir = path.join('..', path.basename(__dirname), 'fixtures', 'noop'); const {stdout} = await m(pathViaParentDir, ['foo']); t.is(stdout, 'foo'); }); if (process.platform !== 'win32') { test('execa() rejects if running non-executable', t => { const cp = m('non-executable'); t.throws(cp); }); } test('err.killed is true if process was killed directly', async t => { const cp = m('forever'); setTimeout(() => { cp.kill(); }, 100); const err = await t.throws(cp); t.true(err.killed); }); // TODO: Should this really be the case, or should we improve on child_process? test('err.killed is false if process was killed indirectly', async t => { const cp = m('forever'); setTimeout(() => { process.kill(cp.pid, 'SIGINT'); }, 100); const err = await t.throws(cp); t.false(err.killed); }); if (process.platform === 'darwin') { test.cb('sanity check: child_process.exec also has killed.false if killed indirectly', t => { const cp = childProcess.exec('forever', err => { t.truthy(err); t.false(err.killed); t.end(); }); setTimeout(() => { process.kill(cp.pid, 'SIGINT'); }, 100); }); } if (process.platform !== 'win32') { test('err.signal is SIGINT', async t => { const cp = m('forever'); setTimeout(() => { process.kill(cp.pid, 'SIGINT'); }, 100); const err = await t.throws(cp); t.is(err.signal, 'SIGINT'); }); test('err.signal is SIGTERM', async t => { const cp = m('forever'); setTimeout(() => { process.kill(cp.pid, 'SIGTERM'); }, 100); const err = await t.throws(cp); t.is(err.signal, 'SIGTERM'); }); } test('result.signal is null for successful execution', async t => { t.is((await m('noop')).signal, null); }); test('result.signal is null if process failed, but was not killed', async t => { const err = await t.throws(m('exit', [2])); t.is(err.signal, null); }); async function code(t, num) { const err = await t.throws(m('exit', [`${num}`])); t.is(err.code, num); } test('err.code is 2', code, 2); test('err.code is 3', code, 3); test('err.code is 4', code, 4); async function errorMessage(t, expected, ...args) { const err = await t.throws(m('exit', args)); t.regex(err.message, expected); } errorMessage.title = (message, expected) => `err.message matches: ${expected}`; test(errorMessage, /Command failed: exit 2 foo bar/, 2, 'foo', 'bar'); test(errorMessage, /Command failed: exit 3 baz quz/, 3, 'baz', 'quz'); async function cmd(t, expected, ...args) { const err = await t.throws(m('fail', args)); t.is(err.cmd, `fail${expected}`); const result = await m('noop', args); t.is(result.cmd, `noop${expected}`); } cmd.title = (message, expected) => `cmd is: ${JSON.stringify(expected)}`; test(cmd, ' foo bar', 'foo', 'bar'); test(cmd, ' baz quz', 'baz', 'quz'); test(cmd, ''); async function spawnAndKill(t, signal, cleanup) { const name = cleanup ? 'sub-process' : 'sub-process-false'; const cp = m(name); let pid; cp.stdout.setEncoding('utf8'); cp.stdout.on('data', chunk => { pid = parseInt(chunk, 10); t.is(typeof pid, 'number'); setTimeout(() => { process.kill(cp.pid, signal); }, 100); }); await t.throws(cp); // Give everybody some time to breath and kill things await delay(200); t.false(isRunning(cp.pid)); t.is(isRunning(pid), !cleanup); } test('cleanup - SIGINT', spawnAndKill, 'SIGINT', true); test('cleanup - SIGKILL', spawnAndKill, 'SIGTERM', true); if (process.platform !== 'win32') { // On Windows the subprocesses are actually always killed test('cleanup false - SIGINT', spawnAndKill, 'SIGTERM', false); test('cleanup false - SIGKILL', spawnAndKill, 'SIGKILL', false); } // see: https://github.com/sindresorhus/execa/issues/56 const onlyWinFailing = test[process.platform === 'win32' ? 'failing' : 'serial']; onlyWinFailing('execa.shell() supports the `shell` option', async t => { const {stdout} = await m.shell('noop foo', { shell: process.platform === 'win32' ? 'cmd.exe' : '/bin/bash' }); t.is(stdout, 'foo'); }); execa-0.5.0/test/000077500000000000000000000000001277513463600135765ustar00rootroot00000000000000execa-0.5.0/test/errname.js000066400000000000000000000013231277513463600155640ustar00rootroot00000000000000import test from 'ava'; import errname from '../lib/errname'; const isWin = process.platform === 'win32'; // simulates failure to capture `process.binding('uv');` const fallback = code => errname.__test__(null, code); function makeTests(name, m, expected) { test(`${name}: >=0 exit codes`, t => { // throws >= 0 t.throws(() => m(0), /err >= 0/); t.throws(() => m(1), /err >= 0/); t.throws(() => m('2'), /err >= 0/); t.throws(() => m('foo'), /err >= 0/); }); test(`${name}: negative exit codes`, t => { t.is(m(-2), expected); t.is(m('-2'), expected); }); } const unknown = 'Unknown system error -2'; makeTests('native', errname, isWin ? unknown : 'ENOENT'); makeTests('fallback', fallback, unknown);