From fd2b23ebf06f2aa5c77203d40e8ec5b4cd120b5e Mon Sep 17 00:00:00 2001 From: zkochan Date: Sat, 1 Jul 2017 16:05:31 +0300 Subject: [PATCH] feat: add an option to pass in a logs listener Ref https://github.com/pnpm/pnpm/issues/572 --- README.md | 10 ++++++++++ src/api/install.ts | 28 ++++++++++++++++++++++++---- src/api/link.ts | 25 +++++++++++++++++++++++++ src/api/prune.ts | 14 ++++++++++++-- src/api/storeStatus.ts | 13 ++++++++++++- src/api/uninstall.ts | 15 +++++++++++++-- src/logging/streamParser.ts | 1 + src/types.ts | 3 ++- test/install/peerDependencies.ts | 13 ++----------- 9 files changed, 101 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index b22bbd11bf..48fd1e9d0d 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ Install packages. * `options.metaCache` - *Map* - a cache for package meta info. * `options.networkConcurrency` - *Number* - `16` by default. Max amount of network requests to perform concurrently. * `options.offline` - *Boolean* - `false` by default. Install packages using only the local registry mirror, w/o doing any network requests. +* `options.reporter` - *Function* - A function that listens for logs. **Returns:** a Promise @@ -65,6 +66,7 @@ Uninstalls a package, completely removing everything pnpm installed on its behal * `options.saveDev` - *Boolean* - the package will be removed from `devDependencies`. * `options.saveOptional` - *Boolean* - the package will be removed from `optionalDependencies`. * `options.global` - *Boolean* - the packages will be uninstalled globally. +* `options.reporter` - *Function* - A function that listens for logs. ### `pnpm.link(linkFrom, lintTo, [options])` @@ -74,6 +76,7 @@ Create a symbolic link from the linked package to the target package's `node_mod * `linkFrom` - *String* - path to the package that should be linked. * `lintTo` - *String* - path to the dependent package. +* `options.reporter` - *Function* - A function that listens for logs. ### `pnpm.linkToGlobal(linkFrom, options)` @@ -83,6 +86,7 @@ Create a symbolic link from the specified package to the global `node_modules`. * `linkFrom` - *String* - path to the package that should be linked. * `globalPrefix` - *String* - path to the global directory. +* `options.reporter` - *Function* - A function that listens for logs. ### `pnpm.linkFromGlobal(pkgName, linkTo, options)` @@ -93,6 +97,7 @@ Create a symbolic link from the global `pkgName` to the `linkTo/node_modules` fo * `pkgName` - *String* - package to link. * `linkTo` - *String* - package to link to. * `globalPrefix` - *String* - path to the global directory. +* `options.reporter` - *Function* - A function that listens for logs. ### `pnpm.prune([options])` @@ -102,11 +107,16 @@ Remove extraneous packages. Extraneous packages are packages that are not listed * `options.production` - *Boolean* - by default `false`. If this property is `true`, prune will remove the packages specified in `devDependencies`. * `options.prefix` - *String* - by default `process.cwd()`. +* `options.reporter` - *Function* - A function that listens for logs. ### `pnpm.storeStatus([options])` Return the list of modified dependencies. +**Arguments:** + +* `options.reporter` - *Function* - A function that listens for logs. + **Returns:** `Promise` - the paths to the modified packages of the current project. The paths contain the location of packages in the store, not in the projects `node_modules` folder. diff --git a/src/api/install.ts b/src/api/install.ts index a2550a5fca..a468d87f98 100644 --- a/src/api/install.ts +++ b/src/api/install.ts @@ -37,6 +37,7 @@ import {Package} from '../types' import {PackageSpec, DirectoryResolution, Resolution} from '../resolve' import {DependencyTreeNode} from '../link/resolvePeers' import depsToSpecs, {similarDepsToSpecs} from '../depsToSpecs' +import streamParser from '../logging/streamParser' export type InstalledPackages = { [name: string]: InstalledPackage @@ -91,13 +92,22 @@ export type InstallContext = { } export async function install (maybeOpts?: PnpmOptions) { + const reporter = maybeOpts && maybeOpts.reporter + if (reporter) { + streamParser.on('data', reporter) + } + const opts = extendOptions(maybeOpts) if (opts.lock) { - return lock(opts.prefix, _install, {stale: opts.lockStaleDuration}) + await lock(opts.prefix, _install, {stale: opts.lockStaleDuration}) + } else { + await _install() } - return _install() + if (reporter) { + streamParser.removeListener('data', opts.reporter) + } async function _install() { const installType = 'general' @@ -180,12 +190,22 @@ function depsFromPackage (pkg: Package): Dependencies { * install({'lodash': '1.0.0', 'foo': '^2.1.0' }, { silent: true }) */ export async function installPkgs (fuzzyDeps: string[] | Dependencies, maybeOpts?: PnpmOptions) { + const reporter = maybeOpts && maybeOpts.reporter + if (reporter) { + streamParser.on('data', reporter) + } + const opts = extendOptions(maybeOpts) if (opts.lock) { - return lock(opts.prefix, _installPkgs, {stale: opts.lockStaleDuration}) + await lock(opts.prefix, _installPkgs, {stale: opts.lockStaleDuration}) + } else { + await _installPkgs() + } + + if (reporter) { + streamParser.removeListener('data', opts.reporter) } - return _installPkgs() async function _installPkgs () { const installType = 'named' diff --git a/src/api/link.ts b/src/api/link.ts index a0070a82a0..ead7114642 100644 --- a/src/api/link.ts +++ b/src/api/link.ts @@ -7,6 +7,7 @@ import expandTilde from '../fs/expandTilde' import {linkPkgBins} from '../link/linkBins' import {PnpmOptions} from '../types' import extendOptions from './extendOptions' +import streamParser from '../logging/streamParser' const linkLogger = logger('link') @@ -15,6 +16,10 @@ export default async function link ( linkTo: string, maybeOpts?: PnpmOptions & {skipInstall?: boolean} ) { + const reporter = maybeOpts && maybeOpts.reporter + if (reporter) { + streamParser.on('data', reporter) + } const opts = extendOptions(maybeOpts) if (!maybeOpts || !maybeOpts.skipInstall) { @@ -26,6 +31,10 @@ export default async function link ( const bin = path.join(destModules, '.bin') await linkPkgBins(linkFrom, bin) + + if (reporter) { + streamParser.removeListener('data', reporter) + } } async function linkToModules (linkFrom: string, modules: string) { @@ -40,18 +49,34 @@ export async function linkFromGlobal ( linkTo: string, maybeOpts: PnpmOptions & {globalPrefix: string} ) { + const reporter = maybeOpts && maybeOpts.reporter + if (reporter) { + streamParser.on('data', reporter) + } const opts = extendOptions(maybeOpts) const globalPkgPath = expandTilde(maybeOpts.globalPrefix) const linkedPkgPath = path.join(globalPkgPath, 'node_modules', pkgName) await link(linkedPkgPath, linkTo, opts) + + if (reporter) { + streamParser.removeListener('data', reporter) + } } export async function linkToGlobal ( linkFrom: string, maybeOpts: PnpmOptions & {globalPrefix: string} ) { + const reporter = maybeOpts && maybeOpts.reporter + if (reporter) { + streamParser.on('data', reporter) + } const opts = extendOptions(maybeOpts) opts.global = true // bins will be linked to the global bin path const globalPkgPath = expandTilde(maybeOpts.globalPrefix) await link(linkFrom, globalPkgPath, opts) + + if (reporter) { + streamParser.removeListener('data', reporter) + } } diff --git a/src/api/prune.ts b/src/api/prune.ts index e38f80c32b..f5c9dbdbcb 100644 --- a/src/api/prune.ts +++ b/src/api/prune.ts @@ -12,17 +12,27 @@ import { ResolvedDependencies, prune as pruneShrinkwrap, } from 'pnpm-shrinkwrap' +import streamParser from '../logging/streamParser' export async function prune(maybeOpts?: PnpmOptions): Promise { + const reporter = maybeOpts && maybeOpts.reporter + if (reporter) { + streamParser.on('data', reporter) + } + const opts = extendOptions(maybeOpts) const ctx = await getContext(opts) if (opts.lock === false) { - return run() + await run() + } else { + await lock(ctx.storePath, run, {stale: opts.lockStaleDuration}) } - return lock(ctx.storePath, run, {stale: opts.lockStaleDuration}) + if (reporter) { + streamParser.removeListener('data', reporter) + } async function run () { if (!ctx.pkg) { diff --git a/src/api/storeStatus.ts b/src/api/storeStatus.ts index 45e78325a0..fb3ae0d89a 100644 --- a/src/api/storeStatus.ts +++ b/src/api/storeStatus.ts @@ -5,8 +5,13 @@ import extendOptions from './extendOptions' import getContext from './getContext' import untouched from '../pkgIsUntouched' import {shortIdToFullId} from '../fs/shrinkwrap' +import streamParser from '../logging/streamParser' export default async function (maybeOpts: PnpmOptions) { + const reporter = maybeOpts && maybeOpts.reporter + if (reporter) { + streamParser.on('data', reporter) + } const opts = extendOptions(maybeOpts) const ctx = await getContext(opts) if (!ctx.shrinkwrap) return [] @@ -19,5 +24,11 @@ export default async function (maybeOpts: PnpmOptions) { .filter(pkgId => pkgId && !ctx.skipped.has(pkgId)) .map((pkgPath: string) => path.join(ctx.storePath, pkgPath)) - return await pFilter(pkgPaths, async (pkgPath: string) => !await untouched(path.join(pkgPath, 'package'))) + const modified = await pFilter(pkgPaths, async (pkgPath: string) => !await untouched(path.join(pkgPath, 'package'))) + + if (reporter) { + streamParser.removeListener('data', reporter) + } + + return modified } diff --git a/src/api/uninstall.ts b/src/api/uninstall.ts index 7c4093c9d9..bc6c830922 100644 --- a/src/api/uninstall.ts +++ b/src/api/uninstall.ts @@ -20,14 +20,25 @@ import {PackageSpec} from '../resolve' import pnpmPkgJson from '../pnpmPkgJson' import safeIsInnerLink from '../safeIsInnerLink' import removeTopDependency from '../removeTopDependency' +import streamParser from '../logging/streamParser' export default async function uninstall (pkgsToUninstall: string[], maybeOpts?: PnpmOptions) { + const reporter = maybeOpts && maybeOpts.reporter + if (reporter) { + streamParser.on('data', reporter) + } + const opts = extendOptions(maybeOpts) if (opts.lock) { - return lock(opts.prefix, _uninstall, {stale: opts.lockStaleDuration}) + await lock(opts.prefix, _uninstall, {stale: opts.lockStaleDuration}) + } else { + await _uninstall() + } + + if (reporter) { + streamParser.removeListener('data', opts.reporter) } - return _uninstall() async function _uninstall () { const ctx = await getContext(opts) diff --git a/src/logging/streamParser.ts b/src/logging/streamParser.ts index 3c94f7de26..aea485f05c 100644 --- a/src/logging/streamParser.ts +++ b/src/logging/streamParser.ts @@ -3,6 +3,7 @@ import bole = require('bole') export type StreamParser = { on: Function, + removeListener: Function, } const streamParser: StreamParser = ndjson.parse() diff --git a/src/types.ts b/src/types.ts index edee6d0229..e6d35ece70 100644 --- a/src/types.ts +++ b/src/types.ts @@ -54,9 +54,10 @@ export type PnpmOptions = { // cannot be specified via configs update?: boolean, + reporter?: (logObj: Object) => void, } -export type StrictPnpmOptions = { +export type StrictPnpmOptions = PnpmOptions & { rawNpmConfig: Object, global: boolean, prefix: string, diff --git a/test/install/peerDependencies.ts b/test/install/peerDependencies.ts index f78d913d36..8beb476d92 100644 --- a/test/install/peerDependencies.ts +++ b/test/install/peerDependencies.ts @@ -7,7 +7,6 @@ import { prepare, testDefaults, } from '../utils' -import streamParser from '../../src/logging/streamParser' import deepRequireCwd = require('deep-require-cwd') import rimraf = require('rimraf-then') @@ -46,11 +45,7 @@ test('peer dependency is not grouped with dependent when the peer is a top depen } } - streamParser.on('data', reporter) - - await installPkgs(['ajv@4.10.4', 'ajv-keywords@1.5.0'], testDefaults()) - - streamParser['removeListener']('data', reporter) + await installPkgs(['ajv@4.10.4', 'ajv-keywords@1.5.0'], testDefaults({reporter})) t.ok(await exists(path.join(NM, '.localhost+4873', 'ajv-keywords', '1.5.0', NM, 'ajv-keywords')), 'dependent is at the normal location') t.notOk(log, 'no warning is logged about unresolved peer dep') @@ -66,11 +61,7 @@ test('warning is reported when cannot resolve peer dependency', async (t: tape.T } } - streamParser.on('data', reporter) - - await installPkgs(['ajv-keywords@1.5.0'], testDefaults()) - - streamParser['removeListener']('data', reporter) + await installPkgs(['ajv-keywords@1.5.0'], testDefaults({reporter})) t.ok(log) })