Files
XingfenD 321d78a017 refactor: switch config format from YAML to TOML
- Replace gopkg.in/yaml.v3 with github.com/BurntSushi/toml
- Update struct tags from yaml to toml
- Update config tests to use TOML syntax
- Add testdata/config.toml, update Helm configmap template
2026-08-10 17:19:09 +08:00

120 lines
2.6 KiB
Go

package config
import (
"fmt"
"os"
"regexp"
"strings"
"github.com/BurntSushi/toml"
)
type Config struct {
Server ServerConfig `toml:"server"`
Git GitConfig `toml:"git"`
Cluster ClusterConfig `toml:"cluster"`
ToolchainRegistry string `toml:"toolchain_registry"`
TargetRepoTemplate string `toml:"target_repo_template"`
Plugins []PluginConfig `toml:"plugins"`
}
type ServerConfig struct {
Addr string `toml:"addr"`
PublicURL string `toml:"public_url"`
}
type GitConfig struct {
Type string `toml:"type"`
BaseURL string `toml:"base_url"`
Token string `toml:"token"`
}
type ClusterConfig struct {
Kubeconfig string `toml:"kubeconfig"`
Namespace string `toml:"namespace"`
JobTimeout int `toml:"job_timeout"`
MaxConcurrent int `toml:"max_concurrent"`
}
type PluginConfig struct {
Language string `toml:"language"`
Image string `toml:"image"`
}
var envVarRegex = regexp.MustCompile(`\$\{(\w+)\}`)
func Load(path string) (*Config, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("reading config file: %w", err)
}
expanded := expandEnvVars(string(data))
var cfg Config
if _, err := toml.Decode(expanded, &cfg); err != nil {
return nil, fmt.Errorf("parsing config: %w", err)
}
if err := cfg.validate(); err != nil {
return nil, err
}
return &cfg, nil
}
func expandEnvVars(s string) string {
return envVarRegex.ReplaceAllStringFunc(s, func(match string) string {
varName := match[2 : len(match)-1]
if val, ok := os.LookupEnv(varName); ok {
return val
}
return match
})
}
func (c *Config) validate() error {
if c.Git.Type == "" {
return fmt.Errorf("git.type is required")
}
if c.Git.BaseURL == "" {
return fmt.Errorf("git.base_url is required")
}
if c.Git.Token == "" {
return fmt.Errorf("git.token is required")
}
if c.Cluster.Namespace == "" {
return fmt.Errorf("cluster.namespace is required")
}
if c.Cluster.JobTimeout == 0 {
c.Cluster.JobTimeout = 600
}
if c.Cluster.MaxConcurrent == 0 {
c.Cluster.MaxConcurrent = 2
}
if c.Server.Addr == "" {
c.Server.Addr = ":8080"
}
if c.TargetRepoTemplate == "" {
c.TargetRepoTemplate = "{proto_repo}-gen-{lang}"
}
for i, p := range c.Plugins {
if p.Language == "" {
return fmt.Errorf("plugins[%d].language is required", i)
}
if p.Image == "" {
return fmt.Errorf("plugins[%d].image is required", i)
}
}
return nil
}
func (c *Config) GetPluginByLanguage(lang string) *PluginConfig {
for i := range c.Plugins {
if strings.EqualFold(c.Plugins[i].Language, lang) {
return &c.Plugins[i]
}
}
return nil
}