diff options
author | bill-auger <mr.j.spam.me@gmail.com> | 2023-12-24 03:47:46 -0500 |
---|---|---|
committer | bill-auger <mr.j.spam.me@gmail.com> | 2024-03-28 23:13:28 -0400 |
commit | 8f1839b025e1e12d6b104b02ad8a445003c460dc (patch) | |
tree | 793e2dc8ca19a3504e64f792cf66f94d0a5f9b22 | |
parent | 2478cf7b101ec6769b45b8372c2e7aba8dd8b1d8 (diff) |
refactor librerelease
-rw-r--r-- | po/es/libretools.po | 2 | ||||
-rwxr-xr-x | src/abslibre-tools/librerelease | 306 | ||||
-rw-r--r-- | src/lib/notifications.sh | 4 | ||||
-rw-r--r-- | src/libretools.conf | 37 |
4 files changed, 191 insertions, 158 deletions
diff --git a/po/es/libretools.po b/po/es/libretools.po index fbd4122..880e915 100644 --- a/po/es/libretools.po +++ b/po/es/libretools.po @@ -341,7 +341,7 @@ msgid "Dry-run; don't actually do anything" msgstr "Dry-run; no hace nada en realidad" #: src/abslibre-tools/librerelease:139 -msgid "This program should be run as regular user" +msgid "This program should be run as unprivileged user" msgstr "Este programa debiera ser ejecutado como usuario normal" #: src/abslibre-tools/librerelease:201 diff --git a/src/abslibre-tools/librerelease b/src/abslibre-tools/librerelease index 70a20b0..24e163d 100755 --- a/src/abslibre-tools/librerelease +++ b/src/abslibre-tools/librerelease @@ -1,7 +1,7 @@ #!/usr/bin/env bash -# Librerelease -# Uploads packages and releases them +# librerelease - uploads packages to the repo server and publishes them +# # Copyright (C) 2010-2012 Joshua Ismael Haase Hernández (xihh) <hahj87@gmail.com> # Copyright (C) 2010-2013 Nicolás Reynolds <fauno@parabola.nu> # Copyright (C) 2013 Michał Masłowski <mtjm@mtjm.eu> @@ -11,13 +11,13 @@ # For just the create_signature() function: # Copyright (C) 2006-2013 Pacman Development Team <pacman-dev@archlinux.org> # Copyright (C) 2002-2006 Judd Vinet <jvinet@zeroflux.org> -# Copyright (C) 2005 Aurelien Foret <orelien@chez.com> -# Copyright (C) 2006 Miklos Vajna <vmiklos@frugalware.org> -# Copyright (C) 2005 Christian Hamar <krics@linuxforum.hu> -# Copyright (C) 2006 Alex Smith <alex@alex-smith.me.uk> -# Copyright (C) 2006 Andras Voroskoi <voroskoi@frugalware.org> +# Copyright (C) 2005 Aurelien Foret <orelien@chez.com> +# Copyright (C) 2006 Miklos Vajna <vmiklos@frugalware.org> +# Copyright (C) 2005 Christian Hamar <krics@linuxforum.hu> +# Copyright (C) 2006 Alex Smith <alex@alex-smith.me.uk> +# Copyright (C) 2006 Andras Voroskoi <voroskoi@frugalware.org> # -# License: GNU GPLv3+ +# SPDX-License-Identifier: GPL-3.0-or-later # # This file is part of Parabola Libretools. # @@ -37,17 +37,16 @@ # create_signature() is taken from pacman:makepkg, which is GPLv2+, # so we take the '+' to combine it with our GPLv3+. + set -euE -source "$(librelib conf )" -source "$(librelib messages )" -source "$(librelib notifications)" +source "$(librelib conf )" # LIBREUSER, load_conf() +source "$(librelib messages )" # setup_traps(), msg(), msg2() error(), print(), prose(), flag() +source "$(librelib notifications)" # notify_release() -setup_traps -dryrun="" -upload_only=false -readonly rsync_flags=( +declare -ri STAGING_LOCK=8 +declare -ra RSYNC_FLAGS=( --no-group --no-perms --copy-links @@ -56,7 +55,6 @@ readonly rsync_flags=( --human-readable --progress ) - DRY_RUN='' # main() UPLOAD_ONLY='' # main() TIER0_HOST='' # main() @@ -67,16 +65,24 @@ SSH_CMD='' # main() RSYNC_DEST='' # main() -# Functions #################################################################### +## helpers ## + +lock_staging() { + lock $STAGING_LOCK "${WORKDIR}/staging.lock" \ + "Waiting for an exclusive lock on the staging directory ...." +} + +unlock_staging() { + lock_close $STAGING_LOCK +} list0_files() { find -L "${WORKDIR}/staging" -type f -not -name '*.lock' \ - -exec realpath -z --relative-to="${WORKDIR}/staging" {} + + -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..." @@ -85,14 +91,13 @@ create_signature() { SIGNWITHKEY=(-u "${GPGKEY}") fi - gpg --detach-sign --use-agent "${SIGNWITHKEY[@]}" --no-armor "$filename" &>/dev/null || ret=$EXIT_FAILURE - - - if (( ! ret )); then + if gpg --detach-sign --use-agent "${SIGNWITHKEY[@]}" \ + --no-armor "$filename" &>/dev/null ; then msg2 "Created signature file %s." "$filename.sig" + return $EXIT_SUCCESS else error "Failed to sign package file." - return $ret + return $EXIT_FAILURE fi } @@ -120,20 +125,23 @@ sign_packages() { # Clean everything if not in dry-run mode clean_files() ( local file_list=$1 + local rmcmd - local rmcmd=(rm -fv) - if [[ -n "${dryrun}" ]]; then - rmcmd=(printf "$(_ "removed '%s' (dry-run)")\n") + if [[ -z "$DRY_RUN" ]]; then + rmcmd=( rm -fv ) + else + 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 -- '{}' + + -exec rmdir --ignore-fail-on-non-empty -- '{}' + ) -################################################################################ + +## The different modes ## usage() { print "Usage: %s [OPTIONS]" "${0##*/}" @@ -154,82 +162,14 @@ usage() { \$XDG_CONFIG_HOME/libretools/libretools.conf 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 - - # source makepkg and libretools configuration files - # the specified config vars will be used in this script, and so are mandatory - # optional config vars used in this script, if specified in libretools.conf: - # TIER0_LOGIN, TIER0_PORT, TIER0_STAGING, HOOKPRERELEASE, HOOKPOSTRELEASE - if ! load_conf makepkg.conf GPGKEY; then - error '$GPGKEY is not configured.' - return $EXIT_NOTCONFIGURED - elif ! load_conf libretools.conf WORKDIR TIER0_HOST DBSCRIPTS_CONFIG; then - config_error_msg WORKDIR TIER0_HOST DBSCRIPTS_CONFIG - return $EXIT_NOTCONFIGURED - fi - - # validate/sanitize tier-0 repo URL components - if [[ -n ${TIER0_HOST:-} ]]; then - # normalize or reject tilde operator in staging path - if [[ "$TIER0_STAGING" == '/~/'* ]]; then - TIER0_STAGING=${TIER0_STAGING#'/~/'} - elif [[ "$TIER0_STAGING" == '/~'* ]]; then - error "Unfortunately, tilde expansion ('~' home directory) is not supported in libretools.conf::TIER0_STAGING" - return $EXIT_NOTCONFIGURED - fi - else - config_error_msg TIER0_HOST ; return $EXIT_NOTCONFIGURED ; - fi - - # construct the SSH and rsync destination parameters - readonly TIER0_HOST - readonly TIER0_STAGING=${TIER0_STAGING:-/home/${TIER0_LOGIN:-$LIBREUSER}/staging} - readonly TIER0_LOGIN=${TIER0_LOGIN:+${TIER0_LOGIN}@} - readonly TIER0_PORT=${TIER0_PORT:+-p $TIER0_PORT} - readonly SSH_CMD=( ssh ${TIER0_PORT} ${TIER0_LOGIN}${TIER0_HOST} ) - readonly RSYNC_DEST=${TIER0_LOGIN}${TIER0_HOST}:${TIER0_STAGING%/}/ - - "$mode" + flag '-c' "Clean Local: delete packages in local staging directory" + flag '-h' "Help: Show this message" + flag '-l' "List: list packages but not upload them" + flag '-n' "Dry-run: don't actually do anything" + flag '-u' "Upload-only: do not run db-update on the server" } -# The different modes (sans 'usage') ########################################### - -pretty_print_packages() { +list() { find "$WORKDIR/staging/" -mindepth 1 -maxdepth 1 -type d -not -empty | sort | while read -r path; do msg2 "${path##*/}" @@ -239,30 +179,34 @@ pretty_print_packages() { } clean() { - lock 8 "${WORKDIR}/staging.lock" \ - 'Waiting for an exclusive lock on the staging directory' + lock_staging local file_list file_list="$(mktemp -t "${0##*/}.XXXXXXXXXX")" trap "rm -f -- ${file_list@Q}" EXIT list0_files > "$file_list" - lock_close 8 + unlock_staging clean_files "$file_list" } -release_packages() { - local tier0_port="${REPODEST_port:+-p "$REPODEST_port"}" - local tier0_host="${REPODEST_userhost}" - local ssh_cmd=( ssh ${tier0_port} ${tier0_host} ) # eg: ssh -p 1863 autobuilder@repo.parabola.nu STAGING='staging/' DBSCRIPTS_CONFIG='/etc/dbscripts/config.local.parabola' db-update - local dbupdate_cmd="STAGING=${REPODEST_path@Q} DBSCRIPTS_CONFIG=${DBSCRIPTS_CONFIG@Q} db-update" +release() { + local file_list="$( mktemp -t ${0##*/}_lst.XXXXXXXXXX)" + local dbupdate_log="$(mktemp -t ${0##*/}_log.XXXXXXXXXX)" + local mkdir_cmd="mkdir -p -- ${TIER0_STAGING@Q} && cd ${TIER0_STAGING@Q} && xargs -0r mkdir -pv --" + local dbupdate_cmd="STAGING=${TIER0_STAGING@Q} DBSCRIPTS_CONFIG=${DBSCRIPTS_CONFIG@Q} db-update" + local upload_size - # verify connection and login - if ! ${ssh_cmd[0]} -fN ${ssh_cmd[*]:1}; then - error "Connection or login failed." - return $EXIT_FAILURE - fi + trap "rm -f -- ${file_list@Q} ${dbupdate_log@Q}" INT RETURN TERM + + lock_staging + + # verify connection and login + if ! ${SSH_CMD[0]} -fN ${SSH_CMD[*]:1}; then + error "Connection or login failed." + return $EXIT_FAILURE + fi ## prepare ## @@ -275,31 +219,29 @@ release_packages() { ) fi - lock 8 "${WORKDIR}/staging.lock" \ - 'Waiting for an exclusive lock on the staging directory' - - sign_packages || return + sign_packages || return $EXIT_FAILURE - # 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). + # collect staged files and set permissions for repository-bound files + list0_files > "$file_list" + upload_size="$(cd "${WORKDIR}/staging" && du -hc --files0-from="$file_list" | sed -n '$s/\t.*//p')" 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" + unlock_staging - lock_close 8 + # prepare remote staging directory tree + msg "%s to upload" "$upload_size" + xargs -0r -a "$file_list" dirname -z | ${SSH_CMD[*]} "$mkdir_cmd" + + + ## upload ## - 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/" + if ! rsync ${DRY_RUN} "${RSYNC_FLAGS[@]}" \ + -e "ssh $SSH_PORT" \ + -0 --files-from="$file_list" \ + "${WORKDIR}/staging" \ + "$RSYNC_DEST" then error "Sync failed, try again" return $EXIT_FAILURE @@ -307,32 +249,104 @@ release_packages() { clean_files "$file_list" - if $upload_only; then + if $UPLOAD_ONLY; then return $EXIT_SUCCESS fi ## publish ## - msg "Running db-update on repos" - ${ssh_cmd[*]} "${dbupdate_cmd}" + msg "Running db-update on repos" + if ${SSH_CMD[*]} "${dbupdate_cmd}"; then # eg: ssh -p 1863 autobuilder@repo.parabola.nu STAGING='staging/' DBSCRIPTS_CONFIG='/etc/dbscripts/config.local.parabola' db-update + if [[ -n $HOOKPOSTRELEASE ]]; then + msg "Running HOOKPOSTRELEASE..." + ( + PS4=" \\[$BOLD\\]\$\\[$ALL_OFF\\] " + eval -- "set -x; $HOOKPOSTRELEASE" + ) + fi + + # notify pbot of the excellent work that we have done today + notify_release ${SSH_CMD[*]} < $file_list - if [[ -n $HOOKPOSTRELEASE ]]; then - msg "Running HOOKPOSTRELEASE..." - ( - PS4=" \\[$BOLD\\]\$\\[$ALL_OFF\\] " - eval -- "set -x; $HOOKPOSTRELEASE" - ) + return $EXIT_SUCCESS + else + return $EXIT_FAILURE fi +} - ## notify pbot of the excellent work we have done ## +## main entry ## - notify_pbot ${ssh_cmd[*]} < $file_list +main() { + # Parse CLI options + local mode=release # publish packages to public repo (default) + UPLOAD_ONLY=false # upload and publish + while getopts 'chlnu' arg; do + case $arg in + c) mode=clean ;; # empties local staging area + h) mode=usage ;; # print 'Usage' message + l) mode=list ;; # pretty-print locally-staged packages + n) DRY_RUN='--dry-run' ;; # only show what would be done + u) UPLOAD_ONLY=true ;; # upload, but do not publish + *) usage >&2 ; return $EXIT_INVALIDARGUMENT ;; + esac + done + shift $(( OPTIND - 1 )) + if [[ -w / ]]; then + error "This program should be run as unprivileged user" + return $EXIT_NOPERMISSION + elif (( $# )); then + usage >&2 + return $EXIT_INVALIDARGUMENT + elif [[ $mode == usage ]]; then + usage + return $EXIT_SUCCESS + fi + # source makepkg and libretools configuration files + # the specified config vars will be used in this script, and so are mandatory + # optional config vars used in this script, if specified in libretools.conf: + # TIER0_LOGIN, TIER0_PORT, TIER0_STAGING, HOOKPRERELEASE, HOOKPOSTRELEASE + if ! load_conf makepkg.conf GPGKEY; then + error "The %s config variable is misconfigured." \$GPGKEY + return $EXIT_NOTCONFIGURED + elif ! load_conf libretools.conf WORKDIR TIER0_HOST DBSCRIPTS_CONFIG; then + for var in WORKDIR TIER0_HOST DBSCRIPTS_CONFIG; do + [[ -n ${!var} ]] || error "The $%s config variable is misconfigured." \$$var + done + prose "The format of %s variables may have changed. + Merge the %s file, if one is present; and adapt any custom %s to it." \ + libretools.conf /etc/libretools.conf.pacnew ~/.config/libretools/libretools.conf + return $EXIT_NOTCONFIGURED + fi + + # validate/sanitize tier-0 repo URL components + if [[ "$TIER0_STAGING" == '/~/'* ]]; then + TIER0_STAGING=${TIER0_STAGING#'/~/'} + elif [[ "$TIER0_STAGING" == '/~'* ]]; then + error "Unfortunately, tilde expansion ('~' home directory) is not supported in libretools.conf::TIER0_STAGING" + return $EXIT_NOTCONFIGURED + fi - return $EXIT_SUCCESS + # finalize state + readonly DRY_RUN + readonly UPLOAD_ONLY + + # construct the SSH and rsync destination parameters + readonly TIER0_LOGIN + readonly TIER0_HOST + readonly TIER0_PORT + readonly TIER0_STAGING=${TIER0_STAGING:-/home/${TIER0_LOGIN:-$LIBREUSER}/staging} + readonly SSH_URL=${TIER0_LOGIN:+${TIER0_LOGIN}@}${TIER0_HOST} + readonly SSH_PORT=${TIER0_PORT:+-p $TIER0_PORT} + readonly SSH_CMD=( ssh ${SSH_PORT} ${SSH_URL} ) + readonly RSYNC_DEST=${SSH_URL}:${TIER0_STAGING%/}/ + + # do the requested business + $mode } +setup_traps main "$@" diff --git a/src/lib/notifications.sh b/src/lib/notifications.sh index 2aa0b0e..2457dbd 100644 --- a/src/lib/notifications.sh +++ b/src/lib/notifications.sh @@ -1,5 +1,5 @@ # process librerelease::$file_list via STDIN -notify_pbot() # ( ssh_cmd*** ) file_list->STDIN +notify_release() # ( ssh_cmd* ) file_list->STDIN { local ssh_cmd=( $* ) local repo_user=${REPOUSER:-${LIBREUSER:-somebody}} @@ -22,7 +22,7 @@ notify_pbot() # ( ssh_cmd*** ) file_list->STDIN local pbotsay_msg="$(printf "%s just published:" ${repo_user}) ${releases[@]}" local pbotsay_cmd="which pbot-say &> /dev/null && pbot-say '${pbotsay_msg}'" - if [[ ${ssh_cmd[0]} =~ ^ssh\ ]] && (( ${#releases[@]} )); then + if [[ ${ssh_cmd[0]} == ssh ]] && (( ${#releases[@]} )); then msg2 "$(_ "Notifying pbot:")" ; print " ${pbotsay_msg}" ; ${ssh_cmd[*]} "${pbotsay_cmd}" &> /dev/null || : fi diff --git a/src/libretools.conf b/src/libretools.conf index b99a347..3ed6fa6 100644 --- a/src/libretools.conf +++ b/src/libretools.conf @@ -1,27 +1,45 @@ #!/hint/bash # shellcheck disable=2034 +# System-wide Libretools configuration +# +# Users may over-ride this file in ~$LIBREUSER/.config/libretools/libretools.conf. +# This file may be copied verbatim and adapted, or the user config may simply +# redefine only the variables desired to over-ride. +# +# NOTE: * $LIBREHOME and $LIBREUSER are set in /usr/lib/libretools/conf.sh, +# implicitly, before /etc/libretools.conf and overrides are loaded +# * $DISPLAY is set implicitly by the X-server + ################################################################################ -# misc # +# general # ################################################################################ -# The dir where you work on +## The directory where you work on packages (large storage) +# This will be the parent directory of abslibre/ and staging/. +# You can keep your VCS work area tidy by assigning SRCDEST and LOGDEST +# in makepkg.conf to a subdirectory of this $$WORKDIR. +# If you do that, use absolute paths. +# $WORKDIR and $LIBREHOME are not valid in makepkg.conf when running `makepkg`. +# SRCDEST=/path/to/WORKDIR/sources +# LOGDEST=/path/to/WORKDIR/logs WORKDIR="${LIBREHOME:-}"/packages +## ABSLibre +## Used by: `createworkdir` +ABSLIBRERECV=git://git.parabola.nu/abslibre/abslibre.git +ABSLIBRESEND=ssh://git@git.parabola.nu:1863/~git/abslibre/abslibre.git + ## Blacklist URL +## Used by: `blacklist.sh` BLACKLIST=https://git.parabola.nu/blacklist.git/plain/blacklist.txt -## Diff tool (vimdiff, gvimdiff, meld, etc) +## Diff tool ## Used by `aur`, `diff-unfree` # shellcheck disable=2046 DIFFPROG=$(which $([ -z "${DISPLAY:-}" ]||echo kdiff3 meld gvimdiff) vimdiff colordiff diff 2>/dev/null|sed 's/\s.*//;1q') -## ABSLibre -## Used by: `createworkdir` -ABSLIBRERECV=git://git.parabola.nu/abslibre/abslibre.git -ABSLIBRESEND=ssh://git@git.parabola.nu:1863/~git/abslibre/abslibre.git - ################################################################################ # librerelease # @@ -85,4 +103,5 @@ TORUPATH=/var/lib/libretools/toru # inverted order of precedence. Put testing repos first so dagpkg will find new # PKGBUILDs first, for instance. `toru-path` uses reverse order to enforce repo # precedence on the path cache (the last path added replaces the rest) -REPOS=('core' 'libre' 'extra' 'community' 'libre-testing' 'social' 'sugar' 'pcr' 'java') +REPOS=( pcr{,-testing} extra core libre{,-testing} nonsystemd{,-testing} nonprism{,-testing} ) + |