feat: 新增安装脚本
This commit is contained in:
parent
4f68fdc28e
commit
229bbe76e8
150
cmd/weatherstationctl/main.go
Normal file
150
cmd/weatherstationctl/main.go
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
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()
|
||||||
|
}
|
||||||
@ -90,14 +90,15 @@ func (c *Config) loadConfig() error {
|
|||||||
if exePath != "" {
|
if exePath != "" {
|
||||||
exeDir = filepath.Dir(exePath)
|
exeDir = filepath.Dir(exePath)
|
||||||
}
|
}
|
||||||
|
// 优先顺序:可执行文件所在目录,其次其父目录;然后回退到工作目录及上级,再到系统级/用户级
|
||||||
configPaths := []string{
|
configPaths := []string{
|
||||||
|
// 可执行文件所在目录优先
|
||||||
|
filepath.Join(exeDir, "config.yaml"),
|
||||||
|
filepath.Join(exeDir, "..", "config.yaml"),
|
||||||
// 工作目录及其上级
|
// 工作目录及其上级
|
||||||
"config.yaml",
|
"config.yaml",
|
||||||
"../config.yaml",
|
"../config.yaml",
|
||||||
"../../config.yaml",
|
"../../config.yaml",
|
||||||
// 可执行文件所在目录(用于 /opt/weatherstation/bin 场景)
|
|
||||||
filepath.Join(exeDir, "config.yaml"),
|
|
||||||
filepath.Join(exeDir, "..", "config.yaml"),
|
|
||||||
// 系统级与用户级
|
// 系统级与用户级
|
||||||
"/etc/weatherstation/config.yaml",
|
"/etc/weatherstation/config.yaml",
|
||||||
filepath.Join(os.Getenv("HOME"), ".weatherstation", "config.yaml"),
|
filepath.Join(os.Getenv("HOME"), ".weatherstation", "config.yaml"),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user