This commit is contained in:
crusader 2018-10-17 13:50:50 +09:00
parent 5e221b0753
commit 60e7dd9ca9
5 changed files with 161 additions and 160 deletions

View File

@ -85,6 +85,7 @@
"electron-connect-webpack-plugin": "^0.1.1", "electron-connect-webpack-plugin": "^0.1.1",
"electron-debug": "^2.0.0", "electron-debug": "^2.0.0",
"electron-log": "^2.2.17", "electron-log": "^2.2.17",
"electron-updater": "^3.1.2",
"fs-extra": "^7.0.0", "fs-extra": "^7.0.0",
"ip-cidr": "^2.0.0", "ip-cidr": "^2.0.0",
"jasmine-core": "~2.99.1", "jasmine-core": "~2.99.1",
@ -113,4 +114,4 @@
"webpack-node-externals": "^1.7.2", "webpack-node-externals": "^1.7.2",
"zone.js": "^0.8.26" "zone.js": "^0.8.26"
} }
} }

View File

@ -0,0 +1,138 @@
import { app, Menu, ipcMain, BrowserWindow, shell } from 'electron';
import * as log from 'electron-log';
import { autoUpdater } from 'electron-updater';
// -------------------------------------------------------------------
// Logging
//
// THIS SECTION IS NOT REQUIRED
//
// This logging setup is not required for auto-updates to work,
// but it sure makes debugging easier :)
// -------------------------------------------------------------------
autoUpdater.logger = log;
log.info('App starting...');
// -------------------------------------------------------------------
// Define the menu
//
// THIS SECTION IS NOT REQUIRED
// -------------------------------------------------------------------
const template = [];
if (process.platform === 'darwin') {
// OS X
const name = app.getName();
template.unshift({
label: name,
submenu: [
{
label: 'About ' + name,
role: 'about'
},
{
label: 'Quit',
accelerator: 'Command+Q',
click() { app.quit(); }
},
]
});
}
// -------------------------------------------------------------------
// Open a window that displays the version
//
// THIS SECTION IS NOT REQUIRED
//
// This isn't required for auto-updates to work, but it's easier
// for the app to show a window than to have to click "About" to see
// that updates are working.
// -------------------------------------------------------------------
let win;
function sendStatusToWindow(text) {
log.info(text);
win.webContents.send('message', text);
}
function createDefaultWindow() {
win = new BrowserWindow();
win.webContents.openDevTools();
win.on('closed', () => {
win = null;
});
win.loadURL(`file://${__dirname}/version.html#v${app.getVersion()}`);
return win;
}
autoUpdater.on('checking-for-update', () => {
sendStatusToWindow('Checking for update...');
});
autoUpdater.on('update-available', (info) => {
sendStatusToWindow('Update available.');
});
autoUpdater.on('update-not-available', (info) => {
sendStatusToWindow('Update not available.');
});
autoUpdater.on('error', (err) => {
sendStatusToWindow('Error in auto-updater. ' + err);
});
autoUpdater.on('download-progress', (progressObj) => {
let log_message = 'Download speed: ' + progressObj.bytesPerSecond;
log_message = log_message + ' - Downloaded ' + progressObj.percent + '%';
log_message = log_message + ' (' + progressObj.transferred + '/' + progressObj.total + ')';
sendStatusToWindow(log_message);
});
autoUpdater.on('update-downloaded', (info) => {
sendStatusToWindow('Update downloaded');
});
app.on('ready', function () {
// Create the Menu
const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
createDefaultWindow();
});
app.on('window-all-closed', () => {
app.quit();
});
//
// CHOOSE one of the following options for Auto updates
//
// -------------------------------------------------------------------
// Auto updates - Option 1 - Simplest version
//
// This will immediately download an update, then install when the
// app quits.
// -------------------------------------------------------------------
app.on('ready', function () {
autoUpdater.checkForUpdatesAndNotify();
});
// -------------------------------------------------------------------
// Auto updates - Option 2 - More control
//
// For details about these events, see the Wiki:
// https://github.com/electron-userland/electron-builder/wiki/Auto-Update#events
//
// The app doesn't need to listen to any events except `update-downloaded`
//
// Uncomment any of the below events to listen for them. Also,
// look in the previous section to see them being used.
// -------------------------------------------------------------------
// app.on('ready', function() {
// autoUpdater.checkForUpdates();
// });
// autoUpdater.on('checking-for-update', () => {
// })
// autoUpdater.on('update-available', (info) => {
// })
// autoUpdater.on('update-not-available', (info) => {
// })
// autoUpdater.on('error', (err) => {
// })
// autoUpdater.on('download-progress', (progressObj) => {
// })
// autoUpdater.on('update-downloaded', (info) => {
// autoUpdater.quitAndInstall();
// })

View File

