v0.1.3 added unknown cli flag handling, dependency update

This commit is contained in:
2026-07-12 13:22:28 -04:00
parent f4a19aa72a
commit f53c004155
4 changed files with 29 additions and 8 deletions
+13 -2
View File
@@ -1,4 +1,3 @@
// FILE: lixenwraith/config/config.go
// Package config provides thread-safe configuration management for Go applications
// with support for multiple sources: TOML files, environment variables, command-line
// arguments, and default values with configurable precedence.
@@ -7,6 +6,7 @@ package config
import (
"fmt"
"reflect"
"slices"
"sync"
"sync/atomic"
)
@@ -50,6 +50,9 @@ type Config struct {
version atomic.Int64
structCache *structCache
// CLI paths that matched no registered path (reset on each CLI load)
unknownCLIKeys []string
// File watching support
watcher *watcher
configFilePath string // Track loaded file path
@@ -249,6 +252,7 @@ func (c *Config) SetSource(source Source, path string, value any) error {
c.envData[path] = value
case SourceCLI:
c.cliData[path] = value
c.unknownCLIKeys = nil
}
c.invalidateCache() // Invalidate cache after changes
@@ -337,6 +341,13 @@ func (c *Config) AsStruct() (any, error) {
return c.structCache.target, nil
}
// UnknownCLIKeys returns CLI paths that matched no registered config path
func (c *Config) UnknownCLIKeys() []string {
c.mutex.RLock()
defer c.mutex.RUnlock()
return slices.Clone(c.unknownCLIKeys)
}
// computeValue determines the current value based on precedence
func (c *Config) computeValue(item configItem) any {
// Check sources in precedence order
@@ -372,4 +383,4 @@ func (c *Config) populateStruct() error {
// invalidateCache override Set methods to invalidate cache
func (c *Config) invalidateCache() {
c.version.Add(1)
}
}
+3 -3
View File
@@ -1,10 +1,10 @@
module github.com/lixenwraith/config
go 1.25.4
go 1.26.0
require (
github.com/BurntSushi/toml v1.5.0
github.com/go-viper/mapstructure/v2 v2.4.0
github.com/BurntSushi/toml v1.6.0
github.com/go-viper/mapstructure/v2 v2.5.0
github.com/stretchr/testify v1.10.0
gopkg.in/yaml.v3 v3.0.1
)
+4
View File
@@ -1,9 +1,13 @@
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
+9 -3
View File
@@ -435,7 +435,7 @@ func (c *Config) loadEnv(opts LoadOptions) error {
transform = defaultEnvTransform(opts.EnvPrefix)
}
// -- 1. Prepare data (Read-Lock to get paths)
// 1. Prepare data (Read-Lock to get paths)
c.mutex.RLock()
paths := make([]string, 0, len(c.items))
for p := range c.items {
@@ -443,7 +443,7 @@ func (c *Config) loadEnv(opts LoadOptions) error {
}
c.mutex.RUnlock()
// -- 2. Process env vars (No Lock)
// 2. Process env vars (No Lock)
foundEnvVars := make(map[string]string)
for _, path := range paths {
if opts.EnvWhitelist != nil && !opts.EnvWhitelist[path] {
@@ -506,6 +506,9 @@ func (c *Config) loadCLI(args []string) error {
c.cliData = flattenedCLI
// Reset per load; reloads must not accumulate duplicates
c.unknownCLIKeys = c.unknownCLIKeys[:0]
for path, value := range flattenedCLI {
if item, exists := c.items[path]; exists {
if item.values == nil {
@@ -514,6 +517,9 @@ func (c *Config) loadCLI(args []string) error {
item.values[SourceCLI] = value
item.currentValue = c.computeValue(item)
c.items[path] = item
} else {
// Record CLI keys that match no registered path
c.unknownCLIKeys = append(c.unknownCLIKeys, path)
}
}
@@ -693,4 +699,4 @@ func detectFormatFromContent(data []byte) string {
}
return ""
}
}