Coder Social home page Coder Social logo

sindresorhus / execa Goto Github PK

View Code? Open in Web Editor NEW
6.8K 40.0 214.0 2.39 MB

Process execution for humans

License: MIT License

JavaScript 79.33% TypeScript 20.67%
nodejs spawn exec spawned-processes javascript child-process shell execute binary streams

execa's Issues

`execa` and `execa.sync` have return type mismatches.

I think it would be better if the following were basically equivalent:

const val = execa.sync(...args);

const val = await execa(...args);

This would mean a breaking change to execa.sync, using child.spawnSync instead, but I think it's worth it to have a more consistent API.

execa.shell not running on windows

This code from the readme was tested on windows 7:

execa.shell('echo unicorns').then(result => {
    console.log(result.stdout);
});

and the result was no output at all. No error, unicorns or anything.

I also tested known windows commands like dir, and echo:

execa.shell('dir').then(result => {
    console.log(result.stdout);
});

execa.shell('echo unicorns').then(result => {
    console.log(result.stdout);
});

None of these commands produced any results. Just nothing in the console at all.

However, when I run the execa example, it works:

execa('echo', ['unicorns']).then(result => {
    console.log(result.stdout);
});
//=> unicorns

Am I missing something simple?

Allow transform streams convert output to an array of any objects, instead of a single string

We need to think through the ideal API for this and #20 as well, but something like:

execa('./cli', [], {
  transforms: {
     // shortcut to a built-in transform we provide
    stdout: 'line',

    stderr: through2(function (chunk, encoding, callback) {
      // custom processing here
    })
  }
}).then(function (result) {
  result.stdout;
  // => an array of lines

  result.stderr;
  // => an array of whatever the custom transform emits
});

Shorthand for piping stdout and stderr

I use this pattern a lot and have created a function for personal use:

const cp = execa('echo', ['foo', 'unicorns'])
cp.stdout.pipe(process.stdout)
cp.stderr.pipe(process.stderr)

Do you think it's a good idea to include it as a shorthand in the library? It could be named execa.echo or execa.log or execa.piped...

Inherited stdio results in null stdout, stderr in Error

Ran across a funky error case today while converting gulp-mocha to use execa. If {stdio: 'inherit'} is used in execa's options, and the command fails, the resulting Error message contains nullnull

Line in question: https://github.com/sindresorhus/execa/blob/master/index.js#L201

Example output:

