farmcontrol-server/scripts/apply-windows-launcher-icon.mjs
Tom Butcher 29444e2ed4
All checks were successful
farmcontrol/farmcontrol-server/pipeline/head This commit looks good
Add rcedit dependency and implement Windows launcher icon embedding
- Added rcedit dependency in package.json and bun.lock for embedding icons in Windows executables.
- Introduced a new script to generate and apply the application icon for Windows launcher binaries, improving visual consistency.
- Updated the NSIS installer script to support dynamic icon paths, enhancing flexibility in icon management during installation.
- Integrated the icon application process into the finalization of desktop artifacts, ensuring the icon is embedded in the generated binaries.
2026-08-01 23:16:22 +01:00

84 lines
2.4 KiB
JavaScript

import { existsSync } from "node:fs";
import path from "node:path";
import { spawnSync } from "node:child_process";
import { fileURLToPath } from "node:url";
const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const WINDOWS_BIN_FILES = ["launcher.exe", "bun.exe"];
function ensureIconIco() {
const iconPath = path.join(rootDir, "assets/icon.ico");
if (existsSync(iconPath)) {
return iconPath;
}
const sources = [
path.join(rootDir, "assets/farmcontrolhosticon.png"),
path.join(rootDir, "assets/icon.png"),
];
const source = sources.find((candidate) => existsSync(candidate));
if (!source) {
throw new Error(
"apply-windows-launcher-icon: assets/icon.ico not found and no source PNG to generate it",
);
}
console.log(`apply-windows-launcher-icon: generating icon.ico from ${source}`);
const result = spawnSync(
"bun",
[path.join(rootDir, "scripts/prepare-app-icons.mjs"), source],
{ cwd: rootDir, stdio: "inherit", env: process.env },
);
if (result.status !== 0 || !existsSync(iconPath)) {
throw new Error("apply-windows-launcher-icon: failed to generate assets/icon.ico");
}
return iconPath;
}
/**
* Embed the Farm Control icon into Windows launcher binaries.
* Electrobun's built-in rcedit step often fails in CI (see electrobun#429).
*/
export async function applyWindowsLauncherIcon(appDir) {
if (process.platform !== "win32") {
console.log("apply-windows-launcher-icon: skipped (not Windows)");
return;
}
const iconPath = ensureIconIco();
const binDir = path.join(appDir, "bin");
if (!existsSync(binDir)) {
throw new Error(`apply-windows-launcher-icon: bin directory not found: ${binDir}`);
}
const rcedit = (await import("rcedit")).default;
let patched = 0;
for (const fileName of WINDOWS_BIN_FILES) {
const exePath = path.join(binDir, fileName);
if (!existsSync(exePath)) {
continue;
}
console.log(`apply-windows-launcher-icon: embedding icon into ${exePath}`);
try {
await rcedit(exePath, { icon: iconPath });
patched += 1;
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
throw new Error(
`apply-windows-launcher-icon: failed to embed icon into ${fileName}: ${message}`,
);
}
}
if (patched === 0) {
throw new Error(
`apply-windows-launcher-icon: no launcher binaries found in ${binDir}`,
);
}
}