Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/main/java/com/hubspot/jinjava/lib/tag/IncludeTag.java
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public String interpret(TagNode tagNode, JinjavaInterpreter interpreter) {
.getCurrentPathStack()
.push(templateFile, interpreter.getLineNumber(), interpreter.getPosition());

return interpreter.render(node);
return interpreter.render(node, false);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you explain a bit more why this is more correct?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ve been trying to check other examples of Cycle Exception being thrown. It was the only combination of tags like “import/export/extends” that reacted like that, ending up with TagCycleException which seems some kind of last resort in the case when common types of exceptions weren’t handled.
In that instance, we have an error because we went to render() method again before we actually pop the node from CurrentPathStack.

Comparing to “import”: there we also try to render the template when we got to the imported part, but unlike “include” we’re creating a new interpreter instance. It’s alright because jinja documentation told us so: “It’s important to know that imports are cached and imported templates don’t have access to the current template variables”
However, we cannot use the same trick with “import”. About this tag jinja has that statement: “Included templates have access to the variables of the active context by default”. So we must use the same interpreter for both the original templates and the imported ones.

Knowing that I found the only way to get rid of that problem: forbid the included template to render whatever we have inside ExtendedRoots. It shouldn’t break anything because eventually we will process them but it’s better to do that outside the imported template.

Sources for the behavior of each tag:
https://jinja.palletsprojects.com/en/2.11.x/templates/#include
https://jinja.palletsprojects.com/en/2.11.x/templates/#import

} catch (IOException e) {
throw new InterpretException(
e.getMessage(),
Expand Down
12 changes: 12 additions & 0 deletions src/test/java/com/hubspot/jinjava/lib/tag/IncludeTagTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -188,4 +188,16 @@ public void itSetsErrorLineNumbersCorrectlyTwoLevelsDeep() throws IOException {
assertThat(result.getErrors().get(0).getSourceTemplate().get())
.isEqualTo("tags/includetag/errors/error.html");
}

@Test
public void itAvoidsTagCycleExceptionInsideExtendedFiles() throws Exception {
String result = jinjava.render(
Resources.toString(
Resources.getResource("tags/extendstag/tagcycleexception/template-a.jinja"),
StandardCharsets.UTF_8
),
new HashMap<>()
);
assertThat(result).isEqualTo("Extended text, will be rendered");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{% extends 'tags/extendstag/tagcycleexception/template-b.jinja' %}
{% extends 'tags/extendstag/tagcycleexception/template-d.jinja' %}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{% import 'tags/extendstag/tagcycleexception/template-c.jinja' %}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Included text, won't be rendered
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Extended text, will be rendered