mirror of
https://github.com/pnpm/pnpm.git
synced 2026-05-07 23:48:05 -04:00
committed by
Zoltan Kochan
parent
8f209b3149
commit
b8658a7d6c
@@ -43,6 +43,7 @@
|
||||
"cross-spawn": "^6.0.3",
|
||||
"delay": "^3.0.0",
|
||||
"diable": "^4.0.1",
|
||||
"execa": "^0.10.0",
|
||||
"find-packages": "^2.2.0",
|
||||
"get-port": "^3.2.0",
|
||||
"graceful-fs": "^4.1.11",
|
||||
@@ -96,7 +97,6 @@
|
||||
"byline": "^5.0.0",
|
||||
"caw": "^2.0.0",
|
||||
"deep-require-cwd": "^1.0.0",
|
||||
"execa": "^0.10.0",
|
||||
"exists-link": "^2.0.0",
|
||||
"mkdirp": "^0.5.1",
|
||||
"normalize-newline": "^3.0.0",
|
||||
|
||||
@@ -236,78 +236,33 @@ function getHelpText (command: string) {
|
||||
|
||||
case 'recursive':
|
||||
return stripIndent`
|
||||
Usage: pnpm recursive [command] [flags]
|
||||
pnpm recursive [command] [flags]
|
||||
pnpm multi [command] [flags]
|
||||
pnpm m [command] [flags]
|
||||
|
||||
Aliases: multi, m
|
||||
Concurrently performs some actions in all subdirectories with a \`package.json\` (excluding node_modules).
|
||||
A \`pnpm-workspace.yaml\` file may be used to control what directories are searched for packages.
|
||||
|
||||
pnpm recursive install
|
||||
Commands:
|
||||
|
||||
Concurrently runs installation in all subdirectories with a \`package.json\` (excluding node_modules).
|
||||
install
|
||||
update
|
||||
link 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.
|
||||
|
||||
Options: same as for \`pnpm install\`
|
||||
run <command> [-- <args>...] this runs an arbitrary command from each package's "scripts" object.
|
||||
If a package doesn't have the command, it is skipped.
|
||||
If none of the packages have the command, the command fails.
|
||||
|
||||
* * *
|
||||
test [-- <args>...] this runs each package's "test" script, if one was provided.
|
||||
|
||||
pnpm recursive update
|
||||
rebuild [[<@scope>/<name>]...] this command runs the "npm build" command on each package.
|
||||
This is useful when you install a new version of node,
|
||||
and must recompile all your C++ addons with the new binary.
|
||||
|
||||
Concurrently runs update in all subdirectories with a \`package.json\` (excluding node_modules).
|
||||
|
||||
Options: same as for \`pnpm update\`
|
||||
|
||||
* * *
|
||||
|
||||
pnpm recursive link
|
||||
|
||||
Concurrently runs installation in all subdirectories with a \`package.json\` (excluding node_modules).
|
||||
If a package is available locally, the local version is linked.
|
||||
|
||||
Options: same as for \`pnpm install\`
|
||||
|
||||
* * *
|
||||
|
||||
pnpm recursive unlink
|
||||
|
||||
Removes links to local packages and reinstalls them from the registry.
|
||||
|
||||
* * *
|
||||
|
||||
pnpm recursive list [[<@scope>/]<pkg> ...]
|
||||
|
||||
List packages in each project of the multi-package repo.
|
||||
Accepts the same arguments and flags as the regular \`pnpm list\` command.
|
||||
|
||||
* * *
|
||||
|
||||
pnpm recursive outdated [[<@scope>/]<pkg> ...]
|
||||
|
||||
Check for outdated packages in every project of the multi-package repo.
|
||||
|
||||
* * *
|
||||
|
||||
pnpm recursive run <command> [-- <args>...]
|
||||
|
||||
alias: pnpm recursive run-script
|
||||
|
||||
This runs an arbitrary command from each package's "scripts" object.
|
||||
If a package doesn't have the command, it is skipped.
|
||||
If none of the packages have the command, the command fails.
|
||||
|
||||
* * *
|
||||
|
||||
pnpm recursive test <command> [-- <args>...]
|
||||
|
||||
alias: pnpm recursive t, pnpm recursive tst
|
||||
|
||||
This runs each package's "test" script, if one was provided.
|
||||
|
||||
* * *
|
||||
|
||||
pnpm recursive rebuild [[<@scope>/<name>]...]
|
||||
|
||||
alias: pnpm recursive rb
|
||||
|
||||
This command runs the "npm build" command on each package.
|
||||
This is useful when you install a new version of node, and must recompile all your C++ addons with the new binary.
|
||||
exec -- <command> [args...] run a command in each package.
|
||||
|
||||
Options:
|
||||
|
||||
@@ -343,6 +298,7 @@ function getHelpText (command: string) {
|
||||
- recursive run
|
||||
- recursive test
|
||||
- recursive rebuild
|
||||
- recursive exec
|
||||
|
||||
- server start
|
||||
- server stop
|
||||
|
||||
18
packages/pnpm/src/cmd/recursive/dividePackagesToChunks.ts
Normal file
18
packages/pnpm/src/cmd/recursive/dividePackagesToChunks.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import {PackageJson} from '@pnpm/types'
|
||||
import graphSequencer = require('graph-sequencer')
|
||||
import createPkgGraph from 'pkgs-graph'
|
||||
|
||||
export default (pkgs: Array<{path: string, manifest: PackageJson}>) => {
|
||||
const pkgGraphResult = createPkgGraph(pkgs)
|
||||
const graph = new Map(
|
||||
Object.keys(pkgGraphResult.graph).map((pkgPath) => [pkgPath, pkgGraphResult.graph[pkgPath].dependencies]) as Array<[string, string[]]>,
|
||||
)
|
||||
const graphSequencerResult = graphSequencer({
|
||||
graph,
|
||||
groups: [Object.keys(pkgGraphResult.graph)],
|
||||
})
|
||||
return {
|
||||
chunks: graphSequencerResult.chunks,
|
||||
graph: pkgGraphResult.graph,
|
||||
}
|
||||
}
|
||||
34
packages/pnpm/src/cmd/recursive/exec.ts
Normal file
34
packages/pnpm/src/cmd/recursive/exec.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import logger from '@pnpm/logger'
|
||||
import {PackageJson} from '@pnpm/types'
|
||||
import execa = require('execa')
|
||||
import pLimit = require('p-limit')
|
||||
import dividePackagesToChunks from './dividePackagesToChunks'
|
||||
|
||||
export default async (
|
||||
pkgs: Array<{path: string, manifest: PackageJson}>,
|
||||
args: string[],
|
||||
cmd: string,
|
||||
opts: {
|
||||
concurrency: number,
|
||||
unsafePerm: boolean,
|
||||
rawNpmConfig: object,
|
||||
},
|
||||
) => {
|
||||
const {chunks} = dividePackagesToChunks(pkgs)
|
||||
|
||||
const limitRun = pLimit(opts.concurrency)
|
||||
|
||||
for (const chunk of chunks) {
|
||||
await Promise.all(chunk.map((prefix: string) =>
|
||||
limitRun(async () => {
|
||||
try {
|
||||
await execa(args[0], args.slice(1), {cwd: prefix, stdio: 'inherit'})
|
||||
} catch (err) {
|
||||
logger.info(err)
|
||||
err['prefix'] = prefix // tslint:disable-line:no-string-literal
|
||||
throw err
|
||||
}
|
||||
},
|
||||
)))
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import getCommandFullName from '../../getCommandFullName'
|
||||
import requireHooks from '../../requireHooks'
|
||||
import {PnpmOptions} from '../../types'
|
||||
import help from '../help'
|
||||
import exec from './exec'
|
||||
import list from './list'
|
||||
import outdated from './outdated'
|
||||
import run from './run'
|
||||
@@ -40,6 +41,7 @@ const supportedRecursiveCommands = new Set([
|
||||
'rebuild',
|
||||
'run',
|
||||
'test',
|
||||
'exec',
|
||||
])
|
||||
|
||||
export default async (
|
||||
@@ -99,6 +101,8 @@ export default async (
|
||||
case 'update':
|
||||
opts = {...opts, update: true, allowNew: false, concurrency} as any // tslint:disable-line:no-any
|
||||
break
|
||||
case 'exec':
|
||||
return exec(pkgs, input, cmd, {...opts, concurrency} as any) // tslint:disable-line:no-any
|
||||
}
|
||||
|
||||
const store = await createStoreController(opts)
|
||||
|
||||
@@ -2,9 +2,8 @@ import runLifecycleHooks from '@pnpm/lifecycle'
|
||||
import logger from '@pnpm/logger'
|
||||
import {PackageJson} from '@pnpm/types'
|
||||
import {realNodeModulesDir} from '@pnpm/utils'
|
||||
import graphSequencer = require('graph-sequencer')
|
||||
import pLimit = require('p-limit')
|
||||
import createPkgGraph from 'pkgs-graph'
|
||||
import dividePackagesToChunks from './dividePackagesToChunks'
|
||||
|
||||
export default async (
|
||||
pkgs: Array<{path: string, manifest: PackageJson}>,
|
||||
@@ -17,15 +16,7 @@ export default async (
|
||||
},
|
||||
) => {
|
||||
const scriptName = args[0]
|
||||
const pkgGraphResult = createPkgGraph(pkgs)
|
||||
const graph = new Map(
|
||||
Object.keys(pkgGraphResult.graph).map((pkgPath) => [pkgPath, pkgGraphResult.graph[pkgPath].dependencies]) as Array<[string, string[]]>,
|
||||
)
|
||||
const graphSequencerResult = graphSequencer({
|
||||
graph,
|
||||
groups: [Object.keys(pkgGraphResult.graph)],
|
||||
})
|
||||
const chunks = graphSequencerResult.chunks
|
||||
const {chunks, graph} = dividePackagesToChunks(pkgs)
|
||||
let hasCommand = 0
|
||||
|
||||
const limitRun = pLimit(opts.concurrency)
|
||||
@@ -33,7 +24,7 @@ export default async (
|
||||
for (const chunk of chunks) {
|
||||
await Promise.all(chunk.map((prefix: string) =>
|
||||
limitRun(async () => {
|
||||
const pkg = pkgGraphResult.graph[prefix] as {manifest: PackageJson, path: string}
|
||||
const pkg = graph[prefix] as {manifest: PackageJson, path: string}
|
||||
if (!pkg.manifest.scripts || !pkg.manifest.scripts[scriptName]) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -887,3 +887,56 @@ test('recursive --scope ignore excluded packages', async (t: tape.Test) => {
|
||||
projects['project-2'].hasNot('is-negative')
|
||||
projects['project-3'].hasNot('minimatch')
|
||||
})
|
||||
|
||||
test('pnpm recursive exec', async (t: tape.Test) => {
|
||||
const projects = prepare(t, [
|
||||
{
|
||||
name: 'project-1',
|
||||
version: '1.0.0',
|
||||
dependencies: {
|
||||
'json-append': '1',
|
||||
},
|
||||
scripts: {
|
||||
build: `node -e "process.stdout.write('project-1')" | json-append ../output.json`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'project-2',
|
||||
version: '1.0.0',
|
||||
dependencies: {
|
||||
'json-append': '1',
|
||||
'project-1': '1'
|
||||
},
|
||||
scripts: {
|
||||
prebuild: `node -e "process.stdout.write('project-2-prebuild')" | json-append ../output.json`,
|
||||
build: `node -e "process.stdout.write('project-2')" | json-append ../output.json`,
|
||||
postbuild: `node -e "process.stdout.write('project-2-postbuild')" | json-append ../output.json`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'project-3',
|
||||
version: '1.0.0',
|
||||
dependencies: {
|
||||
'json-append': '1',
|
||||
'project-1': '1'
|
||||
},
|
||||
scripts: {
|
||||
build: `node -e "process.stdout.write('project-3')" | json-append ../output.json`,
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
await execPnpm('recursive', 'link')
|
||||
await execPnpm('recursive', 'exec', 'npm', 'run', 'build')
|
||||
|
||||
const outputs = await import(path.resolve('output.json')) as string[]
|
||||
const p1 = outputs.indexOf('project-1')
|
||||
const p2 = outputs.indexOf('project-2')
|
||||
const p2pre = outputs.indexOf('project-2-prebuild')
|
||||
const p2post = outputs.indexOf('project-2-postbuild')
|
||||
const p3 = outputs.indexOf('project-3')
|
||||
|
||||
t.ok(p1 < p2 && p1 < p3)
|
||||
t.ok(p1 < p2pre && p1 < p2post)
|
||||
t.ok(p2 < p2post && p2 > p2pre)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user