diff --git a/src/which.js b/src/which.js index 0e5433c0..ed02ab8d 100644 --- a/src/which.js +++ b/src/which.js @@ -18,8 +18,17 @@ function splitPath(p) { return p ? p.split(path.delimiter) : []; } +function isExecutable(pathName) { + try { + fs.accessSync(pathName, fs.constants.X_OK); + } catch (err) { + return false; + } + return true; +} + function checkPath(pathName) { - return fs.existsSync(pathName) && !common.statFollowLinks(pathName).isDirectory(); + return fs.existsSync(pathName) && !common.statFollowLinks(pathName).isDirectory() && isExecutable(pathName); } //@ diff --git a/test/resources/which/node b/test/resources/which/node new file mode 100644 index 00000000..0b917ba3 --- /dev/null +++ b/test/resources/which/node @@ -0,0 +1 @@ +text file, not an executable diff --git a/test/which.js b/test/which.js index 530fcd2c..3a7ab977 100644 --- a/test/which.js +++ b/test/which.js @@ -1,4 +1,5 @@ import fs from 'fs'; +import path from 'path'; import test from 'ava'; @@ -69,5 +70,25 @@ test('Searching with -a flag returns an array with first item equals to the regu t.falsy(shell.error()); t.truthy(resultForWhich); t.truthy(resultForWhichA); - t.is(resultForWhich.toString(), resultForWhichA[0].toString()); + t.is(resultForWhich.toString(), resultForWhichA[0]); +}); + +test('None executable files does not appear in the result list', t => { + const commandName = 'node'; // Should be an existing command + const pathEnv = process.env.path || process.env.Path || process.env.PATH; + const extraPath = path.resolve(__dirname, 'resources', 'which'); + const matchingFile = path.resolve(extraPath, commandName); + + // make sure that file is exists (will throw error otherwise) + fs.statSync(matchingFile); + + process.env.path = process.env.Path = process.env.PATH = extraPath + path.delimiter + pathEnv; + const resultForWhich = shell.which(commandName); + const resultForWhichA = shell.which('-a', commandName); + t.falsy(shell.error()); + t.truthy(resultForWhich); + t.truthy(resultForWhichA); + t.truthy(resultForWhichA.length); + t.not(resultForWhich.toString(), matchingFile); + t.not(resultForWhichA[0], matchingFile); });