diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index 7a7ad9e..9efe6ac 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -39,7 +39,7 @@ jobs: steps: - name: Prepare Environment run: | - apk add --no-cache --update abuild-rootbld alpine-sdk atools-apkbuild-lint bash ca-certificates curl doas git nodejs rsync shellcheck sudo tar + apk add --no-cache --update abuild-rootbld alpine-sdk atools-apkbuild-lint bash ca-certificates curl doas git jq nodejs rsync shellcheck sudo tar mkdir -p "$ALPINE_APK_REPO_CACHE" "$CARGO_HOME" "$RUSTUP_HOME" "$CARGO_TARGET_DIR" chown -R 1000:1000 /cache/public-alpine-packages/${{ matrix.alpine_registry_branch }} @@ -64,6 +64,7 @@ jobs: - name: Prepare package cache if: github.event_name != 'schedule' + id: package-selection run: | scripts/apk/ci-package-cache.sh prepare @@ -71,9 +72,13 @@ jobs: if: github.event_name != 'schedule' run: | scripts/apk/ci-build.sh - scripts/apk/ci-package-cache.sh sync - scripts/apk/export-ci-assets.sh - scripts/apk/list-packages.sh + if [ -d packages/local ]; then + scripts/apk/list-packages.sh + fi + + - name: Export GreptimeDB CI assets + if: github.event_name != 'schedule' && steps.package-selection.outputs.greptimedb_selected == 'true' + run: scripts/apk/export-ci-assets.sh - name: Check artifact upload support if: github.event_name != 'schedule' @@ -86,7 +91,7 @@ jobs: fi - name: Upload generated CI assets - if: github.event_name != 'schedule' && steps.artifact-upload.outputs.available == 'true' + if: github.event_name != 'schedule' && steps.package-selection.outputs.greptimedb_selected == 'true' && steps.artifact-upload.outputs.available == 'true' uses: actions/upload-artifact@v3 with: name: greptimedb-musl-binaries-${{ matrix.alpine_registry_branch }} @@ -97,9 +102,9 @@ jobs: run: scripts/apk/ci-smoke.sh - name: Runtime test - if: github.event_name != 'schedule' + if: github.event_name != 'schedule' && env.ALPINE_SKIP_BUILD != '1' run: scripts/apk/runtime-test.sh - name: Publish Alpine packages - if: github.event_name != 'pull_request' && github.event_name != 'schedule' + if: github.event_name != 'pull_request' && github.event_name != 'schedule' && env.ALPINE_SKIP_BUILD != '1' run: scripts/apk/publish-gitea.sh diff --git a/README.md b/README.md index 4af6842..eea9da1 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ apk:lint-shell Run ShellCheck for packaging automation apk:packages List built Alpine packages and dependencies apk:publish-check Run lint, multi-arch build, package listing, and smoke test apk:publish-gitea Publish built packages to the Gitea Alpine package registry -apk:outdated Check packaged upstream versions against latest GitHub releases +apk:outdated Check packaged upstream versions and release summaries apk:shell Open an Alpine package build shell in Docker apk:smoke Install-test built packages from the local repository in Docker apk:test-install Test README installation instructions in a fresh Alpine container @@ -231,10 +231,15 @@ versions fail the command: APK_UPDATE_CHECK_MODE=fail mise run apk:outdated ``` +When an update is available, the command also lists compact release-note +summaries for every release between the packaged and latest versions. + ### Gitea Workflow `.gitea/workflows/build.yml` builds and publishes `v3.24`. Pull requests -build only. +build only. CI compares source package versions with the published registry, +then rebuilds only changed or unpublished packages; local build commands keep +using their local caches. Repository variables: diff --git a/mise.toml b/mise.toml index a0cb587..a9d53b8 100644 --- a/mise.toml +++ b/mise.toml @@ -1,6 +1,7 @@ [tools] act = "latest" docker-cli = "latest" +jq = "latest" shellcheck = "latest" [tasks."apk:build"] diff --git a/packaging/alpine/local/lavinmq/APKBUILD b/packaging/alpine/local/lavinmq/APKBUILD index 60d5b7c..5f4458b 100644 --- a/packaging/alpine/local/lavinmq/APKBUILD +++ b/packaging/alpine/local/lavinmq/APKBUILD @@ -8,7 +8,7 @@ arch="x86_64" license="Apache-2.0" depends="ca-certificates /bin/sh" makedepends=" - crystal>=1.20.1 + crystal=1.21.0-r0 curl gc-dev help2man @@ -40,6 +40,7 @@ export CRYSTAL_CACHE_DIR="${CRYSTAL_CACHE_DIR:-$srcdir/crystal-cache}" export SHARDS_CACHE_PATH="${SHARDS_CACHE_PATH:-$srcdir/shards-cache}" build() { + crystal --version make make man } diff --git a/packaging/alpine/local/lavinmq/README.md b/packaging/alpine/local/lavinmq/README.md index d121673..baa8eb9 100644 --- a/packaging/alpine/local/lavinmq/README.md +++ b/packaging/alpine/local/lavinmq/README.md @@ -9,8 +9,8 @@ Build command: make ``` -LavinMQ 2.9.1 requires Crystal 1.20.1 or newer, so build with Alpine 3.24 or -newer. +LavinMQ 2.9.2 requires Crystal 1.21.0. The package pins Alpine edge's native +Crystal package, avoiding a glibc toolchain in the Alpine musl build. ## Runtime Layout diff --git a/scripts/apk/Dockerfile b/scripts/apk/Dockerfile index a780900..adad333 100644 --- a/scripts/apk/Dockerfile +++ b/scripts/apk/Dockerfile @@ -4,6 +4,9 @@ FROM alpine:${ALPINE_VERSION} ARG BUILDER_UID=1000 ARG BUILDER_GID=1000 +RUN printf '%s\n' 'https://dl-cdn.alpinelinux.org/alpine/edge/community' \ + >> /etc/apk/repositories + RUN apk add --no-cache \ abuild-rootbld \ alpine-sdk \ diff --git a/scripts/apk/ci-package-cache.sh b/scripts/apk/ci-package-cache.sh index d41b1ba..6b18fd0 100755 --- a/scripts/apk/ci-package-cache.sh +++ b/scripts/apk/ci-package-cache.sh @@ -5,11 +5,29 @@ 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}" arches="${ALPINE_ARCHES:-x86_64 aarch64}" -cache_root="${ALPINE_APK_REPO_CACHE:-/cache/public-alpine-packages/${ALPINE_REGISTRY_BRANCH:-local}/apk-repo}" -repo_dest="${repo_root}/packages/${repo_name}" +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 @@ -18,9 +36,7 @@ all_packages() { } mark_all_packages() { - local reason="$1" - - printf 'Rebuilding all packages: %s\n' "${reason}" >&2 + printf 'Rebuilding all packages: %s\n' "$1" >&2 all_packages } @@ -30,34 +46,23 @@ diff_base() { if [[ -n "${base_ref}" ]] && git rev-parse --verify "origin/${base_ref}" >/dev/null 2>&1; then printf '%s...HEAD\n' "origin/${base_ref}" - return - fi - - if [[ -n "${before}" && ! "${before}" =~ ^0+$ ]] && git rev-parse --verify "${before}^{commit}" >/dev/null 2>&1; then + elif [[ -n "${before}" && ! "${before}" =~ ^0+$ ]] && git rev-parse --verify "${before}^{commit}" >/dev/null 2>&1; then printf '%s..HEAD\n' "${before}" - return - fi - - if git rev-parse --verify "HEAD^" >/dev/null 2>&1; then + elif git rev-parse --verify HEAD^ >/dev/null 2>&1; then printf 'HEAD^..HEAD\n' - return + else + return 1 fi - - return 1 } changed_packages() { - local base - local changed_paths - local changed_path - local package + 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 @@ -72,8 +77,7 @@ changed_packages() { ;; packaging/alpine/local/*) package="${changed_path#packaging/alpine/local/}" - package="${package%%/*}" - selected["${package}"]=1 + selected["${package%%/*}"]=1 ;; esac done <<< "${changed_paths}" @@ -83,167 +87,107 @@ changed_packages() { done | sort } -restore_cache() { - if [[ -d "${cache_root}" ]]; then - mkdir -p "${repo_dest}" - cp -a "${cache_root}/." "${repo_dest}/" - printf 'Restored Alpine package repository cache from %s\n' "${cache_root}" - else - printf 'No Alpine package repository cache found at %s\n' "${cache_root}" - fi +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)" } -package_apk_names() { - local package_dir="$1" - local arch="$2" - - apk_package_apk_names "${package_dir}" "${arch}" -} - -package_cache_complete() { - local package_dir="$1" - local package_name - local arch - local apk_name - - package_name="$(apk_package_name "${package_dir}")" +load_registry_index() { + local arch package_name package_version + declare -gA registry_packages=() 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 - if [[ ! -f "${repo_dest}/${arch}/${apk_name}" ]]; then - printf 'Cache miss for %s: missing %s/%s\n' "${package_name}" "${arch}" "${apk_name}" >&2 - return 1 - fi - done < <(package_apk_names "${package_dir}" "${arch}") + 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 - - return 0 } -select_missing_packages() { - local package_dir - local package_name +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}")" - if ! package_cache_complete "${package_dir}"; then - printf '%s\n' "${package_name}" - fi - 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}" + missing=0 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}") + 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}") - - 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() { - local selected_packages local selected declare -A selected_map=() - restore_cache - prune_stale_apks - + download_registry_metadata + load_registry_index while IFS= read -r selected; do - [[ -n "${selected}" ]] || continue - selected_map["${selected}"]=1 + [[ -n "${selected}" ]] && selected_map["${selected}"]=1 done < <(changed_packages) - while IFS= read -r selected; do - [[ -n "${selected}" ]] || continue - selected_map["${selected}"]=1 - done < <(select_missing_packages) + [[ -n "${selected}" ]] && selected_map["${selected}"]=1 + done < <(registry_missing_packages) - selected_packages="$( - for selected in "${!selected_map[@]}"; do - printf '%s\n' "${selected}" - done | sort | xargs - )" - - if [[ -n "${selected_packages}" ]]; then - printf 'Selected packages for rebuild: %s\n' "${selected_packages}" - export ALPINE_PACKAGES="${selected_packages}" - export ALPINE_SKIP_BUILD=0 + 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 - printf 'No packages selected for rebuild\n' - export ALPINE_PACKAGES="" - export ALPINE_SKIP_BUILD=1 + 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 -} - -sync_cache() { - if [[ ! -d "${repo_dest}" ]]; then - printf 'missing package repository: %s\n' "${repo_dest}" >&2 - exit 1 + 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 - - prune_stale_apks - mkdir -p "${cache_root}" - rsync -a --delete "${repo_dest}/" "${cache_root}/" - printf 'Updated Alpine package repository cache at %s\n' "${cache_root}" } case "${command_name}" in - prepare) - prepare - ;; - sync) - sync_cache - ;; - *) - printf 'usage: %s [prepare|sync]\n' "$0" >&2 - exit 2 - ;; + prepare) prepare ;; + *) printf 'usage: %s prepare\n' "$0" >&2; exit 2 ;; esac diff --git a/scripts/apk/ci-smoke.sh b/scripts/apk/ci-smoke.sh index 6591512..8f5e834 100755 --- a/scripts/apk/ci-smoke.sh +++ b/scripts/apk/ci-smoke.sh @@ -2,19 +2,50 @@ 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}" arch="${ALPINE_ARCH:-$(apk --print-arch)}" packages="${SMOKE_PACKAGES:-seaweedfs seaweedfs-master-openrc seaweedfs-filer-openrc seaweedfs-worker-openrc greptimedb lavinmq lavinmq-openrc gitea gitea-openrc}" repo_dir="${repo_root}/packages/${repo_name}/${arch}" +registry_url="${ALPINE_REGISTRY_URL:-}" +registry_key="${ALPINE_REGISTRY_KEY:-}" read -r -a package_list <<< "${packages}" +declare -A versioned_packages=() -if [[ ! -d "${repo_dir}" ]]; then - printf 'missing local repository: packages/%s/%s\n' "${repo_name}" "${arch}" >&2 +while IFS= read -r package_dir; do + while IFS= read -r spec; do + versioned_packages["${spec%%=*}"]="${spec}" + done < <(apk_package_versioned_names "${package_dir}" "${arch}") +done < <(apk_all_package_dirs "${repo_root}") + +for package in "${package_list[@]}"; do + if [[ -z "${versioned_packages[${package}]:-}" ]]; then + printf 'smoke package is not defined by a source APKBUILD: %s\n' "${package}" >&2 + exit 2 + fi + package="${versioned_packages[${package}]}" +done + +if [[ -d "${repo_dir}" ]]; then + cp "${repo_dir}"/*.rsa.pub /etc/apk/keys/ + echo "${repo_root}/packages/${repo_name}" >> /etc/apk/repositories +elif [[ -z "${registry_url}" ]]; then + printf 'missing local repository and no registry fallback: packages/%s/%s\n' "${repo_name}" "${arch}" >&2 exit 1 fi +if [[ -n "${registry_url}" ]]; then + if [[ ! -f "${registry_key}" ]]; then + printf 'missing Alpine registry signing key: %s\n' "${registry_key:-}" >&2 + exit 1 + fi + cp "${registry_key}" /etc/apk/keys/ + echo "${registry_url}" >> /etc/apk/repositories +fi -cp "${repo_dir}"/*.rsa.pub /etc/apk/keys/ -echo "${repo_root}/packages/${repo_name}" >> /etc/apk/repositories +for index in "${!package_list[@]}"; do + package_list[index]="${versioned_packages[${package_list[index]}]}" +done apk update apk add "${package_list[@]}" if command -v weed >/dev/null 2>&1; then diff --git a/scripts/apk/outdated.sh b/scripts/apk/outdated.sh index 746c9b3..cbcee09 100755 --- a/scripts/apk/outdated.sh +++ b/scripts/apk/outdated.sh @@ -13,17 +13,59 @@ fi github_latest_release() { local repo="$1" - local api_url="https://api.github.com/repos/${repo}/releases/latest" local response response="$(curl -fsSL \ -H 'Accept: application/vnd.github+json' \ -H 'X-GitHub-Api-Version: 2022-11-28' \ - "${api_url}" 2>/dev/null)" || return 1 + "https://api.github.com/repos/${repo}/releases/latest" 2>/dev/null)" || return 1 + printf '%s\n' "${response}" | jq -er '.tag_name' +} - printf '%s\n' "${response}" \ - | sed -n 's/^[[:space:]]*"tag_name":[[:space:]]*"\([^"]*\)".*/\1/p' \ - | head -n 1 +github_release_rows() { + local repo="$1" + local current_tag="$2" + local page=1 + local response + local release_count + + while :; do + response="$(curl -fsSL \ + -H 'Accept: application/vnd.github+json' \ + -H 'X-GitHub-Api-Version: 2022-11-28' \ + "https://api.github.com/repos/${repo}/releases?per_page=100&page=${page}" 2>/dev/null)" || return 1 + release_count="$(printf '%s\n' "${response}" | jq -er 'if type == "array" then length else error("expected release array") end')" || return 1 + [[ "${release_count}" -gt 0 ]] || return 0 + + printf '%s\n' "${response}" | jq -r ' + .[] + | select(.draft | not) + | select(.prerelease | not) + | [ + .tag_name, + (.published_at // "-"), + (.name // .tag_name), + .html_url, + ( + (.body // "") + | gsub("[\\r\\n\\t]+"; " ") + | gsub("[`*_>#]"; "") + | gsub(" +"; " ") + | gsub("^ +"; "") + | gsub(" +$"; "") + | if length > 240 then .[0:237] + "..." else . end + ) + ] + | @tsv + ' + + if printf '%s\n' "${response}" | jq -e --arg tag "${current_tag}" ' + any(.[]; .tag_name == $tag and (.draft | not) and (.prerelease | not)) + ' >/dev/null; then + return 0 + fi + page=$((page + 1)) + done } apkbuild_value() { @@ -104,6 +146,7 @@ printf '%-14s %-14s %-14s %-18s %s\n' "PACKAGE" "CURRENT" "LATEST" "STATUS" "UPS has_update=0 has_unknown=0 +release_details="" while IFS= read -r package_dir; do apk_validate_package_dir "${package_dir}" @@ -121,6 +164,40 @@ while IFS= read -r package_dir; do if version_is_newer "${latest_version}" "${current_version}"; then status="update-available" has_update=1 + package_details="${package_name}: ${current_version} -> ${latest_version}" + case "${version_prefix}" in + none|"") current_tag="${current_version}" ;; + *) current_tag="${version_prefix}${current_version}" ;; + esac + if release_rows="$(github_release_rows "${repo}" "${current_tag}")" && [[ -n "${release_rows}" ]]; then + current_tag_found=0 + while IFS=$'\t' read -r release_tag published_at release_name release_url release_excerpt; do + [[ -n "${release_tag}" ]] || continue + release_version="$(normalize_version "${release_tag}" "${version_prefix}")" + if [[ "${release_tag}" == "${current_tag}" ]]; then + current_tag_found=1 + fi + if version_is_newer "${release_version}" "${current_version}"; then + package_details+=$'\n' + package_details+=" ${release_version} (${published_at}) — ${release_name}" + package_details+=$'\n' + package_details+=" ${release_url}" + if [[ -n "${release_excerpt}" ]]; then + package_details+=$'\n' + package_details+=" ${release_excerpt}" + fi + fi + done <<< "${release_rows}" + if [[ "${current_tag_found}" == 0 ]]; then + package_details+=$'\n' + package_details+=" Note: current release tag ${current_tag} was not found; listed releases compare newer than ${current_version}." + fi + else + package_details+=$'\n' + package_details+=" Note: release details could not be fetched." + fi + release_details+=$'\n' + release_details+="${package_details}" else status="current" fi @@ -139,6 +216,10 @@ while IFS= read -r package_dir; do "${upstream_url}" done < <(apk_package_dirs "${repo_root}") +if [[ -n "${release_details}" ]]; then + printf '\nRelease details:%s\n' "${release_details}" +fi + if [[ "${mode}" == "fail" && ( "${has_update}" -ne 0 || "${has_unknown}" -ne 0 ) ]]; then exit 1 fi diff --git a/scripts/apk/package-lib.sh b/scripts/apk/package-lib.sh index edc77cd..ca85539 100644 --- a/scripts/apk/package-lib.sh +++ b/scripts/apk/package-lib.sh @@ -106,7 +106,8 @@ apk_package_apk_names() { local pkgrel local subpackage local subpackages - export CARCH="${arch}" + # shellcheck disable=SC2034 # APKBUILD reads CARCH while sourced below. + local CARCH="${arch}" cd "${package_dir}" || exit 1 # shellcheck source=/dev/null . ./APKBUILD @@ -119,6 +120,31 @@ apk_package_apk_names() { ) } +apk_package_versioned_names() { + local package_dir="$1" + local arch="$2" + + ( + set +u + local pkgname + local pkgver + local pkgrel + local subpackage + local subpackages + # shellcheck disable=SC2034 # APKBUILD reads CARCH while sourced below. + local CARCH="${arch}" + cd "${package_dir}" || exit 1 + # shellcheck source=/dev/null + . ./APKBUILD + + printf '%s=%s-r%s\n' "${pkgname}" "${pkgver}" "${pkgrel}" + for subpackage in ${subpackages:-}; do + subpackage="${subpackage%%:*}" + printf '%s=%s-r%s\n' "${subpackage}" "${pkgver}" "${pkgrel}" + done + ) +} + apk_container_package_dir() { local repo_root="$1" local package_dir="$2"