2
0
mirror of https://github.com/frappe/books.git synced 2025-01-22 22:58:28 +00:00

fix: use unlinkIfExists

- handle failed migration copy issue separately
This commit is contained in:
18alantom 2022-08-30 18:13:42 +05:30
parent 65a91e6f86
commit a8e681b973
7 changed files with 100 additions and 27 deletions

View File

@ -1,9 +1,12 @@
import { constants } from 'fs';
import fs from 'fs/promises'; import fs from 'fs/promises';
import path from 'path'; import path from 'path';
import { DatabaseDemuxBase, DatabaseMethod } from 'utils/db/types'; import { DatabaseDemuxBase, DatabaseMethod } from 'utils/db/types';
import { getSchemas } from '../../schemas'; import { getSchemas } from '../../schemas';
import { databaseMethodSet } from '../helpers'; import {
databaseMethodSet,
emitMainProcessError,
unlinkIfExists
} from '../helpers';
import patches from '../patches'; import patches from '../patches';
import { BespokeQueries } from './bespoke'; import { BespokeQueries } from './bespoke';
import DatabaseCore from './core'; import DatabaseCore from './core';
@ -22,7 +25,7 @@ export class DatabaseManager extends DatabaseDemuxBase {
} }
async createNewDatabase(dbPath: string, countryCode: string) { async createNewDatabase(dbPath: string, countryCode: string) {
await this.#unlinkIfExists(dbPath); await unlinkIfExists(dbPath);
return await this.connectToDatabase(dbPath, countryCode); return await this.connectToDatabase(dbPath, countryCode);
} }
@ -61,12 +64,35 @@ export class DatabaseManager extends DatabaseDemuxBase {
try { try {
await this.#runPatchesAndMigrate(); await this.#runPatchesAndMigrate();
} catch (err) { } catch (err) {
console.error(err); this.#handleFailedMigration(err, dbPath, copyPath);
await this.db!.close();
copyPath && (await fs.copyFile(copyPath, dbPath));
throw err;
} finally { } finally {
copyPath && (await fs.unlink(copyPath)); await unlinkIfExists(copyPath);
}
}
async #handleFailedMigration(
error: unknown,
dbPath: string,
copyPath: string | null
) {
await this.db!.close();
if (copyPath) {
await this.#restoreDbCopy(dbPath, copyPath);
}
if (error instanceof Error) {
error.message = `failed migration\n${error.message}`;
}
throw error;
}
async #restoreDbCopy(dbPath: string, copyPath: string) {
try {
await fs.copyFile(copyPath!, dbPath);
} catch (err) {
emitMainProcessError(err);
} }
} }
@ -130,17 +156,6 @@ export class DatabaseManager extends DatabaseDemuxBase {
return await queryFunction(this.db!, ...args); return await queryFunction(this.db!, ...args);
} }
async #unlinkIfExists(dbPath: string) {
const exists = await fs
.access(dbPath, constants.W_OK)
.then(() => true)
.catch(() => false);
if (exists) {
fs.unlink(dbPath);
}
}
async #getIsFirstRun(): Promise<boolean> { async #getIsFirstRun(): Promise<boolean> {
if (!this.#isInitialized) { if (!this.#isInitialized) {
return true; return true;
@ -160,7 +175,14 @@ export class DatabaseManager extends DatabaseDemuxBase {
const dir = path.parse(src).dir; const dir = path.parse(src).dir;
const dest = path.join(dir, '__premigratory_temp.db'); const dest = path.join(dir, '__premigratory_temp.db');
await fs.copyFile(src, dest);
try {
await fs.copyFile(src, dest);
} catch (err) {
emitMainProcessError(err);
return null;
}
return dest; return dest;
} }
} }

View File

@ -1,4 +1,7 @@
import { constants } from 'fs';
import fs from 'fs/promises';
import { DatabaseMethod } from 'utils/db/types'; import { DatabaseMethod } from 'utils/db/types';
import { CUSTOM_EVENTS } from 'utils/messages';
import { KnexColumnType } from './database/types'; import { KnexColumnType } from './database/types';
export const sqliteTypeMap: Record<string, KnexColumnType> = { export const sqliteTypeMap: Record<string, KnexColumnType> = {
@ -47,3 +50,29 @@ export const databaseMethodSet: Set<DatabaseMethod> = new Set([
'close', 'close',
'exists', 'exists',
]); ]);
export function emitMainProcessError(error: unknown) {
(process.emit as Function)(CUSTOM_EVENTS.MAIN_PROCESS_ERROR, error);
}
export async function checkFileAccess(filePath: string, mode?: number) {
mode ??= constants.W_OK;
return await fs
.access(filePath, mode)
.then(() => true)
.catch(() => false);
}
export async function unlinkIfExists(filePath: unknown) {
if (!filePath || typeof filePath !== 'string') {
return false;
}
const exists = await checkFileAccess(filePath);
if (exists) {
await fs.unlink(filePath);
return true;
}
return false;
}

