From b6ceea9347cfa51659a8fbccb102c3544a6e804c Mon Sep 17 00:00:00 2001 From: Douglas Teles Date: Tue, 23 Jun 2026 17:03:35 -0300 Subject: [PATCH] 2.1: pacman as real update mechanism (client side) Decision: pacman repo lives on GitHub Releases at archr-linux/archr-repo. No VPS, no repo.arch-r.io. Google Drive stays out of runtime (backup/archive only). Cloudflare R2 fallback deferred. Detail in docs/release-policy.md. archr-update rewritten end-to-end: - 188 lines of dead POST-to-update.arch-r.io code replaced by an 87-line wrapper around pacman -Syu. The POST endpoint never existed so there is no legacy compat to preserve. - subcommands: check, update, info. system.cfg "updates.branch" maps to repo-stable / repo-next / repo-dev tags on archr-linux/archr-repo; the mirrorlist is rewritten on every invocation so channel switches are immediate. pacman.conf rebuilt around a single [archr] repo (Arch Linux ARM upstream removed). SigLevel starts at "Required DatabaseOptional" during bootstrap; will tighten to "Required" once the production master key signs the .db. pacman-init reachability test points at github.com and the keyring populate target is "archr" instead of "archlinuxarm". archr-keyring repurposed: the three archlinuxarm keyring files are removed; package.mk now expects archr.gpg / archr-trusted / archr-revoked under keys/ and ships empty placeholders until the real ArchR master key is generated. scripts/repo/gen-pacman-repo + README: take the build.*-RK3326 tree that "make docker-RK3326" leaves behind, package each install_pkg/ as a .pkg.tar.zst with synthesized .PKGINFO, run repo-add to build archr.db, optionally GPG-sign everything. Emits a `gh release create` command for the publish step. CI hook left as a follow-up. docs/improvements.md 2.1 marked partial: client and build script are ready; what blocks the first usable release is generating the GPG master key, creating archr-linux/archr-repo on GitHub, and one manual publish for the repo-dev tag to validate the end-to-end loop. Co-Authored-By: Claude Opus 4.7 --- docs/improvements.md | 16 +- docs/release-policy.md | 36 ++- .../archr/sources/scripts/archr-update | 227 +++++------------- .../archr-keyring/keys/archlinuxarm-revoked | 0 .../archr-keyring/keys/archlinuxarm-trusted | 1 - .../archr-keyring/keys/archlinuxarm.gpg | 51 ---- .../security/archr-keyring/package.mk | 27 ++- .../sysutils/pacman/config/mirrorlist | 29 +-- .../sysutils/pacman/config/pacman.conf | 31 ++- .../sysutils/pacman/scripts/pacman-init | 45 ++-- scripts/repo/README.md | 59 +++++ scripts/repo/gen-pacman-repo | 126 ++++++++++ 12 files changed, 360 insertions(+), 288 deletions(-) delete mode 100644 projects/ArchR/packages/security/archr-keyring/keys/archlinuxarm-revoked delete mode 100644 projects/ArchR/packages/security/archr-keyring/keys/archlinuxarm-trusted delete mode 100644 projects/ArchR/packages/security/archr-keyring/keys/archlinuxarm.gpg create mode 100644 scripts/repo/README.md create mode 100755 scripts/repo/gen-pacman-repo diff --git a/docs/improvements.md b/docs/improvements.md index 99419e31c4..b041a583df 100644 --- a/docs/improvements.md +++ b/docs/improvements.md @@ -89,11 +89,17 @@ Identidade Arch vem dos 7 itens desta seção (pacman, PKGBUILD, FHS, rolling, K ### 2.1. Wirar pacman como mecanismo de update real -- [ ] **Subir mirror `repo.arch-r.io`** L. Hospedar `archr-core` (sistema base) e `archr-extra` (emuladores, temas, scrapers) como repos pacman. Sync via CI quando build de release sai. -- [ ] **Construir packages `.pkg.tar.zst` no pipeline de release** M. Hoje cuspimos `.img.gz`; passar a também produzir um pacote pacman por componente quando o build do package.mk concluir. Permite atualização granular. -- [ ] **Substituir `archr-update` por wrapper de `pacman -Syu`** M. Apenas para upgrades incrementais. Reservar image-based para upgrades grandes (kernel, mudança de major version) com migração assistida. -- [ ] **Suporte a `pacman -S `** M. Quando 2.1.1 e 2.1.2 estiverem ativos, o usuário pode instalar emuladores opcionais sem reflash. Reduz tamanho da imagem base. -- [ ] **Rollback via pacman cache** S. `/storage/.pacman/cache` já está reservado no package.mk; só falta UI no settings menu para "voltar para a release anterior". +**Status: pipeline cliente pronto (2026-06-23).** Falta gerar a primeira release no `archr-linux/archr-repo` para o sistema ter o que sincronizar. + +- [x] **Decisão de infra: GitHub Releases como mirror único.** Sem VPS, sem `repo.arch-r.io`. Detalhes em `docs/release-policy.md`. Google Drive como backup; Cloudflare R2 fica como fallback futuro se aparecer problema concreto. +- [x] **`archr-update` reescrito** como wrapper fino de `pacman -Syu`. 87 linhas (eram 188). Comandos: `archr-update [check|update|info]`. Channel lido de `system.cfg "updates.branch"` e refletido no mirrorlist via rewrite on-the-fly. +- [x] **`pacman.conf` apontando para o repo `archr`** (não mais Arch Linux ARM repos). `SigLevel = Required DatabaseOptional` durante bootstrap; aperta para `Required` quando o keyring de produção entrar. +- [x] **`pacman-init` adaptado**: testa conectividade via `github.com` em vez de `mirror.archlinuxarm.org`, popula keyring `archr` (não mais `archlinuxarm`). +- [x] **`archr-keyring` reformulado**: ship empty placeholders por enquanto, hooks prontos para receber o keyring real (`archr.gpg`, `archr-trusted`, `archr-revoked`) quando a chave master for gerada. +- [x] **`scripts/repo/gen-pacman-repo`**: empacota `build.*/install_pkg//` em `.pkg.tar.zst`, gera `.PKGINFO`, monta `archr.db` via `repo-add`. README ao lado documenta o workflow `gh release create repo-`. +- [ ] **Gerar a chave master GPG**: chave ArchR offline + subchave de signer. Atualizar `archr-keyring/keys/` com `archr.gpg`, `archr-trusted`, `archr-revoked`. Bloqueia o primeiro release assinado. +- [ ] **Primeira release no `archr-linux/archr-repo`**: criar o repo no GitHub, rodar `gen-pacman-repo` em build local, publicar `repo-dev` para teste interno antes de promover para `repo-next` e `repo-stable`. +- [ ] **CI no `archr-linux/Arch-R`** que invoque `gen-pacman-repo` após `make docker-RK3326` e publique no `archr-repo` automaticamente. GitHub Actions free tier basta. ### 2.2. Aproximar do FHS diff --git a/docs/release-policy.md b/docs/release-policy.md index 6e46c07b5e..78a73665f8 100644 --- a/docs/release-policy.md +++ b/docs/release-policy.md @@ -71,12 +71,36 @@ Tooling consumidor (Flasher, archr-update) pode parsear essa tag e mostrar banne 3. Permanece em `next` por no mínimo 7 dias com feedback dos testers. 4. Promove para `stable`: anúncio com tag apropriada (Action Required se houver migração). -## Compatibilidade com `archr-update` existente +## Infra de distribuição -`archr-update` atual já aceita `BRANCH` como variável de canal e faz POST para `update.arch-r.io`. Nenhuma mudança no cliente é necessária. O servidor precisa entender: +**Decisão registrada em 2026-06-23.** -- `BRANCH=stable` (default): retorna último `YYYY.MM.PATCH` validado. -- `BRANCH=next`: retorna último build da branch principal. -- `BRANCH=dev`: retorna último build noturno (com warning de instabilidade). +**Mirror único: GitHub Releases.** Tudo que ArchR distribui (imagem `.img.gz` e pacotes `.pkg.tar.zst` quando 2.1 estiver pronto) sai pelo GitHub. Justificativa: -Quando 2.1 (pacman como update real) estiver implementado, os canais migram naturalmente para repos pacman separados (`archr-core-stable`, `archr-core-next`, `archr-core-dev`). +- Custo zero. GitHub serve a CDN, TLS e storage como bônus do repo público. +- Throughput global. CDN distribuída cobre o usuário onde estiver. +- Limites suficientes. 2 GB por asset cobre o maior pacote (kernel + initramfs). Sem limite total por release nem por conta. +- Já é o canal vigente. Reduzimos uma variável (não há "novo provedor para o usuário aprender"). + +**Google Drive (10 TB do mantenedor):** ficou de fora do runtime. Usos legítimos discutidos e aprovados: +- Backup das releases publicadas (via rclone após upload no GitHub). +- Archive histórico de versões antigas que saíram do GitHub. +- Assets pesados internos (BIOS de teste, gameplay para QA, scraper packs). +- Não serve como mirror pacman: URLs com hash, virus-scan warning em arquivos >25 MB, throttling, range requests inconsistentes. + +**Cloudflare R2 ou Backblaze B2 como fallback:** avaliados, descartados por enquanto. Reavaliar se aparecer um problema concreto de disponibilidade do GitHub. + +## Plano de update sem legacy + +`archr-update` original faz POST para `update.arch-r.io`. Esse endpoint **nunca existiu**: o script nunca entregou update funcional. Significa que hoje o único caminho de update é reflashar a microSD com nova imagem baixada do GitHub Releases manualmente, e que **não há compatibilidade legada a preservar**. + +A implementação de 2.1 (pacman como update real) é portanto clean slate: + +1. Repo pacman `archr-linux/archr-repo` no GitHub. +2. Cada release nesse repo é uma tag tipo `repo-YYYY.MM.PATCH`, com todos os `.pkg.tar.zst` da snapshot + `archr-core.db` assinado. +3. Tags rolling `repo-stable`, `repo-next`, `repo-dev` mantêm sempre o snapshot mais recente do canal e ficam como alvo do `mirrorlist`. +4. `/etc/pacman.d/mirrorlist` aponta para `https://github.com/archr-linux/archr-repo/releases/download/repo-`. +5. `archr-update` reescrito como wrapper de `pacman -Syu` (algumas dezenas de linhas). +6. Reflashar continua sendo o caminho de upgrade para major bumps (kernel ABI, FHS, etc.); pacman cobre incrementais. + +Primeira release ArchR a ter update via pacman será marco histórico. Pode ser RC5 ou v2.0 final, conforme prontidão da infra GPG e CI. diff --git a/projects/ArchR/packages/archr/sources/scripts/archr-update b/projects/ArchR/packages/archr/sources/scripts/archr-update index 4dfb9e5016..850fdf7d65 100755 --- a/projects/ArchR/packages/archr/sources/scripts/archr-update +++ b/projects/ArchR/packages/archr/sources/scripts/archr-update @@ -1,188 +1,87 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0 # Copyright (C) 2026 ArchR (https://github.com/archr-linux/Arch-R) +# +# archr-update: wrapper around pacman to surface the same CLI ArchR +# users were promised before, while the actual update mechanism is +# pacman -Syu against the repo published on GitHub Releases. +# +# Release channel is read from system.cfg "updates.branch" and maps to +# the matching mirror tag on github.com/archr-linux/archr-repo: +# stable -> repo-stable +# next -> repo-next +# dev -> repo-dev +# +# The mirrorlist that points to those tags is installed by the pacman +# package (/etc/pacman.d/mirrorlist). . /etc/profile -BRANCH="$(get_setting updates.branch)" -FORCE="$(get_setting updates.force)" +BRANCH="$(get_setting updates.branch 2>/dev/null)" +BRANCH="${BRANCH:-stable}" -ENDPOINT_URL="https://update.arch-r.io" - -MACHINEIDFILE=/storage/.cache/systemd-machine-id -USERID=$(cat ${MACHINEIDFILE}) - -# Function to check for an update. It returns a URL if an update is available. -check_update() { - custom_force="${1:-$FORCE}" - - update_url=$(curl -s -S -X POST \ - -F "OS=${OS_NAME}" \ - -F "ARCH=${HW_ARCH}" \ - -F "SOC=${HW_DEVICE}" \ - -F "VERSION=${OS_VERSION}" \ - -F "UID=${USERID:(-12)}" \ - -F "BUILD=${OS_BUILD}" \ - -F "DEV=${QUIRK_DEVICE}" \ - -F "FORCE=${custom_force}" \ - -F "BRANCH=${BRANCH}" \ - "$ENDPOINT_URL") - echo "$update_url" - return $? +# Channel is reflected by a single line in mirrorlist; rewrite it on +# the fly so the user can switch channels by changing the setting. +write_mirrorlist() { + cat >/etc/pacman.d/mirrorlist </dev/null 2>&1 } -# Returns 0 if there is enough available free space at target_path in megabytes. -check_disk_space() { - target_path=$1 - required_mB=$2 - available_mB=$(df -m "$target_path" | awk 'NR==2 {print $4}') - if [ "$available_mB" -ge "$required_mB" ]; then - return 0 - else +usage() { + cat </dev/null 2>&1 || { + echo "Failed to sync repo metadata. Check network." + return 1 + } + pending=$(pacman -Qu | wc -l) + if [ "${pending}" -eq 0 ]; then + echo "No updates available." return 1 fi + echo "Updates available: ${pending} package(s)." + pacman -Qu } -# Download a file from url to destination and show progress. -download_file() { - url=$1 - destination=$2 - curl --progress-bar -S -L "$url" -o "$destination" - return $? +cmd_update() { + write_mirrorlist + pacman -Syu --noconfirm } -# Main update logic. -main_update() { - custom_force="${1:-$FORCE}" - update_url=$(check_update "$custom_force") - - # Check if the returned update_url looks like a URL (e.g., starts with http) - case "$update_url" in - http://*|https://*) - echo "Update available at: $update_url" ;; - *) - echo "No update available or invalid update URL." - exit 1 - ;; - esac - - # Check that there is at least 2GB of available free space on /storage. - if ! check_disk_space "/storage" "2048"; then - echo "Not enough free space on /storage (need at least 2GB)." - exit 1 - fi - - # Ensure that the /var/cache/archr/update folder exists. - if [ ! -d "/var/cache/archr/update" ]; then - mkdir -p /var/cache/archr/update || { echo "Failed to create /var/cache/archr/update directory."; exit 1; } - fi - - # Extract the file name from the update URL. - filename=$(basename "$update_url") - - # Define download destinations inside /var/cache/archr/update folder using the original file names. - update_file="/var/cache/archr/update/${filename}" - checksum_file="/var/cache/archr/update/${filename}.sha256" - - # Download the update file. - echo "Downloading update file..." - download_file "$update_url" "$update_file" - if [ $? -ne 0 ]; then - echo "Failed to download update file." - exit 1 - fi - - # Download the checksum file (append .sha256 to the update URL). - checksum_url="${update_url}.sha256" - echo "Downloading checksum file..." - download_file "$checksum_url" "$checksum_file" - if [ $? -ne 0 ]; then - echo "Failed to download checksum file." - rm -f "$update_file" - exit 1 - fi - - # Verify checksum. - echo "Verifying the downloaded update..." - expected_checksum=$(awk '{print $1}' "$checksum_file") - actual_checksum=$(sha256sum "$update_file" | awk '{print $1}') - if [ "$expected_checksum" = "$actual_checksum" ]; then - echo "Checksum verified successfully. Reboot to apply the update." - set_setting updates.force 0 - sync - else - echo "Checksum verification failed. Removing downloaded files." - rm -f "$update_file" "$checksum_file" - exit 1 - fi +cmd_info() { + echo "OS: ${OS_NAME:-ArchR} ${OS_VERSION:-?}" + echo "Build: ${OS_BUILD:-?}" + echo "Channel: ${BRANCH}" + echo "Mirror: https://github.com/archr-linux/archr-repo/releases/download/repo-${BRANCH}" + echo "Pacman: $(pacman --version | head -1 | awk '{print $3}')" } -# Check network connectivity (ping DNS server) -if ! ping -c 1 8.8.8.8 >/dev/null 2>&1; then +if ! network_ok; then echo "Network connection unavailable." exit 1 fi -# Read the first argument to determine the mode. -mode=$1 - -# Check if the mode is a number (e.g., 20250101), which indicates forcing a specific version -if echo "$mode" | grep -q '^[0-9]\{8\}$'; then - # If mode is a date (8 digits), treat it as a forced version - echo "Forcing update to version $mode..." - main_update "$mode" - exit 0 -fi - -case "$mode" in - check) - update_url=$(check_update) - case "$update_url" in - http://*|https://*) - # Extract the filename from the URL. - filename=$(basename "$update_url") - # Use shell parameter expansion to remove everything up to the last dash, then remove the .tar suffix. - version=${filename##*-} - version=${version%.tar} - echo "$version" - exit 0 - ;; - *) - echo "No update available." - exit 1 - ;; - esac - ;; - releases) - # Get the list of available releases - echo "Checking available releases..." - releases=$(get_releases) - echo "$releases" - exit 0 - ;; - update|"") - # If mode is "update" or no argument is provided, proceed with the update. - main_update - ;; - *) - echo "Usage: $0 [check|update|releases|]" - echo " check - Check for available updates and print version" - echo " update - Update to the latest version" - echo " releases - Show available releases" - echo " - Force update to specific version (e.g., 20250101)" - exit 1 - ;; +case "${1:-update}" in + check) cmd_check ;; + update) cmd_update ;; + info) cmd_info ;; + -h|--help|help) usage ;; + *) usage; exit 2 ;; esac diff --git a/projects/ArchR/packages/security/archr-keyring/keys/archlinuxarm-revoked b/projects/ArchR/packages/security/archr-keyring/keys/archlinuxarm-revoked deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/projects/ArchR/packages/security/archr-keyring/keys/archlinuxarm-trusted b/projects/ArchR/packages/security/archr-keyring/keys/archlinuxarm-trusted deleted file mode 100644 index eb5943d7ba..0000000000 --- a/projects/ArchR/packages/security/archr-keyring/keys/archlinuxarm-trusted +++ /dev/null @@ -1 +0,0 @@ -68B3537F39A313B3E574D06777193F152BDBE6A6:4: diff --git a/projects/ArchR/packages/security/archr-keyring/keys/archlinuxarm.gpg b/projects/ArchR/packages/security/archr-keyring/keys/archlinuxarm.gpg deleted file mode 100644 index c043b82c42..0000000000 --- a/projects/ArchR/packages/security/archr-keyring/keys/archlinuxarm.gpg +++ /dev/null @@ -1,51 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- - -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 -fx6y8+A0kBiaAmcY01U/upYXeHs= -=AIgD ------END PGP PUBLIC KEY BLOCK----- diff --git a/projects/ArchR/packages/security/archr-keyring/package.mk b/projects/ArchR/packages/security/archr-keyring/package.mk index 3040d0ff73..c40451a7b2 100644 --- a/projects/ArchR/packages/security/archr-keyring/package.mk +++ b/projects/ArchR/packages/security/archr-keyring/package.mk @@ -2,12 +2,12 @@ # Copyright (C) 2026 ArchR (https://github.com/archr-linux) PKG_NAME="archr-keyring" -PKG_VERSION="20240419" +PKG_VERSION="20260623" PKG_LICENSE="GPL" -PKG_SITE="https://archlinuxarm.org" +PKG_SITE="https://arch-r.io" PKG_URL="" PKG_DEPENDS_TARGET="toolchain gnupg" -PKG_LONGDESC="ArchR keyring: Arch Linux ARM GPG keys for pacman package verification." +PKG_LONGDESC="ArchR pacman keyring: master + signer public keys for package verification." PKG_TOOLCHAIN="manual" make_target() { @@ -15,9 +15,22 @@ make_target() { } makeinstall_target() { - # Install Arch Linux ARM keyring for pacman-key --populate mkdir -p ${INSTALL}/usr/share/pacman/keyrings - cp ${PKG_DIR}/keys/archlinuxarm.gpg ${INSTALL}/usr/share/pacman/keyrings/ - cp ${PKG_DIR}/keys/archlinuxarm-trusted ${INSTALL}/usr/share/pacman/keyrings/ - cp ${PKG_DIR}/keys/archlinuxarm-revoked ${INSTALL}/usr/share/pacman/keyrings/ + + # ArchR master + signer keys. When a real keyring is generated, ship: + # keys/archr.gpg - public keyring file + # keys/archr-trusted - trusted key fingerprints, one per line, + # format: :: + # keys/archr-revoked - revoked fingerprints, one per line + # The placeholder release ships an empty keyring; pacman runs with + # SigLevel = Required DatabaseOptional and accepts unsigned packages + # from the archr repo because the .db remains optional. Tighten to + # 'Required' once the real master key is generated and signs the .db. + for f in archr.gpg archr-trusted archr-revoked; do + if [ -f "${PKG_DIR}/keys/${f}" ]; then + cp "${PKG_DIR}/keys/${f}" ${INSTALL}/usr/share/pacman/keyrings/ + else + : >${INSTALL}/usr/share/pacman/keyrings/${f} + fi + done } diff --git a/projects/ArchR/packages/sysutils/pacman/config/mirrorlist b/projects/ArchR/packages/sysutils/pacman/config/mirrorlist index 8833962a7b..269c9559a7 100644 --- a/projects/ArchR/packages/sysutils/pacman/config/mirrorlist +++ b/projects/ArchR/packages/sysutils/pacman/config/mirrorlist @@ -1,20 +1,15 @@ # -# Arch Linux ARM mirror list -# Generated for ArchR distribution +# ArchR pacman mirror list +# +# Auto-rewritten by archr-update based on system.cfg "updates.branch". +# The line below is the stable-channel default; running +# archr-update +# regenerates the file from the current channel setting. +# +# Channels available: +# repo-stable - monthly validated snapshot, default for end users +# repo-next - validated next-channel build, for testers +# repo-dev - nightly, may break, for maintainers # -## Arch Linux ARM - Primary -Server = http://mirror.archlinuxarm.org/$arch/$repo - -## Arch Linux ARM - US mirrors -# Server = http://ca.us.mirror.archlinuxarm.org/$arch/$repo -# Server = http://fl.us.mirror.archlinuxarm.org/$arch/$repo -# Server = http://il.us.mirror.archlinuxarm.org/$arch/$repo -# Server = http://nj.us.mirror.archlinuxarm.org/$arch/$repo - -## Arch Linux ARM - EU mirrors -# Server = http://de.mirror.archlinuxarm.org/$arch/$repo -# Server = http://dk.mirror.archlinuxarm.org/$arch/$repo -# Server = http://eu.mirror.archlinuxarm.org/$arch/$repo -# Server = http://hu.mirror.archlinuxarm.org/$arch/$repo -# Server = http://sg.mirror.archlinuxarm.org/$arch/$repo +Server = https://github.com/archr-linux/archr-repo/releases/download/repo-stable diff --git a/projects/ArchR/packages/sysutils/pacman/config/pacman.conf b/projects/ArchR/packages/sysutils/pacman/config/pacman.conf index 8a47d3ef3f..24a84d17ed 100644 --- a/projects/ArchR/packages/sysutils/pacman/config/pacman.conf +++ b/projects/ArchR/packages/sysutils/pacman/config/pacman.conf @@ -5,7 +5,8 @@ # [options] -# Paths adapted for ArchR (mutable state on /storage partition) +# Paths follow Arch convention; on ArchR the dirs are bridge symlinks +# pointing into the /storage rw overlay (see archr meta-package). RootDir = / DBPath = /var/lib/pacman/ CacheDir = /var/cache/pacman/pkg/ @@ -13,31 +14,27 @@ LogFile = /var/log/pacman.log GPGDir = /etc/pacman.d/gnupg/ HookDir = /etc/pacman.d/hooks/ -HoldPkg = pacman glibc bash +HoldPkg = pacman glibc bash linux archr-keyring Architecture = aarch64 -# Signature checking - relaxed for initial setup -# Tighten to 'Required DatabaseOptional' after running pacman-key --init -SigLevel = Optional TrustAll +# Signature checking. Required is the target once archr-keyring ships +# the production master key; DatabaseOptional during bootstrap because +# the .db files in the first releases may not be signed yet. +SigLevel = Required DatabaseOptional LocalFileSigLevel = Optional -# Misc options CheckSpace ParallelDownloads = 3 Color # -# Arch Linux ARM repositories +# ArchR official repository +# +# Hosted as GitHub Releases under archr-linux/archr-repo. The release +# tag is per channel (repo-stable, repo-next, repo-dev); archr-update +# rewrites /etc/pacman.d/mirrorlist with the right tag based on the +# system.cfg "updates.branch" setting before invoking pacman. # -[core] -Include = /etc/pacman.d/mirrorlist - -[extra] -Include = /etc/pacman.d/mirrorlist - -[alarm] -Include = /etc/pacman.d/mirrorlist - -[aur] +[archr] Include = /etc/pacman.d/mirrorlist diff --git a/projects/ArchR/packages/sysutils/pacman/scripts/pacman-init b/projects/ArchR/packages/sysutils/pacman/scripts/pacman-init index ec2b1e48d5..f1f4726c79 100644 --- a/projects/ArchR/packages/sysutils/pacman/scripts/pacman-init +++ b/projects/ArchR/packages/sysutils/pacman/scripts/pacman-init @@ -2,9 +2,15 @@ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2026 ArchR (https://github.com/archr-linux) # -# pacman-init: Initialize pacman on first boot -# Creates directory structure and initializes GPG keyring -# Works offline using embedded Arch Linux ARM keys +# pacman-init: bring pacman state up on first boot. +# +# - Materialize the dir structure the package config expects on +# /storage (the bridge symlinks /var/lib/pacman, /var/cache/pacman/pkg +# already point here). +# - Initialize the GPG keyring and trust the embedded ArchR master key +# (populated by the archr-keyring package). +# - Sync repo metadata if we have network. Best-effort; archr-update +# will sync again on demand. set -e @@ -12,7 +18,6 @@ PACMAN_ROOT="/storage/.pacman" echo "ArchR: Initializing pacman..." -# Create pacman directory structure on /storage mkdir -p "${PACMAN_ROOT}/db/local" mkdir -p "${PACMAN_ROOT}/db/sync" mkdir -p "${PACMAN_ROOT}/cache" @@ -23,31 +28,31 @@ mkdir -p "${PACMAN_ROOT}/logs" echo "ArchR: Pacman directory structure created." -# Initialize pacman GPG keyring -if [ ! -d /etc/pacman.d/gnupg/trustdb.gpg ] || [ ! -s /etc/pacman.d/gnupg/trustdb.gpg ]; then +# Initialize and populate the GPG keyring with the ArchR master key +# (offline; archr-keyring ships the keyring file). +if [ ! -s /etc/pacman.d/gnupg/trustdb.gpg ]; then echo "ArchR: Initializing pacman keyring..." pacman-key --init 2>/dev/null || true - # Populate with embedded Arch Linux ARM keys (offline, no network needed) - if [ -f /usr/share/pacman/keyrings/archlinuxarm.gpg ]; then - echo "ArchR: Populating keyring with Arch Linux ARM keys (offline)..." - pacman-key --populate archlinuxarm 2>/dev/null || true - echo "ArchR: Keyring populated successfully." + if [ -f /usr/share/pacman/keyrings/archr.gpg ]; then + echo "ArchR: Populating keyring with ArchR master key..." + pacman-key --populate archr 2>/dev/null || true + echo "ArchR: Keyring populated." else - echo "ArchR: WARNING: archlinuxarm keyring not found at /usr/share/pacman/keyrings/" - echo "ArchR: Package signature verification may fail." + echo "ArchR: WARNING: archr keyring not found at /usr/share/pacman/keyrings/archr.gpg" + echo "ArchR: Package signature verification will fail until archr-keyring is reinstalled." fi fi -# Sync package databases if network is available -if ping -c 1 -W 3 mirror.archlinuxarm.org >/dev/null 2>&1; then - echo "ArchR: Network available, syncing package databases..." - pacman -Sy --noconfirm 2>/dev/null || true +# Best-effort metadata sync against GitHub. Silent failure: pacman -Sy +# (and archr-update check / update) will retry interactively later. +if curl -s -o /dev/null --max-time 4 https://github.com; then + echo "ArchR: Network available, syncing repo metadata..." + pacman -Sy --noconfirm >/dev/null 2>&1 || true else - echo "ArchR: Network unavailable, skipping database sync." - echo "ArchR: Run 'pacman -Sy' when online to sync databases." + echo "ArchR: Network unavailable, skipping initial metadata sync." + echo "ArchR: Run 'archr-update check' when online." fi -# Mark as initialized touch "${PACMAN_ROOT}/.initialized" echo "ArchR: Pacman initialization complete." diff --git a/scripts/repo/README.md b/scripts/repo/README.md new file mode 100644 index 0000000000..ada9415542 --- /dev/null +++ b/scripts/repo/README.md @@ -0,0 +1,59 @@ +# scripts/repo + +Tooling for the GitHub-Releases-as-pacman-mirror workflow described in +`docs/release-policy.md`. The end result is a tag like `repo-stable` +on `archr-linux/archr-repo` with the assembled `.pkg.tar.zst` files +and signed metadata. + +## gen-pacman-repo + +Reads the finished build tree (`build.*-RK3326/install_pkg//`) +that `make docker-RK3326` leaves behind, packs each `` directory +into a `--1-aarch64.pkg.tar.zst`, generates the +`.PKGINFO` sidecar that pacman needs, and runs `repo-add` to build +`archr.db` and `archr.files`. + +Run after a successful build: + +```sh +BUILD_DIR=build.ArchR-RK3326.aarch64-2026.06-devel \ +OUT_DIR=/tmp/repo-out \ +CHANNEL=dev \ +SIGNER= \ + scripts/repo/gen-pacman-repo +``` + +Then upload: + +```sh +gh release create repo-dev \ + --repo archr-linux/archr-repo \ + --title "ArchR repo dev $(date +%Y%m%d)" \ + /tmp/repo-out/* +``` + +## GPG signing + +For production releases, set `SIGNER=` and have the +agent (or a YubiKey-backed agent) ready. `repo-add --sign` will sign +the .db as it walks the package list, and each .pkg.tar.zst gets a +.sig as well. + +The master key whose public half is bundled into the `archr-keyring` +package must include `` either directly or as a signed +subkey, otherwise `pacman-key --populate archr` on the client will +not extend trust to packages signed by it. + +## Channels and tag mapping + +`archr-update` rewrites `/etc/pacman.d/mirrorlist` based on +`system.cfg "updates.branch"`: + +| Channel value | Mirror tag on archr-linux/archr-repo | +|---------------|--------------------------------------| +| `stable` (default) | `repo-stable` | +| `next` | `repo-next` | +| `dev` | `repo-dev` | + +The promotion workflow (dev -> next -> stable) is documented in +`docs/release-policy.md`. diff --git a/scripts/repo/gen-pacman-repo b/scripts/repo/gen-pacman-repo new file mode 100755 index 0000000000..762c687c1c --- /dev/null +++ b/scripts/repo/gen-pacman-repo @@ -0,0 +1,126 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2026 ArchR (https://github.com/archr-linux/Arch-R) +# +# gen-pacman-repo: build a pacman repo (archr-core.db + .pkg.tar.zst per +# package) out of a finished ArchR build tree. +# +# Inputs: +# BUILD_DIR - the build.* dir that has install_pkg// trees +# (defaults to the most recent build.*-RK3326 under cwd) +# OUT_DIR - where the .pkg.tar.zst and .db get written +# (defaults to ${BUILD_DIR}/../repo-out) +# CHANNEL - stable|next|dev. Goes into PKGINFO and the .db name +# (defaults to dev) +# SIGNER - GPG key id to sign packages and the .db with. +# If empty, packages are not signed (good for local CI). +# +# Output: +# ${OUT_DIR}/archr.db (+.sig if signed) +# ${OUT_DIR}/archr.files +# ${OUT_DIR}/---aarch64.pkg.tar.zst (+.sig) +# +# This is the GitHub-Releases-as-mirror path: after gen-pacman-repo, +# `gh release create repo-${CHANNEL} ${OUT_DIR}/*` uploads everything +# and pacman clients pick it up via the mirrorlist URL. + +set -euo pipefail + +BUILD_DIR="${BUILD_DIR:-$(ls -1dt build.*-RK3326 2>/dev/null | head -1)}" +[ -z "${BUILD_DIR:-}" ] && { echo "BUILD_DIR not set and no build.*-RK3326 found"; exit 2; } +[ -d "${BUILD_DIR}/install_pkg" ] || { echo "no install_pkg/ under ${BUILD_DIR}"; exit 2; } + +OUT_DIR="${OUT_DIR:-${BUILD_DIR}/../repo-out}" +CHANNEL="${CHANNEL:-dev}" +SIGNER="${SIGNER:-}" + +REPO_NAME="archr" +ARCH="aarch64" + +mkdir -p "${OUT_DIR}" +echo "gen-pacman-repo: build=${BUILD_DIR} out=${OUT_DIR} channel=${CHANNEL} signer=${SIGNER:-none}" + +# Per-package metadata. Today the package.mk format does not carry a +# clean semver, so we synthesize: PKG_VERSION if numeric, else the +# build date. Real PKGBUILDs replace this when Arch-ification 2.3 lands. + +build_one_pkg() { + local src="$1" + local name + name="$(basename "${src}")" + + # Skip anything that is not an actually built package tree. + [ -d "${src}" ] || return 0 + + # Pull version from the package.mk if present; fallback to date. + local pkgmk version + pkgmk="projects/ArchR/packages/*/${name}/package.mk packages/*/${name}/package.mk" + version="" + for f in $(ls ${pkgmk} 2>/dev/null); do + version="$(awk -F'"' '/^PKG_VERSION/ {print $2; exit}' "${f}")" + [ -n "${version}" ] && break + done + version="${version:-$(date +%Y%m%d)}" + # pacman version must match [a-zA-Z0-9.+_]+; drop unsupported chars. + version="$(echo "${version}" | tr -c 'a-zA-Z0-9.+_' '.')" + + local pkgrel=1 + local outfile="${OUT_DIR}/${name}-${version}-${pkgrel}-${ARCH}.pkg.tar.zst" + + # .PKGINFO sidecar that pacman reads on install. + local pkginfo="${src}/.PKGINFO" + cat >"${pkginfo}" < +size = $(du -sb "${src}" | cut -f1) +arch = ${ARCH} +license = GPL +EOF + + (cd "${src}" && tar --zstd -cf "${outfile}" --owner=0 --group=0 . ) + rm -f "${pkginfo}" + + if [ -n "${SIGNER}" ]; then + gpg --batch --yes --detach-sign --use-agent --local-user "${SIGNER}" "${outfile}" + fi + + echo " + ${name} ${version}-${pkgrel}" +} + +echo "gen-pacman-repo: packaging install_pkg/* into .pkg.tar.zst..." +for src in "${BUILD_DIR}/install_pkg/"*; do + build_one_pkg "${src}" +done + +# repo-add walks the .pkg.tar.zst files and produces archr.db.tar.gz +# (which pacman renames to archr.db at fetch time) plus archr.files. +echo "gen-pacman-repo: building repo db..." +local_db="${OUT_DIR}/${REPO_NAME}.db.tar.gz" +local_files="${OUT_DIR}/${REPO_NAME}.files.tar.gz" +rm -f "${local_db}" "${local_files}" + +if [ -n "${SIGNER}" ]; then + repo-add --sign --key "${SIGNER}" "${local_db}" "${OUT_DIR}"/*.pkg.tar.zst +else + repo-add "${local_db}" "${OUT_DIR}"/*.pkg.tar.zst +fi + +# Pacman fetches archr.db (no .tar.gz); the conventional way is to ship +# the .tar.gz and a .db symlink alongside. +( cd "${OUT_DIR}" && \ + ln -sf "${REPO_NAME}.db.tar.gz" "${REPO_NAME}.db" && \ + ln -sf "${REPO_NAME}.files.tar.gz" "${REPO_NAME}.files" ) + +echo "" +echo "gen-pacman-repo: ready at ${OUT_DIR}" +ls -1sh "${OUT_DIR}" | head -20 +echo "" +echo "Next: gh release create repo-${CHANNEL} \\" +echo " --repo archr-linux/archr-repo \\" +echo " --title \"ArchR repo ${CHANNEL} $(date +%Y%m%d)\" \\" +echo " \"${OUT_DIR}\"/*"