From d6a162fc336c1e162cfa0ed4b98301a102a4727b Mon Sep 17 00:00:00 2001 From: Justin Searls Date: Sun, 10 Apr 2016 20:42:44 -0400 Subject: [PATCH 01/10] Windows is always executable (Untested. Windows test requires windows) --- lib/resolve-script/is-executable.js | 3 ++- lib/resolve-script/is-executable.test.js | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/resolve-script/is-executable.js b/lib/resolve-script/is-executable.js index ec81a18..f06d93b 100644 --- a/lib/resolve-script/is-executable.js +++ b/lib/resolve-script/is-executable.js @@ -1,14 +1,15 @@ var fs = require('fs') module.exports = function (path, cb) { + if (process.platform === 'win32') return cb(null, true) fs.stat(path, function (er, stats) { + if (er) return cb(er) var mode = stats.mode var owner = mode >> 6 var group = (mode << 3) >> 6 var others = (mode << 6) >> 6 - if (er) return cb(er) cb(er, !!(owner & 1) || !!(group & 1) || !!(others & 1)) }) } diff --git a/lib/resolve-script/is-executable.test.js b/lib/resolve-script/is-executable.test.js index ffe76ed..0e00897 100644 --- a/lib/resolve-script/is-executable.test.js +++ b/lib/resolve-script/is-executable.test.js @@ -38,5 +38,12 @@ module.exports = { assert.equal(answer, false) done(er) }) + }, + anyWindowsIsAllX: function (done) { + if (process.platform !== 'win32') return done() + subject(root + '/silly-lololo', function (er, answer) { + assert.equal(answer, true) + done(er) + }) } } From 3cbfdd8379db2def2b1b699329dcc9f0ec671cb3 Mon Sep 17 00:00:00 2001 From: Justin Searls Date: Sun, 10 Apr 2016 20:49:40 -0400 Subject: [PATCH 02/10] Fix obvious forward-slashing that'll break windows --- lib/resolve-script/generate-glob.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/resolve-script/generate-glob.js b/lib/resolve-script/generate-glob.js index 6e9fd0b..1d49c62 100644 --- a/lib/resolve-script/generate-glob.js +++ b/lib/resolve-script/generate-glob.js @@ -2,12 +2,12 @@ var path = require('path') var fs = require('fs') module.exports = function (dir1, dir2) { - var expanded = path.resolve(dir1, dir2.replace(/\:/g, '/')) + var expanded = path.resolve(dir1, path.join.apply(this, dir2.split(':'))) if (isDir(expanded)) { if (containsIndexFile(expanded)) { - return expanded + '/index*' + return path.join(expanded, '/index') + '*' } else { - return expanded + '/*' + return path.join(expanded, '/') + '*' } } else { return expanded + '*' From 9e445cc490678d505ba9ac459449549bc8300f2f Mon Sep 17 00:00:00 2001 From: Justin Searls Date: Sun, 10 Apr 2016 20:54:07 -0400 Subject: [PATCH 03/10] slashes. --- lib/resolve-script/generate-glob.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/resolve-script/generate-glob.js b/lib/resolve-script/generate-glob.js index 1d49c62..c7e5707 100644 --- a/lib/resolve-script/generate-glob.js +++ b/lib/resolve-script/generate-glob.js @@ -5,7 +5,7 @@ module.exports = function (dir1, dir2) { var expanded = path.resolve(dir1, path.join.apply(this, dir2.split(':'))) if (isDir(expanded)) { if (containsIndexFile(expanded)) { - return path.join(expanded, '/index') + '*' + return path.join(expanded, 'index') + '*' } else { return path.join(expanded, '/') + '*' } From 1e950b2d53d7550f4f78c69286cd21cea9854431 Mon Sep 17 00:00:00 2001 From: Justin Searls Date: Mon, 11 Apr 2016 19:36:39 -0700 Subject: [PATCH 04/10] Fix generate-glob unit test on windows --- lib/resolve-script/generate-glob.test.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/resolve-script/generate-glob.test.js b/lib/resolve-script/generate-glob.test.js index a8cf26c..f5da0cc 100644 --- a/lib/resolve-script/generate-glob.test.js +++ b/lib/resolve-script/generate-glob.test.js @@ -1,23 +1,27 @@ var path = require('path') +var base = path.resolve('test/fixtures/user-scripts') module.exports = { beforeEach: function () { this.subject = require('./generate-glob') - this.root = path.resolve('test/fixtures/user-scripts') }, fileInADir: function () { - assert.equal(this.root + '/foo/bar*', this.subject(this.root, 'foo:bar')) + assert.equal(this.subject(base, 'foo:bar'), globFor('foo/bar')) }, nonExistentFile: function () { - assert.equal(this.root + '/fake/stuff*', this.subject(this.root, 'fake:stuff')) + assert.equal(this.subject(base, 'fake:stuff'), globFor('fake/stuff')) }, dirWithNoIndex: function () { - assert.equal(this.root + '/baz/*', this.subject(this.root, 'baz')) + assert.equal(this.subject(base, 'baz'), globFor('baz/')) }, dirWithAnIndexFile: function () { - assert.equal(this.root + '/car/index*', this.subject(this.root, 'car')) + assert.equal(this.subject(base, 'car'), globFor('car/index')) }, dirWithADirNamedIndex: function () { - assert.equal(this.root + '/dog/*', this.subject(this.root, 'dog')) + assert.equal(this.subject(base, 'dog'), globFor('dog/')) } } + +function globFor (partialPath) { + return path.join(base, partialPath) + '*' +} From 726a4c4043a9192baaf5a29d72544812cec04af5 Mon Sep 17 00:00:00 2001 From: Justin Searls Date: Mon, 11 Apr 2016 19:37:52 -0700 Subject: [PATCH 05/10] Fix test for windows This test can't pass on windows --- lib/resolve-script/is-executable.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/resolve-script/is-executable.test.js b/lib/resolve-script/is-executable.test.js index 0e00897..05f3467 100644 --- a/lib/resolve-script/is-executable.test.js +++ b/lib/resolve-script/is-executable.test.js @@ -33,6 +33,7 @@ module.exports = { }) }, noXIsNotX: function (done) { + if (process.platform === 'win32') return done() fs.chmodSync(root + '/no-x', '644') subject(root + '/no-x', function (er, answer) { assert.equal(answer, false) From 2ce11e06a035b8ac834806630685bd7c01b5769f Mon Sep 17 00:00:00 2001 From: Justin Searls Date: Mon, 11 Apr 2016 19:51:33 -0700 Subject: [PATCH 06/10] Fix test for windows --- lib/resolve-script/find-executables.js | 4 ++-- lib/resolve-script/find-executables.test.js | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/resolve-script/find-executables.js b/lib/resolve-script/find-executables.js index 86e7dae..fac8e6f 100644 --- a/lib/resolve-script/find-executables.js +++ b/lib/resolve-script/find-executables.js @@ -1,4 +1,5 @@ var glob = require('glob') +var path = require('path') var async = require('async') var isExecutable = require('./is-executable') var _ = require('lodash') @@ -9,7 +10,7 @@ module.exports = function (pattern, cb) { async.map(results, function (result, cb) { isExecutable(result, function (er, itIsExecutable) { if (itIsExecutable) { - cb(er, result) + cb(er, path.resolve(result)) } else { console.warn( 'Warning: scripty - ignoring script "' + result + '" because it' + @@ -24,4 +25,3 @@ module.exports = function (pattern, cb) { }) }) } - diff --git a/lib/resolve-script/find-executables.test.js b/lib/resolve-script/find-executables.test.js index 11618c3..e59baee 100644 --- a/lib/resolve-script/find-executables.test.js +++ b/lib/resolve-script/find-executables.test.js @@ -17,8 +17,6 @@ module.exports = { }) }, noFilesFound: function (done) { - fs.writeFileSync(this.foo1, 'hi') - this.subject(path.resolve(__dirname, 'foo*'), function (er, result) { assert.deepEqual(result, []) done(er) @@ -34,6 +32,7 @@ module.exports = { }.bind(this)) }, oneFileFoundWithOneNonExecutable: function (done) { + if (process.platform === 'win32') return done() fs.writeFileSync(this.foo1, 'hi') fs.writeFileSync(this.foo2, 'hi') exec('chmod +x "' + this.foo1 + '"', function () { From ca307337c73347f5cdfd951ce86b445e72287173 Mon Sep 17 00:00:00 2001 From: Justin Searls Date: Mon, 11 Apr 2016 20:37:48 -0700 Subject: [PATCH 07/10] Fix tests for windows No idea why windows hated the multi-line assertion test, but gave up trying to figure out why. --- lib/print-script.test.js | 9 ++------- lib/resolve-script/index.test.js | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/lib/print-script.test.js b/lib/print-script.test.js index fd5458e..b5539db 100644 --- a/lib/print-script.test.js +++ b/lib/print-script.test.js @@ -13,13 +13,8 @@ module.exports = { this.subject(script) assert.includes(log.read(), 'Executing "' + script + '":\n') - assert.includes(log.read(), - '> #!/usr/bin/env sh\n' + - '> \n' + - '> npm test -- --debug-brk\n' + - '> \n' + - '\n' - ) + assert.includes(log.read(), '> #!/usr/bin/env sh') + assert.includes(log.read(), '> npm test -- --debug-brk') }, sadPath: function () { var script = '/silly/nonsense' diff --git a/lib/resolve-script/index.test.js b/lib/resolve-script/index.test.js index 44d56ba..779ac50 100644 --- a/lib/resolve-script/index.test.js +++ b/lib/resolve-script/index.test.js @@ -8,7 +8,7 @@ module.exports = { this.subject = require('./index') this.scriptsDir = path.resolve(__dirname, '../../scripts') - td.when(this.generateGlob('/user-dir/scripts', 'fake')).thenReturn('glob1') + td.when(this.generateGlob(path.resolve('/user-dir/scripts'), 'fake')).thenReturn('glob1') td.when(this.generateGlob(this.scriptsDir, 'fake')).thenReturn('glob2') }, bothUserAndBuiltInScriptsExist: function (done) { From 757d16edb1e94af9ac388a8a7db9018292ff9b11 Mon Sep 17 00:00:00 2001 From: Justin Searls Date: Mon, 11 Apr 2016 21:46:09 -0700 Subject: [PATCH 08/10] Get basic-test passing on Windows Copy all our fixtures to have windows-friendly equivalents. --- scripts-win/noop.cmd | 1 + test/fixtures/built-in-scripts-win/hello/world.cmd | 5 +++++ test/fixtures/user-scripts-win/baz/.keep | 0 test/fixtures/user-scripts-win/car/index | 0 test/fixtures/user-scripts-win/dog/index/.keep | 0 test/fixtures/user-scripts-win/fail.cmd | 3 +++ test/fixtures/user-scripts-win/foo/bar | 0 test/fixtures/user-scripts-win/parent/a | 3 +++ test/fixtures/user-scripts-win/parent/b | 3 +++ test/fixtures/user-scripts-win/parent/c | 3 +++ test/fixtures/user-scripts-win/top/index.cmd | 3 +++ test/run-scripty.js | 13 +++++++++++-- test/safe/basic-test.js | 14 ++++++++++---- 13 files changed, 42 insertions(+), 6 deletions(-) create mode 100644 scripts-win/noop.cmd create mode 100644 test/fixtures/built-in-scripts-win/hello/world.cmd create mode 100644 test/fixtures/user-scripts-win/baz/.keep create mode 100644 test/fixtures/user-scripts-win/car/index create mode 100644 test/fixtures/user-scripts-win/dog/index/.keep create mode 100644 test/fixtures/user-scripts-win/fail.cmd create mode 100644 test/fixtures/user-scripts-win/foo/bar create mode 100644 test/fixtures/user-scripts-win/parent/a create mode 100644 test/fixtures/user-scripts-win/parent/b create mode 100644 test/fixtures/user-scripts-win/parent/c create mode 100644 test/fixtures/user-scripts-win/top/index.cmd diff --git a/scripts-win/noop.cmd b/scripts-win/noop.cmd new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/scripts-win/noop.cmd @@ -0,0 +1 @@ + diff --git a/test/fixtures/built-in-scripts-win/hello/world.cmd b/test/fixtures/built-in-scripts-win/hello/world.cmd new file mode 100644 index 0000000..7b7f894 --- /dev/null +++ b/test/fixtures/built-in-scripts-win/hello/world.cmd @@ -0,0 +1,5 @@ +@ECHO OFF + +SET WORLD=World + +ECHO Hello, %WORLD%! diff --git a/test/fixtures/user-scripts-win/baz/.keep b/test/fixtures/user-scripts-win/baz/.keep new file mode 100644 index 0000000..e69de29 diff --git a/test/fixtures/user-scripts-win/car/index b/test/fixtures/user-scripts-win/car/index new file mode 100644 index 0000000..e69de29 diff --git a/test/fixtures/user-scripts-win/dog/index/.keep b/test/fixtures/user-scripts-win/dog/index/.keep new file mode 100644 index 0000000..e69de29 diff --git a/test/fixtures/user-scripts-win/fail.cmd b/test/fixtures/user-scripts-win/fail.cmd new file mode 100644 index 0000000..b2badb4 --- /dev/null +++ b/test/fixtures/user-scripts-win/fail.cmd @@ -0,0 +1,3 @@ +@ECHO OFF + +type C:\silly\nonsense diff --git a/test/fixtures/user-scripts-win/foo/bar b/test/fixtures/user-scripts-win/foo/bar new file mode 100644 index 0000000..e69de29 diff --git a/test/fixtures/user-scripts-win/parent/a b/test/fixtures/user-scripts-win/parent/a new file mode 100644 index 0000000..e28ae93 --- /dev/null +++ b/test/fixtures/user-scripts-win/parent/a @@ -0,0 +1,3 @@ +@ECHO OFF + +ECHO AAA diff --git a/test/fixtures/user-scripts-win/parent/b b/test/fixtures/user-scripts-win/parent/b new file mode 100644 index 0000000..d658413 --- /dev/null +++ b/test/fixtures/user-scripts-win/parent/b @@ -0,0 +1,3 @@ +@ECHO OFF + +ECHO BBB diff --git a/test/fixtures/user-scripts-win/parent/c b/test/fixtures/user-scripts-win/parent/c new file mode 100644 index 0000000..bf445d9 --- /dev/null +++ b/test/fixtures/user-scripts-win/parent/c @@ -0,0 +1,3 @@ +@ECHO OFF + +ECHO CCC diff --git a/test/fixtures/user-scripts-win/top/index.cmd b/test/fixtures/user-scripts-win/top/index.cmd new file mode 100644 index 0000000..19c2b75 --- /dev/null +++ b/test/fixtures/user-scripts-win/top/index.cmd @@ -0,0 +1,3 @@ +@ECHO OFF + +ECHO rubby diff --git a/test/run-scripty.js b/test/run-scripty.js index 2eaccec..66eb4a1 100644 --- a/test/run-scripty.js +++ b/test/run-scripty.js @@ -4,13 +4,22 @@ var path = require('path') var scripty = require('../index') var grabStdio = require('./grab-stdio') +var builtInPath, userPath +if (process.platform === 'win32') { + builtInPath = path.resolve('test/fixtures/built-in-scripts-win') + userPath = path.resolve('test/fixtures/user-scripts-win') +} else { + builtInPath = path.resolve('test/fixtures/built-in-scripts') + userPath = path.resolve('test/fixtures/user-scripts') +} + module.exports = function (name, opts, cb) { var stdio = {} scripty(name, _.extend({}, { resolve: { - builtIn: path.resolve('test/fixtures/built-in-scripts'), - scripts: path.resolve('test/fixtures/user-scripts') + builtIn: builtInPath, + scripts: userPath }, spawn: { tap: grabStdio(stdio) diff --git a/test/safe/basic-test.js b/test/safe/basic-test.js index e2eda13..5368649 100644 --- a/test/safe/basic-test.js +++ b/test/safe/basic-test.js @@ -5,7 +5,11 @@ module.exports = { outputAndRunScript: function (done) { runScripty('hello:world', {}, function (er, code, stdio) { assert.equal(0, code) - assert.includes(log.read(), '> echo "Hello, $WORLD!"') + if (process.platform === 'win32') { + assert.includes(log.read(), '> ECHO Hello, %WORLD%!') + } else { + assert.includes(log.read(), '> echo "Hello, $WORLD!') + } assert.includes(stdio.stdout, 'Hello, World!') done(er) @@ -28,9 +32,11 @@ module.exports = { 'Error: scripty - script "fail" failed by exiting ' + 'with a non-zero code (' + code + ').' ) - assert.includes(stdio.stderr, - 'cat: /silly/nonsense: No such file or directory' - ) + if (process.platform === 'win32') { + assert.includes(stdio.stderr, 'The system cannot find the path specified.') + } else { + assert.includes(stdio.stderr, 'cat: /silly/nonsense: No such file or directory') + } done(null) }) } From 66730f7527f4596911a22b01606b9274cbd9c63e Mon Sep 17 00:00:00 2001 From: Justin Searls Date: Mon, 11 Apr 2016 21:47:40 -0700 Subject: [PATCH 09/10] Fix dir-test --- test/fixtures/user-scripts-win/parent/{a => a.cmd} | 0 test/fixtures/user-scripts-win/parent/{b => b.cmd} | 0 test/fixtures/user-scripts-win/parent/{c => c.cmd} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename test/fixtures/user-scripts-win/parent/{a => a.cmd} (100%) rename test/fixtures/user-scripts-win/parent/{b => b.cmd} (100%) rename test/fixtures/user-scripts-win/parent/{c => c.cmd} (100%) diff --git a/test/fixtures/user-scripts-win/parent/a b/test/fixtures/user-scripts-win/parent/a.cmd similarity index 100% rename from test/fixtures/user-scripts-win/parent/a rename to test/fixtures/user-scripts-win/parent/a.cmd diff --git a/test/fixtures/user-scripts-win/parent/b b/test/fixtures/user-scripts-win/parent/b.cmd similarity index 100% rename from test/fixtures/user-scripts-win/parent/b rename to test/fixtures/user-scripts-win/parent/b.cmd diff --git a/test/fixtures/user-scripts-win/parent/c b/test/fixtures/user-scripts-win/parent/c.cmd similarity index 100% rename from test/fixtures/user-scripts-win/parent/c rename to test/fixtures/user-scripts-win/parent/c.cmd From e57344c22e772a694c4c02410705a8da06e4fb49 Mon Sep 17 00:00:00 2001 From: Justin Searls Date: Mon, 11 Apr 2016 22:29:39 -0700 Subject: [PATCH 10/10] Woot! All tests passing on windows --- lib/resolve-script/index.js | 10 ++++------ lib/resolve-script/index.test.js | 9 +++++---- lib/resolve-script/script-dirs.js | 19 +++++++++++++++++++ lib/resolve-script/script-dirs.test.js | 26 ++++++++++++++++++++++++++ 4 files changed, 54 insertions(+), 10 deletions(-) create mode 100644 lib/resolve-script/script-dirs.js create mode 100644 lib/resolve-script/script-dirs.test.js diff --git a/lib/resolve-script/index.js b/lib/resolve-script/index.js index 56382ec..ebc2a4e 100644 --- a/lib/resolve-script/index.js +++ b/lib/resolve-script/index.js @@ -1,17 +1,15 @@ -var path = require('path') - var generateGlob = require('./generate-glob') var findExecutables = require('./find-executables') +var scriptDirs = require('./script-dirs') module.exports = function (name, options, cb) { - var userDir = options.scripts || path.resolve(process.cwd(), 'scripts') - var userGlob = generateGlob(userDir, name) + var dirs = scriptDirs(options) + var userGlob = generateGlob(dirs.userDir, name) findExecutables(userGlob, function (er, userPaths) { if (userPaths.length > 0) { cb(er, userPaths) } else { - var ourDir = options.builtIn || path.resolve(__dirname, '../../scripts') - var ourGlob = generateGlob(ourDir, name) + var ourGlob = generateGlob(dirs.ourDir, name) findExecutables(ourGlob, function (er, ourPaths) { if (ourPaths.length > 0) { cb(er, ourPaths) diff --git a/lib/resolve-script/index.test.js b/lib/resolve-script/index.test.js index 779ac50..509e643 100644 --- a/lib/resolve-script/index.test.js +++ b/lib/resolve-script/index.test.js @@ -1,15 +1,16 @@ -var path = require('path') +var isA = td.matchers.isA module.exports = { beforeEach: function () { td.when(td.replace(process, 'cwd')()).thenReturn('/user-dir') this.generateGlob = td.replace('./generate-glob') this.findExecutables = td.replace('./find-executables') + this.scriptDirs = td.replace('./script-dirs') this.subject = require('./index') - this.scriptsDir = path.resolve(__dirname, '../../scripts') - td.when(this.generateGlob(path.resolve('/user-dir/scripts'), 'fake')).thenReturn('glob1') - td.when(this.generateGlob(this.scriptsDir, 'fake')).thenReturn('glob2') + td.when(this.scriptDirs(isA(Object))).thenReturn({userDir: 'A', ourDir: 'B'}) + td.when(this.generateGlob('A', 'fake')).thenReturn('glob1') + td.when(this.generateGlob('B', 'fake')).thenReturn('glob2') }, bothUserAndBuiltInScriptsExist: function (done) { td.when(this.findExecutables('glob1')).thenCallback(null, ['user-path']) diff --git a/lib/resolve-script/script-dirs.js b/lib/resolve-script/script-dirs.js new file mode 100644 index 0000000..29c3293 --- /dev/null +++ b/lib/resolve-script/script-dirs.js @@ -0,0 +1,19 @@ +var path = require('path') +var fs = require('fs') + +module.exports = function (options) { + return { + userDir: findDir(process.cwd(), options.scripts), + ourDir: findDir(path.resolve(__dirname, '../..'), options.builtIn) + } +} + +function findDir (base, custom) { + if (custom) { + return custom + } else if (process.platform === 'win32' && fs.existsSync(path.resolve(base, 'scripts-win'))) { + return path.resolve(base, 'scripts-win') + } else { + return path.resolve(base, 'scripts') + } +} diff --git a/lib/resolve-script/script-dirs.test.js b/lib/resolve-script/script-dirs.test.js new file mode 100644 index 0000000..97f6779 --- /dev/null +++ b/lib/resolve-script/script-dirs.test.js @@ -0,0 +1,26 @@ +var path = require('path') + +var subject = require('./script-dirs') + +module.exports = { + optionSet: function () { + assert.equal(subject({scripts: 'A'}).userDir, 'A') + assert.equal(subject({builtIn: 'B'}).ourDir, 'B') + }, + noOptionSet: function () { + var dirName = process.platform === 'win32' ? 'scripts-win' : 'scripts' + + var result = subject({}) + + assert.equal(result.userDir, path.resolve(process.cwd(), dirName)) + assert.equal(result.ourDir, path.resolve(__dirname, '../..', dirName)) + }, + onWindowsAndNoScriptsWinAssumesScripts: function () { + if (process.platform !== 'win32') return + td.when(td.replace(process, 'cwd')()).thenReturn(__dirname) + + var result = subject({}) + + assert.equal(result.userDir, path.resolve(process.cwd(), 'scripts')) + } +}