1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 | 'use strict';
|
11 |
|
12 |
|
13 | var util = require('util');
|
14 |
|
15 |
|
16 | var hooker = require('hooker');
|
17 |
|
18 | var colors = require('colors');
|
19 |
|
20 | var _ = require('lodash');
|
21 | _.str = require('underscore.string');
|
22 | _.mixin(_.str.exports());
|
23 |
|
24 |
|
25 | var logUtils = require('grunt-legacy-log-utils');
|
26 |
|
27 | function Log(options) {
|
28 |
|
29 | this.always = this;
|
30 |
|
31 | this.options = _.extend({}, {
|
32 |
|
33 | color: true,
|
34 |
|
35 | verbose: false,
|
36 |
|
37 | debug: false,
|
38 |
|
39 | outStream: process.stdout,
|
40 |
|
41 |
|
42 |
|
43 | grunt: null,
|
44 |
|
45 | maxCols: null,
|
46 |
|
47 | muted: false,
|
48 | }, options);
|
49 |
|
50 | this.hasLogged = false;
|
51 |
|
52 |
|
53 | this.verbose = new VerboseLog(this, true);
|
54 | this.notverbose = new VerboseLog(this, false);
|
55 | this.verbose.or = this.notverbose;
|
56 | this.notverbose.or = this.verbose;
|
57 |
|
58 |
|
59 |
|
60 | if (this.options.grunt) {
|
61 | _.bindAll(this);
|
62 | _.bindAll(this.verbose);
|
63 | _.bindAll(this.notverbose);
|
64 | }
|
65 | }
|
66 | exports.Log = Log;
|
67 |
|
68 |
|
69 | function VerboseLog(parentLog, verbose) {
|
70 |
|
71 | this.always = parentLog;
|
72 |
|
73 | this._isVerbose = verbose;
|
74 | }
|
75 | util.inherits(VerboseLog, Log);
|
76 |
|
77 | VerboseLog.prototype._write = function() {
|
78 |
|
79 | if (Boolean(this.option('verbose')) !== this._isVerbose) { return; }
|
80 |
|
81 | return VerboseLog.super_.prototype._write.apply(this, arguments);
|
82 | };
|
83 |
|
84 |
|
85 |
|
86 | function makeSmartAccessor(name, isOption) {
|
87 | Object.defineProperty(Log.prototype, name, {
|
88 | enumerable: true,
|
89 | configurable: true,
|
90 | get: function() {
|
91 | return isOption ? this.always._options[name] : this.always['_' + name];
|
92 | },
|
93 | set: function(value) {
|
94 | if (isOption) {
|
95 | this.always._options[name] = value;
|
96 | } else {
|
97 | this.always['_' + name] = value;
|
98 | }
|
99 | },
|
100 | });
|
101 | }
|
102 | makeSmartAccessor('options');
|
103 | makeSmartAccessor('hasLogged');
|
104 | makeSmartAccessor('muted', true);
|
105 |
|
106 |
|
107 | Log.prototype.initColors = function() {
|
108 | if (this.option('no-color')) {
|
109 |
|
110 | colors.mode = 'none';
|
111 |
|
112 | hooker.hook(console, 'log', function() {
|
113 | var args = _.toArray(arguments);
|
114 | return hooker.filter(this, args.map(function(arg) {
|
115 | return typeof arg === 'string' ? colors.stripColors(arg) : arg;
|
116 | }));
|
117 | });
|
118 | }
|
119 | };
|
120 |
|
121 |
|
122 |
|
123 | Log.prototype.option = function(name) {
|
124 | if (this.options.grunt && this.options.grunt.option) {
|
125 | return this.options.grunt.option(name);
|
126 | }
|
127 | var no = name.match(/^no-(.+)$/);
|
128 | return no ? !this.options[no[1]] : this.options[name];
|
129 | };
|
130 |
|
131 |
|
132 | Log.prototype._markup = function(str) {
|
133 | str = str || '';
|
134 |
|
135 | str = str.replace(/(\s|^)_(\S|\S[\s\S]+?\S)_(?=[\s,.!?]|$)/g, '$1' + '$2'.underline);
|
136 |
|
137 | str = str.replace(/(\s|^)\*(\S|\S[\s\S]+?\S)\*(?=[\s,.!?]|$)/g, '$1' + '$2'.bold);
|
138 | return str;
|
139 | };
|
140 |
|
141 |
|
142 |
|
143 | Log.prototype._format = function(args) {
|
144 | args = _.toArray(args);
|
145 | if (args.length > 0) {
|
146 | args[0] = String(args[0]);
|
147 | }
|
148 | return util.format.apply(util, args);
|
149 | };
|
150 |
|
151 | Log.prototype._write = function(msg) {
|
152 |
|
153 | if (this.muted) { return; }
|
154 |
|
155 | this.hasLogged = true;
|
156 | msg = msg || '';
|
157 |
|
158 |
|
159 | if (this.option('no-color')) { msg = colors.stripColors(msg); }
|
160 |
|
161 | this.options.outStream.write(this._markup(msg));
|
162 | };
|
163 |
|
164 | Log.prototype._writeln = function(msg) {
|
165 |
|
166 | this._write((msg || '') + '\n');
|
167 | };
|
168 |
|
169 |
|
170 | Log.prototype.write = function() {
|
171 | this._write(this._format(arguments));
|
172 | return this;
|
173 | };
|
174 |
|
175 |
|
176 | Log.prototype.writeln = function() {
|
177 | this._writeln(this._format(arguments));
|
178 | return this;
|
179 | };
|
180 |
|
181 | Log.prototype.warn = function() {
|
182 | var msg = this._format(arguments);
|
183 | if (arguments.length > 0) {
|
184 | this._writeln('>> '.red + _.trim(msg).replace(/\n/g, '\n>> '.red));
|
185 | } else {
|
186 | this._writeln('ERROR'.red);
|
187 | }
|
188 | return this;
|
189 | };
|
190 | Log.prototype.error = function() {
|
191 | if (this.options.grunt && this.options.grunt.fail) {
|
192 | this.options.grunt.fail.errorcount++;
|
193 | }
|
194 | this.warn.apply(this, arguments);
|
195 | return this;
|
196 | };
|
197 | Log.prototype.ok = function() {
|
198 | var msg = this._format(arguments);
|
199 | if (arguments.length > 0) {
|
200 | this._writeln('>> '.green + _.trim(msg).replace(/\n/g, '\n>> '.green));
|
201 | } else {
|
202 | this._writeln('OK'.green);
|
203 | }
|
204 | return this;
|
205 | };
|
206 | Log.prototype.errorlns = function() {
|
207 | var msg = this._format(arguments);
|
208 | this.error(this.wraptext(this.options.maxCols || 77, msg));
|
209 | return this;
|
210 | };
|
211 | Log.prototype.oklns = function() {
|
212 | var msg = this._format(arguments);
|
213 | this.ok(this.wraptext(this.options.maxCols || 77, msg));
|
214 | return this;
|
215 | };
|
216 | Log.prototype.success = function() {
|
217 | var msg = this._format(arguments);
|
218 | this._writeln(msg.green);
|
219 | return this;
|
220 | };
|
221 | Log.prototype.fail = function() {
|
222 | var msg = this._format(arguments);
|
223 | this._writeln(msg.red);
|
224 | return this;
|
225 | };
|
226 | Log.prototype.header = function() {
|
227 | var msg = this._format(arguments);
|
228 |
|
229 | if (this.hasLogged) { this._writeln(); }
|
230 | this._writeln(msg.underline);
|
231 | return this;
|
232 | };
|
233 | Log.prototype.subhead = function() {
|
234 | var msg = this._format(arguments);
|
235 |
|
236 | if (this.hasLogged) { this._writeln(); }
|
237 | this._writeln(msg.bold);
|
238 | return this;
|
239 | };
|
240 |
|
241 | Log.prototype.debug = function() {
|
242 | var msg = this._format(arguments);
|
243 | if (this.option('debug')) {
|
244 | this._writeln('[D] ' + msg.magenta);
|
245 | }
|
246 | return this;
|
247 | };
|
248 |
|
249 |
|
250 | Log.prototype.writetableln = function(widths, texts) {
|
251 | this._writeln(this.table(widths, texts));
|
252 | return this;
|
253 | };
|
254 |
|
255 |
|
256 | Log.prototype.writelns = function() {
|
257 | var msg = this._format(arguments);
|
258 | this._writeln(this.wraptext(this.options.maxCols || 80, msg));
|
259 | return this;
|
260 | };
|
261 |
|
262 |
|
263 | Log.prototype.writeflags = function(obj, prefix) {
|
264 | var wordlist;
|
265 | if (Array.isArray(obj)) {
|
266 | wordlist = this.wordlist(obj);
|
267 | } else if (typeof obj === 'object' && obj) {
|
268 | wordlist = this.wordlist(Object.keys(obj).map(function(key) {
|
269 | var val = obj[key];
|
270 | return key + (val === true ? '' : '=' + JSON.stringify(val));
|
271 | }));
|
272 | }
|
273 | this._writeln((prefix || 'Flags') + ': ' + (wordlist || '(none)'.cyan));
|
274 | return this;
|
275 | };
|
276 |
|
277 |
|
278 | [
|
279 | 'wordlist',
|
280 | 'uncolor',
|
281 | 'wraptext',
|
282 | 'table',
|
283 | ].forEach(function(prop) {
|
284 | Log.prototype[prop] = exports[prop] = logUtils[prop];
|
285 | });
|