Skip to content

Commit b9c3857

Browse files
committed
feat: streaming debug logfile
This decouples the log file writing from the terminal logging. We now open an append only file at the start of the process and stream logs to it. We still only display the log file message in timing mode or if there is an error, but the file is still written regardless. All logging now goes through `proc-log` and his is the first step to removing `npmlog`. For now `npmlog` is still used for the terminal logging but with a shim in front of it to make it easier to test and use in conjunction with `proc-log`. Ref: npm/statusboard#366 This also refactors many of the tests to always use an explicit `t.testdir` for their cache since the file is opened on each `new Npm()`. Tests are also refactored to use more of `MockNpm` with behavior to add config items and load `npm` if necessary. A new fixture `mockGlobals` was also added to make much of this for ergonomic. Ref: npm/statusboard#410 Closes npm/statusboard#411 Closes npm/statusboard#367
1 parent a8bc95f commit b9c3857

File tree

146 files changed

+4504
-3288
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

146 files changed

+4504
-3288
lines changed

.eslintrc.json

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
11
{
2-
"extends": ["@npmcli"]
2+
"extends": ["@npmcli"],
3+
"overrides": [{
4+
"files": "test/**",
5+
"rules": {
6+
"no-extend-native": "off",
7+
"no-global-assign": "off"
8+
}
9+
}, {
10+
"files": ["lib/**"],
11+
"rules": {
12+
"no-console": "warn"
13+
}
14+
}]
315
}

lib/auth/legacy.js

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
1-
const log = require('npmlog')
21
const profile = require('npm-profile')
3-
2+
const log = require('../utils/log-shim')
43
const openUrl = require('../utils/open-url.js')
54
const read = require('../utils/read-user-info.js')
65

76
const loginPrompter = async (creds) => {
8-
const opts = { log: log }
9-
10-
creds.username = await read.username('Username:', creds.username, opts)
7+
creds.username = await read.username('Username:', creds.username)
118
creds.password = await read.password('Password:', creds.password)
12-
creds.email = await read.email('Email: (this IS public) ', creds.email, opts)
9+
creds.email = await read.email('Email: (this IS public) ', creds.email)
1310

1411
return creds
1512
}

lib/auth/sso.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@
77
// CLI, we can remove this, and fold the lib/auth/legacy.js back into
88
// lib/adduser.js
99

10-
const log = require('npmlog')
1110
const profile = require('npm-profile')
1211
const npmFetch = require('npm-registry-fetch')
13-
12+
const log = require('../utils/log-shim')
1413
const openUrl = require('../utils/open-url.js')
1514
const otplease = require('../utils/otplease.js')
1615

lib/cli.js

