diff --git a/Cargo.lock b/Cargo.lock index ffa87ba87..7c999fdeb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] @@ -634,9 +634,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.24" +version = "1.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812acba72f0a070b003d3697490d2b55b837230ae7c6c6497f05cc2ddbb8d938" +checksum = "2e80e3b6a3ab07840e1cae9b0666a63970dc28e8ed5ffbcdacbfc760c281bfc1" dependencies = [ "jobserver", "libc", @@ -709,9 +709,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.19" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7be5744db7978a28d9df86a214130d106a89ce49644cbc4e3f0c22c3fba30615" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" dependencies = [ "clap_builder", "clap_derive", @@ -729,9 +729,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.19" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5fbc17d3ef8278f55b282b2a2e75ae6f6c7d4bb70ed3d0382375104bfafdb4b" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" dependencies = [ "anstream", "anstyle", @@ -741,18 +741,18 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.32" +version = "4.5.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74a01f4f9ee6c066d42a1c8dedf0dcddad16c72a8981a309d6398de3a75b0c39" +checksum = "9646e2e245bf62f45d39a0f3f36f1171ad1ea0d6967fd114bca72cb02a8fcdfb" dependencies = [ "clap", ] [[package]] name = "clap_complete_nushell" -version = "4.5.3" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fe32110e006bccf720f8c9af3fee1ba7db290c724eab61544e1d3295be3a40e" +checksum = "315902e790cc6e5ddd20cbd313c1d0d49db77f191e149f96397230fb82a17677" dependencies = [ "clap", "clap_complete", @@ -1357,6 +1357,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + [[package]] name = "foreign-types" version = "0.3.2" @@ -1577,9 +1583,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.31.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" @@ -1732,6 +1738,11 @@ name = "hashbrown" version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] [[package]] name = "hashlink" @@ -1891,9 +1902,9 @@ dependencies = [ [[package]] name = "http-content-range" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f0d1a8ef218a86416107794b34cc446958d9203556c312bb41eab4c924c1d2e" +checksum = "162948b27201b0f0eb2691726b03694ecab6d670916949796f9e6cb3637c4e7c" [[package]] name = "http-serde" @@ -2000,7 +2011,7 @@ dependencies = [ "http 1.1.0", "hyper 1.4.1", "hyper-util", - "rustls 0.23.13", + "rustls 0.23.14", "rustls-native-certs", "rustls-pki-types", "tokio", @@ -2211,9 +2222,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.10.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" [[package]] name = "is_ci" @@ -2428,11 +2439,11 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lru" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ee39891760e7d94734f6f63fedc29a2e4a152f836120753a72503f09fcf904" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "hashbrown 0.14.5", + "hashbrown 0.15.0", ] [[package]] @@ -2581,9 +2592,9 @@ dependencies = [ [[package]] name = "minijinja" -version = "1.0.14" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe5b00f90b3542f74bb9aaaccd2627920c16367787de103883461365580e5481" +checksum = "1028b628753a7e1a88fc59c9ba4b02ecc3bc0bd3c7af23df667bc28df9b3310e" dependencies = [ "aho-corasick", "serde", @@ -2790,21 +2801,18 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "object" -version = "0.36.4" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.20.1" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1" -dependencies = [ - "portable-atomic", -] +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "openssl" @@ -3115,18 +3123,18 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" dependencies = [ "proc-macro2", "quote", @@ -3228,9 +3236,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" dependencies = [ "unicode-ident", ] @@ -3296,7 +3304,7 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.23.13", + "rustls 0.23.14", "socket2", "thiserror", "tokio", @@ -3313,7 +3321,7 @@ dependencies = [ "rand", "ring", "rustc-hash", - "rustls 0.23.13", + "rustls 0.23.14", "slab", "thiserror", "tinyvec", @@ -3471,6 +3479,7 @@ dependencies = [ "indicatif", "insta", "itertools 0.13.0", + "lazy_static", "marked-yaml", "memchr", "memmap2 0.9.5", @@ -4084,7 +4093,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.13", + "rustls 0.23.14", "rustls-native-certs", "rustls-pemfile 2.2.0", "rustls-pki-types", @@ -4289,9 +4298,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.13" +version = "0.23.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" +checksum = "415d9944693cb90382053259f89fbb077ea730ad7273047ec63b19bc9b160ba8" dependencies = [ "once_cell", "ring", @@ -4382,9 +4391,9 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.24" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b" +checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" dependencies = [ "windows-sys 0.59.0", ] @@ -4688,9 +4697,9 @@ checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" [[package]] name = "simd-json" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f0b376aada35f30a0012f5790e50aed62f91804a0682669aefdbe81c7fcb91" +checksum = "bfa5500f67df6466a45c6f83d1aada89fe0f7e9b17afec424ea06feee0906549" dependencies = [ "getrandom", "halfbrown", @@ -5174,7 +5183,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.13", + "rustls 0.23.14", "rustls-pki-types", "tokio", ] diff --git a/Cargo.toml b/Cargo.toml index bdff303aa..c6d4797c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,8 +61,8 @@ content_inspector = "0.2.4" serde_with = "3.11.0" url = "2.5.2" tracing = "0.1.40" -clap = { version = "4.5.19", features = ["derive", "env", "cargo"] } -minijinja = { version = "=1.0.14", features = [ +clap = { version = "4.5.20", features = ["derive", "env", "cargo"] } +minijinja = { version = "2.3.1", features = [ "unstable_machinery", "custom_syntax", ] } @@ -96,8 +96,8 @@ indexmap = "2.6.0" dunce = "1.0.5" fs-err = "2.11.0" which = "6.0.3" -clap_complete = "4.5.32" -clap_complete_nushell = "4.5.3" +clap_complete = "4.5.33" +clap_complete_nushell = "4.5.4" tokio-util = "0.7.12" tar = "0.4.42" @@ -141,6 +141,7 @@ rattler_shell = { version = "0.22.4", default-features = false, features = ["sys rattler_solve = { version = "1.1.0", default-features = false, features = ["resolvo", "serde"] } rattler_virtual_packages = { version = "1.1.7", default-features = false } rattler_package_streaming = { version = "0.22.10", default-features = false } +lazy_static = "1.5.0" [dev-dependencies] insta = { version = "1.40.0", features = ["yaml"] } diff --git a/docs/reference/jinja.md b/docs/reference/jinja.md index 7a0cfcef9..5e1faa316 100644 --- a/docs/reference/jinja.md +++ b/docs/reference/jinja.md @@ -232,7 +232,7 @@ will return `1`) - `last`: return the last element of a list (e.g. `"{{ [1, 2, 3 - `sort`: sort a list (e.g. `"{{ [3, 1, 2] | sort }}"` will return `[1, 2, 3]`) - `trim`: remove leading and trailing whitespace from a string (e.g. `"{{ ' foo ' | trim }}"` will return `"foo"`) - `unique`: remove duplicates from a list (e.g. `"{{ [1, 2, 1, 3] | unique }}"` will return `[1, 2, 3]`) -- `split`: split a string into a list (e.g. `"{{ '1.2.3' | split('.') }}"` will return `['1', '2', '3']`). By default, splits on whitespace. +- `split`: split a string into a list (e.g. `"{{ '1.2.3' | split('.') | list }}"` will return `['1', '2', '3']`). By default, splits on whitespace. ??? "Removed filters" diff --git a/src/recipe/jinja.rs b/src/recipe/jinja.rs index e2e73d977..df84a6335 100644 --- a/src/recipe/jinja.rs +++ b/src/recipe/jinja.rs @@ -1,6 +1,7 @@ //! Module for types and functions related to miniJinja setup for recipes. use fs_err as fs; +use minijinja::syntax::SyntaxConfig; use std::process::Command; use std::sync::Arc; use std::{collections::BTreeMap, str::FromStr}; @@ -333,12 +334,6 @@ fn default_filters(env: &mut Environment) { format!("{}{}", major, minor) }); - env.add_filter("split", |s: String, sep: Option| -> Vec { - s.split(sep.as_deref().unwrap_or(" ")) - .map(|s| s.to_string()) - .collect() - }); - env.add_filter("replace", minijinja::filters::replace); env.add_filter("lower", minijinja::filters::lower); env.add_filter("upper", minijinja::filters::upper); @@ -359,6 +354,7 @@ fn default_filters(env: &mut Environment) { env.add_filter("sort", minijinja::filters::sort); env.add_filter("trim", minijinja::filters::trim); env.add_filter("unique", minijinja::filters::unique); + env.add_filter("split", minijinja::filters::split); } fn parse_platform(platform: &str) -> Result { @@ -370,6 +366,16 @@ fn parse_platform(platform: &str) -> Result { }) } +lazy_static::lazy_static! { + /// The syntax config for MiniJinja / rattler-build + pub static ref SYNTAX_CONFIG: SyntaxConfig = SyntaxConfig::builder() + .block_delimiters("{%", "%}") + .variable_delimiters("${{", "}}") + .comment_delimiters("#{{", "}}") + .build() + .unwrap(); +} + fn set_jinja(config: &SelectorConfig) -> minijinja::Environment<'static> { let SelectorConfig { target_platform, @@ -386,15 +392,7 @@ fn set_jinja(config: &SelectorConfig) -> minijinja::Environment<'static> { default_filters(&mut env); // Ok to unwrap here because we know that the syntax is valid - env.set_syntax(minijinja::Syntax { - block_start: "{%".into(), - block_end: "%}".into(), - variable_start: "${{".into(), - variable_end: "}}".into(), - comment_start: "#{{".into(), - comment_end: "}}#".into(), - }) - .expect("is tested to be correct"); + env.set_syntax(SYNTAX_CONFIG.clone()); let variant = Arc::new(variant.clone()); @@ -624,12 +622,8 @@ impl Git { } impl Object for Git { - fn kind(&self) -> minijinja::value::ObjectKind<'_> { - minijinja::value::ObjectKind::Plain - } - fn call_method( - &self, + self: &Arc, _state: &minijinja::State, name: &str, args: &[Value], @@ -684,12 +678,8 @@ impl Env { } impl Object for Env { - fn kind(&self) -> minijinja::value::ObjectKind<'_> { - minijinja::value::ObjectKind::Plain - } - fn call_method( - &self, + self: &Arc, _state: &minijinja::State, name: &str, args: &[Value], @@ -1114,12 +1104,28 @@ mod tests { "split".to_string() }; - jinja.eval(&format!("var | {func}")).unwrap().to_string() + jinja + .eval(&format!("var | {func} | list")) + .unwrap() + .to_string() }; assert_eq!(split_test("foo bar", None), "[\"foo\", \"bar\"]"); assert_eq!(split_test("foobar", None), "[\"foobar\"]"); assert_eq!(split_test("1.2.3", Some(".")), "[\"1\", \"2\", \"3\"]"); + + jinja.context_mut().insert( + "var".to_string(), + Value::from_safe_string("1.2.3".to_string()), + ); + + assert_eq!( + jinja + .eval(&format!("(var | split('.'))[2]")) + .unwrap() + .to_string(), + "3" + ); } #[test] diff --git a/src/used_variables.rs b/src/used_variables.rs index 61254bb21..a6257098c 100644 --- a/src/used_variables.rs +++ b/src/used_variables.rs @@ -14,11 +14,12 @@ use std::collections::{HashSet, VecDeque}; use marked_yaml::Span; use minijinja::machinery::{ ast::{self, Expr, Stmt}, - parse, + parse_expr, WhitespaceConfig, }; use crate::recipe::{ custom_yaml::{self, HasSpan, Node, ScalarNode, SequenceNodeInternal}, + jinja::SYNTAX_CONFIG, parser::CollectErrors, ParsingError, }; @@ -38,6 +39,18 @@ fn extract_variables(node: &Stmt, variables: &mut HashSet) { } } +fn parse<'source>( + expr: &'source str, + filename: &str, +) -> Result, minijinja::Error> { + minijinja::machinery::parse( + expr, + filename, + SYNTAX_CONFIG.clone(), + WhitespaceConfig::default(), + ) +} + /// Extract all variables from a jinja expression (called from [`extract_variables`]) fn extract_variable_from_expression(expr: &Expr, variables: &mut HashSet) { match expr { @@ -130,12 +143,12 @@ fn find_jinja( ) -> Result<(), Vec> { let mut errs = Vec::::new(); let mut queue = VecDeque::from([(node, src)]); + while let Some((node, src)) = queue.pop_front() { match node { Node::Mapping(map) => { for (_, value) in map.iter() { queue.push_back((value, src)); - // find_jinja(value, src, variables)?; } } Node::Sequence(seq) => { @@ -143,16 +156,13 @@ fn find_jinja( match item { SequenceNodeInternal::Simple(node) => queue.push_back((node, src)), SequenceNodeInternal::Conditional(if_sel) => { - // we need to convert the if condition to a Jinja expression to parse it - let as_jinja_expr = format!("${{{{ {} }}}}", if_sel.cond().as_str()); - match parse(&as_jinja_expr, "jinja.yaml") { - Ok(ast) => { - extract_variables(&ast, variables); + match parse_expr(if_sel.cond().as_str()) { + Ok(expr) => { + extract_variable_from_expression(&expr, variables); queue.push_back((if_sel.then(), src)); - // find_jinja(if_sel.then(), src, variables)?; + if let Some(otherwise) = if_sel.otherwise() { queue.push_back((otherwise, src)); - // find_jinja(otherwise, src, variables)?; } } Err(err) => {