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:
Jonas Hermsmeier 2017-09-13 18:34:26 +02:00 committed by GitHub
parent a3c54f22c8
commit b5912eb9f6
6 changed files with 68 additions and 14 deletions

View File

@ -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,

View File

@ -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
}

View File

@ -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({

View File

@ -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)
}
/**

View File

@ -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 () {

View File

@ -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({