#!/bin/sh # # Copyright (c) 2020 - 2023 Peter Pentchev # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. set -e usage() { cat <<'EOUSAGE' Usage: repopush [-Nv] local remote repopush [-Nv] [-f configfile] -s section EOUSAGE } debug() { [ -z "$v" ] || printf -- '%s\n' "$*" 1>&2 } taste_dep_repo() { local locpath="$1" if [ -d "$locpath/dists" ] && [ -d "$locpath/pool" ]; then echo 'deb' fi } taste_yum_repo() { local locpath="$1" local arches valid_arches arch if [ ! -d "$locpath/SRPMS/Sources" ]; then return fi arches="$(cd -- "$locpath" && find . -mindepth 2 -maxdepth 2 -type d -path '*/repodata' \! -path './SRPMS/repodata' | cut -d/ -f2 | xargs -r)" if [ -z "$arches" ]; then return fi valid_arches='' for arch in $arches; do if [ -d "$locpath/$arch/Packages" ]; then valid_arches="$valid_arches $arch" fi done if [ -z "$valid_arches" ]; then return fi echo "yum$valid_arches" } taste_repo() { local locpath="$1" local repo_params repo_params="$(taste_dep_repo "$locpath")" if [ -n "$repo_params" ]; then printf -- '%s\n' "$repo_params" return fi repo_params="$(taste_yum_repo "$locpath")" if [ -n "$repo_params" ]; then printf -- '%s\n' "$repo_params" return fi # *crickets* } rsync_step() { local n="$1" ntotal="$2" desc="$3" path="$4" delete="$5" debug "- $n/$ntotal: $desc" rsync ${noop:+-n} ${v:+-v} -az ${delete:+--delete} -- "$locpath$path/" "$remote$path/" } sync_debrepo() { local locpath="$1" remote="$2" echo "Syncing a Debian repository $locpath -> $remote" rsync_step 1 4 'pool' /pool '' rsync_step 2 4 'dists' /dists '' rsync_step 3 4 'all without --delete' '' '' rsync_step 4 4 'all with --delete' '' '--delete' } sync_yumrepo() { local locpath="$1" remote="$2" arches="$3" echo "Syncing a Yum repository $locpath -> $remote ($arches)" rsync_step 1 6 'Sources' /SRPMS/Sources '' for arch in $arches; do rsync_step 2 6 "Packages $arch" "/$arch/Packages" '' done rsync_step 3 6 'source repodata' /SRPMS/repodata '' for arch in $arches; do rsync_step 4 6 "$arch repodata" "/$arch/repodata" '' done rsync_step 5 6 'all without --delete' '' '' rsync_step 6 6 'all with --delete' '' '--delete' } cfgfile="${XDG_CONFIG_HOME-$HOME/.config}/repopush.conf" unset noop section v while getopts 'f:Ns:v' o; do case "$o" in f) cfgfile="$OPTARG" ;; N) noop='-n' ;; s) section="$OPTARG" ;; v) v='-v' ;; *) usage 1>&2 exit 1 ;; esac done shift "$((OPTIND - 1))" if [ -z "$section" ]; then if [ "$#" -ne 2 ]; then usage 1>&2 exit 1 fi locpath="$1" remote="$2" else if [ "$#" -ne 0 ]; then usage 1>&2 exit 1 fi debug "Looking for the '$section' section in $cfgfile" locpath="$(confget -f "$cfgfile" -s "$section" local)" if [ -z "$locpath" ]; then echo "Could not fetch $section.local from $cfgfile" 1>&2 exit 1 fi remote="$(confget -f "$cfgfile" -s "$section" remote)" if [ -z "$remote" ]; then echo "Could not fetch $section.remote from $cfgfile" 1>&2 exit 1 fi fi if [ "$locpath" != '/' ]; then locpath="${locpath%/}" fi if [ "$remote" != '/' ]; then remote="${remote%/}" fi if [ ! -d "$locpath" ]; then echo "Not a directory: $locpath" 1>&2 exit 1 fi repo_params="$(taste_repo "$locpath")" if [ -z "$repo_params" ]; then echo "Cannot determine the type of the repository at $locpath" 1>&2 exit 1 fi repo_type="${repo_params%% *}" repo_args="${repo_params#* }" case "$repo_type" in deb) sync_debrepo "$locpath" "$remote" ;; yum) sync_yumrepo "$locpath" "$remote" "$repo_args" ;; *) echo "Internal error: repo params '$repo_params'" 1>&2 exit 1 ;; esac