summaryrefslogtreecommitdiff
path: root/src/diffpkg.in
diff options
context:
space:
mode:
Diffstat (limited to 'src/diffpkg.in')
-rw-r--r--src/diffpkg.in228
1 files changed, 228 insertions, 0 deletions
diff --git a/src/diffpkg.in b/src/diffpkg.in
new file mode 100644
index 0000000..963f2c6
--- /dev/null
+++ b/src/diffpkg.in
@@ -0,0 +1,228 @@
+#!/bin/bash
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+shopt -s extglob
+
+m4_include(lib/common.sh)
+
+usage() {
+ cat <<- _EOF_
+ Usage: ${BASH_SOURCE[0]##*/} [OPTIONS] [MODES] [FILE|PKGNAME...]
+
+ Searches for a locally built package corresponding to the PKGBUILD, and
+ downloads the last version of that package from the Pacman repositories.
+ It then compares the package archives using different modes while using
+ simple tar content list by default.
+
+ When given one package, use it to diff against the locally built one.
+ When given two packages, diff both packages against each other.
+
+ In either case, a package name will be converted to a filename from the
+ cache, and diffpkg will proceed as though this filename was initially
+ specified.
+
+ OPTIONS
+ -M, --makepkg-config Set an alternate makepkg configuration file
+ -v, --verbose Provide more detailed/unfiltered output
+ -h, --help Show this help text
+
+ MODES
+ -l, --list Activate content list diff mode (default)
+ -d, --diffoscope Activate diffoscope diff mode
+ -p, --pkginfo Activate .PKGINFO diff mode
+ -b, --buildinfo Activate .BUILDINFO diff mode
+_EOF_
+}
+
+MAKEPKG_CONF=/etc/makepkg.conf
+VERBOSE=0
+TARLIST=0
+DIFFOSCOPE=0
+PKGINFO=0
+BUILDINFO=0
+
+# option checking
+while (( $# )); do
+ case $1 in
+ -h|--help)
+ usage
+ exit 0
+ ;;
+ -M|--makepkg-config)
+ MAKEPKG_CONF="$2"
+ shift 2
+ ;;
+ -l|--list)
+ TARLIST=1
+ shift
+ ;;
+ -d|--diffoscope)
+ DIFFOSCOPE=1
+ shift
+ ;;
+ -p|--pkginfo)
+ PKGINFO=1
+ shift
+ ;;
+ -b|--buildinfo)
+ BUILDINFO=1
+ shift
+ ;;
+ -v|--verbose)
+ VERBOSE=1
+ shift
+ ;;
+ --)
+ shift
+ break
+ ;;
+ -*,--*)
+ die "invalid argument: %s" "$1"
+ ;;
+ *)
+ break
+ ;;
+ esac
+done
+
+if ! (( DIFFOSCOPE || TARLIST || PKGINFO || BUILDINFO )); then
+ TARLIST=1
+fi
+
+# Source makepkg.conf; fail if it is not found
+if [[ -r "${MAKEPKG_CONF}" ]]; then
+ # shellcheck source=config/makepkg/x86_64.conf
+ source "${MAKEPKG_CONF}"
+else
+ die "${MAKEPKG_CONF} not found!"
+fi
+
+# Source user-specific makepkg.conf overrides
+if [[ -r "${XDG_CONFIG_HOME:-$HOME/.config}/pacman/makepkg.conf" ]]; then
+ # shellcheck source=/dev/null
+ source "${XDG_CONFIG_HOME:-$HOME/.config}/pacman/makepkg.conf"
+elif [[ -r "$HOME/.makepkg.conf" ]]; then
+ # shellcheck source=/dev/null
+ source "$HOME/.makepkg.conf"
+fi
+
+STARTDIR=$(pwd)
+trap 'rm -rf $TMPDIR' EXIT INT TERM QUIT
+TMPDIR=$(mktemp -d --tmpdir diffpkg-script.XXXXXXXX)
+export TMPDIR
+
+tar_list() {
+ bsdtar tf "$*" | if (( VERBOSE )); then
+ cat
+ else
+ sed -E 's|^usr/lib/modules/[0-9][^/]+|usr/lib/modules/[…]|g'
+ fi | sort
+}
+
+diff_pkgs() {
+ local oldpkg newpkg
+ oldpkg=$(readlink -m "$1")
+ newpkg=$(readlink -m "$2")
+
+ [[ -f $oldpkg ]] || die "No such file: %s" "${oldpkg}"
+ [[ -f $newpkg ]] || die "No such file: %s" "${newpkg}"
+
+ if (( TARLIST )); then
+ tar_list "$oldpkg" > "$TMPDIR/filelist-old"
+ tar_list "$newpkg" > "$TMPDIR/filelist"
+
+ sdiff -s "$TMPDIR/filelist-old" "$TMPDIR/filelist"
+ fi
+
+ if (( PKGINFO )); then
+ bsdtar xOqf "$oldpkg" .PKGINFO > "$TMPDIR/pkginfo-old"
+ bsdtar xOqf "$newpkg" .PKGINFO > "$TMPDIR/pkginfo"
+
+ sdiff -s "$TMPDIR/pkginfo-old" "$TMPDIR/pkginfo"
+ fi
+
+ if (( BUILDINFO )); then
+ bsdtar xOqf "$oldpkg" .BUILDINFO > "$TMPDIR/buildinfo-old"
+ bsdtar xOqf "$newpkg" .BUILDINFO > "$TMPDIR/buildinfo"
+
+ sdiff -s "$TMPDIR/buildinfo-old" "$TMPDIR/buildinfo"
+ fi
+
+ if (( DIFFOSCOPE )); then
+ diffoscope "$oldpkg" "$newpkg"
+ fi
+}
+
+fetch_pkg() {
+ local pkg pkgdest pkgurl
+ case $1 in
+ *://*)
+ pkgurl=$1 ;;
+ /*|*/*)
+ pkgurl=$(readlink -m "$1") ;;
+ *.pkg.tar*)
+ pkgurl=$1 ;;
+ '')
+ ;;
+ *)
+ pkg=$1 ;;
+ esac
+
+ [[ -n $pkgurl ]] || pkgurl=$(pacman -Spdd --print-format '%l' --noconfirm "$pkg") ||
+ die "Couldn't download previous package for %s." "$pkg"
+
+ pkg=${pkgurl##*/}
+ pkgdest=$(mktemp -t -d "${pkg}-XXXXXX")/${pkg}
+
+ if [[ $pkgurl = file://* || ( $pkgurl = /* && -f $pkgurl ) ]]; then
+ ln -sf "${pkgurl#file://}" "$pkgdest"
+ elif [[ -f "$PKGDEST/$pkg" ]]; then
+ ln -sf "$PKGDEST/$pkg" "$pkgdest"
+ elif [[ -f "$STARTDIR/$pkg" ]]; then
+ ln -sf "$STARTDIR/$pkg" "$pkgdest"
+ elif [[ $pkgurl = *://* ]]; then
+ curl -fsLC - --retry 3 --retry-delay 3 -o "$pkgdest" "$pkgurl" || \
+ die "Couldn't download %s" "$pkgurl"
+ else
+ die "File not found: %s" "$pkgurl"
+ fi
+
+ echo "$pkgdest"
+}
+
+if (( $# < 2 )); then
+ if [[ ! -f PKGBUILD ]]; then
+ die "This must be run in the directory of a built package.\nTry '$(basename "$0") --help' for more information."
+ fi
+
+ # shellcheck source=PKGBUILD.proto
+ . ./PKGBUILD
+ if [[ ${arch[0]} == 'any' ]]; then
+ CARCH='any'
+ fi
+
+ for _pkgname in "${pkgname[@]}"; do
+ comparepkg=$_pkgname
+ pkgurl=
+ target_pkgver=$(get_full_version "$_pkgname")
+ if ! pkgfile=$(find_cached_package "$_pkgname" "$target_pkgver" "$CARCH"); then
+ die 'tarball not found for package: %s' "${_pkgname}-$target_pkgver"
+ fi
+
+ ln -s "$pkgfile" "$TMPDIR"
+
+ if (( $# )); then
+ comparepkg="$1"
+ fi
+
+ oldpkg=$(fetch_pkg "$comparepkg") || exit 1
+
+ diff_pkgs "$oldpkg" "$pkgfile"
+ done
+else
+ file1=$(fetch_pkg "$1") || exit 1
+ file2=$(fetch_pkg "$2") || exit 1
+
+ diff_pkgs "$file1" "$file2"
+fi