From 7fc21a0b378ba8724a8b370848fb7bfebdf1a051 Mon Sep 17 00:00:00 2001 From: Brian Olore Date: Sat, 25 Aug 2018 22:29:20 -0400 Subject: [PATCH 1/3] replace update-notifier --- bin/npm-cli.js | 67 ++++-------------------- lib/utils/version-checker-launch.js | 30 +++++++++++ lib/utils/version-checker.js | 81 +++++++++++++++++++++++++++++ package.json | 1 - 4 files changed, 122 insertions(+), 57 deletions(-) create mode 100644 lib/utils/version-checker-launch.js create mode 100644 lib/utils/version-checker.js diff --git a/bin/npm-cli.js b/bin/npm-cli.js index 6f76b23828531..57232d544919d 100755 --- a/bin/npm-cli.js +++ b/bin/npm-cli.js @@ -29,7 +29,7 @@ var npm = require('../lib/npm.js') var npmconf = require('../lib/config/core.js') var errorHandler = require('../lib/utils/error-handler.js') - + var versionChecker = require('../lib/utils/version-checker.js') var configDefs = npmconf.defs var shorthands = configDefs.shorthands var types = configDefs.types @@ -69,67 +69,13 @@ npm.command = 'help' } - var isGlobalNpmUpdate = conf.global && ['install', 'update'].includes(npm.command) && npm.argv.includes('npm') - // now actually fire up npm and run the command. // this is how to use npm programmatically: conf._exit = true npm.load(conf, function (er) { if (er) return errorHandler(er) - if ( - !isGlobalNpmUpdate && - npm.config.get('update-notifier') && - !unsupported.checkVersion(process.version).unsupported - ) { - const pkg = require('../package.json') - let notifier = require('update-notifier')({pkg}) - const isCI = require('ci-info').isCI - if ( - notifier.update && - notifier.update.latest !== pkg.version && - !isCI - ) { - const color = require('ansicolors') - const useColor = npm.config.get('color') - const useUnicode = npm.config.get('unicode') - const old = notifier.update.current - const latest = notifier.update.latest - let type = notifier.update.type - if (useColor) { - switch (type) { - case 'major': - type = color.red(type) - break - case 'minor': - type = color.yellow(type) - break - case 'patch': - type = color.green(type) - break - } - } - const changelog = `https://github.com/npm/cli/releases/tag/v${latest}` - notifier.notify({ - message: `New ${type} version of ${pkg.name} available! ${ - useColor ? color.red(old) : old - } ${useUnicode ? '→' : '->'} ${ - useColor ? color.green(latest) : latest - }\n` + - `${ - useColor ? color.yellow('Changelog:') : 'Changelog:' - } ${ - useColor ? color.cyan(changelog) : changelog - }\n` + - `Run ${ - useColor - ? color.green(`npm install -g ${pkg.name}`) - : `npm i -g ${pkg.name}` - } to update!` - }) - } - } npm.commands[npm.command](npm.argv, function (err) { - // https://genius.com/Lin-manuel-miranda-your-obedient-servant-lyrics + // https://genius.com/Lin-manuel-miranda-your-obedient-servant-lyrics if ( !err && npm.config.get('ham-it-up') && @@ -150,4 +96,13 @@ errorHandler.apply(this, arguments) }) }) + + var versionCheckerMessages = [] + versionChecker.check() + .stdout.on('data', function (data) { + versionCheckerMessages.push(data.toString()) + }) + process.on('exit', () => { + console.error(versionCheckerMessages.join('\n')) + }) })() diff --git a/lib/utils/version-checker-launch.js b/lib/utils/version-checker-launch.js new file mode 100644 index 0000000000000..8e1bf56c1be3e --- /dev/null +++ b/lib/utils/version-checker-launch.js @@ -0,0 +1,30 @@ +'use strict' +/* eslint-disable camelcase */ +const child_process = require('child_process') + +module.exports = launchCheck + +if (require.main === module) main() + +function launchCheck () { + try { + return runInBackground(__filename, []) + } catch (ex) { + // ignore failures + } +} + +function runInBackground (js, args, opts) { + if (!args) args = [] + args.unshift(js) + if (!opts) opts = {} + opts.detached = true + var child = child_process.spawn(process.execPath, args, opts) + child.unref() + return child +} + +function main () { + var check = require('./version-checker').doCheck + check() +} diff --git a/lib/utils/version-checker.js b/lib/utils/version-checker.js new file mode 100644 index 0000000000000..77db84b55e48b --- /dev/null +++ b/lib/utils/version-checker.js @@ -0,0 +1,81 @@ +const log = require('npmlog') +const pacote = require('pacote') +const semver = require('semver') +var npmconf = require('../config/core.js') +var configDefs = npmconf.defs +const shorthands = configDefs.shorthands +const types = configDefs.types +const nopt = require('nopt') +let npm = require('../npm.js') + +const pacoteOpts = require('../config/pacote') +const unsupported = require('./unsupported.js') + +exports.check = function () { + var checkerLaunch = require('./version-checker-launch') + return checkerLaunch() +} + +exports.doCheck = function () { + const conf = nopt(types, shorthands) + npm.argv = conf.argv.remain + const isGlobalNpmUpdate = conf.global && ['install', 'update'].includes(npm.command) && npm.argv.includes('npm') + const isCI = require('ci-info').isCI + + npm.load(conf, function (err) { + if (err) return + if ( + npm.config.get('update-notifier') && + !isGlobalNpmUpdate && + !unsupported.checkVersion(process.version).unsupported && + !isCI + ) { + pacote.manifest('npm@latest', pacoteOpts()) + .then((latest) => { + const oldVersion = require('../../package.json').version + let diffType = semver.diff(oldVersion, latest.version) + if (diffType) { + console.log(generateMessage(oldVersion, latest.version, diffType, npm)) + } else { + log.silly('version-check', 'we are running the latest version of npm') + } + }) + } + }) +} + +function generateMessage (oldVersion, latestVersion, diffType, npm) { + const color = require('ansicolors') + const useColor = npm.config.get('color') + const useUnicode = npm.config.get('unicode') + if (useColor) { + switch (diffType) { + case 'major': + diffType = color.red(diffType) + break + case 'minor': + diffType = color.yellow(diffType) + break + case 'patch': + diffType = color.green(diffType) + break + } + } + const changelog = `https://github.com/npm/cli/releases/tag/v${latestVersion}` + + return `New ${diffType} version of npm available! ${ + useColor ? color.red(oldVersion) : oldVersion + } ${useUnicode ? '→' : '->'} ${ + useColor ? color.green(latestVersion) : latestVersion + }\n` + + `${ + useColor ? color.yellow('Changelog:') : 'Changelog:' + } ${ + useColor ? color.cyan(changelog) : changelog + }\n` + + `Run ${ + useColor + ? color.green(`npm install -g npm`) + : `npm i -g npm` + } to update!` +} diff --git a/package.json b/package.json index 35f4e956169ff..404f5e2f5751d 100644 --- a/package.json +++ b/package.json @@ -135,7 +135,6 @@ "umask": "~1.1.0", "unique-filename": "~1.1.0", "unpipe": "~1.0.0", - "update-notifier": "^2.5.0", "uuid": "^3.3.2", "validate-npm-package-license": "^3.0.4", "validate-npm-package-name": "~3.0.0", From c583ba77cbf3faa9480df0e65f7e585fd72b65b3 Mon Sep 17 00:00:00 2001 From: Brian Olore Date: Tue, 28 Aug 2018 22:25:03 -0400 Subject: [PATCH 2/3] add boxen to version-checker output --- bin/npm-cli.js | 18 +++++++++++------- lib/utils/version-checker.js | 12 +++++++++++- node_modules/boxen/package.json | 16 +++++++++------- package.json | 3 ++- 4 files changed, 33 insertions(+), 16 deletions(-) diff --git a/bin/npm-cli.js b/bin/npm-cli.js index 57232d544919d..5819f0f8e21f3 100755 --- a/bin/npm-cli.js +++ b/bin/npm-cli.js @@ -97,12 +97,16 @@ }) }) - var versionCheckerMessages = [] - versionChecker.check() - .stdout.on('data', function (data) { - versionCheckerMessages.push(data.toString()) + if (process.stdout.isTTY) { + var versionCheckerMessages = [] + versionChecker.check() + .stdout.on('data', function (data) { + versionCheckerMessages.push(data.toString()) + }) + process.on('exit', () => { + if (versionCheckerMessages.length > 0) { + console.error(versionCheckerMessages.join('\n')) + } }) - process.on('exit', () => { - console.error(versionCheckerMessages.join('\n')) - }) + } })() diff --git a/lib/utils/version-checker.js b/lib/utils/version-checker.js index 77db84b55e48b..39392fbf8e8a6 100644 --- a/lib/utils/version-checker.js +++ b/lib/utils/version-checker.js @@ -1,3 +1,4 @@ +const boxen = require('boxen') const log = require('npmlog') const pacote = require('pacote') const semver = require('semver') @@ -63,7 +64,7 @@ function generateMessage (oldVersion, latestVersion, diffType, npm) { } const changelog = `https://github.com/npm/cli/releases/tag/v${latestVersion}` - return `New ${diffType} version of npm available! ${ + let message = `New ${diffType} version of npm available! ${ useColor ? color.red(oldVersion) : oldVersion } ${useUnicode ? '→' : '->'} ${ useColor ? color.green(latestVersion) : latestVersion @@ -78,4 +79,13 @@ function generateMessage (oldVersion, latestVersion, diffType, npm) { ? color.green(`npm install -g npm`) : `npm i -g npm` } to update!` + + const boxenOptions = { + padding: 1, + margin: 1, + align: 'center', + borderColor: 'yellow', + borderStyle: 'round' + } + return boxen(message, boxenOptions) } diff --git a/node_modules/boxen/package.json b/node_modules/boxen/package.json index 51cca1d2110ef..85809ed3e81e4 100644 --- a/node_modules/boxen/package.json +++ b/node_modules/boxen/package.json @@ -1,27 +1,29 @@ { - "_from": "boxen@^1.2.1", + "_from": "boxen", "_id": "boxen@1.3.0", "_inBundle": false, "_integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", "_location": "/boxen", "_phantomChildren": {}, "_requested": { - "type": "range", + "type": "tag", "registry": true, - "raw": "boxen@^1.2.1", + "raw": "boxen", "name": "boxen", "escapedName": "boxen", - "rawSpec": "^1.2.1", + "rawSpec": "", "saveSpec": null, - "fetchSpec": "^1.2.1" + "fetchSpec": "latest" }, "_requiredBy": [ + "#USER", + "/", "/update-notifier" ], "_resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", "_shasum": "55c6c39a8ba58d9c61ad22cd877532deb665a20b", - "_spec": "boxen@^1.2.1", - "_where": "/Users/rebecca/code/npm/node_modules/update-notifier", + "_spec": "boxen", + "_where": "/Users/brian/dev/cli", "author": { "name": "Sindre Sorhus", "email": "sindresorhus@gmail.com", diff --git a/package.json b/package.json index 404f5e2f5751d..3916a8adc2dc2 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "archy": "~1.0.0", "bin-links": "^1.1.2", "bluebird": "^3.5.3", + "boxen": "^1.3.0", "byte-size": "^4.0.3", "cacache": "^11.2.0", "call-limit": "~1.1.0", @@ -152,6 +153,7 @@ "cacache", "call-limit", "bluebird", + "boxen", "bin-links", "chownr", "ci-info", @@ -247,7 +249,6 @@ "umask", "unique-filename", "unpipe", - "update-notifier", "uuid", "validate-npm-package-license", "validate-npm-package-name", From f6c6883e0718d0bda029ba70b2ba01c7c0dfa76f Mon Sep 17 00:00:00 2001 From: Brian Olore Date: Fri, 31 Aug 2018 20:35:19 -0400 Subject: [PATCH 3/3] version-checker: use cacache to only check for new versions once per 24 hours --- lib/utils/version-checker.js | 66 ++++++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/lib/utils/version-checker.js b/lib/utils/version-checker.js index 39392fbf8e8a6..9ae7a0e0875b0 100644 --- a/lib/utils/version-checker.js +++ b/lib/utils/version-checker.js @@ -1,14 +1,16 @@ const boxen = require('boxen') +const cacache = require('cacache') const log = require('npmlog') +const nopt = require('nopt') +const path = require('path') const pacote = require('pacote') const semver = require('semver') -var npmconf = require('../config/core.js') -var configDefs = npmconf.defs + +const npm = require('../npm.js') +const npmconf = require('../config/core.js') +const configDefs = npmconf.defs const shorthands = configDefs.shorthands const types = configDefs.types -const nopt = require('nopt') -let npm = require('../npm.js') - const pacoteOpts = require('../config/pacote') const unsupported = require('./unsupported.js') @@ -25,23 +27,43 @@ exports.doCheck = function () { npm.load(conf, function (err) { if (err) return - if ( - npm.config.get('update-notifier') && - !isGlobalNpmUpdate && - !unsupported.checkVersion(process.version).unsupported && - !isCI - ) { - pacote.manifest('npm@latest', pacoteOpts()) - .then((latest) => { - const oldVersion = require('../../package.json').version - let diffType = semver.diff(oldVersion, latest.version) - if (diffType) { - console.log(generateMessage(oldVersion, latest.version, diffType, npm)) - } else { - log.silly('version-check', 'we are running the latest version of npm') - } - }) - } + + isBeyondCheckInterval().then((shouldCheck) => { + if (shouldCheck) { + if ( + npm.config.get('update-notifier') && + !isGlobalNpmUpdate && + !unsupported.checkVersion(process.version).unsupported && + !isCI + ) { + pacote.manifest('npm@latest', pacoteOpts()) + .then((latest) => { + const oldVersion = require('../../package.json').version + let diffType = semver.diff(oldVersion, latest.version) + if (diffType) { + console.log(generateMessage(oldVersion, latest.version, diffType, npm)) + } else { + log.silly('version-checker', 'we are running the latest version of npm') + } + }) + } + } + }) + }) +} + +function isBeyondCheckInterval () { + const cache = path.join(npm.config.get('cache'), '_cacache') + const ONE_DAY = 24 * 60 * 60 * 1000 + + return cacache.get(cache, 'update-notifier:last-check').then(cacheObj => { + const time = Number(cacheObj.data.toString('utf8')) + return (time + ONE_DAY) < Date.now() + }).catch((notFound) => { + const time = Number(Date.now()).toString() + return cacache.put(cache, 'update-notifier:last-check', time).then(() => { + return true + }) }) }