@ -18,8 +18,6 @@ import { IMenuItem } from '@overflow/core/menu-item';
import { root } from './app-path'; import { root } from './app-path';
import { AppWindow } from './app-window'; import { AppWindow } from './app-window';
import { handleSquirrelEvent } from './squirrel-updater';
import { openDirectorySafe } from './shell'; import { openDirectorySafe } from './shell';
import { buildDefaultMenu } from './menu/build-default'; import { buildDefaultMenu } from './menu/build-default';
import { MenuEvent } from '../commons/type'; import { MenuEvent } from '../commons/type';

View File

@ -1,156 +0,0 @@
import * as Path from 'path';
import * as Os from 'os';
import { pathExists, ensureDir, writeFile } from 'fs-extra';
import { spawn, getPathSegments, setPathSegments } from '@overflow/core/process/win32';
const appFolder = Path.resolve(process.execPath, '..');
const rootAppDir = Path.resolve(appFolder, '..');
const updateDotExe = Path.resolve(Path.join(rootAppDir, 'Update.exe'));
const exeName = Path.basename(process.execPath);
// A lot of this code was cargo-culted from our Atom comrades:
// https://github.com/atom/atom/blob/7c9f39e3f1d05ee423e0093e6b83f042ce11c90a/src/main-process/squirrel-update.coffee.
/**
* Handle Squirrel.Windows app lifecycle events.
*
* Returns a promise which will resolve when the work is done.
*/
export function handleSquirrelEvent(eventName: string): Promise<void> | null {
switch (eventName) {
case '--squirrel-install':
return handleInstalled();
case '--squirrel-updated':
return handleUpdated();
case '--squirrel-uninstall':
return handleUninstall();
case '--squirrel-obsolete':
return Promise.resolve();
}
return null;
}
async function handleInstalled(): Promise<void> {
await createShortcut(['StartMenu', 'Desktop']);
await installCLI();
}
async function handleUpdated(): Promise<void> {
await updateShortcut();
await installCLI();
}
async function installCLI(): Promise<void> {
const binPath = getBinPath();
await ensureDir(binPath);
await writeBatchScriptCLITrampoline(binPath);
await writeShellScriptCLITrampoline(binPath);
const paths = await getPathSegments();
if (paths.indexOf(binPath) < 0) {
await setPathSegments([...paths, binPath]);
}
}
/**
* Get the path for the `bin` directory which exists in our `AppData` but
* outside path which includes the installed app version.
*/
function getBinPath(): string {
return Path.resolve(process.execPath, '../../bin');
}
function resolveVersionedPath(binPath: string, relativePath: string): string {
const _appFolder = Path.resolve(process.execPath, '..');
return Path.relative(binPath, Path.join(_appFolder, relativePath));
}
/**
* Here's the problem: our app's path contains its version number. So each time
* we update, the path to our app changes. So it's Real Hard to add our path
* directly to `Path`. We'd have to detect and remove stale entries, etc.
*
* So instead, we write a trampoline out to a fixed path, still inside our
* `AppData` directory but outside the version-specific path. That trampoline
* just launches the current version's CLI tool. Then, whenever we update, we
* rewrite the trampoline to point to the new, version-specific path. Bingo
* bango Bob's your uncle.
*/
function writeBatchScriptCLITrampoline(binPath: string): Promise<void> {
const versionedPath = resolveVersionedPath(
binPath,
'resources/app/static/github.bat'
);
const trampoline = `@echo off\n"%~dp0\\${versionedPath}" %*`;
const trampolinePath = Path.join(binPath, 'github.bat');
return writeFile(trampolinePath, trampoline);
}
function writeShellScriptCLITrampoline(binPath: string): Promise<void> {
const versionedPath = resolveVersionedPath(
binPath,
'resources/app/static/github.sh'
);
const trampoline = `#!/usr/bin/env bash
DIR="$( cd "$( dirname "\$\{BASH_SOURCE[0]\}" )" && pwd )"
sh "$DIR/${versionedPath}" "$@"`;
const trampolinePath = Path.join(binPath, 'github');
return writeFile(trampolinePath, trampoline, { encoding: 'utf8', mode: 755 });
}
/** Spawn the Squirrel.Windows `Update.exe` with a command. */
async function spawnSquirrelUpdate(
commands: ReadonlyArray<string>
): Promise<void> {
await spawn(updateDotExe, commands);
}
type ShortcutLocations = ReadonlyArray<'StartMenu' | 'Desktop'>;
function createShortcut(locations: ShortcutLocations): Promise<void> {
return spawnSquirrelUpdate([
'--createShortcut',
exeName,
'-l',
locations.join(','),
]);
}
async function handleUninstall(): Promise<void> {
await removeShortcut();
const paths = await getPathSegments();
const binPath = getBinPath();
const pathsWithoutBinPath = paths.filter(p => p !== binPath);
return setPathSegments(pathsWithoutBinPath);
}
function removeShortcut(): Promise<void> {
return spawnSquirrelUpdate(['--removeShortcut', exeName]);
}
async function updateShortcut(): Promise<void> {
const homeDirectory = Os.homedir();
if (homeDirectory) {
const desktopShortcutPath = Path.join(
homeDirectory,
'Desktop',
'overFlow Scanner.lnk'
);
const exists = await pathExists(desktopShortcutPath);
const locations: ShortcutLocations = exists
? ['StartMenu', 'Desktop']
: ['StartMenu'];
return createShortcut(locations);
} else {
return createShortcut(['StartMenu', 'Desktop']);
}
}

