mirror of
https://github.com/pnpm/pnpm.git
synced 2025-12-23 23:29:17 -05:00
feat: add support to install different architectures (#7214)
close #5965 --------- Co-authored-by: Zoltan Kochan <z@kochan.io>
This commit is contained in:
55
.changeset/angry-maps-hide.md
Normal file
55
.changeset/angry-maps-hide.md
Normal file
@@ -0,0 +1,55 @@
|
||||
---
|
||||
"@pnpm/plugin-commands-publishing": minor
|
||||
"@pnpm/plugin-commands-script-runners": minor
|
||||
"@pnpm/filter-workspace-packages": minor
|
||||
"@pnpm/plugin-commands-licenses": minor
|
||||
"@pnpm/plugin-commands-patching": minor
|
||||
"@pnpm/resolve-dependencies": minor
|
||||
"@pnpm/package-is-installable": minor
|
||||
"@pnpm/package-requester": minor
|
||||
"@pnpm/plugin-commands-rebuild": minor
|
||||
"@pnpm/store-controller-types": minor
|
||||
"@pnpm/plugin-commands-store": minor
|
||||
"@pnpm/license-scanner": minor
|
||||
"@pnpm/filter-lockfile": minor
|
||||
"@pnpm/workspace.find-packages": minor
|
||||
"@pnpm/headless": minor
|
||||
"@pnpm/deps.graph-builder": minor
|
||||
"@pnpm/core": minor
|
||||
"@pnpm/types": minor
|
||||
"@pnpm/cli-utils": minor
|
||||
"@pnpm/config": minor
|
||||
"pnpm": minor
|
||||
---
|
||||
|
||||
Support for multiple architectures when installing dependencies [#5965](https://github.com/pnpm/pnpm/issues/5965).
|
||||
|
||||
You can now specify architectures for which you'd like to install optional dependencies, even if they don't match the architecture of the system running the install. Use the `supportedArchitectures` field in `package.json` to define your preferences.
|
||||
|
||||
For example, the following configuration tells pnpm to install optional dependencies for Windows x64:
|
||||
|
||||
```json
|
||||
{
|
||||
"pnpm": {
|
||||
"supportedArchitectures": {
|
||||
"os": ["win32"],
|
||||
"cpu": ["x64"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Whereas this configuration will have pnpm install optional dependencies for Windows, macOS, and the architecture of the system currently running the install. It includes artifacts for both x64 and arm64 CPUs:
|
||||
|
||||
```json
|
||||
{
|
||||
"pnpm": {
|
||||
"supportedArchitectures": {
|
||||
"os": ["win32", "darwin", "current"],
|
||||
"cpu": ["x64", "arm64"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Additionally, `supportedArchitectures` also supports specifying the `libc` of the system.
|
||||
5
.changeset/dirty-crews-boil.md
Normal file
5
.changeset/dirty-crews-boil.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@pnpm/build-modules": patch
|
||||
---
|
||||
|
||||
`filesIndexFile` may be undefined.
|
||||
@@ -1,6 +1,7 @@
|
||||
import { packageManager } from '@pnpm/cli-meta'
|
||||
import { logger } from '@pnpm/logger'
|
||||
import { checkPackage, UnsupportedEngineError, type WantedEngine } from '@pnpm/package-is-installable'
|
||||
import { type SupportedArchitectures } from '@pnpm/types'
|
||||
|
||||
export function packageIsInstallable (
|
||||
pkgPath: string,
|
||||
@@ -13,6 +14,7 @@ export function packageIsInstallable (
|
||||
opts: {
|
||||
engineStrict?: boolean
|
||||
nodeVersion?: string
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
}
|
||||
) {
|
||||
const pnpmVersion = packageManager.name === 'pnpm'
|
||||
@@ -21,6 +23,11 @@ export function packageIsInstallable (
|
||||
const err = checkPackage(pkgPath, pkg, {
|
||||
nodeVersion: opts.nodeVersion,
|
||||
pnpmVersion,
|
||||
supportedArchitectures: opts.supportedArchitectures ?? {
|
||||
os: ['current'],
|
||||
cpu: ['current'],
|
||||
libc: ['current'],
|
||||
},
|
||||
})
|
||||
if (err === null) return
|
||||
if (
|
||||
|
||||
@@ -1,18 +1,26 @@
|
||||
import * as utils from '@pnpm/read-project-manifest'
|
||||
import { type ProjectManifest } from '@pnpm/types'
|
||||
import { type SupportedArchitectures, type ProjectManifest } from '@pnpm/types'
|
||||
import { packageIsInstallable } from './packageIsInstallable'
|
||||
|
||||
export interface ReadProjectManifestOpts {
|
||||
engineStrict?: boolean
|
||||
nodeVersion?: string
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
}
|
||||
|
||||
interface BaseReadProjectManifestResult {
|
||||
fileName: string
|
||||
writeProjectManifest: (manifest: ProjectManifest, force?: boolean) => Promise<void>
|
||||
}
|
||||
|
||||
export interface ReadProjectManifestResult extends BaseReadProjectManifestResult {
|
||||
manifest: ProjectManifest
|
||||
}
|
||||
|
||||
export async function readProjectManifest (
|
||||
projectDir: string,
|
||||
opts: {
|
||||
engineStrict?: boolean
|
||||
nodeVersion?: string
|
||||
}
|
||||
): Promise<{
|
||||
fileName: string
|
||||
manifest: ProjectManifest
|
||||
writeProjectManifest: (manifest: ProjectManifest, force?: boolean) => Promise<void>
|
||||
}> {
|
||||
opts: ReadProjectManifestOpts = {}
|
||||
): Promise<ReadProjectManifestResult> {
|
||||
const { fileName, manifest, writeProjectManifest } = await utils.readProjectManifest(projectDir)
|
||||
packageIsInstallable(projectDir, manifest as any, opts) // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
return { fileName, manifest, writeProjectManifest }
|
||||
@@ -20,27 +28,21 @@ export async function readProjectManifest (
|
||||
|
||||
export async function readProjectManifestOnly (
|
||||
projectDir: string,
|
||||
opts: {
|
||||
engineStrict?: boolean
|
||||
nodeVersion?: string
|
||||
} = {}
|
||||
opts: ReadProjectManifestOpts = {}
|
||||
): Promise<ProjectManifest> {
|
||||
const manifest = await utils.readProjectManifestOnly(projectDir)
|
||||
packageIsInstallable(projectDir, manifest as any, opts) // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
return manifest
|
||||
}
|
||||
|
||||
export interface TryReadProjectManifestResult extends BaseReadProjectManifestResult {
|
||||
manifest: ProjectManifest | null
|
||||
}
|
||||
|
||||
export async function tryReadProjectManifest (
|
||||
projectDir: string,
|
||||
opts: {
|
||||
engineStrict?: boolean
|
||||
nodeVersion?: string
|
||||
}
|
||||
): Promise<{
|
||||
fileName: string
|
||||
manifest: ProjectManifest | null
|
||||
writeProjectManifest: (manifest: ProjectManifest, force?: boolean) => Promise<void>
|
||||
}> {
|
||||
opts: ReadProjectManifestOpts
|
||||
): Promise<TryReadProjectManifestResult> {
|
||||
const { fileName, manifest, writeProjectManifest } = await utils.tryReadProjectManifest(projectDir)
|
||||
if (manifest == null) return { fileName, manifest, writeProjectManifest }
|
||||
packageIsInstallable(projectDir, manifest as any, opts) // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import path from 'path'
|
||||
import { PnpmError } from '@pnpm/error'
|
||||
import {
|
||||
type SupportedArchitectures,
|
||||
type AllowedDeprecatedVersions,
|
||||
type PackageExtension,
|
||||
type PeerDependencyRules,
|
||||
@@ -18,6 +19,7 @@ export interface OptionsFromRootManifest {
|
||||
packageExtensions?: Record<string, PackageExtension>
|
||||
patchedDependencies?: Record<string, string>
|
||||
peerDependencyRules?: PeerDependencyRules
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
}
|
||||
|
||||
export function getOptionsFromRootManifest (manifestDir: string, manifest: ProjectManifest): OptionsFromRootManifest {
|
||||
@@ -46,6 +48,13 @@ export function getOptionsFromRootManifest (manifestDir: string, manifest: Proje
|
||||
patchedDependencies[dep] = path.join(manifestDir, patchFile)
|
||||
}
|
||||
}
|
||||
|
||||
const supportedArchitectures = {
|
||||
os: manifest.pnpm?.supportedArchitectures?.os ?? ['current'],
|
||||
cpu: manifest.pnpm?.supportedArchitectures?.cpu ?? ['current'],
|
||||
libc: manifest.pnpm?.supportedArchitectures?.libc ?? ['current'],
|
||||
}
|
||||
|
||||
const settings: OptionsFromRootManifest = {
|
||||
allowedDeprecatedVersions,
|
||||
allowNonAppliedPatches,
|
||||
@@ -54,6 +63,7 @@ export function getOptionsFromRootManifest (manifestDir: string, manifest: Proje
|
||||
packageExtensions,
|
||||
peerDependencyRules,
|
||||
patchedDependencies,
|
||||
supportedArchitectures,
|
||||
}
|
||||
if (onlyBuiltDependencies) {
|
||||
settings.onlyBuiltDependencies = onlyBuiltDependencies
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { PnpmError } from '@pnpm/error'
|
||||
import { type SupportedArchitectures } from '@pnpm/types'
|
||||
import { familySync as getLibcFamilySync } from 'detect-libc'
|
||||
|
||||
const currentLibc = getLibcFamilySync() ?? 'unknown'
|
||||
@@ -16,19 +17,26 @@ export class UnsupportedPlatformError extends PnpmError {
|
||||
|
||||
export function checkPlatform (
|
||||
packageId: string,
|
||||
wantedPlatform: WantedPlatform
|
||||
wantedPlatform: WantedPlatform,
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
) {
|
||||
const current = {
|
||||
os: dedupeCurrent(process.platform, supportedArchitectures?.os ?? ['current']),
|
||||
cpu: dedupeCurrent(process.arch, supportedArchitectures?.cpu ?? ['current']),
|
||||
libc: dedupeCurrent(currentLibc, supportedArchitectures?.libc ?? ['current']),
|
||||
}
|
||||
|
||||
const { platform, arch } = process
|
||||
let osOk = true; let cpuOk = true; let libcOk = true
|
||||
|
||||
if (wantedPlatform.os) {
|
||||
osOk = checkList(platform, wantedPlatform.os)
|
||||
osOk = checkList(current.os, wantedPlatform.os)
|
||||
}
|
||||
if (wantedPlatform.cpu) {
|
||||
cpuOk = checkList(arch, wantedPlatform.cpu)
|
||||
cpuOk = checkList(current.cpu, wantedPlatform.cpu)
|
||||
}
|
||||
if (wantedPlatform.libc && currentLibc !== 'unknown') {
|
||||
libcOk = checkList(currentLibc, wantedPlatform.libc)
|
||||
libcOk = checkList(current.libc, wantedPlatform.libc)
|
||||
}
|
||||
|
||||
if (!osOk || !cpuOk || !libcOk) {
|
||||
@@ -45,25 +53,35 @@ export interface Platform {
|
||||
|
||||
export type WantedPlatform = Partial<Platform>
|
||||
|
||||
function checkList (value: string, list: string | string[]) {
|
||||
let tmp; let match = false; let blc = 0
|
||||
function checkList (value: string | string[], list: string | string[]): boolean {
|
||||
let tmp
|
||||
let match = false
|
||||
let blc = 0
|
||||
|
||||
if (typeof list === 'string') {
|
||||
list = [list]
|
||||
}
|
||||
if (list.length === 1 && list[0] === 'any') {
|
||||
return true
|
||||
}
|
||||
for (let i = 0; i < list.length; ++i) {
|
||||
tmp = list[i]
|
||||
if (tmp[0] === '!') {
|
||||
tmp = tmp.slice(1)
|
||||
if (tmp === value) {
|
||||
return false
|
||||
const values = Array.isArray(value) ? value : [value]
|
||||
for (const value of values) {
|
||||
for (let i = 0; i < list.length; ++i) {
|
||||
tmp = list[i]
|
||||
if (tmp[0] === '!') {
|
||||
tmp = tmp.slice(1)
|
||||
if (tmp === value) {
|
||||
return false
|
||||
}
|
||||
++blc
|
||||
} else {
|
||||
match = match || tmp === value
|
||||
}
|
||||
++blc
|
||||
} else {
|
||||
match = match || tmp === value
|
||||
}
|
||||
}
|
||||
return match || blc === list.length
|
||||
}
|
||||
|
||||
function dedupeCurrent (current: string, supported: string[]) {
|
||||
return supported.map((supported) => supported === 'current' ? current : supported)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
import { checkEngine, UnsupportedEngineError, type WantedEngine } from './checkEngine'
|
||||
import { checkPlatform, UnsupportedPlatformError } from './checkPlatform'
|
||||
import { getSystemNodeVersion } from './getSystemNodeVersion'
|
||||
import { type SupportedArchitectures } from '@pnpm/types'
|
||||
|
||||
export type { Engine } from './checkEngine'
|
||||
export type { Platform, WantedPlatform } from './checkPlatform'
|
||||
@@ -31,6 +32,7 @@ export function packageIsInstallable (
|
||||
optional: boolean
|
||||
pnpmVersion?: string
|
||||
lockfileDir: string
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
}
|
||||
): boolean | null {
|
||||
const warn = checkPackage(pkgId, pkg, options)
|
||||
@@ -73,13 +75,14 @@ export function checkPackage (
|
||||
options: {
|
||||
nodeVersion?: string
|
||||
pnpmVersion?: string
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
}
|
||||
): null | UnsupportedEngineError | UnsupportedPlatformError {
|
||||
return checkPlatform(pkgId, {
|
||||
cpu: manifest.cpu ?? ['any'],
|
||||
os: manifest.os ?? ['any'],
|
||||
libc: manifest.libc ?? ['any'],
|
||||
}) ?? (
|
||||
}, options.supportedArchitectures) ?? (
|
||||
(manifest.engines == null)
|
||||
? null
|
||||
: checkEngine(pkgId, manifest.engines, {
|
||||
@@ -87,4 +90,4 @@ export function checkPackage (
|
||||
pnpm: options.pnpmVersion,
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -79,3 +79,45 @@ test('os wrong (negation)', () => {
|
||||
test('nothing wrong (negation)', () => {
|
||||
expect(checkPlatform(packageId, { cpu: '!enten-cpu', os: '!enten-os', libc: '!enten-libc' })).toBe(null)
|
||||
})
|
||||
|
||||
test('override OS', () => {
|
||||
expect(checkPlatform(packageId, { cpu: 'any', os: 'win32', libc: 'any' }, {
|
||||
os: ['win32'],
|
||||
cpu: ['current'],
|
||||
libc: ['current'],
|
||||
})).toBe(null)
|
||||
})
|
||||
|
||||
test('accept another CPU', () => {
|
||||
expect(checkPlatform(packageId, { cpu: 'x64', os: 'any', libc: 'any' }, {
|
||||
os: ['current'],
|
||||
cpu: ['current', 'x64'],
|
||||
libc: ['current'],
|
||||
})).toBe(null)
|
||||
})
|
||||
|
||||
test('fail when CPU is different', () => {
|
||||
const err = checkPlatform(packageId, { cpu: 'x64', os: 'any', libc: 'any' }, {
|
||||
os: ['current'],
|
||||
cpu: ['arm64'],
|
||||
libc: ['current'],
|
||||
})
|
||||
expect(err).toBeTruthy()
|
||||
expect(err?.code).toBe('ERR_PNPM_UNSUPPORTED_PLATFORM')
|
||||
})
|
||||
|
||||
test('override libc', () => {
|
||||
expect(checkPlatform(packageId, { cpu: 'any', os: 'any', libc: 'glibc' }, {
|
||||
os: ['current'],
|
||||
cpu: ['current'],
|
||||
libc: ['glibc'],
|
||||
})).toBe(null)
|
||||
})
|
||||
|
||||
test('accept another libc', () => {
|
||||
expect(checkPlatform(packageId, { cpu: 'any', os: 'any', libc: 'glibc' }, {
|
||||
os: ['current'],
|
||||
cpu: ['current'],
|
||||
libc: ['current', 'glibc'],
|
||||
})).toBe(null)
|
||||
})
|
||||
|
||||
77
deps/graph-builder/src/lockfileToDepGraph.ts
vendored
77
deps/graph-builder/src/lockfileToDepGraph.ts
vendored
@@ -16,7 +16,7 @@ import {
|
||||
import { logger } from '@pnpm/logger'
|
||||
import { type IncludedDependencies } from '@pnpm/modules-yaml'
|
||||
import { packageIsInstallable } from '@pnpm/package-is-installable'
|
||||
import { type PatchFile, type Registries } from '@pnpm/types'
|
||||
import { type SupportedArchitectures, type PatchFile, type Registries } from '@pnpm/types'
|
||||
import {
|
||||
type PkgRequestFetchResult,
|
||||
type FetchPackageToStoreFunction,
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
import * as dp from '@pnpm/dependency-path'
|
||||
import pathExists from 'path-exists'
|
||||
import equals from 'ramda/src/equals'
|
||||
import isEmpty from 'ramda/src/isEmpty'
|
||||
|
||||
const brokenModulesLogger = logger('_broken_node_modules')
|
||||
|
||||
@@ -33,7 +34,7 @@ export interface DependenciesGraphNode {
|
||||
hasBundledDependencies: boolean
|
||||
modules: string
|
||||
name: string
|
||||
fetching: () => Promise<PkgRequestFetchResult>
|
||||
fetching?: () => Promise<PkgRequestFetchResult>
|
||||
dir: string
|
||||
children: Record<string, string>
|
||||
optionalDependencies: Set<string>
|
||||
@@ -43,7 +44,7 @@ export interface DependenciesGraphNode {
|
||||
requiresBuild: boolean
|
||||
prepare: boolean
|
||||
hasBin: boolean
|
||||
filesIndexFile: string
|
||||
filesIndexFile?: string
|
||||
patchFile?: PatchFile
|
||||
}
|
||||
|
||||
@@ -68,6 +69,7 @@ export interface LockfileToDepGraphOptions {
|
||||
storeController: StoreController
|
||||
storeDir: string
|
||||
virtualStoreDir: string
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
}
|
||||
|
||||
export interface DirectDependenciesByImporterId {
|
||||
@@ -121,16 +123,18 @@ export async function lockfileToDepGraph (
|
||||
nodeVersion: opts.nodeVersion,
|
||||
optional: pkgSnapshot.optional === true,
|
||||
pnpmVersion: opts.pnpmVersion,
|
||||
supportedArchitectures: opts.supportedArchitectures,
|
||||
}) === false
|
||||
) {
|
||||
opts.skipped.add(depPath)
|
||||
return
|
||||
}
|
||||
const dir = path.join(modules, pkgName)
|
||||
const depIsPresent = !refIsLocalDirectory(depPath) &&
|
||||
currentPackages[depPath] && equals(currentPackages[depPath].dependencies, lockfile.packages![depPath].dependencies)
|
||||
if (
|
||||
!refIsLocalDirectory(depPath) &&
|
||||
currentPackages[depPath] && equals(currentPackages[depPath].dependencies, lockfile.packages![depPath].dependencies) &&
|
||||
equals(currentPackages[depPath].optionalDependencies, lockfile.packages![depPath].optionalDependencies)
|
||||
depIsPresent && isEmpty(currentPackages[depPath].optionalDependencies) &&
|
||||
isEmpty(lockfile.packages![depPath].optionalDependencies)
|
||||
) {
|
||||
if (await pathExists(dir)) {
|
||||
return
|
||||
@@ -140,31 +144,42 @@ export async function lockfileToDepGraph (
|
||||
missing: dir,
|
||||
})
|
||||
}
|
||||
const resolution = pkgSnapshotToResolution(depPath, pkgSnapshot, opts.registries)
|
||||
progressLogger.debug({
|
||||
packageId,
|
||||
requester: opts.lockfileDir,
|
||||
status: 'resolved',
|
||||
})
|
||||
let fetchResponse!: ReturnType<FetchPackageToStoreFunction>
|
||||
try {
|
||||
fetchResponse = opts.storeController.fetchPackage({
|
||||
force: false,
|
||||
lockfileDir: opts.lockfileDir,
|
||||
ignoreScripts: opts.ignoreScripts,
|
||||
pkg: {
|
||||
id: packageId,
|
||||
resolution,
|
||||
},
|
||||
expectedPkg: {
|
||||
name: pkgName,
|
||||
version: pkgVersion,
|
||||
},
|
||||
}) as any // eslint-disable-line
|
||||
if (fetchResponse instanceof Promise) fetchResponse = await fetchResponse
|
||||
} catch (err: any) { // eslint-disable-line
|
||||
if (pkgSnapshot.optional) return
|
||||
throw err
|
||||
let fetchResponse!: Partial<ReturnType<FetchPackageToStoreFunction>>
|
||||
if (depIsPresent && equals(currentPackages[depPath].optionalDependencies, lockfile.packages![depPath].optionalDependencies)) {
|
||||
if (await pathExists(dir)) {
|
||||
fetchResponse = {}
|
||||
} else {
|
||||
brokenModulesLogger.debug({
|
||||
missing: dir,
|
||||
})
|
||||
}
|
||||
}
|
||||
if (!fetchResponse) {
|
||||
const resolution = pkgSnapshotToResolution(depPath, pkgSnapshot, opts.registries)
|
||||
progressLogger.debug({
|
||||
packageId,
|
||||
requester: opts.lockfileDir,
|
||||
status: 'resolved',
|
||||
})
|
||||
try {
|
||||
fetchResponse = opts.storeController.fetchPackage({
|
||||
force: false,
|
||||
lockfileDir: opts.lockfileDir,
|
||||
ignoreScripts: opts.ignoreScripts,
|
||||
pkg: {
|
||||
id: packageId,
|
||||
resolution,
|
||||
},
|
||||
expectedPkg: {
|
||||
name: pkgName,
|
||||
version: pkgVersion,
|
||||
},
|
||||
}) as any // eslint-disable-line
|
||||
if (fetchResponse instanceof Promise) fetchResponse = await fetchResponse
|
||||
} catch (err: any) { // eslint-disable-line
|
||||
if (pkgSnapshot.optional) return
|
||||
throw err
|
||||
}
|
||||
}
|
||||
graph[dir] = {
|
||||
children: {},
|
||||
|
||||
@@ -8,7 +8,7 @@ export interface DependenciesGraphNode {
|
||||
name: string
|
||||
dir: string
|
||||
fetchingBundledManifest?: () => Promise<PackageManifest | undefined>
|
||||
filesIndexFile: string
|
||||
filesIndexFile?: string
|
||||
hasBin: boolean
|
||||
hasBundledDependencies: boolean
|
||||
installable?: boolean
|
||||
|
||||
@@ -135,10 +135,12 @@ async function buildDependency (
|
||||
patchFileHash: depNode.patchFile?.hash,
|
||||
isBuilt: hasSideEffects,
|
||||
})
|
||||
await opts.storeController.upload(depNode.dir, {
|
||||
sideEffectsCacheKey,
|
||||
filesIndexFile: depNode.filesIndexFile,
|
||||
})
|
||||
if (depNode.filesIndexFile) {
|
||||
await opts.storeController.upload(depNode.dir, {
|
||||
sideEffectsCacheKey,
|
||||
filesIndexFile: depNode.filesIndexFile,
|
||||
})
|
||||
}
|
||||
} catch (err: any) { // eslint-disable-line
|
||||
if (err.statusCode === 403) {
|
||||
logger.warn({
|
||||
|
||||
@@ -47,4 +47,9 @@ export const DEFAULT_OPTS = {
|
||||
useRunningStoreServer: false,
|
||||
useStoreServer: false,
|
||||
workspaceConcurrency: 4,
|
||||
supportedArchitectures: {
|
||||
os: ['current'],
|
||||
cpu: ['current'],
|
||||
libc: ['current'],
|
||||
},
|
||||
}
|
||||
|
||||
@@ -50,6 +50,11 @@ export const DEFAULT_OPTS = {
|
||||
useRunningStoreServer: false,
|
||||
useStoreServer: false,
|
||||
workspaceConcurrency: 4,
|
||||
supportedArchitectures: {
|
||||
os: ['current'],
|
||||
cpu: ['current'],
|
||||
libc: ['current'],
|
||||
},
|
||||
}
|
||||
|
||||
export const DLX_DEFAULT_OPTS = {
|
||||
@@ -80,4 +85,9 @@ export const DLX_DEFAULT_OPTS = {
|
||||
storeDir: path.join(tmp, 'store'),
|
||||
userConfig: {},
|
||||
workspaceConcurrency: 1,
|
||||
supportedArchitectures: {
|
||||
os: ['current'],
|
||||
cpu: ['current'],
|
||||
libc: ['current'],
|
||||
},
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
import { nameVerFromPkgSnapshot } from '@pnpm/lockfile-utils'
|
||||
import { logger } from '@pnpm/logger'
|
||||
import { packageIsInstallable } from '@pnpm/package-is-installable'
|
||||
import { type DependenciesField } from '@pnpm/types'
|
||||
import { type SupportedArchitectures, type DependenciesField } from '@pnpm/types'
|
||||
import * as dp from '@pnpm/dependency-path'
|
||||
import mapValues from 'ramda/src/map'
|
||||
import pickBy from 'ramda/src/pickBy'
|
||||
@@ -16,21 +16,32 @@ import { filterImporter } from './filterImporter'
|
||||
|
||||
const lockfileLogger = logger('lockfile')
|
||||
|
||||
export function filterLockfileByEngine (
|
||||
lockfile: Lockfile,
|
||||
opts: FilterLockfileOptions
|
||||
) {
|
||||
const importerIds = Object.keys(lockfile.importers)
|
||||
return filterLockfileByImportersAndEngine(lockfile, importerIds, opts)
|
||||
}
|
||||
|
||||
export interface FilterLockfileOptions {
|
||||
currentEngine: {
|
||||
nodeVersion: string
|
||||
pnpmVersion: string
|
||||
}
|
||||
engineStrict: boolean
|
||||
include: { [dependenciesField in DependenciesField]: boolean }
|
||||
includeIncompatiblePackages?: boolean
|
||||
failOnMissingDependencies: boolean
|
||||
lockfileDir: string
|
||||
skipped: Set<string>
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
}
|
||||
|
||||
export function filterLockfileByImportersAndEngine (
|
||||
lockfile: Lockfile,
|
||||
importerIds: string[],
|
||||
opts: {
|
||||
currentEngine: {
|
||||
nodeVersion: string
|
||||
pnpmVersion: string
|
||||
}
|
||||
engineStrict: boolean
|
||||
include: { [dependenciesField in DependenciesField]: boolean }
|
||||
includeIncompatiblePackages?: boolean
|
||||
failOnMissingDependencies: boolean
|
||||
lockfileDir: string
|
||||
skipped: Set<string>
|
||||
}
|
||||
opts: FilterLockfileOptions
|
||||
): { lockfile: Lockfile, selectedImporterIds: string[] } {
|
||||
const importerIdSet = new Set(importerIds) as Set<string>
|
||||
|
||||
@@ -50,6 +61,7 @@ export function filterLockfileByImportersAndEngine (
|
||||
opts.includeIncompatiblePackages === true,
|
||||
lockfileDir: opts.lockfileDir,
|
||||
skipped: opts.skipped,
|
||||
supportedArchitectures: opts.supportedArchitectures,
|
||||
})
|
||||
: {}
|
||||
|
||||
@@ -89,6 +101,7 @@ function pickPkgsWithAllDeps (
|
||||
includeIncompatiblePackages: boolean
|
||||
lockfileDir: string
|
||||
skipped: Set<string>
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
}
|
||||
) {
|
||||
const pickedPackages = {} as PackageSnapshots
|
||||
@@ -115,6 +128,7 @@ function pkgAllDeps (
|
||||
includeIncompatiblePackages: boolean
|
||||
lockfileDir: string
|
||||
skipped: Set<string>
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
}
|
||||
) {
|
||||
for (const depPath of depPaths) {
|
||||
@@ -150,6 +164,7 @@ function pkgAllDeps (
|
||||
nodeVersion: opts.currentEngine.nodeVersion,
|
||||
optional: pkgSnapshot.optional === true,
|
||||
pnpmVersion: opts.currentEngine.pnpmVersion,
|
||||
supportedArchitectures: opts.supportedArchitectures,
|
||||
}) !== false
|
||||
if (!installable) {
|
||||
if (!ctx.pickedPackages[depPath] && pkgSnapshot.optional === true) {
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export { filterLockfile } from './filterLockfile'
|
||||
export { filterLockfileByImporters } from './filterLockfileByImporters'
|
||||
export { filterLockfileByImportersAndEngine } from './filterLockfileByImportersAndEngine'
|
||||
export { filterLockfileByImportersAndEngine, filterLockfileByEngine } from './filterLockfileByImportersAndEngine'
|
||||
|
||||
@@ -116,6 +116,11 @@ test('filterByImportersAndEngine(): skip packages that are not installable', ()
|
||||
},
|
||||
lockfileDir: process.cwd(),
|
||||
skipped: skippedPackages,
|
||||
supportedArchitectures: {
|
||||
os: ['current'],
|
||||
cpu: ['current'],
|
||||
libc: ['current'],
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
@@ -297,6 +302,11 @@ test('filterByImportersAndEngine(): filter the packages that set os and cpu', ()
|
||||
},
|
||||
lockfileDir: process.cwd(),
|
||||
skipped: skippedPackages,
|
||||
supportedArchitectures: {
|
||||
os: ['current'],
|
||||
cpu: ['current'],
|
||||
libc: ['current'],
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
@@ -467,6 +477,11 @@ test('filterByImportersAndEngine(): filter the packages that set libc', () => {
|
||||
},
|
||||
lockfileDir: process.cwd(),
|
||||
skipped: skippedPackages,
|
||||
supportedArchitectures: {
|
||||
os: ['current'],
|
||||
cpu: ['current'],
|
||||
libc: ['current'],
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
@@ -602,6 +617,11 @@ test('filterByImportersAndEngine(): includes linked packages', () => {
|
||||
},
|
||||
lockfileDir: process.cwd(),
|
||||
skipped: new Set(),
|
||||
supportedArchitectures: {
|
||||
os: ['current'],
|
||||
cpu: ['current'],
|
||||
libc: ['current'],
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -140,6 +140,7 @@ export type ProjectManifest = BaseManifest & {
|
||||
ignoreCves?: string[]
|
||||
}
|
||||
requiredScripts?: string[]
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
}
|
||||
private?: boolean
|
||||
resolutions?: Record<string, string>
|
||||
@@ -148,3 +149,9 @@ export type ProjectManifest = BaseManifest & {
|
||||
export type PackageManifest = DependencyManifest & {
|
||||
deprecated?: string
|
||||
}
|
||||
|
||||
export interface SupportedArchitectures {
|
||||
os?: string[]
|
||||
cpu?: string[]
|
||||
libc?: string[]
|
||||
}
|
||||
|
||||
@@ -48,4 +48,9 @@ export const DEFAULT_OPTS = {
|
||||
useRunningStoreServer: false,
|
||||
useStoreServer: false,
|
||||
workspaceConcurrency: 4,
|
||||
supportedArchitectures: {
|
||||
os: ['current'],
|
||||
cpu: ['current'],
|
||||
libc: ['current'],
|
||||
},
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ export type ListMissingPeersOptions = Partial<GetContextOptions>
|
||||
| 'useGitBranchLockfile'
|
||||
| 'workspacePackages'
|
||||
>
|
||||
& Partial<Pick<InstallOptions, 'supportedArchitectures'>>
|
||||
& Pick<GetContextOptions, 'autoInstallPeers' | 'excludeLinksFromLockfile' | 'storeDir'>
|
||||
|
||||
export async function getPeerDependencyIssues (
|
||||
@@ -84,6 +85,7 @@ export async function getPeerDependencyIssues (
|
||||
virtualStoreDir: ctx.virtualStoreDir,
|
||||
wantedLockfile: ctx.wantedLockfile,
|
||||
workspacePackages: opts.workspacePackages ?? {},
|
||||
supportedArchitectures: opts.supportedArchitectures,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import { normalizeRegistries, DEFAULT_REGISTRIES } from '@pnpm/normalize-registr
|
||||
import { type WorkspacePackages } from '@pnpm/resolver-base'
|
||||
import { type StoreController } from '@pnpm/store-controller-types'
|
||||
import {
|
||||
type SupportedArchitectures,
|
||||
type AllowedDeprecatedVersions,
|
||||
type PackageExtension,
|
||||
type PeerDependencyRules,
|
||||
@@ -136,6 +137,8 @@ export interface StrictInstallOptions {
|
||||
* The option might be used in the future to improve performance.
|
||||
*/
|
||||
disableRelinkLocalDirDeps: boolean
|
||||
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
}
|
||||
|
||||
export type InstallOptions =
|
||||
|
||||
@@ -1038,6 +1038,7 @@ const _installInContext: InstallFunction = async (projects, ctx, opts) => {
|
||||
patchedDependencies: opts.patchedDependencies,
|
||||
lockfileIncludeTarballUrl: opts.lockfileIncludeTarballUrl,
|
||||
resolvePeersFromWorkspaceRoot: opts.resolvePeersFromWorkspaceRoot,
|
||||
supportedArchitectures: opts.supportedArchitectures,
|
||||
}
|
||||
)
|
||||
if (!opts.include.optionalDependencies || !opts.include.devDependencies || !opts.include.dependencies) {
|
||||
|
||||
@@ -342,7 +342,9 @@ async function linkNewPackages (
|
||||
for (const depPath of wantedRelDepPaths) {
|
||||
if (currentLockfile.packages[depPath] &&
|
||||
(!equals(currentLockfile.packages[depPath].dependencies, wantedLockfile.packages[depPath].dependencies) ||
|
||||
!equals(currentLockfile.packages[depPath].optionalDependencies, wantedLockfile.packages[depPath].optionalDependencies))) {
|
||||
!isEmpty(currentLockfile.packages[depPath].optionalDependencies) ||
|
||||
!isEmpty(wantedLockfile.packages[depPath].optionalDependencies))
|
||||
) {
|
||||
// TODO: come up with a test that triggers the usecase of depGraph[depPath] undefined
|
||||
// see related issue: https://github.com/pnpm/pnpm/issues/870
|
||||
if (depGraph[depPath] && !newDepPathsSet.has(depPath)) {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { type Lockfile } from '@pnpm/lockfile-file'
|
||||
import { prepareEmpty, preparePackages } from '@pnpm/prepare'
|
||||
import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
|
||||
import deepRequireCwd from 'deep-require-cwd'
|
||||
import readYamlFile from 'read-yaml-file'
|
||||
import {
|
||||
addDependenciesToPackage,
|
||||
@@ -13,7 +15,6 @@ import {
|
||||
import rimraf from '@zkochan/rimraf'
|
||||
import exists from 'path-exists'
|
||||
import sinon from 'sinon'
|
||||
import deepRequireCwd from 'deep-require-cwd'
|
||||
import { testDefaults } from '../utils'
|
||||
|
||||
test('successfully install optional dependency with subdependencies', async () => {
|
||||
@@ -575,3 +576,75 @@ test('fail on a package with failing postinstall if the package is both an optio
|
||||
)
|
||||
).rejects.toThrow()
|
||||
})
|
||||
|
||||
describe('supported architectures', () => {
|
||||
test.each(['isolated', 'hoisted'])('install optional dependency for the supported architecture set by the user (nodeLinker=%s)', async (nodeLinker) => {
|
||||
prepareEmpty()
|
||||
const opts = await testDefaults({ nodeLinker })
|
||||
|
||||
const manifest = await addDependenciesToPackage({}, ['@pnpm.e2e/has-many-optional-deps@1.0.0'], {
|
||||
...opts,
|
||||
supportedArchitectures: { os: ['darwin'], cpu: ['arm64'] },
|
||||
})
|
||||
expect(deepRequireCwd(['@pnpm.e2e/has-many-optional-deps', '@pnpm.e2e/darwin-arm64', './package.json']).version).toBe('1.0.0')
|
||||
|
||||
await install(manifest, {
|
||||
...opts,
|
||||
preferFrozenLockfile: false,
|
||||
supportedArchitectures: { os: ['darwin'], cpu: ['x64'] },
|
||||
})
|
||||
expect(deepRequireCwd(['@pnpm.e2e/has-many-optional-deps', '@pnpm.e2e/darwin-x64', './package.json']).version).toBe('1.0.0')
|
||||
|
||||
await install(manifest, {
|
||||
...opts,
|
||||
frozenLockfile: true,
|
||||
supportedArchitectures: { os: ['linux'], cpu: ['x64'] },
|
||||
})
|
||||
expect(deepRequireCwd(['@pnpm.e2e/has-many-optional-deps', '@pnpm.e2e/linux-x64', './package.json']).version).toBe('1.0.0')
|
||||
})
|
||||
test('remove optional dependencies that are not used', async () => {
|
||||
prepareEmpty()
|
||||
const opts = await testDefaults({ modulesCacheMaxAge: 0 })
|
||||
|
||||
const manifest = await addDependenciesToPackage({}, ['@pnpm.e2e/has-many-optional-deps@1.0.0'], {
|
||||
...opts,
|
||||
supportedArchitectures: { os: ['darwin', 'linux', 'win32'], cpu: ['arm64', 'x64'] },
|
||||
})
|
||||
|
||||
await install(manifest, {
|
||||
...opts,
|
||||
supportedArchitectures: { os: ['darwin'], cpu: ['x64'] },
|
||||
})
|
||||
expect(fs.readdirSync('node_modules/.pnpm').length).toBe(3)
|
||||
})
|
||||
test('remove optional dependencies that are not used, when hoisted node linker is used', async () => {
|
||||
prepareEmpty()
|
||||
const opts = await testDefaults({ nodeLinker: 'hoisted' })
|
||||
|
||||
const manifest = await addDependenciesToPackage({}, ['@pnpm.e2e/has-many-optional-deps@1.0.0'], {
|
||||
...opts,
|
||||
supportedArchitectures: { os: ['darwin', 'linux', 'win32'], cpu: ['arm64', 'x64'] },
|
||||
})
|
||||
|
||||
await install(manifest, {
|
||||
...opts,
|
||||
supportedArchitectures: { os: ['darwin'], cpu: ['x64'] },
|
||||
})
|
||||
expect(fs.readdirSync('node_modules/@pnpm.e2e').sort()).toStrictEqual(['darwin-x64', 'has-many-optional-deps'])
|
||||
})
|
||||
test('remove optional dependencies if supported architectures have changed and a new dependency is added', async () => {
|
||||
prepareEmpty()
|
||||
const opts = await testDefaults({ modulesCacheMaxAge: 0 })
|
||||
|
||||
const manifest = await addDependenciesToPackage({}, ['@pnpm.e2e/parent-of-has-many-optional-deps@1.0.0'], {
|
||||
...opts,
|
||||
supportedArchitectures: { os: ['darwin', 'linux', 'win32'], cpu: ['arm64', 'x64'] },
|
||||
})
|
||||
|
||||
await addDependenciesToPackage(manifest, ['is-positive@1.0.0'], {
|
||||
...opts,
|
||||
supportedArchitectures: { os: ['darwin'], cpu: ['x64'] },
|
||||
})
|
||||
expect(fs.readdirSync('node_modules/.pnpm').length).toBe(5)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
summaryLogger,
|
||||
} from '@pnpm/core-loggers'
|
||||
import {
|
||||
filterLockfileByEngine,
|
||||
filterLockfileByImportersAndEngine,
|
||||
} from '@pnpm/filter-lockfile'
|
||||
import { hoist } from '@pnpm/hoist'
|
||||
@@ -55,7 +56,7 @@ import {
|
||||
type StoreController,
|
||||
} from '@pnpm/store-controller-types'
|
||||
import { symlinkDependency } from '@pnpm/symlink-dependency'
|
||||
import { type DependencyManifest, type HoistedDependencies, type ProjectManifest, type Registries, DEPENDENCIES_FIELDS } from '@pnpm/types'
|
||||
import { type DependencyManifest, type HoistedDependencies, type ProjectManifest, type Registries, DEPENDENCIES_FIELDS, type SupportedArchitectures } from '@pnpm/types'
|
||||
import * as dp from '@pnpm/dependency-path'
|
||||
import { symlinkAllModules } from '@pnpm/worker'
|
||||
import pLimit from 'p-limit'
|
||||
@@ -159,6 +160,7 @@ export interface HeadlessOptions {
|
||||
nodeLinker?: 'isolated' | 'hoisted' | 'pnp'
|
||||
useGitBranchLockfile?: boolean
|
||||
useLockfile?: boolean
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
}
|
||||
|
||||
export interface InstallationResultStats {
|
||||
@@ -215,6 +217,17 @@ export async function headlessInstall (opts: HeadlessOptions): Promise<Installat
|
||||
}
|
||||
|
||||
const skipped = opts.skipped || new Set<string>()
|
||||
const filterOpts = {
|
||||
include: opts.include,
|
||||
registries: opts.registries,
|
||||
skipped,
|
||||
currentEngine: opts.currentEngine,
|
||||
engineStrict: opts.engineStrict,
|
||||
failOnMissingDependencies: true,
|
||||
includeIncompatiblePackages: opts.force,
|
||||
lockfileDir,
|
||||
supportedArchitectures: opts.supportedArchitectures,
|
||||
}
|
||||
let removed = 0
|
||||
if (opts.nodeLinker !== 'hoisted') {
|
||||
if (currentLockfile != null && !opts.ignorePackageManifest) {
|
||||
@@ -234,7 +247,7 @@ export async function headlessInstall (opts: HeadlessOptions): Promise<Installat
|
||||
skipped,
|
||||
storeController: opts.storeController,
|
||||
virtualStoreDir,
|
||||
wantedLockfile,
|
||||
wantedLockfile: filterLockfileByEngine(wantedLockfile, filterOpts).lockfile,
|
||||
}
|
||||
)
|
||||
removed = removedDepPaths.size
|
||||
@@ -251,22 +264,10 @@ export async function headlessInstall (opts: HeadlessOptions): Promise<Installat
|
||||
stage: 'importing_started',
|
||||
})
|
||||
|
||||
const filterOpts = {
|
||||
include: opts.include,
|
||||
registries: opts.registries,
|
||||
skipped,
|
||||
}
|
||||
const initialImporterIds = (opts.ignorePackageManifest === true || opts.nodeLinker === 'hoisted')
|
||||
? Object.keys(wantedLockfile.importers)
|
||||
: selectedProjects.map(({ id }) => id)
|
||||
const { lockfile: filteredLockfile, selectedImporterIds: importerIds } = filterLockfileByImportersAndEngine(wantedLockfile, initialImporterIds, {
|
||||
...filterOpts,
|
||||
currentEngine: opts.currentEngine,
|
||||
engineStrict: opts.engineStrict,
|
||||
failOnMissingDependencies: true,
|
||||
includeIncompatiblePackages: opts.force,
|
||||
lockfileDir,
|
||||
})
|
||||
const { lockfile: filteredLockfile, selectedImporterIds: importerIds } = filterLockfileByImportersAndEngine(wantedLockfile, initialImporterIds, filterOpts)
|
||||
if (opts.excludeLinksFromLockfile) {
|
||||
for (const { id, manifest, rootDir } of selectedProjects) {
|
||||
if (filteredLockfile.importers[id]) {
|
||||
@@ -305,6 +306,7 @@ export async function headlessInstall (opts: HeadlessOptions): Promise<Installat
|
||||
virtualStoreDir,
|
||||
nodeVersion: opts.currentEngine.nodeVersion,
|
||||
pnpmVersion: opts.currentEngine.pnpmVersion,
|
||||
supportedArchitectures: opts.supportedArchitectures,
|
||||
} as LockfileToDepGraphOptions
|
||||
const {
|
||||
directDependenciesByImporterId,
|
||||
@@ -787,6 +789,7 @@ async function linkAllPkgs (
|
||||
) {
|
||||
return Promise.all(
|
||||
depNodes.map(async (depNode) => {
|
||||
if (!depNode.fetching) return
|
||||
let filesResponse!: PackageFilesResponse
|
||||
try {
|
||||
filesResponse = (await depNode.fetching()).files
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
import { type IncludedDependencies } from '@pnpm/modules-yaml'
|
||||
import { packageIsInstallable } from '@pnpm/package-is-installable'
|
||||
import { safeReadPackageJsonFromDir } from '@pnpm/read-package-json'
|
||||
import { type PatchFile, type Registries } from '@pnpm/types'
|
||||
import { type SupportedArchitectures, type PatchFile, type Registries } from '@pnpm/types'
|
||||
import {
|
||||
type FetchPackageToStoreFunction,
|
||||
type StoreController,
|
||||
@@ -47,6 +47,7 @@ export interface LockfileToHoistedDepGraphOptions {
|
||||
storeController: StoreController
|
||||
storeDir: string
|
||||
virtualStoreDir: string
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
}
|
||||
|
||||
export async function lockfileToHoistedDepGraph (
|
||||
@@ -56,7 +57,11 @@ export async function lockfileToHoistedDepGraph (
|
||||
): Promise<LockfileToDepGraphResult> {
|
||||
let prevGraph!: DependenciesGraph
|
||||
if (currentLockfile?.packages != null) {
|
||||
prevGraph = (await _lockfileToHoistedDepGraph(currentLockfile, opts)).graph
|
||||
prevGraph = (await _lockfileToHoistedDepGraph(currentLockfile, {
|
||||
...opts,
|
||||
force: true,
|
||||
skipped: new Set(),
|
||||
})).graph
|
||||
} else {
|
||||
prevGraph = {}
|
||||
}
|
||||
@@ -181,6 +186,7 @@ async function fetchDeps (
|
||||
nodeVersion: opts.nodeVersion,
|
||||
optional: pkgSnapshot.optional === true,
|
||||
pnpmVersion: opts.pnpmVersion,
|
||||
supportedArchitectures: opts.supportedArchitectures,
|
||||
}) === false
|
||||
) {
|
||||
opts.skipped.add(depPath)
|
||||
|
||||
@@ -231,6 +231,7 @@ async function resolveAndFetch (
|
||||
nodeVersion: ctx.nodeVersion,
|
||||
optional: wantedDependency.optional === true,
|
||||
pnpmVersion: ctx.pnpmVersion,
|
||||
supportedArchitectures: options.supportedArchitectures,
|
||||
})
|
||||
)
|
||||
)
|
||||
|
||||
@@ -30,6 +30,7 @@ import {
|
||||
type StoreController,
|
||||
} from '@pnpm/store-controller-types'
|
||||
import {
|
||||
type SupportedArchitectures,
|
||||
type AllowedDeprecatedVersions,
|
||||
type Dependencies,
|
||||
type PackageManifest,
|
||||
@@ -253,6 +254,7 @@ interface ResolvedDependenciesOptions {
|
||||
updateMatching?: UpdateMatchingFunction
|
||||
updateDepth: number
|
||||
prefix: string
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
}
|
||||
|
||||
interface PostponedResolutionOpts {
|
||||
@@ -674,6 +676,7 @@ async function resolveDependenciesOfDependency (
|
||||
update,
|
||||
updateDepth,
|
||||
updateMatching: options.updateMatching,
|
||||
supportedArchitectures: options.supportedArchitectures,
|
||||
}
|
||||
const resolveDependencyResult = await resolveDependency(extendedWantedDep.wantedDependency, ctx, resolveDependencyOpts)
|
||||
|
||||
@@ -709,6 +712,7 @@ async function resolveDependenciesOfDependency (
|
||||
updateDepth,
|
||||
prefix: options.prefix,
|
||||
updateMatching: options.updateMatching,
|
||||
supportedArchitectures: options.supportedArchitectures,
|
||||
})
|
||||
return {
|
||||
resolveDependencyResult,
|
||||
@@ -756,6 +760,7 @@ async function resolveChildren (
|
||||
updateDepth,
|
||||
updateMatching,
|
||||
prefix,
|
||||
supportedArchitectures,
|
||||
}: {
|
||||
parentPkg: PkgAddress
|
||||
dependencyLockfile: PackageSnapshot | undefined
|
||||
@@ -763,6 +768,7 @@ async function resolveChildren (
|
||||
updateDepth: number
|
||||
prefix: string
|
||||
updateMatching?: UpdateMatchingFunction
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
},
|
||||
{
|
||||
parentPkgAliases,
|
||||
@@ -808,6 +814,7 @@ async function resolveChildren (
|
||||
resolvedDependencies,
|
||||
updateDepth,
|
||||
updateMatching,
|
||||
supportedArchitectures,
|
||||
}
|
||||
)
|
||||
ctx.childrenByParentDepPath[parentPkg.depPath] = pkgAddresses.map((child) => ({
|
||||
@@ -1011,6 +1018,7 @@ interface ResolveDependencyOptions {
|
||||
update: boolean
|
||||
updateDepth: number
|
||||
updateMatching?: UpdateMatchingFunction
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
}
|
||||
|
||||
type ResolveDependencyResult = PkgAddress | LinkedDependency | null
|
||||
@@ -1083,6 +1091,7 @@ async function resolveDependency (
|
||||
skipFetch: false,
|
||||
update: options.update,
|
||||
workspacePackages: ctx.workspacePackages,
|
||||
supportedArchitectures: options.supportedArchitectures,
|
||||
})
|
||||
} catch (err: any) { // eslint-disable-line
|
||||
if (wantedDependency.optional) {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { type Lockfile, type PatchFile } from '@pnpm/lockfile-types'
|
||||
import { type PreferredVersions, type Resolution, type WorkspacePackages } from '@pnpm/resolver-base'
|
||||
import { type StoreController } from '@pnpm/store-controller-types'
|
||||
import {
|
||||
type SupportedArchitectures,
|
||||
type AllowedDeprecatedVersions,
|
||||
type ProjectManifest,
|
||||
type ReadPackageHook,
|
||||
@@ -87,6 +88,7 @@ export interface ResolveDependenciesOptions {
|
||||
virtualStoreDir: string
|
||||
wantedLockfile: Lockfile
|
||||
workspacePackages: WorkspacePackages
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
}
|
||||
|
||||
export async function resolveDependencyTree<T> (
|
||||
@@ -153,6 +155,7 @@ export async function resolveDependencyTree<T> (
|
||||
updateDepth: -1,
|
||||
updateMatching: importer.updateMatching,
|
||||
prefix: importer.rootDir,
|
||||
supportedArchitectures: opts.supportedArchitectures,
|
||||
}
|
||||
return {
|
||||
updatePackageManifest: importer.updatePackageManifest,
|
||||
|
||||
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
@@ -6110,6 +6110,9 @@ importers:
|
||||
'@pnpm/filter-workspace-packages':
|
||||
specifier: workspace:*
|
||||
version: 'link:'
|
||||
'@pnpm/types':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/types
|
||||
'@types/is-windows':
|
||||
specifier: ^1.0.0
|
||||
version: 1.0.0
|
||||
|
||||
@@ -31,7 +31,13 @@ export async function complete (
|
||||
if (input.currentTypedWordType !== 'option') {
|
||||
if (input.lastOption === '--filter') {
|
||||
const workspaceDir = await findWorkspaceDir(process.cwd()) ?? process.cwd()
|
||||
const allProjects = await findWorkspacePackages(workspaceDir, {})
|
||||
const allProjects = await findWorkspacePackages(workspaceDir, {
|
||||
supportedArchitectures: {
|
||||
os: ['current'],
|
||||
cpu: ['current'],
|
||||
libc: ['current'],
|
||||
},
|
||||
})
|
||||
return allProjects
|
||||
.filter(({ manifest }) => manifest.name)
|
||||
.map(({ manifest }) => ({ name: manifest.name }))
|
||||
|
||||
@@ -146,7 +146,7 @@ async function packPkg (opts: {
|
||||
projectDir,
|
||||
embedReadme,
|
||||
} = opts
|
||||
const { manifest } = await readProjectManifest(projectDir, {})
|
||||
const { manifest } = await readProjectManifest(projectDir)
|
||||
const bins = [
|
||||
...(await getBinsFromPackageManifest(manifest as DependencyManifest, projectDir)).map(({ path }) => path),
|
||||
...(manifest.publishConfig?.executableFiles ?? [])
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { PnpmError } from '@pnpm/error'
|
||||
import { type Lockfile } from '@pnpm/lockfile-file'
|
||||
import {
|
||||
type SupportedArchitectures,
|
||||
type DependenciesField,
|
||||
type IncludedDependencies,
|
||||
type ProjectManifest,
|
||||
@@ -74,6 +75,7 @@ export async function findDependencyLicenses (opts: {
|
||||
registries: Registries
|
||||
wantedLockfile: Lockfile | null
|
||||
includedImporterIds?: string[]
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
}): Promise<LicensePackage[]> {
|
||||
if (opts.wantedLockfile == null) {
|
||||
throw new PnpmError(
|
||||
@@ -90,6 +92,7 @@ export async function findDependencyLicenses (opts: {
|
||||
include: opts.include,
|
||||
registries: opts.registries,
|
||||
includedImporterIds: opts.includedImporterIds,
|
||||
supportedArchitectures: opts.supportedArchitectures,
|
||||
})
|
||||
|
||||
const licensePackages = new Map<string, LicensePackage>()
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
lockfileWalkerGroupImporterSteps,
|
||||
type LockfileWalkerStep,
|
||||
} from '@pnpm/lockfile-walker'
|
||||
import { type DependenciesField, type Registries } from '@pnpm/types'
|
||||
import { type SupportedArchitectures, type DependenciesField, type Registries } from '@pnpm/types'
|
||||
import { getPkgInfo } from './getPkgInfo'
|
||||
import mapValues from 'ramda/src/map'
|
||||
|
||||
@@ -36,6 +36,7 @@ export interface LicenseExtractOptions {
|
||||
modulesDir?: string
|
||||
dir: string
|
||||
registries: Registries
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
}
|
||||
|
||||
export async function lockfileToLicenseNode (
|
||||
@@ -56,6 +57,7 @@ export async function lockfileToLicenseNode (
|
||||
}, {
|
||||
optional: pkgSnapshot.optional ?? false,
|
||||
lockfileDir: options.dir,
|
||||
supportedArchitectures: options.supportedArchitectures,
|
||||
})
|
||||
|
||||
// If the package is not installable on the given platform, we ignore the
|
||||
@@ -137,6 +139,7 @@ export async function lockfileToLicenseNodeTree (
|
||||
modulesDir: opts.modulesDir,
|
||||
dir: opts.dir,
|
||||
registries: opts.registries,
|
||||
supportedArchitectures: opts.supportedArchitectures,
|
||||
})
|
||||
return [importerWalker.importerId, {
|
||||
dependencies: importerDeps,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { readProjectManifestOnly } from '@pnpm/cli-utils'
|
||||
import { type Config } from '@pnpm/config'
|
||||
import { type Config, getOptionsFromRootManifest } from '@pnpm/config'
|
||||
import { PnpmError } from '@pnpm/error'
|
||||
import { getStorePath } from '@pnpm/store-path'
|
||||
import { WANTED_LOCKFILE } from '@pnpm/constants'
|
||||
@@ -47,7 +47,7 @@ export async function licensesList (opts: LicensesCommandOptions) {
|
||||
optionalDependencies: opts.optional !== false,
|
||||
}
|
||||
|
||||
const manifest = await readProjectManifestOnly(opts.dir, {})
|
||||
const manifest = await readProjectManifestOnly(opts.dir)
|
||||
|
||||
const includedImporterIds = opts.selectedProjectsGraph
|
||||
? Object.keys(opts.selectedProjectsGraph)
|
||||
@@ -70,6 +70,7 @@ export async function licensesList (opts: LicensesCommandOptions) {
|
||||
wantedLockfile: lockfile,
|
||||
manifest,
|
||||
includedImporterIds,
|
||||
supportedArchitectures: getOptionsFromRootManifest(opts.rootProjectManifestDir, opts.rootProjectManifest ?? {}).supportedArchitectures,
|
||||
})
|
||||
|
||||
if (licensePackages.length === 0)
|
||||
|
||||
@@ -3,7 +3,7 @@ import { logger, globalInfo, streamParser } from '@pnpm/logger'
|
||||
import { parseWantedDependency } from '@pnpm/parse-wanted-dependency'
|
||||
import { pickRegistryForPackage } from '@pnpm/pick-registry-for-package'
|
||||
import { type StoreController } from '@pnpm/store-controller-types'
|
||||
import { type Registries } from '@pnpm/types'
|
||||
import { type SupportedArchitectures, type Registries } from '@pnpm/types'
|
||||
import { type ReporterFunction } from './types'
|
||||
|
||||
export async function storeAdd (
|
||||
@@ -14,6 +14,7 @@ export async function storeAdd (
|
||||
reporter?: ReporterFunction
|
||||
storeController: StoreController
|
||||
tag?: string
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
}
|
||||
) {
|
||||
const reporter = opts?.reporter
|
||||
@@ -36,6 +37,7 @@ export async function storeAdd (
|
||||
preferredVersions: {},
|
||||
projectDir: prefix,
|
||||
registry: (dep.alias && pickRegistryForPackage(registries, dep.alias)) ?? registries.default,
|
||||
supportedArchitectures: opts.supportedArchitectures,
|
||||
})
|
||||
await pkgResponse.fetching!()
|
||||
globalInfo(`+ ${pkgResponse.body.id}`)
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
type ResolvedFrom,
|
||||
} from '@pnpm/cafs-types'
|
||||
import {
|
||||
type SupportedArchitectures,
|
||||
type DependencyManifest,
|
||||
type PackageManifest,
|
||||
} from '@pnpm/types'
|
||||
@@ -128,6 +129,7 @@ export interface RequestPackageOptions {
|
||||
update?: boolean
|
||||
workspacePackages?: WorkspacePackages
|
||||
forceResolve?: boolean
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
}
|
||||
|
||||
export type BundledManifestFunction = () => Promise<BundledManifest | undefined>
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@pnpm/filter-workspace-packages": "workspace:*",
|
||||
"@pnpm/types": "workspace:*",
|
||||
"@types/is-windows": "^1.0.0",
|
||||
"@types/micromatch": "^4.0.3",
|
||||
"@types/ramda": "0.28.20",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createMatcher } from '@pnpm/matcher'
|
||||
import { type SupportedArchitectures } from '@pnpm/types'
|
||||
import { findWorkspacePackages, type Project } from '@pnpm/workspace.find-packages'
|
||||
import { createPkgGraph, type Package, type PackageNode } from '@pnpm/workspace.pkgs-graph'
|
||||
import isSubdir from 'is-subdir'
|
||||
@@ -42,9 +43,10 @@ export async function readProjects (
|
||||
engineStrict?: boolean
|
||||
linkWorkspacePackages?: boolean
|
||||
changedFilesIgnorePattern?: string[]
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
}
|
||||
): Promise<ReadProjectsResult> {
|
||||
const allProjects = await findWorkspacePackages(workspaceDir, { engineStrict: opts?.engineStrict })
|
||||
const allProjects = await findWorkspacePackages(workspaceDir, { engineStrict: opts?.engineStrict, supportedArchitectures: opts?.supportedArchitectures ?? { os: ['current'], cpu: ['current'], libc: ['current'] } })
|
||||
const { allProjectsGraph, selectedProjectsGraph } = await filterPkgsBySelectorObjects(
|
||||
allProjects,
|
||||
pkgSelectors,
|
||||
@@ -74,6 +76,7 @@ export async function filterPackagesFromDir (
|
||||
engineStrict?: boolean
|
||||
nodeVersion?: string
|
||||
patterns: string[]
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
}
|
||||
) {
|
||||
const allProjects = await findWorkspacePackages(workspaceDir, {
|
||||
@@ -81,6 +84,7 @@ export async function filterPackagesFromDir (
|
||||
patterns: opts.patterns,
|
||||
sharedWorkspaceLockfile: opts.sharedWorkspaceLockfile,
|
||||
nodeVersion: opts.nodeVersion,
|
||||
supportedArchitectures: opts.supportedArchitectures,
|
||||
})
|
||||
return {
|
||||
allProjects,
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
{
|
||||
"path": "../../packages/error"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/types"
|
||||
},
|
||||
{
|
||||
"path": "../find-packages"
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import path from 'path'
|
||||
import { packageIsInstallable } from '@pnpm/cli-utils'
|
||||
import { WORKSPACE_MANIFEST_FILENAME } from '@pnpm/constants'
|
||||
import { type ProjectManifest, type Project } from '@pnpm/types'
|
||||
import { type ProjectManifest, type Project, type SupportedArchitectures } from '@pnpm/types'
|
||||
import { lexCompare } from '@pnpm/util.lex-comparator'
|
||||
import { findPackages } from '@pnpm/fs.find-packages'
|
||||
import { logger } from '@pnpm/logger'
|
||||
@@ -16,11 +16,18 @@ export async function findWorkspacePackages (
|
||||
nodeVersion?: string
|
||||
patterns?: string[]
|
||||
sharedWorkspaceLockfile?: boolean
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
}
|
||||
): Promise<Project[]> {
|
||||
const pkgs = await findWorkspacePackagesNoCheck(workspaceRoot, opts)
|
||||
for (const pkg of pkgs) {
|
||||
packageIsInstallable(pkg.dir, pkg.manifest, opts ?? {})
|
||||
packageIsInstallable(pkg.dir, pkg.manifest, opts ?? {
|
||||
supportedArchitectures: {
|
||||
os: ['current'],
|
||||
cpu: ['current'],
|
||||
libc: ['current'],
|
||||
},
|
||||
})
|
||||
// When setting shared-workspace-lockfile=false, `pnpm` can be set in sub-project's package.json.
|
||||
if (opts?.sharedWorkspaceLockfile && pkg.dir !== workspaceRoot) {
|
||||
checkNonRootProjectManifest(pkg)
|
||||
|
||||
Reference in New Issue
Block a user