-
-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Think about interaction with clap to allow loading/overriding config values from CLI args #19
Comments
For the record, I also use Gumdrop in my actix-web projects, where I don't need the path arguments to support accepting non-UTF8-able POSIX paths (i.e. where they're just going to be a path to a server root folder or config file) and I want to benefit from the reduced compile times and smaller output binaries. |
Fair point. It's certainly worth considering how one could support multiple cli libraries. Or even be completely library-agnostic. |
I would also love to have an integration with clap. I followed your workaround described above and I find it quite ok. However I was not able to derive I didn't see a better way of doing it for now, but I still find your crate awesome and clean and can live with the solution. Just wanted to raise the point of defaults in clap and confique. |
A different kind of approach to support overriding via the command line is to have a general flag that accepts a fragment of config and applies it, this is the approach taken by #[derive(confique::Config, Debug)]
#[config(partial_attr(derive(Clone, Debug)))]
#[config(partial_attr(serde(deny_unknown_fields)))]
struct Config {
...
}
type Partial = <Config as confique::Config>::Partial;
impl Config {
fn load(fragments: Vec<Partial>) -> Result<Self> {
let dirs = ProjectDirs::from(...).ok_or_eyre("cannot get config directory")?;
let mut builder = Config::builder();
// reverse so that later fragments take precedence
for fragment in fragments.into_iter().rev() {
builder = builder.preloaded(fragment)
}
Ok(builder.env().file(dirs.config_dir().join("config.toml")).load()?)
}
}
#[derive(Debug, Parser)]
struct App {
/// Config overrides to apply, these should be fragments of the config file.
#[arg(long = "config-toml", value_name = "TOML", value_parser = toml::from_str::<Partial>)]
config_fragments: Vec<config::Partial>,
...
}
fn main() -> Result<()> {
let app = App::parse();
let config = Config::load(app.config_fragments)?;
tracing::trace!(?config, "loaded config");
...
} |
Often it's useful to allow users to override some (or all) configuration values via command line. Confique should work nicely for that use case. The currently best way to do it is probably to convert the CLI values to a partial type (manually) and then add it via
Builder::preloaded
. I would like to investigate whether this can be made more convenient and with less duplicate code.If this improvement has to be CLI-library specific, I am pretty sure I only want to support clap. I only ever use clap with the derive feature and I think it's the most mature library.
Just to throw some random ideas into this issue, maybe one can annotate config fields with
#[config(clap(...))]
and if any are annotated this way, we will generate an additional type containing the fields annotated that way that has thederive(clap::*)
on it. And has a method to convert it to a partial config type. This extra type can then be flattened into the main clap type. But again, haven't thought about this too deeply yet.The text was updated successfully, but these errors were encountered: