diff --git a/electron/build-backend.js b/electron/build-backend.js new file mode 100644 index 0000000..3711021 --- /dev/null +++ b/electron/build-backend.js @@ -0,0 +1,91 @@ +#!/usr/bin/env node + +/** + * Build script to ensure PyInstaller backend is built before Electron packaging + * This script is called by electron-builder before packaging + */ + +const { spawn } = require('child_process'); +const path = require('path'); +const fs = require('fs'); + +function runCommand(command, args, cwd) { + return new Promise((resolve, reject) => { + console.log(`Running: ${command} ${args.join(' ')} in ${cwd}`); + const process = spawn(command, args, { + cwd, + stdio: 'inherit', + shell: true + }); + + process.on('close', (code) => { + if (code === 0) { + resolve(); + } else { + reject(new Error(`Command failed with exit code ${code}`)); + } + }); + + process.on('error', (err) => { + reject(err); + }); + }); +} + +async function buildBackend() { + const projectRoot = path.resolve(__dirname, '..'); + const buildDir = path.join(projectRoot, 'build'); + const backendDistPath = path.join(buildDir, 'electron', 'dist', 'fourdst-backend'); + + console.log('Building PyInstaller backend...'); + console.log(`Project root: ${projectRoot}`); + console.log(`Build directory: ${buildDir}`); + console.log(`Target platform: ${process.platform}`); + + try { + // Check if meson build directory exists + if (!fs.existsSync(buildDir)) { + console.log('Meson build directory not found. Setting up build...'); + await runCommand('meson', ['setup', 'build', '--buildtype=release', '-Dbuild-py-backend=true'], projectRoot); + } else { + // Ensure py-backend option is enabled + console.log('Reconfiguring meson build with py-backend enabled...'); + await runCommand('meson', ['configure', 'build', '-Dbuild-py-backend=true'], projectRoot); + } + + // Build the backend using meson + console.log('Building backend with meson...'); + await runCommand('meson', ['compile', '-C', 'build'], projectRoot); + + // Verify the backend executable was created + const executableName = process.platform === 'win32' ? 'fourdst-backend.exe' : 'fourdst-backend'; + const backendExecutable = path.join(backendDistPath, executableName); + + if (fs.existsSync(backendExecutable)) { + console.log(`✅ Backend executable built successfully: ${backendExecutable}`); + + // Make executable on Unix systems + if (process.platform !== 'win32') { + const { execSync } = require('child_process'); + execSync(`chmod +x "${backendExecutable}"`); + console.log('✅ Backend executable permissions set'); + } + } else { + throw new Error(`Backend executable not found at: ${backendExecutable}`); + } + + } catch (error) { + console.error('❌ Failed to build backend:', error.message); + process.exit(1); + } +} + +// Run the build if this script is called directly +if (require.main === module) { + buildBackend().catch(error => { + console.error('Build failed:', error); + process.exit(1); + }); +} + +module.exports = { buildBackend }; diff --git a/electron/fourdst-backend.spec b/electron/fourdst-backend.spec index 60ea4b3..9a43bee 100644 --- a/electron/fourdst-backend.spec +++ b/electron/fourdst-backend.spec @@ -1,6 +1,7 @@ # -*- mode: python ; coding: utf-8 -*- import sys +import os from pathlib import Path # This is a PyInstaller spec file. It is used to bundle the Python backend @@ -14,6 +15,15 @@ project_root = Path(SPECPATH).parent # We need to add the project root to the path so that PyInstaller can find the 'fourdst' module. sys.path.insert(0, str(project_root)) +# Platform-specific configurations +platform = sys.platform +print(f"Building for platform: {platform}") + +# Determine executable name based on platform +exe_name = 'fourdst-backend' +if platform == 'win32': + exe_name += '.exe' + # The main script to be bundled. analysis = Analysis(['bridge.py'], pathex=[str(project_root)], @@ -35,7 +45,7 @@ exe = EXE(pyz, analysis.scripts, [], exclude_binaries=True, - name='fourdst-backend', + name=exe_name, debug=False, bootloader_ignore_signals=False, strip=False, diff --git a/electron/main/app-lifecycle.js b/electron/main/app-lifecycle.js index 6098e08..51605c7 100644 --- a/electron/main/app-lifecycle.js +++ b/electron/main/app-lifecycle.js @@ -2,8 +2,13 @@ const { app, BrowserWindow, ipcMain, nativeTheme } = require('electron'); const path = require('path'); // Handle creating/removing shortcuts on Windows when installing/uninstalling. -if (require('electron-squirrel-startup')) { - app.quit(); +try { + if (require('electron-squirrel-startup')) { + app.quit(); + } +} catch (error) { + // electron-squirrel-startup is not available or not needed on this platform + console.log('electron-squirrel-startup not available, continuing...'); } let mainWindow; diff --git a/electron/main/backend-bridge.js b/electron/main/backend-bridge.js index 4954cf0..e3de303 100644 --- a/electron/main/backend-bridge.js +++ b/electron/main/backend-bridge.js @@ -6,10 +6,16 @@ const { spawn } = require('child_process'); function runPythonCommand(command, kwargs, event) { const buildDir = path.resolve(__dirname, '..', '..', 'build'); let backendPath; + + // Determine executable name based on platform + const executableName = process.platform === 'win32' ? 'fourdst-backend.exe' : 'fourdst-backend'; + if (app.isPackaged) { - backendPath = path.join(process.resourcesPath, 'fourdst-backend'); + // In packaged app, backend is in resources/backend/ directory + backendPath = path.join(process.resourcesPath, 'backend', executableName); } else { - backendPath = path.join(buildDir, 'electron', 'dist', 'fourdst-backend', 'fourdst-backend'); + // In development, use the meson build output + backendPath = path.join(buildDir, 'electron', 'dist', 'fourdst-backend', executableName); } console.log(`[MAIN_PROCESS] Spawning backend: ${backendPath}`); diff --git a/electron/package-lock.json b/electron/package-lock.json index f9ee86d..729335c 100644 --- a/electron/package-lock.json +++ b/electron/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "@electron/remote": "^2.0.0", "adm-zip": "^0.5.14", + "electron-squirrel-startup": "^1.0.1", "fs-extra": "^11.0.0", "js-yaml": "^4.1.0", "plotly.js-dist": "^2.26.0", @@ -19,8 +20,7 @@ "devDependencies": { "adm-zip": "^0.5.14", "electron": "^31.0.2", - "electron-builder": "^24.0.0", - "electron-squirrel-startup": "^1.0.1" + "electron-builder": "^24.0.0" } }, "node_modules/@develar/schema-utils": { @@ -1800,7 +1800,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/electron-squirrel-startup/-/electron-squirrel-startup-1.0.1.tgz", "integrity": "sha512-sTfFIHGku+7PsHLJ7v0dRcZNkALrV+YEozINTW8X1nM//e5O3L+rfYuvSW00lmGHnYmUjARZulD8F2V8ISI9RA==", - "dev": true, "license": "Apache-2.0", "dependencies": { "debug": "^2.2.0" @@ -1810,7 +1809,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "2.0.0" @@ -1820,7 +1818,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, "license": "MIT" }, "node_modules/emoji-regex": { diff --git a/electron/package.json b/electron/package.json index 6102616..29191f7 100644 --- a/electron/package.json +++ b/electron/package.json @@ -6,7 +6,9 @@ "scripts": { "start": "electron .", "dev": "electron .", + "prebuild": "node build-backend.js", "build": "electron-builder", + "prepack": "node build-backend.js", "pack": "electron-builder --dir" }, "repository": { @@ -23,8 +25,7 @@ "devDependencies": { "electron": "^31.0.2", "adm-zip": "^0.5.14", - "electron-builder": "^24.0.0", - "electron-squirrel-startup": "^1.0.1" + "electron-builder": "^24.0.0" }, "dependencies": { "fs-extra": "^11.0.0", @@ -32,7 +33,8 @@ "adm-zip": "^0.5.14", "@electron/remote": "^2.0.0", "python-shell": "^5.0.0", - "plotly.js-dist": "^2.26.0" + "plotly.js-dist": "^2.26.0", + "electron-squirrel-startup": "^1.0.1" }, "build": { "appId": "com.fourdst.bundlemanager", @@ -40,6 +42,20 @@ "directories": { "output": "dist" }, + "icon": "toolkitIcon.png", + "files": [ + "**/*", + "node_modules/**/*", + "!node_modules/electron/**/*", + "!node_modules/electron-builder/**/*" + ], + "extraResources": [ + { + "from": "../build/electron/dist/fourdst-backend/", + "to": "backend/", + "filter": ["**/*"] + } + ], "mac": { "category": "public.app-category.developer-tools", "target": [ diff --git a/electron/styles.css b/electron/styles.css index 37ce023..6f7e17a 100644 --- a/electron/styles.css +++ b/electron/styles.css @@ -504,7 +504,7 @@ body.dark-mode .info-button:hover { flex-direction: column; overflow: hidden; min-width: 0; - padding: 20px; + padding: 0; } #welcome-screen {