Add support for including files using the default template processor

The syntax is '{% include "file" %}' where file is either an absolute path or a
path relative to the current template file's directory.

Variables in the included file will be replaced as for the main template. But
the included file can't include files itself.
This commit is contained in:
Erik Flodin 2020-10-09 15:36:58 +02:00
parent 48d77c9f21
commit 9bcf070dfe
No known key found for this signature in database
GPG Key ID: 420A7C865EE3F85F
3 changed files with 97 additions and 3 deletions

View File

@ -88,6 +88,36 @@ Included section for distro = {LOCAL_DISTRO} ({LOCAL_DISTRO} again)
end of template
'''
INCLUDE_BASIC = 'basic\n'
INCLUDE_VARIABLES = f'''\
included <{{{{ yadm.class }}}}> file
empty line above
'''
INCLUDE_NESTED = 'no newline at the end'
TEMPLATE_INCLUDE = '''\
The first line
{% include empty %}
An empty file removes the line above
{%include basic%}
{% include "./variables.{{ yadm.os }}" %}
{% include dir/nested %}
Include basic again:
{% include basic %}
'''
EXPECTED_INCLUDE = f'''\
The first line
An empty file removes the line above
basic
included <{LOCAL_CLASS}> file
empty line above
no newline at the end
Include basic again:
basic
'''
def test_template_default(runner, yadm, tmpdir):
"""Test template_default"""
@ -132,3 +162,37 @@ def test_source(runner, yadm, tmpdir):
assert run.err == ''
assert output_file.read().strip() == str(input_file)
assert os.stat(output_file).st_mode == os.stat(input_file).st_mode
def test_include(runner, yadm, tmpdir):
"""Test include"""
empty_file = tmpdir.join('empty')
empty_file.write('', ensure=True)
basic_file = tmpdir.join('basic')
basic_file.write(INCLUDE_BASIC)
variables_file = tmpdir.join(f'variables.{LOCAL_SYSTEM}')
variables_file.write(INCLUDE_VARIABLES)
nested_file = tmpdir.join('dir').join('nested')
nested_file.write(INCLUDE_NESTED, ensure=True)
input_file = tmpdir.join('input')
input_file.write(TEMPLATE_INCLUDE)
input_file.chmod(FILE_MODE)
output_file = tmpdir.join('output')
script = f"""
YADM_TEST=1 source {yadm}
set_awk
local_class="{LOCAL_CLASS}"
local_system="{LOCAL_SYSTEM}"
template_default "{input_file}" "{output_file}"
"""
run = runner(command=['bash'], inp=script)
assert run.success
assert run.err == ''
assert output_file.read() == EXPECTED_INCLUDE
assert os.stat(output_file).st_mode == os.stat(input_file).st_mode

28
yadm
View File

@ -357,8 +357,13 @@ BEGIN {
els = "^{%" blank "*else" blank "*%}$"
end = "^{%" blank "*endif" blank "*%}$"
skp = "^{%" blank "*(if|else|endif)"
inc_start = "^{%" blank "*include" blank "+\"?"
inc_end = "\"?" blank "*%}$"
inc = inc_start ".+" inc_end
prt = 1
err = 0
}
END { exit err }
{ replace_vars() } # variable replacements
$0 ~ vld, $0 ~ end {
if ($0 ~ vld || $0 ~ end) prt=1;
@ -370,7 +375,25 @@ $0 ~ vld, $0 ~ end {
if ($0 ~ els || $0 ~ end) prt=1;
if ($0 ~ skp) next;
}
{ if (prt) print }
{ if (!prt) next }
$0 ~ inc {
file = $0
sub(inc_start, "", file)
sub(inc_end, "", file)
sub(/^[^\/].*$/, source_dir "/&", file)
while ((res = getline <file) > 0) {
replace_vars()
print
}
if (res < 0) {
printf "%s:%d: error: could not read '%s'\n", FILENAME, NR, file | "cat 1>&2"
err = 1
}
close(file)
next
}
{ print }
function replace_vars() {
for (label in c) {
gsub(("{{" blank "*yadm\\." label blank "*}}"), c[label])
@ -396,8 +419,9 @@ EOF
-v user="$local_user" \
-v distro="$local_distro" \
-v source="$input" \
-v source_dir="$(dirname "$input")" \
"$awk_pgm" \
"$input" > "$temp_file"
"$input" > "$temp_file" || rm -f "$temp_file"
if [ -f "$temp_file" ] ; then
copy_perms "$input" "$temp_file"

8
yadm.1
View File

@ -708,6 +708,7 @@ with the following content
config={{yadm.class}}-{{yadm.os}}
{% else %}
config=dev-whatever
{% include "whatever.extra" %}
{% endif %}
would output a file named
@ -716,9 +717,12 @@ with the following content if the user is "harvey":
config=work-Linux
and the following otherwise:
and the following otherwise (if
.I whatever.extra
contains admin=false):
config=dev-whatever
admin=false
An equivalent Jinja template named
.I whatever##template.j2
@ -728,6 +732,7 @@ would look like:
config={{YADM_CLASS}}-{{YADM_OS}}
{% else -%}
config=dev-whatever
{% include 'whatever.extra' %}
{% endif -%}
An equivalent ESH templated named
@ -738,6 +743,7 @@ would look like:
config=<%= $YADM_CLASS %>-<%= $YADM_OS %>
<% else -%>
config=dev-whatever
<%+ whatever.extra %>
<% fi -%>
.SH ENCRYPTION