summaryrefslogtreecommitdiff
path: root/lib/ansible/template
diff options
context:
space:
mode:
authorMatt Martz <matt@sivel.net>2019-06-06 14:49:27 -0500
committerBrian Coca <bcoca@users.noreply.github.com>2019-06-06 15:49:26 -0400
commit728fce0c4474e3ef8d38f62934454070605c8d1a (patch)
tree015b9a6d2a51cae7bc8027151b1459c4bfc00f82 /lib/ansible/template
parent95882faca6e3e37119d6b53a1dfb6138e33aefd3 (diff)
downloadansible-728fce0c4474e3ef8d38f62934454070605c8d1a.tar.gz
Perf improvement for Templar.is_template (#57489)
* Faster is_template
Diffstat (limited to 'lib/ansible/template')
-rw-r--r--lib/ansible/template/__init__.py68
1 files changed, 40 insertions, 28 deletions
diff --git a/lib/ansible/template/__init__.py b/lib/ansible/template/__init__.py
index ec4bf67713..e942ce5da6 100644
--- a/lib/ansible/template/__init__.py
+++ b/lib/ansible/template/__init__.py
@@ -88,6 +88,10 @@ else:
from jinja2.utils import concat as j2_concat
+JINJA2_BEGIN_TOKENS = frozenset(('variable_begin', 'block_begin', 'comment_begin', 'raw_begin'))
+JINJA2_END_TOKENS = frozenset(('variable_end', 'block_end', 'comment_end', 'raw_end'))
+
+
def generate_ansible_template_vars(path, dest_path=None):
b_path = to_bytes(path)
try:
@@ -159,6 +163,39 @@ def _escape_backslashes(data, jinja_env):
return data
+def is_template(data, jinja_env):
+ """This function attempts to quickly detect whether a value is a jinja2
+ template. To do so, we look for the first 2 matching jinja2 tokens for
+ start and end delimiters.
+ """
+ found = None
+ start = True
+ comment = False
+ d2 = jinja_env.preprocess(data)
+
+ # This wraps a lot of code, but this is due to lex returing a generator
+ # so we may get an exception at any part of the loop
+ try:
+ for token in jinja_env.lex(d2):
+ if token[1] in JINJA2_BEGIN_TOKENS:
+ if start and token[1] == 'comment_begin':
+ # Comments can wrap other token types
+ comment = True
+ start = False
+ # Example: variable_end -> variable
+ found = token[1].split('_')[0]
+ elif token[1] in JINJA2_END_TOKENS:
+ if token[1].split('_')[0] == found:
+ return True
+ elif comment:
+ continue
+ return False
+ except TemplateSyntaxError:
+ return False
+
+ return False
+
+
def _count_newlines_from_end(in_str):
'''
Counts the number of newlines at the end of a string. This is used during
@@ -498,7 +535,7 @@ class Templar:
if isinstance(variable, string_types):
result = variable
- if self._contains_vars(variable):
+ if self.is_template(variable):
# Check to see if the string we are trying to render is just referencing a single
# var. In this case we don't want to accidentally change the type of the variable
# to a string by using the jinja template renderer. We just want to pass it.
@@ -596,13 +633,7 @@ class Templar:
def is_template(self, data):
''' lets us know if data has a template'''
if isinstance(data, string_types):
- try:
- new = self.do_template(data, fail_on_undefined=True)
- except (AnsibleUndefinedVariable, UndefinedError):
- return True
- except Exception:
- return False
- return (new != data)
+ return is_template(data, self.environment)
elif isinstance(data, (list, tuple)):
for v in data:
if self.is_template(v):
@@ -613,26 +644,7 @@ class Templar:
return True
return False
- def templatable(self, data):
- '''
- returns True if the data can be templated w/o errors
- '''
- templatable = True
- try:
- self.template(data)
- except Exception:
- templatable = False
- return templatable
-
- def _contains_vars(self, data):
- '''
- returns True if the data contains a variable pattern
- '''
- if isinstance(data, string_types):
- for marker in (self.environment.block_start_string, self.environment.variable_start_string, self.environment.comment_start_string):
- if marker in data:
- return True
- return False
+ templatable = _contains_vars = is_template
def _convert_bare_variable(self, variable):
'''