diff --git a/.resinci.json b/.resinci.json
index 4f85d729..56dc4038 100644
--- a/.resinci.json
+++ b/.resinci.json
@@ -62,6 +62,12 @@
"depends": [
"polkit-1-auth-agent | policykit-1-gnome | polkit-kde-1"
]
+ },
+ "protocols": {
+ "name": "etcher",
+ "schemes": [
+ "etcher"
+ ]
}
}
}
diff --git a/Makefile b/Makefile
index 17c738c0..b313533a 100644
--- a/Makefile
+++ b/Makefile
@@ -164,10 +164,8 @@ lint: lint-ts lint-sass lint-cpp lint-spell
MOCHA_OPTIONS=--recursive --reporter spec --require ts-node/register --require-main "tests/gui/allow-renderer-process-reuse.ts"
-# See https://github.com/electron/spectron/issues/127
-ETCHER_SPECTRON_ENTRYPOINT ?= $(shell node -e 'console.log(require("electron"))')
test-spectron:
- ETCHER_SPECTRON_ENTRYPOINT="$(ETCHER_SPECTRON_ENTRYPOINT)" mocha $(MOCHA_OPTIONS) tests/spectron/runner.spec.ts
+ mocha $(MOCHA_OPTIONS) tests/spectron/runner.spec.ts
test-gui:
electron-mocha $(MOCHA_OPTIONS) --full-trace --no-sandbox --renderer tests/gui/**/*.ts
diff --git a/afterSignHook.js b/afterSignHook.js
index 1a281cca..d071ea85 100644
--- a/afterSignHook.js
+++ b/afterSignHook.js
@@ -1,10 +1,11 @@
'use strict'
const { notarize } = require('electron-notarize')
+const { ELECTRON_SKIP_NOTARIZATION } = process.env
async function main(context) {
const { electronPlatformName, appOutDir } = context
- if (electronPlatformName !== 'darwin') {
+ if (electronPlatformName !== 'darwin' || ELECTRON_SKIP_NOTARIZATION === 'true') {
return
}
diff --git a/beforeBuild.js b/beforeBuild.js
index c08296a9..d63b3609 100644
--- a/beforeBuild.js
+++ b/beforeBuild.js
@@ -1,17 +1,26 @@
'use strict'
-const cp = require('child_process')
+const cp = require('child_process');
+const rimraf = require('rimraf');
+const process = require('process');
// Rebuild native modules for ia32 and run webpack again for the ia32 part of windows packages
exports.default = function(context) {
if (context.platform.name === 'windows') {
cp.execFileSync(
'bash',
- ['./node_modules/.bin/electron-rebuild', '--types', 'dev', '--arch', context.arch]
+ ['./node_modules/.bin/electron-rebuild', '--types', 'dev', '--arch', context.arch],
);
+ rimraf.sync('generated');
cp.execFileSync(
'bash',
- ['./node_modules/.bin/webpack']
+ ['./node_modules/.bin/webpack'],
+ {
+ env: {
+ ...process.env,
+ npm_config_target_arch: context.arch,
+ },
+ },
);
}
}
diff --git a/electron-builder.yml b/electron-builder.yml
index 180bb7fd..c75fb5e4 100644
--- a/electron-builder.yml
+++ b/electron-builder.yml
@@ -91,3 +91,7 @@ deb:
rpm:
depends:
- util-linux
+protocols:
+ name: etcher
+ schemes:
+ - etcher
diff --git a/lib/gui/app/components/source-selector/source-selector.tsx b/lib/gui/app/components/source-selector/source-selector.tsx
index 42d06a6f..f3d053ed 100644
--- a/lib/gui/app/components/source-selector/source-selector.tsx
+++ b/lib/gui/app/components/source-selector/source-selector.tsx
@@ -17,6 +17,7 @@
import { faFile, faLink } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { sourceDestination } from 'etcher-sdk';
+import { ipcRenderer, IpcRendererEvent } from 'electron';
import * as _ from 'lodash';
import { GPTPartition, MBRPartition } from 'partitioninfo';
import * as path from 'path';
@@ -237,6 +238,7 @@ export class SourceSelector extends React.Component<
this.openImageSelector = this.openImageSelector.bind(this);
this.openURLSelector = this.openURLSelector.bind(this);
this.reselectImage = this.reselectImage.bind(this);
+ this.onSelectImage = this.onSelectImage.bind(this);
this.onDrop = this.onDrop.bind(this);
this.showSelectedImageDetails = this.showSelectedImageDetails.bind(this);
this.afterSelected = props.afterSelected.bind(this);
@@ -246,10 +248,22 @@ export class SourceSelector extends React.Component<
this.unsubscribe = observe(() => {
this.setState(getState());
});
+ ipcRenderer.on('select-image', this.onSelectImage);
+ ipcRenderer.send('source-selector-ready');
}
public componentWillUnmount() {
this.unsubscribe();
+ ipcRenderer.removeListener('select-image', this.onSelectImage);
+ }
+
+ private async onSelectImage(_event: IpcRendererEvent, imagePath: string) {
+ const isURL =
+ _.startsWith(imagePath, 'https://') || _.startsWith(imagePath, 'http://');
+ await this.selectImageByPath({
+ imagePath,
+ SourceType: isURL ? sourceDestination.Http : sourceDestination.File,
+ });
}
private reselectImage() {
diff --git a/lib/gui/etcher.ts b/lib/gui/etcher.ts
index e98b475e..76cf50b5 100644
--- a/lib/gui/etcher.ts
+++ b/lib/gui/etcher.ts
@@ -17,6 +17,7 @@
import { delay } from 'bluebird';
import * as electron from 'electron';
import { autoUpdater } from 'electron-updater';
+import { platform } from 'os';
import * as _ from 'lodash';
import * as path from 'path';
import * as semver from 'semver';
@@ -28,6 +29,8 @@ import * as settings from './app/models/settings';
import * as analytics from './app/modules/analytics';
import { buildWindowMenu } from './menu';
+const customProtocol = 'etcher';
+const scheme = `${customProtocol}://`;
const updatablePackageTypes = ['appimage', 'nsis', 'dmg'];
const packageUpdatable = _.includes(updatablePackageTypes, packageType);
let packageUpdated = false;
@@ -54,6 +57,44 @@ async function checkForUpdates(interval: number) {
}
}
+function getCommandLineURL(argv: string[]): string | undefined {
+ argv = argv.slice(electron.app.isPackaged ? 1 : 2);
+ if (argv.length) {
+ const value = argv[argv.length - 1];
+ // Take into account electron arguments
+ if (value.startsWith('--')) {
+ return;
+ }
+ // https://stackoverflow.com/questions/10242115/os-x-strange-psn-command-line-parameter-when-launched-from-finder
+ if (platform() === 'darwin' && value.startsWith('-psn_')) {
+ return;
+ }
+ return value;
+ }
+}
+
+const sourceSelectorReady = new Promise((resolve) => {
+ electron.ipcMain.on('source-selector-ready', resolve);
+});
+
+async function selectImageURL(url?: string) {
+ // 'data:,' is the default chromedriver url that is passed as last argument when running spectron tests
+ if (url !== undefined && url !== 'data:,') {
+ url = url.startsWith(scheme) ? url.slice(scheme.length) : url;
+ await sourceSelectorReady;
+ electron.BrowserWindow.getAllWindows().forEach((window) => {
+ window.webContents.send('select-image', url);
+ });
+ }
+}
+
+// This will catch clicks on links such as Open in Etcher
+// We need to listen to the event before everything else otherwise the event won't be fired
+electron.app.on('open-url', async (event, data) => {
+ event.preventDefault();
+ await selectImageURL(data);
+});
+
async function createMainWindow() {
const fullscreen = Boolean(await settings.get('fullscreen'));
const defaultWidth = 800;
@@ -87,6 +128,8 @@ async function createMainWindow() {
},
});
+ electron.app.setAsDefaultProtocolClient(customProtocol);
+
buildWindowMenu(mainWindow);
mainWindow.setFullScreen(true);
@@ -133,6 +176,7 @@ async function createMainWindow() {
}
}
});
+ return mainWindow;
}
electron.app.allowRendererProcessReuse = false;
@@ -145,14 +189,24 @@ electron.app.on('window-all-closed', electron.app.quit);
// make use of it to ensure the browser window is completely destroyed.
// See https://github.com/electron/electron/issues/5273
electron.app.on('before-quit', () => {
+ electron.app.releaseSingleInstanceLock();
process.exit(EXIT_CODES.SUCCESS);
});
async function main(): Promise {
- if (electron.app.isReady()) {
- await createMainWindow();
+ if (!electron.app.requestSingleInstanceLock()) {
+ electron.app.quit();
} else {
- electron.app.on('ready', createMainWindow);
+ await electron.app.whenReady();
+ const window = await createMainWindow();
+ electron.app.on('second-instance', async (_event, argv) => {
+ if (window.isMinimized()) {
+ window.restore();
+ }
+ window.focus();
+ await selectImageURL(getCommandLineURL(argv));
+ });
+ await selectImageURL(getCommandLineURL(process.argv));
}
}
diff --git a/lib/gui/modules/child-writer.ts b/lib/gui/modules/child-writer.ts
index 390a931d..108932e8 100644
--- a/lib/gui/modules/child-writer.ts
+++ b/lib/gui/modules/child-writer.ts
@@ -246,7 +246,7 @@ ipc.connectTo(IPC_SERVER_ID, () => {
path: options.imagePath,
});
} else {
- source = new Http({ url: options.imagePath });
+ source = new Http({ url: options.imagePath, avoidRandomAccess: true });
}
try {
const results = await writeAndValidate({
diff --git a/lib/shared/permissions.ts b/lib/shared/permissions.ts
index a3c93665..51580a35 100755
--- a/lib/shared/permissions.ts
+++ b/lib/shared/permissions.ts
@@ -29,7 +29,10 @@ import { tmpFileDisposer } from './utils';
const execAsync = promisify(childProcess.exec);
const execFileAsync = promisify(childProcess.execFile);
-const sudoExecAsync = promisify(sudoPrompt.exec);
+// sudo-prompt's exec callback is function(error, stdout, stderr) so we need multiArgs
+const sudoExecAsync = Bluebird.promisify(sudoPrompt.exec, {
+ multiArgs: true,
+}) as (cmd: string, options: any) => Bluebird<[string, string]>;
/**
* @summary The user id of the UNIX "superuser"
@@ -123,10 +126,7 @@ async function elevateScriptUnix(
name: string,
): Promise<{ cancelled: boolean }> {
const cmd = ['bash', escapeSh(path)].join(' ');
- const [, stderr] = await sudoExecAsync(cmd, { name });
- if (!_.isEmpty(stderr)) {
- throw errors.createError({ title: stderr });
- }
+ await sudoExecAsync(cmd, { name });
return { cancelled: false };
}
diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index aa65efc4..4b02ed7c 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -677,6 +677,16 @@
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
"dev": true
},
+ "@types/copy-webpack-plugin": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/@types/copy-webpack-plugin/-/copy-webpack-plugin-6.0.0.tgz",
+ "integrity": "sha512-Ousy+sNap1j44eG+C9FZvTUybpp9lFmKjBRF7L0NDs/+SDA9OXKo2OpsHJfD/LMWflz+uvfTCBXH1CgdL6AW/g==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*",
+ "@types/webpack": "*"
+ }
+ },
"@types/debug": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz",
@@ -965,13 +975,13 @@
}
},
"@types/terser-webpack-plugin": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/@types/terser-webpack-plugin/-/terser-webpack-plugin-2.2.0.tgz",
- "integrity": "sha512-ywqEfTm7KdKoX9aYx0zYtiFU1z6IHrIYW9FJqeay2Ea58rTPML1J0hvoztGal2Jow3bkgGKcAmEZNL+8LqUVrA==",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@types/terser-webpack-plugin/-/terser-webpack-plugin-3.0.0.tgz",
+ "integrity": "sha512-K5C7izOT8rR4qiE2vfXcQNEJN4lT9cq/2qJgpMUWR2HsjDW/KVrHx2CaHuaXvaqDNsRmdELPLaxeJHiI4GjVrA==",
"dev": true,
"requires": {
"@types/webpack": "*",
- "terser": "^4.3.9"
+ "terser": "^4.6.13"
}
},
"@types/tmp": {
@@ -4325,9 +4335,9 @@
"dev": true
},
"drivelist": {
- "version": "9.0.0",
- "resolved": "https://registry.npmjs.org/drivelist/-/drivelist-9.0.0.tgz",
- "integrity": "sha512-DNQ1oFAv5p1+UKVkQHCYQFHolFbItxSnjcJchxrhlEkW4RSuLfC0xOnq87uM8dcMzOuPfA37SKX7HsUIpw14uA==",
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/drivelist/-/drivelist-9.0.2.tgz",
+ "integrity": "sha512-B68AttNDXsew8M2viM99I4sNMJ2T5/lZ2fDlVsEAAzaJ1pyZN2Ibhhd37LAqsNRPhhPtpyrCi9+C6AfJ2kwo4g==",
"dev": true,
"requires": {
"bindings": "^1.3.0",
@@ -4402,9 +4412,9 @@
}
},
"electron": {
- "version": "9.0.0",
- "resolved": "https://registry.npmjs.org/electron/-/electron-9.0.0.tgz",
- "integrity": "sha512-JsaSQNPh+XDYkLj8APtVKTtvpb86KIG57W5OOss4TNrn8L3isC9LsCITwfnVmGIXHhvX6oY/weCtN5hAAytjVg==",
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/electron/-/electron-9.0.2.tgz",
+ "integrity": "sha512-+a3KegLvQXVjC3b6yBWwZmtWp3tHf9ut27yORAWHO9JRFtKfNf88fi1UvTPJSW8R0sUH7ZEdzN6A95T22KGtlA==",
"dev": true,
"requires": {
"@electron/get": "^1.0.1",
@@ -4756,6 +4766,25 @@
"path-exists": "^3.0.0"
}
},
+ "node-gyp": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-6.1.0.tgz",
+ "integrity": "sha512-h4A2zDlOujeeaaTx06r4Vy+8MZ1679lU+wbCKDS4ZtvY2A37DESo37oejIw0mtmR3+rvNwts5B6Kpt1KrNYdNw==",
+ "dev": true,
+ "requires": {
+ "env-paths": "^2.2.0",
+ "glob": "^7.1.4",
+ "graceful-fs": "^4.2.2",
+ "mkdirp": "^0.5.1",
+ "nopt": "^4.0.1",
+ "npmlog": "^4.1.2",
+ "request": "^2.88.0",
+ "rimraf": "^2.6.3",
+ "semver": "^5.7.1",
+ "tar": "^4.4.12",
+ "which": "^1.3.1"
+ }
+ },
"p-locate": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
@@ -4771,6 +4800,12 @@
"integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
"dev": true
},
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true
+ },
"string-width": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
@@ -5320,9 +5355,9 @@
"dev": true
},
"etcher-sdk": {
- "version": "4.1.4",
- "resolved": "https://registry.npmjs.org/etcher-sdk/-/etcher-sdk-4.1.4.tgz",
- "integrity": "sha512-s9KXeLOtwrOxZs6F2VpGdS2VARwgJzmQp7/Xh4DG0yTAIR58djzZ2+cmUQQN16ztFMiQdCgTWWnOUJV1eVtO4g==",
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/etcher-sdk/-/etcher-sdk-4.1.8.tgz",
+ "integrity": "sha512-fSNwpqeCdc75xNIKwf+At8+r/EQ+/X/IV7gUYFa/wKXtnFHHxYJor6VfPdELUbtDDBWWa2cneJvtwGmcDPBAvA==",
"dev": true,
"requires": {
"@ronomon/direct-io": "^3.0.1",
@@ -9454,9 +9489,9 @@
}
},
"node-addon-api": {
- "version": "1.7.1",
- "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.1.tgz",
- "integrity": "sha512-2+DuKodWvwRTrCfKOeR24KIc5unKjOh8mz17NCzVnHWfjAdDqbfbjqh7gUT+BkXBRQM52+xCHciKWonJ3CbJMQ==",
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz",
+ "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==",
"dev": true
},
"node-environment-flags": {
@@ -9488,28 +9523,90 @@
}
},
"node-gyp": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-6.1.0.tgz",
- "integrity": "sha512-h4A2zDlOujeeaaTx06r4Vy+8MZ1679lU+wbCKDS4ZtvY2A37DESo37oejIw0mtmR3+rvNwts5B6Kpt1KrNYdNw==",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-7.0.0.tgz",
+ "integrity": "sha512-ZW34qA3CJSPKDz2SJBHKRvyNQN0yWO5EGKKksJc+jElu9VA468gwJTyTArC1iOXU7rN3Wtfg/CMt/dBAOFIjvg==",
"dev": true,
"requires": {
"env-paths": "^2.2.0",
"glob": "^7.1.4",
- "graceful-fs": "^4.2.2",
- "mkdirp": "^0.5.1",
- "nopt": "^4.0.1",
+ "graceful-fs": "^4.2.3",
+ "nopt": "^4.0.3",
"npmlog": "^4.1.2",
- "request": "^2.88.0",
+ "request": "^2.88.2",
"rimraf": "^2.6.3",
- "semver": "^5.7.1",
- "tar": "^4.4.12",
- "which": "^1.3.1"
+ "semver": "^7.3.2",
+ "tar": "^6.0.1",
+ "which": "^2.0.2"
},
"dependencies": {
- "semver": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
- "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "chownr": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
+ "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
+ "dev": true
+ },
+ "fs-minipass": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
+ "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
+ "dev": true,
+ "requires": {
+ "minipass": "^3.0.0"
+ }
+ },
+ "minipass": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz",
+ "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==",
+ "dev": true,
+ "requires": {
+ "yallist": "^4.0.0"
+ }
+ },
+ "minizlib": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.0.tgz",
+ "integrity": "sha512-EzTZN/fjSvifSX0SlqUERCN39o6T40AMarPbv0MrarSFtIITCBh7bi+dU8nxGFHuqs9jdIAeoYoKuQAAASsPPA==",
+ "dev": true,
+ "requires": {
+ "minipass": "^3.0.0",
+ "yallist": "^4.0.0"
+ }
+ },
+ "mkdirp": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+ "dev": true
+ },
+ "tar": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-6.0.2.tgz",
+ "integrity": "sha512-Glo3jkRtPcvpDlAs/0+hozav78yoXKFr+c4wgw62NNMO3oo4AaJdCo21Uu7lcwr55h39W2XD1LMERc64wtbItg==",
+ "dev": true,
+ "requires": {
+ "chownr": "^2.0.0",
+ "fs-minipass": "^2.0.0",
+ "minipass": "^3.0.0",
+ "minizlib": "^2.1.0",
+ "mkdirp": "^1.0.3",
+ "yallist": "^4.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"
+ }
+ },
+ "yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"dev": true
}
}
@@ -14963,4 +15060,4 @@
}
}
}
-}
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index 311a8d80..cc51030c 100644
--- a/package.json
+++ b/package.json
@@ -51,6 +51,7 @@
"@fortawesome/react-fontawesome": "^0.1.7",
"@types/bluebird": "^3.5.30",
"@types/chai": "^4.2.7",
+ "@types/copy-webpack-plugin": "^6.0.0",
"@types/mime-types": "^2.1.0",
"@types/mini-css-extract-plugin": "^0.9.1",
"@types/mocha": "^7.0.2",
@@ -60,7 +61,7 @@
"@types/request": "^2.48.4",
"@types/semver": "^7.1.0",
"@types/sinon": "^9.0.0",
- "@types/terser-webpack-plugin": "^2.2.0",
+ "@types/terser-webpack-plugin": "^3.0.0",
"@types/tmp": "^0.2.0",
"@types/webpack-node-externals": "^1.7.0",
"bluebird": "^3.7.2",
@@ -70,13 +71,13 @@
"css-loader": "^3.5.3",
"d3": "^4.13.0",
"debug": "^4.2.0",
- "electron": "9.0.0",
+ "electron": "9.0.2",
"electron-builder": "^22.7.0",
"electron-mocha": "^8.2.0",
"electron-notarize": "^0.3.0",
"electron-rebuild": "^1.11.0",
"electron-updater": "^4.3.2",
- "etcher-sdk": "^4.1.4",
+ "etcher-sdk": "^4.1.8",
"file-loader": "^6.0.0",
"flexboxgrid": "^6.3.0",
"husky": "^4.2.5",
@@ -89,7 +90,7 @@
"mocha": "^7.0.1",
"nan": "^2.14.0",
"native-addon-loader": "^2.0.1",
- "node-gyp": "^6.1.0",
+ "node-gyp": "^7.0.0",
"node-ipc": "^9.1.1",
"omit-deep-lodash": "1.1.4",
"path-is-inside": "^1.0.2",
diff --git a/tests/spectron/runner.spec.ts b/tests/spectron/runner.spec.ts
index e693b50e..98f7c3e5 100644
--- a/tests/spectron/runner.spec.ts
+++ b/tests/spectron/runner.spec.ts
@@ -16,41 +16,29 @@
import { expect } from 'chai';
import { Application } from 'spectron';
-
-import * as EXIT_CODES from '../../lib/shared/exit-codes';
-
-const entrypoint = process.env.ETCHER_SPECTRON_ENTRYPOINT;
-
-if (!entrypoint) {
- console.error('You need to properly configure ETCHER_SPECTRON_ENTRYPOINT');
- process.exit(EXIT_CODES.GENERAL_ERROR);
-}
+import * as electronPath from 'electron';
describe('Spectron', function () {
// Mainly for CI jobs
this.timeout(40000);
- let app: Application;
-
- before('app:start', function () {
- app = new Application({
- path: entrypoint,
- args: ['--no-sandbox', '.'],
- });
-
- return app.start();
+ const app = new Application({
+ path: (electronPath as unknown) as string,
+ args: ['--no-sandbox', '.'],
});
- after('app:stop', function () {
+ before('app:start', async () => {
+ await app.start();
+ });
+
+ after('app:stop', async () => {
if (app && app.isRunning()) {
- return app.stop();
+ await app.stop();
}
-
- return Promise.resolve();
});
- describe('Browser Window', function () {
- it('should open a browser window', async function () {
+ describe('Browser Window', () => {
+ it('should open a browser window', async () => {
// We can't use `isVisible()` here as it won't work inside
// a Windows Docker container, but we can approximate it
// with these set of checks:
@@ -61,7 +49,7 @@ describe('Spectron', function () {
expect(await app.browserWindow.isFocused()).to.be.true;
});
- it('should set a proper title', async function () {
+ it('should set a proper title', async () => {
// @ts-ignore (SpectronClient.getTitle exists)
return expect(await app.client.getTitle()).to.equal('Etcher');
});
diff --git a/webpack.config.ts b/webpack.config.ts
index 67561937..0badecc7 100644
--- a/webpack.config.ts
+++ b/webpack.config.ts
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-// @ts-ignore @types for copy-webpack-plugin@6.0.1 not released yet
import * as CopyPlugin from 'copy-webpack-plugin';
import { readdirSync } from 'fs';
import * as _ from 'lodash';
@@ -22,6 +21,7 @@ import * as MiniCssExtractPlugin from 'mini-css-extract-plugin';
import * as os from 'os';
import outdent from 'outdent';
import * as path from 'path';
+import { env } from 'process';
import * as SimpleProgressWebpackPlugin from 'simple-progress-webpack-plugin';
import * as TerserPlugin from 'terser-webpack-plugin';
import { BannerPlugin, NormalModuleReplacementPlugin } from 'webpack';
@@ -77,7 +77,11 @@ function renameNodeModules(resourcePath: string) {
function findLzmaNativeBindingsFolder(): string {
const files = readdirSync(path.join('node_modules', 'lzma-native'));
- const bindingsFolder = files.find((f) => f.startsWith('binding-'));
+ const bindingsFolder = files.find(
+ (f) =>
+ f.startsWith('binding-') &&
+ f.endsWith(env.npm_config_target_arch || os.arch()),
+ );
if (bindingsFolder === undefined) {
throw new Error('Could not find lzma_native binding');
}
@@ -91,11 +95,15 @@ interface ReplacementRule {
replace: string | (() => string);
}
+function slashOrAntislash(pattern: RegExp): RegExp {
+ return new RegExp(pattern.source.replace(/\\\//g, '(\\/|\\\\)'));
+}
+
function replace(test: RegExp, ...replacements: ReplacementRule[]) {
return {
loader: 'string-replace-loader',
// Handle windows path separators
- test: new RegExp(test.source.replace(/\\\//g, '(\\/|\\\\)')),
+ test: slashOrAntislash(test),
options: { multiple: replacements.map((r) => ({ ...r, strict: true })) },
};
}
@@ -218,7 +226,7 @@ const commonConfig = {
// Force axios to use http.js, not xhr.js as we need stream support
// (it's package.json file replaces http with xhr for browser targets).
new NormalModuleReplacementPlugin(
- /node_modules\/axios\/lib\/adapters\/xhr\.js/,
+ slashOrAntislash(/node_modules\/axios\/lib\/adapters\/xhr\.js/),
'./http.js',
),
],