extensions: many fixes; allow for dumping the source of hooks, via dump_extension_method_sources_functions() and dump_extension_method_sources_body()

- fix: indent of generated sources
- fix: no reason to source the generated file in a loop. do it once. 20x faster?
- `dump_extension_method_sources_functions "name_of_hook"`: get function definitions (inside braces)
- `dump_extension_method_sources_body "name_of_hook"`: get the function bodies (sans-braces)
This commit is contained in:
Ricardo Pardini
2023-03-31 01:01:16 +02:00
committed by Igor Pečovnik
parent 61d85648ea
commit d2bb1f893a

View File

@@ -59,6 +59,60 @@ function call_extension_method() {
done
}
function dump_extension_method_sources_functions() {
declare hook_name="${1}"
declare dump_source_hook_function="dump_custom_sources_extension_hooks_${hook_name}"
function dump_function_declaration_and_braces() {
declare function_name="${1}"
echo -e "\t# Begin of function declaration '${function_name}'"
declare -f "${function_name}" | sed -e '2d' -e '1d' -e '$d'
echo -e "\t# End of function declaration '${function_name}'"
echo ""
}
display_alert "Extension Method source custom dump: ${hook_name}" "hook: ${hook_name} via dump_function_declaration_and_braces" "extensions"
if [[ $(type -t ${dump_source_hook_function} || true) == function ]]; then
display_alert "Dumping extensions hooks with function declaration and braces" "${dump_source_hook_function}" "debug"
echo "# Begin of all custom functions for hook '${hook_name}'"
"${dump_source_hook_function}" dump_function_declaration_and_braces
echo "# End of all custom functions for hook '${hook_name}'"
echo ""
else
display_alert "Extension Method source custom dump: ${hook_name}" "not found hook: ${dump_source_hook_function}: '$(type -t ${dump_source_hook_function} || true)'" "debug"
fi
unset dump_body_sans_function_header_or_trailer
return 0 # always success
}
function dump_extension_method_sources_body() {
declare hook_name="${1}"
declare dump_source_hook_function="dump_custom_sources_extension_hooks_${hook_name}"
function dump_body_sans_function_header_or_trailer() {
declare function_name="${1}"
echo -e "\t# Begin of function body '${function_name}'"
declare -f "${function_name}" | sed -e '2d' -e '1d' -e '$d'
echo -e "\t# End of function body '${function_name}'"
echo ""
}
display_alert "Extension Method source custom dump: ${hook_name}" "hook: ${hook_name} via dump_body_sans_function_header_or_trailer" "extensions"
if [[ $(type -t ${dump_source_hook_function} || true) == function ]]; then
display_alert "Dumping extension source via custom method" "${dump_source_hook_function}" "debug"
echo "# Begin of all custom sources for '${hook_name}'"
"${dump_source_hook_function}" dump_body_sans_function_header_or_trailer
echo "# End of all custom sources for '${hook_name}'"
echo ""
else
display_alert "Extension Method source custom dump: ${hook_name}" "not found hook: ${dump_source_hook_function}: '$(type -t ${dump_source_hook_function} || true)'" "debug"
fi
unset dump_body_sans_function_header_or_trailer
return 0 # always success
}
# what this does is a lot of bash mumbo-jumbo to find all board-,family-,config- or user-defined hook points.
# the meat of this is 'compgen -A function', which is bash builtin that lists all defined functions.
# it will then compose a full hook point (function) that calls all the implementing hooks.
@@ -102,10 +156,16 @@ function initialize_extension_manager() {
declare -i hook_points_counter=0 hook_functions_counter=0 hook_point_functions_counter=0
# initialize the function declarations(init) file.
local temp_source_file_for_hook_point="${EXTENSION_MANAGER_TMP_DIR}/extension_function_definition.sh"
echo "# extension function definitions: " > "${temp_source_file_for_hook_point}"
# initialize the cleanups file.
extension_manager_cleanup_file="${EXTENSION_MANAGER_TMP_DIR}/extension_function_cleanup.sh"
echo "# cleanups: " > "${extension_manager_cleanup_file}"
local tab=" " newline="" # for indentation/readability...
newline=$'\n' # ... of generated code
local FUNCTION_SORT_OPTIONS="--general-numeric-sort --ignore-case" # --random-sort could be used to introduce chaos
local hook_point=""
# now loop over the hook_points.
@@ -188,7 +248,6 @@ function initialize_extension_manager() {
common_function_vars="${common_function_vars} HOOK_POINT_TOTAL_FUNCS=\"${hook_point_functions_counter}\""
display_alert "Extensions hook_point: ${hook_point} will run ${hook_point_functions_counter} functions" "${hook_point_functions_counter}" "extensions"
local temp_source_file_for_hook_point="${EXTENSION_MANAGER_TMP_DIR}/extension_function_definition.sh"
declare hook_point_functions_loop_counter=0
@@ -201,11 +260,14 @@ function initialize_extension_manager() {
# theres a lot of opportunities here, but for now I keep it simple:
# - execute functions in the order defined by ${hook_point_functions} above
# - define call-specific environment variables, to help extension authors to write portable extensions (eg: EXTENSION_DIR)
cat <<- FUNCTION_DEFINITION_HEADER > "${temp_source_file_for_hook_point}"
${hook_point}() {
display_alert "Extension-managed hook starting '${hook_point}': will run ${hook_point_functions_counter} functions" "${hook_point_functions}" "extensionstrace"
cat <<- FUNCTION_DEFINITION_HEADER >> "${temp_source_file_for_hook_point}"
function ${hook_point}() {
${tab}display_alert "Extension-managed hook starting '${hook_point}': will run ${hook_point_functions_counter} functions" "${hook_point_functions}" "extensionstrace"
FUNCTION_DEFINITION_HEADER
# keep a list of the called functions. we'll use it to generate the source-dumping function, below.
declare -a list_of_called_functions=()
for hook_point_function in ${hook_point_functions}; do
hook_point_functions_loop_counter=$((hook_point_functions_loop_counter + 1))
@@ -225,17 +287,20 @@ function initialize_extension_manager() {
# output the call, passing arguments, and also logging the output to the extensions log.
# attention: don't pipe here (eg, capture output), otherwise hook function cant modify the environment (which is mostly the point)
cat <<- FUNCTION_DEFINITION_CALLSITE >> "${temp_source_file_for_hook_point}"
hook_point_function_trace_sources["${hook_point}${hook_extension_delimiter}${hook_point_function}"]="\${BASH_SOURCE[*]}"
hook_point_function_trace_lines["${hook_point}${hook_extension_delimiter}${hook_point_function}"]="\${BASH_LINENO[*]}"
display_alert "Extension Method ${hook_point}" "${hook_point_functions_loop_counter}/${hook_point_functions_counter} (ext:${EXTENSION:-built-in}) ${hook_point_function}" "extensionstrace"
display_alert "Extension-managed hook starting ${hook_point_functions_loop_counter}/${hook_point_functions_counter}" "${hook_point}${hook_extension_delimiter}${hook_point_function}" "extensionstrace"
${hook_point_function_variables} ${hook_point}${hook_extension_delimiter}${hook_point_function} "\$@"
display_alert "Extension-managed hook finished ${hook_point_functions_loop_counter}/${hook_point_functions_counter}" "${hook_point}${hook_extension_delimiter}${hook_point_function}" "extensionstrace"
${tab}hook_point_function_trace_sources["${hook_point}${hook_extension_delimiter}${hook_point_function}"]="\${BASH_SOURCE[*]}"
${tab}hook_point_function_trace_lines["${hook_point}${hook_extension_delimiter}${hook_point_function}"]="\${BASH_LINENO[*]}"
${tab}display_alert "Extension Method ${hook_point}" "${hook_point_functions_loop_counter}/${hook_point_functions_counter} (ext:${EXTENSION:-built-in}) ${hook_point_function}" "extensionstrace"
${tab}display_alert "Extension-managed hook starting ${hook_point_functions_loop_counter}/${hook_point_functions_counter}" "${hook_point}${hook_extension_delimiter}${hook_point_function}" "extensionstrace"
${tab}${hook_point_function_variables} ${hook_point}${hook_extension_delimiter}${hook_point_function} "\$@"
${tab}display_alert "Extension-managed hook finished ${hook_point_functions_loop_counter}/${hook_point_functions_counter}" "${hook_point}${hook_extension_delimiter}${hook_point_function}" "extensionstrace"
FUNCTION_DEFINITION_CALLSITE
# feed the list of called functions for the source-dumping function.
list_of_called_functions+=("${hook_point}${hook_extension_delimiter}${hook_point_function}")
# output the cleanup for the implementation as well.
cat <<- FUNCTION_CLEANUP_FOR_HOOK_POINT_IMPLEMENTATION >> "${extension_manager_cleanup_file}"
unset ${hook_point}${hook_extension_delimiter}${hook_point_function}
${tab}unset ${hook_point}${hook_extension_delimiter}${hook_point_function}
FUNCTION_CLEANUP_FOR_HOOK_POINT_IMPLEMENTATION
# unset extension vars for the next loop.
@@ -243,20 +308,45 @@ function initialize_extension_manager() {
done
cat <<- FUNCTION_DEFINITION_FOOTER >> "${temp_source_file_for_hook_point}"
display_alert "Extension-managed hook ending '${hook_point}': completed" "${hook_point}" "extensionstrace"
} # end ${hook_point}() function
${tab}display_alert "Extension-managed hook ending '${hook_point}': completed" "${hook_point}" "extensionstrace"
} # end ${hook_point}() function${newline}
FUNCTION_DEFINITION_FOOTER
# Extra function, running over the implementations and calling the arguments passed with each as parameter.
# Useful for getting the source code of the implementations, for example, or the list of called functions
# in a given hook. See dump_extension_method_sources_body() and dump_extension_method_sources_functions().
cat <<- FUNCTION_DUMP_SOURCE_CUSTOM_START >> "${temp_source_file_for_hook_point}"
function dump_custom_sources_extension_hooks_${hook_point}() {
FUNCTION_DUMP_SOURCE_CUSTOM_START
declare function_name
for function_name in "${list_of_called_functions[@]}"; do
# call the arguments as function, passing the function name as argument
echo "${tab}\"\${@}\" \"${function_name}\" " >> "${temp_source_file_for_hook_point}"
done
cat <<- FUNCTION_DUMP_SOURCE_CUSTOM_END >> "${temp_source_file_for_hook_point}"
} # end dump_source_extension_hooks_${hook_point}() function${newline}
FUNCTION_DUMP_SOURCE_CUSTOM_END
# unsets, lest the next loop inherits them
unset hook_point_functions hook_point_functions_sortname_to_realname hook_point_functions_realname_to_sortname
# source the generated function.
# shellcheck disable=SC1090
source "${temp_source_file_for_hook_point}"
rm -f "${temp_source_file_for_hook_point}"
unset hook_point_functions hook_point_functions_sortname_to_realname hook_point_functions_realname_to_sortname list_of_called_functions
done
# Extra debug, show the generated source and cleanup.
if [[ "${SHOW_EXTENSIONS}" == "yes" ]]; then
display_alert "Showing" "extensions initialization generated code" "info"
run_tool_batcat --file-name "extensions_initialize.sh" "${temp_source_file_for_hook_point}"
display_alert "Showing" "extensions cleanup generated code" "info"
run_tool_batcat --file-name "extensions_cleanup.sh" "${extension_manager_cleanup_file}"
fi
# source the generated function.
# shellcheck disable=SC1090
source "${temp_source_file_for_hook_point}"
rm -f "${temp_source_file_for_hook_point}"
# Dont show any output until we have more than 1 hook function (we implement one already, below)
[[ ${hook_functions_counter} -gt 0 ]] &&
display_alert "Extension manager" "processed ${hook_points_counter} Extension Methods calls and ${hook_functions_counter} Extension Method implementations" "info"