+17-16
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,23 @@ module.exports = async process => {
44
// leak any private CLI configs to other programs
55
process.title = 'npm'
66

7-
const { checkForBrokenNode, checkForUnsupportedNode } = require('../lib/utils/unsupported.js')
8-
7+
// We used to differentiate between known broken and unsupported
8+
// versions of node and attempt to only log unsupported but still run.
9+
// After we dropped node 10 support, we can use new features
10+
// (like static, private, etc) which will only give vague syntax errors,
11+
// so now both broken and unsupported use console, but only broken
12+
// will process.exit. It is important to now perform *both* of these
13+
// checks as early as possible so the user gets the error message.
14+
const { checkForBrokenNode, checkForUnsupportedNode } = require('./utils/unsupported.js')
915
checkForBrokenNode()
10-
11-
const log = require('npmlog')
12-
// pause it here so it can unpause when we've loaded the configs
13-
// and know what loglevel we should be printing.
14-
log.pause()
15-
1616
checkForUnsupportedNode()
1717

18-
const Npm = require('../lib/npm.js')
18+
const exitHandler = require('./utils/exit-handler.js')
19+
process.on('uncaughtException', exitHandler)
20+
process.on('unhandledRejection', exitHandler)
21+
22+
const Npm = require('./npm.js')
1923
const npm = new Npm()
20-
const exitHandler = require('../lib/utils/exit-handler.js')
2124
exitHandler.setNpm(npm)
2225

2326
// if npm is called as "npmg" or "npm_g", then
@@ -26,16 +29,14 @@ module.exports = async process => {
2629
process.argv.splice(1, 1, 'npm', '-g')
2730
}
2831

29-
const replaceInfo = require('../lib/utils/replace-info.js')
32+
const log = require('./utils/log-shim.js')
33+
const replaceInfo = require('./utils/replace-info.js')
3034
log.verbose('cli', replaceInfo(process.argv))
3135

3236
log.info('using', 'npm@%s', npm.version)
3337
log.info('using', 'node@%s', process.version)
3438

35-
process.on('uncaughtException', exitHandler)
36-
process.on('unhandledRejection', exitHandler)
37-
38-
const updateNotifier = require('../lib/utils/update-notifier.js')
39+
const updateNotifier = require('./utils/update-notifier.js')
3940

4041
let cmd
4142
// now actually fire up npm and run the command.
@@ -63,7 +64,7 @@ module.exports = async process => {
6364
}
6465

6566
await npm.exec(cmd, npm.argv)
66-
exitHandler()
67+
return exitHandler()
6768
} catch (err) {
6869
if (err.code === 'EUNKNOWNCOMMAND') {
6970
const didYouMean = require('./utils/did-you-mean.js')

lib/commands/adduser.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const log = require('npmlog')
1+
const log = require('../utils/log-shim.js')
22
const replaceInfo = require('../utils/replace-info.js')
33
const BaseCommand = require('../base-command.js')
44
const authTypes = {
@@ -31,6 +31,7 @@ class AddUser extends BaseCommand {
3131
creds,
3232
registry,
3333
scope,
34+
log,
3435
})
3536

3637
await this.updateConfig({

lib/commands/bin.js

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class Bin extends BaseCommand {
1010
const b = this.npm.bin
1111
this.npm.output(b)
1212
if (this.npm.config.get('global') && !envPath.includes(b)) {
13+
// XXX: does this need to be console?
1314
console.error('(not in PATH env variable)')
1415
}
1516
}

lib/commands/bugs.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
const log = require('npmlog')
21
const pacote = require('pacote')
2+
const log = require('../utils/log-shim')
33
const openUrl = require('../utils/open-url.js')
44
const hostedFromMani = require('../utils/hosted-git-info-from-manifest.js')
55
const BaseCommand = require('../base-command.js')

lib/commands/cache.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
const cacache = require('cacache')
22
const { promisify } = require('util')
3-
const log = require('npmlog')
43
const pacote = require('pacote')
54
const path = require('path')
65
const rimraf = promisify(require('rimraf'))
@@ -9,6 +8,7 @@ const BaseCommand = require('../base-command.js')
98
const npa = require('npm-package-arg')
109
const jsonParse = require('json-parse-even-better-errors')
1110
const localeCompare = require('@isaacs/string-locale-compare')('en')
11+
const log = require('../utils/log-shim')
1212

1313
const searchCachePackage = async (path, spec, cacheKeys) => {
1414
const parsed = npa(spec)
@@ -141,7 +141,7 @@ class Cache extends BaseCommand {
141141
try {
142142
entry = await cacache.get(cachePath, key)
143143
} catch (err) {
144-
this.npm.log.warn(`Not Found: ${key}`)
144+
log.warn(`Not Found: ${key}`)
145145
break
146146
}
147147
this.npm.output(`Deleted: ${key}`)

lib/commands/ci.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ const reifyFinish = require('../utils/reify-finish.js')
55
const runScript = require('@npmcli/run-script')
66
const fs = require('fs')
77
const readdir = util.promisify(fs.readdir)
8-
9-
const log = require('npmlog')
8+
const log = require('../utils/log-shim.js')
109

1110
const removeNodeModules = async where => {
1211
const rimrafOpts = { glob: false }
@@ -39,7 +38,7 @@ class CI extends ArboristWorkspaceCmd {
3938
const opts = {
4039
...this.npm.flatOptions,
4140
path: where,
42-
log: this.npm.log,
41+
log,
4342
save: false, // npm ci should never modify the lockfile or package.json
4443
workspaces: this.workspaceNames,
4544
}

lib/commands/config.js

+6-5
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const { spawn } = require('child_process')
1111
const { EOL } = require('os')
1212
const ini = require('ini')
1313
const localeCompare = require('@isaacs/string-locale-compare')('en')
14+
const log = require('../utils/log-shim.js')
1415

1516
// take an array of `[key, value, k2=v2, k3, v3, ...]` and turn into
1617
// { key: value, k2: v2, k3: v3 }
@@ -87,12 +88,12 @@ class Config extends BaseCommand {
8788
}
8889

8990
async execWorkspaces (args, filters) {
90-
this.npm.log.warn('config', 'This command does not support workspaces.')
91+
log.warn('config', 'This command does not support workspaces.')
9192
return this.exec(args)
9293
}
9394

9495
async exec ([action, ...args]) {
95-
this.npm.log.disableProgress()
96+
log.disableProgress()
9697
try {
9798
switch (action) {
9899
case 'set':
@@ -117,7 +118,7 @@ class Config extends BaseCommand {
117118
throw this.usageError()
118119
}
119120
} finally {
120-
this.npm.log.enableProgress()
121+
log.enableProgress()
121122
}
122123
}
123124

@@ -128,10 +129,10 @@ class Config extends BaseCommand {
128129

129130
const where = this.npm.flatOptions.location
130131
for (const [key, val] of Object.entries(keyValues(args))) {
131-
this.npm.log.info('config', 'set %j %j', key, val)
132+
log.info('config', 'set %j %j', key, val)
132133
this.npm.config.set(key, val || '', where)
133134
if (!this.npm.config.validate(where)) {
134-
this.npm.log.warn('config', 'omitting invalid config values')
135+
log.warn('config', 'omitting invalid config values')
135136
}
136137
}
137138

lib/commands/dedupe.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// dedupe duplicated packages, or find them in the tree
22
const Arborist = require('@npmcli/arborist')
33
const reifyFinish = require('../utils/reify-finish.js')
4+
const log = require('../utils/log-shim.js')
45

56
const ArboristWorkspaceCmd = require('../arborist-cmd.js')
67

@@ -32,7 +33,7 @@ class Dedupe extends ArboristWorkspaceCmd {
3233
const where = this.npm.prefix
3334
const opts = {
3435
...this.npm.flatOptions,
35-
log: this.npm.log,
36+
log,
3637
path: where,
3738
dryRun,
3839
workspaces: this.workspaceNames,

lib/commands/diff.js

+7-9
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
const { resolve } = require('path')
2-
32
const semver = require('semver')
43
const libnpmdiff = require('libnpmdiff')
54
const npa = require('npm-package-arg')
65
const Arborist = require('@npmcli/arborist')
7-
const npmlog = require('npmlog')
86
const pacote = require('pacote')
97
const pickManifest = require('npm-pick-manifest')
10-
8+
const log = require('../utils/log-shim')
119
const readPackageName = require('../utils/read-package-name.js')
1210
const BaseCommand = require('../base-command.js')
1311

@@ -57,7 +55,7 @@ class Diff extends BaseCommand {
5755
}
5856

5957
const [a, b] = await this.retrieveSpecs(specs)
60-
npmlog.info('diff', { src: a, dst: b })
58+
log.info('diff', { src: a, dst: b })
6159

6260
const res = await libnpmdiff([a, b], {
6361
...this.npm.flatOptions,
@@ -83,7 +81,7 @@ class Diff extends BaseCommand {
8381
try {
8482
name = await readPackageName(this.prefix)
8583
} catch (e) {
86-
npmlog.verbose('diff', 'could not read project dir package.json')
84+
log.verbose('diff', 'could not read project dir package.json')
8785
}
8886

8987
if (!name) {
@@ -116,7 +114,7 @@ class Diff extends BaseCommand {
116114
try {
117115
pkgName = await readPackageName(this.prefix)
118116
} catch (e) {
119-
npmlog.verbose('diff', 'could not read project dir package.json')
117+
log.verbose('diff', 'could not read project dir package.json')
120118
noPackageJson = true
121119
}
122120

@@ -154,7 +152,7 @@ class Diff extends BaseCommand {
154152
actualTree.inventory.query('name', spec.name)
155153
.values().next().value
156154
} catch (e) {
157-
npmlog.verbose('diff', 'failed to load actual install tree')
155+
log.verbose('diff', 'failed to load actual install tree')
158156
}
159157

160158
if (!node || !node.name || !node.package || !node.package.version) {
@@ -227,7 +225,7 @@ class Diff extends BaseCommand {
227225
try {
228226
pkgName = await readPackageName(this.prefix)
229227
} catch (e) {
230-
npmlog.verbose('diff', 'could not read project dir package.json')
228+
log.verbose('diff', 'could not read project dir package.json')
231229
}
232230

233231
if (!pkgName) {
@@ -261,7 +259,7 @@ class Diff extends BaseCommand {
261259
const arb = new Arborist(opts)
262260
actualTree = await arb.loadActual(opts)
263261
} catch (e) {
264-
npmlog.verbose('diff', 'failed to load actual install tree')
262+
log.verbose('diff', 'failed to load actual install tree')
265263
}
266264

267265
return specs.map(i => {

lib/commands/dist-tag.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
const log = require('npmlog')
21
const npa = require('npm-package-arg')
32
const regFetch = require('npm-registry-fetch')
43
const semver = require('semver')
5-
4+
const log = require('../utils/log-shim')
65
const otplease = require('../utils/otplease.js')
76
const readPackageName = require('../utils/read-package-name.js')
87
const BaseCommand = require('../base-command.js')

lib/commands/docs.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
const log = require('npmlog')
21
const pacote = require('pacote')
32
const openUrl = require('../utils/open-url.js')
43
const hostedFromMani = require('../utils/hosted-git-info-from-manifest.js')
5-
4+
const log = require('../utils/log-shim')
65
const BaseCommand = require('../base-command.js')
76
class Docs extends BaseCommand {
87
static description = 'Open documentation for a package in a web browser'

0 commit comments

Comments
 (0)