diff --git a/scripts/apk/ci-package-cache.sh b/scripts/apk/ci-package-cache.sh index 22e04b9..1a09d44 100755 --- a/scripts/apk/ci-package-cache.sh +++ b/scripts/apk/ci-package-cache.sh @@ -14,7 +14,7 @@ command_name="${1:-prepare}" all_packages() { while IFS= read -r package_dir; do apk_package_name "${package_dir}" - done < <(apk_package_dirs "${repo_root}") + done < <(apk_all_package_dirs "${repo_root}") } mark_all_packages() { @@ -97,23 +97,7 @@ package_apk_names() { local package_dir="$1" local arch="$2" - ( - set +u - local pkgname - local pkgver - local pkgrel - local subpackages - export CARCH="${arch}" - cd "${package_dir}" - # shellcheck source=/dev/null - . ./APKBUILD - - printf '%s-%s-r%s.apk\n' "${pkgname}" "${pkgver}" "${pkgrel}" - for subpackage in ${subpackages:-}; do - subpackage="${subpackage%%:*}" - printf '%s-%s-r%s.apk\n' "${subpackage}" "${pkgver}" "${pkgrel}" - done - ) + apk_package_apk_names "${package_dir}" "${arch}" } package_cache_complete() { @@ -155,7 +139,46 @@ select_missing_packages() { if ! package_cache_complete "${package_dir}"; then printf '%s\n' "${package_name}" fi - done < <(apk_package_dirs "${repo_root}") + done < <(apk_all_package_dirs "${repo_root}") +} + +prune_stale_apks() { + local package_dir + local arch + local apk_name + local current_apk + declare -A expected_apks=() + + if [[ ! -d "${repo_dest}" ]]; then + return + fi + + while IFS= read -r package_dir; do + apk_validate_package_dir "${package_dir}" + for arch in ${arches}; do + case "${arch}" in + x86_64|aarch64) ;; + *) printf 'unsupported Alpine architecture: %s\n' "${arch}" >&2; exit 2 ;; + esac + + if ! apk_package_supports_arch "${package_dir}" "${arch}"; then + continue + fi + + while IFS= read -r apk_name; do + expected_apks["${repo_dest}/${arch}/${apk_name}"]=1 + done < <(package_apk_names "${package_dir}" "${arch}") + done + done < <(apk_all_package_dirs "${repo_root}") + + shopt -s nullglob + for current_apk in "${repo_dest}"/*/*.apk; do + if [[ -z "${expected_apks[${current_apk}]:-}" ]]; then + rm -f "${current_apk}" + printf 'Pruned stale cached APK: %s\n' "${current_apk#"${repo_root}/"}" + fi + done + shopt -u nullglob } prepare() { @@ -164,6 +187,7 @@ prepare() { declare -A selected_map=() restore_cache + prune_stale_apks while IFS= read -r selected; do [[ -n "${selected}" ]] || continue @@ -205,6 +229,7 @@ sync_cache() { exit 1 fi + prune_stale_apks mkdir -p "${cache_root}" find "${cache_root}" -mindepth 1 -maxdepth 1 -exec rm -rf {} + cp -a "${repo_dest}/." "${cache_root}/" diff --git a/scripts/apk/list-packages.sh b/scripts/apk/list-packages.sh index 671e969..0a660ee 100755 --- a/scripts/apk/list-packages.sh +++ b/scripts/apk/list-packages.sh @@ -2,7 +2,25 @@ set -euo pipefail repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +# shellcheck source=scripts/apk/package-lib.sh +. "${repo_root}/scripts/apk/package-lib.sh" + repo_dir="${repo_root}/packages/local" +arches="${ALPINE_ARCHES:-x86_64 aarch64}" +declare -A expected_apks=() + +while IFS= read -r package_source_dir; do + apk_validate_package_dir "${package_source_dir}" + for arch in ${arches}; do + if ! apk_package_supports_arch "${package_source_dir}" "${arch}"; then + continue + fi + + while IFS= read -r apk_name; do + expected_apks["${repo_dir}/${arch}/${apk_name}"]=1 + done < <(apk_package_apk_names "${package_source_dir}" "${arch}") + done +done < <(apk_all_package_dirs "${repo_root}") if [[ -n "${ALPINE_ARCH:-}" ]]; then package_dirs=("${repo_dir}/${ALPINE_ARCH}") @@ -29,6 +47,10 @@ for package_dir in "${package_dirs[@]}"; do printf '## %s\n' "$(basename "${package_dir}")" for apk in "${apks[@]}"; do + if [[ -z "${expected_apks[${apk}]:-}" ]]; then + printf 'Skipping stale local APK: %s\n' "${apk#"${repo_root}/"}" + continue + fi printf '### %s\n' "$(basename "${apk}")" tar -xOf "${apk}" .PKGINFO 2>/dev/null \ | sed -n '/^pkgname =/p;/^pkgver =/p;/^arch =/p;/^depend =/p;/^provides =/p;/^install_if =/p' diff --git a/scripts/apk/package-lib.sh b/scripts/apk/package-lib.sh index f415dff..f1b5c2e 100644 --- a/scripts/apk/package-lib.sh +++ b/scripts/apk/package-lib.sh @@ -37,6 +37,14 @@ apk_package_dirs() { return fi + apk_all_package_dirs "${repo_root}" +} + +apk_all_package_dirs() { + local repo_root="$1" + local package_root + + package_root="$(apk_package_root "${repo_root}")" find "${package_root}" -mindepth 2 -maxdepth 2 -name APKBUILD -print \ | sed 's#/APKBUILD$##' \ | sort @@ -87,6 +95,30 @@ apk_package_supports_arch() { return 1 } +apk_package_apk_names() { + local package_dir="$1" + local arch="$2" + + ( + set +u + local pkgname + local pkgver + local pkgrel + local subpackage + local subpackages + export CARCH="${arch}" + cd "${package_dir}" + # shellcheck source=/dev/null + . ./APKBUILD + + printf '%s-%s-r%s.apk\n' "${pkgname}" "${pkgver}" "${pkgrel}" + for subpackage in ${subpackages:-}; do + subpackage="${subpackage%%:*}" + printf '%s-%s-r%s.apk\n' "${subpackage}" "${pkgver}" "${pkgrel}" + done + ) +} + apk_container_package_dir() { local repo_root="$1" local package_dir="$2" diff --git a/scripts/apk/publish-gitea.sh b/scripts/apk/publish-gitea.sh index 4698c8e..7970568 100755 --- a/scripts/apk/publish-gitea.sh +++ b/scripts/apk/publish-gitea.sh @@ -2,8 +2,12 @@ set -euo pipefail repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +# shellcheck source=scripts/apk/package-lib.sh +. "${repo_root}/scripts/apk/package-lib.sh" + repo_name="${ALPINE_REPO_NAME:-local}" alpine_version="${ALPINE_VERSION:-3.24}" +arches="${ALPINE_ARCHES:-x86_64 aarch64}" branch="${ALPINE_REGISTRY_BRANCH:-v${alpine_version}}" repository="${ALPINE_REGISTRY_REPOSITORY:-${PACKAGE_NAME:-main}}" instance_url="${INSTANCE_URL:-}" @@ -46,20 +50,50 @@ if [[ "${#apks[@]}" -eq 0 ]]; then exit 1 fi +declare -A expected_apks=() +while IFS= read -r package_dir; do + apk_validate_package_dir "${package_dir}" + for arch in ${arches}; do + if ! apk_package_supports_arch "${package_dir}" "${arch}"; then + continue + fi + + while IFS= read -r apk_name; do + expected_apks["${package_root}/${arch}/${apk_name}"]=1 + done < <(apk_package_apk_names "${package_dir}" "${arch}") + done +done < <(apk_all_package_dirs "${repo_root}") + declare -A published_filenames=() unique_apks=() +stale_count=0 +duplicate_count=0 for apk in "${apks[@]}"; do filename="$(basename "${apk}")" + if [[ -z "${expected_apks[${apk}]:-}" ]]; then + printf 'Skipping stale local APK: %s\n' "${apk#"${repo_root}/"}" + stale_count=$((stale_count + 1)) + continue + fi if [[ -n "${published_filenames[${filename}]:-}" ]]; then + duplicate_count=$((duplicate_count + 1)) continue fi published_filenames["${filename}"]=1 unique_apks+=("${apk}") done +if [[ "${#unique_apks[@]}" -eq 0 ]]; then + printf 'no current APK files found under %s\n' "${package_root}" >&2 + exit 1 +fi + printf 'Publishing %d APK files to %s\n' "${#unique_apks[@]}" "${upload_url}" -if [[ "${#unique_apks[@]}" -ne "${#apks[@]}" ]]; then - printf 'Skipping %d duplicate local APK filename(s)\n' "$((${#apks[@]} - ${#unique_apks[@]}))" +if [[ "${duplicate_count}" -ne 0 ]]; then + printf 'Skipping %d duplicate local APK filename(s)\n' "${duplicate_count}" +fi +if [[ "${stale_count}" -ne 0 ]]; then + printf 'Skipping %d stale local APK file(s)\n' "${stale_count}" fi for apk in "${unique_apks[@]}"; do