prefer

package module
v0.7.0 Latest Latest
Warning

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

Go to latest
Published: Dec 28, 2025 License: MIT Imports: 17 Imported by: 2

README

prefer.go

Test Lint Go Report Card codecov

Powerful configuration management in Go

Features

  • Load configuration files from standard system paths
  • Support for YAML, JSON, and XML formats
  • File watching for automatic configuration reloading
  • Cross-platform support (Unix, Linux, macOS, Windows)

Installation

go get github.com/LimpidTech/prefer.go

Usage

Basic Loading
package main

import (
    "fmt"
    "log"
    "github.com/LimpidTech/prefer.go"
)

type Config struct {
    Name string `yaml:"name"`
    Port int    `yaml:"port"`
}

func main() {
    var config Config
    
    // Load config from standard paths (./config.yaml, /etc/config.yaml, etc.)
    cfg, err := prefer.Load("config", &config)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("Loaded from: %s\n", cfg.Identifier)
    fmt.Printf("Name: %s, Port: %d\n", config.Name, config.Port)
}
File Watching
package main

import (
    "fmt"
    "log"
    "github.com/LimpidTech/prefer.go"
)

type Config struct {
    Name string `yaml:"name"`
}

func main() {
    var config Config
    
    // Watch for configuration changes
    channel, err := prefer.Watch("config", &config)
    if err != nil {
        log.Fatal(err)
    }
    
    for updatedConfig := range channel {
        cfg := updatedConfig.(*Config)
        fmt.Printf("Config updated: %s\n", cfg.Name)
    }
}

Supported Formats

  • YAML (.yaml, .yml)
  • JSON (.json)
  • XML (.xml)
  • INI (.ini)

Standard Search Paths

The library searches for configuration files in the following locations (in order):

Unix/Linux/macOS
  • Current directory (.)
  • Working directory
  • $XDG_CONFIG_DIRS
  • $HOME/.config
  • $HOME
  • /usr/local/etc
  • /usr/etc
  • /etc
Windows
  • Current directory
  • %USERPROFILE%
  • %LOCALPROFILE%
  • %APPDATA%
  • %CommonProgramFiles%
  • %ProgramData%
  • %ProgramFiles%
  • %SystemRoot%

Requirements

  • Go 1.25 or later

License

See LICENSE file for details.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DeepMerge

func DeepMerge(base, override map[string]interface{}) map[string]interface{}

DeepMerge merges override into base, returning a new map. Nested maps are merged recursively; other values are overwritten.

func GetStandardPaths

func GetStandardPaths() []string

func Watch

func Watch(identifier string, dest interface{}, opts ...Option) (chan interface{}, error)

Watch watches for configuration changes and returns a channel that receives updated configuration values.

func WatchWithDone

func WatchWithDone(identifier string, dest interface{}, done <-chan struct{}, opts ...Option) (chan interface{}, error)

WatchWithDone watches a configuration file with support for graceful shutdown. Close the done channel to stop watching.

Types

type ConfigBuilder

type ConfigBuilder struct {
	// contains filtered or unexported fields
}

ConfigBuilder builds configuration from multiple layered sources. Sources are applied in order, with later sources overriding earlier ones.

func NewConfigBuilder

func NewConfigBuilder() *ConfigBuilder

NewConfigBuilder creates a new ConfigBuilder.

func (*ConfigBuilder) AddDefaults

func (b *ConfigBuilder) AddDefaults(defaults map[string]interface{}) *ConfigBuilder

AddDefaults adds in-memory default values.

func (*ConfigBuilder) AddEnv

func (b *ConfigBuilder) AddEnv(prefix string) *ConfigBuilder

AddEnv adds environment variables with the given prefix. Variables are converted to nested structure using the separator. Example: MYAPP_DATABASE_HOST with prefix "MYAPP" becomes database.host

func (*ConfigBuilder) AddEnvWithSeparator

func (b *ConfigBuilder) AddEnvWithSeparator(prefix, separator string) *ConfigBuilder

AddEnvWithSeparator adds environment variables with a custom separator.

func (*ConfigBuilder) AddFile

func (b *ConfigBuilder) AddFile(identifier string) *ConfigBuilder

AddFile adds a required configuration file.

func (*ConfigBuilder) AddOptionalFile

func (b *ConfigBuilder) AddOptionalFile(identifier string) *ConfigBuilder

AddOptionalFile adds an optional configuration file. If the file doesn't exist, it's silently skipped.

func (*ConfigBuilder) AddSource

func (b *ConfigBuilder) AddSource(source Source) *ConfigBuilder

AddSource adds a custom source to the builder.

func (*ConfigBuilder) Build

