This commit is contained in:
Alexis Svinartchouk 2018-07-05 19:48:44 +01:00
parent e68dbcf4ee
commit caf5f10326
9 changed files with 164 additions and 119 deletions

View File

@ -74,8 +74,9 @@ permissions.isElevated().then((elevated) => {
}
const progressBars = new Map()
let lastStateType
let lastStateType = null
// eslint-disable-next-line require-jsdoc
const onProgress = (state) => {
state.message = state.active > 1
? `${bytes(state.totalSpeed)}/s total, ${bytes(state.speed)}/s x ${state.active}`
@ -83,21 +84,25 @@ permissions.isElevated().then((elevated) => {
state.message = `${state.type === 'flashing' ? 'Flashing' : 'Validating'}: ${state.message}`
// eslint-disable-next-line no-undefined
if (state.percentage === undefined) {
state.message += ` - ${bytes(state.bytes)} written`
}
// Update progress bar
let progressBar = progressBars.get(state.type)
// eslint-disable-next-line no-undefined
if (progressBar === undefined) {
// Stop the spinner if there is one
if ((lastStateType !== undefined) && (lastStateType !== state.type)) {
if ((lastStateType !== null) && (lastStateType !== state.type)) {
const spinner = progressBars.get(lastStateType)
// eslint-disable-next-line no-undefined
if ((spinner !== undefined) && (spinner instanceof visuals.Spinner)) {
console.log()
spinner.stop()
}
}
// eslint-disable-next-line no-undefined
if (state.percentage === undefined) {
progressBar = new visuals.Spinner(state.message)
progressBar.start()
@ -106,13 +111,11 @@ permissions.isElevated().then((elevated) => {
progressBar.update(state)
}
progressBars.set(state.type, progressBar)
} else {
if (progressBar instanceof visuals.Spinner) {
} else if (progressBar instanceof visuals.Spinner) {
progressBar.spinner.setSpinnerTitle(state.message)
} else {
progressBar.update(state)
}
}
lastStateType = state.type
}
@ -130,9 +133,9 @@ permissions.isElevated().then((elevated) => {
})
.then((innerSource) => {
// NOTE: Drive can be (String|Array)
const destinations = [].concat(answers.drive).map((device) => {
const destinations = _.map([].concat(answers.drive), (device) => {
const drive = scanner.getBy('device', device)
if (drive === undefined) {
if (!drive) {
throw new Error(`No such drive ${device}`)
}
return drive

View File

@ -232,13 +232,13 @@ app.run(() => {
})
})
app.run(($timeout) => {
const BLACKLISTED_DRIVES = settings.has('driveBlacklist')
? settings.get('driveBlacklist').split(',')
: []
function driveIsAllowed(drive) {
// eslint-disable-next-line require-jsdoc
const driveIsAllowed = (drive) => {
return !(
BLACKLISTED_DRIVES.includes(drive.devicePath) ||
BLACKLISTED_DRIVES.includes(drive.device) ||
@ -246,7 +246,8 @@ app.run(($timeout) => {
)
}
function prepareDrive(drive) {
// eslint-disable-next-line require-jsdoc,consistent-return
const prepareDrive = (drive) => {
if (drive instanceof sdk.sourceDestination.BlockDevice) {
return drive.drive
} else if (drive instanceof sdk.sourceDestination.UsbbootDrive) {
@ -261,9 +262,10 @@ app.run(($timeout) => {
}
}
function setDrives(drives) {
drives = _.values(drives)
availableDrives.setDrives(drives)
// eslint-disable-next-line require-jsdoc
const setDrives = (drives) => {
availableDrives.setDrives(_.values(drives))
// Safely trigger a digest cycle.
// In some cases, AngularJS doesn't acknowledge that the
// available drives list has changed, and incorrectly
@ -271,32 +273,37 @@ app.run(($timeout) => {
$timeout()
}
function getDrives() {
// eslint-disable-next-line require-jsdoc
const getDrives = () => {
return _.keyBy(availableDrives.getDrives() || [], 'device')
}
function addDrive(drive) {
drive = prepareDrive(drive)
if (!driveIsAllowed(drive)) {
// eslint-disable-next-line require-jsdoc
const addDrive = (drive) => {
const preparedDrive = prepareDrive(drive)
if (!driveIsAllowed(preparedDrive)) {
return
}
const drives = getDrives()
drives[drive.device] = drive
drives[preparedDrive.device] = preparedDrive
setDrives(drives)
}
function removeDrive(drive) {
drive = prepareDrive(drive)
// eslint-disable-next-line require-jsdoc
const removeDrive = (drive) => {
const preparedDrive = prepareDrive(drive)
const drives = getDrives()
delete drives[drive.device]
// eslint-disable-next-line prefer-reflect
delete drives[preparedDrive.device]
setDrives(drives)
}
function updateDriveProgress(drive, progress) {
// eslint-disable-next-line require-jsdoc
const updateDriveProgress = (drive, progress) => {
const drives = getDrives()
const drive_ = drives[drive.device]
if (drive !== undefined) {
drive.progress = progress
const driveInMap = drives[drive.device]
if (driveInMap) {
driveInMap.progress = progress
setDrives(drives)
}
}

View File

@ -24,7 +24,6 @@ const constraints = require('../../../shared/drive-constraints')
const supportedFormats = require('../../../shared/supported-formats')
const errors = require('../../../shared/errors')
const fileExtensions = require('../../../shared/file-extensions')
const utils = require('../../../shared/utils')
const settings = require('./settings')
/**
@ -46,7 +45,7 @@ const verifyNoNilFields = (object, fields, name) => {
return _.isNil(_.get(object, field))
})
if (nilFields.length) {
throw new Error(`Missing ${name} fields: ${nilFields.join(', ')} ${JSON.stringify(object, null, 4)}`)
throw new Error(`Missing ${name} fields: ${nilFields.join(', ')}`)
}
}
@ -162,7 +161,7 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
const drives = action.data
//if (!_.isArray(drives) || !_.every(drives, _.isPlainObject)) {
// If (!_.isArray(drives) || !_.every(drives, _.isPlainObject)) {
if (!_.isArray(drives)) {
throw errors.createError({
title: `Invalid drives: ${drives}`
@ -407,6 +406,7 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
const MINIMUM_IMAGE_SIZE = 0
// eslint-disable-next-line no-undefined
if ((action.data.size !== undefined) && (action.data.size < MINIMUM_IMAGE_SIZE)) {
throw errors.createError({
title: `Invalid image size: ${action.data.size}`

View File

@ -21,7 +21,16 @@ const process = require('process')
const settings = require('../models/settings')
function includeSystemDrives() {
/**
* @summary returns true if system drives should be shown
* @function
*
* @returns {Boolean}
*
* @example
* const shouldInclude = includeSystemDrives()
*/
const includeSystemDrives = () => {
return settings.get('unsafeMode') && !settings.get('disableUnsafeMode')
}
@ -31,6 +40,7 @@ const adapters = [
// Can't use permissions.isElevated() here as it returns a promise and we need to set
// module.exports = scanner right now.
// eslint-disable-next-line no-magic-numbers
if ((process.platform !== 'linux') || (process.geteuid() === 0)) {
adapters.push(new sdk.scanner.adapters.UsbbootDeviceAdapter())
}

View File

@ -59,11 +59,11 @@ exports.fromFlashState = (state) => {
return 'Finishing...'
} else if (isFlashing) {
// eslint-disable-next-line no-eq-null
if (state.percentage != null) {
return `${state.percentage}% Flashing`
} else {
return `${units.bytesToClosestUnit(state.position)} flashed`
}
return `${units.bytesToClosestUnit(state.position)} flashed`
} else if (isValidating) {
return `${state.percentage}% Validating`
} else if (!isFlashing && !isValidating) {

View File

@ -90,7 +90,8 @@ exports.currentWindow = electron.remote.getCurrentWindow()
* })
*/
exports.set = (state) => {
if (state.percentage != null) {
// eslint-disable-next-line no-eq-null
if (state.percentage !== null) {
exports.currentWindow.setProgressBar(utils.percentageToFloat(state.percentage))
}
exports.currentWindow.setTitle(getWindowTitle(state))

View File

@ -164,12 +164,13 @@ module.exports = function (
.then((metadata) => {
return innerSource.getPartitionTable()
.then((partitionTable) => {
if (partitionTable !== undefined) {
if (partitionTable) {
metadata.hasMBR = true
metadata.partitions = partitionTable.partitions
}
$timeout(() => {
metadata.path = imagePath
// eslint-disable-next-line no-magic-numbers
metadata.extension = path.extname(imagePath).slice(1)
this.selectImage(metadata)
})
@ -185,7 +186,7 @@ module.exports = function (
})
.then(() => {
return innerSource.close()
.catch(() => {})
.catch(_.noop)
})
})
}

View File

@ -16,7 +16,6 @@
'use strict'
const Bluebird = require('bluebird')
const _ = require('lodash')
const ipc = require('node-ipc')
const sdk = require('etcher-sdk')
@ -86,14 +85,37 @@ const handleError = (error) => {
terminate(EXIT_CODES.GENERAL_ERROR)
}
function lastMapValue(map) {
let value
for (value of map.values()){
/**
* @summary returns the last value in a Map
* @param {Map} map - map
* @returns {Any} the last value of the map (in insertion order)
*
* @example
* const last = lastMapValue(map)
*/
const lastMapValue = (map) => {
let value = null
for (value of map.values()) {
// eslint-disable-next-line no-empty
}
return value
}
function writeAndValidate(source, destinations, verify, onProgress, onFail, onFinish, onError) {
/**
* @summary writes the source to the destinations and valiates the writes
* @param {SourceDestination} source - source
* @param {SourceDestination[]} destinations - destinations
* @param {Boolean} verify - whether to validate the writes or not
* @param {Function} onProgress - function to call on progress
* @param {Function} onFail - function to call on fail
* @param {Function} onFinish - function to call on finish
* @param {Function} onError - function to call on error
* @returns {Promise<void>}
*
* @example
* writeAndValidate(source, destinations, verify, onProgress, onFail, onFinish, onError)
*/
const writeAndValidate = (source, destinations, verify, onProgress, onFail, onFinish, onError) => {
return source.getInnerSource()
.then((innerSource) => {
return sdk.multiWrite.pipeSourceToDestinations(
@ -101,7 +123,7 @@ function writeAndValidate(source, destinations, verify, onProgress, onFail, onFi
destinations,
onFail,
onProgress,
verify,
verify
)
})
.then(({ failures, bytesWritten }) => {
@ -113,7 +135,7 @@ function writeAndValidate(source, destinations, verify, onProgress, onFail, onFi
bytesWritten,
devices: {
failed: failures.size,
successful: destinations.length - failures.size,
successful: destinations.length - failures.size
},
errors: []
}
@ -152,8 +174,6 @@ ipc.connectTo(IPC_SERVER_ID, () => {
terminate(EXIT_CODES.SUCCESS)
})
let writer = null
ipc.of[IPC_SERVER_ID].on('write', (options) => {
/**
* @summary Progress handler
@ -209,19 +229,21 @@ ipc.connectTo(IPC_SERVER_ID, () => {
/**
* @summary Failure handler (non-fatal errors)
* @param {Object} error - MultiDestinationError
* @param {SourceDestination} destination - destination
* @param {Error} error - error
* @example
* writer.on('fail', onFail)
*/
const onFail = (destination, error) => {
ipc.of[IPC_SERVER_ID].emit('fail', {
device: destination.drive, // TODO: device should be destination
// TODO: device should be destination
device: destination.drive,
error: errors.toJSON(error)
})
}
const destinations = _.map(options.destinations, 'device')
const dests = options.destinations.map((destination) => {
const dests = _.map(options.destinations, (destination) => {
return new sdk.sourceDestination.BlockDevice(destination, options.unmountOnSuccess)
})
const source = new sdk.sourceDestination.File(options.imagePath, sdk.sourceDestination.File.OpenFlags.Read)

View File

@ -18,6 +18,7 @@
const sdk = require('etcher-sdk')
const _ = require('lodash')
// eslint-disable-next-line node/no-extraneous-require
const mime = require('mime')
const path = require('path')
@ -40,7 +41,7 @@ exports.getCompressedExtensions = () => {
for (const [ mimetype, cls ] of sdk.sourceDestination.SourceDestination.mimetypes.entries()) {
if (cls.prototype instanceof sdk.sourceDestination.CompressedSource) {
const mtype = mime.getExtension(mimetype)
if (mtype != null) {
if (mtype !== null) {
result.push(mtype)
}
}