v0.2.0 toml-only, harden concurrency and env export, dep updates
Test / test (push) Canceled after 0s

This commit is contained in:
lixen committed 2026-09-28 16:55:58 -04:00
1 parent 3c35601179
commit e08467bf38
42 files changed
+2533 -4274

No files matched your search

+93 -48
View File
@@ -1,68 +1,113 @@
# Config
# config
Thread-safe configuration management for Go applications with support for multiple sources (files, environment variables, command-line arguments, defaults) and configurable precedence.
## Features
- **Multiple Sources**: Load configuration from defaults, files, environment variables, and CLI arguments
- **Configurable Precedence**: Control which sources override others
- **Type Safety**: Struct-based configuration with automatic validation
- **Thread-Safe**: Concurrent access with read-write locking
- **File Watching**: Automatic reloading on configuration changes
- **Source Tracking**: Know exactly where each value came from
- **Tag Support**: Use `toml`, `json`, or `yaml` struct tags
## Installation
```bash
go get github.com/lixenwraith/config
```
## Quick Start
Thread-safe configuration from TOML files, environment variables, command-line
arguments and registered defaults. Requires Go 1.27.1. The only runtime dependency
is [lixenwraith/toml](https://github.com/lixenwraith/toml), pinned to merged commit
`b59d068ff6a4`. Testify and its dependencies are used only by tests.
```go
package main
import (
"log"
"time"
"github.com/lixenwraith/config"
)
type AppConfig struct {
Server struct {
Host string `toml:"host"`
Port int `toml:"port"`
} `toml:"server"`
Debug bool `toml:"debug"`
type Settings struct {
Port uint16 `toml:"port"`
Timeout time.Duration `toml:"timeout"`
}
func main() {
defaults := &AppConfig{}
defaults.Server.Host = "localhost"
defaults.Server.Port = 8080
cfg, err := config.Quick(defaults, "MYAPP_", "config.toml")
if err != nil {
log.Fatal(err)
}
port, _ := cfg.Get("server.port")
log.Printf("Server port: %d", port.(int64))
initial := Settings{Port: 8080, Timeout: 5 * time.Second}
cfg, err := config.NewBuilder().
WithTarget(&initial).
WithFile("config.toml").
WithEnvPrefix("APP_").
WithArgs([]string{"--port=9090"}).
Build()
if err != nil { log.Fatal(err) }
latest, err := cfg.AsStruct()
if err != nil { log.Fatal(err) }
log.Printf("%+v", latest.(*Settings))
}
```
```toml
# Service settings
timeout = "10s"
port = 8080
```
Precedence is CLI > environment > file > default. Register paths with `Register`
or structs with `RegisterStruct`; defaults define the types used to validate new
values. `LoadFile`, `LoadEnv` and `LoadCLI` replace their complete source. A failed
source load keeps its previous values. Removing an environment variable, CLI flag
or file key removes the old override on the next load.
`Get` returns a detached raw source value: environment and CLI values remain
strings, TOML integers are int64. `GetTyped[T]`, `Scan`, `ScanSource`, `ScanTyped[T]`
and `ScanMap` provide checked conversions. Errors leave destinations unchanged;
missing struct fields retain their existing values. `AsStruct` returns a detached
snapshot on every call. Build fills `WithTarget` once; subsequent reloads never
mutate that caller-owned object.
## Migration
- Only TOML files and `toml` tags are supported. JSON/YAML parsers, format constants
and alternate tag modes are removed. Existing format/tag option methods accept
only `toml` (`auto` remains an alias for TOML for file options).
- Numeric conversion rejects overflow, negative unsigned inputs, fractional
integer conversion, non-finite floats and integer-to-float precision loss.
Float64-to-float32 rounding within range remains supported. Full uint64 is
supported in memory; saving a value above MaxInt64 fails without changing the
destination file. Use an application-level string representation if needed.
- Strings can represent decimal numbers, booleans, comma-separated slices/arrays,
durations, RFC3339 timestamps, IP addresses, CIDR networks and URLs. Boolean to
string conversion uses `true`/`false`. There are no user decode hooks or automatic
`encoding.TextUnmarshaler` calls.
- Setters and source loads reject values incompatible with registered defaults
immediately. Check their errors. Untyped nil defaults leave the value type open;
typed nil pointers retain their declared type. Unsupported values, non-finite
floats and cyclic/deep graphs are rejected. Configuration value depth is 128.
- All public values, defaults, options and clones own their mutable containers.
Existing references returned from `AsStruct` are snapshots, not live objects.
- Saves standardize formatting and retain loaded comments as a preamble. Comment
positions are not preserved. Existing file permissions are retained; new files
use 0600. Only registered paths are saved, so unknown file keys are omitted.
- Paths use dot-separated ASCII key segments. Numeric-only segments and overlapping
registrations such as `server` plus `server.port` are rejected. Embedded fields
are not promoted. Recursive struct schemas are unsupported.
## Watching
```go
changes := cfg.WatchWithOptions(config.DefaultWatchOptions())
defer cfg.StopAutoUpdate()
for event := range changes {
// Events are hints; always read the latest complete state.
log.Print(event)
latest, err := cfg.AsStruct()
if err != nil { log.Print(err); continue }
_ = latest.(*Settings)
}
```
The watcher fingerprints file contents, waits for a quiet debounce interval, then
validates and publishes. Invalid edits, timeouts, deletion and blocked permission
changes retain the last valid state. Cancelled, expired or superseded reloads
cannot publish. Stop closes subscriptions synchronously; a new Watch call can
restart watching. Notifications are buffered and best effort.
## Documentation
- [Quick Start](doc/quick-start.md) - Get started
- [Builder Pattern](doc/builder.md) - Advanced configuration with the builder
- [Access Patterns](doc/access.md) - Getting and setting values
- [Command Line](doc/cli.md) - CLI argument handling
- [Environment Variables](doc/env.md) - Environment variable handling
- [File Configuration](doc/file.md) - File formats and loading
- [Validation](doc/validator.md) - Validation functions and integration
- [Live Reconfiguration](doc/reconfiguration.md) - File watching and auto-update on change
- [Quick Guide](doc/quick-guide_lixenwraith_config.md) - Quick reference guide
- [Quick start](doc/quick-start.md), [builder](doc/builder.md), [access](doc/access.md)
- [Files and saving](doc/file.md), [environment](doc/env.md), [CLI](doc/cli.md)
- [Live reconfiguration](doc/reconfiguration.md), [validation](doc/validator.md)
- [Architecture](doc/architecture.md), [audit evidence](doc/audit.md)
## License
Run `go test -race ./...` and `go vet ./...`. CI also executes the 386 suite,
cross-compiles for Windows and runs bounded numeric conversion fuzzing.
BSD-3-Clause
BSD-3-Clause; see LICENSE.