refactor: ssr-*.cfg files are user-owned after creation
ssr mackup scan now only suggests NEW files — it never overwrites an existing ssr-*.cfg. Once created, the file belongs to the user who edits it directly in ~/.mackup/ to customise which paths are backed up. - _ssr_mackup_write_cfg: returns early if file already exists - scan: drops UPD logic; only shows NEW suggestions - _ssr_mackup_resolve_paths: removed SSR_MACKUP_SELECTIVE_PATHS support (ssr.conf config variable removed — edit the cfg files instead) - Scan output: hints to edit files directly after creation Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+12
-23
@@ -85,26 +85,16 @@ cmd_scan() {
|
|||||||
_is_declared "$stale_path" && to_remove+=("$stale_cfg")
|
_is_declared "$stale_path" && to_remove+=("$stale_cfg")
|
||||||
done
|
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 to_write=()
|
||||||
local -a labels=()
|
|
||||||
local -a cfg_paths=()
|
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
|
for it in "${items[@]:-}"; do
|
||||||
app_name="$(_ssr_mackup_cfg_name "$it")"
|
app_name="$(_ssr_mackup_cfg_name "$it")"
|
||||||
cfg_file="$cfg_dir/${app_name}.cfg"
|
cfg_file="$cfg_dir/${app_name}.cfg"
|
||||||
paths_block="$(_ssr_mackup_resolve_paths "$it")"
|
[[ -f "$cfg_file" ]] && continue # user owns it — skip
|
||||||
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
|
|
||||||
to_write+=("$it")
|
to_write+=("$it")
|
||||||
cfg_paths+=("$cfg_file")
|
cfg_paths+=("$cfg_file")
|
||||||
done
|
done
|
||||||
@@ -120,22 +110,20 @@ cmd_scan() {
|
|||||||
printf '\nSuggested Mackup app definitions:\n'
|
printf '\nSuggested Mackup app definitions:\n'
|
||||||
local i
|
local i
|
||||||
for i in "${!to_write[@]}"; do
|
for i in "${!to_write[@]}"; do
|
||||||
local label="${labels[$i]}"
|
|
||||||
local path="${cfg_paths[$i]##*/}"
|
local path="${cfg_paths[$i]##*/}"
|
||||||
local colour
|
# Show resolved paths (selective default or whole dir).
|
||||||
[[ "$label" == "NEW" ]] && colour="\033[32m" || colour="\033[33m"
|
|
||||||
# Show resolved paths (selective or whole dir).
|
|
||||||
local resolved; resolved="$(_ssr_mackup_resolve_paths "${to_write[$i]}")"
|
local resolved; resolved="$(_ssr_mackup_resolve_paths "${to_write[$i]}")"
|
||||||
local line_count; line_count="$(printf '%s\n' "$resolved" | wc -l | tr -d ' ')"
|
local line_count; line_count="$(printf '%s\n' "$resolved" | wc -l | tr -d ' ')"
|
||||||
local paths_hint
|
local paths_hint
|
||||||
if [[ "$line_count" -eq 1 && "$resolved" == "${to_write[$i]}" ]]; then
|
if [[ "$line_count" -eq 1 && "$resolved" == "${to_write[$i]}" ]]; then
|
||||||
paths_hint="${to_write[$i]}/" # whole directory
|
paths_hint="${to_write[$i]}/"
|
||||||
else
|
else
|
||||||
paths_hint="$line_count sub-path(s) of ${to_write[$i]}/"
|
paths_hint="$line_count sub-path(s) of ${to_write[$i]}/"
|
||||||
fi
|
fi
|
||||||
printf " ${colour}%s\033[0m %-38s %s\n" \
|
printf " \033[32mNEW\033[0m %-38s %s\n" \
|
||||||
"$label" "~/.mackup/$path" "$paths_hint"
|
"~/.mackup/$path" "$paths_hint"
|
||||||
done
|
done
|
||||||
|
printf '\n\033[2mEdit the generated files directly in ~/.mackup/ to customise paths.\033[0m\n'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ${#to_remove[@]} -gt 0 ]]; then
|
if [[ ${#to_remove[@]} -gt 0 ]]; then
|
||||||
@@ -151,7 +139,7 @@ cmd_scan() {
|
|||||||
local total=$(( ${#to_write[@]} + ${#to_remove[@]} ))
|
local total=$(( ${#to_write[@]} + ${#to_remove[@]} ))
|
||||||
ssr::confirm "Apply $total change(s)?" 60 || { printf 'Aborted.\n'; return 0; }
|
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
|
for it in "${to_write[@]:-}"; do
|
||||||
_ssr_mackup_write_cfg "$cfg_dir" "$it"
|
_ssr_mackup_write_cfg "$cfg_dir" "$it"
|
||||||
done
|
done
|
||||||
@@ -163,7 +151,8 @@ cmd_scan() {
|
|||||||
done
|
done
|
||||||
|
|
||||||
ssr::ok "Done — ${#to_write[@]} written, ${#to_remove[@]} removed."
|
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'
|
||||||
}
|
}
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -26,11 +26,6 @@ SSR_MACKUP_AUTODISCOVER=true
|
|||||||
# Built-in defaults: .claude/debug .cursor/logs .vscode/logs .npm/_logs
|
# Built-in defaults: .claude/debug .cursor/logs .vscode/logs .npm/_logs
|
||||||
# SSR_MACKUP_PRECLEAN_PATHS=".my-app/tmp .other-app/run"
|
# 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.
|
# Extra paths (relative to $HOME) to always include, space-separated.
|
||||||
# Example: ".easymcp .my-tool .config/my-cli"
|
# Example: ".easymcp .my-tool .config/my-cli"
|
||||||
# SSR_MACKUP_EXTRA_PATHS=""
|
# SSR_MACKUP_EXTRA_PATHS=""
|
||||||
|
|||||||
+13
-29
@@ -76,62 +76,46 @@ _ssr_mackup_cfg_name() {
|
|||||||
printf 'ssr-%s' "$name"
|
printf 'ssr-%s' "$name"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Resolve the list of [configuration_files] entries for an item.
|
# Resolve the initial [configuration_files] entries for a NEW item.
|
||||||
# If a selective override exists for the item, expand sub-paths that are
|
# Uses _SSR_MACKUP_SELECTIVE defaults; once a cfg file exists the user owns
|
||||||
# present on disk. Falls back to the item itself (whole directory).
|
# it and this function is never called for that item again.
|
||||||
#
|
#
|
||||||
# Outputs one path per line.
|
# Outputs one path per line.
|
||||||
_ssr_mackup_resolve_paths() {
|
_ssr_mackup_resolve_paths() {
|
||||||
local item="$1"
|
local item="$1"
|
||||||
local -a all_selective=("${_SSR_MACKUP_SELECTIVE[@]}")
|
|
||||||
# Merge user-defined selectives from ssr.conf.
|
|
||||||
local entry
|
local entry
|
||||||
for entry in ${SSR_MACKUP_SELECTIVE_PATHS:-}; do
|
for entry in "${_SSR_MACKUP_SELECTIVE[@]}"; do
|
||||||
all_selective+=("$entry")
|
|
||||||
done
|
|
||||||
|
|
||||||
for entry in "${all_selective[@]}"; do
|
|
||||||
local key="${entry%%=*}"
|
local key="${entry%%=*}"
|
||||||
local val="${entry#*=}"
|
local val="${entry#*=}"
|
||||||
if [[ "$key" == "$item" ]]; then
|
if [[ "$key" == "$item" ]]; then
|
||||||
# Split comma-separated sub-paths; only include those that exist.
|
|
||||||
local sub
|
local sub
|
||||||
local IFS=','
|
local IFS=','
|
||||||
for sub in $val; do
|
for sub in $val; do
|
||||||
IFS=' '
|
IFS=' '
|
||||||
local full="$item/$sub"
|
printf '%s\n' "$item/$sub"
|
||||||
# List the path even if it doesn't exist yet — it may be created later.
|
|
||||||
printf '%s\n' "$full"
|
|
||||||
done
|
done
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
# No selective default — back up the whole directory.
|
||||||
# No selective entry — back up the whole directory.
|
|
||||||
printf '%s\n' "$item"
|
printf '%s\n' "$item"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Write a single ~/.mackup/<name>.cfg for one dot-path.
|
# Write a single ~/.mackup/<name>.cfg for a NEW item.
|
||||||
# Uses selective sub-paths when a matching entry exists in _SSR_MACKUP_SELECTIVE.
|
# Never called when the file already exists — existing files are user-owned.
|
||||||
# Skips writing if content is unchanged (idempotent).
|
|
||||||
_ssr_mackup_write_cfg() {
|
_ssr_mackup_write_cfg() {
|
||||||
local cfg_dir="$1" item="$2"
|
local cfg_dir="$1" item="$2"
|
||||||
local app_name; app_name="$(_ssr_mackup_cfg_name "$item")"
|
local app_name; app_name="$(_ssr_mackup_cfg_name "$item")"
|
||||||
local cfg_file="$cfg_dir/${app_name}.cfg"
|
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
|
local paths_block
|
||||||
paths_block="$(_ssr_mackup_resolve_paths "$item")"
|
paths_block="$(_ssr_mackup_resolve_paths "$item")"
|
||||||
|
|
||||||
local desired
|
printf '[application]\nname = %s\n\n[configuration_files]\n%s\n' \
|
||||||
desired="$(printf '[application]\nname = %s\n\n[configuration_files]\n%s\n' \
|
"$app_name" "$paths_block" > "$cfg_file"
|
||||||
"$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"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Build a newline-separated list of all paths already declared in Mackup's
|
# Build a newline-separated list of all paths already declared in Mackup's
|
||||||
|
|||||||
Reference in New Issue
Block a user