feat(exp-update): add --default-choice option for non-interactive updates

This commit is contained in:
Bishoy Ehab
2026-01-22 15:14:39 +02:00
parent 36051b5970
commit a217d4c5da
2 changed files with 136 additions and 117 deletions
+123 -116
View File
@@ -113,7 +113,16 @@ safe_read() {
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
# stdin is a terminal
read -r input_value
@@ -339,145 +348,124 @@ handle_file_conflict() {
local home_file="$2"
local filename=$(basename "$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"
echo "Repository version differs from your local version."
echo
echo "Choose an action:"
echo "1) Replace local file with repository version"
echo "2) Keep local file unchanged"
echo "3) Backup local file as ${filename}.old, use repository version"
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
# In non-interactive mode, use default directly (acts like pressing Enter)
if [[ "$NON_INTERACTIVE" == true ]]; then
choice="$default_val"
log_info "Using choice $choice for: $home_file"
else
echo -e "\n${STY_YELLOW}Conflict detected:${STY_RST} $home_file"
echo "Repository version differs from your local version."
echo
echo "Choose an action:"
echo "1) Replace local file with repository version"
echo "2) Keep local file unchanged"
echo "3) Backup local file as ${filename}.old, use repository version"
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
if ! safe_read "Enter your choice (1-8): " choice "6"; then
while true; do
if ! safe_read "Enter your choice (1-8) [${default_val}]: " choice "$default_val"; then
echo
log_warning "Failed to read input. Skipping file."
return
fi
# Validate choice
if [[ "$choice" =~ ^[1-8]$ ]]; then
break
else
echo "Invalid choice. Please enter 1-8."
fi
done
fi
case $choice in
1)
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)
log_info "Keeping local version of $home_file"
;;
3)
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)
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)
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 $choice in
1)
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
;;
2)
k)
log_info "Keeping local version of $home_file"
break
;;
3)
b)
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
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"
log_success "Backed up local file to ${filename}.old and updated"
fi
break
;;
4)
n)
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
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
break
;;
5)
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)
s)
log_info "Skipping $home_file"
break
;;
7)
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"
@@ -485,22 +473,41 @@ handle_file_conflict() {
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
;;
8)
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 enter 1-8."
log_info "Skipping $home_file"
;;
esac
done
;;
6)
log_info "Skipping $home_file"
;;
7)
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)
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
+13 -1
View File
@@ -16,6 +16,10 @@ Options:
-s, --skip-notice Skip notice about script being untested
--non-interactive
Run without prompting for user input
--default-choice=N
Set default choice for file conflicts (1-8, used with --non-interactive)
1=Replace local 2=Keep local 3=Backup as .old 4=Save as .new
5=Show diff 6=Skip 7=Add to ignore 8=Backup and replace
This script updates your dotfiles by:
1. Auto-detecting repository structure (dots/ prefix or direct)
@@ -35,7 +39,7 @@ Ignore file patterns support:
# `man getopt` to see more
para=$(getopt \
-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" -- "$@")
[ $? != 0 ] && echo "$0: Error when getopt, please recheck parameters." && exit 1
#####################################################################################
@@ -58,6 +62,7 @@ DRY_RUN=false
VERBOSE=false
SKIP_NOTICE=false
NON_INTERACTIVE=false
DEFAULT_CHOICE=""
eval set -- "$para"
while true ; do
@@ -81,6 +86,13 @@ while true ; do
--non-interactive) NON_INTERACTIVE=true;shift
log_info "Non-interactive mode enabled"
;;
--default-choice) DEFAULT_CHOICE="$2";shift 2
if [[ ! "$DEFAULT_CHOICE" =~ ^[1-8]$ ]]; then
log_error "Invalid --default-choice value: $DEFAULT_CHOICE (must be 1-8)"
exit 1
fi
log_info "Default conflict choice set to: $DEFAULT_CHOICE"
;;
## Ending
--) break ;;