package main import ( "fmt" "io" "io/fs" "os" "os/exec" "path/filepath" "strings" ) // installPrefix is the base install directory. // Binaries go to installPrefix/bin, assets and config go to installPrefix/. const installPrefix = "/opt/weatherstation" func main() { // Ensure target directories exist binDir := filepath.Join(installPrefix, "bin") if err := os.MkdirAll(binDir, 0o755); err != nil { fatalf("创建目录失败: %s: %v", binDir, err) } // Build all service-* under cmd/ serviceDirs, err := findServiceDirs() if err != nil { fatalf("扫描服务目录失败: %v", err) } if len(serviceDirs) == 0 { fatalf("未发现任何 service-* 微服务目录") } for _, svc := range serviceDirs { out := filepath.Join(binDir, svc) pkg := filepath.ToSlash(filepath.Join("./cmd", svc)) fmt.Printf("编译 %s -> %s\n", pkg, out) if err := run("go", "build", "-o", out, pkg); err != nil { fatalf("编译失败 %s: %v", pkg, err) } } // Copy templates, static, config.yaml to installPrefix // Replace existing files/directories if err := copyDirReplacing("templates", filepath.Join(installPrefix, "templates")); err != nil { fatalf("复制 templates 失败: %v", err) } if err := copyDirReplacing("static", filepath.Join(installPrefix, "static")); err != nil { fatalf("复制 static 失败: %v", err) } if err := copyFileReplacing("config.yaml", filepath.Join(installPrefix, "config.yaml"), 0o644); err != nil { // 配置文件可能不存在于仓库,但按照需求尝试复制,若不存在给出提示 if !os.IsNotExist(err) { fatalf("复制 config.yaml 失败: %v", err) } else { fmt.Println("提示: 仓库根目录未找到 config.yaml,跳过复制") } } fmt.Printf("完成: 微服务安装于 %s,资源已同步到 %s\n", binDir, installPrefix) } func fatalf(format string, a ...any) { fmt.Fprintf(os.Stderr, format+"\n", a...) os.Exit(1) } // findServiceDirs returns names like service-api, service-udp under cmd/. func findServiceDirs() ([]string, error) { entries, err := os.ReadDir("cmd") if err != nil { return nil, err } var list []string for _, e := range entries { if !e.IsDir() { continue } name := e.Name() if strings.HasPrefix(name, "service-") { // ensure main.go exists to be buildable if _, err := os.Stat(filepath.Join("cmd", name, "main.go")); err == nil { list = append(list, name) } } } return list, nil } func run(name string, args ...string) error { cmd := exec.Command(name, args...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr return cmd.Run() } func copyDirReplacing(src, dst string) error { st, err := os.Stat(src) if err != nil { return err } if !st.IsDir() { return fmt.Errorf("%s 不是目录", src) } // Remove destination to ensure clean replace if err := os.RemoveAll(dst); err != nil { return err } if err := os.MkdirAll(dst, 0o755); err != nil { return err } return filepath.WalkDir(src, func(path string, d fs.DirEntry, err error) error { if err != nil { return err } rel, err := filepath.Rel(src, path) if err != nil { return err } target := filepath.Join(dst, rel) if d.IsDir() { if rel == "." { return nil } return os.MkdirAll(target, 0o755) } return copyFileReplacing(path, target, 0o644) }) } func copyFileReplacing(src, dst string, perm os.FileMode) 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.OpenFile(dst, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, perm) if err != nil { return err } defer func() { _ = out.Close() }() if _, err := io.Copy(out, in); err != nil { return err } return out.Sync() }