From f28c0cf330c2da17daab59755675420b0e2724a8 Mon Sep 17 00:00:00 2001 From: John McQuah Date: Tue, 31 May 2022 16:02:44 -0400 Subject: [PATCH] pkgmeek: initial commit --- scripts/pkgmeek | 575 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 575 insertions(+) create mode 100755 scripts/pkgmeek diff --git a/scripts/pkgmeek b/scripts/pkgmeek new file mode 100755 index 0000000..7d0b869 --- /dev/null +++ b/scripts/pkgmeek @@ -0,0 +1,575 @@ +#!/bin/bash +# +# pkgmeek - a drop-in replacement for pkgmk +# based on upkgmk (c) 2018 therealfun +# and pkgmk (c) 2004--2022 Per Liden et al. +# Distributed under the same license, +# https://crux.nu/gitweb/?p=tools/pkgutils.git;a=blob_plain;f=COPYING;hb=HEAD + +main() { +######################## main routine ################################ +local o_ignored work _local_ here url u f errDL pkg_ood errUZ +parse_options "$@" +# +# Exit early if cleaning was requested +# +if [ "$PKGMK_CLEAN" = "yes" ]; then + [ "$PKGMK_MTIME_ONLY" = "yes" ] && o_ignored="-utd" + [ "$PKGMK_UPDATE_FOOTPRINT" = "yes" ] && o_ignored+=" -uf" + [ "$PKGMK_CHECK_SIG" = "yes" ] && o_ignored+=" -cs" + [ "$PKGMK_REFRESH_SIG" = "yes" ] && refresh_signature + [ "$o_ignored" = "" ] || { warning "option -c nullifies these requested options:"; + echo "$o_ignored"; } + exec $PRTWASH_COMMAND -p -s "$(pwd)" +fi +# +# Read the Pkgfile to determine what to do next. But first ensure that +# it came from a trusted source (FS#1851) +# +validate_pkgfile +[ -f .32bit ] && PGKMK_ARCH=32 || PKGMK_ARCH=64 +. "Pkgfile"; . "$PKGMK_CONF" + +set -e + +# respect the settings for centralized source and package directories +[ -v pkg_dir ] || pkg_dir="$PKGMK_PACKAGE_DIR"/ +[ -w "$pkg_dir" ] || pkg_dir="$(pwd)"/ +[ -v src_dir ] || src_dir="$PKGMK_SOURCE_DIR" +[ -w "$src_dir" ] || src_dir= + +# respect the setting for WORK_DIR in case the user wants to build in RAM +[ -v PKGMK_WORK_DIR ] && work="$PKGMK_WORK_DIR" + +# Let the main routine and subsequent subroutines know what filenames +# they should expect to see on disk. +package="${name}#${version}-${release}.pkg.tar.${PKGMK_COMPRESSION_MODE}" +declare -A _local_ +for (( s=0; s<${#source[@]}; s++ )); do + if [[ ${source[$s]} =~ ^(https|ssh|git)://.*/(.+)\.git ]]; then + _local_[$s]="${BASH_REMATCH[2]}" + elif [[ ${source[$s]} =~ ^(http|https|ftp|file)://.*/(.+) ]]; then + _local_[$s]="${BASH_REMATCH[2]}" + else + _local_[$s]="${source[$s]}" + fi + [ -z "${renames[$s]}" ] || [ "${renames[$s]}" = "SKIP" ] || \ + _local_[$s]="${renames[$s]}" +done +# Example: _local_ = ( upstream-ball-v12.tgz +# random.patch +# some-git-repo/ ) + +# The effective user should at least have write permissions on $PWD +[ -w "$(dirname "$work")" ] || work="$(pwd)"/work +rm -rf "$work"; mkdir -p "$work"/{src,pkg} && cd "$work" + +for (( u=0; u<${#_local_[@]}; u++ )); do + here="${_local_[$u]}" + url="${source[$u]}" + # at least one of the following commands should put a file of the + # appropriate name in the current directory + [ -e "$here" ] || [ "$src_dir" = "" ] || [ ! -e "$src_dir/$here" ] || ln -sf "$src_dir/$here" . + [ -e "$here" ] || [ ! -e "$PKGMK_ROOT/$here" ] || ln -sf "$PKGMK_ROOT/$here" . + [ -e "$here" ] || [[ $url =~ ^(https|ssh|git)://.*/(.+)\.git ]] || { + "$PKGMK_DOWNLOAD_PROG" -O "$here" "$url"; + [ "$src_dir" = "" ] || { mv "$here" "$src_dir"/ && ln -sf "$src_dir/$here" . ; }; + } + [ -e "$here" ] || [[ ! $url =~ ^(https|ssh|git)://.*/(.+)\.git ]] || \ + ( "$PKGMK_GIT_COMMAND" clone "$url" "$here" ) || continue + # but if not, exit with an informative error message + if [ ! -e "$here" ]; then + error "failed to download $here. Check connection and try again." + errDL=$E_DOWNLOAD + fi +done + +{ [ "$PKGMK_DOWNLOAD_ONLY" = "yes" ] || [ "$errDL" ]; } && exit $errDL + +# Now that all the files are on disk, check mtimes to determine whether a build is needed. +check_pkg_mtime && pkg_ood=0 || pkg_ood=1 +[ "$PKGMK_MTIME_ONLY" = "no" ] || exit $pkg_ood +[ "$pkg_ood" = 1 ] || [ "$PKGMK_FORCE" = "yes" ] || [ "$PKGMK_UPDATE_FOOTPRINT" = "yes" ] || \ + [ "$PKGMK_UPDATE_SIG" = "yes" ] || exit 0 +[ "$PKGMK_CHECK_SIG" = "yes" ] || echo "Checking signatures before unpacking..." + +# The option -uf is meant to be used after a previous invocation of pkgmk has +# alerted the user to a footprint mismatch. The option -us is likewise meant +# to update the signature, which only requires the sources and the footprint. +if [ "$PKGMK_UPDATE_FOOTPRINT" = "yes" ]; then + [ -f "$package" ] || \ + { error "unable to update footprint. File '$package' not found."; + exit "$E_MANIFEST"; } + [ "$pkg_ood" = 0 ] || [ "$PKGMK_FORCE" = "yes" ] || \ + { error "outdated package. Use '-f' to force the footprint update."; + exit "$E_FOOTPRINT"; } + make_manifest "footprint" > "$PKGMK_ROOT/.footprint" || \ + { error "Failed to write the footprint."; exit "$E_DIRPERM"; } +fi +if [ "$PKGMK_UPDATE_SIG" = "yes" ]; then + make_signature > "$PKGMK_ROOT/.signature" || + { error "Failed to update signature."; exit "$E_DIRPERM"; } +fi +if [ "$PKGMK_UPDATE_SIG" = "yes" ] || [ "$PKGMK_UPDATE_FOOTPRINT" = "yes" ]; + then exit 0 +fi + +# All the sources should be here by now, let's verify that we can trust them. +readonly cs_fail_msg="Use '--ignore-signature' to override, if you have determined their integrity by other means." +check_signature "pre-build" | parse_signify_output +case $? in + 0) info "Sources successfully authenticated." ;; + 1) error "Signature file missing or corrupted." ; echo "$cs_fail_msg" ;; + 2) error "Failed to authenticate remote sources using signify." ; echo "$cs_fail_msg" ;; +esac +[ "$PKGMK_CHECK_SIG" = "no" ] || exit 0 # no need to continue if the user only requested -cs + +# What used to be called unpack_source() is now hard-coded into the main routine. +# If you need to shield specific source files from unpacking, use the "renames" +# feature of Pkgfile(5). +errUZ=0 +for (( u=0; u<${#_local_[@]}; u++ )) ; do + here="${_local_[$u]}" + case "$here" in + *.tar|*.tar.gz|*.tar.Z|*.tgz|*.tar.bz2|*.tbz2|*.tar.xz|*.txz|*.tar.lzma|*.tar.lz|*.zip|*.rpm) + [ -d "$here" ] || bsdtar -p -o -C src -xf "$here" || errUZ+=1 ;; + *) + cp -r "$here" src/ ;; + esac +done + +[ $errUZ = 0 ] || { error "Failed to unpack all sources."; exit "$E_UNPACK"; } +[ "$PKGMK_EXTRACT_ONLY" = "yes" ] && exit 0 + +# The actual build step! +if ! (SRC=$(pwd)/src; PKG=$(pwd)/pkg; cd src; set -x; build); then + error "Unsuccessful build!"; exit $E_BUILD +else + info "Build succeeded. Moving on to compression." +fi + +[ -f "$PKGMK_ROOT/$PKGMK_NOSTRIP" ] && ns_filter="| grep -v -f $PKGMK_NOSTRIP" +find pkg -type f $ns_filter | while read -r f; do + case $(file -b "$f") in + *ELF*executable*not\ stripped*) strip --strip-all "$f" ;; + *ELF*shared\ object*not\ stripped*) strip --strip-unneeded "$f" ;; + current\ ar\ archive) strip --strip-debug "$f" ;; + esac +done + +find pkg -type f -path '*/man/man*/*' | grep -v '.gz$' | xargs gzip -9 +find pkg -xtype l -path '*/man/man*/*' -print0 \ + | xargs -x -r -n1 sh -c "ln -sf \"\$(readlink -n '{}')\" '{}'" + +[ $UID = 0 ] || fake_uid="--uid 0 --gid 0" +if (cd pkg; bsdtar --format=gnutar $fake_uid -cf "$pkg_dir$package" *); then + info "Package creation successful." +else + error "Unable to create the compressed package $package." + exit $E_DIRPERM +fi +[ "$pkg_dir" = "$(pwd)/" ] || ln -sf "$pkg_dir$package" . + +# The $work directory now has a symlink to the package, so check its footprint +if ! check_manifest "footprint" ; then + [ "$PKGMK_UPDATE_FOOTPRINT" = "yes" ] && make_manifest "footprint" > "$PKGMK_ROOT"/.footprint + [ "$PKGMK_IGNORE_FOOTPRINT" = "no" ] && exit $E_MANIFEST +fi + +# Fulfill any *explicit* requests for (signed) manifests, then exit +# (disposal of the work directory is retained from the first run of pkgmeek) +[ -f "$PKGMK_ROOT/.signature" ] || [ "$PKGMK_UPDATE_SIG" = "no" ] || \ + warning "Signature not found, creating new." +[ "$PKGMK_UPDATE_SIG" = "no" ] || \ + { make_signature > "$PKGMK_ROOT/.signature" && + echo "Signature successfully created."; } || \ + { make_manifest "md5sum" > "$PKGMK_ROOT"/.md5sum && + warning "Signature creation failed, falling back to md5sums."; } \ + || { info "Could not create signatures or md5sums."; exit "$E_DIRPERM"; } +[ "$PKGMK_UPDATE_MD5" = "no" ] || \ + make_manifest "md5sum" >"$PKGMK_ROOT"/.md5sum || \ + { info "Could not create requested md5sums."; exit "$E_DIRPERM"; } +if [ "$PKGMK_UPDATE_SIG" = "yes" ] || [ "$PKGMK_UPDATE_MD5" = "yes" ]; then + exit 0 +fi + +# Clean up, part 1 +[ "$PKGMK_KEEP_WORK" = "yes" ] || rm -rf src pkg + +# Install if requested +# First find out how the effective user will invoke pkgadd +case $UID in + 0) SUDO="" ;; + *) SUDO="sudo " ;; +esac +[ -z "$SUDO" ] || [ -x $(command -v "$SUDO") ] || SUDO="/usr/bin/doas " +[ -x $(command -v "$SUDO") ] || SUDO="su -c" + +if [ "$PKGMK_INSTALL_COMMAND" ]; then + if ! $SUDO $PKGMK_INSTALL_COMMAND "$package"; then + error "Unable to install $package using pkgadd." + exit $E_INSTALL + fi +fi + +# Clean up, part 2 +[ "$PKGMK_KEEP_WORK" = "yes" ] || [ "$pkg_dir" = "$(pwd)/" ] || rm -f "$package" + +# Done! +} + +####################### error codes ############################## +E_PKGFILE=2 # invalid Pkgfile +E_DIRPERM=3 # (source/build) directory missing or missing read/write permission +E_DOWNLOAD=4 # error during download +E_UNPACK=5 # error during unpacking of source file(s) +E_MANIFEST=7 # footprint or md5sum failure +E_BUILD=8 # error while running 'build()' +E_INSTALL=9 # error while installing the package via 'pkgadd' +E_SIGNATURE=10 # error verifying the signature + +######################## settings ################################ +readonly PKGMK_VERSION="#VERSION#" +readonly PKGMK_COMMAND="$0" +readonly PKGMK_ROOT="$PWD" +readonly PKGMK_SIGNIFY="/usr/bin/signify" +readonly PRTWASH_COMMAND="/usr/bin/prtwash" +readonly PKGMK_GIT_COMMAND="/usr/bin/git" +PKGMK_DOWNLOAD_PROG="/usr/bin/wget" + +PKGMK_CONF="/etc/pkgmk.conf" +PKGMK_SOURCE_DIR="$PWD" +PKGMK_PACKAGE_DIR="$PWD" +PKGMK_WORK_DIR="$PWD/work" +PKGMK_COMPRESSION_MODE="gz" + +PKGMK_INSTALL_COMMAND="" +PKGMK_DOWNLOAD_ONLY="no" +PKGMK_EXTRACT_ONLY="no" +PKGMK_MTIME_ONLY="no" +PKGMK_UPDATE_FOOTPRINT="no" +PKGMK_IGNORE_FOOTPRINT="no" +PKGMK_IGNORE_NEW="no" +PKGMK_FORCE="no" +PKGMK_KEEP_WORK="no" +PKGMK_UPDATE_MD5="no" +PKGMK_IGNORE_MD5="no" +PKGMK_UPDATE_SIG="no" +PKGMK_IGNORE_SIG="no" +PKGMK_REFRESH_SIG="no" +PKGMK_CHECK_SIG="no" +PKGMK_PRIVATEKEY="" +PKGMK_NOSTRIP=".nostrip" + +######################## subroutines ################################ +parse_options() { + while [ "$1" ]; do + case $1 in + -r|--recursive) recursive "$@" ;; + -c|--clean) PKGMK_CLEAN="yes" ;; + -uf|--update-footprint) PKGMK_UPDATE_FOOTPRINT="yes" ;; + -um|--update-md5sum) PKGMK_UPDATE_MD5="yes" ;; + -us|--update-signature) PKGMK_UPDATE_SIG="yes" ;; + -rs|--refresh-signature) PKGMK_REFRESH_SIG="yes" ;; + -cs|--check-signature) PKGMK_CHECK_SIG="yes" ;; + -d|-cm|--download|--check-md5sum) ;; + -do|--download-only) PKGMK_DOWNLOAD_ONLY="yes" ;; + -eo|--extract-only) PKGMK_EXTRACT_ONLY="yes" ;; + -utd|--up-to-date) PKGMK_MTIME_ONLY="yes" ;; + -if|--ignore-footprint) PKGMK_IGNORE_FOOTPRINT="yes" ;; + -in|--ignore-new) PKGMK_IGNORE_NEW="yes" ;; + -im|--ignore-md5sum) PKGMK_IGNORE_MD5="yes" ;; + -is|--ignore-signature) PKGMK_IGNORE_SIG="yes" ;; + -ns|--no-strip) touch "$PKGMK_NOSTRIP" ;; + -f|--force) PKGMK_FORCE="yes" ;; + -kw|--keep-work) PKGMK_KEEP_WORK="yes" ;; + -i|--install) PKGMK_INSTALL_COMMAND="/usr/bin/pkgadd" ;; + -u|--upgrade) PKGMK_INSTALL_COMMAND="/usr/bin/pkgadd -u" ;; + -pk|--public-key) + if [ ! "$2" ]; then + echo "$(basename "$PKGMK_COMMAND"): option $1 requires an argument" + exit 1 + fi + PKGMK_PUBLICKEY="$2" + shift ;; + -sk|--secret-key) + if [ ! "$2" ]; then + echo "$(basename "$PKGMK_COMMAND"): option $1 requires an argument" + exit 1 + fi + PKGMK_PRIVATEKEY="$2" + shift ;; + -cf|--config-file) + if [ ! "$2" ]; then + echo "$(basename "$PKGMK_COMMAND"): option $1 requires an argument" + exit 1 + fi + PKGMK_CONF="$2" + shift ;; + -v|--version) + echo "$(basename "$PKGMK_COMMAND") (pkgutils) $PKGMK_VERSION" + exit 0 ;; + -h|--help) + print_help + exit 0 ;; + *) + echo "$(basename "$PKGMK_COMMAND"): invalid option $1" + exit 1 ;; + esac + shift + done +} + +print_help() { + echo "usage: $(basename "$PKGMK_COMMAND") [options]" + echo "options: " + echo " -r, --recursive search for Pkgfiles under $PWD, and run $(basename "$PKGMK_COMMAND")" + echo " with the other given options inside each directory found" + echo " -c, --clean remove package and downloaded files" + echo " -i, --install build and install package" + echo " -u, --upgrade build and install package (as upgrade)" + echo " -do, --download-only stop after downloading all the necessary source file(s)" + echo " -eo, --extract-only stop after downloading and extracting source file(s)" + echo " -utd, --up-to-date check whether the built package is up to date, then exit" + echo " -uf, --update-footprint update footprint using result from last build" + echo " -if, --ignore-footprint build package without checking footprint" + echo " -in, --ignore-new build package, ignoring new files in a footprint mismatch" + echo " -um, --update-md5sum update md5sum" + echo " -im, --ignore-md5sum build package without checking md5sum" + echo " -cs, --check-signature verify the signatures, do not proceed with the build" + echo " -us, --update-signature update signatures only, do not proceed with the build" + echo " -is, --ignore-signature build package without checking the signature" + echo " -rs, --refresh-signature create new signature and keep existing sha256 checksums" + echo " -sk, --secret-key use to sign the port" + echo " -pk, --public-key check the port signature using public-key " + echo " -ns, --no-strip do not strip executable binaries or libraries" + echo " -f, --force build package even if it appears to be up to date" + echo " -kw, --keep-work keep temporary working directory" + echo " -cf, --config-file use alternative configuration file" + echo " -v, --version print version and exit" + echo " -h, --help print help and exit" +} + +validate_pkgfile() { # called from within PKGMK_ROOT + local errcode nn nv nr nb + check_signature "pre-Pkgfile" | parse_signify_output + errcode=$? + [ "$errcode" = 0 ] || info "Use '-is' if you have confirmed its origin some other way." + [ "$errcode" = 0 ] || [ "$PKGMK_IGNORE_SIG" = "yes" ] || exit $E_SIGNATURE + + # the environment should not be affected by sourcing the Pkgfile both here + # and in the later build, but to be safe we use a nested subshell + ( . Pkgfile; [ -n "$name" ] || nn=1; [ -n "$version" ] || nv=1; \ + [ -n "$release" ] || nr=1; [ "$(type -t build)" = "function" ] || nb=1; \ + echo $(( nn+2*nv+4*nr+8*nb )) ) | check_required_vars +} + +check_required_vars() { + local checksum absent v + read -r checksum + + [ $((checksum & 1)) = 1 ] && absent=("'name'") + [ $((checksum & 2)) = 2 ] && absent=("${absent[@]}" "'version'") + [ $((checksum & 4)) = 4 ] && absent=("${absent[@]}" "'release'") + [ $((checksum & 8)) = 8 ] && absent=("${absent[@]}" "'build()'") + + if [ "$checksum" -gt 0 ]; then + error "Pkgfile does not specify these required variables:" + for v in "${absent[@]}"; do + echo -n "$v " + done + echo; exit $E_PKGFILE + fi +} + +check_pkg_mtime() { # only called before a build attempt, not again after a successful build + local status=1; local li=0; local pkg_ood="yes" + + if [ -f "$package" ]; then + pkg_ood="no" + while [ $li -lt ${#_local_[@]} ] && [ "$pkg_ood" = "no" ]; do + [ ! -e "${_local_[$li]}" ] || [ "$package" -nt "${_local_[$li]}" ] || pkg_ood="yes" + li=$(( li+1 )) + done + [ ! -e Pkgfile ] || [ "$package" -nt Pkgfile ] || pkg_ood="yes" + fi + + if [ "$pkg_ood" = "no" ]; then + status=0; info "$package is up to date." + else + [ "$PKGMK_CHECK_SIG" = "yes" ] || info "$package is not up to date." + fi + return $status +} + +make_manifest() { + case "$1" in + footprint) + pkginfo --footprint "$package" \ + | sed "s|\tlib/modules/$(uname -r)/|\tlib/modules//|g" \ + | sort -k 3 + ;; + md5sum) + [ ! -e "$PKGMK_ROOT/.signature" ] || [ "$PKGMK_UPDATE_MD5" = "yes" ] || return + md5sum "${_local_[@]}" 2>&1 \ + | grep -v "is a directory" | sed 's, .*/, ,' | sort -k 2 + ;; + esac +} + +check_manifest() { + local FILTER TRUTH CN CM + local FILE="$1.tmp"; local retval=0 + [ ! -f "$package" ] && { error "$package not found. Cannot check $1."; + return "$E_MANIFEST"; } + [ "$1" = "md5sum" ] && FILTER="| sort -k 3" || FILTER="" + TRUTH="$PKGMK_ROOT/.$1" + + make_manifest $1 $FILTER > "$FILE" + if [ -f "$TRUTH" ]; then + cat "$TRUTH" $FILTER > "${FILE%tmp}orig" + diff -w -t -U 0 <(sort "${FILE%tmp}orig") <(sort "${FILE}") | \ + sed '/^@@/d; /^+++/d; /^---/d; s/^+/NEW /g; s/^-/MISSING /g' \ + > "${FILE%tmp}diff" + if [ -s "${FILE%tmp}diff" ]; then + error "$1 mismatch found:" + cat "${FILE%tmp}diff" >&2 + CN=$(grep -c ^NEW "${FILE%tmp}diff") + CM=$(grep -c ^MISSING "${FILE%tmp}diff") + if [ "$1" = "footprint" ]; then + [ "$PKGMK_IGNORE_NEW" = "yes" ] || retval+=$CN + [ "$PKGMK_IGNORE_MISSING" = "yes" ] || retval+=$CM + retval=$(( E_MANIFEST*( retval>0 ) )) + else + retval=$E_MANIFEST + fi + fi + else + warning ".$1 not found, creating new."; mv "$FILE" "$TRUTH" + fi + return $retval +} + +parse_signify_output() { # chomps the output of check_signature() + local signout signerr + [ "$PKGMK_IGNORE_SIG" = "yes" ] && return 0 + while read -r signout; do + case "$signout" in + *"verification failed") + signerr=1; echo "Signature file corrupted or unreadable." + ;; + *"FAIL") + signerr=2; echo "Signature mismatch found:" + echo "$signout" | awk -F: '/FAIL/ {printf "MISMATCH %s\n", $1}' + ;; + esac + done + return $signerr +} + +check_signature() { + # called from within the src subdir unless "when"="pre-Pkgfile". + # Pass control to check_manifest() if the signature is missing and + # "ignore-md5" has not been requested. + local reqfiles s + local when="$1" + [ "$PKGMK_IGNORE_SIG" = "yes" ] && echo; return + + if [ -f "$PKGMK_ROOT/.signature" ]; then + [ "$when" = "pre-Pkgfile" ] && reqfiles=(Pkgfile) || reqfiles=(.footprint) + while [ "$when" = "pre-build" ] && [ $s -le ${#_local_[@]} ]; do + [[ "${source[$s]}" =~ ^(http|https|git).*/\.git ]] || \ + reqfiles=("${reqfiles[@]}" "${_local_[$s]}") + s=$(( s+1 )) + done + for FILE in "${reqfiles[@]}" "${_local_[@]}"; do + [ -e "$FILE" ] || ln -sf "$PKGMK_ROOT/$FILE" . + done + if [ -f "$PKGMK_PUBLICKEY" ]; then + $PKGMK_SIGNIFY -q -C -p "$PKGMK_PUBLICKEY" -x "$PKGMK_ROOT/.signature" \ + "${reqfiles[@]}" 2>&1 + else + $PKGMK_SIGNIFY -q -C -x "$PKGMK_ROOT/.signature" \ + "${reqfiles[@]}" 2>&1 + fi + else + [ "$when" = "pre-Pkgfile" ] || [ "$PKGMK_IGNORE_MD5" = "yes" ] || \ + { info "Signature not found, falling back to old md5sum checking."; + check_manifest "md5sum" ; } + fi + # remove soft links + [ "$when" = "post-build" ] && find . -maxdepth 1 -mindepth 1 -type l -delete +} + +make_signature() { + for key in ~/.ssh/*.sec /etc/ports/*.sec; do + [[ -e "$key" ]] || continue # workaround for brain-dead shell globbing + pub=/etc/ports/$(basename "${key/%.sec/.pub}") + if [ -e "$pub" ]; then + pub=$(readlink -f "$pub") + ordered=() + for f in "${source[@]}"; do ordered+=("${_local_[$f]}"); done + sha256sum --tag Pkgfile .footprint "${ordered[@]}" \ + | sed 's|^SHA256 (.*/\(.*\))\(.* = .*\)|SHA256 (\1)\2|' \ + | signify -S -e -x - -q -s "$key" -m - \ + | sed "s|${key/%.sec/.pub}|$pub|" + break + fi + done +} + +refresh_signature() { + if [ -e ".signature" ] && [ ! -w ".signature" ]; then + echo "error: .signature not writable." + return $E_SIGNATURE + fi + + local REPO + [ -n "$PKGMK_PRIVATEKEY" ] || REPO=$(dirname "$PWD" | sed 's|^.*/||; s|\.git$||;') + [ -n "$REPO" ] && PKGMK_PRIVATEKEY="/etc/ports/${REPO}.sec" + + if ! tail -n +3 ".signature" | $PKGMK_SIGNIFY -S -e -x - -q \ + -s "$PKGMK_PRIVATEKEY" -m - > .signature.tmp ; then + rm .signature.tmp + error "Refreshing signature failed" + return $E_SIGNATURE + else + mv .signature.tmp .signature + fi +} + +recursive() { + local ARGS FILE DIR + [ "$PKGMK_CLEAN" == "no" ] || { find "$PKGMK_ROOT" -name Pkgfile \ + -printf "%h\n" | xargs "$PRTWASH_COMMAND" -s -p -b ; exit $? ; } + + ARGS=$(echo "$@" | sed -e "s/--recursive//g; s/[ ]+-r[ ]+/ /g") + for FILE in $(find "$PKGMK_ROOT" -name Pkgfile | sort); do + DIR="$(dirname "$FILE")/" + if [ -d "$DIR" ]; then + info "Entering directory '$DIR'." + (cd "$DIR" && "$PKGMK_COMMAND" "$ARGS") + info "Leaving directory '$DIR'." + fi + done +} + +info() { + echo "=======> $1" +} + +warning() { + info "WARNING: $1" >&2 +} + +error() { + info "ERROR: $1" >&2 +} + +######################## end of subroutines ########################### +## Now ensure that they cannot be overwritten when sourcing Pkgfile ## +readonly -f main parse_options print_help validate_pkgfile check_required_vars \ + check_pkg_mtime make_manifest check_manifest check_signature make_signature \ + parse_signify_output refresh_signature recursive + +main "$@"