From eb30aac3101eb5f35f160d257eeb1314e242d869 Mon Sep 17 00:00:00 2001 From: Ricardo Pardini Date: Sat, 21 Jan 2023 05:15:19 +0100 Subject: [PATCH] armbian-next: extensions: move 'extensions.sh' into library; replace manual source with init function - wraps globals in `extension_manager_declare_globals()` -- and make them actually global - whoever wrote this original code is insane, add copyright --- lib/functions/cli/entrypoint.sh | 7 ++--- lib/{ => functions/general}/extensions.sh | 38 ++++++++++++++--------- lib/functions/logging/stacktraces.sh | 5 +-- lib/library-functions.sh | 9 ++++++ lib/tools/call-stack-analyze.py | 2 +- 5 files changed, 39 insertions(+), 22 deletions(-) rename lib/{ => functions/general}/extensions.sh (94%) diff --git a/lib/functions/cli/entrypoint.sh b/lib/functions/cli/entrypoint.sh index a7e15c0e8..289b1be9c 100644 --- a/lib/functions/cli/entrypoint.sh +++ b/lib/functions/cli/entrypoint.sh @@ -131,10 +131,9 @@ function cli_entrypoint() { fi fi - # Source the extensions manager library at this point, before sourcing the config. - # This allows early calls to enable_extension(), but initialization proper is done later. - # shellcheck source=lib/extensions.sh - source "${SRC}"/lib/extensions.sh + # Legacy. We used to source the extension manager here, but now it's included in the library. + # @TODO: a quick check on the globals in extensions.sh would get rid of this. + extension_manager_declare_globals # Loop over the ARMBIAN_CONFIG_FILES array and source each. The order is important. for config_file in "${ARMBIAN_CONFIG_FILES[@]}"; do diff --git a/lib/extensions.sh b/lib/functions/general/extensions.sh similarity index 94% rename from lib/extensions.sh rename to lib/functions/general/extensions.sh index 95884e46b..61ffcb4bd 100644 --- a/lib/extensions.sh +++ b/lib/functions/general/extensions.sh @@ -1,11 +1,21 @@ #!/usr/bin/env bash -# global variables managing the state of the extension manager. treat as private. -declare -A extension_function_info # maps a function name to a string with KEY=VALUEs information about the defining extension -declare -i initialize_extension_manager_counter=0 # how many times has the extension manager initialized? -declare -A defined_hook_point_functions # keeps a map of hook point functions that were defined and their extension info -declare -A hook_point_function_trace_sources # keeps a map of hook point functions that were actually called and their source -declare -A hook_point_function_trace_lines # keeps a map of hook point functions that were actually called and their source -declare fragment_manager_cleanup_file # this is a file used to cleanup the manager's produced functions, for build_all_ng + +# The whole of this is Copyright (c) 2020-2023 Ricardo Pardini +# This file is licensed under the terms of the GNU General Public +# License version 2. This program is licensed "as is" without any +# warranty of any kind, whether express or implied. + +function extension_manager_declare_globals() { + # global variables managing the state of the extension manager. treat as private. + declare -g -A extension_function_info # maps a function name to a string with KEY=VALUEs information about the defining extension + declare -g -i initialize_extension_manager_counter=0 # how many times has the extension manager initialized? + declare -g -A defined_hook_point_functions # keeps a map of hook point functions that were defined and their extension info + declare -g -A hook_point_function_trace_sources # keeps a map of hook point functions that were actually called and their source + declare -g -A hook_point_function_trace_lines # keeps a map of hook point functions that were actually called and their source + declare -g fragment_manager_cleanup_file # this is a file used to cleanup the manager's produced functions, for build_all_ng + declare -g -i enable_extension_recurse_counter=0 + declare -g -a enable_extension_recurse_stack +} # This is a helper function for calling hooks. # It follows the pattern long used in the codebase for hook-like behaviour: @@ -16,7 +26,7 @@ declare fragment_manager_cleanup_file # this is a file used to clean # 2) it will read the stdin and assume it's (Markdown) documentation for the hook point. # combined with heredoc in the call site, it allows for "inline" documentation about the hook # notice: this is not involved in how the hook functions came to be. read below for that. -call_extension_method() { +function call_extension_method() { # First, consume the stdin and write metadata about the call. write_hook_point_metadata "$@" @@ -46,7 +56,7 @@ call_extension_method() { # it came to be. (although it is encouraged to call hook points via call_extension_method() above) # to avoid hard coding the list of hook-points (eg: user_config, image_tweaks_pre_customize, etc) we use # a marker in the function names, namely "__" (two underscores) to determine the hook point. -initialize_extension_manager() { +function initialize_extension_manager() { # before starting, auto-add extensions specified (eg, on the command-line) via the ENABLE_EXTENSIONS or EXT env var. Do it only once. [[ ${initialize_extension_manager_counter} -lt 1 ]] && [[ "${ENABLE_EXTENSIONS:-"${EXT}"}" != "" ]] && { local auto_extension @@ -241,7 +251,7 @@ initialize_extension_manager() { return 0 # exit with success, short-circuit above. } -cleanup_extension_manager() { +function cleanup_extension_manager() { if [[ -f "${fragment_manager_cleanup_file}" ]]; then display_alert "Cleaning up" "extension manager" "debug" # shellcheck disable=SC1090 # dynamic source, thanks, shellcheck @@ -270,7 +280,7 @@ function cleanup_handler_extensions() { # process everything that happened during extension related activities # and write it to the log. also, move the log from the .tmp dir to its # final location. this will make run_after_build() "hot" (eg, emit warnings) -run_after_build__999_finish_extension_manager() { +function run_after_build__999_finish_extension_manager() { # export these maps, so the hook can access them and produce useful stuff. export defined_hook_point_functions hook_point_function_trace_sources @@ -293,7 +303,7 @@ run_after_build__999_finish_extension_manager() { } # This is called by call_extension_method(). To say the truth, this should be in an extension. But then it gets too meta for anyone's head. -write_hook_point_metadata() { +function write_hook_point_metadata() { # Dont do anything if told not to. [[ "${WRITE_EXTENSIONS_METADATA:-yes}" == "no" ]] && return 0 @@ -315,9 +325,7 @@ write_hook_point_metadata() { # will look for it in /userpatches/extensions first. # if not found there will look in /extensions # if not found will exit 17 -declare -i enable_extension_recurse_counter=0 -declare -a enable_extension_recurse_stack -enable_extension() { +function enable_extension() { local extension_name="$1" local extension_dir extension_file extension_file_in_dir extension_floating_file local stacktrace diff --git a/lib/functions/logging/stacktraces.sh b/lib/functions/logging/stacktraces.sh index cfe54dcab..651fbf748 100644 --- a/lib/functions/logging/stacktraces.sh +++ b/lib/functions/logging/stacktraces.sh @@ -1,4 +1,5 @@ # Helper function, to get clean "stack traces" that do not include the hook/extension infrastructure code. +# @TODO this in practice is only used... ? function get_extension_hook_stracktrace() { [[ "${CONFIG_DEFS_ONLY}" == "yes" ]] && return 0 # don't waste time here local sources_str="$1" # Give this ${BASH_SOURCE[*]} - expanded @@ -10,8 +11,8 @@ function get_extension_hook_stracktrace() { local source="${sources[index]}" line="${lines[((index - 1))]}" # skip extension infrastructure sources, these only pollute the trace and add no insight to users [[ ${source} == */extension_function_definition.sh ]] && continue - [[ ${source} == *lib/extensions.sh ]] && continue - [[ ${source} == *lib/functions/logging.sh ]] && continue + [[ ${source} == *lib/functions/general/extensions.sh ]] && continue + [[ ${source} == *lib/functions/logging.sh ]] && continue # @TODO this doesnt match for a looong time [[ ${source} == */compile.sh ]] && continue [[ ${line} -lt 1 ]] && continue # relativize the source, otherwise too long to display diff --git a/lib/library-functions.sh b/lib/library-functions.sh index 26467988d..fe58b06a0 100644 --- a/lib/library-functions.sh +++ b/lib/library-functions.sh @@ -469,6 +469,15 @@ set -o errexit ## set -e : exit the script if any statement returns a non-true # shellcheck source=lib/functions/general/downloads.sh source "${SRC}"/lib/functions/general/downloads.sh +# no errors tolerated. invoked before each sourced file to make sure. +#set -o pipefail # trace ERR through pipes - will be enabled "soon" +#set -o nounset ## set -u : exit the script if you try to use an uninitialised variable - one day will be enabled +set -o errtrace # trace ERR through - enabled +set -o errexit ## set -e : exit the script if any statement returns a non-true return value - enabled +### lib/functions/general/extensions.sh +# shellcheck source=lib/functions/general/extensions.sh +source "${SRC}"/lib/functions/general/extensions.sh + # no errors tolerated. invoked before each sourced file to make sure. #set -o pipefail # trace ERR through pipes - will be enabled "soon" #set -o nounset ## set -u : exit the script if you try to use an uninitialised variable - one day will be enabled diff --git a/lib/tools/call-stack-analyze.py b/lib/tools/call-stack-analyze.py index 6438f5f7a..f1c261c14 100644 --- a/lib/tools/call-stack-analyze.py +++ b/lib/tools/call-stack-analyze.py @@ -18,7 +18,7 @@ def get_group_from_filename(file): return "extension_magic" if file == "": return "start_here" - if file.startswith("lib/extensions.sh"): + if file.startswith("lib/functions/general/extensions.sh"): return "extensions_infra" if file.startswith("extensions/"): return "core_extensions"