abuild/checkapk.in
Dominique Martinet d9f3f05b50 checkapk: fix size difference output when multiple info matches
I rebuilt networkmanager locally and was greeted with this:
>>> Size difference for networkmanager: 16 MiB -> 2772 KiB

It turns out networkmanager-elogind provides networkmanager so apk info
will list both, and the former is much bigger so it looked like the
rebuilt package was much smaller when there was almost no difference (as
expected)

Fix by matching on exact package name for both lines; this is already
what we were doing with the local package anyway and the apk fetch
correctly picks the correct package in this case
2024-10-07 20:07:31 +00:00

158 lines
4.5 KiB
Bash

#!/bin/sh
# checkapk - find ABI breakages in package upgrades
# Copyright (c) 2012 Natanael Copa <natanael.copa@gmail.com>
#
# Distributed under GPL-2.0-only
#
program_version=@VERSION@
sharedir=${ABUILD_SHAREDIR:-@sharedir@}
if ! [ -f "$sharedir/functions.sh" ]; then
echo "$sharedir/functions.sh: not found" >&2
exit 1
fi
. "$sharedir/functions.sh"
usage() {
cat <<-__EOF__
$program $program_version - find ABI breakages in package upgrades
Usage: $program [-h|--help]
Run in the directory of a built package.
Options:
-h, --help Print this help
__EOF__
}
args=$(getopt -o h --long help \
-n "$program" -- "$@")
if [ $? -ne 0 ]; then
usage >&2
exit 2
fi
eval set -- "$args"
while true; do
case $1 in
-h|--help) usage; exit 0;;
--) shift; break;;
*) exit 1;; # getopt error
esac
shift
done
if [ $# -gt 0 ]; then
usage >&2
exit 2
fi
if ! [ -f "$ABUILD_CONF" ] && ! [ -f "$ABUILD_USERCONF" ] && ! [ -f "$ABUILD_DEFCONF" ]; then
die "no abuild.conf found"
fi
if ! [ -f APKBUILD ]; then
die 'must be run in the directory of a built package'
fi
if ! [ -n "$CARCH" ]; then
die "failed to detect CARCH"
fi
. ./APKBUILD
startdir="$PWD"
tmpdir=$(mktemp -d -t checkpkg-script.XXXXXX)
trap "rm -rf '$tmpdir'; exit" INT EXIT
cd "$tmpdir" || die "failed to create temp dir"
# storage for downloaded/copied apks
mkdir -p apks
# default to pigz for unpacking
gunzip="$(command -v pigz || echo gzip) -d"
for i in $pkgname $subpackages; do
_pkgname=${i%%:*}
pkg=${_pkgname}-$pkgver-r$pkgrel
pkgfile=${pkg}.apk
repodir=${startdir%/*}
repo=${repodir##*/}
for filepath in "$PKGDEST"/$pkgfile "$REPODEST"/$repo/$CARCH/$pkgfile "$startdir"/$pkgfile; do
if [ -f "$filepath" ]; then
break
fi
done
[ -f "$filepath" ] || die "can't find $pkgfile"
# generate a temp repositories file with only the http(s) repos
grep -E "^https?:" /etc/apk/repositories > "$tmpdir"/repositories
oldpkg=$(apk fetch --repositories-file "$tmpdir"/repositories --simulate $_pkgname 2>&1 | sed 's/^Downloading //')
if [ "${oldpkg}" = "${pkg}" ]; then
die "the built package ($_pkgname) is already in the repo"
fi
# apk info could return multiple lines if multiple packages share a provide
# (e.g. dnsmasq); filter with the exact package name and take the second line:
# 7zip-23.01-r0 installed size:
# 1668 KiB
newsize="$(apk info --repositories-file /dev/null --repository "$REPODEST"/$repo --size $_pkgname | \
grep -F "$pkg" -A1 | \
tail -n1)"
oldsize="$(apk info --repositories-file "$tmpdir"/repositories --size "$_pkgname" | \
grep -F "$oldpkg" -A1 | \
tail -n1)"
if [ "$oldsize" = "$newsize" ]; then
msg "No size differences for $_pkgname."
else
msg "Size difference for $_pkgname: $oldsize -> $newsize"
fi
apk fetch --quiet --repositories-file "$tmpdir"/repositories --stdout "$_pkgname" > apks/old.apk \
|| msg2 "Old apk for $_pkgname missing. (new package/arch? broken internet?)"
# pre-uncompress to not decompress twice
# we do a decompression + tar -t for the file list, but then later we might do a full extraction for sodiff.
# to not decompress here and then later again, store the intermediate tar
$gunzip -c 2>/dev/null < apks/old.apk > apks/old.tar &
$gunzip -c "$filepath" < "$filepath" > apks/new.tar &
wait
tar -t -f apks/old.tar 2>/dev/null | grep -v '^\.SIGN\.' | sort > "filelist-$_pkgname-old" &
tar -t -f apks/new.tar | grep -v '^\.SIGN\.' | sort > "filelist-$_pkgname-new" &
wait
diff -U3 "filelist-$_pkgname-old" "filelist-$_pkgname-new"
if diff -U0 "filelist-$_pkgname-old" "filelist-$_pkgname-new" | grep -q '\.so'; then
echo "SODIFF:"
mkdir -p "$_pkgname-pkg-old" "$_pkgname-pkg-new"
tar -C "$_pkgname-pkg-old" 2>/dev/null -x -f apks/old.tar > /dev/null &
tar -C "$_pkgname-pkg-new" -x -f apks/new.tar > /dev/null &
wait
# filter to things that start with -+ but strip the header (---/+++)
diff -U0 "filelist-$_pkgname-old" "filelist-$_pkgname-new" | grep -E '^(\+|-)[A-Za-z0-9]+' | grep '\.so' | while read -r diff_sofile; do
case "$diff_sofile" in
-*) path="$_pkgname-pkg-old"; sofile="${diff_sofile#\-}" ;;
+*) path="$_pkgname-pkg-new"; sofile="${diff_sofile#\+}" ;;
esac
# skip symlinks (only adds duplicate output or is dangling), and things that aren't valid elfs
# matching .so above matches anything with .so in the name, e.g. xyz.sourceforge
if ! [ -L "$path"/"$sofile" ] && readelf -h "$path"/"$sofile" >/dev/null 2>&1; then
echo "$diff_sofile: " "$(objdump -p "$path"/"$sofile" | grep SONAME)"
fi
done
else
msg "No soname differences for $_pkgname."
fi
done