feat(exp-update): add --default-choice option (#2915)

This commit is contained in:
Celestial.y
2026-01-23 08:06:39 +08:00
committed by GitHub
2 changed files with 148 additions and 118 deletions
+123 -116
View File
@@ -113,7 +113,16 @@ safe_read() {
echo -n "$prompt" echo -n "$prompt"
# Try to read from terminal with better detection # First, try reading from stdin (supports piped input like "yes 1 |")
if read -r -t 0.1 input_value 2>/dev/null; then
# Successfully read from stdin (piped input)
if [[ -n "$input_value" ]]; then
printf -v "$varname" '%s' "$input_value"
return 0
fi
fi
# If stdin had no data, try interactive terminal
if [[ -t 0 ]]; then if [[ -t 0 ]]; then
# stdin is a terminal # stdin is a terminal
read -r input_value read -r input_value
@@ -339,145 +348,124 @@ handle_file_conflict() {
local home_file="$2" local home_file="$2"
local filename=$(basename "$home_file") local filename=$(basename "$home_file")
local dirname=$(dirname "$home_file") local dirname=$(dirname "$home_file")
local choice=""
local default_val="${DEFAULT_CHOICE:-6}" # Use DEFAULT_CHOICE or 6 (skip) as fallback
echo -e "\n${STY_YELLOW}Conflict detected:${STY_RST} $home_file" # In non-interactive mode, use default directly (acts like pressing Enter)
echo "Repository version differs from your local version." if [[ "$NON_INTERACTIVE" == true ]]; then
echo choice="$default_val"
echo "Choose an action:" log_info "Using choice $choice for: $home_file"
echo "1) Replace local file with repository version" else
echo "2) Keep local file unchanged" echo -e "\n${STY_YELLOW}Conflict detected:${STY_RST} $home_file"
echo "3) Backup local file as ${filename}.old, use repository version" echo "Repository version differs from your local version."
echo "4) Save repository version as ${filename}.new, keep local file" echo
echo "5) Show diff and decide" echo "Choose an action:"
echo "6) Skip this file" echo "1) Replace local file with repository version"
echo "7) Add to ignore and skip" echo "2) Keep local file unchanged"
echo "8) Backup to .update-backups/ and replace with repository version" echo "3) Backup local file as ${filename}.old, use repository version"
echo echo "4) Save repository version as ${filename}.new, keep local file"
echo "5) Show diff and decide"
echo "6) Skip this file"
echo "7) Add to ignore and skip"
echo "8) Backup to .update-backups/ and replace with repository version"
echo
while true; do while true; do
if ! safe_read "Enter your choice (1-8): " choice "6"; then if ! safe_read "Enter your choice (1-8 or name) [${default_val}]: " choice "$default_val"; then
echo
log_warning "Failed to read input. Skipping file."
return
fi
# Validate choice
if [[ "$choice" =~ ^[1-8]$ ]] || [[ "$choice" =~ ^(replace|keep|old|new|diff|skip|ignore|backup)$ ]]; then
break
else
echo "Invalid choice. Please enter 1-8 or a valid name (replace, keep, old ...)."
fi
done
fi
case $choice in
1|replace)
if [[ "$DRY_RUN" == true ]]; then
log_info "[DRY-RUN] Would replace $home_file with repository version"
else
cp -p "$repo_file" "$home_file"
log_success "Replaced $home_file with repository version"
fi
;;
2|keep)
log_info "Keeping local version of $home_file"
;;
3|old)
if [[ "$DRY_RUN" == true ]]; then
log_info "[DRY-RUN] Would backup local file to ${filename}.old and update with repository version"
else
mv "$home_file" "${dirname}/${filename}.old"
cp -p "$repo_file" "$home_file"
log_success "Backed up local file to ${filename}.old and updated with repository version"
fi
;;
4|new)
if [[ "$DRY_RUN" == true ]]; then
log_info "[DRY-RUN] Would save repository version as ${filename}.new, keep local file"
else
cp -p "$repo_file" "${dirname}/${filename}.new"
log_success "Saved repository version as ${filename}.new, kept local file"
fi
;;
5|diff)
show_diff "$home_file" "$repo_file"
echo
echo "After reviewing the diff, choose:"
echo "r) Replace with repository version"
echo "k) Keep local version"
echo "b) Backup local and use repository version"
echo "n) Save repository version as .new"
echo "s) Skip this file"
echo "i) Add to ignore and skip"
echo "B) Backup to .update-backups/ and replace"
if ! safe_read "Enter your choice (r/k/b/n/s/i/B): " subchoice "s"; then
echo echo
log_warning "Failed to read input. Skipping file." log_warning "Failed to read input. Skipping file."
return return
fi fi
case $choice in case $subchoice in
1) r)
if [[ "$DRY_RUN" == true ]]; then if [[ "$DRY_RUN" == true ]]; then
log_info "[DRY-RUN] Would replace $home_file with repository version" log_info "[DRY-RUN] Would replace $home_file with repository version"
else else
cp -p "$repo_file" "$home_file" cp -p "$repo_file" "$home_file"
log_success "Replaced $home_file with repository version" log_success "Replaced $home_file with repository version"
fi fi
break
;; ;;
2) k)
log_info "Keeping local version of $home_file" log_info "Keeping local version of $home_file"
break
;; ;;
3) b)
if [[ "$DRY_RUN" == true ]]; then if [[ "$DRY_RUN" == true ]]; then
log_info "[DRY-RUN] Would backup local file to ${filename}.old and update with repository version" log_info "[DRY-RUN] Would backup local file to ${filename}.old and update"
else else
mv "$home_file" "${dirname}/${filename}.old" mv "$home_file" "${dirname}/${filename}.old"
cp -p "$repo_file" "$home_file" cp -p "$repo_file" "$home_file"
log_success "Backed up local file to ${filename}.old and updated with repository version" log_success "Backed up local file to ${filename}.old and updated"
fi fi
break
;; ;;
4) n)
if [[ "$DRY_RUN" == true ]]; then if [[ "$DRY_RUN" == true ]]; then
log_info "[DRY-RUN] Would save repository version as ${filename}.new, keep local file" log_info "[DRY-RUN] Would save repository version as ${filename}.new"
else else
cp -p "$repo_file" "${dirname}/${filename}.new" cp -p "$repo_file" "${dirname}/${filename}.new"
log_success "Saved repository version as ${filename}.new, kept local file" log_success "Saved repository version as ${filename}.new"
fi fi
break
;; ;;
5) s)
show_diff "$home_file" "$repo_file"
echo
echo "After reviewing the diff, choose:"
echo "r) Replace with repository version"
echo "k) Keep local version"
echo "b) Backup local and use repository version"
echo "n) Save repository version as .new"
echo "s) Skip this file"
echo "i) Add to ignore and skip"
echo "B) Backup to .update-backups/ and replace"
if ! safe_read "Enter your choice (r/k/b/n/s/i/B): " subchoice "s"; then
echo
log_warning "Failed to read input. Skipping file."
return
fi
case $subchoice in
r)
if [[ "$DRY_RUN" == true ]]; then
log_info "[DRY-RUN] Would replace $home_file with repository version"
else
cp -p "$repo_file" "$home_file"
log_success "Replaced $home_file with repository version"
fi
break
;;
k)
log_info "Keeping local version of $home_file"
break
;;
b)
if [[ "$DRY_RUN" == true ]]; then
log_info "[DRY-RUN] Would backup local file to ${filename}.old and update"
else
mv "$home_file" "${dirname}/${filename}.old"
cp -p "$repo_file" "$home_file"
log_success "Backed up local file to ${filename}.old and updated"
fi
break
;;
n)
if [[ "$DRY_RUN" == true ]]; then
log_info "[DRY-RUN] Would save repository version as ${filename}.new"
else
cp -p "$repo_file" "${dirname}/${filename}.new"
log_success "Saved repository version as ${filename}.new"
fi
break
;;
s)
log_info "Skipping $home_file"
break
;;
i)
local relative_path_to_home="${home_file#$HOME/}"
if [[ "$DRY_RUN" == true ]]; then
log_info "[DRY-RUN] Would add '$relative_path_to_home' to $XDG_UPDATE_IGNORE_FILE"
else
echo "$relative_path_to_home" >>"$XDG_UPDATE_IGNORE_FILE"
log_success "Added '$relative_path_to_home' to $XDG_UPDATE_IGNORE_FILE and skipped."
fi
break
;;
B)
if backup_file "$home_file"; then
if [[ "$DRY_RUN" != true ]]; then
cp -p "$repo_file" "$home_file"
log_success "Replaced $home_file with repository version"
fi
fi
break
;;
*)
echo "Invalid choice. Please try again."
;;
esac
;;
6)
log_info "Skipping $home_file" log_info "Skipping $home_file"
break
;; ;;
7) i)
local relative_path_to_home="${home_file#$HOME/}" local relative_path_to_home="${home_file#$HOME/}"
if [[ "$DRY_RUN" == true ]]; then if [[ "$DRY_RUN" == true ]]; then
log_info "[DRY-RUN] Would add '$relative_path_to_home' to $XDG_UPDATE_IGNORE_FILE" log_info "[DRY-RUN] Would add '$relative_path_to_home' to $XDG_UPDATE_IGNORE_FILE"
@@ -485,22 +473,41 @@ handle_file_conflict() {
echo "$relative_path_to_home" >>"$XDG_UPDATE_IGNORE_FILE" echo "$relative_path_to_home" >>"$XDG_UPDATE_IGNORE_FILE"
log_success "Added '$relative_path_to_home' to $XDG_UPDATE_IGNORE_FILE and skipped." log_success "Added '$relative_path_to_home' to $XDG_UPDATE_IGNORE_FILE and skipped."
fi fi
break
;; ;;
8) B)
if backup_file "$home_file"; then if backup_file "$home_file"; then
if [[ "$DRY_RUN" != true ]]; then if [[ "$DRY_RUN" != true ]]; then
cp -p "$repo_file" "$home_file" cp -p "$repo_file" "$home_file"
log_success "Replaced $home_file with repository version" log_success "Replaced $home_file with repository version"
fi fi
fi fi
break
;; ;;
*) *)
echo "Invalid choice. Please enter 1-8." log_info "Skipping $home_file"
;; ;;
esac esac
done ;;
6|skip)
log_info "Skipping $home_file"
;;
7|ignore)
local relative_path_to_home="${home_file#$HOME/}"
if [[ "$DRY_RUN" == true ]]; then
log_info "[DRY-RUN] Would add '$relative_path_to_home' to $XDG_UPDATE_IGNORE_FILE"
else
echo "$relative_path_to_home" >>"$XDG_UPDATE_IGNORE_FILE"
log_success "Added '$relative_path_to_home' to $XDG_UPDATE_IGNORE_FILE and skipped."
fi
;;
8|backup)
if backup_file "$home_file"; then
if [[ "$DRY_RUN" != true ]]; then
cp -p "$repo_file" "$home_file"
log_success "Replaced $home_file with repository version"
fi
fi
;;
esac
} }
# Function to check if PKGBUILD has changed # Function to check if PKGBUILD has changed
+25 -2
View File
@@ -15,7 +15,10 @@ Options:
-h, --help Show this help message -h, --help Show this help message
-s, --skip-notice Skip notice about script being untested -s, --skip-notice Skip notice about script being untested
--non-interactive --non-interactive
Run without prompting for user input Set default choice for file conflicts
replace: Replace local keep: Keep local old: Backup as .old
new: Save as .new diff: Show diff skip: Skip
ignore: Add to ignore backup: Backup and replace
This script updates your dotfiles by: This script updates your dotfiles by:
1. Auto-detecting repository structure (dots/ prefix or direct) 1. Auto-detecting repository structure (dots/ prefix or direct)
@@ -35,7 +38,7 @@ Ignore file patterns support:
# `man getopt` to see more # `man getopt` to see more
para=$(getopt \ para=$(getopt \
-o hfpnvs \ -o hfpnvs \
-l help,force,packages,dry-run,verbose,skip-notice,non-interactive \ -l help,force,packages,dry-run,verbose,skip-notice,non-interactive,default-choice: \
-n "$0" -- "$@") -n "$0" -- "$@")
[ $? != 0 ] && echo "$0: Error when getopt, please recheck parameters." && exit 1 [ $? != 0 ] && echo "$0: Error when getopt, please recheck parameters." && exit 1
##################################################################################### #####################################################################################
@@ -58,6 +61,7 @@ DRY_RUN=false
VERBOSE=false VERBOSE=false
SKIP_NOTICE=false SKIP_NOTICE=false
NON_INTERACTIVE=false NON_INTERACTIVE=false
DEFAULT_CHOICE=""
eval set -- "$para" eval set -- "$para"
while true ; do while true ; do
@@ -81,6 +85,25 @@ while true ; do
--non-interactive) NON_INTERACTIVE=true;shift --non-interactive) NON_INTERACTIVE=true;shift
log_info "Non-interactive mode enabled" log_info "Non-interactive mode enabled"
;; ;;
--default-choice)
case "$2" in
replace) DEFAULT_CHOICE="1" ;;
keep) DEFAULT_CHOICE="2" ;;
old) DEFAULT_CHOICE="3" ;;
new) DEFAULT_CHOICE="4" ;;
diff) DEFAULT_CHOICE="5" ;;
skip) DEFAULT_CHOICE="6" ;;
ignore) DEFAULT_CHOICE="7" ;;
backup) DEFAULT_CHOICE="8" ;;
*)
log_error "Invalid --default-choice value: $2"
log_error "Valid values: replace, keep, old, new, diff, skip, ignore, backup"
exit 1
;;
esac
shift 2
log_info "Default conflict choice set to: $DEFAULT_CHOICE"
;;
## Ending ## Ending
--) break ;; --) break ;;