rust-cli / rust-cli/config-rs

Exploring a redesign and discussing how a modern Rust configuration library should behave

Open
#111 29 comments 30 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
3.2k
Forks
265
Avg merge
2h 42m
Merged PRs (30d)
4

Description

This library has gotten quite stale over the last year and I've been loathe to come back to it mostly because I don't like it. It's complex to use, complex to develop, etc. I apologize for letting it atrophy.

I'd like to thank you everyone who has contributed or submitted a PR ( especially those who've done so in the last several months and have just sat there ). It's not that I don't want to merge in your work, it's that if I come back to this I'll want to do too much and I haven't had the time available to do that.


With that out of the way I want to explore how a configuration library could behave in Rust, optimally, using some example use cases as a jumping off point:

// load configuration only from envrionment
let settings: Settings = config::env::vars()
    // filter to only keys that case-insentively start with s
    .prefix("app_")
    // explictly transform key names to allow traversing nested configuration
    // replaces .separator("__") from config v0.9
    .map(|key| key.replace("__", "."))
    .load()?;

// find a single configuration file from example.* in
let settings: Settings = config::file::find("example")
    // look in the following paths (by default cwd)
    .paths(&[xdg_config_home, home])
    // expect format in TOML only
    // default allows all formats compiled in
    .format(Format::Toml)
    // and load into Settings
    .load()?;

// find multiple configuration files and merge together
let settings: Settings = config::file::find_all(&[
    "default",
    mode // development, production, or test, etc.
]).load()?;

// load configuration from arguments
let settings: Settings = config::env::args(clap_matches).load();

// manually create a configuration stack
let settings: Settings = config::Stack::new()
    // start with an embedded JSON file 
    .add(config::file::from_bytes(Format::Json, include_bytes!("default.json")))
    // override from environment
    .add(config::env::vars())
    // load into settings
    .load()?;

// create a dynamic configuration (ala config v0.9)
// any _source_ could be built into a Config struct
let settings: config::Config = config::file::find("example").build();

// a dyn configuration can listen for changes on supported sources
let _handle = settings.watch(|| do_something_fun_when_config_changes);

// use path access
let host: &str = settings.get("db.host");

Thoughts? How would you want config to work?

Are there any pain points in the current design you'd like to discuss?

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the Rust configuration use cases and API sketches in issue #111, then compare them with the current config-rs design and its existing pain points. Done means reaching agreement on the desired behavior and scope of a modern redesign; this issue does not name specific files or tests to change.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
20/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.