From ea59d5b2684c746c41ab78627a5a22894f6c4bd2 Mon Sep 17 00:00:00 2001 From: librelad Date: Tue, 26 May 2026 23:53:21 +0100 Subject: [PATCH] feat(config): reconcileConfigFile now syncs comments from template (preserves user values) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Existing installs were locked out of template-side description / options / marker changes because reconciliation kept the user's whole `CFG_KEY=value # comment` line verbatim. So new metadata like the **DEV** marker I'm adding for the developer-mode feature wouldn't take effect on already-deployed boxes — only fresh installs. Updated reconcileConfigFile to split each line into value-part and comment-part. User value is still sacred; the comment (title, description, [options], **ADVANCED**/**DEV** markers) now comes from the template. Field renames, label tweaks, marker additions/removals shipped in a release reach existing installs on the next CLI invocation (which runs the reconciler). Specifically unblocks: the developer-mode WebUI feature (CFG_DEV_MODE field gets added by the existing add-only path; CFG_INSTALL_MODE and CFG_RELEASE_CHANNEL now pick up their new **DEV** markers and the 'Release - Stable' / 'Bleeding Edge' labels). Signed-off-by: librelad --- .../core/variables/config_scan_variables.sh | 57 ++++++++++++++++--- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/scripts/config/core/variables/config_scan_variables.sh b/scripts/config/core/variables/config_scan_variables.sh index 23ea2de..2ef4774 100755 --- a/scripts/config/core/variables/config_scan_variables.sh +++ b/scripts/config/core/variables/config_scan_variables.sh @@ -4,9 +4,34 @@ # - keep the user's existing value for any key the template still defines # - add new template keys (CFG_REQUIREMENT_CONFIGS_AUTO_UPDATE) # - drop keys the template no longer defines (CFG_REQUIREMENT_CONFIGS_AUTO_DELETE) +# - take the COMMENT (title, description, [options], **DEV** / **ADVANCED** +# markers) from the template, so label / metadata / marker changes shipped +# in a release reach existing installs without nuking user values. # Structure, ordering and comments follow the template. Non-interactive, atomic, # and keeps a .bak. Refuses to act on a missing/empty template so a broken # clone can never wipe a live config. + +# Split `CFG_KEY=value...#comment` into its value-part and comment-part. +# Used by reconcileConfigFile to swap the template's comment onto the user's +# value. Sets _reconcile_value and _reconcile_comment as side outputs. +_reconcileSplitValueComment() +{ + local line="$1" + # Drop the "CFG_KEY=" prefix; remainder is value [whitespace #comment]. + local rest="${line#*=}" + if [[ "$rest" == *"#"* ]]; then + _reconcile_value="${rest%%#*}" + # Strip trailing whitespace from the value half. + _reconcile_value="${_reconcile_value%"${_reconcile_value##*[![:space:]]}"}" + _reconcile_comment="#${rest#*#}" + else + _reconcile_value="$rest" + # Strip trailing whitespace from the value half. + _reconcile_value="${_reconcile_value%"${_reconcile_value##*[![:space:]]}"}" + _reconcile_comment="" + fi +} + reconcileConfigFile() { local live="$1" template="$2" @@ -16,18 +41,34 @@ reconcileConfigFile() [[ -f "$live" ]] || return 0 runInstallOp test -s "$template" 2>/dev/null || return 0 - declare -A live_line emitted + declare -A live_value emitted local line key - while IFS= read -r line; do - [[ "$line" =~ ^(CFG_[A-Za-z0-9_]+)= ]] && live_line["${BASH_REMATCH[1]}"]="$line" - done < <(runInstallOp cat "$live") - - local tmp; tmp=$(mktemp) while IFS= read -r line; do if [[ "$line" =~ ^(CFG_[A-Za-z0-9_]+)= ]]; then key="${BASH_REMATCH[1]}" - if [[ -n "${live_line[$key]+x}" ]]; then - printf '%s\n' "${live_line[$key]}" >> "$tmp" # keep the user's value + _reconcileSplitValueComment "$line" + live_value["$key"]="$_reconcile_value" + fi + done < <(runInstallOp cat "$live") + + local tmp; tmp=$(mktemp) + local tmpl_value tmpl_comment merged + while IFS= read -r line; do + if [[ "$line" =~ ^(CFG_[A-Za-z0-9_]+)= ]]; then + key="${BASH_REMATCH[1]}" + _reconcileSplitValueComment "$line" + tmpl_value="$_reconcile_value" + tmpl_comment="$_reconcile_comment" + + if [[ -n "${live_value[$key]+x}" ]]; then + # Keep the user's value, take the template's comment (so + # title/description/options/markers stay in sync with the repo). + if [[ -n "$tmpl_comment" ]]; then + merged="${key}=${live_value[$key]} ${tmpl_comment}" + else + merged="${key}=${live_value[$key]}" + fi + printf '%s\n' "$merged" >> "$tmp" emitted["$key"]=1 elif [[ "$do_add" == "true" ]]; then printf '%s\n' "$line" >> "$tmp" # new key, template default