diff --git a/lib/child-writer/index.js b/lib/child-writer/index.js index 2b348201..514edb14 100644 --- a/lib/child-writer/index.js +++ b/lib/child-writer/index.js @@ -113,25 +113,43 @@ exports.write = (image, drive, options) => { emitter.emit('error', error); }; - ipc.server.on('error', emitError); - ipc.server.on('message', (data) => { - let message = null; - + /** + * @summary Bridge robot message to the child writer caller + * @function + * @private + * + * @param {String} message - robot message + * + * @example + * bridgeRobotMessage(robot.buildMessage('foo', { + * bar: 'baz' + * })); + */ + const bridgeRobotMessage = (message) => { try { - message = robot.parseMessage(data); + const parsedMessage = robot.parseMessage(message); + + // These are lighweight accessor methods for + // the properties of the parsed message + const messageCommand = robot.getCommand(parsedMessage); + const messageData = robot.getData(parsedMessage); + + // The error object is decomposed by the CLI for serialisation + // purposes. We compose it back to an `Error` here in order + // to provide better encapsulation. + if (messageCommand === 'error') { + emitError(robot.recomposeErrorMessage(parsedMessage)); + } else { + emitter.emit(messageCommand, messageData); + } + } catch (error) { - return emitError(error); + emitError(error); } + }; - // The error object is decomposed by the CLI for serialisation - // purposes. We compose it back to an `Error` here in order - // to provide better encapsulation. - if (robot.getCommand(message) === 'error') { - return emitError(robot.recomposeErrorMessage(message)); - } - - return emitter.emit(robot.getCommand(message), robot.getData(message)); - }); + ipc.server.on('error', emitError); + ipc.server.on('message', bridgeRobotMessage); ipc.server.on('start', () => { const child = childProcess.fork(CONSTANTS.WRITER_PROXY_SCRIPT, argv, { @@ -144,7 +162,7 @@ exports.write = (image, drive, options) => { }); child.stderr.on('data', (data) => { - emitError(new Error(data.toString())); + bridgeRobotMessage(data.toString()); // This function causes the `close` event to be emitted child.kill(); diff --git a/lib/child-writer/writer-proxy.js b/lib/child-writer/writer-proxy.js index 7ab3e4a0..be3c9d26 100644 --- a/lib/child-writer/writer-proxy.js +++ b/lib/child-writer/writer-proxy.js @@ -28,6 +28,7 @@ const sudoPrompt = Bluebird.promisifyAll(require('sudo-prompt')); const utils = require('./utils'); const EXIT_CODES = require('../shared/exit-codes'); const errors = require('../shared/errors'); +const robot = require('../shared/robot'); const packageJSON = require('../../package.json'); // This script is in charge of spawning the writer process and @@ -153,10 +154,23 @@ return isElevated().then((elevated) => { if (!_.isEmpty(stderr)) { throw errors.createError(stderr); } + + // We're hardcoding internal error messages declared by `sudo-prompt`. + // There doesn't seem to be a better way to handle these errors, so + // for now, we should make sure we double check if the error messages + // have changed every time we upgrade `sudo-prompt`. + }).catch({ message: 'User did not grant permission.' }, () => { process.exit(EXIT_CODES.CANCELLED); + }).catch({ + message: 'No polkit authentication agent found.' + }, () => { + throw errors.createUserError( + 'No polkit authentication agent found', + 'Please install a polkit authentication agent for your desktop environment of choice to continue' + ); }); } @@ -226,6 +240,6 @@ return isElevated().then((elevated) => { process.exit(exitCode); }); }).catch((error) => { - console.error(error); + robot.printError(error); process.exit(EXIT_CODES.GENERAL_ERROR); });