Skip to content

Commit

Permalink
Fix the bug #95 and add tests for it.
Browse files Browse the repository at this point in the history
  • Loading branch information
dakusui committed Dec 10, 2019
1 parent f810c7e commit 7086e48
Show file tree
Hide file tree
Showing 12 changed files with 293 additions and 17 deletions.
17 changes: 13 additions & 4 deletions jq-front
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ source "${JF_BASEDIR}/lib/templating.sh"
source "${JF_BASEDIR}/lib/helpers.sh"

function perform_jqfront() {
local _target="${1}" _templating="${2}" _validation_mode="${3}" _jf_path="${4}"
local _target="${1}" _templating="${2}" _templating_level="${3}" _validation_mode="${4}" _jf_path="${5}"
local _content
perf "begin"
mkdir -p "$(_sourced_files_dir)"
Expand All @@ -37,7 +37,7 @@ function perform_jqfront() {
if [[ "${_templating}" == "yes" ]]; then
local _out
_out=$(mktemp_with_content "${_content}")
_content=$(perform_templating "${_out}")
_content=$(perform_templating "${_out}" "${_templating_level}")
fi
echo "${_content}"
perf "end"
Expand All @@ -62,7 +62,9 @@ function usage() {

function main() {
# Call getopt to validate the provided input.
options=$(getopt -o hde --long help,disable-templating,enable-templating,validation: -- "$@") || {
options=$(getopt \
-o hde \
--long help,disable-templating,enable-templating,validation:,nested-templating-levels: -- "$@") || {
usage_exit
}
if [[ $# -gt 0 ]]; then
Expand All @@ -81,6 +83,11 @@ function main() {
_JF_TEMPLATING_ENABLED=yes
shift
;;
--nested-templating-levels)
_JF_NESTED_TEMPLATING_LEVELS=$2
shift
shift
;;
--validation)
_JF_VALIDATION=$2
shift
Expand All @@ -102,14 +109,15 @@ function main() {
_target="${1}"
fi
mkdir -p "${_JF_SESSION_DIR}"
perform_jqfront "${_target}" "${_JF_TEMPLATING_ENABLED}" "${_JF_VALIDATION}" "${_JF_PATH}"
perform_jqfront "${_target}" "${_JF_TEMPLATING_ENABLED}" "${_JF_NESTED_TEMPLATING_LEVELS}" "${_JF_VALIDATION}" "${_JF_PATH}"
}

_JF_CWD="${JF_CWD:-"$(pwd)"}"
_JF_BASEDIR="${JF_BASEDIR}"
_JF_PATH_BASE=${JF_PATH_BASE:-""}
_JF_PATH=$(_mangle_path "${JF_PATH:-"."}" "${_JF_PATH_BASE}")
_JF_TEMPLATING_ENABLED=${JF_TEMPLATING_ENABLED:-"yes"}
_JF_NESTED_TEMPLATING_LEVELS=5
_JF_VALIDATION=${JF_VALIDATION:-"no"}
_JF_DEBUG=${JF_DEBUG:-"disabled"}
_JF_PERF=${JF_PERF:-"${_JF_DEBUG}"}
Expand All @@ -123,6 +131,7 @@ debug "_JF_BASEDIR=${_JF_BASEDIR}"
debug "_JF_PATH_BASE=${_JF_PATH_BASE}"
debug "_JF_PATH=${_JF_PATH}"
debug "_JF_TEMPLATING_ENABLED=${_JF_TEMPLATING_ENABLED}"
debug "_JF_NESTED_TEMPLATING_LEVELS=${_JF_NESTED_TEMPLATING_LEVELS}"
debug "_JF_VALIDATION=${_JF_VALIDATION}"
debug "_JF_DEBUG=${_JF_DEBUG}"
debug "_JF_PERF=${_JF_PERF}"
Expand Down
10 changes: 6 additions & 4 deletions lib/dependency.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ function _mark_as_in_progress() {
local _encoded_filename
_encoded_filename="$(_encode_filename "${_filename}" "${_dependency_space}")"
touch "${_encoded_filename}"
debug "'${_filename}' was marked as in progress with: '${_encoded_filename}'"
[[ -e "${_encoded_filename}" ]] || abort "Failed to create a mark file!"
}

function _unmark_as_in_progress() {
Expand All @@ -23,7 +25,7 @@ function _unmark_as_in_progress() {
debug "check: unmark: '${_filename}'"
_encoded_filename="$(_encode_filename "${_filename}" "${_dependency_space}")"
rm "${_encoded_filename}" || {
message "WARN: ${_filename} was not found."
message "INFO: A markfile:'${_encoded_filename}' for ${_dependency_space}:${_filename} was not found."
}
}

Expand All @@ -41,10 +43,10 @@ function _is_in_progress() {

function _check_cyclic_dependency() {
local _in="${1}" _dependency_space="${2}"
if _is_in_progress "${_in}" inheritance; then
if _is_in_progress "${_in}" "${_dependency_space}"; then
abort "Cyclic ${_dependency_space} was detected on:'${_in}'"
else
debug "check: mark as in progress: '${_in}'"
_mark_as_in_progress "${_in}" inheritance
debug "mark '${_in}' as in progress"
_mark_as_in_progress "${_in}" "${_dependency_space}"
fi
}
30 changes: 21 additions & 9 deletions lib/templating.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,31 @@ set -eu
_TEMPLATING_SH=yes

function perform_templating() {
local _src_file="${1}"
local _src_file="${1}" _levels="${2}"
local _content _ret
perf "begin"
# define builtin functions such as "ref", "self"
_define_builtin_functions
# source files, for which SOURCE directive is specified
_source_files
_perform_templating "$(cat "${_src_file}")"
_perform_templating "$(cat "${_src_file}")" "${_levels}"
perf "end"
}

function _perform_templating() {
local _content="${1}"
local _content="${1}" _levels="${2}"
local _ret="${_content}"
local i
local _c="${_levels}"
local -a _keys
# Shorter path comes earlier than longer.
while true; do
while [[ "${_c}" -ge 0 || "${_levels}" == -1 ]]; do
mapfile -t _keys < <(_paths_of_string_nodes_perform_templating "${_ret}")
if is_empty_array "${_keys[@]}"; then
break
fi
if [[ "${_c}" -eq 0 ]]; then
error "Templating has been repeated ${_levels} time(s) but it did not finish.: Keys left untemplated are: [${_keys[*]}]"
fi
debug "begin loop"
for i in "${_keys[@]}"; do
local _node_value _templated_node_value _ret_file
Expand All @@ -33,6 +36,7 @@ function _perform_templating() {
_templated_node_value="$(_render_text_node "${_node_value}" "${i}" "${_ret_file}")"
_ret="$(jq -r -c -n "input|${i}=input" <(echo "${_ret}") <(echo "${_templated_node_value}"))"
done
_c=$((_c - 1))
debug "end loop"
done
echo "${_ret}"
Expand All @@ -56,7 +60,7 @@ function _render_text_node() {
local _node_value="${1}"
local _path="${2}" # DO NOT REMOVE: This local variable is referenced by built-in functions invoked on 'templating' stage.
local _self="${3}" # DO NOT REMOVE: This local variable is referenced by built-in functions invoked on 'templating' stage.
local _mode="raw" _quote="yes" _ret_code=0
local _mode="raw" _quote="yes" _ret_code=0 _expected_type="string"
local _body _ret
if [[ "${_node_value}" != template:* && "${_node_value}" != eval:* && "${_node_value}" != raw:* ]]; then
abort "Non-templating text node was found: '${_node_value}'"
Expand All @@ -68,6 +72,7 @@ function _render_text_node() {
if [[ "${_body}" != string:* ]]; then
_quote="no"
fi
_expected_type="${_body%%:*}"
_body="${_body#*:}"
fi

Expand All @@ -88,10 +93,16 @@ function _render_text_node() {
fi
if [[ "${_quote}" == yes ]]; then
_ret="${_ret//\\/\\\\}"
echo "\"${_ret//\"/\\\"}\""
_ret="\"${_ret//\"/\\\"}\""
else
echo "${_ret}"
_ret="${_ret}"
fi
local _actual_type="(malformed)"
_actual_type="$(echo "${_ret}" | jq -r '.|type')"
debug "expected type:'${_expected_type}' actual type:'${_actual_type}'"
[[ "${_expected_type}" == "${_actual_type}" ]] ||
abort "Type mismatch was detected for:'${_node_value}' expected type:'${_expected_type}' actual type:'${_actual_type}'"
echo "${_ret}"
return "${_ret_code}"
}

Expand Down Expand Up @@ -131,11 +142,12 @@ function _define_builtin_functions() {
local value type
value=$(value_at "${_path}" "$(cat "$(self)")")
type="$(type_of "${value}")"
debug "value:'${value}'(type:'${type}')"
debug "value:'${value}'(type:'${type}') self:'${_self}' path:'${_path}'"
if [[ "${type}" == string && ("${value}" == eval:* || "${value}" == template:*) ]]; then
local ret
_check_cyclic_dependency "${_path}" reference
ret="$(_render_text_node "${value}" "${_path}" "${_self}")"
[[ $? == 0 ]] || abort "TODO"
_unmark_as_in_progress "${_path}" reference
jq -r -c '.' <(echo "${ret}")
else
Expand Down
1 change: 1 addition & 0 deletions tests/templating/nested-templating/many/expected.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ERROR: Cyclic reference was detected on
83 changes: 83 additions & 0 deletions tests/templating/nested-templating/many/input.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
{
"a": {
"key": "eval:object:$(ref .b)"
},
"b": {
"key": "eval:object:$(ref .c)"
},
"c": {
"key": "eval:object:$(ref .d)"
},
"d": {
"key": "eval:object:$(ref .e)"
},
"e": {
"key": "eval:object:$(ref .f)"
},
"f": {
"key": "eval:object:$(ref .g)"
},
"g": {
"key": "eval:object:$(ref .h)"
},
"h": {
"key": "eval:object:$(ref .i)"
},
"i": {
"key": "eval:object:$(ref .j)"
},
"j": {
"key": "eval:object:$(ref .k)"
},
"k": {
"key": "eval:object:$(ref .l)"
},
"l": {
"key": "eval:object:$(ref .m)"
},
"m": {
"key": "eval:object:$(ref .n)"
},
"n": {
"key": "eval:object:$(ref .o)"
},
"o": {
"key": "eval:object:$(ref .p)"
},
"p": {
"key": "eval:object:$(ref .q)"
},
"q": {
"key": "eval:object:$(ref .r)"
},
"r": {
"key": "eval:object:$(ref .s)"
},
"s": {
"key": "eval:object:$(ref .t)"
},
"t": {
"key": "eval:object:$(ref .u)"
},
"u": {
"key": "eval:object:$(ref .v)"
},
"v": {
"key": "eval:object:$(ref .w)"
},
"w": {
"key": "eval:object:$(ref .x)"
},
"x": {
"key": "eval:object:$(ref .y)"
},
"y": {
"key": "eval:object:$(ref .z)"
},
"z": {
"key": "eval:object:$(ref .A)"
},
"A": {
"hello": "world"
}
}
3 changes: 3 additions & 0 deletions tests/templating/nested-templating/many/test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"testType": "negative"
}
2 changes: 2 additions & 0 deletions tests/templating/nested-templating/negative/expected.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ERROR: Templating has been repeated 5 time
but it did not finish.: Keys left untemplated are:
Loading

0 comments on commit 7086e48

Please sign in to comment.