func (b *ConfigBuilder) Build() (*ConfigMap, error)

Build loads and merges all sources, returning a ConfigMap.

type ConfigMap

type ConfigMap struct {
	// contains filtered or unexported fields
}

ConfigMap provides dot-notation access to configuration values. It wraps a map[string]interface{} and supports nested key access using dot-separated paths like "database.host".

func LoadMap

func LoadMap(identifier string) (*ConfigMap, error)

LoadMap loads a configuration file into a ConfigMap for dot-notation access.

func NewConfigMap

func NewConfigMap(data map[string]interface{}) *ConfigMap

NewConfigMap creates a new ConfigMap from a map.

func (*ConfigMap) Data

func (c *ConfigMap) Data() map[string]interface{}

Data returns the underlying map.

func (*ConfigMap) Get

func (c *ConfigMap) Get(key string) (interface{}, bool)

Get retrieves a value by dot-separated key path. Returns the value and true if found, nil and false otherwise.

func (*ConfigMap) GetBool

func (c *ConfigMap) GetBool(key string) (bool, bool)

GetBool retrieves a boolean value by key.

func (*ConfigMap) GetFloat

func (c *ConfigMap) GetFloat(key string) (float64, bool)

GetFloat retrieves a float64 value by key.

func (*ConfigMap) GetInt

func (c *ConfigMap) GetInt(key string) (int, bool)

GetInt retrieves an integer value by key. Handles both int and float64 (JSON numbers are float64).

func (*ConfigMap) GetMap

func (c *ConfigMap) GetMap(key string) (map[string]interface{}, bool)

GetMap retrieves a nested map value by key.

func (*ConfigMap) GetSlice

func (c *ConfigMap) GetSlice(key string) ([]interface{}, bool)

GetSlice retrieves a slice value by key.

func (*ConfigMap) GetString

func (c *ConfigMap) GetString(key string) (string, bool)

GetString retrieves a string value by key. Returns the value and true if found and is a string, empty string and false otherwise.

func (*ConfigMap) Has

func (c *ConfigMap) Has(key string) bool

Has checks if a key exists.

func (*ConfigMap) Keys

func (c *ConfigMap) Keys() []string

Keys returns all top-level keys.

func (*ConfigMap) Set

func (c *ConfigMap) Set(key string, value interface{}) error

Set sets a value at the given dot-separated key path. Creates intermediate maps as needed.

type Configuration

type Configuration struct {
	Identifier string

	Loaders     map[Loader]filterable
	Serializers map[Serializer]SerializerFactory
	// contains filtered or unexported fields
}

func Load

func Load(identifier string, dest interface{}, opts ...Option) (*Configuration, error)

Load loads configuration from the given identifier into dest. Options can be used to customize loading behavior, e.g., WithLoader.

func NewConfiguration

func NewConfiguration(identifier string, opts ...Option) *Configuration

NewConfiguration creates a new Configuration with the given identifier and options.

func (*Configuration) Reload

func (this *Configuration) Reload(dest interface{}) error

func (*Configuration) Watch

func (this *Configuration) Watch(dest interface{}, channel chan interface{}) error

func (*Configuration) WatchWithDone

func (this *Configuration) WatchWithDone(dest interface{}, channel chan interface{}, done <-chan struct{}) error

WatchWithDone watches for configuration changes with support for graceful shutdown. Close the done channel to stop watching. Errors during reload are skipped (resilient watching) rather than terminating the watch loop.

type EnvSource

type EnvSource struct {
	// contains filtered or unexported fields
}

EnvSource loads configuration from environment variables.

func NewEnvSource

func NewEnvSource(prefix string) *EnvSource

NewEnvSource creates a new EnvSource with the default separator "_".

func NewEnvSourceWithSeparator

func NewEnvSourceWithSeparator(prefix, separator string) *EnvSource

NewEnvSourceWithSeparator creates an EnvSource with a custom separator.

func (*EnvSource) Load

func (s *EnvSource) Load() (map[string]interface{}, error)

type FileLoader

type FileLoader struct {
	// contains filtered or unexported fields
}

func (FileLoader) Load

func (this FileLoader) Load() (string, []byte, error)

func (FileLoader) Locate

func (this FileLoader) Locate() (string, error)

func (FileLoader) Watch

func (this FileLoader) Watch(channel chan bool) error

func (FileLoader) WatchWithContext

func (this FileLoader) WatchWithContext(channel chan bool, done <-chan struct{}) error

WatchWithContext watches for file changes with support for graceful shutdown. Close the done channel to stop watching.

type FileSource

type FileSource struct {
	// contains filtered or unexported fields
}

FileSource loads configuration from a file.

func NewFileSource

