Recipe
Layer a command-line tool's settings
Use when: one setting can come from a built-in default, a config file, an environment variable and a flag
Goal: one merged value per setting, where the most specific source that said something wins
Taught in Configuration
Quick recipe
-
1
Give the clap field no default (
Option<T>), and read each file key into anOption<T>too.Example
#[arg(short = 'n', long, env = "TALLY_TOP")] top: Option<usize>Why:
Noneis how a layer says "I have no opinion"; a default in clap would hide that. -
2
Put
env = "NAME"on the field, with clap'senvfeature on.Why: clap already applies flag-over-variable, and reports a bad value like a bad flag.
-
3
A missing file gives all-
Nonesettings; a broken file is an error with its path.Why: most users never write the file, but a typo in one must not be ignored.
-
4
cli.x.or(file.x).unwrap_or(DEFAULT)for each setting.Why:
orkeeps the firstSome, so the most specific layer that spoke wins. -
5
Write it in the doc comment,
[default: 10].Why: clap can't show a default it doesn't know about.
Common mistakes
- Keeping
default_value_ton a field the file is meant to override. - Ignoring a config file that fails to parse.
- Letting the file override a flag the user just typed.