View File

@ -1630,7 +1630,7 @@ buffer@^4.3.0:
ieee754 "^1.1.4" ieee754 "^1.1.4"
isarray "^1.0.0" isarray "^1.0.0"
builder-util-runtime@4.4.1, builder-util-runtime@^4.4.1: builder-util-runtime@4.4.1, builder-util-runtime@^4.4.1, builder-util-runtime@~4.4.1:
version "4.4.1" version "4.4.1"
resolved "https://nexus.loafle.net/repository/npm-all/builder-util-runtime/-/builder-util-runtime-4.4.1.tgz#2770d03241e51fde46acacc7ed3ed8a9f45f02cb" resolved "https://nexus.loafle.net/repository/npm-all/builder-util-runtime/-/builder-util-runtime-4.4.1.tgz#2770d03241e51fde46acacc7ed3ed8a9f45f02cb"
integrity sha512-8L2pbL6D3VdI1f8OMknlZJpw0c7KK15BRz3cY77AOUElc4XlCv2UhVV01jJM7+6Lx7henaQh80ALULp64eFYAQ== integrity sha512-8L2pbL6D3VdI1f8OMknlZJpw0c7KK15BRz3cY77AOUElc4XlCv2UhVV01jJM7+6Lx7henaQh80ALULp64eFYAQ==
@ -3154,6 +3154,21 @@ electron-to-chromium@^1.3.47:
resolved "https://nexus.loafle.net/repository/npm-all/electron-to-chromium/-/electron-to-chromium-1.3.79.tgz#774718f06284a4bf8f578ac67e74508fe659f13a" resolved "https://nexus.loafle.net/repository/npm-all/electron-to-chromium/-/electron-to-chromium-1.3.79.tgz#774718f06284a4bf8f578ac67e74508fe659f13a"
integrity sha512-LQdY3j4PxuUl6xfxiFruTSlCniTrTrzAd8/HfsLEMi0PUpaQ0Iy+Pr4N4VllDYjs0Hyu2lkTbvzqlG+PX9NsNw== integrity sha512-LQdY3j4PxuUl6xfxiFruTSlCniTrTrzAd8/HfsLEMi0PUpaQ0Iy+Pr4N4VllDYjs0Hyu2lkTbvzqlG+PX9NsNw==
electron-updater@^3.1.2:
version "3.1.2"
resolved "https://nexus.loafle.net/repository/npm-all/electron-updater/-/electron-updater-3.1.2.tgz#30d9790d5b16048e4afc74a31748790348b153bf"
integrity sha512-y3n37O01pdynMJHhJbOd2UVhVrmDW6zLvR2SOZ+gk3S6r16872+0nNbC48GXWwc26lTeus/Zja/XUpiqrvdw4A==
dependencies:
bluebird-lst "^1.0.5"
builder-util-runtime "~4.4.1"
electron-is-dev "^0.3.0"
fs-extra-p "^4.6.1"
js-yaml "^3.12.0"
lazy-val "^1.0.3"
lodash.isequal "^4.5.0"
semver "^5.5.1"
source-map-support "^0.5.9"
electron-window-state@^5.0.1: electron-window-state@^5.0.1:
version "5.0.2" version "5.0.2"
resolved "https://nexus.loafle.net/repository/npm-all/electron-window-state/-/electron-window-state-5.0.2.tgz#dfc4f7dd0ca2d7116d1e246acf1683b0bdfd45c2" resolved "https://nexus.loafle.net/repository/npm-all/electron-window-state/-/electron-window-state-5.0.2.tgz#dfc4f7dd0ca2d7116d1e246acf1683b0bdfd45c2"
@ -5545,6 +5560,11 @@ lodash.find@^4.6.0:
resolved "https://nexus.loafle.net/repository/npm-all/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1" resolved "https://nexus.loafle.net/repository/npm-all/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1"
integrity sha1-ywcE1Hq3F4n/oN6Ll92Sb7iLE7E= integrity sha1-ywcE1Hq3F4n/oN6Ll92Sb7iLE7E=
lodash.isequal@^4.5.0:
version "4.5.0"
resolved "https://nexus.loafle.net/repository/npm-all/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=
lodash.max@^4.0.1: lodash.max@^4.0.1:
version "4.0.1" version "4.0.1"
resolved "https://nexus.loafle.net/repository/npm-all/lodash.max/-/lodash.max-4.0.1.tgz#8735566c618b35a9f760520b487ae79658af136a" resolved "https://nexus.loafle.net/repository/npm-all/lodash.max/-/lodash.max-4.0.1.tgz#8735566c618b35a9f760520b487ae79658af136a"