mirror of https://github.com/lukechilds/node.git
Browse Source
PR-URL: https://github.com/nodejs/node/pull/10781 Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>v7.x
Rebecca Turner
8 years ago
committed by
Italo A. Casas
347 changed files with 4716 additions and 6785 deletions
@ -0,0 +1,102 @@ |
|||
npm-doctor(1) -- Check your environments |
|||
======================================================== |
|||
|
|||
## SYNOPSIS |
|||
|
|||
npm doctor |
|||
|
|||
## DESCRIPTION |
|||
|
|||
`npm doctor` runs a set of checks to ensure that your npm installation has |
|||
what it needs to manage your JavaScript packages. npm is mostly a standalone tool, but it does |
|||
have some basic requirements that must be met: |
|||
|
|||
+ Node.js and git must be executable by npm. |
|||
+ The primary npm registry, `registry.npmjs.com`, or another service that uses |
|||
the registry API, is available. |
|||
+ The directories that npm uses, `node_modules` (both locally and globally), |
|||
exist and can be written by the current user. |
|||
+ The npm cache exists, and the package tarballs within it aren't corrupt. |
|||
|
|||
Without all of these working properly, npm may not work properly. Many issues |
|||
are often attributable to things that are outside npm's code base, so `npm |
|||
doctor` confirms that the npm installation is in a good state. |
|||
|
|||
Also, in addition to this, there are also very many issue reports due to using |
|||
old versions of npm. Since npm is constantly improving, running `npm@latest` is |
|||
better than an old version. |
|||
|
|||
`npm doctor` verifies the following items in your environment, and if there are |
|||
any recommended changes, it will display them. |
|||
|
|||
### `npm ping` |
|||
|
|||
By default, npm installs from the primary npm registry, `registry.npmjs.org`. |
|||
`npm doctor` hits a special ping endpoint within the registry. This can also be |
|||
checked with `npm ping`. If this check fails, you may be using a proxy that |
|||
needs to be configured, or may need to talk to your IT staff to get access over |
|||
HTTPS to `registry.npmjs.org`. |
|||
|
|||
This check is done against whichever registry you've configured (you can see |
|||
what that is by running `npm config get registry`), and if you're using a |
|||
private registry that doesn't support the `/whoami` endpoint supported by the |
|||
primary registry, this check may fail. |
|||
|
|||
### `npm -v` |
|||
|
|||
While Node.js may come bundled with a particular version of npm, it's the |
|||
policy of the CLI team that we recommend all users run `npm@latest` if they |
|||
can. As the CLI is maintained by a small team of contributors, there are only |
|||
resources for a single line of development, so npm's own long-term support |
|||
releases typically only receive critical security and regression fixes. The |
|||
team believes that the latest tested version of npm is almost always likely to |
|||
be the most functional and defect-free version of npm. |
|||
|
|||
### `node -v` |
|||
|
|||
For most users, in most circumstances, the best version of Node will be the |
|||
latest long-term support (LTS) release. Those of you who want access to new |
|||
ECMAscript features or bleeding-edge changes to Node's standard library may be |
|||
running a newer version, and some of you may be required to run an older |
|||
version of Node because of enterprise change control policies. That's OK! But |
|||
in general, the npm team recommends that most users run Node.js LTS. |
|||
|
|||
### `npm config get registry` |
|||
|
|||
Some of you may be installing from private package registries for your project |
|||
or company. That's great! Others of you may be following tutorials or |
|||
StackOverflow questions in an effort to troubleshoot problems you may be |
|||
having. Sometimes, this may entail changing the registry you're pointing at. |
|||
This part of `npm doctor` just lets you, and maybe whoever's helping you with |
|||
support, know that you're not using the default registry. |
|||
|
|||
### `which git` |
|||
|
|||
While it's documented in the README, it may not be obvious that npm needs Git |
|||
installed to do many of the things that it does. Also, in some cases |
|||
– especially on Windows – you may have Git set up in such a way that it's not |
|||
accessible via your `PATH` so that npm can find it. This check ensures that Git |
|||
is available. |
|||
|
|||
### Permissions checks |
|||
|
|||
* Your cache must be readable and writable by the user running npm. |
|||
* Global package binaries must be writable by the user running npm. |
|||
* Your local `node_modules` path, if you're running `npm doctor` with a project |
|||
directory, must be readable and writable by the user running npm. |
|||
|
|||
### Validate the checksums of cached packages |
|||
|
|||
When an npm package is published, the publishing process generates a checksum |
|||
that npm uses at install time to verify that the package didn't get corrupted |
|||
in transit. `npm doctor` uses these checksums to validate the package tarballs |
|||
in your local cache (you can see where that cache is located with `npm config |
|||
get cache`, and see what's in that cache with `npm cache ls` – probably more |
|||
than you were expecting!). In the event that there are corrupt packages in your |
|||
cache, you should probably run `npm cache clean` and reset the cache. |
|||
|
|||
## SEE ALSO |
|||
|
|||
* npm-bugs(1) |
|||
* npm-help(1) |
|||
* npm-ping(1) |
@ -0,0 +1,106 @@ |
|||
<!doctype html> |
|||
<html> |
|||
<title>npm-doctor</title> |
|||
<meta charset="utf-8"> |
|||
<link rel="stylesheet" type="text/css" href="../../static/style.css"> |
|||
<link rel="canonical" href="https://www.npmjs.org/doc/cli/npm-doctor.html"> |
|||
<script async=true src="../../static/toc.js"></script> |
|||
|
|||
<body> |
|||
<div id="wrapper"> |
|||
|
|||
<h1><a href="../cli/npm-doctor.html">npm-doctor</a></h1> <p>Check your environments</p> |
|||
<h2 id="synopsis">SYNOPSIS</h2> |
|||
<pre><code>npm doctor |
|||
</code></pre><h2 id="description">DESCRIPTION</h2> |
|||
<p><code>npm doctor</code> runs a set of checks to ensure that your npm installation has |
|||
what it needs to manage your JavaScript packages. npm is mostly a standalone tool, but it does |
|||
have some basic requirements that must be met:</p> |
|||
<ul> |
|||
<li>Node.js and git must be executable by npm.</li> |
|||
<li>The primary npm registry, <code>registry.npmjs.com</code>, or another service that uses |
|||
the registry API, is available.</li> |
|||
<li>The directories that npm uses, <code>node_modules</code> (both locally and globally), |
|||
exist and can be written by the current user.</li> |
|||
<li>The npm cache exists, and the package tarballs within it aren't corrupt.</li> |
|||
</ul> |
|||
<p>Without all of these working properly, npm may not work properly. Many issues |
|||
are often attributable to things that are outside npm's code base, so <code>npm |
|||
doctor</code> confirms that the npm installation is in a good state.</p> |
|||
<p>Also, in addition to this, there are also very many issue reports due to using |
|||
old versions of npm. Since npm is constantly improving, running <code>npm@latest</code> is |
|||
better than an old version.</p> |
|||
<p><code>npm doctor</code> verifies the following items in your environment, and if there are |
|||
any recommended changes, it will display them.</p> |
|||
<h3 id="-npm-ping-"><code>npm ping</code></h3> |
|||
<p>By default, npm installs from the primary npm registry, <code>registry.npmjs.org</code>. |
|||
<code>npm doctor</code> hits a special ping endpoint within the registry. This can also be |
|||
checked with <code>npm ping</code>. If this check fails, you may be using a proxy that |
|||
needs to be configured, or may need to talk to your IT staff to get access over |
|||
HTTPS to <code>registry.npmjs.org</code>.</p> |
|||
<p>This check is done against whichever registry you've configured (you can see |
|||
what that is by running <code>npm config get registry</code>), and if you're using a |
|||
private registry that doesn't support the <code>/whoami</code> endpoint supported by the |
|||
primary registry, this check may fail.</p> |
|||
<h3 id="-npm-v-"><code>npm -v</code></h3> |
|||
<p>While Node.js may come bundled with a particular version of npm, it's the |
|||
policy of the CLI team that we recommend all users run <code>npm@latest</code> if they |
|||
can. As the CLI is maintained by a small team of contributors, there are only |
|||
resources for a single line of development, so npm's own long-term support |
|||
releases typically only receive critical security and regression fixes. The |
|||
team believes that the latest tested version of npm is almost always likely to |
|||
be the most functional and defect-free version of npm.</p> |
|||
<h3 id="-node-v-"><code>node -v</code></h3> |
|||
<p>For most users, in most circumstances, the best version of Node will be the |
|||
latest long-term support (LTS) release. Those of you who want access to new |
|||
ECMAscript features or bleeding-edge changes to Node's standard library may be |
|||
running a newer version, and some of you may be required to run an older |
|||
version of Node because of enterprise change control policies. That's OK! But |
|||
in general, the npm team recommends that most users run Node.js LTS.</p> |
|||
<h3 id="-npm-config-get-registry-"><code>npm config get registry</code></h3> |
|||
<p>Some of you may be installing from private package registries for your project |
|||
or company. That's great! Others of you may be following tutorials or |
|||
StackOverflow questions in an effort to troubleshoot problems you may be |
|||
having. Sometimes, this may entail changing the registry you're pointing at. |
|||
This part of <code>npm doctor</code> just lets you, and maybe whoever's helping you with |
|||
support, know that you're not using the default registry.</p> |
|||
<h3 id="-which-git-"><code>which git</code></h3> |
|||
<p>While it's documented in the <a href="../../doc/README.html">README</a>, it may not be obvious that npm needs Git |
|||
installed to do many of the things that it does. Also, in some cases |
|||
– especially on Windows – you may have Git set up in such a way that it's not |
|||
accessible via your <code>PATH</code> so that npm can find it. This check ensures that Git |
|||
is available.</p> |
|||
<h3 id="permissions-checks">Permissions checks</h3> |
|||
<ul> |
|||
<li>Your cache must be readable and writable by the user running npm.</li> |
|||
<li>Global package binaries must be writable by the user running npm.</li> |
|||
<li>Your local <code>node_modules</code> path, if you're running <code>npm doctor</code> with a project |
|||
directory, must be readable and writable by the user running npm.</li> |
|||
</ul> |
|||
<h3 id="validate-the-checksums-of-cached-packages">Validate the checksums of cached packages</h3> |
|||
<p>When an npm package is published, the publishing process generates a checksum |
|||
that npm uses at install time to verify that the package didn't get corrupted |
|||
in transit. <code>npm doctor</code> uses these checksums to validate the package tarballs |
|||
in your local cache (you can see where that cache is located with <code>npm config |
|||
get cache</code>, and see what's in that cache with <code>npm cache ls</code> – probably more |
|||
than you were expecting!). In the event that there are corrupt packages in your |
|||
cache, you should probably run <code>npm cache clean</code> and reset the cache.</p> |
|||
<h2 id="see-also">SEE ALSO</h2> |
|||
<ul> |
|||
<li><a href="../cli/npm-bugs.html">npm-bugs(1)</a></li> |
|||
<li><a href="../cli/npm-help.html">npm-help(1)</a></li> |
|||
<li><a href="../cli/npm-ping.html">npm-ping(1)</a></li> |
|||
</ul> |
|||
|
|||
</div> |
|||
|
|||
<table border=0 cellspacing=0 cellpadding=0 id=npmlogo> |
|||
<tr><td style="width:180px;height:10px;background:rgb(237,127,127)" colspan=18> </td></tr> |
|||
<tr><td rowspan=4 style="width:10px;height:10px;background:rgb(237,127,127)"> </td><td style="width:40px;height:10px;background:#fff" colspan=4> </td><td style="width:10px;height:10px;background:rgb(237,127,127)" rowspan=4> </td><td style="width:40px;height:10px;background:#fff" colspan=4> </td><td rowspan=4 style="width:10px;height:10px;background:rgb(237,127,127)"> </td><td colspan=6 style="width:60px;height:10px;background:#fff"> </td><td style="width:10px;height:10px;background:rgb(237,127,127)" rowspan=4> </td></tr> |
|||
<tr><td colspan=2 style="width:20px;height:30px;background:#fff" rowspan=3> </td><td style="width:10px;height:10px;background:rgb(237,127,127)" rowspan=3> </td><td style="width:10px;height:10px;background:#fff" rowspan=3> </td><td style="width:20px;height:10px;background:#fff" rowspan=4 colspan=2> </td><td style="width:10px;height:20px;background:rgb(237,127,127)" rowspan=2> </td><td style="width:10px;height:10px;background:#fff" rowspan=3> </td><td style="width:20px;height:10px;background:#fff" rowspan=3 colspan=2> </td><td style="width:10px;height:10px;background:rgb(237,127,127)" rowspan=3> </td><td style="width:10px;height:10px;background:#fff" rowspan=3> </td><td style="width:10px;height:10px;background:rgb(237,127,127)" rowspan=3> </td></tr> |
|||
<tr><td style="width:10px;height:10px;background:#fff" rowspan=2> </td></tr> |
|||
<tr><td style="width:10px;height:10px;background:#fff"> </td></tr> |
|||
<tr><td style="width:60px;height:10px;background:rgb(237,127,127)" colspan=6> </td><td colspan=10 style="width:10px;height:10px;background:rgb(237,127,127)"> </td></tr> |
|||
<tr><td colspan=5 style="width:50px;height:10px;background:#fff"> </td><td style="width:40px;height:10px;background:rgb(237,127,127)" colspan=4> </td><td style="width:90px;height:10px;background:#fff" colspan=9> </td></tr> |
|||
</table> |
|||
<p id="footer">npm-doctor — npm@4.1.1</p> |
@ -0,0 +1,109 @@ |
|||
var path = require('path') |
|||
var chain = require('slide').chain |
|||
var table = require('text-table') |
|||
var color = require('ansicolors') |
|||
var styles = require('ansistyles') |
|||
var semver = require('semver') |
|||
var npm = require('./npm.js') |
|||
var log = require('npmlog') |
|||
var ansiTrim = require('./utils/ansi-trim.js') |
|||
var output = require('./utils/output.js') |
|||
var defaultRegistry = require('./config/defaults.js').defaults.registry |
|||
var checkPing = require('./doctor/check-ping.js') |
|||
var getGitPath = require('./doctor/get-git-path.js') |
|||
var checksumCachedFiles = require('./doctor/checksum-cached-files.js') |
|||
var checkFilesPermission = require('./doctor/check-files-permission.js') |
|||
var getLatestNodejsVersion = require('./doctor/get-latest-nodejs-version.js') |
|||
var getLatestNpmVersion = require('./doctor/get-latest-npm-version') |
|||
var globalNodeModules = path.join(npm.config.globalPrefix, 'lib', 'node_modules') |
|||
var localNodeModules = path.join(npm.config.localPrefix, 'node_modules') |
|||
|
|||
module.exports = doctor |
|||
|
|||
doctor.usage = 'npm doctor' |
|||
|
|||
function doctor (args, silent, cb) { |
|||
args = args || {} |
|||
if (typeof cb !== 'function') { |
|||
cb = silent |
|||
silent = false |
|||
} |
|||
|
|||
var actionsToRun = [ |
|||
[checkPing], |
|||
[getLatestNpmVersion], |
|||
[getLatestNodejsVersion, args['node-url']], |
|||
[getGitPath], |
|||
[checkFilesPermission, npm.cache, 6], |
|||
[checkFilesPermission, globalNodeModules, 4], |
|||
[checkFilesPermission, localNodeModules, 6], |
|||
[checksumCachedFiles] |
|||
] |
|||
|
|||
log.info('doctor', 'Running checkup') |
|||
chain(actionsToRun, function (stderr, stdout) { |
|||
if (stderr && stderr.message !== 'not found: git') return cb(stderr) |
|||
var outHead = ['Check', 'Value', 'Recommendation'] |
|||
var list = makePretty(stdout) |
|||
var outBody = list |
|||
|
|||
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 |
|||
}) |
|||
} |
|||
|
|||
var outTable = [outHead].concat(outBody) |
|||
var tableOpts = { |
|||
stringLength: function (s) { return ansiTrim(s).length } |
|||
} |
|||
|
|||
if (!silent) output(table(outTable, tableOpts)) |
|||
|
|||
cb(null, list) |
|||
}) |
|||
} |
|||
|
|||
function makePretty (p) { |
|||
var ping = p[0] ? 'ok' : 'notOk' |
|||
var npmLTS = p[1] |
|||
var nodeLTS = p[2].replace('v', '') |
|||
var whichGit = p[3] || 'not installed' |
|||
var readbleCaches = p[4] ? 'ok' : 'notOk' |
|||
var executableGlobalModules = p[5] ? 'ok' : 'notOk' |
|||
var executableLocalModules = p[6] ? 'ok' : 'notOk' |
|||
var checksumCachedFiles = p[7] ? 'ok' : 'notOk' |
|||
var npmV = npm.version |
|||
var nodeV = process.version.replace('v', '') |
|||
var registry = npm.config.get('registry') |
|||
var list = [ |
|||
['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], |
|||
['Checksum cached files', checksumCachedFiles] |
|||
] |
|||
|
|||
if (ping !== 'ok') list[0][2] = 'Check your internet connection' |
|||
if (!semver.satisfies(npmV, '>=' + npmLTS)) list[1][2] = 'Use npm v' + npmLTS |
|||
if (!semver.satisfies(nodeV, '>=' + nodeLTS)) list[2][2] = 'Use node v' + nodeLTS |
|||
if (registry !== defaultRegistry) list[3][2] = 'Try `npm config set registry ' + defaultRegistry |
|||
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.' |
|||
if (checksumCachedFiles !== 'ok') list[8][2] = 'You have some broken packages in your cache.' |
|||
|
|||
return list |
|||
} |
@ -0,0 +1,55 @@ |
|||
var fs = require('fs') |
|||
var path = require('path') |
|||
var getUid = require('uid-number') |
|||
var chain = require('slide').chain |
|||
var log = require('npmlog') |
|||
var npm = require('../npm.js') |
|||
var fileCompletion = require('../utils/completion/file-completion.js') |
|||
|
|||
function checkFilesPermission (root, mask, cb) { |
|||
if (process.platform === 'win32') return cb(null, true) |
|||
getUid(npm.config.get('user'), npm.config.get('group'), function (e, uid, gid) { |
|||
if (e) { |
|||
tracker.finish() |
|||
tracker.warn('checkFilePermissions', 'Error looking up user and group:', e) |
|||
return cb(e) |
|||
} |
|||
var tracker = log.newItem('checkFilePermissions', 1) |
|||
tracker.info('checkFilePermissions', 'Building file list of ' + root) |
|||
fileCompletion(root, '.', Infinity, function (e, files) { |
|||
if (e) { |
|||
tracker.warn('checkFilePermissions', 'Error building file list:', e) |
|||
tracker.finish() |
|||
return cb(e) |
|||
} |
|||
tracker.addWork(files.length) |
|||
tracker.completeWork(1) |
|||
chain(files.map(andCheckFile), function (er) { |
|||
tracker.finish() |
|||
cb(null, !er) |
|||
}) |
|||
function andCheckFile (f) { |
|||
return [checkFile, f] |
|||
} |
|||
function checkFile (f, next) { |
|||
var file = path.join(root, f) |
|||
tracker.silly('checkFilePermissions', f) |
|||
fs.stat(file, function (e, stat) { |
|||
tracker.completeWork(1) |
|||
if (e) return next(e) |
|||
if (!stat.isFile()) return next() |
|||
var mode = stat.mode |
|||
var isGroup = stat.gid ? stat.gid === gid : true |
|||
var isUser = stat.uid ? stat.uid === uid : true |
|||
if ((mode & parseInt('000' + mask, 8))) return next() |
|||
if ((isGroup && mode & parseInt('00' + mask + '0', 8))) return next() |
|||
if ((isUser && mode & parseInt('0' + mask + '00', 8))) return next() |
|||
tracker.error('checkFilePermissions', 'Missing permissions on (' + isGroup + ', ' + isUser + ', ' + mode + ')', file) |
|||
return next(new Error('Missing permissions for ' + file)) |
|||
}) |
|||
} |
|||
}) |
|||
}) |
|||
} |
|||
|
|||
module.exports = checkFilesPermission |
@ -0,0 +1,13 @@ |
|||
var log = require('npmlog') |
|||
var ping = require('../ping.js') |
|||
|
|||
function checkPing (cb) { |
|||
var tracker = log.newItem('checkPing', 1) |
|||
tracker.info('checkPing', 'Pinging registry') |
|||
ping({}, true, function (err, pong) { |
|||
tracker.finish() |
|||
cb(err, pong) |
|||
}) |
|||
} |
|||
|
|||
module.exports = checkPing |
@ -0,0 +1,62 @@ |
|||
var crypto = require('crypto') |
|||
var fs = require('fs') |
|||
var path = require('path') |
|||
var chain = require('slide').chain |
|||
var log = require('npmlog') |
|||
var npm = require('../npm') |
|||
var fileCompletion = require('../utils/completion/file-completion.js') |
|||
|
|||
function checksum (str) { |
|||
return crypto |
|||
.createHash('sha1') |
|||
.update(str, 'utf8') |
|||
.digest('hex') |
|||
} |
|||
|
|||
function checksumCachedFiles (cb) { |
|||
var tracker = log.newItem('checksumCachedFiles', 1) |
|||
tracker.info('checksumCachedFiles', 'Building file list of ' + npm.cache) |
|||
fileCompletion(npm.cache, '.', Infinity, function (e, files) { |
|||
if (e) { |
|||
tracker.finish() |
|||
return cb(e) |
|||
} |
|||
tracker.addWork(files.length) |
|||
tracker.completeWork(1) |
|||
chain(files.map(andChecksumFile), function (er) { |
|||
tracker.finish() |
|||
cb(null, !er) |
|||
}) |
|||
function andChecksumFile (f) { |
|||
return [function (next) { process.nextTick(function () { checksumFile(f, next) }) }] |
|||
} |
|||
function checksumFile (f, next) { |
|||
var file = path.join(npm.cache, f) |
|||
tracker.silly('checksumFile', f) |
|||
if (!/.tgz$/.test(file)) { |
|||
tracker.completeWork(1) |
|||
return next() |
|||
} |
|||
fs.readFile(file, function (err, tgz) { |
|||
tracker.completeWork(1) |
|||
if (err) return next(err) |
|||
try { |
|||
var pkgJSON = fs.readFileSync(path.join(path.dirname(file), 'package/package.json')) |
|||
} catch (e) { |
|||
return next() // no package.json in cche is ok
|
|||
} |
|||
try { |
|||
var pkg = JSON.parse(pkgJSON) |
|||
var shasum = (pkg.dist && pkg.dist.shasum) || pkg._shasum |
|||
var actual = checksum(tgz) |
|||
if (actual !== shasum) return next(new Error('Checksum mismatch on ' + file + ', expected: ' + shasum + ', got: ' + shasum)) |
|||
return next() |
|||
} catch (e) { |
|||
return next(new Error('Error parsing JSON in ' + file + ': ' + e)) |
|||
} |
|||
}) |
|||
} |
|||
}) |
|||
} |
|||
|
|||
module.exports = checksumCachedFiles |
@ -0,0 +1,13 @@ |
|||
var log = require('npmlog') |
|||
var which = require('which') |
|||
|
|||
function getGitPath (cb) { |
|||
var tracker = log.newItem('getGitPath', 1) |
|||
tracker.info('getGitPath', 'Finding git in your PATH') |
|||
which('git', function (err, path) { |
|||
tracker.finish() |
|||
cb(err, path) |
|||
}) |
|||
} |
|||
|
|||
module.exports = getGitPath |
@ -0,0 +1,26 @@ |
|||
var log = require('npmlog') |
|||
var request = require('request') |
|||
|
|||
function getLatestNodejsVersion (url, cb) { |
|||
var tracker = log.newItem('getLatestNodejsVersion', 1) |
|||
tracker.info('getLatestNodejsVersion', 'Getting Node.js release information') |
|||
var version = '' |
|||
url = url || 'https://nodejs.org/dist/index.json' |
|||
request(url, function (e, res, index) { |
|||
tracker.finish() |
|||
if (e) return cb(e) |
|||
if (res.statusCode !== 200) { |
|||
return cb(new Error('Status not 200, ' + res.statusCode)) |
|||
} |
|||
try { |
|||
JSON.parse(index).forEach(function (item) { |
|||
if (item.lts && item.version > version) version = item.version |
|||
}) |
|||
cb(null, version) |
|||
} catch (e) { |
|||
cb(e) |
|||
} |
|||
}) |
|||
} |
|||
|
|||
module.exports = getLatestNodejsVersion |
@ -0,0 +1,13 @@ |
|||
var log = require('npmlog') |
|||
var fetchPackageMetadata = require('../fetch-package-metadata') |
|||
|
|||
function getLatestNpmVersion (cb) { |
|||
var tracker = log.newItem('getLatestNpmVersion', 1) |
|||
tracker.info('getLatestNpmVersion', 'Getting npm package information') |
|||
fetchPackageMetadata('npm@latest', '.', function (e, d) { |
|||
tracker.finish() |
|||
cb(e, d.version) |
|||
}) |
|||
} |
|||
|
|||
module.exports = getLatestNpmVersion |
@ -1,54 +1,66 @@ |
|||
// prune extraneous packages.
|
|||
|
|||
module.exports = prune |
|||
module.exports.Pruner = Pruner |
|||
|
|||
prune.usage = 'npm prune [[<@scope>/]<pkg>...] [--production]' |
|||
|
|||
var readInstalled = require('read-installed') |
|||
var npm = require('./npm.js') |
|||
var path = require('path') |
|||
var readJson = require('read-package-json') |
|||
var log = require('npmlog') |
|||
var util = require('util') |
|||
var moduleName = require('./utils/module-name.js') |
|||
var Installer = require('./install.js').Installer |
|||
var isExtraneous = require('./install/is-extraneous.js') |
|||
var isDev = require('./install/is-dev-dep.js') |
|||
var removeDeps = require('./install/deps.js').removeDeps |
|||
var loadExtraneous = require('./install/deps.js').loadExtraneous |
|||
var chain = require('slide').chain |
|||
|
|||
prune.completion = require('./utils/completion/installed-deep.js') |
|||
|
|||
function prune (args, cb) { |
|||
// check if is a valid package.json file
|
|||
var jsonFile = path.resolve(npm.dir, '..', 'package.json') |
|||
readJson(jsonFile, log.warn, function (er) { |
|||
if (er) return cb(er) |
|||
next() |
|||
}) |
|||
|
|||
function next () { |
|||
var opt = { |
|||
depth: npm.config.get('depth'), |
|||
dev: !npm.config.get('production') || npm.config.get('dev') |
|||
} |
|||
readInstalled(npm.prefix, opt, function (er, data) { |
|||
if (er) return cb(er) |
|||
prune_(args, data, cb) |
|||
}) |
|||
} |
|||
var dryrun = !!npm.config.get('dry-run') |
|||
new Pruner('.', dryrun, args).run(cb) |
|||
} |
|||
|
|||
function prune_ (args, data, cb) { |
|||
npm.commands.unbuild(prunables(args, data, []), cb) |
|||
function Pruner (where, dryrun, args) { |
|||
Installer.call(this, where, dryrun, args) |
|||
} |
|||
util.inherits(Pruner, Installer) |
|||
|
|||
Pruner.prototype.loadAllDepsIntoIdealTree = function (cb) { |
|||
log.silly('uninstall', 'loadAllDepsIntoIdealtree') |
|||
|
|||
var cg = this.progress.loadAllDepsIntoIdealTree |
|||
var steps = [] |
|||
|
|||
function prunables (args, data, seen) { |
|||
var deps = data.dependencies || {} |
|||
return Object.keys(deps).map(function (d) { |
|||
if (typeof deps[d] !== 'object' || seen.indexOf(deps[d]) !== -1) return null |
|||
seen.push(deps[d]) |
|||
if (deps[d].extraneous && (args.length === 0 || args.indexOf(d) !== -1)) { |
|||
var extra = deps[d] |
|||
delete deps[d] |
|||
return extra.path |
|||
} |
|||
return prunables(args, deps[d], seen) |
|||
}).filter(function (d) { return d !== null }) |
|||
.reduce(function FLAT (l, r) { |
|||
return l.concat(Array.isArray(r) ? r.reduce(FLAT, []) : r) |
|||
}, []) |
|||
var self = this |
|||
var excludeDev = npm.config.get('production') || /^prod(uction)?$/.test(npm.config.get('only')) |
|||
function shouldPrune (child) { |
|||
if (isExtraneous(child)) return true |
|||
if (!excludeDev) return false |
|||
var childName = moduleName(child) |
|||
var isChildDev = function (parent) { return isDev(parent, childName) } |
|||
if (child.requiredBy.every(isChildDev)) return true |
|||
} |
|||
function getModuleName (child) { |
|||
// wrapping because moduleName doesn't like extra args and we're called
|
|||
// from map.
|
|||
return moduleName(child) |
|||
} |
|||
function matchesArg (name) { |
|||
return self.args.length === 0 || self.args.indexOf(name) !== -1 |
|||
} |
|||
function nameObj (name) { |
|||
return {name: name} |
|||
} |
|||
var toPrune = this.currentTree.children.filter(shouldPrune).map(getModuleName).filter(matchesArg).map(nameObj) |
|||
|
|||
steps.push( |
|||
[removeDeps, toPrune, this.idealTree, null, cg.newGroup('removeDeps')], |
|||
[loadExtraneous, this.idealTree, cg.newGroup('loadExtraneous')]) |
|||
chain(steps, cb) |
|||
} |
|||
|
|||
Pruner.prototype.runPreinstallTopLevelLifecycles = function (cb) { cb() } |
|||
Pruner.prototype.runPostinstallTopLevelLifecycles = function (cb) { cb() } |
|||
|
@ -0,0 +1,7 @@ |
|||
function ansiTrim (str) { |
|||
var r = new RegExp('\x1b(?:\\[(?:\\d+[ABCDEFGJKSTm]|\\d+;\\d+[Hfm]|' + |
|||
'\\d+;\\d+;\\d+m|6n|s|u|\\?25[lh])|\\w)', 'g') |
|||
return str.replace(r, '') |
|||
} |
|||
|
|||
module.exports = ansiTrim |
@ -0,0 +1,39 @@ |
|||
'use strict' |
|||
module.exports = launchSendMetrics |
|||
var fs = require('graceful-fs') |
|||
var child_process = require('child_process') |
|||
|
|||
if (require.main === module) main() |
|||
|
|||
function launchSendMetrics () { |
|||
var path = require('path') |
|||
var npm = require('../npm.js') |
|||
try { |
|||
if (!npm.config.get('send-metrics')) return |
|||
var cliMetrics = path.join(npm.config.get('cache'), 'anonymous-cli-metrics.json') |
|||
var targetRegistry = npm.config.get('metrics-registry') |
|||
fs.statSync(cliMetrics) |
|||
return runInBackground(__filename, [cliMetrics, targetRegistry]) |
|||
} catch (ex) { |
|||
// if the metrics file doesn't exist, don't run
|
|||
} |
|||
} |
|||
|
|||
function runInBackground (js, args, opts) { |
|||
if (!args) args = [] |
|||
args.unshift(js) |
|||
if (!opts) opts = {} |
|||
opts.stdio = 'ignore' |
|||
opts.detached = true |
|||
var child = child_process.spawn(process.execPath, args, opts) |
|||
child.unref() |
|||
return child |
|||
} |
|||
|
|||
function main () { |
|||
var sendMetrics = require('./metrics.js').send |
|||
var metricsFile = process.argv[2] |
|||
var metricsRegistry = process.argv[3] |
|||
|
|||
sendMetrics(metricsFile, metricsRegistry) |
|||
} |
@ -0,0 +1,73 @@ |
|||
'use strict' |
|||
exports.start = startMetrics |
|||
exports.stop = stopMetrics |
|||
exports.save = saveMetrics |
|||
exports.send = sendMetrics |
|||
|
|||
var fs = require('fs') |
|||
var path = require('path') |
|||
var npm = require('../npm.js') |
|||
var uuid = require('uuid') |
|||
|
|||
var inMetrics = false |
|||
|
|||
function startMetrics () { |
|||
if (inMetrics) return |
|||
// loaded on demand to avoid any recursive deps when `./metrics-launch` requires us.
|
|||
var metricsLaunch = require('./metrics-launch.js') |
|||
npm.metricsProcess = metricsLaunch() |
|||
} |
|||
|
|||
function stopMetrics () { |
|||
if (inMetrics) return |
|||
if (npm.metricsProcess) npm.metricsProcess.kill('SIGKILL') |
|||
} |
|||
|
|||
function saveMetrics (itWorked) { |
|||
if (inMetrics) return |
|||
// If the metrics reporter hasn't managed to PUT yet then kill it so that it doesn't
|
|||
// step on our updating the anonymous-cli-metrics json
|
|||
stopMetrics() |
|||
var metricsFile = path.join(npm.config.get('cache'), 'anonymous-cli-metrics.json') |
|||
var metrics |
|||
try { |
|||
metrics = JSON.parse(fs.readFileSync(metricsFile)) |
|||
metrics.metrics.to = new Date().toISOString() |
|||
if (itWorked) { |
|||
++metrics.metrics.successfulInstalls |
|||
} else { |
|||
++metrics.metrics.failedInstalls |
|||
} |
|||
} catch (ex) { |
|||
metrics = { |
|||
metricId: uuid.v4(), |
|||
metrics: { |
|||
from: new Date().toISOString(), |
|||
to: new Date().toISOString(), |
|||
successfulInstalls: itWorked ? 1 : 0, |
|||
failedInstalls: itWorked ? 0 : 1 |
|||
} |
|||
} |
|||
} |
|||
try { |
|||
fs.writeFileSync(metricsFile, JSON.stringify(metrics)) |
|||
} catch (ex) { |
|||
// we couldn't write the error metrics file, um, well, oh well.
|
|||
} |
|||
} |
|||
|
|||
function sendMetrics (metricsFile, metricsRegistry) { |
|||
inMetrics = true |
|||
var cliMetrics = JSON.parse(fs.readFileSync(metricsFile)) |
|||
npm.load({}, function (err) { |
|||
if (err) return |
|||
npm.registry.config.retry.retries = 0 |
|||
npm.registry.sendAnonymousCLIMetrics(metricsRegistry, cliMetrics, function (err) { |
|||
if (err) { |
|||
fs.writeFileSync(path.join(path.dirname(metricsFile), 'last-send-metrics-error.txt'), err.stack) |
|||
} else { |
|||
fs.unlinkSync(metricsFile) |
|||
} |
|||
}) |
|||
}) |
|||
} |
@ -0,0 +1,26 @@ |
|||
'use strict' |
|||
module.exports = pickManifestFromRegistryMetadata |
|||
|
|||
var log = require('npmlog') |
|||
var semver = require('semver') |
|||
|
|||
function pickManifestFromRegistryMetadata (spec, tag, versions, metadata) { |
|||
log.silly('pickManifestFromRegistryMetadata', 'spec', spec, 'tag', tag, 'versions', versions) |
|||
|
|||
// if the tagged version satisfies, then use that.
|
|||
var tagged = metadata['dist-tags'][tag] |
|||
if (tagged && |
|||
metadata.versions[tagged] && |
|||
semver.satisfies(tagged, spec, true)) { |
|||
return {resolvedTo: tag, manifest: metadata.versions[tagged]} |
|||
} |
|||
// find the max satisfying version.
|
|||
var ms = semver.maxSatisfying(versions, spec, true) |
|||
if (ms) { |
|||
return {resolvedTo: ms, manifest: metadata.versions[ms]} |
|||
} else if (spec === '*' && versions.length && tagged && metadata.versions[tagged]) { |
|||
return {resolvedTo: tag, manifest: metadata.versions[tagged]} |
|||
} else { |
|||
return |
|||
} |
|||
} |
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue