From 2158e20380276240e725da4da5baa4a563be6a35 Mon Sep 17 00:00:00 2001 From: Alexis Svinartchouk Date: Wed, 25 Nov 2020 18:21:45 +0100 Subject: [PATCH] Improve flashing error handling Changelog-entry: Improve flashing error handling Change-type: patch --- .../flash-results/flash-results.tsx | 6 +-- lib/gui/app/modules/image-writer.ts | 26 ++++++++---- lib/gui/app/pages/main/Flash.tsx | 41 ++++++++++++++----- 3 files changed, 52 insertions(+), 21 deletions(-) diff --git a/lib/gui/app/components/flash-results/flash-results.tsx b/lib/gui/app/components/flash-results/flash-results.tsx index 2eaaee95..dad0d822 100644 --- a/lib/gui/app/components/flash-results/flash-results.tsx +++ b/lib/gui/app/components/flash-results/flash-results.tsx @@ -127,12 +127,12 @@ export function FlashResults({ }; } & FlexProps) { const [showErrorsInfo, setShowErrorsInfo] = React.useState(false); - const allFailed = results.devices.successful === 0; + const allFailed = !skip && results.devices.successful === 0; const someFailed = results.devices.failed !== 0 || errors.length !== 0; const effectiveSpeed = _.round( bytesToMegabytes( results.sourceMetadata.size / - (results.bytesWritten / results.averageFlashingSpeed), + (results.sourceMetadata.blockmappedSize / results.averageFlashingSpeed), ), 1, ); @@ -155,7 +155,7 @@ export function FlashResults({ {middleEllipsis(image, 24)} - Flash Complete! + Flash {allFailed ? 'Failed' : 'Complete'}! {skip ? Validation has been skipped : null} diff --git a/lib/gui/app/modules/image-writer.ts b/lib/gui/app/modules/image-writer.ts index c8034267..09a78e2d 100644 --- a/lib/gui/app/modules/image-writer.ts +++ b/lib/gui/app/modules/image-writer.ts @@ -17,7 +17,7 @@ import { Drive as DrivelistDrive } from 'drivelist'; import * as electron from 'electron'; import * as sdk from 'etcher-sdk'; -import * as _ from 'lodash'; +import { Dictionary } from 'lodash'; import * as ipc from 'node-ipc'; import * as os from 'os'; import * as path from 'path'; @@ -133,6 +133,14 @@ function writerEnv() { interface FlashResults { skip?: boolean; cancelled?: boolean; + results?: { + bytesWritten: number; + devices: { + failed: number; + successful: number; + }; + errors: Error[]; + }; } async function performWrite( @@ -177,10 +185,12 @@ async function performWrite( }); ipc.server.on('done', (event) => { - event.results.errors = _.map(event.results.errors, (data) => { - return errors.fromJSON(data); - }); - _.merge(flashResults, event); + event.results.errors = event.results.errors.map( + (data: Dictionary & { message: string }) => { + return errors.fromJSON(data); + }, + ); + flashResults.results = event.results; }); ipc.server.on('abort', () => { @@ -209,7 +219,7 @@ async function performWrite( const argv = writerArgv(); ipc.server.on('start', async () => { - console.log(`Elevating command: ${_.join(argv, ' ')}`); + console.log(`Elevating command: ${argv.join(' ')}`); const env = writerEnv(); try { const results = await permissions.elevateCommand(argv, { @@ -231,11 +241,11 @@ async function performWrite( } console.log('Flash results', flashResults); - // This likely means the child died halfway through + // The flash wasn't cancelled and we didn't get a 'done' event if ( !flashResults.cancelled && !flashResults.skip && - !_.get(flashResults, ['results', 'bytesWritten']) + flashResults.results === undefined ) { reject( errors.createUserError({ diff --git a/lib/gui/app/pages/main/Flash.tsx b/lib/gui/app/pages/main/Flash.tsx index 70affdaf..8a6dc3cb 100644 --- a/lib/gui/app/pages/main/Flash.tsx +++ b/lib/gui/app/pages/main/Flash.tsx @@ -59,6 +59,27 @@ const getErrorMessageFromCode = (errorCode: string) => { return ''; }; +function notifySuccess( + iconPath: string, + basename: string, + drives: any, + devices: { successful: number; failed: number }, +) { + notification.send( + 'Flash complete!', + messages.info.flashComplete(basename, drives, devices), + iconPath, + ); +} + +function notifyFailure(iconPath: string, basename: string, drives: any) { + notification.send( + 'Oops! Looks like the flash failed.', + messages.error.flashFailure(basename, drives), + iconPath, + ); +} + async function flashImageToDrive( isFlashing: boolean, goToSuccess: () => void, @@ -84,20 +105,20 @@ async function flashImageToDrive( if (!flashState.wasLastFlashCancelled()) { const { results = { devices: { successful: 0, failed: 0 } }, + skip, + cancelled, } = flashState.getFlashResults(); - notification.send( - 'Flash complete!', - messages.info.flashComplete(basename, drives as any, results.devices), - iconPath, - ); + if (!skip && !cancelled) { + if (results.devices.successful > 0) { + notifySuccess(iconPath, basename, drives, results.devices); + } else { + notifyFailure(iconPath, basename, drives); + } + } goToSuccess(); } } catch (error) { - notification.send( - 'Oops! Looks like the flash failed.', - messages.error.flashFailure(path.basename(image.path), drives), - iconPath, - ); + notifyFailure(iconPath, basename, drives); let errorMessage = getErrorMessageFromCode(error.code); if (!errorMessage) { error.image = basename;