forked from artix/artools
		
	Compare commits
	
		
			8 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 41ddcf3bbb | |||
| 4f53ee4a0a | |||
| cd338d1bb3 | |||
| ce4329def7 | |||
| 7fc5ecf0e1 | |||
| f77d29fdd7 | |||
| bfa243b21c | |||
| 6a4527b6f2 | 
							
								
								
									
										5
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								Makefile
									
									
									
									
									
								
							| @@ -42,7 +42,10 @@ PKG_BIN = \ | ||||
| 	bin/pkg/checkrepo \ | ||||
| 	bin/pkg/gitearepo \ | ||||
| 	bin/pkg/tidyarch \ | ||||
| 	bin/pkg/mkdepgraph | ||||
| 	bin/pkg/mkdepgraph \ | ||||
| 	bin/pkg/diffpkg \ | ||||
| 	bin/pkg/makerepropkg \ | ||||
| 	bin/pkg/export-pkgbuild-keys | ||||
|  | ||||
| LN_COMMITPKG = \ | ||||
| 	extrapkg \ | ||||
|   | ||||
| @@ -90,11 +90,11 @@ for f in "${files[@]}"; do | ||||
|     cp "$f" "$working_dir$f" | ||||
| done | ||||
|  | ||||
| basestrap -${umode}Mc ${pacman_conf:+-C "$pacman_conf"} "$working_dir" \ | ||||
| unshare --mount basestrap -${umode}Mc ${pacman_conf:+-C "$pacman_conf"} "$working_dir" \ | ||||
|     "${cache_dirs[@]/#/--cachedir=}" "$@" || die 'Failed to install all packages' | ||||
|  | ||||
| printf '%s.UTF-8 UTF-8\n' en_US de_DE > "$working_dir/etc/locale.gen" | ||||
| printf 'LANG=en_US.UTF-8\n' > "$working_dir/etc/locale.conf" | ||||
| printf '%s.UTF-8 UTF-8\n' C en_US de_DE > "$working_dir/etc/locale.gen" | ||||
| printf 'LANG=C.UTF-8\n' > "$working_dir/etc/locale.conf" | ||||
| # printf 'KEYMAP=en\n' > "$working_dir/etc/vconsole.conf" | ||||
| printf "%s\n" "${CHROOTVERSION}" > "$working_dir/.artools" | ||||
|  | ||||
|   | ||||
| @@ -13,77 +13,12 @@ | ||||
| # GNU General Public License for more details. | ||||
|  | ||||
| m4_include(lib/base/message.sh) | ||||
| m4_include(lib/pkg/diff.sh) | ||||
|  | ||||
| shopt -s extglob | ||||
|  | ||||
| load_makepkg_config | ||||
|  | ||||
| #{{{ functions | ||||
|  | ||||
| pkgver_equal() { | ||||
|     if [[ $1 = *-* && $2 = *-* ]]; then | ||||
|         # if both versions have a pkgrel, then they must be an exact match | ||||
|         [[ $1 = "$2" ]] | ||||
|     else | ||||
|         # otherwise, trim any pkgrel and compare the bare version. | ||||
|         [[ ${1%%-*} = "${2%%-*}" ]] | ||||
|     fi | ||||
| } | ||||
|  | ||||
| find_cached_package() { | ||||
|     local searchdirs=("$PKGDEST" "$PWD") results=() | ||||
|     local targetname=$1 targetver=$2 targetarch=$3 | ||||
|     local dir pkg pkgbasename name ver rel arch r results | ||||
|  | ||||
|     for dir in "${searchdirs[@]}"; do | ||||
|         [[ -d $dir ]] || continue | ||||
|  | ||||
|         for pkg in "$dir"/*.pkg.tar?(.!(sig|*.*)); do | ||||
|             [[ -f $pkg ]] || continue | ||||
|  | ||||
|             # avoid adding duplicates of the same inode | ||||
|             for r in "${results[@]}"; do | ||||
|                 [[ $r -ef $pkg ]] && continue 2 | ||||
|             done | ||||
|  | ||||
|             # split apart package filename into parts | ||||
|             pkgbasename=${pkg##*/} | ||||
|             pkgbasename=${pkgbasename%.pkg.tar*} | ||||
|  | ||||
|             arch=${pkgbasename##*-} | ||||
|             pkgbasename=${pkgbasename%-"$arch"} | ||||
|  | ||||
|             rel=${pkgbasename##*-} | ||||
|             pkgbasename=${pkgbasename%-"$rel"} | ||||
|  | ||||
|             ver=${pkgbasename##*-} | ||||
|             name=${pkgbasename%-"$ver"} | ||||
|  | ||||
|             if [[ $targetname = "$name" && $targetarch = "$arch" ]] && | ||||
|                 pkgver_equal "$targetver" "$ver-$rel"; then | ||||
|                 results+=("$pkg") | ||||
|             fi | ||||
|         done | ||||
|     done | ||||
|  | ||||
|     case ${#results[*]} in | ||||
|         0) | ||||
|             return 1 | ||||
|         ;; | ||||
|         1) | ||||
|             printf '%s\n' "${results[0]}" | ||||
|             return 0 | ||||
|         ;; | ||||
|         *) | ||||
|             error 'Multiple packages found:' | ||||
|             printf '\t%s\n' "${results[@]}" >&2 | ||||
|             return 1 | ||||
|         ;; | ||||
|     esac | ||||
| } | ||||
|  | ||||
| #}}} | ||||
|  | ||||
| usage() { | ||||
|     cat <<- _EOF_ | ||||
|         Usage: ${BASH_SOURCE[0]##*/} [OPTIONS] | ||||
|   | ||||
							
								
								
									
										229
									
								
								bin/pkg/diffpkg.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										229
									
								
								bin/pkg/diffpkg.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,229 @@ | ||||
| #!/bin/bash | ||||
| # | ||||
| # SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  | ||||
| shopt -s extglob | ||||
|  | ||||
| m4_include(lib/base/message.sh) | ||||
| m4_include(lib/pkg/diff.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=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 | ||||
							
								
								
									
										70
									
								
								bin/pkg/export-pkgbuild-keys.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								bin/pkg/export-pkgbuild-keys.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | ||||
| #!/bin/bash | ||||
| # | ||||
| # SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  | ||||
| m4_include(lib/base/message.sh) | ||||
|  | ||||
| usage() { | ||||
|     cat <<- _EOF_ | ||||
|         Usage: ${BASH_SOURCE[0]##*/} | ||||
|  | ||||
|         Export the PGP keys from a PKGBUILDs validpgpkeys array into the keys/pgp/ | ||||
|         subdirectory. Useful for distributing packager validated source signing | ||||
|         keys alongside PKGBUILDs. | ||||
|  | ||||
|         OPTIONS | ||||
|             -h, --help      Show this help text | ||||
| _EOF_ | ||||
| } | ||||
|  | ||||
| # option checking | ||||
| while (( $# )); do | ||||
|     case $1 in | ||||
|         -h|--help) usage; exit 0 ;; | ||||
|         *) die "invalid argument: %s" "$1" ;; | ||||
|     esac | ||||
| done | ||||
|  | ||||
| if [[ ! -f PKGBUILD ]]; then | ||||
|     die "This must be run a directory containing a PKGBUILD." | ||||
| fi | ||||
|  | ||||
| mapfile -t validpgpkeys < <( | ||||
|     # shellcheck source=PKGBUILD.proto | ||||
|     . ./PKGBUILD | ||||
|     if (( ${#validpgpkeys[@]} )); then | ||||
|         printf "%s\n" "${validpgpkeys[@]}" | ||||
|     fi | ||||
| ) | ||||
|  | ||||
| msg "Exporting ${#validpgpkeys[@]} PGP keys..." | ||||
| if (( ${#validpgpkeys[@]} == 0 )); then | ||||
|     exit 0 | ||||
| fi | ||||
|  | ||||
| trap 'rm -rf $TEMPDIR' EXIT INT TERM QUIT | ||||
| TEMPDIR=$(mktemp -d --tmpdir export-pkgbuild-keys.XXXXXXXXXX) | ||||
|  | ||||
| mkdir -p keys/pgp | ||||
| error=0 | ||||
|  | ||||
| for key in "${validpgpkeys[@]}"; do | ||||
|     gpg --output "$TEMPDIR/$key.asc" --armor --export --export-options export-minimal "$key" 2>/dev/null | ||||
|  | ||||
|     # gpg does not give a non-zero return value if it fails to export... | ||||
|     if [[ -f $TEMPDIR/$key.asc ]]; then | ||||
|         msg2 "Exported $key" | ||||
|         mv "$TEMPDIR/$key.asc" "keys/pgp/$key.asc" | ||||
|     else | ||||
|         if [[ -f keys/pgp/$key.asc ]]; then | ||||
|             warning "Failed to update key: $key" | ||||
|         else | ||||
|             error "Key unavailable: $key" | ||||
|             error=1 | ||||
|         fi | ||||
|     fi | ||||
| done | ||||
|  | ||||
| if (( error )); then | ||||
|     die "Failed to export all \'validpgpkeys\' entries." | ||||
| fi | ||||
							
								
								
									
										271
									
								
								bin/pkg/makerepropkg.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										271
									
								
								bin/pkg/makerepropkg.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,271 @@ | ||||
| #!/bin/bash | ||||
| # | ||||
| # makerepropkg - rebuild a package to see if it is reproducible | ||||
| # | ||||
| # Copyright (c) 2019 by Eli Schwartz <eschwartz@archlinux.org> | ||||
| # | ||||
| # SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  | ||||
| m4_include(lib/util-base.sh) | ||||
| m4_include(lib/base/message.sh) | ||||
| m4_include(lib/base/chroot.sh) | ||||
| m4_include(lib/base/chroot.sh) | ||||
|  | ||||
| declare -A buildinfo | ||||
| declare -a buildenv buildopts installed installpkgs | ||||
|  | ||||
| archiveurl='https://archive.artixlinux.org/packages' | ||||
| buildroot="${CHROOTS_DIR}"/reproducible | ||||
| diffoscope=0 | ||||
|  | ||||
| chroot=$USER | ||||
| [[ -n ${SUDO_USER:-} ]] && chroot=$SUDO_USER | ||||
| [[ -z "$chroot" || $chroot = root ]] && chroot=copy | ||||
|  | ||||
| parse_buildinfo() { | ||||
|     local line var val | ||||
|  | ||||
|     while read -r line; do | ||||
|         var="${line%% = *}" | ||||
|         val="${line#* = }" | ||||
|         case ${var} in | ||||
|             buildenv) | ||||
|                 buildenv+=("${val}") | ||||
|                 ;; | ||||
|             options) | ||||
|                 buildopts+=("${val}") | ||||
|                 ;; | ||||
|             installed) | ||||
|                 installed+=("${val}") | ||||
|                 ;; | ||||
|             *) | ||||
|                 buildinfo["${var}"]="${val}" | ||||
|                 ;; | ||||
|         esac | ||||
|     done | ||||
| } | ||||
|  | ||||
| get_pkgfile() { | ||||
|     local cdir=${cache_dirs[0]} | ||||
|     local pkgfilebase=${1} | ||||
|     local mode=${2} | ||||
|     local pkgname=${pkgfilebase%-*-*-*} | ||||
|     local pkgfile ext | ||||
|  | ||||
|     # try without downloading | ||||
|     if [[ ${mode} != localonly ]] && get_pkgfile "${pkgfilebase}" localonly; then | ||||
|         return 0 | ||||
|     fi | ||||
|  | ||||
|     for ext in .zst .xz ''; do | ||||
|         pkgfile=${pkgfilebase}.pkg.tar${ext} | ||||
|  | ||||
|         for c in "${cache_dirs[@]}"; do | ||||
|             if [[ -f ${c}/${pkgfile} ]]; then | ||||
|                 cdir=${c} | ||||
|                 break | ||||
|             fi | ||||
|         done | ||||
|  | ||||
|         for f in "${pkgfile}" "${pkgfile}.sig"; do | ||||
|             if [[ ! -f "${cdir}/${f}" ]]; then | ||||
|                 if [[ ${mode} = localonly ]]; then | ||||
|                     continue 2 | ||||
|                 fi | ||||
|                 msg2 "retrieving '%s'..." "${f}" >&2 | ||||
|                 curl -Llf -# -o "${cdir}/${f}" "${archiveurl}/${pkgname:0:1}/${pkgname}/${f}" || continue 2 | ||||
|             fi | ||||
|         done | ||||
|         printf '%s\n' "file://${cdir}/${pkgfile}" | ||||
|         return 0 | ||||
|     done | ||||
|  | ||||
|     return 1 | ||||
| } | ||||
|  | ||||
| get_makepkg_conf() { | ||||
|     local fname=${1} | ||||
|     local makepkg_conf="${2}" | ||||
|     if ! buildtool_file=$(get_pkgfile "${fname}"); then | ||||
|         error "failed to retrieve ${fname}" | ||||
|         return 1 | ||||
|     fi | ||||
|     msg2 "using makepkg.conf from ${fname}" | ||||
|     bsdtar xOqf "${buildtool_file/file:\/\//}" usr/share/artools/makepkg.conf > "${makepkg_conf}" | ||||
|     return 0 | ||||
| } | ||||
|  | ||||
| usage() { | ||||
|     cat << __EOF__ | ||||
|     usage: ${BASH_SOURCE[0]##*/} [options] <package_file> | ||||
|  | ||||
|     Run this script in a PKGBUILD dir to build a package inside a | ||||
|     clean chroot while attempting to reproduce it. The package file | ||||
|     will be used to derive metadata needed for reproducing the | ||||
|     package, including the .PKGINFO as well as the buildinfo. | ||||
|  | ||||
|     For more details see https://reproducible-builds.org/ | ||||
|  | ||||
|     OPTIONS | ||||
|         -d            Run diffoscope if the package is unreproducible | ||||
|         -c <dir>      Set pacman cache | ||||
|         -M <file>     Location of a makepkg config file | ||||
|         -l <chroot>   The directory name to use as the chroot namespace | ||||
|                     Useful for maintaining multiple copies | ||||
|                     Default: $chroot | ||||
|         -h            Show this usage message | ||||
| __EOF__ | ||||
| } | ||||
|  | ||||
| while getopts 'dM:c:l:h' arg; do | ||||
|     case "$arg" in | ||||
|         d) diffoscope=1 ;; | ||||
|         M) artixroot_args+=(-M "$OPTARG") ;; | ||||
|         c) cache_dirs+=("$OPTARG") ;; | ||||
|         l) chroot="$OPTARG" ;; | ||||
|         h) usage; exit 0 ;; | ||||
|         *|?) usage; exit 1 ;; | ||||
|     esac | ||||
| done | ||||
| shift $((OPTIND - 1)) | ||||
|  | ||||
| check_root | ||||
|  | ||||
| [[ -f PKGBUILD ]] || { error "No PKGBUILD in current directory."; exit 1; } | ||||
|  | ||||
| # without arguments, get list of packages from PKGBUILD | ||||
| if [[ -z $1 ]]; then | ||||
|     mapfile -t pkgnames < <(source PKGBUILD; pacman -Sddp --print-format '%r/%n' "${pkgname[@]}") | ||||
|     wait $! || { | ||||
|         error "No package file specified and failed to retrieve package names from './PKGBUILD'." | ||||
|         plain "Try '${BASH_SOURCE[0]##*/} -h' for more information." >&2 | ||||
|         exit 1 | ||||
|     } | ||||
|     msg "Reproducing all pkgnames listed in ./PKGBUILD" | ||||
|     set -- "${pkgnames[@]}" | ||||
| fi | ||||
|  | ||||
| # check each package to see if it's a file, and if not, try to download it | ||||
| # using pacman -Sw, and get the filename from there | ||||
| splitpkgs=() | ||||
| for p in "$@"; do | ||||
|     if [[ -f ${p} ]]; then | ||||
|         splitpkgs+=("${p}") | ||||
|     else | ||||
|         pkgfile_remote=$(pacman -Sddp "${p}" 2>/dev/null) || { error "package name '%s' not in repos" "${p}"; exit 1; } | ||||
|         pkgfile=${pkgfile_remote#file://} | ||||
|         if [[ ! -f ${pkgfile} ]]; then | ||||
|             msg "Downloading package '%s' into pacman's cache" "${pkgfile}" | ||||
|             sudo pacman -Swdd --noconfirm --logfile /dev/null "${p}" || exit 1 | ||||
|             pkgfile_remote=$(pacman -Sddp "${p}" 2>/dev/null) | ||||
|             pkgfile="${pkgfile_remote#file://}" | ||||
|         fi | ||||
|         splitpkgs+=("${pkgfile}") | ||||
|     fi | ||||
| done | ||||
|  | ||||
| for f in "${splitpkgs[@]}"; do | ||||
|     if ! bsdtar -tqf "${f}" .BUILDINFO >/dev/null 2>&1; then | ||||
|         error "file is not a valid pacman package: '%s'" "${f}" | ||||
|         exit 1 | ||||
|     fi | ||||
| done | ||||
|  | ||||
| if (( ${#cache_dirs[@]} == 0 )); then | ||||
| 	mapfile -t cache_dirs < <(pacman-conf CacheDir) | ||||
| fi | ||||
|  | ||||
| ORIG_HOME=${HOME} | ||||
| IFS=: read -r _ _ _ _ _ HOME _ < <(getent passwd "${SUDO_USER:-$USER}") | ||||
| load_makepkg_config | ||||
| HOME=${ORIG_HOME} | ||||
| [[ -d ${SRCDEST} ]] || SRCDEST=${PWD} | ||||
|  | ||||
| parse_buildinfo < <(bsdtar -xOqf "${splitpkgs[0]}" .BUILDINFO) | ||||
| export SOURCE_DATE_EPOCH="${buildinfo[builddate]}" | ||||
| PACKAGER="${buildinfo[packager]}" | ||||
| BUILDDIR="${buildinfo[builddir]}" | ||||
| BUILDTOOL="${buildinfo[buildtool]}" | ||||
| BUILDTOOLVER="${buildinfo[buildtoolver]}" | ||||
| PKGEXT=${splitpkgs[0]#${splitpkgs[0]%.pkg.tar*}} | ||||
|  | ||||
| # nuke and restore reproducible testenv | ||||
| namespace="$buildroot/$chroot" | ||||
| lock 9 "${namespace}.lock" "Locking chroot namespace '%s'" "${namespace}" | ||||
| for copy in "${namespace}"/*/; do | ||||
|     [[ -d ${copy} ]] || continue | ||||
|     subvolume_delete_recursive "${copy}" | ||||
| done | ||||
| rm -rf --one-file-system "${namespace}" | ||||
| (umask 0022; mkdir -p "${namespace}") | ||||
|  | ||||
| for fname in "${installed[@]}"; do | ||||
|     if ! allpkgfiles+=("$(get_pkgfile "${fname}")"); then | ||||
|         error "failed to retrieve ${fname}" | ||||
|         exit 1 | ||||
|     fi | ||||
| done | ||||
|  | ||||
| trap 'rm -rf $TEMPDIR' EXIT INT TERM QUIT | ||||
| TEMPDIR=$(mktemp -d --tmpdir makerepropkg.XXXXXXXXXX) | ||||
|  | ||||
| makepkg_conf="${TEMPDIR}/makepkg.conf" | ||||
| # anything before buildtool support is pinned to the last none buildtool aware release | ||||
| if [[ -z "${BUILDTOOL}" ]]; then | ||||
|     get_makepkg_conf "artools-pkg-0.28.2-1-any" "${makepkg_conf}" || exit 1 | ||||
| # prefere to assume artools-pkg up until matching makepkg version so repository packages remain reproducible | ||||
| elif [[ "${BUILDTOOL}" = makepkg ]] && (( $(vercmp "${BUILDTOOLVER}" 6.0.1) <= 0 )); then | ||||
|     get_makepkg_conf "artools-pkg-0.28.2-1-any" "${makepkg_conf}" || exit 1 | ||||
| # all artools-pkg builds | ||||
| elif [[ "${BUILDTOOL}" = artools-pkg ]] && get_makepkg_conf "${BUILDTOOL}-${BUILDTOOLVER}" "${makepkg_conf}"; then | ||||
|     true | ||||
| # fallback to current makepkg.conf | ||||
| else | ||||
|     warning "Unknown buildtool (${BUILDTOOL}-${BUILDTOOLVER}), using fallback" | ||||
|     makepkg_conf="${DATADIR}"/makepkg.conf | ||||
| fi | ||||
| printf '%s\n' "${allpkgfiles[@]}" | mkchroot -M "${makepkg_conf}" -U "${artixroot_args[@]}" "${namespace}/root" - || exit 1 | ||||
|  | ||||
| # use makechrootpkg to prep the build directory | ||||
| mkchrootpkg -r "${namespace}" -l build -- --packagelist || exit 1 | ||||
|  | ||||
| # set detected makepkg.conf options | ||||
| { | ||||
|     for var in PACKAGER BUILDDIR BUILDTOOL BUILDTOOLVER PKGEXT; do | ||||
|         printf '%s=%s\n' "${var}" "${!var@Q}" | ||||
|     done | ||||
|     printf 'OPTIONS=(%s)\n' "${buildopts[*]@Q}" | ||||
|     printf 'BUILDENV=(%s)\n' "${buildenv[*]@Q}" | ||||
| } >> "${namespace}/build"/etc/makepkg.conf | ||||
| install -d -o "${SUDO_UID:-$UID}" -g "$(id -g "${SUDO_UID:-$UID}")" "${namespace}/build/${BUILDDIR}" | ||||
|  | ||||
| bindmounts+=("-B:${PWD}:/startdir" "-B:${SRCDEST}:/srcdest") | ||||
|  | ||||
| # kick off the build | ||||
| chroot-run \ | ||||
|     -b "${bindmounts[*]}" \ | ||||
|     "${namespace}/build" \ | ||||
|     /chrootbuild -C --noconfirm --log --holdver --skipinteg | ||||
| ret=$? | ||||
|  | ||||
| if (( ${ret} == 0 )); then | ||||
|     msg2 "built succeeded! built packages can be found in ${namespace}/build/pkgdest" | ||||
|     msg "comparing artifacts..." | ||||
|  | ||||
|     for pkgfile in "${splitpkgs[@]}"; do | ||||
|         comparefiles=("${pkgfile}" "${namespace}/build/pkgdest/${pkgfile##*/}") | ||||
|         if cmp -s "${comparefiles[@]}"; then | ||||
|             msg2 "Package '%s' successfully reproduced!" "${pkgfile}" | ||||
|         else | ||||
|             ret=1 | ||||
|             warning "Package '%s' is not reproducible. :(" "${pkgfile}" | ||||
|             sha256sum "${comparefiles[@]}" | ||||
|             if (( diffoscope )); then | ||||
|                 diffoscope "${comparefiles[@]}" | ||||
|             fi | ||||
|         fi | ||||
|     done | ||||
| fi | ||||
|  | ||||
| # return failure from chrootbuild, or the reproducibility status | ||||
| exit ${ret} | ||||
							
								
								
									
										67
									
								
								lib/pkg/diff.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								lib/pkg/diff.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | ||||
| #!/hint/bash | ||||
|  | ||||
| #{{{ functions | ||||
|  | ||||
| pkgver_equal() { | ||||
|     if [[ $1 = *-* && $2 = *-* ]]; then | ||||
|         # if both versions have a pkgrel, then they must be an exact match | ||||
|         [[ $1 = "$2" ]] | ||||
|     else | ||||
|         # otherwise, trim any pkgrel and compare the bare version. | ||||
|         [[ ${1%%-*} = "${2%%-*}" ]] | ||||
|     fi | ||||
| } | ||||
|  | ||||
| find_cached_package() { | ||||
|     local searchdirs=("$PKGDEST" "$PWD") results=() | ||||
|     local targetname=$1 targetver=$2 targetarch=$3 | ||||
|     local dir pkg pkgbasename name ver rel arch r results | ||||
|  | ||||
|     for dir in "${searchdirs[@]}"; do | ||||
|         [[ -d $dir ]] || continue | ||||
|  | ||||
|         for pkg in "$dir"/*.pkg.tar?(.!(sig|*.*)); do | ||||
|             [[ -f $pkg ]] || continue | ||||
|  | ||||
|             # avoid adding duplicates of the same inode | ||||
|             for r in "${results[@]}"; do | ||||
|                 [[ $r -ef $pkg ]] && continue 2 | ||||
|             done | ||||
|  | ||||
|             # split apart package filename into parts | ||||
|             pkgbasename=${pkg##*/} | ||||
|             pkgbasename=${pkgbasename%.pkg.tar*} | ||||
|  | ||||
|             arch=${pkgbasename##*-} | ||||
|             pkgbasename=${pkgbasename%-"$arch"} | ||||
|  | ||||
|             rel=${pkgbasename##*-} | ||||
|             pkgbasename=${pkgbasename%-"$rel"} | ||||
|  | ||||
|             ver=${pkgbasename##*-} | ||||
|             name=${pkgbasename%-"$ver"} | ||||
|  | ||||
|             if [[ $targetname = "$name" && $targetarch = "$arch" ]] && | ||||
|                 pkgver_equal "$targetver" "$ver-$rel"; then | ||||
|                 results+=("$pkg") | ||||
|             fi | ||||
|         done | ||||
|     done | ||||
|  | ||||
|     case ${#results[*]} in | ||||
|         0) | ||||
|             return 1 | ||||
|         ;; | ||||
|         1) | ||||
|             printf '%s\n' "${results[0]}" | ||||
|             return 0 | ||||
|         ;; | ||||
|         *) | ||||
|             error 'Multiple packages found:' | ||||
|             printf '\t%s\n' "${results[@]}" >&2 | ||||
|             return 1 | ||||
|         ;; | ||||
|     esac | ||||
| } | ||||
|  | ||||
| #}}} | ||||
		Reference in New Issue
	
	Block a user