This commit is contained in:
Lukas Wurzinger 2024-12-05 19:20:15 +01:00
parent 65b8fd210a
commit 7b9b034802
3 changed files with 42 additions and 22 deletions

5
go.mod
View file

@ -1,3 +1,8 @@
module github.com/lukaswrz/gonfig module github.com/lukaswrz/gonfig
go 1.23.3 go 1.23.3
require (
github.com/hashicorp/errwrap v1.0.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
)

4
go.sum Normal file
View file

@ -0,0 +1,4 @@
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=

View file

@ -8,46 +8,57 @@ import (
"os" "os"
) )
// Validator defines an interface for validating a configuration of type T. It // UnmarshalFunc is a function that unmarshals raw bytes into a configuration
// ensures that the provided configuration meets required constraints. // object of type T.
type Validator[T any] interface { type UnmarshalFunc[T any] func([]byte, T) error
// Validate checks the provided configuration and returns an error if it is
// invalid. // ValidateFunc is a function that validates a configuration object of type T
Validate(config T) []error // and returns an error if validation fails.
} type ValidateFunc[T any] func(T) error
// ReadConfig reads a configuration file, unmarshals its content into the given // ReadConfig reads a configuration file, unmarshals its content into the given
// configuration object, and validates it using the provided validator. If the // configuration object, and validates it.
// primary path is empty, it searches for the configuration file in the //
// fallback paths. The function returns the resolved path to the configuration // If the primary path is empty, it searches for the configuration file in the
// file or a list of errors if the file cannot be located, read, unmarshaled, // fallback paths. Returns the resolved path or an error if the file cannot be
// or validated. // located, read, unmarshaled, or validated.
func ReadConfig[T any](path string, paths []string, c *T, unmarshal func([]byte, *T) error, validator Validator[T]) (string, []error) { func ReadConfig[T any](path string, searchPaths []string, c *T, unmarshal UnmarshalFunc[*T], validate ValidateFunc[T]) (string, error) {
var err error var err error
path, err = findConfig(path, paths) path, err = FindConfig(path, searchPaths)
if err != nil { if err != nil {
return "", []error{err} return "", err
} }
return path, ReadFoundConfig(path, c, unmarshal, validate)
}
// ReadFoundConfig reads and processes a configuration file from a known path.
//
// Unmarshals the file's content into the given configuration object and
// validates it. Returns an error if the file cannot be read, unmarshaled, or
// validated.
func ReadFoundConfig[T any](path string, c *T, unmarshal UnmarshalFunc[*T], validate ValidateFunc[T]) error {
content, err := os.ReadFile(path) content, err := os.ReadFile(path)
if err != nil { if err != nil {
return "", []error{fmt.Errorf("unable to read configuration file %s: %w", path, err)} return fmt.Errorf("unable to read configuration file %s: %w", path, err)
} }
err = unmarshal(content, c) err = unmarshal(content, c)
if err != nil { if err != nil {
return "", []error{fmt.Errorf("unable to unmarshal configuration file %s: %w", path, err)} return fmt.Errorf("unable to unmarshal configuration file %s: %w", path, err)
} }
return path, validator.Validate(*c) return validate(*c)
} }
// findConfig determines the path to the configuration file by using the // FindConfig determines the path to the configuration file by using the
// provided primary path or searching through a list of fallback paths if the // provided primary path or searching through a list of fallback paths if the
// primary path is empty. If no valid file is found, or if the specified file is // primary path is empty.
// inaccessible, an error is returned. //
func findConfig(path string, paths []string) (string, error) { // Returns the resolved path or an error if no valid file is found or if the
// file is inaccessible.
func FindConfig(path string, paths []string) (string, error) {
var err error var err error
if path == "" { if path == "" {