1 | 'use strict'
|
2 |
|
3 | const ansiTrim = require('./utils/ansi-trim')
|
4 | const chain = require('slide').chain
|
5 | const color = require('ansicolors')
|
6 | const defaultRegistry = require('./config/defaults').defaults.registry
|
7 | const log = require('npmlog')
|
8 | const npm = require('./npm')
|
9 | const output = require('./utils/output')
|
10 | const path = require('path')
|
11 | const semver = require('semver')
|
12 | const styles = require('ansistyles')
|
13 | const table = require('text-table')
|
14 |
|
15 |
|
16 | const checkFilesPermission = require('./doctor/check-files-permission')
|
17 | const checkPing = require('./doctor/check-ping')
|
18 | const getGitPath = require('./doctor/get-git-path')
|
19 | const getLatestNodejsVersion = require('./doctor/get-latest-nodejs-version')
|
20 | const getLatestNpmVersion = require('./doctor/get-latest-npm-version')
|
21 | const verifyCachedFiles = require('./doctor/verify-cached-files')
|
22 |
|
23 | const globalNodeModules = path.join(npm.config.globalPrefix, 'lib', 'node_modules')
|
24 | const localNodeModules = path.join(npm.config.localPrefix, 'node_modules')
|
25 |
|
26 | module.exports = doctor
|
27 |
|
28 | doctor.usage = 'npm doctor'
|
29 |
|
30 | function doctor (args, silent, cb) {
|
31 | args = args || {}
|
32 | if (typeof cb !== 'function') {
|
33 | cb = silent
|
34 | silent = false
|
35 | }
|
36 |
|
37 | const actionsToRun = [
|
38 | [checkPing],
|
39 | [getLatestNpmVersion],
|
40 | [getLatestNodejsVersion, args['node-url']],
|
41 | [getGitPath],
|
42 | [checkFilesPermission, npm.cache, 6],
|
43 | [checkFilesPermission, globalNodeModules, 4],
|
44 | [checkFilesPermission, localNodeModules, 6],
|
45 | [verifyCachedFiles, path.join(npm.cache, '_cacache')]
|
46 | ]
|
47 |
|
48 | log.info('doctor', 'Running checkup')
|
49 | chain(actionsToRun, function (stderr, stdout) {
|
50 | if (stderr && stderr.message !== 'not found: git') return cb(stderr)
|
51 | const list = makePretty(stdout)
|
52 | let outHead = ['Check', 'Value', 'Recommendation']
|
53 | let outBody = list
|
54 |
|
55 | if (npm.color) {
|
56 | outHead = outHead.map(function (item) {
|
57 | return styles.underline(item)
|
58 | })
|
59 | outBody = outBody.map(function (item) {
|
60 | if (item[2]) {
|
61 | item[0] = color.red(item[0])
|
62 | item[2] = color.magenta(item[2])
|
63 | }
|
64 | return item
|
65 | })
|
66 | }
|
67 |
|
68 | const outTable = [outHead].concat(outBody)
|
69 | const tableOpts = {
|
70 | stringLength: function (s) { return ansiTrim(s).length }
|
71 | }
|
72 |
|
73 | if (!silent) output(table(outTable, tableOpts))
|
74 |
|
75 | cb(null, list)
|
76 | })
|
77 | }
|
78 |
|
79 | function makePretty (p) {
|
80 | const ping = p[1]
|
81 | const npmLTS = p[2]
|
82 | const nodeLTS = p[3].replace('v', '')
|
83 | const whichGit = p[4] || 'not installed'
|
84 | const readbleCaches = p[5] ? 'ok' : 'notOk'
|
85 | const executableGlobalModules = p[6] ? 'ok' : 'notOk'
|
86 | const executableLocalModules = p[7] ? 'ok' : 'notOk'
|
87 | const cacheStatus = p[8] ? `verified ${p[8].verifiedContent} tarballs` : 'notOk'
|
88 | const npmV = npm.version
|
89 | const nodeV = process.version.replace('v', '')
|
90 | const registry = npm.config.get('registry')
|
91 | const list = [
|
92 | ['npm ping', ping],
|
93 | ['npm -v', 'v' + npmV],
|
94 | ['node -v', 'v' + nodeV],
|
95 | ['npm config get registry', registry],
|
96 | ['which git', whichGit],
|
97 | ['Perms check on cached files', readbleCaches],
|
98 | ['Perms check on global node_modules', executableGlobalModules],
|
99 | ['Perms check on local node_modules', executableLocalModules],
|
100 | ['Verify cache contents', cacheStatus]
|
101 | ]
|
102 |
|
103 | if (p[0] !== 200) list[0][2] = 'Check your internet connection'
|
104 | if (!semver.satisfies(npmV, '>=' + npmLTS)) list[1][2] = 'Use npm v' + npmLTS
|
105 | if (!semver.satisfies(nodeV, '>=' + nodeLTS)) list[2][2] = 'Use node v' + nodeLTS
|
106 | if (registry !== defaultRegistry) list[3][2] = 'Try `npm config set registry ' + defaultRegistry + '`'
|
107 | if (whichGit === 'not installed') list[4][2] = 'Install git and ensure it\'s in your PATH.'
|
108 | if (readbleCaches !== 'ok') list[5][2] = 'Check the permissions of your files in ' + npm.config.get('cache')
|
109 | if (executableGlobalModules !== 'ok') list[6][2] = globalNodeModules + ' must be readable and writable by the current user.'
|
110 | if (executableLocalModules !== 'ok') list[7][2] = localNodeModules + ' must be readable and writable by the current user.'
|
111 |
|
112 | return list
|
113 | }
|