diff --git a/README.md b/README.md index 51f67cc8d0..46da063d41 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,19 @@ Controls the maximum number of HTTP requests that can be done simultaneously. Controls the number of child processes run parallely to build node modules. +#### lock + +* Default: **true** +* Type: **Boolean** + +Dangerous! If false, the store is not locked. It means that several installations using the same +store can run simultaneously. + +Can be passed in via a CLI option. `--no-lock` to set it to false. E.g.: `pnpm install --no-lock`. + +> If you experience issues similar to the ones described in [#594](https://github.com/pnpm/pnpm/issues/594), use this option to disable locking. +> In the meanwhile, we'll try to find a solution that will make locking work for everyone. + ## Benchmark pnpm is usually 10 times faster than npm and 30% faster than yarn. See [this](https://github.com/zkochan/node-package-manager-benchmark) diff --git a/src/api/extendOptions.ts b/src/api/extendOptions.ts index 3377a5cb0a..db8d3277ce 100644 --- a/src/api/extendOptions.ts +++ b/src/api/extendOptions.ts @@ -29,6 +29,7 @@ const defaults = (opts: PnpmOptions) => { networkConcurrency: 16, fetchingConcurrency: 16, lockStaleDuration: 60 * 1000, // 1 minute + lock: true, childConcurrency: 5, offline: false, registry: 'https://registry.npmjs.org/', @@ -52,6 +53,9 @@ export default (opts?: PnpmOptions): StrictPnpmOptions => { if (extendedOpts.force) { logger.warn('using --force I sure hope you know what you are doing') } + if (extendedOpts.lock === false) { + logger.warn('using --no-lock I sure hope you know what you are doing') + } if (extendedOpts.localRegistry !== DEFAULT_LOCAL_REGISTRY) { extendedOpts.localRegistry = expandTilde(extendedOpts.localRegistry, extendedOpts.prefix) } diff --git a/src/api/install.ts b/src/api/install.ts index 7110ac1287..7e85ca17d4 100644 --- a/src/api/install.ts +++ b/src/api/install.ts @@ -61,25 +61,27 @@ export async function install (maybeOpts?: PnpmOptions) { const optionalDeps = R.keys(ctx.pkg.optionalDependencies) - return lock( - ctx.storePath, - async () => { - const scripts = !opts.ignoreScripts && ctx.pkg && ctx.pkg.scripts || {} - if (scripts['preinstall']) { - npmRun('preinstall', ctx.root, opts.userAgent) - } + if (opts.lock === false) { + return run() + } - await installInContext(installType, specs, optionalDeps, [], ctx, installCtx, opts) + return lock(ctx.storePath, run, {stale: opts.lockStaleDuration}) - if (scripts['postinstall']) { - npmRun('postinstall', ctx.root, opts.userAgent) - } - if (scripts['prepublish']) { - npmRun('prepublish', ctx.root, opts.userAgent) - } - }, - {stale: opts.lockStaleDuration} - ) + async function run () { + const scripts = !opts.ignoreScripts && ctx.pkg && ctx.pkg.scripts || {} + if (scripts['preinstall']) { + npmRun('preinstall', ctx.root, opts.userAgent) + } + + await installInContext(installType, specs, optionalDeps, [], ctx, installCtx, opts) + + if (scripts['postinstall']) { + npmRun('postinstall', ctx.root, opts.userAgent) + } + if (scripts['prepublish']) { + npmRun('prepublish', ctx.root, opts.userAgent) + } + } } function specsToInstallFromPackage( @@ -131,18 +133,22 @@ export async function installPkgs (fuzzyDeps: string[] | Dependencies, maybeOpts ? packagesToInstall.map(spec => spec.name) : [] - return lock( - ctx.storePath, - () => installInContext( + if (opts.lock === false) { + return run() + } + + return lock(ctx.storePath, run, {stale: opts.lockStaleDuration}) + + function run () { + return installInContext( installType, packagesToInstall, optionalDependencies, packagesToInstall.map(spec => spec.name), ctx, installCtx, - opts), - {stale: opts.lockStaleDuration} - ) + opts) + } } function argsToSpecs (args: string[], defaultTag: string, where: string): PackageSpec[] { diff --git a/src/api/prune.ts b/src/api/prune.ts index 0d47ee0c24..63d8ada3cb 100644 --- a/src/api/prune.ts +++ b/src/api/prune.ts @@ -19,7 +19,13 @@ export async function prune(maybeOpts?: PnpmOptions): Promise { const ctx = await getContext(opts) - return lock(ctx.storePath, async function () { + if (opts.lock === false) { + return run() + } + + return lock(ctx.storePath, run, {stale: opts.lockStaleDuration}) + + async function run () { if (!ctx.pkg) { throw new Error('No package.json found - cannot prune') } @@ -37,8 +43,7 @@ export async function prune(maybeOpts?: PnpmOptions): Promise { const prunedShr = pruneShrinkwrap(newShr) await removeOrphanPkgs(ctx.privateShrinkwrap, prunedShr, ctx.root, ctx.storePath) - }, - {stale: opts.lockStaleDuration}) + } } async function getExtraneousPkgs (pkg: Package, root: string, production: boolean) { diff --git a/src/api/uninstall.ts b/src/api/uninstall.ts index 0a9d3a1f50..0f241fd320 100644 --- a/src/api/uninstall.ts +++ b/src/api/uninstall.ts @@ -32,11 +32,16 @@ export default async function uninstallCmd (pkgsToUninstall: string[], maybeOpts } const pkg = ctx.pkg - return lock( - ctx.storePath, - () => uninstallInContext(pkgsToUninstall, pkg, ctx, opts), - {stale: opts.lockStaleDuration} - ) + + if (opts.lock === false) { + return run() + } + + return lock(ctx.storePath, run, {stale: opts.lockStaleDuration}) + + function run () { + return uninstallInContext(pkgsToUninstall, pkg, ctx, opts) + } } export async function uninstallInContext (pkgsToUninstall: string[], pkg: Package, ctx: PnpmContext, opts: StrictPnpmOptions) { diff --git a/src/bin/pnpm.ts b/src/bin/pnpm.ts index fd5ee79280..7f90035139 100755 --- a/src/bin/pnpm.ts +++ b/src/bin/pnpm.ts @@ -59,6 +59,7 @@ async function run (argv: string[]) { 'network-concurrency': Number, 'fetching-concurrency': Number, 'lock-stale-duration': Number, + 'lock': Boolean, 'child-concurrency': Number, 'offline': Boolean, 'reporter': String, diff --git a/src/types.ts b/src/types.ts index 81d5beaabe..0b455578e5 100644 --- a/src/types.ts +++ b/src/types.ts @@ -46,6 +46,7 @@ export type PnpmOptions = { networkConcurrency?: number, fetchingConcurrency?: number, lockStaleDuration?: number, + lock?: boolean, childConcurrency?: number, repeatInstallDepth?: number, @@ -98,6 +99,7 @@ export type StrictPnpmOptions = { networkConcurrency: number, fetchingConcurrency: number, lockStaleDuration: number, + lock: boolean, childConcurrency: number, repeatInstallDepth: number,