Skip to content

Commit 774c092

Browse files
authored
Merge pull request #14 from bordeux/feature/fix-include-problem
fix: implement dynamic template loader for include functionality
2 parents 71f5484 + 989feba commit 774c092

14 files changed

Lines changed: 574 additions & 163 deletions

.github/pull_request_template.md

Lines changed: 0 additions & 158 deletions
This file was deleted.

Cargo.lock

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ keywords = ["template", "minijinja", "cli", "environment", "variables"]
1010
categories = ["command-line-utilities", "template-engine"]
1111

1212
[dependencies]
13-
minijinja = { version = "2", features = ["builtins"] }
13+
minijinja = { version = "2", features = ["builtins", "loader"] }
1414
clap = { version = "4", features = ["derive"] }
1515
serde = { version = "1", features = ["derive"] }
1616
regex = "1"

README.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
[![Docker](https://img.shields.io/badge/docker-ghcr.io-blue)](https://github.com/bordeux/tmpltool/pkgs/container/tmpltool)
88
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
99

10-
A fast and simple command-line template rendering tool using [Tera](https://keats.github.io/tera/) templates with environment variables.
10+
A fast and simple command-line template rendering tool using [MiniJinja](https://github.com/mitsuhiko/minijinja) templates with environment variables.
1111

1212
## Table of Contents
1313

@@ -71,7 +71,7 @@ tmpltool greeting.tmpl
7171
- **Validation**: Validate emails, URLs, IPs, UUIDs, regex matching
7272
- **Security**: Built-in protections with optional `--trust` mode
7373
- **Flexible I/O**: File or stdin input, file or stdout output
74-
- **Full Tera Syntax**: Conditionals, loops, filters, and more
74+
- **Full Jinja2 Syntax**: Conditionals, loops, filters, and more
7575
- **Single Binary**: No runtime dependencies
7676
- **Docker Support**: Multi-arch images available
7777

@@ -285,7 +285,7 @@ tmpltool build-report.tmpl
285285

286286
## Template Syntax
287287

288-
tmpltool uses the [Tera](https://keats.github.io/tera/) template engine. For complete documentation, visit: https://keats.github.io/tera/docs/
288+
tmpltool uses the [MiniJinja](https://github.com/mitsuhiko/minijinja) template engine, which is compatible with Python's Jinja2. For complete documentation, visit: https://docs.rs/minijinja/
289289

290290
### Variables
291291

@@ -1346,4 +1346,6 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
13461346

13471347
For more examples, see the [examples/](examples/) directory and [examples/README.md](examples/README.md).
13481348

1349-
For complete Tera syntax documentation, visit: https://keats.github.io/tera/docs/
1349+
For complete MiniJinja/Jinja2 syntax documentation, visit:
1350+
- MiniJinja Docs: https://docs.rs/minijinja/
1351+
- Jinja2 Template Designer: https://jinja.palletsprojects.com/templates/

examples/test-include.tmpl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Testing relative path resolution:
2+
3+
File content from ./basic.tmpl parsed:
4+
{% include "./basic.tmpl" %}
5+
6+
End of test.

src/renderer.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,49 @@ fn render(
8585
// Set strict undefined behavior - fail on undefined variables (like Tera)
8686
env.set_undefined_behavior(minijinja::UndefinedBehavior::Strict);
8787

88+
// Clone template_context for use in the loader closure
89+
let loader_context = template_context.clone();
90+
91+
// Set up lazy template loader for includes
92+
env.set_loader(move |name: &str| -> Result<Option<String>, minijinja::Error> {
93+
// Validate path security unless in trust mode
94+
if !loader_context.is_trust_mode() {
95+
if name.starts_with('/') {
96+
return Err(minijinja::Error::new(
97+
minijinja::ErrorKind::InvalidOperation,
98+
format!(
99+
"Security: Absolute paths are not allowed: {}. Use --trust to bypass this restriction.",
100+
name
101+
),
102+
));
103+
}
104+
if name.contains("..") {
105+
return Err(minijinja::Error::new(
106+
minijinja::ErrorKind::InvalidOperation,
107+
format!(
108+
"Security: Parent directory (..) traversal is not allowed: {}. Use --trust to bypass this restriction.",
109+
name
110+
),
111+
));
112+
}
113+
}
114+
115+
// Resolve the template path relative to the base directory
116+
let resolved_path = loader_context.resolve_path(name);
117+
118+
// Read the template file
119+
match fs::read_to_string(&resolved_path) {
120+
Ok(content) => Ok(Some(content)),
121+
Err(e) => {
122+
// Return a helpful error message
123+
Err(minijinja::Error::new(
124+
minijinja::ErrorKind::TemplateNotFound,
125+
format!("Failed to load template '{}': {}", resolved_path.display(), e),
126+
))
127+
}
128+
}
129+
});
130+
88131
// Register all custom functions
89132
functions::register_all(&mut env, template_context);
90133

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Header: Default Header
2+
Content from partial template.
3+
User: guest
4+
Footer: Done
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Main template start
2+
Level 1 start
3+
Level 2: nested value
4+
Level 1 end
5+
Main template end
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Header: {{ get_env(name="HEADER", default="Default Header") }}
2+
{% include "./include_partial.tmpl" %}
3+
Footer: Done
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Level 1 start
2+
{% include "./include_nested_level2.tmpl" %}
3+
Level 1 end

0 commit comments

Comments
 (0)