LibrePortal/scripts/source/loading/initilize_files.sh
librelad f07ec0e358 fix(lazy-load): exclude function_manifest.sh from the early find-loop
The early loop in sourceInitilize() sources every .sh under source/files/
recursively — including the new arrays/function_manifest.sh, which now
carries ~860 autoload stub definitions (~50 ms parse cost). Even in
eager mode where lazy infrastructure is never touched, every invocation
was paying that cost up front.

The manifest is only needed in lazy mode, where it's sourced explicitly
at the top of the lazy branch. Excluding it from the early loop:
  - Eager mode: drops the ~50 ms regression introduced by Phase 5.
  - Lazy mode: unchanged — the explicit source still runs.

This brings eager back to the pre-Phase-5 baseline and lets the lazy
container-stub gain (skipping sourceScanFiles containers, ~70 ms) show
through as a real saving.

Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-26 21:32:52 +01:00

154 lines
6.9 KiB
Bash
Executable File

#!/bin/bash
sourceInitilize()
{
local flag="$1"
# We will only show the header for the full app
if [[ $flag == "run" ]]; then
isHeader "Loading LibrePortal Startup Files"
isNotice "If you are experiencing loading issues..."
isNotice "Please run the following : 'libreportal reset'"
fi
# Directory containing the files to source recursively
local file_list_directory="${install_scripts_dir}source/files"
# Check if the directory exists
if [ -d "$file_list_directory" ]; then
# Use find to get a list of all files (excluding directories) in the
# directory and its subdirectories. The function_manifest.sh file is
# excluded — it carries ~860 stub function definitions (~50 ms parse
# cost) that are only needed in lazy mode, where it's sourced
# explicitly. Including it here makes every eager-mode invocation pay
# for lazy infrastructure it never uses.
local file_list=$(find "$file_list_directory" -type f -name "*.sh" \
! -name "function_manifest.sh")
# Loop through each file in the file list
while IFS= read -r file; do
# Source the file
source "$file"
done <<< "$file_list"
else
echo "Directory $file_list_directory does not exist. Unable to start!"
fi
# For loading files needed for the full app or CLI
if [[ $flag == "run" ]]; then
source "${install_scripts_dir}source/files/app_files.sh"
files_to_source=("${files_libreportal_app[@]}")
elif [[ $flag == "cli" ]]; then
source "${install_scripts_dir}source/files/cli_files.sh"
files_to_source=("${files_libreportal_cli[@]}")
fi
# Trace setup — LP_LOAD_TRACE=1 logs `<ms>\t<file>` to LP_LOAD_TRACE_FILE
# for `libreportal debug load-trace`. Zero overhead when unset.
if [[ "$LP_LOAD_TRACE" == "1" ]]; then
: "${LP_LOAD_TRACE_FILE:=/tmp/libreportal-load-trace.$$.log}"
export LP_LOAD_TRACE_FILE
: > "$LP_LOAD_TRACE_FILE"
fi
# LP_LAZY=1: defer the bulk of file sourcing. Install autoload stubs from
# function_manifest.sh, source only the files with top-level side effects
# (LP_EAGER_FILES — set by the manifest), and skip the rest. Each stub
# sources its real file on first call; subsequent calls hit the real
# function directly (the source replaced the stub).
#
# Default (LP_LAZY unset or 0): the historical behaviour — source every
# file in files_to_source up front. Long-running processes (task
# processor, WebUI) want this so their first call to anything is hot.
if [[ "$LP_LAZY" == "1" ]]; then
local manifest="${install_scripts_dir}source/files/arrays/function_manifest.sh"
if [[ -f "$manifest" ]]; then
# Sourcing the manifest defines LP_FN_MAP, LP_EAGER_FILES, AND
# the autoload stubs (precompiled by the generator so we pay one
# parse cost instead of evaling ~700 snippets at startup).
if [[ "$LP_LOAD_TRACE" == "1" ]]; then
local _t0=$EPOCHREALTIME
source "$manifest"
local _t1=$EPOCHREALTIME
local _ms
_ms=$(awk -v a="$_t0" -v b="$_t1" 'BEGIN{printf "%.3f", (b-a)*1000}')
printf '%s\t%s\n' "$_ms" "source/files/arrays/function_manifest.sh (LAZY-manifest)" >> "$LP_LOAD_TRACE_FILE"
else
source "$manifest"
fi
# Eager-source the side-effect files. Entries are `<root>:<relpath>`
# where root selects the base dir ("scripts" → install_scripts_dir,
# "containers" → install_containers_dir). Pre-Phase-5 manifests
# without a `:` default to scripts/.
local _eager _root _path _base
for _eager in "${LP_EAGER_FILES[@]}"; do
if [[ "$_eager" == *:* ]]; then
_root="${_eager%%:*}"
_path="${_eager#*:}"
else
_root="scripts"; _path="$_eager"
fi
case "$_root" in
containers) _base="$install_containers_dir" ;;
*) _base="$install_scripts_dir" ;;
esac
[[ -f "${_base}${_path}" ]] || continue
if [[ "$LP_LOAD_TRACE" == "1" ]]; then
local _t0=$EPOCHREALTIME
source "${_base}${_path}"
local _t1=$EPOCHREALTIME
local _ms
_ms=$(awk -v a="$_t0" -v b="$_t1" 'BEGIN{printf "%.3f", (b-a)*1000}')
printf '%s\t%s\n' "$_ms" "${_root}/${_path} (LAZY-EAGER)" >> "$LP_LOAD_TRACE_FILE"
else
source "${_base}${_path}"
fi
done
else
# No manifest present — fall back to eager loading so we never
# leave the user with a broken install just because regen
# hasn't run. Silently — this is the safety net, not the path.
export LP_LAZY=0
fi
fi
# Eager path (default OR lazy-with-no-manifest fallback). Sources every
# file in files_to_source. Skipped entirely when LP_LAZY=1 succeeded.
if [[ "$LP_LAZY" != "1" ]]; then
for file_to_source in "${files_to_source[@]}"; do
if [ ! -f "${install_scripts_dir}${file_to_source}" ]; then
isNotice "Missing file: ${install_scripts_dir}${file_to_source}"
else
if [[ "$LP_LOAD_TRACE" == "1" ]]; then
local _t0=$EPOCHREALTIME
source "${install_scripts_dir}${file_to_source}"
local _t1=$EPOCHREALTIME
local _ms
_ms=$(awk -v a="$_t0" -v b="$_t1" 'BEGIN{printf "%.3f", (b-a)*1000}')
printf '%s\t%s\n' "$_ms" "$file_to_source" >> "$LP_LOAD_TRACE_FILE"
else
source "${install_scripts_dir}${file_to_source}"
fi
fi
done
fi
# Loading of all files. Three scans:
# libreportal_configs CFG_* vars from configs/* (~180 ms)
# app_configs CFG_<APP>_* vars from containers/* (~37 ms)
# containers Per-app installer functions (~70 ms)
#
# Under LP_LAZY=1 with a present manifest, the container scan is replaced
# by autoload stubs in function_manifest.sh — sourcing every container
# installer eagerly would defeat the lazy optimisation. The two config
# scans still run because bash can't lazy-load variables (Phase 6 will
# tackle this with a precompiled cache file).
sourceScanFiles "libreportal_configs";
sourceScanFiles "app_configs";
if [[ "$LP_LAZY" == "1" ]] && declare -p LP_FN_MAP >/dev/null 2>&1; then
: # containers covered by autoload stubs; skip the eager scan
else
sourceScanFiles "containers";
fi
}