which.js 3.1 KB

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