index.js
3.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
'use strict';
var spawn = require('child_process').spawn;
var path = require('path');
var Configstore = require('configstore');
var chalk = require('chalk');
var semverDiff = require('semver-diff');
var latestVersion = require('latest-version');
var stringLength = require('string-length');
var isNpm = require('is-npm');
var repeating = require('repeating');
function UpdateNotifier(options) {
this.options = options = options || {};
options.pkg = options.pkg || {};
// deprecated options
// TODO: remove this at some point far into the future
if (options.packageName && options.packageVersion) {
options.pkg.name = options.packageName;
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 : 1000 * 60 * 60 * 24; // 1 day
this.hasCallback = typeof options.callback === 'function';
this.callback = options.callback || function () {};
if (!this.hasCallback) {
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()
});
}
}
UpdateNotifier.prototype.check = function () {
if (this.hasCallback) {
return this.checkNpm(this.callback);
}
if (this.config.get('optOut') || 'NO_UPDATE_NOTIFIER' in process.env || process.argv.indexOf('--no-update-notifier') !== -1) {
return;
}
this.update = this.config.get('update');
if (this.update) {
this.config.del('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();
};
UpdateNotifier.prototype.checkNpm = function (cb) {
latestVersion(this.packageName, function (err, latestVersion) {
if (err) {
return cb(err);
}
cb(null, {
latest: latestVersion,
current: this.packageVersion,
type: semverDiff(this.packageVersion, latestVersion) || 'latest',
name: this.packageName
});
}.bind(this));
};
UpdateNotifier.prototype.notify = function (opts) {
if (!process.stdout.isTTY || isNpm || !this.update) {
return this;
}
opts = opts || {};
opts.defer = opts.defer === undefined ? true : false;
var line1 = ' Update available: ' + chalk.green.bold(this.update.latest) +
chalk.dim(' (current: ' + this.update.current + ')') + ' ';
var line2 = ' Run ' + chalk.blue('npm install -g ' + this.packageName) +
' to update. ';
var contentWidth = Math.max(stringLength(line1), stringLength(line2));
var line1rest = contentWidth - stringLength(line1);
var line2rest = contentWidth - stringLength(line2);
var top = chalk.yellow('┌' + repeating('─', contentWidth) + '┐');
var bottom = chalk.yellow('└' + repeating('─', contentWidth) + '┘');
var side = chalk.yellow('│');
var message =
'\n\n' +
top + '\n' +
side + line1 + repeating(' ', line1rest) + side + '\n' +
side + line2 + repeating(' ', line2rest) + side + '\n' +
bottom + '\n';
if (opts.defer) {
process.on('exit', function () {
console.error(message);
});
} else {
console.error(message);
}
return this;
};
module.exports = function (options) {
var updateNotifier = new UpdateNotifier(options);
updateNotifier.check();
return updateNotifier;
};
module.exports.UpdateNotifier = UpdateNotifier;