cfgcascade

package
v1.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 27, 2026 License: Apache-2.0 Imports: 4 Imported by: 1

Documentation

Overview

Package cfgcascade provides a generic, layered configuration cascade.

A Cascade resolves configuration by loading values from ranked providers (least-specific first), merging them with a caller-supplied function, and tracking which providers contributed to the final value.

Providers that return os.ErrNotExist are silently skipped (source not present). Any other error is recorded but does not stop resolution.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Cascade

type Cascade[T any] struct {
	// Layers are the ranked config sources. They do not need to be pre-sorted;
	// Resolve sorts them by Rank before processing.
	Layers []Layer[T]

	// MergeFn combines two values. It receives (base, overlay) where overlay
	// comes from the higher-ranked (more specific) layer. The returned value
	// becomes the new base for subsequent merges.
	MergeFn func(base, overlay T) T
}

Cascade merges config layers in rank order using a provided merge function.

func (*Cascade[T]) Resolve

func (c *Cascade[T]) Resolve(getenv func(string) string) *ResolvedValue[T]

Resolve loads all layers in rank order (ascending), skips providers that return os.ErrNotExist, records real errors, and merges using MergeFn.

If no provider succeeds, Value will be the zero value of T with an empty Sources slice.

type DefaultProvider

type DefaultProvider[T any] struct {
	ProviderName string
	Default      T
}

DefaultProvider returns a static default value. It never fails.

func (*DefaultProvider[T]) Load

func (p *DefaultProvider[T]) Load(_ func(string) string) (T, error)

func (*DefaultProvider[T]) Name

func (p *DefaultProvider[T]) Name() string

type EnvProvider

type EnvProvider struct {
	// ProviderName is the human-readable name for this provider.
	ProviderName string

	// Prefix is the env var prefix to match (e.g. "TAP_"). Only variables
	// starting with this prefix are included.
	Prefix string

	// Keys lists the env var names (without prefix) to look up. If empty,
	// the provider returns ErrNotExist. Each key is looked up as Prefix+key.
	// For example, Keys=["DEFAULT_KEG", "LOG_LEVEL"] with Prefix="TAP_"
	// looks up TAP_DEFAULT_KEG and TAP_LOG_LEVEL.
	Keys []string
}

EnvProvider reads environment variables with a configurable prefix and returns a map[string]string of stripped, lowercased keys.

For example, with prefix "TAP_" and env vars TAP_DEFAULT_KEG=home and TAP_LOG_LEVEL=debug, Load returns {"default_keg": "home", "log_level": "debug"}.

If no matching env vars are found, Load returns os.ErrNotExist so the cascade treats it as an absent source.

func (*EnvProvider) Load

func (p *EnvProvider) Load(getenv func(string) string) (map[string]string, error)

Load reads environment variables matching Prefix+key for each key in Keys. The getenv parameter accepts a func(string) string for env var lookup, keeping cfgcascade decoupled from any specific env abstraction. Runtime- managed applications should pass their sandboxed lookup (e.g. rt.Env().Get) to preserve test isolation. If getenv is nil, falls back to os.Getenv for standalone use outside Runtime-managed applications.

func (*EnvProvider) Name

func (p *EnvProvider) Name() string

type FuncProvider

type FuncProvider[T any] struct {
	ProviderName string
	Fn           func(getenv func(string) string) (T, error)
}

FuncProvider wraps a function as a Provider.

func (*FuncProvider[T]) Load

func (p *FuncProvider[T]) Load(getenv func(string) string) (T, error)

func (*FuncProvider[T]) Name

func (p *FuncProvider[T]) Name() string

type Layer

type Layer[T any] struct {
	Rank     int
	Provider Provider[T]
}

Layer is a ranked config source. Lower Rank values are less specific (loaded first, overridden by higher ranks).

type MissingProvider

type MissingProvider[T any] struct {
	ProviderName string
}

MissingProvider always returns os.ErrNotExist. Useful for representing an optional source that is not configured.

func (*MissingProvider[T]) Load

func (p *MissingProvider[T]) Load(_ func(string) string) (T, error)

func (*MissingProvider[T]) Name

func (p *MissingProvider[T]) Name() string

type Provider

type Provider[T any] interface {
	// Load returns a value from this source. Return an error wrapping
	// os.ErrNotExist to signal that the source is absent (graceful skip).
	Load(getenv func(string) string) (T, error)

	// Name returns a human-readable name for this provider (e.g. "user-config",
	// "env-vars").
	Name() string
}

Provider loads a config value from a single source.

type ProviderError

type ProviderError struct {
	Name string
	Err  error
}

ProviderError records a provider that failed with a non-ErrNotExist error.

func (ProviderError) Error

func (pe ProviderError) Error() string

func (ProviderError) Unwrap

func (pe ProviderError) Unwrap() error

type ResolvedValue

type ResolvedValue[T any] struct {
	// Value is the final merged configuration.
	Value T

	// Sources lists the names of providers that contributed, ordered from
	// most-specific (highest rank) to least-specific.
	Sources []string

	// Errors lists providers that returned non-ErrNotExist errors.
	Errors []ProviderError
}

ResolvedValue holds the merged result and provenance metadata.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL