From 6f1fefd2600f7536124eb3ef050b2e3b925f92de Mon Sep 17 00:00:00 2001 From: Lightning Pixel Date: Thu, 19 Mar 2026 17:20:17 +0100 Subject: [PATCH] fix(setup): use requirements.txt hash trigger reinstall --- electron/main/python-setup.ts | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/electron/main/python-setup.ts b/electron/main/python-setup.ts index 8d48b89..09c0fd4 100644 --- a/electron/main/python-setup.ts +++ b/electron/main/python-setup.ts @@ -2,13 +2,29 @@ import { BrowserWindow, app } from 'electron' import { existsSync, readFileSync, writeFileSync, readdirSync } from 'fs' import { join } from 'path' import { spawn, execSync } from 'child_process' +import { createHash } from 'crypto' const SETUP_VERSION = 2 const TOTAL_PACKAGES = 20 interface SetupJson { version: number - appVersion?: string + requirementsHash?: string +} + +function getRequirementsPath(): string { + return app.isPackaged + ? join(process.resourcesPath, 'api', 'requirements.txt') + : join(app.getAppPath(), 'api', 'requirements.txt') +} + +function hashRequirements(): string { + try { + const content = readFileSync(getRequirementsPath(), 'utf-8') + return createHash('sha256').update(content).digest('hex') + } catch { + return '' + } } // ─── Public helpers ────────────────────────────────────────────────────────── @@ -19,8 +35,7 @@ export function checkSetupNeeded(userData: string): boolean { try { const data = JSON.parse(readFileSync(jsonPath, 'utf-8')) as SetupJson if (data.version < SETUP_VERSION) return true - // Re-run setup if the app was updated (new python-embed is fresh, no packages) - if (data.appVersion !== app.getVersion()) return true + if (data.requirementsHash !== hashRequirements()) return true } catch { return true } @@ -35,7 +50,7 @@ export function markSetupDone(userData: string): void { const jsonPath = join(userData, 'python_setup.json') writeFileSync( jsonPath, - JSON.stringify({ version: SETUP_VERSION, appVersion: app.getVersion() }), + JSON.stringify({ version: SETUP_VERSION, requirementsHash: hashRequirements() }), 'utf-8' ) } @@ -188,9 +203,7 @@ function createVenv(python3: string, venvDir: string, win: BrowserWindow): Promi export async function runFullSetup(win: BrowserWindow, userData: string): Promise { try { - const requirementsPath = app.isPackaged - ? join(process.resourcesPath, 'api', 'requirements.txt') - : join(app.getAppPath(), 'api', 'requirements.txt') + const requirementsPath = getRequirementsPath() if (process.platform === 'win32') { // Windows: use embedded Python bundled with the app