4 var isWindows = process.platform === 'win32' ||
5 process.env.OSTYPE === 'cygwin' ||
6 process.env.OSTYPE === 'msys'
8 var path = require('path')
9 var COLON = isWindows ? ';' : ':'
11 var fs = require('fs')
12 var isAbsolute = require('is-absolute')
14 var G = parseInt('0010', 8)
15 var U = parseInt('0100', 8)
16 var UG = parseInt('0110', 8)
19 // On windows, there is no good way to check that a file is executable
20 isExe = function isExe () { return true }
22 isExe = function isExe (mod, uid, gid) {
24 || (mod & U) && process.getgid && gid === process.getgid()
25 || (mod & G) && process.getuid && uid === process.getuid()
26 || (mod & UG) && process.getuid && 0 === process.getuid()
28 if (!ret && process.getgroups && (mod & G)) {
29 var groups = process.getgroups()
30 for (var g = 0; g < groups.length; g++) {
31 if (groups[g] === gid)
40 function getPathInfo(cmd, opt) {
41 var colon = opt.colon || COLON
42 var pathEnv = opt.path || process.env.PATH || ''
45 pathEnv = pathEnv.split(colon)
48 pathEnv.unshift(process.cwd())
49 pathExt = (opt.pathExt || process.env.PATHEXT || '.EXE').split(colon)
50 if (cmd.indexOf('.') !== -1 && pathExt[0] !== '')
54 // If it's absolute, then we don't bother searching the pathenv.
55 // just check the file itself, and that's it.
59 return {env: pathEnv, ext: pathExt}
62 function which (cmd, opt, cb) {
63 if (typeof opt === 'function') {
68 var info = getPathInfo(cmd, opt)
69 var pathEnv = info.env
70 var pathExt = info.ext
73 if (i === l) return cb(new Error('not found: '+cmd))
74 var p = path.resolve(pathEnv[i], cmd)
75 ;(function E (ii, ll) {
76 if (ii === ll) return F(i + 1, l)
78 fs.stat(p + ext, function (er, stat) {
81 isExe(stat.mode, stat.uid, stat.gid)) {
82 return cb(null, p + ext)
90 function whichSync (cmd, opt) {
93 var info = getPathInfo(cmd, opt)
94 var pathEnv = info.env
95 var pathExt = info.ext
97 for (var i = 0, l = pathEnv.length; i < l; i ++) {
98 var p = path.join(pathEnv[i], cmd)
99 for (var j = 0, ll = pathExt.length; j < ll; j ++) {
100 var cur = p + pathExt[j]
103 stat = fs.statSync(cur)
104 if (stat.isFile() && isExe(stat.mode, stat.uid, stat.gid))
110 throw new Error('not found: '+cmd)