GithubHelp home page GithubHelp logo

zeekay / executive Goto Github PK

View Code? Open in Web Editor NEW
37.0 2.0 7.0 205 KB

🕴Elegant command execution for Node.

License: MIT License

CoffeeScript 100.00%
executable commands parallel serial control-flow javascript nodejs promise shell

executive's Introduction

executive

npm build dependencies downloads license chat

An elegant child_process.spawn

Executive is simple and intuitive interface to child_process.spawn with zero depdencies. Built-in support for async and sync process creation, built-in flow control and automatic shell make working with external processes in Node easy.

Features

  • Async callback, promise and sync APIs
  • Automatically pipes stderr and stdout by default
  • Automatically uses shell when commands use builtins, globs or operators
  • Built-in control flow with support for parallel and serial execution
  • Mix simple string commands with functions and promises returning commands
  • Multi-line strings parsed as multiple commands and executed sequentially
  • Streams stderr and stdout rather than blocking on command completion
  • Included TypeScript type definition
  • Improved Windows support
  • No external dependencies

Install

$ npm install executive --save-dev

Usage

No need to echo as stderr and stdout are piped by default.

import exec from 'executive'

exec('uglifyjs foo.js --compress --mangle > foo.min.js')

It's easy to be quiet too.

exec.quiet('uglifyjs foo.js --compress --mangle > foo.min.js')

Callbacks and promises are both supported.

exec('ls', (err, stdout, stderr) => console.log(stdout))
exec('ls').then(res => console.log(res.stdout))

Automatically serializes commands.

exec(['ls', 'ls', 'ls']) // All three ls commands will be executed in order

exec(`ls -l
      ls -lh
      ls -lha`) // Also executed in order

Want to execute your commands in parallel? No problem.

exec.parallel(['ls', 'ls', 'ls'])

Want to collect individual results? Easy.

{a, b, c} = await exec.parallel({
  a: 'echo a',
  b: 'echo b',
  c: 'echo c'
})

Want to blend in Promises or pure functions? You got it.

exec.parallel([
  'ls',

  // Promises can be blended directly in
  exec('ls'),

  // Promises returned by functions are automatically consumed
  () => exec('ls'),

  // Functions which return a string are assumed to be commands
  () => 'ls',

  // Functions and promises can return objects with stdout, stderr or status
  () => ({ stdout: 'huzzah', stderr: '', status: 0 }),

  'ls'
])

Options

Options are passed as the second argument to exec. Helper methods for quiet, interactive, parallel and sync do what you expect.

exec('ls', { quiet: true })

and

exec.quiet('ls')

are equivalent.

options.interactive | exec.interactive

default false

If you need to interact with a program (your favorite text editor for instance) or watch the output of a long running process (tail -f), or just don't care about checking stderr and stdout, set interactive to true:

exec.interactive('vim', err => {
  // Edit your commit message
})

options.quiet | exec.quiet

default false

If you'd prefer not to pipe stdout and stderr set quiet to true:

exec.quiet(['ls', 'ls'], (err, stdout, stderr) => {
  // You can still inspect stdout, stderr of course
})

options.sync | exec.sync

default false

Blocking version of exec. Returns {stdout, stderr} or throws an error.

options.parallel | exec.parallel

default false

Uses parallel rather than serial execution of commands.

options.shell

default null

Force a shell to be used for command execution.

options.strict

default false

Any non-zero exit status is treated as an error. Promises will be rejected and an error will be thrown with exec.sync if syncThrows is enabled.

options.syncThrows

default false

Will cause exec.sync to throw errors rather than returning them.

Extra

Great with sake, grunt, gulp and other task runners. Even nicer with async and await.

Fancy example using sake:

task('package', 'Package project', => {
  // Create dist folder
  await exec(`
    mkdir -p dist/
    rm   -rf dist/*
  `)

  // Copy assets to dist in parallel
  await exec.parallel(`
    cp manifest.json dist/
    cp -rf assets/   dist/
    cp -rf lib/      dist/
    cp -rf views/    dist/
  `)

  // Get current git commit hash
  let {stdout} = await exec('git rev-parse HEAD')
  let hash     = stdout.substring(0, 8)

  # Zip up dist
  exec(`zip -r package-${hash}.zip dist/`)
})

You can find more usage examples in the tests.

License

MIT

executive's People

Contributors

alexwhitman avatar antisocialmunky avatar developer-av avatar greenkeeper[bot] avatar mindlapse avatar zeekay avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

executive's Issues

No error is thrown if command does not exist

executive does not signal errors / throw exceptions if the command one tries to execute does not exist.

Simple repro:

const exec = require('executive');
const res = await exec(
      `hullu-bullu`,
      { strict: true }
    );
console.log(JSON.stringify(res));

Something emits this to my console:

Error: ENOENT, spawn hullu-bullu
Make sure 'hullu-bullu' exists and is executable.

However the console.log above produces:

{"status":0,"stderr":"","stdout":""}

Given that no exception is thrown (which is what I would expect as the command failed) and that status/stdout/stderr is empty, I have no way of catching the fact that the command did not succeed.

I have seen the issue on macOS 10.14 and ubuntu 16.04 with nodejs v10.15.3 LTS.

An in-range update of sake-cli is breaking the build 🚨

Version 0.5.19 of sake-cli just got published.

