From 9f0262640a278443546518dfa4f7f80a58173145 Mon Sep 17 00:00:00 2001 From: Benjamin Coe Date: Mon, 7 Sep 2015 20:25:16 -0700 Subject: [PATCH 01/10] a couple tweaks to make things work on windows --- index.js | 34 +++++++++++++--------------------- lib/is-windows.js | 5 +++++ lib/win-rebase.js | 7 +++++++ package.json | 4 +++- test/basic.js | 9 +++++++-- test/win-rebase.js | 20 ++++++++++++++++++++ 6 files changed, 55 insertions(+), 24 deletions(-) create mode 100644 lib/is-windows.js create mode 100644 lib/win-rebase.js create mode 100644 test/win-rebase.js diff --git a/index.js b/index.js index f9167fa..3cc4a40 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. @@ -215,6 +201,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..eca0886 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,8 @@ }, "homepage": "https://github.com/isaacs/spawn-wrap#readme", "devDependencies": { - "tap": "^2.3.0" + "tap": "^2.3.0", + "tap": "^1.1.0", + "win-spawn": "^2.0.0" } } diff --git a/test/basic.js b/test/basic.js index 33de9be..fa36a5d 100644 --- a/test/basic.js +++ b/test/basic.js @@ -2,6 +2,8 @@ var sw = require('../') var onExit = require('signal-exit') var cp = require('child_process') +var isWindows = require('../lib/is-windows')() +var spawn = require('win-spawn') var fixture = require.resolve('./fixtures/script.js') var fs = require('fs') var path = require('path') @@ -38,7 +40,7 @@ var expect = 'WRAP ["{{FIXTURE}}","xyz"]\n' + 'EXIT [0,null]\n' t.test('spawn execPath', function (t) { - var child = cp.spawn(process.execPath, [fixture, 'xyz']) + var child = spawn(process.execPath, [fixture, 'xyz']) var out = '' child.stdout.on('data', function (c) { @@ -52,6 +54,7 @@ t.test('spawn execPath', function (t) { }) }) +if (!isWindows) t.test('exec shebang', function (t) { var child = cp.exec(fixture + ' xyz') @@ -67,6 +70,7 @@ t.test('exec shebang', function (t) { }) }) +if (!isWindows) t.test('SIGHUP', function (t) { var child = cp.exec(fixture + ' xyz') @@ -87,6 +91,7 @@ t.test('SIGHUP', function (t) { }) }) +if (!isWindows) t.test('SIGINT', function (t) { var child = cp.exec(fixture + ' xyz') @@ -114,7 +119,7 @@ t.test('SIGINT', function (t) { t.test('--harmony', function (t) { var node = process.execPath - var child = cp.spawn(node, ['--harmony', fixture, 'xyz']) + var child = spawn(node, ['--harmony', fixture, 'xyz']) var out = '' child.stdout.on('data', function (c) { out += c 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() +}) From 8475c8a22f17aa58bda8c1b04025fcea71062667 Mon Sep 17 00:00:00 2001 From: Benjamin Coe Date: Mon, 7 Sep 2015 20:31:18 -0700 Subject: [PATCH 02/10] disable one more test, enable another --- test/basic.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/basic.js b/test/basic.js index fa36a5d..e0d2eb7 100644 --- a/test/basic.js +++ b/test/basic.js @@ -54,9 +54,8 @@ t.test('spawn execPath', function (t) { }) }) -if (!isWindows) t.test('exec shebang', function (t) { - var child = cp.exec(fixture + ' xyz') + var child = spawn(fixture, ['xyz']) var out = '' child.stdout.on('data', function (c) { @@ -117,6 +116,7 @@ t.test('SIGINT', function (t) { }) }) +if (!isWindows) t.test('--harmony', function (t) { var node = process.execPath var child = spawn(node, ['--harmony', fixture, 'xyz']) From 2716443b86ae4fbd8a591e30fb0ba5ca6977c893 Mon Sep 17 00:00:00 2001 From: Benjamin Coe Date: Mon, 7 Sep 2015 22:09:11 -0700 Subject: [PATCH 03/10] whoops, was missing a + --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 3cc4a40..e693889 100644 --- a/index.js +++ b/index.js @@ -202,7 +202,7 @@ function setup (argv, env) { workingDir = fs.realpathSync(workingDir) if (isWindows) { var cmdShim = - '@echo off\r\n' + '@echo off\r\n' + 'SETLOCAL\r\n' + 'SET PATHEXT=%PATHEXT:;.JS;=;%\r\n' + '"' + process.execPath + '"' + ' "%~dp0\\.\\node" %*\r\n' From 20a4957d7c0604825569c4e7472f5163e2ec7b9e Mon Sep 17 00:00:00 2001 From: Benjamin Coe Date: Wed, 9 Dec 2015 00:02:54 -0800 Subject: [PATCH 04/10] make Windows run the shim --- .gitignore | 1 + index.js | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 .gitignore 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 e693889..b4e229c 100644 --- a/index.js +++ b/index.js @@ -130,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 From 1c87b8ccce216ecafa428b0b0d7f3916304a78f6 Mon Sep 17 00:00:00 2001 From: Benjamin Coe Date: Wed, 23 Dec 2015 18:30:03 -0800 Subject: [PATCH 05/10] move tests to spawn --- test/basic.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/basic.js b/test/basic.js index e0d2eb7..c695fd0 100644 --- a/test/basic.js +++ b/test/basic.js @@ -1,7 +1,6 @@ var sw = require('../') var onExit = require('signal-exit') -var cp = require('child_process') var isWindows = require('../lib/is-windows')() var spawn = require('win-spawn') var fixture = require.resolve('./fixtures/script.js') @@ -71,7 +70,7 @@ t.test('exec shebang', function (t) { if (!isWindows) t.test('SIGHUP', function (t) { - var child = cp.exec(fixture + ' xyz') + var child = spawn(fixture, ['xyz']) var out = '' child.stdout.on('data', function (c) { @@ -92,7 +91,7 @@ t.test('SIGHUP', function (t) { if (!isWindows) t.test('SIGINT', function (t) { - var child = cp.exec(fixture + ' xyz') + var child = spawn(fixture, ['xyz']) var out = '' child.stdout.on('data', function (c) { @@ -140,7 +139,7 @@ t.test('node exe with different name', function(t) { var data = fs.readFileSync(process.execPath) fs.writeFileSync(fp, data) fs.chmodSync(fp, '0775') - var child = cp.spawn(process.execPath, [fixture, 'xyz']) + var child = spawn(process.execPath, [fixture, 'xyz']) var out = '' child.stdout.on('data', function (c) { From cb1fadaf7ee3e0d6edb791dc2cb38b361d2deea6 Mon Sep 17 00:00:00 2001 From: Benjamin Coe Date: Wed, 23 Dec 2015 18:43:47 -0800 Subject: [PATCH 06/10] harmony test works in Windows --- test/basic.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/basic.js b/test/basic.js index c695fd0..00fabac 100644 --- a/test/basic.js +++ b/test/basic.js @@ -115,7 +115,6 @@ t.test('SIGINT', function (t) { }) }) -if (!isWindows) t.test('--harmony', function (t) { var node = process.execPath var child = spawn(node, ['--harmony', fixture, 'xyz']) From f2d819712445bb0a3b0f662ee6a003d91c9e1e24 Mon Sep 17 00:00:00 2001 From: Benjamin Coe Date: Thu, 24 Dec 2015 20:31:07 -0800 Subject: [PATCH 07/10] remove win-spawn, as-per @isaacs' code-review --- package.json | 4 +--- test/basic.js | 3 --- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/package.json b/package.json index eca0886..b282867 100644 --- a/package.json +++ b/package.json @@ -24,8 +24,6 @@ }, "homepage": "https://github.com/isaacs/spawn-wrap#readme", "devDependencies": { - "tap": "^2.3.0", - "tap": "^1.1.0", - "win-spawn": "^2.0.0" + "tap": "^2.3.0" } } diff --git a/test/basic.js b/test/basic.js index 00fabac..61c7d55 100644 --- a/test/basic.js +++ b/test/basic.js @@ -1,7 +1,6 @@ var sw = require('../') var onExit = require('signal-exit') -var isWindows = require('../lib/is-windows')() var spawn = require('win-spawn') var fixture = require.resolve('./fixtures/script.js') var fs = require('fs') @@ -68,7 +67,6 @@ t.test('exec shebang', function (t) { }) }) -if (!isWindows) t.test('SIGHUP', function (t) { var child = spawn(fixture, ['xyz']) @@ -89,7 +87,6 @@ t.test('SIGHUP', function (t) { }) }) -if (!isWindows) t.test('SIGINT', function (t) { var child = spawn(fixture, ['xyz']) From 47cfd55c4dd033e659aa8112fa5cad0d0232b599 Mon Sep 17 00:00:00 2001 From: Benjamin Coe Date: Thu, 24 Dec 2015 20:33:19 -0800 Subject: [PATCH 08/10] actually stop pulling in win-spawn --- test/basic.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/basic.js b/test/basic.js index 61c7d55..3ae6b6f 100644 --- a/test/basic.js +++ b/test/basic.js @@ -1,7 +1,7 @@ var sw = require('../') var onExit = require('signal-exit') -var spawn = require('win-spawn') +var spawn = require('child_process').spawn var fixture = require.resolve('./fixtures/script.js') var fs = require('fs') var path = require('path') From fd338fe51199b2b1fc940c1e498af590de8dcb1a Mon Sep 17 00:00:00 2001 From: Benjamin Coe Date: Sat, 26 Dec 2015 16:21:45 -0800 Subject: [PATCH 09/10] handle shell-based exec() discrepancies --- test/basic.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/test/basic.js b/test/basic.js index 3ae6b6f..df1951c 100644 --- a/test/basic.js +++ b/test/basic.js @@ -1,7 +1,7 @@ var sw = require('../') var onExit = require('signal-exit') -var spawn = require('child_process').spawn +var cp = require('child_process') var fixture = require.resolve('./fixtures/script.js') var fs = require('fs') var path = require('path') @@ -38,7 +38,7 @@ var expect = 'WRAP ["{{FIXTURE}}","xyz"]\n' + 'EXIT [0,null]\n' t.test('spawn execPath', function (t) { - var child = spawn(process.execPath, [fixture, 'xyz']) + var child = cp.spawn(process.execPath, [fixture, 'xyz']) var out = '' child.stdout.on('data', function (c) { @@ -53,7 +53,7 @@ t.test('spawn execPath', function (t) { }) t.test('exec shebang', function (t) { - var child = spawn(fixture, ['xyz']) + var child = cp.exec(fixture + ' xyz') var out = '' child.stdout.on('data', function (c) { @@ -68,12 +68,13 @@ t.test('exec shebang', function (t) { }) t.test('SIGHUP', function (t) { - var child = spawn(fixture, ['xyz']) + var child = cp.exec(fixture + ' xyz') 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) @@ -88,14 +89,15 @@ t.test('SIGHUP', function (t) { }) t.test('SIGINT', function (t) { - var child = spawn(fixture, ['xyz']) + var child = cp.exec(fixture + ' xyz') var out = '' child.stdout.on('data', function (c) { 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) @@ -114,7 +116,7 @@ t.test('SIGINT', function (t) { t.test('--harmony', function (t) { var node = process.execPath - var child = spawn(node, ['--harmony', fixture, 'xyz']) + var child = cp.spawn(node, ['--harmony', fixture, 'xyz']) var out = '' child.stdout.on('data', function (c) { out += c @@ -135,7 +137,7 @@ t.test('node exe with different name', function(t) { var data = fs.readFileSync(process.execPath) fs.writeFileSync(fp, data) fs.chmodSync(fp, '0775') - var child = spawn(process.execPath, [fixture, 'xyz']) + var child = cp.spawn(process.execPath, [fixture, 'xyz']) var out = '' child.stdout.on('data', function (c) { From d7abc066e9bdbf723394b9fdbb25653801d05f28 Mon Sep 17 00:00:00 2001 From: Benjamin Coe Date: Sat, 26 Dec 2015 16:33:19 -0800 Subject: [PATCH 10/10] another tiny tweak for Travis --- package.json | 1 + test/basic.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) 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 df1951c..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') @@ -77,7 +77,7 @@ t.test('SIGHUP', function (t) { 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' +