2025-10-14 13:26:09 +08:00

152 lines
3.8 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)
// 必须使用相对前缀 ./,否则 go 会将其当成标准库/模块路径
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()
}