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:
parent
65a91e6f86
commit
a8e681b973
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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()
|
||||||
|
@ -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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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',
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user