diff options
author | Rebecca Turner <me@re-becca.org> | 2016-01-28 03:42:20 +0300 |
---|---|---|
committer | Rebecca Turner <me@re-becca.org> | 2016-01-29 01:58:48 +0300 |
commit | 9e5c84f1903748897e54f8ff099729ff744eab0f (patch) | |
tree | f42bed5ee7a8bdd3764f4d1df29a8287855756b5 /node_modules/which | |
parent | 375b9c42fe0c6de47ac2f92527354b2ea79b7968 (diff) |
which@1.2.4
Update `isexe` and fix bug in pathExt, in which files without extensions
would sometimes be preferred to files with extensions on Windows, even though
those without extensions aren't executable.
pathExt is a list of extensions that are considered executable (exe, cmd,
bat, com on Windows).
Credit: @isaacs
Diffstat (limited to 'node_modules/which')
-rw-r--r-- | node_modules/which/.npmignore | 3 | ||||
-rw-r--r-- | node_modules/which/node_modules/isexe/.npmignore | 2 | ||||
-rw-r--r-- | node_modules/which/node_modules/isexe/README.md | 51 | ||||
-rw-r--r-- | node_modules/which/node_modules/isexe/access.js | 15 | ||||
-rw-r--r-- | node_modules/which/node_modules/isexe/index.js | 59 | ||||
-rw-r--r-- | node_modules/which/node_modules/isexe/mode.js | 37 | ||||
-rw-r--r-- | node_modules/which/node_modules/isexe/package.json | 80 | ||||
-rw-r--r-- | node_modules/which/node_modules/isexe/test/basic.js | 211 | ||||
-rw-r--r-- | node_modules/which/node_modules/isexe/windows.js | 36 | ||||
-rw-r--r-- | node_modules/which/package.json | 38 | ||||
-rw-r--r-- | node_modules/which/test/basic.js | 33 | ||||
-rw-r--r-- | node_modules/which/test/windows.js | 10 | ||||
-rw-r--r-- | node_modules/which/which.js | 58 |
13 files changed, 572 insertions, 61 deletions
diff --git a/node_modules/which/.npmignore b/node_modules/which/.npmignore new file mode 100644 index 000000000..0ac606ffc --- /dev/null +++ b/node_modules/which/.npmignore @@ -0,0 +1,3 @@ +.nyc_output/ +coverage/ +node_modules/ diff --git a/node_modules/which/node_modules/isexe/.npmignore b/node_modules/which/node_modules/isexe/.npmignore new file mode 100644 index 000000000..c1cb757ac --- /dev/null +++ b/node_modules/which/node_modules/isexe/.npmignore @@ -0,0 +1,2 @@ +.nyc_output/ +coverage/ diff --git a/node_modules/which/node_modules/isexe/README.md b/node_modules/which/node_modules/isexe/README.md new file mode 100644 index 000000000..30995ad7d --- /dev/null +++ b/node_modules/which/node_modules/isexe/README.md @@ -0,0 +1,51 @@ +# isexe + +Minimal module to check if a file is executable. + +Uses `fs.access` if available, and tests against the `PATHEXT` +environment variable on Windows. + +## USAGE + +```javascript +var isexe = require('isexe') +isexe('some-file-name', function (err, isExe) { + if (err) { + console.error('probably file does not exist or something', err) + } else if (isExe) { + console.error('this thing can be run') + } else { + console.error('cannot be run') + } +}) + +// same thing but synchronous, throws errors +var isExe = isexe.sync('some-file-name') + +// treat errors as just "not executable" +isexe('maybe-missing-file', { ignoreErrors: true }, callback) +var isExe = isexe.sync('maybe-missing-file', { ignoreErrors: true }) +``` + +## API + +### `isexe(path, [options], [callback])` + +Check if the path is executable. If no callback provided, and a +global `Promise` object is available, then a Promise will be returned. + +Will raise whatever errors may be raised by `fs.access` or `fs.stat`, +unless `options.ignoreErrors` is set to true. + +### `isexe.sync(path, [options])` + +Same as `isexe` but returns the value and throws any errors raised. + +### Options + +* `ignoreErrors` Treat all errors as "no, this is not executable", but + don't raise them. +* `uid` Number to use as the user id when using the `mode` approach. +* `gid` Number to use as the group id when using the `mode` approach. +* `pathExt` List of path extensions to use instead of `PATHEXT` + environment variable on Windows. diff --git a/node_modules/which/node_modules/isexe/access.js b/node_modules/which/node_modules/isexe/access.js new file mode 100644 index 000000000..e67b28bd6 --- /dev/null +++ b/node_modules/which/node_modules/isexe/access.js @@ -0,0 +1,15 @@ +module.exports = isexe +isexe.sync = sync + +var fs = require('fs') + +function isexe (path, _, cb) { + fs.access(path, fs.X_OK, function (er) { + cb(er, !er) + }) +} + +function sync (path, _) { + fs.accessSync(path, fs.X_OK) + return true +} diff --git a/node_modules/which/node_modules/isexe/index.js b/node_modules/which/node_modules/isexe/index.js new file mode 100644 index 000000000..ff8ef113b --- /dev/null +++ b/node_modules/which/node_modules/isexe/index.js @@ -0,0 +1,59 @@ +var fs = require('fs') +var core +if (process.platform === 'win32' || global.TESTING_WINDOWS) { + core = require('./windows.js') +} else if (typeof fs.access === 'function') { + core = require('./access.js') +} else { + core = require('./mode.js') +} + +module.exports = isexe +isexe.sync = sync + +function isexe (path, options, cb) { + if (typeof options === 'function') { + cb = options + options = {} + } + + if (!cb) { + if (typeof Promise !== 'function') { + throw new TypeError('callback not provided') + } + + return new Promise(function (resolve, reject) { + isexe(path, options || {}, function (er, is) { + if (er) { + reject(er) + } else { + resolve(is) + } + }) + }) + } + + core(path, options || {}, function (er, is) { + // ignore EACCES because that just means we aren't allowed to run it + if (er) { + if (er.code === 'EACCES' || options && options.ignoreErrors) { + er = null + is = false + } + } + cb(er, is) + }) +} + +function sync (path, options) { + // my kingdom for a filtered catch + try { + return core.sync(path, options || {}) + } catch (er) { + if (options && options.ignoreErrors || er.code === 'EACCES') { + return false + } else { + throw er + } + } +} diff --git a/node_modules/which/node_modules/isexe/mode.js b/node_modules/which/node_modules/isexe/mode.js new file mode 100644 index 000000000..204428072 --- /dev/null +++ b/node_modules/which/node_modules/isexe/mode.js @@ -0,0 +1,37 @@ +module.exports = isexe +isexe.sync = sync + +var fs = require('fs') + +function isexe (path, options, cb) { + fs.stat(path, function (er, st) { + cb(er, er ? false : checkMode(st, options)) + }) +} + +function sync (path, options) { + return checkMode(fs.statSync(path), options) +} + +function checkMode (stat, options) { + var mod = stat.mode + var uid = stat.uid + var gid = stat.gid + + var myUid = options.uid !== undefined ? + options.uid : process.getuid && process.getuid() + var myGid = options.gid !== undefined ? + options.gid : process.getgid && process.getgid() + + var u = parseInt('100', 8) + var g = parseInt('010', 8) + var o = parseInt('001', 8) + var ug = u | g + + var ret = (mod & o) || + (mod & g) && gid === myGid || + (mod & u) && uid === myUid || + (mod & ug) && myUid === 0 + + return ret +} diff --git a/node_modules/which/node_modules/isexe/package.json b/node_modules/which/node_modules/isexe/package.json new file mode 100644 index 000000000..49aeeab2a --- /dev/null +++ b/node_modules/which/node_modules/isexe/package.json @@ -0,0 +1,80 @@ +{ + "_args": [ + [ + "isexe@^1.1.1", + "/Users/rebecca/code/npm/node_modules/which" + ] + ], + "_from": "isexe@>=1.1.1 <2.0.0", + "_id": "isexe@1.1.1", + "_inCache": true, + "_installable": true, + "_location": "/which/isexe", + "_nodeVersion": "4.0.0", + "_npmUser": { + "email": "i@izs.me", + "name": "isaacs" + }, + "_npmVersion": "2.14.15", + "_phantomChildren": {}, + "_requested": { + "name": "isexe", + "raw": "isexe@^1.1.1", + "rawSpec": "^1.1.1", + "scope": null, + "spec": ">=1.1.1 <2.0.0", + "type": "range" + }, + "_requiredBy": [ + "/which" + ], + "_resolved": "https://registry.npmjs.org/isexe/-/isexe-1.1.1.tgz", + "_shasum": "f0d4793ed2fb5c46bfdeab760bbb965f4485a66c", + "_shrinkwrap": null, + "_spec": "isexe@^1.1.1", + "_where": "/Users/rebecca/code/npm/node_modules/which", + "author": { + "email": "i@izs.me", + "name": "Isaac Z. Schlueter", + "url": "http://blog.izs.me/" + }, + "bugs": { + "url": "https://github.com/isaacs/isexe/issues" + }, + "dependencies": {}, + "description": "Minimal module to check if a file is executable.", + "devDependencies": { + "mkdirp": "^0.5.1", + "rimraf": "^2.5.0", + "tap": "^5.1.2" + }, + "directories": { + "test": "test" + }, + "dist": { + "shasum": "f0d4793ed2fb5c46bfdeab760bbb965f4485a66c", + "tarball": "http://registry.npmjs.org/isexe/-/isexe-1.1.1.tgz" + }, + "gitHead": "af83031caed58654ad9d20b98eb710d383618ad7", + "homepage": "https://github.com/isaacs/isexe#readme", + "keywords": [], + "license": "ISC", + "main": "index.js", + "maintainers": [ + { + "name": "isaacs", + "email": "i@izs.me" + } + ], + "name": "isexe", + "optionalDependencies": {}, + "readme": "ERROR: No README data found!", + "repository": { + "type": "git", + "url": "git+https://github.com/isaacs/isexe.git" + }, + "scripts": { + "test": "tap test/*.js --branches=100 --statements=100 --functions=100 --lines=100" + }, + "version": "1.1.1" +} diff --git a/node_modules/which/node_modules/isexe/test/basic.js b/node_modules/which/node_modules/isexe/test/basic.js new file mode 100644 index 000000000..969fc9a0a --- /dev/null +++ b/node_modules/which/node_modules/isexe/test/basic.js @@ -0,0 +1,211 @@ +var t = require('tap') +var fs = require('fs') +var path = require('path') +var fixture = path.resolve(__dirname, 'fixtures') +var meow = fixture + '/meow.cat' +var mine = fixture + '/mine.cat' +var ours = fixture + '/ours.cat' +var fail = fixture + '/fail.false' +var noent = fixture + '/enoent.exe' +var mkdirp = require('mkdirp') +var rimraf = require('rimraf') + +var isWindows = process.platform === 'win32' +var hasAccess = typeof fs.access === 'function' +var winSkip = isWindows && 'windows' +var accessSkip = !hasAccess && 'no fs.access function' +var hasPromise = typeof Promise === 'function' +var promiseSkip = !hasPromise && 'no global Promise' + +function reset () { + delete require.cache[require.resolve('../')] + return require('../') +} + +t.test('setup fixtures', function (t) { + rimraf.sync(fixture) + mkdirp.sync(fixture) + fs.writeFileSync(meow, '#!/usr/bin/env cat\nmeow\n') + fs.chmodSync(meow, parseInt('0755', 8)) + fs.writeFileSync(fail, '#!/usr/bin/env false\n') + fs.chmodSync(fail, parseInt('0644', 8)) + fs.writeFileSync(mine, '#!/usr/bin/env cat\nmine\n') + fs.chmodSync(mine, parseInt('0744', 8)) + fs.writeFileSync(ours, '#!/usr/bin/env cat\nours\n') + fs.chmodSync(ours, parseInt('0754', 8)) + t.end() +}) + +t.test('promise', { skip: promiseSkip }, function (t) { + var isexe = reset() + t.test('meow async', function (t) { + isexe(meow).then(function (is) { + t.ok(is) + t.end() + }) + }) + t.test('fail async', function (t) { + isexe(fail).then(function (is) { + t.notOk(is) + t.end() + }) + }) + t.test('noent async', function (t) { + isexe(noent).catch(function (er) { + t.ok(er) + t.end() + }) + }) + t.test('noent ignore async', function (t) { + isexe(noent, { ignoreErrors: true }).then(function (is) { + t.notOk(is) + t.end() + }) + }) + t.end() +}) + +t.test('no promise', function (t) { + global.Promise = null + var isexe = reset() + t.throws('try to meow a promise', function () { + isexe(meow) + }) + t.end() +}) + +t.test('access', { skip: accessSkip || winSkip }, function (t) { + runTest(t) +}) + +t.test('mode', { skip: winSkip }, function (t) { + delete fs.access + delete fs.accessSync + var isexe = reset() + t.ok(isexe.sync(ours, { uid: 0, gid: 0 })) + t.ok(isexe.sync(mine, { uid: 0, gid: 0 })) + runTest(t) +}) + +t.test('windows', function (t) { + global.TESTING_WINDOWS = true + var pathExt = '.EXE;.CAT;.CMD;.COM' + t.test('pathExt option', function (t) { + runTest(t, { pathExt: '.EXE;.CAT;.CMD;.COM' }) + }) + t.test('pathExt env', function (t) { + process.env.PATHEXT = pathExt + runTest(t) + }) + t.test('no pathExt', function (t) { + // with a pathExt of '', any filename is fine. + // so the "fail" one would still pass. + runTest(t, { pathExt: '', skipFail: true }) + }) + t.test('pathext with empty entry', function (t) { + // with a pathExt of '', any filename is fine. + // so the "fail" one would still pass. + runTest(t, { pathExt: ';' + pathExt, skipFail: true }) + }) + t.end() +}) + +t.test('cleanup', function (t) { + rimraf.sync(fixture) + t.end() +}) + +function runTest (t, options) { + var isexe = reset() + + var optionsIgnore = Object.create(options || {}) + optionsIgnore.ignoreErrors = true + + if (!options || !options.skipFail) { + t.notOk(isexe.sync(fail, options)) + } + t.notOk(isexe.sync(noent, optionsIgnore)) + if (!options) { + t.ok(isexe.sync(meow)) + } else { + t.ok(isexe.sync(meow, options)) + } + + t.ok(isexe.sync(mine, options)) + t.ok(isexe.sync(ours, options)) + t.throws(function () { + isexe.sync(noent, options) + }) + + t.test('meow async', function (t) { + if (!options) { + isexe(meow, function (er, is) { + if (er) { + throw er + } + t.ok(is) + t.end() + }) + } else { + isexe(meow, options, function (er, is) { + if (er) { + throw er + } + t.ok(is) + t.end() + }) + } + }) + + t.test('mine async', function (t) { + isexe(mine, options, function (er, is) { + if (er) { + throw er + } + t.ok(is) + t.end() + }) + }) + + t.test('ours async', function (t) { + isexe(ours, options, function (er, is) { + if (er) { + throw er + } + t.ok(is) + t.end() + }) + }) + + if (!options || !options.skipFail) { + t.test('fail async', function (t) { + isexe(fail, options, function (er, is) { + if (er) { + throw er + } + t.notOk(is) + t.end() + }) + }) + } + + t.test('noent async', function (t) { + isexe(noent, options, function (er, is) { + t.ok(er) + t.notOk(is) + t.end() + }) + }) + + t.test('noent ignore async', function (t) { + isexe(noent, optionsIgnore, function (er, is) { + if (er) { + throw er + } + t.notOk(is) + t.end() + }) + }) + + t.end() +} diff --git a/node_modules/which/node_modules/isexe/windows.js b/node_modules/which/node_modules/isexe/windows.js new file mode 100644 index 000000000..aba8561f3 --- /dev/null +++ b/node_modules/which/node_modules/isexe/windows.js @@ -0,0 +1,36 @@ +module.exports = isexe +isexe.sync = sync + +var fs = require('fs') + +function checkPathExt (path, options) { + var pathext = options.pathExt !== undefined ? + options.pathExt : process.env.PATHEXT + + if (!pathext) { + return true + } + + pathext = pathext.split(';') + if (pathext.indexOf('') !== -1) { + return true + } + for (var i = 0; i < pathext.length; i++) { + var p = pathext[i].toLowerCase() + if (p && path.substr(-p.length).toLowerCase() === p) { + return true + } + } + return false +} + +function isexe (path, options, cb) { + fs.stat(path, function (er, st) { + cb(er, er ? false : checkPathExt(path, options)) + }) +} + +function sync (path, options) { + fs.statSync(path) + return checkPathExt(path, options) +} diff --git a/node_modules/which/package.json b/node_modules/which/package.json index 79d84875b..04f90fa68 100644 --- a/node_modules/which/package.json +++ b/node_modules/which/package.json @@ -1,12 +1,12 @@ { "_args": [ [ - "which@1.2.1", + "which@~1.2.1", "/Users/rebecca/code/npm" ] ], - "_from": "which@1.2.1", - "_id": "which@1.2.1", + "_from": "which@>=1.2.1 <1.3.0", + "_id": "which@1.2.4", "_inCache": true, "_installable": true, "_location": "/which", @@ -15,26 +15,27 @@ "email": "i@izs.me", "name": "isaacs" }, - "_npmVersion": "3.3.2", + "_npmVersion": "2.14.15", "_phantomChildren": {}, "_requested": { "name": "which", - "raw": "which@1.2.1", - "rawSpec": "1.2.1", + "raw": "which@~1.2.1", + "rawSpec": "~1.2.1", "scope": null, - "spec": "1.2.1", - "type": "version" + "spec": ">=1.2.1 <1.3.0", + "type": "range" }, "_requiredBy": [ "/", "/node-gyp", "/standard/standard-format/esformatter/npm-run/npm-path", + "/tap/foreground-child/cross-spawn-async", "/tap/nyc/istanbul" ], - "_resolved": "https://registry.npmjs.org/which/-/which-1.2.1.tgz", - "_shasum": "a010c43aade1a798a3e6c1b1e453d45cb497a2bc", + "_resolved": "https://registry.npmjs.org/which/-/which-1.2.4.tgz", + "_shasum": "1557f96080604e5b11b3599eb9f45b50a9efd722", "_shrinkwrap": null, - "_spec": "which@1.2.1", + "_spec": "which@~1.2.1", "_where": "/Users/rebecca/code/npm", "author": { "email": "i@izs.me", @@ -48,20 +49,21 @@ "url": "https://github.com/isaacs/node-which/issues" }, "dependencies": { - "is-absolute": "^0.1.7" + "is-absolute": "^0.1.7", + "isexe": "^1.1.1" }, "description": "Like which(1) unix command. Find the first instance of an executable in the PATH.", "devDependencies": { "mkdirp": "^0.5.0", "rimraf": "^2.3.3", - "tap": "^2.0.0" + "tap": "^5.1.1" }, "directories": {}, "dist": { - "shasum": "a010c43aade1a798a3e6c1b1e453d45cb497a2bc", - "tarball": "http://registry.npmjs.org/which/-/which-1.2.1.tgz" + "shasum": "1557f96080604e5b11b3599eb9f45b50a9efd722", + "tarball": "http://registry.npmjs.org/which/-/which-1.2.4.tgz" }, - "gitHead": "c3b472bd2e13a61a880eca44c76025920a4cb1d5", + "gitHead": "1375684d40af9de2ecc527d1ab9b87b537d7a1cc", "homepage": "https://github.com/isaacs/node-which#readme", "license": "ISC", "main": "which.js", @@ -79,7 +81,7 @@ "url": "git://github.com/isaacs/node-which.git" }, "scripts": { - "test": "tap test/*.js" + "test": "tap test/*.js --cov" }, - "version": "1.2.1" + "version": "1.2.4" } diff --git a/node_modules/which/test/basic.js b/node_modules/which/test/basic.js index 80e9e96b2..54c8d2384 100644 --- a/node_modules/which/test/basic.js +++ b/node_modules/which/test/basic.js @@ -51,17 +51,16 @@ t.test('make executable', function (t) { }) t.test('find when executable', function (t) { - t.plan(4) var opt = { pathExt: '.sh' } var expect = path.resolve(fixture, 'foo.sh').toLowerCase() - var PATH = process.env.PATH + var PATH = process.env.PATH || process.env.Path t.test('absolute', function (t) { runTest(fixture + '/foo.sh', t) }) t.test('with process.env.PATH', function (t) { - process.env.PATH = fixture + process.env.PATH = process.env.Path = fixture runTest('foo.sh', t) }) @@ -73,6 +72,25 @@ t.test('find when executable', function (t) { runTest('foo.sh', t) }) + t.test('with pathExt', { + skip: isWindows ? false : 'Only for Windows' + }, function (t) { + var pe = process.env.PATHEXT + process.env.PATHEXT = '.SH' + + t.test('foo.sh', function (t) { + runTest('foo.sh', t) + }) + t.test('foo', function (t) { + runTest('foo', t) + }) + t.test('replace', function (t) { + process.env.PATHEXT = pe + t.end() + }) + t.end() + }) + t.test('with path opt', function (t) { opt.path = fixture runTest('foo.sh', t) @@ -80,17 +98,20 @@ t.test('find when executable', function (t) { function runTest(exec, t) { t.plan(2) + + var found = which.sync(exec, opt).toLowerCase() + t.equal(found, expect) + which(exec, opt, function (er, found) { if (er) throw er t.equal(found.toLowerCase(), expect) + t.end() process.env.PATH = PATH }) - - var found = which.sync(exec, opt).toLowerCase() - t.equal(found, expect) } + t.end() }) t.test('clean', function (t) { diff --git a/node_modules/which/test/windows.js b/node_modules/which/test/windows.js new file mode 100644 index 000000000..1d5e4294a --- /dev/null +++ b/node_modules/which/test/windows.js @@ -0,0 +1,10 @@ +// pretend to be Windows. +if (process.platform === 'win32') { + var t = require('tap') + t.plan(0, 'already on windows') + process.exit(0) +} + +process.env.Path = process.env.PATH.split(':').join(';') +process.env.OSTYPE = 'cygwin' +require('./basic.js') diff --git a/node_modules/which/which.js b/node_modules/which/which.js index e878351c1..5cf0124d7 100644 --- a/node_modules/which/which.js +++ b/node_modules/which/which.js @@ -7,46 +7,26 @@ var isWindows = process.platform === 'win32' || var path = require('path') var COLON = isWindows ? ';' : ':' -var isExe +var isexe = require('isexe') var fs = require('fs') var isAbsolute = require('is-absolute') -var G = parseInt('0010', 8) -var U = parseInt('0100', 8) -var UG = parseInt('0110', 8) - -if (isWindows) { - // On windows, there is no good way to check that a file is executable - isExe = function isExe () { return true } -} else { - isExe = function isExe (mod, uid, gid) { - var ret = (mod & 1) - || (mod & G) && process.getgid && gid === process.getgid() - || (mod & U) && process.getuid && uid === process.getuid() - || (mod & UG) && process.getuid && 0 === process.getuid() - - if (!ret && process.getgroups && (mod & G)) { - var groups = process.getgroups() - for (var g = 0; g < groups.length; g++) { - if (groups[g] === gid) - return true - } - } - - return ret - } -} - function getPathInfo(cmd, opt) { var colon = opt.colon || COLON - var pathEnv = opt.path || process.env.PATH || '' + var pathEnv = opt.path || process.env.Path || process.env.PATH || '' var pathExt = [''] pathEnv = pathEnv.split(colon) + var pathExtExe = '' if (isWindows) { pathEnv.unshift(process.cwd()) - pathExt = (opt.pathExt || process.env.PATHEXT || '.EXE').split(colon) + pathExtExe = (opt.pathExt || process.env.PATHEXT || '.EXE;.CMD;.BAT;.COM') + pathExt = pathExtExe.split(colon) + + + // Always test the cmd itself first. isexe will check to make sure + // it's found in the pathExt set. if (cmd.indexOf('.') !== -1 && pathExt[0] !== '') pathExt.unshift('') } @@ -56,7 +36,11 @@ function getPathInfo(cmd, opt) { if (isAbsolute(cmd)) pathEnv = [''] - return {env: pathEnv, ext: pathExt} + return { + env: pathEnv, + ext: pathExt, + extExe: pathExtExe + } } function which (cmd, opt, cb) { @@ -68,6 +52,7 @@ function which (cmd, opt, cb) { var info = getPathInfo(cmd, opt) var pathEnv = info.env var pathExt = info.ext + var pathExtExe = info.extExe var found = [] ;(function F (i, l) { @@ -86,10 +71,8 @@ function which (cmd, opt, cb) { ;(function E (ii, ll) { if (ii === ll) return F(i + 1, l) var ext = pathExt[ii] - fs.stat(p + ext, function (er, stat) { - if (!er && - stat.isFile() && - isExe(stat.mode, stat.uid, stat.gid)) { + isexe(p + ext, { pathExt: pathExtExe }, function (er, is) { + if (!er && is) { if (opt.all) found.push(p + ext) else @@ -107,6 +90,7 @@ function whichSync (cmd, opt) { var info = getPathInfo(cmd, opt) var pathEnv = info.env var pathExt = info.ext + var pathExtExe = info.extExe var found = [] for (var i = 0, l = pathEnv.length; i < l; i ++) { @@ -117,10 +101,10 @@ function whichSync (cmd, opt) { var p = path.join(pathPart, cmd) for (var j = 0, ll = pathExt.length; j < ll; j ++) { var cur = p + pathExt[j] - var stat + var is try { - stat = fs.statSync(cur) - if (stat.isFile() && isExe(stat.mode, stat.uid, stat.gid)) { + is = isexe.sync(cur, { pathExt: pathExtExe }) + if (is) { if (opt.all) found.push(cur) else |