From 87e19e197af61a5e7bfe0f1942cbffde02da110d Mon Sep 17 00:00:00 2001 From: librelad Date: Fri, 12 Jun 2026 23:11:14 +0100 Subject: [PATCH] fix(config): hide reconcile backups as dot-named siblings; guard the option resolver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reconcile backups now land as ..bak instead of .bak, so they no longer clutter the configs folder. The .bak suffix is kept, so every existing walker/sourcing exclusion still applies. Also exclude dotfiles and *.bak from findConfigFileForOption: it walked the configs tree with no backup exclusion, so depending on directory order a 'config update' could resolve a key to the backup file and write the user's change there — silently lost. Co-Authored-By: Claude Fable 5 Signed-off-by: librelad --- scripts/config/core/config_find_file.sh | 6 ++++-- .../config/core/variables/config_scan_variables.sh | 11 +++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/scripts/config/core/config_find_file.sh b/scripts/config/core/config_find_file.sh index db2c719..44e1d8c 100755 --- a/scripts/config/core/config_find_file.sh +++ b/scripts/config/core/config_find_file.sh @@ -5,8 +5,10 @@ findConfigFileForOption() { local config_option="$1" - # Global configs first. - for config_file in $(find "$configs_dir" -type f -name "*" ! -name ".category"); do + # Global configs first. Dotfiles (reconcile backups, markers) are excluded — + # finding a key in a .bak before its real file would write the user's + # config update into the backup and silently lose it. + for config_file in $(find "$configs_dir" -type f ! -name ".category" ! -name ".*" ! -name "*.bak"); do if [ -f "$config_file" ] && grep -q "^$config_option=" "$config_file"; then echo "$config_file" return 0 diff --git a/scripts/config/core/variables/config_scan_variables.sh b/scripts/config/core/variables/config_scan_variables.sh index f10a3d2..d5eb46a 100755 --- a/scripts/config/core/variables/config_scan_variables.sh +++ b/scripts/config/core/variables/config_scan_variables.sh @@ -8,8 +8,10 @@ # 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. +# and keeps a hidden ..bak sibling (dot-named so backups don't clutter the +# configs folder and can never be picked up by the config walkers/sourcing). +# 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 @@ -87,9 +89,10 @@ reconcileConfigFile() # Replace only when the result is sane (non-empty, has keys) and differs. if [[ -s "$tmp" ]] && grep -q '^CFG_' "$tmp" && ! runInstallOp cmp -s "$tmp" "$live"; then - runCfgOp cp -a "$live" "${live}.bak" + local bak_file="${live%/*}/.${live##*/}.bak" + runCfgOp cp -a "$live" "$bak_file" { [[ -n "$containers_dir" && "$live" == "$containers_dir"* ]] && runFileWrite "$live" < "$tmp" || runInstallOp cp "$tmp" "$live"; } - isSuccessful "Reconciled config: $(basename "$live") (backup: $(basename "$live").bak)" + isSuccessful "Reconciled config: $(basename "$live") (backup: ${bak_file##*/})" fi rm -f "$tmp" }