From 76f2fd5bf34bae83e75c804130a779034775d763 Mon Sep 17 00:00:00 2001 From: Matthias Kruk Date: Wed, 14 Apr 2021 09:15:44 +0900 Subject: [PATCH] distbot: Add script to automate debian repository housekeeping This commit adds a script that automatically adds debian packages that have been placed in a queue directory to a debian package repository. --- distbot.sh | 266 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 266 insertions(+) create mode 100755 distbot.sh diff --git a/distbot.sh b/distbot.sh new file mode 100755 index 0000000..8fc3a0e --- /dev/null +++ b/distbot.sh @@ -0,0 +1,266 @@ +#!/bin/bash + +sem="distbot" + +check_config() { + local arg + + for arg in "$@"; do + if ! conf_get "$arg" &> /dev/null; then + log_error "$arg not configured" + return 1 + fi + done + + return 0 +} + +make_repo_config() { + local domain="$1" + local codename="$2" + local architectures="$3" + local gpgkeyid="$4" + local description="$5" + + echo "Origin: $domain" + echo "Label: $domain" + echo "Codename: $codename" + echo "Architectures: $architectures" + echo "Components: main" + echo "Description: $description" + echo "SignWith: $gpgkeyid" + + return 0 +} + +repo_init() { + local repo="$1" + local domain="$2" + local codename="$3" + local arch="$4" + local gpgkeyid="$5" + local description="$6" + + local config + + if ! mkdir -p "$repo/conf" &>/dev/null; then + log_error "Could not create $repo/conf" + return 1 + fi + + config=$(make_repo_config "$domain" "$codename" "$arch" \ + "$gpgkeyid" "$description") + + if ! echo "$config" > "$repo/conf/distributions"; then + return 1 + fi + + return 0 +} + +stop() { + if ! sem_post "$sem"; then + return 1 + fi + + return 0 +} + +repo_add_package() { + local repository="$1" + local codename="$2" + local package="$3" + + log_info "Adding $package to $repository:$codename" + + if ! reprepro -b "$repository" includedeb \ + "$codename" "$package"; then + return 1 + fi + + return 0 +} + +verify_package() { + local package="$1" + local output + + if ! output=$(dpkg-sig --verify "$package"); then + log_error "Could not verify signature on $package" + echo "$output" | log_highlight "dpkg-sig" | log_error + + return 1 + fi + + return 0 +} + +process_new_packages() { + local watchdir="$1" + local repodir="$2" + local codename="$3" + + local package + + while read -r package; do + local failed + + failed=true + + log_info "New package: $package" + + if ! verify_package "$package"; then + log_error "Invalid signature on package $package" + elif ! repo_add_package "$repodir" "$codename" "$package"; then + log_error "Could not process $package" + else + log_info "$package successfully added to $repodir:$codename" + failed=false + fi + + if "$failed"; then + if ! mv "$package" "$repodir/failed/."; then + log_error "Could not move $package to $dest" + fi + else + if ! rm "$package"; then + log_error "Could not remove $package" + fi + fi + done < <(find "$watchdir" -type f -iname "*.deb") + + return 0 +} + +watch_new_packages() { + local watchdir="$1" + local repodir="$2" + local codename="$3" + + local lock + + lock="$watchdir/lock" + + if ! trap stop TERM HUP INT EXIT QUIT; then + return 1 + fi + + if ! sem_init "$sem" 0; then + log_info "Looks like another instance is already running" + return 1 + fi + + while ! sem_trywait "$sem"; do + # Without the timeout, we'd wait forever even if we're told to stop + if ! inotifywait -qq -t 15 "$watchdir/queue" &>/dev/null; then + continue + fi + + if mutex_lock "$lock"; then + process_new_packages "$watchdir/queue" "$repodir" "$codename" + mutex_unlock "$lock" + else + log_error "Could not acquire lock $lock" + fi + done + + if ! sem_destroy "$sem"; then + log_error "Could not destroy semaphore $sem" + return 1 + fi + + return 0 +} + +increase_verbosity() { + local verbosity + + verbosity=$(log_get_verbosity) + ((verbosity++)) + log_set_verbosity "$verbosity" + return 0 +} + +decrease_verbosity() { + local verbosity + + verbosity=$(log_get_verbosity) + ((verbosity--)) + log_set_verbosity "$verbosity" + return 0 +} + +main() { + local repo_path + local repo_codename + local watchdir + + opt_add_arg "s" "stop" "no" 0 "Stop a running instance" + opt_add_arg "v" "verbose" "no" 0 "Be more verbose" increase_verbosity + opt_add_arg "w" "shush" "no" 0 "Be less verbose" decrease_verbosity + + if ! opt_parse "$@"; then + return 1 + fi + + if (( $(opt_get "stop") > 0 )); then + if ! stop; then + return 1 + fi + + return 0 + fi + + if ! check_config "repo.path" "repo.domain" "repo.codename" \ + "repo.architectures" "repo.gpgkey" "repo.description" "watchdir"; then + return 1 + fi + + watchdir=$(conf_get "watchdir") + repo_path=$(conf_get "repo.path") + repo_codename=$(conf_get "repo.codename") + + if ! mkdir -p "$watchdir/queue" "$watchdir/failed"; then + log_error "Could not create watchdir" + return 1 + fi + + if ! [ -d "$repo_path" ]; then + local repo_domain + local repo_arch + local repo_key + local repo_desc + + repo_domain=$(conf_get "repo.domain") + repo_arch=$(conf_get "repo.architectures") + repo_key=$(conf_get "repo.gpgkey") + repo_desc=$(conf_get "repo.description") + + log_info "Initializing repository $repo_domain:$repo_codename in $repo_path" + + if ! repo_init "$repo_path" "$repo_domain" "$repo_codename" \ + "$repo_arch" "$repo_key" "$repo_desc"; then + log_error "Could not initialize repository" + return 1 + fi + fi + + watch_new_packages "$watchdir" "$repo_path" "$repo_codename" \ + /dev/null & + disown + + return 0 +} + +{ + if ! . toolbox.sh; then + exit 1 + fi + + if ! include "log" "conf" "opt" "mutex" "sem"; then + exit 1 + fi + + main "$@" + exit "$?" +} -- 2.47.3