From 08355f48d778d075dc9d328cc140294ebaa4e9d2 Mon Sep 17 00:00:00 2001 From: Misakiotoha <1841738040@qq.com> Date: Sun, 21 Jun 2026 18:11:58 +0800 Subject: [PATCH] first --- .gitignore | 25 ++++++++ go.mod | 3 + main.go | 173 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 201 insertions(+) create mode 100644 .gitignore create mode 100644 go.mod create mode 100644 main.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e990f70 --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +# Python-generated files +__pycache__/ +*.py[oc] +build/ +dist/ +wheels/ +*.egg-info + +# from ide +.vscode +.idea + +# Virtual environments +.venv +venv + +# config +settings.json + +# logs +log/* + +updater.exe + + diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..2deb50b --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module Embalming_Girl_Updater + +go 1.22 diff --git a/main.go b/main.go new file mode 100644 index 0000000..5fd9dc1 --- /dev/null +++ b/main.go @@ -0,0 +1,173 @@ +package main + +import ( + "archive/zip" + "flag" + "fmt" + "io" + "os" + "os/exec" + "path/filepath" + "strings" + "time" +) + +var preservePaths = map[string]bool{ + "config/settings.json": true, + "data": true, +} + +func shouldPreserve(rel string) bool { + rel = filepath.ToSlash(rel) + for p := range preservePaths { + if rel == p || strings.HasPrefix(rel, p+"/") { + return true + } + } + return false +} + +func isProcessRunning(pid int) bool { + cmd := exec.Command("tasklist", "/FI", fmt.Sprintf("PID eq %d", pid), "/NH") + out, err := cmd.Output() + if err != nil { + return false + } + return strings.Contains(string(out), fmt.Sprintf("%d", pid)) +} + +func main() { + pid := flag.Int("pid", 0, "PID of main app to wait for") + zipPath := flag.String("zip", "", "Path to update zip") + target := flag.String("target", "", "Install directory") + launch := flag.String("launch", "", "Executable to launch after update") + flag.Parse() + + if *zipPath == "" || *target == "" { + fmt.Println("Usage: updater --pid PID --zip FILE --target DIR --launch EXE") + os.Exit(1) + } + + logsDir := filepath.Join(*target, "logs") + os.MkdirAll(logsDir, 0755) + logFile, _ := os.Create(filepath.Join(logsDir, "updater.log")) + log := func(msg string, args ...interface{}) { + line := fmt.Sprintf("[%s] %s\n", time.Now().Format("15:04:05"), fmt.Sprintf(msg, args...)) + fmt.Print(line) + if logFile != nil { + logFile.WriteString(line) + } + } + + if *pid > 0 { + log("Waiting for process %d to exit...", *pid) + for i := 0; i < 30; i++ { + if !isProcessRunning(*pid) { + log("Process exited") + break + } + time.Sleep(500 * time.Millisecond) + } + time.Sleep(500 * time.Millisecond) + } + + log("Extracting %s", *zipPath) + tmpDir := *zipPath + "_extract" + os.RemoveAll(tmpDir) + if err := extractZip(*zipPath, tmpDir); err != nil { + log("Extract failed: %v", err) + os.Exit(1) + } + + // Auto-detect nested top-level directory and strip it + entries, _ := os.ReadDir(tmpDir) + if len(entries) == 1 && entries[0].IsDir() { + nested := filepath.Join(tmpDir, entries[0].Name()) + log("Detected nested directory: %s, stripping", entries[0].Name()) + tmpDir = nested + } + + log("Installing to %s", *target) + count := 0 + skipped := 0 + err := filepath.Walk(tmpDir, func(path string, info os.FileInfo, err error) error { + if err != nil || info.IsDir() { + return err + } + rel, _ := filepath.Rel(tmpDir, path) + if shouldPreserve(rel) { + log(" Skip: %s", rel) + skipped++ + return nil + } + dst := filepath.Join(*target, rel) + os.MkdirAll(filepath.Dir(dst), 0755) + + src, err := os.Open(path) + if err != nil { + return err + } + defer src.Close() + + out, err := os.Create(dst) + if err != nil { + log(" Failed to write: %s (%v)", rel, err) + return nil + } + defer out.Close() + io.Copy(out, src) + count++ + return nil + }) + if err != nil { + log("Install error: %v", err) + } + log("Updated %d files, skipped %d", count, skipped) + + os.RemoveAll(tmpDir) + os.Remove(*zipPath) + log("Cleanup done") + + if *launch != "" { + exe := filepath.Join(*target, *launch) + log("Launching %s", exe) + cmd := exec.Command(exe) + cmd.Dir = *target + cmd.Start() + } + + log("Update complete") + if logFile != nil { + logFile.Close() + } +} + +func extractZip(src, dst string) error { + r, err := zip.OpenReader(src) + if err != nil { + return err + } + defer r.Close() + + for _, f := range r.File { + path := filepath.Join(dst, f.Name) + if f.FileInfo().IsDir() { + os.MkdirAll(path, 0755) + continue + } + os.MkdirAll(filepath.Dir(path), 0755) + rc, err := f.Open() + if err != nil { + return err + } + out, err := os.Create(path) + if err != nil { + rc.Close() + return err + } + io.Copy(out, rc) + out.Close() + rc.Close() + } + return nil +}