Improve flashing error handling

Changelog-entry: Improve flashing error handling
Change-type: patch
This commit is contained in:
Alexis Svinartchouk 2020-11-25 18:21:45 +01:00
parent fa593e33d1
commit 2158e20380
3 changed files with 52 additions and 21 deletions

View File

@ -127,12 +127,12 @@ export function FlashResults({
}; };
} & FlexProps) { } & FlexProps) {
const [showErrorsInfo, setShowErrorsInfo] = React.useState(false); 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 someFailed = results.devices.failed !== 0 || errors.length !== 0;
const effectiveSpeed = _.round( const effectiveSpeed = _.round(
bytesToMegabytes( bytesToMegabytes(
results.sourceMetadata.size / results.sourceMetadata.size /
(results.bytesWritten / results.averageFlashingSpeed), (results.sourceMetadata.blockmappedSize / results.averageFlashingSpeed),
), ),
1, 1,
); );
@ -155,7 +155,7 @@ export function FlashResults({
<Txt>{middleEllipsis(image, 24)}</Txt> <Txt>{middleEllipsis(image, 24)}</Txt>
</Flex> </Flex>
<Txt fontSize={24} color="#fff" mb="17px"> <Txt fontSize={24} color="#fff" mb="17px">
Flash Complete! Flash {allFailed ? 'Failed' : 'Complete'}!
</Txt> </Txt>
{skip ? <Txt color="#7e8085">Validation has been skipped</Txt> : null} {skip ? <Txt color="#7e8085">Validation has been skipped</Txt> : null}
</Flex> </Flex>

View File

@ -17,7 +17,7 @@
import { Drive as DrivelistDrive } from 'drivelist'; import { Drive as DrivelistDrive } from 'drivelist';
import * as electron from 'electron'; import * as electron from 'electron';
import * as sdk from 'etcher-sdk'; import * as sdk from 'etcher-sdk';
import * as _ from 'lodash'; import { Dictionary } from 'lodash';
import * as ipc from 'node-ipc'; import * as ipc from 'node-ipc';
import * as os from 'os'; import * as os from 'os';
import * as path from 'path'; import * as path from 'path';
@ -133,6 +133,14 @@ function writerEnv() {
interface FlashResults { interface FlashResults {
skip?: boolean; skip?: boolean;
cancelled?: boolean; cancelled?: boolean;
results?: {
bytesWritten: number;
devices: {
failed: number;
successful: number;
};
errors: Error[];
};
} }
async function performWrite( async function performWrite(
@ -177,10 +185,12 @@ async function performWrite(
}); });
ipc.server.on('done', (event) => { ipc.server.on('done', (event) => {
event.results.errors = _.map(event.results.errors, (data) => { event.results.errors = event.results.errors.map(
return errors.fromJSON(data); (data: Dictionary<any> & { message: string }) => {
}); return errors.fromJSON(data);
_.merge(flashResults, event); },
);
flashResults.results = event.results;
}); });
ipc.server.on('abort', () => { ipc.server.on('abort', () => {
@ -209,7 +219,7 @@ async function performWrite(
const argv = writerArgv(); const argv = writerArgv();
ipc.server.on('start', async () => { ipc.server.on('start', async () => {
console.log(`Elevating command: ${_.join(argv, ' ')}`); console.log(`Elevating command: ${argv.join(' ')}`);
const env = writerEnv(); const env = writerEnv();
try { try {
const results = await permissions.elevateCommand(argv, { const results = await permissions.elevateCommand(argv, {
@ -231,11 +241,11 @@ async function performWrite(
} }
console.log('Flash results', flashResults); 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 ( if (
!flashResults.cancelled && !flashResults.cancelled &&
!flashResults.skip && !flashResults.skip &&
!_.get(flashResults, ['results', 'bytesWritten']) flashResults.results === undefined
) { ) {
reject( reject(
errors.createUserError({ errors.createUserError({

View File

@ -59,6 +59,27 @@ const getErrorMessageFromCode = (errorCode: string) => {
return ''; 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( async function flashImageToDrive(
isFlashing: boolean, isFlashing: boolean,
goToSuccess: () => void, goToSuccess: () => void,
@ -84,20 +105,20 @@ async function flashImageToDrive(
if (!flashState.wasLastFlashCancelled()) { if (!flashState.wasLastFlashCancelled()) {
const { const {
results = { devices: { successful: 0, failed: 0 } }, results = { devices: { successful: 0, failed: 0 } },
skip,
cancelled,
} = flashState.getFlashResults(); } = flashState.getFlashResults();
notification.send( if (!skip && !cancelled) {
'Flash complete!', if (results.devices.successful > 0) {
messages.info.flashComplete(basename, drives as any, results.devices), notifySuccess(iconPath, basename, drives, results.devices);
iconPath, } else {
); notifyFailure(iconPath, basename, drives);
}
}
goToSuccess(); goToSuccess();
} }
} catch (error) { } catch (error) {
notification.send( notifyFailure(iconPath, basename, drives);
'Oops! Looks like the flash failed.',
messages.error.flashFailure(path.basename(image.path), drives),
iconPath,
);
let errorMessage = getErrorMessageFromCode(error.code); let errorMessage = getErrorMessageFromCode(error.code);
if (!errorMessage) { if (!errorMessage) {
error.image = basename; error.image = basename;