#!/usr/bin/env bash # Drop unsupported releases drop_unsupported_releases() { if [[ "$1" == "all" ]]; then echo "Cleanup: dropping published repositories" | sudo tee -a "${DEBUGFILE}" BUILD_FW=() else echo "Cleanup: dropping unsupported" | sudo tee -a "${DEBUGFILE}" BUILD_FW=($(grep -rw config/distributions/*/support -ve 'eos' | cut -d"/" -f3)) fi REPO=($(aptly publish list -config="${CONFIG}" --raw | sed "s/. //g")) DROP=() for i in "${REPO[@]}"; do skip= for j in "${BUILD_FW[@]}"; do [[ $i == $j ]] && { skip=1; break ; } done [[ -n $skip ]] || DROP+=("$i") done # drop for i in "${DROP[@]}"; do aptly publish drop -config="${CONFIG}" "${i}" | sudo tee -a "${DEBUGFILE}" >/dev/null done } # Display repository content # showall(){ echo "Displaying common repository contents" aptly repo show -with-packages -config="${CONFIG}" common | tail -n +7 for release in "${DISTROS[@]}"; do echo "Displaying repository contents for $release-utils" aptly repo show -with-packages -config="${CONFIG}" "${release}-utils" | tail -n +7 echo "Displaying repository contents for $release-desktop" aptly repo show -with-packages -config="${CONFIG}" "${release}-desktop" | tail -n +7 done } # Adding package # # @arg $1 string component # @arg $2 string incoming folder # @arg $3 string description # @arg $4 input folder # adding_packages() { # add deb files to repository if they are not already there if ! find "${4}${2}" -maxdepth 1 -type f -name "*.deb" 2> /dev/null | grep -q .; then return 0 fi for f in "${4}${2}"/*.deb; do # If we have a list of last known working kernels, repack BSP files to prevent upgrade to kernel that breaks if [[ -f userpatches/last-known-good.map ]]; then PACKAGE_NAME=$(dpkg-deb -W $f | awk '{ print $1 }') for g in $(cat userpatches/last-known-good-kernel-pkg.map); do # Read values from file BOARD=$(echo $g | cut -d"|" -f1); BRANCH=$(echo $g | cut -d"|" -f2); LINUXFAMILY=$(echo $g | cut -d"|" -f3) LASTKERNEL=$(echo $g | cut -d"|" -f4); if [[ ${PACKAGE_NAME} == "armbian-bsp-cli-${BOARD}-${BRANCH}" ]]; then echo "Setting last kernel upgrade for $BOARD to linux-image-$BRANCH-$BOARD=${LASTKERNEL}" tempdir=$(mktemp -d) dpkg-deb -R $f $tempdir sed -i '/^Replaces:/ s/$/, linux-image-'$BRANCH'-'$LINUXFAMILY' (>> '$LASTKERNEL'), linux-dtb-'$BRANCH'-'$LINUXFAMILY' (>> '$LASTKERNEL')/' $tempdir/DEBIAN/control dpkg-deb -b $tempdir ${f} >/dev/null fi done fi aptly repo add -remove-files -force-replace -config="${CONFIG}" "${1}" "${f}" done } # publishing repository # # $1: Input folder # $2: Output folder # $3: Command # $4: GPG password # $5: jammy,sid publishing(){ # this repository contains packages that are the same in all releases. if [[ -z $(aptly repo list -config="${CONFIG}" -raw | awk '{print $(NF)}' | grep common) ]]; then aptly repo create -config="${CONFIG}" -distribution="common" -component="main" -comment="Armbian common packages" "common" | sudo tee -a "${DEBUGFILE}" >/dev/null fi # add packages from main folder adding_packages "common" "" "main" "$1" # create snapshot UNIQUE_NAME=$(date +%s) if [[ -n $(aptly snapshot list -config="${CONFIG}" -raw | awk '{print $(NF)}' | grep "common") ]]; then aptly -config="${CONFIG}" snapshot drop common | sudo tee -a "${DEBUGFILE}" >/dev/null fi aptly -config="${CONFIG}" snapshot create common from repo common | sudo tee -a "${DEBUGFILE}" >/dev/null # make it for all that exists. It costs little extra time local distributions=($(grep -rw config/distributions/*/support -ve '' | cut -d"/" -f3)) for release in "${distributions[@]}"; do # create for each one if [[ -z $(aptly repo list -config="${CONFIG}" -raw | awk '{print $(NF)}' | grep "${release}-utils") ]]; then aptly repo create -config="${CONFIG}" -component="${release}-utils" -distribution="${release}" -comment="Armbian ${release}-utils repository" "${release}-utils" | sudo tee -a "${DEBUGFILE}" >/dev/null fi if [[ -z $(aptly repo list -config="${CONFIG}" -raw | awk '{print $(NF)}' | grep "${release}-desktop") ]]; then aptly repo create -config="${CONFIG}" -component="${release}-desktop" -distribution="${release}" -comment="Armbian ma${release}-desktop repository" "${release}-desktop" | sudo tee -a "${DEBUGFILE}" >/dev/null fi adding_packages "${release}-utils" "/extra/${release}-utils" "release utils" "$1" adding_packages "${release}-desktop" "/extra/${release}-desktop" "release desktop" "$1" # drop release utils snapshot if [[ -n $(aptly snapshot list -config="${CONFIG}" -raw | awk '{print $(NF)}' | grep "${release}-utils") ]]; then aptly -config="${CONFIG}" snapshot drop ${release}-utils | sudo tee -a "${DEBUGFILE}" 2>/dev/null fi # drop release desktop snapshot if [[ -n $(aptly snapshot list -config="${CONFIG}" -raw | awk '{print $(NF)}' | grep "${release}-desktop") ]]; then aptly -config="${CONFIG}" snapshot drop ${release}-desktop | sudo tee -a "${DEBUGFILE}" 2>/dev/null fi aptly -config="${CONFIG}" snapshot create ${release}-utils from repo ${release}-utils | sudo tee -a "${DEBUGFILE}" >/dev/null aptly -config="${CONFIG}" snapshot create ${release}-desktop from repo ${release}-desktop | sudo tee -a "${DEBUGFILE}" >/dev/null echo "Publishing $release" aptly publish \ -skip-signing \ -architectures="armhf,arm64,amd64,riscv64,i386,loong64,all" \ -passphrase="${4}" \ -origin="Armbian" \ -label="Armbian" \ -config="${CONFIG}" \ -component=main,${release}-utils,${release}-desktop \ -distribution="${release}" snapshot common ${release}-utils ${release}-desktop > /dev/null done # cleanup aptly db cleanup -config="${CONFIG}" # key mkdir -p "${2}"/public/ cp config/armbian.key "${2}"/public/ # write repo sync control file sudo date +%s > ${2}/public/control # display what we have showall } # Sign repository Release files in the given output folder using provided GPG keys # $1: Output folder path # $@: GPG key IDs to use for signing signing() { local output_folder="$1" shift local gpg_keys=("$@") if [[ ${#gpg_keys[@]} -eq 0 ]]; then echo "No GPG keys provided for signing." >&2 return 1 fi local gpg_params=("--yes" "--armor") for key in "${gpg_keys[@]}"; do if ! gpg --list-secret-keys "$key" >/dev/null 2>&1; then echo "Warning: GPG key $key not found on this system." >&2 continue fi gpg_params+=("-u" "$key") done find "$output_folder/public/dists" -type f -name Release | while read -r release_file; do local distro_path distro_path="$(dirname "$release_file")" echo "Signing release at: $distro_path" | sudo tee -a "$DEBUGFILE" gpg "${gpg_params[@]}" --clear-sign -o "$distro_path/InRelease" "$release_file" gpg "${gpg_params[@]}" --detach-sign -o "$distro_path/Release.gpg" "$release_file" done } # # $1: Input folder # $2: Output folder # $3: Command # $4: GPG password # $5: jammy,sid # $6: list of packages to delete repo-manipulate() { # read comma delimited distros into array IFS=', ' read -r -a DISTROS <<< "$5" case $3 in serve) sudo aptly serve -listen=$(ip -f inet addr | grep -Po 'inet \K[\d.]+' | grep -v 127.0.0.1 | head -1):80 -config="${CONFIG}" return 0 ;; html) cat tools/repository/header.html for release in "${DISTROS[@]}"; do echo "

