#!/usr/bin/env bash 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" arches="${ALPINE_ARCHES:-x86_64 aarch64}" branch="${ALPINE_REGISTRY_BRANCH:-v${ALPINE_VERSION:-3.24}}" repository="${ALPINE_REGISTRY_REPOSITORY:-${PACKAGE_NAME:-main}}" instance_url="${INSTANCE_URL:-}" owner="${PACKAGE_OWNER:-}" command_name="${1:-prepare}" registry_cache="${CI_REGISTRY_CACHE_DIR:-${repo_root}/.cache/ci-registry}" require_registry_config() { local name="$1" value="$2" [[ -n "${value}" ]] && return printf 'missing required CI registry setting: %s\n' "${name}" >&2 exit 2 } registry_url() { printf '%s/api/packages/%s/alpine/%s/%s\n' \ "${instance_url%/}" "${owner}" "${branch}" "${repository}" } registry_key_url() { printf '%s/api/packages/%s/alpine/key\n' "${instance_url%/}" "${owner}" } all_packages() { while IFS= read -r package_dir; do apk_package_name "${package_dir}" done < <(apk_all_package_dirs "${repo_root}") } mark_all_packages() { printf 'Rebuilding all packages: %s\n' "$1" >&2 all_packages } diff_base() { local before="${GITHUB_EVENT_BEFORE:-${CI_COMMIT_BEFORE_SHA:-}}" local base_ref="${GITHUB_BASE_REF:-}" if [[ -n "${base_ref}" ]] && git rev-parse --verify "origin/${base_ref}" >/dev/null 2>&1; then printf '%s...HEAD\n' "origin/${base_ref}" elif [[ -n "${before}" && ! "${before}" =~ ^0+$ ]] && git rev-parse --verify "${before}^{commit}" >/dev/null 2>&1; then printf '%s..HEAD\n' "${before}" elif git rev-parse --verify HEAD^ >/dev/null 2>&1; then printf 'HEAD^..HEAD\n' else return 1 fi } changed_packages() { local base changed_paths changed_path package declare -A selected=() if ! base="$(diff_base)"; then mark_all_packages "no usable git diff base" return fi if ! changed_paths="$(git diff --name-only "${base}")"; then mark_all_packages "git diff failed for ${base}" return fi while IFS= read -r changed_path; do [[ -n "${changed_path}" ]] || continue case "${changed_path}" in scripts/apk/*|.gitea/workflows/build.yml|mise.toml) mark_all_packages "shared build logic changed" return ;; packaging/alpine/local/*) package="${changed_path#packaging/alpine/local/}" selected["${package%%/*}"]=1 ;; esac done <<< "${changed_paths}" for package in "${!selected[@]}"; do printf '%s\n' "${package}" done | sort } download_registry_metadata() { local arch url require_registry_config INSTANCE_URL "${instance_url}" require_registry_config PACKAGE_OWNER "${owner}" mkdir -p "${registry_cache}" url="$(registry_url)" for arch in ${arches}; do curl --fail --silent --show-error --location \ --output "${registry_cache}/${arch}.APKINDEX.tar.gz" \ "${url}/${arch}/APKINDEX.tar.gz" done curl --fail --silent --show-error --location \ --output "${registry_cache}/registry.rsa.pub" \ "$(registry_key_url)" } load_registry_index() { local arch package_name package_version declare -gA registry_packages=() for arch in ${arches}; do while IFS=$'\t' read -r package_name package_version; do [[ -n "${package_name}" && -n "${package_version}" ]] || continue registry_packages["${arch}|${package_name}|${package_version}"]=1 done < <( tar -xOzf "${registry_cache}/${arch}.APKINDEX.tar.gz" APKINDEX | awk ' /^P:/ { package = substr($0, 3); next } /^V:/ { if (package != "") print package "\t" substr($0, 3); package = "" } ' ) done } registry_missing_packages() { local package_dir package_name arch spec spec_name spec_version missing while IFS= read -r package_dir; do apk_validate_package_dir "${package_dir}" package_name="$(apk_package_name "${package_dir}")" missing=0 for arch in ${arches}; do apk_package_supports_arch "${package_dir}" "${arch}" || continue while IFS= read -r spec; do spec_name="${spec%%=*}" spec_version="${spec#*=}" if [[ -z "${registry_packages[${arch}|${spec_name}|${spec_version}]:-}" ]]; then missing=1 printf 'Registry miss: %s (%s, %s)\n' "${package_name}" "${arch}" "${spec}" >&2 fi done < <(apk_package_versioned_names "${package_dir}" "${arch}") done [[ "${missing}" == 1 ]] && printf '%s\n' "${package_name}" done < <(apk_all_package_dirs "${repo_root}") } prepare() { local selected declare -A selected_map=() download_registry_metadata load_registry_index while IFS= read -r selected; do [[ -n "${selected}" ]] && selected_map["${selected}"]=1 done < <(changed_packages) while IFS= read -r selected; do [[ -n "${selected}" ]] && selected_map["${selected}"]=1 done < <(registry_missing_packages) ALPINE_PACKAGES="$(for selected in "${!selected_map[@]}"; do printf '%s\n' "${selected}"; done | sort | xargs)" if [[ -n "${ALPINE_PACKAGES}" ]]; then ALPINE_SKIP_BUILD=0 printf 'Selected packages for rebuild: %s\n' "${ALPINE_PACKAGES}" else ALPINE_SKIP_BUILD=1 printf 'No packages selected for rebuild: registry satisfies source metadata\n' fi if [[ -n "${GITHUB_ENV:-}" ]]; then { printf 'ALPINE_PACKAGES=%s\n' "${ALPINE_PACKAGES}" printf 'ALPINE_SKIP_BUILD=%s\n' "${ALPINE_SKIP_BUILD}" printf 'ALPINE_REGISTRY_URL=%s\n' "$(registry_url)" printf 'ALPINE_REGISTRY_KEY=%s\n' "${registry_cache}/registry.rsa.pub" } >> "${GITHUB_ENV}" fi if [[ -n "${GITHUB_OUTPUT:-}" ]]; then if [[ -n "${ALPINE_PACKAGES}" ]]; then printf 'packages_selected=true\n' >> "${GITHUB_OUTPUT}" else printf 'packages_selected=false\n' >> "${GITHUB_OUTPUT}" fi if [[ " ${ALPINE_PACKAGES} " == *" greptimedb "* ]]; then printf 'greptimedb_selected=true\n' >> "${GITHUB_OUTPUT}" else printf 'greptimedb_selected=false\n' >> "${GITHUB_OUTPUT}" fi fi } case "${command_name}" in prepare) prepare ;; *) printf 'usage: %s prepare\n' "$0" >&2; exit 2 ;; esac