Skip to content

Instantly share code, notes, and snippets.

@jirutka
Last active September 13, 2021 17:50
Show Gist options
  • Save jirutka/6717f68c7f76c9425b21d0cbe2eaa007 to your computer and use it in GitHub Desktop.
Save jirutka/6717f68c7f76c9425b21d0cbe2eaa007 to your computer and use it in GitHub Desktop.
Some helper scripts for checking dependencies of Alpine packages.
#!/bin/sh
#
# This scripts checks the given list of packages if they have
# reverse dependencies (i.e. there are packages which depends on them).
# Dependencies that are on the list are excluded.
#
# Usage: $0 LIST
set -eu
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
find_revdeps() {
local pkgname="$1"
local excludes="$2"
"$SCRIPT_DIR"/abuild-deps -ors $pkgname \
| grep -vFf "$excludes" \
| sort | uniq
}
has_maintainer() {
local pkgname="$1"
local abuild="$pkgname/APKBUILD"
if [ -f "$abuild" ]; then
grep -qE '# Maintainer: *\w+' "$abuild"
else
echo "ERROR: $abuild does not exist!" >&2
fi
}
mark_unmaintained() {
local pkg; for pkg in $@; do
if has_maintainer $pkg; then
printf "%s " $pkg
else
printf "%s* " $pkg
fi
done
}
pkglist="$1"
echo '# PKGNAME <- list of packages that (make)depends on PKGNAME' >&2
cat "$pkglist" | while read pkgname; do
revdeps="$(find_revdeps "$pkgname" "$pkglist")"
if [ -n "$revdeps" ]; then
printf "%s <- %s\n" "$pkgname" "$(mark_unmaintained $revdeps)"
fi
done
echo ''
echo '* package without a maintainer' >&2
#!/bin/sh
#
# Script for resolving (reverse) dependencies (both runtime and buildtime)
# of an abuild. It uses abuild-deps-index to build index of dependencies
# and abuild-origin to translate to/from origin name.
#
set -eu
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
export PATH="$SCRIPT_DIR:$PATH"
find_deps() {
cat "$DEPS_INDEX" \
| grep $(printf '-e ^%s\s ' $@) \
| cut -d ' ' -f 2 \
| sort | uniq
}
find_rdeps() {
cat "$DEPS_INDEX" \
| grep $(printf '-e \s%s$ ' $@) \
| cut -d ' ' -f 1 \
| sort | uniq
}
usage() {
cat <<-EOF
Usage: $0 [options] PKGNAME
Find all (reverse) dependencies, both runtime and buildtime, of PKGNAME.
Note that this script is just a quick hack with many limitations!
It ignores version ranges, archs and "provides".
Options:
-c Rebuild indexes.
-h Show this message.
-o Print origins instead of (sub)packages.
-r Resolve reverse dependencies.
-s Include subpackages of PKGNAME.
Environment:
REPODIR Path of the abuilds repository (defaults to .)
DEPS_INDEX Path of the dependencies index (defaults to \$REPODIR/deps.idx).
EOF
}
: ${REPODIR:="."}
: ${DEPS_INDEX:="$(readlink -f "$REPODIR/deps.idx")"}
origin='no'
reindex='no'
reverse='no'
incl_subpkgs='no'
while getopts 'chors' opt; do
case $opt in
c) reindex='yes';;
o) origin='yes';;
r) reverse='yes';;
s) incl_subpkgs='yes';;
h) usage; exit 0;;
--) break;;
esac
done
shift $(($OPTIND - 1))
if [ $# -ne 1 ]; then
usage; exit 1
fi
pkgnames="$1"
cd "$REPODIR"
if [ "$reindex" = 'yes' ] || [ ! -f "$DEPS_INDEX" ]; then
abuild-deps-index "$REPODIR"
abuild-origin-index "$REPODIR"
fi
if [ "$incl_subpkgs" = 'yes' ]; then
pkgnames="$(abuild-origin -r $1)"
fi
deps=''
if [ "$reverse" = 'yes' ]; then
deps="$(find_rdeps $pkgnames)"
else
deps="$(find_deps $pkgnames)"
fi
if [ "$origin" = 'yes' ]; then
printf '%s\n' $deps | xargs -I% abuild-origin % | sort | uniq
else
printf '%s\n' $deps
fi
#!/bin/sh
set -eu
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
export PATH="$SCRIPT_DIR:$PATH"
# $1: dependency name
resolve_dep() {
local name="$1"
apk info -d "$name" \
| head -n 1 \
| sed -En 's/^(.*)-[^-]+-r[0-9]+ .*/\1/p'
}
usage() {
cat >&2 <<-EOF
Usage: $0 <main | community | testing>
Check missing dependencies (both runtime and buildtime) of abuilds
in the specified repository.
Note that this script is just a quick hack with many limitations!
It ignores version ranges and archs.
EOF
}
if [ $# -ne 1 ] || [ "$1" = '-h' ]; then
usage; exit 1
exit 1
fi
repo="$1"
case "$repo" in
testing) repos='testing community main';;
community) repos='community main';;
main) repos='main';;
*) repos="$repo main";;
esac
for dir in $repos; do
if [ ! -d "$dir" ]; then
echo "ERROR: Directory $dir does not exist in $(pwd)" >&2
exit 1
fi
if [ -f "$dir/deps.idx" ]; then
echo "Using existing index $dir/deps.idx" >&2
else
abuild-deps-index $dir
fi
if [ -f "$dir/origins.idx" ]; then
echo "Using exiting index $dir/origins.idx" >&2
else
abuild-origin-index $dir
fi
done
pkgs_file="$(mktemp)"
( for dir in $repos; do cat $dir/origins.idx; done ) \
| cut -d ' ' -f 1 \
| sort | uniq \
> "$pkgs_file"
cd "$repo"
echo ''
echo "# PKGNAME <- List of packages that (make)depends on missing PKGNAME" >&2
cat deps.idx | cut -d ' ' -f 2 | sort | uniq \
| grep -vFf "$pkgs_file" | while read pkgname; do
# XXX: We don't index "provides", so try to resolve the $pkgname with
# apk and if found, check if it's in the $pkgs_file.
pkgname="$(resolve_dep $pkgname)"
if [ -n "$pkgname" ] && ! grep -Fq "$pkgname" "$pkgs_file"; then
printf '%s <- %s\n' "$pkgname" "$(abuild-deps -ro $pkgname | tr '\n' ' ')"
fi
done
rm "$pkgs_file"
#!/bin/sh
set -eu
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
export PATH="$SCRIPT_DIR:$PATH"
eval_in_abuild() {
local startdir="$(dirname "$1")"; shift
(
set +eu
cd "$startdir"
. /usr/share/abuild/functions.sh
. APKBUILD
eval "$(cat)"
)
}
# $1: path of APKBUILD file
pkg_names() {
eval_in_abuild "$1" <<-'EOF'
printf '%s\n' $pkgname $subpackages | cut -d : -f 1
EOF
}
# $1: path of APKBUILD file
pkg_makedepends() {
eval_in_abuild "$1" <<-'EOF'
printf '%s\n' $makedepends | sed 's/[<>=][^ ]*//'
EOF
}
# $1: dependency name (e.g. so:libc)
resolve_autodep() {
local name="$1"
local pkgname="$(cat "$AUTODEPS_CACHE" | grep "^$name " | cut -d ' ' -f 2)"
if [ -n "$pkgname" ]; then
echo "$pkgname"; return 0
fi
pkgname="$(apk info -d "$name" | head -n 1 | sed -En 's/^(.*)-[^-]+-r[0-9]+ .*/\1/p')"
if [ -n "$pkgname" ]; then
printf '%s %s\n' "$name" "$pkgname" >> "$AUTODEPS_CACHE"
echo "$pkgname"
return 0
fi
return 1
}
# XXX: apk info --depends is very slow.
# $1: pkgname
pkg_depends() {
local pkgname="$1"
local dep line
apk info --depends "$pkgname" | tail -n +2 | head -n -1 | while read line; do
dep="$(echo "$line" | sed 's/[<>=][^ ]*//')"
case "$line" in
*:*) resolve_autodep "$dep" || echo "WARNING: $dep not found!" >&2;;
!*) ;;
'') break;;
*) echo "$dep";;
esac
done
}
usage() {
cat >&2 <<-EOF
Usage: $0 [REPODIR]
Index all dependencies (both runtime and buildtime) of abuilds in
REPODIR (default is current directory).
This script is just a hack, not a complete production-ready solution!
EOF
}
if [ "${1:-}" = '-h' ]; then
usage; exit 1
fi
repodir="${1:-"$(pwd)"}"
: ${DEPS_INDEX:="$repodir/deps.idx"}
: ${AUTODEPS_CACHE:="$(mktemp)"}
tmpfile="$(mktemp)"
total="$(find "$repodir" -name APKBUILD | wc -l)"
count=1
touch "$AUTODEPS_CACHE"
echo "Indexing dependencies in $repodir..." >&2
find "$repodir" -name APKBUILD | while read -r abuild; do
printf "[%d/%d] %s\n" $count $total "${abuild%/*}"
makedepends="$(pkg_makedepends "$abuild")"
for pkg in $(pkg_names "$abuild"); do
for dep in $(pkg_depends "$pkg") $makedepends; do
printf '%s %s\n' $pkg $dep >> "$tmpfile"
done
done
count=$(( count + 1 ))
done
echo "Completed. Writing index into $DEPS_INDEX" >&2
cat "$tmpfile" | sort | uniq > "$DEPS_INDEX"
rm "$tmpfile"
#!/bin/sh
set -eu
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
export PATH="$SCRIPT_DIR:$PATH"
usage() {
cat <<-EOF
Usage: $0 [options] PKGNAME
Resolve origin name of (sub)package PKGNAME, or subpackages of PKGNAME.
Options:
-c Rebuild indexes.
-h Show this message.
-r Resolve subpackages instead of origin.
Environment:
REPODIR Path of the abuilds repository (defaults to .)
ORIGINS_INDEX Path of the origins index (defaults to \$REPODIR/origins.idx).
EOF
}
: ${REPODIR:="."}
: ${ORIGINS_INDEX:="$REPODIR/origins.idx"}
reindex='no'
reverse='no'
while getopts 'chr' opt; do
case $opt in
c) reindex='yes';;
r) reverse='yes';;
h) usage; exit 0;;
--) break;;
esac
done
shift $(($OPTIND - 1))
if [ $# -ne 1 ]; then
usage; exit 1
fi
if [ "$reindex" = 'yes' ] || [ ! -f "$ORIGINS_INDEX" ]; then
abuild-origin-index "$REPODIR"
fi
if [ "$reverse" = 'yes' ]; then
out="$(cat "$ORIGINS_INDEX" | grep " $1$" | cut -d ' ' -f 1)"
else
out="$(cat "$ORIGINS_INDEX" | grep "^$1 " | cut -d ' ' -f 2)"
fi
[ -n "$out" ] && echo "$out" || exit 1
#!/bin/sh
set -eu
# $1: path of APKBUILD file
pkg_subpkgs() {
local startdir="$(dirname "$1")"
(
set +eu
cd "$startdir"
. /usr/share/abuild/functions.sh
. APKBUILD
printf '%s\n' $subpackages | cut -d : -f 1
)
}
usage() {
cat >&2 <<-EOF
Usage: $0 [REPODIR]
Index names of origin and subpackages in REPODIR (default is
current directory).
This script is just a hack, not a complete production-ready solution!
EOF
}
if [ "${1:-}" = '-h' ]; then
usage; exit 1
fi
repodir="${1:-"$(pwd)"}"
: ${ORIGINS_INDEX:="$repodir/origins.idx"}
tmpfile="$(mktemp)"
echo "Indexing (sub)packages in $repodir..." >&2
find "$repodir" -name APKBUILD | while read -r abuild; do
origin="$(basename "${abuild%/*}")"
for pkgname in $origin $(pkg_subpkgs "$abuild"); do
printf "%s %s\n" $pkgname $origin >> "$tmpfile"
done
done
echo "Completed. Writing index into $ORIGINS_INDEX" >&2
mv "$tmpfile" "$ORIGINS_INDEX"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment