mirror of
https://github.com/balena-io/etcher.git
synced 2025-08-05 09:27:44 +00:00
Convert utils, settings and errors to typescript
Change-type: patch Changelog-entry: Convert utils, settings and errors to typescript
This commit is contained in:
parent
7be07bfe8c
commit
3706770322
2
Makefile
2
Makefile
@ -174,7 +174,7 @@ lint-spell:
|
||||
|
||||
lint: lint-ts lint-js lint-sass lint-cpp lint-html lint-spell
|
||||
|
||||
MOCHA_OPTIONS=--recursive --reporter spec
|
||||
MOCHA_OPTIONS=--recursive --reporter spec --require ts-node/register
|
||||
|
||||
# See https://github.com/electron/spectron/issues/127
|
||||
ETCHER_SPECTRON_ENTRYPOINT ?= $(shell node -e 'console.log(require("electron"))')
|
||||
|
@ -36,6 +36,7 @@ const messages = require('../../gui/app/modules/messages')
|
||||
const store = require('./models/store')
|
||||
const packageJSON = require('../../../package.json')
|
||||
const flashState = require('./models/flash-state')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const settings = require('./models/settings')
|
||||
const windowProgress = require('./os/window-progress')
|
||||
const analytics = require('./modules/analytics')
|
||||
@ -45,6 +46,7 @@ const driveScanner = require('./modules/drive-scanner')
|
||||
const osDialog = require('./os/dialog')
|
||||
const exceptionReporter = require('./modules/exception-reporter')
|
||||
const updateLock = require('./modules/update-lock')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const screensaver = require('./modules/screensaver')
|
||||
|
||||
/* eslint-disable lodash/prefer-lodash-method,lodash/prefer-get */
|
||||
|
@ -24,6 +24,7 @@ const store = require('../../../models/store')
|
||||
const analytics = require('../../../modules/analytics')
|
||||
const availableDrives = require('../../../models/available-drives')
|
||||
const selectionState = require('../../../models/selection-state')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const utils = require('../../../../../gui/app/modules/utils')
|
||||
|
||||
module.exports = function (
|
||||
|
@ -18,7 +18,9 @@
|
||||
|
||||
const _ = require('lodash')
|
||||
const os = require('os')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const settings = require('../../../models/settings')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const utils = require('../../../../../gui/app/modules/utils')
|
||||
const angular = require('angular')
|
||||
|
||||
|
@ -14,18 +14,21 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
import { app, remote } from 'electron';
|
||||
import { readFile, unlink, writeFile } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { promisify } from 'util';
|
||||
|
||||
const Bluebird = require('bluebird')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const readFileAsync = promisify(readFile);
|
||||
const writeFileAsync = promisify(writeFile);
|
||||
const unlinkAsync = promisify(unlink);
|
||||
|
||||
/**
|
||||
* @summary Number of spaces to indent JSON output with
|
||||
* @type {Number}
|
||||
* @constant
|
||||
*/
|
||||
const JSON_INDENT = 2
|
||||
const JSON_INDENT = 2;
|
||||
|
||||
/**
|
||||
* @summary Userdata directory path
|
||||
@ -38,21 +41,16 @@ const JSON_INDENT = 2
|
||||
* @constant
|
||||
* @type {String}
|
||||
*/
|
||||
const USER_DATA_DIR = (() => {
|
||||
// NOTE: The ternary is due to this module being loaded both,
|
||||
// Electron's main process and renderer process
|
||||
const electron = require('electron')
|
||||
return electron.app
|
||||
? electron.app.getPath('userData')
|
||||
: electron.remote.app.getPath('userData')
|
||||
})()
|
||||
// NOTE: The ternary is due to this module being loaded both,
|
||||
// Electron's main process and renderer process
|
||||
const USER_DATA_DIR = (app || remote.app).getPath('userData');
|
||||
|
||||
/**
|
||||
* @summary Configuration file path
|
||||
* @type {String}
|
||||
* @constant
|
||||
*/
|
||||
const CONFIG_PATH = path.join(USER_DATA_DIR, 'config.json')
|
||||
const CONFIG_PATH = join(USER_DATA_DIR, 'config.json');
|
||||
|
||||
/**
|
||||
* @summary Read a local config.json file
|
||||
@ -68,26 +66,22 @@ const CONFIG_PATH = path.join(USER_DATA_DIR, 'config.json')
|
||||
* console.log(settings)
|
||||
* })
|
||||
*/
|
||||
const readConfigFile = (filename) => {
|
||||
return new Bluebird((resolve, reject) => {
|
||||
fs.readFile(filename, { encoding: 'utf8' }, (error, contents) => {
|
||||
let data = {}
|
||||
if (error) {
|
||||
if (error.code === 'ENOENT') {
|
||||
resolve(data)
|
||||
} else {
|
||||
reject(error)
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
data = JSON.parse(contents)
|
||||
} catch (parseError) {
|
||||
console.error(parseError)
|
||||
}
|
||||
resolve(data)
|
||||
}
|
||||
})
|
||||
})
|
||||
async function readConfigFile(filename: string): Promise<any> {
|
||||
let contents = '{}';
|
||||
try {
|
||||
contents = await readFileAsync(filename, { encoding: 'utf8' });
|
||||
} catch (error) {
|
||||
if (error.code === 'ENOENT') {
|
||||
return {};
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
return JSON.parse(contents);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -106,17 +100,10 @@ const readConfigFile = (filename) => {
|
||||
* console.log('data written')
|
||||
* })
|
||||
*/
|
||||
const writeConfigFile = (filename, data) => {
|
||||
return new Bluebird((resolve, reject) => {
|
||||
const contents = JSON.stringify(data, null, JSON_INDENT)
|
||||
fs.writeFile(filename, contents, (error) => {
|
||||
if (error) {
|
||||
reject(error)
|
||||
} else {
|
||||
resolve(data)
|
||||
}
|
||||
})
|
||||
})
|
||||
async function writeConfigFile(filename: string, data: any) {
|
||||
const contents = JSON.stringify(data, null, JSON_INDENT);
|
||||
await writeFileAsync(filename, contents);
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -132,8 +119,8 @@ const writeConfigFile = (filename, data) => {
|
||||
* console.log(settings);
|
||||
* });
|
||||
*/
|
||||
exports.readAll = () => {
|
||||
return readConfigFile(CONFIG_PATH)
|
||||
export async function readAll(): Promise<any> {
|
||||
return await readConfigFile(CONFIG_PATH);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -152,8 +139,8 @@ exports.readAll = () => {
|
||||
* console.log('Done!');
|
||||
* });
|
||||
*/
|
||||
exports.writeAll = (settings) => {
|
||||
return writeConfigFile(CONFIG_PATH, settings)
|
||||
export async function writeAll(settings: any) {
|
||||
return await writeConfigFile(CONFIG_PATH, settings);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -171,14 +158,6 @@ exports.writeAll = (settings) => {
|
||||
* console.log('Done!');
|
||||
* });
|
||||
*/
|
||||
exports.clear = () => {
|
||||
return new Bluebird((resolve, reject) => {
|
||||
fs.unlink(CONFIG_PATH, (error) => {
|
||||
if (error) {
|
||||
reject(error)
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
})
|
||||
export async function clear(): Promise<void> {
|
||||
await unlinkAsync(CONFIG_PATH);
|
||||
}
|
@ -1,232 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 resin.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* @module Etcher.Models.Settings
|
||||
*/
|
||||
|
||||
const _ = require('lodash')
|
||||
const Bluebird = require('bluebird')
|
||||
const localSettings = require('./local-settings')
|
||||
const errors = require('../modules/errors')
|
||||
const packageJSON = require('../../../../package.json')
|
||||
const debug = require('debug')('etcher:models:settings')
|
||||
|
||||
/**
|
||||
* @summary Default settings
|
||||
* @constant
|
||||
* @type {Object}
|
||||
*/
|
||||
const DEFAULT_SETTINGS = {
|
||||
unsafeMode: false,
|
||||
errorReporting: true,
|
||||
unmountOnSuccess: true,
|
||||
validateWriteOnSuccess: true,
|
||||
trim: false,
|
||||
updatesEnabled: packageJSON.updates.enabled && !_.includes([ 'rpm', 'deb' ], packageJSON.packageType),
|
||||
lastSleptUpdateNotifier: null,
|
||||
lastSleptUpdateNotifierVersion: null,
|
||||
desktopNotifications: true
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Settings state
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
let settings = _.cloneDeep(DEFAULT_SETTINGS)
|
||||
|
||||
/**
|
||||
* @summary Reset settings to their default values
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @returns {Promise}
|
||||
*
|
||||
* @example
|
||||
* settings.reset().then(() => {
|
||||
* console.log('Done!');
|
||||
* });
|
||||
*/
|
||||
exports.reset = () => {
|
||||
debug('reset')
|
||||
|
||||
// TODO: Remove default settings from config file (?)
|
||||
settings = _.cloneDeep(DEFAULT_SETTINGS)
|
||||
return localSettings.writeAll(settings)
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Extend the current settings
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @param {Object} value - value
|
||||
* @returns {Promise}
|
||||
*
|
||||
* @example
|
||||
* settings.assign({
|
||||
* foo: 'bar'
|
||||
* }).then(() => {
|
||||
* console.log('Done!');
|
||||
* });
|
||||
*/
|
||||
exports.assign = (value) => {
|
||||
debug('assign', value)
|
||||
if (_.isNil(value)) {
|
||||
return Bluebird.reject(errors.createError({
|
||||
title: 'Missing settings'
|
||||
}))
|
||||
}
|
||||
|
||||
if (!_.isPlainObject(value)) {
|
||||
return Bluebird.reject(errors.createError({
|
||||
title: 'Settings must be an object'
|
||||
}))
|
||||
}
|
||||
|
||||
const newSettings = _.assign({}, settings, value)
|
||||
|
||||
return localSettings.writeAll(newSettings)
|
||||
.then((updatedSettings) => {
|
||||
// NOTE: Only update in memory settings when successfully written
|
||||
settings = updatedSettings
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Extend the application state with the local settings
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @returns {Promise}
|
||||
*
|
||||
* @example
|
||||
* settings.load().then(() => {
|
||||
* console.log('Done!');
|
||||
* });
|
||||
*/
|
||||
exports.load = () => {
|
||||
debug('load')
|
||||
return localSettings.readAll().then((loadedSettings) => {
|
||||
return _.assign(settings, loadedSettings)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Set a setting value
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @param {String} key - setting key
|
||||
* @param {*} value - setting value
|
||||
* @returns {Promise}
|
||||
*
|
||||
* @example
|
||||
* settings.set('unmountOnSuccess', true).then(() => {
|
||||
* console.log('Done!');
|
||||
* });
|
||||
*/
|
||||
exports.set = (key, value) => {
|
||||
debug('set', key, value)
|
||||
if (_.isNil(key)) {
|
||||
return Bluebird.reject(errors.createError({
|
||||
title: 'Missing setting key'
|
||||
}))
|
||||
}
|
||||
|
||||
if (!_.isString(key)) {
|
||||
return Bluebird.reject(errors.createError({
|
||||
title: `Invalid setting key: ${key}`
|
||||
}))
|
||||
}
|
||||
|
||||
const previousValue = settings[key]
|
||||
|
||||
settings[key] = value
|
||||
|
||||
return localSettings.writeAll(settings)
|
||||
.catch((error) => {
|
||||
// Revert to previous value if persisting settings failed
|
||||
settings[key] = previousValue
|
||||
throw error
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Get a setting value
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @param {String} key - setting key
|
||||
* @returns {*} setting value
|
||||
*
|
||||
* @example
|
||||
* const value = settings.get('unmountOnSuccess');
|
||||
*/
|
||||
exports.get = (key) => {
|
||||
return _.cloneDeep(_.get(settings, [ key ]))
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Check if setting value exists
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @param {String} key - setting key
|
||||
* @returns {Boolean} exists
|
||||
*
|
||||
* @example
|
||||
* const hasValue = settings.has('unmountOnSuccess');
|
||||
*/
|
||||
exports.has = (key) => {
|
||||
/* eslint-disable no-eq-null */
|
||||
return settings[key] != null
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Get all setting values
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @returns {Object} all setting values
|
||||
*
|
||||
* @example
|
||||
* const allSettings = settings.getAll();
|
||||
* console.log(allSettings.unmountOnSuccess);
|
||||
*/
|
||||
exports.getAll = () => {
|
||||
debug('getAll')
|
||||
return _.cloneDeep(settings)
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Get the default setting values
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @returns {Object} all setting values
|
||||
*
|
||||
* @example
|
||||
* const defaults = settings.getDefaults();
|
||||
* console.log(defaults.unmountOnSuccess);
|
||||
*/
|
||||
exports.getDefaults = () => {
|
||||
debug('getDefaults')
|
||||
return _.cloneDeep(DEFAULT_SETTINGS)
|
||||
}
|
101
lib/gui/app/models/settings.ts
Normal file
101
lib/gui/app/models/settings.ts
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2016 resin.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as debug_ from 'debug';
|
||||
import { cloneDeep, isPlainObject } from 'lodash';
|
||||
|
||||
import { createError } from '../modules/errors';
|
||||
import { Dict } from '../modules/utils';
|
||||
import { readAll, writeAll } from './local-settings';
|
||||
|
||||
import * as packageJSON from '../../../../package.json';
|
||||
|
||||
const debug = debug_('etcher:models:settings');
|
||||
|
||||
const DEFAULT_SETTINGS = {
|
||||
unsafeMode: false,
|
||||
errorReporting: true,
|
||||
unmountOnSuccess: true,
|
||||
validateWriteOnSuccess: true,
|
||||
trim: false,
|
||||
updatesEnabled:
|
||||
packageJSON.updates.enabled &&
|
||||
!['rpm', 'deb'].includes(packageJSON.packageType),
|
||||
lastSleptUpdateNotifier: null,
|
||||
lastSleptUpdateNotifierVersion: null,
|
||||
desktopNotifications: true,
|
||||
};
|
||||
|
||||
let settings: Dict<any> = cloneDeep(DEFAULT_SETTINGS);
|
||||
|
||||
export async function reset(): Promise<void> {
|
||||
debug('reset');
|
||||
// TODO: Remove default settings from config file (?)
|
||||
settings = cloneDeep(DEFAULT_SETTINGS);
|
||||
await writeAll(settings);
|
||||
}
|
||||
|
||||
export async function assign(value: any): Promise<void> {
|
||||
debug('assign', value);
|
||||
if (!isPlainObject(value)) {
|
||||
throw createError({ title: 'Settings must be an object' });
|
||||
}
|
||||
const newSettings = { ...settings, ...value };
|
||||
const updatedSettings = await writeAll(newSettings);
|
||||
// NOTE: Only update in memory settings when successfully written
|
||||
settings = updatedSettings;
|
||||
}
|
||||
|
||||
export async function load(): Promise<any> {
|
||||
debug('load');
|
||||
const loadedSettings = await readAll();
|
||||
settings = { ...settings, ...loadedSettings };
|
||||
return settings;
|
||||
}
|
||||
|
||||
export async function set(key: string, value: any): Promise<void> {
|
||||
debug('set', key, value);
|
||||
if (typeof key !== 'string') {
|
||||
throw createError({ title: `Invalid setting key: ${key}` });
|
||||
}
|
||||
const previousValue = settings[key];
|
||||
settings[key] = value;
|
||||
try {
|
||||
await writeAll(settings);
|
||||
} catch (error) {
|
||||
// Revert to previous value if persisting settings failed
|
||||
settings[key] = previousValue;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export function get(key: string): any {
|
||||
return cloneDeep(settings[key]);
|
||||
}
|
||||
|
||||
export function has(key: string): boolean {
|
||||
return settings[key] !== undefined;
|
||||
}
|
||||
|
||||
export function getAll(): any {
|
||||
debug('getAll');
|
||||
return cloneDeep(settings);
|
||||
}
|
||||
|
||||
export function getDefaults(): any {
|
||||
debug('getDefaults');
|
||||
return cloneDeep(DEFAULT_SETTINGS);
|
||||
}
|
@ -22,9 +22,12 @@ const redux = require('redux')
|
||||
const uuidV4 = require('uuid/v4')
|
||||
const constraints = require('../modules/drive-constraints')
|
||||
const supportedFormats = require('../modules/supported-formats')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const errors = require('../modules/errors')
|
||||
const fileExtensions = require('../modules/file-extensions')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const utils = require('../modules/utils')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const settings = require('./settings')
|
||||
|
||||
/**
|
||||
|
@ -19,7 +19,9 @@
|
||||
const _ = require('lodash')
|
||||
const resinCorvus = require('resin-corvus/browser')
|
||||
const packageJSON = require('../../../../package.json')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const settings = require('../models/settings')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const { getConfig, hasProps } = require('../../../gui/app/modules/utils')
|
||||
|
||||
const sentryToken = settings.get('analyticsSentryToken') ||
|
||||
|
@ -21,6 +21,7 @@ const _ = require('lodash')
|
||||
const ipc = require('node-ipc')
|
||||
const sdk = require('etcher-sdk')
|
||||
const EXIT_CODES = require('./exit-codes')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const errors = require('./errors')
|
||||
|
||||
ipc.config.id = process.env.IPC_CLIENT_ID
|
||||
|
@ -19,6 +19,7 @@
|
||||
const sdk = require('etcher-sdk')
|
||||
const process = require('process')
|
||||
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const settings = require('../models/settings')
|
||||
|
||||
/**
|
||||
|
@ -1,369 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 resin.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const _ = require('lodash')
|
||||
|
||||
/**
|
||||
* @summary Create an error details object
|
||||
* @function
|
||||
* @private
|
||||
*
|
||||
* @param {Object} options - options
|
||||
* @param {(String|Function)} options.title - error title
|
||||
* @param {(String|Function)} options.description - error description
|
||||
* @returns {Object} error details object
|
||||
*
|
||||
* @example
|
||||
* const details = createErrorDetails({
|
||||
* title: (error) => {
|
||||
* return `An error happened, the code is ${error.code}`;
|
||||
* },
|
||||
* description: 'This is the error description'
|
||||
* });
|
||||
*/
|
||||
const createErrorDetails = (options) => {
|
||||
return _.pick(_.mapValues(options, (value) => {
|
||||
return _.isFunction(value) ? value : _.constant(value)
|
||||
}), [ 'title', 'description' ])
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Human-friendly error messages
|
||||
* @namespace HUMAN_FRIENDLY
|
||||
* @public
|
||||
*/
|
||||
exports.HUMAN_FRIENDLY = {
|
||||
|
||||
/* eslint-disable new-cap */
|
||||
|
||||
/**
|
||||
* @namespace ENOENT
|
||||
* @memberof HUMAN_FRIENDLY
|
||||
*/
|
||||
ENOENT: createErrorDetails({
|
||||
title: (error) => {
|
||||
return `No such file or directory: ${error.path}`
|
||||
},
|
||||
description: 'The file you\'re trying to access doesn\'t exist'
|
||||
}),
|
||||
|
||||
/**
|
||||
* @namespace EPERM
|
||||
* @memberof HUMAN_FRIENDLY
|
||||
*/
|
||||
EPERM: createErrorDetails({
|
||||
title: 'You\'re not authorized to perform this operation',
|
||||
description: 'Please ensure you have necessary permissions for this task'
|
||||
}),
|
||||
|
||||
/**
|
||||
* @namespace EACCES
|
||||
* @memberof HUMAN_FRIENDLY
|
||||
*/
|
||||
EACCES: createErrorDetails({
|
||||
title: 'You don\'t have access to this resource',
|
||||
description: 'Please ensure you have necessary permissions to access this resource'
|
||||
}),
|
||||
|
||||
/**
|
||||
* @namespace ENOMEM
|
||||
* @memberof HUMAN_FRIENDLY
|
||||
*/
|
||||
ENOMEM: createErrorDetails({
|
||||
title: 'Your system ran out of memory',
|
||||
description: 'Please make sure your system has enough available memory for this task'
|
||||
})
|
||||
|
||||
/* eslint-enable new-cap */
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Get user friendly property from an error
|
||||
* @function
|
||||
* @private
|
||||
*
|
||||
* @param {Error} error - error
|
||||
* @param {String} property - HUMAN_FRIENDLY property
|
||||
* @returns {(String|Undefined)} user friendly message
|
||||
*
|
||||
* @example
|
||||
* const error = new Error('My error');
|
||||
* error.code = 'ENOMEM';
|
||||
*
|
||||
* const friendlyDescription = getUserFriendlyMessageProperty(error, 'description');
|
||||
*
|
||||
* if (friendlyDescription) {
|
||||
* console.log(friendlyDescription);
|
||||
* }
|
||||
*/
|
||||
const getUserFriendlyMessageProperty = (error, property) => {
|
||||
const code = _.get(error, [ 'code' ])
|
||||
|
||||
if (_.isNil(code) || !_.isString(code)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return _.invoke(exports.HUMAN_FRIENDLY, [ code, property ], error)
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Check if a string is blank
|
||||
* @function
|
||||
* @private
|
||||
*
|
||||
* @param {String} string - string
|
||||
* @returns {Boolean} whether the string is blank
|
||||
*
|
||||
* @example
|
||||
* if (isBlank(' ')) {
|
||||
* console.log('The string is blank');
|
||||
* }
|
||||
*/
|
||||
const isBlank = _.flow([ _.trim, _.isEmpty ])
|
||||
|
||||
/**
|
||||
* @summary Get the title of an error
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @description
|
||||
* Try to get as much information as possible about the error
|
||||
* rather than falling back to generic messages right away.
|
||||
*
|
||||
* @param {Error} error - error
|
||||
* @returns {String} error title
|
||||
*
|
||||
* @example
|
||||
* const error = new Error('Foo bar');
|
||||
* const title = errors.getTitle(error);
|
||||
* console.log(title);
|
||||
*/
|
||||
exports.getTitle = (error) => {
|
||||
if (!_.isError(error) && !_.isPlainObject(error) && !_.isNil(error)) {
|
||||
return _.toString(error)
|
||||
}
|
||||
|
||||
const codeTitle = getUserFriendlyMessageProperty(error, 'title')
|
||||
if (!_.isNil(codeTitle)) {
|
||||
return codeTitle
|
||||
}
|
||||
|
||||
const message = _.get(error, [ 'message' ])
|
||||
if (!isBlank(message)) {
|
||||
return message
|
||||
}
|
||||
|
||||
const code = _.get(error, [ 'code' ])
|
||||
if (!_.isNil(code) && !isBlank(code)) {
|
||||
return `Error code: ${code}`
|
||||
}
|
||||
|
||||
return 'An error ocurred'
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Get the description of an error
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @param {Error} error - error
|
||||
* @param {Object} options - options
|
||||
* @param {Boolean} [options.userFriendlyDescriptionsOnly=false] - only return user friendly descriptions
|
||||
* @returns {String} error description
|
||||
*
|
||||
* @example
|
||||
* const error = new Error('Foo bar');
|
||||
* const description = errors.getDescription(error);
|
||||
* console.log(description);
|
||||
*/
|
||||
exports.getDescription = (error, options = {}) => {
|
||||
_.defaults(options, {
|
||||
userFriendlyDescriptionsOnly: false
|
||||
})
|
||||
|
||||
if (!_.isError(error) && !_.isPlainObject(error)) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!isBlank(error.description)) {
|
||||
return error.description
|
||||
}
|
||||
|
||||
const codeDescription = getUserFriendlyMessageProperty(error, 'description')
|
||||
if (!_.isNil(codeDescription)) {
|
||||
return codeDescription
|
||||
}
|
||||
|
||||
if (options.userFriendlyDescriptionsOnly) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (error.stack) {
|
||||
return error.stack
|
||||
}
|
||||
|
||||
if (_.isEmpty(error)) {
|
||||
return ''
|
||||
}
|
||||
|
||||
const INDENTATION_SPACES = 2
|
||||
return JSON.stringify(error, null, INDENTATION_SPACES)
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Create an error
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @param {Object} options - options
|
||||
* @param {String} options.title - error title
|
||||
* @param {String} [options.description] - error description
|
||||
* @param {Boolean} [options.report] - report error
|
||||
* @returns {Error} error
|
||||
*
|
||||
* @example
|
||||
* const error = errors.createError({
|
||||
* title: 'Foo'
|
||||
* description: 'Bar'
|
||||
* });
|
||||
*
|
||||
* throw error;
|
||||
*/
|
||||
exports.createError = (options) => {
|
||||
if (isBlank(options.title)) {
|
||||
throw new Error(`Invalid error title: ${options.title}`)
|
||||
}
|
||||
|
||||
const error = new Error(options.title)
|
||||
error.description = options.description
|
||||
|
||||
if (!_.isNil(options.report) && !options.report) {
|
||||
error.report = false
|
||||
}
|
||||
|
||||
if (!_.isNil(options.code)) {
|
||||
error.code = options.code
|
||||
}
|
||||
|
||||
return error
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Create a user error
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @description
|
||||
* User errors represent invalid states that the user
|
||||
* caused, that are not errors on the application itself.
|
||||
* Therefore, user errors don't get reported to analytics
|
||||
* and error reporting services.
|
||||
*
|
||||
* @param {Object} options - options
|
||||
* @param {String} options.title - error title
|
||||
* @param {String} [options.description] - error description
|
||||
* @returns {Error} user error
|
||||
*
|
||||
* @example
|
||||
* const error = errors.createUserError({
|
||||
* title: 'Foo',
|
||||
* description: 'Bar'
|
||||
* });
|
||||
*
|
||||
* throw error;
|
||||
*/
|
||||
exports.createUserError = (options) => {
|
||||
return exports.createError({
|
||||
title: options.title,
|
||||
description: options.description,
|
||||
report: false,
|
||||
code: options.code
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Check if an error is an user error
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @param {Error} error - error
|
||||
* @returns {Boolean} whether the error is a user error
|
||||
*
|
||||
* @example
|
||||
* const error = errors.createUserError('Foo', 'Bar');
|
||||
*
|
||||
* if (errors.isUserError(error)) {
|
||||
* console.log('This error is a user error');
|
||||
* }
|
||||
*/
|
||||
exports.isUserError = (error) => {
|
||||
return _.isNil(error.report) ? false : !error.report
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Convert an Error object to a JSON object
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @param {Error} error - error object
|
||||
* @returns {Object} json error
|
||||
*
|
||||
* @example
|
||||
* const error = errors.toJSON(new Error('foo'))
|
||||
*
|
||||
* console.log(error.message);
|
||||
* > 'foo'
|
||||
*/
|
||||
exports.toJSON = (error) => {
|
||||
// Handle string error objects to be on the safe side
|
||||
const isErrorLike = _.isError(error) || _.isPlainObject(error)
|
||||
const errorObject = isErrorLike ? error : new Error(error)
|
||||
|
||||
return {
|
||||
name: errorObject.name,
|
||||
message: errorObject.message,
|
||||
description: errorObject.description,
|
||||
stack: errorObject.stack,
|
||||
report: errorObject.report,
|
||||
code: errorObject.code,
|
||||
syscall: errorObject.syscall,
|
||||
errno: errorObject.errno,
|
||||
stdout: errorObject.stdout,
|
||||
stderr: errorObject.stderr,
|
||||
device: errorObject.device
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Convert a JSON object to an Error object
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @param {Error} json - json object
|
||||
* @returns {Object} error object
|
||||
*
|
||||
* @example
|
||||
* const error = errors.fromJSON(errors.toJSON(new Error('foo')));
|
||||
*
|
||||
* console.log(error.message);
|
||||
* > 'foo'
|
||||
*/
|
||||
exports.fromJSON = (json) => {
|
||||
return _.assign(new Error(json.message), json)
|
||||
}
|
347
lib/gui/app/modules/errors.ts
Normal file
347
lib/gui/app/modules/errors.ts
Normal file
@ -0,0 +1,347 @@
|
||||
/*
|
||||
* Copyright 2016 resin.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
assign,
|
||||
flow,
|
||||
invoke,
|
||||
isEmpty,
|
||||
isError,
|
||||
isNil,
|
||||
isPlainObject,
|
||||
isString,
|
||||
toString,
|
||||
trim,
|
||||
} from 'lodash';
|
||||
|
||||
import { Dict } from './utils';
|
||||
|
||||
const INDENTATION_SPACES = 2;
|
||||
|
||||
/**
|
||||
* @summary Human-friendly error messages
|
||||
*/
|
||||
export const HUMAN_FRIENDLY: Dict<{
|
||||
title: (error?: { path?: string }) => string;
|
||||
description: (error?: any) => string;
|
||||
}> = {
|
||||
ENOENT: {
|
||||
title: (error: { path: string }) =>
|
||||
`No such file or directory: ${error.path}`,
|
||||
description: () => "The file you're trying to access doesn't exist",
|
||||
},
|
||||
EPERM: {
|
||||
title: () => "You're not authorized to perform this operation",
|
||||
description: () =>
|
||||
'Please ensure you have necessary permissions for this task',
|
||||
},
|
||||
EACCES: {
|
||||
title: () => "You don't have access to this resource",
|
||||
description: () =>
|
||||
'Please ensure you have necessary permissions to access this resource',
|
||||
},
|
||||
ENOMEM: {
|
||||
title: () => 'Your system ran out of memory',
|
||||
description: () =>
|
||||
'Please make sure your system has enough available memory for this task',
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @summary Get user friendly property from an error
|
||||
* @function
|
||||
* @private
|
||||
*
|
||||
* @param {Error} error - error
|
||||
* @param {String} property - HUMAN_FRIENDLY property
|
||||
* @returns {(String|Undefined)} user friendly message
|
||||
*
|
||||
* @example
|
||||
* const error = new Error('My error');
|
||||
* error.code = 'ENOMEM';
|
||||
*
|
||||
* const friendlyDescription = getUserFriendlyMessageProperty(error, 'description');
|
||||
*
|
||||
* if (friendlyDescription) {
|
||||
* console.log(friendlyDescription);
|
||||
* }
|
||||
*/
|
||||
function getUserFriendlyMessageProperty(
|
||||
error: { code?: string; path?: string },
|
||||
property: 'title' | 'description',
|
||||
): string | null {
|
||||
const code = error.code;
|
||||
if (!isString(code)) {
|
||||
return null;
|
||||
}
|
||||
return invoke(HUMAN_FRIENDLY, [code, property], error);
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Check if a string is blank
|
||||
* @function
|
||||
* @private
|
||||
*
|
||||
* @param {String} string - string
|
||||
* @returns {Boolean} whether the string is blank
|
||||
*
|
||||
* @example
|
||||
* if (isBlank(' ')) {
|
||||
* console.log('The string is blank');
|
||||
* }
|
||||
*/
|
||||
const isBlank = flow([trim, isEmpty]);
|
||||
|
||||
/**
|
||||
* @summary Get the title of an error
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @description
|
||||
* Try to get as much information as possible about the error
|
||||
* rather than falling back to generic messages right away.
|
||||
*
|
||||
* @param {Error} error - error
|
||||
* @returns {String} error title
|
||||
*
|
||||
* @example
|
||||
* const error = new Error('Foo bar');
|
||||
* const title = errors.getTitle(error);
|
||||
* console.log(title);
|
||||
*/
|
||||
export function getTitle(error: Error | Dict<any>): string {
|
||||
if (!isError(error) && !isPlainObject(error) && !isNil(error)) {
|
||||
return toString(error);
|
||||
}
|
||||
|
||||
const codeTitle = getUserFriendlyMessageProperty(error, 'title');
|
||||
if (!isNil(codeTitle)) {
|
||||
return codeTitle;
|
||||
}
|
||||
|
||||
const message = error.message;
|
||||
if (!isBlank(message)) {
|
||||
return message;
|
||||
}
|
||||
|
||||
const code = error.code;
|
||||
if (!isNil(code) && !isBlank(code)) {
|
||||
return `Error code: ${code}`;
|
||||
}
|
||||
|
||||
return 'An error ocurred';
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Get the description of an error
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @param {Error} error - error
|
||||
* @returns {String} error description
|
||||
*
|
||||
* @example
|
||||
* const error = new Error('Foo bar');
|
||||
* const description = errors.getDescription(error);
|
||||
* console.log(description);
|
||||
*/
|
||||
export function getDescription(error: {
|
||||
code?: string;
|
||||
description?: string;
|
||||
stack?: string;
|
||||
}): string {
|
||||
if (!isError(error) && !isPlainObject(error)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (!isBlank(error.description)) {
|
||||
return error.description as string;
|
||||
}
|
||||
|
||||
const codeDescription = getUserFriendlyMessageProperty(error, 'description');
|
||||
if (!isNil(codeDescription)) {
|
||||
return codeDescription;
|
||||
}
|
||||
|
||||
if (error.stack) {
|
||||
return error.stack;
|
||||
}
|
||||
|
||||
if (isEmpty(error)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return JSON.stringify(error, null, INDENTATION_SPACES);
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Create an error
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @param {Object} options - options
|
||||
* @param {String} options.title - error title
|
||||
* @param {String} [options.description] - error description
|
||||
* @param {Boolean} [options.report] - report error
|
||||
* @returns {Error} error
|
||||
*
|
||||
* @example
|
||||
* const error = errors.createError({
|
||||
* title: 'Foo'
|
||||
* description: 'Bar'
|
||||
* });
|
||||
*
|
||||
* throw error;
|
||||
*/
|
||||
export function createError(options: {
|
||||
title: string;
|
||||
description?: string;
|
||||
report?: boolean;
|
||||
code?: string;
|
||||
}): Error & { description?: string; report?: boolean; code?: string } {
|
||||
if (isBlank(options.title)) {
|
||||
throw new Error(`Invalid error title: ${options.title}`);
|
||||
}
|
||||
|
||||
const error: Error & {
|
||||
description?: string;
|
||||
report?: boolean;
|
||||
code?: string;
|
||||
} = new Error(options.title);
|
||||
error.description = options.description;
|
||||
|
||||
if (!isNil(options.report) && !options.report) {
|
||||
error.report = false;
|
||||
}
|
||||
|
||||
if (!isNil(options.code)) {
|
||||
error.code = options.code;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Create a user error
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @description
|
||||
* User errors represent invalid states that the user
|
||||
* caused, that are not errors on the application itself.
|
||||
* Therefore, user errors don't get reported to analytics
|
||||
* and error reporting services.
|
||||
*
|
||||
* @returns {Error} user error
|
||||
*
|
||||
* @example
|
||||
* const error = errors.createUserError({
|
||||
* title: 'Foo',
|
||||
* description: 'Bar'
|
||||
* });
|
||||
*
|
||||
* throw error;
|
||||
*/
|
||||
export function createUserError(options: {
|
||||
title: string;
|
||||
description: string;
|
||||
code?: string;
|
||||
}): Error {
|
||||
return createError({
|
||||
title: options.title,
|
||||
description: options.description,
|
||||
report: false,
|
||||
code: options.code,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Check if an error is an user error
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @param {Error} error - error
|
||||
* @returns {Boolean} whether the error is a user error
|
||||
*
|
||||
* @example
|
||||
* const error = errors.createUserError('Foo', 'Bar');
|
||||
*
|
||||
* if (errors.isUserError(error)) {
|
||||
* console.log('This error is a user error');
|
||||
* }
|
||||
*/
|
||||
export function isUserError(error: { report?: boolean }): boolean {
|
||||
return isNil(error.report) ? false : !error.report;
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Convert an Error object to a JSON object
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @param {Error} error - error object
|
||||
* @returns {Object} json error
|
||||
*
|
||||
* @example
|
||||
* const error = errors.toJSON(new Error('foo'))
|
||||
*
|
||||
* console.log(error.message);
|
||||
* > 'foo'
|
||||
*/
|
||||
export function toJSON(
|
||||
error: Error & {
|
||||
description?: string;
|
||||
report?: boolean;
|
||||
code?: string;
|
||||
syscall?: string;
|
||||
errno?: string | number;
|
||||
stdout?: string;
|
||||
stderr?: string;
|
||||
device?: any;
|
||||
},
|
||||
) {
|
||||
return {
|
||||
name: error.name,
|
||||
message: error.message,
|
||||
description: error.description,
|
||||
stack: error.stack,
|
||||
report: error.report,
|
||||
code: error.code,
|
||||
syscall: error.syscall,
|
||||
errno: error.errno,
|
||||
stdout: error.stdout,
|
||||
stderr: error.stderr,
|
||||
device: error.device,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Convert a JSON object to an Error object
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @param {Error} json - json object
|
||||
* @returns {Object} error object
|
||||
*
|
||||
* @example
|
||||
* const error = errors.fromJSON(errors.toJSON(new Error('foo')));
|
||||
*
|
||||
* console.log(error.message);
|
||||
* > 'foo'
|
||||
*/
|
||||
export function fromJSON(json: Dict<any>): Error {
|
||||
return assign(new Error(json.message), json);
|
||||
}
|
@ -24,8 +24,10 @@ const ipc = require('node-ipc')
|
||||
const isRunningInAsar = require('electron-is-running-in-asar')
|
||||
const electron = require('electron')
|
||||
const store = require('../models/store')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const settings = require('../models/settings')
|
||||
const flashState = require('../models/flash-state')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const errors = require('../../../gui/app/modules/errors')
|
||||
const permissions = require('../../../gui/app/modules/permissions')
|
||||
const windowProgress = require('../os/window-progress')
|
||||
|
@ -26,8 +26,10 @@ const os = require('os')
|
||||
const sudoPrompt = Bluebird.promisifyAll(require('sudo-prompt'))
|
||||
const { promisify } = require('util')
|
||||
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const errors = require('./errors')
|
||||
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const { tmpFileDisposer } = require('./utils')
|
||||
|
||||
const writeFileAsync = promisify(fs.writeFile)
|
||||
|
@ -16,7 +16,9 @@
|
||||
|
||||
'use strict'
|
||||
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const settings = require('../models/settings')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const utils = require('../../../gui/app/modules/utils')
|
||||
const units = require('../../../gui/app/modules/units')
|
||||
|
||||
|
@ -21,6 +21,7 @@ const EventEmitter = require('events')
|
||||
const createInactivityTimer = require('inactivity-timer')
|
||||
const debug = require('debug')('etcher:update-lock')
|
||||
const analytics = require('./analytics')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const settings = require('../models/settings')
|
||||
|
||||
/* eslint-disable no-magic-numbers, callback-return */
|
||||
|
@ -14,14 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
import * as Bluebird from 'bluebird';
|
||||
import * as _ from 'lodash';
|
||||
import * as request from 'request';
|
||||
import * as tmp from 'tmp';
|
||||
import { promisify } from 'util';
|
||||
|
||||
const _ = require('lodash')
|
||||
const Bluebird = require('bluebird')
|
||||
const request = Bluebird.promisifyAll(require('request'))
|
||||
const tmp = require('tmp')
|
||||
import * as errors from './errors';
|
||||
|
||||
const errors = require('./errors')
|
||||
const getAsync = promisify(request.get);
|
||||
|
||||
/**
|
||||
* @summary Minimum percentage value
|
||||
@ -29,7 +30,7 @@ const errors = require('./errors')
|
||||
* @public
|
||||
* @type {Number}
|
||||
*/
|
||||
exports.PERCENTAGE_MINIMUM = 0
|
||||
export const PERCENTAGE_MINIMUM = 0;
|
||||
|
||||
/**
|
||||
* @summary Maximum percentage value
|
||||
@ -37,7 +38,7 @@ exports.PERCENTAGE_MINIMUM = 0
|
||||
* @public
|
||||
* @type {Number}
|
||||
*/
|
||||
exports.PERCENTAGE_MAXIMUM = 100
|
||||
export const PERCENTAGE_MAXIMUM = 100;
|
||||
|
||||
/**
|
||||
* @summary Check if a percentage is valid
|
||||
@ -52,12 +53,12 @@ exports.PERCENTAGE_MAXIMUM = 100
|
||||
* console.log('The percentage is valid');
|
||||
* }
|
||||
*/
|
||||
exports.isValidPercentage = (percentage) => {
|
||||
return _.every([
|
||||
_.isNumber(percentage),
|
||||
percentage >= exports.PERCENTAGE_MINIMUM,
|
||||
percentage <= exports.PERCENTAGE_MAXIMUM
|
||||
])
|
||||
export function isValidPercentage(percentage: number) {
|
||||
return _.every([
|
||||
_.isNumber(percentage),
|
||||
percentage >= exports.PERCENTAGE_MINIMUM,
|
||||
percentage <= exports.PERCENTAGE_MAXIMUM,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -73,14 +74,14 @@ exports.isValidPercentage = (percentage) => {
|
||||
* console.log(value);
|
||||
* > 0.5
|
||||
*/
|
||||
exports.percentageToFloat = (percentage) => {
|
||||
if (!exports.isValidPercentage(percentage)) {
|
||||
throw errors.createError({
|
||||
title: `Invalid percentage: ${percentage}`
|
||||
})
|
||||
}
|
||||
export function percentageToFloat(percentage: number) {
|
||||
if (!isValidPercentage(percentage)) {
|
||||
throw errors.createError({
|
||||
title: `Invalid percentage: ${percentage}`,
|
||||
});
|
||||
}
|
||||
|
||||
return percentage / exports.PERCENTAGE_MAXIMUM
|
||||
return percentage / PERCENTAGE_MAXIMUM;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -109,37 +110,40 @@ exports.percentageToFloat = (percentage) => {
|
||||
*
|
||||
* const memoizedFunction = memoize(getList, angular.equals);
|
||||
*/
|
||||
exports.memoize = (func, comparer) => {
|
||||
let previousTuples = []
|
||||
export function memoize(
|
||||
func: (...args: any[]) => any,
|
||||
comparer: (a: any, b: any) => boolean,
|
||||
) {
|
||||
let previousTuples: any[] = [];
|
||||
|
||||
return (...restArgs) => {
|
||||
let areArgsInTuple = false
|
||||
let state = Reflect.apply(func, this, restArgs)
|
||||
return (...restArgs: any[]) => {
|
||||
let areArgsInTuple = false;
|
||||
let state = Reflect.apply(func, this, restArgs);
|
||||
|
||||
previousTuples = _.map(previousTuples, ([ oldArgs, oldState ]) => {
|
||||
if (comparer(oldArgs, restArgs)) {
|
||||
areArgsInTuple = true
|
||||
previousTuples = _.map(previousTuples, ([oldArgs, oldState]) => {
|
||||
if (comparer(oldArgs, restArgs)) {
|
||||
areArgsInTuple = true;
|
||||
|
||||
if (comparer(state, oldState)) {
|
||||
// Use the previously memoized state for this argument
|
||||
state = oldState
|
||||
}
|
||||
if (comparer(state, oldState)) {
|
||||
// Use the previously memoized state for this argument
|
||||
state = oldState;
|
||||
}
|
||||
|
||||
// Update the tuple state
|
||||
return [ oldArgs, state ]
|
||||
}
|
||||
// Update the tuple state
|
||||
return [oldArgs, state];
|
||||
}
|
||||
|
||||
// Return the tuple unchanged
|
||||
return [ oldArgs, oldState ]
|
||||
})
|
||||
// Return the tuple unchanged
|
||||
return [oldArgs, oldState];
|
||||
});
|
||||
|
||||
// Add the state associated with these args to be memoized
|
||||
if (!areArgsInTuple) {
|
||||
previousTuples.push([ restArgs, state ])
|
||||
}
|
||||
// Add the state associated with these args to be memoized
|
||||
if (!areArgsInTuple) {
|
||||
previousTuples.push([restArgs, state]);
|
||||
}
|
||||
|
||||
return state
|
||||
}
|
||||
return state;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -155,20 +159,19 @@ exports.memoize = (func, comparer) => {
|
||||
* @example
|
||||
* const doesIt = hasProps({ foo: 'bar' }, [ 'foo' ]);
|
||||
*/
|
||||
exports.hasProps = (obj, props) => {
|
||||
return _.every(props, (prop) => {
|
||||
return _.has(obj, prop)
|
||||
})
|
||||
export function hasProps(obj: any, props: string[]) {
|
||||
return _.every(props, prop => {
|
||||
return _.has(obj, prop);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Get etcher configs stored online
|
||||
* @param {String} - url where config.json is stored
|
||||
*/
|
||||
// eslint-disable-next-line
|
||||
exports.getConfig = (configUrl) => {
|
||||
return request.getAsync(configUrl, { json: true })
|
||||
.get('body')
|
||||
* @summary Get etcher configs stored online
|
||||
* @param {String} - url where config.json is stored
|
||||
*/
|
||||
export async function getConfig(configUrl: string) {
|
||||
// @ts-ignore
|
||||
return (await getAsync(configUrl, { json: true })).body;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -186,16 +189,16 @@ exports.getConfig = (configUrl) => {
|
||||
* cleanup()
|
||||
* });
|
||||
*/
|
||||
const tmpFileAsync = (options) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
tmp.file(options, (error, path, _fd, cleanup) => {
|
||||
if (error) {
|
||||
reject(error)
|
||||
} else {
|
||||
resolve({ path, cleanup })
|
||||
}
|
||||
})
|
||||
})
|
||||
function tmpFileAsync(options: tmp.FileOptions) {
|
||||
return new Promise((resolve, reject) => {
|
||||
tmp.file(options, (error, path, _fd, cleanup) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve({ path, cleanup });
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -211,9 +214,12 @@ const tmpFileAsync = (options) => {
|
||||
* console.log(path);
|
||||
* })
|
||||
*/
|
||||
exports.tmpFileDisposer = (options) => {
|
||||
return Bluebird.resolve(tmpFileAsync(options))
|
||||
.disposer(({ cleanup }) => {
|
||||
cleanup()
|
||||
})
|
||||
export function tmpFileDisposer(options: tmp.FileOptions) {
|
||||
return Bluebird.resolve(tmpFileAsync(options)).disposer(({ cleanup }) => {
|
||||
cleanup();
|
||||
});
|
||||
}
|
||||
|
||||
export interface Dict<T> {
|
||||
[key: string]: T;
|
||||
}
|
@ -19,6 +19,7 @@
|
||||
const _ = require('lodash')
|
||||
const electron = require('electron')
|
||||
const Bluebird = require('bluebird')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const errors = require('../../../gui/app/modules/errors')
|
||||
const supportedFormats = require('../../../gui/app/modules/supported-formats')
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
'use strict'
|
||||
|
||||
const electron = require('electron')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const settings = require('../models/settings')
|
||||
|
||||
/**
|
||||
|
@ -19,6 +19,7 @@
|
||||
const electron = require('electron')
|
||||
const store = require('../../../models/store')
|
||||
const analytics = require('../../../modules/analytics')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const settings = require('../../../models/settings')
|
||||
|
||||
module.exports = function () {
|
||||
|
@ -17,6 +17,7 @@
|
||||
'use strict'
|
||||
|
||||
const electron = require('electron')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const utils = require('../../../gui/app/modules/utils')
|
||||
const progressStatus = require('../modules/progress-status')
|
||||
|
||||
|
@ -25,6 +25,7 @@ const Path = require('path')
|
||||
const process = require('process')
|
||||
const { promisify } = require('util')
|
||||
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const { tmpFileDisposer } = require('../../../gui/app/modules/utils')
|
||||
|
||||
const readFileAsync = promisify(fs.readFile)
|
||||
|
@ -19,6 +19,7 @@
|
||||
const _ = require('lodash')
|
||||
const uuidV4 = require('uuid/v4')
|
||||
const store = require('../../../models/store')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const settings = require('../../../models/settings')
|
||||
const flashState = require('../../../models/flash-state')
|
||||
const selectionState = require('../../../models/selection-state')
|
||||
|
@ -20,10 +20,12 @@ const _ = require('lodash')
|
||||
const angular = require('angular')
|
||||
const prettyBytes = require('pretty-bytes')
|
||||
const store = require('../../../models/store')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const settings = require('../../../models/settings')
|
||||
const selectionState = require('../../../models/selection-state')
|
||||
const analytics = require('../../../modules/analytics')
|
||||
const exceptionReporter = require('../../../modules/exception-reporter')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const utils = require('../../../../../gui/app/modules/utils')
|
||||
|
||||
module.exports = function (DriveSelectorService) {
|
||||
|
@ -23,9 +23,11 @@ const sdk = require('etcher-sdk')
|
||||
|
||||
const store = require('../../../models/store')
|
||||
const messages = require('../../../../../gui/app/modules/messages')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const errors = require('../../../../../gui/app/modules/errors')
|
||||
const supportedFormats = require('../../../../../gui/app/modules/supported-formats')
|
||||
const analytics = require('../../../modules/analytics')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const settings = require('../../../models/settings')
|
||||
const selectionState = require('../../../models/selection-state')
|
||||
const osDialog = require('../../../os/dialog')
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
const path = require('path')
|
||||
const store = require('../../../models/store')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const settings = require('../../../models/settings')
|
||||
const flashState = require('../../../models/flash-state')
|
||||
const analytics = require('../../../modules/analytics')
|
||||
|
@ -19,6 +19,7 @@
|
||||
const os = require('os')
|
||||
const _ = require('lodash')
|
||||
const store = require('../../../models/store')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const settings = require('../../../models/settings')
|
||||
const analytics = require('../../../modules/analytics')
|
||||
const exceptionReporter = require('../../../modules/exception-reporter')
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
'use strict'
|
||||
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const errors = require('../../../../../gui/app/modules/errors')
|
||||
|
||||
/**
|
||||
|
@ -23,8 +23,10 @@ const { autoUpdater } = require('electron-updater')
|
||||
const Bluebird = require('bluebird')
|
||||
const EXIT_CODES = require('./app/modules/exit-codes')
|
||||
const buildWindowMenu = require('./menu')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const settings = require('./app/models/settings')
|
||||
const analytics = require('./app/modules/analytics')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const { getConfig } = require('./app/modules/utils')
|
||||
/* eslint-disable lodash/prefer-lodash-method */
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
||||
// an older equivalent of `ELECTRON_RUN_AS_NODE` that still gets set when
|
||||
// using `child_process.fork()`.
|
||||
if (process.env.ELECTRON_RUN_AS_NODE || process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE) {
|
||||
require('./gui/app/modules/child-writer')
|
||||
require('../generated/child-writer')
|
||||
} else {
|
||||
require('../generated/etcher')
|
||||
}
|
||||
|
90
npm-shrinkwrap.json
generated
90
npm-shrinkwrap.json
generated
@ -980,6 +980,12 @@
|
||||
"integrity": "sha512-6BmYWSBea18+tSjjSC3QIyV93ZKAeNWGM7R6aYt1ryTZXrlHF+QLV0G2yV0viEGVyRkyQsWfMoJ0k/YghBX5sQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/caseless": {
|
||||
"version": "0.12.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz",
|
||||
"integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/color": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/color/-/color-2.0.1.tgz",
|
||||
@ -1001,6 +1007,12 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
|
||||
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ=="
|
||||
},
|
||||
"@types/debug": {
|
||||
"version": "4.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.4.tgz",
|
||||
"integrity": "sha512-D9MyoQFI7iP5VdpEyPZyjjqIJ8Y8EDNQFIFVLOmeg1rI1xiHOChyUPMPRUVfqFCerxfE+yS3vMyj37F6IdtOoQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/depcheck": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/depcheck/-/depcheck-0.6.0.tgz",
|
||||
@ -1013,6 +1025,15 @@
|
||||
"integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/form-data": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-2.2.1.tgz",
|
||||
"integrity": "sha512-JAMFhOaHIciYVh8fb5/83nmuO/AHwmto+Hq7a9y8FzLDcC1KCU344XDOMEmahnrTFlHjgh4L0WJFczNIX2GxnQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/glob": {
|
||||
"version": "5.0.36",
|
||||
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-5.0.36.tgz",
|
||||
@ -1127,6 +1148,18 @@
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/request": {
|
||||
"version": "2.48.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.1.tgz",
|
||||
"integrity": "sha512-ZgEZ1TiD+KGA9LiAAPPJL68Id2UWfeSO62ijSXZjFJArVV+2pKcsVHmrcu+1oiE3q6eDGiFiSolRc4JHoerBBg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/caseless": "*",
|
||||
"@types/form-data": "*",
|
||||
"@types/node": "*",
|
||||
"@types/tough-cookie": "*"
|
||||
}
|
||||
},
|
||||
"@types/styled-components": {
|
||||
"version": "4.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/styled-components/-/styled-components-4.1.8.tgz",
|
||||
@ -1145,6 +1178,18 @@
|
||||
"csstype": "^2.6.4"
|
||||
}
|
||||
},
|
||||
"@types/tmp": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/tmp/-/tmp-0.1.0.tgz",
|
||||
"integrity": "sha512-6IwZ9HzWbCq6XoQWhxLpDjuADodH/MKXRUIDFudvgjcVdjFknvmR+DNsoUeer4XPrEnrZs04Jj+kfV9pFsrhmA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/tough-cookie": {
|
||||
"version": "2.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.5.tgz",
|
||||
"integrity": "sha512-SCcK7mvGi3+ZNz833RRjFIxrn4gI1PPR3NtuIS+6vMkvmsGjosqTJwRt5bAEFLRz+wtJMWv8+uOnZf2hi2QXTg==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/usb": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/usb/-/usb-1.5.1.tgz",
|
||||
@ -1674,6 +1719,12 @@
|
||||
"readable-stream": "^2.0.6"
|
||||
}
|
||||
},
|
||||
"arg": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.0.tgz",
|
||||
"integrity": "sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg==",
|
||||
"dev": true
|
||||
},
|
||||
"argparse": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
|
||||
@ -4504,9 +4555,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"commander": {
|
||||
"version": "2.19.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz",
|
||||
"integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==",
|
||||
"version": "2.20.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
|
||||
"integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==",
|
||||
"dev": true
|
||||
},
|
||||
"fs-extra": {
|
||||
@ -7823,6 +7874,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"make-error": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz",
|
||||
"integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==",
|
||||
"dev": true
|
||||
},
|
||||
"mamacro": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz",
|
||||
@ -12678,6 +12735,27 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"ts-node": {
|
||||
"version": "8.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.3.0.tgz",
|
||||
"integrity": "sha512-dyNS/RqyVTDcmNM4NIBAeDMpsAdaQ+ojdf0GOLqE6nwJOgzEkdRNzJywhDfwnuvB10oa6NLVG1rUJQCpRN7qoQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"arg": "^4.1.0",
|
||||
"diff": "^4.0.1",
|
||||
"make-error": "^1.1.1",
|
||||
"source-map-support": "^0.5.6",
|
||||
"yn": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"diff": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz",
|
||||
"integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"tslib": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
|
||||
@ -14300,6 +14378,12 @@
|
||||
"fd-slicer": "~1.1.0"
|
||||
}
|
||||
},
|
||||
"yn": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.0.tgz",
|
||||
"integrity": "sha512-kKfnnYkbTfrAdd0xICNFw7Atm8nKpLcLv9AZGEt+kczL/WQVai4e2V6ZN8U/O+iI6WrNuJjNNOyu4zfhl9D3Hg==",
|
||||
"dev": true
|
||||
},
|
||||
"zip-stream": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-1.2.0.tgz",
|
||||
|
@ -86,8 +86,11 @@
|
||||
"@babel/plugin-proposal-function-bind": "^7.2.0",
|
||||
"@babel/preset-env": "^7.2.0",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"@types/debug": "^4.1.4",
|
||||
"@types/node": "^10.14.9",
|
||||
"@types/react-dom": "^16.8.4",
|
||||
"@types/request": "^2.48.1",
|
||||
"@types/tmp": "^0.1.0",
|
||||
"acorn": "^6.0.5",
|
||||
"angular-mocks": "1.7.6",
|
||||
"babel-loader": "^8.0.4",
|
||||
@ -119,6 +122,7 @@
|
||||
"spectron": "^5.0.0",
|
||||
"style-loader": "^0.23.1",
|
||||
"ts-loader": "^6.0.2",
|
||||
"ts-node": "^8.3.0",
|
||||
"typescript": "^3.5.1",
|
||||
"webpack": "^4.31.0",
|
||||
"webpack-cli": "^3.1.2",
|
||||
|
@ -20,6 +20,7 @@ const _ = require('lodash')
|
||||
const m = require('mochainon')
|
||||
const angular = require('angular')
|
||||
require('angular-mocks')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const utils = require('../../../lib/gui/app/modules/utils')
|
||||
|
||||
describe('Browser: DriveSelector', function () {
|
||||
|
@ -18,8 +18,9 @@
|
||||
|
||||
const m = require('mochainon')
|
||||
const _ = require('lodash')
|
||||
const Bluebird = require('bluebird')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const settings = require('../../../lib/gui/app/models/settings')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const localSettings = require('../../../lib/gui/app/models/local-settings')
|
||||
|
||||
describe('Browser: settings', function () {
|
||||
@ -73,12 +74,14 @@ describe('Browser: settings', function () {
|
||||
})
|
||||
|
||||
describe('.assign()', function () {
|
||||
it('should throw if no settings', function (done) {
|
||||
settings.assign().asCallback((error) => {
|
||||
it('should throw if no settings', async () => {
|
||||
try {
|
||||
await settings.assign()
|
||||
m.chai.expect(true).to.be.false
|
||||
} catch (error) {
|
||||
m.chai.expect(error).to.be.an.instanceof(Error)
|
||||
m.chai.expect(error.message).to.equal('Missing settings')
|
||||
done()
|
||||
})
|
||||
m.chai.expect(error.message).to.equal('Settings must be an object')
|
||||
}
|
||||
})
|
||||
|
||||
it('should not override all settings', function () {
|
||||
@ -108,23 +111,22 @@ describe('Browser: settings', function () {
|
||||
})
|
||||
})
|
||||
|
||||
it('should not change the application state if storing to the local machine results in an error', function (done) {
|
||||
settings.set('foo', 'bar').then(() => {
|
||||
m.chai.expect(settings.get('foo')).to.equal('bar')
|
||||
it('should not change the application state if storing to the local machine results in an error', async () => {
|
||||
await settings.set('foo', 'bar')
|
||||
m.chai.expect(settings.get('foo')).to.equal('bar')
|
||||
|
||||
const localSettingsWriteAllStub = m.sinon.stub(localSettings, 'writeAll')
|
||||
localSettingsWriteAllStub.returns(Bluebird.reject(new Error('localSettings error')))
|
||||
const localSettingsWriteAllStub = m.sinon.stub(localSettings, 'writeAll')
|
||||
localSettingsWriteAllStub.returns(Promise.reject(new Error('localSettings error')))
|
||||
|
||||
settings.assign({
|
||||
foo: 'baz'
|
||||
}).asCallback((error) => {
|
||||
m.chai.expect(error).to.be.an.instanceof(Error)
|
||||
m.chai.expect(error.message).to.equal('localSettings error')
|
||||
localSettingsWriteAllStub.restore()
|
||||
m.chai.expect(settings.get('foo')).to.equal('bar')
|
||||
done()
|
||||
})
|
||||
}).catch(done)
|
||||
try {
|
||||
await settings.assign({ foo: 'baz' })
|
||||
m.chai.expect(true).to.be.false
|
||||
} catch (error) {
|
||||
m.chai.expect(error).to.be.an.instanceof(Error)
|
||||
m.chai.expect(error.message).to.equal('localSettings error')
|
||||
}
|
||||
localSettingsWriteAllStub.restore()
|
||||
m.chai.expect(settings.get('foo')).to.equal('bar')
|
||||
})
|
||||
})
|
||||
|
||||
@ -160,28 +162,34 @@ describe('Browser: settings', function () {
|
||||
})
|
||||
})
|
||||
|
||||
it('should reject if no key', function (done) {
|
||||
settings.set(null, true).asCallback((error) => {
|
||||
it('should reject if no key', async () => {
|
||||
try {
|
||||
await settings.set(null, true)
|
||||
m.chai.expect(true).to.be.false
|
||||
} catch (error) {
|
||||
m.chai.expect(error).to.be.an.instanceof(Error)
|
||||
m.chai.expect(error.message).to.equal('Missing setting key')
|
||||
done()
|
||||
})
|
||||
m.chai.expect(error.message).to.equal('Invalid setting key: null')
|
||||
}
|
||||
})
|
||||
|
||||
it('should throw if key is not a string', function (done) {
|
||||
settings.set(1234, true).asCallback((error) => {
|
||||
it('should throw if key is not a string', async () => {
|
||||
try {
|
||||
await settings.set(1234, true)
|
||||
m.chai.expect(true).to.be.false
|
||||
} catch (error) {
|
||||
m.chai.expect(error).to.be.an.instanceof(Error)
|
||||
m.chai.expect(error.message).to.equal('Invalid setting key: 1234')
|
||||
done()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it('should throw if setting an array', function (done) {
|
||||
settings.assign([ 1, 2, 3 ]).asCallback((error) => {
|
||||
it('should throw if setting an array', async () => {
|
||||
try {
|
||||
await settings.assign([ 1, 2, 3 ])
|
||||
m.chai.expect(true).to.be.false
|
||||
} catch (error) {
|
||||
m.chai.expect(error).to.be.an.instanceof(Error)
|
||||
m.chai.expect(error.message).to.equal('Settings must be an object')
|
||||
done()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it('should set the key to undefined if no value', function () {
|
||||
@ -202,21 +210,22 @@ describe('Browser: settings', function () {
|
||||
})
|
||||
})
|
||||
|
||||
it('should not change the application state if storing to the local machine results in an error', function (done) {
|
||||
settings.set('foo', 'bar').then(() => {
|
||||
it('should not change the application state if storing to the local machine results in an error', async () => {
|
||||
await settings.set('foo', 'bar')
|
||||
m.chai.expect(settings.get('foo')).to.equal('bar')
|
||||
|
||||
const localSettingsWriteAllStub = m.sinon.stub(localSettings, 'writeAll')
|
||||
localSettingsWriteAllStub.returns(Promise.reject(new Error('localSettings error')))
|
||||
|
||||
try {
|
||||
await settings.set('foo', 'baz')
|
||||
m.chai.expect(true).to.be.false
|
||||
} catch (error) {
|
||||
m.chai.expect(error).to.be.an.instanceof(Error)
|
||||
m.chai.expect(error.message).to.equal('localSettings error')
|
||||
localSettingsWriteAllStub.restore()
|
||||
m.chai.expect(settings.get('foo')).to.equal('bar')
|
||||
|
||||
const localSettingsWriteAllStub = m.sinon.stub(localSettings, 'writeAll')
|
||||
localSettingsWriteAllStub.returns(Bluebird.reject(new Error('localSettings error')))
|
||||
|
||||
settings.set('foo', 'baz').asCallback((error) => {
|
||||
m.chai.expect(error).to.be.an.instanceof(Error)
|
||||
m.chai.expect(error.message).to.equal('localSettings error')
|
||||
localSettingsWriteAllStub.restore()
|
||||
m.chai.expect(settings.get('foo')).to.equal('bar')
|
||||
done()
|
||||
})
|
||||
}).catch(done)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
'use strict'
|
||||
|
||||
const m = require('mochainon')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const settings = require('../../../lib/gui/app/models/settings')
|
||||
const progressStatus = require('../../../lib/gui/app/modules/progress-status')
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
const m = require('mochainon')
|
||||
const _ = require('lodash')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const errors = require('../../lib/gui/app/modules/errors')
|
||||
|
||||
describe('Shared: Errors', function () {
|
||||
@ -64,16 +65,6 @@ describe('Shared: Errors', function () {
|
||||
m.chai.expect(errors.getTitle(error)).to.equal('An error ocurred')
|
||||
})
|
||||
|
||||
it('should return a generic error message if the error is undefined', function () {
|
||||
const error = undefined
|
||||
m.chai.expect(errors.getTitle(error)).to.equal('An error ocurred')
|
||||
})
|
||||
|
||||
it('should return a generic error message if the error is null', function () {
|
||||
const error = null
|
||||
m.chai.expect(errors.getTitle(error)).to.equal('An error ocurred')
|
||||
})
|
||||
|
||||
it('should return the error message', function () {
|
||||
const error = new Error('This is an error')
|
||||
m.chai.expect(errors.getTitle(error)).to.equal('This is an error')
|
||||
@ -325,54 +316,21 @@ describe('Shared: Errors', function () {
|
||||
m.chai.expect(errors.getDescription(error)).to.equal('Memory error')
|
||||
})
|
||||
|
||||
describe('given userFriendlyDescriptionsOnly is false', function () {
|
||||
it('should return the stack for a basic error', function () {
|
||||
const error = new Error('Foo')
|
||||
m.chai.expect(errors.getDescription(error, {
|
||||
userFriendlyDescriptionsOnly: false
|
||||
})).to.equal(error.stack)
|
||||
})
|
||||
|
||||
it('should return the stack if the description is an empty string', function () {
|
||||
const error = new Error('Foo')
|
||||
error.description = ''
|
||||
m.chai.expect(errors.getDescription(error, {
|
||||
userFriendlyDescriptionsOnly: false
|
||||
})).to.equal(error.stack)
|
||||
})
|
||||
|
||||
it('should return the stack if the description is a blank string', function () {
|
||||
const error = new Error('Foo')
|
||||
error.description = ' '
|
||||
m.chai.expect(errors.getDescription(error, {
|
||||
userFriendlyDescriptionsOnly: false
|
||||
})).to.equal(error.stack)
|
||||
})
|
||||
it('should return the stack for a basic error', function () {
|
||||
const error = new Error('Foo')
|
||||
m.chai.expect(errors.getDescription(error)).to.equal(error.stack)
|
||||
})
|
||||
|
||||
describe('given userFriendlyDescriptionsOnly is true', function () {
|
||||
it('should return an empty string for a basic error', function () {
|
||||
const error = new Error('Foo')
|
||||
m.chai.expect(errors.getDescription(error, {
|
||||
userFriendlyDescriptionsOnly: true
|
||||
})).to.equal('')
|
||||
})
|
||||
it('should return the stack if the description is an empty string', function () {
|
||||
const error = new Error('Foo')
|
||||
error.description = ''
|
||||
m.chai.expect(errors.getDescription(error)).to.equal(error.stack)
|
||||
})
|
||||
|
||||
it('should return an empty string if the description is an empty string', function () {
|
||||
const error = new Error('Foo')
|
||||
error.description = ''
|
||||
m.chai.expect(errors.getDescription(error, {
|
||||
userFriendlyDescriptionsOnly: true
|
||||
})).to.equal('')
|
||||
})
|
||||
|
||||
it('should return an empty string if the description is a blank string', function () {
|
||||
const error = new Error('Foo')
|
||||
error.description = ' '
|
||||
m.chai.expect(errors.getDescription(error, {
|
||||
userFriendlyDescriptionsOnly: true
|
||||
})).to.equal('')
|
||||
})
|
||||
it('should return the stack if the description is a blank string', function () {
|
||||
const error = new Error('Foo')
|
||||
error.description = ' '
|
||||
m.chai.expect(errors.getDescription(error)).to.equal(error.stack)
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
const _ = require('lodash')
|
||||
const m = require('mochainon')
|
||||
// eslint-disable-next-line node/no-missing-require
|
||||
const utils = require('../../lib/gui/app/modules/utils')
|
||||
|
||||
describe('Shared: Utils', function () {
|
||||
|
@ -4,8 +4,10 @@
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"strictNullChecks": true,
|
||||
"resolveJsonModule": true,
|
||||
"allowJs": true,
|
||||
"moduleResolution": "node",
|
||||
"module": "esNext",
|
||||
"module": "commonjs",
|
||||
"target": "es2017",
|
||||
"jsx": "react"
|
||||
},
|
||||
|
@ -138,7 +138,22 @@ const etcherConfig = _.assign(
|
||||
}
|
||||
)
|
||||
|
||||
const childWriterConfig = _.assign(
|
||||
{},
|
||||
etcherConfig,
|
||||
{
|
||||
entry: {
|
||||
etcher: path.join(__dirname, 'lib', 'gui', 'app', 'modules', 'child-writer.js')
|
||||
},
|
||||
output: {
|
||||
path: path.join(__dirname, 'generated'),
|
||||
filename: 'child-writer.js'
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
module.exports = [
|
||||
guiConfig,
|
||||
etcherConfig
|
||||
etcherConfig,
|
||||
childWriterConfig
|
||||
]
|
||||
|
Loading…
x
Reference in New Issue
Block a user