diff options
Diffstat (limited to 'deps/node/deps/npm/node_modules/update-notifier/index.js')
-rw-r--r-- | deps/node/deps/npm/node_modules/update-notifier/index.js | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/deps/node/deps/npm/node_modules/update-notifier/index.js b/deps/node/deps/npm/node_modules/update-notifier/index.js new file mode 100644 index 00000000..38ff01e2 --- /dev/null +++ b/deps/node/deps/npm/node_modules/update-notifier/index.js @@ -0,0 +1,155 @@ +'use strict'; +const spawn = require('child_process').spawn; +const path = require('path'); +const format = require('util').format; +const importLazy = require('import-lazy')(require); + +const configstore = importLazy('configstore'); +const chalk = importLazy('chalk'); +const semverDiff = importLazy('semver-diff'); +const latestVersion = importLazy('latest-version'); +const isNpm = importLazy('is-npm'); +const isInstalledGlobally = importLazy('is-installed-globally'); +const boxen = importLazy('boxen'); +const xdgBasedir = importLazy('xdg-basedir'); +const isCi = importLazy('is-ci'); +const ONE_DAY = 1000 * 60 * 60 * 24; + +class UpdateNotifier { + constructor(options) { + options = options || {}; + this.options = options; + options.pkg = options.pkg || {}; + + // Reduce pkg to the essential keys. with fallback to deprecated options + // TODO: Remove deprecated options at some point far into the future + options.pkg = { + name: options.pkg.name || options.packageName, + version: options.pkg.version || options.packageVersion + }; + + if (!options.pkg.name || !options.pkg.version) { + throw new Error('pkg.name and pkg.version required'); + } + + this.packageName = options.pkg.name; + this.packageVersion = options.pkg.version; + this.updateCheckInterval = typeof options.updateCheckInterval === 'number' ? options.updateCheckInterval : ONE_DAY; + this.hasCallback = typeof options.callback === 'function'; + this.callback = options.callback || (() => {}); + this.disabled = 'NO_UPDATE_NOTIFIER' in process.env || + process.argv.indexOf('--no-update-notifier') !== -1 || + isCi(); + this.shouldNotifyInNpmScript = options.shouldNotifyInNpmScript; + + if (!this.disabled && !this.hasCallback) { + try { + const ConfigStore = configstore(); + this.config = new ConfigStore(`update-notifier-${this.packageName}`, { + optOut: false, + // Init with the current time so the first check is only + // after the set interval, so not to bother users right away + lastUpdateCheck: Date.now() + }); + } catch (err) { + // Expecting error code EACCES or EPERM + const msg = + chalk().yellow(format(' %s update check failed ', options.pkg.name)) + + format('\n Try running with %s or get access ', chalk().cyan('sudo')) + + '\n to the local update config store via \n' + + chalk().cyan(format(' sudo chown -R $USER:$(id -gn $USER) %s ', xdgBasedir().config)); + + process.on('exit', () => { + console.error('\n' + boxen()(msg, {align: 'center'})); + }); + } + } + } + check() { + if (this.hasCallback) { + this.checkNpm() + .then(update => this.callback(null, update)) + .catch(err => this.callback(err)); + return; + } + + if ( + !this.config || + this.config.get('optOut') || + this.disabled + ) { + return; + } + + this.update = this.config.get('update'); + + if (this.update) { + this.config.delete('update'); + } + + // Only check for updates on a set interval + if (Date.now() - this.config.get('lastUpdateCheck') < this.updateCheckInterval) { + return; + } + + // Spawn a detached process, passing the options as an environment property + spawn(process.execPath, [path.join(__dirname, 'check.js'), JSON.stringify(this.options)], { + detached: true, + stdio: 'ignore' + }).unref(); + } + checkNpm() { + return latestVersion()(this.packageName).then(latestVersion => { + return { + latest: latestVersion, + current: this.packageVersion, + type: semverDiff()(this.packageVersion, latestVersion) || 'latest', + name: this.packageName + }; + }); + } + notify(opts) { + const suppressForNpm = !this.shouldNotifyInNpmScript && isNpm(); + if (!process.stdout.isTTY || suppressForNpm || !this.update) { + return this; + } + + opts = Object.assign({isGlobal: isInstalledGlobally()}, opts); + + opts.message = opts.message || 'Update available ' + chalk().dim(this.update.current) + chalk().reset(' → ') + + chalk().green(this.update.latest) + ' \nRun ' + chalk().cyan('npm i ' + (opts.isGlobal ? '-g ' : '') + this.packageName) + ' to update'; + + opts.boxenOpts = opts.boxenOpts || { + padding: 1, + margin: 1, + align: 'center', + borderColor: 'yellow', + borderStyle: 'round' + }; + + const message = '\n' + boxen()(opts.message, opts.boxenOpts); + + if (opts.defer === false) { + console.error(message); + } else { + process.on('exit', () => { + console.error(message); + }); + + process.on('SIGINT', () => { + console.error(''); + process.exit(); + }); + } + + return this; + } +} + +module.exports = options => { + const updateNotifier = new UpdateNotifier(options); + updateNotifier.check(); + return updateNotifier; +}; + +module.exports.UpdateNotifier = UpdateNotifier; |