1module.exports = which 2which.sync = whichSync 3 4var isWindows = process.platform === 'win32' || 5 process.env.OSTYPE === 'cygwin' || 6 process.env.OSTYPE === 'msys' 7 8var path = require('path') 9var COLON = isWindows ? ';' : ':' 10var isexe = require('isexe') 11 12function getNotFoundError (cmd) { 13 var er = new Error('not found: ' + cmd) 14 er.code = 'ENOENT' 15 16 return er 17} 18 19function getPathInfo (cmd, opt) { 20 var colon = opt.colon || COLON 21 var pathEnv = opt.path || process.env.PATH || '' 22 var pathExt = [''] 23 24 pathEnv = pathEnv.split(colon) 25 26 var pathExtExe = '' 27 if (isWindows) { 28 pathEnv.unshift(process.cwd()) 29 pathExtExe = (opt.pathExt || process.env.PATHEXT || '.EXE;.CMD;.BAT;.COM') 30 pathExt = pathExtExe.split(colon) 31 32 33 // Always test the cmd itself first. isexe will check to make sure 34 // it's found in the pathExt set. 35 if (cmd.indexOf('.') !== -1 && pathExt[0] !== '') 36 pathExt.unshift('') 37 } 38 39 // If it has a slash, then we don't bother searching the pathenv. 40 // just check the file itself, and that's it. 41 if (cmd.match(/\//) || isWindows && cmd.match(/\\/)) 42 pathEnv = [''] 43 44 return { 45 env: pathEnv, 46 ext: pathExt, 47 extExe: pathExtExe 48 } 49} 50 51function which (cmd, opt, cb) { 52 if (typeof opt === 'function') { 53 cb = opt 54 opt = {} 55 } 56 57 var info = getPathInfo(cmd, opt) 58 var pathEnv = info.env 59 var pathExt = info.ext 60 var pathExtExe = info.extExe 61 var found = [] 62 63 ;(function F (i, l) { 64 if (i === l) { 65 if (opt.all && found.length) 66 return cb(null, found) 67 else 68 return cb(getNotFoundError(cmd)) 69 } 70 71 var pathPart = pathEnv[i] 72 if (pathPart.charAt(0) === '"' && pathPart.slice(-1) === '"') 73 pathPart = pathPart.slice(1, -1) 74 75 var p = path.join(pathPart, cmd) 76 if (!pathPart && (/^\.[\\\/]/).test(cmd)) { 77 p = cmd.slice(0, 2) + p 78 } 79 ;(function E (ii, ll) { 80 if (ii === ll) return F(i + 1, l) 81 var ext = pathExt[ii] 82 isexe(p + ext, { pathExt: pathExtExe }, function (er, is) { 83 if (!er && is) { 84 if (opt.all) 85 found.push(p + ext) 86 else 87 return cb(null, p + ext) 88 } 89 return E(ii + 1, ll) 90 }) 91 })(0, pathExt.length) 92 })(0, pathEnv.length) 93} 94 95function whichSync (cmd, opt) { 96 opt = opt || {} 97 98 var info = getPathInfo(cmd, opt) 99 var pathEnv = info.env 100 var pathExt = info.ext 101 var pathExtExe = info.extExe 102 var found = [] 103 104 for (var i = 0, l = pathEnv.length; i < l; i ++) { 105 var pathPart = pathEnv[i] 106 if (pathPart.charAt(0) === '"' && pathPart.slice(-1) === '"') 107 pathPart = pathPart.slice(1, -1) 108 109 var p = path.join(pathPart, cmd) 110 if (!pathPart && /^\.[\\\/]/.test(cmd)) { 111 p = cmd.slice(0, 2) + p 112 } 113 for (var j = 0, ll = pathExt.length; j < ll; j ++) { 114 var cur = p + pathExt[j] 115 var is 116 try { 117 is = isexe.sync(cur, { pathExt: pathExtExe }) 118 if (is) { 119 if (opt.all) 120 found.push(cur) 121 else 122 return cur 123 } 124 } catch (ex) {} 125 } 126 } 127 128 if (opt.all && found.length) 129 return found 130 131 if (opt.nothrow) 132 return null 133 134 throw getNotFoundError(cmd) 135} 136