Skip to content

Delete viper: 35 of 38 packages to read six environment variables #54

Description

@korya

Revised 2026-08-07. The original issue proposed making the environment uniform across all 19 options via a VisitAll loop. That part was wrong and should not be done — see Why not uniform below. The dependency removal, which is the valuable half, is implemented in the linked PR.

Problem

Viper contributes 35 of the module's 38 non-stdlib packages to configure six flags from the environment. It is used for nothing but AutomaticEnv:

viper.SetEnvPrefix("HTTP_ASSERT")
viper.GetViper().SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
viper.AutomaticEnv()

No config files, no remote providers, no watching — and for that the graph carries fsnotify, afero, mapstructure, pelletier/go-toml, locafero, sourcegraph/conc, gotenv, cast and yaml.

Before After
Non-stdlib packages 38 3 (cobra, pflag, mousetrap)
Total packages 235 193
Binary 9.93 MB 9.01 MB

Why not uniform

The original proposal was to apply the environment to every flag via VisitAll. Preserving --maphost's existing semantics requires splitting one variable into several values on whitespace (viper's behaviour, verified). Applied uniformly, that corrupts every option whose values contain spaces:

'X-Foo: bar baz'              -> strings.Fields -> ['X-Foo:', 'bar', 'baz']
'Cache-Control: max-age=3600' -> strings.Fields -> ['Cache-Control:', 'max-age=3600']

Header values routinely contain spaces; host mappings never do. Uniformity would trade one inconsistency for a silent value-corrupting footgun across ten flags — strictly worse than the split it was meant to fix.

The inconsistency is instead addressed where it actually hurt: it is now a single named list in the source, and documented in the README, rather than an accident of which flags happened to get a BindPFlag line.

If per-flag environment support for the remaining options is still wanted, it needs a separator that cannot appear in a header value (indexed variables such as HTTP_ASSERT_HEADER_1, or a NUL/newline delimiter) — that is a different design and deserves its own issue.

What shipped

  • applyEnv, ~25 lines over the flag set, replacing all 13 viper call sites.
  • Every option now read from cobra; envFlags names the six that also consult the environment.
  • Behaviour preserved exactly — empty variable means unset, whitespace separates repeated values, command line beats environment.
  • Separately: unparseable values are now rejected instead of coerced. Previously HTTP_ASSERT_MAX_TIME=abc became 0, and a zero http.Client.Timeout means no timeout at all.

Verification

The behaviour-preserving commit touches no test file. All 233 subtests — including 32 added beforehand specifically to cover environment parsing — pass unedited. Coverage went 39% → 100%.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions