mirror of
https://github.com/Gator96100/ProxSpace.git
synced 2025-01-08 20:03:14 -08:00
358 lines
8.5 KiB
Bash
358 lines
8.5 KiB
Bash
#!/usr/bin/bash
|
|
# pacdiff : a simple pacnew/pacsave updater
|
|
#
|
|
# Copyright (c) 2007 Aaron Griffin <aaronmgriffin@gmail.com>
|
|
# Copyright (c) 2013-2016 Pacman Development Team <pacman-dev@archlinux.org>
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
|
|
shopt -s extglob
|
|
|
|
declare -r myname='pacdiff'
|
|
declare -r myver='1.9.1'
|
|
|
|
LIBRARY=${LIBRARY:-'/usr/share/makepkg'}
|
|
|
|
diffprog=${DIFFPROG:-'vim -d'}
|
|
diffsearchpath=${DIFFSEARCHPATH:-/etc}
|
|
mergeprog=${MERGEPROG:-'diff3 -m'}
|
|
cachedirs=()
|
|
USE_COLOR='y'
|
|
SUDO=''
|
|
declare -a oldsaves
|
|
declare -i USE_FIND=0 USE_LOCATE=0 USE_PACDB=0 OUTPUTONLY=0 BACKUP=0 THREE_WAY_DIFF=0
|
|
|
|
# Import libmakepkg
|
|
source "$LIBRARY"/util/message.sh
|
|
|
|
die() {
|
|
error "$@"
|
|
exit 1
|
|
}
|
|
|
|
usage() {
|
|
cat <<EOF
|
|
${myname} v${myver}
|
|
|
|
pacorig, pacnew and pacsave maintenance utility.
|
|
|
|
Usage: $myname [options]
|
|
|
|
Search Options: select one (default: --pacmandb)
|
|
-f, --find scan using find
|
|
-l, --locate scan using locate
|
|
-p, --pacmandb scan active config files from pacman database
|
|
|
|
General Options:
|
|
-b, --backup when overwriting, save old files with .bak
|
|
-c, --cachedir <dir> scan "dir" for 3-way merge base candidates
|
|
(default: read from /etc/pacman.conf)
|
|
--nocolor do not colorize output
|
|
-o, --output print files instead of merging them
|
|
-s, --sudo use sudo and sudoedit to merge/remove files
|
|
-3, --threeway view diffs in 3-way fashion
|
|
-h, --help show this help message and exit
|
|
-V, --version display version information and exit
|
|
|
|
Environment Variables:
|
|
DIFFPROG override the merge program (default: 'vim -d')
|
|
DIFFSEARCHPATH override the search path (only when using find)
|
|
(default: /etc)
|
|
MERGEPROG override the 3-way merge program (default: 'diff3 -m')
|
|
|
|
Example: DIFFPROG=meld DIFFSEARCHPATH="/boot /etc /usr" MERGEPROG="git merge-file -p" $myname
|
|
Example: $myname --output --locate
|
|
EOF
|
|
}
|
|
|
|
version() {
|
|
printf "%s %s\n" "$myname" "$myver"
|
|
echo 'Copyright (C) 2007 Aaron Griffin <aaronmgriffin@gmail.com>'
|
|
echo 'Copyright (C) 2013-2016 Pacman Development Team <pacman-dev@archlinux.org>'
|
|
}
|
|
|
|
print_existing() {
|
|
[[ -f "$1" ]] && printf '%s\0' "$1"
|
|
}
|
|
|
|
print_existing_pacsave(){
|
|
for f in "${1}"?(.+([0-9])); do
|
|
[[ -f $f ]] && printf '%s\0' "$f"
|
|
done
|
|
}
|
|
|
|
base_cache_tar() {
|
|
package="$1"
|
|
|
|
for cachedir in "${cachedirs[@]}"; do
|
|
pushd "$cachedir" &>/dev/null || {
|
|
error "failed to chdir to '%s', skipping" "$cachedir"
|
|
continue
|
|
}
|
|
|
|
find "$PWD" -name "$package-[0-9]*.pkg.tar*" ! -name '*.sig' |
|
|
pacsort --files --reverse | sed -ne '2p'
|
|
|
|
popd &>/dev/null
|
|
done
|
|
}
|
|
|
|
diffprog_fn() {
|
|
if [[ -n "$SUDO" ]]; then
|
|
SUDO_EDITOR="$diffprog" sudoedit "$@"
|
|
else
|
|
$diffprog "$@"
|
|
fi
|
|
}
|
|
|
|
view_diff() {
|
|
pacfile="$1"
|
|
file="$2"
|
|
|
|
package="$(pacman -Qoq "$file")" || return 1
|
|
base_tar="$(base_cache_tar "$package")"
|
|
|
|
two_way_diff() {
|
|
diffprog_fn "$pacfile" "$file"
|
|
}
|
|
|
|
three_way_diff() {
|
|
diffprog_fn "$pacfile" "$base" "$file"
|
|
}
|
|
|
|
unset tempdir
|
|
|
|
if (( ! THREE_WAY_DIFF )); then
|
|
two_way_diff
|
|
elif [[ -z $base_tar ]]; then
|
|
msg2 "Unable to find a base package. falling back to 2-way diff."
|
|
two_way_diff
|
|
else
|
|
basename="$(basename "$file")"
|
|
tempdir="$(mktemp -d --tmpdir "pacdiff-diff-$basename.XXX")"
|
|
base="$(mktemp "$tempdir"/"$basename.base.XXX")"
|
|
merged="$(mktemp "$tempdir"/"$basename.merged.XXX")"
|
|
|
|
if ! bsdtar -xqOf "$base_tar" "${file#/}" >"$base"; then
|
|
msg2 "Unable to extract the previous version of this file. falling back to 2-way diff."
|
|
two_way_diff
|
|
else
|
|
three_way_diff
|
|
fi
|
|
fi
|
|
|
|
ret=1
|
|
|
|
if cmp -s "$pacfile" "$file"; then
|
|
msg2 "Files are identical, removing..."
|
|
$SUDO rm -v "$pacfile"
|
|
ret=0
|
|
fi
|
|
|
|
$SUDO rm -rf "$tempdir"
|
|
return $ret
|
|
}
|
|
|
|
merge_file() {
|
|
pacfile="$1"
|
|
file="$2"
|
|
|
|
package="$(pacman -Qoq "$file")" || return 1
|
|
base_tar="$(base_cache_tar "$package")"
|
|
|
|
if [[ -z $base_tar ]]; then
|
|
msg2 "Unable to find a base package."
|
|
return 1
|
|
fi
|
|
|
|
basename="$(basename "$file")"
|
|
tempdir="$(mktemp -d --tmpdir "pacdiff-merge-$basename.XXX")"
|
|
base="$(mktemp "$tempdir"/"$basename.base.XXX")"
|
|
merged="$(mktemp "$tempdir"/"$basename.merged.XXX")"
|
|
|
|
if ! /usr/bin/bsdtar -xqOf "$base_tar" "${file#/}" >"$base"; then
|
|
msg2 "Unable to extract the previous version of this file."
|
|
return 1
|
|
fi
|
|
|
|
if $mergeprog "$file" "$base" "$pacfile" >"$merged"; then
|
|
msg2 "Merged without conflicts."
|
|
fi
|
|
|
|
$diffprog "$file" "$merged"
|
|
|
|
while :; do
|
|
ask "Would you like to use the results of the merge? [y/n] "
|
|
|
|
read c || return 1
|
|
case $c in
|
|
y|Y) break ;;
|
|
n|N) return 1 ;;
|
|
*) msg2 "Invalid answer." ;;
|
|
esac
|
|
done
|
|
|
|
if ! $SUDO cp -v "$merged" "$file"; then
|
|
warning "Unable to write merged file to %s. Merged file is preserved at %s" "$file" "$merged"
|
|
return 1
|
|
fi
|
|
$SUDO rm -rv "$pacfile" "$tempdir"
|
|
return 0
|
|
}
|
|
|
|
cmd() {
|
|
if (( USE_LOCATE )); then
|
|
locate -0 -e -b \*.pacnew \*.pacorig \*.pacsave '*.pacsave.[0-9]*'
|
|
elif (( USE_FIND )); then
|
|
find $diffsearchpath \( -name \*.pacnew -o -name \*.pacorig -o -name \*.pacsave -o -name '*.pacsave.[0-9]*' \) -print0
|
|
elif (( USE_PACDB )); then
|
|
awk '/^%BACKUP%$/ {
|
|
while (getline) {
|
|
if (/^$/) { nextfile }
|
|
print $1
|
|
}
|
|
}' "${pac_db}"/*/files | while read -r bkup; do
|
|
print_existing "/$bkup.pacnew"
|
|
print_existing "/$bkup.pacorig"
|
|
print_existing_pacsave "/$bkup.pacsave"
|
|
done
|
|
fi
|
|
}
|
|
|
|
while [[ -n "$1" ]]; do
|
|
case "$1" in
|
|
-f|--find)
|
|
USE_FIND=1;;
|
|
-l|--locate)
|
|
USE_LOCATE=1;;
|
|
-p|--pacmandb)
|
|
USE_PACDB=1;;
|
|
-b|--backup)
|
|
BACKUP=1;;
|
|
-c|--cachedir)
|
|
cachedirs+=("$2"); shift;;
|
|
--nocolor)
|
|
USE_COLOR='n';;
|
|
-o|--output)
|
|
OUTPUTONLY=1;;
|
|
-s|--sudo)
|
|
SUDO=sudo;;
|
|
-3|--threeway)
|
|
THREE_WAY_DIFF=1 ;;
|
|
-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
|
|
if [[ -t 2 && $USE_COLOR != "n" ]]; then
|
|
colorize
|
|
else
|
|
unset ALL_OFF BOLD BLUE GREEN RED YELLOW
|
|
fi
|
|
|
|
if ! type -p ${diffprog%% *} >/dev/null && (( ! OUTPUTONLY )); then
|
|
die "Cannot find the $diffprog binary required for viewing differences."
|
|
fi
|
|
|
|
if ! type -p ${mergeprog%% *} >/dev/null && (( ! OUTPUTONLY )); then
|
|
die "Cannot find the $mergeprog binary required for merging differences."
|
|
fi
|
|
|
|
case $(( USE_FIND + USE_LOCATE + USE_PACDB )) in
|
|
0) USE_PACDB=1;; # set the default search option
|
|
[^1]) error "Only one search option may be used at a time"
|
|
usage; exit 1;;
|
|
esac
|
|
|
|
if (( USE_PACDB )); then
|
|
if ! DBPath="$(pacman-conf DBPath)"; then
|
|
error "unable to read /etc/pacman.conf"
|
|
usage; exit 1
|
|
fi
|
|
pac_db="${DBPath:-/var/lib/pacman}/local"
|
|
if [[ ! -d "${pac_db}" ]]; then
|
|
error "unable to read pacman database %s". "${pac_db}"
|
|
usage; exit 1
|
|
fi
|
|
fi
|
|
|
|
if [[ -z ${cachedirs[*]} ]]; then
|
|
readarray -t cachedirs < <(pacman-conf CacheDir)
|
|
fi
|
|
|
|
# see http://mywiki.wooledge.org/BashFAQ/020
|
|
while IFS= read -u 3 -r -d '' pacfile; do
|
|
file="${pacfile%.pac*}"
|
|
file_type="pac${pacfile##*.pac}"
|
|
|
|
if (( OUTPUTONLY )); then
|
|
echo "$pacfile"
|
|
continue
|
|
fi
|
|
|
|
# add matches for pacsave.N to oldsaves array, do not prompt
|
|
if [[ $file_type = pacsave.+([0-9]) ]]; then
|
|
oldsaves+=("$pacfile")
|
|
continue
|
|
fi
|
|
|
|
msg "%s file found for %s" "$file_type" "$file"
|
|
if [ ! -f "$file" ]; then
|
|
warning "$file does not exist"
|
|
$SUDO rm -iv "$pacfile"
|
|
continue
|
|
fi
|
|
|
|
if cmp -s "$pacfile" "$file"; then
|
|
msg2 "Files are identical, removing..."
|
|
$SUDO rm -v "$pacfile"
|
|
else
|
|
while :; do
|
|
ask "(V)iew, (M)erge, (S)kip, (R)emove %s, (O)verwrite with %s, (Q)uit: [v/m/s/r/o/q] " "$file_type" "$file_type"
|
|
read c || break
|
|
case $c in
|
|
q|Q) exit 0;;
|
|
r|R) $SUDO rm -v "$pacfile"; break ;;
|
|
o|O)
|
|
if (( BACKUP )); then
|
|
$SUDO cp -v "$file" "$file.bak"
|
|
fi
|
|
$SUDO mv -v "$pacfile" "$file"
|
|
break ;;
|
|
v|V)
|
|
if view_diff "$pacfile" "$file"; then
|
|
break
|
|
fi ;;
|
|
m|M)
|
|
if merge_file "$pacfile" "$file"; then
|
|
break
|
|
fi ;;
|
|
s|S) break ;;
|
|
*) msg2 "Invalid answer." ;;
|
|
esac
|
|
done
|
|
fi
|
|
done 3< <(cmd)
|
|
|
|
(( ${#oldsaves[@]} )) && warning "Ignoring %s" "${oldsaves[@]}"
|
|
|
|
exit 0
|