mirror of
https://github.com/pnpm/pnpm.git
synced 2026-05-05 22:47:50 -04:00
committed by
Zoltan Kochan
parent
363d45ecf3
commit
b09382376e
@@ -68,4 +68,5 @@ export interface PnpmConfigs {
|
||||
workspaceConcurrency: number,
|
||||
workspacePrefix?: string,
|
||||
reporter?: string,
|
||||
linkWorkspacePackages: boolean,
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ export const types = Object.assign({
|
||||
'ignore-stop-requests': Boolean,
|
||||
'ignore-upload-requests': Boolean,
|
||||
'independent-leaves': Boolean,
|
||||
'link-workspace-packages': Boolean,
|
||||
'lock': Boolean,
|
||||
'lock-stale-duration': Number,
|
||||
'network-concurrency': Number,
|
||||
@@ -93,6 +94,7 @@ export default async (
|
||||
'fetch-retry-maxtimeout': 60000,
|
||||
'fetch-retry-mintimeout': 10000,
|
||||
'globalconfig': npmDefaults.globalconfig,
|
||||
'link-workspace-packages': false,
|
||||
'lock': true,
|
||||
'package-lock': npmDefaults['package-lock'],
|
||||
'prefix': npmDefaults.prefix,
|
||||
|
||||
@@ -252,7 +252,8 @@ function getHelpText (command: string) {
|
||||
install
|
||||
update
|
||||
uninstall [<@scope>/]<pkg>... uninstall a dependency from each package
|
||||
link runs installation in each package. If a package is available locally, the local version is linked.
|
||||
link Deprecated. Use the install command with the link-workspace-packages config.
|
||||
runs installation in each package. If a package is available locally, the local version is linked.
|
||||
unlink removes links to local packages and reinstalls them from the registry.
|
||||
list [[<@scope>/]<pkg>...] list dependencies in each package.
|
||||
outdated [[<@scope>/]<pkg>...] check for outdated dependencies in every package.
|
||||
@@ -271,11 +272,13 @@ function getHelpText (command: string) {
|
||||
|
||||
Options:
|
||||
|
||||
--filter <name> restricts the scope to package names matching the given glob.
|
||||
--filter <name>... includes all direct and indirect dependencies of the matched packages.
|
||||
--filter ...<name> includes all direct and indirect dependents of the matched packages.
|
||||
--no-bail continues executing other tasks even if a task threw an error.
|
||||
--workspace-concurrency set the maximum number of concurrency. Default is 4. For unlimited concurrency use Infinity.
|
||||
--filter <name> restricts the scope to package names matching the given glob.
|
||||
--filter <name>... includes all direct and indirect dependencies of the matched packages.
|
||||
--filter ...<name> includes all direct and indirect dependents of the matched packages.
|
||||
--no-bail continues executing other tasks even if a task threw an error.
|
||||
--workspace-concurrency set the maximum number of concurrency. Default is 4. For unlimited concurrency use Infinity.
|
||||
--link-workspace-packages locally available packages are linked to node_modules instead of being downloaded from the registry.
|
||||
Convenient to use in a multi-package repository.
|
||||
`
|
||||
|
||||
default:
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import {
|
||||
install,
|
||||
installPkgs,
|
||||
rebuild,
|
||||
} from 'supi'
|
||||
import createStoreController from '../createStoreController'
|
||||
import findWorkspacePackages, {arrayOfLocalPackagesToMap} from '../findWorkspacePackages'
|
||||
import requireHooks from '../requireHooks'
|
||||
import {PnpmOptions} from '../types'
|
||||
import {recursive} from './recursive'
|
||||
|
||||
/**
|
||||
* Perform installation.
|
||||
@@ -19,18 +22,43 @@ export default async function installCmd (
|
||||
input = input.filter(Boolean)
|
||||
|
||||
const prefix = opts.prefix || process.cwd()
|
||||
|
||||
const localPackages = opts.linkWorkspacePackages && opts.workspacePrefix
|
||||
? arrayOfLocalPackagesToMap(await findWorkspacePackages(opts.workspacePrefix))
|
||||
: undefined
|
||||
|
||||
if (!opts.ignorePnpmfile) {
|
||||
opts.hooks = requireHooks(prefix, opts)
|
||||
}
|
||||
|
||||
const store = await createStoreController(opts)
|
||||
const installOpts = Object.assign(opts, {
|
||||
const installOpts = {
|
||||
...opts,
|
||||
// In case installation is done in a multi-package repository
|
||||
// The dependencies should be built first,
|
||||
// so ignoring scripts for now
|
||||
ignoreScripts: !!localPackages || opts.ignoreScripts,
|
||||
localPackages,
|
||||
store: store.path,
|
||||
storeController: store.ctrl,
|
||||
})
|
||||
|
||||
if (!input || !input.length) {
|
||||
return install(installOpts)
|
||||
}
|
||||
return installPkgs(input, installOpts)
|
||||
if (!input || !input.length) {
|
||||
await install(installOpts)
|
||||
} else {
|
||||
await installPkgs(input, installOpts)
|
||||
}
|
||||
|
||||
if (opts.linkWorkspacePackages && opts.workspacePrefix) {
|
||||
// TODO: reuse somehow the previous read of packages
|
||||
// this is not optimal
|
||||
const allWorkspacePkgs = await findWorkspacePackages(opts.workspacePrefix)
|
||||
await recursive(allWorkspacePkgs, [], {
|
||||
...opts,
|
||||
filterByEntryDirectory: prefix,
|
||||
inputForEntryDirectory: input,
|
||||
}, 'install', 'install')
|
||||
|
||||
if (opts.ignoreScripts) return
|
||||
|
||||
await rebuild({...opts, pending: true} as any) // tslint:disable-line:no-any
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,19 @@ interface Graph {
|
||||
[nodeId: string]: string[],
|
||||
}
|
||||
|
||||
export function filterGraphByEntryDirectory (
|
||||
pkgGraph: PackageGraph,
|
||||
entryDirectory: string,
|
||||
): PackageGraph {
|
||||
if (!pkgGraph[entryDirectory]) return {}
|
||||
|
||||
const walkedDependencies = new Set<string>()
|
||||
const graph = pkgGraphToGraph(pkgGraph)
|
||||
pickSubgraph(graph, [entryDirectory], walkedDependencies)
|
||||
|
||||
return R.pick(Array.from(walkedDependencies), pkgGraph)
|
||||
}
|
||||
|
||||
export function filterGraph (
|
||||
pkgGraph: PackageGraph,
|
||||
filters: string[],
|
||||
|
||||
@@ -26,6 +26,7 @@ import help from '../help'
|
||||
import exec from './exec'
|
||||
import {
|
||||
filterGraph,
|
||||
filterGraphByEntryDirectory,
|
||||
filterGraphByScope,
|
||||
} from './filter'
|
||||
import list from './list'
|
||||
@@ -78,7 +79,10 @@ export default async (
|
||||
export async function recursive (
|
||||
allPkgs: Array<{path: string, manifest: PackageJson}>,
|
||||
input: string[],
|
||||
opts: PnpmOptions,
|
||||
opts: PnpmOptions & {
|
||||
filterByEntryDirectory?: string,
|
||||
inputForEntryDirectory?: string[],
|
||||
},
|
||||
cmdFullName: string,
|
||||
cmd: string,
|
||||
) {
|
||||
@@ -90,6 +94,9 @@ export async function recursive (
|
||||
} else if (opts.filter) {
|
||||
pkgGraphResult.graph = filterGraph(pkgGraphResult.graph, opts.filter)
|
||||
pkgs = allPkgs.filter((pkg: {path: string}) => pkgGraphResult.graph[pkg.path])
|
||||
} else if (opts.filterByEntryDirectory) {
|
||||
pkgGraphResult.graph = filterGraphByEntryDirectory(pkgGraphResult.graph, opts.filterByEntryDirectory)
|
||||
pkgs = allPkgs.filter((pkg: {path: string}) => pkgGraphResult.graph[pkg.path])
|
||||
} else {
|
||||
pkgs = allPkgs
|
||||
}
|
||||
@@ -138,7 +145,12 @@ export async function recursive (
|
||||
})
|
||||
const chunks = graphSequencerResult.chunks
|
||||
|
||||
const localPackages = cmdFullName === 'link'
|
||||
if (cmdFullName === 'link' && opts.linkWorkspacePackages) {
|
||||
const err = new Error('"pnpm recursive link" is deprecated with link-workspace-packages = true. Please use "pnpm recursive install" instead')
|
||||
err['code'] = 'ERR_PNPM_RECURSIVE_LINK_DEPRECATED' // tslint:disable-line:no-string-literal
|
||||
throw err
|
||||
}
|
||||
const localPackages = cmdFullName === 'link' || opts.linkWorkspacePackages
|
||||
? arrayOfLocalPackagesToMap(allPkgs)
|
||||
: {}
|
||||
const installOpts = Object.assign(opts, {
|
||||
@@ -176,6 +188,9 @@ export async function recursive (
|
||||
const hooks = opts.ignorePnpmfile ? {} : requireHooks(prefix, opts)
|
||||
try {
|
||||
const localConfigs = await readLocalConfigs(prefix)
|
||||
if (opts.filterByEntryDirectory === prefix) {
|
||||
return
|
||||
}
|
||||
await action({
|
||||
...installOpts,
|
||||
...localConfigs,
|
||||
|
||||
@@ -75,6 +75,7 @@ export interface PnpmOptions {
|
||||
useStoreServer?: boolean,
|
||||
workspaceConcurrency: number,
|
||||
workspacePrefix?: string,
|
||||
linkWorkspacePackages: boolean,
|
||||
|
||||
// cannot be specified via configs
|
||||
update?: boolean,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import fs = require('mz/fs')
|
||||
import tape = require('tape')
|
||||
import promisifyTape from 'tape-promise'
|
||||
import path = require('path')
|
||||
@@ -29,7 +30,7 @@ test('linking a package inside a monorepo', async (t: tape.Test) => {
|
||||
},
|
||||
])
|
||||
|
||||
await writeYamlFile('pnpm-workspace.yaml', {packages: ['**']})
|
||||
await writeYamlFile('pnpm-workspace.yaml', {packages: ['**', '!store/**']})
|
||||
|
||||
process.chdir('project-1')
|
||||
|
||||
@@ -49,3 +50,104 @@ test('linking a package inside a monorepo', async (t: tape.Test) => {
|
||||
await projects['project-1'].has('project-3')
|
||||
await projects['project-1'].has('project-4')
|
||||
})
|
||||
|
||||
test('linking a package inside a monorepo with --link-workspace-packages when installing new dependencies', async (t: tape.Test) => {
|
||||
const projects = preparePackages(t, [
|
||||
{
|
||||
name: 'project-1',
|
||||
version: '1.0.0',
|
||||
},
|
||||
{
|
||||
name: 'project-2',
|
||||
version: '2.0.0',
|
||||
},
|
||||
{
|
||||
name: 'project-3',
|
||||
version: '3.0.0',
|
||||
},
|
||||
{
|
||||
name: 'project-4',
|
||||
version: '4.0.0',
|
||||
},
|
||||
])
|
||||
|
||||
await fs.writeFile('.npmrc', 'link-workspace-packages = true', 'utf8')
|
||||
await writeYamlFile('pnpm-workspace.yaml', {packages: ['**', '!store/**']})
|
||||
|
||||
process.chdir('project-1')
|
||||
|
||||
await execPnpm('install', 'project-2')
|
||||
|
||||
await execPnpm('install', 'project-3', '--save-dev')
|
||||
|
||||
await execPnpm('install', 'project-4', '--save-optional')
|
||||
|
||||
const pkg = await import(path.resolve('package.json'))
|
||||
|
||||
t.deepEqual(pkg && pkg.dependencies, {'project-2': '^2.0.0'}, 'spec of linked package added to dependencies')
|
||||
t.deepEqual(pkg && pkg.devDependencies, {'project-3': '^3.0.0'}, 'spec of linked package added to devDependencies')
|
||||
t.deepEqual(pkg && pkg.optionalDependencies, {'project-4': '^4.0.0'}, 'spec of linked package added to optionalDependencies')
|
||||
|
||||
await projects['project-1'].has('project-2')
|
||||
await projects['project-1'].has('project-3')
|
||||
await projects['project-1'].has('project-4')
|
||||
})
|
||||
|
||||
test('linking a package inside a monorepo with --link-workspace-packages', async (t: tape.Test) => {
|
||||
const projects = preparePackages(t, [
|
||||
{
|
||||
name: 'project-1',
|
||||
version: '1.0.0',
|
||||
dependencies: {
|
||||
'json-append': '1',
|
||||
'project-2': '2.0.0',
|
||||
},
|
||||
devDependencies: {
|
||||
'project-3': '3.0.0',
|
||||
},
|
||||
optionalDependencies: {
|
||||
'project-4': '4.0.0',
|
||||
},
|
||||
scripts: {
|
||||
install: `node -e "process.stdout.write('project-1')" | json-append ../output.json`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'project-2',
|
||||
version: '2.0.0',
|
||||
dependencies: {
|
||||
'json-append': '1',
|
||||
},
|
||||
scripts: {
|
||||
install: `node -e "process.stdout.write('project-2')" | json-append ../output.json`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'project-3',
|
||||
version: '3.0.0',
|
||||
},
|
||||
{
|
||||
name: 'project-4',
|
||||
version: '4.0.0',
|
||||
},
|
||||
])
|
||||
|
||||
await fs.writeFile('.npmrc', 'link-workspace-packages = true', 'utf8')
|
||||
await writeYamlFile('pnpm-workspace.yaml', {packages: ['**', '!store/**']})
|
||||
|
||||
process.chdir('project-1')
|
||||
|
||||
await execPnpm('install')
|
||||
|
||||
const outputs = await import(path.resolve('..', 'output.json')) as string[]
|
||||
t.deepEqual(outputs, ['project-2', 'project-1'])
|
||||
|
||||
await projects['project-1'].has('project-2')
|
||||
await projects['project-1'].has('project-3')
|
||||
await projects['project-1'].has('project-4')
|
||||
|
||||
const shr = await projects['project-1'].loadShrinkwrap()
|
||||
t.equal(shr.dependencies['project-2'], 'link:../project-2')
|
||||
t.equal(shr.devDependencies['project-3'], 'link:../project-3')
|
||||
t.equal(shr.optionalDependencies['project-4'], 'link:../project-4')
|
||||
})
|
||||
|
||||
@@ -749,6 +749,7 @@ async function installInContext (
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: link inside resolveDependencies.ts
|
||||
if (installCtx.localPackages.length) {
|
||||
const linkOpts = {
|
||||
...opts,
|
||||
|
||||
Reference in New Issue
Block a user