unos-repository

APK repository for unos
git clone git://git.finwo.net/misc/unos-repository
Log | Files | Refs | README

bootstrap-repo.sh (5135B)


      1 #!/bin/sh
      2 # mk/bootstrap-repo.sh - ensure an APKINDEX exists in the S3 repo.
      3 #
      4 # If the bucket already has x86_64/APKINDEX.tar.gz, do nothing.
      5 # Otherwise publish an empty signed index so `apk add` against the
      6 # repo stops 404ing before the first real package has been published.
      7 set -eu
      8 
      9 HERE=$(cd "$(dirname "$0")" && pwd)
     10 ROOT=$(cd "${HERE}/.." && pwd)
     11 
     12 ARCH="${ARCH:-x86_64}"
     13 case "${ARCH}" in arm64) ARCH=aarch64 ;; esac
     14 
     15 for v in BUCKET_ACCESS_KEY BUCKET_SECRET_KEY BUCKET_NAME BUCKET_ENDPOINT BUCKET_REGION BUCKET_PUBLIC_URL; do
     16   eval "val=\${${v}:-}"
     17   [ -n "${val}" ] || { echo "bootstrap-repo.sh: ${v} is not set" >&2; exit 1; }
     18 done
     19 
     20 url="${BUCKET_ENDPOINT%/}/${BUCKET_NAME}/${ARCH}/APKINDEX.tar.gz"
     21 public_url="${BUCKET_PUBLIC_URL%/}/${ARCH}/APKINDEX.tar.gz"
     22 tmp_body=$(mktemp)
     23 code=$(curl -sS -o "${tmp_body}" -w '%{http_code}' \
     24   --aws-sigv4 "aws:amz:${BUCKET_REGION}:s3" \
     25   --user "${BUCKET_ACCESS_KEY}:${BUCKET_SECRET_KEY}" \
     26   -H "x-amz-content-sha256: UNSIGNED-PAYLOAD" \
     27   "${url}") || code=000
     28 
     29 case "${code}" in
     30   2*) rm -f "${tmp_body}"
     31       anon_code=$(curl -sS -o /dev/null -w '%{http_code}' "${public_url}") || anon_code=000
     32       case "${anon_code}" in 2*) echo "==> repo already has ${ARCH}/APKINDEX.tar.gz (${code}, anon ${anon_code}), nothing to do"; exit 0 ;; *) echo "==> repo has ${ARCH}/APKINDEX.tar.gz but public fetch is ${anon_code}, re-publishing" ;; esac
     33       ;;
     34   404) rm -f "${tmp_body}"; echo "==> no ${ARCH}/APKINDEX.tar.gz (404), bootstrapping empty index" ;;
     35   000) echo "bootstrap-repo.sh: could not reach ${url} (curl failed)" >&2; cat "${tmp_body}" >&2 2>/dev/null || true; rm -f "${tmp_body}"; exit 1 ;;
     36   400) echo "bootstrap-repo.sh: bad request (400) for ${url} -- check BUCKET_ENDPOINT/BUCKET_NAME/BUCKET_REGION" >&2; echo "--- S3 response ---" >&2; cat "${tmp_body}" >&2 2>/dev/null || true; echo "--- env ---" >&2; echo "ENDPOINT=${BUCKET_ENDPOINT} NAME=${BUCKET_NAME} REGION=${BUCKET_REGION}" >&2; rm -f "${tmp_body}"; exit 1 ;;
     37   403) echo "bootstrap-repo.sh: permission denied (403) for ${url} -- check BUCKET credentials/region" >&2; echo "--- S3 response ---" >&2; cat "${tmp_body}" >&2 2>/dev/null || true; rm -f "${tmp_body}"; exit 1 ;;
     38   *) echo "bootstrap-repo.sh: unexpected HTTP ${code} for ${url}" >&2; cat "${tmp_body}" >&2 2>/dev/null || true; rm -f "${tmp_body}"; exit 1 ;;
     39 esac
     40 
     41 mkdir -p "${ROOT}/build/repo/${ARCH}"
     42 
     43 export PATH="${ROOT}/build/host/bin:${PATH}"
     44 command -v apk >/dev/null 2>&1 || { echo "bootstrap-repo.sh: no apk on PATH; run mk/bootstrap-host.sh first" >&2; exit 1; }
     45 
     46 . "${HERE}/sign-key.inc"
     47 KEY=$(resolve_sign_key) || { echo "bootstrap-repo.sh: no signing key" >&2; exit 1; }
     48 KEYNAME=$(basename "${KEY}" .rsa)
     49 
     50 if [ ! -x "${HERE}/pax-tar" ] || [ "${HERE}/pax-tar.c" -nt "${HERE}/pax-tar" ]; then
     51   cc -std=c99 -O2 -Wall -Wextra -o "${HERE}/pax-tar" "${HERE}/pax-tar.c"
     52 fi
     53 
     54 cd "${ROOT}/build/repo/${ARCH}"
     55 
     56 # apk index with no inputs still needs to produce a valid archive;
     57 # `echo` avoids the shell expanding *.apk to a literal when empty.
     58 echo -n "" | tar -czf APKINDEX.tar.gz -T /dev/null 2>/dev/null || true
     59 # Try the real tool first; fall back to the empty tar if it produced nothing.
     60 if [ ! -s APKINDEX.tar.gz ] || ! tar -tzf APKINDEX.tar.gz >/dev/null 2>&1; then
     61   : > APKINDEX
     62   tar -czf APKINDEX.tar.gz APKINDEX
     63   rm -f APKINDEX
     64 fi
     65 
     66 # Rebuild properly if apk can do it (covers the signed-index header fixup below)
     67 # and ensures the index is well-formed even when empty.
     68 if ls ./*.apk >/dev/null 2>&1; then
     69   apk index --allow-untrusted -o APKINDEX.tar.gz ./*.apk
     70 else
     71   # empty repo: create minimal index that `apk add` accepts
     72   rm -f APKINDEX.tar.gz
     73   mkdir -p .idx-empty
     74   : > .idx-empty/APKINDEX
     75   tar -czf APKINDEX.tar.gz -C .idx-empty APKINDEX
     76   rm -rf .idx-empty
     77 fi
     78 
     79 echo "==> signing APKINDEX.tar.gz with ${KEYNAME}"
     80 openssl dgst -sha1 -sign "${KEY}" -out ".SIGN.RSA.${KEYNAME}.rsa.pub" APKINDEX.tar.gz
     81 mkdir -p "${ROOT}/build/work/.idxsig"
     82 cp ".SIGN.RSA.${KEYNAME}.rsa.pub" "${ROOT}/build/work/.idxsig/"
     83 "${HERE}/pax-tar" --no-checksum "${ROOT}/build/work/.idxsig" idxsig.tar
     84 sigsiz=$(stat -c%s idxsig.tar)
     85 head -c $((sigsiz - 1024)) idxsig.tar > idxsignotr.tar
     86 gzip -n -9 -f idxsignotr.tar
     87 cat idxsignotr.tar.gz APKINDEX.tar.gz > APKINDEX.signed.tar.gz
     88 mv APKINDEX.signed.tar.gz APKINDEX.tar.gz
     89 rm -f ".SIGN.RSA.${KEYNAME}.rsa.pub" idxsig.tar idxsignotr.tar.gz
     90 rm -rf "${ROOT}/build/work/.idxsig"
     91 
     92 echo "==> publishing ${ARCH}/APKINDEX.tar.gz"
     93 sha=$(sha256sum APKINDEX.tar.gz | cut -d' ' -f1)
     94 tmp_put=$(mktemp)
     95 code=$(curl -sS -o "${tmp_put}" -w '%{http_code}' \
     96   --aws-sigv4 "aws:amz:${BUCKET_REGION}:s3" \
     97   --user "${BUCKET_ACCESS_KEY}:${BUCKET_SECRET_KEY}" \
     98   -H "x-amz-content-sha256: ${sha}" \
     99   -X PUT --upload-file APKINDEX.tar.gz \
    100   "${url}") || { echo "bootstrap-repo.sh: upload failed" >&2; cat "${tmp_put}" >&2 2>/dev/null || true; rm -f "${tmp_put}"; exit 1; }
    101 case "${code}" in 2*) rm -f "${tmp_put}"; echo "==> bootstrapped ${ARCH}/APKINDEX.tar.gz (${code})" ;; *) echo "bootstrap-repo.sh: upload returned HTTP ${code}" >&2; cat "${tmp_put}" >&2 2>/dev/null || true; rm -f "${tmp_put}"; exit 1 ;; esac