parent
1229d41f36
commit
d193277014
1 changed files with 223 additions and 0 deletions
@ -0,0 +1,223 @@ |
||||
#!/usr/bin/bash |
||||
|
||||
# Check for sync conflicts and resolve them. Idea from the shell |
||||
# script 'pacdiff'. |
||||
|
||||
declare -r myname='syncthing-resolve-conflicts.sh' |
||||
declare -r myver='1.0.0' |
||||
|
||||
diffprog=${DIFFPROG:-'vim -d'} |
||||
USE_COLOR='y' |
||||
declare -a ignored |
||||
declare -a nontext |
||||
|
||||
plain() { |
||||
(( QUIET )) && return |
||||
local mesg=$1; shift |
||||
printf " ${mesg}${ALL_OFF}\n" "$@" >&1 |
||||
} |
||||
|
||||
msg() { |
||||
(( QUIET )) && return |
||||
local mesg=$1; shift |
||||
printf "${GREEN}==>${ALL_OFF} ${mesg}${ALL_OFF}\n" "$@" >&1 |
||||
} |
||||
|
||||
msg2() { |
||||
(( QUIET )) && return |
||||
local mesg=$1; shift |
||||
printf "${BLUE} ->${ALL_OFF} ${mesg}${ALL_OFF}\n" "$@" >&1 |
||||
} |
||||
|
||||
ask() { |
||||
local mesg=$1; shift |
||||
printf " ${BLUE}::${ALL_OFF} ${mesg}${ALL_OFF}" "$@" >&1 |
||||
} |
||||
|
||||
warning() { |
||||
local mesg=$1; shift |
||||
echo |
||||
printf "${YELLOW}==> $(gettext "WARNING:")${ALL_OFF} ${mesg}${ALL_OFF}\n" "$@" >&2 |
||||
} |
||||
|
||||
error() { |
||||
local mesg=$1; shift |
||||
printf "${RED}==> $(gettext "ERROR:")${ALL_OFF} ${mesg}${ALL_OFF}\n" "$@" >&2 |
||||
} |
||||
|
||||
usage() { |
||||
cat <<EOF |
||||
${myname} v${myver} |
||||
|
||||
Inspired by 'pacdiff'. |
||||
A simple program to merge or remove sync conflicts. |
||||
Locate is used to find conflicts. |
||||
In case the database is not recent, run 'updatedb'. |
||||
|
||||
Usage: $myname [-o] [--nocolor] |
||||
|
||||
General Options: |
||||
-o/--output print files instead of merging them |
||||
--nocolor remove colors from output |
||||
|
||||
Environment Variables: |
||||
DIFFPROG override the merge program: (default: 'vim -d') |
||||
|
||||
Example: DIFFPROG=meld $myname |
||||
Example: $myname --output |
||||
|
||||
EOF |
||||
} |
||||
|
||||
version() { |
||||
printf "%s %s\n" "$myname" "$myver" |
||||
echo 'Copyright (C) 2017 Dominik Schrempf <dominik.schrempf@gmail.com>' |
||||
echo 'Inspired by "pacdiff".' |
||||
} |
||||
|
||||
cmd() { |
||||
locate -0 -e -b sync-conflict |
||||
} |
||||
|
||||
while [[ -n "$1" ]]; do |
||||
case "$1" in |
||||
-o|--output) |
||||
OUTPUTONLY=1;; |
||||
--nocolor) |
||||
USE_COLOR='n';; |
||||
-v|-V|--version) |
||||
version; exit 0;; |
||||
-h|--help) |
||||
usage; exit 0;; |
||||
*) |
||||
usage; exit 1;; |
||||
esac |
||||
shift |
||||
done |
||||
|
||||
# Check if messages are to be printed using color. |
||||
unset ALL_OFF BOLD BLUE GREEN RED YELLOW |
||||
if [[ -t 2 && $USE_COLOR = "y" ]]; then |
||||
# Prefer terminal safe colored and bold text when tput is supported. |
||||
if tput setaf 0 &>/dev/null; then |
||||
ALL_OFF="$(tput sgr0)" |
||||
BLUE="$(tput setaf 27)" |
||||
GREEN="$(tput setaf 2)" |
||||
RED="$(tput setaf 1)" |
||||
YELLOW="$(tput setaf 3)" |
||||
else |
||||
ALL_OFF="\e[1;0m" |
||||
BLUE="\e[1;34m" |
||||
GREEN="\e[1;32m" |
||||
RED="\e[1;31m" |
||||
YELLOW="\e[1;33m" |
||||
fi |
||||
fi |
||||
readonly ALL_OFF BOLD BLUE GREEN RED YELLOW |
||||
|
||||
if ! type -p ${diffprog%% *} >/dev/null && (( ! OUTPUTONLY )); then |
||||
error "Cannot find the $diffprog binary required for viewing differences." |
||||
exit 1 |
||||
fi |
||||
|
||||
warning "Recursive sync conflicts are not properly handled." |
||||
|
||||
# See http://mywiki.wooledge.org/BashFAQ/020. |
||||
while IFS= read -u 3 -r -d '' conflict; do |
||||
if (( OUTPUTONLY )); then |
||||
echo "$conflict" |
||||
continue |
||||
fi |
||||
|
||||
# Ignore backups in '.stversions' folders. |
||||
if [[ "$conflict" = */.stversions/* ]] |
||||
then |
||||
ignored+=("$conflict") |
||||
continue |
||||
fi |
||||
|
||||
# XXX: Maybe somebody wants to diff special non-text files? |
||||
|
||||
# Ignore binary files. |
||||
if [[ -z $(file -i "$conflict" | grep text) ]] |
||||
then |
||||
nontext+=("$conflict") |
||||
continue |
||||
fi |
||||
|
||||
# XXX: Recursive sync conflicts lead to problems if they are |
||||
# treated in the wrong order. |
||||
|
||||
# TODO: Improve pattern match (digits only). |
||||
|
||||
# Original filename. |
||||
file="${conflict/.sync-conflict-????????-??????/}" |
||||
|
||||
msg "Sync conflict found: %s" "$conflict" |
||||
# Handle sync conflict if original file exists. |
||||
if [ ! -f "$file" ] |
||||
then |
||||
warning "Original file does not exist for conflict %s." "$conflict" |
||||
ignored+=("$conflict") |
||||
continue |
||||
fi |
||||
msg2 "Original file: %s" "$file" |
||||
|
||||
if cmp -s "$conflict" "$file"; then |
||||
msg2 "Files are identical, removing..." |
||||
plain "$(rm -v "$conflict")" |
||||
else |
||||
ask "(V)iew, (S)kip, (R)emove sync conflict, (O)verwrite with sync conflict, (Q)uit: [v/s/r/o/q] " |
||||
while read c; do |
||||
case $c in |
||||
q|Q) exit 0;; |
||||
r|R) plain "$(rm -v "$conflict")"; break ;; |
||||
o|O) plain "$(mv -v "$conflict" "$file")"; break ;; |
||||
v|V) |
||||
$diffprog "$conflict" "$file" |
||||
ask "(V)iew, (S)kip, (R)emove sync conflict, (O)verwrite with sync conflict, (Q)uit: [v/s/r/o/q] " |
||||
continue ;; |
||||
s|S) break ;; |
||||
*) ask "Invalid answer. Try again: [v/s/r/o/q] "; continue ;; |
||||
esac |
||||
done |
||||
fi |
||||
done 3< <(cmd) |
||||
|
||||
# Print warning if files have been ignored and delete them if |
||||
# specified. |
||||
if [ ! ${#ignored[@]} -eq 0 ] |
||||
then |
||||
warning "Some files have been ignored." |
||||
(( ${#ignored[@]} )) && msg "%s" "${ignored[@]}" |
||||
ask "(R)emove ignored files, (Q)uit: [r/q] " |
||||
while read c; do |
||||
case $c in |
||||
q|Q) exit 0 ;; |
||||
r|R) (( ${#ignored[@]} )) && plain "$(rm -v "${ignored[@]}")"; break ;; |
||||
*) ask "Invalid answer. Try again: [d/q] "; continue ;; |
||||
esac |
||||
done |
||||
fi |
||||
|
||||
# Print warning if non-text sync conflicts have been detected and |
||||
# delete them one by one if specified. |
||||
if [ ! ${#nontext[@]} -eq 0 ] |
||||
then |
||||
warning "Some files that are not text have been ignored." |
||||
for f in "${nontext[@]}" |
||||
do |
||||
msg "%s" "$f" |
||||
ask "(R)emove, (S)kip, (Q)uit: [r/s/q] " |
||||
while read c; do |
||||
case $c in |
||||
q|Q) exit 0 ;; |
||||
s|S) break ;; |
||||
r|R) plain "$(rm -v "$f")"; break ;; |
||||
*) ask "Invalid answer. Try again: [r/s/q] "; continue ;; |
||||
esac |
||||
done |
||||
done |
||||
fi |
||||
|
||||
exit 0 |
||||
Loading…
Reference in new issue