etcher/lib/shared/robot.js
2017-02-07 17:31:30 -04:00

236 lines
5.0 KiB
JavaScript

/*
* Copyright 2016 resin.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
const _ = require('lodash');
/**
* @summary Check whether we should emit parseable output
* @function
* @public
*
* @param {Object} environment - environment
* @returns {Boolean} whether we should emit parseable output
*
* @example
* if (robot.isEnabled(process.env)) {
* console.log('We should emit parseable output');
* }
*/
exports.isEnabled = (environment) => {
const value = _.get(environment, 'ETCHER_CLI_ROBOT', false);
return Boolean(value === 'false' ? false : value);
};
/**
* @summary Build a machine-parseable message
* @function
* @private
*
* @param {String} title - message title
* @param {Object} [data] - message data
* @returns {String} parseable message
*
* @example
* const message = robot.buildMessage('progress', {
* percentage: 50
* });
*
* console.log(message);
* > '{"command":"progress","data":{"percentage":50}}'
*/
exports.buildMessage = (title, data = {}) => {
if (!_.isPlainObject(data)) {
throw new Error(`Invalid data: ${data}`);
}
return JSON.stringify({
command: title,
data: data
});
};
/**
* @summary Parse a machine-parseable message
* @function
* @public
*
* @param {String} string - message string
* @returns {Object} parsed message
*
* @example
* const result = robot.parseMessage('{"command":"progress","data":{"foo":50}}');
* console.log(result);
* > {
* > command: 'progress',
* > data: {
* > foo: 50
* > }
* > }
*/
exports.parseMessage = (string) => {
let output;
try {
output = JSON.parse(string);
} catch (error) {
error.message = 'Invalid message';
error.description = `${string}, ${error.message}`;
throw error;
}
if (!output.command || !output.data) {
const error = new Error('Invalid message');
error.description = `No command or data: ${string}`;
throw error;
}
return output;
};
/**
* @summary Build a machine-parseable error message
* @function
* @private
*
* @param {(String|Error)} error - error
* @returns {String} parseable error message
*
* @example
* const error = new Error('foo');
* const errorMessage = robot.buildErrorMessage(error);
*
* console.log(error.command);
* > 'error'
*
* console.log(error.data.message);
* > 'foo'
*
* error.data.stacktrace === error.stack;
* > true
*/
exports.buildErrorMessage = (error) => {
if (_.isString(error)) {
error = new Error(error);
}
return exports.buildMessage('error', {
message: error.message,
description: error.description,
stacktrace: error.stack,
code: error.code
});
};
/**
* @summary Recompose an error message
* @function
* @public
*
* @param {String} message - error message
* @returns {Error} error object
*
* @example
* const message = robot.buildErrorMessage(new Error('foo'));
* const error = robot.recomposeErrorMessage(robot.parseMessage(message));
*
* error instanceof Error;
* > true
*
* console.log(error.message);
* > 'foo'
*/
exports.recomposeErrorMessage = (message) => {
const error = new Error(message.data.message);
_.assign(error, _.omit(message.data, 'stacktrace'));
error.stack = message.data.stacktrace;
return error;
};
/**
* @summary Get message command
* @function
* @public
*
* @param {Object} message - message
* @returns {String} command
*
* @example
* const command = robot.getCommand({
* command: 'foo',
* data: {}
* });
*
* console.log(command);
* > 'foo'
*/
exports.getCommand = (message) => {
return _.get(message, 'command');
};
/**
* @summary Get message data
* @function
* @public
*
* @param {Object} message - message
* @returns {Object} data
*
* @example
* const data = robot.getData({
* command: 'foo',
* data: {
* foo: 1
* }
* });
*
* console.log(data);
* > { foo: 1 }
*/
exports.getData = (message) => {
return _.get(message, 'data', {});
};
/**
* @summary Print an error in a machine-friendly way
* @function
* @public
*
* @param {(Error|String)} error - error
*
* @example
* robot.printError(new Error('This is an error'));
*/
exports.printError = (error) => {
console.error(exports.buildErrorMessage(error));
};
/**
* @summary Print a message in a machine-friendly way
* @function
* @public
*
* @param {String} message - message
* @param {Object} [data] - data
*
* @example
* robot.printMessage('progress', { percentage: 50 });
*/
exports.printMessage = (message, data) => {
console.log(exports.buildMessage(message, data));
};