v0.1.3 added unknown cli flag handling, dependency update

This commit is contained in:
2026-07-18 17:42:35 -04:00
parent f4a19aa72a
commit 389121f7ad
5 changed files with 30 additions and 13 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
BSD 3-Clause License
Copyright (c) 2025, Lixen Wraith
Copyright (c) 2026, Lixen Wraith
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
+12 -1
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
+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 -4
View File
@@ -1,9 +1,9 @@
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=
+8 -2
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)
}
}