$release

MainUtilsDesktop" echo "" aptly repo show -with-packages -config="${CONFIG}" "${release}-utils" | tail -n +7 | sed 's/.*/&
/' echo "" | sudo tee -a ${filename} aptly repo show -with-packages -config="${CONFIG}" "${release}-desktop" | tail -n +7 | sed 's/.*/&
/' echo "" done cat tools/repository/footer.html return 0 ;; delete) echo "Deleting $6 from common" aptly -config="${CONFIG}" repo remove common "$6" for release in "${DISTROS[@]}"; do echo "Deleting $6 from $release-utils" aptly -config="${CONFIG}" repo remove "${release}-utils" "$6" echo "Deleting $6 from $release-desktop" aptly -config="${CONFIG}" repo remove "${release}-desktop" "$6" done return 0 ;; show) showall return 0 ;; unique) # which package should be removed from all repositories IFS=$'\n' while true; do LIST=() LIST+=($(aptly repo show -with-packages -config="${CONFIG}" common | tail -n +7)) for release in "${DISTROS[@]}"; do LIST+=($(aptly repo show -with-packages -config="${CONFIG}" "${release}-utils" | tail -n +7)) LIST+=($(aptly repo show -with-packages -config="${CONFIG}" "${release}-desktop" | tail -n +7)) done LIST=($(echo "${LIST[@]}" | tr ' ' '\n' | sort -u)) new_list=() # create a human readable menu for ((n = 0; n < $((${#LIST[@]})); n++)); do new_list+=("${LIST[$n]}") new_list+=("") done LIST=("${new_list[@]}") LIST_LENGTH=$((${#LIST[@]} / 2)) exec 3>&1 TARGET_VERSION=$(dialog --cancel-label "Cancel" --backtitle "BACKTITLE" --no-collapse --title \ "Remove packages from repositories" --clear --menu "Delete" $((9 + LIST_LENGTH)) 82 65 "${LIST[@]}" 2>&1 1>&3) exitstatus=$? exec 3>&- if [[ $exitstatus -eq 0 ]]; then aptly repo remove -config="${CONFIG}" "common" "$TARGET_VERSION" for release in "${DISTROS[@]}"; do aptly repo remove -config="${CONFIG}" "${release}-utils" "$TARGET_VERSION" aptly repo remove -config="${CONFIG}" "${release}-desktop" "$TARGET_VERSION" done else return 1 fi aptly db cleanup -config="${CONFIG}" > /dev/null 2>&1 # remove empty folders find $2/public -type d -empty -print -exec rm -rf {} \; done ;; update) # remove old releases from publishing drop_unsupported_releases "all" publishing "$1" "$2" "$3" "$4" "$5" # use the signing function to sign the repository signing "$2" "DF00FAF1C577104B50BF1D0093D6889F9F0E78D5" "8CFA83D13EB2181EEF5843E41EB30FAF236099FE" ;; *) echo -e "Unknown command" return 1 ;; esac } # defaults input="output/debs-beta" output="output/repository" command="show" releases=$(grep -rw config/distributions/*/support -ve 'eos' | cut -d"/" -f3 | xargs | sed -e 's/ /,/g') help() { echo "Armbian wrapper for Aptly v1.0 (c) Igor Pecovnik, igor@armbian.com License: (MIT) Usage: $0 [ -short | --long ] -h --help displays this -i --input [input folder] -o --output [output folder] -p --password [GPG password] -r --repository [jammy,sid,bullseye,...] -l --list [\"Name (% linux*)|armbian-config\"] -c --command [show] displays packages in each repository [sign] sign repository [html] displays packages in each repository in html form [serve] serve repository - useful for local diagnostics [unique] manually select which package should be removed from all repositories [update] search for packages in input folder [delete] delete package from -l LIST of packages " exit 2 } SHORT=i:,l:,o:,c:,p:,r:,h LONG=input:,list:,output:,command:,password:,releases:,help OPTS=$(getopt -a -n repo --options $SHORT --longoptions $LONG -- "$@") DEBUGFILE="/var/log/repo-management.log" VALID_ARGUMENTS=$# # Returns the count of arguments that are in short or long options eval set -- "$OPTS" while : do case "$1" in -i | --input ) input="$2" shift 2 ;; -o | --output ) output="$2" shift 2 ;; -c | --command ) command="$2" shift 2 ;; -p | --password ) password="$2" shift 2 ;; -r | --releases ) releases="$2" shift 2 ;; -l | --list ) list="$2" shift 2 ;; -h | --help) help ;; --) shift; break ;; *) echo "Unexpected option: $1" help ;; esac done # redefine output folder in Aptly TempDir="$(mktemp -d || exit 1)" sed 's|"rootDir": ".*"|"rootDir": "'$output'"|g' tools/repository/aptly.conf > "${TempDir}"/aptly.conf CONFIG="${TempDir}/aptly.conf" # main repo-manipulate "$input" "$output" "$command" "$password" "$releases" "$list" RETURN=$? exit $RETURN