From 638c035eeee9e60a8b7c54d4fa1ab5eb7c99abd6 Mon Sep 17 00:00:00 2001 From: Erik Flodin Date: Thu, 20 Mar 2025 22:03:33 +0100 Subject: [PATCH] Add support for running commands from default template processor In a default template, "{% command something arg1 ... argN %}" will be replaced by the first line output from the command "something" run with the given arguments (#452). --- .github/workflows/test.yml | 1 + test/test_unit_template_default.py | 33 ++++++++++++++++++++++++++++++ yadm | 14 ++++++++++++- yadm.1 | 4 ++++ 4 files changed, 51 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 710b0e8..f392877 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -43,6 +43,7 @@ jobs: if: ${{ runner.os == 'macOS' }} run: | command -v expect || brew install expect + command -v sha1sum || brew install md5sha1sum - name: Install dependencies on Windows (WSL) if: ${{ runner.os == 'Windows' }} diff --git a/test/test_unit_template_default.py b/test/test_unit_template_default.py index a4532c2..8c312aa 100644 --- a/test/test_unit_template_default.py +++ b/test/test_unit_template_default.py @@ -1,5 +1,6 @@ """Unit tests: template_default""" +import hashlib import os FILE_MODE = 0o754 @@ -169,6 +170,18 @@ Include basic again: basic """ +TEMPLATE_COMMAND = """\ +sha1="{% command sha1sum "{{ yadm.filename }}" | cut -d' ' -f1 %}" +{% command sha1sum "no endtag" +{% command echo foobar | tr oa OA %} +""" + +EXPECTED_COMMAND = """\ +sha1="{SHA1}" +{{% command sha1sum "no endtag" +fOObAr +""" + TEMPLATE_NESTED_IFS = """\ {% if yadm.user == "me" %} print1 @@ -296,6 +309,26 @@ def test_include(runner, yadm, tmpdir): assert os.stat(output_file).st_mode == os.stat(input_file).st_mode +def test_command(runner, yadm, tmpdir): + """Test custom commands""" + + input_file = tmpdir.join("input with space") + input_file.write(TEMPLATE_COMMAND, ensure=True) + output_file = tmpdir.join("output") + + expected = EXPECTED_COMMAND.format(SHA1=hashlib.sha1(TEMPLATE_COMMAND.encode(), usedforsecurity=False).hexdigest()) + + script = f""" + YADM_TEST=1 source {yadm} + set_awk + template default "{input_file}" "{output_file}" + """ + run = runner(command=["bash"], inp=script) + assert run.success + assert run.err == "" + assert output_file.read() == expected + + def test_nested_ifs(runner, yadm, tmpdir): """Test nested if statements""" diff --git a/yadm b/yadm index 9757345..fac1a90 100755 --- a/yadm +++ b/yadm @@ -436,7 +436,19 @@ BEGIN { filename[++current] = include line[current] = 0 } - else { print } + else { + if (match($0, /\{%[ \t]*command[ \t]+/)) { + prefix = substr($0, 0, RSTART - 1) + command = substr($0, RSTART + RLENGTH) + if (match(command, /[ \t]*%\}/) && RSTART > 1) { + suffix = substr(command, RSTART + RLENGTH) + command = substr(command, 0, RSTART - 1) + command | getline + $0 = prefix $0 suffix + } + } + print + } } } if (res >= 0) { close(filename[current]) } diff --git a/yadm.1 b/yadm.1 index b62dbbd..85de15e 100644 --- a/yadm.1 +++ b/yadm.1 @@ -739,6 +739,7 @@ with the following content {% if yadm.user == "harvey" %} config={{yadm.class}}-{{yadm.os}} + user={% command echo "{{ yadm.user }}" | tr a-z A-Z %} {% else %} config=dev-whatever {% include "whatever.extra" %} @@ -749,6 +750,7 @@ would output a file named with the following content if the user is "harvey": config=work-Linux + user=HARVEY and the following otherwise (if .I whatever.extra @@ -763,6 +765,7 @@ would look like: {% if YADM_USER == 'harvey' -%} config={{YADM_CLASS}}-{{YADM_OS}} + user={{ YADM_USER | upper }} {% else -%} config=dev-whatever {% include 'whatever.extra' %} @@ -774,6 +777,7 @@ would look like: <% if [ "$YADM_USER" = "harvey" ]; then -%> config=<%= $YADM_CLASS %>-<%= $YADM_OS %> + user=<% echo "$YADM_USER" | tr a-z A-Z %> <% else -%> config=dev-whatever <%+ whatever.extra %>