191 lines
6.4 KiB
Bash
Executable File
191 lines
6.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
BACKUP_DIR="${SCRIPT_DIR}/backups"
|
|
|
|
# Function to sanitize a konsolerc file by stripping the [MainWindow] section
|
|
sanitize_konsolerc() {
|
|
local target_file="$1"
|
|
if [ -f "${target_file}" ]; then
|
|
local cleaned_file="${target_file}.clean"
|
|
awk '
|
|
/^\[MainWindow\]/ { skip=1; next }
|
|
/^\[.*\]/ { skip=0 }
|
|
!skip { print }
|
|
' "${target_file}" > "${cleaned_file}"
|
|
mv "${cleaned_file}" "${target_file}"
|
|
fi
|
|
}
|
|
|
|
show_diff() {
|
|
local source_dir="$1"
|
|
echo ""
|
|
echo "==================== Changes Preview (Diff) ===================="
|
|
local changes_found=0
|
|
|
|
while IFS= read -r -d '' item; do
|
|
rel_path="${item#"${source_dir}"/}"
|
|
dest_item="${HOME}/${rel_path}"
|
|
|
|
if [ -d "${item}" ]; then
|
|
continue
|
|
fi
|
|
|
|
if [ ! -e "${dest_item}" ]; then
|
|
changes_found=1
|
|
echo -e "\n\033[1;32m[NEW FILE]\033[0m ~/${rel_path}"
|
|
else
|
|
if [ "${rel_path}" = ".config/konsolerc" ]; then
|
|
# Compare against sanitized version of local konsolerc so [MainWindow] geometry noise is ignored
|
|
local temp_local_clean
|
|
temp_local_clean="$(mktemp)"
|
|
sanitize_konsolerc "${dest_item}" 2>/dev/null || true
|
|
awk '
|
|
/^\[MainWindow\]/ { skip=1; next }
|
|
/^\[.*\]/ { skip=0 }
|
|
!skip { print }
|
|
' "${dest_item}" > "${temp_local_clean}"
|
|
|
|
if ! cmp -s "${item}" "${temp_local_clean}"; then
|
|
changes_found=1
|
|
echo -e "\n\033[1;33m[MODIFIED]\033[0m ~/${rel_path}"
|
|
if command -v git &>/dev/null; then
|
|
git diff --no-index --color "${temp_local_clean}" "${item}" || true
|
|
else
|
|
diff -u --color=always "${temp_local_clean}" "${item}" || true
|
|
fi
|
|
fi
|
|
rm -f "${temp_local_clean}"
|
|
else
|
|
if ! cmp -s "${item}" "${dest_item}"; then
|
|
changes_found=1
|
|
echo -e "\n\033[1;33m[MODIFIED]\033[0m ~/${rel_path}"
|
|
if command -v git &>/dev/null; then
|
|
git diff --no-index --color "${dest_item}" "${item}" || true
|
|
else
|
|
diff -u --color=always "${dest_item}" "${item}" || true
|
|
fi
|
|
fi
|
|
fi
|
|
fi
|
|
done < <(find "${source_dir}" -type f -print0)
|
|
|
|
if [ "${changes_found}" -eq 0 ]; then
|
|
echo -e "\n\033[1;32mNo differences detected. Current configuration matches the backup exactly.\033[0m"
|
|
fi
|
|
echo "================================================================"
|
|
echo ""
|
|
}
|
|
|
|
ARCHIVE_PATH=""
|
|
|
|
# 1. Check positional argument
|
|
if [ $# -ge 1 ] && [ -n "$1" ]; then
|
|
ARCHIVE_PATH="$1"
|
|
# 2. Check if piped via stdin
|
|
elif [ ! -t 0 ]; then
|
|
read -r ARCHIVE_PATH || true
|
|
fi
|
|
|
|
# 3. Interactive prompt / selection menu if no input given
|
|
if [ -z "${ARCHIVE_PATH}" ]; then
|
|
if [ ! -d "${BACKUP_DIR}" ]; then
|
|
echo "Error: No backups directory found at ${BACKUP_DIR}"
|
|
exit 1
|
|
fi
|
|
|
|
mapfile -t AVAILABLE_BACKUPS < <(find "${BACKUP_DIR}" -maxdepth 1 -name "konsole_backup_*.zip" | sort -r)
|
|
|
|
if [ "${#AVAILABLE_BACKUPS[@]}" -eq 0 ]; then
|
|
echo "Error: No backup archives found in ${BACKUP_DIR}."
|
|
exit 1
|
|
fi
|
|
|
|
echo "Available Konsole backups:"
|
|
for i in "${!AVAILABLE_BACKUPS[@]}"; do
|
|
echo " [$((i + 1))] $(basename "${AVAILABLE_BACKUPS[$i]}")"
|
|
done
|
|
echo " [q] Quit"
|
|
|
|
if [ -t 0 ]; then
|
|
read -r -p "Select a backup to restore [1-${#AVAILABLE_BACKUPS[@]}]: " choice || true
|
|
elif [ -c /dev/tty ] && [ -r /dev/tty ] && { : < /dev/tty; } 2>/dev/null; then
|
|
read -r -p "Select a backup to restore [1-${#AVAILABLE_BACKUPS[@]}]: " choice < /dev/tty || true
|
|
else
|
|
read -r -p "Select a backup to restore [1-${#AVAILABLE_BACKUPS[@]}]: " choice || true
|
|
fi
|
|
if [[ "${choice}" =~ ^[0-9]+$ ]] && [ "${choice}" -ge 1 ] && [ "${choice}" -le "${#AVAILABLE_BACKUPS[@]}" ]; then
|
|
ARCHIVE_PATH="${AVAILABLE_BACKUPS[$((choice - 1))]}"
|
|
else
|
|
echo "Aborted."
|
|
exit 0
|
|
fi
|
|
fi
|
|
|
|
# Expand relative paths
|
|
if [[ "${ARCHIVE_PATH}" != /* ]]; then
|
|
if [ -f "${BACKUP_DIR}/${ARCHIVE_PATH}" ]; then
|
|
ARCHIVE_PATH="${BACKUP_DIR}/${ARCHIVE_PATH}"
|
|
elif [ -f "./${ARCHIVE_PATH}" ]; then
|
|
ARCHIVE_PATH="$(pwd)/${ARCHIVE_PATH}"
|
|
fi
|
|
fi
|
|
|
|
if [ ! -f "${ARCHIVE_PATH}" ]; then
|
|
echo "Error: Backup file not found: ${ARCHIVE_PATH}"
|
|
exit 1
|
|
fi
|
|
|
|
echo "Selected backup archive: ${ARCHIVE_PATH}"
|
|
|
|
# Extract to temporary staging directory
|
|
TEMP_DIR="$(mktemp -d)"
|
|
trap 'rm -rf "${TEMP_DIR}"' EXIT
|
|
|
|
unzip -q -o "${ARCHIVE_PATH}" -d "${TEMP_DIR}"
|
|
|
|
# Extra safety: Sanitize extracted konsolerc in case restoring an older archive
|
|
if [ -f "${TEMP_DIR}/.config/konsolerc" ]; then
|
|
sanitize_konsolerc "${TEMP_DIR}/.config/konsolerc"
|
|
fi
|
|
|
|
# Interactive confirmation loop (allows viewing diffs)
|
|
while true; do
|
|
echo ""
|
|
echo "Konsole configuration files to be restored:"
|
|
find "${TEMP_DIR}" -type f | while read -r f; do
|
|
rel="${f#"${TEMP_DIR}"/}"
|
|
echo " - ~/${rel}"
|
|
done
|
|
echo ""
|
|
|
|
if [ -t 0 ]; then
|
|
read -r -p "Choose action: [r] Restore / [d] View Diff / [c] Cancel: " action || true
|
|
elif [ -c /dev/tty ] && [ -r /dev/tty ] && { : < /dev/tty; } 2>/dev/null; then
|
|
read -r -p "Choose action: [r] Restore / [d] View Diff / [c] Cancel: " action < /dev/tty || true
|
|
else
|
|
read -r -p "Choose action: [r] Restore / [d] View Diff / [c] Cancel: " action || true
|
|
fi
|
|
|
|
case "${action,,}" in
|
|
r|y|yes)
|
|
echo "Restoring configuration files..."
|
|
cp -a "${TEMP_DIR}/." "${HOME}/"
|
|
echo -e "\033[1;32mKonsole configurations restored successfully from $(basename "${ARCHIVE_PATH}")!\033[0m"
|
|
echo "Note: If Konsole is currently running, please restart it to apply all settings."
|
|
break
|
|
;;
|
|
d|diff)
|
|
show_diff "${TEMP_DIR}"
|
|
;;
|
|
c|q|n|no|cancel)
|
|
echo "Restoration cancelled."
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Invalid option. Please enter 'r', 'd', or 'c'."
|
|
;;
|
|
esac
|
|
done
|