Files
weatherreporter/internal/config/load.go

100 lines
2.1 KiB
Go

package config
import (
"bytes"
"errors"
"fmt"
"os"
"gopkg.in/yaml.v3"
)
type LoadOptions struct {
Path string
Units string
Timezone string
}
func Load(opts LoadOptions) (Config, error) {
cfg := Defaults()
path := opts.Path
if path == "" {
path = DefaultPath
}
if err := mergeFile(&cfg, path); err != nil {
if opts.Path != "" || !errors.Is(err, os.ErrNotExist) {
return Config{}, err
}
}
if opts.Units != "" {
cfg.WeatherAPI.Units = opts.Units
}
if opts.Timezone != "" {
cfg.WeatherAPI.Timezone = opts.Timezone
}
if err := normalizeReportModules(&cfg); err != nil {
return Config{}, err
}
secrets, err := loadSecrets(cfg.Secrets)
if err != nil {
return Config{}, err
}
if err := Validate(cfg); err != nil {
return Config{}, err
}
if err := applySecrets(secrets); err != nil {
return Config{}, err
}
return cfg, nil
}
func LoadFile(path string) (Config, error) {
return Load(LoadOptions{Path: path})
}
func mergeFile(cfg *Config, path string) error {
data, err := os.ReadFile(path)
if err != nil {
return fmt.Errorf("read config %q: %w", path, err)
}
if err := rejectRetiredExecutionConfig(data); err != nil {
return fmt.Errorf("parse config %q: %w", path, err)
}
decoder := yaml.NewDecoder(bytes.NewReader(data))
decoder.KnownFields(true)
if err := decoder.Decode(cfg); err != nil {
return fmt.Errorf("parse config %q: %w", path, err)
}
if cfg.MissingSource.Sources == nil {
cfg.MissingSource.Sources = map[string]MissingSourcePolicy{}
}
if cfg.Reports == nil {
cfg.Reports = map[string]ReportConfig{}
}
return nil
}
func rejectRetiredExecutionConfig(data []byte) error {
var document yaml.Node
if err := yaml.Unmarshal(data, &document); err != nil {
return err
}
if len(document.Content) == 0 || document.Content[0].Kind != yaml.MappingNode {
return nil
}
root := document.Content[0]
for i := 0; i+1 < len(root.Content); i += 2 {
if root.Content[i].Value == "scriptorium" {
return fmt.Errorf("scriptorium configuration is no longer supported; migrate to promptkit configuration")
}
}
return nil
}