mirror of
https://github.com/balena-io/etcher.git
synced 2025-07-21 18:26:32 +00:00
Read image path from arguments, register etcher://...
protocol
Changelog-entry: Read image path from arguments, register `etcher://...` protocol Change-type: patch
This commit is contained in:
parent
7e7a669116
commit
1449478c5b
@ -62,6 +62,12 @@
|
|||||||
"depends": [
|
"depends": [
|
||||||
"polkit-1-auth-agent | policykit-1-gnome | polkit-kde-1"
|
"polkit-1-auth-agent | policykit-1-gnome | polkit-kde-1"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"protocols": {
|
||||||
|
"name": "etcher",
|
||||||
|
"schemes": [
|
||||||
|
"etcher"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,3 +91,7 @@ deb:
|
|||||||
rpm:
|
rpm:
|
||||||
depends:
|
depends:
|
||||||
- util-linux
|
- util-linux
|
||||||
|
protocols:
|
||||||
|
name: etcher
|
||||||
|
schemes:
|
||||||
|
- etcher
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
import { faFile, faLink } from '@fortawesome/free-solid-svg-icons';
|
import { faFile, faLink } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { sourceDestination } from 'etcher-sdk';
|
import { sourceDestination } from 'etcher-sdk';
|
||||||
|
import { ipcRenderer, IpcRendererEvent } from 'electron';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import { GPTPartition, MBRPartition } from 'partitioninfo';
|
import { GPTPartition, MBRPartition } from 'partitioninfo';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
@ -237,6 +238,7 @@ export class SourceSelector extends React.Component<
|
|||||||
this.openImageSelector = this.openImageSelector.bind(this);
|
this.openImageSelector = this.openImageSelector.bind(this);
|
||||||
this.openURLSelector = this.openURLSelector.bind(this);
|
this.openURLSelector = this.openURLSelector.bind(this);
|
||||||
this.reselectImage = this.reselectImage.bind(this);
|
this.reselectImage = this.reselectImage.bind(this);
|
||||||
|
this.onSelectImage = this.onSelectImage.bind(this);
|
||||||
this.onDrop = this.onDrop.bind(this);
|
this.onDrop = this.onDrop.bind(this);
|
||||||
this.showSelectedImageDetails = this.showSelectedImageDetails.bind(this);
|
this.showSelectedImageDetails = this.showSelectedImageDetails.bind(this);
|
||||||
this.afterSelected = props.afterSelected.bind(this);
|
this.afterSelected = props.afterSelected.bind(this);
|
||||||
@ -246,10 +248,22 @@ export class SourceSelector extends React.Component<
|
|||||||
this.unsubscribe = observe(() => {
|
this.unsubscribe = observe(() => {
|
||||||
this.setState(getState());
|
this.setState(getState());
|
||||||
});
|
});
|
||||||
|
ipcRenderer.on('select-image', this.onSelectImage);
|
||||||
|
ipcRenderer.send('source-selector-ready');
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentWillUnmount() {
|
public componentWillUnmount() {
|
||||||
this.unsubscribe();
|
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() {
|
private reselectImage() {
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
import { delay } from 'bluebird';
|
import { delay } from 'bluebird';
|
||||||
import * as electron from 'electron';
|
import * as electron from 'electron';
|
||||||
import { autoUpdater } from 'electron-updater';
|
import { autoUpdater } from 'electron-updater';
|
||||||
|
import { platform } from 'os';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as semver from 'semver';
|
import * as semver from 'semver';
|
||||||
@ -28,6 +29,8 @@ import * as settings from './app/models/settings';
|
|||||||
import * as analytics from './app/modules/analytics';
|
import * as analytics from './app/modules/analytics';
|
||||||
import { buildWindowMenu } from './menu';
|
import { buildWindowMenu } from './menu';
|
||||||
|
|
||||||
|
const customProtocol = 'etcher';
|
||||||
|
const scheme = `${customProtocol}://`;
|
||||||
const updatablePackageTypes = ['appimage', 'nsis', 'dmg'];
|
const updatablePackageTypes = ['appimage', 'nsis', 'dmg'];
|
||||||
const packageUpdatable = _.includes(updatablePackageTypes, packageType);
|
const packageUpdatable = _.includes(updatablePackageTypes, packageType);
|
||||||
let packageUpdated = false;
|
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 <a href="etcher://...">Open in Etcher</a>
|
||||||
|
// 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() {
|
async function createMainWindow() {
|
||||||
const fullscreen = Boolean(await settings.get('fullscreen'));
|
const fullscreen = Boolean(await settings.get('fullscreen'));
|
||||||
const defaultWidth = 800;
|
const defaultWidth = 800;
|
||||||
@ -87,6 +128,8 @@ async function createMainWindow() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
electron.app.setAsDefaultProtocolClient(customProtocol);
|
||||||
|
|
||||||
buildWindowMenu(mainWindow);
|
buildWindowMenu(mainWindow);
|
||||||
mainWindow.setFullScreen(true);
|
mainWindow.setFullScreen(true);
|
||||||
|
|
||||||
@ -133,6 +176,7 @@ async function createMainWindow() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
return mainWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
electron.app.allowRendererProcessReuse = false;
|
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.
|
// make use of it to ensure the browser window is completely destroyed.
|
||||||
// See https://github.com/electron/electron/issues/5273
|
// See https://github.com/electron/electron/issues/5273
|
||||||
electron.app.on('before-quit', () => {
|
electron.app.on('before-quit', () => {
|
||||||
|
electron.app.releaseSingleInstanceLock();
|
||||||
process.exit(EXIT_CODES.SUCCESS);
|
process.exit(EXIT_CODES.SUCCESS);
|
||||||
});
|
});
|
||||||
|
|
||||||
async function main(): Promise<void> {
|
async function main(): Promise<void> {
|
||||||
if (electron.app.isReady()) {
|
if (!electron.app.requestSingleInstanceLock()) {
|
||||||
await createMainWindow();
|
electron.app.quit();
|
||||||
} else {
|
} 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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user