package main import ( "flag" "fmt" "os" "strings" "time" ) func main() { // Define flags for all configurable parameters. name := flag.String("name", "", "Application name (e.g. 'Spitfire Installer')") version := flag.String("version", "", "Application version (e.g. '2025.02.11.0'). If empty, current date will be used") company := flag.String("company", "", "Company name") description := flag.String("description", "", "File description") internalName := flag.String("internalName", "", "Internal name for the application (default: same as name)") officialURL := flag.String("official", "", "Official website URL") devURL := flag.String("dev", "", "Source/Development website URL") requireAdmin := flag.Bool("requireAdmin", false, "Set to true if the application requires administrator privileges") flag.Parse() // Validate required parameters. if *name == "" || *company == "" || *description == "" || *officialURL == "" || *devURL == "" { fmt.Println("Error: --name, --company, --description, --official, and --dev are required") flag.Usage() os.Exit(1) } // Use name as default for internalName if not provided. if *internalName == "" { *internalName = *name } // Use current date as version if not provided. if *version == "" { now := time.Now().Format("2006.01.02") *version = now + ".0" } // --- Generate app.manifest --- level := "asInvoker" if *requireAdmin { level = "requireAdministrator" } manifestContent := fmt.Sprintf(` `, level) if err := os.WriteFile("app.manifest", []byte(manifestContent), 0644); err != nil { fmt.Println("Error writing app.manifest:", err) os.Exit(1) } // --- Generate app.rc (Resource Script) --- // Convert version string "YYYY.MM.DD.0" into numeric version parts. parts := strings.Split(*version, ".") if len(parts) < 4 { fmt.Println("Version must have at least 4 parts separated by '.'") os.Exit(1) } // Remove leading zeros. v1 := strings.TrimLeft(parts[0], "0") if v1 == "" { v1 = "0" } v2 := strings.TrimLeft(parts[1], "0") if v2 == "" { v2 = "0" } v3 := strings.TrimLeft(parts[2], "0") if v3 == "" { v3 = "0" } v4 := strings.TrimLeft(parts[3], "0") if v4 == "" { v4 = "0" } fileVersion := fmt.Sprintf("%s,%s,%s,%s", v1, v2, v3, v4) // Generate the resource script. // Note: The manifest is embedded here under resource ID 1 (type 24), but after running, it's enforced by mt.exe. // I'm not sure if I should remove mt.exe enforcement or remove it here. rcContent := fmt.Sprintf(`1 VERSIONINFO FILEVERSION %s PRODUCTVERSION %s FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x40004L FILETYPE 0x1L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904E4" BEGIN VALUE "CompanyName", "%s\0" VALUE "FileDescription", "%s\0" VALUE "FileVersion", "%s\0" VALUE "InternalName", "%s\0" VALUE "OriginalFilename", "%s.exe\0" VALUE "ProductName", "%s\0" VALUE "ProductVersion", "%s\0" VALUE "Comments", "Official website: %s; Source/Dev website: %s\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x0409, 1252 END END 1 24 "app.manifest" `, fileVersion, fileVersion, *company, *description, *version, *internalName, *internalName, *name, *version, *officialURL, *devURL) if err := os.WriteFile("app.rc", []byte(rcContent), 0644); err != nil { fmt.Println("Error writing app.rc:", err) os.Exit(1) } fmt.Printf("Generated app.manifest and app.rc with version: %s\n", *version) }