All checks were successful
farmcontrol/farmcontrol-server/pipeline/head This commit looks good
- Added a new script to embed icons into Windows executables, improving visual consistency across application binaries. - Updated the NSIS installer script to conditionally embed an icon if provided, enhancing flexibility in icon management. - Refactored the Windows app binary preparation process to utilize the new icon embedding functionality, ensuring icons are correctly applied to the launcher and runtime executables.
125 lines
3.8 KiB
JavaScript
125 lines
3.8 KiB
JavaScript
import {
|
|
cpSync,
|
|
existsSync,
|
|
readFileSync,
|
|
renameSync,
|
|
rmSync,
|
|
writeFileSync,
|
|
} from "node:fs";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import {
|
|
DEFAULT_WINDOWS_ICON,
|
|
embedWindowsAppIcons,
|
|
} from "./embed-windows-exe-icon.mjs";
|
|
|
|
const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
|
|
/** User-facing Windows app entry point (Electrobun launcher). */
|
|
export const WINDOWS_APP_EXECUTABLE = "farmcontrol-server.exe";
|
|
|
|
/**
|
|
* Bun runtime filename embedded in the Electrobun launcher binary.
|
|
* Must stay exactly 7 characters (same length as "bun.exe") for binary patching.
|
|
*/
|
|
export const WINDOWS_RUNTIME_EXECUTABLE = "farm.exe";
|
|
|
|
const LAUNCHER_BINARY = "launcher.exe";
|
|
const LEGACY_RUNTIME_BINARY = "bun.exe";
|
|
const LAUNCHER_RUNTIME_REFERENCE = Buffer.from(`${LEGACY_RUNTIME_BINARY}\0`);
|
|
const PATCHED_RUNTIME_REFERENCE = Buffer.from(`${WINDOWS_RUNTIME_EXECUTABLE}\0`);
|
|
|
|
function patchLauncherRuntimeReference(launcherPath) {
|
|
const binary = readFileSync(launcherPath);
|
|
const index = binary.indexOf(LAUNCHER_RUNTIME_REFERENCE);
|
|
if (index === -1) {
|
|
if (binary.includes(PATCHED_RUNTIME_REFERENCE)) {
|
|
return;
|
|
}
|
|
|
|
throw new Error(
|
|
`prepare-windows-app-binaries: could not find ${LEGACY_RUNTIME_BINARY} reference in ${launcherPath}`,
|
|
);
|
|
}
|
|
|
|
PATCHED_RUNTIME_REFERENCE.copy(binary, index);
|
|
writeFileSync(launcherPath, binary);
|
|
console.log(
|
|
`prepare-windows-app-binaries: patched ${path.basename(launcherPath)} to spawn ${WINDOWS_RUNTIME_EXECUTABLE}`,
|
|
);
|
|
}
|
|
|
|
function renameWindowsRuntime(binDir) {
|
|
const legacyRuntimePath = path.join(binDir, LEGACY_RUNTIME_BINARY);
|
|
const runtimePath = path.join(binDir, WINDOWS_RUNTIME_EXECUTABLE);
|
|
|
|
if (existsSync(runtimePath)) {
|
|
return runtimePath;
|
|
}
|
|
|
|
if (!existsSync(legacyRuntimePath)) {
|
|
throw new Error(
|
|
`prepare-windows-app-binaries: neither ${LEGACY_RUNTIME_BINARY} nor ${WINDOWS_RUNTIME_EXECUTABLE} found in ${binDir}`,
|
|
);
|
|
}
|
|
|
|
renameSync(legacyRuntimePath, runtimePath);
|
|
console.log(
|
|
`prepare-windows-app-binaries: renamed ${LEGACY_RUNTIME_BINARY} -> ${WINDOWS_RUNTIME_EXECUTABLE}`,
|
|
);
|
|
return runtimePath;
|
|
}
|
|
|
|
function createBrandedAppExecutable(binDir) {
|
|
const launcherPath = path.join(binDir, LAUNCHER_BINARY);
|
|
const appExecutablePath = path.join(binDir, WINDOWS_APP_EXECUTABLE);
|
|
|
|
if (!existsSync(launcherPath)) {
|
|
if (existsSync(appExecutablePath)) {
|
|
patchLauncherRuntimeReference(appExecutablePath);
|
|
return appExecutablePath;
|
|
}
|
|
|
|
throw new Error(
|
|
`prepare-windows-app-binaries: ${LAUNCHER_BINARY} not found in ${binDir}`,
|
|
);
|
|
}
|
|
|
|
patchLauncherRuntimeReference(launcherPath);
|
|
cpSync(launcherPath, appExecutablePath);
|
|
rmSync(launcherPath, { force: true });
|
|
console.log(
|
|
`prepare-windows-app-binaries: created ${WINDOWS_APP_EXECUTABLE} and removed ${LAUNCHER_BINARY}`,
|
|
);
|
|
return appExecutablePath;
|
|
}
|
|
|
|
/**
|
|
* Brand Windows app binaries and embed icons per Electrobun application-icons docs:
|
|
* launcher executable, Bun runtime executable, then NSIS installer (separately).
|
|
*/
|
|
export async function prepareWindowsAppBinaries(appDir) {
|
|
if (process.platform !== "win32") {
|
|
console.log("prepare-windows-app-binaries: skipped (not Windows)");
|
|
return;
|
|
}
|
|
|
|
const binDir = path.join(appDir, "bin");
|
|
if (!existsSync(binDir)) {
|
|
throw new Error(`prepare-windows-app-binaries: bin directory not found: ${binDir}`);
|
|
}
|
|
|
|
const launcherPath = path.join(binDir, LAUNCHER_BINARY);
|
|
if (existsSync(launcherPath)) {
|
|
await embedWindowsAppIcons([launcherPath], { icon: DEFAULT_WINDOWS_ICON });
|
|
}
|
|
|
|
const runtimePath = renameWindowsRuntime(binDir);
|
|
const appExecutablePath = createBrandedAppExecutable(binDir);
|
|
|
|
await embedWindowsAppIcons([appExecutablePath, runtimePath], {
|
|
icon: DEFAULT_WINDOWS_ICON,
|
|
cleanupTemp: true,
|
|
});
|
|
}
|