package config import ( "fmt" "os" "path/filepath" "strings" "github.com/spf13/viper" ) const ( BaseDir string = "/etc/sunhpc" LogDir string = "/var/log/sunhpc" TmplDir string = BaseDir + "/tmpl.d" appName string = "sunhpc" defaultDBPath string = "/var/lib/sunhpc" defaultDBName string = "sunhpc.db" ) type Config struct { DB DBConfig `yaml:"db"` Log LogConfig `yaml:"log"` Cluster ClusterConfig `yaml:"cluster"` } type DBConfig struct { Type string `yaml:"type"` Path string `yaml:"path"` // SQLite: 目录路径 Name string `yaml:"name"` // SQLite: 文件名 User string `yaml:"user"` Password string `yaml:"password"` Host string `yaml:"host"` Port int `yaml:"port"` Socket string `yaml:"socket"` Verbose bool `yaml:"verbose"` } type LogConfig struct { Level string `yaml:"level"` Format string `yaml:"format"` Output string `yaml:"output"` FilePath string `yaml:"file_path"` } type ClusterConfig struct { Name string `yaml:"name"` AdminEmail string `yaml:"admin_email"` TimeZone string `yaml:"time_zone"` NodePrefix string `yaml:"node_prefix"` } // LoadConfig loads configuration with the following precedence: // 优先级排序: // 1. 环境变量 (prefix: SUNHPC_) // 2. ~/.sunhpc.yaml // 3. ./sunhpc.yaml // 4. /etc/sunhpc/sunhpc.yaml // 5. Default values /* 示例配置文件: ```yaml db: type: sqlite name: sunhpc.db path: /var/lib/sunhpc socket: /var/lib/sunhpc/mysql/mysqld.sock user: root password: "" host: localhost ``` 环境变量配置示例: ```bash export SUNHPC_DATABASE_TYPE=mysql export SUNHPC_DATABASE_NAME=sunhpc export SUNHPC_DATABASE_USER=root export SUNHPC_DATABASE_PASSWORD=123456 export SUNHPC_DATABASE_HOST=localhost ``` */ func LoadConfig() (*Config, error) { v := viper.New() // Step 1: 设置默认值(最低优先级) v.SetDefault("db.type", "sqlite") v.SetDefault("db.name", "sunhpc.db") v.SetDefault("db.path", "/var/lib/sunhpc") v.SetDefault("db.socket", "/var/lib/sunhpc/mysql/mysqld.sock") v.SetDefault("db.user", "") v.SetDefault("db.password", "") v.SetDefault("db.host", "localhost") v.SetDefault("db.port", 3306) v.SetDefault("db.verbose", false) // Step 2: 启用环境变量(高优先级) v.SetEnvPrefix("SUNHPC") // e.g., SUNHPC_DATABASE_NAME v.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) // db.type -> SUNHPC_DB_TYPE v.AutomaticEnv() // Auto bind env vars matching config keys // Step 3: 按优先级从高到低加载配置文件 // 优先级: env > ./sunhpc.yaml > ~/.sunhpc.yaml > /etc/sunhpc/sunhpc.yaml > defaults configFiles := []string{ "./sunhpc.yaml", filepath.Join(os.Getenv("HOME"), ".sunhpc.yaml"), filepath.Join(BaseDir, "sunhpc.yaml"), } var configFile string for _, cfgFile := range configFiles { if _, err := os.Stat(cfgFile); err == nil { configFile = cfgFile break // 找到第一个就停止. } } // 如果找到配置文件,就加载它. if configFile != "" { v.SetConfigFile(configFile) if err := v.ReadInConfig(); err != nil { return nil, fmt.Errorf("加载配置文件 %s 失败: %w", configFile, err) } } // 解码到结构体 var cfg Config if err := v.Unmarshal(&cfg); err != nil { return nil, fmt.Errorf("解码配置到结构体失败: %w", err) } return &cfg, nil } // InitDirs 创建所有必需目录 func InitDirs() error { dirs := []string{ BaseDir, TmplDir, LogDir, } for _, d := range dirs { if err := os.MkdirAll(d, 0755); err != nil { return fmt.Errorf("创建目录 %s 失败: %w", d, err) } } return nil }