|
|
|
@ -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'. |
|
|
|
@ -13,36 +13,55 @@ declare -a nontext |
|
|
|
|
|
|
|
|
|
|
|
plain() { |
|
|
|
plain() { |
|
|
|
(( QUIET )) && return |
|
|
|
(( QUIET )) && return |
|
|
|
local mesg=$1; shift |
|
|
|
local mesg |
|
|
|
|
|
|
|
mesg="$1"; shift |
|
|
|
printf " ${mesg}${ALL_OFF}\n" "$@" >&1 |
|
|
|
printf " ${mesg}${ALL_OFF}\n" "$@" >&1 |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
msg() { |
|
|
|
msg() { |
|
|
|
(( QUIET )) && return |
|
|
|
(( QUIET )) && return |
|
|
|
local mesg=$1; shift |
|
|
|
local mesg |
|
|
|
|
|
|
|
mesg="$1"; shift |
|
|
|
|
|
|
|
# shellcheck disable=SC2059 |
|
|
|
printf "${GREEN}==>${ALL_OFF} ${mesg}${ALL_OFF}\n" "$@" >&1 |
|
|
|
printf "${GREEN}==>${ALL_OFF} ${mesg}${ALL_OFF}\n" "$@" >&1 |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
msg2() { |
|
|
|
msg2() { |
|
|
|
(( QUIET )) && return |
|
|
|
(( QUIET )) && return |
|
|
|
local mesg=$1; shift |
|
|
|
local mesg |
|
|
|
|
|
|
|
mesg="$1"; shift |
|
|
|
|
|
|
|
# shellcheck disable=SC2059 |
|
|
|
printf "${BLUE} ->${ALL_OFF} ${mesg}${ALL_OFF}\n" "$@" >&1 |
|
|
|
printf "${BLUE} ->${ALL_OFF} ${mesg}${ALL_OFF}\n" "$@" >&1 |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ask() { |
|
|
|
ask() { |
|
|
|
local mesg=$1; shift |
|
|
|
local mesg |
|
|
|
|
|
|
|
mesg="$1"; shift |
|
|
|
|
|
|
|
# shellcheck disable=SC2059 |
|
|
|
printf " ${BLUE}::${ALL_OFF} ${mesg}${ALL_OFF}" "$@" >&1 |
|
|
|
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() { |
|
|
|
@ -76,7 +95,10 @@ version() { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
|
@ -115,7 +137,7 @@ if [[ -t 2 && $USE_COLOR = "y" ]]; then |
|
|
|
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 |
|
|
|
@ -124,6 +146,7 @@ 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 |
|
|
|
|
|
|
|
[[ ! -e "$conflict" && ! -L "$conflict" && ! -d "$conflict" ]] && continue |
|
|
|
if (( OUTPUTONLY )); then |
|
|
|
if (( OUTPUTONLY )); then |
|
|
|
echo "$conflict" |
|
|
|
echo "$conflict" |
|
|
|
continue |
|
|
|
continue |
|
|
|
@ -139,7 +162,7 @@ while IFS= read -u 3 -r -d '' conflict; do |
|
|
|
# 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 |
|
|
|
@ -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,11 +185,15 @@ 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 |
|
|
|
|
|
|
|
warning "Original file and conflict file point to the same file. Ignoring conflict." |
|
|
|
|
|
|
|
continue |
|
|
|
|
|
|
|
elif cmp -s "$conflict" "$file"; then |
|
|
|
msg2 "Files are identical, removing..." |
|
|
|
msg2 "Files are identical, removing..." |
|
|
|
plain "$(rm -v "$conflict")" |
|
|
|
plain "$(rm -v "$conflict")" |
|
|
|
else |
|
|
|
else |
|
|
|
ask "(V)iew, (S)kip, (R)emove sync conflict, (O)verwrite with sync conflict, (Q)uit: [v/s/r/o/q] " |
|
|
|
ask "(V)iew, (S)kip, (R)emove sync conflict, (O)verwrite with sync conflict, (Q)uit: [v/s/r/o/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;; |
|
|
|
@ -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 ;; |
|
|
|
|
|
|
|
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 ;; |
|
|
|
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 ;; |
|
|
|
|