From fab2d767b0ae6b0401b428910096af236897973d Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Fri, 29 Apr 2016 13:01:06 -0400 Subject: [PATCH] Implement writing by spawning the CLI as a child process (#385) Signed-off-by: Juan Cruz Viotti --- lib/gui/modules/image-writer.js | 79 +++++++++++++++++++++++++++++---- package.json | 1 + 2 files changed, 72 insertions(+), 8 deletions(-) diff --git a/lib/gui/modules/image-writer.js b/lib/gui/modules/image-writer.js index 324896e5..12784f6f 100644 --- a/lib/gui/modules/image-writer.js +++ b/lib/gui/modules/image-writer.js @@ -21,13 +21,10 @@ */ const angular = require('angular'); +const _ = require('lodash'); const electron = require('electron'); - -if (window.mocha) { - var writer = electron.remote.require(require('path').join(__dirname, '..', '..', 'src', 'writer')); -} else { - var writer = electron.remote.require('./src/writer'); -} +const childProcess = require('child_process'); +const EXIT_CODES = require('../../src/exit-codes'); const MODULE_NAME = 'Etcher.image-writer'; const imageWriter = angular.module(MODULE_NAME, [ @@ -107,6 +104,7 @@ imageWriter.service('ImageWriterService', function($q, $timeout, SettingsModel, * @param {Object} drive - drive * @param {Function} onProgress - in progress callback (state) * + * @fulfil {Boolean} - whether the operation succeeded * @returns {Promise} * * @example @@ -117,7 +115,72 @@ imageWriter.service('ImageWriterService', function($q, $timeout, SettingsModel, * }); */ this.performWrite = function(image, drive, onProgress) { - return $q.when(writer.writeImage(image, drive, SettingsModel.data, onProgress)); + const argv = _.clone(electron.remote.process.argv); + + argv.push(image); + argv.push('--drive', drive.device); + argv.push('--robot'); + + // Explicitly set the boolen flag in positive + // or negative way in order to be on the safe + // side in case the Etcher CLI changes the + // default value of these options. + + if (SettingsModel.data.unmountOnSuccess) { + argv.push('--unmount'); + } else { + argv.push('--no-unmount'); + } + + if (SettingsModel.data.validateWriteOnSuccess) { + argv.push('--check'); + } else { + argv.push('--no-check'); + } + + return $q(function(resolve, reject) { + const child = childProcess.spawn(argv[0], argv.slice(1), { + env: { + + // This environment variable tells Etcher to run + // in CLI mode. See `lib.start.js`. + ELECTRON_RUN_AS_NODE: 1 + + } + }); + + child.stderr.on('data', function(data) { + child.kill(); + reject(new Error(data)); + }); + + child.stdout.on('data', function(data) { + const information = data.toString().split(' '); + + if (information[0] === 'progress') { + return onProgress({ + type: information[1], + percentage: _.parseInt(information[2]), + eta: _.parseInt(information[3]), + speed: _.parseInt(information[4]) + }); + } + }); + + child.on('error', reject); + + child.on('close', function(code) { + if (code === EXIT_CODES.SUCCESS) { + return resolve(true); + } + + if (code === EXIT_CODES.VALIDATION_ERROR) { + return resolve(false); + } + + return reject(new Error(`Child process exitted with error code: ${code}`)); + }); + }); }; /** @@ -154,7 +217,7 @@ imageWriter.service('ImageWriterService', function($q, $timeout, SettingsModel, self.state = { type: state.type, - progress: Math.floor(state.percentage), + progress: state.percentage, // Transform bytes to megabytes preserving only two decimal places speed: Math.floor(state.speed / 1e+6 * 100) / 100 || 0 diff --git a/package.json b/package.json index 4e8fda41..7cf1def9 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "bootstrap-sass": "^3.3.5", "chalk": "^1.1.3", "drivelist": "^3.0.0", + "etcher-image-stream": "^1.2.0", "etcher-image-write": "^4.0.2", "flexboxgrid": "^6.3.0", "is-elevated": "^1.0.0",