diff --git a/bin/ssr-mackup b/bin/ssr-mackup index 09af2d4..f0a5e9e 100755 --- a/bin/ssr-mackup +++ b/bin/ssr-mackup @@ -85,26 +85,16 @@ cmd_scan() { _is_declared "$stale_path" && to_remove+=("$stale_cfg") done - # Classify each candidate: NEW or UPD (content differs from existing). + # Only suggest items that have NO cfg file yet. + # Existing files are user-owned — edit them directly in ~/.mackup/. local -a to_write=() - local -a labels=() local -a cfg_paths=() - local it app_name desired existing cfg_file paths_block + local it app_name cfg_file for it in "${items[@]:-}"; do app_name="$(_ssr_mackup_cfg_name "$it")" cfg_file="$cfg_dir/${app_name}.cfg" - paths_block="$(_ssr_mackup_resolve_paths "$it")" - desired="$(printf '[application]\nname = %s\n\n[configuration_files]\n%s\n' "$app_name" "$paths_block")" - if [[ -f "$cfg_file" ]]; then - existing="$(cat "$cfg_file")" - if [[ "$existing" == "$desired" ]]; then - continue # already up-to-date, skip - fi - labels+=("UPD") - else - labels+=("NEW") - fi + [[ -f "$cfg_file" ]] && continue # user owns it — skip to_write+=("$it") cfg_paths+=("$cfg_file") done @@ -120,22 +110,20 @@ cmd_scan() { printf '\nSuggested Mackup app definitions:\n' local i for i in "${!to_write[@]}"; do - local label="${labels[$i]}" local path="${cfg_paths[$i]##*/}" - local colour - [[ "$label" == "NEW" ]] && colour="\033[32m" || colour="\033[33m" - # Show resolved paths (selective or whole dir). + # Show resolved paths (selective default or whole dir). local resolved; resolved="$(_ssr_mackup_resolve_paths "${to_write[$i]}")" local line_count; line_count="$(printf '%s\n' "$resolved" | wc -l | tr -d ' ')" local paths_hint if [[ "$line_count" -eq 1 && "$resolved" == "${to_write[$i]}" ]]; then - paths_hint="${to_write[$i]}/" # whole directory + paths_hint="${to_write[$i]}/" else paths_hint="$line_count sub-path(s) of ${to_write[$i]}/" fi - printf " ${colour}%s\033[0m %-38s %s\n" \ - "$label" "~/.mackup/$path" "$paths_hint" + printf " \033[32mNEW\033[0m %-38s %s\n" \ + "~/.mackup/$path" "$paths_hint" done + printf '\n\033[2mEdit the generated files directly in ~/.mackup/ to customise paths.\033[0m\n' fi if [[ ${#to_remove[@]} -gt 0 ]]; then @@ -151,7 +139,7 @@ cmd_scan() { local total=$(( ${#to_write[@]} + ${#to_remove[@]} )) ssr::confirm "Apply $total change(s)?" 60 || { printf 'Aborted.\n'; return 0; } - # Write new/updated files. + # Write new files (never overwrites existing ones). for it in "${to_write[@]:-}"; do _ssr_mackup_write_cfg "$cfg_dir" "$it" done @@ -163,7 +151,8 @@ cmd_scan() { done ssr::ok "Done — ${#to_write[@]} written, ${#to_remove[@]} removed." - printf '\nRun \033[1mssr sync\033[0m to back up with the new definitions.\n\n' + printf '\nEdit ~/.mackup/ssr-*.cfg directly to customise paths.\n' + printf 'Run \033[1mssr sync\033[0m to back up with the new definitions.\n\n' } # --------------------------------------------------------------------------- diff --git a/config/ssr.conf.example b/config/ssr.conf.example index f6af8f9..59249bb 100644 --- a/config/ssr.conf.example +++ b/config/ssr.conf.example @@ -26,11 +26,6 @@ SSR_MACKUP_AUTODISCOVER=true # Built-in defaults: .claude/debug .cursor/logs .vscode/logs .npm/_logs # SSR_MACKUP_PRECLEAN_PATHS=".my-app/tmp .other-app/run" -# Selective sub-path overrides — back up only listed sub-paths for a dir -# instead of the whole directory (avoids sockets/debug symlinks in volatile dirs). -# Format: ".dir=subpath1,subpath2" Built-in defaults cover .claude, .cursor, etc. -# SSR_MACKUP_SELECTIVE_PATHS=".my-app=config.json,themes" - # Extra paths (relative to $HOME) to always include, space-separated. # Example: ".easymcp .my-tool .config/my-cli" # SSR_MACKUP_EXTRA_PATHS="" diff --git a/lib/mackup.sh b/lib/mackup.sh index 78d7eb1..ac5aa42 100644 --- a/lib/mackup.sh +++ b/lib/mackup.sh @@ -76,62 +76,46 @@ _ssr_mackup_cfg_name() { printf 'ssr-%s' "$name" } -# Resolve the list of [configuration_files] entries for an item. -# If a selective override exists for the item, expand sub-paths that are -# present on disk. Falls back to the item itself (whole directory). +# Resolve the initial [configuration_files] entries for a NEW item. +# Uses _SSR_MACKUP_SELECTIVE defaults; once a cfg file exists the user owns +# it and this function is never called for that item again. # # Outputs one path per line. _ssr_mackup_resolve_paths() { local item="$1" - local -a all_selective=("${_SSR_MACKUP_SELECTIVE[@]}") - # Merge user-defined selectives from ssr.conf. local entry - for entry in ${SSR_MACKUP_SELECTIVE_PATHS:-}; do - all_selective+=("$entry") - done - - for entry in "${all_selective[@]}"; do + for entry in "${_SSR_MACKUP_SELECTIVE[@]}"; do local key="${entry%%=*}" local val="${entry#*=}" if [[ "$key" == "$item" ]]; then - # Split comma-separated sub-paths; only include those that exist. local sub local IFS=',' for sub in $val; do IFS=' ' - local full="$item/$sub" - # List the path even if it doesn't exist yet — it may be created later. - printf '%s\n' "$full" + printf '%s\n' "$item/$sub" done return 0 fi done - - # No selective entry — back up the whole directory. + # No selective default — back up the whole directory. printf '%s\n' "$item" } -# Write a single ~/.mackup/.cfg for one dot-path. -# Uses selective sub-paths when a matching entry exists in _SSR_MACKUP_SELECTIVE. -# Skips writing if content is unchanged (idempotent). +# Write a single ~/.mackup/.cfg for a NEW item. +# Never called when the file already exists — existing files are user-owned. _ssr_mackup_write_cfg() { local cfg_dir="$1" item="$2" local app_name; app_name="$(_ssr_mackup_cfg_name "$item")" local cfg_file="$cfg_dir/${app_name}.cfg" - # Build [configuration_files] block. + # Never overwrite existing files — user may have customised them. + [[ -f "$cfg_file" ]] && return 0 + local paths_block paths_block="$(_ssr_mackup_resolve_paths "$item")" - local desired - desired="$(printf '[application]\nname = %s\n\n[configuration_files]\n%s\n' \ - "$app_name" "$paths_block")" - - if [[ -f "$cfg_file" ]] && [[ "$(cat "$cfg_file")" == "$desired" ]]; then - return 0 # already up-to-date - fi - - printf '%s\n' "$desired" > "$cfg_file" + printf '[application]\nname = %s\n\n[configuration_files]\n%s\n' \ + "$app_name" "$paths_block" > "$cfg_file" } # Build a newline-separated list of all paths already declared in Mackup's