fix: install packages with incompatible libc (#8569)

close #7362
This commit is contained in:
Khải
2024-09-28 03:46:16 +07:00
committed by GitHub
parent 59a745d84e
commit 83681daf57
14 changed files with 92 additions and 30 deletions

View File

@@ -0,0 +1,8 @@
---
"@pnpm/store-connection-manager": minor
"@pnpm/plugin-commands-rebuild": minor
"@pnpm/plugin-commands-installation": patch
"pnpm": patch
---
Fix a bug in which pnpm downloads packages whose `libc` differ from `pnpm.supportedArchitectures.libc` [#7362](https://github.com/pnpm/pnpm/issues/7362).

View File

@@ -0,0 +1,7 @@
---
"@pnpm/constants": major
"@pnpm/npm-resolver": minor
"@pnpm/package-store": minor
---
Keep `libc` field in `clearMeta`.

View File

@@ -50,6 +50,7 @@ export type StrictRebuildOptions = {
virtualStoreDirMaxLength: number
peersSuffixMaxLength: number
strictStorePkgContentCheck: boolean
fetchFullMetadata?: boolean
} & Pick<Config, 'sslConfigs'>
export type RebuildOptions = Partial<StrictRebuildOptions> &

View File

@@ -13,4 +13,4 @@ export const WORKSPACE_MANIFEST_FILENAME = 'pnpm-workspace.yaml'
// of one package/version
export const META_DIR = 'metadata'
export const FULL_META_DIR = 'metadata-full'
export const FULL_FILTERED_META_DIR = 'metadata-v1.1'
export const FULL_FILTERED_META_DIR = 'metadata-v1.2'

View File

@@ -325,6 +325,9 @@ export async function handler (opts: InstallCommandOptions): Promise<void> {
devDependencies: opts.dev !== false,
optionalDependencies: opts.optional !== false,
}
// npm registry's abbreviated metadata currently does not contain libc
// see <https://github.com/pnpm/pnpm/issues/7362#issuecomment-1971964689>
const fetchFullMetadata: true | undefined = opts.rootProjectManifest?.pnpm?.supportedArchitectures?.libc && true
const installDepsOptions: InstallDepsOptions = {
...opts,
frozenLockfileIfExists: isCI && !opts.lockfileOnly &&
@@ -333,6 +336,7 @@ export async function handler (opts: InstallCommandOptions): Promise<void> {
include,
includeDirect: include,
prepareExecutionEnv: prepareExecutionEnv.bind(null, opts),
fetchFullMetadata,
}
if (opts.resolutionOnly) {
installDepsOptions.lockfileOnly = true

View File

@@ -116,6 +116,7 @@ export type InstallDepsOptions = Pick<Config,
workspace?: boolean
includeOnlyPackageFiles?: boolean
prepareExecutionEnv: PrepareExecutionEnv
fetchFullMetadata?: boolean
} & Partial<Pick<Config, 'pnpmHomeDir'>>
export async function installDeps (

View File

@@ -2,10 +2,12 @@ import fs from 'fs'
import delay from 'delay'
import path from 'path'
import { add, install } from '@pnpm/plugin-commands-installation'
import { prepareEmpty } from '@pnpm/prepare'
import { prepare, prepareEmpty } from '@pnpm/prepare'
import { sync as rimraf } from '@zkochan/rimraf'
import { DEFAULT_OPTS } from './utils'
const describeOnLinuxOnly = process.platform === 'linux' ? describe : describe.skip
test('install fails if no package.json is found', async () => {
prepareEmpty()
@@ -52,3 +54,37 @@ test('install with no store integrity validation', async () => {
expect(fs.readFileSync('node_modules/is-positive/readme.md', 'utf8')).toBe('modified')
})
// Covers https://github.com/pnpm/pnpm/issues/7362
describeOnLinuxOnly('filters optional dependencies based on libc', () => {
test.each([
['glibc', '@pnpm.e2e+only-linux-x64-glibc@1.0.0', '@pnpm.e2e+only-linux-x64-musl@1.0.0'],
['musl', '@pnpm.e2e+only-linux-x64-musl@1.0.0', '@pnpm.e2e+only-linux-x64-glibc@1.0.0'],
])('%p → installs %p, does not install %p', async (libc, found, notFound) => {
const rootProjectManifest = {
dependencies: {
'@pnpm.e2e/support-different-architectures': '1.0.0',
},
pnpm: {
supportedArchitectures: {
os: ['linux'],
cpu: ['x64'],
libc: [libc],
},
},
}
prepare(rootProjectManifest)
await install.handler({
...DEFAULT_OPTS,
rootProjectManifest,
dir: process.cwd(),
})
const pkgDirs = fs.readdirSync(path.resolve('node_modules', '.pnpm'))
expect(pkgDirs).toContain('@pnpm.e2e+support-different-architectures@1.0.0')
expect(pkgDirs).toContain(found)
expect(pkgDirs).not.toContain(notFound)
})
})

46
pnpm-lock.yaml generated
View File

@@ -55,8 +55,8 @@ catalogs:
specifier: 0.0.0
version: 0.0.0
'@pnpm/registry-mock':
specifier: 3.40.0
version: 3.40.0
specifier: 3.41.0
version: 3.41.0
'@pnpm/semver-diff':
specifier: ^1.1.0
version: 1.1.0
@@ -722,7 +722,7 @@ importers:
version: 2.0.3
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 3.40.0(encoding@0.1.13)(typanion@3.14.0)
version: 3.41.0(encoding@0.1.13)(typanion@3.14.0)
'@pnpm/tsconfig':
specifier: workspace:*
version: link:__utils__/tsconfig
@@ -846,7 +846,7 @@ importers:
version: link:../../pkg-manager/modules-yaml
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 3.40.0(encoding@0.1.13)(typanion@3.14.0)
version: 3.41.0(encoding@0.1.13)(typanion@3.14.0)
'@pnpm/types':
specifier: workspace:*
version: link:../../packages/types
@@ -880,7 +880,7 @@ importers:
dependencies:
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 3.40.0(encoding@0.1.13)(typanion@3.14.0)
version: 3.41.0(encoding@0.1.13)(typanion@3.14.0)
'@pnpm/store.cafs':
specifier: workspace:*
version: link:../../store/cafs
@@ -1101,7 +1101,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 3.40.0(encoding@0.1.13)(typanion@3.14.0)
version: 3.41.0(encoding@0.1.13)(typanion@3.14.0)
'@types/ramda':
specifier: 'catalog:'
version: 0.29.12
@@ -2175,7 +2175,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 3.40.0(encoding@0.1.13)(typanion@3.14.0)
version: 3.41.0(encoding@0.1.13)(typanion@3.14.0)
'@pnpm/test-fixtures':
specifier: workspace:*
version: link:../../__utils__/test-fixtures
@@ -2305,7 +2305,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 3.40.0(encoding@0.1.13)(typanion@3.14.0)
version: 3.41.0(encoding@0.1.13)(typanion@3.14.0)
'@pnpm/test-ipc-server':
specifier: workspace:*
version: link:../../__utils__/test-ipc-server
@@ -3933,7 +3933,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 3.40.0(encoding@0.1.13)(typanion@3.14.0)
version: 3.41.0(encoding@0.1.13)(typanion@3.14.0)
'@pnpm/test-fixtures':
specifier: workspace:*
version: link:../../__utils__/test-fixtures
@@ -4217,7 +4217,7 @@ importers:
version: link:../../pkg-manifest/read-package-json
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 3.40.0(encoding@0.1.13)(typanion@3.14.0)
version: 3.41.0(encoding@0.1.13)(typanion@3.14.0)
'@pnpm/store-path':
specifier: workspace:*
version: link:../../store/store-path
@@ -4505,7 +4505,7 @@ importers:
version: link:../read-projects-context
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 3.40.0(encoding@0.1.13)(typanion@3.14.0)
version: 3.41.0(encoding@0.1.13)(typanion@3.14.0)
'@pnpm/store-path':
specifier: workspace:*
version: link:../../store/store-path
@@ -4865,7 +4865,7 @@ importers:
version: 'link:'
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 3.40.0(encoding@0.1.13)(typanion@3.14.0)
version: 3.41.0(encoding@0.1.13)(typanion@3.14.0)
'@pnpm/test-fixtures':
specifier: workspace:*
version: link:../../__utils__/test-fixtures
@@ -5061,7 +5061,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 3.40.0(encoding@0.1.13)(typanion@3.14.0)
version: 3.41.0(encoding@0.1.13)(typanion@3.14.0)
'@pnpm/test-fixtures':
specifier: workspace:*
version: link:../../__utils__/test-fixtures
@@ -5669,7 +5669,7 @@ importers:
version: link:../pkg-manifest/read-project-manifest
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 3.40.0(encoding@0.1.13)(typanion@3.14.0)
version: 3.41.0(encoding@0.1.13)(typanion@3.14.0)
'@pnpm/run-npm':
specifier: workspace:*
version: link:../exec/run-npm
@@ -5947,7 +5947,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 3.40.0(encoding@0.1.13)(typanion@3.14.0)
version: 3.41.0(encoding@0.1.13)(typanion@3.14.0)
'@pnpm/workspace.filter-packages-from-dir':
specifier: workspace:*
version: link:../../workspace/filter-packages-from-dir
@@ -6056,7 +6056,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 3.40.0(encoding@0.1.13)(typanion@3.14.0)
version: 3.41.0(encoding@0.1.13)(typanion@3.14.0)
'@pnpm/test-ipc-server':
specifier: workspace:*
version: link:../../__utils__/test-ipc-server
@@ -6637,7 +6637,7 @@ importers:
version: link:../../pkg-manifest/read-package-json
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 3.40.0(encoding@0.1.13)(typanion@3.14.0)
version: 3.41.0(encoding@0.1.13)(typanion@3.14.0)
'@pnpm/test-fixtures':
specifier: workspace:*
version: link:../../__utils__/test-fixtures
@@ -6704,7 +6704,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 3.40.0(encoding@0.1.13)(typanion@3.14.0)
version: 3.41.0(encoding@0.1.13)(typanion@3.14.0)
'@pnpm/workspace.filter-packages-from-dir':
specifier: workspace:*
version: link:../../workspace/filter-packages-from-dir
@@ -6795,7 +6795,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 3.40.0(encoding@0.1.13)(typanion@3.14.0)
version: 3.41.0(encoding@0.1.13)(typanion@3.14.0)
'@pnpm/test-fixtures':
specifier: workspace:*
version: link:../../__utils__/test-fixtures
@@ -7133,7 +7133,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 3.40.0(encoding@0.1.13)(typanion@3.14.0)
version: 3.41.0(encoding@0.1.13)(typanion@3.14.0)
'@types/archy':
specifier: 'catalog:'
version: 0.0.33
@@ -8810,8 +8810,8 @@ packages:
resolution: {integrity: sha512-LFTWzfJbu6+l86bw/uUAsPU05n1oTqg6jzqyTXYDJPfVclqTfPnHiZoC1nvVvQlE7iVg3bhJ7SXg9IyzK7RWDQ==}
engines: {node: '>=18.12'}
'@pnpm/registry-mock@3.40.0':
resolution: {integrity: sha512-9yJHuhHalHVHBhANoZwa6ZQhbcrXGWEULuAP+gA8XYQdTi1Mfn2EKJqZaZjs9pACoJauRh90e86X3/r6HlITpA==}
'@pnpm/registry-mock@3.41.0':
resolution: {integrity: sha512-AtnFxhDGrN8tKtXyZpAqFobOVYkb1HSUPlOk6v/+WzJq2iowNDrtKYs0MKuzGNizlQr+rBWcGEXaIUcS7oNZ0Q==}
engines: {node: '>=10.13'}
hasBin: true
@@ -15682,7 +15682,7 @@ snapshots:
sort-keys: 4.2.0
strip-bom: 4.0.0
'@pnpm/registry-mock@3.40.0(encoding@0.1.13)(typanion@3.14.0)':
'@pnpm/registry-mock@3.41.0(encoding@0.1.13)(typanion@3.14.0)':
dependencies:
anonymous-npm-registry-client: 0.2.0
execa: 5.1.1

View File

@@ -54,7 +54,7 @@ catalog:
"@pnpm/npm-package-arg": ^1.0.0
"@pnpm/os.env.path-extender": ^2.0.0
"@pnpm/patch-package": 0.0.0
"@pnpm/registry-mock": 3.40.0
"@pnpm/registry-mock": 3.41.0
"@pnpm/semver-diff": ^1.1.0
"@pnpm/tabtab": ^0.5.4
"@pnpm/util.lex-comparator": 3.0.0

View File

@@ -236,6 +236,7 @@ function clearMeta (pkg: PackageMeta): PackageMeta {
const versions: PackageMeta['versions'] = {}
for (const [version, info] of Object.entries(pkg.versions)) {
// The list taken from https://github.com/npm/registry/blob/master/docs/responses/package-metadata.md#abbreviated-version-object
// with the addition of 'libc'
versions[version] = pick([
'name',
'version',
@@ -250,6 +251,7 @@ function clearMeta (pkg: PackageMeta): PackageMeta {
'peerDependenciesMeta',
'cpu',
'os',
'libc',
'deprecated',
'bundleDependencies',
'bundledDependencies',

View File

@@ -1,5 +1,6 @@
import fs from 'fs'
import path from 'path'
import { FULL_FILTERED_META_DIR } from '@pnpm/constants'
import { createFetchFromRegistry } from '@pnpm/fetch'
import { createNpmResolver } from '@pnpm/npm-resolver'
import { fixtures } from '@pnpm/test-fixtures'
@@ -55,8 +56,8 @@ test('request metadata when the one in cache does not have a version satisfying
time: {},
cachedAt: '2016-08-17T19:26:00.508Z',
}
fs.mkdirSync(path.join(cacheDir, 'metadata-v1.1/registry.npmjs.org'), { recursive: true })
fs.writeFileSync(path.join(cacheDir, 'metadata-v1.1/registry.npmjs.org/bad-dates.json'), JSON.stringify(cachedMeta), 'utf8')
fs.mkdirSync(path.join(cacheDir, `${FULL_FILTERED_META_DIR}/registry.npmjs.org`), { recursive: true })
fs.writeFileSync(path.join(cacheDir, `${FULL_FILTERED_META_DIR}/registry.npmjs.org/bad-dates.json`), JSON.stringify(cachedMeta), 'utf8')
nock(registry)
.get('/bad-dates')

View File

@@ -20,6 +20,7 @@ export async function prune ({ cacheDir, storeDir }: PruneOptions, removeAlienFi
rimraf(path.join(cacheDir, 'metadata')),
rimraf(path.join(cacheDir, 'metadata-full')),
rimraf(path.join(cacheDir, 'metadata-v1.1')),
rimraf(path.join(cacheDir, 'metadata-v1.2')),
])
await rimraf(path.join(storeDir, 'tmp'))
globalInfo('Removed all cached metadata files')

View File

@@ -85,7 +85,7 @@ test('remove unreferenced packages', async () => {
message: 'Removed 1 package',
})
)
expect(fs.readdirSync(cacheDir).length).toEqual(0)
expect(fs.readdirSync(cacheDir)).toStrictEqual([])
})
test.skip('remove packages that are used by project that no longer exist', async () => {

View File

@@ -45,12 +45,13 @@ export type CreateNewStoreControllerOptions = CreateResolverOptions & Pick<Confi
> & {
cafsLocker?: CafsLocker
ignoreFile?: (filename: string) => boolean
fetchFullMetadata?: boolean
} & Partial<Pick<Config, 'userConfig' | 'deployAllFiles' | 'sslConfigs' | 'strictStorePkgContentCheck'>> & Pick<ClientOptions, 'resolveSymlinksInInjectedDirs'>
export async function createNewStoreController (
opts: CreateNewStoreControllerOptions
): Promise<{ ctrl: StoreController, dir: string }> {
const fullMetadata = opts.resolutionMode === 'time-based' && !opts.registrySupportsTimeField
const fullMetadata = opts.fetchFullMetadata ?? (opts.resolutionMode === 'time-based' && !opts.registrySupportsTimeField)
const { resolve, fetchers, clearResolutionCache } = createClient({
customFetchers: opts.hooks?.fetchers,
userConfig: opts.userConfig,