Skip to content

Commit

Permalink
Detect shebangs absolutely to node, wrap those too
Browse files Browse the repository at this point in the history
  • Loading branch information
isaacs committed Apr 5, 2016
1 parent bd26d72 commit d640c5b
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 1 deletion.
22 changes: 22 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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')

Expand Down Expand Up @@ -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++) {
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
62 changes: 62 additions & 0 deletions test/abs-shebang.js
Original file line number Diff line number Diff line change
@@ -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()
})
3 changes: 3 additions & 0 deletions test/fixtures/test-shim.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
console.log('before in shim')
require('../..').runMain()
console.log('after in shim')
27 changes: 27 additions & 0 deletions test/fixtures/wrap.js
Original file line number Diff line number Diff line change
@@ -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))
}
})
})

0 comments on commit d640c5b

Please sign in to comment.