From c4cbfd352e509157eca3d0277ef98744607d8880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Cruz?= Date: Fri, 24 May 2013 11:14:14 +0100 Subject: [PATCH] Move stdout/stderr logic to the renderers to allow for greater flexibility. --- bin/bower_new | 39 ++++++--------- lib/renderers/cli.js | 108 ++++++++++++++++------------------------ lib/renderers/index.js | 2 +- lib/renderers/json.js | 59 +++++++++++----------- lib/renderers/mute.js | 13 ----- lib/renderers/silent.js | 12 +++++ lib/util/cli.js | 4 +- 7 files changed, 104 insertions(+), 133 deletions(-) delete mode 100644 lib/renderers/mute.js create mode 100644 lib/renderers/silent.js diff --git a/bin/bower_new b/bin/bower_new index fca6fdbc..21d2d423 100755 --- a/bin/bower_new +++ b/bin/bower_new @@ -28,9 +28,8 @@ if (options.version) { } // Parse log levels -levels = options['log-levels']; -if (levels) { - levels = levels +if (mout.object.hasOwn(options, 'log-levels')) { + levels = (options['log-levels'] || '') .split(',') .map(function (level) { return level.trim(); }); } else { @@ -43,15 +42,14 @@ command = options.argv.remain && options.argv.remain.shift(); command = commands[command] || commands.help; // Get the renderer -renderer = cli.createRenderer(options); +renderer = cli.getRenderer(options); // Execute the command -process.stdout.write(renderer.head()); +renderer.begin(); + command.line(process.argv) .on('data', function (data) { - var renderFuncName; - var renderFunc; - var str; + var func; // Check if this log level is allowed if (levels && levels.indexOf(data.level) === -1) { @@ -59,26 +57,21 @@ command.line(process.argv) } // Attempt to use renderer function specified by the tag - // Tags can be namespaced, this means that if the tag is - // help.install it will call renderer.help.install() // Fallback to renderer.data if not found - renderFuncName = data.tag - .split('.') - .map(function (slice) { return mout.string.camelCase(slice); }) - .join('.'); + func = mout.string.camelCase(data.tag); + if (!renderer[func]) { + func = 'data'; + } - renderFunc = mout.object.get(renderer, renderFuncName) || renderer.data; - str = renderFunc(data); - - // If level is warn, print to stderr instead - process[data.level === 'warn' ? 'stderr' : 'stdout'].write(str); + renderer[func](data); }) .on('end', function (data) { - process.stdout.write(renderer.end(data)); - process.stdout.write(renderer.tail()); + renderer.end(data); }) .on('error', function (err) { - process.stderr.write(renderer.error(err)); - process.stdout.write(renderer.tail()); + err.label = 'error'; + err.tag = err.code || 'error'; + + renderer.error(err); process.exit(1); }); \ No newline at end of file diff --git a/lib/renderers/cli.js b/lib/renderers/cli.js index 36d30814..e34e3897 100644 --- a/lib/renderers/cli.js +++ b/lib/renderers/cli.js @@ -1,7 +1,5 @@ var mout = require('mout'); -var colorful; -var colorless; var paddings = { tag: 10, tagPlusLabel: 31 @@ -9,67 +7,23 @@ var paddings = { var tagColors = { 'warn': 'yellow', 'error': 'red', - '_default': 'cyan', + 'default': 'cyan', }; -function renderData(data) { - // Ensure data - data.data = data.data || ''; - - return 'bower ' + renderTagPlusLabel(data) + ' ' + data.data + '\n'; -} - -function renderError(err) { - var str; - - err.level = 'error'; - err.tag = 'error'; - - str = 'bower ' + renderTagPlusLabel(err) + ' ' + (err.code ? err.code + ' ,' : '') + err.message + '\n'; - - // Check if additional details were provided - if (err.details) { - str += err.details + '\n'; - } - - // Print stack - str += '\n' + err.stack + '\n'; - - return str; -} - -function renderEnd() { - return ''; -} - -function renderCheckout(data) { - if (isCompact()) { - data.data = data.origin + '#' + data.data; - } - - return renderData(data); -} - -// ------------------------- - -function empty() { - return ''; +function isCompact() { + return process.stdout.columns < 120; } function uncolor(str) { return str.replace(/\x1B\[\d+m/g, ''); } -function isCompact() { - return process.stdout.columns < 120; -} - function renderTagPlusLabel(data) { var label; var length; var nrSpaces; var tag = data.tag; - var tagColor = tagColors[data.level] || tagColors._default; + var tagColor = tagColors[data.level] || tagColors['default']; // If there's not enough space, print only the tag if (isCompact()) { @@ -80,31 +34,57 @@ function renderTagPlusLabel(data) { length = tag.length + label.length + 1; nrSpaces = paddings.tagPlusLabel - length; - // Ensure at least one space + // Ensure at least one space between the label and the tag if (nrSpaces < 1) { nrSpaces = 1; } + return label.green + mout.string.repeat(' ', nrSpaces) + tag[tagColor]; } // ------------------------- -colorful = { - head: empty, - tail: empty, - data: renderData, - error: renderError, - end: renderEnd, - checkout: renderCheckout +var colorful = { + begin: function () {}, + end: function () {}, + error: function (err) { + var str; + + str = 'bower ' + renderTagPlusLabel(err) + ' ' + (err.code ? err.code + ' ,' : '') + err.message + '\n'; + + // Check if additional details were provided + if (err.details) { + str += err.details + '\n'; + } + + // Print stack + str += '\n' + err.stack + '\n'; + + this._write(process.stderr, str); + }, + data: function (data) { + data.data = data.data || ''; + + this._write(process.stdout, 'bower ' + renderTagPlusLabel(data) + ' ' + data.data + '\n'); + }, + checkout: function (data) { + if (isCompact()) { + data.data = data.origin + '#' + data.data; + } + + this.data(data); + }, + _write: function (channel, str) { + channel.write(str); + } }; -// The colorless variant simply removes the colors from the colorful methods -colorless = mout.object.map(module.exports.colorful, function (fn) { - return function () { - var str = fn.apply(fn, arguments); - return uncolor(str); - }; +// The colorless variant simply removes the colors from the write method +var colorless = mout.object.mixIn({}, colorful, { + _write: function (channel, str) { + channel.write(uncolor(str)); + } }); module.exports.colorful = colorful; diff --git a/lib/renderers/index.js b/lib/renderers/index.js index 11086987..93a1f7e6 100644 --- a/lib/renderers/index.js +++ b/lib/renderers/index.js @@ -1,5 +1,5 @@ module.exports = { cli: require('./cli'), json: require('./json'), - mute: require('./mute') + silent: require('./silent') }; \ No newline at end of file diff --git a/lib/renderers/json.js b/lib/renderers/json.js index 10fcea58..d81a9e12 100644 --- a/lib/renderers/json.js +++ b/lib/renderers/json.js @@ -1,27 +1,3 @@ -// TODO: take care of trailing , - -function renderHead() { - return '['; -} - -function renderTail() { - return ']\n'; -} - -function renderData(data) { - return stringify(data) + ', '; -} - -function renderError(err) { - return stringify(err) + ', '; -} - -function renderEnd(data) { - return data ? stringify(data) : ''; -} - -// ------------------------- - function uncolor(str) { return str.replace(/\x1B\[\d+m/g, ''); } @@ -32,10 +8,33 @@ function stringify(data) { // ------------------------- -module.exports = { - head: renderHead, - tail: renderTail, - data: renderData, - error: renderError, - end: renderEnd +var nrData = 0; + +// In the json output, everything goes to stderr except +// the final command result that goes to stdout. +var json = { + begin: function () { + process.stderr.write('['); + }, + end: function (data) { + process.stderr.write(']\n'); + + if (data) { + process.stdout.write(stringify(data)); + } + }, + error: function (err) { + this.data(err); + }, + data: function (data) { + if (nrData) { + process.stderr.write(', '); + } + + process.stderr.write(stringify(data)); + nrData++; + }, + }; + +module.exports = json; \ No newline at end of file diff --git a/lib/renderers/mute.js b/lib/renderers/mute.js deleted file mode 100644 index bac68e65..00000000 --- a/lib/renderers/mute.js +++ /dev/null @@ -1,13 +0,0 @@ -function empty() { - return ''; -} - -// ------------------------- - -module.exports = { - head: empty, - tail: empty, - data: empty, - error: empty, - end: empty -}; diff --git a/lib/renderers/silent.js b/lib/renderers/silent.js new file mode 100644 index 00000000..960d3fa0 --- /dev/null +++ b/lib/renderers/silent.js @@ -0,0 +1,12 @@ +function empty() {} + +// ------------------------- + +var silent = { + begin: empty, + end: empty, + error: empty, + data: empty, +}; + +module.exports = silent; \ No newline at end of file diff --git a/lib/util/cli.js b/lib/util/cli.js index 281d7972..843e9c13 100644 --- a/lib/util/cli.js +++ b/lib/util/cli.js @@ -25,7 +25,7 @@ function readOptions(argv, options) { function getRenderer(options) { if (options.silent) { - return renderers.mute; + return renderers.silent; } if (options.json) { @@ -38,4 +38,4 @@ function getRenderer(options) { } module.exports.readOptions = readOptions; -module.exports.createRenderer = getRenderer; \ No newline at end of file +module.exports.getRenderer = getRenderer; \ No newline at end of file