-
Notifications
You must be signed in to change notification settings - Fork 0
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
Add first draft of vision #6
Conversation
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
Several things that have to be discussed:
@pksunkara and @Gankra but maybe also @epage and others from the rust-cli WG (feel free to ping them) - feel free to comment and suggest changes! 😉 👍 |
* The crate MUST allow deserializing the loaded configuration objects to a type | ||
that implements `serde::Deserialize` although layering-information and context | ||
is lost this way | ||
* The developer of an app MUST be able to find where a specific value of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd add
configuration errors must point back to the backend location for the layer that they originated from
Unsure how this fits in but some things I've run into with my applications
And one out of left field that would probably need to be its own crate:
|
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
Can you give a user-story for this? I am not sure I completely understand what you mean here.
That should be easily possible. A "give me a full example of a config"-type functionality would require that the complete configuration schema is known. That would mean that the user of the crate can actually write a Or do you mean something different?
I think that should also be possible, I will think about it a bit. I think this also plays into the next point
I totally get your point here. The basic issue here is, that the full configuration schema is not known at compiletime but only at runtime. I think we can and should add some schema-verification functionality. That would also cover the "report errors for extra fields" usecase. My idea here would be to let the user write some form of verification "field abc must be there" and then validate the loaded configuration against that. The "issue" in this crate is basically that each field in a schema is optional if you only look at a single layer of configuration, even if the field is non-optional in the joined configuration object. |
The cases I remember
Basically
That might be one way to put it, I'm unsure. Its more of there is no canonical full schema. The schema is defined on a per-field basis. I've been playing a little with it in git dive but still not happy with the results. I wouldn't say this is exclusively a feature related to git either. I also did it for an internal build tool at a company I worked at. It is more related to when multiple plugins all share the same config file. For git and that build tool, I liked to do it on a per-field basis. I haven't fully looked into how cargo handles this but I it has a decentralized schema but do not provide a type-safe API, instead having the the caller have to know which type to do the lookup with.. |
So, just that I understand correctly: Your config type looked like this: And you layer something else above that, which does contain the Did I get that right?
What would be your expectations in this case? How can the configuration crate help with consolidating this? Or am I misunderstanding your point here?
I think I know what you mean. For the "all fields are known" usecase (which is "deserializing into a known Type"), config-rs would only provide the "layering". If you have only one configuration file and all your configuration options are known at compiletime, I do not see any benefit of config-rs over plain serde_json/toml/serde_yaml/etc. config-rs (IMHO) should target the usecases where you actually have multiple files and want to merge them. That's where the benefit lies. If you also happen to have a schema that is not fully known at compiletime and you have to access values at runtime because you cannot deserialize the configuration to So if we take git as an example: Some config members are known (the ones of the Maybe that's something we can explore as well? Does the above match your thoughts/expectations? |
For typos, yes, that is correct. For evolving the fields, that is exactly the same case as typos. In both cases, the goal is to not break compatibility. Ideally, we produce warnings in both cases to help people migrate.
While you can stretch it to work this way, really you are working on the field level rather than the tables level. There are two levels of tables and both are decentralized, so trying to deserialize into top-level types adds a lot of ceremony to the API. Ideally, it would be more like cargo where you pass a path to the field and specify what type to deserialize that field to. |
Another use case I thought of is that For example, in |
Yes, something like that exists today and I plan to support it as well! 👍
That is indeed something we have to carefully think about and design! And actually something I haven't thought about yet, thanks for bringing it up! 👍 ❤️ |
In the systems I've worked on, outside of cargo, they've gone a step further and defined a type that holds the key and has a generic parameter for the type so you can centralize knowledge of this. Roughly const PAGER_FIELD = TypedField::<Pager>::new("pager.path");
config.get(PAGER_FIELD) |
This all makes sense, I especially like the stuff about holding onto all the configuration context. In particular it would be great if I could point to the what specified a config value if it later turns out to be problematic. Say, you said to
I've experimented with this a bit in cargo-vet using I also experimented with implementing a parser as a validator on top of kdl-rs' toml-edit-like API in kdl-script. To do this I added a Unfortunately there isn't really any harmonious portable solution for this (and the API I designed for kdl-rs isn't great). Also really production-grade span stuff would involve interners and compression stuff. I think there's an opportunity here for config-rs to be a bit of a guiding light on this stuff, since it wants to cram everything into a unified framework. |
After some brief discussion with @zkat on mastodon (thread): I guess we also want to put down into the vision the fact that the crate should be as format agnostic as possible. Right now, we're holding JSONish data still: pub enum ConfigElement {
Null,
Bool(bool),
I8(i8),
I16(i16),
/* and some more... */
List(Vec<ConfigElement>),
Map(HashMap<String, ConfigElement>),
} (here). But for KDL or XML to work, that's not enough. I guess we would need some system where That as well as span information (as noted by @Gankra above) should be considered crucial features, I think. |
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
Does 7994b36 fit? Is there something else that should be added? |
I've been playing with this a bit now and I noticed that being format independent will make things really hard. Because the layering and accessing of values needs to be able to understand and traverse data. If we abstract access to values via a trait inside config-rs, that might make things really hard to implement. I do still think that this is a viable goal and should be included, though! |
bors merge |
Build succeeded: |
This PR adds the vision document for this crate, to document what the idea is and what we aim for.