Merge origin/main: Navis 2.7.2+2 with app icon and update UX.

Combine remote update check/skip flow with green N AppIcon packaging for macOS.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
M4
2026-07-29 18:08:01 +03:00
co-authored by Cursor
35 changed files with 255 additions and 264 deletions
+39 -49
View File
@@ -19,33 +19,25 @@ 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 (e.g. 2.7.2.3)")
build := flag.String("build", "", "CFBundleVersion build number (default: last segment of -version)")
version := flag.String("version", "1.4.1", "CFBundleShortVersionString")
build := flag.String("build", "", "CFBundleVersion (defaults to -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 2.7.2.3] [-build 3] [-arch arm64]")
fmt.Fprintln(os.Stderr, "usage: packmac -bin <Navis> -out <dir> [-version 2.7.2] [-build 2.7.2.1] [-arch arm64]")
os.Exit(2)
}
buildNo := *build
if buildNo == "" {
buildNo = lastVersionSegment(*version)
bundleVer := *build
if bundleVer == "" {
bundleVer = *version
}
if err := run(*bin, *outDir, *version, buildNo, *arch); err != nil {
if err := run(*bin, *outDir, *version, bundleVer, *arch); err != nil {
fmt.Fprintf(os.Stderr, "packmac: %v\n", err)
os.Exit(1)
}
}
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 {
func run(binPath, outDir, version, bundleVersion, arch string) error {
if err := os.MkdirAll(outDir, 0o755); err != nil {
return err
}
@@ -56,7 +48,7 @@ func run(binPath, outDir, version, buildNo, arch string) error {
defer os.RemoveAll(stage)
appRoot := filepath.Join(stage, "Navis.app")
if err := writeAppBundle(appRoot, binPath, version, buildNo, arch); err != nil {
if err := writeAppBundle(appRoot, binPath, version, bundleVersion, arch); err != nil {
return err
}
if err := signAppBundle(appRoot); err != nil {
@@ -136,7 +128,7 @@ func writeHdiutilDMG(dmgPath, stageDir, volume string) error {
return nil
}
func writeAppBundle(appRoot, binPath, version, buildNo, arch string) error {
func writeAppBundle(appRoot, binPath, version, bundleVersion, arch string) error {
macOSDir := filepath.Join(appRoot, "Contents", "MacOS")
resDir := filepath.Join(appRoot, "Contents", "Resources")
if err := os.MkdirAll(macOSDir, 0o755); err != nil {
@@ -163,7 +155,7 @@ func writeAppBundle(appRoot, binPath, version, buildNo, arch string) error {
<key>CFBundleInfoDictionaryVersion</key><string>6.0</string>%s
</dict>
</plist>
`, version, buildNo, archPriority)
`, version, bundleVersion, archPriority)
if err := os.WriteFile(filepath.Join(appRoot, "Contents", "Info.plist"), []byte(plist), 0o644); err != nil {
return err
}
@@ -179,39 +171,9 @@ func writeAppBundle(appRoot, binPath, version, buildNo, arch string) error {
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
@@ -432,6 +394,34 @@ func mustStat(path string) os.FileInfo {
return fi
}
// 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 copyFile(src, dst string, mode os.FileMode) error {
in, err := os.Open(src)
if err != nil {