├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── bin.js ├── index.js ├── package.json └── tests ├── echo.js └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" 4 | 5 | script: "npm test" 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2013 Mathias Buus 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # npm-execspawn 2 | 3 | Spawn locally installed npm dependencies with cross platform env and argument parsing support. 4 | 5 | ``` 6 | npm install npm-execspawn 7 | ``` 8 | 9 | [![build status](http://img.shields.io/travis/mafintosh/npm-execspawn.svg?style=flat)](http://travis-ci.org/mafintosh/npm-execspawn) 10 | 11 | ## Usage 12 | 13 | First do 14 | 15 | ``` 16 | npm install browserify 17 | ``` 18 | 19 | Then 20 | 21 | ``` js 22 | var execspawn = require('npm-execspawn') 23 | 24 | var child = execspawn('browserify $FILENAME', {env:{FILENAME:'test.js'}}) 25 | child.stderr.pipe(process.stderr) 26 | child.stdout.pipe(process.stdout) 27 | ``` 28 | 29 | The above should browserify test.js and both windows and unix. 30 | The options is passed directly to `child_process.spawn`. 31 | 32 | You can also pass in a arguments array 33 | 34 | ``` js 35 | execspawn('echo $0 $1 and $2', ['a', 'b', 'c']).stdout.pipe(process.stdout) 36 | ``` 37 | 38 | The above will print `echo a b and c` on all platforms. 39 | 40 | ## License 41 | 42 | MIT -------------------------------------------------------------------------------- /bin.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var execspawn = require('./') 3 | 4 | var child = execspawn(process.argv.slice(2).join(' ')) 5 | process.stdin.on('readable', function () { 6 | process.stdin.pipe(child.stdin) 7 | }) 8 | child.stdout.pipe(process.stdout) 9 | child.stderr.pipe(process.stderr) 10 | child.on('exit', function (code) { 11 | process.exit(code) 12 | }) -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var execspawn = require('execspawn') 2 | var parse = require('shell-quote').parse 3 | var xtend = require('xtend') 4 | var path = require('path') 5 | var debug = require('debug')('npm-execspawn') 6 | 7 | var PATH_SEP = process.platform === 'win32' ? ';' : ':' 8 | var PATH_KEY = process.platform === 'win32' && !(process.env.PATH && !process.env.Path) ? 'Path' : 'PATH' 9 | var ESCAPE_CHAR = process.platform === 'win32' ? '^' : '\\' 10 | 11 | var quote = function (s) { // lifted from shell-quote since we need different quote ordering for win support 12 | if (/["'\s]/.test(s)) return '"' + s.replace(/(["\\$`!])/g, '\\$1') + '"' 13 | if (/["\s]/.test(s) && !/'/.test(s)) return "'" + s.replace(/(['\\])/g, '\\$1') + "'" 14 | return String(s).replace(/([\\$`()!#&*|])/g, '\\$1') 15 | } 16 | 17 | var toString = function(cmd) { 18 | return cmd.pattern || cmd.op || quote(cmd) 19 | } 20 | 21 | var npmRunPath = function(cwd, PATH) { 22 | var prev = cwd 23 | var result = [] 24 | while (true) { 25 | result.push(path.join(cwd, 'node_modules/.bin')) 26 | var parent = path.join(cwd, '..') 27 | if (parent === cwd) return result.concat(PATH).join(PATH_SEP) 28 | cwd = parent 29 | } 30 | } 31 | 32 | module.exports = function(cmd, args, opts) { 33 | if (!Array.isArray(args)) return module.exports(cmd, [], args || opts) 34 | if (!opts) opts = {} 35 | if (!args) args = [] 36 | 37 | var env = opts.env || process.env 38 | var parsed = parse(cmd, xtend(env, args, {'':'$'}), {escape: ESCAPE_CHAR}).map(toString).join(' ') 39 | var override = {} 40 | override[PATH_KEY] = npmRunPath(path.resolve(process.cwd(), opts.cwd || '.'), env[PATH_KEY] || process.env[PATH_KEY]) 41 | 42 | debug('execspawn', parsed) 43 | return execspawn(parsed, xtend(opts, {env:xtend(env, override)})) 44 | } 45 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "npm-execspawn", 3 | "version": "1.3.0", 4 | "description": "Spawn locally installed npm dependencies with cross platform env and argument parsing support", 5 | "main": "index.js", 6 | "dependencies": { 7 | "debug": "^2.1.3", 8 | "execspawn": "^1.0.0", 9 | "shell-quote": "^1.5.0", 10 | "xtend": "^3.0.0" 11 | }, 12 | "devDependencies": { 13 | "concat-stream": "^1.4.6", 14 | "tape": "^2.13.3" 15 | }, 16 | "bin": { 17 | "npm-execspawn": "./bin.js" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git://github.com/mafintosh/npm-execspawn" 22 | }, 23 | "scripts": { 24 | "test": "node tests/test.js" 25 | }, 26 | "keywords": [ 27 | "npm", 28 | "exec", 29 | "spawn", 30 | "run", 31 | "path" 32 | ], 33 | "author": "Mathias Buus", 34 | "license": "MIT", 35 | "bugs": { 36 | "url": "https://github.com/mafintosh/npm-execspawn/issues" 37 | }, 38 | "homepage": "https://github.com/mafintosh/npm-execspawn" 39 | } 40 | -------------------------------------------------------------------------------- /tests/echo.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | console.log(process.argv.slice(2).join(' ')) 3 | -------------------------------------------------------------------------------- /tests/test.js: -------------------------------------------------------------------------------- 1 | var os = require('os') 2 | var path = require('path') 3 | var tape = require('tape') 4 | var execspawn = require('..') 5 | var concat = require('concat-stream') 6 | 7 | tape('echo', function(t) { 8 | execspawn('echo $0 $1 and $2', ['a', 'b', 'c']).stdout.pipe(concat(function(data) { 9 | t.same(data.toString(), 'a b and c'+os.EOL) 10 | t.end() 11 | })) 12 | }) 13 | 14 | tape('npm deps', function(t) { 15 | execspawn('tape').on('exit', function(code) { 16 | t.same(code, 0) 17 | t.end() 18 | }) 19 | }) 20 | 21 | tape('works on windows paths', function(t) { 22 | execspawn(path.join(__dirname, 'echo.js') + ' $0 $1 and $2', ['a', 'b', 'c']).stdout.pipe(concat(function(data) { 23 | t.same(data.toString(), 'a b and c'+os.EOL) 24 | t.end() 25 | })) 26 | }) 27 | --------------------------------------------------------------------------------