Skip to content

Commit

Permalink
feat: updated 'npm install' command
Browse files Browse the repository at this point in the history
- functionality to get diff and explicitRequets from arborist instace
  requires @npmcli/arborist@0.0.0-pre.12
- create printResult function
- output install action time (fairly naively)
- added functionality to create and print archy dep tree
  • Loading branch information
Michael Perrotte committed Mar 13, 2020
1 parent bf3370b commit e32956f
Showing 1 changed file with 113 additions and 41 deletions.
154 changes: 113 additions & 41 deletions lib/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,30 @@

module.exports = install

var usage = require('./utils/usage')
// --- node core modules
const fs = require('fs')
// - @npmcli modules
const Arborist = require('@npmcli/arborist')
const log = require('npmlog')
const validate = require('aproba')
// - deps
const asyncMap = require('slide').asyncMap // XXX remove this
const archy = require('archy')
// - npm internal utils
const audit = require('./install/audit.js')
const {
getPrintFundingReport,
getPrintFundingReportJSON
} = require('./install/fund.js')
const usage = require('./utils/usage')
const npm = require('./npm.js')
const output = require('./utils/output.js')
const errorMessage = require('./utils/error-message.js')
// XXX this file doesn't exist anymore; remove this
// const sillyLogTree = require('./util/silly-log-tree.js')
// ---

const path = require('path')

install.usage = usage(
'install',
Expand All @@ -34,8 +57,6 @@ install.usage = usage(
'[--save-prod|--save-dev|--save-optional] [--save-exact] [--no-save]'
)

const npa = require('npm-package-arg')

install.completion = function (opts, cb) {
validate('OF', arguments)
// install can complete to a folder with a package.json, or any package.
Expand Down Expand Up @@ -95,69 +116,120 @@ install.completion = function (opts, cb) {
cb()
}

const Arborist = require('@npmcli/arborist')

// dependencies
var log = require('npmlog')
// const sillyLogTree = require('./util/silly-log-tree.js')

// npm internal utils
var npm = require('./npm.js')
var output = require('./utils/output.js')
var saveMetrics = require('./utils/metrics.js').save

// install specific libraries
var audit = require('./install/audit.js')
var {
getPrintFundingReport,
getPrintFundingReportJSON
} = require('./install/fund.js')
var errorMessage = require('./utils/error-message.js')

const path = require('path')

function install (where, args, cb) {
async function install (where, args, cb) {
if (!cb) {
cb = args
args = where
where = null
}

// the /path/to/node_modules/..
const globalTop = path.resolve(npm.globalDir, '..')
if (!where) {
where = npm.flatOptions.global
const {
dryRun,
global: isGlobalInstall
} = npm.flatOptions

// Determine where install is happening
// - If `where` is NOT set, then we need to determine if it's a global install
// or if it's a local context install (hence nested ternary)
// - `where` IS SET, just use it
where = (!where)
? (isGlobalInstall)
? globalTop
: npm.prefix
}
const {dryRun} = npm.flatOptions
: where

// TODO: Add warnings for other deprecated flags
if (npm.config.get('dev')) {
log.warn('install', 'Usage of the `--dev` option is deprecated. Use `--include=dev` instead.')
}

// If global install, and NO args passed; user meant "this directory context"
if (where === globalTop && !args.length) {
args = ['.']
}

// XXX What does this do?
args = args.filter(a => path.resolve(a) !== npm.prefix)

const arb = new Arborist({
...this.flatOptions,
path: where,
})
// Create arborist object to work with
const arb = new Arborist({ ...npm.flatOptions, path: where })

// TODO:
// - audit
// - funding
// - more logging (archy-ize the tree for silly logging)
// - global installs in Arborist

const opt = {
...this.flatOptions,
add: args,
}
arb[dryRun ? 'buildIdealTree' : 'reify'](opt).then(tree => {
output('TREEEEEEEE', tree)
const arbCallOpts = { ...npm.flatOptions, add: args }

try {
const start = Date.now()

const tree = (dryRun)
? await arb.buildIdealTree(arbCallOpts)
: await arb.reify(arbCallOpts)

const stop = Date.now()

// Print list of installed packages and their version
// Buffer with newline
output('')
arb.diff.children.forEach(diff => {
const node = diff.ideal
if (diff.action === 'ADD' && arb.explicitRequests.has(node.name)) {
output(`+ ${node.name}@${node.package.version}`)
}
})

/**
* TODO:
* - Add audit
* - Add funding
*/

printResults({ start, stop }, tree, arb)
cb()
}, er => cb(er))
} catch (err) {
const msg = errorMessage(err)
msg.summary.forEach(s => log.warn.apply(log, s))
msg.detail.forEach(d => log.verbose.apply(log, d))
cb(err)
}
}

function printResults (timing, tree, arb) {
const { unicode } = npm.flatOptions

// Create archy tree from arborist tree
const reducedTree = reduceArbTree(tree)
const archyTree = archy(reducedTree, '', { unicode })

// Collect information about command action taken
const pkgCount = arb.diff.children.length
const contribCount = pkgCount
const added = `added ${pkgCount}`

const from = `from ${contribCount} contributor${contribCount ? 's' : ''}`
const audited = `audited ${0} package${'s'}`
const time = (timing.stop - timing.start) / 1000

// Print summary of command action taken
output(`${added}, ${from}, and ${audited} in ${time}s`)

// Optionally print the top level dependency tree
log.silly('topLevelDepTree', archyTree)
}

function reduceArbTree (rootNode) {
const initialValue = {
label: rootNode.name,
nodes: []
}
const rootChildrenMap = rootNode.children
for (const child of rootChildrenMap.keys()) {
initialValue.nodes.push(child)
}

return initialValue
}

0 comments on commit e32956f

Please sign in to comment.