fix(plugin-commands-script-runners): support directory with path delimiter when running local bin (#5874)

close #5846

Co-authored-by: Zoltan Kochan <z@kochan.io>
This commit is contained in:
await-ovo
2023-01-09 00:09:03 +08:00
committed by GitHub
parent 044cfe5175
commit 8ecbcafdd5
6 changed files with 68 additions and 3 deletions

View File

@@ -0,0 +1,6 @@
---
"@pnpm/plugin-commands-script-runners": patch
"pnpm": patch
---
`pnpm run` should fail if the path to the project contains colon(s).

View File

@@ -0,0 +1,6 @@
---
"@pnpm/plugin-commands-script-runners": patch
"pnpm": patch
---
`pnpm exec` should work when the path to the project contains colon(s) [#5846](https://github.com/pnpm/pnpm/issues/5846).

View File

@@ -1,4 +1,3 @@
import path from 'path'
import { docsUrl, RecursiveSummary, throwOnCommandFail } from '@pnpm/cli-utils'
import { Config, types } from '@pnpm/config'
import { makeNodeRequireOption } from '@pnpm/lifecycle'
@@ -173,7 +172,7 @@ export async function handler (
PNPM_PACKAGE_NAME: opts.selectedProjectsGraph[prefix]?.package.manifest.name,
},
prependPaths: [
path.join(prefix, 'node_modules/.bin'),
'./node_modules/.bin',
...opts.extraBinPaths,
],
userAgent: opts.userAgent,
@@ -201,7 +200,9 @@ export async function handler (
return
}
err['code'] = 'ERR_PNPM_RECURSIVE_EXEC_FIRST_FAIL'
if (!err['code']?.startsWith('ERR_PNPM_')) {
err['code'] = 'ERR_PNPM_RECURSIVE_EXEC_FIRST_FAIL'
}
err['prefix'] = prefix
/* eslint-enable @typescript-eslint/dot-notation */
throw err

View File

@@ -1,3 +1,4 @@
import { PnpmError } from '@pnpm/error'
import path from 'path'
import PATH from 'path-name'
@@ -8,6 +9,13 @@ export function makeEnv (
prependPaths: string[]
}
) {
for (const prependPath of opts.prependPaths) {
if (prependPath.includes(path.delimiter)) {
// Unfortunately, there is no way to escape the PATH delimiter,
// so directories added to the PATH should not contain it.
throw new PnpmError('BAD_PATH_DIR', `Cannot add ${prependPath} to PATH because it contains the path delimiter character (${path.delimiter})`)
}
}
return {
...process.env,
...opts.extraEnv,

View File

@@ -661,3 +661,38 @@ test('should throw error when the package specified by resume-from does not exis
expect(err.code).toBe('ERR_PNPM_RESUME_FROM_NOT_FOUND')
}
})
test('pnpm exec in directory with path delimiter', async () => {
preparePackages([
{
name: `foo${path.delimiter}delimiter`,
version: '1.0.0',
dependencies: {
cowsay: '1.5.0',
},
},
])
const { selectedProjectsGraph } = await readProjects(process.cwd(), [])
await execa(pnpmBin, [
'install',
'-r',
'--registry',
REGISTRY_URL,
'--store-dir',
path.resolve(DEFAULT_OPTS.storeDir),
])
let error
try {
await exec.handler({
...DEFAULT_OPTS,
dir: process.cwd(),
selectedProjectsGraph,
recursive: true,
}, ['cowsay', 'hi'])
} catch (err: any) { // eslint-disable-line
error = err
}
expect(error).toBeUndefined()
})

View File

@@ -0,0 +1,9 @@
import path from 'path'
import { makeEnv } from '../src/makeEnv'
test('makeEnv should fail if prependPaths has a path with a colon', () => {
const prependPath = `/foo/bar${path.delimiter}/baz`
expect(() => makeEnv({
prependPaths: [prependPath],
})).toThrow(`Cannot add ${prependPath} to PATH because it contains the path delimiter character (${path.delimiter})`)
})