mirror of
https://github.com/Llewellynvdm/nativefier.git
synced 2024-11-10 15:21:03 +00:00
Fix upgrade not working (#1286)
* Attempt to get upgrade working right; in progress * Got it fixed in Mac * Fix some linting errors * Finish fixing upgrade + tests * Integration testing for global shortcuts * Regenerate shrinkwrap * Get rid of deprecated rmdirSync * Remove instead of rm for 12.x support * Make dereferencing platform dependent * Fix folder copy funkiness * Whoops * Whoops 2: Extra Whoops * Update Electron to 13.5.1; Fix auth manual tests * Rework relock * Add a request for help. * Update @types/node to 14
This commit is contained in:
parent
adcf7c4c0c
commit
b9c5e2b464
12
app/npm-shrinkwrap.json
generated
12
app/npm-shrinkwrap.json
generated
@ -235,9 +235,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/debug": {
|
"node_modules/debug": {
|
||||||
"version": "4.3.2",
|
"version": "4.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
|
||||||
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
|
"integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ms": "2.1.2"
|
"ms": "2.1.2"
|
||||||
@ -1375,9 +1375,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"debug": {
|
"debug": {
|
||||||
"version": "4.3.2",
|
"version": "4.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
|
||||||
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
|
"integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"ms": "2.1.2"
|
"ms": "2.1.2"
|
||||||
|
1699
npm-shrinkwrap.json
generated
1699
npm-shrinkwrap.json
generated
File diff suppressed because it is too large
Load Diff
@ -43,7 +43,7 @@
|
|||||||
"lint": "eslint shared app src --ext .ts",
|
"lint": "eslint shared app src --ext .ts",
|
||||||
"list-outdated-deps": "npm out; cd app && npm out; true",
|
"list-outdated-deps": "npm out; cd app && npm out; true",
|
||||||
"prepare": "cd app && npm ci && cd .. && npm run build",
|
"prepare": "cd app && npm ci && cd .. && npm run build",
|
||||||
"relock": "rm -rf ./node_modules/ ./app/node_modules/ ./npm-shrinkwrap.json ./app/npm-shrinkwrap.json; npm install --ignore-scripts --package-lock && mv package-lock.json npm-shrinkwrap.json && npm out; cd app && npm install --ignore-scripts --package-lock && mv package-lock.json npm-shrinkwrap.json && npm out; cd .. && true",
|
"relock": "rm -rf ./node_modules/ ./app/node_modules/ ./npm-shrinkwrap.json ./app/npm-shrinkwrap.json && npm install --ignore-scripts --package-lock && mv package-lock.json npm-shrinkwrap.json && npm out && cd app && npm install --ignore-scripts --package-lock && mv package-lock.json npm-shrinkwrap.json && npm out",
|
||||||
"test:integration": "jest --testRegex '.*integration-test.js'",
|
"test:integration": "jest --testRegex '.*integration-test.js'",
|
||||||
"test:manual": "npm run build && ./.github/manual-test",
|
"test:manual": "npm run build && ./.github/manual-test",
|
||||||
"test:unit": "jest",
|
"test:unit": "jest",
|
||||||
@ -55,6 +55,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^0.24.0",
|
"axios": "^0.24.0",
|
||||||
"electron-packager": "^15.2.0",
|
"electron-packager": "^15.2.0",
|
||||||
|
"fs-extra": "^10.0.0",
|
||||||
"gitcloud": "^0.2.3",
|
"gitcloud": "^0.2.3",
|
||||||
"hasbin": "^1.2.3",
|
"hasbin": "^1.2.3",
|
||||||
"loglevel": "^1.7.1",
|
"loglevel": "^1.7.1",
|
||||||
@ -67,10 +68,11 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/debug": "^4.1.6",
|
"@types/debug": "^4.1.6",
|
||||||
|
"@types/fs-extra": "^9.0.13",
|
||||||
"@types/hasbin": "^1.2.0",
|
"@types/hasbin": "^1.2.0",
|
||||||
"@types/jest": "^27.0.1",
|
"@types/jest": "^27.0.1",
|
||||||
"@types/ncp": "^2.0.5",
|
"@types/ncp": "^2.0.5",
|
||||||
"@types/node": "^12.20.16",
|
"@types/node": "14.14.20",
|
||||||
"@types/page-icon": "^0.3.4",
|
"@types/page-icon": "^0.3.4",
|
||||||
"@types/tmp": "^0.2.1",
|
"@types/tmp": "^0.2.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.3.0",
|
"@typescript-eslint/eslint-plugin": "^5.3.0",
|
||||||
|
@ -183,7 +183,7 @@ export type RawOptions = {
|
|||||||
singleInstance?: boolean;
|
singleInstance?: boolean;
|
||||||
targetUrl?: string;
|
targetUrl?: string;
|
||||||
titleBarStyle?: TitleBarValue;
|
titleBarStyle?: TitleBarValue;
|
||||||
tray: TrayValue;
|
tray?: TrayValue;
|
||||||
upgrade?: string | boolean;
|
upgrade?: string | boolean;
|
||||||
upgradeFrom?: string;
|
upgradeFrom?: string;
|
||||||
userAgent?: string;
|
userAgent?: string;
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
import * as electronGet from '@electron/get';
|
import * as electronGet from '@electron/get';
|
||||||
|
import * as chalk from 'chalk';
|
||||||
import electronPackager from 'electron-packager';
|
import electronPackager from 'electron-packager';
|
||||||
|
import * as fs from 'fs-extra';
|
||||||
import * as log from 'loglevel';
|
import * as log from 'loglevel';
|
||||||
|
|
||||||
import { convertIconIfNecessary } from './buildIcon';
|
import { convertIconIfNecessary } from './buildIcon';
|
||||||
import {
|
import {
|
||||||
copyFileOrDir,
|
|
||||||
getTempDir,
|
getTempDir,
|
||||||
hasWine,
|
hasWine,
|
||||||
isWindows,
|
isWindows,
|
||||||
@ -49,7 +50,7 @@ async function copyIconsIfNecessary(
|
|||||||
log.debug('Copying icon for tray application');
|
log.debug('Copying icon for tray application');
|
||||||
const trayIconFileName = `tray-icon.png`;
|
const trayIconFileName = `tray-icon.png`;
|
||||||
const destIconPath = path.join(appPath, 'icon.png');
|
const destIconPath = path.join(appPath, 'icon.png');
|
||||||
await copyFileOrDir(
|
await fs.copy(
|
||||||
`${path.dirname(options.packager.icon)}/${trayIconFileName}`,
|
`${path.dirname(options.packager.icon)}/${trayIconFileName}`,
|
||||||
destIconPath,
|
destIconPath,
|
||||||
);
|
);
|
||||||
@ -64,7 +65,7 @@ async function copyIconsIfNecessary(
|
|||||||
const destIconPath = path.join(appPath, destFileName);
|
const destIconPath = path.join(appPath, destFileName);
|
||||||
|
|
||||||
log.debug(`Copying icon ${options.packager.icon} to`, destIconPath);
|
log.debug(`Copying icon ${options.packager.icon} to`, destIconPath);
|
||||||
await copyFileOrDir(options.packager.icon, destIconPath);
|
await fs.copy(options.packager.icon, destIconPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -129,12 +130,22 @@ function trimUnprocessableOptions(options: AppOptions): void {
|
|||||||
export async function buildNativefierApp(
|
export async function buildNativefierApp(
|
||||||
rawOptions: RawOptions,
|
rawOptions: RawOptions,
|
||||||
): Promise<string | undefined> {
|
): Promise<string | undefined> {
|
||||||
|
log.warn(
|
||||||
|
new chalk.Instance().yellowBright.bold(
|
||||||
|
'\n\n Hi! Nativefier is minimally maintained these days, and needs more hands.\n' +
|
||||||
|
' If you have the time & motivation, help with bugfixes and maintenance is VERY welcome.\n' +
|
||||||
|
' Please go to https://github.com/nativefier/nativefier and help how you can. Thanks.\n\n',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
log.info('\nProcessing options...');
|
log.info('\nProcessing options...');
|
||||||
|
|
||||||
|
let finalOutDirectory = rawOptions.out ?? process.cwd();
|
||||||
|
|
||||||
if (isUpgrade(rawOptions)) {
|
if (isUpgrade(rawOptions)) {
|
||||||
log.debug('Attempting to upgrade from', rawOptions.upgradeFrom);
|
log.debug('Attempting to upgrade from', rawOptions.upgradeFrom);
|
||||||
const oldApp = findUpgradeApp(rawOptions.upgradeFrom as string);
|
const oldApp = findUpgradeApp(rawOptions.upgradeFrom as string);
|
||||||
if (oldApp === null) {
|
if (!oldApp) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Could not find an old Nativfier app in "${
|
`Could not find an old Nativfier app in "${
|
||||||
rawOptions.upgradeFrom as string
|
rawOptions.upgradeFrom as string
|
||||||
@ -143,7 +154,8 @@ export async function buildNativefierApp(
|
|||||||
}
|
}
|
||||||
rawOptions = useOldAppOptions(rawOptions, oldApp);
|
rawOptions = useOldAppOptions(rawOptions, oldApp);
|
||||||
if (rawOptions.out === undefined && rawOptions.overwrite) {
|
if (rawOptions.out === undefined && rawOptions.overwrite) {
|
||||||
rawOptions.out = path.dirname(rawOptions.upgradeFrom as string);
|
finalOutDirectory = oldApp.appRoot;
|
||||||
|
rawOptions.out = getTempDir('appUpgrade', 0o755);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.debug('rawOptions', rawOptions);
|
log.debug('rawOptions', rawOptions);
|
||||||
@ -172,7 +184,7 @@ export async function buildNativefierApp(
|
|||||||
await prepareElectronApp(options.packager.dir, tmpPath, options);
|
await prepareElectronApp(options.packager.dir, tmpPath, options);
|
||||||
|
|
||||||
log.info('\nConverting icons...');
|
log.info('\nConverting icons...');
|
||||||
options.packager.dir = tmpPath; // const optionsWithTmpPath = { ...options, dir: tmpPath };
|
options.packager.dir = tmpPath;
|
||||||
convertIconIfNecessary(options);
|
convertIconIfNecessary(options);
|
||||||
await copyIconsIfNecessary(options, tmpPath);
|
await copyIconsIfNecessary(options, tmpPath);
|
||||||
|
|
||||||
@ -184,20 +196,64 @@ export async function buildNativefierApp(
|
|||||||
const appPathArray = await electronPackager(options.packager);
|
const appPathArray = await electronPackager(options.packager);
|
||||||
|
|
||||||
log.info('\nFinalizing build...');
|
log.info('\nFinalizing build...');
|
||||||
const appPath = getAppPath(appPathArray);
|
let appPath = getAppPath(appPathArray);
|
||||||
|
|
||||||
if (appPath) {
|
if (!appPath) {
|
||||||
let osRunHelp = '';
|
throw new Error('App Path could not be determined.');
|
||||||
if (options.packager.platform === 'win32') {
|
|
||||||
osRunHelp = `the contained .exe file.`;
|
|
||||||
} else if (options.packager.platform === 'linux') {
|
|
||||||
osRunHelp = `the contained executable file (prefixing with ./ if necessary)\nMenu/desktop shortcuts are up to you, because Nativefier cannot know where you're going to move the app. Search for "linux .desktop file" for help, or see https://wiki.archlinux.org/index.php/Desktop_entries`;
|
|
||||||
} else if (options.packager.platform === 'darwin') {
|
|
||||||
osRunHelp = `the app bundle.`;
|
|
||||||
}
|
|
||||||
log.info(
|
|
||||||
`App built to ${appPath}, move to wherever it makes sense for you and run ${osRunHelp}`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
options.packager.upgrade &&
|
||||||
|
options.packager.upgradeFrom &&
|
||||||
|
options.packager.overwrite
|
||||||
|
) {
|
||||||
|
if (options.packager.platform === 'darwin') {
|
||||||
|
try {
|
||||||
|
// This is needed due to a funky thing that happens when copying Squirrel.framework
|
||||||
|
// over where it gets into a circular file reference somehow.
|
||||||
|
await fs.remove(
|
||||||
|
path.join(
|
||||||
|
finalOutDirectory,
|
||||||
|
`${options.packager.name ?? ''}.app`,
|
||||||
|
'Contents',
|
||||||
|
'Frameworks',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} catch (err: unknown) {
|
||||||
|
log.warn(
|
||||||
|
'Encountered an error when attempting to pre-delete old frameworks:',
|
||||||
|
err,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await fs.copy(
|
||||||
|
path.join(appPath, `${options.packager.name ?? ''}.app`),
|
||||||
|
path.join(finalOutDirectory, `${options.packager.name ?? ''}.app`),
|
||||||
|
{
|
||||||
|
overwrite: options.packager.overwrite,
|
||||||
|
preserveTimestamps: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await fs.copy(appPath, finalOutDirectory, {
|
||||||
|
overwrite: options.packager.overwrite,
|
||||||
|
preserveTimestamps: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await fs.remove(appPath);
|
||||||
|
appPath = finalOutDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
let osRunHelp = '';
|
||||||
|
if (options.packager.platform === 'win32') {
|
||||||
|
osRunHelp = `the contained .exe file.`;
|
||||||
|
} else if (options.packager.platform === 'linux') {
|
||||||
|
osRunHelp = `the contained executable file (prefixing with ./ if necessary)\nMenu/desktop shortcuts are up to you, because Nativefier cannot know where you're going to move the app. Search for "linux .desktop file" for help, or see https://wiki.archlinux.org/index.php/Desktop_entries`;
|
||||||
|
} else if (options.packager.platform === 'darwin') {
|
||||||
|
osRunHelp = `the app bundle.`;
|
||||||
|
}
|
||||||
|
log.info(
|
||||||
|
`App built to ${appPath}, move to wherever it makes sense for you and run ${osRunHelp}`,
|
||||||
|
);
|
||||||
|
|
||||||
return appPath;
|
return appPath;
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import * as crypto from 'crypto';
|
import * as crypto from 'crypto';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs-extra';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import { promisify } from 'util';
|
|
||||||
|
|
||||||
import * as log from 'loglevel';
|
import * as log from 'loglevel';
|
||||||
|
|
||||||
import { copyFileOrDir, generateRandomSuffix } from '../helpers/helpers';
|
import { generateRandomSuffix } from '../helpers/helpers';
|
||||||
import {
|
import {
|
||||||
AppOptions,
|
AppOptions,
|
||||||
OutputOptions,
|
OutputOptions,
|
||||||
@ -14,8 +13,6 @@ import {
|
|||||||
import { parseJson } from '../utils/parseUtils';
|
import { parseJson } from '../utils/parseUtils';
|
||||||
import { DEFAULT_APP_NAME } from '../constants';
|
import { DEFAULT_APP_NAME } from '../constants';
|
||||||
|
|
||||||
const writeFileAsync = promisify(fs.writeFile);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Only picks certain app args to pass to nativefier.json
|
* Only picks certain app args to pass to nativefier.json
|
||||||
*/
|
*/
|
||||||
@ -133,7 +130,7 @@ async function maybeCopyScripts(
|
|||||||
const destFileName = `inject-${postFixHash}${path.extname(src)}`;
|
const destFileName = `inject-${postFixHash}${path.extname(src)}`;
|
||||||
const destPath = path.join(dest, 'inject', destFileName);
|
const destPath = path.join(dest, 'inject', destFileName);
|
||||||
log.debug(`Copying injection file "${src}" to "${destPath}"`);
|
log.debug(`Copying injection file "${src}" to "${destPath}"`);
|
||||||
await copyFileOrDir(src, destPath);
|
await fs.copy(src, destPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,7 +183,7 @@ export async function prepareElectronApp(
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
log.debug(`Copying electron app from ${src} to ${dest}`);
|
log.debug(`Copying electron app from ${src} to ${dest}`);
|
||||||
try {
|
try {
|
||||||
await copyFileOrDir(src, dest);
|
await fs.copy(src, dest);
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
throw `Error copying electron app from ${src} to temp dir ${dest}. Error: ${
|
throw `Error copying electron app from ${src} to temp dir ${dest}. Error: ${
|
||||||
(err as Error).message
|
(err as Error).message
|
||||||
@ -194,16 +191,14 @@ export async function prepareElectronApp(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const appJsonPath = path.join(dest, '/nativefier.json');
|
const appJsonPath = path.join(dest, '/nativefier.json');
|
||||||
log.debug(`Writing app config to ${appJsonPath}`);
|
const pickedOptions = pickElectronAppArgs(options);
|
||||||
await writeFileAsync(
|
log.debug(`Writing app config to ${appJsonPath}`, pickedOptions);
|
||||||
appJsonPath,
|
await fs.writeFile(appJsonPath, JSON.stringify(pickedOptions));
|
||||||
JSON.stringify(pickElectronAppArgs(options), null, 2),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (options.nativefier.bookmarksMenu) {
|
if (options.nativefier.bookmarksMenu) {
|
||||||
const bookmarksJsonPath = path.join(dest, '/bookmarks.json');
|
const bookmarksJsonPath = path.join(dest, '/bookmarks.json');
|
||||||
try {
|
try {
|
||||||
await copyFileOrDir(options.nativefier.bookmarksMenu, bookmarksJsonPath);
|
await fs.copy(options.nativefier.bookmarksMenu, bookmarksJsonPath);
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
log.error('Error copying bookmarks menu config file.', err);
|
log.error('Error copying bookmarks menu config file.', err);
|
||||||
}
|
}
|
||||||
|
20
src/cli.ts
20
src/cli.ts
@ -638,6 +638,26 @@ if (require.main === module) {
|
|||||||
...parsedArgs,
|
...parsedArgs,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (options.verbose) {
|
||||||
|
log.setLevel('trace');
|
||||||
|
try {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
|
||||||
|
require('debug').enable('electron-packager');
|
||||||
|
} catch (err: unknown) {
|
||||||
|
log.debug(
|
||||||
|
'Failed to enable electron-packager debug output. This should not happen,',
|
||||||
|
'and suggests their internals changed. Please report an issue.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug(
|
||||||
|
'Running in verbose mode! This will produce a mountain of logs and',
|
||||||
|
'is recommended only for troubleshooting or if you like Shakespeare.',
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
log.setLevel('info');
|
||||||
|
}
|
||||||
|
|
||||||
checkInternet();
|
checkInternet();
|
||||||
|
|
||||||
buildNativefierApp(options).catch((error) => {
|
buildNativefierApp(options).catch((error) => {
|
||||||
|
@ -7,7 +7,6 @@ import axios from 'axios';
|
|||||||
import * as dns from 'dns';
|
import * as dns from 'dns';
|
||||||
import * as hasbin from 'hasbin';
|
import * as hasbin from 'hasbin';
|
||||||
import * as log from 'loglevel';
|
import * as log from 'loglevel';
|
||||||
import { ncp } from 'ncp';
|
|
||||||
import * as tmp from 'tmp';
|
import * as tmp from 'tmp';
|
||||||
|
|
||||||
import { parseJson } from '../utils/parseUtils';
|
import { parseJson } from '../utils/parseUtils';
|
||||||
@ -58,20 +57,6 @@ export function getTempDir(prefix: string, mode?: number): string {
|
|||||||
}).name;
|
}).name;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function copyFileOrDir(
|
|
||||||
sourceFileOrDir: string,
|
|
||||||
dest: string,
|
|
||||||
): Promise<void> {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
ncp(sourceFileOrDir, dest, (error: Error[] | null): void => {
|
|
||||||
if (error) {
|
|
||||||
reject(error);
|
|
||||||
}
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function downloadFile(
|
export function downloadFile(
|
||||||
fileUrl: string,
|
fileUrl: string,
|
||||||
): Promise<DownloadResult | undefined> {
|
): Promise<DownloadResult | undefined> {
|
||||||
|
@ -36,7 +36,6 @@ function getExecutableArch(
|
|||||||
case 'darwin':
|
case 'darwin':
|
||||||
case 'mas':
|
case 'mas':
|
||||||
// https://opensource.apple.com/source/xnu/xnu-2050.18.24/EXTERNAL_HEADERS/mach-o/loader.h
|
// https://opensource.apple.com/source/xnu/xnu-2050.18.24/EXTERNAL_HEADERS/mach-o/loader.h
|
||||||
|
|
||||||
switch ((exeBytes[0x04] << 8) + exeBytes[0x05]) {
|
switch ((exeBytes[0x04] << 8) + exeBytes[0x05]) {
|
||||||
case 0x0700:
|
case 0x0700:
|
||||||
return 'x64';
|
return 'x64';
|
||||||
@ -45,7 +44,7 @@ function getExecutableArch(
|
|||||||
default:
|
default:
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
case 'windows':
|
case 'win32':
|
||||||
// https://en.wikibooks.org/wiki/X86_Disassembly/Windows_Executable_Files#COFF_Header
|
// https://en.wikibooks.org/wiki/X86_Disassembly/Windows_Executable_Files#COFF_Header
|
||||||
switch ((exeBytes[0x7d] << 8) + exeBytes[0x7c]) {
|
switch ((exeBytes[0x7d] << 8) + exeBytes[0x7c]) {
|
||||||
case 0x014c:
|
case 0x014c:
|
||||||
@ -118,7 +117,7 @@ export function getOptionsFromExecutable(
|
|||||||
log.debug('This looks like a Windows app...');
|
log.debug('This looks like a Windows app...');
|
||||||
|
|
||||||
if (newOptions.platform === undefined) {
|
if (newOptions.platform === undefined) {
|
||||||
newOptions.platform = 'windows';
|
newOptions.platform = 'win32';
|
||||||
}
|
}
|
||||||
executablePath = path.join(
|
executablePath = path.join(
|
||||||
appRoot,
|
appRoot,
|
||||||
|
@ -14,6 +14,7 @@ import { parseJson } from '../../utils/parseUtils';
|
|||||||
|
|
||||||
export type UpgradeAppInfo = {
|
export type UpgradeAppInfo = {
|
||||||
appResourcesDir: string;
|
appResourcesDir: string;
|
||||||
|
appRoot: string;
|
||||||
options: NativefierOptions;
|
options: NativefierOptions;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -40,6 +41,25 @@ function findUpgradeAppResourcesDir(searchDir: string): string | null {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getAppRoot(
|
||||||
|
appResourcesDir: string,
|
||||||
|
options: NativefierOptions,
|
||||||
|
): string {
|
||||||
|
switch (options.platform) {
|
||||||
|
case 'darwin':
|
||||||
|
return path.resolve(path.join(appResourcesDir, '..', '..', '..', '..'));
|
||||||
|
case 'linux':
|
||||||
|
case 'win32':
|
||||||
|
return path.resolve(path.join(appResourcesDir, '..', '..'));
|
||||||
|
default:
|
||||||
|
throw new Error(
|
||||||
|
`Could not find the app root for platform: ${
|
||||||
|
options.platform ?? 'undefined'
|
||||||
|
}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getIconPath(appResourcesDir: string): string | undefined {
|
function getIconPath(appResourcesDir: string): string | undefined {
|
||||||
const icnsPath = path.join(appResourcesDir, '..', 'electron.icns');
|
const icnsPath = path.join(appResourcesDir, '..', 'electron.icns');
|
||||||
if (fileExists(icnsPath)) {
|
if (fileExists(icnsPath)) {
|
||||||
@ -163,7 +183,7 @@ export function findUpgradeApp(upgradeFrom: string): UpgradeAppInfo | null {
|
|||||||
const nativefierJSONPath = path.join(appResourcesDir, 'nativefier.json');
|
const nativefierJSONPath = path.join(appResourcesDir, 'nativefier.json');
|
||||||
|
|
||||||
log.debug(`Loading ${nativefierJSONPath}`);
|
log.debug(`Loading ${nativefierJSONPath}`);
|
||||||
const options = parseJson<NativefierOptions>(
|
let options = parseJson<NativefierOptions>(
|
||||||
fs.readFileSync(nativefierJSONPath, 'utf8'),
|
fs.readFileSync(nativefierJSONPath, 'utf8'),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -175,11 +195,18 @@ export function findUpgradeApp(upgradeFrom: string): UpgradeAppInfo | null {
|
|||||||
|
|
||||||
options.electronVersion = undefined;
|
options.electronVersion = undefined;
|
||||||
|
|
||||||
|
options = {
|
||||||
|
...options,
|
||||||
|
...getOptionsFromExecutable(appResourcesDir, options),
|
||||||
|
};
|
||||||
|
|
||||||
|
const appRoot = getAppRoot(appResourcesDir, options);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
appResourcesDir,
|
appResourcesDir,
|
||||||
|
appRoot,
|
||||||
options: {
|
options: {
|
||||||
...options,
|
...options,
|
||||||
...getOptionsFromExecutable(appResourcesDir, options),
|
|
||||||
...getInfoPListOptions(appResourcesDir, options),
|
...getInfoPListOptions(appResourcesDir, options),
|
||||||
asar: options.asar !== undefined ? options.asar : isAsar(appResourcesDir),
|
asar: options.asar !== undefined ? options.asar : isAsar(appResourcesDir),
|
||||||
icon: getIconPath(appResourcesDir),
|
icon: getIconPath(appResourcesDir),
|
||||||
@ -197,7 +224,6 @@ export function useOldAppOptions(
|
|||||||
rawOptions.out = rawOptions.targetUrl;
|
rawOptions.out = rawOptions.targetUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug('rawOptions', rawOptions);
|
|
||||||
log.debug('oldApp', oldApp);
|
log.debug('oldApp', oldApp);
|
||||||
|
|
||||||
const combinedOptions = { ...rawOptions, ...oldApp.options };
|
const combinedOptions = { ...rawOptions, ...oldApp.options };
|
||||||
|
@ -14,6 +14,7 @@ export const supportedPlatforms = [
|
|||||||
'mac',
|
'mac',
|
||||||
'mas',
|
'mas',
|
||||||
'osx',
|
'osx',
|
||||||
|
'win32',
|
||||||
'windows',
|
'windows',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -10,7 +10,11 @@ import { getLatestSafariVersion } from './infer/browsers/inferSafariVersion';
|
|||||||
import { inferArch } from './infer/inferOs';
|
import { inferArch } from './infer/inferOs';
|
||||||
import { buildNativefierApp } from './main';
|
import { buildNativefierApp } from './main';
|
||||||
import { userAgent } from './options/fields/userAgent';
|
import { userAgent } from './options/fields/userAgent';
|
||||||
import { NativefierOptions, RawOptions } from '../shared/src/options/model';
|
import {
|
||||||
|
GlobalShortcut,
|
||||||
|
NativefierOptions,
|
||||||
|
RawOptions,
|
||||||
|
} from '../shared/src/options/model';
|
||||||
import { parseJson } from './utils/parseUtils';
|
import { parseJson } from './utils/parseUtils';
|
||||||
|
|
||||||
async function checkApp(
|
async function checkApp(
|
||||||
@ -27,25 +31,13 @@ async function checkApp(
|
|||||||
).toBe(appRoot);
|
).toBe(appRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
let relativeAppFolder: string;
|
let relativeResourcesDir = 'resources';
|
||||||
|
|
||||||
switch (inputOptions.platform) {
|
if (inputOptions.platform === 'darwin') {
|
||||||
case 'darwin':
|
relativeResourcesDir = path.join('Google.app', 'Contents', 'Resources');
|
||||||
relativeAppFolder = path.join('Google.app', 'Contents/Resources/app');
|
|
||||||
break;
|
|
||||||
case 'linux':
|
|
||||||
relativeAppFolder = 'resources/app';
|
|
||||||
break;
|
|
||||||
case 'win32':
|
|
||||||
relativeAppFolder = 'resources/app';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Error(
|
|
||||||
`Unknown app platform: ${new String(inputOptions.platform).toString()}`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const appPath = path.join(appRoot, relativeAppFolder);
|
const appPath = path.join(appRoot, relativeResourcesDir, 'app');
|
||||||
|
|
||||||
const configPath = path.join(appPath, 'nativefier.json');
|
const configPath = path.join(appPath, 'nativefier.json');
|
||||||
const nativefierConfig: NativefierOptions | undefined =
|
const nativefierConfig: NativefierOptions | undefined =
|
||||||
@ -59,7 +51,11 @@ async function checkApp(
|
|||||||
|
|
||||||
// Test icon writing
|
// Test icon writing
|
||||||
const iconFile =
|
const iconFile =
|
||||||
inputOptions.platform === 'darwin' ? '../electron.icns' : 'icon.png';
|
inputOptions.platform === 'darwin'
|
||||||
|
? path.join('..', 'electron.icns')
|
||||||
|
: inputOptions.platform === 'linux'
|
||||||
|
? 'icon.png'
|
||||||
|
: 'icon.ico';
|
||||||
const iconPath = path.join(appPath, iconFile);
|
const iconPath = path.join(appPath, iconFile);
|
||||||
expect(fs.existsSync(iconPath)).toEqual(true);
|
expect(fs.existsSync(iconPath)).toEqual(true);
|
||||||
expect(fs.statSync(iconPath).size).toBeGreaterThan(1000);
|
expect(fs.statSync(iconPath).size).toBeGreaterThan(1000);
|
||||||
@ -93,6 +89,21 @@ async function checkApp(
|
|||||||
|
|
||||||
// Test lang
|
// Test lang
|
||||||
expect(nativefierConfig?.lang).toEqual(inputOptions.lang);
|
expect(nativefierConfig?.lang).toEqual(inputOptions.lang);
|
||||||
|
|
||||||
|
// Test global shortcuts
|
||||||
|
if (inputOptions.globalShortcuts) {
|
||||||
|
let shortcutData: GlobalShortcut[] | undefined = [];
|
||||||
|
|
||||||
|
if (typeof inputOptions.globalShortcuts === 'string') {
|
||||||
|
shortcutData = parseJson<GlobalShortcut[]>(
|
||||||
|
fs.readFileSync(inputOptions.globalShortcuts, 'utf8'),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
shortcutData = inputOptions.globalShortcuts;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(nativefierConfig?.globalShortcuts).toStrictEqual(shortcutData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('Nativefier', () => {
|
describe('Nativefier', () => {
|
||||||
@ -108,7 +119,6 @@ describe('Nativefier', () => {
|
|||||||
overwrite: true,
|
overwrite: true,
|
||||||
platform,
|
platform,
|
||||||
targetUrl: 'https://google.com/',
|
targetUrl: 'https://google.com/',
|
||||||
tray: 'false',
|
|
||||||
};
|
};
|
||||||
const appPath = await buildNativefierApp(options);
|
const appPath = await buildNativefierApp(options);
|
||||||
expect(appPath).not.toBeUndefined();
|
expect(appPath).not.toBeUndefined();
|
||||||
@ -117,6 +127,34 @@ describe('Nativefier', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function generateShortcutsFile(dir: string): string {
|
||||||
|
const shortcuts = [
|
||||||
|
{
|
||||||
|
key: 'MediaPlayPause',
|
||||||
|
inputEvents: [
|
||||||
|
{
|
||||||
|
type: 'keyDown',
|
||||||
|
keyCode: 'Space',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'MediaNextTrack',
|
||||||
|
inputEvents: [
|
||||||
|
{
|
||||||
|
type: 'keyDown',
|
||||||
|
keyCode: 'Right',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const filename = path.join(dir, 'shortcuts.json');
|
||||||
|
fs.writeFileSync(filename, JSON.stringify(shortcuts));
|
||||||
|
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
describe('Nativefier upgrade', () => {
|
describe('Nativefier upgrade', () => {
|
||||||
jest.setTimeout(300000);
|
jest.setTimeout(300000);
|
||||||
|
|
||||||
@ -135,12 +173,13 @@ describe('Nativefier upgrade', () => {
|
|||||||
'can upgrade a Nativefier app for platform/arch: %s',
|
'can upgrade a Nativefier app for platform/arch: %s',
|
||||||
async (baseAppOptions) => {
|
async (baseAppOptions) => {
|
||||||
const tempDirectory = getTempDir('integtestUpgrade1');
|
const tempDirectory = getTempDir('integtestUpgrade1');
|
||||||
|
const shortcuts = generateShortcutsFile(tempDirectory);
|
||||||
const options: RawOptions = {
|
const options: RawOptions = {
|
||||||
electronVersion: '11.2.3',
|
electronVersion: '11.2.3',
|
||||||
|
globalShortcuts: shortcuts,
|
||||||
out: tempDirectory,
|
out: tempDirectory,
|
||||||
overwrite: true,
|
overwrite: true,
|
||||||
targetUrl: 'https://google.com/',
|
targetUrl: 'https://google.com/',
|
||||||
tray: 'false',
|
|
||||||
...baseAppOptions,
|
...baseAppOptions,
|
||||||
};
|
};
|
||||||
const appPath = await buildNativefierApp(options);
|
const appPath = await buildNativefierApp(options);
|
||||||
@ -148,9 +187,8 @@ describe('Nativefier upgrade', () => {
|
|||||||
await checkApp(appPath as string, options);
|
await checkApp(appPath as string, options);
|
||||||
|
|
||||||
const upgradeOptions: RawOptions = {
|
const upgradeOptions: RawOptions = {
|
||||||
upgrade: appPath,
|
upgrade: appPath as string,
|
||||||
overwrite: true,
|
overwrite: true,
|
||||||
tray: 'false',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const upgradeAppPath = await buildNativefierApp(upgradeOptions);
|
const upgradeAppPath = await buildNativefierApp(upgradeOptions);
|
||||||
|
@ -226,11 +226,18 @@ export async function getOptions(rawOptions: RawOptions): Promise<AppOptions> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rawOptions.globalShortcuts) {
|
if (rawOptions.globalShortcuts) {
|
||||||
log.debug('Using global shortcuts file at', rawOptions.globalShortcuts);
|
if (typeof rawOptions.globalShortcuts === 'string') {
|
||||||
const globalShortcuts = parseJson<GlobalShortcut[]>(
|
// This is a file we got over the command line
|
||||||
fs.readFileSync(rawOptions.globalShortcuts as string).toString(),
|
log.debug('Using global shortcuts file at', rawOptions.globalShortcuts);
|
||||||
);
|
const globalShortcuts = parseJson<GlobalShortcut[]>(
|
||||||
options.nativefier.globalShortcuts = globalShortcuts;
|
fs.readFileSync(rawOptions.globalShortcuts).toString(),
|
||||||
|
);
|
||||||
|
options.nativefier.globalShortcuts = globalShortcuts;
|
||||||
|
} else {
|
||||||
|
// This is an object we got from an existing config in an upgrade
|
||||||
|
log.debug('Using global shortcuts object', rawOptions.globalShortcuts);
|
||||||
|
options.nativefier.globalShortcuts = rawOptions.globalShortcuts;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await asyncConfig(options);
|
await asyncConfig(options);
|
||||||
|
Loading…
Reference in New Issue
Block a user