Branch Build failing 🚨
Dependency sake-cli
Current Version 0.5.18
Type devDependency

This version is covered by your current version range and after updating it in your project the build failed.

As sake-cli is “only” a devDependency of this project it might not break production or downstream projects, but “only” your build or test tools – preventing new deploys or publishes.

I recommend you give this issue a high priority. I’m sure you can resolve this 💪

Status Details
  • continuous-integration/travis-ci/push The Travis CI build failed Details

Commits

The new version differs by 2 commits.

See the full diff

Not sure how things should work exactly?

There is a collection of frequently asked questions and of course you may always ask my humans.


Your Greenkeeper Bot 🌴

An in-range update of sake-test is breaking the build 🚨

☝️ Greenkeeper’s updated Terms of Service will come into effect on April 6th, 2018.

Version 0.1.6 of sake-test was just published.

Branch Build failing 🚨
Dependency sake-test
Current Version 0.1.5
Type devDependency

This version is covered by your current version range and after updating it in your project the build failed.

sake-test is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • continuous-integration/travis-ci/push The Travis CI build failed Details

Commits

The new version differs by 6 commits.

  • c544e7a 0.1.6
  • fb42362 Update coffeescript, sake-bundle, sake-cli
  • b5556cc Migrate to coffeescript package
  • 318534e Update sake-bundle, sake-cli
  • 53bfa07 Update coffee-script, sake-bundle, sake-cli, sake-outdated, sake-publish, sake-version
  • 2e01ff6 Update gitignore

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Argument parsing fails for single forward slash

When running exec(['git reset --hard origin/master']); the origin/master gets converted to originmaster with the output then being: fatal: 'originmaster' does not appear to be a git repository

Error in piping

I have sth like this

exec.quiet( 'cat version.txt | jq -s -R -f version.jq' )

I am getting an error as result cat: invalid option -- 'R'
It seems that the output from cat isnt piping to the jq prog.

Whats wrong ?
Thanks for any support and best regards,
Nic

An in-range update of sake-bundle is breaking the build 🚨

☝️ Greenkeeper’s updated Terms of Service will come into effect on April 6th, 2018.

Version 0.6.5 of sake-bundle was just published.

Branch Build failing 🚨
Dependency sake-bundle
Current Version 0.6.4
Type devDependency

This version is covered by your current version range and after updating it in your project the build failed.

sake-bundle is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • continuous-integration/travis-ci/push The Travis CI build failed Details

Commits

The new version differs by 5 commits.

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Version 10 of node.js has been released

Version 10 of Node.js (code name Dubnium) has been released! 🎊

To see what happens to your code in Node.js 10, Greenkeeper has created a branch with the following changes:

  • Added the new Node.js version to your .travis.yml

If you’re interested in upgrading this repo to Node.js 10, you can open a PR with these changes. Please note that this issue is just intended as a friendly reminder and the PR as a possible starting point for getting your code running on Node.js 10.

More information on this issue

Greenkeeper has checked the engines key in any package.json file, the .nvmrc file, and the .travis.yml file, if present.

  • engines was only updated if it defined a single version, not a range.
  • .nvmrc was updated to Node.js 10
  • .travis.yml was only changed if there was a root-level node_js that didn’t already include Node.js 10, such as node or lts/*. In this case, the new version was appended to the list. We didn’t touch job or matrix configurations because these tend to be quite specific and complex, and it’s difficult to infer what the intentions were.

For many simpler .travis.yml configurations, this PR should suffice as-is, but depending on what you’re doing it may require additional work or may not be applicable at all. We’re also aware that you may have good reasons to not update to Node.js 10, which is why this was sent as an issue and not a pull request. Feel free to delete it without comment, I’m a humble robot and won’t feel rejected 🤖


FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Error executive

Hey, suddenly this error appear in my app when I use node v.4.4.x

/home/rub/apps/test/node_modules/executive/dist/lib.js:226
var parse = function(args, opts = {}) {
                                ^

SyntaxError: Unexpected token =
    at exports.runInThisContext (vm.js:53:16)
    at Module._compile (module.js:373:25)
    at Object.Module._extensions..js (module.js:416:10)
    at Module.load (module.js:343:32)
    at Function.Module._load (module.js:300:12)
    at Module.require (module.js:353:17)
    at require (internal/module.js:12:17)
    at Module._compile (module.js:409:26)
    at Object.Module._extensions..js (module.js:416:10)

escaping untrusted text arguments

Say I have some untrusted text, is there a recommended way to escape the contents of the text as an argument?

  var exec = require('executive')
  var untrustedText = /* some text here */

  exec(`say '${untrustedText}'`)

In this example, I would assume that I have a shell injection vulnerability, since the untrustedText variable could have a single quote, i.e. hello'; rm -rf / which could hose my computer. Any idea how to fix this?

typescript: the readme example won't compile

import exec from 'executive'
exec('uglifyjs foo.js --compress --mangle > foo.min.js')

when trying to compile it tsc will throw

src/force-dependency.ts:10:1 - error TS2693: 'exec' only refers to a type, but is being used as a value here.
10 exec('uglifyjs foo.js --compress --mangle > foo.min.js')

now don't have time for a PR just wanted to track this error here. thanks. Node 10.3, ts: 2.9.3

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.