From 50aa18e2a64a727e2afd51cbc7e73038b7eea0a1 Mon Sep 17 00:00:00 2001 From: Alexey Maslennikov Date: Thu, 15 Jun 2017 20:47:51 +0200 Subject: [PATCH 1/3] Adding an option to fail upon unset env variables --- .gitignore | 1 + mo | 46 +++++++++++++++++++++++++------------ tests/fail-not-set.expected | 1 + tests/fail-not-set.sh | 9 ++++++++ tests/help.expected | 7 +++--- 5 files changed, 46 insertions(+), 18 deletions(-) create mode 100644 tests/fail-not-set.expected create mode 100755 tests/fail-not-set.sh diff --git a/.gitignore b/.gitignore index 5a1b4f1..a6047cb 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ diagnostic.test tests/*.diff spec/ spec-runner/ +node_modules/ diff --git a/mo b/mo index b143808..fc168b5 100755 --- a/mo +++ b/mo @@ -13,9 +13,10 @@ #/ #/ mo [--false] [--help] [--source=FILE] filenames... #/ -#/ --false - Treat the string "false" as empty for conditionals. -#/ --help - This message. -#/ --source=FILE - Load FILE into the environment before processing templates. +#/ --fail-not-set - Fail upon expansion of an unset variable. +#/ --false - Treat the string "false" as empty for conditionals. +#/ --help - This message. +#/ --source=FILE - Load FILE into the environment before processing templates. # # Mo is under a MIT style licence with an additional non-advertising clause. # See LICENSE.md for the full text. @@ -27,19 +28,23 @@ # Public: Template parser function. Writes templates to stdout. # -# $0 - Name of the mo file, used for getting the help message. -# --false - Treat "false" as an empty value. You may set the -# MO_FALSE_IS_EMPTY environment variable instead to a non-empty -# value to enable this behavior. -# --help - Display a help message. -# --source=FILE - Source a file into the environment before processint -# template files. -# -- - Used to indicate the end of options. You may optionally -# use this when filenames may start with two hyphens. -# $@ - Filenames to parse. +# $0 - Name of the mo file, used for getting the help message. +# --fail-not-set - Fail upon expansion of an unset variable. Default behavior +# is to silently ignore and expand into empty string. +# --false - Treat "false" as an empty value. You may set the +# MO_FALSE_IS_EMPTY environment variable instead to a non-empty +# value to enable this behavior. +# --help - Display a help message. +# --source=FILE - Source a file into the environment before processint +# template files. +# -- - Used to indicate the end of options. You may optionally +# use this when filenames may start with two hyphens. +# $@ - Filenames to parse. # # Mo uses the following environment variables: # +# MO_FAIL_ON_UNSET - When set to a non-empty value, expansion of an unset +# env variable will be aborted with an error. # MO_FALSE_IS_EMPTY - When set to a non-empty value, the string "false" # will be treated as an empty value for the purposes # of conditionals. @@ -69,6 +74,11 @@ mo() ( exit 0 ;; + --fail-not-set) + # shellcheck disable=SC2030 + MO_FAIL_ON_UNSET=true + ;; + --false) # shellcheck disable=SC2030 MO_FALSE_IS_EMPTY=true @@ -255,7 +265,7 @@ moIndentLines() { local content fragment len posN posR result trimmed result="" - + #: Remove the period from the end of the string. len=$((${#3} - 1)) content=${3:0:$len} @@ -746,7 +756,13 @@ moShow() { eval moJoin moJoined "," "\${$1[@]}" echo -n "$moJoined" else - echo -n "${!1}" + # shellcheck disable=SC2031 + if [[ -z "$MO_FAIL_ON_UNSET" ]] || moTest "$1"; then + echo -n "${!1}" + else + echo "Env variable not set: $1" >&2 + exit 1 + fi fi else # Further subindexes are disallowed diff --git a/tests/fail-not-set.expected b/tests/fail-not-set.expected new file mode 100644 index 0000000..06dea8f --- /dev/null +++ b/tests/fail-not-set.expected @@ -0,0 +1 @@ +This will fail: Env variable not set: __NO_SUCH_VAR diff --git a/tests/fail-not-set.sh b/tests/fail-not-set.sh new file mode 100755 index 0000000..d3f9ef7 --- /dev/null +++ b/tests/fail-not-set.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +cd "${0%/*}" +unset __NO_SUCH_VAR +echo "This will fail: {{__NO_SUCH_VAR}}" | ../mo --fail-not-set 2>&1 + +if [[ $? -ne 1 ]]; then + echo "Did not return 1" +fi diff --git a/tests/help.expected b/tests/help.expected index 95e8df5..51a740a 100644 --- a/tests/help.expected +++ b/tests/help.expected @@ -11,6 +11,7 @@ Simple usage: mo [--false] [--help] [--source=FILE] filenames... ---false - Treat the string "false" as empty for conditionals. ---help - This message. ---source=FILE - Load FILE into the environment before processing templates. +--fail-not-set - Fail upon expansion of an unset variable. +--false - Treat the string "false" as empty for conditionals. +--help - This message. +--source=FILE - Load FILE into the environment before processing templates. From 2b611b8f907365cd25202297ee91adfbd87cf994 Mon Sep 17 00:00:00 2001 From: Alexey Maslennikov Date: Thu, 15 Jun 2017 21:47:12 +0200 Subject: [PATCH 2/3] Making --fail-not-set work with partials The return code was not propagated through nested subshells in case when files were passed in as arguments. --- mo | 9 +++++---- tests/fail-not-set-file.expected | 1 + tests/fail-not-set-file.sh | 9 +++++++++ tests/fail-not-set-file.template | 1 + 4 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 tests/fail-not-set-file.expected create mode 100755 tests/fail-not-set-file.sh create mode 100644 tests/fail-not-set-file.template diff --git a/mo b/mo index fc168b5..f1d1b31 100755 --- a/mo +++ b/mo @@ -696,7 +696,7 @@ moParse() { # Returns nothing. moPartial() { # Namespace variables here to prevent conflicts. - local moContent moFilename moIndent moPartial moStandalone + local moContent moFilename moIndent moPartial moStandalone moUnindented if moIsStandalone moStandalone "$2" "$4" "$5"; then moStandalone=( $moStandalone ) @@ -715,16 +715,17 @@ moPartial() { ( # TODO: Remove dirname and use a function instead cd "$(dirname -- "$moFilename")" || exit 1 - moIndentLines moPartial "$moIndent" "$( + moUnindented="$( moLoadFile moPartial "${moFilename##*/}" moParse "${moPartial}" "$6" true # Fix bash handling of subshells and keep trailing whitespace. # This is removed in moIndentLines. echo -n "." - )" + )" || exit 1 + moIndentLines moPartial "$moIndent" "$moUnindented" echo -n "$moPartial" - ) + ) || exit 1 local "$1" && moIndirect "$1" "$moContent" } diff --git a/tests/fail-not-set-file.expected b/tests/fail-not-set-file.expected new file mode 100644 index 0000000..439982b --- /dev/null +++ b/tests/fail-not-set-file.expected @@ -0,0 +1 @@ +Env variable not set: __NO_SUCH_VAR diff --git a/tests/fail-not-set-file.sh b/tests/fail-not-set-file.sh new file mode 100755 index 0000000..0355219 --- /dev/null +++ b/tests/fail-not-set-file.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +cd "${0%/*}" +unset __NO_SUCH_VAR +../mo --fail-not-set ./fail-not-set-file.template 2>&1 + +if [[ $? -ne 1 ]]; then + echo "Did not return 1" +fi diff --git a/tests/fail-not-set-file.template b/tests/fail-not-set-file.template new file mode 100644 index 0000000..bd8b3ee --- /dev/null +++ b/tests/fail-not-set-file.template @@ -0,0 +1 @@ +* {{__NO_SUCH_VAR}} From 31b2faf1358fb2d3869bd62b26f453f8110d1713 Mon Sep 17 00:00:00 2001 From: Alexey Maslennikov Date: Fri, 16 Jun 2017 15:59:57 +0200 Subject: [PATCH 3/3] Fixing empty variable failure for --fail-not-set --- mo | 12 +++++++++++- tests/fail-not-set-file.sh | 2 +- tests/fail-not-set-file.template | 4 +++- tests/fail-not-set.expected | 4 +++- tests/fail-not-set.sh | 6 +++++- 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/mo b/mo index f1d1b31..57f0fba 100755 --- a/mo +++ b/mo @@ -758,7 +758,7 @@ moShow() { echo -n "$moJoined" else # shellcheck disable=SC2031 - if [[ -z "$MO_FAIL_ON_UNSET" ]] || moTest "$1"; then + if [[ -z "$MO_FAIL_ON_UNSET" ]] || moTestVarSet "$1"; then echo -n "${!1}" else echo "Env variable not set: $1" >&2 @@ -880,6 +880,16 @@ moTest() { return 1 } +# Internal: Determine if a variable is assigned, even if it is assigned an empty +# value. +# +# $1 - Variable name to check. +# +# Returns true (0) if the variable is set, 1 if the variable is unset. +moTestVarSet() { + [[ "${!1-a}" == "${!1-b}" ]] +} + # Internal: Trim the leading whitespace only. # diff --git a/tests/fail-not-set-file.sh b/tests/fail-not-set-file.sh index 0355219..fe24e85 100755 --- a/tests/fail-not-set-file.sh +++ b/tests/fail-not-set-file.sh @@ -2,7 +2,7 @@ cd "${0%/*}" unset __NO_SUCH_VAR -../mo --fail-not-set ./fail-not-set-file.template 2>&1 +POPULATED="words" EMPTY="" ../mo --fail-not-set ./fail-not-set-file.template 2>&1 if [[ $? -ne 1 ]]; then echo "Did not return 1" diff --git a/tests/fail-not-set-file.template b/tests/fail-not-set-file.template index bd8b3ee..d249abe 100644 --- a/tests/fail-not-set-file.template +++ b/tests/fail-not-set-file.template @@ -1 +1,3 @@ -* {{__NO_SUCH_VAR}} +Populated: {{POPULATED}}; +Empty: {{EMPTY}}; +Unset: {{__NO_SUCH_VAR}}; diff --git a/tests/fail-not-set.expected b/tests/fail-not-set.expected index 06dea8f..6713890 100644 --- a/tests/fail-not-set.expected +++ b/tests/fail-not-set.expected @@ -1 +1,3 @@ -This will fail: Env variable not set: __NO_SUCH_VAR +Populated: words; +Empty: ; +Unset: Env variable not set: __NO_SUCH_VAR diff --git a/tests/fail-not-set.sh b/tests/fail-not-set.sh index d3f9ef7..b0b6b34 100755 --- a/tests/fail-not-set.sh +++ b/tests/fail-not-set.sh @@ -2,7 +2,11 @@ cd "${0%/*}" unset __NO_SUCH_VAR -echo "This will fail: {{__NO_SUCH_VAR}}" | ../mo --fail-not-set 2>&1 +POPULATED="words" EMPTY="" ../mo --fail-not-set 2>&1 <