diff options
author | bill-auger <mr.j.spam.me@gmail.com> | 2020-07-14 09:45:44 -0400 |
---|---|---|
committer | bill-auger <mr.j.spam.me@gmail.com> | 2020-11-20 22:53:30 -0500 |
commit | 3c86b7cd19def6c0b9c41ab8868ff3c07bf742a3 (patch) | |
tree | 29cd8e5419d68afb45b13bed691ef030f5e78cfb | |
parent | d3a4b74c817fc8aa7fbcc67195ac2af3f1c7d66b (diff) |
whitespace
-rwxr-xr-x | src/abslibre-tools/librerelease | 434 | ||||
-rwxr-xr-x | src/chroot-tools/librechroot | 915 | ||||
-rwxr-xr-x | src/chroot-tools/libremakepkg | 500 | ||||
-rw-r--r-- | src/lib/conf.sh.in | 340 | ||||
-rwxr-xr-x | src/lib/libremessages | 8 | ||||
-rwxr-xr-x | src/librefetch/librefetch | 566 | ||||
-rwxr-xr-x | src/pkgbuild-summarize-nonfree | 122 |
7 files changed, 1440 insertions, 1445 deletions
diff --git a/src/abslibre-tools/librerelease b/src/abslibre-tools/librerelease index c8518fb..83898af 100755 --- a/src/abslibre-tools/librerelease +++ b/src/abslibre-tools/librerelease @@ -47,266 +47,266 @@ setup_traps dryrun="" upload_only=false readonly rsync_flags=( - --no-group - --no-perms - --copy-links - --hard-links - --partial - --human-readable - --progress + --no-group + --no-perms + --copy-links + --hard-links + --partial + --human-readable + --progress ) # Functions #################################################################### list0_files() { - find -L "${WORKDIR}/staging" -type f -not -name '*.lock' \ - -exec realpath -z --relative-to="${WORKDIR}/staging" {} + + find -L "${WORKDIR}/staging" -type f -not -name '*.lock' \ + -exec realpath -z --relative-to="${WORKDIR}/staging" {} + } # This function is taken almost verbatim from makepkg create_signature() { - local ret=$EXIT_SUCCESS - local filename="$1" - msg "Signing package..." + local ret=$EXIT_SUCCESS + local filename="$1" + msg "Signing package..." - local SIGNWITHKEY=() - if [[ -n $GPGKEY ]]; then - SIGNWITHKEY=(-u "${GPGKEY}") - fi + local SIGNWITHKEY=() + if [[ -n $GPGKEY ]]; then + SIGNWITHKEY=(-u "${GPGKEY}") + fi - gpg --detach-sign --use-agent "${SIGNWITHKEY[@]}" --no-armor "$filename" &>/dev/null || ret=$EXIT_FAILURE + gpg --detach-sign --use-agent "${SIGNWITHKEY[@]}" --no-armor "$filename" &>/dev/null || ret=$EXIT_FAILURE - if (( ! ret )); then - msg2 "Created signature file %s." "$filename.sig" - else - error "Failed to sign package file." - return $ret - fi + if (( ! ret )); then + msg2 "Created signature file %s." "$filename.sig" + else + error "Failed to sign package file." + return $ret + fi } sign_packages() { - IFS=$'\n' - local files=($(find "${WORKDIR}/staging/" -type f -not -iname '*.sig' -print)) - local file - for file in "${files[@]}"; do - if [[ -f "${file}.sig" ]]; then - msg2 "File signature found, verifying..." - - # Verify that the signature is correct, else remove for re-signing - if ! gpg --quiet --verify "${file}.sig" >/dev/null 2>&1; then - error "Failed! Re-signing..." - rm -f "${file}.sig" - fi - fi - - if ! [[ -f "${file}.sig" ]]; then - create_signature "$file" || return - fi - done + IFS=$'\n' + local files=($(find "${WORKDIR}/staging/" -type f -not -iname '*.sig' -print)) + local file + for file in "${files[@]}"; do + if [[ -f "${file}.sig" ]]; then + msg2 "File signature found, verifying..." + + # Verify that the signature is correct, else remove for re-signing + if ! gpg --quiet --verify "${file}.sig" >/dev/null 2>&1; then + error "Failed! Re-signing..." + rm -f "${file}.sig" + fi + fi + + if ! [[ -f "${file}.sig" ]]; then + create_signature "$file" || return + fi + done } # Clean everything if not in dry-run mode clean_files() ( - local file_list=$1 - - local rmcmd=(rm -fv) - if [[ -n "${dryrun}" ]]; then - rmcmd=(printf "$(_ "removed '%s' (dry-run)")\n") - fi - - msg "Removing files from local staging directory" - cd "${WORKDIR}/staging" - xargs -0r -a "$file_list" "${rmcmd[@]}" - find . -depth -mindepth 1 -type d \ - -exec rmdir --ignore-fail-on-non-empty -- '{}' + + local file_list=$1 + + local rmcmd=(rm -fv) + if [[ -n "${dryrun}" ]]; then + rmcmd=(printf "$(_ "removed '%s' (dry-run)")\n") + fi + + msg "Removing files from local staging directory" + cd "${WORKDIR}/staging" + xargs -0r -a "$file_list" "${rmcmd[@]}" + find . -depth -mindepth 1 -type d \ + -exec rmdir --ignore-fail-on-non-empty -- '{}' + ) ################################################################################ usage() { - print "Usage: %s [OPTIONS]" "${0##*/}" - print 'Upload packages in $WORKDIR/staging to the Parabola server' - echo - print "Options:" - flag '-c' 'Clean; delete packages in $WORKDIR/staging' - flag '-l' "List; list packages but not upload them" - flag '-u' "Upload-only; do not run db-update on the server" - - flag '-n' "Dry-run; don't actually do anything" - flag '-h' "Show this message" + print "Usage: %s [OPTIONS]" "${0##*/}" + print 'Upload packages in $WORKDIR/staging to the Parabola server' + echo + print "Options:" + flag '-c' 'Clean; delete packages in $WORKDIR/staging' + flag '-l' "List; list packages but not upload them" + flag '-u' "Upload-only; do not run db-update on the server" + + flag '-n' "Dry-run; don't actually do anything" + flag '-h' "Show this message" } main() { - if [[ -w / ]]; then - error "This program should be run as regular user" - return $EXIT_NOPERMISSION - fi - - # Parse options - local mode="release_packages" - while getopts 'clunh' arg; do - case $arg in - c) mode=clean ;; - l) mode=pretty_print_packages ;; - u) upload_only=true ;; - n) dryrun="--dry-run" ;; - h) mode=usage ;; - *) usage >&2; return $EXIT_INVALIDARGUMENT ;; - esac - done - shift $((OPTIND - 1)) - if [[ $# != 0 ]]; then - usage >&2 - return $EXIT_INVALIDARGUMENT - fi - - if [[ $mode == usage ]]; then - usage - return $EXIT_SUCCESS - fi - - declare -i ret=0 - load_conf makepkg.conf GPGKEY || ret=$? - load_conf libretools.conf WORKDIR REPODEST DBSCRIPTS_CONFIG || ret=$? # and HOOK{PRE,POST}RELEASE, which are optional - [[ $ret = 0 ]] || exit $ret - - local re_url='^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$' - local re_authority='^(([^@]*)@)?([^][@:]*|\[[^]]*\])(:([0-9]*))?$' - local REPODEST_ok=false - if [[ "$REPODEST" =~ $re_url ]]; then - REPODEST_ok=true - - REPODEST_scheme=${BASH_REMATCH[2]} - REPODEST_authority=${BASH_REMATCH[4]} - REPODEST_path=${BASH_REMATCH[5]} - REPODEST_query=${BASH_REMATCH[7]} - REPODEST_fragment=${BASH_REMATCH[9]} - - if [[ "$REPODEST_authority" =~ $re_authority ]]; then - REPODEST_userinfo=${BASH_REMATCH[2]} - REPODEST_host=${BASH_REMATCH[3]} - REPODEST_port=${BASH_REMATCH[5]} - - if [[ "$REPODEST_host" = '['*']' ]]; then - REPODEST_host=${REPODEST_HOST#'['} - REPODEST_host=${REPODEST_HOST#']'} - fi - else - REPODEST_ok=false - fi - - [[ $REPODEST_scheme == ssh ]] || REPODEST_ok=false - [[ -n $REPODEST_host ]] || REPODEST_ok=false - [[ -n $REPODEST_path ]] || REPODEST_ok=false - fi - if ! $REPODEST_ok; then - error 'The format of libretools.conf:REPODEST has changed.' - plain 'Merge the /etc/libretools.conf.pacnew file!' - return $EXIT_NOTCONFIGURED - fi - if [[ "$REPODEST_path" = '/~'* ]]; then - if [[ "$REPODEST_path" = '/~/'* ]]; then - REPODEST_path=${REPODEST_path#'/~/'} - else - error 'Unfortunately, `~user` home-directory expansion is not (yet?) supported in libretools.conf:REPODEST' - return $EXIT_NOTCONFIGURED - fi - fi - REPODEST_userhost="${REPODEST_userinfo:+${REPODEST_userinfo%%:*}@}${REPODEST_host}" - - "$mode" + if [[ -w / ]]; then + error "This program should be run as regular user" + return $EXIT_NOPERMISSION + fi + + # Parse options + local mode="release_packages" + while getopts 'clunh' arg; do + case $arg in + c) mode=clean ;; + l) mode=pretty_print_packages ;; + u) upload_only=true ;; + n) dryrun="--dry-run" ;; + h) mode=usage ;; + *) usage >&2; return $EXIT_INVALIDARGUMENT ;; + esac + done + shift $((OPTIND - 1)) + if [[ $# != 0 ]]; then + usage >&2 + return $EXIT_INVALIDARGUMENT + fi + + if [[ $mode == usage ]]; then + usage + return $EXIT_SUCCESS + fi + + declare -i ret=0 + load_conf makepkg.conf GPGKEY || ret=$? + load_conf libretools.conf WORKDIR REPODEST DBSCRIPTS_CONFIG || ret=$? # and HOOK{PRE,POST}RELEASE, which are optional + [[ $ret = 0 ]] || exit $ret + + local re_url='^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$' + local re_authority='^(([^@]*)@)?([^][@:]*|\[[^]]*\])(:([0-9]*))?$' + local REPODEST_ok=false + if [[ "$REPODEST" =~ $re_url ]]; then + REPODEST_ok=true + + REPODEST_scheme=${BASH_REMATCH[2]} + REPODEST_authority=${BASH_REMATCH[4]} + REPODEST_path=${BASH_REMATCH[5]} + REPODEST_query=${BASH_REMATCH[7]} + REPODEST_fragment=${BASH_REMATCH[9]} + + if [[ "$REPODEST_authority" =~ $re_authority ]]; then + REPODEST_userinfo=${BASH_REMATCH[2]} + REPODEST_host=${BASH_REMATCH[3]} + REPODEST_port=${BASH_REMATCH[5]} + + if [[ "$REPODEST_host" = '['*']' ]]; then + REPODEST_host=${REPODEST_HOST#'['} + REPODEST_host=${REPODEST_HOST#']'} + fi + else + REPODEST_ok=false + fi + + [[ $REPODEST_scheme == ssh ]] || REPODEST_ok=false + [[ -n $REPODEST_host ]] || REPODEST_ok=false + [[ -n $REPODEST_path ]] || REPODEST_ok=false + fi + if ! $REPODEST_ok; then + error 'The format of libretools.conf:REPODEST has changed.' + plain 'Merge the /etc/libretools.conf.pacnew file!' + return $EXIT_NOTCONFIGURED + fi + if [[ "$REPODEST_path" = '/~'* ]]; then + if [[ "$REPODEST_path" = '/~/'* ]]; then + REPODEST_path=${REPODEST_path#'/~/'} + else + error 'Unfortunately, `~user` home-directory expansion is not (yet?) supported in libretools.conf:REPODEST' + return $EXIT_NOTCONFIGURED + fi + fi + REPODEST_userhost="${REPODEST_userinfo:+${REPODEST_userinfo%%:*}@}${REPODEST_host}" + + "$mode" } # The different modes (sans 'usage') ########################################### pretty_print_packages() { - find "$WORKDIR/staging/" -mindepth 1 -maxdepth 1 -type d -not -empty | sort | - while read -r path; do - msg2 "${path##*/}" - cd "$path" - find -L . -type f -not -name '*.lock' | sed 's|^\./| |' | sort - done + find "$WORKDIR/staging/" -mindepth 1 -maxdepth 1 -type d -not -empty | sort | + while read -r path; do + msg2 "${path##*/}" + cd "$path" + find -L . -type f -not -name '*.lock' | sed 's|^\./| |' | sort + done } clean() { - lock 8 "${WORKDIR}/staging.lock" \ - 'Waiting for an exclusive lock on the staging directory' + lock 8 "${WORKDIR}/staging.lock" \ + 'Waiting for an exclusive lock on the staging directory' - local file_list - file_list="$(mktemp -t "${0##*/}.XXXXXXXXXX")" - trap "rm -f -- ${file_list@Q}" EXIT - list0_files > "$file_list" + local file_list + file_list="$(mktemp -t "${0##*/}.XXXXXXXXXX")" + trap "rm -f -- ${file_list@Q}" EXIT + list0_files > "$file_list" - lock_close 8 + lock_close 8 - clean_files "$file_list" + clean_files "$file_list" } release_packages() { - if [[ -n $HOOKPRERELEASE ]]; then - msg "Running HOOKPRERELEASE..." - ( - PS4=" \\[$BOLD\\]\$\\[$ALL_OFF\\] " - eval -- "set -x; $HOOKPRERELEASE" - ) - fi - - lock 8 "${WORKDIR}/staging.lock" \ - 'Waiting for an exclusive lock on the staging directory' - - sign_packages || return - - # Make the permissions of the packages 644 otherwise the user will get access - # denied error when they try to download (rsync --no-perms doesn't seem to - # work). - find "${WORKDIR}/staging" -type f -exec chmod 644 {} + - find "${WORKDIR}/staging" -type d -exec chmod 755 {} + - - local file_list="$(mktemp -t ${0##*/}.XXXXXXXXXX)" - trap "rm -f -- ${file_list@Q}" EXIT - list0_files > "$file_list" - - lock_close 8 - - msg "%s to upload" "$(cd "${WORKDIR}/staging" && du -hc --files0-from="$file_list" | sed -n '$s/\t.*//p')" - msg "Uploading packages..." - xargs -0r -a "$file_list" dirname -z | ssh ${REPODEST_port:+-p "$REPODEST_port"} "${REPODEST_userhost}" "mkdir -p -- ${REPODEST_path@Q} && cd ${REPODEST_path@Q} && xargs -0r mkdir -pv --" - if ! rsync ${dryrun} "${rsync_flags[@]}" \ - -e "ssh ${REPODEST_port:+-p $REPODEST_port}" \ - -0 --files-from="$file_list" \ - "${WORKDIR}/staging" \ - "$REPODEST_userhost:$REPODEST_path/" - then - error "Sync failed, try again" - return $EXIT_FAILURE - fi - - clean_files "$file_list" - - if $upload_only; then - return $EXIT_SUCCESS - fi - - msg "Running db-update on repos" - ssh ${REPODEST_port:+-p "$REPODEST_port"} "${REPODEST_userhost}" "STAGING=${REPODEST_path@Q} DBSCRIPTS_CONFIG=${DBSCRIPTS_CONFIG@Q} db-update" - - if [[ -n $HOOKPOSTRELEASE ]]; then - msg "Running HOOKPOSTRELEASE..." - ( - PS4=" \\[$BOLD\\]\$\\[$ALL_OFF\\] " - eval -- "set -x; $HOOKPOSTRELEASE" - ) - fi - - # notify pbot of the excellent work we have done - local packages=$(grep -E '\.pkg\.tar\.[^\.]+$' ${file_list} | sed 's|.*/\([^/ ]*\)/[^\ ]*$|\1|' | xargs) - local login=${REPODEST_userinfo:-somebody} ; login=${login%%:*} ; - local pbot_say_cmd="which pbot-say && pbot-say ${login} just published: ${packages}" - ssh ${REPODEST_port:+-p "$REPODEST_port"} "${REPODEST_userhost}" "${pbot_say_cmd}" - - return $EXIT_SUCCESS + if [[ -n $HOOKPRERELEASE ]]; then + msg "Running HOOKPRERELEASE..." + ( + PS4=" \\[$BOLD\\]\$\\[$ALL_OFF\\] " + eval -- "set -x; $HOOKPRERELEASE" + ) + fi + + lock 8 "${WORKDIR}/staging.lock" \ + 'Waiting for an exclusive lock on the staging directory' + + sign_packages || return + + # Make the permissions of the packages 644 otherwise the user will get access + # denied error when they try to download (rsync --no-perms doesn't seem to + # work). + find "${WORKDIR}/staging" -type f -exec chmod 644 {} + + find "${WORKDIR}/staging" -type d -exec chmod 755 {} + + + local file_list="$(mktemp -t ${0##*/}.XXXXXXXXXX)" + trap "rm -f -- ${file_list@Q}" EXIT + list0_files > "$file_list" + + lock_close 8 + + msg "%s to upload" "$(cd "${WORKDIR}/staging" && du -hc --files0-from="$file_list" | sed -n '$s/\t.*//p')" + msg "Uploading packages..." + xargs -0r -a "$file_list" dirname -z | ssh ${REPODEST_port:+-p "$REPODEST_port"} "${REPODEST_userhost}" "mkdir -p -- ${REPODEST_path@Q} && cd ${REPODEST_path@Q} && xargs -0r mkdir -pv --" + if ! rsync ${dryrun} "${rsync_flags[@]}" \ + -e "ssh ${REPODEST_port:+-p $REPODEST_port}" \ + -0 --files-from="$file_list" \ + "${WORKDIR}/staging" \ + "$REPODEST_userhost:$REPODEST_path/" + then + error "Sync failed, try again" + return $EXIT_FAILURE + fi + + clean_files "$file_list" + + if $upload_only; then + return $EXIT_SUCCESS + fi + + msg "Running db-update on repos" + ssh ${REPODEST_port:+-p "$REPODEST_port"} "${REPODEST_userhost}" "STAGING=${REPODEST_path@Q} DBSCRIPTS_CONFIG=${DBSCRIPTS_CONFIG@Q} db-update" + + if [[ -n $HOOKPOSTRELEASE ]]; then + msg "Running HOOKPOSTRELEASE..." + ( + PS4=" \\[$BOLD\\]\$\\[$ALL_OFF\\] " + eval -- "set -x; $HOOKPOSTRELEASE" + ) + fi + + # notify pbot of the excellent work we have done + local packages=$(grep -E '\.pkg\.tar\.[^\.]+$' ${file_list} | sed 's|.*/\([^/ ]*\)/[^\ ]*$|\1|' | xargs) + local login=${REPODEST_userinfo:-somebody} ; login=${login%%:*} ; + local pbot_say_cmd="which pbot-say && pbot-say ${login} just published: ${packages}" + ssh ${REPODEST_port:+-p "$REPODEST_port"} "${REPODEST_userhost}" "${pbot_say_cmd}" + + return $EXIT_SUCCESS } main "$@" diff --git a/src/chroot-tools/librechroot b/src/chroot-tools/librechroot index ae01e51..f7921bf 100755 --- a/src/chroot-tools/librechroot +++ b/src/chroot-tools/librechroot @@ -47,66 +47,66 @@ umask 0022 # Usage: detect_chroot_arch $makepkg_conf detect_chroot_arch() { - local makepkg_conf="$1" - local chroot_arch + local makepkg_conf="$1" + local chroot_arch - chroot_arch=$(grep -a '^CARCH=' "$makepkg_conf" 2> /dev/null | cut -d '=' -f 2 | tr -d '"') - [[ ${chroot_arch} =~ x86_64|i686|armv7h ]] || chroot_arch=$(uname -m) + chroot_arch=$(grep -a '^CARCH=' "$makepkg_conf" 2> /dev/null | cut -d '=' -f 2 | tr -d '"') + [[ ${chroot_arch} =~ x86_64|i686|armv7h ]] || chroot_arch=$(uname -m) - echo ${chroot_arch} + echo ${chroot_arch} } # Usage: make_empty_repo $copydir make_empty_repo() { - local copydir=$1 - mkdir -p "${copydir}/repo" - bsdtar -czf "${copydir}/repo/repo.db.tar.gz" -T /dev/null - ln -s "repo.db.tar.gz" "${copydir}/repo/repo.db" + local copydir=$1 + mkdir -p "${copydir}/repo" + bsdtar -czf "${copydir}/repo/repo.db.tar.gz" -T /dev/null + ln -s "repo.db.tar.gz" "${copydir}/repo/repo.db" } # Usage: chroot_add_to_local_repo $copydir $pkgfiles... chroot_add_to_local_repo() { - local copydir=$1; shift - mkdir -p "$copydir/repo" - local pkgfile - for pkgfile in "$@"; do - cp "$pkgfile" "$copydir/repo" - pushd "$copydir/repo" >/dev/null - repo-add repo.db.tar.gz "${pkgfile##*/}" - popd >/dev/null - done + local copydir=$1; shift + mkdir -p "$copydir/repo" + local pkgfile + for pkgfile in "$@"; do + cp "$pkgfile" "$copydir/repo" + pushd "$copydir/repo" >/dev/null + repo-add repo.db.tar.gz "${pkgfile##*/}" + popd >/dev/null + done } # Print code to set $rootdir and $copydir; blank them on error calculate_directories() { - # Don't assume that CHROOTDIR or CHROOT are set, - # but assume that COPY is set. - local rootdir copydir - - if [[ -n ${CHROOTDIR:-} ]] && [[ -n ${CHROOT:-} ]]; then - rootdir="${CHROOTDIR}/${CHROOT}/root" - else - rootdir='' - fi - - if [[ ${COPY:0:1} = / ]]; then - copydir=$COPY - elif [[ -n ${CHROOTDIR:-} ]] && [[ -n ${CHROOT:-} ]]; then - copydir="${CHROOTDIR}/${CHROOT}/${COPY}" - else - copydir='' - fi - - declare -p rootdir - declare -p copydir + # Don't assume that CHROOTDIR or CHROOT are set, + # but assume that COPY is set. + local rootdir copydir + + if [[ -n ${CHROOTDIR:-} ]] && [[ -n ${CHROOT:-} ]]; then + rootdir="${CHROOTDIR}/${CHROOT}/root" + else + rootdir='' + fi + + if [[ ${COPY:0:1} = / ]]; then + copydir=$COPY + elif [[ -n ${CHROOTDIR:-} ]] && [[ -n ${CHROOT:-} ]]; then + copydir="${CHROOTDIR}/${CHROOT}/${COPY}" + else + copydir='' + fi + + declare -p rootdir + declare -p copydir } check_mountpoint() { - local file=$1 - local mountpoint mountopts - mountpoint="$(df -P "$file"|sed '1d;s/.*\s//')" - mountopts=($(LC_ALL=C mount|awk "{ if (\$3==\"$mountpoint\") { gsub(/[(,)]/, \" \", \$6); print \$6 } }")) - ! in_array nosuid "${mountopts[@]}" && ! in_array noexec "${mountopts[@]}" + local file=$1 + local mountpoint mountopts + mountpoint="$(df -P "$file"|sed '1d;s/.*\s//')" + mountopts=($(LC_ALL=C mount|awk "{ if (\$3==\"$mountpoint\") { gsub(/[(,)]/, \" \", \$6); print \$6 } }")) + ! in_array nosuid "${mountopts[@]}" && ! in_array noexec "${mountopts[@]}" } @@ -122,87 +122,87 @@ sysd_nspawn_flags=() hack_arch_nspawn_flags() { - local copydir="$1" - local makepkg_conf="$copydir/etc/makepkg.conf" - - OPTIND=1 - set -- "${arch_nspawn_flags[@]}" - while getopts 'hC:M:c:f:s' arg; do - case "$arg" in - M) makepkg_conf="$OPTARG" ;; - *) :;; - esac - done - - local CARCH=$(detect_chroot_arch "$makepkg_conf") - local setarch interpreter - - case $CARCH in - armv7h|armv7l) setarch=armv7l; interpreter=/usr/bin/qemu-arm-static ;; - *) setarch=$CARCH; interpreter=/usr/bin/qemu-$CARCH-static ;; - esac - if ! setarch $setarch /bin/true 2>/dev/null; then - # We're running a cross-arch chroot - - # Make sure that qemu-static is set up with binfmt_misc - if [[ -z $(grep -l -xF \ - -e "interpreter $interpreter" \ - -r -- /proc/sys/fs/binfmt_misc 2>/dev/null \ - | xargs -r grep -xF 'enabled') ]] - then - error 'Cannot cross-compile for %s on %s' "$CARCH" "$(uname -m)" - plain 'This requires a binfmt_misc entry for %s.' "$interpreter" - prose 'Such a binfmt_misc entry is provided by the %s - package. If you have it installed, but still see - this message, you may need to restart %s.' \ - qemu-user-static-binfmt systemd-binfmt.service - return $EXIT_NOTINSTALLED - fi - - # Let qemu/binfmt_misc do its thing - arch_nspawn_flags+=(-f "$interpreter" -s) - fi + local copydir="$1" + local makepkg_conf="$copydir/etc/makepkg.conf" + + OPTIND=1 + set -- "${arch_nspawn_flags[@]}" + while getopts 'hC:M:c:f:s' arg; do + case "$arg" in + M) makepkg_conf="$OPTARG" ;; + *) :;; + esac + done + + local CARCH=$(detect_chroot_arch "$makepkg_conf") + local setarch interpreter + + case $CARCH in + armv7h|armv7l) setarch=armv7l; interpreter=/usr/bin/qemu-arm-static ;; + *) setarch=$CARCH; interpreter=/usr/bin/qemu-$CARCH-static ;; + esac + if ! setarch $setarch /bin/true 2>/dev/null; then + # We're running a cross-arch chroot + + # Make sure that qemu-static is set up with binfmt_misc + if [[ -z $(grep -l -xF \ + -e "interpreter $interpreter" \ + -r -- /proc/sys/fs/binfmt_misc 2>/dev/null \ + | xargs -r grep -xF 'enabled') ]] + then + error 'Cannot cross-compile for %s on %s' "$CARCH" "$(uname -m)" + plain 'This requires a binfmt_misc entry for %s.' "$interpreter" + prose 'Such a binfmt_misc entry is provided by the %s + package. If you have it installed, but still see + this message, you may need to restart %s.' \ + qemu-user-static-binfmt systemd-binfmt.service + return $EXIT_NOTINSTALLED + fi + + # Let qemu/binfmt_misc do its thing + arch_nspawn_flags+=(-f "$interpreter" -s) + fi } # Usage: arch-nspawn $copydir $cmd... arch-nspawn() { - local copydir=$1; shift - local cmd=("$@") - - local arch_nspawn_flags=("${arch_nspawn_flags[@]}") - hack_arch_nspawn_flags "$copydir" - - "$_arch_nspawn" \ - "${arch_nspawn_flags[@]}" \ - "$copydir" \ - "${sysd_nspawn_flags[@]}" \ - -- \ - "${cmd[@]}" + local copydir=$1; shift + local cmd=("$@") + + local arch_nspawn_flags=("${arch_nspawn_flags[@]}") + hack_arch_nspawn_flags "$copydir" + + "$_arch_nspawn" \ + "${arch_nspawn_flags[@]}" \ + "$copydir" \ + "${sysd_nspawn_flags[@]}" \ + -- \ + "${cmd[@]}" } # Usage: mkarchroot $copydir $pkgs... mkarchroot() { - local copydir=$1; shift - local pkgs=("$@") - - local arch_nspawn_flags=("${arch_nspawn_flags[@]}") - hack_arch_nspawn_flags "$copydir" - - local cmd=( - unshare -m "$_mkarchroot" - # mkarchroot flags: (flags are very similar to arch-nspawn) - "${arch_nspawn_flags[@]}" - # chroot directory: - -- "$copydir" - # pacman flags: - # * hack around https://bugs.archlinux.org/task/49347 - --hookdir="$copydir/etc/pacman.d/hooks" - # packages: (and maybe more flags... pacstrap injects - # flags at the end, so we can't turn of flag parsing - # with '--') - "${pkgs[@]}" - ) - "${cmd[@]}" + local copydir=$1; shift + local pkgs=("$@") + + local arch_nspawn_flags=("${arch_nspawn_flags[@]}") + hack_arch_nspawn_flags "$copydir" + + local cmd=( + unshare -m "$_mkarchroot" + # mkarchroot flags: (flags are very similar to arch-nspawn) + "${arch_nspawn_flags[@]}" + # chroot directory: + -- "$copydir" + # pacman flags: + # * hack around https://bugs.archlinux.org/task/49347 + --hookdir="$copydir/etc/pacman.d/hooks" + # packages: (and maybe more flags... pacstrap injects + # flags at the end, so we can't turn of flag parsing + # with '--') + "${pkgs[@]}" + ) + "${cmd[@]}" } @@ -214,360 +214,355 @@ readonly DEF_PACMANCONF_DIR=/usr/share/pacman/defaults/ usage() { - eval "$(calculate_directories)" - print "Usage: %s [OPTIONS] COMMAND [ARGS...]" "${0##*/}" - print 'Interacts with an archroot (arch chroot).' - echo - prose 'This is configured with `chroot.conf`, either in - `/etc/libretools.d/`, or `$XDG_CONFIG_HOME/libretools/`. - The variables you may set are $CHROOTDIR, $CHROOT, and - $CHROOTEXTRAPKG.' - echo - prose 'There may be multiple chroots; they are stored in $CHROOTDIR.' - echo - prose 'Each chroot is named; the default is configured with $CHROOT.' - echo - prose 'Each named chroot has a master clean copy (named `root`), and any - number of other named copies; the copy used by default is the - current username (or $SUDO_USER, or `copy` if root).' - echo - prose 'The full path to the chroot copy is "$CHROOTDIR/$CHROOT/$COPY", - unless the copy name is manually specified as an absolute path, - in which case, that path is used.' - echo - prose 'The current settings for the above variables are:' - printf ' CHROOTDIR : %s\n' "${CHROOTDIR:-$(_ 'ERROR: NO SETTING')}" - printf ' CHROOT : %s\n' "${CHROOT:-$(_ 'ERROR: NO SETTING')}" - printf ' COPY : %s\n' "$COPY" - printf ' rootdir : %s\n' "${rootdir:-$(_ 'ERROR')}" - printf ' copydir : %s\n' "${copydir:-$(_ 'ERROR')}" - echo - prose 'If the chroot or copy does not exist, it will be created - automatically. A chroot by default contains the packages in the - group "base-devel" and any packages named in $CHROOTEXTRAPKG. - Unless the `-C` or `-M` flags are used, the configuration files - that this program installs are the stock versions supplied in the - packages, not the versions from your host system. Other tools - (such as libremakepkg) may alter the configuration.' - echo - prose 'This command will make the following configuration changes in the - chroot:' - bullet 'overwrite `/etc/libretools.d/chroot.conf`' # libretools/librechroot - bullet 'overwrite `/etc/pacman.d/mirrorlist`' # devtools/arch-nspawn - bullet 'set `CacheDir` in `/etc/pacman.conf`' # devtools/arch-nspawn - prose 'If a new `pacman.conf` is inserted with the `-C` flag, the change - is made after the file is copied in; the `-C` flag doesn'"'"'t - stop the change from being effective.' - echo - prose 'The processor architecture of the chroot is determined - by the by `CARCH` variable in the `/etc/makepkg.conf` - file inside of the chroot.' - echo + eval "$(calculate_directories)" + print "Usage: %s [OPTIONS] COMMAND [ARGS...]" "${0##*/}" + print 'Interacts with an archroot (arch chroot).' + echo + prose 'This is configured with `chroot.conf`, either in + `/etc/libretools.d/`, or `$XDG_CONFIG_HOME/libretools/`. + The variables you may set are $CHROOTDIR, $CHROOT, and + $CHROOTEXTRAPKG.' + echo + prose 'There may be multiple chroots; they are stored in $CHROOTDIR.' + echo + prose 'Each chroot is named; the default is configured with $CHROOT.' + echo + prose 'Each named chroot has a master clean copy (named `root`), and any + number of other named copies; the copy used by default is the + current username (or $SUDO_USER, or `copy` if root).' + echo + prose 'The full path to the chroot copy is "$CHROOTDIR/$CHROOT/$COPY", + unless the copy name is manually specified as an absolute path, + in which case, that path is used.' + echo + prose 'The current settings for the above variables are:' + printf ' CHROOTDIR : %s\n' "${CHROOTDIR:-$(_ 'ERROR: NO SETTING')}" + printf ' CHROOT : %s\n' "${CHROOT:-$(_ 'ERROR: NO SETTING')}" + printf ' COPY : %s\n' "$COPY" + printf ' rootdir : %s\n' "${rootdir:-$(_ 'ERROR')}" + printf ' copydir : %s\n' "${copydir:-$(_ 'ERROR')}" + echo + prose 'If the chroot or copy does not exist, it will be created + automatically. A chroot by default contains the packages in the + group "base-devel" and any packages named in $CHROOTEXTRAPKG. + Unless the `-C` or `-M` flags are used, the configuration files + that this program installs are the stock versions supplied in the + packages, not the versions from your host system. Other tools + (such as libremakepkg) may alter the configuration.' + echo + prose 'This command will make the following configuration changes in the + chroot:' + bullet 'overwrite `/etc/libretools.d/chroot.conf`' # libretools/librechroot + bullet 'overwrite `/etc/pacman.d/mirrorlist`' # devtools/arch-nspawn + bullet 'set `CacheDir` in `/etc/pacman.conf`' # devtools/arch-nspawn + prose 'If a new `pacman.conf` is inserted with the `-C` flag, the change + is made after the file is copied in; the `-C` flag doesn'"'"'t + stop the change from being effective.' + echo + prose 'The processor architecture of the chroot is determined + by the by `CARCH` variable in the `/etc/makepkg.conf` + file inside of the chroot.' + echo prose 'The `-A CARCH` flag is *almost* simply an alias for' printf ' %s\n' \ "-C \"${DEF_PACMAN_CONF_DIR}pacman.conf.\$CARCH\" \\" \ "-M \"${DEF_PACMAN_CONF_DIR}makepkg.conf.\$CARCH\"" - prose 'However, before doing that, it actually makes a temporary copy of - `pacman.conf`, and modifies it to:' - bullet 'set `Architecture` to match the `CARCH` line in `makepkg.conf`' - bullet 'comment out any `Include = /etc/pacman.d/*.conf` lines' - echo - prose 'Creating a copy, deleting a copy, or syncing a copy can be fairly - slow; but are very fast if $CHROOTDIR is on a btrfs partition.' - echo - print 'Options:' - flag "-n <$(_ CHROOT)>" 'Name of the chroot to use' - flag "-l <$(_ COPY)>" 'Name of, or absolute path to, the copy to use' - flag '-N' 'Disable networking in the chroot' - flag "-C <$(_ FILE)>" 'Copy this file to `$copydir/etc/pacman.conf`' - flag "-M <$(_ FILE)>" 'Copy this file to `$copydir/etc/makepkg.conf`' - flag "-A <$(_ CARCH)>" 'Set the architecture of the copy; simply an - alias for the `-C` and `-M` flags, see above.' - flag "-w <$(_ 'PATH[:INSIDE_PATH[:OPTIONS]]')>" 'Bind mount a file or directory, read/write' - flag "-r <$(_ 'PATH[:INSIDE_PATH[:OPTIONS]]')>" 'Bind mount a file or directory, read-only' - echo - print 'Commands:' - print ' Create/copy/delete:' - flag 'noop|make' 'Do not do anything, but still creates the chroot - copy if it does not exist' - flag 'sync' 'Sync the copy with the clean (`root`) copy' - flag 'delete' 'Delete the chroot copy' - print ' Dealing with packages:' - flag "install-file $(_ FILES...)" 'Like `pacman -U FILES...`' - flag "install-name $(_ NAMES...)" 'Like `pacman -S NAMES...`' - flag 'update' 'Like `pacman -Syu`' - flag 'clean-pkgs' 'Remove all packages from the chroot copy that - are not in base-devel, $CHROOTEXTRAPKG, or named - as a dependency in the file `/startdir/PKGBUILD` - in the chroot copy; and install all packages - that are.' - print ' Other:' - flag "run $(_ CMD...)" 'Run CMD in the chroot copy' - flag 'enter' 'Enter an interactive shell in the chroot copy' - flag 'clean-repo' 'Clean /repo in the chroot copy' - flag 'help' 'Show this message' + prose 'However, before doing that, it actually makes a temporary copy of + `pacman.conf`, and modifies it to:' + bullet 'set `Architecture` to match the `CARCH` line in `makepkg.conf`' + bullet 'comment out any `Include = /etc/pacman.d/*.conf` lines' + echo + prose 'Creating a copy, deleting a copy, or syncing a copy can be fairly + slow; but are very fast if $CHROOTDIR is on a btrfs partition.' + echo + print 'Options:' + flag "-n <$(_ CHROOT)>" 'Name of the chroot to use' + flag "-l <$(_ COPY)>" 'Name of, or absolute path to, the copy to use' + flag '-N' 'Disable networking in the chroot' + flag "-C <$(_ FILE)>" 'Copy this file to `$copydir/etc/pacman.conf`' + flag "-M <$(_ FILE)>" 'Copy this file to `$copydir/etc/makepkg.conf`' + flag "-A <$(_ CARCH)>" 'Set the architecture of the copy; simply an + alias for the `-C` and `-M` flags, see above.' + flag "-w <$(_ 'PATH[:INSIDE_PATH[:OPTIONS]]')>" 'Bind mount a file or directory, read/write' + flag "-r <$(_ 'PATH[:INSIDE_PATH[:OPTIONS]]')>" 'Bind mount a file or directory, read-only' + echo + print 'Commands:' + print ' Create/copy/delete:' + flag 'noop|make' 'Do not do anything, but still creates the chroot + copy if it does not exist' + flag 'sync' 'Sync the copy with the clean (`root`) copy' + flag 'delete' 'Delete the chroot copy' + print ' Dealing with packages:' + flag "install-file $(_ FILES...)" 'Like `pacman -U FILES...`' + flag "install-name $(_ NAMES...)" 'Like `pacman -S NAMES...`' + flag 'update' 'Like `pacman -Syu`' + flag 'clean-pkgs' 'Remove all packages from the chroot copy that + are not in base-devel, $CHROOTEXTRAPKG, or named + as a dependency in the file `/startdir/PKGBUILD` + in the chroot copy; and install all packages + that are.' + print ' Other:' + flag "run $(_ CMD...)" 'Run CMD in the chroot copy' + flag 'enter' 'Enter an interactive shell in the chroot copy' + flag 'clean-repo' 'Clean /repo in the chroot copy' + flag 'help' 'Show this message' } readonly commands=( - noop make sync delete - install-file install-name update clean-pkgs - run enter clean-repo help + noop make sync delete + install-file install-name update clean-pkgs + run enter clean-repo help ) # Globals: $CHROOTDIR, $CHROOT, $COPY, $rootdir and $copydir main() { - COPY=$LIBREUSER - [[ $COPY != root ]] || COPY=copy - - declare -i retconf=0 - load_conf chroot.conf CHROOTDIR CHROOT || retconf=$? - - local target_arch=$(uname -m) - local mode=enter opt - declare -Ai used_opts - - local tmp_pacmanconf="$(mktemp --tmpdir ${tmp_pacmanconf_prefix}.XXXXXXXXXX)" - local has_tmp_pacmanconf=0 - local def_pacmanconf - local def_makepkgconf - - trap 'rm -f -- "$tmp_pacmanconf"' EXIT - - - ## parse CLI options ## - - while getopts 'n:l:NC:M:A:w:r:' opt; do - case $opt in - n ) CHROOT=$OPTARG ;; - l ) COPY=$OPTARG ;; - N ) sysd_nspawn_flags+=(--private-network) ;; - C|M) target_arch=$(detect_chroot_arch "$OPTARG") - arch_nspawn_flags+=(-$opt "$OPTARG") ;; - A ) target_arch=$OPTARG - def_pacmanconf="${DEF_PACMANCONF_DIR}"pacman.conf.${target_arch} - def_makepkgconf="${DEF_PACMANCONF_DIR}"makepkg.conf.${target_arch} - arch_nspawn_flags+=( -C "${tmp_pacmanconf}" - -M "${def_makepkgconf}" ) - has_tmp_pacmanconf=1 ;; - w ) sysd_nspawn_flags+=("--bind=$OPTARG") ;; - r ) sysd_nspawn_flags+=("--bind-ro=$OPTARG") ;; - * ) usage >&2; return $EXIT_INVALIDARGUMENT ;; - esac - used_opts[$opt]+=1 - done - - - ## validate CLI options ## - - for opt in n l C M A; do - if (( ${used_opts[$opt]:-0} > 1 )); then - error "Option -%s may only be given once" "$opt" - usage >&2 - return $EXIT_INVALIDARGUMENT - fi - done - if (( ${used_opts[A]:-0} && ( ${used_opts[C]:-0} || ${used_opts[M]:-0} ) )); then - error "Option -A may not be used together with -C or -M" - usage >&2 - return $EXIT_INVALIDARGUMENT - fi - shift $((OPTIND - 1)) - if [[ $# -lt 1 ]]; then - error "Must specify a command" - usage >&2 - return $EXIT_INVALIDARGUMENT - fi - mode=$1 - if ! in_array "$mode" "${commands[@]}"; then - error "Unrecognized command: %s" "$mode" - usage >&2 - return $EXIT_INVALIDARGUMENT - fi - shift - case "$mode" in - help) - usage - return $EXIT_SUCCESS - :;; - noop|make|sync|delete|update|enter|clean-pkgs|clean-repo) - if [[ $# -gt 0 ]]; then - error 'Command `%s` does not take any arguments: %s' "$mode" "$*" - usage >&2 - return $EXIT_INVALIDARGUMENT - fi - :;; - install-file) - if [[ $# -lt 1 ]]; then - error 'Command `%s` requires at least one file' "$mode" - usage >&2 - return $EXIT_INVALIDARGUMENT - else - local missing=() - local file - for file in "$@"; do - if ! [[ -f $file ]]; then - missing+=("$file") - fi - done - if [[ ${#missing[@]} -gt 0 ]]; then - error "%s: file(s) not found: %s" "$mode" "${missing[*]}" - return $EXIT_INVALIDARGUMENT - fi - fi - :;; - install-name) - if [[ $# -lt 1 ]]; then - error 'Command `%s` requires at least one package name' "$mode" - usage >&2 - return $EXIT_INVALIDARGUMENT - fi - :;; - run) - if [[ $# -lt 1 ]]; then - error 'Command `%s` requires at least one argument' "$mode" - usage >&2 - return $EXIT_INVALIDARGUMENT - fi - :;; - esac - if (( has_tmp_pacmanconf )) && \ - ! [[ -f "${def_pacmanconf}" && -f "${def_makepkgconf}" ]]; then - error 'Unsupported architecture: %s' "${target_arch}" - plain 'See the files in %q for valid architectures.' "${DEF_PACMANCONF_DIR}" - return $EXIT_INVALIDARGUMENT; - fi - - - ## process CLI options ## - - if (( has_tmp_pacmanconf )); then - sed -r \ - -e "s|^#?\\s*Architecture.+|Architecture = ${target_arch}|g" \ - -e "s|^.*Include\s*=\s*/etc/pacman.d/.*\.conf|#&|" \ - < "${def_pacmanconf}" \ - > "$tmp_pacmanconf" - echo -e '\n\n# Enable the volatile i686 [build-support] repo only as needed.' \ - '\n#[build-support]\n#Server = http://mirror.archlinux32.org/$arch/$repo/' \ - '\n\n# Enable the volatile arm [aur] repo only as needed.' \ - '\n#[aur]\n#Server = https://mirror.archlinuxarm.org/$arch/$repo/' \ - >> "$tmp_pacmanconf" - fi - - - ## finalize state ## - - [[ $retconf = 0 ]] || exit $retconf - eval "$(calculate_directories)" - - readonly LIBREUSER LIBREHOME - readonly CHROOTDIR CHROOT COPY - readonly rootdir copydir - readonly mode - - - ## business ## - - if (( EUID )); then - error "This program must be run as root." - return $EXIT_NOPERMISSION - fi - - umask 0022 - - # Keep this lock for as long as we are running - # Note that '9' is the same FD number as in mkarchroot et al. - lock 9 "$copydir.lock" \ - "Waiting for existing lock on chroot copy to be released: [%s]" "$COPY" - - if [[ $mode != delete ]]; then - if ! check_mountpoint "$copydir.lock"; then - error "Chroot copy is mounted with nosuid or noexec options: [%s]" "$COPY" - return $EXIT_FAILURE - fi - - if [[ ! -d $rootdir ]]; then - msg "Creating 'root' copy for chroot [%s]" "$CHROOT" - mkarchroot "$rootdir" base-devel </dev/null - make_empty_repo "$rootdir" - fi - - if [[ ! -d $copydir ]] || [[ $mode == sync ]]; then - msg "Syncing copy [%s] with root copy" "$COPY" - sync_chroot "$CHROOTDIR/$CHROOT/root" "$copydir" "$COPY" - fi - - # Note: the in-chroot pkgconfdir is non-configurable, this is - # intentionally hard-coded. - mkdir -p "$copydir/etc/libretools.d" - { - if [[ ${#CHROOTEXTRAPKG[*]} -eq 0 ]]; then - echo 'CHROOTEXTRAPKG=()' - else - printf 'CHROOTEXTRAPKG=(' - printf '%q ' "${CHROOTEXTRAPKG[@]}" - printf ')\n' - fi - } > "$copydir"/etc/libretools.d/chroot.conf - - # "touch" the chroot first - # this will - # - overwrite '/etc/pacman.d/mirrorlist'" - # - set 'CacheDir' in \`/etc/pacman.conf'" - # - apply -C or -M flags - arch-nspawn "$copydir" true </dev/null - if [[ -n ${tmp_pacmanconf:-} ]]; then - rm -f -- "$tmp_pacmanconf" - fi - trap EXIT # clear the trap to remove the tmp pacman.conf from -A - arch_nspawn_flags=() # XXX dirty hack, don't apply -C or -M again - fi - - ######################################################################## - - case "$mode" in - # Create/copy/delete - noop|make|sync) :;; - delete) - if [[ -d $copydir ]]; then - delete_chroot "$copydir" - fi - ;; - - # Dealing with packages - install-file) - install_packages "$copydir" "$@" </dev/null - chroot_add_to_local_repo "$copydir" "$@" - ;; - install-name) - arch-nspawn "$copydir" pacman -Sy --noconfirm -- "$@" </dev/null - ;; - update) - arch-nspawn "$copydir" pacman -Syu --noconfirm </dev/null - ;; - clean-pkgs) - trap "rm -f -- ${copydir@Q}/{chcleanup,chrootexec}" EXIT - install -m755 "$(librelib chroot/chcleanup)" "$copydir/chcleanup" - printf '%s\n' \ - '#!/bin/bash' \ - 'mkdir -p /startdir' \ - 'cd /startdir' \ - '/chcleanup' \ - > "$copydir/chrootexec" - chmod 755 "$copydir/chrootexec" - arch-nspawn "$copydir" /chrootexec </dev/null - ;; - - # Other - run) - arch-nspawn "$copydir" "$@" - ;; - enter) - arch-nspawn "$copydir" bash - ;; - clean-repo) - rm -rf "${copydir}"/repo/* - make_empty_repo "$copydir" - ;; - esac + COPY=$LIBREUSER + [[ $COPY != root ]] || COPY=copy + + declare -i retconf=0 + load_conf chroot.conf CHROOTDIR CHROOT || retconf=$? + + local target_arch=$(uname -m) + local mode=enter opt + declare -Ai used_opts + + local tmp_pacmanconf="$(mktemp --tmpdir ${tmp_pacmanconf_prefix}.XXXXXXXXXX)" + local has_tmp_pacmanconf=0 + local def_pacmanconf + local def_makepkgconf + + trap 'rm -f -- "$tmp_pacmanconf"' EXIT + + + ## parse CLI options ## + + while getopts 'n:l:NC:M:A:w:r:' opt; do + case $opt in + n ) CHROOT=$OPTARG ;; + l ) COPY=$OPTARG ;; + N ) sysd_nspawn_flags+=(--private-network) ;; + C|M) target_arch=$(detect_chroot_arch "$OPTARG") + arch_nspawn_flags+=(-$opt "$OPTARG") ;; + A ) target_arch=$OPTARG + def_pacmanconf="${DEF_PACMANCONF_DIR}"pacman.conf.${target_arch} + def_makepkgconf="${DEF_PACMANCONF_DIR}"makepkg.conf.${target_arch} + arch_nspawn_flags+=( -C "${tmp_pacmanconf}" + -M "${def_makepkgconf}" ) + has_tmp_pacmanconf=1 ;; + w ) sysd_nspawn_flags+=("--bind=$OPTARG") ;; + r ) sysd_nspawn_flags+=("--bind-ro=$OPTARG") ;; + * ) usage >&2; return $EXIT_INVALIDARGUMENT ;; + esac + used_opts[$opt]+=1 + done + + + ## validate CLI options ## + + for opt in n l C M A; do + if (( ${used_opts[$opt]:-0} > 1 )); then + error "Option -%s may only be given once" "$opt" + usage >&2 + return $EXIT_INVALIDARGUMENT + fi + done + if (( ${used_opts[A]:-0} && ( ${used_opts[C]:-0} || ${used_opts[M]:-0} ) )); then + error "Option -A may not be used together with -C or -M" + usage >&2 + return $EXIT_INVALIDARGUMENT + fi + shift $((OPTIND - 1)) + if [[ $# -lt 1 ]]; then + error "Must specify a command" + usage >&2 + return $EXIT_INVALIDARGUMENT + fi + mode=$1 + if ! in_array "$mode" "${commands[@]}"; then + error "Unrecognized command: %s" "$mode" + usage >&2 + return $EXIT_INVALIDARGUMENT + fi + shift + case "$mode" in + help) + usage + return $EXIT_SUCCESS + :;; + noop|make|sync|delete|update|enter|clean-pkgs|clean-repo) + if [[ $# -gt 0 ]]; then + error 'Command `%s` does not take any arguments: %s' "$mode" "$*" + usage >&2 + return $EXIT_INVALIDARGUMENT + fi + :;; + install-file) + if [[ $# -lt 1 ]]; then + error 'Command `%s` requires at least one file' "$mode" + usage >&2 + return $EXIT_INVALIDARGUMENT + else + local missing=() + local file + for file in "$@"; do + if ! [[ -f $file ]]; then + missing+=("$file") + fi + done + if [[ ${#missing[@]} -gt 0 ]]; then + error "%s: file(s) not found: %s" "$mode" "${missing[*]}" + return $EXIT_INVALIDARGUMENT + fi + fi + :;; + install-name) + if [[ $# -lt 1 ]]; then + error 'Command `%s` requires at least one package name' "$mode" + usage >&2 + return $EXIT_INVALIDARGUMENT + fi + :;; + run) + if [[ $# -lt 1 ]]; then + error 'Command `%s` requires at least one argument' "$mode" + usage >&2 + return $EXIT_INVALIDARGUMENT + fi + :;; + esac + if (( has_tmp_pacmanconf )) && \ + ! [[ -f "${def_pacmanconf}" && -f "${def_makepkgconf}" ]]; then + error 'Unsupported architecture: %s' "${target_arch}" + plain 'See the files in %q for valid architectures.' "${DEF_PACMANCONF_DIR}" + return $EXIT_INVALIDARGUMENT; + fi + + + ## process CLI options ## + + if (( has_tmp_pacmanconf )); then + sed -r \ + -e "s|^#?\\s*Architecture.+|Architecture = ${target_arch}|g" \ + -e "s|^.*Include\s*=\s*/etc/pacman.d/.*\.conf|#&|" \ + < "${def_pacmanconf}" \ + > "${tmp_pacmanconf}" + fi + + + ## finalize state ## + + [[ $retconf = 0 ]] || exit $retconf + eval "$(calculate_directories)" + + readonly LIBREUSER LIBREHOME + readonly CHROOTDIR CHROOT COPY + readonly rootdir copydir + readonly mode + + + ## business ## + + if (( EUID )); then + error "This program must be run as root." + return $EXIT_NOPERMISSION + fi + + umask 0022 + + # Keep this lock for as long as we are running + # Note that '9' is the same FD number as in mkarchroot et al. + lock 9 "$copydir.lock" \ + "Waiting for existing lock on chroot copy to be released: [%s]" "$COPY" + + if [[ $mode != delete ]]; then + if ! check_mountpoint "$copydir.lock"; then + error "Chroot copy is mounted with nosuid or noexec options: [%s]" "$COPY" + return $EXIT_FAILURE + fi + + if [[ ! -d $rootdir ]]; then + msg "Creating 'root' copy for chroot [%s]" "$CHROOT" + mkarchroot "$rootdir" base-devel </dev/null + make_empty_repo "$rootdir" + fi + + if [[ ! -d $copydir ]] || [[ $mode == sync ]]; then + msg "Syncing copy [%s] with root copy" "$COPY" + sync_chroot "$CHROOTDIR/$CHROOT/root" "$copydir" "$COPY" + fi + + # Note: the in-chroot pkgconfdir is non-configurable, this is + # intentionally hard-coded. + mkdir -p "$copydir/etc/libretools.d" + { + if [[ ${#CHROOTEXTRAPKG[*]} -eq 0 ]]; then + echo 'CHROOTEXTRAPKG=()' + else + printf 'CHROOTEXTRAPKG=(' + printf '%q ' "${CHROOTEXTRAPKG[@]}" + printf ')\n' + fi + } > "$copydir"/etc/libretools.d/chroot.conf + + # "touch" the chroot first + # this will + # - overwrite '/etc/pacman.d/mirrorlist'" + # - set 'CacheDir' in \`/etc/pacman.conf'" + # - apply -C or -M flags + arch-nspawn "$copydir" true </dev/null + if [[ -n ${tmp_pacmanconf:-} ]]; then + rm -f -- "$tmp_pacmanconf" + fi + trap EXIT # clear the trap to remove the tmp pacman.conf from -A + arch_nspawn_flags=() # XXX dirty hack, don't apply -C or -M again + fi + + ######################################################################## + + case "$mode" in + # Create/copy/delete + noop|make|sync) :;; + delete) + if [[ -d $copydir ]]; then + delete_chroot "$copydir" + fi + ;; + + # Dealing with packages + install-file) + install_packages "$copydir" "$@" </dev/null + chroot_add_to_local_repo "$copydir" "$@" + ;; + install-name) + arch-nspawn "$copydir" pacman -Sy --noconfirm -- "$@" </dev/null + ;; + update) + arch-nspawn "$copydir" pacman -Syu --noconfirm </dev/null + ;; + clean-pkgs) + trap "rm -f -- ${copydir@Q}/{chcleanup,chrootexec}" EXIT + install -m755 "$(librelib chroot/chcleanup)" "$copydir/chcleanup" + printf '%s\n' \ + '#!/bin/bash' \ + 'mkdir -p /startdir' \ + 'cd /startdir' \ + '/chcleanup' \ + > "$copydir/chrootexec" + chmod 755 "$copydir/chrootexec" + arch-nspawn "$copydir" /chrootexec </dev/null + ;; + + # Other + run) + arch-nspawn "$copydir" "$@" + ;; + enter) + arch-nspawn "$copydir" bash + ;; + clean-repo) + rm -rf "${copydir}"/repo/* + make_empty_repo "$copydir" + ;; + esac } diff --git a/src/chroot-tools/libremakepkg b/src/chroot-tools/libremakepkg index 274600d..41aa74e 100755 --- a/src/chroot-tools/libremakepkg +++ b/src/chroot-tools/libremakepkg @@ -55,288 +55,288 @@ source "$(librelib chroot/hooks-distcc.sh)" # Boring/mundane functions ##################################################### indent() { - "$_indent" ' | ' + "$_indent" ' | ' } # Usage: exit_copy $copydir $src_owner # End immediately, but copy log files out exit_copy() { - local copydir=$1 - local src_owner=$2 - if ! $INCHROOT; then - msg "Copying log and package files out of the chroot..." - move_products "$copydir" "$src_owner" - fi + local copydir=$1 + local src_owner=$2 + if ! $INCHROOT; then + msg "Copying log and package files out of the chroot..." + move_products "$copydir" "$src_owner" + fi } # Usage; run_hook $hookname $args... run_hook() { - local hookname=$1; shift - local hookvar="hook_${hookname}[@]" - local fails=() - - for hook in "${!hookvar}"; do - # The "& wait $!" trick prevents "||" from disabling "set -e" - { "$hook" "$@" |& indent; } & - wait $! || fails+=("$hook") - done - - if [[ ${#fails[@]} -gt 0 ]]; then - error "Failure(s) in %s: %s" "$hookname" "${fails[*]}" - return $EXIT_FAILURE - else - return $EXIT_SUCCESS - fi + local hookname=$1; shift + local hookvar="hook_${hookname}[@]" + local fails=() + + for hook in "${!hookvar}"; do + # The "& wait $!" trick prevents "||" from disabling "set -e" + { "$hook" "$@" |& indent; } & + wait $! || fails+=("$hook") + done + + if [[ ${#fails[@]} -gt 0 ]]; then + error "Failure(s) in %s: %s" "$hookname" "${fails[*]}" + return $EXIT_FAILURE + else + return $EXIT_SUCCESS + fi } # Usage: add_to_local_repo $copydir $pkgfiles... add_to_local_repo() { - local copydir=$1; shift - mkdir -p "$copydir/repo" - local pkgfile - for pkgfile in "$@"; do - cp "$pkgfile" "$copydir/repo" - pushd "$copydir/repo" >/dev/null - repo-add repo.db.tar.gz "${pkgfile##*/}" - popd >/dev/null - done + local copydir=$1; shift + mkdir -p "$copydir/repo" + local pkgfile + for pkgfile in "$@"; do + cp "$pkgfile" "$copydir/repo" + pushd "$copydir/repo" >/dev/null + repo-add repo.db.tar.gz "${pkgfile##*/}" + popd >/dev/null + done } hook_post_build+=('chroot_cleanup') chroot_cleanup() { - local copydir=$1 - rm -f -- "$copydir"/chrootbuild + local copydir=$1 + rm -f -- "$copydir"/chrootbuild } build() ( - local copydir=$1 - local srcpkg=$2 - local repack=$3 - local makepkg_args=("${@:4}") - - local startdir - startdir=$(mktemp -d) - chown "$LIBREUSER:" "$startdir" - trap "rm -rf -- ${startdir@Q}" EXIT - sudo -u "$LIBREUSER" bsdtar -xf "$srcpkg" -C "$startdir" --strip-components 1 - - local run_ynet=() - local run_nnet=() - if $INCHROOT; then - local _run=(sh -c "mount --bind -o ro -- ${startdir@Q} ${startdir@Q} && cd ${startdir@Q} && \$@" --) - run_ynet=(unshare --mount -- "${_run[@]}") - run_nnet=(unshare --mount --net -- "${_run[@]}") - else - librechroot_flags+=(-r "$startdir:/startdir") - run_ynet=(librechroot "${librechroot_flags[@]}" run) - run_nnet=(librechroot "${librechroot_flags[@]}" -N run) - fi - $NONET || run_nnet=("${run_ynet[@]}") - - prepare_chroot "$copydir" "$LIBREHOME" "$repack" false - run_hook pre_build "$copydir" - trap "run_hook post_build ${copydir@Q}; rm -rf -- ${startdir@Q}" EXIT - "${run_nnet[@]}" /chrootbuild "${makepkg_args[@]}" </dev/null |& indent + local copydir=$1 + local srcpkg=$2 + local repack=$3 + local makepkg_args=("${@:4}") + + local startdir + startdir=$(mktemp -d) + chown "$LIBREUSER:" "$startdir" + trap "rm -rf -- ${startdir@Q}" EXIT + sudo -u "$LIBREUSER" bsdtar -xf "$srcpkg" -C "$startdir" --strip-components 1 + + local run_ynet=() + local run_nnet=() + if $INCHROOT; then + local _run=(sh -c "mount --bind -o ro -- ${startdir@Q} ${startdir@Q} && cd ${startdir@Q} && \$@" --) + run_ynet=(unshare --mount -- "${_run[@]}") + run_nnet=(unshare --mount --net -- "${_run[@]}") + else + librechroot_flags+=(-r "$startdir:/startdir") + run_ynet=(librechroot "${librechroot_flags[@]}" run) + run_nnet=(librechroot "${librechroot_flags[@]}" -N run) + fi + $NONET || run_nnet=("${run_ynet[@]}") + + prepare_chroot "$copydir" "$LIBREHOME" "$repack" false + run_hook pre_build "$copydir" + trap "run_hook post_build ${copydir@Q}; rm -rf -- ${startdir@Q}" EXIT + "${run_nnet[@]}" /chrootbuild "${makepkg_args[@]}" </dev/null |& indent ) # The main program ############################################################# usage() { - print "Usage: %s [options]" "${0##*/}" - print 'This program will build your package.' - echo - prose 'If run from outside of a chroot, this command will make the - following configuration changes in the chroot:' - bullet 'whatever changes `librechroot` makes.' - bullet 'set `{PKG,SRC,SRCPKG,LOG}DEST` in `/etc/makepkg.conf`' - bullet 'set `MAKEFLAGS` and `PACKAGER` in `/etc/makepkg.conf` to reflect - the value outside of the chroot.' - bullet 'create a `builduser` with the same numeric UID as the - invoking $SUDO_USER.' - bullet 'let this `builduser` call `sudo pacman` without a password.' - bullet 'set `keyserver-options` in `~builduser/.gnupg/gpg.conf`' - bullet "copy the user's GnuPG pubring to be the \`builduser\`'s pubring" - bullet 'add a pacman repositoriy of locally built packages' - echo - prose 'This command is configured both with `chroot.conf` (either in - `/etc/libretools.d/` or `$XDG_CONFIG_HOME/libretools/`), and with - makepkg.conf(5). However, similarly to makepkg(8), it lets - environment variables for {SRC,SRCPKG,PKG,LOG}DEST, MAKEFLAGS and - PACKAGER override the settings in makepkg.conf(5).' - echo - prose 'The `-n` and `-l` options behave identically to librechroot, see - the documentation there.' - echo - print 'Options:' - flag 'librechroot options:' \ - "-n <$(_ CHROOT)>" 'Name of the chroot to use' \ - "-l <$(_ COPY)>" 'Name of, or absolute path to, the chroot copy to use' \ - "-w <$(_ 'PATH[:INSIDE_PATH[:OPTIONS]]')>" 'Bind mount a file or directory, read/write' \ - "-r <$(_ 'PATH[:INSIDE_PATH[:OPTIONS]]')>" 'Bind mount a file or directory, read-only' - flag 'libremakepkg options:' \ - '-N' "Don't disable networking during prepare(), - build(), and package(). PLEASE don't use - this unless you have a special reason, its - use is a violation of Parabola policy." \ - '-R' 'Repackage contents of the package without - rebuilding' \ - "-S <$(_ SRCPKGFILE)>" 'Use an existing --allsource source-package' \ - '-h' 'Show this message' + print "Usage: %s [options]" "${0##*/}" + print 'This program will build your package.' + echo + prose 'If run from outside of a chroot, this command will make the + following configuration changes in the chroot:' + bullet 'whatever changes `librechroot` makes.' + bullet 'set `{PKG,SRC,SRCPKG,LOG}DEST` in `/etc/makepkg.conf`' + bullet 'set `MAKEFLAGS` and `PACKAGER` in `/etc/makepkg.conf` to reflect + the value outside of the chroot.' + bullet 'create a `builduser` with the same numeric UID as the + invoking $SUDO_USER.' + bullet 'let this `builduser` call `sudo pacman` without a password.' + bullet 'set `keyserver-options` in `~builduser/.gnupg/gpg.conf`' + bullet "copy the user's GnuPG pubring to be the \`builduser\`'s pubring" + bullet 'add a pacman repositoriy of locally built packages' + echo + prose 'This command is configured both with `chroot.conf` (either in + `/etc/libretools.d/` or `$XDG_CONFIG_HOME/libretools/`), and with + makepkg.conf(5). However, similarly to makepkg(8), it lets + environment variables for {SRC,SRCPKG,PKG,LOG}DEST, MAKEFLAGS and + PACKAGER override the settings in makepkg.conf(5).' + echo + prose 'The `-n` and `-l` options behave identically to librechroot, see + the documentation there.' + echo + print 'Options:' + flag 'librechroot options:' \ + "-n <$(_ CHROOT)>" 'Name of the chroot to use' \ + "-l <$(_ COPY)>" 'Name of, or absolute path to, the chroot copy to use' \ + "-w <$(_ 'PATH[:INSIDE_PATH[:OPTIONS]]')>" 'Bind mount a file or directory, read/write' \ + "-r <$(_ 'PATH[:INSIDE_PATH[:OPTIONS]]')>" 'Bind mount a file or directory, read-only' + flag 'libremakepkg options:' \ + '-N' "Don't disable networking during prepare(), + build(), and package(). PLEASE don't use + this unless you have a special reason, its + use is a violation of Parabola policy." \ + '-R' 'Repackage contents of the package without + rebuilding' \ + "-S <$(_ SRCPKGFILE)>" 'Use an existing --allsource source-package' \ + '-h' 'Show this message' } # Convenience method for use in option parsing err_chflag() { - local flag=$1 - error 'The -%s flag does not make sense inside of a chroot' "$flag" - exit $EXIT_INVALIDARGUMENT + local flag=$1 + error 'The -%s flag does not make sense inside of a chroot' "$flag" + exit $EXIT_INVALIDARGUMENT } main() { - # Initial variable values ############################################## - local copy=$([[ $LIBREUSER == root ]] && echo copy || echo "$LIBREUSER") - local makepkg_args=(--syncdeps --noconfirm --log --holdver --skipinteg) - local repack=false - local chroot='' - local srcpkg='' - - # Parse command line options ########################################### - while getopts 'n:l:w:r:NRS:h' flag ; do - case "${flag}" in - n) if $INCHROOT; then err_chflag "$flag"; else - chroot=$OPTARG; fi;; - l) if $INCHROOT; then err_chflag "$flag"; else - copy=$OPTARG; fi;; - w|r) if $INCHROOT; then err_chflag "$flag"; else - librechroot_flags+=(-$flag "$OPTARG"); fi;; - N) NONET=false;; - R) repack=true; makepkg_args+=(-R);; - S) srcpkg=$OPTARG;; - h) usage; exit $EXIT_SUCCESS;; - *) usage >&2; exit $EXIT_INVALIDARGUMENT;; - esac - done - shift $((OPTIND - 1)) - if [[ $# != 0 ]]; then - error 'Extra arguments: %s' "$*" - exit $EXIT_INVALIDARGUMENT - fi - - # Resolve the chroot path ############################################## - local copydir - if $INCHROOT; then - copydir='/' - else - load_conf chroot.conf CHROOTDIR CHROOT || exit - [[ -z ${chroot} ]] || CHROOT=$chroot - if [[ ${copy:0:1} = / ]]; then - copydir=$copy - else - copydir="${CHROOTDIR}/${CHROOT}/${copy}" - fi - unset CHROOTDIR CHROOTEXTRAPKG - fi - unset chroot - - # Load makepkg configuration ########################################### - # Note that all of these are globals - PKGDEST="$(get_var makepkg PKGDEST "$PWD")" - SRCDEST="$(get_var makepkg SRCDEST "$PWD")" - SRCPKGDEST="$(get_var makepkg SRCPKGDEST "$PWD")" - LOGDEST="$(get_var makepkg LOGDEST "$PWD")" - MAKEFLAGS="$(get_var makepkg MAKEFLAGS '')" - PACKAGER="$(get_var makepkg PACKAGER '')" - - # Quick sanity check ################################################### - - if (( EUID )); then - error "This program must be run as root" - exit $EXIT_NOPERMISSION - fi - - if [[ -n $srcpkg ]]; then - if [[ ! -f $srcpkg ]]; then - error 'Source package does not exist: %s' "$srcpkg" - exit $EXIT_INVALIDARGUMENT - fi - else - if [[ ! -f PKGBUILD ]]; then - # This is the message used by makepkg - error "PKGBUILD does not exist." - exit $EXIT_FAILURE - fi - fi - - # Make sure that the various *DEST directories exist - sudo -u "$LIBREUSER" mkdir -p -- "$PKGDEST" "$SRCDEST" "$SRCPKGDEST" "$LOGDEST" - - # OK, we are starting now ############################################## - - if $INCHROOT; then - lock 9 "/build/.lock" \ - "Waiting for existing lock on build directory to be released" - else - librechroot_flags+=( - -n "$CHROOT" - -l "$copy" - ) - - # Obtain a lock on the chroot - lock 9 "$copydir.lock" \ - "Waiting for existing lock on chroot copy to be released: [%s]" "$copy" - # Create the chroot if it does not exist - msg 'Initializing the chroot...' - librechroot "${librechroot_flags[@]}" make |& indent - fi - - # Set target CARCH - # note that we waited until after locking/creating the chroot to do this - CARCH="$(MAKEPKG_CONF=$copydir/etc/makepkg.conf get_var makepkg CARCH)" - export CARCH - - # Pre-build - msg 'Starting pre-build activities...' - run_hook check_pkgbuild - - if [[ -n $srcpkg ]]; then - msg 'Using existing source package %s' "$srcpkg" - # TODO: symlink $srcpkg to ${SRCPKGDEST}/${pkgbase}-${evr}-${CARCH}${SRCEXT} - else - msg 'Downloading sources...' - local srcpkgdest - srcpkgdest="$(mktemp -d)" - chown "$LIBREUSER:" "$srcpkgdest" - trap "rm -rf -- ${srcpkgdest@Q}" EXIT - SRCPKGDEST="$srcpkgdest" download_sources "$copydir" "$LIBREUSER" |& indent - srcpkg=("$srcpkgdest"/*) - if (( ${#srcpkg[@]} != 1 )); then - error 'Something went funny with makepkg --allsource' - return $EXIT_FAILURE - fi - # We want to inject "-$pkgarch" in to srcpkg's filename, right before $SRCEXT - local srcext pkgarch srcpkg_filename - srcext="$(MAKEPKG_CONF=$copydir/etc/makepkg.conf get_var makepkg SRCEXT)" - if [[ "$(bsdtar xfO "$srcpkg" --include='*/.SRCINFO' | grep $'\tarch =')" = $'\tarch = any' ]]; then - pkgarch=any - else - pkgarch=$CARCH - fi - srcpkg_filename=${srcpkg##*/} - srcpkg_filename=${srcpkg_filename%"${srcext}"}-${pkgarch}${srcext} - mv -T -- "$srcpkg" "$SRCPKGDEST/${srcpkg_filename}" - srcpkg="$SRCPKGDEST/${srcpkg_filename}" - rmdir -- "${srcpkgdest}" - trap EXIT - fi - - # Build - msg 'Starting to build the package...' - trap "exit_copy '$copydir' '$LIBREUSER'" EXIT - build "$copydir" "$srcpkg" "$repack" "${makepkg_args[@]}" - - # Post-build - msg 'Starting post-build activities...' - run_hook check_pkg - add_to_local_repo "$copydir" "$copydir"/pkgdest/*.pkg.tar* |& indent + # Initial variable values ############################################## + local copy=$([[ $LIBREUSER == root ]] && echo copy || echo "$LIBREUSER") + local makepkg_args=(--syncdeps --noconfirm --log --holdver --skipinteg) + local repack=false + local chroot='' + local srcpkg='' + + # Parse command line options ########################################### + while getopts 'n:l:w:r:NRS:h' flag ; do + case "${flag}" in + n) if $INCHROOT; then err_chflag "$flag"; else + chroot=$OPTARG; fi;; + l) if $INCHROOT; then err_chflag "$flag"; else + copy=$OPTARG; fi;; + w|r) if $INCHROOT; then err_chflag "$flag"; else + librechroot_flags+=(-$flag "$OPTARG"); fi;; + N) NONET=false;; + R) repack=true; makepkg_args+=(-R);; + S) srcpkg=$OPTARG;; + h) usage; exit $EXIT_SUCCESS;; + *) usage >&2; exit $EXIT_INVALIDARGUMENT;; + esac + done + shift $((OPTIND - 1)) + if [[ $# != 0 ]]; then + error 'Extra arguments: %s' "$*" + exit $EXIT_INVALIDARGUMENT + fi + + # Resolve the chroot path ############################################## + local copydir + if $INCHROOT; then + copydir='/' + else + load_conf chroot.conf CHROOTDIR CHROOT || exit + [[ -z ${chroot} ]] || CHROOT=$chroot + if [[ ${copy:0:1} = / ]]; then + copydir=$copy + else + copydir="${CHROOTDIR}/${CHROOT}/${copy}" + fi + unset CHROOTDIR CHROOTEXTRAPKG + fi + unset chroot + + # Load makepkg configuration ########################################### + # Note that all of these are globals + PKGDEST="$(get_var makepkg PKGDEST "$PWD")" + SRCDEST="$(get_var makepkg SRCDEST "$PWD")" + SRCPKGDEST="$(get_var makepkg SRCPKGDEST "$PWD")" + LOGDEST="$(get_var makepkg LOGDEST "$PWD")" + MAKEFLAGS="$(get_var makepkg MAKEFLAGS '')" + PACKAGER="$(get_var makepkg PACKAGER '')" + + # Quick sanity check ################################################### + + if (( EUID )); then + error "This program must be run as root" + exit $EXIT_NOPERMISSION + fi + + if [[ -n $srcpkg ]]; then + if [[ ! -f $srcpkg ]]; then + error 'Source package does not exist: %s' "$srcpkg" + exit $EXIT_INVALIDARGUMENT + fi + else + if [[ ! -f PKGBUILD ]]; then + # This is the message used by makepkg + error "PKGBUILD does not exist." + exit $EXIT_FAILURE + fi + fi + + # Make sure that the various *DEST directories exist + sudo -u "$LIBREUSER" mkdir -p -- "$PKGDEST" "$SRCDEST" "$SRCPKGDEST" "$LOGDEST" + + # OK, we are starting now ############################################## + + if $INCHROOT; then + lock 9 "/build/.lock" \ + "Waiting for existing lock on build directory to be released" + else + librechroot_flags+=( + -n "$CHROOT" + -l "$copy" + ) + + # Obtain a lock on the chroot + lock 9 "$copydir.lock" \ + "Waiting for existing lock on chroot copy to be released: [%s]" "$copy" + # Create the chroot if it does not exist + msg 'Initializing the chroot...' + librechroot "${librechroot_flags[@]}" make |& indent + fi + + # Set target CARCH + # note that we waited until after locking/creating the chroot to do this + CARCH="$(MAKEPKG_CONF=$copydir/etc/makepkg.conf get_var makepkg CARCH)" + export CARCH + + # Pre-build + msg 'Starting pre-build activities...' + run_hook check_pkgbuild + + if [[ -n $srcpkg ]]; then + msg 'Using existing source package %s' "$srcpkg" + # TODO: symlink $srcpkg to ${SRCPKGDEST}/${pkgbase}-${evr}-${CARCH}${SRCEXT} + else + msg 'Downloading sources...' + local srcpkgdest + srcpkgdest="$(mktemp -d)" + chown "$LIBREUSER:" "$srcpkgdest" + trap "rm -rf -- ${srcpkgdest@Q}" EXIT + SRCPKGDEST="$srcpkgdest" download_sources "$copydir" "$LIBREUSER" |& indent + srcpkg=("$srcpkgdest"/*) + if (( ${#srcpkg[@]} != 1 )); then + error 'Something went funny with makepkg --allsource' + return $EXIT_FAILURE + fi + # We want to inject "-$pkgarch" in to srcpkg's filename, right before $SRCEXT + local srcext pkgarch srcpkg_filename + srcext="$(MAKEPKG_CONF=$copydir/etc/makepkg.conf get_var makepkg SRCEXT)" + if [[ "$(bsdtar xfO "$srcpkg" --include='*/.SRCINFO' | grep $'\tarch =')" = $'\tarch = any' ]]; then + pkgarch=any + else + pkgarch=$CARCH + fi + srcpkg_filename=${srcpkg##*/} + srcpkg_filename=${srcpkg_filename%"${srcext}"}-${pkgarch}${srcext} + mv -T -- "$srcpkg" "$SRCPKGDEST/${srcpkg_filename}" + srcpkg="$SRCPKGDEST/${srcpkg_filename}" + rmdir -- "${srcpkgdest}" + trap EXIT + fi + + # Build + msg 'Starting to build the package...' + trap "exit_copy '$copydir' '$LIBREUSER'" EXIT + build "$copydir" "$srcpkg" "$repack" "${makepkg_args[@]}" + + # Post-build + msg 'Starting post-build activities...' + run_hook check_pkg + add_to_local_repo "$copydir" "$copydir"/pkgdest/*.pkg.tar* |& indent } diff --git a/src/lib/conf.sh.in b/src/lib/conf.sh.in index 25afa1d..603a28c 100644 --- a/src/lib/conf.sh.in +++ b/src/lib/conf.sh.in @@ -19,19 +19,19 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. if [[ "$(id -u "${SUDO_USER:-root}")" == 0 ]]; then - unset SUDO_USER + unset SUDO_USER fi LIBREUSER="${SUDO_USER:-$USER}" if [[ $LIBREUSER == "$USER" ]]; then - LIBREHOME=$HOME + LIBREHOME=$HOME else - eval "LIBREHOME=~$LIBREUSER" + eval "LIBREHOME=~$LIBREUSER" fi if [[ -z ${XDG_CONFIG_HOME:-} ]]; then - export XDG_CONFIG_HOME="${LIBREHOME}/.config" + export XDG_CONFIG_HOME="${LIBREHOME}/.config" fi if [[ -z ${XDG_CACHE_HOME:-} ]]; then - export XDG_CACHE_HOME="${LIBREHOME}/.cache" + export XDG_CACHE_HOME="${LIBREHOME}/.cache" fi # Low-level generic functions ################################################## @@ -40,62 +40,62 @@ fi # Lists the configuration files to be considered for $slug. # Later files should take precedence over earlier files. list_files() { - local slug=$1 - local sysconfdir=${_librelib_conf_sh_sysconfdir:-@sysconfdir@} - local pkgconfdir=${_librelib_conf_sh_pkgconfdir:-@pkgconfdir@} - case $slug in - abs) - echo "${sysconfdir}/$slug.conf" - echo "$LIBREHOME/.$slug.conf" - ;; - makepkg) - local manual="${MAKEPKG_CONF:-}" - local system="${sysconfdir}/$slug.conf" - local olduser="$LIBREHOME/.$slug.conf" - local newuser="$XDG_CONFIG_HOME/pacman/$slug.conf" - if [[ "$manual" != "$system" && -r "$manual" ]]; then - # Manually-specified file - echo "$manual" - else - # Normal file lookup - echo "$system" - if [[ -r "$olduser" && ! -r "$newuser" ]]; then - echo "$olduser" - else - echo "$newuser" - fi - fi - ;; - libretools) - echo "${sysconfdir}/$slug.conf" - echo "$XDG_CONFIG_HOME/libretools/$slug.conf" - ;; - *) - echo "${pkgconfdir}/$slug.conf" - echo "$XDG_CONFIG_HOME/libretools/$slug.conf" - ;; - esac + local slug=$1 + local sysconfdir=${_librelib_conf_sh_sysconfdir:-@sysconfdir@} + local pkgconfdir=${_librelib_conf_sh_pkgconfdir:-@pkgconfdir@} + case $slug in + abs) + echo "${sysconfdir}/$slug.conf" + echo "$LIBREHOME/.$slug.conf" + ;; + makepkg) + local manual="${MAKEPKG_CONF:-}" + local system="${sysconfdir}/$slug.conf" + local olduser="$LIBREHOME/.$slug.conf" + local newuser="$XDG_CONFIG_HOME/pacman/$slug.conf" + if [[ "$manual" != "$system" && -r "$manual" ]]; then + # Manually-specified file + echo "$manual" + else + # Normal file lookup + echo "$system" + if [[ -r "$olduser" && ! -r "$newuser" ]]; then + echo "$olduser" + else + echo "$newuser" + fi + fi + ;; + libretools) + echo "${sysconfdir}/$slug.conf" + echo "$XDG_CONFIG_HOME/libretools/$slug.conf" + ;; + *) + echo "${pkgconfdir}/$slug.conf" + echo "$XDG_CONFIG_HOME/libretools/$slug.conf" + ;; + esac } # Usage: list_envvars $slug # Lists the environmental variables that take precedence over the configuration # files for $slug. list_envvars() { - local slug=$1 - case $slug in - makepkg) - printf '%s\n' \ - PKGDEST SRCDEST SRCPKGDEST LOGDEST \ - BUILDDIR \ - PKGEXT SRCEXT \ - GPGKEY PACKAGER \ - CARCH - ;; - libretools) - printf '%s\n' DIFFPROG - ;; - *) :;; - esac + local slug=$1 + case $slug in + makepkg) + printf '%s\n' \ + PKGDEST SRCDEST SRCPKGDEST LOGDEST \ + BUILDDIR \ + PKGEXT SRCEXT \ + GPGKEY PACKAGER \ + CARCH + ;; + libretools) + printf '%s\n' DIFFPROG + ;; + *) :;; + esac } # High-level generic functions ################################################# @@ -105,137 +105,137 @@ list_envvars() { # Loads the configuration files for $slug in the proper order, and # optionally verify that certain variables are set. load_conf() { - [[ $1 = /* || $1 = *.conf ]] || libremessages panic || exit 1 # $EXIT_FAILURE - local files envvars - if [[ $1 = /* ]]; then - files=("$1") - envvars=() - shift - else - local slug=${1%.conf} - shift - readarray -t files < <(list_files "$slug") - readarray -t envvars < <(list_envvars "$slug") - fi - local var file - - # Save the existing versions at _VARNAME - for var in "${envvars[@]}"; do - [[ -n ${!var:-} ]] && eval "local _$var=\${$var}" - done - - # Load the files - for file in "${files[@]}"; do - if [[ -r $file ]]; then - source "$file" || return 6 # $EXIT_NOTCONFIGURED - fi - done - - # Restore the _SAVED versions - for var in "${envvars[@]}"; do - eval "$var=\${_$var:-\${$var:-}}" - done - - # Verify that the variables we need were set - declare -i ret=0 # $EXIT_SUCCESS - for var in "$@"; do - if [[ -z ${!var:-} ]]; then - if [[ ${#files[@]} -gt 1 ]]; then - libremessages _l print "Configure '%s' in one of:" "$var" - printf ' -> %s\n' "${files[@]}" - else - libremessages _l print "Configure '%s' in '%s'" "$var" "${files[0]}" - fi - ret=6 # $EXIT_NOTCONFIGURED - fi - done >&2 - return $ret + [[ $1 = /* || $1 = *.conf ]] || libremessages panic || exit 1 # $EXIT_FAILURE + local files envvars + if [[ $1 = /* ]]; then + files=("$1") + envvars=() + shift + else + local slug=${1%.conf} + shift + readarray -t files < <(list_files "$slug") + readarray -t envvars < <(list_envvars "$slug") + fi + local var file + + # Save the existing versions at _VARNAME + for var in "${envvars[@]}"; do + [[ -n ${!var:-} ]] && eval "local _$var=\${$var}" + done + + # Load the files + for file in "${files[@]}"; do + if [[ -r $file ]]; then + source "$file" || return 6 # $EXIT_NOTCONFIGURED + fi + done + + # Restore the _SAVED versions + for var in "${envvars[@]}"; do + eval "$var=\${_$var:-\${$var:-}}" + done + + # Verify that the variables we need were set + declare -i ret=0 # $EXIT_SUCCESS + for var in "$@"; do + if [[ -z ${!var:-} ]]; then + if [[ ${#files[@]} -gt 1 ]]; then + libremessages _l print "Configure '%s' in one of:" "$var" + printf ' -> %s\n' "${files[@]}" + else + libremessages _l print "Configure '%s' in '%s'" "$var" "${files[0]}" + fi + ret=6 # $EXIT_NOTCONFIGURED + fi + done >&2 + return $ret } # Usage: get_var <slug> <var_name> <default_value> # Does not work with arrays get_var() ( - set +euE - local slug=$1 - local setting=$2 - local default=$3 - load_conf "$slug.conf" - printf '%s' "${!setting:-${default}}" + set +euE + local slug=$1 + local setting=$2 + local default=$3 + load_conf "$slug.conf" + printf '%s' "${!setting:-${default}}" ) # Usage: set_var <slug> <var_name> <value> # Does not work with arrays set_var() { - local slug=$1 - local key=$2 - local val=$3 - local file - while read -r file; do - if [[ -w $file ]]; then - sed -i "/^\s*$key=/d" "$file" - printf '%s=%q\n' "$key" "$val" >> "$file" - return 0 # $EXIT_SUCCESS - fi - done < <(list_files "$slug"|tac) - return 1 # $EXIT_FAILURE + local slug=$1 + local key=$2 + local val=$3 + local file + while read -r file; do + if [[ -w $file ]]; then + sed -i "/^\s*$key=/d" "$file" + printf '%s=%q\n' "$key" "$val" >> "$file" + return 0 # $EXIT_SUCCESS + fi + done < <(list_files "$slug"|tac) + return 1 # $EXIT_FAILURE } # PKGBUILD (not configuration, per se) ######################################### unset_PKGBUILD() { - # This routine is based primarily off of the PKGBUILD(5) man-page, - # version 4.2.0, dated 2014-12-31 - - # This is kinda weird, but everything is more readable with - # this as a utility function, but I didn't want to introduce a - # new global function, so I just introduced it with the name - # of a function that we get to unset anyway. So it can't - # clash with anything! - mksource() { - # For each arg, `unset -v` all variables matching ${arg} and ${arg}_* - local v - for v in "$@"; do - # shellcheck disable=228 - unset -v "$v" $(declare -p|sed -rn "s/^declare -\S+ (${v}_[a-zA-Z0-9_]*)=.*/\1/p") - done - } - - # This line is taken from the makepkg source - local known_hash_algos=('md5' 'sha1' 'sha224' 'sha256' 'sha384' 'sha512') - - # From the "OPTIONS AND DIRECTIVES" section (in order of mention) - unset -v pkgname pkgver - unset -f pkgver - unset -v pkgrel pkgdesc epoch url license install changelog - - mksource source - unset -v validpgpkeys noextract - local sums=("${known_hash_algos[@]/%/sums}") - mksource "${sums[@]}" - - unset -v groups arch backup - mksource depends makedepends checkdepends optdepends - mksource conflicts provides replaces - unset -v options - - # From the "PACKAGING FUNCTIONS" section (in order of mention) - unset -f package prepare build check - - # From the "PACKAGE SPLITTING" section - unset -f $(declare -f|sed -n 's/^\(package_\S*\) ()\s*$/\1/p') - unset -v pkgbase - - # These are used by the `librefetch` program - unset -v mksource mknoextract "${sums[@]/#/mk}" - unset -v mkdepends - unset -f mksource + # This routine is based primarily off of the PKGBUILD(5) man-page, + # version 4.2.0, dated 2014-12-31 + + # This is kinda weird, but everything is more readable with + # this as a utility function, but I didn't want to introduce a + # new global function, so I just introduced it with the name + # of a function that we get to unset anyway. So it can't + # clash with anything! + mksource() { + # For each arg, `unset -v` all variables matching ${arg} and ${arg}_* + local v + for v in "$@"; do + # shellcheck disable=228 + unset -v "$v" $(declare -p|sed -rn "s/^declare -\S+ (${v}_[a-zA-Z0-9_]*)=.*/\1/p") + done + } + + # This line is taken from the makepkg source + local known_hash_algos=('md5' 'sha1' 'sha224' 'sha256' 'sha384' 'sha512') + + # From the "OPTIONS AND DIRECTIVES" section (in order of mention) + unset -v pkgname pkgver + unset -f pkgver + unset -v pkgrel pkgdesc epoch url license install changelog + + mksource source + unset -v validpgpkeys noextract + local sums=("${known_hash_algos[@]/%/sums}") + mksource "${sums[@]}" + + unset -v groups arch backup + mksource depends makedepends checkdepends optdepends + mksource conflicts provides replaces + unset -v options + + # From the "PACKAGING FUNCTIONS" section (in order of mention) + unset -f package prepare build check + + # From the "PACKAGE SPLITTING" section + unset -f $(declare -f|sed -n 's/^\(package_\S*\) ()\s*$/\1/p') + unset -v pkgbase + + # These are used by the `librefetch` program + unset -v mksource mknoextract "${sums[@]/#/mk}" + unset -v mkdepends + unset -f mksource } load_PKGBUILD() { - local file=${1:-./PKGBUILD} - unset_PKGBUILD - # shellcheck disable=2034 - CARCH="$(get_var makepkg CARCH "$(uname -m)")" - source "$file" - pkgbase=${pkgbase:-${pkgname[0]}} + local file=${1:-./PKGBUILD} + unset_PKGBUILD + # shellcheck disable=2034 + CARCH="$(get_var makepkg CARCH "$(uname -m)")" + source "$file" + pkgbase=${pkgbase:-${pkgname[0]}} } diff --git a/src/lib/libremessages b/src/lib/libremessages index 43779af..19ceece 100755 --- a/src/lib/libremessages +++ b/src/lib/libremessages @@ -18,9 +18,9 @@ if [[ "${0##*/}" != libremessages ]]; then - source "$(librelib messages)" + source "$(librelib messages)" else - set -euE - source "$(librelib messages)" - "$@" + set -euE + source "$(librelib messages)" + "$@" fi diff --git a/src/librefetch/librefetch b/src/librefetch/librefetch index d8e40a6..e91e58a 100755 --- a/src/librefetch/librefetch +++ b/src/librefetch/librefetch @@ -45,280 +45,280 @@ cmd=${0##*/} usage() { - print "Usage: %s [OPTIONS] SOURCE_URL [OUTPUT_FILE]" "$cmd" - print "Usage: %s -[g|S|M|h]" "$cmd" - print "Downloads or creates a liberated source tarball." - echo - prose "The default mode is to create OUTPUT_FILE, first by trying - download mode, then create mode." - echo - prose "If OUTPUT_FILE isn't specified, it defaults to the non-directory - part of SOURCE_URL, in the current directory." - echo - prose "Unless '-C' is specified, if SOURCE_URL does not begin with a - configured mirror, create mode is inhibited." - echo - prose "In download mode, it simply tries to download SOURCE_URL. At the - beginning of a URL, 'libre://' expands to the first configured - mirror." - echo - prose "In create mode, it either looks at a build script and uses that - to create the source tarball, or it uses GPG to create a - signature (if OUTPUT_FILE ends with \`.sig\` or \`.sig.part\`). - If it is using GPG to create a signature, but the file that it is - trying to sign doesn't exist yet, it recurses on itself to first - create that file. SOURCE_URL is ignored, except that it is used - to set the default value of OUTPUT_FILE, and that it may be used - when recursing." - echo - prose "The default build script is 'PKGBUILD', or 'SRCBUILD' if it - exists." - echo - prose "Other options, if they are valid \`makepkg\` options, are passed - straight to makepkg." - echo - print "Example usage:" - print ' $ %s https://repo.parabola.nu/other/mypackage/mypackage-1.0.tar.gz' "$cmd" - echo - print "Options:" - flag 'Settings:' \ - "-C" "Force create mode (don't download)" \ - "-D" "Force download mode (don't create)" \ - "-p <$(_ FILE)>" "Use an alternate build script (instead of - 'PKGBUILD'). If an SRCBUILD exists in the same - directory, it is used instead" \ - 'Alternate modes:' \ - "-g, --geninteg" "Generate integrity checks for source files" \ - "-S, --srcbuild" "Print the effective build script (SRCBUILD)" \ - "-M, --makepkg" "Generate and print the location of the - effective makepkg script" \ - "-h, --help" "Show this message" + print "Usage: %s [OPTIONS] SOURCE_URL [OUTPUT_FILE]" "$cmd" + print "Usage: %s -[g|S|M|h]" "$cmd" + print "Downloads or creates a liberated source tarball." + echo + prose "The default mode is to create OUTPUT_FILE, first by trying + download mode, then create mode." + echo + prose "If OUTPUT_FILE isn't specified, it defaults to the non-directory + part of SOURCE_URL, in the current directory." + echo + prose "Unless '-C' is specified, if SOURCE_URL does not begin with a + configured mirror, create mode is inhibited." + echo + prose "In download mode, it simply tries to download SOURCE_URL. At the + beginning of a URL, 'libre://' expands to the first configured + mirror." + echo + prose "In create mode, it either looks at a build script and uses that + to create the source tarball, or it uses GPG to create a + signature (if OUTPUT_FILE ends with \`.sig\` or \`.sig.part\`). + If it is using GPG to create a signature, but the file that it is + trying to sign doesn't exist yet, it recurses on itself to first + create that file. SOURCE_URL is ignored, except that it is used + to set the default value of OUTPUT_FILE, and that it may be used + when recursing." + echo + prose "The default build script is 'PKGBUILD', or 'SRCBUILD' if it + exists." + echo + prose "Other options, if they are valid \`makepkg\` options, are passed + straight to makepkg." + echo + print "Example usage:" + print ' $ %s https://repo.parabola.nu/other/mypackage/mypackage-1.0.tar.gz' "$cmd" + echo + print "Options:" + flag 'Settings:' \ + "-C" "Force create mode (don't download)" \ + "-D" "Force download mode (don't create)" \ + "-p <$(_ FILE)>" "Use an alternate build script (instead of + 'PKGBUILD'). If an SRCBUILD exists in the same + directory, it is used instead" \ + 'Alternate modes:' \ + "-g, --geninteg" "Generate integrity checks for source files" \ + "-S, --srcbuild" "Print the effective build script (SRCBUILD)" \ + "-M, --makepkg" "Generate and print the location of the + effective makepkg script" \ + "-h, --help" "Show this message" } main() { - BUILDFILE="$(realpath -Lm PKGBUILD)" - makepkg_opts=() - extra_opts=() - mode=download-create - if ! parse_options "$@"; then - usage >&2 - exit $EXIT_INVALIDARGUMENT - fi - - doit + BUILDFILE="$(realpath -Lm PKGBUILD)" + makepkg_opts=() + extra_opts=() + mode=download-create + if ! parse_options "$@"; then + usage >&2 + exit $EXIT_INVALIDARGUMENT + fi + + doit } doit() { - # Mode: help ########################################################### - - if [[ $mode =~ help ]]; then - usage - exit $EXIT_SUCCESS - fi - - ######################################################################## - - makepkg="$(modified_makepkg)" - - # Mode: makepkg ######################################################## - - if [[ $mode =~ makepkg ]]; then - printf '%s\n' "$makepkg" - exit $EXIT_SUCCESS - else - tmpdirs+=("${makepkg%/*}") - fi - - ######################################################################## - - local BUILDFILEDIR="${BUILDFILE%/*}" - if [[ -f "${BUILDFILEDIR}/SRCBUILD" ]]; then - BUILDFILE="${BUILDFILEDIR}/SRCBUILD" - fi - if [[ ! -f "$BUILDFILE" ]]; then - error "%s does not exist." "$BUILDFILE" - exit $EXIT_FAILURE - fi - case "$BUILDFILE" in - */SRCBUILD) srcbuild="$(modified_srcbuild "$BUILDFILE")";; - *) srcbuild="$(modified_pkgbuild "$BUILDFILE")";; - esac - tmpfiles+=("$srcbuild") - - # Mode: checksums ###################################################### - - if [[ $mode =~ checksums ]]; then - "$makepkg" "${makepkg_opts[@]}" -g -p "$srcbuild" | - case ${BUILDFILE##*/} in - PKGBUILD) sed -e 's/^[a-z]/mk&/' -e 's/^\s/ &/';; - SRCBUILD) cat;; - esac - exit $EXIT_SUCCESS - fi - - # Mode: srcbuild ####################################################### - - if [[ $mode =~ srcbuild ]]; then - cat "$srcbuild" - exit $EXIT_SUCCESS - fi - - ######################################################################## - - local src="${extra_opts[0]}" - local dst="${extra_opts[1]:-${src##*/}}" - - # Don't canonicalize $src unless mode =~ download, and we've validated - # that $MIRRORS is configured. - - # Canonicalize $dst - dst="$(realpath -Lm -- "$dst")" - - # Mode: download ####################################################### - - if [[ $mode =~ download ]]; then - load_conf librefetch.conf MIRRORS DOWNLOADER || exit - - # Canonicalize $src - if [[ "$src" == libre://* ]]; then - src="${MIRRORS[0]}/${src#libre://}" - fi - - # check to see if $src is a candidate for create mode - local inmirror=false; - local mirror - for mirror in "${MIRRORS[@]}"; do - if [[ "$src" == "$mirror"* ]]; then - inmirror=true - break - fi - done - if ! $inmirror; then - # inhibit create - mode=download - fi - - local dlcmd="${DOWNLOADER}" - [[ $dlcmd = *%u* ]] || dlcmd="$dlcmd %u" - dlcmd="${dlcmd//\%o/\"\$dst\"}" - dlcmd="${dlcmd//\%u/\"\$src\"}" - - if { eval "$dlcmd"; } >&2; then - exit $EXIT_SUCCESS - fi - fi - - # Mode: create ######################################################### - - if [[ $mode =~ create ]]; then - local base_dst=${dst%.part} - local suffix=${dst#"$base_dst"} - - if [[ $base_dst == *.sig ]]; then - if ! [[ -e ${base_dst%.sig} ]]; then - extra_opts=("${src%.sig}" "${base_dst%.sig}") - doit || exit - fi - create_signature "${base_dst%.sig}" || exit - if [[ -n $suffix ]]; then - mv -f "$base_dst" "$dst" - fi - else - export PKGEXT=${base_dst##*/} - export PKGDEST=${dst%/*} - export pkg_file=$dst - - cd "$BUILDFILEDIR" - "$makepkg" "${makepkg_opts[@]}" -p "$srcbuild" >&2 || exit - fi - fi + # Mode: help ########################################################### + + if [[ $mode =~ help ]]; then + usage + exit $EXIT_SUCCESS + fi + + ######################################################################## + + makepkg="$(modified_makepkg)" + + # Mode: makepkg ######################################################## + + if [[ $mode =~ makepkg ]]; then + printf '%s\n' "$makepkg" + exit $EXIT_SUCCESS + else + tmpdirs+=("${makepkg%/*}") + fi + + ######################################################################## + + local BUILDFILEDIR="${BUILDFILE%/*}" + if [[ -f "${BUILDFILEDIR}/SRCBUILD" ]]; then + BUILDFILE="${BUILDFILEDIR}/SRCBUILD" + fi + if [[ ! -f "$BUILDFILE" ]]; then + error "%s does not exist." "$BUILDFILE" + exit $EXIT_FAILURE + fi + case "$BUILDFILE" in + */SRCBUILD) srcbuild="$(modified_srcbuild "$BUILDFILE")";; + *) srcbuild="$(modified_pkgbuild "$BUILDFILE")";; + esac + tmpfiles+=("$srcbuild") + + # Mode: checksums ###################################################### + + if [[ $mode =~ checksums ]]; then + "$makepkg" "${makepkg_opts[@]}" -g -p "$srcbuild" | + case ${BUILDFILE##*/} in + PKGBUILD) sed -e 's/^[a-z]/mk&/' -e 's/^\s/ &/';; + SRCBUILD) cat;; + esac + exit $EXIT_SUCCESS + fi + + # Mode: srcbuild ####################################################### + + if [[ $mode =~ srcbuild ]]; then + cat "$srcbuild" + exit $EXIT_SUCCESS + fi + + ######################################################################## + + local src="${extra_opts[0]}" + local dst="${extra_opts[1]:-${src##*/}}" + + # Don't canonicalize $src unless mode =~ download, and we've validated + # that $MIRRORS is configured. + + # Canonicalize $dst + dst="$(realpath -Lm -- "$dst")" + + # Mode: download ####################################################### + + if [[ $mode =~ download ]]; then + load_conf librefetch.conf MIRRORS DOWNLOADER || exit + + # Canonicalize $src + if [[ "$src" == libre://* ]]; then + src="${MIRRORS[0]}/${src#libre://}" + fi + + # check to see if $src is a candidate for create mode + local inmirror=false; + local mirror + for mirror in "${MIRRORS[@]}"; do + if [[ "$src" == "$mirror"* ]]; then + inmirror=true + break + fi + done + if ! $inmirror; then + # inhibit create + mode=download + fi + + local dlcmd="${DOWNLOADER}" + [[ $dlcmd = *%u* ]] || dlcmd="$dlcmd %u" + dlcmd="${dlcmd//\%o/\"\$dst\"}" + dlcmd="${dlcmd//\%u/\"\$src\"}" + + if { eval "$dlcmd"; } >&2; then + exit $EXIT_SUCCESS + fi + fi + + # Mode: create ######################################################### + + if [[ $mode =~ create ]]; then + local base_dst=${dst%.part} + local suffix=${dst#"$base_dst"} + + if [[ $base_dst == *.sig ]]; then + if ! [[ -e ${base_dst%.sig} ]]; then + extra_opts=("${src%.sig}" "${base_dst%.sig}") + doit || exit + fi + create_signature "${base_dst%.sig}" || exit + if [[ -n $suffix ]]; then + mv -f "$base_dst" "$dst" + fi + else + export PKGEXT=${base_dst##*/} + export PKGDEST=${dst%/*} + export pkg_file=$dst + + cd "$BUILDFILEDIR" + "$makepkg" "${makepkg_opts[@]}" -p "$srcbuild" >&2 || exit + fi + fi } # sets the variables BUILDFILE, makepkg_opts, extra_opts, mode parse_options() { - declare -i ret=$EXIT_SUCCESS - local {shrt,long}{1,2} - - # makepkg options - local makepkg_orig - makepkg_orig="$(which makepkg)" - shrt1=($(LC_ALL=C "${makepkg_orig}" -h | sed -rn 's/^ +-(.)(,| [^<]).*/\1/p')) - shrt2=($(LC_ALL=C "${makepkg_orig}" -h | sed -rn 's/^ +-(.) <.*/\1/p')) - long1=($(LC_ALL=C "${makepkg_orig}" -h | sed -rn -e 's/^ +(-., )?--(\S*) [^<].*/\2/p')) - long2=($(LC_ALL=C "${makepkg_orig}" -h | sed -rn 's/^ +--(\S*) <.*/\1/p')) - - # librefetch options - shrt1+=(C D g S M h) - shrt2+=(p) - long1+=(geninteg srcbuild makepkg help) - long2+=() - - # Feed the options through getopt (sanitize them) - local shrt long args - shrt="$({ printf '%s\0' "${shrt1[@]}"; printf '%s:\0' "${shrt2[@]}"; } | sort -zu | xargs -0 printf '%s')" - long="$({ printf '%s\0' "${long1[@]}"; printf '%s:\0' "${long2[@]}"; } | sort -zu | xargs -0 printf '%s,')" - args="$(getopt -n "$cmd" -o "$shrt" -l "${long%,}" -- "$@")" || ret=$EXIT_INVALIDARGUMENT - eval "set -- $args" - unset shrt long args - - # Parse the options. - local opt optarg have_optarg - while [[ $# -gt 0 ]]; do - opt=$1; shift - have_optarg=false - - if { [[ $opt == --?* ]] && in_array "${opt#--}" "${long2[@]}"; } \ - || { [[ $opt == -? ]] && in_array "${opt#-}" "${shrt2[@]}"; } - then - optarg=$1; shift - have_optarg=true - fi - - case "$opt" in - -C) mode=create;; - -D) mode=download;; - -g|--geninteg) mode=checksums;; - -S|--srcbuild) mode=srcbuild;; - -M|--makepkg) mode=makepkg;; - -p) BUILDFILE="$(realpath -Lm -- "$optarg")";; - -h|--help) mode=help;; - --) break;; - *) - makepkg_opts+=("$opt") - if $have_optarg; then makepkg_opts+=("$optarg"); fi - ;; - esac - done - extra_opts+=("$@") - - # check the number of extra_opts - case "$mode" in - help) # don't worry about it - :;; - checksums|srcbuild|makepkg) # don't take any extra arguments - if [[ ${#extra_opts[@]} != 0 ]]; then - print "%s: found extra non-flag arguments: %s" "$cmd" "${extra_opts[*]}" >&2 - ret=$EXIT_INVALIDARGUMENT - fi - ;; - *download*|*create*) # take 1 or 2 extra arguments - if [[ ${#extra_opts[@]} != 1 ]] && [[ ${#extra_opts[@]} != 2 ]]; then - print "%s: %d non-flag arguments found, expected 1 or 2: %s" "$cmd" ${#extra_opts[@]} >&2 - ret=$EXIT_INVALIDARGUMENT - fi - ;; - esac - - return $ret + declare -i ret=$EXIT_SUCCESS + local {shrt,long}{1,2} + + # makepkg options + local makepkg_orig + makepkg_orig="$(which makepkg)" + shrt1=($(LC_ALL=C "${makepkg_orig}" -h | sed -rn 's/^ +-(.)(,| [^<]).*/\1/p')) + shrt2=($(LC_ALL=C "${makepkg_orig}" -h | sed -rn 's/^ +-(.) <.*/\1/p')) + long1=($(LC_ALL=C "${makepkg_orig}" -h | sed -rn -e 's/^ +(-., )?--(\S*) [^<].*/\2/p')) + long2=($(LC_ALL=C "${makepkg_orig}" -h | sed -rn 's/^ +--(\S*) <.*/\1/p')) + + # librefetch options + shrt1+=(C D g S M h) + shrt2+=(p) + long1+=(geninteg srcbuild makepkg help) + long2+=() + + # Feed the options through getopt (sanitize them) + local shrt long args + shrt="$({ printf '%s\0' "${shrt1[@]}"; printf '%s:\0' "${shrt2[@]}"; } | sort -zu | xargs -0 printf '%s')" + long="$({ printf '%s\0' "${long1[@]}"; printf '%s:\0' "${long2[@]}"; } | sort -zu | xargs -0 printf '%s,')" + args="$(getopt -n "$cmd" -o "$shrt" -l "${long%,}" -- "$@")" || ret=$EXIT_INVALIDARGUMENT + eval "set -- $args" + unset shrt long args + + # Parse the options. + local opt optarg have_optarg + while [[ $# -gt 0 ]]; do + opt=$1; shift + have_optarg=false + + if { [[ $opt == --?* ]] && in_array "${opt#--}" "${long2[@]}"; } \ + || { [[ $opt == -? ]] && in_array "${opt#-}" "${shrt2[@]}"; } + then + optarg=$1; shift + have_optarg=true + fi + + case "$opt" in + -C) mode=create;; + -D) mode=download;; + -g|--geninteg) mode=checksums;; + -S|--srcbuild) mode=srcbuild;; + -M|--makepkg) mode=makepkg;; + -p) BUILDFILE="$(realpath -Lm -- "$optarg")";; + -h|--help) mode=help;; + --) break;; + *) + makepkg_opts+=("$opt") + if $have_optarg; then makepkg_opts+=("$optarg"); fi + ;; + esac + done + extra_opts+=("$@") + + # check the number of extra_opts + case "$mode" in + help) # don't worry about it + :;; + checksums|srcbuild|makepkg) # don't take any extra arguments + if [[ ${#extra_opts[@]} != 0 ]]; then + print "%s: found extra non-flag arguments: %s" "$cmd" "${extra_opts[*]}" >&2 + ret=$EXIT_INVALIDARGUMENT + fi + ;; + *download*|*create*) # take 1 or 2 extra arguments + if [[ ${#extra_opts[@]} != 1 ]] && [[ ${#extra_opts[@]} != 2 ]]; then + print "%s: %d non-flag arguments found, expected 1 or 2: %s" "$cmd" ${#extra_opts[@]} >&2 + ret=$EXIT_INVALIDARGUMENT + fi + ;; + esac + + return $ret } # Modify makepkg ############################################################### modified_makepkg() { - local dir - dir="$(mktemp --tmpdir --directory "${cmd}.XXXXXXXXXXX.makepkg")" - make -s -f "$(librelib librefetchdir/Makefile)" new="$dir" - realpath -es "$dir/makepkg" + local dir + dir="$(mktemp --tmpdir --directory "${cmd}.XXXXXXXXXXX.makepkg")" + make -s -f "$(librelib librefetchdir/Makefile)" new="$dir" + realpath -es "$dir/makepkg" } # Modify PKGBUILD ############################################################## @@ -366,46 +366,46 @@ package() { cp -a "$srcdir"/*/ "$pkgdir/"; } ' modified_pkgbuild() { - local pkgbuild=$1 - local srcbuild - srcbuild="$(mktemp "${pkgbuild%/*}/${cmd}.XXXXXXXXXXX.PKGBUILD.to.SRCBUILD")" - printf '%s' "$pkgbuild_append" | cat "$pkgbuild" - > "$srcbuild" - printf '%s\n' "$srcbuild" + local pkgbuild=$1 + local srcbuild + srcbuild="$(mktemp "${pkgbuild%/*}/${cmd}.XXXXXXXXXXX.PKGBUILD.to.SRCBUILD")" + printf '%s' "$pkgbuild_append" | cat "$pkgbuild" - > "$srcbuild" + printf '%s\n' "$srcbuild" } # Modify SRCBUILD ############################################################## modified_srcbuild() { - local orig=$1 - local new - new="$(mktemp "${orig%/*}/${cmd}.XXXXXXXXXXX.SRCBUILD.to.SRCBUILD")" - sed -e '/PKGDEST=/d' -e '/PKGEXT=/d' < "$orig" > "$new" - printf '%s\n' "$new" + local orig=$1 + local new + new="$(mktemp "${orig%/*}/${cmd}.XXXXXXXXXXX.SRCBUILD.to.SRCBUILD")" + sed -e '/PKGDEST=/d' -e '/PKGEXT=/d' < "$orig" > "$new" + printf '%s\n' "$new" } ################################################################################ # This function is taken almost verbatim from makepkg create_signature() { - local ret=$EXIT_SUCCESS - local filename="$1" - msg "Signing package..." + local ret=$EXIT_SUCCESS + local filename="$1" + msg "Signing package..." - local SIGNWITHKEY=() - if [[ -n $GPGKEY ]]; then - SIGNWITHKEY=(-u "${GPGKEY}") - fi + local SIGNWITHKEY=() + if [[ -n $GPGKEY ]]; then + SIGNWITHKEY=(-u "${GPGKEY}") + fi - gpg --detach-sign --use-agent "${SIGNWITHKEY[@]}" --no-armor "$filename" &>/dev/null || ret=$EXIT_FAILURE + gpg --detach-sign --use-agent "${SIGNWITHKEY[@]}" --no-armor "$filename" &>/dev/null || ret=$EXIT_FAILURE - if (( ! ret )); then - msg2 "Created signature file %s." "$filename.sig" - else - error "Failed to sign package file." - return $ret - fi + if (( ! ret )); then + msg2 "Created signature file %s." "$filename.sig" + else + error "Failed to sign package file." + return $ret + fi } diff --git a/src/pkgbuild-summarize-nonfree b/src/pkgbuild-summarize-nonfree index fe0e342..dd063bc 100755 --- a/src/pkgbuild-summarize-nonfree +++ b/src/pkgbuild-summarize-nonfree @@ -31,78 +31,78 @@ declare -ri _E_PKG_NONFREE=32 usage() { - print "Usage: %s [OPTIONS] STATUS" "${0##*/}" - print "Summarizes a status code from pkgbuild-check-nonfree" - echo - prose 'It thresholds the issues it finds, only failing for error-level - issues, and ignoring warnings. Unless `-q` is specified, it also - prints a summary of the issues it found.' - echo - print 'Options:' - flag '-q' 'Be quiet' - flag '-h' 'Show this message' + print "Usage: %s [OPTIONS] STATUS" "${0##*/}" + print "Summarizes a status code from pkgbuild-check-nonfree" + echo + prose 'It thresholds the issues it finds, only failing for error-level + issues, and ignoring warnings. Unless `-q` is specified, it also + prints a summary of the issues it found.' + echo + print 'Options:' + flag '-q' 'Be quiet' + flag '-h' 'Show this message' } main() { - local quiet=false - while getopts 'qh' arg; do - case "$arg" in - q) quiet=true;; - h) usage; exit $EXIT_SUCCESS;; - *) usage >&2; exit $EXIT_INVALIDARGUMENT;; - esac - done - shift $((OPTIND - 1)) - if [[ $# -ne 1 ]]; then - usage >&2 - exit $EXIT_INVALIDARGUMENT - fi - if ! [[ $1 =~ ^[0-9]+$ ]]; then - error 'STATUS must be an integer' - usage >&2 - exit $EXIT_INVALIDARGUMENT - fi + local quiet=false + while getopts 'qh' arg; do + case "$arg" in + q) quiet=true;; + h) usage; exit $EXIT_SUCCESS;; + *) usage >&2; exit $EXIT_INVALIDARGUMENT;; + esac + done + shift $((OPTIND - 1)) + if [[ $# -ne 1 ]]; then + usage >&2 + exit $EXIT_INVALIDARGUMENT + fi + if ! [[ $1 =~ ^[0-9]+$ ]]; then + error 'STATUS must be an integer' + usage >&2 + exit $EXIT_INVALIDARGUMENT + fi - if $quiet; then - error() { :; } - warning() { :; } - fi + if $quiet; then + error() { :; } + warning() { :; } + fi - parse "$1" + parse "$1" } parse() { - [[ $# == 1 ]] || panic 'malformed call to parse' - declare -i s=$1; + [[ $# == 1 ]] || panic 'malformed call to parse' - declare -i ret=$EXIT_SUCCESS - declare -i i + declare -i s=$1; + declare -i ret=$EXIT_SUCCESS + declare -i i - for i in 1 2 4 8 16 32; do - if [[ $((s & i)) -gt 0 ]]; then - case $i in - $_E_ERROR) - # could be anything, assume the worst - error "There was an error processing the PKGBUILD" - ret=$EXIT_FAILURE;; - $_E_LIC_UNKNOWN) - warning "This PKGBUILD has an unknown license";; - $_E_LIC_NOGPL) - warning "This PKGBUILD has a GPL-incompatible license";; - $_E_LIC_NONFREE) - error "This PKGBUILD has a known nonfree license" - ret=$EXIT_FAILURE;; - $_E_DEP_NONFREE) - error "This PKGBUILD depends on known nonfree packages" - ret=$EXIT_FAILURE;; - $_E_PKG_NONFREE) - error "This PKGBUILD is for a known nonfree package" - ret=$EXIT_FAILURE;; - esac - fi - done + for i in 1 2 4 8 16 32; do + if [[ $((s & i)) -gt 0 ]]; then + case $i in + $_E_ERROR) + # could be anything, assume the worst + error "There was an error processing the PKGBUILD" + ret=$EXIT_FAILURE;; + $_E_LIC_UNKNOWN) + warning "This PKGBUILD has an unknown license";; + $_E_LIC_NOGPL) + warning "This PKGBUILD has a GPL-incompatible license";; + $_E_LIC_NONFREE) + error "This PKGBUILD has a known nonfree license" + ret=$EXIT_FAILURE;; + $_E_DEP_NONFREE) + error "This PKGBUILD depends on known nonfree packages" + ret=$EXIT_FAILURE;; + $_E_PKG_NONFREE) + error "This PKGBUILD is for a known nonfree package" + ret=$EXIT_FAILURE;; + esac + fi + done - return $ret + return $ret } |