mirror of
https://github.com/pnpm/pnpm.git
synced 2026-05-31 03:58:11 -04:00
* fix(installation): skip pnpm exe when no Node.js is on PATH
When pnpm is installed as @pnpm/exe (a Single Executable Application
that bundles Node.js into the pnpm binary) and the user has no separate
Node.js on PATH, `which('node')` fails and `getNodeExecPath` used to
fall back to `process.execPath` - which in @pnpm/exe is the pnpm binary
itself, not a Node binary. That path got baked into generated global
bin shims via nodeExecPath, so running any globally-installed CLI
invoked pnpm with the target script as its first positional arg,
producing `ERR_PNPM_NO_IMPORTER_MANIFEST_FOUND` from the current
working directory.
Detect the @pnpm/exe case via `detectIfCurrentPkgIsExecutable` and
return undefined from the fallback so the shim emits a plain
`exec node <target>` instead.
Closes #11291
Refs #4645
* Update pkg-manager/plugin-commands-installation/src/nodeExecPath.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
38 lines
1.3 KiB
TypeScript
38 lines
1.3 KiB
TypeScript
import { detectIfCurrentPkgIsExecutable } from '@pnpm/cli-meta'
|
|
import which from 'which'
|
|
import { getNodeExecPath } from '../lib/nodeExecPath.js'
|
|
|
|
jest.mock('which', () => jest.fn())
|
|
jest.mock('@pnpm/cli-meta', () => ({
|
|
detectIfCurrentPkgIsExecutable: jest.fn(),
|
|
}))
|
|
|
|
const whichMock = jest.mocked(which)
|
|
const detectMock = jest.mocked(detectIfCurrentPkgIsExecutable)
|
|
|
|
afterEach(() => {
|
|
whichMock.mockReset()
|
|
detectMock.mockReset()
|
|
})
|
|
|
|
test('returns undefined when node is not on PATH and pnpm is running as @pnpm/exe', async () => {
|
|
const enoent: NodeJS.ErrnoException = Object.assign(new Error('not found: node'), { code: 'ENOENT' })
|
|
whichMock.mockRejectedValue(enoent)
|
|
detectMock.mockReturnValue(true)
|
|
|
|
await expect(getNodeExecPath()).resolves.toBeUndefined()
|
|
})
|
|
|
|
test('falls back to process.execPath when node is not on PATH and pnpm is running under a real Node.js', async () => {
|
|
const enoent: NodeJS.ErrnoException = Object.assign(new Error('not found: node'), { code: 'ENOENT' })
|
|
whichMock.mockRejectedValue(enoent)
|
|
detectMock.mockReturnValue(false)
|
|
const savedNode = process.env.NODE
|
|
delete process.env.NODE
|
|
try {
|
|
await expect(getNodeExecPath()).resolves.toBe(process.execPath)
|
|
} finally {
|
|
if (savedNode != null) process.env.NODE = savedNode
|
|
}
|
|
})
|