From d640c5bef68c12844a555eb6d83f8eb1741b396d Mon Sep 17 00:00:00 2001 From: isaacs Date: Sun, 3 Apr 2016 00:01:37 -0700 Subject: [PATCH] Detect shebangs absolutely to node, wrap those too --- index.js | 22 ++++++++++++++ package.json | 3 +- test/abs-shebang.js | 62 ++++++++++++++++++++++++++++++++++++++ test/fixtures/test-shim.js | 3 ++ test/fixtures/wrap.js | 27 +++++++++++++++++ 5 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 test/abs-shebang.js create mode 100644 test/fixtures/test-shim.js create mode 100644 test/fixtures/wrap.js diff --git a/index.js b/index.js index 20fc092..ac20287 100644 --- a/index.js +++ b/index.js @@ -12,6 +12,7 @@ var path = require('path') var signalExit = require('signal-exit') var homedir = require('os-homedir')() + '/.node-spawn-wrap-' var winRebase = require('./lib/win-rebase') +var which = require('which') var cmdname = path.basename(process.execPath, '.exe') @@ -119,6 +120,27 @@ function wrap (argv, env, workingDir) { options.file = workingDir + '/' + file options.args[0] = workingDir + '/' + file } + + } else { + try { + var resolved = which.sync(options.file) + } catch (er) {} + if (resolved) { + var shebang = fs.readFileSync(resolved, 'utf8') + var match = shebang.match(/^#!([^\r\n]+)/) + if (match) { + var shebangbin = match[1].split(' ')[0] + var maybeNode = path.basename(shebangbin) + if (maybeNode === 'node' || maybeNode === 'iojs' || cmdname === maybeNode) { + + options.file = shebangbin + options.args = [shebangbin, workingDir + '/' + maybeNode] + .concat(resolved) + .concat(match[1].split(' ').slice(1)) + .concat(options.args) + } + } + } } for (var i = 0; i < options.envPairs.length; i++) { diff --git a/package.json b/package.json index 6fd302d..2621a19 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "mkdirp": "^0.5.0", "os-homedir": "^1.0.1", "rimraf": "^2.3.3", - "signal-exit": "^2.0.0" + "signal-exit": "^2.0.0", + "which": "^1.2.4" }, "scripts": { "test": "tap test/*.js" diff --git a/test/abs-shebang.js b/test/abs-shebang.js new file mode 100644 index 0000000..6217d63 --- /dev/null +++ b/test/abs-shebang.js @@ -0,0 +1,62 @@ +var path = require('path') +var fs = require('fs') +var spawn = require('child_process').spawn +var t = require('tap') +var node = process.execPath +var wrap = require.resolve('./fixtures/wrap.js') +var rimraf = require('rimraf') +var mkdirp = require('mkdirp') +var fs = require('fs') + +var expect = + 'before in shim\n' + + 'shebang main\n' + + 'after in shim\n' + + 'before in shim\n' + + 'shebang main\n' + + 'after in shim\n' + +var fixdir = path.resolve(__dirname, 'fixtures', 'shebangs') + +t.test('setup', function (t) { + rimraf.sync(fixdir) + mkdirp.sync(fixdir) + t.end() +}) + +t.test('absolute', function (t) { + var file = path.resolve(fixdir, 'absolute.js') + runTest(file, process.execPath, t) +}) + +t.test('env', function (t) { + var file = path.resolve(fixdir, 'env.js') + runTest(file, '/usr/bin/env node', t) +}) + +function runTest (file, shebang, t) { + var content = '#!' + shebang + '\nconsole.log("shebang main")\n' + fs.writeFileSync(file, content, 'utf8') + fs.chmodSync(file, '0755') + var child = spawn(node, [wrap, file]) + var out = '' + var err = '' + child.stdout.on('data', function (c) { + out += c + }) + child.stderr.on('data', function (c) { + err += c + }) + child.on('close', function (code, signal) { + t.equal(code, 0) + t.equal(signal, null) + t.equal(out, expect) + // console.error(err) + t.end() + }) +} + +t.test('cleanup', function (t) { + rimraf.sync(fixdir) + t.end() +}) diff --git a/test/fixtures/test-shim.js b/test/fixtures/test-shim.js new file mode 100644 index 0000000..b6baf69 --- /dev/null +++ b/test/fixtures/test-shim.js @@ -0,0 +1,3 @@ +console.log('before in shim') +require('../..').runMain() +console.log('after in shim') diff --git a/test/fixtures/wrap.js b/test/fixtures/wrap.js new file mode 100644 index 0000000..a8af6e4 --- /dev/null +++ b/test/fixtures/wrap.js @@ -0,0 +1,27 @@ +#!/usr/bin/env node +var sw = require('../..') + +sw([require.resolve('./test-shim.js')]) + +var path = require('path') +var spawn = require('child_process').spawn + +spawn(path.resolve(process.argv[2]), process.argv.slice(3), { + stdio: 'inherit' +}).on('close', function (code, signal) { + if (code || signal) { + throw new Error('failed with ' + (code || signal)) + } + + // now run using PATH + process.env.PATH = path.resolve(path.dirname(process.argv[2])) + + ':' + process.env.PATH + + spawn(path.basename(process.argv[2]), process.argv.slice(3), { + stdio: 'inherit', + }, function (code, signal) { + if (code || signal) { + throw new Error('failed with ' + (code || signal)) + } + }) +})