diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/index.js b/index.js index f9167fa..b4e229c 100644 --- a/index.js +++ b/index.js @@ -11,6 +11,7 @@ var rimraf = require('rimraf') var path = require('path') var signalExit = require('signal-exit') var homedir = require('os-homedir')() + '/.node-spawn-wrap-' +var winRebase = require('./lib/win-rebase') var pieces = process.execPath.split(path.sep) var cmdname = pieces[pieces.length - 1] @@ -18,18 +19,10 @@ var cmdname = pieces[pieces.length - 1] var shim = '#!' + process.execPath + '\n' + fs.readFileSync(__dirname + '/shim.js') -var cmdShim = 'SETLOCAL\r\n' + - 'SET PATHEXT=%PATHEXT:;.JS;=;%\r\n' + - process.execPath + ' "%~dp0\\.\\node" %*\r\n' +var isWindows = require('./lib/is-windows')() -var isWindows = false var pathRe = /^PATH=/ -if (process.platform === 'win32' || - process.env.OSTYPE === 'cygwin' || - process.env.OSTYPE === 'msys') { - pathRe = /^PATH=/i - isWindows = true -} +if (isWindows) pathRe = /^PATH=/i var colon = isWindows ? ';' : ':' @@ -80,19 +73,12 @@ function wrap (argv, env, workingDir) { } } else if (isWindows && ( file === path.basename(process.env.comspec) || - file === 'cmd.exe')) { + file === 'cmd.exe' || + file === 'cmd' + )) { cmdi = options.args.indexOf('/c') if (cmdi !== -1) { - c = options.args[cmdi + 1] - re = new RegExp('^\\s*"([^\\s]*(?:node|iojs)) ') - match = c.match(re) - if (match) { - exe = path.basename(match[1]).replace(/\.exe$/, '') - if (exe === 'node' || exe === 'iojs' || exe === cmdname) { - c = c.replace(re, exe + ' ') - options.args[cmdi + 1] = c - } - } + options.args[cmdi + 1] = winRebase(options.args[cmdi + 1], workingDir + '/node.cmd') } } else if (file === 'node' || file === 'iojs' || cmdname === file) { // make sure it has a main script. @@ -144,12 +130,31 @@ function wrap (argv, env, workingDir) { options.envPairs.push((isWindows ? 'Path=' : 'PATH=') + workingDir) } + if (isWindows) fixWindowsBins(workingDir, options) + return spawn.call(this, options) } return unwrap } +// by default Windows will reference the full +// path to the node.exe or iojs.exe as the bin, +// we should instead point spawn() at our .cmd shim. +function fixWindowsBins (workingDir, options) { + var renode = new RegExp('.*node\\.exe$') + var reiojs = new RegExp('.*iojs\\.exe$') + + options.file = options.file.replace(renode, workingDir + '/node.cmd') + options.file = options.file.replace(reiojs, workingDir + '/node.cmd') + + options.args = options.args.map(function (a) { + a = a.replace(renode, workingDir + '/node.cmd') + a = a.replace(reiojs, workingDir + '/node.cmd') + return a + }) +} + function setup (argv, env) { if (argv && typeof argv === 'object' && !env && !Array.isArray(argv)) { env = argv @@ -215,6 +220,12 @@ function setup (argv, env) { mkdirp.sync(workingDir) workingDir = fs.realpathSync(workingDir) if (isWindows) { + var cmdShim = + '@echo off\r\n' + + 'SETLOCAL\r\n' + + 'SET PATHEXT=%PATHEXT:;.JS;=;%\r\n' + + '"' + process.execPath + '"' + ' "%~dp0\\.\\node" %*\r\n' + fs.writeFileSync(workingDir + '/node.cmd', cmdShim) fs.chmodSync(workingDir + '/node.cmd', '0755') fs.writeFileSync(workingDir + '/iojs.cmd', cmdShim) diff --git a/lib/is-windows.js b/lib/is-windows.js new file mode 100644 index 0000000..278abb3 --- /dev/null +++ b/lib/is-windows.js @@ -0,0 +1,5 @@ +module.exports = function () { + return process.platform === 'win32' || + process.env.OSTYPE === 'cygwin' || + process.env.OSTYPE === 'msys' +} diff --git a/lib/win-rebase.js b/lib/win-rebase.js new file mode 100644 index 0000000..e24ba49 --- /dev/null +++ b/lib/win-rebase.js @@ -0,0 +1,7 @@ +var re = new RegExp(/(.*((node\.exe($| ))|(node($| ))|(iojs($| ))|(iojs\.exe($| )))) ?(.*)$/) + +module.exports = function (path, rebase) { + var m = path.match(re) + if (!m) return path + return path.replace(m[1].trim(), rebase) +} diff --git a/package.json b/package.json index b282867..4f2796d 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ }, "homepage": "https://github.com/isaacs/spawn-wrap#readme", "devDependencies": { + "code-to-signal": "^1.0.2", "tap": "^2.3.0" } } diff --git a/test/basic.js b/test/basic.js index 33de9be..a64744a 100644 --- a/test/basic.js +++ b/test/basic.js @@ -1,6 +1,6 @@ var sw = require('../') var onExit = require('signal-exit') - +var codeToSignal = require('code-to-signal') var cp = require('child_process') var fixture = require.resolve('./fixtures/script.js') var fs = require('fs') @@ -72,11 +72,12 @@ t.test('SIGHUP', function (t) { var out = '' child.stdout.on('data', function (c) { + var pid = process.env.TRAVIS ? child.pid + 1 : child.pid out += c - child.kill('SIGHUP') + process.kill(pid, 'SIGHUP') }) child.on('close', function (code, signal) { - t.equal(code, null) + if (process.env.TRAVIS) signal = codeToSignal(code) t.equal(signal, 'SIGHUP') t.equal(out, 'WRAP ["{{FIXTURE}}","xyz"]\n' + '[]\n' + @@ -95,7 +96,8 @@ t.test('SIGINT', function (t) { out += c }) child.stdout.once('data', function () { - child.kill('SIGINT') + var pid = process.env.TRAVIS ? child.pid + 1 : child.pid + process.kill(pid, 'SIGINT') }) child.stderr.on('data', function (t) { console.error(t) diff --git a/test/win-rebase.js b/test/win-rebase.js new file mode 100644 index 0000000..4694f4b --- /dev/null +++ b/test/win-rebase.js @@ -0,0 +1,20 @@ +var t = require('tap') +var winRebase = require('../lib/win-rebase') + +t.test('it replaces path to node bin', function (t) { + var result = winRebase('C:\\Program Files\\nodejs\\node.exe', 'C:\\foo') + t.equal(result, 'C:\\foo') + t.done() +}) + +t.test('it does not replace path if it references an unknown bin', function (t) { + var result = winRebase('C:\\Program Files\\nodejs\\banana', 'C:\\foo') + t.equal(result, 'C:\\Program Files\\nodejs\\banana') + t.done() +}) + +t.test('replaces node bin and leaves the script being executed', function (t) { + var result = winRebase('C:\\Program Files\\nodejs\\node.exe foo.js', 'C:\\foo') + t.equal(result, 'C:\\foo foo.js') + t.done() +})