Comparing version 1.0.1 to 1.1.0
@@ -6,3 +6,3 @@ module.exports = isexe | ||
function isexe (path, cb) { | ||
function isexe (path, _, cb) { | ||
fs.access(path, fs.X_OK, function (er) { | ||
@@ -13,5 +13,5 @@ cb(er, !er) | ||
function sync (path) { | ||
function sync (path, _) { | ||
fs.accessSync(path, fs.X_OK) | ||
return true | ||
} |
@@ -26,3 +26,3 @@ var fs = require('fs') | ||
return new Promise(function (resolve, reject) { | ||
isexe(path, options, function (er, is) { | ||
isexe(path, options || {}, function (er, is) { | ||
if (er) { | ||
@@ -37,3 +37,3 @@ reject(er) | ||
core(path, function (er, is) { | ||
core(path, options || {}, function (er, is) { | ||
// ignore EACCES because that just means we aren't allowed to run it | ||
@@ -53,3 +53,3 @@ if (er) { | ||
try { | ||
return core.sync(path) | ||
return core.sync(path, options || {}) | ||
} catch (er) { | ||
@@ -56,0 +56,0 @@ if (options && options.ignoreErrors || er.code === 'EACCES') { |
22
mode.js
@@ -6,16 +6,22 @@ module.exports = isexe | ||
function isexe (path, cb) { | ||
function isexe (path, options, cb) { | ||
fs.stat(path, function (er, st) { | ||
cb(er, er ? false : checkMode(st)) | ||
cb(er, er ? false : checkMode(st, options)) | ||
}) | ||
} | ||
function sync (path) { | ||
return checkMode(fs.statSync(path)) | ||
function sync (path, options) { | ||
return checkMode(fs.statSync(path), options) | ||
} | ||
function checkMode (stat) { | ||
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) | ||
@@ -27,7 +33,7 @@ var g = parseInt('010', 8) | ||
var ret = (mod & o) || | ||
(mod & g) && process.getgid && gid === process.getgid() || | ||
(mod & u) && process.getuid && uid === process.getuid() || | ||
(mod & ug) && process.getuid && process.getuid() === 0 | ||
(mod & g) && gid === myGid || | ||
(mod & u) && uid === myUid || | ||
(mod & ug) && myUid === 0 | ||
return ret | ||
} |
{ | ||
"name": "isexe", | ||
"version": "1.0.1", | ||
"version": "1.1.0", | ||
"description": "Minimal module to check if a file is executable.", | ||
@@ -12,6 +12,6 @@ "main": "index.js", | ||
"rimraf": "^2.5.0", | ||
"tap": "^5.0.1" | ||
"tap": "^5.1.2" | ||
}, | ||
"scripts": { | ||
"test": "tap test/*.js --cov" | ||
"test": "tap test/*.js --branches=100 --statements=100 --functions=100 --lines=100" | ||
}, | ||
@@ -18,0 +18,0 @@ "author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)", |
@@ -6,2 +6,4 @@ var t = require('tap') | ||
var meow = fixture + '/meow.cat' | ||
var mine = fixture + '/mine.cat' | ||
var ours = fixture + '/ours.cat' | ||
var fail = fixture + '/fail.false' | ||
@@ -31,2 +33,6 @@ var noent = fixture + '/enoent.exe' | ||
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() | ||
@@ -36,3 +42,3 @@ }) | ||
t.test('promise', { skip: promiseSkip }, function (t) { | ||
isexe = reset() | ||
var isexe = reset() | ||
t.test('meow async', function (t) { | ||
@@ -65,2 +71,11 @@ isexe(meow).then(function (is) { | ||
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) { | ||
@@ -73,2 +88,5 @@ runTest(t) | ||
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) | ||
@@ -79,4 +97,21 @@ }) | ||
global.TESTING_WINDOWS = true | ||
process.env.PATHEXT = '.EXE;.CAT;.CMD;.COM' | ||
runTest(t) | ||
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() | ||
}) | ||
@@ -89,14 +124,46 @@ | ||
function runTest (t) { | ||
function runTest (t, options) { | ||
var isexe = reset() | ||
t.notOk(isexe.sync(fail)) | ||
t.notOk(isexe.sync(noent, { ignoreErrors: true })) | ||
t.ok(isexe.sync(meow)) | ||
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) | ||
isexe.sync(noent, options) | ||
}) | ||
t.test('meow async', function (t) { | ||
isexe(meow, function (er, is) { | ||
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) { | ||
@@ -110,8 +177,8 @@ throw er | ||
t.test('fail async', function (t) { | ||
isexe(fail, function (er, is) { | ||
t.test('ours async', function (t) { | ||
isexe(ours, options, function (er, is) { | ||
if (er) { | ||
throw er | ||
} | ||
t.notOk(is) | ||
t.ok(is) | ||
t.end() | ||
@@ -121,4 +188,16 @@ }) | ||
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, function (er, is) { | ||
isexe(noent, options, function (er, is) { | ||
t.ok(er) | ||
@@ -131,3 +210,3 @@ t.notOk(is) | ||
t.test('noent ignore async', function (t) { | ||
isexe(noent, { ignoreErrors: true }, function (er, is) { | ||
isexe(noent, optionsIgnore, function (er, is) { | ||
if (er) { | ||
@@ -134,0 +213,0 @@ throw er |
@@ -6,8 +6,14 @@ module.exports = isexe | ||
function checkPathExt (path) { | ||
var pathext = process.env.PATHEXT | ||
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++) { | ||
@@ -22,11 +28,11 @@ var p = pathext[i].toLowerCase() | ||
function isexe (path, cb) { | ||
function isexe (path, options, cb) { | ||
fs.stat(path, function (er, st) { | ||
cb(er, er ? false : checkPathExt(path)) | ||
cb(er, er ? false : checkPathExt(path, options)) | ||
}) | ||
} | ||
function sync (path) { | ||
function sync (path, options) { | ||
fs.statSync(path) | ||
return checkPathExt(path) | ||
return checkPathExt(path, options) | ||
} |
9719
315