git.lirion.de

Of git, get, and gud

summaryrefslogtreecommitdiffstats
path: root/bin
diff options
context:
space:
mode:
authormail_redacted_for_web 2024-09-15 15:29:35 +0200
committermail_redacted_for_web 2024-09-15 15:29:35 +0200
commit0d5486752d654086ca3bed648c008c60216726ba (patch)
treea8bd8f9360ea4e9835df0eb2f7ad0bebcc6d7283 /bin
downloadaptly-lirionde-503f6717d2f6dad394f700e3c940e7855309b618.tar.bz2
Initial commitHEAD0.5.0master
Diffstat (limited to 'bin')
-rwxr-xr-xbin/aptly-lirionde210
1 files changed, 210 insertions, 0 deletions
diff --git a/bin/aptly-lirionde b/bin/aptly-lirionde
new file mode 100755
index 0000000..0131fa5
--- /dev/null
+++ b/bin/aptly-lirionde
@@ -0,0 +1,210 @@
+#!/usr/bin/env bash
+
+# Manages aptly input repositories and publishes a merged output repository.
+# Structure is as follows:
+# repo1 ───> snapshot "repo1-%Y-%m-%d" ─┬─> snapshot "%Y-%m-%d" ───> publish inside $TBASE/public
+# │
+# repo2 ───> snapshot "repo2-%Y-%m-%d" ─┘
+#
+# Furthermore, our PACKAGE input folder is /tmp/aptly with repository names as subfolder, so if
+# you want a new package added inside repo1, you would place a file inside /tmp/aptly/repo1/.
+# The package would then be added and its file inside /tmp be removed.
+#
+# Why bash?
+# 1. This script is INTERACTIVE, it asks for your GPG passphrase before signing packages
+# 2. It still uses a lot of syscalls like aptly
+# 3. The steps we do are still not that resource-hungry, so the downsides while using bash are rather low
+# The combination of these three led to bash in the first iteration.
+#
+# What doesn't this script do?
+# 1. It does not create the source repos or the aptly config.
+# 2. It does not repair if one of the parts of the structure above is missing; in that case,
+# we assume an extraordinary failure and will fail ourselves. Exception: We skip failing
+# on removal if a published repo or a snapshot does not exist.
+# 3. It does not manage multiple snapshots yet. Nor does it cleanup snapshot remainders in case the script
+# is interrupted. Both can be considered a TODO.
+
+
+if [ ! -r "/etc/aptly-lirionde/aptly.conf" ];then
+ printf '/etc/aptly-lirionde/aptly.conf cannot be read, exiting!\n' >&2
+ exit 254
+else
+ # shellcheck disable=SC1091
+ source /etc/aptly-lirionde/aptly.conf || exit 254
+fi
+
+MALFORMED=0
+[ -z "$MYREPS" ] && MALFORMED=1
+[ -z "$GPGKEY" ] && MALFORMED=1
+[ -z "$GPGTESTKEY" ] && GPGKEY="$GPGTESTKEY"
+[ -z "$PBASE" ] && MALFORMED=1
+[ -z "$TBASE" ] && MALFORMED=1
+
+[ "$MALFORMED" -eq 1 ] && printf '/etc/aptly-lirionde/aptly.conf malformed, exiting.\n' >&2 && exit 253
+
+
+printf -v repjoined "%s-$(date -I) " "${MYREPS[@]}"
+
+# shellcheck disable=SC1091
+source /usr/lib/lirion/ln-initfunctions || exit 10
+
+SNDATE="$(aptly snapshot list -raw | head -n1)"
+if ! printf '%b' "$SNDATE" | grep -P '^[0-9]{4}-[0-9]{2}-[0-9]{2}$' > /dev/null; then
+ SNDATE="$(date -I)"
+fi
+printf -v repoldjoined "%s-$SNDATE " "${MYREPS[@]}"
+printf 'Snapshot suffix that will be deleted: %b\n' "$SNDATE" || exit 11
+
+printf 'Have you added all packages? :)\n'
+printf 'Starting snapshots and publication\033[s in '
+for ((i=5;i>0;--i)); do
+ printf '\r\033[u\033[K in %b...' "$i"
+ sleep 1
+done
+printf '\r\033[u\033[K:\n'
+
+for rep in "${MYREPS[@]}"; do
+ if ! aptly repo list -raw 2>/dev/null | grep -P "^${rep}$" >/dev/null; then
+ lnfail "repository ${rep} does not exist!"
+ fi
+ lnbegin "Adding packages to repo $rep"
+ if [ ! -d "${PBASE}/$rep" ]; then
+ lnskip "source directory not existing"
+ continue
+ fi
+ readarray -t debfiles < <(
+ find "${PBASE}/$rep" -type l -name "*deb" 2>/dev/null
+ find "${PBASE}/$rep" -type f -name "*deb" 2>/dev/null
+ )
+ case "${#debfiles[@]}" in
+ 0)
+ lnskip "no files in ${PBASE}/$rep"
+ ;;
+ *)
+ for debfile in "${debfiles[@]}"; do
+ lnprog "$(basename "$debfile")"
+ sleep 0.271828
+ if ! aptly repo add "$rep" "$debfile" >/dev/null 2>&1; then
+ lnfail "adding file failed"
+ exit 100
+ fi
+ if ! rm -f "$debfile" >/dev/null 2>&1; then
+ lnfail "source file removal failed"
+ exit 101
+ fi
+ done
+ lnok
+ ;;
+ esac
+done
+
+lnbegin "Unpublishing repo \"all\""
+if [ "$(aptly publish list | grep -cv '^No snapshots/local repos')" -lt 1 ]; then
+ lnskip "No snapshots / published repos"
+else
+ if ! aptly publish drop all >/dev/null 2>&1; then
+ lnfail
+ exit 110
+ fi
+fi
+lnok
+
+lnbegin "Dropping snapshots"
+for ss in "$SNDATE" ${repoldjoined%,};do
+ lnprog "$ss"
+ sleep 0.271828
+ if ! aptly snapshot list -raw | grep "^$ss\$" > /dev/null; then
+ lnprog "skipping $ss, not present"
+ sleep 0.314159
+ else
+ if ! aptly snapshot drop "$ss" >/dev/null 2>&1; then
+ lnfail
+ exit 111
+ fi
+ fi
+done
+lnok
+
+lnbegin "Creating fresh snapshots"
+for rep in "${MYREPS[@]}"; do
+ lnprog "$rep"
+ sleep 0.271828
+ if ! faketime "$(date -I) 13:37:08" aptly snapshot create \
+ "${rep}-$(date -I)" from repo "$rep" >/dev/null 2>&1; then
+ lnfail
+ exit 120
+ fi
+done
+lnok
+
+lnbegin "Merging snapshots"
+printf -v repjoined "%s-$(date -I) " "${MYREPS[@]}"
+# shellcheck disable=SC2086
+if ! aptly snapshot merge "$(date -I)" ${repjoined%,} >/dev/null 2>&1; then
+ lnfail
+ exit 121
+fi
+lnok
+
+printf 'GPG pseudo operation...'
+printf 'lel\n' > /tmp/lel
+gpg -eu "$GPGKEY" -r "$GPGTESTKEY" /tmp/lel
+rm /tmp/lel* || exit 122
+printf ' done.\n'
+
+lnbegin "Publishing snapshot result"
+if ! faketime "$(date -I) 13:37:11" aptly publish snapshot \
+ -gpg-key="$GPGKEY" -distribution='all' "$(date -I)" >/dev/null 2>&1; then
+ lnfail
+ exit 123
+fi
+lnok
+
+lnbegin "Creating aptly graphs"
+for layout in horizontal vertical; do
+ lnprog "$layout"
+ if ! aptly graph -layout="$layout" \
+ -output="${TBASE}/public/aptly-graph-${layout}.png" >/dev/null 2>&1; then
+ lnfail
+ exit 130
+ fi
+done
+lnok
+
+lnbegin "Creating sha256 checksums"
+lnprog "directories"
+if ! mkdir -p "${TBASE}/public/dists/all/utils"/binary-{amd64,arm64}/by-hash/SHA{256,512} 2>/dev/null; then
+ lnfail "directory creation failed"
+ exit 140
+fi
+lnprog "old hash removal"
+for dir in "${TBASE}/public/dists/all/utils"/binary-{amd64,arm64}/by-hash/SHA{256,512}; do
+ if ! find "$dir" -type l -exec rm -f '{}' \; ; then
+ lnfail "hash file removal failed in $dir"
+ exit 141
+ fi
+done
+lnprog "hash creation"
+for file in "${TBASE}/public/dists/all/utils"/binary-{amd64,arm64}/{Packages,Release}*;do
+ S256="$(sha256sum "$file"|awk '{print $1}')"
+ S512="$(sha512sum "$file"|awk '{print $1}')"
+ PROGSTR="SHA256 hash for $(dirname "$file")/$(basename "$file")"
+ PROGSTR="$(printf '%b' "$PROGSTR" | sed 's#.*\(/dists/\)#...\1#')"
+ lnprog "$PROGSTR"
+ unset PROGSTR
+ sleep 0.271828
+ if ! ln -fs "../../$(basename "$file")" "$(dirname "$file")/by-hash/SHA256/$S256" 2>/dev/null; then
+ lnfail "hash failed for $(dirname "$file")/$(basename "$file")"
+ exit 142
+ fi
+ PROGSTR="SHA512 hash for $(dirname "$file")/$(basename "$file")"
+ PROGSTR="$(printf '%b' "$PROGSTR" | sed 's#.*\(/dists/\)#...\1#')"
+ lnprog "$PROGSTR"
+ unset PROGSTR
+ sleep 0.271828
+ if ! ln -fs "../../$(basename "$file")" "$(dirname "$file")/by-hash/SHA512/$S512" 2>/dev/null; then
+ lnfail "hash failed for $(dirname "$file")/$(basename "$file")"
+ exit 142
+ fi
+done
+lnok