Parallel Builds (#10)
Build Alpine Packages / preflight (push) Successful in 12s
Build Alpine Packages / build (gitea) (push) Successful in 21s
Build Alpine Packages / build (lavinmq) (push) Successful in 2m54s
Build Alpine Packages / build (seaweedfs) (push) Successful in 20m49s
Build Alpine Packages / build (greptimedb) (push) Successful in 1h42m55s
Build Alpine Packages / verify-and-publish (push) Failing after 1m26s

Reviewed-on: #10
This commit was merged in pull request #10.
This commit is contained in:
2026-09-29 07:17:00 +02:00
parent a2da4acc53
commit e8333709a5
26 changed files with 444 additions and 145 deletions
+132 -53
View File
@@ -1,52 +1,43 @@
name: Build Alpine Packages
on:
schedule:
- cron: "17 5 * * 1"
push:
branches:
- master
- main
tags:
- "*"
pull_request:
workflow_dispatch:
jobs:
build-and-publish:
runs-on: ubuntu-latest
strategy:
matrix:
include:
- alpine_version: "3.24"
alpine_registry_branch: "v3.24"
container:
image: "alpine:${{ matrix.alpine_version }}"
env:
ALPINE_VERSION: "${{ matrix.alpine_version }}"
env:
ALPINE_VERSION: "3.24"
ALPINE_ARCHES: "x86_64 aarch64"
ALPINE_REGISTRY_BRANCH: "${{ matrix.alpine_registry_branch }}"
ALPINE_REGISTRY_BRANCH: "v3.24"
ALPINE_REGISTRY_REPOSITORY: "${{ vars.PACKAGE_NAME }}"
INSTANCE_URL: "${{ vars.INSTANCE_URL }}"
PACKAGE_OWNER: "${{ vars.PACKAGE_OWNER }}"
PACKAGE_USER: "${{ secrets.PACKAGE_USER }}"
PACKAGE_TOKEN: "${{ secrets.PACKAGE_TOKEN }}"
PACKAGER: "${{ gitea.repository_owner }}"
ALPINE_APK_REPO_CACHE: "/cache/public-alpine-packages/${{ matrix.alpine_registry_branch }}/apk-repo"
ALPINE_RUST_CACHE_ROOT: "/cache/public-alpine-packages/${{ matrix.alpine_registry_branch }}/rust"
ALPINE_RUST_CACHE_ROOT: "/cache/public-alpine-packages/v3.24/rust"
TRIVY_VERSION: "0.74.0"
TRIVY_SHA256: "2ae6fe3ee734b7fdf11335663e18c75ea12dccc76062f09f164a3b0f8be4371a"
jobs:
preflight:
runs-on: ubuntu-latest
timeout-minutes: 180
container:
image: "alpine:3.24"
outputs:
packages_selected: "${{ steps.package-selection.outputs.packages_selected }}"
selected_packages: "${{ steps.package-selection.outputs.selected_packages }}"
greptimedb_selected: "${{ steps.package-selection.outputs.greptimedb_selected }}"
steps:
- name: Prepare Environment
run: |
printf '%s\n' 'https://dl-cdn.alpinelinux.org/alpine/edge/community' >> /etc/apk/repositories
apk add --no-cache --update abuild-rootbld alpine-sdk atools-apkbuild-lint bash ca-certificates curl doas git jq nodejs rsync shellcheck sudo tar
trivy_archive="trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz"
curl -fsSL -o "/tmp/${trivy_archive}" "https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/${trivy_archive}"
echo "${TRIVY_SHA256} /tmp/${trivy_archive}" | sha256sum -c -
tar -xzf "/tmp/${trivy_archive}" -C /usr/local/bin trivy
mkdir -p "$ALPINE_APK_REPO_CACHE" "$ALPINE_RUST_CACHE_ROOT"
chown -R 1000:1000 /cache/public-alpine-packages/${{ matrix.alpine_registry_branch }}
apk add --no-cache --update atools-apkbuild-lint bash ca-certificates curl git jq nodejs shellcheck tar
- name: Checkout
uses: actions/checkout@v3
@@ -68,46 +59,136 @@ jobs:
fi
- name: Prepare package cache
if: github.event_name != 'schedule'
id: package-selection
run: |
scripts/apk/ci-package-cache.sh prepare
run: scripts/apk/ci-package-cache.sh prepare
- name: Build packages
if: github.event_name != 'schedule'
build:
needs: preflight
if: needs.preflight.outputs.packages_selected == 'true'
runs-on: ubuntu-latest
timeout-minutes: 180
strategy:
fail-fast: false
matrix:
package: [seaweedfs, greptimedb, lavinmq, gitea]
container:
image: "alpine:3.24"
env:
ALPINE_PACKAGE: "${{ matrix.package }}"
steps:
- name: Prepare Environment
run: |
printf '%s\n' 'https://dl-cdn.alpinelinux.org/alpine/edge/community' >> /etc/apk/repositories
apk add --no-cache --update abuild-rootbld alpine-sdk bash ca-certificates doas git nodejs sudo
mkdir -p "$ALPINE_RUST_CACHE_ROOT"
chown -R 1000:1000 /cache/public-alpine-packages/v3.24
- name: Checkout
uses: actions/checkout@v3
- name: Build package
if: contains(needs.preflight.outputs.selected_packages, matrix.package)
run: |
scripts/apk/ci-build.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'
id: artifact-upload
if: contains(needs.preflight.outputs.selected_packages, matrix.package)
run: |
if [ -n "${ACTIONS_RUNTIME_TOKEN:-}" ]; then
echo "available=true" >> "$GITHUB_OUTPUT"
else
echo "available=false" >> "$GITHUB_OUTPUT"
fi
test -n "${ACTIONS_RUNTIME_TOKEN:-}" || {
echo "artifact upload support is required for split package builds" >&2
exit 1
}
- name: Upload generated CI assets
if: github.event_name != 'schedule' && steps.package-selection.outputs.greptimedb_selected == 'true' && steps.artifact-upload.outputs.available == 'true'
- name: Upload package artifacts
if: contains(needs.preflight.outputs.selected_packages, matrix.package)
uses: actions/upload-artifact@v3
with:
name: greptimedb-musl-binaries-${{ matrix.alpine_registry_branch }}
name: alpine-package-${{ matrix.package }}-${{ github.sha }}
path: packages/local/
retention-days: 1
verify-and-publish:
needs: [preflight, build]
if: needs.preflight.outputs.packages_selected == 'true'
runs-on: ubuntu-latest
timeout-minutes: 180
container:
image: "alpine:3.24"
env:
ALPINE_PACKAGES: "${{ needs.preflight.outputs.selected_packages }}"
steps:
- name: Prepare Environment
run: |
printf '%s\n' 'https://dl-cdn.alpinelinux.org/alpine/edge/community' >> /etc/apk/repositories
apk add --no-cache --update abuild-rootbld alpine-sdk bash ca-certificates curl doas docker-cli git jq nodejs rsync shellcheck sudo tar
trivy_archive="trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz"
curl -fsSL -o "/tmp/${trivy_archive}" "https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/${trivy_archive}"
echo "${TRIVY_SHA256} /tmp/${trivy_archive}" | sha256sum -c -
tar -xzf "/tmp/${trivy_archive}" -C /usr/local/bin trivy
- name: Checkout
uses: actions/checkout@v3
- name: Prepare registry fallback
run: |
selected_packages="$ALPINE_PACKAGES"
scripts/apk/ci-package-cache.sh prepare
printf 'ALPINE_PACKAGES=%s\n' "$selected_packages" >> "$GITHUB_ENV"
- name: Download SeaweedFS artifacts
if: contains(needs.preflight.outputs.selected_packages, 'seaweedfs')
uses: actions/download-artifact@v3
with:
name: alpine-package-seaweedfs-${{ github.sha }}
path: packages/worker-artifacts/seaweedfs
- name: Download GreptimeDB artifacts
if: contains(needs.preflight.outputs.selected_packages, 'greptimedb')
uses: actions/download-artifact@v3
with:
name: alpine-package-greptimedb-${{ github.sha }}
path: packages/worker-artifacts/greptimedb
- name: Download LavinMQ artifacts
if: contains(needs.preflight.outputs.selected_packages, 'lavinmq')
uses: actions/download-artifact@v3
with:
name: alpine-package-lavinmq-${{ github.sha }}
path: packages/worker-artifacts/lavinmq
- name: Download Gitea artifacts
if: contains(needs.preflight.outputs.selected_packages, 'gitea')
uses: actions/download-artifact@v3
with:
name: alpine-package-gitea-${{ github.sha }}
path: packages/worker-artifacts/gitea
- name: Merge package artifacts
run: scripts/apk/merge-ci-artifacts.sh
- name: Export GreptimeDB CI assets
if: needs.preflight.outputs.greptimedb_selected == 'true'
run: scripts/apk/export-ci-assets.sh
- name: Upload generated CI assets
if: needs.preflight.outputs.greptimedb_selected == 'true'
uses: actions/upload-artifact@v3
with:
name: greptimedb-musl-binaries-v3.24
path: packages/ci-assets/
- name: Upload local Alpine registry
uses: actions/upload-artifact@v3
with:
name: alpine-local-registry-v3.24-${{ github.sha }}
path: packages/local/
retention-days: 30
- name: Smoke test
if: github.event_name != 'schedule'
run: scripts/apk/ci-smoke.sh
- name: Generate security reports
if: github.event_name != 'schedule' && env.ALPINE_SKIP_BUILD != '1'
run: |
scripts/apk/security-report.sh
if [ -n "${GITHUB_STEP_SUMMARY:-}" ]; then
@@ -117,16 +198,14 @@ jobs:
fi
- name: Upload security reports
if: github.event_name != 'schedule' && env.ALPINE_SKIP_BUILD != '1' && steps.artifact-upload.outputs.available == 'true'
uses: actions/upload-artifact@v3
with:
name: apk-security-reports-${{ matrix.alpine_registry_branch }}
name: apk-security-reports-v3.24
path: packages/security-reports/
- name: Runtime test
if: github.event_name != 'schedule' && env.ALPINE_SKIP_BUILD != '1'
run: scripts/apk/runtime-test.sh
run: ALPINE_RUNTIME_TEST_MODE=docker scripts/apk/runtime-test.sh
- name: Publish Alpine packages
if: github.event_name != 'pull_request' && github.event_name != 'schedule' && env.ALPINE_SKIP_BUILD != '1'
if: github.ref == 'refs/heads/main'
run: scripts/apk/publish-gitea.sh
+30
View File
@@ -0,0 +1,30 @@
name: Package Update Status
on:
schedule:
- cron: "17 5 * * 1"
workflow_dispatch:
jobs:
package-status:
runs-on: ubuntu-latest
container:
image: alpine:3.24
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Check packaged upstream versions
run: |
apk add --no-cache bash curl git jq
APK_UPDATE_CHECK_MODE=warn scripts/apk/outdated.sh > update-check.txt
cat update-check.txt
if [ -n "${GITHUB_STEP_SUMMARY:-}" ]; then
{
echo "## Upstream package update check"
echo
echo '```text'
cat update-check.txt
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
fi
+1
View File
@@ -5,3 +5,4 @@ packaging/alpine/*/*/pkg/
packaging/alpine/*/*/src/
packaging/alpine/*/*/*.apk
packaging/alpine/*/*/*.tar.*
!packaging/alpine/*/*/*-vendor.tar.gz
+3 -1
View File
@@ -1,5 +1,7 @@
# Alpine Packages
[![Package update check](https://code.factoring.digital/public/alpine-packages/actions/workflows/package-status.yml/badge.svg?branch=main&event=schedule)](https://code.factoring.digital/public/alpine-packages/actions?workflow=package-status.yml)
Alpine stable packaging for internal packages. This repository carries selected
upstream releases ahead of Alpine community packages when we need newer
features, packaging fixes, or service layouts on the current Alpine branch.
@@ -19,7 +21,7 @@ https://code.factoring.digital/api/packages/public/alpine/v3.24/alpine-packages
| Package | APK Name | Package Version | Package Type | Purpose |
|-----------------------------------------------------------|--------------|-----------------|----------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------|
| [SeaweedFS](packaging/alpine/local/seaweedfs/README.md) | `seaweedfs` | `4.47` | Binary repackaging of official upstream release tarballs | Ships current SeaweedFS features with Alpine OpenRC role splits. |
| [SeaweedFS](packaging/alpine/local/seaweedfs/README.md) | `seaweedfs` | `4.48` | Binary repackaging of official upstream release tarballs | Ships current SeaweedFS features with Alpine OpenRC role splits. |
| [GreptimeDB](packaging/alpine/local/greptimedb/README.md) | `greptimedb` | `1.2.1` | Source build from upstream release | Provides a current GreptimeDB build and component OpenRC packages before it is available from Alpine community. |
| [LavinMQ](packaging/alpine/local/lavinmq/README.md) | `lavinmq` | `2.10.0` | Source build from upstream release | Provides a current LavinMQ build on Alpine 3.24 with matching Crystal support. |
| [Gitea](packaging/alpine/local/gitea/README.md) | `gitea` | `1.27.3` | Binary repackaging of official upstream release binaries | Ships current Gitea releases with the expected Alpine runtime layout and OpenRC service. |
+28 -10
View File
@@ -1,7 +1,7 @@
# Maintainer: Joachim Schlöffel <joachim.schloeffel@financial-service-plus.de>
pkgname=greptimedb
pkgver=1.2.1
pkgrel=0
pkgrel=3
pkgdesc="Cloud-native observability database for metrics, logs, and traces"
url="https://github.com/GreptimeTeam/greptimedb"
arch="x86_64"
@@ -12,14 +12,17 @@ makedepends="
clang
cmake
coreutils
curl
cargo-auditable
git
lld
linux-headers
make
mold
nodejs
openssl-dev
openssl-libs-static
perl
pnpm
protobuf
protobuf-dev
rustup
@@ -28,6 +31,7 @@ makedepends="
zstd-dev
zstd-static
"
checkdepends="cargo-nextest"
install="$pkgname.pre-install"
subpackages="
$pkgname-datanode-openrc:_openrc_datanode:noarch
@@ -41,7 +45,7 @@ options="net"
_dashboard_version="v0.12.0"
source="
$pkgname-$pkgver.tar.gz::https://github.com/GreptimeTeam/greptimedb/archive/refs/tags/v$pkgver.tar.gz
dashboard-$_dashboard_version.tar.gz::https://github.com/GreptimeTeam/dashboard/releases/download/$_dashboard_version/build.tar.gz
dashboard-$_dashboard_version.tar.gz::https://github.com/GreptimeTeam/dashboard/archive/refs/tags/$_dashboard_version.tar.gz
datanode.toml
flownode.toml
frontend.toml
@@ -64,31 +68,45 @@ export CARGO_BUILD_JOBS="${CARGO_BUILD_JOBS:-2}"
export CARGO_PROFILE_NIGHTLY_CODEGEN_UNITS="${CARGO_PROFILE_NIGHTLY_CODEGEN_UNITS:-16}"
export CARGO_PROFILE_NIGHTLY_DEBUG="${CARGO_PROFILE_NIGHTLY_DEBUG:-false}"
export CARGO_PROFILE_NIGHTLY_LTO="${CARGO_PROFILE_NIGHTLY_LTO:-thin}"
export CARGO_PROFILE_TEST_DEBUG="${CARGO_PROFILE_TEST_DEBUG:-false}"
export LIBRARY_PATH="/usr/lib"
export RUSTFLAGS="${RUSTFLAGS:-} -C link-arg=-fuse-ld=mold"
prepare() {
default_prepare
if [ ! -d "$builddir"/src/servers/dashboard/dist ]; then
mv "$srcdir"/dist "$builddir"/src/servers/dashboard/dist
fi
rustup-init \
-y \
--no-modify-path \
--profile minimal \
--default-toolchain "$_rust_toolchain"
"$CARGO_HOME"/bin/rustup run "$_rust_toolchain" cargo fetch \
--locked
local _dashboard_builddir="$srcdir"/dashboard-${_dashboard_version#v}
(
cd "$_dashboard_builddir"
pnpm install --frozen-lockfile --store-dir "$srcdir"/pnpm-store
pnpm run build:docker
)
rm -rf "$builddir"/src/servers/dashboard/dist
cp -a "$_dashboard_builddir"/dist "$builddir"/src/servers/dashboard/
}
build() {
"$CARGO_HOME"/bin/rustup run "$_rust_toolchain" cargo build \
"$CARGO_HOME"/bin/rustup run "$_rust_toolchain" cargo auditable build \
--profile "$_cargo_profile" \
--frozen \
--locked \
--bin greptime \
--features servers/dashboard
}
check() {
"$CARGO_TARGET_DIR"/"$_cargo_profile"/greptime --version
"$CARGO_HOME"/bin/rustup run "$_rust_toolchain" cargo nextest run \
-p cmd \
--lib \
--frozen
}
package() {
@@ -128,14 +146,14 @@ _docs() {
sha512sums="
fc580f6e34df84b4f37219047d751968324c356f3cad352d1515abb4b441515a1ad98f0d01e2de33aac5129a2d7a5335edc4d8888923da7683a084a484769bea greptimedb-1.2.1.tar.gz
4260acae5bed00a693dceffe9f53d0f8b25fd677b15638e951cf973dc29681f4bacde352c661a12bd78af7be9181a3740812f814fc3c4c8c87ea4eee6ee07e2d dashboard-v0.12.0.tar.gz
3f853b6767a86cfa97ec640a17de59b2e798561c9402026e9b3a749907780b9b686149dba8a932b5d61ae538c430deab2410248e5c9e6e1961909000445ee2ee dashboard-v0.12.0.tar.gz
29cc3376753487b216748e3f85e12639830e1ac4a763e94f330f87c3651a8ef9de35732958311c0049e1b7cbb4e90a9e602b3aff43297fe088c5ce795a110a79 datanode.toml
52790808cb4f5cf0220ac2ab169b623fe76b6318d27d7f003e1197e850373cb915bfd40556098bcb7650f293d751039cb3bccbf9107bb160b8284887794ba975 flownode.toml
e3e19ab3c7a345ecf8cf0a507f7fc95dd3b036a4a797385cf77fcf1999f2e4f053042c7bbda8de73ed43ff72e87aad81e4ac6d4a34d01773bbc1f6d0d967d9f7 frontend.toml
313ed7d9ccd174b1869f3009e174266cdc414599e0b0f8307c8aaf2b73841eb36ce4c1b2f6244a0358b5a587a4edaa621b781fbd767835088b3fa13623fcc0df greptimedb.datanode.confd
daf8efacc8bf2b74abd9f4900f889585295b57333a8a562a722de0596d35f25d5f9149e0879f4140bfdf727caa59c3f55b1380212722df92c588d912275530b8 greptimedb.flownode.confd
e3e61b1df00f8172a3b1d4a0d37ed2574a8c5cd27676b4e2ce14d15ad8933d233baabe8da374f715d00cfaee26f665244c1ba00f70197fcc713c4e9af9c3229e greptimedb.frontend.confd
c00740aee566b161bbe3610e0e0d6e8340022055750e6778772262474ffd6484d9f58be2fd498beafe28d0943e259e2277930af691bedea7650726e6c8998881 greptimedb.initd
f72f52aa8277fc56eb071b5118990b8f4e09d143634c2f7fc54ed1f5ff065631c8630c45fe90d3db1f3ea0540c1ab3154a383d2000b4c5978e889ca02a1b6564 greptimedb.initd
df495367d85844dcba99e5aa01e5a23fd14799b7521a72d9ea00d29fc0e5fbc5c5d06ee88e88d9637e260f8337249a39d2b0115de58da4899824d20bd844254a greptimedb.metasrv.confd
882a79e969cac42adfada22060e6507fb687755a6d266d6728154b3e4da5777d2eaf5ad9bc331ed050448249ca609e6a61977b624d9faf25d83ed975345452cf greptimedb.standalone.confd
8120ec338ebe1330d43b20d9b34a8f5f778ea13cb056febd3c8e9dc189d0de2380b90e5474a0990294d7004827c6133d44d2dd3e32d463b9259c47c82592d257 metasrv.toml
+12 -4
View File
@@ -1,14 +1,22 @@
# GreptimeDB Alpine Package
Builds `greptime` from the upstream source release and packages OpenRC service
subpackages plus `/etc/greptimedb` defaults.
Builds `greptime` and its embedded dashboard from their upstream source
releases, and packages OpenRC service subpackages plus `/etc/greptimedb`
defaults.
Build command:
```sh
cargo build --profile nightly --locked --bin greptime --features servers/dashboard
cargo auditable build --profile nightly --frozen --locked --bin greptime --features servers/dashboard
```
GreptimeDB requires the nightly pinned in its source release
(`nightly-2026-03-21`). The package uses Rustup to install that toolchain and
uses locked Cargo and pnpm dependency resolution, so `options="net"` is
intentional. Cargo dependencies are fetched before compilation; the Rust build
then runs frozen. The dashboard is built from the matching `v0.12.0` source tag
with its checked-in `pnpm-lock.yaml`.
## Runtime Layout
Installs `/usr/bin/greptime` and component OpenRC packages:
@@ -92,4 +100,4 @@ ALPINE_REPOSITORY_KEY_URL=https://code.factoring.digital/api/packages/public/alp
mise run apk:test-install
```
Full builds take close to an hour.
Full builds and the targeted upstream Nextest check take close to an hour.
@@ -6,6 +6,7 @@ description="GreptimeDB ${service_name} service"
command="/usr/bin/greptime"
command_user="${GREPTIMEDB_USER:-greptimedb}:${GREPTIMEDB_GROUP:-greptimedb}"
command_background="yes"
retry="TERM/30/KILL/5"
pidfile="/run/greptimedb/${RC_SVCNAME}.pid"
output_log="${GREPTIMEDB_LOG:-/var/log/greptimedb/${RC_SVCNAME}.log}"
error_log="${GREPTIMEDB_ERRLOG:-/var/log/greptimedb/${RC_SVCNAME}.log}"
@@ -21,3 +21,14 @@ greptime --version
rc-update add greptimedb.standalone default || true
test -L /etc/runlevels/default/greptimedb.standalone
rc-service greptimedb.standalone start
for _attempt in $(seq 1 30); do
if wget -qO- http://127.0.0.1:4000/status >/dev/null; then
break
fi
sleep 1
done
wget -qO- http://127.0.0.1:4000/status >/dev/null
wget -qO- http://127.0.0.1:4000/dashboard/ | grep -qi '<!doctype html>'
rc-service greptimedb.standalone stop
@@ -1,6 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
package_dir="${PACKAGE_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
printf 'No generated sources for %s\n' "${package_dir}"
+15 -9
View File
@@ -1,15 +1,14 @@
# Maintainer: Joachim Schlöffel <joachim.schloeffel@financial-service-plus.de>
pkgname=lavinmq
pkgver=2.10.0
pkgrel=0
pkgrel=2
pkgdesc="High-performance AMQP and MQTT message queue server"
url="https://github.com/cloudamqp/lavinmq"
arch="x86_64"
license="Apache-2.0"
depends="ca-certificates /bin/sh"
makedepends="
crystal=1.21.0-r0
curl
crystal>=1.21.0
gc-dev
help2man
libevent-dev
@@ -29,15 +28,21 @@ subpackages="
$pkgname-doc
$pkgname-openrc:_openrc:noarch
"
options="net"
source="
$pkgname-$pkgver.tar.gz::https://github.com/cloudamqp/lavinmq/archive/refs/tags/v$pkgver.tar.gz
$pkgname-$pkgver-shards.tar.gz
$pkgname-$pkgver-assets.tar.gz
lavinmq.confd
lavinmq.initd
use-vendored-build-inputs.patch
"
export CRYSTAL_CACHE_DIR="${CRYSTAL_CACHE_DIR:-$srcdir/crystal-cache}"
export SHARDS_CACHE_PATH="${SHARDS_CACHE_PATH:-$srcdir/shards-cache}"
prepare() {
default_prepare
tar -xzf "$srcdir/$pkgname-$pkgver-shards.tar.gz" -C "$builddir"
mkdir -p "$builddir/.alpine-assets"
tar -xzf "$srcdir/$pkgname-$pkgver-assets.tar.gz" -C "$builddir/.alpine-assets"
}
build() {
crystal --version
@@ -46,9 +51,7 @@ build() {
}
check() {
bin/lavinmq -v
bin/lavinmqctl --version
bin/lavinmqperf --version
crystal spec spec/config_spec.cr
}
package() {
@@ -70,6 +73,9 @@ _openrc() {
sha512sums="
b494892dada6eb713025bc3245e16035a63265805d77c537b4530226195f00dacab1fb14de5bf4c999165faa6bf2f7ef7c6b8ffb4c6f4a921977f1c13a4f1545 lavinmq-2.10.0.tar.gz
d0dfdd5c0e474024f57deb9e31c76e3f176e798c8d21dea53d3aea1b05436bd03fa34e69ccddf322bc89adedce5f379df5a316cddbbdfe12520e5bf672ad8228 lavinmq-2.10.0-shards.tar.gz
ae3cea2534b211abbcbd1e4fcb6da73dfaf383a19aef1c45f367cba77492cc20a7ce8283fc42f26c0a023149114c369bed307fb8cde0b8f27fba61165092e986 lavinmq-2.10.0-assets.tar.gz
62a609d50f28db960098c4c84ce4f1dad78413366a9a9aca18fe321114d687be3bf7b71924d4ace69bd74383c5ac40d2ee09ae0eef9c1bfe653b97448e42e110 lavinmq.confd
1853196e70297b5c4a2207fde50df735620cf6d99c4994644fd676bffaf863d67300ad7ae771c4bbb86fce1a0485c2a7968cf912c5f5bb878e08b15e5a28ba1b lavinmq.initd
e7617099f745ecbf2f0686830d0a1b28044741ebd543798505b5b3c08f1be96b6cc478eb18f6785af49b100c2f49d837775f0721ac27519ddf3f081e681c581c use-vendored-build-inputs.patch
"
+6 -3
View File
@@ -1,7 +1,9 @@
# LavinMQ Alpine Package
Builds LavinMQ from the upstream source release for `x86_64` and packages the
OpenRC service plus `/etc/lavinmq` defaults.
OpenRC service plus `/etc/lavinmq` defaults. The locked Shards dependencies and
frontend assets are versioned, checksummed source inputs, so the build does not
need network access.
Build command:
@@ -9,8 +11,9 @@ Build command:
make
```
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.
LavinMQ 2.10.0 requires Crystal 1.21.0 or newer. The package uses Alpine
edge's native Crystal package, avoiding a glibc toolchain in the Alpine musl
build.
## Runtime Layout
@@ -0,0 +1,36 @@
--- a/Makefile
+++ b/Makefile
@@ -8,0 +9 @@
+LAVINMQ_ASSET_DIR ?= .alpine-assets
@@ -55,2 +56,2 @@
-lib: shard.yml shard.lock
- shards install --production
+lib:
+ test -d lib
@@ -62,3 +63 @@
- curl --fail --retry 5 -sL https://github.com/chartjs/Chart.js/releases/download/v4.0.1/chart.js-4.0.1.tgz | \
- tar -zxOf- package/dist/chart.js > $@
- [ "038d0a4f9c61f0b35ff70f883e7591403a349542625a4caaf48caa141adedfd5 *$@" = "$$(openssl dgst -sha256 -r $@)" ]
+ install -Dm644 "$(LAVINMQ_ASSET_DIR)/chart.js" "$@"
@@ -67,3 +66 @@
- curl --fail --retry 5 -sL https://github.com/chartjs/Chart.js/releases/download/v4.0.1/chart.js-4.0.1.tgz | \
- tar -zxOf- package/dist/chunks/helpers.segment.js > $@
- [ "b4746b748fe583a18ef921e341b8b65166c2ebd0b737fde6527b254baaeb1aa1 *$@" = "$$(openssl dgst -sha256 -r $@)" ]
+ install -Dm644 "$(LAVINMQ_ASSET_DIR)/helpers.segment.js" "$@"
@@ -72,2 +69 @@
- curl --fail --retry 5 -sLo $@ https://moment.github.io/luxon/es6/luxon.mjs
- [ "b495ad5cabea3439d04387e6622f2c3fa81d319424d9d76d9e7f874ac5a0807a *$@" = "$$(openssl dgst -sha256 -r $@)" ]
+ install -Dm644 "$(LAVINMQ_ASSET_DIR)/luxon.js" "$@"
@@ -76,3 +72 @@
- curl --fail --retry 5 -sLo $@ https://cdn.jsdelivr.net/npm/chartjs-adapter-luxon@1.3.1/dist/chartjs-adapter-luxon.esm.js
- sed -i'' -e "s|\(import { _adapters } from\).*|\1 './chart.js'|; s|\(import { DateTime } from\).*|\1 './luxon.js'|" $@
- [ "17d7b6567d656a004f86b6b5cbdbe64cb308e9a2ebfa7675caa79ba0bc72ef91 *$@" = "$$(openssl dgst -sha256 -r $@)" ]
+ install -Dm644 "$(LAVINMQ_ASSET_DIR)/chartjs-adapter-luxon.esm.js" "$@"
@@ -81,2 +75 @@
- curl --fail --retry 5 -sLo $@ https://unpkg.com/@stoplight/elements@8.2.0/web-components.min.js
- [ "598862da6d551769ebad9d61d4e3037535de573a13d3e0bd1ded4c5fc65c5885 *$@" = "$$(openssl dgst -sha256 -r $@)" ]
+ install -Dm644 "$(LAVINMQ_ASSET_DIR)/elements-8.2.0.js" "$@"
@@ -85,2 +78 @@
- curl --fail --retry 5 -sLo $@ https://unpkg.com/@stoplight/elements@8.2.0/styles.min.css
- [ "119784e23ffc39b6fa3fdb3df93f391f8250e8af141b78dfc3b6bed86079f93b *$@" = "$$(openssl dgst -sha256 -r $@)" ]
+ install -Dm644 "$(LAVINMQ_ASSET_DIR)/elements-8.2.0.css" "$@"
+19 -27
View File
@@ -1,13 +1,13 @@
# Maintainer: Joachim Schlöffel <joachim.schloeffel@financial-service-plus.de>
pkgname=seaweedfs
pkgver=4.47
pkgrel=2
pkgver=4.48
pkgrel=0
pkgdesc="Distributed storage system for object storage, file systems, and Iceberg tables"
url="https://github.com/seaweedfs/seaweedfs"
arch="x86_64 aarch64"
license="Apache-2.0"
depends="ca-certificates /bin/sh"
makedepends="build-base cargo rust protobuf-dev"
makedepends="build-base cargo go protobuf-dev rust"
provides="!$pkgname-openrc cmd:weed=$pkgver-r$pkgrel"
install="$pkgname.pre-install"
subpackages="
@@ -24,20 +24,9 @@ subpackages="
$pkgname-worker-lance:_worker_lance
$pkgname-worker-lance-openrc:_openrc_worker_lance:noarch
"
options="!check !strip !tracedeps"
case "$CARCH" in
x86_64)
_archive="$pkgname-$pkgver-linux-amd64.tar.gz"
;;
aarch64)
_archive="$pkgname-$pkgver-linux-arm64.tar.gz"
;;
esac
options="!strip !tracedeps net"
source="
$pkgname-$pkgver-linux-amd64.tar.gz::https://github.com/seaweedfs/seaweedfs/releases/download/$pkgver/linux_amd64.tar.gz
$pkgname-$pkgver-linux-arm64.tar.gz::https://github.com/seaweedfs/seaweedfs/releases/download/$pkgver/linux_arm64.tar.gz
$pkgname-$pkgver-src.tar.gz::https://github.com/seaweedfs/seaweedfs/archive/refs/tags/$pkgver.tar.gz
admin.toml
credential.toml
@@ -66,22 +55,27 @@ source="
weed.bash-completion
"
builddir="$srcdir"
_worker_builddir="$builddir/$pkgname-$pkgver/seaweed-worker"
_worker_builddir="$srcdir/$pkgname-$pkgver/seaweed-worker"
prepare() {
default_prepare
tar -xzf "$srcdir/$_archive" -C "$builddir"
tar -xzf "$srcdir/$pkgname-$pkgver-src.tar.gz" -C "$builddir"
}
build() {
go build -mod=readonly -buildvcs=false -trimpath -o "$builddir/weed-bin" ./weed
cd "$_worker_builddir"
cargo build --locked --release -p weed-lance-worker
}
check() {
"$builddir/weed-bin" version
"$builddir/weed-bin" scaffold -config master >/dev/null
"${CARGO_TARGET_DIR:-$_worker_builddir/target}/release/weed-worker" --help >/dev/null
}
package() {
install -Dm755 "$srcdir"/weed "$pkgdir"/usr/bin/weed
install -Dm755 "$builddir"/weed-bin "$pkgdir"/usr/bin/weed
install -Dm755 "${CARGO_TARGET_DIR:-$_worker_builddir/target}/release/weed-worker" \
"$pkgdir"/usr/bin/weed-worker
local _config
@@ -137,26 +131,24 @@ _bashcomp() {
}
sha512sums="
f2e90fac760ac93951becce0314fa27aa69308a538a14d9066635d64c5fca07eababdbd41f5bb2215ba5793bf14fa2c019163438467aab2cf5bfea7f204f3faa seaweedfs-4.47-linux-amd64.tar.gz
a3e44542fa6e0f1266dea998a50120325c67a448d2cf09ad370a6d147f3d6096363fea57a056b2bd38d5b0674f4b2695644eed7e93110542efdc03fd8b5cde9e seaweedfs-4.47-linux-arm64.tar.gz
b04ed6a4d16a016d08179a85fb0d4a7cf9de354f39820f8590a92384f5c750236f690a2110e9c33ba253564eadc02f639a329754f48b5d213c9c117c4ba46578 seaweedfs-4.47-src.tar.gz
91a34fec9bb78832f421b54dd823adb1c1690b746083d947c5f72e4ad7670362512bbb920432f42342482774fd8be2b396645ff3bc764b10f328432601733fe3 seaweedfs-4.48-src.tar.gz
58be6587b082f45b4dd22ad8ebb1b8bf84cea2a7c0cb6b4ad4a749ac0bfdf92d10d22281a432f9e5a87afa0b940cd0172671a292fbe17803e56425cd940d47f9 admin.toml
7f77ad8787629e3defbc89e39e5432482aa50d87ddd723de927a9c6c77b14b1673cbf5b3fc3c18dd7d0eba26fbcd4220d2da6939ed097d0294b24ccd5c002635 credential.toml
507b389f6373b5f4d8ca69f27bc806b39bda8edf7f58e4f32720958e7782ee171dd0461bdecb285e5a8bf2cf4ea3d6cbe8b62ae6ac43c2a40d0eb053d50a22f8 example-admin.toml
7105de7053654b8c0502521ce58585915fc831c3152801e1db02b1c5214dc3c3ed31f4fc18000665d8338c7a10ffbf0d248368bef2ef3a6d37d46cd856398366 example-credential.toml
c6ec4fc7709c42dc6771b5039203c44cbd693742abcd7720936c00b1bd5f99bb2999bb1545680ae4418efedd65d71c234f4602f52ce9d58b1ff7ec53eafb1a1a example-filer.toml
e5753bd0bcc60dc84428c40ba556c08acae61dec083a5b76640125f637532e7c5759a72cdfd95114222a7a0901a916ec3c4d12f306853cfca0fe9a0b1857893e example-master.toml
2d64cde0ba4f91ed78a580399d7cada2af254c974a8f6458be70339d218d772680ca1bdefcb69e3a3eced1b0fd8206fa0e30122c1cd0a4dc9f306f813da935ee example-volume.toml
59965fd2649a956677c6d4104ff07ff010d6edd1d3733eaa5c5bc01eabe54429c413e35d52ed4a4c0129bfa798e434828b32a5f0ef19dbbe4eab0199faa2738c example-master.toml
aea1b3114311304230cb30143825329ef7353a302d094c131ca4e049b847305e2143b76078e6574c6d7d4039c03a2e2d5a4925de80cd7cb2be75b2b522ce47f7 example-volume.toml
2c200c28172a5d0b1c80ab28e849287e7af8d103355638fd3183b8614d3e2b1b3482132522663f7c6d844e10e13b8c6e23fb5fba0dec2cc83de45c2f17b33477 example-notification.toml
328cfe43d0c2ebf5092a1178af45c37b07593085135c31649754f0df9fd4c043847c13b56c3c7c45194541db8082309c4845c825d7011e4c3e503b1e6576528d example-replication.toml
3b45b0f5bf6c5339cfb63c3ddb489b7122e03996ce380c7a244778ef1e7f6c06b4e3e56ea695a2dc3c9c49322a58df865ff50b2904318abafee5e66b2af757f1 example-security.toml
b7caad9dff0bb812d4046b8e0285ac4e88a7af3a742a168579df08762da735a025725f78286e17bdd4b19a966a3d7ab88e0e52efbb5cf1c69d7a4ff071390e0f example-security.toml
70069f97edf261a2cd0669dd60adad80533609a25d7429254e0c3322d7e80337f5ff69a5581bc39e6a15442098d14d610ce5f0cb14f02c461c8d3dd440b22c56 example-shell.toml
130b9932f99d0a3ec3c30c74eaf1dc441c1a9252da30e2c5365084f2a0679f58531e6180689c24b71f92cf9a7966b02ea25ee31d356e7118cbb82743d0bfcbd9 filer.toml
088c3aebc142054af1b54a92a2c5bd30d53be61bdf382f7cae2efef2d917d7b57022d9b494a60f32c7bf56689d4ce2f971e19c98da1d87e27021a3e948035605 master.toml
79a078133c259473e601488cd1d8032b74c5fa32da6f34a4ed46efa9736bf5369365a77d775e3d78512b1060cd87012eb40226829eecb30544e1542d165af7d6 security.toml
82e2793bf483ffb5b0c8fbe38e6c9df75afe01f824f8414cafd91e4bed5c79c13dae1ca659070401d4968d16ed4b26455b0c6208f777705527bceb2e5f286988 seaweedfs.admin.confd
5ad952c37c62a770327bd70f7349fa677406606f0b9bf03fdc8f6c6804701f1e77710ab20d6153f9e0cfb549ec161d68a3316abab9c59837bbe3f91ee99e5ce0 seaweedfs.filer.confd
583de285a15b9006881821127b3fa0759216649c87c2f9aa5eaf73993ebfa66f7e06d364b1a35dd332efc9db4867120a3564f6ef12d2b39f00d7020c604599d6 seaweedfs.initd
077c513851bbbe53dd32d26455abc361f97006f9ace1190f96eb4b9136d16befab1a6153752eae8dac695c3a9aed084a00b411684915618cb30dd0770e608403 seaweedfs.initd
57ba77519bb266f0117eaadae3af5ae6bc99bb653668ff526202f327df1c8d93973c0e19dae0c53a19e06389868043c04e53f16f01c851b77fe1387e92cc993b seaweedfs.master.confd
22a3ea6c83266a979ea7c848fc74b40fc0f2ade960b273fa11e63d4a72a1328bd688c9918be3e9234cfb19f889fd9c931388bb5c2863cea3500e534b8bd90282 seaweedfs.s3.confd
3e9c41bc61cdd9a4c53ece64d847eca26ab7d0ce0cc98e72462c3dbb225a40de10a02201362801015a9c629d77d5c0d54c7228e9d20111fb6f478b2267d2db98 seaweedfs.sftp.confd
+7 -5
View File
@@ -1,18 +1,20 @@
# SeaweedFS Alpine Package
Repackages official SeaweedFS 4.47 Linux release tarballs for `x86_64` and
`aarch64`.
Builds SeaweedFS 4.48 from its upstream source release for `x86_64` and
`aarch64`. The package intentionally builds the upstream baseline feature set,
without optional build tags. Go and Cargo dependencies are resolved from the
versions pinned in the upstream `go.sum` and `Cargo.lock` files.
## Package Commands
Refresh generated sources:
When updating SeaweedFS, generate the config scaffolds and refresh checksums:
```sh
ALPINE_PACKAGE=seaweedfs mise run apk:update-generated
ALPINE_PACKAGE=seaweedfs mise run apk:checksum
```
The refresh command generates every SeaweedFS 4.47 scaffold configuration:
The refresh command generates every SeaweedFS scaffold configuration:
`admin`, `credential`, `filer`, `master`, `volume`, `notification`,
`replication`, `security`, and `shell`.
@@ -140,5 +142,5 @@ rc-service seaweedfs.master restart
Pin:
```sh
apk add seaweedfs=4.47-r2
apk add seaweedfs=4.47-r3
```
@@ -52,6 +52,7 @@ copy_2 = 6 # create 2 x 6 = 12 actual volumes
copy_3 = 3 # create 3 x 3 = 9 actual volumes
copy_other = 1 # create n x 1 = n actual volumes
threshold = 0.9 # create threshold
reservation_timeout = "5m"# capacity reservation timeout before unreleased reservations expire
disable = false # disables volume growth if true
# configuration flags for replication
@@ -232,6 +232,15 @@ kek = ""
# Cannot be used while /etc/s3/sse_kek exists on the filer — delete it first.
key = ""
# Trusted reverse proxies allowed to set X-Forwarded-For / X-Real-Ip for
# aws:SourceIp condition evaluation in S3 bucket and IAM policies. When the
# direct TCP peer is in this list, forwarded headers are honored; otherwise
# the direct peer address is used (matching AWS S3 semantics). Leave empty to
# always use the direct peer, which is the safe default.
# Can also be set via env var: WEED_S3_TRUSTED_PROXIES_WHITE_LIST
[s3.trusted_proxies]
white_list = "" # comma separated; bare IPs or CIDRs, e.g. "10.10.10.0/24"
# white list. It's checking request ip address.
[guard]
white_list = ""
@@ -27,3 +27,4 @@ percent = 10
hdd = "500ms"
ssd = "100ms"
nvme = "50ms"
@@ -7,29 +7,26 @@ pkgver="$(
awk -F= '$1 == "pkgver" { print $2; exit }' "${package_dir}/APKBUILD"
)"
tmpdir="$(mktemp -d)"
repo_root="${REPO_ROOT:-$(cd "${package_dir}/../../../.." && pwd)}"
source_archive="${repo_root}/.cache/apk-distfiles/seaweedfs-${pkgver}-src.tar.gz"
cleanup() {
rm -rf "${tmpdir}"
}
trap cleanup EXIT
case "$(uname -m)" in
x86_64)
archive="linux_amd64.tar.gz"
;;
aarch64|arm64)
archive="linux_arm64.tar.gz"
;;
*)
printf 'unsupported host architecture for SeaweedFS generated sources: %s\n' "$(uname -m)" >&2
exit 2
;;
esac
curl -fsSL \
-o "${tmpdir}/${archive}" \
"https://github.com/seaweedfs/seaweedfs/releases/download/${pkgver}/${archive}"
tar -xzf "${tmpdir}/${archive}" -C "${tmpdir}" weed
if [[ ! -f "${source_archive}" ]]; then
source_archive="${tmpdir}/seaweedfs-${pkgver}-src.tar.gz"
curl -fsSL \
-o "${source_archive}" \
"https://github.com/seaweedfs/seaweedfs/archive/refs/tags/${pkgver}.tar.gz"
fi
tar -xzf "${source_archive}" -C "${tmpdir}"
source_dir="${tmpdir}/seaweedfs-${pkgver}"
(
cd "${source_dir}"
go build -mod=readonly -buildvcs=false -trimpath -o "${tmpdir}/weed" ./weed
)
for config in "${configs[@]}"; do
"${tmpdir}/weed" scaffold -config "${config}" 2>/dev/null \
@@ -52,8 +52,6 @@ build_command_args() {
;;
esac
[ -n "${SEAWEEDFS_IP:-}" ] && command_args="$command_args -ip=${SEAWEEDFS_IP}"
[ -n "${SEAWEEDFS_PORT:-}" ] && command_args="$command_args -port=${SEAWEEDFS_PORT}"
command_args="$command_args ${SEAWEEDFS_OPTS:-}"
}
+7 -1
View File
@@ -50,7 +50,13 @@ if [[ ! -e "${HOME}/.abuild/abuild.conf" && -d "${repo_root}/.cache/abuild" ]];
fi
if ! compgen -G "${HOME}/.abuild/*.rsa" > /dev/null; then
abuild-keygen -a -n
# APK signatures identify their public key by filename. Matrix workers can
# otherwise generate different builder-<timestamp>.rsa keys with the same
# name when they start during the same second, making their artifacts
# impossible to merge. Use the selected package only while generating the
# key so the package metadata retains the configured PACKAGER value.
key_identity="${ALPINE_PACKAGE:-ci}"
PACKAGER="CI key <ci-${key_identity}@local.invalid>" abuild-keygen -a -n
fi
doas cp "${HOME}"/.abuild/*.rsa.pub /etc/apk/keys/
+1
View File
@@ -138,6 +138,7 @@ prepare() {
} >> "${GITHUB_ENV}"
fi
if [[ -n "${GITHUB_OUTPUT:-}" ]]; then
printf 'selected_packages=%s\n' "${ALPINE_PACKAGES}" >> "${GITHUB_OUTPUT}"
if [[ -n "${ALPINE_PACKAGES}" ]]; then
printf 'packages_selected=true\n' >> "${GITHUB_OUTPUT}"
else
+103
View File
@@ -0,0 +1,103 @@
#!/usr/bin/env bash
set -euo pipefail
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
repo_name="${ALPINE_REPO_NAME:-local}"
arches="${ALPINE_ARCHES:-x86_64 aarch64}"
artifact_root="${APK_CI_ARTIFACTS_DIR:-${repo_root}/packages/worker-artifacts}"
package_root="${APK_CI_PACKAGE_ROOT:-${repo_root}/packages/${repo_name}}"
keys_root="$(mktemp -d)"
cleanup() {
rm -rf "${keys_root}"
}
trap cleanup EXIT
require_command() {
command -v "$1" >/dev/null 2>&1 || {
printf 'missing required command: %s\n' "$1" >&2
exit 2
}
}
copy_key() {
local key="$1"
local destination="$2"
local key_name
key_name="$(basename "${key}")"
if [[ -e "${destination}/${key_name}" ]]; then
if cmp -s "${key}" "${destination}/${key_name}"; then
return
fi
printf 'conflicting public keys named %s\n' "${key_name}" >&2
exit 1
fi
cp "${key}" "${destination}/${key_name}"
}
require_command abuild-keygen
require_command abuild-sign
require_command apk
if [[ ! -d "${artifact_root}" ]]; then
printf 'missing worker artifacts directory: %s\n' "${artifact_root}" >&2
exit 1
fi
rm -rf "${package_root}"
mkdir -p "${package_root}" "${HOME}/.abuild"
if ! compgen -G "${HOME}/.abuild/*.rsa" > /dev/null; then
abuild-keygen -a -n
fi
shopt -s nullglob
merge_private_keys=("${HOME}"/.abuild/*.rsa)
merge_public_keys=("${HOME}"/.abuild/*.rsa.pub)
shopt -u nullglob
if [[ "${#merge_private_keys[@]}" -ne 1 || "${#merge_public_keys[@]}" -ne 1 ]]; then
printf 'expected exactly one merge signing key in %s/.abuild\n' "${HOME}" >&2
exit 1
fi
for arch in ${arches}; do
destination="${package_root}/${arch}"
keys_dir="${keys_root}/${arch}"
mkdir -p "${destination}"
while IFS= read -r -d '' apk; do
cp "${apk}" "${destination}/"
done < <(find "${artifact_root}" -type f -path "*/${arch}/*.apk" -print0)
shopt -s nullglob
apks=("${destination}"/*.apk)
shopt -u nullglob
if [[ "${#apks[@]}" -eq 0 ]]; then
rmdir "${destination}"
continue
fi
while IFS= read -r -d '' key; do
copy_key "${key}" "${destination}"
mkdir -p "${keys_dir}"
copy_key "${key}" "${keys_dir}"
done < <(find "${artifact_root}" -type f -path "*/${arch}/*.rsa.pub" -print0)
if ! compgen -G "${keys_dir}/*.rsa.pub" > /dev/null; then
printf 'missing worker signing key for %s artifacts\n' "${arch}" >&2
exit 1
fi
copy_key "${merge_public_keys[0]}" "${destination}"
(
cd "${destination}"
apk --keys-dir "${keys_dir}" index --rewrite-arch "${arch}" -o APKINDEX.tar.gz ./*.apk
abuild-sign -k "${merge_private_keys[0]}" APKINDEX.tar.gz
)
done
if ! compgen -G "${package_root}"/*/*.apk > /dev/null; then
printf 'no APK files found in worker artifacts: %s\n' "${artifact_root}" >&2
exit 1
fi