tweag / nickel

Better configuration for less

Home Page:https://nickel-lang.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Feature request: Examples of how to use this to configure a rust program.

cstorey opened this issue · comments

I've an application where i might need to update small parts of th configuration for different environments (credentials, which messaging topics to subscribe to, etc). I'm currently using dhall for this, but it seems like the current implementation is no longer maintained.

i've been thinking that nickel might be a good replacement for this, but I can't find clear guidance on how to integrate this for configuration (eg: being able to pass an io::Reader into nickle function, and get back either a deserialized data type or a useful error).

I'd love to see a clear examples of how to do this, along with helper functions like serde_dhall::from_file that make it easy to use for common cases, while preservinvg the existing usage for less common cases.

It's entirely possible for me to pick through the types (eg: it looks like various types in the crate implement serde's Deserialize/r, but I've never quite had the time to properly sit through it and implement it.

Thanks for your consideration.

Hey, thanks for the question! We've been definitely more focused on the CLI usage than the rust APIs, so most things here are under-documented and subject to change. But you should be able to get started by using Program::new_from_source to load from a std::io::Read (or see the other Program::new_from... methods). Then Program::eval_full_for_export will give you back a RichTerm that implements serde::Serialize. You can either serialize it to some format, or use serde-transcode to convert it to something else.

For a full example, you could look at the code for the export cli command

Oh, amazing. Thanks for the pointers!

Additionally, the tests of the deserialize module are also a good inspiration on how to just eval a Nickel string and get back an arbitrary Rust structure that derives Deserialize:

mod tests {

FWIW, here's what seemed to work for me (with Nickel 0.4), based on the hints above - please note it can probably be improved, it's just in the hacked-together state in which I first got it to work:

https://github.com/akavel/mana/blob/01736bebe81d355335368992e6b19e543f025cbf/src/main.rs#L254-L272

    use nickel_lang_core::error::report::ErrorFormat;
    use nickel_lang_core::eval::cache::lazy::CBNCache;
    use nickel_lang_core::program::Program as Prog;
    let err = std::io::stderr();
    let mut prog = Prog::<CBNCache>::new_from_file(&path, err)?;
    let res_field = prog.parse_field_path(field_path.clone());
    let Ok(field) = res_field else {
        prog.report(res_field.unwrap_err(), ErrorFormat::Text);
        bail!("failed to parse {field_path:?} as Nickel path");
    };
    prog.field = field;
    let res_term = prog.eval_full_for_export();
    let Ok(term) = res_term else {
        prog.report(res_term.unwrap_err(), ErrorFormat::Text);
        bail!("script {path:?} failed");
    };
    // FIXME: shorten to: toml::Table::deserialize(term)
    let toml = toml::to_string(&term).unwrap();
    parse_input_toml(&toml)