{ Error: Command failed: mocha /.../github/gulp-mocha/test/fixtures/fixture-fail.js
nullnull
    at Promise.all.then.arr (/.../github/gulp-mocha/node_modules/execa/index.js:201:11)
    at process._tickCallback (internal/process/next_tick.js:103:7)

FWIW, for commands that succeed, result.stdout and result.stderr are also both null in the .then(result => handler when {stdio: 'inherit'{ is used. That isn't mentioned anywhere in the README, and the option appears to be the only way to preserve terminal formatting.

Sync methods

execa already cover the async methods and the sync methods could then take advantage of of the npm path thing, and utf8 by default instead of buffer.

Cleanup doesn't work reliably

I'm using execa to start a child node process which simply starts an express server listening on port 5000.

But this child process often ends up running after I've exited the parent program, so when I run the parent again, I get an error saying port 5000 is already bound when it tries to start the child process. This happens about 25% of the time.

I haven't yet figured out what conditions cause the cleanup to fail. Any ideas?

warning: possible EventEmitter memory leak detected

Description

My test print a warning

(node) warning: possible EventEmitter memory leak detected. 11 exit listeners added. Use emitter.setMaxListeners() to increase limit.

I use execa 16 times in my unit tests

Test Source

tests are here : https://github.com/lesspass/cli/blob/master/test.js

I try to test my command line interface with 16 tests like this one :

test('test space in password', async t => {
    const {stdout} = await execa('./cli.js', ['lesspass.com', '[email protected]', 'my Master Password']);
    t.is(stdout, 'onAV7&uvEC2=');
});

Here the output for my tests : https://travis-ci.org/lesspass/cli/jobs/169243714

Github

Here the github repository to reproduce the bug : https://github.com/lesspass/cli

Environment

Node.js v4.6.0
linux 4.4.0-45-generic
ava version 0.16.0
excea version 0.5.0
npm version 3.10.8

How can I avoid to raise this warning ?

previously post on avajs/ava#1087

`preferLocal` fails for globally installed CLI programs

When you have a globally installed binary that uses execa within it, the preferLocal option doesn't work correctly.

Example: foo is a js cli program that depends on a (which has a binary installed to foo's node_modules/.bin/ folder.

npm link # within foo directory
foo doSomethingThatCallsA # within another directory
output: spawn a ENOENT

The reason for this is because npmRunPath uses the CWD by default. This isn't an issue in npm-run-path necessarily though, because execa should provide an option (along with preferLocal to specify the directory to look into.

For example:

// foo.js
const execa = require('execa');

execa('a', ['some', 'options'], {
    preferLocal: true,
    localDir: __dirname 
});

More than happy to PR this, just want to get approval on the localDir option name or to have a better name suggested before I submit a PR ๐Ÿ˜„

Add `.fork()` method

Issuehunt badges

We could just use execa('node', ['becomeTheOne.js']), but that would mean not capitalising on the added optimization that happens when using fork, as mentioned here.

There is no spoon matrix


IssueHunt Summary

[
<
i
m
g

s
r
c

'
h
t
t
p
s
:
/
/
a
v
a
t
a
r
s
3
.
g
i
t
h
u
b
u
s
e
r
c
o
n
t
e
n
t
.
c
o
m
/
u
/
2
5
4
3
5
1
1
?
v

4
'

a
l
t

'
g
m
a
r
t
i
g
n
y
'

w
i
d
t
h

2
4

h
e
i
g
h
t

2
4

g
m
a
r
t
i
g
n
y
]
(
h
t
t
p
s
:
/
/
i
s
s
u
e
h
u
n
t
.
i
o
/
u
/
g
m
a
r
t
i
g
n
y
)

h
a
s

b
e
e
n

r
e
w
a
r
d
e
d
.

Backers (Total: $60.00)

Submitted pull Requests


Tips


IssueHunt has been backed by the following sponsors. Become a sponsor

re-implement errname resolution

#27 dropped execFile in favor of using spawn directly, so we've lost some features.

One is whatever these two lines do:

  1. https://github.com/nodejs/node/blob/31600735f40e02935b936802ff42d66d49e9769b/lib/child_process.js#L8
  2. https://github.com/nodejs/node/blob/31600735f40e02935b936802ff42d66d49e9769b/lib/child_process.js#L204

Can we reliably just do process.binding('uv')? Or is that asking for problems. I know it means importing some native lib, but not much beyond that.

Maybe we look back all the way to Node 0.12 and make sure it was still imported and used the same back then?

stdout encoding issue.

This is more of a heads up to an interesting issue I've run into. I'm curious if others have seen it and if there's a known workaround.

foo.py (Python 2.7.10):

#!/usr/bin/env python
import sys
print(sys.stdout.encoding)

foo.js (execa v0.6.0, node 7.6.0):

'use strict'
const execa = require('execa')
const spawned = execa('./foo.py', [], { 'encoding': 'utf8' })
spawned.stdout.setEncoding('utf8')
spawned.then(({ stdout }) => console.log(stdout))

running node foo.js:

None

I'm wondering how to ensure the invoked Python script has a stdout.encoding of UTF-8.

Undefined and null argument variables are passed as strings

Undefined and null variables are passed to child process as their string representations, "undefined" and "null". I'm not sure what the expected behavior is, but when working with shell scripts, I expect the undefined or null arguments to be passed as empty strings.

Automatically wait for file streams to open

It might be possible to wait for the open event on file streams (if we can find a way to detect that a stream is in fact a file stream, and that it will indeed eventually open).

See the discussion here

Kill child when exiting

If I use execa.shell to spawn a long running process, but the original process dies for some reason it would be great if the spawned process gets terminated automatically.

A small example

'use strict'

const execa = require('execa')

execa.shell('ipfs daemon')
  .then((res) => {
    console.log(res.stdout)
  })
  .catch((err) => {
    console.log('failed', err)
  })

console.log('starting')
setTimeout(() => {
  console.log('exiting')
  process.exit()
}, 10 * 1000)

Running this will print exiting after 10s and exit but when I grep for ipfs dameon the process is still running.

How to maintain console colors

I have created a simple script:

	execa('bash',['./scripts/lint-styles.sh'])
		.then(result => {
			console.log(result.stdout);
		});

This script calls

#!/usr/bin/env bash

./node_modules/.bin/sass-lint "./resources/assets/sass/*.s+(a|c)ss" -q -v

When executed, the output is correct, but it does not have the color output which displays when executing from cli

Ability to turn off buffering

If you only pipe the output it's a waste of resources to buffer it and the user can also easily hit the maxBuffer.

Either {buffer: false} or detect when .then() is used. I would prefer the latter, but not sure how feasible it is.


This would have prevented sindresorhus/gulp-mocha#169

Error: spawn EACCES

When I run my tests, which have this format:

import test from 'ava';
import execa from 'execa';

test('action', async (t) => {
  const { stdout } = await execa('./cli.js', ['action']);
  t.true(stdout.search('export default ClassName;') > -1);
});

I am getting the Error of Error: spawn EACCES on each test run.

image

I have a feeling it could be something simple I am overlooking, like bad formatting or something, but figured I would ask here in case I have stumbled onto something. Is this error trying to tell me that the module doesn't have access to execa's index.js file from within the node_modules directory? I deleted the node_modules directory and reinstalled everything, but I got the same set of errors.

If you want to see more of the code in context, the module that is experiencing this issue is here.

Thanks in advance for your help.

Why append the entire contents of stdout on error?

It seems just as likely the info needed will be in stderr, and it could be a whole bunch of data to print. Also, it gives you no means of extracting the original error.message property.

Is this providing any real value? If people want to log it to the console, can't they just:

console.log(error.message + error.stdout);

readable stream 'end' event

This is not an issue, but more a question on node streams.
Just wanted to know if there is any technical difference between those 2 implementations

  function runCommandAndWriteToFile (cmd, name) {
   // cmd is an execa instance
    return new Promise((resolve) => {
      cmd.stderr.pipe(process.stdout)
      cmd.stderr.on('end', () => {
        cmd.then((res) => {
          const msg = `Command run:\n${res.cmd}`
          utils.log(chalk.magenta(msg))
          resolve()
        })
      })
    })
  }

and

  function runCommandAndWriteToFile (cmd, name) {
    cmd.stderr.pipe(process.stdout)
    return cmd.then((res) => {
      const msg = `Command run:\n${res.cmd}`
      utils.log(chalk.magenta(msg))
    })
  }

thanks

Getting the pid of a long-running process

I'm using execa to start a process that runs "forever" (a web server). I would like to send a kill signal to the process about 30 seconds after launch, but I don't know how/where to get its process id from execa. Is it possible?

At the moment, execa returns a promise that is only resolved after the process ends, which isn't really useful for indefinitely-running processes. It would be nice if execa returned some additional info along with the promise, like the pid.

Capture exit code

I'm not sure what would be the best way to implement this, but it would be great if this module also captured the exit code of whatever file or command is ran somehow.

Doesn't work with electron

Feel free to close this as a wontfix but I wanted to log the issue anyway.

With standard exec:

const exec = require('child_process').exec;
exec('networksetup', console.log.bind(console));
// 'networksetup Help Information...' Works OK

With execa:

const execa = require('execa');
execa.shell('networksetup').then(console.log.bind(console));
// Error: Command failed: /bin/sh -c networksetup

Release version w/ cross-spawn

#42

Could this one possibly be released? 0.4.1?
So that we don't get the annoying warning in all packages using execa ๐Ÿ‘ผ

Thanks!

`reject` option

Currently execa rejects the promise on non-zero exit code. Sometimes though, you want to get the output regardless, like e.g. running ESLint and reading the result regardless of it having linter issues.

Not totally sold on the name. Suggestions welcome.

Does this option make sense?

execa.shell(cmd, {shell: '/bin/bash'}) only runs the first word of command

Let's say that I have to run man ls command.

// runs correctly, with man page of 'ls' in stdout
execa.shell('man ls')
  .then(function (result) {
    console.log(`stdout: ${result.stdout}`)
    console.log(`stderr: ${result.stderr}`)
  })

but

// this just runs 'man'
execa.shell('man ls', {shell: '/bin/bash'})
  .then(function (result) {
    console.log(`stdout: ${result.stdout}`)
    console.log(`stderr: ${result.stderr}`)
  })

Output

stdout: 
stderr: What manual page do you want?

Promisify spawn

Is there any reason that execa.spawn isn't promisified as execa?

Crash when running file without execute permissions

Steps to reproduce:

  1. Create a normal file touch foo.sh
  2. chmod -x foo.sh to be explicit.
  3. npm i execa
  4. Run execa('foo.sh') as below
// index.js
const execa = require('execa')
execa(__dirname + '/foo.sh')
  .then(() => console.log('Ran successfully'))
  .catch(err => console.error('Caught an error', err))

Crashes with error message

/repos/node_modules/execa/index.js:120
        spawned.then = promise.then.bind(promise);
                     ^

TypeError: Cannot set property 'then' of undefined
    at module.exports (/repos/node_modules/execa/index.js:120:15)
    at Object.<anonymous> (/repos/index.js:2:1)
    at Module._compile (module.js:556:32)
    at Object.Module._extensions..js (module.js:565:10)
    at Module.load (module.js:473:32)
    at tryModuleLoad (module.js:432:12)
    at Function.Module._load (module.js:424:3)
    at Module.runMain (module.js:590:10)
    at run (bootstrap_node.js:394:7)
    at startup (bootstrap_node.js:149:9)

Ideas?

Are there any annoyances you've had with child processes that could potentially be fixed in execa? Anything that could be done better? I'm open for any kind of suggestions.

Better `stdio` option.

I think the stdio array is a pretty poor UI, you have to remember the order of things. I'm constantly pulling up that piece of documentation. Instead, of the three member array, let's just give each one it's own named property:

execa('./cli.js', [], {
  stdin: someReadableStream,
  stdout: 'pipe',
  stderr: 'inherit'
});

Stdio `tap` option

For stderr and stdout the choice between inherit and pipe, has tradeoffs.

Specifically, if you choose inherit, you loose the ability to observe the stream, it's piped straight to the parents stdout/stderr.

I propose we add a tap option. It will be converted internally to the pipe option, but we will grab the pipe, split it into two streams, one stream we pipe directly to stdout/stderr, the other we make available for observation.

Add a promise-getter to spawned child process objects

promoted from #6 (comment)

Sometimes you want to use execa.spawn() because you need an object representing the child process while it's running, so you can send signals or listen to events. But then you lose the convenience of a promise-based API (i.e. having a thing you can easily await, which will collect up the stdout/stderr for you).

Suggest adding a method to spawned child objects. This method would return a promise that resolves when the child process exits.

const child = execa.spawn(...);

// do any necessary manual stuff with events/signals etc
child.on(...);

// await the final outcome
const { stdio, stderr, code } = await child.exited();

(I'm not sure about the name exited though.)


Possible extra feature: the method could take an optional parameter specifying the expected exit code, e.g. .exited(0). If the child process exits with any other code, the promise rejects. If no exit code is specified, the promise will always resolve when the child process exits, no matter how.

Allow userland streams to be passed to `stdio` option

UPDATE: I think this is the right way to do it. Everything in between here and there is interesting background though.


I think you should be able to do this:

const PassThrough = require('stream').PassThrough;
const execa = require('execa');

const stdin = new PassThrough();
const stdout = new PassThrough();
const stderr = new PassThrough();

execa('foo', [], {stdio: [stdin, stdout, stderr]});

But you aren't actually allowed to pass any old stream to child_process. It has to be a very specific type of native stream (here is the internal Node code that checks that).

Instead, if you've got some userland stream you want to use, you've got to go about it a bit more convoluted way:

const PassThrough = require('stream').PassThrough;
const execa = require('execa');

const stdin = new PassThrough();
const stdout = new PassThrough();
const stderr = new PassThrough();

const cp = execa('foo', [], ['pipe', 'pipe', 'pipe']);

stdin.pipe(cp.stdin);
cp.stdout.pipe(stdout);
cp.stderr.pipe(stderr);

I think it's a weird choice to allow streams, but only certain types of streams. I've written native-stream-type which would help us figure out if we can pass the stream directly to child_process.spawn or not. For userland streams, we just convert to using pipe.

Observable support with customizable through filters

var child = execa('./cli.js', [], {stdio: [null, 'observable', null]});

t.plan(5); // should get 5 lines
await child.stdin
  .filter(line => /^s/.test(line)) // only lines that start with "s"
  .forEach(line => t.true(fitsSpecifiedFormat(line)));

Additionally, it would be cool if you could use DuplexStreams to modify what reaches the observable, I'm thinking "newline-separated-json" byte stream converted to a JSON object stream, etc.

There are a number of "split-stream-XXX" modules already on NPM, but they convert to a stream, would be cool to write object-stream-to-observable, and then use that to make CLI output processing awesome.

Release?

Could you release a new version with the reject option available?

Add some tests around the logic copied out of `execFile`

#27 really only went so far as copying the execFile implementation where necessary to get tests passing using spawn.

Most of the required test aren't terribly consequential, but should still be completed. The one set of tests I can think of right now is the creation of the Error property. It builds the command by concatting args together, then uses that to build the error message. Also, it attaches a few extra properties: killed, code, etc.

Examine the diff of #27 for a complete picture of what should be tested.

I will tackle this, just recording for posterity.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.