func NewFileSource(identifier string) *FileSource

NewFileSource creates a required file source.

func NewOptionalFileSource

func NewOptionalFileSource(identifier string) *FileSource

NewOptionalFileSource creates an optional file source.

func (*FileSource) Load

func (s *FileSource) Load() (map[string]interface{}, error)

type INISerializer

type INISerializer struct{}

func (INISerializer) Deserialize

func (this INISerializer) Deserialize(input []byte, obj interface{}) error

func (INISerializer) Serialize

func (this INISerializer) Serialize(input interface{}) ([]byte, error)

type JSONSerializer

type JSONSerializer struct{}

func (JSONSerializer) Deserialize

func (this JSONSerializer) Deserialize(input []byte, obj interface{}) error

func (JSONSerializer) Serialize

func (this JSONSerializer) Serialize(input interface{}) ([]byte, error)

type Loader

type Loader interface {
	Load() (string, []byte, error)
	Watch(channel chan bool) error
	WatchWithContext(channel chan bool, done <-chan struct{}) error
}

func NewLoader

func NewLoader(identifier string) (Loader, error)

type MemoryLoader

type MemoryLoader struct {
	// contains filtered or unexported fields
}

MemoryLoader loads configuration from in-memory content. Useful for testing and embedding configurations.

func NewMemoryLoader

func NewMemoryLoader(identifier string, content []byte) *MemoryLoader

NewMemoryLoader creates a loader that returns the given content. The identifier is used for format detection (e.g., "config.json" for JSON).

func (*MemoryLoader) Load

func (m *MemoryLoader) Load() (string, []byte, error)

func (*MemoryLoader) Watch

func (m *MemoryLoader) Watch(channel chan bool) error

func (*MemoryLoader) WatchWithContext

func (m *MemoryLoader) WatchWithContext(channel chan bool, done <-chan struct{}) error

type MemorySource

type MemorySource struct {
	// contains filtered or unexported fields
}

MemorySource provides configuration from an in-memory map.

func NewMemorySource

func NewMemorySource(data map[string]interface{}) *MemorySource

NewMemorySource creates a new MemorySource.

func (*MemorySource) Load

func (s *MemorySource) Load() (map[string]interface{}, error)

type Option

type Option func(*Configuration)

Option configures how configuration is loaded

func WithLoader

func WithLoader(loader Loader) Option

WithLoader sets a custom loader for the configuration

type Serializer

type Serializer interface {
	Serialize(interface{}) ([]byte, error)
	Deserialize([]byte, interface{}) error
}

NOTE: It may make more sense to use a map to these instead of creating potentially unnecessray structs for implementing interfaces on.

func NewINISerializer

func NewINISerializer() Serializer

func NewJSONSerializer

func NewJSONSerializer() Serializer

func NewSerializer

func NewSerializer(identifier string, content []byte) (serializer Serializer, err error)

func NewTOMLSerializer

func NewTOMLSerializer() Serializer

func NewXMLSerializer

func NewXMLSerializer() Serializer

func NewYAMLSerializer

func NewYAMLSerializer() Serializer

type SerializerFactory

type SerializerFactory func() Serializer

type Source

type Source interface {
	// Load returns configuration data as a map.
	Load() (map[string]interface{}, error)
}

Source represents a configuration source for the ConfigBuilder.

type TOMLSerializer

type TOMLSerializer struct{}

func (TOMLSerializer) Deserialize

func (this TOMLSerializer) Deserialize(input []byte, obj interface{}) error

func (TOMLSerializer) Serialize

func (this TOMLSerializer) Serialize(input interface{}) ([]byte, error)

type WatchEvent

type WatchEvent struct {
	Path  string
	Error error
}

WatchEvent represents a file system event during watching

type Watcher

type Watcher interface {
	Add(name string) error
	Close() error
	Events() <-chan fsnotify.Event
	Errors() <-chan error
}

Watcher interface abstracts fsnotify.Watcher for testing

type WatcherFactory

type WatcherFactory func() (Watcher, error)

WatcherFactory creates new Watcher instances

type XMLSerializer

type XMLSerializer struct{}

func (XMLSerializer) Deserialize

func (this XMLSerializer) Deserialize(input []byte, obj interface{}) error

func (XMLSerializer) Serialize

func (this XMLSerializer) Serialize(input interface{}) ([]byte, error)

type YAMLSerializer

type YAMLSerializer struct{}

func (YAMLSerializer) Deserialize

func (this YAMLSerializer) Deserialize(input []byte, obj interface{}) error

func (YAMLSerializer) Serialize

func (this YAMLSerializer) Serialize(input interface{}) ([]byte, error)

Jump to

Keyboard shortcuts

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