mirror of
https://github.com/balena-io/etcher.git
synced 2025-07-16 07:46:31 +00:00
Merge pull request #1807 from resin-io/patch-1136
feat(gui): Display image size when drive too small Close #1136 Close #2004
This commit is contained in:
commit
ad7c8760eb
@ -18,6 +18,8 @@
|
||||
|
||||
const _ = require('lodash')
|
||||
const pathIsInside = require('path-is-inside')
|
||||
const prettyBytes = require('pretty-bytes')
|
||||
const messages = require('./messages')
|
||||
|
||||
/**
|
||||
* @summary The default unknown size for things such as images and drives
|
||||
@ -299,72 +301,6 @@ exports.isDriveSizeLarge = (drive) => {
|
||||
return _.get(drive, [ 'size' ], UNKNOWN_SIZE) > exports.LARGE_DRIVE_SIZE
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Drive/image compatibility status messages.
|
||||
* @public
|
||||
* @type {Object}
|
||||
*
|
||||
* @description
|
||||
* Status messages intended to be shown to the user.
|
||||
*/
|
||||
exports.COMPATIBILITY_STATUS_MESSAGES = {
|
||||
|
||||
/**
|
||||
* @property {String} SIZE_NOT_RECOMMENDED
|
||||
* @memberof COMPATIBILITY_STATUS_MESSAGES
|
||||
*
|
||||
* @description
|
||||
* The image and drive compatibility is not recommended; happens when the
|
||||
* actual drive size is smaller than the image's recommended drive size.
|
||||
*/
|
||||
SIZE_NOT_RECOMMENDED: 'Not Recommended',
|
||||
|
||||
/**
|
||||
* @property {String} TOO_SMALL
|
||||
* @memberof COMPATIBILITY_STATUS_MESSAGES
|
||||
*
|
||||
* @description
|
||||
* The drive is too small for the image.
|
||||
*/
|
||||
TOO_SMALL: 'Too Small For Image',
|
||||
|
||||
/**
|
||||
* @property {String} LOCKED
|
||||
* @memberof COMPATIBILITY_STATUS_MESSAGES
|
||||
*
|
||||
* @description
|
||||
* The drive is locked (e.g. the lock-tab on SD cards) and cannot be written to.
|
||||
*/
|
||||
LOCKED: 'Locked',
|
||||
|
||||
/**
|
||||
* @property {String} SYSTEM
|
||||
* @memberof COMPATIBILITY_STATUS_MESSAGES
|
||||
*
|
||||
* @description
|
||||
* The drive is a system drive and should not be written to.
|
||||
*/
|
||||
SYSTEM: 'System Drive',
|
||||
|
||||
/**
|
||||
* @property {String} CONTAINS_IMAGE
|
||||
* @memberof COMPATIBILITY_STATUS_MESSAGES
|
||||
*
|
||||
* @description
|
||||
* The drive contains the image and therefore cannot be written to.
|
||||
*/
|
||||
CONTAINS_IMAGE: 'Drive Contains Image',
|
||||
|
||||
/**
|
||||
* @property {String} LARGE_DRIVE
|
||||
* @memberof COMPATIBILITY_STATUS_MESSAGES
|
||||
*
|
||||
* @description
|
||||
* The drive is large and therefore likely not a medium you want to write to.
|
||||
*/
|
||||
LARGE_DRIVE: 'Large Drive'
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Drive/image compatibility status types.
|
||||
* @public
|
||||
@ -428,37 +364,39 @@ exports.getDriveImageCompatibilityStatuses = (drive, image) => {
|
||||
if (exports.isSourceDrive(drive, image)) {
|
||||
statusList.push({
|
||||
type: exports.COMPATIBILITY_STATUS_TYPES.ERROR,
|
||||
message: exports.COMPATIBILITY_STATUS_MESSAGES.CONTAINS_IMAGE
|
||||
message: messages.compatibility.containsImage()
|
||||
})
|
||||
} else if (exports.isDriveLocked(drive)) {
|
||||
statusList.push({
|
||||
type: exports.COMPATIBILITY_STATUS_TYPES.ERROR,
|
||||
message: exports.COMPATIBILITY_STATUS_MESSAGES.LOCKED
|
||||
message: messages.compatibility.locked()
|
||||
})
|
||||
} else if (!_.isNil(drive) && !_.isNil(drive.size) && !exports.isDriveLargeEnough(drive, image)) {
|
||||
const imageSize = _.get(image, [ 'size', 'final', 'estimation' ]) ? image.size.original : image.size.final.value
|
||||
const relativeBytes = imageSize - drive.size
|
||||
statusList.push({
|
||||
type: exports.COMPATIBILITY_STATUS_TYPES.ERROR,
|
||||
message: exports.COMPATIBILITY_STATUS_MESSAGES.TOO_SMALL
|
||||
message: messages.compatibility.tooSmall(prettyBytes(relativeBytes))
|
||||
})
|
||||
} else {
|
||||
if (exports.isSystemDrive(drive)) {
|
||||
statusList.push({
|
||||
type: exports.COMPATIBILITY_STATUS_TYPES.WARNING,
|
||||
message: exports.COMPATIBILITY_STATUS_MESSAGES.SYSTEM
|
||||
message: messages.compatibility.system()
|
||||
})
|
||||
}
|
||||
|
||||
if (exports.isDriveSizeLarge(drive)) {
|
||||
statusList.push({
|
||||
type: exports.COMPATIBILITY_STATUS_TYPES.WARNING,
|
||||
message: exports.COMPATIBILITY_STATUS_MESSAGES.LARGE_DRIVE
|
||||
message: messages.compatibility.largeDrive()
|
||||
})
|
||||
}
|
||||
|
||||
if (!_.isNil(drive) && !exports.isDriveSizeRecommended(drive, image)) {
|
||||
statusList.push({
|
||||
type: exports.COMPATIBILITY_STATUS_TYPES.WARNING,
|
||||
message: exports.COMPATIBILITY_STATUS_MESSAGES.SIZE_NOT_RECOMMENDED
|
||||
message: messages.compatibility.sizeNotRecommended()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -62,6 +62,41 @@ module.exports = {
|
||||
`${drive.description} (${drive.displayName})`
|
||||
].join(' ')
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* @summary Drive compatibility messages
|
||||
* @namespace compatibility
|
||||
* @memberof messages
|
||||
*/
|
||||
compatibility: {
|
||||
|
||||
sizeNotRecommended () {
|
||||
return 'Not Recommended'
|
||||
},
|
||||
|
||||
tooSmall (additionalSpace) {
|
||||
return `Insufficient space, additional ${additionalSpace} required`
|
||||
},
|
||||
|
||||
locked () {
|
||||
return 'Locked'
|
||||
},
|
||||
|
||||
system () {
|
||||
return 'System Drive'
|
||||
},
|
||||
|
||||
containsImage () {
|
||||
return 'Drive Contains Image'
|
||||
},
|
||||
|
||||
// The drive is large and therefore likely not a medium you want to write to.
|
||||
largeDrive () {
|
||||
return 'Large Drive'
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -20,6 +20,7 @@ const m = require('mochainon')
|
||||
const _ = require('lodash')
|
||||
const path = require('path')
|
||||
const constraints = require('../../lib/shared/drive-constraints')
|
||||
const messages = require('../../lib/shared/messages')
|
||||
|
||||
describe('Shared: DriveConstraints', function () {
|
||||
describe('.isDriveLocked()', function () {
|
||||
@ -1029,7 +1030,7 @@ describe('Shared: DriveConstraints', function () {
|
||||
const expectedTuplesSorted = _.sortBy(_.map(expectedTuples, (tuple) => {
|
||||
return {
|
||||
type: constraints.COMPATIBILITY_STATUS_TYPES[tuple[0]],
|
||||
message: constraints.COMPATIBILITY_STATUS_MESSAGES[tuple[1]]
|
||||
message: messages.compatibility[tuple[1]]()
|
||||
}
|
||||
}), [ 'message' ])
|
||||
const resultTuplesSorted = _.sortBy(resultList, [ 'message' ])
|
||||
@ -1060,7 +1061,7 @@ describe('Shared: DriveConstraints', function () {
|
||||
this.image.path = path.join(this.mountpoint, 'rpi.img')
|
||||
|
||||
const result = constraints.getDriveImageCompatibilityStatuses(this.drive, this.image)
|
||||
const expectedTuples = [ [ 'ERROR', 'CONTAINS_IMAGE' ] ]
|
||||
const expectedTuples = [ [ 'ERROR', 'containsImage' ] ]
|
||||
|
||||
expectStatusTypesAndMessagesToBe(result, expectedTuples)
|
||||
})
|
||||
@ -1071,7 +1072,7 @@ describe('Shared: DriveConstraints', function () {
|
||||
this.drive.isSystem = true
|
||||
|
||||
const result = constraints.getDriveImageCompatibilityStatuses(this.drive, this.image)
|
||||
const expectedTuples = [ [ 'WARNING', 'SYSTEM' ] ]
|
||||
const expectedTuples = [ [ 'WARNING', 'system' ] ]
|
||||
|
||||
expectStatusTypesAndMessagesToBe(result, expectedTuples)
|
||||
})
|
||||
@ -1082,9 +1083,14 @@ describe('Shared: DriveConstraints', function () {
|
||||
this.image.size.final.value = this.drive.size + 1
|
||||
|
||||
const result = constraints.getDriveImageCompatibilityStatuses(this.drive, this.image)
|
||||
const expectedTuples = [ [ 'ERROR', 'TOO_SMALL' ] ]
|
||||
const expected = [
|
||||
{
|
||||
message: messages.compatibility.tooSmall('1 B'),
|
||||
type: constraints.COMPATIBILITY_STATUS_TYPES.ERROR
|
||||
}
|
||||
]
|
||||
|
||||
expectStatusTypesAndMessagesToBe(result, expectedTuples)
|
||||
m.chai.expect(result).to.deep.equal(expected)
|
||||
})
|
||||
})
|
||||
|
||||
@ -1105,7 +1111,7 @@ describe('Shared: DriveConstraints', function () {
|
||||
this.drive.isReadOnly = true
|
||||
|
||||
const result = constraints.getDriveImageCompatibilityStatuses(this.drive, this.image)
|
||||
const expectedTuples = [ [ 'ERROR', 'LOCKED' ] ]
|
||||
const expectedTuples = [ [ 'ERROR', 'locked' ] ]
|
||||
|
||||
expectStatusTypesAndMessagesToBe(result, expectedTuples)
|
||||
})
|
||||
@ -1116,7 +1122,7 @@ describe('Shared: DriveConstraints', function () {
|
||||
this.image.recommendedDriveSize = this.drive.size + 1
|
||||
|
||||
const result = constraints.getDriveImageCompatibilityStatuses(this.drive, this.image)
|
||||
const expectedTuples = [ [ 'WARNING', 'SIZE_NOT_RECOMMENDED' ] ]
|
||||
const expectedTuples = [ [ 'WARNING', 'sizeNotRecommended' ] ]
|
||||
|
||||
expectStatusTypesAndMessagesToBe(result, expectedTuples)
|
||||
})
|
||||
@ -1127,7 +1133,7 @@ describe('Shared: DriveConstraints', function () {
|
||||
this.drive.size = constraints.LARGE_DRIVE_SIZE + 1
|
||||
|
||||
const result = constraints.getDriveImageCompatibilityStatuses(this.drive, this.image)
|
||||
const expectedTuples = [ [ 'WARNING', 'LARGE_DRIVE' ] ]
|
||||
const expectedTuples = [ [ 'WARNING', 'largeDrive' ] ]
|
||||
|
||||
expectStatusTypesAndMessagesToBe(result, expectedTuples)
|
||||
})
|
||||
@ -1154,7 +1160,7 @@ describe('Shared: DriveConstraints', function () {
|
||||
this.drive.isReadOnly = true
|
||||
|
||||
const result = constraints.getDriveImageCompatibilityStatuses(this.drive, null)
|
||||
const expectedTuples = [ [ 'ERROR', 'LOCKED' ] ]
|
||||
const expectedTuples = [ [ 'ERROR', 'locked' ] ]
|
||||
|
||||
expectStatusTypesAndMessagesToBe(result, expectedTuples)
|
||||
})
|
||||
@ -1165,7 +1171,7 @@ describe('Shared: DriveConstraints', function () {
|
||||
this.drive.isSystem = true
|
||||
|
||||
const result = constraints.getDriveImageCompatibilityStatuses(this.drive, null)
|
||||
const expectedTuples = [ [ 'WARNING', 'SYSTEM' ] ]
|
||||
const expectedTuples = [ [ 'WARNING', 'system' ] ]
|
||||
|
||||
expectStatusTypesAndMessagesToBe(result, expectedTuples)
|
||||
})
|
||||
@ -1177,7 +1183,7 @@ describe('Shared: DriveConstraints', function () {
|
||||
this.image.path = path.join(this.mountpoint, 'rpi.img')
|
||||
|
||||
const result = constraints.getDriveImageCompatibilityStatuses(this.drive, this.image)
|
||||
const expectedTuples = [ [ 'ERROR', 'CONTAINS_IMAGE' ] ]
|
||||
const expectedTuples = [ [ 'ERROR', 'containsImage' ] ]
|
||||
|
||||
expectStatusTypesAndMessagesToBe(result, expectedTuples)
|
||||
})
|
||||
@ -1188,7 +1194,7 @@ describe('Shared: DriveConstraints', function () {
|
||||
this.drive.isReadOnly = true
|
||||
|
||||
const result = constraints.getDriveImageCompatibilityStatuses(this.drive, this.image)
|
||||
const expectedTuples = [ [ 'ERROR', 'LOCKED' ] ]
|
||||
const expectedTuples = [ [ 'ERROR', 'locked' ] ]
|
||||
|
||||
expectStatusTypesAndMessagesToBe(result, expectedTuples)
|
||||
})
|
||||
@ -1200,9 +1206,14 @@ describe('Shared: DriveConstraints', function () {
|
||||
this.drive.isSystem = true
|
||||
|
||||
const result = constraints.getDriveImageCompatibilityStatuses(this.drive, this.image)
|
||||
const expectedTuples = [ [ 'ERROR', 'TOO_SMALL' ] ]
|
||||
const expected = [
|
||||
{
|
||||
message: messages.compatibility.tooSmall('1 B'),
|
||||
type: constraints.COMPATIBILITY_STATUS_TYPES.ERROR
|
||||
}
|
||||
]
|
||||
|
||||
expectStatusTypesAndMessagesToBe(result, expectedTuples)
|
||||
m.chai.expect(result).to.deep.equal(expected)
|
||||
})
|
||||
})
|
||||
|
||||
@ -1212,7 +1223,7 @@ describe('Shared: DriveConstraints', function () {
|
||||
this.image.recommendedDriveSize = this.drive.size + 1
|
||||
|
||||
const result = constraints.getDriveImageCompatibilityStatuses(this.drive, this.image)
|
||||
const expectedTuples = [ [ 'WARNING', 'SIZE_NOT_RECOMMENDED' ], [ 'WARNING', 'SYSTEM' ] ]
|
||||
const expectedTuples = [ [ 'WARNING', 'sizeNotRecommended' ], [ 'WARNING', 'system' ] ]
|
||||
|
||||
expectStatusTypesAndMessagesToBe(result, expectedTuples)
|
||||
})
|
||||
|
Loading…
x
Reference in New Issue
Block a user