From 1d2b94f10c9c9abd8a1d7d0e217f253cd2087357 Mon Sep 17 00:00:00 2001 From: Konrad Wojas Date: Wed, 10 May 2023 16:14:26 +0800 Subject: [PATCH 1/9] Templates: support nested @IF statements --- .github/workflows/tests.yml | 2 + templating/templating.sh | 12 ++-- templating/test-templating.sh | 14 ++++ templating/testdata/test-expected.txt | 36 ++++++++++ .../testdata/test-template-include1.txt | 3 + .../testdata/test-template-include2.txt | 3 + templating/testdata/test-template.txt | 66 +++++++++++++++++++ 7 files changed, 131 insertions(+), 5 deletions(-) create mode 100755 templating/test-templating.sh create mode 100644 templating/testdata/test-expected.txt create mode 100644 templating/testdata/test-template-include1.txt create mode 100644 templating/testdata/test-template-include2.txt create mode 100644 templating/testdata/test-template.txt diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 32753dd..6972b99 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -20,6 +20,8 @@ jobs: with: fetch-depth: 5 submodules: recursive + - run: ./test-templating.sh + working-directory: ./templating - run: ./tests/test_versioning.sh working-directory: . - run: ./prepare.sh diff --git a/templating/templating.sh b/templating/templating.sh index 3dd73dc..377bcae 100755 --- a/templating/templating.sh +++ b/templating/templating.sh @@ -12,7 +12,7 @@ if [ "$1" = "" ]; then echo '@EXEC uname -a' echo '@EXEC [ "$foo" = "bar" ] && include bar.txt' echo '@IF [ "$foo" = "bar" ]' - echo 'This line is only printed if $foo = "bar" (cannot be nested)' + echo 'This line is only printed if $foo = "bar"' echo '@ENDIF' echo 'Other lines are printed unchanged.' echo @@ -28,15 +28,17 @@ tmpl_prefix=${tmpl_prefix:-@} include() { [ "$tmpl_debug" != "" ] && echo "$tmpl_comment $1" - local skip + local skip=0 local line local condition ( cat "$1" && echo ) | while IFS= read -r line; do if [[ $line = ${tmpl_prefix}ENDIF* ]]; then - skip= + # Only decrement if larger than 0, because it was only + # incremented if the block was disabled. + [ $skip -gt 0 ] && skip=$((skip-1)) [ "$tmpl_debug" != "" ] && echo "$tmpl_comment $line" - elif [ ! -z "$skip" ]; then + elif [ $skip -gt 0 ]; then # nothing, in IF that evaluated to false [ "$tmpl_debug" != "" ] && echo "$tmpl_comment $line" @@ -56,7 +58,7 @@ include() { elif [[ $line = ${tmpl_prefix}IF\ * ]]; then condition=${line#* } [ "$tmpl_debug" != "" ] && echo "$tmpl_comment $line" - eval "$condition" || skip=1 + eval "$condition" || skip=$((skip+1)) else echo "$line" diff --git a/templating/test-templating.sh b/templating/test-templating.sh new file mode 100755 index 0000000..75bd8ad --- /dev/null +++ b/templating/test-templating.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +set -e + +cd testdata + +if ! diff -u test-expected.txt <(../templating.sh test-template.txt) ; then + echo + echo "FAILED" + exit 1 +fi + +echo "PASSED" + diff --git a/templating/testdata/test-expected.txt b/templating/testdata/test-expected.txt new file mode 100644 index 0000000..e1ec386 --- /dev/null +++ b/templating/testdata/test-expected.txt @@ -0,0 +1,36 @@ +Lines can start with @INCLUDE, @EVAL or @EXEC for special processing, they +have no effect when not at the start of a line. + + +Direct @INCLUDE: +[Include file 1 start] +value of FOO in include is also 123 +[Include file 1 end] + + +The value of FOO is 123 + +Empty @EXEC: +@EXEC + +Conditional include in @EXEC: +[Second include start] +Hello world! +[Second include end] + + +This line is only printed if $FOO = "123", which is the case. +Nested IF that is true. +In between IFs. +Last line of first IF. + +Triple nested IF that is true. +Also true. +Second level. +First level. + + + + +Other lines are printed unchanged. + diff --git a/templating/testdata/test-template-include1.txt b/templating/testdata/test-template-include1.txt new file mode 100644 index 0000000..d508a36 --- /dev/null +++ b/templating/testdata/test-template-include1.txt @@ -0,0 +1,3 @@ +[Include file 1 start] +@EVAL value of FOO in include is also $FOO +[Include file 1 end] diff --git a/templating/testdata/test-template-include2.txt b/templating/testdata/test-template-include2.txt new file mode 100644 index 0000000..4b56018 --- /dev/null +++ b/templating/testdata/test-template-include2.txt @@ -0,0 +1,3 @@ +[Second include start] +@EXEC echo "Hello world!" +[Second include end] diff --git a/templating/testdata/test-template.txt b/templating/testdata/test-template.txt new file mode 100644 index 0000000..e728cdc --- /dev/null +++ b/templating/testdata/test-template.txt @@ -0,0 +1,66 @@ +Lines can start with @INCLUDE, @EVAL or @EXEC for special processing, they +have no effect when not at the start of a line. + +@EXEC FOO=123 + +Direct @INCLUDE: +@INCLUDE test-template-include1.txt + +@EVAL The value of FOO is $FOO + +Empty @EXEC: +@EXEC + +Conditional include in @EXEC: +@EXEC [ "$FOO" = "123" ] && include test-template-include2.txt + +@IF [ "$FOO" = "123" ] +This line is only printed if $FOO = "123", which is the case. +@IF true +Nested IF that is true. +@ENDIF +In between IFs. +@IF [ "$FOO" = "wrong" ] +THIS WILL NEVER BE PRINTED. +@ENDIF +Last line of first IF. +@ENDIF + +@IF true +@IF true +@IF true +Triple nested IF that is true. +@ENDIF +@IF true +Also true. +@ENDIF +Second level. +@ENDIF +First level. +@ENDIF + +@IF false +@IF true +@IF true +Triple nested IF that is FALSE. +@ENDIF +@ENDIF +@ENDIF + +@IF true +@IF false +@IF true +Triple nested IF that is FALSE. +@ENDIF +@ENDIF +@ENDIF + +@IF true +@IF true +@IF false +Triple nested IF that is FALSE. +@ENDIF +@ENDIF +@ENDIF + +Other lines are printed unchanged. From 97e1cf1a952063b7941d9eb92288664db6e38798 Mon Sep 17 00:00:00 2001 From: Konrad Wojas Date: Wed, 10 May 2023 16:26:42 +0800 Subject: [PATCH 2/9] Disable test schedule "This scheduled workflow is disabled because there hasn't been activity in this repository for at least 60 days. Enable this workflow to resume scheduled runs." This appears to disable the whole workflow, not just the schedule... --- .github/workflows/tests.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6972b99..571550c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -4,8 +4,10 @@ name: 'Run tests' on: push: pull_request: - schedule: - - cron: '0 7 * * *' + # Disabled, because Github appears to disable the whole workflow if you have a schedule + # and no updates for 60 days... + # schedule: + #- cron: '0 7 * * *' jobs: tests: From 38000c0b9fb56cc46fbe3bf2f40e8c0504c675f7 Mon Sep 17 00:00:00 2001 From: Konrad Wojas Date: Wed, 10 May 2023 17:04:52 +0800 Subject: [PATCH 3/9] Templating: fix nested @IF The previous implementation was flawed, because skip would only be incremented when a glock evaluated to false, but decremented for any @ENDIF, even if an inner one. --- templating/templating.sh | 40 +++++++++++++++++++-------- templating/testdata/test-expected.txt | 6 ++++ templating/testdata/test-template.txt | 8 ++++++ 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/templating/templating.sh b/templating/templating.sh index 377bcae..395cc83 100755 --- a/templating/templating.sh +++ b/templating/templating.sh @@ -28,17 +28,39 @@ tmpl_prefix=${tmpl_prefix:-@} include() { [ "$tmpl_debug" != "" ] && echo "$tmpl_comment $1" - local skip=0 + # Current level of @IF we are in + local iflevel=0 + # Set to the @IF level that disabled the current block, if any + local ifdisablelevel=0 local line local condition ( cat "$1" && echo ) | while IFS= read -r line; do - if [[ $line = ${tmpl_prefix}ENDIF* ]]; then - # Only decrement if larger than 0, because it was only - # incremented if the block was disabled. - [ $skip -gt 0 ] && skip=$((skip-1)) + + if [[ $line = ${tmpl_prefix}IF\ * ]]; then + [ "$tmpl_debug" != "" ] && echo "$tmpl_comment $line" + iflevel=$((iflevel+1)) + if ! [ $ifdisablelevel -gt 0 ]; then + # Only if not already in a disabled IF statement + condition=${line#* } + if ! eval "$condition" ; then + # Disabled at the current IF level + ifdisablelevel=$iflevel + fi + fi + + elif [[ $line = ${tmpl_prefix}ENDIF* ]]; then [ "$tmpl_debug" != "" ] && echo "$tmpl_comment $line" + if [ $iflevel = 0 ] ; then + echo "ERROR: @ENDIF without matching @IF in file $1" > /dev/stderr + exit 30 + fi + iflevel=$((iflevel-1)) + if [ $ifdisablelevel -gt $iflevel ]; then + # We left the IF block level that was disabled + ifdisablelevel=0 + fi - elif [ $skip -gt 0 ]; then + elif [ $ifdisablelevel -gt 0 ]; then # nothing, in IF that evaluated to false [ "$tmpl_debug" != "" ] && echo "$tmpl_comment $line" @@ -55,14 +77,10 @@ include() { line=${line#* } eval "$line" - elif [[ $line = ${tmpl_prefix}IF\ * ]]; then - condition=${line#* } - [ "$tmpl_debug" != "" ] && echo "$tmpl_comment $line" - eval "$condition" || skip=$((skip+1)) - else echo "$line" fi + done [ "$tmpl_debug" != "" ] && echo "$tmpl_comment /$1" } diff --git a/templating/testdata/test-expected.txt b/templating/testdata/test-expected.txt index e1ec386..ded0814 100644 --- a/templating/testdata/test-expected.txt +++ b/templating/testdata/test-expected.txt @@ -30,7 +30,13 @@ Second level. First level. +true1 +true1 +true1 +true2 +true2 +true1 Other lines are printed unchanged. diff --git a/templating/testdata/test-template.txt b/templating/testdata/test-template.txt index e728cdc..267ebcb 100644 --- a/templating/testdata/test-template.txt +++ b/templating/testdata/test-template.txt @@ -48,19 +48,27 @@ Triple nested IF that is FALSE. @ENDIF @IF true +true1 @IF false +false2 @IF true Triple nested IF that is FALSE. @ENDIF +false2 MUST NOT APPEAR, BUG! @ENDIF +true1 @ENDIF @IF true +true1 @IF true +true2 @IF false Triple nested IF that is FALSE. @ENDIF +true2 @ENDIF +true1 @ENDIF Other lines are printed unchanged. From a7bc551be89bada3ae7eb79598368a1e5d44036b Mon Sep 17 00:00:00 2001 From: Konrad Wojas Date: Wed, 10 May 2023 17:12:19 +0800 Subject: [PATCH 4/9] Fix tests: replace centos-8 by rocky-8 --- .github/workflows/tests.yml | 4 ++-- ...file.target.centos-8 => Dockerfile.target.rocky-8} | 11 ++++++----- ...8-reproducible.sh => test-rocky-8-reproducible.sh} | 10 +++++----- 3 files changed, 13 insertions(+), 12 deletions(-) rename demo/builder-support/dockerfiles/{Dockerfile.target.centos-8 => Dockerfile.target.rocky-8} (66%) rename tests/{test-centos-8-reproducible.sh => test-rocky-8-reproducible.sh} (57%) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 571550c..83e1fb6 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -38,6 +38,6 @@ jobs: - run: ./builder/build.sh -c -B MYCOOLARG=iLikeTests centos-7 # - Third one is very fast due to the Docker layer cache - run: ./builder/build.sh -c -B MYCOOLARG=iLikeTests centos-7 - # Do a reproducible centos-8 build (does not work for centos-7) - - run: ../tests/test-centos-8-reproducible.sh + # Do a reproducible rocky-8 build (does not work for centos-7) + - run: ../tests/test-rocky-8-reproducible.sh diff --git a/demo/builder-support/dockerfiles/Dockerfile.target.centos-8 b/demo/builder-support/dockerfiles/Dockerfile.target.rocky-8 similarity index 66% rename from demo/builder-support/dockerfiles/Dockerfile.target.centos-8 rename to demo/builder-support/dockerfiles/Dockerfile.target.rocky-8 index 2e1831f..0138a71 100644 --- a/demo/builder-support/dockerfiles/Dockerfile.target.centos-8 +++ b/demo/builder-support/dockerfiles/Dockerfile.target.rocky-8 @@ -3,13 +3,14 @@ # This defines the distribution base layer # Put only the bare minimum of common commands here, without dev tools -FROM centos:8 as dist-base +FROM rockylinux:8 as dist-base ARG BUILDER_CACHE_BUSTER= -RUN yum install -y epel-release +#RUN dnf install -y epel-release # Python 3.4+ is needed for the builder helpers -RUN yum install -y /usr/bin/python3 -RUN yum install -y dnf-plugins-core -RUN yum config-manager --set-enabled powertools +RUN dnf install -y /usr/bin/python3 +RUN dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm +RUN dnf install -y dnf-plugins-core +RUN dnf config-manager --set-enabled powertools # Do the actual rpm build @INCLUDE Dockerfile.rpmbuild diff --git a/tests/test-centos-8-reproducible.sh b/tests/test-rocky-8-reproducible.sh similarity index 57% rename from tests/test-centos-8-reproducible.sh rename to tests/test-rocky-8-reproducible.sh index 7a8247f..b84b114 100755 --- a/tests/test-centos-8-reproducible.sh +++ b/tests/test-rocky-8-reproducible.sh @@ -1,22 +1,22 @@ #!/bin/sh -# Test if centos-8 RPM builds are reproducible +# Test if rcoky-8 RPM builds are reproducible # Must be run from demo dir set -ex # First build -./builder/build.sh -B MYCOOLARG=iLikeTests centos-8 +./builder/build.sh -B MYCOOLARG=iLikeTests rocky-8 # Record hashes sha256sum \ - builder/tmp/latest/centos-8/dist/noarch/*.rpm \ + builder/tmp/latest/rocky-8/dist/noarch/*.rpm \ builder/tmp/latest/sdist/*.tar.gz \ > /tmp/sha256sum.txt # Second build after cleaning and adding a file to invalidate the build context -rm -rf ./builder/tmp/latest/centos-8 +rm -rf ./builder/tmp/latest/rocky-8 rm -rf ./builder/tmp/latest/sdist -./builder/build.sh -B MYCOOLARG=iLikeTests -b build-again centos-8 +./builder/build.sh -B MYCOOLARG=iLikeTests -b build-again rocky-8 # Check hashes, should be identical sha256sum -c /tmp/sha256sum.txt From f123f5550aabce690b80955a71c197507da5a72f Mon Sep 17 00:00:00 2001 From: Konrad Wojas Date: Thu, 11 May 2023 16:36:11 +0800 Subject: [PATCH 5/9] templates: exit with 0 on success --- templating/templating.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/templating/templating.sh b/templating/templating.sh index 395cc83..b69b089 100755 --- a/templating/templating.sh +++ b/templating/templating.sh @@ -86,3 +86,5 @@ include() { } include "$1" + +exit 0 From 649eff80f2fd2687a256a575e0570253a3e3e444 Mon Sep 17 00:00:00 2001 From: Konrad Wojas Date: Thu, 11 May 2023 20:55:42 +0800 Subject: [PATCH 6/9] templating: allow indenting between @ and IF --- templating/templating.sh | 6 +++--- templating/testdata/test-expected.txt | 8 ++++++++ templating/testdata/test-template.txt | 15 +++++++++++++++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/templating/templating.sh b/templating/templating.sh index b69b089..a392611 100755 --- a/templating/templating.sh +++ b/templating/templating.sh @@ -36,19 +36,19 @@ include() { local condition ( cat "$1" && echo ) | while IFS= read -r line; do - if [[ $line = ${tmpl_prefix}IF\ * ]]; then + if [[ $line =~ ^${tmpl_prefix}\ *IF?\ (.*) ]]; then [ "$tmpl_debug" != "" ] && echo "$tmpl_comment $line" iflevel=$((iflevel+1)) if ! [ $ifdisablelevel -gt 0 ]; then # Only if not already in a disabled IF statement - condition=${line#* } + condition="${BASH_REMATCH[1]}" if ! eval "$condition" ; then # Disabled at the current IF level ifdisablelevel=$iflevel fi fi - elif [[ $line = ${tmpl_prefix}ENDIF* ]]; then + elif [[ $line =~ ^${tmpl_prefix}\ *ENDIF? ]]; then [ "$tmpl_debug" != "" ] && echo "$tmpl_comment $line" if [ $iflevel = 0 ] ; then echo "ERROR: @ENDIF without matching @IF in file $1" > /dev/stderr diff --git a/templating/testdata/test-expected.txt b/templating/testdata/test-expected.txt index ded0814..6bc3b8a 100644 --- a/templating/testdata/test-expected.txt +++ b/templating/testdata/test-expected.txt @@ -38,5 +38,13 @@ true2 true2 true1 +# Test @IF with extra indenting after the @ + +true1 +true2 +true2 +true1 + + Other lines are printed unchanged. diff --git a/templating/testdata/test-template.txt b/templating/testdata/test-template.txt index 267ebcb..5430dea 100644 --- a/templating/testdata/test-template.txt +++ b/templating/testdata/test-template.txt @@ -71,4 +71,19 @@ true2 true1 @ENDIF +# Test @IF with extra indenting after the @ + +@IF true +true1 +@ IF true +true2 +@ IF false +Triple nested IF that is FALSE. +@ ENDIF +true2 +@ ENDIF +true1 +@ENDIF + + Other lines are printed unchanged. From e4afb02b89ea070174d9d1a22a6c09c3264b5fe3 Mon Sep 17 00:00:00 2001 From: Konrad Wojas Date: Thu, 11 May 2023 21:00:26 +0800 Subject: [PATCH 7/9] Fix typos and remove '?' from regexp --- templating/templating.sh | 4 ++-- tests/test-rocky-8-reproducible.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/templating/templating.sh b/templating/templating.sh index a392611..1981b7d 100755 --- a/templating/templating.sh +++ b/templating/templating.sh @@ -36,7 +36,7 @@ include() { local condition ( cat "$1" && echo ) | while IFS= read -r line; do - if [[ $line =~ ^${tmpl_prefix}\ *IF?\ (.*) ]]; then + if [[ $line =~ ^${tmpl_prefix}\ *IF\ (.*) ]]; then [ "$tmpl_debug" != "" ] && echo "$tmpl_comment $line" iflevel=$((iflevel+1)) if ! [ $ifdisablelevel -gt 0 ]; then @@ -48,7 +48,7 @@ include() { fi fi - elif [[ $line =~ ^${tmpl_prefix}\ *ENDIF? ]]; then + elif [[ $line =~ ^${tmpl_prefix}\ *ENDIF ]]; then [ "$tmpl_debug" != "" ] && echo "$tmpl_comment $line" if [ $iflevel = 0 ] ; then echo "ERROR: @ENDIF without matching @IF in file $1" > /dev/stderr diff --git a/tests/test-rocky-8-reproducible.sh b/tests/test-rocky-8-reproducible.sh index b84b114..c9700fe 100755 --- a/tests/test-rocky-8-reproducible.sh +++ b/tests/test-rocky-8-reproducible.sh @@ -1,5 +1,5 @@ #!/bin/sh -# Test if rcoky-8 RPM builds are reproducible +# Test if rocky-8 RPM builds are reproducible # Must be run from demo dir set -ex From 4d2867380e32af9766941ea154ced0500553d0fb Mon Sep 17 00:00:00 2001 From: Konrad Wojas Date: Thu, 11 May 2023 21:20:00 +0800 Subject: [PATCH 8/9] templating: always use regexps for consistent tmpl_prefix Switch all matches to regexp matching to ensure that tmpl_prefix is consistently matched. --- templating/templating.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/templating/templating.sh b/templating/templating.sh index 1981b7d..d2510ac 100755 --- a/templating/templating.sh +++ b/templating/templating.sh @@ -19,7 +19,7 @@ if [ "$1" = "" ]; then echo "Environment variables:" echo " tmpl_debug: If set, markers are printed around included files" echo " tmpl_comment: Characters to use to start the marker comments (default: #)" - echo " tmpl_prefix: Characters to start processing directives (default: @)" + echo " tmpl_prefix: Regexp to match processing directive prefixes (default: @)" exit 1 fi @@ -65,16 +65,16 @@ include() { [ "$tmpl_debug" != "" ] && echo "$tmpl_comment $line" - elif [[ $line = ${tmpl_prefix}INCLUDE\ * ]]; then - include=${line#* } + elif [[ $line =~ ^${tmpl_prefix}INCLUDE\ +([^ ]*) ]]; then + include="${BASH_REMATCH[1]}" include $include - elif [[ $line = ${tmpl_prefix}EVAL\ * ]]; then - line=${line#* } + elif [[ $line =~ ^${tmpl_prefix}EVAL\ (.*) ]]; then + line="${BASH_REMATCH[1]}" eval echo "\"$line\"" - elif [[ $line = ${tmpl_prefix}EXEC\ * ]]; then - line=${line#* } + elif [[ $line =~ ^${tmpl_prefix}EXEC\ (.*) ]]; then + line="${BASH_REMATCH[1]}" eval "$line" else From 215db57f4281c78688405b9f1122b4b7851e1091 Mon Sep 17 00:00:00 2001 From: Konrad Wojas Date: Thu, 11 May 2023 21:24:24 +0800 Subject: [PATCH 9/9] templating: allow indenting for all directives --- templating/templating.sh | 6 +++--- templating/testdata/test-expected.txt | 1 + templating/testdata/test-template.txt | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/templating/templating.sh b/templating/templating.sh index d2510ac..380c3e1 100755 --- a/templating/templating.sh +++ b/templating/templating.sh @@ -65,15 +65,15 @@ include() { [ "$tmpl_debug" != "" ] && echo "$tmpl_comment $line" - elif [[ $line =~ ^${tmpl_prefix}INCLUDE\ +([^ ]*) ]]; then + elif [[ $line =~ ^${tmpl_prefix}\ *INCLUDE\ +([^ ]*) ]]; then include="${BASH_REMATCH[1]}" include $include - elif [[ $line =~ ^${tmpl_prefix}EVAL\ (.*) ]]; then + elif [[ $line =~ ^${tmpl_prefix}\ *EVAL\ (.*) ]]; then line="${BASH_REMATCH[1]}" eval echo "\"$line\"" - elif [[ $line =~ ^${tmpl_prefix}EXEC\ (.*) ]]; then + elif [[ $line =~ ^${tmpl_prefix}\ *EXEC\ (.*) ]]; then line="${BASH_REMATCH[1]}" eval "$line" diff --git a/templating/testdata/test-expected.txt b/templating/testdata/test-expected.txt index 6bc3b8a..e07ae80 100644 --- a/templating/testdata/test-expected.txt +++ b/templating/testdata/test-expected.txt @@ -43,6 +43,7 @@ true1 true1 true2 true2 +Other directives also get indenting true1 diff --git a/templating/testdata/test-template.txt b/templating/testdata/test-template.txt index 5430dea..407cf6c 100644 --- a/templating/testdata/test-template.txt +++ b/templating/testdata/test-template.txt @@ -81,6 +81,7 @@ true2 Triple nested IF that is FALSE. @ ENDIF true2 +@ EXEC echo "Other directives also get indenting" @ ENDIF true1 @ENDIF