UNPKG

3.03 kBJavaScriptView Raw
1var common = require('./common');
2var fs = require('fs');
3var path = require('path');
4
5common.register('which', _which, {
6 allowGlobbing: false,
7 cmdOptions: {
8 'a': 'all',
9 },
10});
11
12// XP's system default value for PATHEXT system variable, just in case it's not
13// set on Windows.
14var XP_DEFAULT_PATHEXT = '.com;.exe;.bat;.cmd;.vbs;.vbe;.js;.jse;.wsf;.wsh';
15
16// Cross-platform method for splitting environment PATH variables
17function splitPath(p) {
18 return p ? p.split(path.delimiter) : [];
19}
20
21function checkPath(pathName) {
22 return fs.existsSync(pathName) && !common.statFollowLinks(pathName).isDirectory();
23}
24
25//@
26//@ ### which(command)
27//@
28//@ Examples:
29//@
30//@ ```javascript
31//@ var nodeExec = which('node');
32//@ ```
33//@
34//@ Searches for `command` in the system's PATH. On Windows, this uses the
35//@ `PATHEXT` variable to append the extension if it's not already executable.
36//@ Returns string containing the absolute path to the command.
37function _which(options, cmd) {
38 if (!cmd) common.error('must specify command');
39
40 var isWindows = process.platform === 'win32';
41 var pathEnv = process.env.path || process.env.Path || process.env.PATH;
42 var pathArray = splitPath(pathEnv);
43
44 var queryMatches = [];
45
46 // No relative/absolute paths provided?
47 if (cmd.indexOf('/') === -1) {
48 // Assume that there are no extensions to append to queries (this is the
49 // case for unix)
50 var pathExtArray = [''];
51 if (isWindows) {
52 // In case the PATHEXT variable is somehow not set (e.g.
53 // child_process.spawn with an empty environment), use the XP default.
54 var pathExtEnv = process.env.PATHEXT || XP_DEFAULT_PATHEXT;
55 pathExtArray = splitPath(pathExtEnv.toUpperCase());
56 }
57
58 // Search for command in PATH
59 for (var k = 0; k < pathArray.length; k++) {
60 // already found it
61 if (queryMatches.length > 0 && !options.all) break;
62
63 var attempt = path.resolve(pathArray[k], cmd);
64
65 if (isWindows) {
66 attempt = attempt.toUpperCase();
67 }
68
69 var match = attempt.match(/\.[^<>:"/\|?*.]+$/);
70 if (match && pathExtArray.indexOf(match[0]) >= 0) { // this is Windows-only
71 // The user typed a query with the file extension, like
72 // `which('node.exe')`
73 if (checkPath(attempt)) {
74 queryMatches.push(attempt);
75 break;
76 }
77 } else { // All-platforms
78 // Cycle through the PATHEXT array, and check each extension
79 // Note: the array is always [''] on Unix
80 for (var i = 0; i < pathExtArray.length; i++) {
81 var ext = pathExtArray[i];
82 var newAttempt = attempt + ext;
83 if (checkPath(newAttempt)) {
84 queryMatches.push(newAttempt);
85 break;
86 }
87 }
88 }
89 }
90 } else if (checkPath(cmd)) { // a valid absolute or relative path
91 queryMatches.push(path.resolve(cmd));
92 }
93
94 if (queryMatches.length > 0) {
95 return options.all ? queryMatches : queryMatches[0];
96 }
97 return options.all ? [] : null;
98}
99module.exports = _which;