View File

@ -13,7 +13,7 @@ export default function registerAutoUpdaterListeners(main: Main) {
return; return;
} }
main.mainWindow!.webContents.send(IPC_CHANNELS.MAIN_PROCESS_ERROR, error); main.mainWindow!.webContents.send(IPC_CHANNELS.LOG_MAIN_PROCESS_ERROR, error);
dialog.showErrorBox( dialog.showErrorBox(
'Update Error: ', 'Update Error: ',
error == null ? 'unknown' : (error.stack || error).toString() error == null ? 'unknown' : (error.stack || error).toString()

View File

@ -1,5 +1,5 @@
import { app } from 'electron'; import { app } from 'electron';
import { IPC_CHANNELS } from 'utils/messages'; import { CUSTOM_EVENTS, IPC_CHANNELS } from 'utils/messages';
import { Main } from '../main'; import { Main } from '../main';
export default function registerProcessListeners(main: Main) { export default function registerProcessListeners(main: Main) {
@ -17,12 +17,25 @@ export default function registerProcessListeners(main: Main) {
} }
} }
process.on(CUSTOM_EVENTS.MAIN_PROCESS_ERROR, (error) => {
main.mainWindow!.webContents.send(
IPC_CHANNELS.LOG_MAIN_PROCESS_ERROR,
error
);
});
process.on('unhandledRejection', (error) => { process.on('unhandledRejection', (error) => {
main.mainWindow!.webContents.send(IPC_CHANNELS.MAIN_PROCESS_ERROR, error); main.mainWindow!.webContents.send(
IPC_CHANNELS.LOG_MAIN_PROCESS_ERROR,
error
);
}); });
process.on('uncaughtException', (error) => { process.on('uncaughtException', (error) => {
main.mainWindow!.webContents.send(IPC_CHANNELS.MAIN_PROCESS_ERROR, error); main.mainWindow!.webContents.send(
IPC_CHANNELS.LOG_MAIN_PROCESS_ERROR,
error
);
setTimeout(() => process.exit(1), 10000); setTimeout(() => process.exit(1), 10000);
}); });
} }

View File

@ -57,7 +57,11 @@ export function getErrorLogObject(
error: Error, error: Error,
more: Record<string, unknown> more: Record<string, unknown>
): ErrorLog { ): ErrorLog {
const { name, stack, message } = error; const { name, stack, message, cause } = error;
if (cause) {
more.cause = cause;
}
const errorLogObj = { name, stack, message, more }; const errorLogObj = { name, stack, message, more };
fyo.errorLog.push(errorLogObj); fyo.errorLog.push(errorLogObj);

View File

@ -4,7 +4,7 @@ import { fyo } from 'src/initFyo';
import { IPC_CHANNELS } from 'utils/messages'; import { IPC_CHANNELS } from 'utils/messages';
export default function registerIpcRendererListeners() { export default function registerIpcRendererListeners() {
ipcRenderer.on(IPC_CHANNELS.MAIN_PROCESS_ERROR, async (_, error) => { ipcRenderer.on(IPC_CHANNELS.LOG_MAIN_PROCESS_ERROR, async (_, error) => {
if (fyo.store.isDevelopment) { if (fyo.store.isDevelopment) {
console.error(error); console.error(error);
} }

View File

@ -33,7 +33,7 @@ export enum IPC_ACTIONS {
// ipcMain.send(...) // ipcMain.send(...)
export enum IPC_CHANNELS { export enum IPC_CHANNELS {
MAIN_PROCESS_ERROR = 'main-process-error', LOG_MAIN_PROCESS_ERROR = 'main-process-error',
CONSOLE_LOG = 'console-log', CONSOLE_LOG = 'console-log',
} }
@ -42,3 +42,8 @@ export enum DB_CONN_FAILURE {
CANT_OPEN = 'cant-open', CANT_OPEN = 'cant-open',
CANT_CONNECT = 'cant-connect', CANT_CONNECT = 'cant-connect',
} }
// events
export enum CUSTOM_EVENTS {
MAIN_PROCESS_ERROR = 'main-process-error',
}