#!/bin/bash # # SPDX-License-Identifier: GPL-3.0-or-later m4_include(lib/common.sh) source /usr/share/makepkg/util/config.sh source /usr/share/makepkg/util/message.sh set -e usage() { cat <<- _EOF_ Usage: ${BASH_SOURCE[0]##*/} [COMMAND] [OPTIONS] Manage Git packaging repositories and helps with their configuration according to distro specs. Git author information and the used signing key is set up from makepkg.conf read from any valid location like /etc or XDG_CONFIG_HOME. The configure command can be used to synchronize the distro specs and makepkg.conf settings for previously cloned repositories. The unprivileged option can be used for cloning packaging repositories without SSH access using read-only HTTPS. COMMANDS clone Clone a package repository configure Configure a clone according to distro specs OPTIONS -h, --help Show this help text _EOF_ } usage_clone() { cat <<- _EOF_ Usage: ${BASH_SOURCE[0]##*/} clone [OPTIONS] [PKGNAME...] Clone Git packaging repositories from the canonical namespace. The configure command is subsequently invoked to synchronize the distro specs and makepkg.conf settings. The unprivileged option can be used for cloning packaging repositories without SSH access using read-only HTTPS. OPTIONS -m, --maintainer=NAME Clone all packages of the named maintainer -u, --unprivileged Clone package with read-only access and without packager info as Git author. -h, --help Show this help text _EOF_ } usage_configure() { cat <<- _EOF_ Usage: ${BASH_SOURCE[0]##*/} configure [OPTIONS] [PATH...] Configure Git packaging repositories according to distro specs and makepkg.conf settings. Git author information and the used signing key is set up from makepkg.conf read from any valid location like /etc or XDG_CONFIG_HOME. The unprivileged option can be used for cloning packaging repositories without SSH access using read-only HTTPS. OPTIONS -u, --unprivileged Configure read-only repo without packager info as Git author. -h, --help Show this help text _EOF_ } if (( $# < 1 )); then usage exit 1 fi # commands CLONE=0 CONFIGURE=0 # options GIT_REPO_BASE_URL=${GIT_PACKAGING_URL_SSH} UNPRIVILEGED=0 MAINTAINER= PACKAGER_NAME= PACKAGER_EMAIL= # command checking while (( $# )); do case $1 in -h|--help) usage exit 0 ;; clone) CLONE=1 CONFIGURE=1 shift break ;; configure) CONFIGURE=1 shift break ;; *) die "invalid argument: %s" "$1" ;; esac done if (( CLONE )); then # option checking if (( $# < 1 )); then usage_clone exit 1 fi while (( $# )); do case $1 in -h|--help) usage_clone exit 0 ;; -u|--unprivileged) GIT_REPO_BASE_URL=${GIT_PACKAGING_URL_HTTPS} UNPRIVILEGED=1 shift ;; -m|--maintainer) (( $# <= 1 )) && die "missing argument for %s" "$1" MAINTAINER="$2" shift 2 ;; --maintainer=*) MAINTAINER="${1#*=}" shift ;; --) shift break ;; -*) die "invalid argument: %s" "$1" ;; *) break ;; esac done elif (( CONFIGURE )); then # option checking if (( $# < 1 )); then usage_configure exit 1 fi while (( $# )); do case $1 in -h|--help) usage_configure exit 0 ;; -u|--unprivileged) GIT_REPO_BASE_URL=${GIT_PACKAGING_URL_HTTPS} UNPRIVILEGED=1 shift ;; --) shift break ;; -*) die "invalid argument: %s" "$1" ;; *) break ;; esac done fi pkgbases=("$@") # Load makepkg.conf variables to be available load_makepkg_config # Check official packaging identity before setting Git author if (( ! UNPRIVILEGED )); then if [[ $PACKAGER == *"Unknown Packager"* ]]; then die "Packager must be set in makepkg.conf" fi packager_pattern="(.+) <(.+@.+)>" if [[ ! $PACKAGER =~ $packager_pattern ]]; then die "Invalid Packager format '${PACKAGER}' in makepkg.conf" fi PACKAGER_NAME=$(echo "${PACKAGER}"|sed -E "s/${packager_pattern}/\1/") PACKAGER_EMAIL=$(echo "${PACKAGER}"|sed -E "s/${packager_pattern}/\2/") if [[ ! $PACKAGER_EMAIL =~ .+@archlinux.org ]]; then die "Packager email '${PACKAGER_EMAIL}' is not an @archlinux.org address" fi fi # Query packages of a maintainer if [[ -n ${MAINTAINER} ]]; then stat_busy "Query packages for ${MAINTAINER}" max_pages=$(curl --silent --location --fail --retry 3 --retry-delay 3 "https://archlinux.org/packages/search/json/?sort=name&maintainer=${MAINTAINER}" | jq -r '.num_pages') mapfile -t pkgbases < <(for page in $(seq "${max_pages}"); do curl --silent --location --fail --retry 3 --retry-delay 3 "https://archlinux.org/packages/search/json/?sort=name&maintainer=${MAINTAINER}&page=${page}" | jq -r '.results[].pkgbase' stat_progress done | sort --unique) stat_done fi for pkgbase in "${pkgbases[@]}"; do if (( CLONE )); then if [[ ! -d ${pkgbase} ]]; then msg "Cloning ${pkgbase} ..." remote_url="${GIT_REPO_BASE_URL}/${pkgbase}.git" git clone --origin origin "${remote_url}" else warning "Skip cloning ${pkgbase}: Directory exists" fi fi if (( CONFIGURE )); then msg "Configuring $(basename "${pkgbase}") ..." path=${pkgbase} if [[ ! -d "${path}/.git" ]]; then error "Not a Git repository: ${path}" continue fi giturl=$(git -C "${path}" remote get-url origin) if [[ ${giturl} != *${GIT_PACKAGING_NAMESPACE}* ]]; then error "Not a packaging repository: ${path}" continue fi pkgbase=$(basename "${giturl}") pkgbase=${pkgbase%.git} remote_url="${GIT_REPO_BASE_URL}/${pkgbase}.git" git -C "${path}" remote set-url origin "${remote_url}" git -C "${path}" config devtools.version "${GIT_REPO_SPEC_VERSION}" git -C "${path}" config commit.gpgsign true git -C "${path}" config pull.rebase true git -C "${path}" config branch.main.rebase true if (( ! UNPRIVILEGED )); then git -C "${path}" config user.name "${PACKAGER_NAME}" git -C "${path}" config user.email "${PACKAGER_EMAIL}" if [[ -n $GPGKEY ]]; then git -C "${path}" config user.signingKey "${GPGKEY}" fi fi fi done