Release 2.7.2.4: macOS app icon, glaze UI and auto build numbers.
Add green N AppIcon to the .app bundle, keep WKWebView GUI stable, and stamp builds via BaseVersion/BuildNumber. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+60
-7
@@ -19,20 +19,33 @@ import (
|
||||
func main() {
|
||||
bin := flag.String("bin", "", "path to darwin Navis binary")
|
||||
outDir := flag.String("out", "", "output directory (e.g. dist/navis-release/darwin-arm64)")
|
||||
version := flag.String("version", "1.4.1", "CFBundleShortVersionString")
|
||||
version := flag.String("version", "1.4.1", "CFBundleShortVersionString (e.g. 2.7.2.3)")
|
||||
build := flag.String("build", "", "CFBundleVersion build number (default: last segment of -version)")
|
||||
arch := flag.String("arch", "arm64", "arch label for volume name")
|
||||
flag.Parse()
|
||||
if *bin == "" || *outDir == "" {
|
||||
fmt.Fprintln(os.Stderr, "usage: packmac -bin <Navis> -out <dir> [-version 1.4.1] [-arch arm64]")
|
||||
fmt.Fprintln(os.Stderr, "usage: packmac -bin <Navis> -out <dir> [-version 2.7.2.3] [-build 3] [-arch arm64]")
|
||||
os.Exit(2)
|
||||
}
|
||||
if err := run(*bin, *outDir, *version, *arch); err != nil {
|
||||
buildNo := *build
|
||||
if buildNo == "" {
|
||||
buildNo = lastVersionSegment(*version)
|
||||
}
|
||||
if err := run(*bin, *outDir, *version, buildNo, *arch); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "packmac: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func run(binPath, outDir, version, arch string) error {
|
||||
func lastVersionSegment(v string) string {
|
||||
v = strings.TrimSpace(v)
|
||||
if i := strings.LastIndex(v, "."); i >= 0 && i+1 < len(v) {
|
||||
return v[i+1:]
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func run(binPath, outDir, version, buildNo, arch string) error {
|
||||
if err := os.MkdirAll(outDir, 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -43,7 +56,7 @@ func run(binPath, outDir, version, arch string) error {
|
||||
defer os.RemoveAll(stage)
|
||||
|
||||
appRoot := filepath.Join(stage, "Navis.app")
|
||||
if err := writeAppBundle(appRoot, binPath, version, arch); err != nil {
|
||||
if err := writeAppBundle(appRoot, binPath, version, buildNo, arch); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := signAppBundle(appRoot); err != nil {
|
||||
@@ -123,11 +136,15 @@ func writeHdiutilDMG(dmgPath, stageDir, volume string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeAppBundle(appRoot, binPath, version, arch string) error {
|
||||
func writeAppBundle(appRoot, binPath, version, buildNo, arch string) error {
|
||||
macOSDir := filepath.Join(appRoot, "Contents", "MacOS")
|
||||
resDir := filepath.Join(appRoot, "Contents", "Resources")
|
||||
if err := os.MkdirAll(macOSDir, 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.MkdirAll(resDir, 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
archPriority := architecturePriorityXML(arch)
|
||||
plist := fmt.Sprintf(`<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
@@ -137,6 +154,7 @@ func writeAppBundle(appRoot, binPath, version, arch string) error {
|
||||
<key>CFBundleIdentifier</key><string>win.evilfox.navis</string>
|
||||
<key>CFBundleName</key><string>Navis</string>
|
||||
<key>CFBundleDisplayName</key><string>Navis</string>
|
||||
<key>CFBundleIconFile</key><string>AppIcon</string>
|
||||
<key>CFBundlePackageType</key><string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key><string>%s</string>
|
||||
<key>CFBundleVersion</key><string>%s</string>
|
||||
@@ -145,20 +163,55 @@ func writeAppBundle(appRoot, binPath, version, arch string) error {
|
||||
<key>CFBundleInfoDictionaryVersion</key><string>6.0</string>%s
|
||||
</dict>
|
||||
</plist>
|
||||
`, version, version, archPriority)
|
||||
`, version, buildNo, archPriority)
|
||||
if err := os.WriteFile(filepath.Join(appRoot, "Contents", "Info.plist"), []byte(plist), 0o644); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(appRoot, "Contents", "PkgInfo"), []byte("APPL????"), 0o644); err != nil {
|
||||
return err
|
||||
}
|
||||
if icns := findAsset("navis.icns"); icns != "" {
|
||||
if err := copyFile(icns, filepath.Join(resDir, "AppIcon.icns"), 0o644); err != nil {
|
||||
return fmt.Errorf("app icon: %w", err)
|
||||
}
|
||||
}
|
||||
dest := filepath.Join(macOSDir, "Navis")
|
||||
if err := copyFile(binPath, dest, 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
// Embed human-readable version next to the binary inside the .app
|
||||
_ = os.WriteFile(filepath.Join(macOSDir, "VERSION"), []byte(version+"\n"), 0o644)
|
||||
return nil
|
||||
}
|
||||
|
||||
// findAsset locates a file under assets/ relative to cwd or the packmac binary.
|
||||
func findAsset(name string) string {
|
||||
candidates := []string{
|
||||
filepath.Join("assets", name),
|
||||
}
|
||||
if exe, err := os.Executable(); err == nil {
|
||||
dir := filepath.Dir(exe)
|
||||
candidates = append(candidates,
|
||||
filepath.Join(dir, "..", "..", "assets", name),
|
||||
filepath.Join(dir, "..", "assets", name),
|
||||
filepath.Join(dir, "assets", name),
|
||||
)
|
||||
}
|
||||
if wd, err := os.Getwd(); err == nil {
|
||||
candidates = append(candidates, filepath.Join(wd, "assets", name))
|
||||
}
|
||||
for _, c := range candidates {
|
||||
if st, err := os.Stat(c); err == nil && !st.IsDir() {
|
||||
abs, err := filepath.Abs(c)
|
||||
if err == nil {
|
||||
return abs
|
||||
}
|
||||
return c
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func signAppBundle(appRoot string) error {
|
||||
if _, err := exec.LookPath("codesign"); err != nil {
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user