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 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) && process.getgid && gid === process.getgid() ||
27
- (mod & u) && process.getuid && uid === process.getuid() ||
28
- (mod & ug) && process.getuid && process.getuid() === 0
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.0.0",
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.0.1"
12
+ "tap": "^5.1.2"
13
13
  },
14
14
  "scripts": {
15
- "test": "tap test/*.js --cov"
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
- process.env.PATHEXT = '.EXE;.CAT;.CMD;.COM'
75
- runTest(t)
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
- t.notOk(isexe.sync(fail))
87
- t.notOk(isexe.sync(noent, { ignoreErrors: true }))
88
- t.ok(isexe.sync(meow))
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
- isexe(meow, function (er, is) {
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('fail async', function (t) {
104
- isexe(fail, function (er, is) {
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.notOk(is)
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, { ignoreErrors: true }, function (er, is) {
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 = process.env.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
  }