#!/bin/sh # Resolve ports/alpine/world into world.lock. # # tools/posix/alpine-lock.sh APK_STATIC MINIROOTFS WORLD LOCK DISTDIR # # Asks Alpine's mirror, so it needs the network; nothing else in the build # does. Every package in the dependency closure is fetched into DISTDIR and # recorded as # # # # which is all a build needs to download it again and know it got the same # bytes. apk checks Alpine's signature on top of that when it installs. set -eu [ $# -eq 5 ] || { echo "usage: $0 APK_STATIC MINIROOTFS WORLD LOCK DISTDIR" >&2; exit 2; } abs() { case "$1" in /*) echo "$1" ;; *) echo "$(pwd)/$1" ;; esac; } APK=$(abs "$1"); MINI=$(abs "$2"); WORLD=$(abs "$3"); LOCK=$(abs "$4"); DIST=$(abs "$5") T=$(mktemp -d) trap 'rm -rf "$T"' EXIT mkdir -p "$T/root" "$DIST" tar -xzf "$MINI" -C "$T/root" # apk.static looks for CA certificates on the host, where a NixOS or a macOS # keeps them somewhere else; Alpine's own bundle is right here. export SSL_CERT_FILE="$T/root/etc/ssl/certs/ca-certificates.crt" PKGS=$(sed 's/#.*//' "$WORLD" | tr -s ' \t' '\n' | grep . || true) [ -n "$PKGS" ] || { echo "alpine-lock: $WORLD lists nothing" >&2; exit 1; } "$APK" --root "$T/root" --no-cache update -q # shellcheck disable=SC2086 "$APK" --root "$T/root" --no-cache fetch --recursive --output "$DIST" $PKGS # Which repository each one came from, read from the indexes apk just used. MIRROR=$(grep -m1 '^http' "$T/root/etc/apk/repositories" | sed 's|/[^/]*$||') for r in main community; do curl -fsSL "$MIRROR/$r/x86_64/APKINDEX.tar.gz" | tar -xzO APKINDEX | awk -v r="$r" '/^P:/{p=substr($0,3)} /^V:/{print p "-" substr($0,3) ".apk", r}' done > "$T/where" # The closure, as apk resolved it: install it into the scratch root and read # back what is there. # shellcheck disable=SC2086 "$APK" --root "$T/root" --no-cache --no-scripts --no-chown add -q $PKGS "$APK" --root "$T/root" info -v 2>/dev/null | sort > "$T/closure" { echo "# Generated by tools/posix/alpine-lock.sh from world. Do not edit;" echo "# change world and run \`make alpine-lock\`." echo "# file sha256 repository" while read -r nv; do f=$nv.apk [ -f "$DIST/$f" ] || continue # in the minirootfs, not needed by world repo=$(awk -v f="$f" '$1 == f { print $2; exit }' "$T/where") [ -n "$repo" ] || { echo "alpine-lock: $f is in no repository" >&2; exit 1; } sum=$(sha256sum "$DIST/$f" | cut -d' ' -f1) echo "$f $sum $repo" done < "$T/closure" } > "$LOCK.new" mv "$LOCK.new" "$LOCK" echo "alpine-lock: $(grep -vc '^#' "$LOCK") packages in $LOCK"