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 }