fix(CLI): wait for robot output to be flushed before exitting (#616)

When using the `--robot` option, we write to `stdout`/`stderr` using
`WritableStream#write()`. This operation is asynchronous, however we're
not waiting for the data to be flushed before calling `process.exit()`
right after emitting the `done` event.

This causes a rance condition where sometimes `done` is never written to
the log file, and therefore the GUI remains waiting forever.

Change-Type: patch
Changelog-Entry: Fix application stuck at "Finishing".
See: https://github.com/resin-io/etcher/issues/613
See: https://github.com/resin-io/etcher/issues/609
See: https://github.com/resin-io/etcher/issues/573
Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
This commit is contained in:
Juan Cruz Viotti 2016-08-02 21:52:39 -04:00 committed by GitHub
parent bdbff0e814
commit 49bb9677cd
2 changed files with 58 additions and 34 deletions

View File

@ -91,33 +91,36 @@ form.run([
}); });
}).then((results) => { }).then((results) => {
return Bluebird.try(() => {
if (options.robot) { if (options.robot) {
log.toStdout(JSON.stringify({ return log.toStdout(JSON.stringify({
command: 'done', command: 'done',
data: { data: {
passedValidation: results.passedValidation, passedValidation: results.passedValidation,
sourceChecksum: results.sourceChecksum sourceChecksum: results.sourceChecksum
} }
})); }));
} else { }
if (results.passedValidation) { if (results.passedValidation) {
console.log('Your flash is complete!'); console.log('Your flash is complete!');
console.log(`Checksum: ${results.sourceChecksum}`); console.log(`Checksum: ${results.sourceChecksum}`);
} else { } else {
console.error('Validation failed!'); console.error('Validation failed!');
} }
} }).then(() => {
if (results.passedValidation) { if (results.passedValidation) {
process.exit(EXIT_CODES.SUCCESS); process.exit(EXIT_CODES.SUCCESS);
} else { } else {
process.exit(EXIT_CODES.VALIDATION_ERROR); process.exit(EXIT_CODES.VALIDATION_ERROR);
} }
});
}).catch((error) => { }).catch((error) => {
return Bluebird.try(() => {
if (options.robot) { if (options.robot) {
log.toStderr(JSON.stringify({ return log.toStderr(JSON.stringify({
command: 'error', command: 'error',
data: { data: {
message: error.message, message: error.message,
@ -125,9 +128,11 @@ form.run([
code: error.code code: error.code
} }
})); }));
} else {
utils.printError(error);
} }
utils.printError(error);
}).then(() => {
process.exit(EXIT_CODES.GENERAL_ERROR); process.exit(EXIT_CODES.GENERAL_ERROR);
});
}).finally(log.close); }).finally(log.close);

View File

@ -16,6 +16,7 @@
'use strict'; 'use strict';
const Bluebird = require('bluebird');
const fs = require('fs'); const fs = require('fs');
const options = require('./cli'); const options = require('./cli');
const logStream = options.log ? fs.createWriteStream(options.log) : null; const logStream = options.log ? fs.createWriteStream(options.log) : null;
@ -46,12 +47,17 @@ const STDERR_STREAM = logStream || process.stderr;
* to it, otherwise to `process.stdout`. * to it, otherwise to `process.stdout`.
* *
* @param {String} line - line * @param {String} line - line
* @returns {Promise}
* *
* @example * @example
* log.toStdout('Hello world!'); * log.toStdout('Hello world!');
*/ */
exports.toStdout = (line) => { exports.toStdout = (line) => {
STDOUT_STREAM.write(line + '\n'); return new Bluebird((resolve) => {
STDOUT_STREAM.write(line + '\n', () => {
return resolve();
});
});
}; };
/** /**
@ -64,12 +70,17 @@ exports.toStdout = (line) => {
* to it, otherwise to `process.stderr`. * to it, otherwise to `process.stderr`.
* *
* @param {String} line - line * @param {String} line - line
* @returns {Promise}
* *
* @example * @example
* log.toStderr('Hello world!'); * log.toStderr('Hello world!');
*/ */
exports.toStderr = (line) => { exports.toStderr = (line) => {
STDERR_STREAM.write(line + '\n'); return new Bluebird((resolve) => {
STDERR_STREAM.write(line + '\n', () => {
return resolve();
});
});
}; };
/** /**
@ -77,11 +88,19 @@ exports.toStderr = (line) => {
* @function * @function
* @public * @public
* *
* @returns {Promise}
*
* @example * @example
* log.close(); * log.close();
*/ */
exports.close = () => { exports.close = () => {
if (logStream) { return new Bluebird((resolve) => {
logStream.close(); if (!logStream) {
return resolve();
} }
logStream.close(() => {
return resolve();
});
});
}; };