1
0
mirror of https://github.com/siderolabs/kres.git synced 2026-02-05 09:45:35 +01:00
Files
kres/internal/config/config.go
Andrey Smirnov a1a34ff9f1 feat: update dependencies, pin actions
Pin actions to the specific hash matching a release.

Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
2025-12-01 14:12:22 +04:00

110 lines
2.2 KiB
Go

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
// Package config provides config loading and mapping.
package config
import (
"errors"
"fmt"
"io"
"os"
"path"
"reflect"
"go.yaml.in/yaml/v4"
)
// Document is a part of config.
type Document struct {
// Class name and package name, e.g. `golang.Toolchain`.
Kind string `yaml:"kind"`
// Name of particular object (if supported).
Name string `yaml:"name,omitempty"`
// Spec is loaded into the matching object.
Spec yaml.Node `yaml:"spec"`
}
// Provider resolves configuration for each object.
type Provider struct {
docs []Document
}
// NewProvider loads configuration file and parses it.
func NewProvider(path string) (*Provider, error) {
r, err := os.Open(path)
if err != nil {
if os.IsNotExist(err) {
return &Provider{}, nil
}
return nil, err
}
defer r.Close() //nolint:errcheck
decoder := yaml.NewDecoder(r)
provider := &Provider{}
for {
var doc Document
if err := decoder.Decode(&doc); err != nil {
if errors.Is(err, io.EOF) {
break
}
return provider, err
}
provider.docs = append(provider.docs, doc)
}
decoder.KnownFields(true)
return provider, nil
}
// Load config into passed object.
//
// All the matching configs are loaded in the order specified.
func (provider *Provider) Load(obj any) error {
type named interface {
Name() string
}
typ := reflect.TypeOf(obj).Elem()
kind := path.Base(typ.PkgPath()) + "." + typ.Name()
name := ""
if namedObj, ok := obj.(named); ok {
name = namedObj.Name()
}
for _, doc := range provider.docs {
if doc.Kind != kind {
continue
}
if doc.Name != "" && name == "" {
return fmt.Errorf("config has name %v for kind %v, while object doesn't support names", doc.Name, kind)
}
if doc.Name == "" || doc.Name == name {
if doc.Spec.IsZero() {
return fmt.Errorf("missing spec for config block %v/%v", doc.Kind, doc.Name)
}
if err := doc.Spec.Decode(obj); err != nil {
return fmt.Errorf("error decoding config block %v/%v into %v: %w", doc.Kind, doc.Name, obj, err)
}
}
}
return nil
}