diff options
Diffstat (limited to 'src/abslibre-tools/librerelease')
-rwxr-xr-x | src/abslibre-tools/librerelease | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/src/abslibre-tools/librerelease b/src/abslibre-tools/librerelease new file mode 100755 index 0000000..b7a77d3 --- /dev/null +++ b/src/abslibre-tools/librerelease @@ -0,0 +1,257 @@ +#!/usr/bin/env bash +# Librerelease +# Uploads packages and releases 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> +# Copyright (C) 2013-2014 Luke Shumaker <lukeshu@sbcglobal.net> +# +# 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> +# +# License: GNU GPLv3+ +# +# This file is part of Parabola. +# +# Parabola is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Parabola is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Parabola. If not, see <http://www.gnu.org/licenses/>. + +# create_signature() is taken from pacman:makepkg, which is GPLv2+, +# so we take the '+' to combine it with our GPLv3+. + +. libremessages +. "$(librelib conf.sh)" + +dryrun="" +upload_only=false +readonly rsync_flags=( + --no-group + --no-perms + --copy-links + --hard-links + --partial + --human-readable + --progress + -e ssh +) + +# Functions #################################################################### + +list0_files() { + 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=0 + local filename="$1" + msg "Signing package..." + + local SIGNWITHKEY=() + if [[ -n $GPGKEY ]]; then + SIGNWITHKEY=(-u "${GPGKEY}") + fi + # The signature will be generated directly in ascii-friendly format + gpg --detach-sign --use-agent "${SIGNWITHKEY[@]}" "$filename" || ret=$? + + + 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 d -name "${ABSLIBREDEST##*/}" \) -prune \ + -o \( -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 2 + 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[@]}" + cd "${WORKDIR}/staging" && find . -mindepth 1 -type d -empty \ + -exec rmdir -p {} + 2>/dev/null +} + +################################################################################ + +usage() { + print "Usage: %s [OPTIONS]" "${0##*/}" + echo + prose 'This script uploads packages on $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 1 + 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 1 ;; + esac + done + shift $(($OPTIND - 1)) + if [[ $# != 0 ]]; then + usage >&2 + return 1 + fi + + if [[ $mode == usage ]]; then + usage + return 0 + fi + + load_files makepkg + check_vars makepkg GPGKEY + load_files libretools + check_vars libretools WORKDIR REPODEST ABSLIBREDEST || return 1 + REPODEST+='/staging/' + # The following settings are actually optional + #check_vars libretools HOOKPRERELEASE HOOKPOSTRELEASE || return 1 + + "$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 +} + +clean() { + lock 8 "${WORKDIR}/staging.lock" \ + 'Waiting for an exclusive lock on the staging directory' + + local file_list="$(mktemp -t ${0##*/}.XXXXXXXXXX)" + trap "$(printf 'rm -f -- %q' "$file_list")" EXIT + list0_files > "$file_list" + + lock_close 8 + + clean_files "$file_list" +} + +release_packages() { + if [[ -n $HOOKPRERELEASE ]]; then + msg "Running HOOKPRERELEASE..." + plain '%s' "${HOOKPRERELEASE}" + bash -c "${HOOKPRERELEASE}" + fi + + lock 8 "${WORKDIR}/staging.lock" \ + 'Waiting for an exclusive lock on the staging directory' + + sign_packages || return 1 + + # 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 "$(printf 'rm -f -- %q' "$file_list")" 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%%:*}" "$(printf 'mkdir -p -- %q && cd %q && xargs -0r mkdir -pv --' "${REPODEST#*:}"{,})" + if ! rsync ${dryrun} "${rsync_flags[@]}" \ + -0 --files-from="$file_list" \ + "${WORKDIR}/staging" \ + "${REPODEST}/" + then + error "Sync failed, try again" + return 1 + fi + + clean_files "$file_list" + + if $upload_only; then + return 0 + fi + + msg "Running db-update on repos" + ssh "${REPODEST%%:*}" "$(printf 'STAGING=%q dbscripts/db-update' "${REPODEST#*:}")" + + if [[ -n $HOOKPOSTRELEASE ]]; then + msg "Running HOOKPOSTRELEASE..." + plain '%s' "${HOOKPOSTRELEASE}" + bash -c "${HOOKPOSTRELEASE}" + fi + + return 0 +} + +main "$@" |