isexe 1.0.0 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +15 -0
- package/README.md +9 -0
- package/access.js +2 -2
- package/index.js +3 -3
- package/mode.js +14 -8
- package/package.json +13 -4
- package/test/basic.js +93 -14
- package/windows.js +12 -6
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
The ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Isaac Z. Schlueter and Contributors
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
10
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
11
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
12
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
13
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
14
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
|
15
|
+
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
CHANGED
|
@@ -40,3 +40,12 @@ unless `options.ignoreErrors` is set to true.
|
|
|
40
40
|
### `isexe.sync(path, [options])`
|
|
41
41
|
|
|
42
42
|
Same as `isexe` but returns the value and throws any errors raised.
|
|
43
|
+
|
|
44
|
+
### Options
|
|
45
|
+
|
|
46
|
+
* `ignoreErrors` Treat all errors as "no, this is not executable", but
|
|
47
|
+
don't raise them.
|
|
48
|
+
* `uid` Number to use as the user id when using the `mode` approach.
|
|
49
|
+
* `gid` Number to use as the group id when using the `mode` approach.
|
|
50
|
+
* `pathExt` List of path extensions to use instead of `PATHEXT`
|
|
51
|
+
environment variable on Windows.
|
package/access.js
CHANGED
|
@@ -3,13 +3,13 @@ isexe.sync = sync
|
|
|
3
3
|
|
|
4
4
|
var fs = require('fs')
|
|
5
5
|
|
|
6
|
-
function isexe (path, cb) {
|
|
6
|
+
function isexe (path, _, cb) {
|
|
7
7
|
fs.access(path, fs.X_OK, function (er) {
|
|
8
8
|
cb(er, !er)
|
|
9
9
|
})
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
function sync (path) {
|
|
12
|
+
function sync (path, _) {
|
|
13
13
|
fs.accessSync(path, fs.X_OK)
|
|
14
14
|
return true
|
|
15
15
|
}
|
package/index.js
CHANGED
|
@@ -23,7 +23,7 @@ function isexe (path, options, cb) {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
return new Promise(function (resolve, reject) {
|
|
26
|
-
isexe(path, options, function (er, is) {
|
|
26
|
+
isexe(path, options || {}, function (er, is) {
|
|
27
27
|
if (er) {
|
|
28
28
|
reject(er)
|
|
29
29
|
} else {
|
|
@@ -33,7 +33,7 @@ function isexe (path, options, cb) {
|
|
|
33
33
|
})
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
core(path, function (er, is) {
|
|
36
|
+
core(path, options || {}, function (er, is) {
|
|
37
37
|
// ignore EACCES because that just means we aren't allowed to run it
|
|
38
38
|
if (er) {
|
|
39
39
|
if (er.code === 'EACCES' || options && options.ignoreErrors) {
|
|
@@ -48,7 +48,7 @@ function isexe (path, options, cb) {
|
|
|
48
48
|
function sync (path, options) {
|
|
49
49
|
// my kingdom for a filtered catch
|
|
50
50
|
try {
|
|
51
|
-
return core.sync(path)
|
|
51
|
+
return core.sync(path, options || {})
|
|
52
52
|
} catch (er) {
|
|
53
53
|
if (options && options.ignoreErrors || er.code === 'EACCES') {
|
|
54
54
|
return false
|
package/mode.js
CHANGED
|
@@ -3,29 +3,35 @@ isexe.sync = sync
|
|
|
3
3
|
|
|
4
4
|
var fs = require('fs')
|
|
5
5
|
|
|
6
|
-
function isexe (path, cb) {
|
|
6
|
+
function isexe (path, options, cb) {
|
|
7
7
|
fs.stat(path, function (er, st) {
|
|
8
|
-
cb(er, er ? false : checkMode(st))
|
|
8
|
+
cb(er, er ? false : checkMode(st, options))
|
|
9
9
|
})
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
function sync (path) {
|
|
13
|
-
return checkMode(fs.statSync(path))
|
|
12
|
+
function sync (path, options) {
|
|
13
|
+
return checkMode(fs.statSync(path), options)
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
function checkMode (stat) {
|
|
16
|
+
function checkMode (stat, options) {
|
|
17
17
|
var mod = stat.mode
|
|
18
18
|
var uid = stat.uid
|
|
19
19
|
var gid = stat.gid
|
|
20
|
+
|
|
21
|
+
var myUid = options.uid !== undefined ?
|
|
22
|
+
options.uid : process.getuid && process.getuid()
|
|
23
|
+
var myGid = options.gid !== undefined ?
|
|
24
|
+
options.gid : process.getgid && process.getgid()
|
|
25
|
+
|
|
20
26
|
var u = parseInt('100', 8)
|
|
21
27
|
var g = parseInt('010', 8)
|
|
22
28
|
var o = parseInt('001', 8)
|
|
23
29
|
var ug = u | g
|
|
24
30
|
|
|
25
31
|
var ret = (mod & o) ||
|
|
26
|
-
(mod & g) &&
|
|
27
|
-
(mod & u) &&
|
|
28
|
-
(mod & ug) &&
|
|
32
|
+
(mod & g) && gid === myGid ||
|
|
33
|
+
(mod & u) && uid === myUid ||
|
|
34
|
+
(mod & ug) && myUid === 0
|
|
29
35
|
|
|
30
36
|
return ret
|
|
31
37
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "isexe",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "Minimal module to check if a file is executable.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"directories": {
|
|
@@ -9,11 +9,20 @@
|
|
|
9
9
|
"devDependencies": {
|
|
10
10
|
"mkdirp": "^0.5.1",
|
|
11
11
|
"rimraf": "^2.5.0",
|
|
12
|
-
"tap": "^5.
|
|
12
|
+
"tap": "^5.1.2"
|
|
13
13
|
},
|
|
14
14
|
"scripts": {
|
|
15
|
-
"test": "tap test/*.js --
|
|
15
|
+
"test": "tap test/*.js --branches=100 --statements=100 --functions=100 --lines=100"
|
|
16
16
|
},
|
|
17
17
|
"author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)",
|
|
18
|
-
"license": "ISC"
|
|
18
|
+
"license": "ISC",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/isaacs/isexe.git"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [],
|
|
24
|
+
"bugs": {
|
|
25
|
+
"url": "https://github.com/isaacs/isexe/issues"
|
|
26
|
+
},
|
|
27
|
+
"homepage": "https://github.com/isaacs/isexe#readme"
|
|
19
28
|
}
|
package/test/basic.js
CHANGED
|
@@ -3,6 +3,8 @@ var fs = require('fs')
|
|
|
3
3
|
var path = require('path')
|
|
4
4
|
var fixture = path.resolve(__dirname, 'fixtures')
|
|
5
5
|
var meow = fixture + '/meow.cat'
|
|
6
|
+
var mine = fixture + '/mine.cat'
|
|
7
|
+
var ours = fixture + '/ours.cat'
|
|
6
8
|
var fail = fixture + '/fail.false'
|
|
7
9
|
var noent = fixture + '/enoent.exe'
|
|
8
10
|
var mkdirp = require('mkdirp')
|
|
@@ -27,11 +29,15 @@ t.test('setup fixtures', function (t) {
|
|
|
27
29
|
fs.chmodSync(meow, parseInt('0755', 8))
|
|
28
30
|
fs.writeFileSync(fail, '#!/usr/bin/env false\n')
|
|
29
31
|
fs.chmodSync(fail, parseInt('0644', 8))
|
|
32
|
+
fs.writeFileSync(mine, '#!/usr/bin/env cat\nmine\n')
|
|
33
|
+
fs.chmodSync(mine, parseInt('0744', 8))
|
|
34
|
+
fs.writeFileSync(ours, '#!/usr/bin/env cat\nours\n')
|
|
35
|
+
fs.chmodSync(ours, parseInt('0754', 8))
|
|
30
36
|
t.end()
|
|
31
37
|
})
|
|
32
38
|
|
|
33
39
|
t.test('promise', { skip: promiseSkip }, function (t) {
|
|
34
|
-
isexe = reset()
|
|
40
|
+
var isexe = reset()
|
|
35
41
|
t.test('meow async', function (t) {
|
|
36
42
|
isexe(meow).then(function (is) {
|
|
37
43
|
t.ok(is)
|
|
@@ -59,6 +65,15 @@ t.test('promise', { skip: promiseSkip }, function (t) {
|
|
|
59
65
|
t.end()
|
|
60
66
|
})
|
|
61
67
|
|
|
68
|
+
t.test('no promise', function (t) {
|
|
69
|
+
global.Promise = null
|
|
70
|
+
var isexe = reset()
|
|
71
|
+
t.throws('try to meow a promise', function () {
|
|
72
|
+
isexe(meow)
|
|
73
|
+
})
|
|
74
|
+
t.end()
|
|
75
|
+
})
|
|
76
|
+
|
|
62
77
|
t.test('access', { skip: accessSkip || winSkip }, function (t) {
|
|
63
78
|
runTest(t)
|
|
64
79
|
})
|
|
@@ -66,13 +81,33 @@ t.test('access', { skip: accessSkip || winSkip }, function (t) {
|
|
|
66
81
|
t.test('mode', { skip: winSkip }, function (t) {
|
|
67
82
|
delete fs.access
|
|
68
83
|
delete fs.accessSync
|
|
84
|
+
var isexe = reset()
|
|
85
|
+
t.ok(isexe.sync(ours, { uid: 0, gid: 0 }))
|
|
86
|
+
t.ok(isexe.sync(mine, { uid: 0, gid: 0 }))
|
|
69
87
|
runTest(t)
|
|
70
88
|
})
|
|
71
89
|
|
|
72
90
|
t.test('windows', function (t) {
|
|
73
91
|
global.TESTING_WINDOWS = true
|
|
74
|
-
|
|
75
|
-
|
|
92
|
+
var pathExt = '.EXE;.CAT;.CMD;.COM'
|
|
93
|
+
t.test('pathExt option', function (t) {
|
|
94
|
+
runTest(t, { pathExt: '.EXE;.CAT;.CMD;.COM' })
|
|
95
|
+
})
|
|
96
|
+
t.test('pathExt env', function (t) {
|
|
97
|
+
process.env.PATHEXT = pathExt
|
|
98
|
+
runTest(t)
|
|
99
|
+
})
|
|
100
|
+
t.test('no pathExt', function (t) {
|
|
101
|
+
// with a pathExt of '', any filename is fine.
|
|
102
|
+
// so the "fail" one would still pass.
|
|
103
|
+
runTest(t, { pathExt: '', skipFail: true })
|
|
104
|
+
})
|
|
105
|
+
t.test('pathext with empty entry', function (t) {
|
|
106
|
+
// with a pathExt of '', any filename is fine.
|
|
107
|
+
// so the "fail" one would still pass.
|
|
108
|
+
runTest(t, { pathExt: ';' + pathExt, skipFail: true })
|
|
109
|
+
})
|
|
110
|
+
t.end()
|
|
76
111
|
})
|
|
77
112
|
|
|
78
113
|
t.test('cleanup', function (t) {
|
|
@@ -80,18 +115,50 @@ t.test('cleanup', function (t) {
|
|
|
80
115
|
t.end()
|
|
81
116
|
})
|
|
82
117
|
|
|
83
|
-
function runTest (t) {
|
|
118
|
+
function runTest (t, options) {
|
|
84
119
|
var isexe = reset()
|
|
85
120
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
121
|
+
var optionsIgnore = Object.create(options || {})
|
|
122
|
+
optionsIgnore.ignoreErrors = true
|
|
123
|
+
|
|
124
|
+
if (!options || !options.skipFail) {
|
|
125
|
+
t.notOk(isexe.sync(fail, options))
|
|
126
|
+
}
|
|
127
|
+
t.notOk(isexe.sync(noent, optionsIgnore))
|
|
128
|
+
if (!options) {
|
|
129
|
+
t.ok(isexe.sync(meow))
|
|
130
|
+
} else {
|
|
131
|
+
t.ok(isexe.sync(meow, options))
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
t.ok(isexe.sync(mine, options))
|
|
135
|
+
t.ok(isexe.sync(ours, options))
|
|
89
136
|
t.throws(function () {
|
|
90
|
-
isexe.sync(noent)
|
|
137
|
+
isexe.sync(noent, options)
|
|
91
138
|
})
|
|
92
139
|
|
|
93
140
|
t.test('meow async', function (t) {
|
|
94
|
-
|
|
141
|
+
if (!options) {
|
|
142
|
+
isexe(meow, function (er, is) {
|
|
143
|
+
if (er) {
|
|
144
|
+
throw er
|
|
145
|
+
}
|
|
146
|
+
t.ok(is)
|
|
147
|
+
t.end()
|
|
148
|
+
})
|
|
149
|
+
} else {
|
|
150
|
+
isexe(meow, options, function (er, is) {
|
|
151
|
+
if (er) {
|
|
152
|
+
throw er
|
|
153
|
+
}
|
|
154
|
+
t.ok(is)
|
|
155
|
+
t.end()
|
|
156
|
+
})
|
|
157
|
+
}
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
t.test('mine async', function (t) {
|
|
161
|
+
isexe(mine, options, function (er, is) {
|
|
95
162
|
if (er) {
|
|
96
163
|
throw er
|
|
97
164
|
}
|
|
@@ -100,18 +167,30 @@ function runTest (t) {
|
|
|
100
167
|
})
|
|
101
168
|
})
|
|
102
169
|
|
|
103
|
-
t.test('
|
|
104
|
-
isexe(
|
|
170
|
+
t.test('ours async', function (t) {
|
|
171
|
+
isexe(ours, options, function (er, is) {
|
|
105
172
|
if (er) {
|
|
106
173
|
throw er
|
|
107
174
|
}
|
|
108
|
-
t.
|
|
175
|
+
t.ok(is)
|
|
109
176
|
t.end()
|
|
110
177
|
})
|
|
111
178
|
})
|
|
112
179
|
|
|
180
|
+
if (!options || !options.skipFail) {
|
|
181
|
+
t.test('fail async', function (t) {
|
|
182
|
+
isexe(fail, options, function (er, is) {
|
|
183
|
+
if (er) {
|
|
184
|
+
throw er
|
|
185
|
+
}
|
|
186
|
+
t.notOk(is)
|
|
187
|
+
t.end()
|
|
188
|
+
})
|
|
189
|
+
})
|
|
190
|
+
}
|
|
191
|
+
|
|
113
192
|
t.test('noent async', function (t) {
|
|
114
|
-
isexe(noent, function (er, is) {
|
|
193
|
+
isexe(noent, options, function (er, is) {
|
|
115
194
|
t.ok(er)
|
|
116
195
|
t.notOk(is)
|
|
117
196
|
t.end()
|
|
@@ -119,7 +198,7 @@ function runTest (t) {
|
|
|
119
198
|
})
|
|
120
199
|
|
|
121
200
|
t.test('noent ignore async', function (t) {
|
|
122
|
-
isexe(noent,
|
|
201
|
+
isexe(noent, optionsIgnore, function (er, is) {
|
|
123
202
|
if (er) {
|
|
124
203
|
throw er
|
|
125
204
|
}
|
package/windows.js
CHANGED
|
@@ -3,12 +3,18 @@ isexe.sync = sync
|
|
|
3
3
|
|
|
4
4
|
var fs = require('fs')
|
|
5
5
|
|
|
6
|
-
function checkPathExt (path) {
|
|
7
|
-
var pathext =
|
|
6
|
+
function checkPathExt (path, options) {
|
|
7
|
+
var pathext = options.pathExt !== undefined ?
|
|
8
|
+
options.pathExt : process.env.PATHEXT
|
|
9
|
+
|
|
8
10
|
if (!pathext) {
|
|
9
11
|
return true
|
|
10
12
|
}
|
|
13
|
+
|
|
11
14
|
pathext = pathext.split(';')
|
|
15
|
+
if (pathext.indexOf('') !== -1) {
|
|
16
|
+
return true
|
|
17
|
+
}
|
|
12
18
|
for (var i = 0; i < pathext.length; i++) {
|
|
13
19
|
var p = pathext[i].toLowerCase()
|
|
14
20
|
if (p && path.substr(-p.length).toLowerCase() === p) {
|
|
@@ -18,13 +24,13 @@ function checkPathExt (path) {
|
|
|
18
24
|
return false
|
|
19
25
|
}
|
|
20
26
|
|
|
21
|
-
function isexe (path, cb) {
|
|
27
|
+
function isexe (path, options, cb) {
|
|
22
28
|
fs.stat(path, function (er, st) {
|
|
23
|
-
cb(er, er ? false : checkPathExt(path))
|
|
29
|
+
cb(er, er ? false : checkPathExt(path, options))
|
|
24
30
|
})
|
|
25
31
|
}
|
|
26
32
|
|
|
27
|
-
function sync (path) {
|
|
33
|
+
function sync (path, options) {
|
|
28
34
|
fs.statSync(path)
|
|
29
|
-
return checkPathExt(path)
|
|
35
|
+
return checkPathExt(path, options)
|
|
30
36
|
}
|