mirror of
https://github.com/pnpm/pnpm.git
synced 2025-12-24 07:38:12 -05:00
6
.changeset/pink-cars-guess.md
Normal file
6
.changeset/pink-cars-guess.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@pnpm/plugin-commands-installation": patch
|
||||
"pnpm": patch
|
||||
---
|
||||
|
||||
Fix a bug in which `pnpm add` downloads packages whose `libc` differ from `pnpm.supportedArchitectures.libc`.
|
||||
8
.changeset/slick-steaks-admire.md
Normal file
8
.changeset/slick-steaks-admire.md
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
"@pnpm/plugin-commands-script-runners": major
|
||||
"@pnpm/plugin-commands-installation": minor
|
||||
"@pnpm/config": minor
|
||||
"pnpm": minor
|
||||
---
|
||||
|
||||
Add `--cpu`, `--libc`, and `--os` to `pnpm install`, `pnpm add`, and `pnpm dlx` to customize `supportedArchitectures` via the CLI [#7510](https://github.com/pnpm/pnpm/issues/7510).
|
||||
@@ -36,6 +36,10 @@ import { readWorkspaceManifest } from '@pnpm/workspace.read-manifest'
|
||||
|
||||
import { types } from './types'
|
||||
import { getOptionsFromPnpmSettings, getOptionsFromRootManifest } from './getOptionsFromRootManifest'
|
||||
import {
|
||||
type CliOptions as SupportedArchitecturesCliOptions,
|
||||
overrideSupportedArchitecturesWithCLI,
|
||||
} from './overrideSupportedArchitecturesWithCLI'
|
||||
export { types }
|
||||
|
||||
export { getOptionsFromRootManifest, getOptionsFromPnpmSettings, type OptionsFromRootManifest } from './getOptionsFromRootManifest'
|
||||
@@ -54,7 +58,7 @@ type KebabCaseConfig = {
|
||||
|
||||
const npmDefaults = loadNpmConf.defaults
|
||||
|
||||
export type CliOptions = Record<string, unknown> & { dir?: string, json?: boolean }
|
||||
export type CliOptions = Record<string, unknown> & SupportedArchitecturesCliOptions & { dir?: string, json?: boolean }
|
||||
|
||||
export async function getConfig (opts: {
|
||||
globalDirShouldAllowWrite?: boolean
|
||||
@@ -379,6 +383,9 @@ export async function getConfig (opts: {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
overrideSupportedArchitecturesWithCLI(pnpmConfig, cliOptions)
|
||||
|
||||
if (opts.cliOptions['global']) {
|
||||
extractAndRemoveDependencyBuildOptions(pnpmConfig)
|
||||
Object.assign(pnpmConfig, globalDepsBuildConfig)
|
||||
|
||||
23
config/config/src/overrideSupportedArchitecturesWithCLI.ts
Normal file
23
config/config/src/overrideSupportedArchitecturesWithCLI.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { type Config } from './Config'
|
||||
import { type types } from './types'
|
||||
|
||||
const CLI_OPTION_NAMES = ['cpu', 'libc', 'os'] as const satisfies Array<keyof typeof types>
|
||||
type CliOptionName = typeof CLI_OPTION_NAMES[number]
|
||||
|
||||
export type CliOptions = Partial<Record<CliOptionName, string | string[]>>
|
||||
export type TargetConfig = Pick<Config, 'supportedArchitectures'>
|
||||
|
||||
/**
|
||||
* If `--cpu`, `--libc`, or `--os` was provided from the command line, override `supportedArchitectures` with them.
|
||||
* @param targetConfig - The config object whose `supportedArchitectures` would be overridden.
|
||||
* @param cliOptions - The object that contains object
|
||||
*/
|
||||
export function overrideSupportedArchitecturesWithCLI (targetConfig: TargetConfig, cliOptions: CliOptions): void {
|
||||
for (const key of CLI_OPTION_NAMES) {
|
||||
const values = cliOptions[key]
|
||||
if (values != null) {
|
||||
targetConfig.supportedArchitectures ??= {}
|
||||
targetConfig.supportedArchitectures[key] = typeof values === 'string' ? [values] : values
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -129,4 +129,7 @@ export const types = Object.assign({
|
||||
'registry-supports-time-field': Boolean,
|
||||
'fail-if-no-match': Boolean,
|
||||
'sync-injected-deps-after-scripts': Array,
|
||||
cpu: [String, Array],
|
||||
libc: [String, Array],
|
||||
os: [String, Array],
|
||||
}, npmTypes.types)
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
import { type SupportedArchitectures } from '@pnpm/types'
|
||||
import { type CliOptions, type TargetConfig, overrideSupportedArchitecturesWithCLI } from '../src/overrideSupportedArchitecturesWithCLI'
|
||||
|
||||
function getOverriddenSupportedArchitectures (
|
||||
supportedArchitectures: SupportedArchitectures | undefined,
|
||||
cliOptions: CliOptions
|
||||
): SupportedArchitectures | undefined {
|
||||
const config: TargetConfig = { supportedArchitectures }
|
||||
overrideSupportedArchitecturesWithCLI(config, cliOptions)
|
||||
return config.supportedArchitectures
|
||||
}
|
||||
|
||||
test('no flags, no overrides', () => {
|
||||
expect(getOverriddenSupportedArchitectures(undefined, {})).toBeUndefined()
|
||||
|
||||
expect(getOverriddenSupportedArchitectures({}, {})).toStrictEqual({})
|
||||
|
||||
expect(getOverriddenSupportedArchitectures({
|
||||
os: ['linux'],
|
||||
}, {})).toStrictEqual({
|
||||
os: ['linux'],
|
||||
} as SupportedArchitectures)
|
||||
|
||||
expect(getOverriddenSupportedArchitectures({
|
||||
cpu: ['x64'],
|
||||
os: ['linux'],
|
||||
}, {})).toStrictEqual({
|
||||
cpu: ['x64'],
|
||||
os: ['linux'],
|
||||
} as SupportedArchitectures)
|
||||
|
||||
expect(getOverriddenSupportedArchitectures({
|
||||
cpu: ['x64'],
|
||||
libc: ['glibc'],
|
||||
os: ['linux'],
|
||||
}, {})).toStrictEqual({
|
||||
cpu: ['x64'],
|
||||
libc: ['glibc'],
|
||||
os: ['linux'],
|
||||
} as SupportedArchitectures)
|
||||
})
|
||||
|
||||
test('overrides', () => {
|
||||
expect(getOverriddenSupportedArchitectures(undefined, {
|
||||
cpu: ['arm64'],
|
||||
os: ['darwin'],
|
||||
})).toStrictEqual({
|
||||
cpu: ['arm64'],
|
||||
os: ['darwin'],
|
||||
})
|
||||
|
||||
expect(getOverriddenSupportedArchitectures({}, {
|
||||
cpu: ['arm64'],
|
||||
os: ['darwin'],
|
||||
})).toStrictEqual({
|
||||
cpu: ['arm64'],
|
||||
os: ['darwin'],
|
||||
})
|
||||
|
||||
expect(getOverriddenSupportedArchitectures({
|
||||
os: ['linux'],
|
||||
}, {
|
||||
cpu: ['arm64'],
|
||||
os: ['darwin'],
|
||||
})).toStrictEqual({
|
||||
cpu: ['arm64'],
|
||||
os: ['darwin'],
|
||||
} as SupportedArchitectures)
|
||||
|
||||
expect(getOverriddenSupportedArchitectures({
|
||||
cpu: ['x64'],
|
||||
os: ['linux'],
|
||||
}, {
|
||||
cpu: ['arm64'],
|
||||
os: ['darwin'],
|
||||
})).toStrictEqual({
|
||||
cpu: ['arm64'],
|
||||
os: ['darwin'],
|
||||
} as SupportedArchitectures)
|
||||
|
||||
expect(getOverriddenSupportedArchitectures({
|
||||
cpu: ['x64'],
|
||||
libc: ['glibc'],
|
||||
os: ['linux'],
|
||||
}, {
|
||||
cpu: ['arm64'],
|
||||
os: ['darwin'],
|
||||
})).toStrictEqual({
|
||||
cpu: ['arm64'],
|
||||
libc: ['glibc'],
|
||||
os: ['darwin'],
|
||||
} as SupportedArchitectures)
|
||||
})
|
||||
@@ -54,6 +54,7 @@
|
||||
"@pnpm/sort-packages": "workspace:*",
|
||||
"@pnpm/store-path": "workspace:*",
|
||||
"@pnpm/types": "workspace:*",
|
||||
"@pnpm/util.lex-comparator": "catalog:",
|
||||
"@pnpm/workspace.injected-deps-syncer": "workspace:*",
|
||||
"@zkochan/rimraf": "catalog:",
|
||||
"didyoumean2": "catalog:",
|
||||
|
||||
@@ -11,7 +11,8 @@ import { PnpmError } from '@pnpm/error'
|
||||
import { add } from '@pnpm/plugin-commands-installation'
|
||||
import { readPackageJsonFromDir } from '@pnpm/read-package-json'
|
||||
import { getBinsFromPackageManifest } from '@pnpm/package-bins'
|
||||
import { type PnpmSettings } from '@pnpm/types'
|
||||
import { type PnpmSettings, type SupportedArchitectures } from '@pnpm/types'
|
||||
import { lexCompare } from '@pnpm/util.lex-comparator'
|
||||
import execa from 'execa'
|
||||
import pick from 'ramda/src/pick'
|
||||
import renderHelp from 'render-help'
|
||||
@@ -29,6 +30,9 @@ export const shorthands: Record<string, string> = {
|
||||
export function rcOptionsTypes (): Record<string, unknown> {
|
||||
return {
|
||||
...pick([
|
||||
'cpu',
|
||||
'libc',
|
||||
'os',
|
||||
'use-node-version',
|
||||
], types),
|
||||
'shell-mode': Boolean,
|
||||
@@ -97,11 +101,13 @@ export async function handler (
|
||||
})
|
||||
return resolved.id
|
||||
}))
|
||||
const { cacheLink, cacheExists, cachedDir } = findCache(resolvedPkgs, {
|
||||
const { cacheLink, cacheExists, cachedDir } = findCache({
|
||||
packages: resolvedPkgs,
|
||||
dlxCacheMaxAge: opts.dlxCacheMaxAge,
|
||||
cacheDir: opts.cacheDir,
|
||||
registries: opts.registries,
|
||||
allowBuild: opts.allowBuild ?? [],
|
||||
allowBuild: opts.allowBuild,
|
||||
supportedArchitectures: opts.supportedArchitectures,
|
||||
})
|
||||
if (!cacheExists) {
|
||||
fs.mkdirSync(cachedDir, { recursive: true })
|
||||
@@ -196,13 +202,15 @@ function scopeless (pkgName: string): string {
|
||||
return pkgName
|
||||
}
|
||||
|
||||
function findCache (pkgs: string[], opts: {
|
||||
function findCache (opts: {
|
||||
packages: string[]
|
||||
cacheDir: string
|
||||
dlxCacheMaxAge: number
|
||||
registries: Record<string, string>
|
||||
allowBuild: string[]
|
||||
allowBuild?: string[]
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
}): { cacheLink: string, cacheExists: boolean, cachedDir: string } {
|
||||
const dlxCommandCacheDir = createDlxCommandCacheDir(pkgs, opts)
|
||||
const dlxCommandCacheDir = createDlxCommandCacheDir(opts)
|
||||
const cacheLink = path.join(dlxCommandCacheDir, 'pkg')
|
||||
const cachedDir = getValidCacheDir(cacheLink, opts.dlxCacheMaxAge)
|
||||
return {
|
||||
@@ -213,26 +221,44 @@ function findCache (pkgs: string[], opts: {
|
||||
}
|
||||
|
||||
function createDlxCommandCacheDir (
|
||||
pkgs: string[],
|
||||
opts: {
|
||||
packages: string[]
|
||||
registries: Record<string, string>
|
||||
cacheDir: string
|
||||
allowBuild: string[]
|
||||
allowBuild?: string[]
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
}
|
||||
): string {
|
||||
const dlxCacheDir = path.resolve(opts.cacheDir, 'dlx')
|
||||
const cacheKey = createCacheKey(pkgs, opts.registries, opts.allowBuild)
|
||||
const cacheKey = createCacheKey(opts)
|
||||
const cachePath = path.join(dlxCacheDir, cacheKey)
|
||||
fs.mkdirSync(cachePath, { recursive: true })
|
||||
return cachePath
|
||||
}
|
||||
|
||||
export function createCacheKey (pkgs: string[], registries: Record<string, string>, allowBuild?: string[]): string {
|
||||
const sortedPkgs = [...pkgs].sort((a, b) => a.localeCompare(b))
|
||||
const sortedRegistries = Object.entries(registries).sort(([k1], [k2]) => k1.localeCompare(k2))
|
||||
export function createCacheKey (opts: {
|
||||
packages: string[]
|
||||
registries: Record<string, string>
|
||||
allowBuild?: string[]
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
}): string {
|
||||
const sortedPkgs = [...opts.packages].sort((a, b) => a.localeCompare(b))
|
||||
const sortedRegistries = Object.entries(opts.registries).sort(([k1], [k2]) => k1.localeCompare(k2))
|
||||
const args: unknown[] = [sortedPkgs, sortedRegistries]
|
||||
if (allowBuild?.length) {
|
||||
args.push({ allowBuild: allowBuild.sort((pkg1, pkg2) => pkg1.localeCompare(pkg2)) })
|
||||
if (opts.allowBuild?.length) {
|
||||
args.push({ allowBuild: opts.allowBuild.sort(lexCompare) })
|
||||
}
|
||||
if (opts.supportedArchitectures) {
|
||||
const supportedArchitecturesKeys = ['cpu', 'libc', 'os'] as const satisfies Array<keyof SupportedArchitectures>
|
||||
for (const key of supportedArchitecturesKeys) {
|
||||
const value = opts.supportedArchitectures[key]
|
||||
if (!value?.length) continue
|
||||
args.push({
|
||||
supportedArchitectures: {
|
||||
[key]: [...new Set(value)].sort(lexCompare),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
const hashStr = JSON.stringify(args)
|
||||
return createHexHash(hashStr)
|
||||
|
||||
@@ -2,9 +2,12 @@ import { createHexHash } from '@pnpm/crypto.hash'
|
||||
import { createCacheKey } from '../src/dlx'
|
||||
|
||||
test('creates a hash', () => {
|
||||
const received = createCacheKey(['shx', '@foo/bar'], {
|
||||
default: 'https://registry.npmjs.com/',
|
||||
'@foo': 'https://example.com/npm-registry/foo/',
|
||||
const received = createCacheKey({
|
||||
packages: ['shx', '@foo/bar'],
|
||||
registries: {
|
||||
default: 'https://registry.npmjs.com/',
|
||||
'@foo': 'https://example.com/npm-registry/foo/',
|
||||
},
|
||||
})
|
||||
const expected = createHexHash(JSON.stringify([['@foo/bar', 'shx'], [
|
||||
['@foo', 'https://example.com/npm-registry/foo/'],
|
||||
@@ -15,16 +18,43 @@ test('creates a hash', () => {
|
||||
|
||||
test('is agnostic to package order', () => {
|
||||
const registries = { default: 'https://registry.npmjs.com/' }
|
||||
expect(createCacheKey(['a', 'c', 'b'], registries)).toBe(createCacheKey(['a', 'b', 'c'], registries))
|
||||
expect(createCacheKey(['b', 'a', 'c'], registries)).toBe(createCacheKey(['a', 'b', 'c'], registries))
|
||||
expect(createCacheKey(['b', 'c', 'a'], registries)).toBe(createCacheKey(['a', 'b', 'c'], registries))
|
||||
expect(createCacheKey(['c', 'a', 'b'], registries)).toBe(createCacheKey(['a', 'b', 'c'], registries))
|
||||
expect(createCacheKey(['c', 'b', 'a'], registries)).toBe(createCacheKey(['a', 'b', 'c'], registries))
|
||||
const makeOpts = (packages: string[]) => ({ packages, registries })
|
||||
expect(createCacheKey(makeOpts(['a', 'c', 'b']))).toBe(createCacheKey(makeOpts(['a', 'b', 'c'])))
|
||||
expect(createCacheKey(makeOpts(['b', 'a', 'c']))).toBe(createCacheKey(makeOpts(['a', 'b', 'c'])))
|
||||
expect(createCacheKey(makeOpts(['b', 'c', 'a']))).toBe(createCacheKey(makeOpts(['a', 'b', 'c'])))
|
||||
expect(createCacheKey(makeOpts(['c', 'a', 'b']))).toBe(createCacheKey(makeOpts(['a', 'b', 'c'])))
|
||||
expect(createCacheKey(makeOpts(['c', 'b', 'a']))).toBe(createCacheKey(makeOpts(['a', 'b', 'c'])))
|
||||
})
|
||||
|
||||
test('is agnostic to registry key order', () => {
|
||||
const packages = ['a', 'b', 'c']
|
||||
const foo = 'https://example.com/foo/'
|
||||
const bar = 'https://example.com/bar/'
|
||||
expect(createCacheKey(packages, { '@foo': foo, '@bar': bar })).toBe(createCacheKey(packages, { '@bar': bar, '@foo': foo }))
|
||||
expect(createCacheKey({
|
||||
packages,
|
||||
registries: { '@foo': foo, '@bar': bar },
|
||||
})).toBe(createCacheKey({
|
||||
packages,
|
||||
registries: { '@bar': bar, '@foo': foo },
|
||||
}))
|
||||
})
|
||||
|
||||
test('is agnostic to supportedArchitectures values order', () => {
|
||||
const packages = ['a', 'b', 'c']
|
||||
const registries = { default: 'https://registry.npmjs.com/' }
|
||||
expect(createCacheKey({
|
||||
packages,
|
||||
registries,
|
||||
supportedArchitectures: {
|
||||
os: ['win32', 'linux', 'darwin'],
|
||||
cpu: ['x86_64', 'armv7', 'i686'],
|
||||
},
|
||||
})).toBe(createCacheKey({
|
||||
packages,
|
||||
registries,
|
||||
supportedArchitectures: {
|
||||
cpu: ['armv7', 'i686', 'x86_64'],
|
||||
os: ['darwin', 'linux', 'win32'],
|
||||
},
|
||||
}))
|
||||
})
|
||||
|
||||
@@ -20,7 +20,11 @@ function sanitizeDlxCacheComponent (cacheName: string): string {
|
||||
return '***********-*****'
|
||||
}
|
||||
|
||||
const createCacheKey = (...pkgs: string[]): string => dlx.createCacheKey(pkgs, DEFAULT_OPTS.registries)
|
||||
const createCacheKey = (...packages: string[]): string => dlx.createCacheKey({
|
||||
packages,
|
||||
registries: DEFAULT_OPTS.registries,
|
||||
supportedArchitectures: DEFAULT_OPTS.supportedArchitectures,
|
||||
})
|
||||
|
||||
function verifyDlxCache (cacheName: string): void {
|
||||
expect(
|
||||
@@ -335,7 +339,12 @@ test('dlx builds the packages passed via --allow-build', async () => {
|
||||
dlxCacheMaxAge: Infinity,
|
||||
}, ['@pnpm.e2e/has-bin-and-needs-build'])
|
||||
|
||||
const dlxCacheDir = path.resolve('cache', 'dlx', dlx.createCacheKey(['@pnpm.e2e/has-bin-and-needs-build@1.0.0'], DEFAULT_OPTS.registries, allowBuild), 'pkg')
|
||||
const dlxCacheDir = path.resolve('cache', 'dlx', dlx.createCacheKey({
|
||||
packages: ['@pnpm.e2e/has-bin-and-needs-build@1.0.0'],
|
||||
allowBuild,
|
||||
registries: DEFAULT_OPTS.registries,
|
||||
supportedArchitectures: DEFAULT_OPTS.supportedArchitectures,
|
||||
}), 'pkg')
|
||||
const builtPkg1Path = path.join(dlxCacheDir, 'node_modules/.pnpm/@pnpm.e2e+pre-and-postinstall-scripts-example@1.0.0/node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example')
|
||||
expect(fs.existsSync(path.join(builtPkg1Path, 'package.json'))).toBeTruthy()
|
||||
expect(fs.existsSync(path.join(builtPkg1Path, 'generated-by-preinstall.js'))).toBeFalsy()
|
||||
|
||||
@@ -7,6 +7,7 @@ import { prepareExecutionEnv } from '@pnpm/plugin-commands-env'
|
||||
import { createOrConnectStoreController } from '@pnpm/store-connection-manager'
|
||||
import pick from 'ramda/src/pick'
|
||||
import renderHelp from 'render-help'
|
||||
import { getFetchFullMetadata } from './getFetchFullMetadata'
|
||||
import { type InstallCommandOptions } from './install'
|
||||
import { installDeps } from './installDeps'
|
||||
import { writeSettings } from '@pnpm/config.config-writer'
|
||||
@@ -18,6 +19,7 @@ export const shorthands: Record<string, string> = {
|
||||
export function rcOptionsTypes (): Record<string, unknown> {
|
||||
return pick([
|
||||
'cache-dir',
|
||||
'cpu',
|
||||
'child-concurrency',
|
||||
'dangerously-allow-all-builds',
|
||||
'engine-strict',
|
||||
@@ -37,6 +39,7 @@ export function rcOptionsTypes (): Record<string, unknown> {
|
||||
'ignore-pnpmfile',
|
||||
'ignore-scripts',
|
||||
'ignore-workspace-root-check',
|
||||
'libc',
|
||||
'link-workspace-packages',
|
||||
'lockfile-dir',
|
||||
'lockfile-directory',
|
||||
@@ -47,6 +50,7 @@ export function rcOptionsTypes (): Record<string, unknown> {
|
||||
'node-linker',
|
||||
'noproxy',
|
||||
'npm-path',
|
||||
'os',
|
||||
'package-import-method',
|
||||
'pnpmfile',
|
||||
'prefer-offline',
|
||||
@@ -278,6 +282,7 @@ export async function handler (
|
||||
}
|
||||
return installDeps({
|
||||
...opts,
|
||||
fetchFullMetadata: getFetchFullMetadata(opts),
|
||||
include,
|
||||
includeDirect: include,
|
||||
prepareExecutionEnv: prepareExecutionEnv.bind(null, opts),
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { type InstallCommandOptions } from './install'
|
||||
|
||||
export type GetFetchFullMetadataOptions = Pick<InstallCommandOptions, 'supportedArchitectures' | 'rootProjectManifest'>
|
||||
|
||||
/**
|
||||
* This function is a workaround for the fact that npm registry's abbreviated metadata currently does not contain `libc`.
|
||||
*
|
||||
* See <https://github.com/pnpm/pnpm/issues/7362#issuecomment-1971964689>.
|
||||
*/
|
||||
export const getFetchFullMetadata = (opts: GetFetchFullMetadataOptions): true | undefined => (
|
||||
opts.supportedArchitectures?.libc ??
|
||||
opts.rootProjectManifest?.pnpm?.supportedArchitectures?.libc
|
||||
) && true
|
||||
@@ -6,12 +6,14 @@ import { prepareExecutionEnv } from '@pnpm/plugin-commands-env'
|
||||
import { type CreateStoreControllerOptions } from '@pnpm/store-connection-manager'
|
||||
import pick from 'ramda/src/pick'
|
||||
import renderHelp from 'render-help'
|
||||
import { getFetchFullMetadata } from './getFetchFullMetadata'
|
||||
import { installDeps, type InstallDepsOptions } from './installDeps'
|
||||
|
||||
export function rcOptionsTypes (): Record<string, unknown> {
|
||||
return pick([
|
||||
'cache-dir',
|
||||
'child-concurrency',
|
||||
'cpu',
|
||||
'dangerously-allow-all-builds',
|
||||
'dev',
|
||||
'engine-strict',
|
||||
@@ -30,6 +32,8 @@ export function rcOptionsTypes (): Record<string, unknown> {
|
||||
'ignore-pnpmfile',
|
||||
'ignore-scripts',
|
||||
'optimistic-repeat-install',
|
||||
'os',
|
||||
'libc',
|
||||
'link-workspace-packages',
|
||||
'lockfile-dir',
|
||||
'lockfile-directory',
|
||||
@@ -317,6 +321,7 @@ export type InstallCommandOptions = Pick<Config,
|
||||
| 'disallowWorkspaceCycles'
|
||||
| 'updateConfig'
|
||||
| 'overrides'
|
||||
| 'supportedArchitectures'
|
||||
> & CreateStoreControllerOptions & {
|
||||
argv: {
|
||||
original: string[]
|
||||
@@ -342,9 +347,6 @@ 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: opts.frozenLockfileIfExists ?? (
|
||||
@@ -355,7 +357,7 @@ export async function handler (opts: InstallCommandOptions): Promise<void> {
|
||||
include,
|
||||
includeDirect: include,
|
||||
prepareExecutionEnv: prepareExecutionEnv.bind(null, opts),
|
||||
fetchFullMetadata,
|
||||
fetchFullMetadata: getFetchFullMetadata(opts),
|
||||
}
|
||||
if (opts.resolutionOnly) {
|
||||
installDepsOptions.lockfileOnly = true
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { type PnpmError } from '@pnpm/error'
|
||||
import { add, remove } from '@pnpm/plugin-commands-installation'
|
||||
import { prepare, prepareEmpty, preparePackages } from '@pnpm/prepare'
|
||||
import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
|
||||
import { type ProjectManifest } from '@pnpm/types'
|
||||
import loadJsonFile from 'load-json-file'
|
||||
import tempy from 'tempy'
|
||||
|
||||
@@ -42,6 +44,8 @@ const DEFAULT_OPTIONS = {
|
||||
virtualStoreDirMaxLength: process.platform === 'win32' ? 60 : 120,
|
||||
}
|
||||
|
||||
const describeOnLinuxOnly = process.platform === 'linux' ? describe : describe.skip
|
||||
|
||||
test('installing with "workspace:" should work even if link-workspace-packages is off', async () => {
|
||||
const projects = preparePackages([
|
||||
{
|
||||
@@ -395,3 +399,34 @@ test('add: fail trying to install @pnpm/exe', async () => {
|
||||
}
|
||||
expect(err.code).toBe('ERR_PNPM_GLOBAL_PNPM_INSTALL')
|
||||
})
|
||||
|
||||
describeOnLinuxOnly('filters optional dependencies based on pnpm.supportedArchitectures.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: ProjectManifest = {
|
||||
pnpm: {
|
||||
supportedArchitectures: {
|
||||
os: ['linux'],
|
||||
cpu: ['x64'],
|
||||
libc: [libc],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
prepare(rootProjectManifest)
|
||||
|
||||
await add.handler({
|
||||
...DEFAULT_OPTIONS,
|
||||
rootProjectManifest,
|
||||
dir: process.cwd(),
|
||||
linkWorkspacePackages: true,
|
||||
}, ['@pnpm.e2e/support-different-architectures'])
|
||||
|
||||
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)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -58,7 +58,7 @@ test('install with no store integrity validation', async () => {
|
||||
})
|
||||
|
||||
// Covers https://github.com/pnpm/pnpm/issues/7362
|
||||
describeOnLinuxOnly('filters optional dependencies based on libc', () => {
|
||||
describeOnLinuxOnly('filters optional dependencies based on pnpm.supportedArchitectures.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'],
|
||||
@@ -90,3 +90,32 @@ describeOnLinuxOnly('filters optional dependencies based on libc', () => {
|
||||
expect(pkgDirs).not.toContain(notFound)
|
||||
})
|
||||
})
|
||||
|
||||
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',
|
||||
},
|
||||
}
|
||||
|
||||
prepare(rootProjectManifest)
|
||||
|
||||
await install.handler({
|
||||
...DEFAULT_OPTS,
|
||||
rootProjectManifest,
|
||||
dir: process.cwd(),
|
||||
supportedArchitectures: {
|
||||
libc: [libc],
|
||||
},
|
||||
})
|
||||
|
||||
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)
|
||||
})
|
||||
})
|
||||
|
||||
56
pnpm-lock.yaml
generated
56
pnpm-lock.yaml
generated
@@ -61,8 +61,8 @@ catalogs:
|
||||
specifier: 0.0.1
|
||||
version: 0.0.1
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 4.6.0
|
||||
version: 4.6.0
|
||||
specifier: 4.7.1
|
||||
version: 4.7.1
|
||||
'@pnpm/semver-diff':
|
||||
specifier: ^1.1.0
|
||||
version: 1.1.0
|
||||
@@ -871,7 +871,7 @@ importers:
|
||||
version: link:../../pkg-manager/modules-yaml
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 4.6.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 4.7.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/types':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/types
|
||||
@@ -905,7 +905,7 @@ importers:
|
||||
dependencies:
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 4.6.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 4.7.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/store.cafs':
|
||||
specifier: workspace:*
|
||||
version: link:../../store/cafs
|
||||
@@ -980,7 +980,7 @@ importers:
|
||||
dependencies:
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 4.6.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 4.7.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/worker':
|
||||
specifier: workspace:*
|
||||
version: link:../../worker
|
||||
@@ -1166,7 +1166,7 @@ importers:
|
||||
version: link:../../__utils__/prepare
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 4.6.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 4.7.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@types/ramda':
|
||||
specifier: 'catalog:'
|
||||
version: 0.29.12
|
||||
@@ -1657,7 +1657,7 @@ importers:
|
||||
version: link:../../__utils__/prepare
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 4.6.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 4.7.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/testing.temp-store':
|
||||
specifier: workspace:*
|
||||
version: link:../../testing/temp-store
|
||||
@@ -2299,7 +2299,7 @@ importers:
|
||||
version: link:../../__utils__/prepare
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 4.6.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 4.7.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/types':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/types
|
||||
@@ -2585,7 +2585,7 @@ importers:
|
||||
version: link:../../__utils__/prepare
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 4.6.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 4.7.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/test-fixtures':
|
||||
specifier: workspace:*
|
||||
version: link:../../__utils__/test-fixtures
|
||||
@@ -2682,6 +2682,9 @@ importers:
|
||||
'@pnpm/types':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/types
|
||||
'@pnpm/util.lex-comparator':
|
||||
specifier: 'catalog:'
|
||||
version: 3.0.2
|
||||
'@pnpm/workspace.injected-deps-syncer':
|
||||
specifier: workspace:*
|
||||
version: link:../../workspace/injected-deps-syncer
|
||||
@@ -2733,7 +2736,7 @@ importers:
|
||||
version: link:../../__utils__/prepare
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 4.6.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 4.7.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/test-ipc-server':
|
||||
specifier: workspace:*
|
||||
version: link:../../__utils__/test-ipc-server
|
||||
@@ -4419,7 +4422,7 @@ importers:
|
||||
version: link:../../__utils__/prepare
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 4.6.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 4.7.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/test-fixtures':
|
||||
specifier: workspace:*
|
||||
version: link:../../__utils__/test-fixtures
|
||||
@@ -4706,7 +4709,7 @@ importers:
|
||||
version: link:../../pkg-manifest/read-package-json
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 4.6.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 4.7.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/store-path':
|
||||
specifier: workspace:*
|
||||
version: link:../../store/store-path
|
||||
@@ -4979,7 +4982,7 @@ importers:
|
||||
version: link:../read-projects-context
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 4.6.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 4.7.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/store-path':
|
||||
specifier: workspace:*
|
||||
version: link:../../store/store-path
|
||||
@@ -5330,7 +5333,7 @@ importers:
|
||||
version: 'link:'
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 4.6.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 4.7.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/test-fixtures':
|
||||
specifier: workspace:*
|
||||
version: link:../../__utils__/test-fixtures
|
||||
@@ -5556,7 +5559,7 @@ importers:
|
||||
version: link:../../__utils__/prepare
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 4.6.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 4.7.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/test-fixtures':
|
||||
specifier: workspace:*
|
||||
version: link:../../__utils__/test-fixtures
|
||||
@@ -6160,7 +6163,7 @@ importers:
|
||||
version: link:../pkg-manifest/read-project-manifest
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 4.6.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 4.7.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/run-npm':
|
||||
specifier: workspace:*
|
||||
version: link:../exec/run-npm
|
||||
@@ -6473,7 +6476,7 @@ importers:
|
||||
version: link:../../__utils__/prepare
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 4.6.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 4.7.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/test-fixtures':
|
||||
specifier: workspace:*
|
||||
version: link:../../__utils__/test-fixtures
|
||||
@@ -6600,7 +6603,7 @@ importers:
|
||||
version: link:../../__utils__/prepare
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 4.6.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 4.7.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/test-ipc-server':
|
||||
specifier: workspace:*
|
||||
version: link:../../__utils__/test-ipc-server
|
||||
@@ -7209,7 +7212,7 @@ importers:
|
||||
version: link:../../pkg-manifest/read-package-json
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 4.6.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 4.7.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/test-fixtures':
|
||||
specifier: workspace:*
|
||||
version: link:../../__utils__/test-fixtures
|
||||
@@ -7273,7 +7276,7 @@ importers:
|
||||
version: link:../../__utils__/prepare
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 4.6.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 4.7.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/workspace.filter-packages-from-dir':
|
||||
specifier: workspace:*
|
||||
version: link:../../workspace/filter-packages-from-dir
|
||||
@@ -7358,7 +7361,7 @@ importers:
|
||||
version: link:../../__utils__/prepare
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 4.6.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 4.7.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/test-fixtures':
|
||||
specifier: workspace:*
|
||||
version: link:../../__utils__/test-fixtures
|
||||
@@ -7712,7 +7715,7 @@ importers:
|
||||
version: link:../../__utils__/prepare
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 4.6.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 4.7.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@types/archy':
|
||||
specifier: 'catalog:'
|
||||
version: 0.0.33
|
||||
@@ -7966,7 +7969,7 @@ importers:
|
||||
version: link:../../store/package-store
|
||||
'@pnpm/registry-mock':
|
||||
specifier: 'catalog:'
|
||||
version: 4.6.0(encoding@0.1.13)(typanion@3.14.0)
|
||||
version: 4.7.1(encoding@0.1.13)(typanion@3.14.0)
|
||||
'@pnpm/store-controller-types':
|
||||
specifier: workspace:*
|
||||
version: link:../../store/store-controller-types
|
||||
@@ -9812,8 +9815,8 @@ packages:
|
||||
resolution: {integrity: sha512-UY5ZFl8jTgWpPMp3qwVt1z455gDLGh4aAna7ufqsJP9qhI6lr9scFpnEamjpA51Y3MJMBtnML8KATmH6RY+NHQ==}
|
||||
engines: {node: '>=18.12'}
|
||||
|
||||
'@pnpm/registry-mock@4.6.0':
|
||||
resolution: {integrity: sha512-VX2paPLc1wmv3mDNZiWVF+xqs47M7iLdemKkkvD50eG1kxjXyTjQMy6sfQjPCn/iFrxea1hpyi6FJ5AtROE7sw==}
|
||||
'@pnpm/registry-mock@4.7.1':
|
||||
resolution: {integrity: sha512-R9ApAYW+4QORO/4R60zwjkm01Ub4LQN6Zt6Ad+OGPw95C0ge4tWgvvQqtRR/3fjPMgw3BZ6SmK21686zqtURrA==}
|
||||
engines: {node: '>=18.12'}
|
||||
hasBin: true
|
||||
|
||||
@@ -15177,7 +15180,6 @@ packages:
|
||||
verdaccio@5.20.1:
|
||||
resolution: {integrity: sha512-zKQXYubQOfl2w09gO9BR7U9ZZkFPPby8tvV+na86/2vGZnY79kNSVnSbK8CM1bpJHTCQ80AGsmIGovg2FgXhdQ==}
|
||||
engines: {node: '>=12.18'}
|
||||
deprecated: this version is deprecated, please migrate to 6.x versions
|
||||
hasBin: true
|
||||
|
||||
verror@1.10.0:
|
||||
@@ -17471,7 +17473,7 @@ snapshots:
|
||||
read-yaml-file: 2.1.0
|
||||
strip-bom: 4.0.0
|
||||
|
||||
'@pnpm/registry-mock@4.6.0(encoding@0.1.13)(typanion@3.14.0)':
|
||||
'@pnpm/registry-mock@4.7.1(encoding@0.1.13)(typanion@3.14.0)':
|
||||
dependencies:
|
||||
anonymous-npm-registry-client: 0.3.2
|
||||
execa: 5.1.1
|
||||
|
||||
@@ -61,7 +61,7 @@ catalog:
|
||||
'@pnpm/npm-package-arg': ^1.0.0
|
||||
'@pnpm/os.env.path-extender': ^2.0.3
|
||||
'@pnpm/patch-package': 0.0.1
|
||||
'@pnpm/registry-mock': 4.6.0
|
||||
'@pnpm/registry-mock': 4.7.1
|
||||
'@pnpm/semver-diff': ^1.1.0
|
||||
'@pnpm/tabtab': ^0.5.4
|
||||
'@pnpm/util.lex-comparator': ^3.0.2
|
||||
|
||||
@@ -6,6 +6,7 @@ import { prepare, prepareEmpty } from '@pnpm/prepare'
|
||||
import { readModulesManifest } from '@pnpm/modules-yaml'
|
||||
import { addUser, REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
|
||||
import { dlx } from '@pnpm/plugin-commands-script-runners'
|
||||
import { type BaseManifest } from '@pnpm/types'
|
||||
import { execPnpm, execPnpmSync } from './utils'
|
||||
|
||||
let registries: Record<string, string>
|
||||
@@ -16,7 +17,9 @@ beforeAll(async () => {
|
||||
registries.default = `http://localhost:${REGISTRY_MOCK_PORT}/`
|
||||
})
|
||||
|
||||
const createCacheKey = (...pkgs: string[]): string => dlx.createCacheKey(pkgs, registries)
|
||||
const createCacheKey = (...packages: string[]): string => dlx.createCacheKey({ packages, registries })
|
||||
|
||||
const describeOnLinuxOnly = process.platform === 'linux' ? describe : describe.skip
|
||||
|
||||
test('dlx parses options between "dlx" and the command name', async () => {
|
||||
prepareEmpty()
|
||||
@@ -298,3 +301,97 @@ test('dlx uses the node version specified by --use-node-version', async () => {
|
||||
: path.join(pnpmHome, 'nodejs', '20.0.0', 'bin', 'node'),
|
||||
})
|
||||
})
|
||||
|
||||
describeOnLinuxOnly('dlx with supportedArchitectures CLI options', () => {
|
||||
type CPU = 'arm64' | 'x64'
|
||||
type LibC = 'glibc' | 'musl'
|
||||
type OS = 'darwin' | 'linux' | 'win32'
|
||||
type CLIOption = `--cpu=${CPU}` | `--libc=${LibC}` | `--os=${OS}`
|
||||
type Installed = string[]
|
||||
type NotInstalled = string[]
|
||||
type Case = [CLIOption[], Installed, NotInstalled]
|
||||
|
||||
test.each([
|
||||
[['--cpu=arm64', '--os=win32'], ['@pnpm.e2e/only-win32-arm64'], [
|
||||
'@pnpm.e2e/only-darwin-arm64',
|
||||
'@pnpm.e2e/only-darwin-x64',
|
||||
'@pnpm.e2e/only-linux-arm64-glibc',
|
||||
'@pnpm.e2e/only-linux-arm64-musl',
|
||||
'@pnpm.e2e/only-linux-x64-glibc',
|
||||
'@pnpm.e2e/only-linux-x64-musl',
|
||||
'@pnpm.e2e/only-win32-x64',
|
||||
]],
|
||||
|
||||
[['--cpu=arm64', '--os=darwin'], ['@pnpm.e2e/only-darwin-arm64'], [
|
||||
'@pnpm.e2e/only-darwin-x64',
|
||||
'@pnpm.e2e/only-linux-arm64-glibc',
|
||||
'@pnpm.e2e/only-linux-arm64-musl',
|
||||
'@pnpm.e2e/only-linux-x64-glibc',
|
||||
'@pnpm.e2e/only-linux-x64-musl',
|
||||
'@pnpm.e2e/only-win32-arm64',
|
||||
'@pnpm.e2e/only-win32-x64',
|
||||
]],
|
||||
|
||||
[['--cpu=x64', '--os=linux', '--libc=musl'], [
|
||||
'@pnpm.e2e/only-linux-x64-musl',
|
||||
], [
|
||||
'@pnpm.e2e/only-darwin-arm64',
|
||||
'@pnpm.e2e/only-darwin-x64',
|
||||
'@pnpm.e2e/only-linux-arm64-glibc',
|
||||
'@pnpm.e2e/only-linux-arm64-musl',
|
||||
'@pnpm.e2e/only-linux-x64-glibc',
|
||||
'@pnpm.e2e/only-win32-arm64',
|
||||
'@pnpm.e2e/only-win32-x64',
|
||||
]],
|
||||
|
||||
[[
|
||||
'--cpu=arm64',
|
||||
'--cpu=x64',
|
||||
'--os=darwin',
|
||||
'--os=linux',
|
||||
'--os=win32',
|
||||
], [
|
||||
'@pnpm.e2e/only-darwin-arm64',
|
||||
'@pnpm.e2e/only-darwin-x64',
|
||||
'@pnpm.e2e/only-linux-arm64-glibc',
|
||||
'@pnpm.e2e/only-linux-arm64-musl',
|
||||
'@pnpm.e2e/only-linux-x64-glibc',
|
||||
'@pnpm.e2e/only-linux-x64-musl',
|
||||
'@pnpm.e2e/only-win32-arm64',
|
||||
'@pnpm.e2e/only-win32-x64',
|
||||
], []],
|
||||
] as Case[])('%p', async (cliOpts, installed, notInstalled) => {
|
||||
prepareEmpty()
|
||||
|
||||
const execResult = execPnpmSync([
|
||||
`--config.store-dir=${path.resolve('store')}`,
|
||||
`--config.cache-dir=${path.resolve('cache')}`,
|
||||
'--package=@pnpm.e2e/support-different-architectures',
|
||||
...cliOpts,
|
||||
'dlx',
|
||||
'get-optional-dependencies',
|
||||
], {
|
||||
stdio: [null, 'pipe', 'inherit'],
|
||||
expectSuccess: true,
|
||||
})
|
||||
|
||||
interface OptionalDepsInfo {
|
||||
installed: Record<string, BaseManifest>
|
||||
notInstalled: string[]
|
||||
}
|
||||
|
||||
let optionalDepsInfo: OptionalDepsInfo
|
||||
try {
|
||||
optionalDepsInfo = JSON.parse(execResult.stdout.toString())
|
||||
} catch (err) {
|
||||
console.error(execResult.stdout.toString())
|
||||
console.error(execResult.stderr.toString())
|
||||
throw err
|
||||
}
|
||||
|
||||
expect(optionalDepsInfo).toStrictEqual({
|
||||
installed: Object.fromEntries(installed.map(name => [name, expect.objectContaining({ name })])),
|
||||
notInstalled,
|
||||
} as OptionalDepsInfo)
|
||||
})
|
||||
})
|
||||
|
||||
139
pnpm/test/install/supportedArchitectures.ts
Normal file
139
pnpm/test/install/supportedArchitectures.ts
Normal file
@@ -0,0 +1,139 @@
|
||||
import fs from 'fs'
|
||||
import { prepare, prepareEmpty } from '@pnpm/prepare'
|
||||
import { readModulesManifest } from '@pnpm/modules-yaml'
|
||||
import { type WorkspaceManifest } from '@pnpm/workspace.read-manifest'
|
||||
import { sync as writeYamlFile } from 'write-yaml-file'
|
||||
import { execPnpm } from '../utils'
|
||||
|
||||
const describeOnLinuxOnly = process.platform === 'linux' ? describe : describe.skip
|
||||
|
||||
type CPU = 'arm64' | 'x64'
|
||||
type LibC = 'glibc' | 'musl'
|
||||
type OS = 'darwin' | 'linux' | 'win32'
|
||||
type CLIOption = `--cpu=${CPU}` | `--libc=${LibC}` | `--os=${OS}`
|
||||
interface WorkspaceConfig {
|
||||
cpu?: CPU[]
|
||||
libc?: LibC[]
|
||||
os?: OS[]
|
||||
}
|
||||
type Installed = string[]
|
||||
type Skipped = string[]
|
||||
type Case = [
|
||||
CLIOption[],
|
||||
WorkspaceConfig | undefined,
|
||||
Installed,
|
||||
Skipped
|
||||
]
|
||||
|
||||
const TEST_CASES: Case[] = [
|
||||
[[], undefined, [
|
||||
'only-linux-x64-glibc',
|
||||
'only-linux-x64-musl',
|
||||
], [
|
||||
'only-darwin-arm64',
|
||||
'only-darwin-x64',
|
||||
'only-linux-arm64-glibc',
|
||||
'only-linux-arm64-musl',
|
||||
'only-win32-arm64',
|
||||
'only-win32-x64',
|
||||
]],
|
||||
|
||||
[[], {
|
||||
os: ['win32'],
|
||||
cpu: ['arm64', 'x64'],
|
||||
}, [
|
||||
'only-win32-arm64',
|
||||
'only-win32-x64',
|
||||
], [
|
||||
'only-darwin-arm64',
|
||||
'only-darwin-x64',
|
||||
'only-linux-arm64-glibc',
|
||||
'only-linux-arm64-musl',
|
||||
'only-linux-x64-glibc',
|
||||
'only-linux-x64-musl',
|
||||
]],
|
||||
|
||||
[[
|
||||
'--os=darwin',
|
||||
'--cpu=arm64',
|
||||
'--cpu=x64',
|
||||
], undefined, [
|
||||
'only-darwin-arm64',
|
||||
'only-darwin-x64',
|
||||
], [
|
||||
'only-linux-arm64-glibc',
|
||||
'only-linux-arm64-musl',
|
||||
'only-linux-x64-glibc',
|
||||
'only-linux-x64-musl',
|
||||
'only-win32-arm64',
|
||||
'only-win32-x64',
|
||||
]],
|
||||
|
||||
[[
|
||||
'--os=darwin',
|
||||
'--cpu=arm64',
|
||||
'--cpu=x64',
|
||||
], {
|
||||
os: ['win32'],
|
||||
cpu: ['arm64', 'x64'],
|
||||
}, [
|
||||
'only-darwin-arm64',
|
||||
'only-darwin-x64',
|
||||
], [
|
||||
'only-linux-arm64-glibc',
|
||||
'only-linux-arm64-musl',
|
||||
'only-linux-x64-glibc',
|
||||
'only-linux-x64-musl',
|
||||
'only-win32-arm64',
|
||||
'only-win32-x64',
|
||||
]],
|
||||
]
|
||||
|
||||
describeOnLinuxOnly('install with supportedArchitectures from CLI options and manifest.pnpm', () => {
|
||||
test.each(TEST_CASES)('%j on %j', async (cliOpts, workspaceConfig, installed, skipped) => {
|
||||
prepare({
|
||||
dependencies: {
|
||||
'@pnpm.e2e/support-different-architectures': '1.0.0',
|
||||
},
|
||||
})
|
||||
|
||||
writeYamlFile('pnpm-workspace.yaml', {
|
||||
supportedArchitectures: workspaceConfig,
|
||||
} as WorkspaceManifest)
|
||||
|
||||
await execPnpm([
|
||||
'install',
|
||||
'--reporter=append-only',
|
||||
...cliOpts,
|
||||
])
|
||||
|
||||
const modulesManifest = await readModulesManifest('node_modules')
|
||||
expect(Object.keys(modulesManifest?.hoistedDependencies ?? {}).sort()).toStrictEqual(installed.map(name => `@pnpm.e2e/${name}@1.0.0`))
|
||||
expect(modulesManifest?.skipped.sort()).toStrictEqual(skipped.map(name => `@pnpm.e2e/${name}@1.0.0`))
|
||||
|
||||
expect(fs.readdirSync('node_modules/.pnpm/node_modules/@pnpm.e2e/')).toStrictEqual(installed)
|
||||
})
|
||||
})
|
||||
|
||||
describeOnLinuxOnly('add with supportedArchitectures from CLI options and manifest.pnpm', () => {
|
||||
test.each(TEST_CASES)('%j on %j', async (cliOpts, workspaceConfig, installed, skipped) => {
|
||||
prepareEmpty()
|
||||
|
||||
writeYamlFile('pnpm-workspace.yaml', {
|
||||
supportedArchitectures: workspaceConfig,
|
||||
} as WorkspaceManifest)
|
||||
|
||||
await execPnpm([
|
||||
'add',
|
||||
'--reporter=append-only',
|
||||
...cliOpts,
|
||||
'@pnpm.e2e/support-different-architectures',
|
||||
])
|
||||
|
||||
const modulesManifest = await readModulesManifest('node_modules')
|
||||
expect(Object.keys(modulesManifest?.hoistedDependencies ?? {}).sort()).toStrictEqual(installed.map(name => `@pnpm.e2e/${name}@1.0.0`))
|
||||
expect(modulesManifest?.skipped.sort()).toStrictEqual(skipped.map(name => `@pnpm.e2e/${name}@1.0.0`))
|
||||
|
||||
expect(fs.readdirSync('node_modules/.pnpm/node_modules/@pnpm.e2e/')).toStrictEqual(installed)
|
||||
})
|
||||
})
|
||||
@@ -4,7 +4,10 @@ import { dlx } from '@pnpm/plugin-commands-script-runners'
|
||||
import { prepareEmpty } from '@pnpm/prepare'
|
||||
import { cleanExpiredDlxCache, cleanOrphans } from './cleanExpiredDlxCache'
|
||||
|
||||
const createCacheKey = (...pkgs: string[]): string => dlx.createCacheKey(pkgs, { default: 'https://registry.npmjs.com/' })
|
||||
const createCacheKey = (...packages: string[]): string => dlx.createCacheKey({
|
||||
packages,
|
||||
registries: { default: 'https://registry.npmjs.com/' },
|
||||
})
|
||||
|
||||
function createSampleDlxCacheLinkTarget (dirPath: string): void {
|
||||
fs.mkdirSync(path.join(dirPath, 'node_modules', '.pnpm'), { recursive: true })
|
||||
|
||||
@@ -12,7 +12,10 @@ import execa from 'execa'
|
||||
const REGISTRY = `http://localhost:${REGISTRY_MOCK_PORT}/`
|
||||
const pnpmBin = path.join(__dirname, '../../../pnpm/bin/pnpm.cjs')
|
||||
|
||||
const createCacheKey = (...pkgs: string[]): string => dlx.createCacheKey(pkgs, { default: REGISTRY })
|
||||
const createCacheKey = (...packages: string[]): string => dlx.createCacheKey({
|
||||
packages,
|
||||
registries: { default: REGISTRY },
|
||||
})
|
||||
|
||||
test('remove unreferenced packages', async () => {
|
||||
const project = prepare()
|
||||
|
||||
Reference in New Issue
Block a user