Files
VRCWT-OSC/VRWT_Tool/VRC_OSC/internal/update/manager.go
every_holiday 8bff7af6bc
All checks were successful
build-windows-exe / build (push) Successful in 1m47s
Add release auto-update launcher
2026-06-24 02:08:19 +09:00

107 lines
2.3 KiB
Go

package update
import (
"fmt"
"io"
"log"
"os"
"os/exec"
"path/filepath"
"runtime"
"vrc_osc_go/internal/buildinfo"
"vrc_osc_go/internal/common"
)
type Manager struct {
Client *Client
OwnerRepo string
AssetName string
CurrentLabel string
}
func (m *Manager) CheckAndUpdate() (bool, error) {
if m.Client == nil || m.OwnerRepo == "" || m.AssetName == "" {
return false, nil
}
latest, err := m.Client.LatestRelease(m.OwnerRepo)
if err != nil {
return false, err
}
if latest.TagName == "" || latest.TagName == m.CurrentLabel {
return false, nil
}
assetURL := ""
for _, a := range latest.Assets {
if a.Name == m.AssetName {
assetURL = a.URL
break
}
}
if assetURL == "" {
return false, fmt.Errorf("asset %q not found in release %s", m.AssetName, latest.TagName)
}
base := common.RootDir()
tmpDir := filepath.Join(base, "update", latest.TagName)
if err := os.MkdirAll(tmpDir, 0o755); err != nil {
return false, err
}
zipPath := filepath.Join(tmpDir, m.AssetName)
log.Printf("update available: %s -> %s", m.CurrentLabel, latest.TagName)
if err := m.Client.DownloadAsset(assetURL, zipPath); err != nil {
return false, err
}
if err := ExtractZip(zipPath, tmpDir); err != nil {
return false, err
}
exePath := filepath.Join(base, CurrentExeName())
newExe := filepath.Join(tmpDir, CurrentExeName())
if _, err := os.Stat(newExe); err != nil {
return false, err
}
backup := exePath + ".bak"
_ = os.Remove(backup)
if err := os.Rename(exePath, backup); err != nil {
return false, err
}
if err := CopyFile(newExe, exePath); err != nil {
_ = os.Rename(backup, exePath)
return false, err
}
_ = os.Remove(backup)
return true, nil
}
func CopyFile(src, dst string) error {
in, err := os.Open(src)
if err != nil {
return err
}
defer in.Close()
if err := os.MkdirAll(filepath.Dir(dst), 0o755); err != nil {
return err
}
out, err := os.Create(dst)
if err != nil {
return err
}
defer out.Close()
_, err = io.Copy(out, in)
return err
}
func Launch(exe string, args []string) error {
cmd := exec.Command(exe, args...)
cmd.Dir = filepath.Dir(exe)
return cmd.Start()
}
func Version() string { return buildinfo.Version }
func CurrentExeName() string {
if runtime.GOOS == "windows" {
return "vrc_osc.exe"
}
return "vrc_osc"
}