#!/usr/bin/env bash ### # # Options Section # ### set -e set -o pipefail ### # # Function Section # ### function help () { local HELP case "${1}" in general) read -r -d '' HELP << EOL Usage: repository (OPTION) Options: [ -h ] | Help [ -i ] | Include Package [ -l ] | List Repository Packages [ -r ] | Remove Package [ -u ] | Update Repository (Additional) EOL ;; include) read -r -d '' HELP << EOL Usage: repository -i (COMPONENT) (PACKAGE) Components: [ bookworm ] | Debian GNU/Linux Bookworm [ noble ] | Ubuntu GNU/Linux Noble Numbat [ trixie ] | Debian GNU/Linux Trixie Package: The package that you want to publish in the repository. EOL ;; list) read -r -d '' HELP << EOL Usage: repository -l (COMPONENT) Components: [ all ] | All distributions listed below [ bookworm ] | Debian GNU/Linux Bookworm [ noble ] | Ubuntu GNU/Linux Noble Numbat [ trixie ] | Debian GNU/Linux Trixie EOL ;; remove) read -r -d '' HELP << EOL Usage: repository -r (COMPONENT) (ARCHITECTURE) (PACKAGE) Package: The package name that you want to remove. Components: [ all ] | All distributions listed below [ bookworm ] | Debian GNU/Linux Bookworm [ noble ] | Ubuntu GNU/Linux Noble Numbat [ trixie ] | Debian GNU/Linux Trixie Architectures: - all | All architectures listed below - arm64 | ARM64 - amd64 | AMD64 EOL ;; update) read -r -d '' HELP << EOL Usage: repository -u (COMPONENT) (SERVICE) Components: [ bookworm ] | Debian GNU/Linux Bookworm [ trixie ] | Debian GNU/Linux Trixie Services: [ pve ] | Proxmox Virtual Environment [ pve-ceph ] | Proxmox Virtual Environment Ceph Squid [ pbs ] | Proxmox Backup Server EOL ;; esac /usr/bin/echo -e "${HELP}" } function proxmox-backup-server () { TMP=$(/usr/bin/mktemp --directory --quiet) trap "/usr/bin/rm --force --recursive ${TMP}" EXIT /usr/bin/wget --quiet --output-document="${TMP}/gitapi.json" "${REPOSITORY}" URLS=$(/usr/bin/grep 'browser_download_url' "${TMP}/gitapi.json" | /usr/bin/cut --delimiter='"' --fields='4') for URL in ${URLS}; do DEB=$(/usr/bin/basename "${URL}") PACKAGE=$(/usr/bin/basename "${URL%%_*}") VERSION_A="${DEB#*_}" VERSION_A="${VERSION_A%_*.deb}" VERSION_B=$(/usr/bin/reprepro --confdir '/etc/reprepro' --silent --component "${COMPONENT}" --architecture 'arm64' list "${CODENAME}" "${PACKAGE}" | /usr/bin/mawk '{print $NF}' | /usr/bin/head --lines='1') if [[ -z "${VERSION_B}" ]] || \ /usr/bin/dpkg --compare-versions "$VERSION_A" gt "${VERSION_B}" 2>/dev/null; then /usr/bin/echo '# --- --- --- --- --- #' /usr/bin/echo "Download (wofferl/proxmox-backup-arm64): ${DEB}" /usr/bin/wget --quiet --output-document="${TMP}/${DEB}" "${URL}" PACKAGE=$(/usr/bin/dpkg-deb --info "${TMP}/${DEB}" | /usr/bin/grep ' Package:' | /usr/bin/sed --expression='s/ Package: //') VERSION=$(/usr/bin/dpkg-deb --info "${TMP}/${DEB}" | /usr/bin/grep ' Version:' | /usr/bin/sed --expression='s/ Version: //') /usr/bin/echo "Repository (${COMPONENT}/arm64): ${PACKAGE} [${VERSION}]" /usr/bin/reprepro --confdir '/etc/reprepro' --silent --component "${COMPONENT}" --architecture 'arm64' includedeb "${CODENAME}" "${TMP}/${DEB}" &> '/dev/null' /usr/bin/rm --force "${TEMP}/${DEB}" fi done } function proxmox-virtual-environment () { TMP=$(/usr/bin/mktemp --directory --quiet) trap "/usr/bin/rm --force --recursive ${TMP}" EXIT declare -A DEBS declare -A VERSIONS /usr/bin/wget --quiet --output-document="${TMP}/repository.html" "${REPOSITORY}" URLS=$(/usr/bin/grep --perl-regexp --only-matching 'href="\K[^"]*(arm64|amd64|all)[^"]*\.deb' "${TMP}/repository.html") /usr/bin/sleep '3s' for DEB in ${URLS}; do NAME=$(/bin/echo "${DEB}" | /usr/bin/sed -E 's/(_[0-9].*)//') VERSION="${DEB#*_}" VERSION="${VERSION%_*.deb}" if [[ -z "${VERSIONS[$NAME]}" ]] || \ /usr/bin/dpkg --compare-versions "$VERSION" gt "${VERSIONS[$NAME]}" 2>/dev/null; then DEBS[$NAME]="$DEB" VERSIONS[$NAME]="$VERSION" fi done for DEB in "${DEBS[@]}"; do PACKAGE="${DEB%%_*}" VERSION_A="${DEB#*_}" VERSION_A="${VERSION_A%_*.deb}" VERSION_B=$(/usr/bin/reprepro --confdir '/etc/reprepro' --silent --component "${COMPONENT}" --architecture 'arm64' list "${CODENAME}" "${PACKAGE}" | /usr/bin/mawk '{print $NF}' | /usr/bin/head --lines='1') if /usr/bin/dpkg --compare-versions "$VERSION_A" gt "${VERSION_B}" 2>/dev/null; then /usr/bin/echo '# --- --- --- --- --- #' /usr/bin/echo "Download (lierfang/pxvirt): ${DEB}" /usr/bin/wget --quiet --output-document="${TMP}/${DEB}" "${REPOSITORY}${DEB}" PACKAGE=$(/usr/bin/dpkg-deb --info "${TMP}/${DEB}" | /usr/bin/grep ' Package:' | /usr/bin/sed --expression='s/ Package: //') VERSION=$(/usr/bin/dpkg-deb --info "${TMP}/${DEB}" | /usr/bin/grep ' Version:' | /usr/bin/sed --expression='s/ Version: //') /usr/bin/echo "Repository (${COMPONENT}/arm64): ${PACKAGE} [${VERSION}]" /usr/bin/reprepro --confdir '/etc/reprepro' --silent --component "${COMPONENT}" --architecture 'arm64' includedeb "${CODENAME}" "${TMP}/${DEB}" &> '/dev/null' /usr/bin/rm --force "${TMP}/${DEB}" fi unset DEBS unset VERSIONS done } ### # # Runtime Environment # ### if [[ "${EUID}" -ne '0' ]]; then /usr/bin/echo -e 'Error: Permission Denied' exit 1 fi OUTDIR=$(/usr/bin/grep 'outdir' '/etc/reprepro/options' | /usr/bin/sed --expression='s/outdir //') while getopts ':dhilru' OPT; do case "${OPT}" in d) for DEB in "${OUTDIR}/include/"*'.run'; do /usr/bin/rm --force "${DEB}" DEB="${DEB%.run}" if ! /usr/bin/dpkg-deb --info "${DEB}" &> '/dev/null'; then /usr/bin/rm --force "${DEB}" continue fi PACKAGE=$(/usr/bin/dpkg-deb --info "${DEB}" | /usr/bin/grep ' Package:' | /usr/bin/sed --expression='s/ Package: //') ARCHITECTURE=$(/usr/bin/dpkg-deb --info "${DEB}" | /usr/bin/grep ' Architecture:' | /usr/bin/sed --expression='s/ Architecture: //') case "${DEB}" in *_bookworm_*) CODENAME='bookworm' COMPONENT='bookworm' ;; *_noble_*) CODENAME='noble' COMPONENT='noble' ;; *_trixie_*) CODENAME='trixie' COMPONENT='trixie' ;; *) /usr/bin/rm --force "${DEB}" continue ;; esac if /usr/bin/reprepro --silent --confdir '/etc/reprepro' --component "${COMPONENT}" --architecture "${ARCHITECTURE}" list "${CODENAME}" "${PACKAGE}" | /usr/bin/grep --only-matching --quiet "${PACKAGE}"; then /usr/bin/reprepro --silent --confdir '/etc/reprepro' --component "${COMPONENT}" --architecture "${ARCHITECTURE}" remove "${CODENAME}" "${PACKAGE}" &> '/dev/null' fi /usr/bin/reprepro --silent --confdir '/etc/reprepro' --component "${COMPONENT}" --architecture "${ARCHITECTURE}" includedeb "${CODENAME}" "${DEB}" &> '/dev/null' /usr/bin/rm --force "${DEB}" done exit 0 ;; h) set +e help general exit 0 ;; i) COMPONENT="${2}" DEB="${3}" CODENAME="${COMPONENT%%-*}" if [[ -z "${DEB}" ]] || \ [[ -z "${COMPONENT}" ]]; then set +e help 'include' exit 0 fi if ! /usr/bin/dpkg-deb --info "${DEB}" &> '/dev/null'; then /usr/bin/echo "Error: The file '${DEB}' is not a Debian package." exit 1 fi PACKAGE=$(/usr/bin/dpkg-deb --info "${DEB}" | /usr/bin/grep ' Package:' | /usr/bin/sed --expression='s/ Package: //') VERSION=$(/usr/bin/dpkg-deb --info "${DEB}" | /usr/bin/grep ' Version:' | /usr/bin/sed --expression='s/ Version: //') ARCHITECTURE=$(/usr/bin/dpkg-deb --info "${DEB}" | /usr/bin/grep ' Architecture:' | /usr/bin/sed --expression='s/ Architecture: //') /usr/bin/echo '# --- --- --- --- --- #' /usr/bin/echo "Repository (${COMPONENT}/${ARCHITECTURE}): ${PACKAGE} [${VERSION}]" if [[ -f "${OUTDIR}/pool/${COMPONENT}/${PACKAGE:0:1}/${PACKAGE}/${PACKAGE}_${VERSION}_${ARCHITECTURE}.deb" ]]; then /usr/bin/reprepro --silent --confdir '/etc/reprepro' --component "${COMPONENT}" --architecture "${ARCHITECTURE}" remove "${CODENAME}" "${PACKAGE}" &> '/dev/null' fi /usr/bin/reprepro --silent --confdir '/etc/reprepro' --component "${COMPONENT}" --architecture "${ARCHITECTURE}" includedeb "${CODENAME}" "${DEB}" &> '/dev/null' /usr/bin/echo '# --- --- --- --- --- #' exit 0 ;; l) COMPONENT="${2}" if [[ -z "${COMPONENT}" ]]; then set +e help 'list' exit 0 fi case "${COMPONENT}" in all) /usr/bin/echo '# ---' /usr/bin/echo '# --- Repository Packages' /usr/bin/echo '# ---' /usr/bin/echo '' /usr/bin/echo '# --- Bookworm' /usr/bin/echo '' /usr/bin/reprepro --confdir '/etc/reprepro' --component 'bookworm' list 'bookworm' | /usr/bin/sed --expression='s/^\([^|]*\)|\1|//' /usr/bin/echo '' /usr/bin/echo '# --- Noble' /usr/bin/echo '' /usr/bin/reprepro --confdir '/etc/reprepro' --component 'noble' list 'noble' | /usr/bin/sed --expression='s/^\([^|]*\)|\1|//' /usr/bin/echo '' /usr/bin/echo '# --- Trixie' /usr/bin/echo '' /usr/bin/reprepro --confdir '/etc/reprepro' --component 'trixie' list 'trixie' | /usr/bin/sed --expression='s/^\([^|]*\)|\1|//' ;; bookworm) /usr/bin/echo '# ---' /usr/bin/echo '# --- Repository Packages' /usr/bin/echo '# ---' /usr/bin/echo '' /usr/bin/echo '# --- Bookworm' /usr/bin/echo '' /usr/bin/reprepro --confdir '/etc/reprepro' --component 'bookworm' list 'bookworm' | /usr/bin/sed --expression='s/^\([^|]*\)|\1|//' ;; noble) /usr/bin/echo '# ---' /usr/bin/echo '# --- Repository Packages' /usr/bin/echo '# ---' /usr/bin/echo '' /usr/bin/echo '# --- Noble' /usr/bin/echo '' /usr/bin/reprepro --confdir '/etc/reprepro' --component 'noble' list 'noble' | /usr/bin/sed --expression='s/^\([^|]*\)|\1|//' ;; trixie) /usr/bin/echo '# ---' /usr/bin/echo '# --- Repository Packages' /usr/bin/echo '# ---' /usr/bin/echo '' /usr/bin/echo '# --- Trixie' /usr/bin/echo '' /usr/bin/reprepro --confdir '/etc/reprepro' --component 'trixie' list 'trixie' | /usr/bin/sed --expression='s/^\([^|]*\)|\1|//' ;; -*|*) set +e help 'list' exit 1 ;; esac exit 0 ;; r) COMPONENTS="${2}" ARCHITECTURES="${3}" PACKAGE="${4}" if [[ -z "${PACKAGE}" ]] || \ [[ -z "${COMPONENTS}" ]] || \ [[ -z "${ARCHITECTURES}" ]]; then set +e help 'remove' exit 0 fi case "${COMPONENTS}" in all) COMPONENTS=('bookworm' 'noble' 'trixie') ;; bookworm) COMPONENTS=('bookworm') ;; noble) COMPONENTS=('noble') ;; trixie) COMPONENTS=('trixie') ;; -*|*) set +e help 'remove' exit 1 ;; esac case "${ARCHITECTURES}" in all) ARCHITECTURES=('arm64' 'amd64') ;; arm64) ARCHITECTURES=('arm64') ;; amd64) ARCHITECTURES=('amd64') ;; -*|*) set +e help 'remove' exit 1 ;; esac for COMPONENT in "${COMPONENTS[@]}"; do CODENAME="${COMPONENT%%-*}" for ARCHITECTURE in "${ARCHITECTURES[@]}"; do if /usr/bin/reprepro --silent --confdir '/etc/reprepro' --component "${COMPONENT}" --architecture "${ARCHITECTURE}" list "${CODENAME}" "${PACKAGE}" | /usr/bin/grep --only-matching --quiet "${PACKAGE}"; then /usr/bin/echo '# --- --- --- --- --- #' /usr/bin/echo "Repository (${COMPONENT}/${ARCHITECTURE}): ${PACKAGE}" /usr/bin/reprepro --silent --confdir '/etc/reprepro' --component "${COMPONENT}" --architecture "${ARCHITECTURE}" remove "${CODENAME}" "${PACKAGE}" &> '/dev/null' /usr/bin/echo '# --- --- --- --- --- #' fi done done exit 0 ;; u) CODENAME="${2}" PROJECT="${3}" if [[ -z "${CODENAME}" ]] || \ [[ -z "${PROJECT}" ]]; then set +e help update exit 0 fi case "${CODENAME}" in bookworm) case "${PROJECT}" in pve) REPOSITORY='https://mirrors.lierfang.com/pxcloud/pxvirt/dists/bookworm/main/binary-arm64/' COMPONENT='bookworm-pve' proxmox-virtual-environment ;; pve-ceph) REPOSITORY='https://mirrors.lierfang.com/pxcloud/pxvirt/dists/bookworm/ceph-squid/binary-arm64/' COMPONENT='bookworm-ceph' proxmox-virtual-environment ;; pbs) REPOSITORY="https://api.github.com/repos/wofferl/proxmox-backup-arm64/releases/tags/3.4.6-1" COMPONENT='bookworm-pbs' proxmox-backup-server ;; -*|*) set +e help update exit 1 ;; esac ;; trixie) case "${PROJECT}" in pve) REPOSITORY='https://mirrors.lierfang.com/pxcloud/pxvirt/dists/trixie/main/binary-arm64/' COMPONENT='trixie-pve' proxmox-virtual-environment ;; pve-ceph) REPOSITORY='https://mirrors.lierfang.com/pxcloud/pxvirt/dists/trixie/ceph-squid/binary-arm64/' COMPONENT='trixie-ceph' proxmox-virtual-environment ;; pbs) REPOSITORY="https://api.github.com/repos/wofferl/proxmox-backup-arm64/releases/latest" COMPONENT='trixie-pbs' proxmox-backup-server ;; -*|*) set +e help 'update' exit 1 ;; esac ;; -*|*) set +e help 'update' exit 1 ;; esac exit 0 ;; -*|*) set +e help 'general' exit 1 ;; esac done set +e help 'general' shift $((OPTIND-1))