Merge pull request #1 from junkblocker/master

Added support for Darwin, some interaction improvement, and style lint
master
Dominik Schrempf 9 years ago committed by GitHub
commit 39b723a9b4
  1. 220
      syncthing-resolve-conflicts.sh

@ -1,4 +1,4 @@
#!/usr/bin/bash #!/usr/bin/env bash
# Check for sync conflicts and resolve them. Idea from the shell # Check for sync conflicts and resolve them. Idea from the shell
# script 'pacdiff'. # script 'pacdiff'.
@ -12,41 +12,60 @@ declare -a ignored
declare -a nontext declare -a nontext
plain() { plain() {
(( QUIET )) && return (( QUIET )) && return
local mesg=$1; shift local mesg
printf " ${mesg}${ALL_OFF}\n" "$@" >&1 mesg="$1"; shift
printf " ${mesg}${ALL_OFF}\n" "$@" >&1
} }
msg() { msg() {
(( QUIET )) && return (( QUIET )) && return
local mesg=$1; shift local mesg
printf "${GREEN}==>${ALL_OFF} ${mesg}${ALL_OFF}\n" "$@" >&1 mesg="$1"; shift
# shellcheck disable=SC2059
printf "${GREEN}==>${ALL_OFF} ${mesg}${ALL_OFF}\n" "$@" >&1
} }
msg2() { msg2() {
(( QUIET )) && return (( QUIET )) && return
local mesg=$1; shift local mesg
printf "${BLUE} ->${ALL_OFF} ${mesg}${ALL_OFF}\n" "$@" >&1 mesg="$1"; shift
# shellcheck disable=SC2059
printf "${BLUE} ->${ALL_OFF} ${mesg}${ALL_OFF}\n" "$@" >&1
} }
ask() { ask() {
local mesg=$1; shift local mesg
printf " ${BLUE}::${ALL_OFF} ${mesg}${ALL_OFF}" "$@" >&1 mesg="$1"; shift
# shellcheck disable=SC2059
printf " ${BLUE}::${ALL_OFF} ${mesg}${ALL_OFF}" "$@" >&1
} }
if [ -n "$(command -v gettext)" ]; then
translate() {
gettext "$@"
}
else
translate() {
printf %s "$@"
}
fi
warning() { warning() {
local mesg=$1; shift local mesg
echo mesg="$1"; shift
printf "${YELLOW}==> $(gettext "WARNING:")${ALL_OFF} ${mesg}${ALL_OFF}\n" "$@" >&2 # shellcheck disable=SC2059
printf "\n${YELLOW}==> $(translate "WARNING:")${ALL_OFF} ${mesg}${ALL_OFF}\n" "$@" >&2
} }
error() { error() {
local mesg=$1; shift local mesg
printf "${RED}==> $(gettext "ERROR:")${ALL_OFF} ${mesg}${ALL_OFF}\n" "$@" >&2 mesg="$1"; shift
# shellcheck disable=SC2059
printf "${RED}==> $(translate "ERROR:")${ALL_OFF} ${mesg}${ALL_OFF}\n" "$@" >&2
} }
usage() { usage() {
cat <<EOF cat <<EOF
${myname} v${myver} ${myname} v${myver}
Inspired by 'pacdiff'. Inspired by 'pacdiff'.
@ -70,81 +89,85 @@ EOF
} }
version() { version() {
printf "%s %s\n" "$myname" "$myver" printf "%s %s\n" "$myname" "$myver"
echo 'Copyright (C) 2017 Dominik Schrempf <dominik.schrempf@gmail.com>' echo 'Copyright (C) 2017 Dominik Schrempf <dominik.schrempf@gmail.com>'
echo 'Inspired by "pacdiff".' echo 'Inspired by "pacdiff".'
} }
cmd() { cmd() {
locate -0 -e -b sync-conflict case "$(uname -s)" in
Darwin) locate -0 sync-conflict;;
*) locate -0 -e -b sync-conflict ;;
esac
} }
while [[ -n "$1" ]]; do while [[ -n "$1" ]]; do
case "$1" in case "$1" in
-o|--output) -o|--output)
OUTPUTONLY=1;; OUTPUTONLY=1;;
--nocolor) --nocolor)
USE_COLOR='n';; USE_COLOR='n';;
-v|-V|--version) -v|-V|--version)
version; exit 0;; version; exit 0;;
-h|--help) -h|--help)
usage; exit 0;; usage; exit 0;;
*) *)
usage; exit 1;; usage; exit 1;;
esac esac
shift shift
done done
# Check if messages are to be printed using color. # Check if messages are to be printed using color.
unset ALL_OFF BOLD BLUE GREEN RED YELLOW unset ALL_OFF BOLD BLUE GREEN RED YELLOW
if [[ -t 2 && $USE_COLOR = "y" ]]; then if [[ -t 2 && $USE_COLOR = "y" ]]; then
# Prefer terminal safe colored and bold text when tput is supported. # Prefer terminal safe colored and bold text when tput is supported.
if tput setaf 0 &>/dev/null; then if tput setaf 0 &>/dev/null; then
ALL_OFF="$(tput sgr0)" ALL_OFF="$(tput sgr0)"
BLUE="$(tput setaf 27)" BLUE="$(tput setaf 27)"
GREEN="$(tput setaf 2)" GREEN="$(tput setaf 2)"
RED="$(tput setaf 1)" RED="$(tput setaf 1)"
YELLOW="$(tput setaf 3)" YELLOW="$(tput setaf 3)"
else else
ALL_OFF="\e[1;0m" ALL_OFF="\e[1;0m"
BLUE="\e[1;34m" BLUE="\e[1;34m"
GREEN="\e[1;32m" GREEN="\e[1;32m"
RED="\e[1;31m" RED="\e[1;31m"
YELLOW="\e[1;33m" YELLOW="\e[1;33m"
fi fi
fi fi
readonly ALL_OFF BOLD BLUE GREEN RED YELLOW readonly ALL_OFF BOLD BLUE GREEN RED YELLOW
if ! type -p ${diffprog%% *} >/dev/null && (( ! OUTPUTONLY )); then if [ -z "$(command -v "${diffprog%% *}")" ] && (( ! OUTPUTONLY )); then
error "Cannot find the $diffprog binary required for viewing differences." error "Cannot find the $diffprog binary required for viewing differences."
exit 1 exit 1
fi fi
warning "Recursive sync conflicts are not properly handled." warning "Recursive sync conflicts are not properly handled."
# See http://mywiki.wooledge.org/BashFAQ/020. # See http://mywiki.wooledge.org/BashFAQ/020.
while IFS= read -u 3 -r -d '' conflict; do while IFS= read -u 3 -r -d '' conflict; do
if (( OUTPUTONLY )); then [[ ! -e "$conflict" && ! -L "$conflict" && ! -d "$conflict" ]] && continue
echo "$conflict" if (( OUTPUTONLY )); then
continue echo "$conflict"
fi continue
fi
# Ignore backups in '.stversions' folders. # Ignore backups in '.stversions' folders.
if [[ "$conflict" = */.stversions/* ]] if [[ "$conflict" = */.stversions/* ]]
then then
ignored+=("$conflict") ignored+=("$conflict")
continue continue
fi fi
# XXX: Maybe somebody wants to diff special non-text files? # XXX: Maybe somebody wants to diff special non-text files?
# Ignore binary files. # Ignore binary files.
if [[ -z $(file -i "$conflict" | grep text) ]] if file -i "$conflict" | grep -qv text
then then
nontext+=("$conflict") nontext+=("$conflict")
continue continue
fi fi
# XXX: Recursive sync conflicts lead to problems if they are # XXX: Recursive sync conflicts lead to problems if they are
# treated in the wrong order. # treated in the wrong order.
@ -152,8 +175,7 @@ while IFS= read -u 3 -r -d '' conflict; do
# Original filename. # Original filename.
file="${conflict/.sync-conflict-????????-??????/}" file="${conflict/.sync-conflict-????????-??????/}"
msg "Sync conflict: %s" "$conflict"
msg "Sync conflict found: %s" "$conflict"
# Handle sync conflict if original file exists. # Handle sync conflict if original file exists.
if [ ! -f "$file" ] if [ ! -f "$file" ]
then then
@ -163,25 +185,29 @@ while IFS= read -u 3 -r -d '' conflict; do
fi fi
msg2 "Original file: %s" "$file" msg2 "Original file: %s" "$file"
if cmp -s "$conflict" "$file"; then if test "$conflict" -ef "$file"; then
msg2 "Files are identical, removing..." warning "Original file and conflict file point to the same file. Ignoring conflict."
plain "$(rm -v "$conflict")" continue
else elif cmp -s "$conflict" "$file"; then
ask "(V)iew, (S)kip, (R)emove sync conflict, (O)verwrite with sync conflict, (Q)uit: [v/s/r/o/q] " msg2 "Files are identical, removing..."
while read c; do plain "$(rm -v "$conflict")"
case $c in else
q|Q) exit 0;; ask "(V)iew, (S)kip, (R)emove sync conflict, (O)verwrite with sync conflict, (Q)uit: [v/s/r/o/q] "
r|R) plain "$(rm -v "$conflict")"; break ;; # shellcheck disable=SC2162
o|O) plain "$(mv -v "$conflict" "$file")"; break ;; while read c; do
v|V) case $c in
$diffprog "$conflict" "$file" q|Q) exit 0;;
ask "(V)iew, (S)kip, (R)emove sync conflict, (O)verwrite with sync conflict, (Q)uit: [v/s/r/o/q] " r|R) plain "$(rm -v "$conflict")"; break ;;
continue ;; o|O) plain "$(mv -v "$conflict" "$file")"; break ;;
s|S) break ;; v|V)
*) ask "Invalid answer. Try again: [v/s/r/o/q] "; continue ;; $diffprog "$conflict" "$file"
esac ask "(V)iew, (S)kip, (R)emove sync conflict, (O)verwrite with sync conflict, (Q)uit: [v/s/r/o/q] "
done continue ;;
fi s|S) break ;;
*) ask "Invalid answer. Try again: [v/s/r/o/q] "; continue ;;
esac
done
fi
done 3< <(cmd) done 3< <(cmd)
# Print warning if files have been ignored and delete them if # Print warning if files have been ignored and delete them if
@ -190,10 +216,27 @@ if [ ! ${#ignored[@]} -eq 0 ]
then then
warning "Some files have been ignored." warning "Some files have been ignored."
(( ${#ignored[@]} )) && msg "%s" "${ignored[@]}" (( ${#ignored[@]} )) && msg "%s" "${ignored[@]}"
ask "(R)emove ignored files, (Q)uit: [r/q] " ask "(R)emove all ignored files, (A)sk for each file, (Q)uit: [r/q] "
# shellcheck disable=SC2162
while read c; do while read c; do
case $c in case "$c" in
q|Q) exit 0 ;; q|Q) exit 0 ;;
a|A)
for f in "${ignored[@]}"
do
msg "Ignored file: %s" "$f"
ask "(R)emove, (S)kip, (Q)uit: [r/s/q] "
# shellcheck disable=SC2162
while read ci; do
case "$ci" 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
;;
r|R) (( ${#ignored[@]} )) && plain "$(rm -v "${ignored[@]}")"; break ;; r|R) (( ${#ignored[@]} )) && plain "$(rm -v "${ignored[@]}")"; break ;;
*) ask "Invalid answer. Try again: [d/q] "; continue ;; *) ask "Invalid answer. Try again: [d/q] "; continue ;;
esac esac
@ -204,13 +247,14 @@ fi
# delete them one by one if specified. # delete them one by one if specified.
if [ ! ${#nontext[@]} -eq 0 ] if [ ! ${#nontext[@]} -eq 0 ]
then then
warning "Some files that are not text have been ignored." warning "The following files that are non-text:"
for f in "${nontext[@]}" for f in "${nontext[@]}"
do do
msg "%s" "$f" msg "Non-text file: %s" "$f"
ask "(R)emove, (S)kip, (Q)uit: [r/s/q] " ask "(R)emove, (S)kip, (Q)uit: [r/s/q] "
# shellcheck disable=SC2162
while read c; do while read c; do
case $c in case "$c" in
q|Q) exit 0 ;; q|Q) exit 0 ;;
s|S) break ;; s|S) break ;;
r|R) plain "$(rm -v "$f")"; break ;; r|R) plain "$(rm -v "$f")"; break ;;

Loading…
Cancel
Save