2017-05-09 23:46:02 +02:00
|
|
|
'use strict'
|
|
|
|
|
|
|
|
const ansiTrim = require('./utils/ansi-trim')
|
|
|
|
const chain = require('slide').chain
|
|
|
|
const color = require('ansicolors')
|
|
|
|
const defaultRegistry = require('./config/defaults').defaults.registry
|
|
|
|
const log = require('npmlog')
|
|
|
|
const npm = require('./npm')
|
|
|
|
const output = require('./utils/output')
|
|
|
|
const path = require('path')
|
|
|
|
const semver = require('semver')
|
|
|
|
const styles = require('ansistyles')
|
|
|
|
const table = require('text-table')
|
|
|
|
|
|
|
|
// steps
|
|
|
|
const checkFilesPermission = require('./doctor/check-files-permission')
|
|
|
|
const checkPing = require('./doctor/check-ping')
|
|
|
|
const getGitPath = require('./doctor/get-git-path')
|
|
|
|
const getLatestNodejsVersion = require('./doctor/get-latest-nodejs-version')
|
|
|
|
const getLatestNpmVersion = require('./doctor/get-latest-npm-version')
|
|
|
|
const verifyCachedFiles = require('./doctor/verify-cached-files')
|
|
|
|
|
|
|
|
const globalNodeModules = path.join(npm.config.globalPrefix, 'lib', 'node_modules')
|
|
|
|
const localNodeModules = path.join(npm.config.localPrefix, 'node_modules')
|
2017-01-13 01:58:10 +01:00
|
|
|
|
|
|
|
module.exports = doctor
|
|
|
|
|
|
|
|
doctor.usage = 'npm doctor'
|
|
|
|
|
|
|
|
function doctor (args, silent, cb) {
|
|
|
|
args = args || {}
|
|
|
|
if (typeof cb !== 'function') {
|
|
|
|
cb = silent
|
|
|
|
silent = false
|
|
|
|
}
|
|
|
|
|
2017-05-09 23:46:02 +02:00
|
|
|
const actionsToRun = [
|
2017-01-13 01:58:10 +01:00
|
|
|
[checkPing],
|
|
|
|
[getLatestNpmVersion],
|
|
|
|
[getLatestNodejsVersion, args['node-url']],
|
|
|
|
[getGitPath],
|
2017-06-06 01:31:14 +02:00
|
|
|
[checkFilesPermission, npm.cache, 4, 6],
|
|
|
|
[checkFilesPermission, globalNodeModules, 4, 4],
|
|
|
|
[checkFilesPermission, localNodeModules, 6, 6],
|
2017-05-09 23:46:02 +02:00
|
|
|
[verifyCachedFiles, path.join(npm.cache, '_cacache')]
|
2017-01-13 01:58:10 +01:00
|
|
|
]
|
|
|
|
|
|
|
|
log.info('doctor', 'Running checkup')
|
|
|
|
chain(actionsToRun, function (stderr, stdout) {
|
|
|
|
if (stderr && stderr.message !== 'not found: git') return cb(stderr)
|
2017-05-09 23:46:02 +02:00
|
|
|
const list = makePretty(stdout)
|
|
|
|
let outHead = ['Check', 'Value', 'Recommendation']
|
|
|
|
let outBody = list
|
2017-01-13 01:58:10 +01:00
|
|
|
|
|
|
|
if (npm.color) {
|
|
|
|
outHead = outHead.map(function (item) {
|
|
|
|
return styles.underline(item)
|
|
|
|
})
|
|
|
|
outBody = outBody.map(function (item) {
|
|
|
|
if (item[2]) {
|
|
|
|
item[0] = color.red(item[0])
|
|
|
|
item[2] = color.magenta(item[2])
|
|
|
|
}
|
|
|
|
return item
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2017-05-09 23:46:02 +02:00
|
|
|
const outTable = [outHead].concat(outBody)
|
|
|
|
const tableOpts = {
|
2017-01-13 01:58:10 +01:00
|
|
|
stringLength: function (s) { return ansiTrim(s).length }
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!silent) output(table(outTable, tableOpts))
|
|
|
|
|
|
|
|
cb(null, list)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
function makePretty (p) {
|
2017-05-09 23:46:02 +02:00
|
|
|
const ping = p[1]
|
|
|
|
const npmLTS = p[2]
|
|
|
|
const nodeLTS = p[3].replace('v', '')
|
|
|
|
const whichGit = p[4] || 'not installed'
|
|
|
|
const readbleCaches = p[5] ? 'ok' : 'notOk'
|
|
|
|
const executableGlobalModules = p[6] ? 'ok' : 'notOk'
|
|
|
|
const executableLocalModules = p[7] ? 'ok' : 'notOk'
|
|
|
|
const cacheStatus = p[8] ? `verified ${p[8].verifiedContent} tarballs` : 'notOk'
|
|
|
|
const npmV = npm.version
|
|
|
|
const nodeV = process.version.replace('v', '')
|
|
|
|
const registry = npm.config.get('registry')
|
|
|
|
const list = [
|
2017-01-13 01:58:10 +01:00
|
|
|
['npm ping', ping],
|
|
|
|
['npm -v', 'v' + npmV],
|
|
|
|
['node -v', 'v' + nodeV],
|
|
|
|
['npm config get registry', registry],
|
|
|
|
['which git', whichGit],
|
|
|
|
['Perms check on cached files', readbleCaches],
|
|
|
|
['Perms check on global node_modules', executableGlobalModules],
|
|
|
|
['Perms check on local node_modules', executableLocalModules],
|
2017-05-09 23:46:02 +02:00
|
|
|
['Verify cache contents', cacheStatus]
|
2017-01-13 01:58:10 +01:00
|
|
|
]
|
|
|
|
|
2017-05-09 23:46:02 +02:00
|
|
|
if (p[0] !== 200) list[0][2] = 'Check your internet connection'
|
2017-01-13 01:58:10 +01:00
|
|
|
if (!semver.satisfies(npmV, '>=' + npmLTS)) list[1][2] = 'Use npm v' + npmLTS
|
|
|
|
if (!semver.satisfies(nodeV, '>=' + nodeLTS)) list[2][2] = 'Use node v' + nodeLTS
|
2017-02-15 00:12:22 +01:00
|
|
|
if (registry !== defaultRegistry) list[3][2] = 'Try `npm config set registry ' + defaultRegistry + '`'
|
2017-01-13 01:58:10 +01:00
|
|
|
if (whichGit === 'not installed') list[4][2] = 'Install git and ensure it\'s in your PATH.'
|
|
|
|
if (readbleCaches !== 'ok') list[5][2] = 'Check the permissions of your files in ' + npm.config.get('cache')
|
|
|
|
if (executableGlobalModules !== 'ok') list[6][2] = globalNodeModules + ' must be readable and writable by the current user.'
|
|
|
|
if (executableLocalModules !== 'ok') list[7][2] = localNodeModules + ' must be readable and writable by the current user.'
|
|
|
|
|
|
|
|
return list
|
|
|
|
}
|