diff --git a/CHANGELOG.md b/CHANGELOG.md index cf5606c4..fd9652f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to MiniJinja are documented here. +## 2.0.4 + +- minijinja-cli now supports `.ini` files. #532 + ## 2.0.3 - Added new methods to pycompat: `str.endswith`, `str.rfind`, diff --git a/Cargo.lock b/Cargo.lock index 9735664c..f3cb52d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -702,6 +702,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "configparser" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57e3272f0190c3f1584272d613719ba5fc7df7f4942fe542e63d949cf3a649b" + [[package]] name = "console" version = "0.15.8" @@ -2003,6 +2009,7 @@ dependencies = [ "clap_complete_fig", "clap_complete_nushell", "clap_mangen", + "configparser", "dunce", "insta", "insta-cmd", diff --git a/minijinja-cli/Cargo.toml b/minijinja-cli/Cargo.toml index 2493cd05..26957e4a 100644 --- a/minijinja-cli/Cargo.toml +++ b/minijinja-cli/Cargo.toml @@ -21,6 +21,7 @@ json5 = ["serde_json5"] repl = ["rustyline"] completions = ["clap_complete", "clap_complete_nushell", "clap_complete_fig"] unicode = ["minijinja/unicode"] +ini = ["configparser"] [dependencies] anyhow = "1.0.74" @@ -53,6 +54,7 @@ toml = { version = "0.7.6", optional = true } clap_complete = { version = "4", optional = true } clap_complete_fig = { version = "4", optional = true } clap_complete_nushell = { version = "4", optional = true } +configparser = { version = "3.1.0", optional = true } [build-dependencies] clap = { version = "4.3.21", default-features = false, features = [ diff --git a/minijinja-cli/README.md b/minijinja-cli/README.md index 47214647..e247a773 100644 --- a/minijinja-cli/README.md +++ b/minijinja-cli/README.md @@ -104,6 +104,8 @@ can be set to stdin at once. the compiled bytecode. - `-o`, `--output` ``: writes the output to a filename rather than stdout. +- `--select` ``: + select a path of the input data. - `--generate-completion` ``: generate the completions for the given shell. - `--version`: @@ -120,6 +122,37 @@ The following formats are supported: - `toml` (`*.toml`): TOML - `cbor` (`*.cbor`): CBOR - `querystring` (`*.qs`): URL encoded query strings +- `ini` (`*.ini`, `*.config`, `*.properties`): text only INI files + +For most formats there is a pretty straightforward mapping into the template +context. The only exception to this is currently INI files where sections are +effectively mandatory. If keys are placed in the unnamed section, the second +is renamed to `default`. You can use `--select` to make a section be implied: + +``` +minijinja-cli template.j2 input.ini --section default +``` + +Note that not all formats support all input types. For instance querystring +and INI will only support strings for the most part. + +## Selecting + +By default the input file is fed directly as context. You can however also +select a sub-portion of this file. For instance if you have a TOML file +where all variables are placed in the `values` section you normally need +to reference the values like so: + +```jinja +{{ values.key }} +``` + +If you however invoke minijinja-cli with `--select=values` you can directly +reference the keys: + +```jinja +{{ key }} +``` ## Examples @@ -177,6 +210,7 @@ selected when the defaults are turned off: * `cbor`: enables CBOR support * `json5`: enables JSON5 support (instead of JSON) * `querystring`: enables querystring support +* `ini`: enables INI support * `datetime`: enables the date and time filters and `now()` function * `completions`: enables the generation of completions * `unicode`: enables the unicode identifier support diff --git a/minijinja-cli/src/main.rs b/minijinja-cli/src/main.rs index 2ac57f81..7ff96973 100644 --- a/minijinja-cli/src/main.rs +++ b/minijinja-cli/src/main.rs @@ -105,6 +105,8 @@ fn load_data( Some("toml") => "toml", #[cfg(feature = "cbor")] Some("cbor") => "cbor", + #[cfg(feature = "ini")] + Some("ini" | "config" | "properties") => "ini", _ => bail!("cannot auto detect format from extension"), } } else { @@ -128,6 +130,14 @@ fn load_data( "toml" => toml::from_str(&contents)?, #[cfg(feature = "cbor")] "cbor" => ciborium::from_reader(contents.as_bytes())?, + #[cfg(feature = "ini")] + "ini" => { + let mut config = configparser::ini::Ini::new(); + config + .read(contents) + .map_err(|msg| anyhow!("could not load ini: {}", msg))?; + Value::from_serialize(config.get_map_ref()) + } _ => unreachable!(), }; diff --git a/minijinja-cli/tests/test_basic.rs b/minijinja-cli/tests/test_basic.rs index 990c241b..723fa01a 100644 --- a/minijinja-cli/tests/test_basic.rs +++ b/minijinja-cli/tests/test_basic.rs @@ -232,6 +232,44 @@ fn test_querystring() { "###); } +#[test] +#[cfg(feature = "ini")] +fn test_ini() { + let input = file_with_contents_and_ext("[section]\nfoo = bar", ".ini"); + let tmpl = file_with_contents(r#"Hello {{ section.foo }}!"#); + + assert_cmd_snapshot!( + cli() + .arg(tmpl.path()) + .arg(input.path()), + @r###" + success: true + exit_code: 0 + ----- stdout ----- + Hello bar! + + ----- stderr ----- + "###); + + let input = file_with_contents_and_ext("foo = bar", ".ini"); + let mut tmpl = NamedTempFile::new().unwrap(); + tmpl.write_all(br#"Hello {{ foo }}!"#).unwrap(); + + assert_cmd_snapshot!( + cli() + .arg("--select=default") + .arg(tmpl.path()) + .arg(input.path()), + @r###" + success: true + exit_code: 0 + ----- stdout ----- + Hello bar! + + ----- stderr ----- + "###); +} + #[test] fn test_context_stdin() { let tmpl = file_with_contents(r#"Hello {{ foo }}!"#);