Release 3.8.0.2: app.zip updates, lock hygiene, secret-safe getState.

This commit is contained in:
M4
2026-07-29 22:00:39 +03:00
parent 54b5b87990
commit 6a7480dceb
31 changed files with 2058 additions and 1537 deletions
+69 -8
View File
@@ -12,21 +12,28 @@ import (
"strings"
)
// Apply downloads the new binary and schedules replacement + relaunch after exit.
// Apply downloads the new binary or .app.zip and schedules replacement + relaunch after exit.
func Apply(ctx context.Context, manifestURL string) (string, error) {
latest, _, _, exe, tmp, err := prepareDownload(ctx, manifestURL)
p, err := prepareUpdate(ctx, manifestURL)
if err != nil {
return "", err
}
_ = os.Chmod(tmp, 0o755)
dir := filepath.Dir(exe)
if p.Kind == AssetKindAppZip {
return applyAppZip(p)
}
return applyBinary(p)
}
func applyBinary(p preparedUpdate) (string, error) {
_ = os.Chmod(p.TmpPath, 0o755)
dir := filepath.Dir(p.ExePath)
scriptPath := filepath.Join(dir, "navis-update.sh")
pid := os.Getpid()
script := "#!/bin/bash\n" +
"set -e\n" +
"EXE=" + shellQuote(exe) + "\n" +
"NEW=" + shellQuote(tmp) + "\n" +
"EXE=" + shellQuote(p.ExePath) + "\n" +
"NEW=" + shellQuote(p.TmpPath) + "\n" +
"PID=" + strconv.Itoa(pid) + "\n" +
"while kill -0 \"$PID\" 2>/dev/null; do sleep 0.4; done\n" +
"sleep 0.5\n" +
@@ -43,7 +50,53 @@ func Apply(ctx context.Context, manifestURL string) (string, error) {
if err := cmd.Start(); err != nil {
return "", fmt.Errorf("start updater: %w", err)
}
return latest, nil
return p.Latest, nil
}
func applyAppZip(p preparedUpdate) (string, error) {
if p.AppRoot == "" {
return "", fmt.Errorf("update: empty app root")
}
parent := filepath.Dir(p.AppRoot)
scriptPath := filepath.Join(parent, "navis-update-app.sh")
pid := os.Getpid()
identity := strings.TrimSpace(os.Getenv("NAVIS_CODESIGN_IDENTITY"))
if identity == "" {
identity = "-"
}
script := "#!/bin/bash\n" +
"set -e\n" +
"APP=" + shellQuote(p.AppRoot) + "\n" +
"ZIP=" + shellQuote(p.TmpPath) + "\n" +
"PID=" + strconv.Itoa(pid) + "\n" +
"ID=" + shellQuote(identity) + "\n" +
"PARENT=$(dirname \"$APP\")\n" +
"while kill -0 \"$PID\" 2>/dev/null; do sleep 0.4; done\n" +
"sleep 0.5\n" +
"TMP=$(mktemp -d \"$PARENT/.navis-update-XXXXXX\")\n" +
"unzip -q \"$ZIP\" -d \"$TMP\"\n" +
"NEW=$(find \"$TMP\" -maxdepth 3 -name 'Navis.app' -type d | head -n 1)\n" +
"if [ -z \"$NEW\" ] || [ ! -d \"$NEW\" ]; then echo 'Navis.app missing in zip' >&2; exit 1; fi\n" +
"rm -rf \"$APP.bak\"\n" +
"mv \"$APP\" \"$APP.bak\"\n" +
"mv \"$NEW\" \"$APP\"\n" +
"if command -v codesign >/dev/null 2>&1; then\n" +
" codesign -s \"$ID\" --force --deep --options runtime \"$APP\" 2>/dev/null || codesign -s \"$ID\" --force --deep \"$APP\" || true\n" +
" xattr -cr \"$APP\" 2>/dev/null || true\n" +
"fi\n" +
"rm -rf \"$APP.bak\" \"$TMP\" \"$ZIP\" " + shellQuote(scriptPath) + "\n" +
"open \"$APP\"\n"
if err := os.WriteFile(scriptPath, []byte(script), 0o755); err != nil {
return "", err
}
cmd := exec.Command("/bin/bash", scriptPath)
cmd.Dir = parent
if err := cmd.Start(); err != nil {
return "", fmt.Errorf("start app updater: %w", err)
}
return p.Latest, nil
}
func shellQuote(s string) string {
@@ -58,5 +111,13 @@ func CleanupStaleDownloads() {
}
exe, _ = filepath.Abs(exe)
_ = os.Remove(exe + ".new")
_ = os.Remove(filepath.Join(filepath.Dir(exe), ".navis-update-download"))
dir := filepath.Dir(exe)
_ = os.Remove(filepath.Join(dir, ".navis-update-download"))
_ = os.Remove(filepath.Join(dir, ".navis-update-app.zip"))
if root, ok := AppBundleRoot(exe); ok {
parent := filepath.Dir(root)
_ = os.Remove(filepath.Join(parent, ".navis-update-app.zip"))
_ = os.Remove(filepath.Join(parent, "navis-update-app.sh"))
_ = os.Remove(filepath.Join(parent, "navis-update.sh"))
}
}