fix: searching for global exec directory

close #2649
This commit is contained in:
Zoltan Kochan
2020-07-04 01:12:40 +03:00
parent e0dd0bca10
commit 245221baa6
3 changed files with 59 additions and 1 deletions

View File

@@ -0,0 +1,5 @@
---
"@pnpm/global-bin-dir": patch
---
When searching a suitable global executables directory, take any directory from the PATH that has a node, pnpm, or npm command in it.

View File

@@ -1,5 +1,6 @@
import PnpmError from '@pnpm/error'
import { sync as canWriteToDir } from 'can-write-to-dir'
import fs = require('fs')
import path = require('path')
import PATH = require('path-name')
@@ -28,7 +29,8 @@ function pickBestGlobalBinDir (dirs: string[], knownCandidates: string[]) {
isUnderDir('nodejs', lowCaseDir) ||
isUnderDir('npm', lowCaseDir) ||
isUnderDir('pnpm', lowCaseDir) ||
knownCandidates.some((candidate) => areDirsEqual(candidate, dir))
knownCandidates.some((candidate) => areDirsEqual(candidate, dir)) ||
dirHasNodeRelatedCommand(dir)
) {
if (canWriteToDirAndExists(dir)) return dir
noWriteAccessDirs.push(dir)
@@ -45,6 +47,18 @@ ${noWriteAccessDirs.join('\n')}`,
})
}
const NODE_RELATED_COMMANDS = new Set(['pnpm', 'npm', 'node'])
function dirHasNodeRelatedCommand (dir: string) {
try {
const files = fs.readdirSync(dir)
return files.map((file) => file.toLowerCase())
.some((file) => NODE_RELATED_COMMANDS.has(file.split('.')[0]))
} catch (err) {
return false
}
}
function isUnderDir (dir: string, target: string) {
target = target.endsWith(path.sep) ? target : `${target}${path.sep}`
return target.includes(`${path.sep}${dir}${path.sep}`) ||

View File

@@ -1,5 +1,6 @@
import PnpmError from '@pnpm/error'
import { sync as _canWriteToDir } from 'can-write-to-dir'
import fs = require('fs')
import isWindows = require('is-windows')
import path = require('path')
import proxiquire = require('proxyquire')
@@ -11,12 +12,16 @@ const makePath =
: (...paths: string[]) => `/${path.join(...paths)}`
let canWriteToDir!: typeof _canWriteToDir
let readdirSync = (dir: string) => [] as string[]
const FAKE_PATH = 'FAKE_PATH'
const globalBinDir = proxiquire('../lib/index.js', {
'can-write-to-dir': {
sync: (dir: string) => canWriteToDir(dir),
},
'fs': {
readdirSync: (dir: string) => readdirSync(dir),
},
'path-name': FAKE_PATH,
}).default
@@ -130,3 +135,37 @@ test('prefer a directory that has "Node" in the path', (t) => {
process.env[FAKE_PATH] = pathEnv
t.end()
})
test('select a directory that has a node command in it', (t) => {
const dir1 = makePath('foo')
const dir2 = makePath('bar')
const pathEnv = process.env[FAKE_PATH]
process.env[FAKE_PATH] = [
dir1,
dir2,
].join(path.delimiter)
canWriteToDir = () => true
readdirSync = (dir) => dir === dir2 ? ['node'] : []
t.equal(globalBinDir(), dir2)
process.env[FAKE_PATH] = pathEnv
t.end()
})
test('select a directory that has a node.bat command in it', (t) => {
const dir1 = makePath('foo')
const dir2 = makePath('bar')
const pathEnv = process.env[FAKE_PATH]
process.env[FAKE_PATH] = [
dir1,
dir2,
].join(path.delimiter)
canWriteToDir = () => true
readdirSync = (dir) => dir === dir2 ? ['node.bat'] : []
t.equal(globalBinDir(), dir2)
process.env[FAKE_PATH] = pathEnv
t.end()
})