mirror of
https://github.com/balena-io/etcher.git
synced 2025-07-23 11:16:39 +00:00
Show raspberry pi usbboot update progress in devices list
This commit is contained in:
parent
a8a75f22b2
commit
d07d535993
@ -28,8 +28,12 @@ var angular = require('angular')
|
|||||||
|
|
||||||
const electron = require('electron')
|
const electron = require('electron')
|
||||||
const Bluebird = require('bluebird')
|
const Bluebird = require('bluebird')
|
||||||
|
const sdk = require('etcher-sdk')
|
||||||
|
const _ = require('lodash')
|
||||||
const semver = require('semver')
|
const semver = require('semver')
|
||||||
const uuidV4 = require('uuid/v4')
|
const uuidV4 = require('uuid/v4')
|
||||||
|
|
||||||
|
>>>>>>> Show raspberry pi usbboot update progress in devices list
|
||||||
const EXIT_CODES = require('../../shared/exit-codes')
|
const EXIT_CODES = require('../../shared/exit-codes')
|
||||||
const messages = require('../../shared/messages')
|
const messages = require('../../shared/messages')
|
||||||
const s3Packages = require('../../shared/s3-packages')
|
const s3Packages = require('../../shared/s3-packages')
|
||||||
@ -229,35 +233,77 @@ app.run(() => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
app.run(($timeout) => {
|
|
||||||
function updateDrives() {
|
|
||||||
const drives = Array.from(driveScanner.drives)
|
|
||||||
const BLACKLISTED_DRIVES = settings.has('driveBlacklist')
|
|
||||||
? settings.get('driveBlacklist').split(',')
|
|
||||||
: []
|
|
||||||
|
|
||||||
|
app.run(($timeout) => {
|
||||||
|
const BLACKLISTED_DRIVES = settings.has('driveBlacklist')
|
||||||
|
? settings.get('driveBlacklist').split(',')
|
||||||
|
: []
|
||||||
|
|
||||||
|
function driveIsAllowed(drive) {
|
||||||
|
return !(
|
||||||
|
BLACKLISTED_DRIVES.includes(drive.devicePath) ||
|
||||||
|
BLACKLISTED_DRIVES.includes(drive.device) ||
|
||||||
|
BLACKLISTED_DRIVES.includes(drive.raw)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function prepareDrive(drive) {
|
||||||
|
if (drive instanceof sdk.sourceDestination.BlockDevice) {
|
||||||
|
return drive.drive
|
||||||
|
} else if (drive instanceof sdk.sourceDestination.UsbbootDrive) {
|
||||||
|
// This is a workaround etcher expecting a device string and a size
|
||||||
|
drive.device = drive.usbDevice.portId
|
||||||
|
drive.size = 0
|
||||||
|
drive.progress = 0
|
||||||
|
drive.on('progress', (progress) => {
|
||||||
|
updateDriveProgress(drive, progress)
|
||||||
|
})
|
||||||
|
return drive
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setDrives(drives) {
|
||||||
|
drives = _.values(drives)
|
||||||
|
availableDrives.setDrives(drives)
|
||||||
// Safely trigger a digest cycle.
|
// Safely trigger a digest cycle.
|
||||||
// In some cases, AngularJS doesn't acknowledge that the
|
// In some cases, AngularJS doesn't acknowledge that the
|
||||||
// available drives list has changed, and incorrectly
|
// available drives list has changed, and incorrectly
|
||||||
// keeps asking the user to "Connect a drive".
|
// keeps asking the user to "Connect a drive".
|
||||||
$timeout(() => {
|
$timeout()
|
||||||
const allowedDrives = drives
|
|
||||||
.filter((drive) => {
|
|
||||||
return !(
|
|
||||||
BLACKLISTED_DRIVES.includes(drive.devicePath) ||
|
|
||||||
BLACKLISTED_DRIVES.includes(drive.device) ||
|
|
||||||
BLACKLISTED_DRIVES.includes(drive.raw)
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.map((drive) => {
|
|
||||||
// TODO: we should be able to use the SourceDestination `drive` directly
|
|
||||||
return drive.drive
|
|
||||||
})
|
|
||||||
availableDrives.setDrives(allowedDrives)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
driveScanner.on('attach', updateDrives)
|
|
||||||
driveScanner.on('detach', updateDrives)
|
function getDrives() {
|
||||||
|
return _.keyBy(availableDrives.getDrives() || [], 'device')
|
||||||
|
}
|
||||||
|
|
||||||
|
function addDrive(drive) {
|
||||||
|
drive = prepareDrive(drive)
|
||||||
|
if (!driveIsAllowed(drive)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const drives = getDrives()
|
||||||
|
drives[drive.device] = drive
|
||||||
|
setDrives(drives)
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeDrive(drive) {
|
||||||
|
drive = prepareDrive(drive)
|
||||||
|
const drives = getDrives()
|
||||||
|
delete drives[drive.device]
|
||||||
|
setDrives(drives)
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateDriveProgress(drive, progress) {
|
||||||
|
const drives = getDrives()
|
||||||
|
const drive_ = drives[drive.device]
|
||||||
|
if (drive !== undefined) {
|
||||||
|
drive.progress = progress
|
||||||
|
setDrives(drives)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
driveScanner.on('attach', addDrive)
|
||||||
|
driveScanner.on('detach', removeDrive)
|
||||||
|
|
||||||
driveScanner.on('error', (error) => {
|
driveScanner.on('error', (error) => {
|
||||||
// Stop the drive scanning loop in case of errors,
|
// Stop the drive scanning loop in case of errors,
|
||||||
|
@ -174,7 +174,7 @@ class FileSelector extends React.PureComponent {
|
|||||||
if (!supportedFormats.isSupportedImage(image.path)) {
|
if (!supportedFormats.isSupportedImage(image.path)) {
|
||||||
const invalidImageError = errors.createUserError({
|
const invalidImageError = errors.createUserError({
|
||||||
title: 'Invalid image',
|
title: 'Invalid image',
|
||||||
description: messages.error.invalidImage(image)
|
description: messages.error.invalidImage(image.path)
|
||||||
})
|
})
|
||||||
|
|
||||||
osDialog.showError(invalidImageError)
|
osDialog.showError(invalidImageError)
|
||||||
@ -229,7 +229,7 @@ class FileSelector extends React.PureComponent {
|
|||||||
// An easy way so we can quickly identify if we're making use of
|
// An easy way so we can quickly identify if we're making use of
|
||||||
// certain features without printing pages of text to DevTools.
|
// certain features without printing pages of text to DevTools.
|
||||||
image.logo = Boolean(image.logo)
|
image.logo = Boolean(image.logo)
|
||||||
image.bmap = Boolean(image.bmap)
|
image.blockMap = Boolean(image.blockMap)
|
||||||
|
|
||||||
analytics.logEvent('Select image', {
|
analytics.logEvent('Select image', {
|
||||||
image,
|
image,
|
||||||
|
@ -211,9 +211,7 @@ exports.getImageSize = () => {
|
|||||||
return _.get(store.getState().toJS(), [
|
return _.get(store.getState().toJS(), [
|
||||||
'selection',
|
'selection',
|
||||||
'image',
|
'image',
|
||||||
'size',
|
'size'
|
||||||
'final',
|
|
||||||
'value'
|
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,8 +67,7 @@ const flashStateNoNilFields = [
|
|||||||
*/
|
*/
|
||||||
const selectImageNoNilFields = [
|
const selectImageNoNilFields = [
|
||||||
'path',
|
'path',
|
||||||
'extension',
|
'extension'
|
||||||
'size'
|
|
||||||
]
|
]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -406,29 +405,11 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_.isPlainObject(action.data.size)) {
|
|
||||||
throw errors.createError({
|
|
||||||
title: `Invalid image size: ${action.data.size}`
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const MINIMUM_IMAGE_SIZE = 0
|
const MINIMUM_IMAGE_SIZE = 0
|
||||||
|
|
||||||
if (!_.isInteger(action.data.size.original) || action.data.size.original < MINIMUM_IMAGE_SIZE) {
|
if ((action.data.size !== undefined) && (action.data.size < MINIMUM_IMAGE_SIZE)) {
|
||||||
throw errors.createError({
|
throw errors.createError({
|
||||||
title: `Invalid original image size: ${action.data.size.original}`
|
title: `Invalid image size: ${action.data.size}`
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_.isInteger(action.data.size.final.value) || action.data.size.final.value < MINIMUM_IMAGE_SIZE) {
|
|
||||||
throw errors.createError({
|
|
||||||
title: `Invalid final image size: ${action.data.size.final.value}`
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_.isBoolean(action.data.size.final.estimation)) {
|
|
||||||
throw errors.createError({
|
|
||||||
title: `Invalid final image size estimation flag: ${action.data.size.final.estimation}`
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,6 @@ const sdk = require('etcher-sdk')
|
|||||||
const process = require('process')
|
const process = require('process')
|
||||||
|
|
||||||
const settings = require('../models/settings')
|
const settings = require('../models/settings')
|
||||||
const permissions = require('../../../shared/permissions')
|
|
||||||
|
|
||||||
function includeSystemDrives() {
|
function includeSystemDrives() {
|
||||||
return settings.get('unsafeMode') && !settings.get('disableUnsafeMode')
|
return settings.get('unsafeMode') && !settings.get('disableUnsafeMode')
|
||||||
@ -30,12 +29,11 @@ const adapters = [
|
|||||||
new sdk.scanner.adapters.BlockDeviceAdapter(includeSystemDrives)
|
new sdk.scanner.adapters.BlockDeviceAdapter(includeSystemDrives)
|
||||||
]
|
]
|
||||||
|
|
||||||
permissions.isElevated()
|
// Can't use permissions.isElevated() here as it returns a promise and we need to set
|
||||||
.then((isElevated) => {
|
// module.exports = scanner right now.
|
||||||
if ((process.platform !== 'linux') || isElevated) {
|
if ((process.platform !== 'linux') || (process.geteuid() === 0)) {
|
||||||
adapters.push(new sdk.scanner.adapters.UsbbootDeviceAdapter())
|
adapters.push(new sdk.scanner.adapters.UsbbootDeviceAdapter())
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
const scanner = new sdk.scanner.Scanner(adapters)
|
const scanner = new sdk.scanner.Scanner(adapters)
|
||||||
|
|
||||||
|
@ -188,6 +188,7 @@ module.exports = function (
|
|||||||
exceptionReporter.report(error)
|
exceptionReporter.report(error)
|
||||||
}
|
}
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
|
availableDrives.setDrives([])
|
||||||
driveScanner.start()
|
driveScanner.start()
|
||||||
unsubscribe()
|
unsubscribe()
|
||||||
})
|
})
|
||||||
|
@ -19,10 +19,11 @@
|
|||||||
const _ = require('lodash')
|
const _ = require('lodash')
|
||||||
const Bluebird = require('bluebird')
|
const Bluebird = require('bluebird')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
const sdk = require('etcher-sdk')
|
||||||
|
|
||||||
const store = require('../../../models/store')
|
const store = require('../../../models/store')
|
||||||
const messages = require('../../../../../shared/messages')
|
const messages = require('../../../../../shared/messages')
|
||||||
const errors = require('../../../../../shared/errors')
|
const errors = require('../../../../../shared/errors')
|
||||||
const imageStream = require('../../../../../sdk/image-stream')
|
|
||||||
const supportedFormats = require('../../../../../shared/supported-formats')
|
const supportedFormats = require('../../../../../shared/supported-formats')
|
||||||
const analytics = require('../../../modules/analytics')
|
const analytics = require('../../../modules/analytics')
|
||||||
const settings = require('../../../models/settings')
|
const settings = require('../../../models/settings')
|
||||||
@ -124,7 +125,7 @@ module.exports = function (
|
|||||||
// An easy way so we can quickly identify if we're making use of
|
// An easy way so we can quickly identify if we're making use of
|
||||||
// certain features without printing pages of text to DevTools.
|
// certain features without printing pages of text to DevTools.
|
||||||
image.logo = Boolean(image.logo)
|
image.logo = Boolean(image.logo)
|
||||||
image.bmap = Boolean(image.bmap)
|
image.blockMap = Boolean(image.blockMap)
|
||||||
|
|
||||||
return analytics.logEvent('Select image', {
|
return analytics.logEvent('Select image', {
|
||||||
image,
|
image,
|
||||||
@ -145,10 +146,33 @@ module.exports = function (
|
|||||||
* ImageSelectionController.selectImageByPath('path/to/image.img');
|
* ImageSelectionController.selectImageByPath('path/to/image.img');
|
||||||
*/
|
*/
|
||||||
this.selectImageByPath = (imagePath) => {
|
this.selectImageByPath = (imagePath) => {
|
||||||
imageStream.getImageMetadata(imagePath)
|
if (!supportedFormats.isSupportedImage(imagePath)) {
|
||||||
.then((imageMetadata) => {
|
const invalidImageError = errors.createUserError({
|
||||||
$timeout(() => {
|
title: 'Invalid image',
|
||||||
this.selectImage(imageMetadata)
|
description: messages.error.invalidImage(imagePath)
|
||||||
|
})
|
||||||
|
|
||||||
|
osDialog.showError(invalidImageError)
|
||||||
|
analytics.logEvent('Invalid image', { path: imagePath })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const source = new sdk.sourceDestination.File(imagePath, sdk.sourceDestination.File.OpenFlags.Read)
|
||||||
|
source.getInnerSource()
|
||||||
|
.then((innerSource) => {
|
||||||
|
return innerSource.getMetadata()
|
||||||
|
.then((metadata) => {
|
||||||
|
return innerSource.getPartitionTable()
|
||||||
|
.then((partitionTable) => {
|
||||||
|
if (partitionTable !== undefined) {
|
||||||
|
metadata.hasMBR = true
|
||||||
|
metadata.partitions = partitionTable.partitions
|
||||||
|
}
|
||||||
|
$timeout(() => {
|
||||||
|
metadata.path = imagePath
|
||||||
|
metadata.extension = path.extname(imagePath).slice(1)
|
||||||
|
this.selectImage(metadata)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@ -156,10 +180,14 @@ module.exports = function (
|
|||||||
title: 'Error opening image',
|
title: 'Error opening image',
|
||||||
description: messages.error.openImage(path.basename(imagePath), error.message)
|
description: messages.error.openImage(path.basename(imagePath), error.message)
|
||||||
})
|
})
|
||||||
|
|
||||||
osDialog.showError(imageError)
|
osDialog.showError(imageError)
|
||||||
analytics.logException(error)
|
analytics.logException(error)
|
||||||
})
|
})
|
||||||
|
.then(() => {
|
||||||
|
return innerSource.close()
|
||||||
|
.catch(() => {})
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -22,9 +22,6 @@ const ipc = require('node-ipc')
|
|||||||
const sdk = require('etcher-sdk')
|
const sdk = require('etcher-sdk')
|
||||||
const EXIT_CODES = require('../../shared/exit-codes')
|
const EXIT_CODES = require('../../shared/exit-codes')
|
||||||
const errors = require('../../shared/errors')
|
const errors = require('../../shared/errors')
|
||||||
const ImageWriter = require('../../sdk/writer')
|
|
||||||
const BlockWriteStream = require('../../sdk/writer/block-write-stream')
|
|
||||||
const BlockReadStream = require('../../sdk/writer/block-read-stream')
|
|
||||||
|
|
||||||
ipc.config.id = process.env.IPC_CLIENT_ID
|
ipc.config.id = process.env.IPC_CLIENT_ID
|
||||||
ipc.config.socketRoot = process.env.IPC_SOCKET_ROOT
|
ipc.config.socketRoot = process.env.IPC_SOCKET_ROOT
|
||||||
@ -99,13 +96,14 @@ function runVerifier(verifier, onFail) {
|
|||||||
|
|
||||||
function pipeRegularSourceToDestination(source, destination, verify, onProgress, onFail) {
|
function pipeRegularSourceToDestination(source, destination, verify, onProgress, onFail) {
|
||||||
let checksum
|
let checksum
|
||||||
|
let sparse
|
||||||
let sourceMetadata
|
let sourceMetadata
|
||||||
let step = 'flashing'
|
let step = 'flashing'
|
||||||
let lastPosition = 0
|
let lastPosition = 0
|
||||||
const errors = new Map() // destination -> error map
|
const errors = new Map() // destination -> error map
|
||||||
const state = {
|
const state = {
|
||||||
active: destination.destinations.length,
|
active: destination.destinations.size,
|
||||||
flashing: destination.destinations.length,
|
flashing: destination.destinations.size,
|
||||||
verifying: 0,
|
verifying: 0,
|
||||||
failed: 0,
|
failed: 0,
|
||||||
successful: 0,
|
successful: 0,
|
||||||
@ -114,7 +112,7 @@ function pipeRegularSourceToDestination(source, destination, verify, onProgress,
|
|||||||
function updateState() {
|
function updateState() {
|
||||||
state.type = step
|
state.type = step
|
||||||
state.failed = errors.size
|
state.failed = errors.size
|
||||||
state.active = destination.destinations.length - state.failed
|
state.active = destination.destinations.size - state.failed
|
||||||
if (step === 'flashing') {
|
if (step === 'flashing') {
|
||||||
state.flashing = state.active
|
state.flashing = state.active
|
||||||
state.verifying = 0
|
state.verifying = 0
|
||||||
@ -127,28 +125,48 @@ function pipeRegularSourceToDestination(source, destination, verify, onProgress,
|
|||||||
}
|
}
|
||||||
function onProgress2(progressEvent) {
|
function onProgress2(progressEvent) {
|
||||||
lastPosition = progressEvent.position
|
lastPosition = progressEvent.position
|
||||||
progressEvent.percentage = progressEvent.position / sourceMetadata.size * 100
|
let size
|
||||||
|
if (sparse && (sourceMetadata.blockMap !== undefined)) {
|
||||||
|
size = sourceMetadata.blockMap.mappedBlockCount * sourceMetadata.blockMap.blockSize
|
||||||
|
progressEvent.percentage = progressEvent.bytes / size * 100
|
||||||
|
} else {
|
||||||
|
size = sourceMetadata.size
|
||||||
|
progressEvent.percentage = progressEvent.position / size * 100
|
||||||
|
}
|
||||||
// NOTE: We need to guard against this becoming Infinity,
|
// NOTE: We need to guard against this becoming Infinity,
|
||||||
// because that value isn't transmitted properly over IPC and becomes `null`
|
// because that value isn't transmitted properly over IPC and becomes `null`
|
||||||
progressEvent.eta = progressEvent.speed ? (sourceMetadata.size - progressEvent.position) / progressEvent.speed : null
|
progressEvent.eta = progressEvent.speed ? (size - progressEvent.bytes) / progressEvent.speed : null
|
||||||
progressEvent.totalSpeed = progressEvent.speed * state.active
|
progressEvent.totalSpeed = progressEvent.speed * state.active
|
||||||
Object.assign(progressEvent, state)
|
Object.assign(progressEvent, state)
|
||||||
onProgress(progressEvent)
|
onProgress(progressEvent)
|
||||||
}
|
}
|
||||||
return Promise.all([ source.createReadStream(), destination.createWriteStream(), source.getMetadata() ])
|
return source.canCreateSparseReadStream()
|
||||||
|
.then((_sparse) => {
|
||||||
|
sparse = _sparse
|
||||||
|
let sourceStream
|
||||||
|
let destinationStream
|
||||||
|
if (sparse) {
|
||||||
|
// TODO: calculate checksums in source if needed
|
||||||
|
sourceStream = source.createSparseReadStream()
|
||||||
|
destinationStream = destination.createSparseWriteStream()
|
||||||
|
} else {
|
||||||
|
sourceStream = source.createReadStream()
|
||||||
|
destinationStream = destination.createWriteStream()
|
||||||
|
}
|
||||||
|
return Promise.all([ sourceStream, destinationStream, source.getMetadata() ])
|
||||||
|
})
|
||||||
.then(([ sourceStream, destinationStream, metadata ]) => {
|
.then(([ sourceStream, destinationStream, metadata ]) => {
|
||||||
destinationStream.on('fail', (error) => {
|
destinationStream.on('fail', (error) => {
|
||||||
errors.set(error.destination, error.error)
|
errors.set(error.destination, error.error)
|
||||||
updateState()
|
updateState()
|
||||||
onFail({ device: error.destination.drive, error: error.error }) // TODO: device should be error.destination
|
onFail({ device: error.destination.drive, error: error.error }) // TODO: device should be error.destination
|
||||||
onProgress2({ eta: 0, speed: 0, position: lastPosition }) // TODO: this is not needed if a success / error screen is shown
|
|
||||||
})
|
})
|
||||||
sourceMetadata = metadata
|
sourceMetadata = metadata
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let done = false
|
let done = false
|
||||||
sourceStream.on('error', reject)
|
sourceStream.on('error', reject)
|
||||||
destinationStream.on('progress', onProgress2)
|
destinationStream.on('progress', onProgress2)
|
||||||
if (verify) {
|
if (verify && !sparse) {
|
||||||
const hasher = sdk.sourceDestination.createHasher()
|
const hasher = sdk.sourceDestination.createHasher()
|
||||||
hasher.on('checksum', (cs) => {
|
hasher.on('checksum', (cs) => {
|
||||||
checksum = cs
|
checksum = cs
|
||||||
@ -160,7 +178,7 @@ function pipeRegularSourceToDestination(source, destination, verify, onProgress,
|
|||||||
}
|
}
|
||||||
destinationStream.on('done', () => {
|
destinationStream.on('done', () => {
|
||||||
done = true;
|
done = true;
|
||||||
if (!verify || (checksum !== undefined)) {
|
if (sparse || !verify || (checksum !== undefined)) {
|
||||||
resolve()
|
resolve()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -176,7 +194,7 @@ function pipeRegularSourceToDestination(source, destination, verify, onProgress,
|
|||||||
if (verify) {
|
if (verify) {
|
||||||
step = 'check'
|
step = 'check'
|
||||||
updateState()
|
updateState()
|
||||||
const verifier = destination.createVerifier(checksum, sourceMetadata.size)
|
const verifier = destination.createVerifier(sparse ? sourceMetadata.blockMap : checksum, sourceMetadata.size) // TODO: ensure blockMap exists
|
||||||
verifier.on('progress', onProgress2)
|
verifier.on('progress', onProgress2)
|
||||||
return runVerifier(verifier, onFail)
|
return runVerifier(verifier, onFail)
|
||||||
}
|
}
|
||||||
@ -184,7 +202,7 @@ function pipeRegularSourceToDestination(source, destination, verify, onProgress,
|
|||||||
.then(() => {
|
.then(() => {
|
||||||
step = 'finished'
|
step = 'finished'
|
||||||
updateState()
|
updateState()
|
||||||
onProgress2({ speed: 0, position: sourceMetadata.size })
|
//onProgress2({ speed: 0, position: sourceMetadata.size })
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const result = {
|
const result = {
|
||||||
@ -281,6 +299,8 @@ ipc.connectTo(IPC_SERVER_ID, () => {
|
|||||||
terminate(exitCode)
|
terminate(exitCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ipc.of[IPC_SERVER_ID].on('cancel', onAbort)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @summary Error handler
|
* @summary Error handler
|
||||||
* @param {Error} error - error
|
* @param {Error} error - error
|
||||||
@ -306,30 +326,22 @@ ipc.connectTo(IPC_SERVER_ID, () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
writer = new ImageWriter({ // TODO: remove
|
|
||||||
verify: options.validateWriteOnSuccess,
|
|
||||||
unmountOnSuccess: options.unmountOnSuccess,
|
|
||||||
checksumAlgorithms: options.checksumAlgorithms || []
|
|
||||||
})
|
|
||||||
|
|
||||||
writer.on('abort', onAbort)
|
|
||||||
|
|
||||||
const destinations = _.map(options.destinations, 'drive.device')
|
const destinations = _.map(options.destinations, 'drive.device')
|
||||||
const dests = options.destinations.map((destination) => {
|
const dests = options.destinations.map((destination) => {
|
||||||
return new sdk.sourceDestination.BlockDevice(destination)
|
return new sdk.sourceDestination.BlockDevice(destination, options.unmountOnSuccess)
|
||||||
|
})
|
||||||
|
const source = new sdk.sourceDestination.File(options.imagePath, sdk.sourceDestination.File.OpenFlags.Read)
|
||||||
|
source.getInnerSource()
|
||||||
|
.then((innerSource) => {
|
||||||
|
return Bluebird.using(
|
||||||
|
sourceDestinationDisposer(innerSource),
|
||||||
|
sourceDestinationDisposer(new sdk.sourceDestination.MultiDestination(dests)),
|
||||||
|
(innerSource, destination) => {
|
||||||
|
destination.on('fail', onFail)
|
||||||
|
return pipeRegularSourceToDestination(innerSource, destination, options.validateWriteOnSuccess, onProgress, onFail)
|
||||||
|
}
|
||||||
|
)
|
||||||
})
|
})
|
||||||
Bluebird.using(
|
|
||||||
sourceDestinationDisposer(new sdk.sourceDestination.File(options.imagePath, sdk.sourceDestination.File.OpenFlags.Read)),
|
|
||||||
sourceDestinationDisposer(new sdk.sourceDestination.MultiDestination(dests)),
|
|
||||||
(source, destination) => {
|
|
||||||
return source.getInnerSource()
|
|
||||||
.then((innerSource) => {
|
|
||||||
return Bluebird.using(sourceDestinationDisposer(innerSource), (innerSource) => {
|
|
||||||
return pipeRegularSourceToDestination(innerSource, destination, options.validateWriteOnSuccess, onProgress, onFail)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.then((results) => {
|
.then((results) => {
|
||||||
onFinish(results)
|
onFinish(results)
|
||||||
})
|
})
|
||||||
@ -343,12 +355,6 @@ ipc.connectTo(IPC_SERVER_ID, () => {
|
|||||||
log(`Validate on success: ${options.validateWriteOnSuccess}`)
|
log(`Validate on success: ${options.validateWriteOnSuccess}`)
|
||||||
})
|
})
|
||||||
|
|
||||||
ipc.of[IPC_SERVER_ID].on('cancel', () => {
|
|
||||||
if (writer) {
|
|
||||||
writer.abort()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
ipc.of[IPC_SERVER_ID].on('connect', () => {
|
ipc.of[IPC_SERVER_ID].on('connect', () => {
|
||||||
log(`Successfully connected to IPC server: ${IPC_SERVER_ID}, socket root ${ipc.config.socketRoot}`)
|
log(`Successfully connected to IPC server: ${IPC_SERVER_ID}, socket root ${ipc.config.socketRoot}`)
|
||||||
ipc.of[IPC_SERVER_ID].emit('ready', {})
|
ipc.of[IPC_SERVER_ID].emit('ready', {})
|
||||||
|
@ -182,8 +182,8 @@ module.exports = {
|
|||||||
].join(' ')
|
].join(' ')
|
||||||
},
|
},
|
||||||
|
|
||||||
invalidImage: (image) => {
|
invalidImage: (imagePath) => {
|
||||||
return `${image.path} is not a supported image type.`
|
return `${imagePath} is not a supported image type.`
|
||||||
},
|
},
|
||||||
|
|
||||||
openImage: (imageBasename, errorMessage) => {
|
openImage: (imageBasename, errorMessage) => {
|
||||||
|
22
npm-shrinkwrap.json
generated
22
npm-shrinkwrap.json
generated
@ -58,6 +58,10 @@
|
|||||||
"version": "0.0.30",
|
"version": "0.0.30",
|
||||||
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-0.0.30.tgz"
|
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-0.0.30.tgz"
|
||||||
},
|
},
|
||||||
|
"@types/events": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/events/-/events-1.2.0.tgz"
|
||||||
|
},
|
||||||
"@types/file-type": {
|
"@types/file-type": {
|
||||||
"version": "5.2.1",
|
"version": "5.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/file-type/-/file-type-5.2.1.tgz"
|
"resolved": "https://registry.npmjs.org/@types/file-type/-/file-type-5.2.1.tgz"
|
||||||
@ -126,6 +130,10 @@
|
|||||||
"version": "3.4.4",
|
"version": "3.4.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.4.tgz"
|
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.4.tgz"
|
||||||
},
|
},
|
||||||
|
"@types/yauzl": {
|
||||||
|
"version": "2.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.0.tgz"
|
||||||
|
},
|
||||||
"7zip-bin": {
|
"7zip-bin": {
|
||||||
"version": "2.4.1",
|
"version": "2.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-2.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-2.4.1.tgz",
|
||||||
@ -661,8 +669,8 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"aws-sdk": {
|
"aws-sdk": {
|
||||||
"version": "2.260.1",
|
"version": "2.263.1",
|
||||||
"resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.260.1.tgz",
|
"resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.263.1.tgz",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ieee754": {
|
"ieee754": {
|
||||||
"version": "1.1.8",
|
"version": "1.1.8",
|
||||||
@ -3060,7 +3068,7 @@
|
|||||||
},
|
},
|
||||||
"etcher-sdk": {
|
"etcher-sdk": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "git://github.com/resin-io-modules/etcher-sdk.git#b12e63b49c4a01305a2809b504859a3940927399",
|
"resolved": "git://github.com/resin-io-modules/etcher-sdk.git#bda51535715edb3691b783973801434bb3d78b30",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/lodash": {
|
"@types/lodash": {
|
||||||
"version": "4.14.110",
|
"version": "4.14.110",
|
||||||
@ -3086,6 +3094,10 @@
|
|||||||
"version": "3.5.1",
|
"version": "3.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz"
|
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz"
|
||||||
},
|
},
|
||||||
|
"fd-slicer": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz"
|
||||||
|
},
|
||||||
"file-type": {
|
"file-type": {
|
||||||
"version": "8.0.0",
|
"version": "8.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/file-type/-/file-type-8.0.0.tgz"
|
"resolved": "https://registry.npmjs.org/file-type/-/file-type-8.0.0.tgz"
|
||||||
@ -3129,6 +3141,10 @@
|
|||||||
"xmlbuilder": {
|
"xmlbuilder": {
|
||||||
"version": "9.0.7",
|
"version": "9.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz"
|
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz"
|
||||||
|
},
|
||||||
|
"yauzl": {
|
||||||
|
"version": "2.9.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.9.2.tgz"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -63,7 +63,7 @@
|
|||||||
"debug": "3.1.0",
|
"debug": "3.1.0",
|
||||||
"drivelist": "6.4.6",
|
"drivelist": "6.4.6",
|
||||||
"electron-is-running-in-asar": "1.0.0",
|
"electron-is-running-in-asar": "1.0.0",
|
||||||
"etcher-sdk": "github:resin-io-modules/etcher-sdk#b12e63b49c4a01305a2809b504859a3940927399",
|
"etcher-sdk": "github:resin-io-modules/etcher-sdk#bda51535715edb3691b783973801434bb3d78b30",
|
||||||
"file-type": "4.1.0",
|
"file-type": "4.1.0",
|
||||||
"flexboxgrid": "6.3.0",
|
"flexboxgrid": "6.3.0",
|
||||||
"gpt": "1.0.0",
|
"gpt": "1.0.0",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user