Skip to content

v0.3.0

Choose a tag to compare

@wrfly wrfly released this 19 Aug 15:55
· 2 commits to master since this release
aed75d2

Panics

Values were built with a hard-coded concrete type and assigned to the field, which panics as soon as the field is not exactly that type — both reachable from an ordinary environment value:

type Level int
type Conf struct{ L []Level }         // reflect.Set: []int is not assignable to []Level
type Conf struct{ D *time.Duration }  // reflect.Set: *int64 is not assignable to *time.Duration

Values are now built through the field's own reflect.Type, so named types behave like their underlying kind. *time.Duration also gains the "10s" syntax that time.Duration already had.

Fixes

before after
PORT=1e1000000 ~100s building a 1MB string rejected immediately
1.5e3 unparsable "1.5000" 1500
yaml:"-" / json:"-" / env:"-" honoured by List, ignored by Parse skipped by both
Parse(config) without & nil error, nothing filled error
*SubStruct section never walked into, bogus key in List optional section, allocated only when set, cycle-guarded
default:"false" on a bool overwrote a caller-set true kept, like every other kind
map / array fields silently ignored reported, and no longer listed
"a b" (default separator) 3 elements, numeric slices fail 2 elements
List quoting A="a "b" c" strconv.Quote
Get no prefix, pointer-only config, missed named types prefix param, works read-only, kind-based
parse errors %s %w, so errors.Is/As work
parser type unexported *ecp exported *ECP

Upgrading

Behaviour changes on purpose: Parse without a pointer now errors, --tagged fields are no longer filled, a caller-set bool survives default:"false", and unsupported kinds error instead of being ignored. The exported type and the new Get prefix argument are source-compatible.

Internals

One setValue helper replaces the fifteen near-identical branches of parseSlice and all of parsePointer (parse.go: 291 → 78 lines). Coverage 91.5% → 94.2%; CI now runs vet, -race and gofmt over Go 1.19/1.21/1.23/stable.