mirror of
https://github.com/balena-io/etcher.git
synced 2025-07-24 03:36:36 +00:00
refactor: Remove use of localStorage for local settings
Change-Type: minor
This commit is contained in:
parent
447efc7096
commit
2a6670a404
@ -16,20 +16,24 @@
|
|||||||
|
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
|
const electron = require('electron')
|
||||||
const Bluebird = require('bluebird')
|
const Bluebird = require('bluebird')
|
||||||
const _ = require('lodash')
|
const _ = require('lodash')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const os = require('os')
|
const os = require('os')
|
||||||
const Storage = require('./storage')
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @summary Local storage settings key
|
* @summary Userdata directory path
|
||||||
|
* @description
|
||||||
|
* Defaults to the following:
|
||||||
|
* - `%APPDATA%/etcher` on Windows
|
||||||
|
* - `$XDG_CONFIG_HOME/etcher` or `~/.config/etcher` on Linux
|
||||||
|
* - `~/Library/Application Support/etcher` on macOS
|
||||||
* @constant
|
* @constant
|
||||||
* @type {String}
|
* @type {String}
|
||||||
*/
|
*/
|
||||||
const LOCAL_STORAGE_SETTINGS_KEY = 'etcher-settings'
|
const USER_DATA_DIR = electron.remote.app.getPath('userData')
|
||||||
const settingsStorage = new Storage(LOCAL_STORAGE_SETTINGS_KEY)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @summary Local settings filename
|
* @summary Local settings filename
|
||||||
@ -38,10 +42,19 @@ const settingsStorage = new Storage(LOCAL_STORAGE_SETTINGS_KEY)
|
|||||||
*/
|
*/
|
||||||
const RCFILE = '.etcher.json'
|
const RCFILE = '.etcher.json'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Configuration file path
|
||||||
|
* @type {String}
|
||||||
|
* @constant
|
||||||
|
*/
|
||||||
|
const HOME_CONFIG_PATH = process.platform === 'win32'
|
||||||
|
? path.join(USER_DATA_DIR, RCFILE)
|
||||||
|
: path.join(USER_DATA_DIR, 'config.json')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @summary Read a local .etcherrc file
|
* @summary Read a local .etcherrc file
|
||||||
* @function
|
* @function
|
||||||
* @public
|
* @private
|
||||||
*
|
*
|
||||||
* @param {String} filename - file path
|
* @param {String} filename - file path
|
||||||
* @fulfil {Object} - settings
|
* @fulfil {Object} - settings
|
||||||
@ -68,6 +81,33 @@ const readConfigFile = (filename) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Read a local .etcherrc file
|
||||||
|
* @function
|
||||||
|
* @private
|
||||||
|
*
|
||||||
|
* @param {String} filename - file path
|
||||||
|
* @returns {Promise}
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* writeConfigFile('.etcherrc', { something: 'good' })
|
||||||
|
* .then(() => {
|
||||||
|
* console.log('data written')
|
||||||
|
* })
|
||||||
|
*/
|
||||||
|
const writeConfigFile = (filename, data) => {
|
||||||
|
return new Bluebird((resolve, reject) => {
|
||||||
|
const contents = JSON.stringify(data, null, 2)
|
||||||
|
fs.writeFile(filename, contents, (error) => {
|
||||||
|
if (error) {
|
||||||
|
reject(error)
|
||||||
|
} else {
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @summary Read all local settings
|
* @summary Read all local settings
|
||||||
* @function
|
* @function
|
||||||
@ -82,22 +122,7 @@ const readConfigFile = (filename) => {
|
|||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
exports.readAll = () => {
|
exports.readAll = () => {
|
||||||
const homeConfigPath = process.platform === 'win32'
|
return readConfigFile(HOME_CONFIG_PATH)
|
||||||
? path.join(os.userInfo().homedir, RCFILE)
|
|
||||||
: path.join(os.userInfo().homedir, '.config', 'etcher', 'config.json')
|
|
||||||
const workdirConfigPath = path.join(process.cwd(), RCFILE)
|
|
||||||
const settings = {}
|
|
||||||
return Bluebird.try(() => {
|
|
||||||
_.merge(settings, settingsStorage.getAll())
|
|
||||||
}).return(readConfigFile(homeConfigPath))
|
|
||||||
.then((homeConfig) => {
|
|
||||||
_.merge(settings, homeConfig)
|
|
||||||
})
|
|
||||||
.return(readConfigFile(workdirConfigPath))
|
|
||||||
.then((workdirConfig) => {
|
|
||||||
_.merge(settings, workdirConfig)
|
|
||||||
})
|
|
||||||
.return(settings)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -116,9 +141,7 @@ exports.readAll = () => {
|
|||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
exports.writeAll = (settings) => {
|
exports.writeAll = (settings) => {
|
||||||
return Bluebird.try(() => {
|
return writeConfigFile(HOME_CONFIG_PATH, settings)
|
||||||
settingsStorage.setAll(settings)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -137,7 +160,8 @@ exports.writeAll = (settings) => {
|
|||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
exports.clear = () => {
|
exports.clear = () => {
|
||||||
|
// TODO: Unlink config file
|
||||||
return Bluebird.try(() => {
|
return Bluebird.try(() => {
|
||||||
settingsStorage.clearAll()
|
// settingsStorage.clearAll()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -23,58 +23,32 @@
|
|||||||
const _ = require('lodash')
|
const _ = require('lodash')
|
||||||
const Bluebird = require('bluebird')
|
const Bluebird = require('bluebird')
|
||||||
const localSettings = require('./local-settings')
|
const localSettings = require('./local-settings')
|
||||||
const store = require('./store')
|
|
||||||
const errors = require('../../../shared/errors')
|
const errors = require('../../../shared/errors')
|
||||||
|
const release = require('../../../shared/release')
|
||||||
/**
|
const packageJSON = require('../../../../package.json')
|
||||||
* @summary Set a settings object
|
|
||||||
* @function
|
|
||||||
* @private
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Use this function with care, given that it will completely
|
|
||||||
* override any existing settings in both the redux store,
|
|
||||||
* and the local user configuration.
|
|
||||||
*
|
|
||||||
* This function is prepared to deal with any local configuration
|
|
||||||
* write issues by rolling back to the previous settings if so.
|
|
||||||
*
|
|
||||||
* @param {Object} settings - settings
|
|
||||||
* @returns {Promise}
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* setSettingsObject({ foo: 'bar' }).then(() => {
|
|
||||||
* console.log('Done!');
|
|
||||||
* });
|
|
||||||
*/
|
|
||||||
const setSettingsObject = (settings) => {
|
|
||||||
const currentSettings = exports.getAll()
|
|
||||||
|
|
||||||
return Bluebird.try(() => {
|
|
||||||
store.dispatch({
|
|
||||||
type: store.Actions.SET_SETTINGS,
|
|
||||||
data: settings
|
|
||||||
})
|
|
||||||
}).then(() => {
|
|
||||||
// Revert the application state if writing the data
|
|
||||||
// to the local machine was not successful
|
|
||||||
return localSettings.writeAll(settings).catch((error) => {
|
|
||||||
store.dispatch({
|
|
||||||
type: store.Actions.SET_SETTINGS,
|
|
||||||
data: currentSettings
|
|
||||||
})
|
|
||||||
|
|
||||||
throw error
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @summary Default settings
|
* @summary Default settings
|
||||||
* @constant
|
* @constant
|
||||||
* @type {Object}
|
* @type {Object}
|
||||||
*/
|
*/
|
||||||
const DEFAULT_SETTINGS = store.Defaults.get('settings').toJS()
|
const DEFAULT_SETTINGS = {
|
||||||
|
unsafeMode: false,
|
||||||
|
errorReporting: true,
|
||||||
|
unmountOnSuccess: true,
|
||||||
|
validateWriteOnSuccess: true,
|
||||||
|
updatesEnabled: packageJSON.updates.enabled && !_.includes([ 'rpm', 'deb' ], packageJSON.packageType),
|
||||||
|
includeUnstableUpdateChannel: !release.isStableRelease(packageJSON.version),
|
||||||
|
lastSleptUpdateNotifier: null,
|
||||||
|
lastSleptUpdateNotifierVersion: null,
|
||||||
|
desktopNotifications: true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Settings state
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
const settings = _.assign({}, DEFAULT_SETTINGS)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @summary Reset settings to their default values
|
* @summary Reset settings to their default values
|
||||||
@ -89,7 +63,8 @@ const DEFAULT_SETTINGS = store.Defaults.get('settings').toJS()
|
|||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
exports.reset = () => {
|
exports.reset = () => {
|
||||||
return setSettingsObject(DEFAULT_SETTINGS)
|
// TODO: Remove default settings from config file (?)
|
||||||
|
return exports.assign(DEFAULT_SETTINGS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -107,14 +82,14 @@ exports.reset = () => {
|
|||||||
* console.log('Done!');
|
* console.log('Done!');
|
||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
exports.assign = (settings) => {
|
exports.assign = (data) => {
|
||||||
if (_.isNil(settings)) {
|
if (_.isNil(data)) {
|
||||||
return Bluebird.reject(errors.createError({
|
return Bluebird.reject(errors.createError({
|
||||||
title: 'Missing settings'
|
title: 'Missing settings'
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
return setSettingsObject(_.assign(exports.getAll(), settings))
|
return localSettings.writeAll(_.assign(exports.getAll(), data))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -177,7 +152,7 @@ exports.set = (key, value) => {
|
|||||||
* const value = settings.get('unmountOnSuccess');
|
* const value = settings.get('unmountOnSuccess');
|
||||||
*/
|
*/
|
||||||
exports.get = (key) => {
|
exports.get = (key) => {
|
||||||
return _.get(exports.getAll(), [ key ])
|
return _.cloneDeep(_.get(settings, [ key ]))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -192,5 +167,5 @@ exports.get = (key) => {
|
|||||||
* console.log(allSettings.unmountOnSuccess);
|
* console.log(allSettings.unmountOnSuccess);
|
||||||
*/
|
*/
|
||||||
exports.getAll = () => {
|
exports.getAll = () => {
|
||||||
return store.getState().get('settings').toJS()
|
return _.cloneDeep(settings)
|
||||||
}
|
}
|
||||||
|
@ -23,10 +23,8 @@ const uuidV4 = require('uuid/v4')
|
|||||||
const constraints = require('../../../shared/drive-constraints')
|
const constraints = require('../../../shared/drive-constraints')
|
||||||
const supportedFormats = require('../../../shared/supported-formats')
|
const supportedFormats = require('../../../shared/supported-formats')
|
||||||
const errors = require('../../../shared/errors')
|
const errors = require('../../../shared/errors')
|
||||||
const release = require('../../../shared/release')
|
|
||||||
const fileExtensions = require('../../../shared/file-extensions')
|
const fileExtensions = require('../../../shared/file-extensions')
|
||||||
const utils = require('../../../shared/utils')
|
const utils = require('../../../shared/utils')
|
||||||
const packageJSON = require('../../../../package.json')
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @summary Verify and throw if any state fields are nil
|
* @summary Verify and throw if any state fields are nil
|
||||||
@ -95,17 +93,6 @@ const DEFAULT_STATE = Immutable.fromJS({
|
|||||||
percentage: 0,
|
percentage: 0,
|
||||||
speed: 0,
|
speed: 0,
|
||||||
totalSpeed: 0
|
totalSpeed: 0
|
||||||
},
|
|
||||||
settings: {
|
|
||||||
unsafeMode: false,
|
|
||||||
errorReporting: true,
|
|
||||||
unmountOnSuccess: true,
|
|
||||||
validateWriteOnSuccess: true,
|
|
||||||
updatesEnabled: packageJSON.updates.enabled && !_.includes([ 'rpm', 'deb' ], packageJSON.packageType),
|
|
||||||
includeUnstableUpdateChannel: !release.isStableRelease(packageJSON.version),
|
|
||||||
lastSleptUpdateNotifier: null,
|
|
||||||
lastSleptUpdateNotifierVersion: null,
|
|
||||||
desktopNotifications: true
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -123,8 +110,7 @@ const ACTIONS = _.fromPairs(_.map([
|
|||||||
'SELECT_DRIVE',
|
'SELECT_DRIVE',
|
||||||
'SELECT_IMAGE',
|
'SELECT_IMAGE',
|
||||||
'DESELECT_DRIVE',
|
'DESELECT_DRIVE',
|
||||||
'DESELECT_IMAGE',
|
'DESELECT_IMAGE'
|
||||||
'SET_SETTINGS'
|
|
||||||
], (message) => {
|
], (message) => {
|
||||||
return [ message, message ]
|
return [ message, message ]
|
||||||
}))
|
}))
|
||||||
@ -512,34 +498,6 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
|
|||||||
return state.deleteIn([ 'selection', 'image' ])
|
return state.deleteIn([ 'selection', 'image' ])
|
||||||
}
|
}
|
||||||
|
|
||||||
case ACTIONS.SET_SETTINGS: {
|
|
||||||
// Type: action.data : SettingsObject
|
|
||||||
|
|
||||||
if (!action.data) {
|
|
||||||
throw errors.createError({
|
|
||||||
title: 'Missing settings'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_.isPlainObject(action.data)) {
|
|
||||||
throw errors.createError({
|
|
||||||
title: `Invalid settings: ${action.data}`
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const invalidPair = _.find(_.toPairs(action.data), (pair) => {
|
|
||||||
return _.isObject(_.last(pair))
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!_.isNil(invalidPair)) {
|
|
||||||
throw errors.createError({
|
|
||||||
title: `Invalid setting value: ${_.last(invalidPair)} for ${_.first(invalidPair)}`
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return state.setIn([ 'settings' ], Immutable.fromJS(action.data))
|
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user