Add rcedit dependency and implement Windows launcher icon embedding
All checks were successful
farmcontrol/farmcontrol-server/pipeline/head This commit looks good
All checks were successful
farmcontrol/farmcontrol-server/pipeline/head This commit looks good
- 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.
This commit is contained in:
parent
eb49ba7ce3
commit
29444e2ed4
1
bun.lock
1
bun.lock
@ -35,6 +35,7 @@
|
||||
"jimp": "^1.6.1",
|
||||
"png-to-ico": "^2.1.8",
|
||||
"prop-types": "^15.8.1",
|
||||
"rcedit": "^4.0.1",
|
||||
"react": "^19.2.6",
|
||||
"react-dom": "^19.2.6",
|
||||
"supertest": "^7.2.2",
|
||||
|
||||
@ -46,6 +46,7 @@
|
||||
"jest": "^30.4.2",
|
||||
"jimp": "^1.6.1",
|
||||
"png-to-ico": "^2.1.8",
|
||||
"rcedit": "^4.0.1",
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "^19.2.6",
|
||||
"react-dom": "^19.2.6",
|
||||
|
||||
@ -21,8 +21,16 @@ InstallDirRegKey HKLM "Software\Tom Butcher\Farm Control Server" "InstallDir"
|
||||
RequestExecutionLevel admin
|
||||
|
||||
!define MUI_ABORTWARNING
|
||||
!define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install.ico"
|
||||
!define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico"
|
||||
|
||||
!ifndef INSTALLER_ICON
|
||||
!define INSTALLER_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install.ico"
|
||||
!endif
|
||||
|
||||
!define MUI_ICON "${INSTALLER_ICON}"
|
||||
!define MUI_UNICON "${INSTALLER_ICON}"
|
||||
|
||||
Icon "${INSTALLER_ICON}"
|
||||
UninstallIcon "${INSTALLER_ICON}"
|
||||
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
!insertmacro MUI_PAGE_COMPONENTS
|
||||
|
||||
83
scripts/apply-windows-launcher-icon.mjs
Normal file
83
scripts/apply-windows-launcher-icon.mjs
Normal file
@ -0,0 +1,83 @@
|
||||
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}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -53,14 +53,20 @@ if (-not (Test-Path $outputDir)) {
|
||||
New-Item -ItemType Directory -Path $outputDir | Out-Null
|
||||
}
|
||||
|
||||
$iconPath = Join-Path $rootDir "assets\icon.ico"
|
||||
$makensisArgs = @(
|
||||
"/NOCD"
|
||||
"/DOUTFILE=$outputExePath"
|
||||
"/DVERSION=$Version"
|
||||
"/DAPP_SOURCE_DIR=$appDirPath"
|
||||
(Join-Path $workDir "farmcontrol-server.nsi")
|
||||
)
|
||||
|
||||
if (Test-Path $iconPath) {
|
||||
$makensisArgs += "/DINSTALLER_ICON=$iconPath"
|
||||
}
|
||||
|
||||
$makensisArgs += (Join-Path $workDir "farmcontrol-server.nsi")
|
||||
|
||||
Push-Location $workDir
|
||||
try {
|
||||
& $makensis @makensisArgs
|
||||
|
||||
@ -20,6 +20,7 @@ import {
|
||||
expandWindowsAppFromArchive,
|
||||
} from "./expand-windows-installer.mjs";
|
||||
import { codesignMacAppBundle } from "./codesign-macos-app.mjs";
|
||||
import { applyWindowsLauncherIcon } from "./apply-windows-launcher-icon.mjs";
|
||||
|
||||
const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
||||
const packageJson = JSON.parse(
|
||||
@ -577,6 +578,7 @@ async function main() {
|
||||
installerFiles.setupArchive,
|
||||
platformDir,
|
||||
);
|
||||
await applyWindowsLauncherIcon(appDir);
|
||||
|
||||
let published;
|
||||
try {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user