From 9caa42d25703a98e624a3674bd803c9b28e29fba Mon Sep 17 00:00:00 2001 From: Alexis Svinartchouk Date: Thu, 30 Jan 2020 16:07:55 +0100 Subject: [PATCH 01/13] Remove unused settings.assign function Change-type: patch --- lib/gui/app/models/settings.ts | 24 --------------------- tests/gui/models/settings.spec.ts | 36 ++++++------------------------- 2 files changed, 6 insertions(+), 54 deletions(-) diff --git a/lib/gui/app/models/settings.ts b/lib/gui/app/models/settings.ts index 5b3725b4..dd4e05da 100644 --- a/lib/gui/app/models/settings.ts +++ b/lib/gui/app/models/settings.ts @@ -49,30 +49,6 @@ export async function reset(): Promise { return await localSettings.writeAll(settings); } -/** - * @summary Extend the current settings - */ -export async function assign(value: _.Dictionary): Promise { - debug('assign', value); - if (_.isNil(value)) { - throw errors.createError({ - title: 'Missing settings', - }); - } - - if (!_.isPlainObject(value)) { - throw errors.createError({ - title: 'Settings must be an object', - }); - } - - const newSettings = _.assign({}, settings, value); - - const updatedSettings = await localSettings.writeAll(newSettings); - // NOTE: Only update in memory settings when successfully written - settings = updatedSettings; -} - /** * @summary Extend the application state with the local settings */ diff --git a/tests/gui/models/settings.spec.ts b/tests/gui/models/settings.spec.ts index 5f78b4d7..aacd8eb4 100644 --- a/tests/gui/models/settings.spec.ts +++ b/tests/gui/models/settings.spec.ts @@ -95,34 +95,17 @@ describe('Browser: settings', function() { }); }); - describe('.assign()', function() { - it('should not override all settings', function() { - return settings - .assign({ - foo: 'bar', - bar: 'baz', - }) - .then(() => { - expect(settings.getAll()).to.deep.equal( - _.assign({}, DEFAULT_SETTINGS, { - foo: 'bar', - bar: 'baz', - }), - ); - }); - }); - + describe('.set()', function() { it('should store the settings to the local machine', function() { return localSettings .readAll() .then(data => { expect(data.foo).to.be.undefined; expect(data.bar).to.be.undefined; - - return settings.assign({ - foo: 'bar', - bar: 'baz', - }); + return settings.set('foo', 'bar'); + }) + .then(() => { + return settings.set('bar', 'baz'); }) .then(localSettings.readAll) .then(data => { @@ -140,7 +123,7 @@ describe('Browser: settings', function() { Promise.reject(new Error('localSettings error')), ); - await checkError(settings.assign({ foo: 'baz' }), error => { + await checkError(settings.set('foo', 'baz'), error => { expect(error).to.be.an.instanceof(Error); expect(error.message).to.equal('localSettings error'); localSettingsWriteAllStub.restore(); @@ -189,13 +172,6 @@ describe('Browser: settings', function() { }); }); - it('should throw if setting an array', async function() { - await checkError(settings.assign([1, 2, 3]), error => { - expect(error).to.be.an.instanceof(Error); - expect(error.message).to.equal('Settings must be an object'); - }); - }); - it('should set the key to undefined if no value', function() { return settings .set('foo', 'bar') From 6fcd9e15950b35130bacc42b1a8c811e4b920169 Mon Sep 17 00:00:00 2001 From: Alexis Svinartchouk Date: Thu, 30 Jan 2020 16:40:58 +0100 Subject: [PATCH 02/13] Remove settings.getDefaults function Change-type: patch --- lib/gui/app/models/settings.ts | 11 ++--------- lib/gui/etcher.ts | 17 ++++++++--------- tests/gui/models/settings.spec.ts | 2 +- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/lib/gui/app/models/settings.ts b/lib/gui/app/models/settings.ts index dd4e05da..2f3a62df 100644 --- a/lib/gui/app/models/settings.ts +++ b/lib/gui/app/models/settings.ts @@ -23,7 +23,8 @@ import * as localSettings from './local-settings'; const debug = _debug('etcher:models:settings'); -const DEFAULT_SETTINGS: _.Dictionary = { +// exported for tests +export const DEFAULT_SETTINGS: _.Dictionary = { unsafeMode: false, errorReporting: true, unmountOnSuccess: true, @@ -107,11 +108,3 @@ export function getAll() { debug('getAll'); return _.cloneDeep(settings); } - -/** - * @summary Get the default setting values - */ -export function getDefaults() { - debug('getDefaults'); - return _.cloneDeep(DEFAULT_SETTINGS); -} diff --git a/lib/gui/etcher.ts b/lib/gui/etcher.ts index c1493aaa..320b7681 100644 --- a/lib/gui/etcher.ts +++ b/lib/gui/etcher.ts @@ -28,7 +28,6 @@ import * as settings from './app/models/settings'; import * as analytics from './app/modules/analytics'; import { buildWindowMenu } from './menu'; -const config = settings.getDefaults(); const configUrl = settings.get('configUrl') || 'https://balena.io/etcher/static/config.json'; const updatablePackageTypes = ['appimage', 'nsis', 'dmg']; @@ -58,17 +57,18 @@ async function checkForUpdates(interval: number) { } function createMainWindow() { + const fullscreen = Boolean(settings.get('fullscreen')); const mainWindow = new electron.BrowserWindow({ - width: parseInt(config.width, 10) || 800, - height: parseInt(config.height, 10) || 480, - frame: !config.fullscreen, + width: parseInt(settings.get('width'), 10) || 800, + height: parseInt(settings.get('height'), 10) || 480, + frame: !fullscreen, useContentSize: false, show: false, resizable: false, maximizable: false, - fullscreen: Boolean(config.fullscreen), - fullscreenable: Boolean(config.fullscreen), - kiosk: Boolean(config.fullscreen), + fullscreen, + fullscreenable: fullscreen, + kiosk: fullscreen, autoHideMenuBar: true, titleBarStyle: 'hiddenInset', icon: path.join(__dirname, '..', '..', 'assets', 'icon.png'), @@ -149,8 +149,7 @@ electron.app.on('before-quit', () => { async function main(): Promise { try { - const localSettings = await settings.load(); - Object.assign(config, localSettings); + await settings.load(); } catch (error) { // TODO: What do if loading the config fails? console.error('Error loading settings:'); diff --git a/tests/gui/models/settings.spec.ts b/tests/gui/models/settings.spec.ts index aacd8eb4..c4ae31d8 100644 --- a/tests/gui/models/settings.spec.ts +++ b/tests/gui/models/settings.spec.ts @@ -36,7 +36,7 @@ describe('Browser: settings', function() { return settings.reset(); }); - const DEFAULT_SETTINGS = settings.getDefaults(); + const DEFAULT_SETTINGS = _.cloneDeep(settings.DEFAULT_SETTINGS); it('should be able to set and read values', function() { expect(settings.get('foo')).to.be.undefined; From 571a3533fb839cb4386cf4a5f467cef776ffab6c Mon Sep 17 00:00:00 2001 From: Alexis Svinartchouk Date: Thu, 30 Jan 2020 16:53:14 +0100 Subject: [PATCH 03/13] Load settings before rendering the app Change-type: patch --- lib/gui/app/app.ts | 14 ++++++++++++-- .../featured-project/featured-project.tsx | 3 +-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/gui/app/app.ts b/lib/gui/app/app.ts index 9475af88..952c0b11 100644 --- a/lib/gui/app/app.ts +++ b/lib/gui/app/app.ts @@ -336,6 +336,16 @@ window.addEventListener('touchstart', extendLock); // Initial update lock acquisition extendLock(); -settings.load().catch(exceptionReporter.report); +async function main(): Promise { + try { + await settings.load(); + } catch (error) { + exceptionReporter.report(error); + } + ReactDOM.render( + React.createElement(MainPage), + document.getElementById('main'), + ); +} -ReactDOM.render(React.createElement(MainPage), document.getElementById('main')); +main(); diff --git a/lib/gui/app/components/featured-project/featured-project.tsx b/lib/gui/app/components/featured-project/featured-project.tsx index 49426a8d..98d39d54 100644 --- a/lib/gui/app/components/featured-project/featured-project.tsx +++ b/lib/gui/app/components/featured-project/featured-project.tsx @@ -37,9 +37,8 @@ export class FeaturedProject extends React.Component< this.state = { endpoint: null }; } - public async componentDidMount() { + public componentDidMount() { try { - await settings.load(); const endpoint = settings.get('featuredProjectEndpoint') || 'https://assets.balena.io/etcher-featured/index.html'; From c09237f0c3e424344da3316abedc0a89fb2be237 Mon Sep 17 00:00:00 2001 From: Alexis Svinartchouk Date: Fri, 31 Jan 2020 13:04:21 +0100 Subject: [PATCH 04/13] Sort devices by device path on Linux Changelog-entry: Sort devices by device path on Linux Change-type: patch --- lib/gui/app/models/store.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/gui/app/models/store.ts b/lib/gui/app/models/store.ts index e7575997..e05552da 100644 --- a/lib/gui/app/models/store.ts +++ b/lib/gui/app/models/store.ts @@ -124,7 +124,7 @@ function storeReducer( }); } - const drives = action.data; + let drives = action.data; if (!_.isArray(drives) || !_.every(drives, _.isObject)) { throw errors.createError({ @@ -132,6 +132,13 @@ function storeReducer( }); } + drives = _.sortBy(drives, [ + // Devices with no devicePath first (usbboot) + d => !!d.devicePath, + // Then sort by devicePath (only available on Linux with udev) or device + d => d.devicePath || d.device, + ]); + const newState = state.set('availableDrives', Immutable.fromJS(drives)); const selectedDevices = newState.getIn(['selection', 'devices']).toJS(); From 990dcc9d5a97baf8bc6f5ee2c8eadb97b60d31b5 Mon Sep 17 00:00:00 2001 From: Alexis Svinartchouk Date: Fri, 31 Jan 2020 15:20:43 +0100 Subject: [PATCH 05/13] Fix loading driveBlacklist settings Change-type: patch --- lib/gui/app/app.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/gui/app/app.ts b/lib/gui/app/app.ts index 952c0b11..d5bce76c 100644 --- a/lib/gui/app/app.ts +++ b/lib/gui/app/app.ts @@ -153,9 +153,7 @@ const COMPUTE_MODULE_DESCRIPTIONS: _.Dictionary = { [USB_PRODUCT_ID_BCM2710_BOOT]: 'Compute Module 3', }; -const BLACKLISTED_DRIVES = settings.has('driveBlacklist') - ? settings.get('driveBlacklist').split(',') - : []; +let BLACKLISTED_DRIVES: string[] = []; function driveIsAllowed(drive: { devicePath: string; @@ -342,6 +340,7 @@ async function main(): Promise { } catch (error) { exceptionReporter.report(error); } + BLACKLISTED_DRIVES = settings.get('driveBlacklist') || []; ReactDOM.render( React.createElement(MainPage), document.getElementById('main'), From f2705a611d63e048fea55d472db9c7a790721d8a Mon Sep 17 00:00:00 2001 From: Alexis Svinartchouk Date: Mon, 3 Feb 2020 12:39:15 +0100 Subject: [PATCH 06/13] Update mocha and electron-mocha Change-type: patch --- npm-shrinkwrap.json | 550 ++++++++++++++++++++++++++++++++++++++++++-- package.json | 4 +- 2 files changed, 538 insertions(+), 16 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 289a7517..aa9508da 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -4507,20 +4507,109 @@ } }, "electron-mocha": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/electron-mocha/-/electron-mocha-8.1.2.tgz", - "integrity": "sha512-FZ9RzKtkjtsccnzjWQMNJF+RBuvdgUG1Xj+Q8q9wGanoNTt/W0YSNoEaZ5Z+GVrO11Q/PpVKHsb9x+wEehXmcQ==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/electron-mocha/-/electron-mocha-8.2.0.tgz", + "integrity": "sha512-Jp+GUHBVyWZHILPaDYplnWtglCsTFrMSG9Ls5kE9kmnHzAaCQtWtyLn/5PHYfVMxwGpEPZrBV4QUDPNgcbiPTQ==", "dev": true, "requires": { "ansi-colors": "^4.1.1", "electron-window": "^0.8.0", "fs-extra": "^8.1.0", "log-symbols": "^3.0.0", - "mocha": "~6.2.0", - "which": "^1.3.1", - "yargs": "^14.0.0" + "mocha": "^7.0.0", + "which": "^2.0.2", + "yargs": "^15.1.0" }, "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "binary-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "chokidar": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, "fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", @@ -4531,6 +4620,374 @@ "jsonfile": "^4.0.0", "universalify": "^0.1.0" } + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", + "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "mocha": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.0.1.tgz", + "integrity": "sha512-9eWmWTdHLXh72rGrdZjNbG3aa1/3NRPpul1z0D979QpEnFdCG0Q5tv834N+94QEN2cysfV72YocQ3fn87s70fg==", + "dev": true, + "requires": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "chokidar": "3.3.0", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "2.2.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "ms": "2.1.1", + "node-environment-flags": "1.0.6", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.0", + "yargs-parser": "13.1.1", + "yargs-unparser": "1.6.0" + }, + "dependencies": { + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "dev": true + }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "yargs": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", + "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.1" + } + } + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "node-environment-flags": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", + "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "requires": { + "picomatch": "^2.0.4" + } + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "yargs": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.1.0.tgz", + "integrity": "sha512-T39FNN1b6hCW4SOIk1XyTOWxtXdcen0t+XYrysQmChzSipvhBO8Bj0nK1ozAasdk24dNWuMZvr4k24nz+8HHLg==", + "dev": true, + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^16.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "yargs-parser": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-16.1.0.tgz", + "integrity": "sha512-H/V41UNZQPkUMIT5h5hiwg4QKIY1RPvoBV4XcjUbRM8Bk2oKqqyZ0DIEbTFZB0XjbtSPG8SAa/0DxCQmiRgzKg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "yargs-parser": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } } } }, @@ -8403,13 +8860,14 @@ } }, "mocha": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.2.tgz", - "integrity": "sha512-FgDS9Re79yU1xz5d+C4rv1G7QagNGHZ+iXF81hO8zY35YZZcLEsJVfFolfsqKFWunATEvNzMK0r/CwWd/szO9A==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.0.1.tgz", + "integrity": "sha512-9eWmWTdHLXh72rGrdZjNbG3aa1/3NRPpul1z0D979QpEnFdCG0Q5tv834N+94QEN2cysfV72YocQ3fn87s70fg==", "dev": true, "requires": { "ansi-colors": "3.2.3", "browser-stdout": "1.3.1", + "chokidar": "3.3.0", "debug": "3.2.6", "diff": "3.5.0", "escape-string-regexp": "1.0.5", @@ -8422,7 +8880,7 @@ "minimatch": "3.0.4", "mkdirp": "0.5.1", "ms": "2.1.1", - "node-environment-flags": "1.0.5", + "node-environment-flags": "1.0.6", "object.assign": "4.1.0", "strip-json-comments": "2.0.1", "supports-color": "6.0.0", @@ -8445,6 +8903,22 @@ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "binary-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", + "dev": true + }, "camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", @@ -8473,6 +8947,21 @@ } } }, + "chokidar": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + } + }, "find-up": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", @@ -8496,6 +8985,24 @@ "path-is-absolute": "^1.0.0" } }, + "glob-parent": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", + "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", @@ -8517,6 +9024,21 @@ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", "dev": true }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "requires": { + "picomatch": "^2.0.4" + } + }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -8824,9 +9346,9 @@ } }, "node-environment-flags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", - "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", + "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", "dev": true, "requires": { "object.getownpropertydescriptors": "^2.0.3", @@ -13928,4 +14450,4 @@ } } } -} +} \ No newline at end of file diff --git a/package.json b/package.json index fa052082..17b5c71b 100644 --- a/package.json +++ b/package.json @@ -105,12 +105,12 @@ "chalk": "^1.1.3", "electron": "7.1.10", "electron-builder": "^22.1.0", - "electron-mocha": "^8.1.2", + "electron-mocha": "^8.2.0", "electron-notarize": "^0.1.1", "html-loader": "^0.5.1", "husky": "^3.1.0", "lint-staged": "^9.5.0", - "mocha": "^6.2.1", + "mocha": "^7.0.1", "node-gyp": "^3.8.0", "node-sass": "^4.12.0", "omit-deep-lodash": "1.1.4", From af64579eb2fa8e78cb7e0ef9825f1c518e43fc51 Mon Sep 17 00:00:00 2001 From: Alexis Svinartchouk Date: Mon, 3 Feb 2020 12:42:24 +0100 Subject: [PATCH 07/13] Update resin-lint to ^3.2.0 Change-type: patch --- lib/gui/app/os/dialog.ts | 7 ++- lib/gui/modules/child-writer.ts | 2 +- npm-shrinkwrap.json | 87 +++++++++++++++++++++++---------- package.json | 2 +- 4 files changed, 65 insertions(+), 33 deletions(-) diff --git a/lib/gui/app/os/dialog.ts b/lib/gui/app/os/dialog.ts index 72aa5c18..e3233cf7 100644 --- a/lib/gui/app/os/dialog.ts +++ b/lib/gui/app/os/dialog.ts @@ -45,10 +45,9 @@ export async function selectImage(): Promise { ], }; const currentWindow = electron.remote.getCurrentWindow(); - const [file] = (await electron.remote.dialog.showOpenDialog( - currentWindow, - options, - )).filePaths; + const [file] = ( + await electron.remote.dialog.showOpenDialog(currentWindow, options) + ).filePaths; return file; } diff --git a/lib/gui/modules/child-writer.ts b/lib/gui/modules/child-writer.ts index 4d3c4413..d479a89d 100644 --- a/lib/gui/modules/child-writer.ts +++ b/lib/gui/modules/child-writer.ts @@ -125,7 +125,7 @@ async function writeAndValidate( errors: [], }; for (const [destination, error] of failures) { - (error as (Error & { device: string })).device = destination.drive.device; + (error as Error & { device: string }).device = destination.drive.device; result.errors.push(error); } return result; diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index aa9508da..43fd87e9 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -415,9 +415,9 @@ "dev": true }, "@types/bluebird": { - "version": "3.5.28", - "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.28.tgz", - "integrity": "sha512-0Vk/kqkukxPKSzP9c8WJgisgGDx5oZDbsLLWIP5t70yThO/YleE+GEm2S1GlRALTaack3O7U5OS5qEm7q2kciA==", + "version": "3.5.29", + "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.29.tgz", + "integrity": "sha512-kmVtnxTuUuhCET669irqQmPAez4KFnFVKvpleVRyfC3g+SHD1hIkFZcWLim9BVcwUBLO59o8VZE4yGCmTif8Yw==", "dev": true }, "@types/caseless": { @@ -565,9 +565,9 @@ "dev": true }, "@types/prettier": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-1.18.3.tgz", - "integrity": "sha512-48rnerQdcZ26odp+HOvDGX8IcUkYOCuMc2BodWYTe956MqkHlOGAG4oFQ83cjZ0a4GAgj7mb4GUClxYd2Hlodg==", + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-1.19.0.tgz", + "integrity": "sha512-gDE8JJEygpay7IjA/u3JiIURvwZW08f0cZSZLAzFoX/ZmeqvS0Sqv+97aKuHpNsalAMMhwPe+iAS6fQbfmbt7A==", "dev": true }, "@types/prop-types": { @@ -10321,9 +10321,9 @@ "dev": true }, "prettier": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz", - "integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", + "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", "dev": true }, "pretty-bytes": { @@ -11155,36 +11155,69 @@ } }, "resin-lint": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/resin-lint/-/resin-lint-3.1.0.tgz", - "integrity": "sha512-bipsVrhMBtoegrBdJf/6NMQke4g8xmZENSu0fBU1KvxLXNhGPQkmobY7vVmP47BeD0m0Zdv9yrEc43w2S+kRWA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/resin-lint/-/resin-lint-3.2.0.tgz", + "integrity": "sha512-pVP/RJXqXpLeY1ZULok0VL02KqP6QEyGVa0wclJpjcmOC4yhYXkWk71k72Jhs+6WKq3Xgw6RjJoy7MhZ5Hjn8A==", "dev": true, "requires": { - "@types/bluebird": "^3.5.26", + "@types/bluebird": "^3.5.29", "@types/depcheck": "^0.6.0", "@types/glob": "^5.0.35", - "@types/node": "^8.10.45", + "@types/lodash": "^4.14.149", + "@types/node": "^8.10.59", "@types/optimist": "0.0.29", - "@types/prettier": "^1.16.1", - "bluebird": "^3.5.4", + "@types/prettier": "^1.18.3", + "bluebird": "^3.7.2", "coffee-script": "^1.10.0", "coffeelint": "^1.15.0", "coffeescope2": "^0.4.5", "depcheck": "^0.6.7", - "glob": "^7.0.3", - "merge": "^1.2.0", + "glob": "^7.1.6", + "lodash": "^4.17.15", "optimist": "^0.6.1", - "prettier": "^1.16.4", - "tslint": "^5.15.0", + "prettier": "^1.19.1", + "tslint": "^5.20.1", "tslint-config-prettier": "^1.18.0", "tslint-no-unused-expression-chai": "^0.1.4", - "typescript": "^3.4.3" + "typescript": "^3.7.5" }, "dependencies": { + "@types/lodash": { + "version": "4.14.149", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.149.tgz", + "integrity": "sha512-ijGqzZt/b7BfzcK9vTrS6MFljQRPn5BFWOx8oE0GYxribu6uV+aA9zZuXI1zc/etK9E8nrgdoF2+LgUw7+9tJQ==", + "dev": true + }, "@types/node": { - "version": "8.10.58", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.58.tgz", - "integrity": "sha512-NNcUk/rAdR7Pie7WiA5NHp345dTkD62qaxqscQXVIjCjog/ZXsrG8Wo7dZMZAzE7PSpA+qR2S3TYTeFCKuBFxQ==", + "version": "8.10.59", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.59.tgz", + "integrity": "sha512-8RkBivJrDCyPpBXhVZcjh7cQxVBSmRk9QM7hOketZzp6Tg79c0N8kkpAIito9bnJ3HCVCHVYz+KHTEbfQNfeVQ==", + "dev": true + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "typescript": { + "version": "3.7.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.5.tgz", + "integrity": "sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==", "dev": true } } @@ -13128,9 +13161,9 @@ } }, "diff": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz", - "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true } } diff --git a/package.json b/package.json index 17b5c71b..942fae9e 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "node-gyp": "^3.8.0", "node-sass": "^4.12.0", "omit-deep-lodash": "1.1.4", - "resin-lint": "^3.1.0", + "resin-lint": "^3.2.0", "sass-lint": "^1.12.1", "simple-progress-webpack-plugin": "^1.1.2", "sinon": "^8.0.4", From a22ea0b82b87ac90b8640c58d846f802e7ef0535 Mon Sep 17 00:00:00 2001 From: Alexis Svinartchouk Date: Mon, 3 Feb 2020 14:53:10 +0100 Subject: [PATCH 08/13] Update scripts submodule to prevent electon-mocha crashes on CI Change-type: patch --- scripts/resin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/resin b/scripts/resin index d73350d1..d067a69b 160000 --- a/scripts/resin +++ b/scripts/resin @@ -1 +1 @@ -Subproject commit d73350d1ad20ce67a32e5c1a74ef1a29c8613abd +Subproject commit d067a69bae5b1b91263f541e0015c214bd414ec8 From 2aa6c83714e9557c86de3717bd3387dd0fb15e83 Mon Sep 17 00:00:00 2001 From: Alexis Svinartchouk Date: Mon, 3 Feb 2020 17:49:56 +0100 Subject: [PATCH 09/13] Update electron to 7.1.11 Changelog-entry: Update electron to 7.1.11 Chanege-type: patch --- npm-shrinkwrap.json | 34 +++++++++++++++++----------------- package.json | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 43fd87e9..3e213859 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -4354,9 +4354,9 @@ "dev": true }, "electron": { - "version": "7.1.10", - "resolved": "https://registry.npmjs.org/electron/-/electron-7.1.10.tgz", - "integrity": "sha512-UDpS2CfBN3yufCrbET5Ozw1XrLhuANHn+Zs8Vgl/BcBT/MoNbkY79nRFcyxj6pCFrEde9IoNOf+DgNp6altNxw==", + "version": "7.1.11", + "resolved": "https://registry.npmjs.org/electron/-/electron-7.1.11.tgz", + "integrity": "sha512-YDXfnovKY+8iZ5ISQh1kRqYIRKbpOSxGXCx2WVxPFPutEQ7Q/Xzr3h4GePEY25/NXMytMfhKaAZAYjtWUm3r9Q==", "dev": true, "requires": { "@electron/get": "^1.0.1", @@ -6345,18 +6345,18 @@ } }, "global-agent": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-2.1.7.tgz", - "integrity": "sha512-ooK7eqGYZku+LgnbfH/Iv0RJ74XfhrBZDlke1QSzcBt0bw1PmJcnRADPAQuFE+R45pKKDTynAr25SBasY2kvow==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-2.1.8.tgz", + "integrity": "sha512-VpBe/rhY6Rw2VDOTszAMNambg+4Qv8j0yiTNDYEXXXxkUNGWLHp8A3ztK4YDBbFNcWF4rgsec6/5gPyryya/+A==", "dev": true, "optional": true, "requires": { "boolean": "^3.0.0", - "core-js": "^3.4.1", + "core-js": "^3.6.4", "es6-error": "^4.1.1", - "matcher": "^2.0.0", - "roarr": "^2.14.5", - "semver": "^6.3.0", + "matcher": "^2.1.0", + "roarr": "^2.15.2", + "semver": "^7.1.2", "serialize-error": "^5.0.0" }, "dependencies": { @@ -6368,9 +6368,9 @@ "optional": true }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.1.2.tgz", + "integrity": "sha512-BJs9T/H8sEVHbeigqzIEo57Iu/3DG6c4QoqTfbQB3BPA4zgzAomh/Fk9E7QtjWQ8mx2dgA9YCfSF4y9k9bHNpQ==", "dev": true, "optional": true } @@ -11338,15 +11338,15 @@ } }, "roarr": { - "version": "2.14.6", - "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.14.6.tgz", - "integrity": "sha512-qjbw0BEesKA+3XFBPt+KVe1PC/Z6ShfJ4wPlx2XifqH5h2Lj8/KQT5XJTsy3n1Es5kai+BwKALaECW3F70B1cg==", + "version": "2.15.2", + "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.2.tgz", + "integrity": "sha512-jmaDhK9CO4YbQAV8zzCnq9vjAqeO489MS5ehZ+rXmFiPFFE6B+S9KYO6prjmLJ5A0zY3QxVlQdrIya7E/azz/Q==", "dev": true, "optional": true, "requires": { "boolean": "^3.0.0", "detect-node": "^2.0.4", - "globalthis": "^1.0.0", + "globalthis": "^1.0.1", "json-stringify-safe": "^5.0.1", "semver-compare": "^1.0.0", "sprintf-js": "^1.1.2" diff --git a/package.json b/package.json index 942fae9e..43d3e560 100644 --- a/package.json +++ b/package.json @@ -103,7 +103,7 @@ "@types/webpack-node-externals": "^1.7.0", "chai": "^4.2.0", "chalk": "^1.1.3", - "electron": "7.1.10", + "electron": "7.1.11", "electron-builder": "^22.1.0", "electron-mocha": "^8.2.0", "electron-notarize": "^0.1.1", From 81e80572d8f7769d20d2854cbe6923e3483b11ac Mon Sep 17 00:00:00 2001 From: Alexis Svinartchouk Date: Mon, 3 Feb 2020 20:19:24 +0100 Subject: [PATCH 10/13] A warning about the selected image does not prevent the selection This was introduced in 1.5.72 Change-type: patch --- lib/gui/app/components/image-selector/image-selector.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/gui/app/components/image-selector/image-selector.tsx b/lib/gui/app/components/image-selector/image-selector.tsx index c510d4a8..10ab240c 100644 --- a/lib/gui/app/components/image-selector/image-selector.tsx +++ b/lib/gui/app/components/image-selector/image-selector.tsx @@ -185,7 +185,6 @@ export class ImageSelector extends React.Component< title, }, }); - return; } selectionState.selectImage(image); From c200a0c7ac19e97f65f689a42c53443ce8feaad7 Mon Sep 17 00:00:00 2001 From: Alexis Svinartchouk Date: Tue, 4 Feb 2020 17:40:39 +0100 Subject: [PATCH 11/13] Compress deb package with bzip instead of xz 7za fails on ia32 CI with "ERROR: Can't allocate required memory!" Changelog-entry: Compress deb package with bzip instead of xz Change-type: patch --- .resinci.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.resinci.json b/.resinci.json index c2932918..9b47bc91 100644 --- a/.resinci.json +++ b/.resinci.json @@ -74,6 +74,7 @@ "synopsis": "balenaEtcher is a powerful OS image flasher built with web technologies to ensure flashing an SDCard or USB drive is a pleasant and safe experience. It protects you from accidentally writing to your hard-drives, ensures every byte of data was written correctly and much more." }, "deb": { + "compression": "bzip2", "priority": "optional", "depends": [ "polkit-1-auth-agent | policykit-1-gnome | polkit-kde-1" From cb8168de41ce3323e43b1e486e91936e7f129f41 Mon Sep 17 00:00:00 2001 From: Alexis Svinartchouk Date: Wed, 29 Jan 2020 19:21:15 +0100 Subject: [PATCH 12/13] Etcher pro leds feature Changelog-entry: Etcher pro leds feature Change-type: patch --- lib/gui/app/app.ts | 2 + lib/gui/app/models/leds.ts | 205 +++++++++++++++++++++++++++++++++++++ 2 files changed, 207 insertions(+) create mode 100644 lib/gui/app/models/leds.ts diff --git a/lib/gui/app/app.ts b/lib/gui/app/app.ts index d5bce76c..8c493267 100644 --- a/lib/gui/app/app.ts +++ b/lib/gui/app/app.ts @@ -27,6 +27,7 @@ import * as EXIT_CODES from '../../shared/exit-codes'; import * as messages from '../../shared/messages'; import * as availableDrives from './models/available-drives'; import * as flashState from './models/flash-state'; +import { init as ledsInit } from './models/leds'; import * as settings from './models/settings'; import { Actions, observe, store } from './models/store'; import * as analytics from './modules/analytics'; @@ -341,6 +342,7 @@ async function main(): Promise { exceptionReporter.report(error); } BLACKLISTED_DRIVES = settings.get('driveBlacklist') || []; + ledsInit(); ReactDOM.render( React.createElement(MainPage), document.getElementById('main'), diff --git a/lib/gui/app/models/leds.ts b/lib/gui/app/models/leds.ts new file mode 100644 index 00000000..7ad1159d --- /dev/null +++ b/lib/gui/app/models/leds.ts @@ -0,0 +1,205 @@ +/* + * Copyright 2020 balena.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 { delay } from 'bluebird'; +import { promises as fs } from 'fs'; + +import * as settings from './settings'; +import { observe } from './store'; + +class Led { + private lastValue?: number; + + constructor(private path: string) {} + + public async setIntensity(intensity: number) { + if (intensity < 0 || intensity > 1) { + throw new Error('Led intensity must be between 0 and 1'); + } + const value = Math.round(intensity * 255); + if (value !== this.lastValue) { + await fs.writeFile(this.path, value.toString()); + this.lastValue = value; + } + } +} + +export type Color = [number, number, number]; +export type AnimationFunction = (t: number) => Color; + +function delay1(duration: number): Promise { + // delay that accepts Infinity + if (duration === Infinity) { + return new Promise(() => { + // Never resolve + }); + } else { + return delay(duration); + } +} + +function cancellableDelay( + duration: number, +): { promise: Promise; cancel: () => void } { + let maybeCancel: () => void; + const cancel = () => { + if (maybeCancel !== undefined) { + maybeCancel(); + } + }; + const cancelPromise: Promise = new Promise(resolve => { + maybeCancel = resolve; + }); + const promise = Promise.race([delay1(duration), cancelPromise]); + return { promise, cancel }; +} + +export class RGBLed { + private leds: [Led, Led, Led]; + private animation: AnimationFunction; + private period: number; // in ms + private wakeUp = () => { + // noop until this.loop() is called + }; + + constructor(paths: [string, string, string]) { + this.leds = paths.map(path => new Led(path)) as [Led, Led, Led]; + this.setStaticColor([0, 0, 0]); + this.loop(); + } + + private setFrequency(frequency: number) { + if (frequency < 0) { + throw new Error('frequency must be greater or equal to 0'); + } + this.period = 1000 / frequency; + this.wakeUp(); + } + + private async loop() { + while (true) { + const start = new Date().getTime(); + await this.setColor(this.animation(start)); + const end = new Date().getTime(); + const duration = end - start; + const { promise, cancel } = cancellableDelay(this.period - duration); + this.wakeUp = cancel; + await promise; + } + } + + public setAnimation(animation: AnimationFunction, frequency = 10) { + this.animation = animation; + this.setFrequency(frequency); + } + + public setStaticColor(color: Color) { + this.setAnimation(() => color, 0); + } + + private async setColor(color: Color) { + await Promise.all([ + this.leds[0].setIntensity(color[0]), + this.leds[1].setIntensity(color[1]), + this.leds[2].setIntensity(color[2]), + ]); + } +} + +// Animations: +function breatheGreen(t: number): Color { + const intensity = (1 + Math.sin(t / 1000)) / 2; + return [0, intensity, 0]; +} + +function blinkWhite(t: number): Color { + const intensity = Math.floor(t / 1000) % 2; + return [intensity, intensity, intensity]; +} + +const leds: Map = new Map(); + +function setLeds( + drivesPaths: Set, + colorOrAnimation: Color | AnimationFunction, +) { + for (const path of drivesPaths) { + const led = leds.get(path); + if (led) { + if (Array.isArray(colorOrAnimation)) { + led.setStaticColor(colorOrAnimation); + } else { + led.setAnimation(colorOrAnimation); + } + } + } +} + +export function updateLeds( + availableDrives: string[], + selectedDrives: string[], +) { + const off = new Set(leds.keys()); + const available = new Set(availableDrives); + const selected = new Set(selectedDrives); + for (const s of selected) { + available.delete(s); + } + for (const a of available) { + off.delete(a); + } + setLeds(off, [0, 0, 0]); + setLeds(available, breatheGreen); + setLeds(selected, blinkWhite); +} + +interface DeviceFromState { + devicePath?: string; + device: string; +} + +export function init() { + // ledsMapping is something like: + // { + // 'platform-xhci-hcd.0.auto-usb-0:1.1.1:1.0-scsi-0:0:0:0': [ + // '/sys/class/leds/led1_r', + // '/sys/class/leds/led1_g', + // '/sys/class/leds/led1_b', + // ], + // ... + // } + const ledsMapping: _.Dictionary<[string, string, string]> = settings.get( + 'ledsMapping', + ); + for (const [drivePath, ledsPaths] of Object.entries(ledsMapping)) { + leds.set('/dev/disk/by-path/' + drivePath, new RGBLed(ledsPaths)); + } + observe(state => { + const availableDrives = state + .get('availableDrives') + .toJS() + .filter((d: DeviceFromState) => d.devicePath); + const availableDrivesPaths = availableDrives.map( + (d: DeviceFromState) => d.devicePath, + ); + // like /dev/sda + const selectedDrivesDevices = state.getIn(['selection', 'devices']).toJS(); + const selectedDrivesPaths = availableDrives + .filter((d: DeviceFromState) => selectedDrivesDevices.includes(d.device)) + .map((d: DeviceFromState) => d.devicePath); + updateLeds(availableDrivesPaths, selectedDrivesPaths); + }); +} From 227bad9e997ac890338bc23fc4a9a7e906c5d6e7 Mon Sep 17 00:00:00 2001 From: Alexis Svinartchouk Date: Fri, 31 Jan 2020 16:23:50 +0100 Subject: [PATCH 13/13] Keep leds sysfs files open Change-type: patch --- lib/gui/app/models/leds.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/gui/app/models/leds.ts b/lib/gui/app/models/leds.ts index 7ad1159d..d018abdb 100644 --- a/lib/gui/app/models/leds.ts +++ b/lib/gui/app/models/leds.ts @@ -21,17 +21,26 @@ import * as settings from './settings'; import { observe } from './store'; class Led { + private handle: fs.FileHandle; private lastValue?: number; constructor(private path: string) {} + private async open() { + if (this.handle === undefined) { + this.handle = await fs.open(this.path, 'w'); + } + } + public async setIntensity(intensity: number) { if (intensity < 0 || intensity > 1) { throw new Error('Led intensity must be between 0 and 1'); } const value = Math.round(intensity * 255); if (value !== this.lastValue) { - await fs.writeFile(this.path, value.toString()); + await this.open(); + await this.handle.write(value.toString(), 0); + // On a regular file we would also need to truncate to the written value length but it looks like it's not the case on sysfs files this.lastValue = value; } }