mirror of
https://github.com/balena-io/etcher.git
synced 2025-04-25 15:57:18 +00:00
fix: Support raw images without secondary file extension (#1724)
This allows selection of images without a secondary file extension (i.e. `example.gz`, compared to `example.img.gz`) by defaulting to `img` in the image-stream handlers, should no secondary extension be found. Further this adjusts `.getPenultimateFileExtension()` to return `null` if the detected penultimate extension is not a known file extension. Change-Type: patch
This commit is contained in:
parent
a3c54f22c8
commit
b5912eb9f6
@ -33,6 +33,13 @@ const fileExtensions = require('../shared/file-extensions')
|
||||
const path = require('path')
|
||||
const errors = require('../shared/errors')
|
||||
|
||||
/**
|
||||
* @summary Default image extension to be assumed
|
||||
* @type {String}
|
||||
* @constant
|
||||
*/
|
||||
const DEFAULT_EXT = 'img'
|
||||
|
||||
/**
|
||||
* @summary Image handlers
|
||||
* @namespace handlers
|
||||
@ -57,7 +64,7 @@ module.exports = {
|
||||
return {
|
||||
path: imagePath,
|
||||
archiveExtension: fileExtensions.getLastFileExtension(imagePath),
|
||||
extension: fileExtensions.getPenultimateFileExtension(imagePath),
|
||||
extension: fileExtensions.getPenultimateFileExtension(imagePath) || DEFAULT_EXT,
|
||||
stream: fs.createReadStream(imagePath),
|
||||
size: {
|
||||
original: options.size,
|
||||
@ -97,7 +104,7 @@ module.exports = {
|
||||
return {
|
||||
path: imagePath,
|
||||
archiveExtension: fileExtensions.getLastFileExtension(imagePath),
|
||||
extension: fileExtensions.getPenultimateFileExtension(imagePath),
|
||||
extension: fileExtensions.getPenultimateFileExtension(imagePath) || DEFAULT_EXT,
|
||||
stream: fs.createReadStream(imagePath),
|
||||
size: {
|
||||
original: options.size,
|
||||
@ -138,7 +145,7 @@ module.exports = {
|
||||
return {
|
||||
path: imagePath,
|
||||
archiveExtension: fileExtensions.getLastFileExtension(imagePath),
|
||||
extension: fileExtensions.getPenultimateFileExtension(imagePath),
|
||||
extension: fileExtensions.getPenultimateFileExtension(imagePath) || DEFAULT_EXT,
|
||||
stream: fs.createReadStream(imagePath),
|
||||
size: {
|
||||
original: options.size,
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
'use strict'
|
||||
|
||||
const mime = require('mime-types')
|
||||
const _ = require('lodash')
|
||||
|
||||
/**
|
||||
@ -45,15 +46,15 @@ exports.getFileExtensions = _.memoize((filePath) => {
|
||||
* @public
|
||||
*
|
||||
* @param {String} filePath - file path
|
||||
* @returns {(String|Undefined)} last extension
|
||||
* @returns {(String|Null)} last extension
|
||||
*
|
||||
* @example
|
||||
* const extension = fileExtensions.getLastFileExtension('path/to/foo.img.gz');
|
||||
* console.log(extension);
|
||||
* > [ 'gz' ]
|
||||
* > 'gz'
|
||||
*/
|
||||
exports.getLastFileExtension = (filePath) => {
|
||||
return _.last(exports.getFileExtensions(filePath))
|
||||
return _.last(exports.getFileExtensions(filePath)) || null
|
||||
}
|
||||
|
||||
/**
|
||||
@ -62,13 +63,14 @@ exports.getLastFileExtension = (filePath) => {
|
||||
* @public
|
||||
*
|
||||
* @param {String} filePath - file path
|
||||
* @returns {(String|Undefined)} penultimate extension
|
||||
* @returns {(String|Null)} penultimate extension
|
||||
*
|
||||
* @example
|
||||
* const extension = fileExtensions.getPenultimateFileExtension('path/to/foo.img.gz');
|
||||
* console.log(extension);
|
||||
* > [ 'img' ]
|
||||
* > 'img'
|
||||
*/
|
||||
exports.getPenultimateFileExtension = (filePath) => {
|
||||
return _.last(_.initial(exports.getFileExtensions(filePath)))
|
||||
const ext = _.last(_.initial(exports.getFileExtensions(filePath)))
|
||||
return !_.isNil(ext) && mime.lookup(ext) ? ext : null
|
||||
}
|
||||
|
@ -311,6 +311,10 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
|
||||
return state.setIn([ 'selection', 'drive' ], Immutable.fromJS(action.data))
|
||||
}
|
||||
|
||||
// TODO(jhermsmeier): Consolidate these assertions
|
||||
// with image-stream / supported-formats, and have *one*
|
||||
// place where all the image extension / format handling
|
||||
// takes place, to avoid having to check 2+ locations with different logic
|
||||
case ACTIONS.SELECT_IMAGE: {
|
||||
if (!action.data.path) {
|
||||
throw errors.createError({
|
||||
|
@ -122,10 +122,15 @@ exports.isSupportedImage = (imagePath) => {
|
||||
return true
|
||||
}
|
||||
|
||||
return _.every([
|
||||
if (_.every([
|
||||
_.includes(exports.getCompressedExtensions(), lastExtension),
|
||||
_.includes(exports.getNonCompressedExtensions(), penultimateExtension)
|
||||
])
|
||||
])) {
|
||||
return true
|
||||
}
|
||||
|
||||
return _.isNil(penultimateExtension) &&
|
||||
_.includes(exports.getCompressedExtensions(), lastExtension)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -101,7 +101,7 @@ describe('Shared: fileExtensions', function () {
|
||||
|
||||
describe('.getLastFileExtension()', function () {
|
||||
it('should return undefined if the file path has no extension', function () {
|
||||
m.chai.expect(fileExtensions.getLastFileExtension('foo')).to.be.undefined
|
||||
m.chai.expect(fileExtensions.getLastFileExtension('foo')).to.equal(null)
|
||||
})
|
||||
|
||||
it('should return the extension if there is only one extension', function () {
|
||||
@ -119,11 +119,11 @@ describe('Shared: fileExtensions', function () {
|
||||
|
||||
describe('.getPenultimateFileExtension()', function () {
|
||||
it('should return undefined in the file path has no extension', function () {
|
||||
m.chai.expect(fileExtensions.getPenultimateFileExtension('foo')).to.be.undefined
|
||||
m.chai.expect(fileExtensions.getPenultimateFileExtension('foo')).to.equal(null)
|
||||
})
|
||||
|
||||
it('should return undefined if there is only one extension', function () {
|
||||
m.chai.expect(fileExtensions.getPenultimateFileExtension('foo.img')).to.be.undefined
|
||||
m.chai.expect(fileExtensions.getPenultimateFileExtension('foo.img')).to.equal(null)
|
||||
})
|
||||
|
||||
it('should return the penultimate extension if there are two extensions', function () {
|
||||
|
@ -370,6 +370,42 @@ describe('Model: selectionState', function () {
|
||||
m.chai.expect(imagePath).to.equal('foo.zip')
|
||||
})
|
||||
|
||||
it('should infer a compressed raw image if the penultimate extension is missing', function () {
|
||||
selectionState.setImage({
|
||||
path: 'foo.xz',
|
||||
extension: 'img',
|
||||
archiveExtension: 'xz',
|
||||
size: {
|
||||
original: 999999999,
|
||||
final: {
|
||||
estimation: false,
|
||||
value: 999999999
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const imagePath = selectionState.getImagePath()
|
||||
m.chai.expect(imagePath).to.equal('foo.xz')
|
||||
})
|
||||
|
||||
it('should infer a compressed raw image if the penultimate extension is not a file extension', function () {
|
||||
selectionState.setImage({
|
||||
path: 'something.linux-x86-64.gz',
|
||||
extension: 'img',
|
||||
archiveExtension: 'gz',
|
||||
size: {
|
||||
original: 999999999,
|
||||
final: {
|
||||
estimation: false,
|
||||
value: 999999999
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const imagePath = selectionState.getImagePath()
|
||||
m.chai.expect(imagePath).to.equal('something.linux-x86-64.gz')
|
||||
})
|
||||
|
||||
it('should throw if no path', function () {
|
||||
m.chai.expect(function () {
|
||||
selectionState.setImage({
|
||||
|
Loading…
x
Reference in New Issue
Block a user