v0.2.2 fixes: split only text sources, report a mode change once, don't block on open
Test / test (push) Canceled after 0s

This commit is contained in:
lixen committed 2026-10-03 22:08:43 -04:00
1 parent 2a47be454d
commit 9b4d98672d
19 files changed
+365 -59

No files matched your search

+36 -12
View File
@@ -201,11 +201,18 @@ func (c *Config) loadEnv(opts LoadOptions) error {
}
c.mutex.RUnlock()
values := make(map[string]any)
byVar := make(map[string]string, len(paths))
for _, path := range paths {
if opts.EnvWhitelist != nil && !opts.EnvWhitelist[path] {
continue
}
if value, ok := os.LookupEnv(transform(path)); ok {
name := transform(path)
// Empty counts as unset, so a template may leave a variable blank
if value, ok := os.LookupEnv(name); ok && value != "" {
if other, dup := byVar[name]; dup {
return fmt.Errorf("%s would set both %s and %s", name, other, path)
}
byVar[name] = path
values[path] = value
}
}
@@ -215,13 +222,17 @@ func (c *Config) loadEnv(opts LoadOptions) error {
}
func (c *Config) loadCLI(args []string) error {
parsed, err := parseArgs(args)
parsed, stray, err := parseArgs(args)
if err != nil {
return err
}
c.mutex.Lock()
defer c.mutex.Unlock()
return c.replaceSourceLocked(SourceCLI, flattenMap(parsed, ""))
if err := c.replaceSourceLocked(SourceCLI, flattenMap(parsed, "")); err != nil {
return err
}
c.unknownCLIKeys = append(c.unknownCLIKeys, stray...)
return nil
}
// Validate the entire replacement before any mutation. Caller holds c.mutex.
@@ -236,6 +247,12 @@ func (c *Config) replaceSourceLocked(source Source, values map[string]any, guard
}
continue
}
if source == SourceEnv || source == SourceCLI {
value = textList(item.defaultValue, value)
}
if t := reflect.TypeOf(item.defaultValue); source == SourceCLI && value == true && t != nil && t.Kind() != reflect.Bool {
return fmt.Errorf("--%s needs a value", path)
}
if err := validateValue(item, value); err != nil {
return fmt.Errorf("%s: %w", path, err)
}
@@ -304,14 +321,16 @@ func parseValue(s string) any {
return s
}
// parseArgs processes command-line arguments into a nested map structure.
func parseArgs(args []string) (map[string]any, error) {
result := make(map[string]any)
// parseArgs processes command-line arguments into a nested map structure. A
// bare flag is the bool true, which only a bool path accepts; arguments that
// are no --flag before "--" come back as stray, for UnknownCLIKeys.
func parseArgs(args []string) (result map[string]any, stray []string, err error) {
result = make(map[string]any)
i := 0
for i < len(args) {
arg := args[i]
if !strings.HasPrefix(arg, "--") {
// Skip non-flag arguments
stray = append(stray, arg)
i++
continue
}
@@ -324,6 +343,7 @@ func parseArgs(args []string) (map[string]any, error) {
var keyPath string
var valueStr string
bare := false
// Check for "--key=value" format
if strings.Contains(argContent, "=") {
@@ -336,7 +356,7 @@ func parseArgs(args []string) (map[string]any, error) {
keyPath = argContent
// Check if it's a boolean flag (next arg is another flag or end of args)
if i+1 >= len(args) || strings.HasPrefix(args[i+1], "--") {
valueStr = "true"
bare = true
i++ // Consume only the flag argument
} else {
// It's a key-value pair with a space
@@ -354,16 +374,20 @@ func parseArgs(args []string) (map[string]any, error) {
segments := strings.Split(keyPath, ".")
for _, segment := range segments {
if !isValidKeySegment(segment) {
return nil, wrapError(ErrInvalidPath, fmt.Errorf("invalid command-line key segment %q in path %q", segment, keyPath))
return nil, nil, wrapError(ErrInvalidPath, fmt.Errorf("invalid command-line key segment %q in path %q", segment, keyPath))
}
}
// Always store as a string. Let Scan handle final type conversion.
if len(valueStr) > MaxValueSize {
return nil, ErrValueSize
return nil, nil, ErrValueSize
}
if bare {
setNestedValue(result, keyPath, true)
} else {
setNestedValue(result, keyPath, valueStr)
}
setNestedValue(result, keyPath, valueStr)
}
return result, nil
return result, stray, nil
}