Cross-package tooling notes
A single generic pacman.conf doesn’t cover both x86_64 and the 32-bit arches – the
[core]/[extra]mirrorlist differs, not just$archinside it. Built 2026-08-13, wiringarchlinuxaba-<arch>-buildup for i486/i686/pentium4 (previously x86_64-only, seememory/REPO_PUBLISH_DESIGN.md). The existingarch/config/pacman.conf.d/archlinuxaba.confis a copy of devtools’ genericextra.conf:Architecture = auto,Include = /etc/pacman.d/mirrorlist(the plain 64-bit Arch mirror). Assumed this would “just work” for every arch since pacman substitutes$archinServer =lines at read time – wrong assumption: devtools32 ships separateextra-i486.conf/extra-i686.conf/extra-pentium4.conffiles (/usr/share/devtools/pacman.conf.d/) with an explicitArchitecture = <arch>and, critically,Include = /etc/pacman.d/mirrorlist32(mirror.archlinux32.org) instead – 32-bit packages live on an entirely different mirror network, not just a different$archsubdirectory of the same one. Buildingarchlinuxaba-i486-buildetc. with the generic config failed immediately at fresh chroot creation (error: failed retrieving file 'core.db'– 404 against the 64-bit mirror, which has no i486/i686/pentium4 trees at all). Fix: addedarchlinuxaba-i486.conf/archlinuxaba-i686.conf/archlinuxaba-pentium4.conf, each the corresponding stockextra-<arch>.confwith our[archlinuxaba]section spliced in ahead of[core](same pattern as the originalarchlinuxaba.confvs.extra.conf).archlinuxaba-archbuild’s existing per-arch config resolution (prefers${repo}-${arch}.confover${repo}.conf, see the script’s own header comment) picked these up with no code change. Lesson for wiring up any new arch here in the future: check whether devtools ships an arch-specific base config before assuming the generic one is arch-agnostic – it usually isn’t for anything outside the “one real mirror network” x86_64 case.A build/publish/rebuild cycle for the same pkgver-pkgrel within one session can poison the local pacman package cache for the next build. Same 2026-08-13 session: rebuilt+republished
libstroke0.5.1-11 twice in a row while iterating on the fix above (each build gets a freshSOURCE_DATE_EPOCH, so the two builds are not byte-identical even though the version string is). A laterfvwmx86_64 build then failed installinglibstrokeas a dependency –pacman: “file … is corrupted (invalid or corrupted package (checksum))” – because a stale copy from the first libstroke build was sitting in the build chroot’s package cache and no longer matched the checksum of what got published second. Not specific to archlinuxaba/fvwm/libstroke; any same-version rebuild-and-republish during a single working session can leave this trap for the next package that depends on it. Fix is just a bare retry of the affected arch (the stale cache entry doesn’t survive a fresh chroot sync) – no need to hunt down and manually clear the cache file.A report script that only prints “what’s new since last run” must never be invoked with
>truncation, and ideally shouldn’t let the caller choose. Built 2026-07-22 (scripts/check_aur_feedback.sh): first run redirected with> ../FEEDBACK.txt, correctly printed all 429 then-current AUR comments across every maintained package. Second run (after fixing an unrelated pkgname-resolution bug) was invoked the same way,>again — its own dedup logic correctly suppressed re-printing the 396 comments already marked “seen” from run 1, which is exactly what dedup is supposed to do, but since>truncated the file first and nothing else on disk held a copy of run 1’s text, that entire history was gone with no way to reconstruct it (the comments still exist on AUR, but re-fetching them would just re-trigger the same dedup and print nothing). Any script with this “print only the diff since last time” shape needs the report file itself to be append-only across runs, not just the in-memory dedup state – otherwise dedup working correctly is exactly what destroys the history. Fix applied: the script now takes the output path itself (default../FEEDBACK.txt) and appends a dated## <timestamp>section internally, skipping the write entirely if there’s nothing new to report – there is no>-redirect invocation path left for a caller to get wrong.check_aur_feedback.shANSWERED/REOPENED tracking (2026-09-07). Before this, a comment thread you’d already replied to on AUR looked identical inFEEDBACK.txtto one nobody had touched – the.seen-file dedup only stops a comment being re-printed, it never recorded whether it had actually been addressed.aur_comments.pylists comments newest-first (matches the AUR page’s own layout), so the script now checks, per package, whether the current newest comment is authored byAUR_USER_NAME(sourced fromconfig/global.conf) – if so the thread is “answered as of now”. State lives inaur_feedback_state/<pkgbase>.answered(the reply’s date, or empty), and anANSWERED/REOPENEDline is printed only on a state transition (mirrors the existingFLAG/UNFLAGGEDOutOfDate pattern right below this script’s other dedup logic) –REOPENEDmeans someone commented again after your reply. Narrow by design: doesn’t catch the reporter self-resolving their own thread (e.g.pacman-static’s “tnx. solved.” case) – that’s still visible in the plainCOMMENTline, just not tracked as a state change. Also never fires when a request is resolved by fixing the PKGBUILD directly without ever replying on AUR – confirmed real case:duckie_xyzasked foraarch64onqt5-connectivity(2026-08-31), user added it straight to the PKGBUILD the next day with no AUR reply (“some small changes are just obvious, I don’t comment them” – user’s own words, 2026-09-07). That thread will show as open/ unanswered by this heuristic forever, even though it’s fully resolved – always check the actual PKGBUILD/repo state before treating an “unanswered”FEEDBACK.txtentry as still needing work. Companion convention (not code): whenever a session acts on, or explicitly decides not to act on, AUR feedback for a package, log a one-line dated note in that package’s ownmemory/<pkgname>.md– theANSWERED/REOPENEDmachinery tracks whether AUR itself shows a reply, not why a decision was made, and that reasoning belongs in the per-package memory file the same as any other packaging decision (seememory/qt5-doc.md’s 2026-09-07 entry for a worked example: a real open upstream-download bug, reproduced by a second reporter after an initial “cannot reproduce”, left open pending a decision on the suggestedprepare()-based fix).AUR RPC maintainer checks must include co-maintainers, not just primary maintainer.
scripts/compare_packages.shqueriesrpc/v5/search/<user>?by=maintainer, which only returns packages where<user>is the primary maintainer — packages held as co-maintainer are silently excluded, and show up as false “local dir not on AUR” diffs. Confirmed 2026-07-20:nagircbot,pacman-static, andtrojitaall looked like AUR-maintainer mismatches from theby=maintainersearch alone, butby=comaintainers(same endpoint, differentbyvalue) showed all three are legitimately co-maintained by this account (primary maintainers are other people) — not orphan or drift situations at all. Any future “is this package actually ours on AUR” check needs bothby=maintainerandby=comaintainersunioned before concluding something’s missing/mismatched.rpc/v5/info/<pkgname>also exposes this per-package via theCoMaintainersarray field (absent entirely if there are none).nvchecker’s
include_regex/exclude_regexusere.fullmatch, notre.matchorre.search(nvchecker/core.py’sapply_list_options:re_pat.fullmatch(str(x))). An anchored-prefix-only pattern like"^5\\."matches nothing – fullmatch requires the whole version string (e.g."5.7.7") to match, and"^5\\."only ever matches the literal 2-char string"5.". Need a trailing.*("5\\..*"–fullmatchalready anchors both ends, no need for^/$). Confirmed 2026-09-08 fixing a false UPD flag onqt5-quickcontrols-nemo(upstream moved to Qt6 tags this package deliberately doesn’t track – see that package’s own memory file); the first attempt ("^5\\.") silently produced “include_regex matched no versions” /no-resultinstead of the intended filter. Always verify a newinclude_regex/exclude_regexwith a directnvchecker -c .nvchecker.toml --logger jsonrun before trusting it.Dependency-resolution checks need
pacman -Si+ a real Provides scan, notpacman -T. Built 2026-07-26 (scripts/check_dependencies.sh, after findingmaintained/lxappearance-obconf-gtk3depended onlxappearance-gtk3, which never existed anywhere – seememory/lxappearance-obconf-gtk3.md). Three separate bugs surfaced while building the checker, in order:pacman -T(deptest) only checks installed packages, not the sync databases –dkms(real package in[extra], just not installed on this build host) came back “unsatisfied” even thoughpacman -Si dkmsfinds it immediately. Use-Sifor an install-state-independent existence check.pacman -Sialone still doesn’t seeProvides– virtual/group deps (sh,pkgconfig,java-runtime,ttf-font,initramfs,fuse,atk) and soname deps (libobrender.so, fromopenbox) are essentially never named after the package that actually provides them, so a plain-Silookup flagged nearly all of them as broken. There’s nopacman -S*query that does a provides-only lookup without an actual transaction; the fix wastar -xOfon every configured repo’s sync db (pacman-conf --repo-list,$(pacman-conf DBPath)sync/<repo>.db) parsed for raw%PROVIDES%fields directly.commneedsLC_ALL=Cto match aLC_ALL=C sort-ed input – this host’s locale isen_US.UTF-8, and a locale-defaultcommagainst C-locale-sorted files silently mis-diffs (“input is not in sorted order” printed to stderr, but the command still exits 0 and produces wrong output that looks plausible). Net effect for any future resolution primitive: verify it against both a known-installed-and-real name and a known-not-installed-but- real name before trusting its output, and assumeProvidesneeds handling explicitly – pacman’s own name-lookup commands don’t do it for you outside a real transaction. As of 2026-07-26 (right after the lxappearance-obconf-gtk3 fix), a full run across all 544 unique dependency entries in arch/ resolves cleanly – 0 BROKEN.
Policy notes, split out since they apply broadly rather than to one package:
HOST_INSTALL_POLICY.md(never install packages on this host to fix a build — chroots exist for that; GPG key imports for source verification are the one exception),PKGREL_VS_PKGVER.md(packaging- only fixes bumppkgrel, notpkgver),ARCHIVE_APPEND_ONLY.md(never remove/move anything out of the private repo’sarchive/dir).This machine can currently only build packages for x86_64, pentium4, i686, and i486 — it has local
extra-<arch>-buildarchbuild chroots for exactly these four. Any other arch that shows up in a PKGBUILD’sarch=()— notably aarch64, arm, armv6h, armv7h, riscv64 — cannot be built here yet; that would need either QEMU user-mode emulation (to run a foreign-arch chroot on this x86_64 host) or SSH access to a real build machine of that architecture, neither of which is set up. Therepo_build.shscript (seeREPO_PUBLISH_DESIGN.md) already treats this as expected: it skips and reports any arch with no localextra-<arch>-buildinstead of failing the whole build.Some existing PKGBUILDs contain pre-existing invalid-UTF-8 byte sequences in comments (e.g. libarchive-static’s
# Tomáš Mrázmaintainer-key comment, which is already mojibake’d to a raw Latin-1 0xE1 byte in git history). My Edit tool and any full-file rewrite (Perl scripts likeupdpkgsums,makepkg --printsrcinfo, etc.) treat the file as UTF-8 text and silently replace such invalid bytes with U+FFFD on save, corrupting them further even in lines I didn’t intend to touch.- After editing a PKGBUILD, diff the full file content against the last
git revision (
git -C <pkg> show HEAD:PKGBUILD) to catch unintended byte-level drift outside the lines you meant to change, not just the lines you meant to change. - Use
LC_ALL=C grep -a/ byte-level tools when inspecting such lines; UTF-8-locale grep can silently fail to match corrupted byte sequences.
- After editing a PKGBUILD, diff the full file content against the last
git revision (
archbuildscripts (extra-<arch>-build) pass args after--straight into their internalmakechrootpkg_argsarray without inserting a separator — so to get args through tomakepkginside the chroot you need a double--:sudo extra-i686-build -- -- --nobuild --skippgpcheck. A single--makesmakechrootpkgitself choke on the makepkg flags (“illegal option – -”).--nobuildis the cheap way to run justprepare()(extract + patch + any config/version reconciliation) inside a chroot without doing the full compile — much faster than a full build when you only need to check/update generated files like kernel configs.- The chroot’s working-copy build tree lives at
/var/lib/archbuild/<repo>-<arch>/<local-copy-user>/build/<pkgname>/src/...(default local-copy name is your own username) — files placed there byprepare()(e.g. a reconciled.config) can besudo cp’d back out andchown’d to your user. namcapinside these chroots is broken (ImportError: libalpm.so.14: cannot open shared object file) andcheckpkgalways says “target not found” since there’s no local repo — both are known-harmless environment issues, not build failures.
Intra-tree dependency ordering — fixed 2026-07-07 for x86_64.
extra-<arch>-buildchroots resolvedepends/makedependsonly against the official Arch mirrors (whateverpacman.confin the chroot points at) — never against other packages built earlier in the samerepo_release_all.shrun, and never in build-order at all (packages are processed in plain alphabetical order). Any package here whosedepends/makedependsnames another custom package from this tree (not an official Arch package — e.g. the Qt5/KDE5 rebuild stack, orarduino-builderneedingarduino-ctags) used to fail witherror: target not found: <pkg>regardless of run order. Seememory/kdstatemachineeditor.mdfor the original diagnosis.- Fix:
scripts/archlinuxaba-archbuild(symlinked asscripts/archlinuxaba-x86_64-build) is a copy of the system/usr/bin/archbuild(devtools32), changed in exactly one place: it resolvespacman_configfrom this project’s ownarch/config/pacman.conf.d/first (falling back to the system location), andarch/config/pacman.conf.d/archlinuxaba.confis a copy of the stockextra.confwith our own private repo (archlinuxaba,SigLevel = Optional TrustAll) added ahead of[core]/[extra]. This mirrors devtools32’s own*-with-build-supportconfig pattern (bootstrap/staging repos layered on top of the base config the same way). It uses its own separate chroot (/var/lib/archbuild/archlinuxaba-x86_64), so the stockextra-x86_64chroot is untouched. Never modifies anything under/usr— everything new lives underarch/. repo_build.shnow resolves the build command per-arch via a_build_cmdhelper:archlinuxaba-x86_64-buildfor x86_64, plainextra-<arch>-buildfor everything else (only x86_64 is wired up so far, per explicit scope).- Verified against a real case:
arduino-builderneedsarduino-ctags(a package in this tree, already published) — failed under plainextra-x86_64-build, succeeded underarchlinuxaba-x86_64-buildonce retried. - Caveat: this only helps once a dependency has actually been
built+published before the package that needs it is attempted —
repo_release_all.shstill processes the tree in plain alphabetical order with no dependency-graph awareness, so a package needing an alphabetically-*later* custom dependency will still fail on a single top-to-bottom pass and needs a manual retry afterward (seememory/gcc-ia16.md,memory/fvwm.mdfor pending examples).
- Fix:
This build box’s GPG keyring is missing some upstream signing keys referenced by
validpgpkeysin various PKGBUILDs, causing--skippgpcheck-less real builds (asrepo_build.shdoes, unlikebuild_all_archs.sh’s own test-build convenience flag) to fail source verification withunknown public key <ID>regardless of anything about the package’s own PKGBUILD/source correctness. First seen 2026-07-07 for key95FA6F43E21188C4acrossmaintained/arduinoandmaintained/arduino-builder. Unlike installing a package on the host (never do that — seememory/feedback_no_host_installs.md’s original, narrower rule), importing a signing key needed purely for source verification is a normal, expected part of doing the build and is fine to do on the host:gpg --recv-keys <ID>(fromhkps://keys.openpgp.orgorkeyserver.ubuntu.comif the PKGBUILD doesn’t specify one). Done for95FA6F43E21188C4on 2026-07-07 — both packages should be retried.A third missing-dependency class, distinct from environment drift and intra-tree ordering: real AUR-only dependencies this tree doesn’t maintain at all (e.g.
dbmodel-qt4needingqt4,adtpro-git/p2c- style needingcc65/gcc14). Unlike the KDE5/Qt5 stack (custom packages that live in this tree, just not resolvable mid-run — fixed byarchlinuxaba-x86_64-build, see above), these depend on packages that were never part ofarch/maintained/private/adapted/ownedin the first place. Building them would mean also building/vendoring a package this tree doesn’t own. Per the user (2026-07-07): note these and move on, don’t try to resolve them now — revisit once there’s an actual plan for out-of-tree AUR dependencies.CMake in this build environment refuses
cmake_minimum_requiredversions below 3.5 (Compatibility with CMake < 3.5 has been removed from CMake.), which will hit any older/unmaintained CMake-based package whoseCMakeLists.txtstill declares an ancient minimum version. First seen 2026-07-07 onkdiagram5(seememory/kdiagram5.md). CMake’s own suggested workaround is-DCMAKE_POLICY_VERSION_MINIMUM=3.5passed to thecmakeinvocation in the PKGBUILD’sbuild()— not applied yet to any package as part of this pass; expect this to recur across other older CMake-based packages in the tree.Modern GCC’s default warnings-as-errors trip older/unmaintained C/C++ sources on genuinely harmless issues like an unused-but-set variable (
error: variable 'X' set but not used [-Werror=unused-but-set-variable=]). Seen 2026-07-07 onmodest(memory/modest.md) andnewsboat-og(memory/newsboat-og.md). Not fixed for either; would need a source fix or relaxing that specific-Werrorin the PKGBUILD’s CFLAGS. Expect this to recur on other old C/C++ packages in the tree.Long-running builds (e.g. kernel compiles via
archbuild) started as a plain backgrounded Bash tool call die with the session (SIGHUP) if the session is closed early. To survive session termination, launch them in a detachedscreensession instead:screen -dmS <name> bash <script>.sh(or-e^Xyfor a custom escape sequence). Check on it later withscreen -r <name>or by tailing the chroot’s own build log at/var/lib/archbuild/<repo>-<arch>/<user>/logdest/<pkg>-<ver>-<arch>-build.log.Danger: manually replicating
repo_build.sh’s git-status-driven post-build cleanup (git status --porcelain -- .→rm -rfevery??entry not matching*.pkg.tar.*/.sig) can delete a brand-new source file you just added, not just real build byproducts. That cleanup’s own assumption is “an untracked file after a successful build is either a release artifact or something makepkg generated” — true when running it via the real pipeline on an already-committed package tree, but this project’s own standing rule is nevergit commit(seeCLAUDE.md). So a genuinely new file you add to amaintained/package (a new local patch, a new config) — something you fully intend to keep — will always show as??untracked, indistinguishable from a downloaded tarball or a.logfile, for as long as this session lives. Hit this for real 2026-07-16 onakonadi-notes: a newly-writtenakonadi-notes-24.08.3-kmime-26.04-api.patchgot deleted by exactly this cleanup snippet run by hand right after a successful publish. Recovered only because a scratch copy of the diff still existed to regenerate it from.- How to apply: before running (or hand-replicating) this cleanup
after a build, check
git status --porcelain -- .yourself first and make sure every??entry it’s about to remove is something you actually expect to be disposable (a downloaded source tarball, a*.logfile, a VCS clone dir) — not a patch/config file you just added as the actual fix. When in doubt, copy the new file somewhere safe (or note its content) before letting any cleanup step run near it. - Confirmed 2026-07-31 that this isn’t just a manual-replication
risk — the real, automated
repo_release.sh→repo_build.shpipeline does this too, every time, to every new uncommitted patch file. Onkdiagram5: wrotekdiagram-2.8.0-ecm-project-version.patch, wired it intoprepare(), ran the normalrepo_release.sh maintained/kdiagram5(not a hand-replicated cleanup), build succeeded, and the patch (plus the unrelated pre-existingPKGBUILD~backup) was silentlyrm -rf’d by this exact cleanup step since neither was git-tracked. Recovered only because the patch content was still in this session’s own context to rewrite verbatim (checksum matched, confirming an exact recreation) — a fresh session with no memory of the patch’s content would have lost it for good. Since this project’s assistant never runsgit commit(seeCLAUDE.md), every single new patch file written in any session is on a countdown to deletion the moment the next successfulrepo_release.sh/repo_build.shrun touches that package directory — there is no “safe” window. Until/unless this cleanup step gets a*.patchexception (not done as of this note — would need explicit user sign-off, since a stray downloaded.patchsource file some PKGBUILDs also legitimately fetch viasource=()complicates a blanket exclusion), treat any newly-written patch as needing the user togit commitit (or add it to.gitignore’s inverse / otherwise mark it tracked) before the first build, not after.
- How to apply: before running (or hand-replicating) this cleanup
after a build, check
repo_publish.sh’s filename-derived arch/pkgname parsing had no validation, and it silently corrupted the remote repo layout twice. Found 2026-07-26 while investigating a user-reported bogus directoryos/x86_64pkg.tar.zst/on the repo host. Root cause:_pkg_arch()/_pkg_name()stripped an expected.pkg.tar.<ext>suffix and then took “whatever’s after the last-” as arch/pkgname, with no check that the strip actually matched anything. Two real incidents from this: (1)m68k-elf-gcc, built via a separate ad-hoc/data/INSTALL/-based flow (not this repo’sarch/tree) with a misconfiguredPKGEXTmissing its leading dot, produced...x86_64pkg.tar.zst– the unguarded strip left it untouched, and${_base##*-}grabbed the wholex86_64pkg.tar.zsttail as “arch”, publishing into a bogus top-level dir with its own orphanedrepo-adddatabase. (2)zoom, built by a separate concurrent session, produced a filename missing its-<pkgrel>-segment (zoom-7.1.5.4332_orig_x86_64.pkg.tar.xz), so the only hyphen left after the (successful, this time) extension strip put7.1.5.4332_orig_x86_64in as “arch”. Both bogus dirs sat unnoticed on the repo host for over a week (m68k-elf-gcc: 2026-07-16 to 2026-07-26; zoom: 2026-07-22 to 2026-07-26) since nothing about publishing failed loudly –mkdir -p/repo-addhappily created a whole new “repo” at the bogus path. Fixed:_pkg_stripped_base()now aborts (non-zero exit,ERROR:to stderr) if the.pkg.tar.*strip didn’t change anything, and_pkg_arch()additionally rejects any result containing a.(real arch names never have one; both incidents above did). Both stale directories were removed from the repo host after confirming a correct copy of m68k-elf-gcc already existed inos/x86_64/(zoom had no other copy – removing its bogus dir removed the package from the repo entirely, done with explicit user confirmation). Lesson for any future filename-parsing helper: validate that an expected-pattern strip actually matched before trusting what’s left over, don’t just chain more stripping operations on a possibly-untouched string.archive/reorganized to be per-arch, 2026-07-26. Was previously one flat directory shared across all archs (deliberate original design – filenames embed pkgver+arch so they can’t collide there either way). User asked for it to mirroros/’s per-arch layout instead._archive_old()inrepo_publish.shalready received the package’s arch as_pkgarch; changed it to create/move into${ARCHIVE_DIR}/${_pkgarch}/instead of flat${ARCHIVE_DIR}/. The existing 73 files were migrated in place on the repo host with a one-off script that reused the same_pkg_arch()parsing logic (not a second implementation) to classify each file, thenmkdir -p+mvper arch – verified file count (73) and total byte size (830534379) matched exactly before and after, nothing lost. Result:archive/{any,i686,pentium4,x86_64}/.**Routine per-package publishes go through
repo_diff_local_remote.shrepo_release_changed.sh, not a hand-chainedextra-x86_64-build->repo_sign.sh->repo_publish.shsequence – even for just one or two UPD-flagged packages.** Went off this rail 2026-07-27 while updatingi686-elf-binutils/x86_64-elf-binutils(2.45/2.46.0 -> 2.47): after editing both PKGBUILDs, ranextra-x86_64-builddirectly to test-build, thenrepo_sign.shandrepo_publish.shby hand for each. That produced a correct result (both published fine, verified against the remote repo and site afterward), but skipped the actual sanctioned tooling:repo_diff_local_remote.shwould have confirmed both read as CHANGED once the PKGBUILDs were bumped, andrepo_release_changed.shbuilds+signs+publishes exactly that detected set (also handles the “already up to date, skip” and multi-package cases uniformly, and keeps theREPO_BUILD_ONLY_ARCHconvention and per-package logfiles underrepo_release_logs/consistent with every other routine cycle).repo_release.sh <pkgdir>(single-package build->sign->publish) is the right manual escape hatch when a package needs individual attention outside the diff-driven flow (e.g. re-testing after a build fix) – reaching for the three lower-level scripts directly should be rarer still, reserved for cases where evenrepo_release.sh’s ordering doesn’t fit (e.g. republishing an already-built artifact without rebuilding it).
Recovering an in-place build into the
/data/INSTALLstaging layout, after building directly insidearch/<category>/<pkgname>by mistake (e.g. viabuild_all_archs.shrun there instead ofrepo_release.sh/repo_build_staged.shfrom the start – don’t do this; see the entry above and the “build staged by default” habit note). If the build already ran and especially if it was expensive (a kernel compile across 4 archs, hours of chroot time), don’t throw the work away and restart staged – migrate the result into the layoutrepo_build_staged.shwould have produced:- If
/data/INSTALL/<pkgname>already exists (a previous release’s staged build), move it aside first – never overwrite/delete it. Follow the existing rotation convention already in use forlinux-lts510(-old,-older,-oldestas each new one bumps the previous aside):mv /data/INSTALL/<pkgname> /data/INSTALL/<pkgname>-old(or-older/-oldestif-oldis already taken). rsync -a --exclude=.git -- arch/<category>/<pkgname>/ /data/INSTALL/<pkgname>/– same invocationrepo_build_staged.shitself uses, just run after the build instead of before. This carries the tracked PKGBUILD/patches/etc and the untracked build byproducts (downloaded sources, produced*.pkg.tar.*, logs) into the staged location together in one shot.git clean -fdinsidearch/<category>/<pkgname>to drop every untracked byproduct from the tracked tree, restoring it to exactly the pre-build state (verify withgit status --short– must be empty). This is the actual goal of staging:arch/never carries build output.- Sign + publish from the
/data/INSTALL/<pkgname>copy directly (repo_sign.sh/repo_publish.shthere) rather than copying package files back intoarch/first – no need, they’re not needed there. - Leave everything else in
/data/INSTALL/<pkgname>as-is afterward (downloaded tarball, per-arch build/package/namcap logs, the package files themselves) – don’t try to replicaterepo_build.sh’s own post-build cleanup (which deletes everything untracked except the release artifacts) by hand here. That cleanup is driven bygit status --porcelaininsidebuild_dir, butrsync --exclude=.gitmeans these staged copies have no working.git(confirmed against the existinglinux-lts515-oldstaged dir:git statusthere fails with “fatal: not a git repository”), sorepo_build.shitself silently skips that cleanup step too when running the normal way – leaving the full build state in/data/INSTALL/<pkgname>permanently is the actual established behavior, not an oversight to fix. First done 2026-08-21 forlinux-lts5155.15.216 (see its own memory file for the specific run) – generalize this same five-step recovery to any other package caught mid-build in place.
- If
Remote ARM build machines (2026-08-27): armv6h/armv7h/aarch64 no longer always
SKIPPED.repo_build.shpreviously had no way to build any arch this host (x86_64) lacks a local chroot for.eurobuild4/eurobuild5/eurobuild14are real dedicated boards (loginbuild@<host>, passwordless sudo) for armv6h/armv7h/aarch64 respectively – no chroot/devtools tooling on them at all, just a plainmakepkg -srun natively. Wired up viaarch/config/remote_build.conf(arch->host map) +arch/scripts/remote_build_lib.sh(config loader, missing file is NOT fatal – an additive fallback path) +arch/scripts/ repo_build_remote.sh(local-side driver: push pkgdir, ssh-build, pull back*.pkg.tar.*+ a combined build log) +arch/scripts/remote_build.sh(the agent script itself, redeployed fresh to each board on every invocation so the three boards can’t drift out of sync with git).repo_build.sh’s per-arch loop falls back to this only when it has no local build command for that arch; sign/publish are completely unaffected either way. A package file already sitting inpkgdirfor the exact current pkgver-pkgrel-arch is reused instead of triggering another remote build – these boards are slow (eurobuild4 is single-core/423Mi RAM) and a real build can take 40+ minutes./dataon each board is a mounted NBD block device (/root/ mount_data.sh, root-owned, board’s own tiny SD-card rootfs is 2-8GB and not meant to take real build I/O) served by a separate NBD server host,eurobuild3– confirmed 2026-08-27 that server has to be up too, not just the target board itself, or the mount fails regardless.remote_build.shauto-runsmount_data.sh(with anbd-client -d /dev/nbd0retry for a stale/dead prior connection – seen once on eurobuild4: “nbd0 already in use”, mount then fails to read the superblock) if/dataisn’t already mounted.repo_build_remote.shalso pings the target board andREMOTE_BUILD_NBD_SERVERbefore attempting anything – fails fast with a clear message instead of a long ssh/rsync connect timeout if either is down. Don’t attempt an arm remote build if any of eurobuild3/4/5/14 aren’t up – ping from this host (euronuc) to check first if in doubt.- makepkg’s automatic key import from a package’s
keys/pgp/*.asc(thevalidpgpkeysconvention) didn’t reliably trigger on these boards for a key never seen there before, even with the.ascfile right there –remote_build.shnow explicitlygpg --imports everything inkeys/pgp/before building. Not package-specific, fixed once at the agent-script level. - eurobuild4 (armv6h) runs
pacman 6.0.1, long EOL (ArchLinux ARM dropped armv6h support entirely a while back, so this can’t be fixed by upgrading – there’s nothing left to upgrade to for this arch) – it can’t compute a checksum for agit+...source at all, reportingNOT FOUNDrather than treating a real sha512sums entry as unhashable the waySKIPwould. Any PKGBUILD with a real hash (notSKIP) on a git source needs acase "${CARCH}" in i486| armv6h) sha512sums[N]='SKIP' ;; esac-style per-arch override for that source’s index – seememory/libarchive-static.md’s 2026-08-27 entry for a worked example (and a cautionary tale: a similar-looking guard already existed there and was completely dead, patching the wrong array indices). - eurobuild4’s bash (5.1.16) also parses
if [[ ... ]] then(no;beforethen) as a hard syntax error, where bash 5.3.15 (eurobuild5/14) accepts it – a real grammar difference between those versions, confirmed withpacman-static’s upstream PKGBUILD. If a PKGBUILD fails to even source on an armv6h remote build (“syntax error near unexpected token”), check for this exact idiom before assuming it’s the checksum issue above. Fix is always just adding the missing;– safe on every bash version. remote_build.shnow runsmakepkg -s -C --noconfirm(-C/--cleanbuild, added 2026-08-27) – without it, a prior partial/failed attempt at the same pkgver-pkgrel can leave$srcdir(“src/”) already-extracted-and-prepare()-mutated, so a retry’spatchcalls can fail with “already exists” even though nothing is actually wrong (hit this on eurobuild4 withpacman-static’spacman-reproducible-builds.patch, after ruling out the checksum/bash issues above as the cause).-Conly removes the ephemeralsrc/working copy – persistent VCS clone caches and already-downloaded tarballs at the top level of pkgdir are untouched, so this doesn’t reintroduce the slow-refetch problemrepo_build_remote.sh’s no---deletersync push was meant to avoid./data-mount ordering bug, fixed 2026-08-27: the mount-ensure check originally lived only insideremote_build.sh(the agent, which only runs afterrepo_build_remote.shhas alreadymkdir’d andrsync’d intoREMOTE_BUILD_ROOT, i.e. under/data). On a freshly-rebooted board (confirmed with eurobuild4 after the user rebooted it to clear a stuck build)/dataisn’t mounted yet at that point, so themkdiritself failed –Permission denied(the bare unmounted mountpoint dir is root-owned). Fixed by moving the mount-ensure+stale-nbd-retry check intorepo_build_remote.sh, running before its ownmkdir/rsync steps – removed the now-redundant duplicate fromremote_build.sh, single source of truth.- More generally: these boards accumulate real leftover build state
across sessions (the user’s own prior manual work, or an earlier
failed automated attempt) in ways a fresh
rsyncpush doesn’t clean, because VCS source checkouts and$srcdirextractions live entirely on the remote board, never touched by the push/pull steps that only movePKGBUILD/patches/*.pkg.tar.*/logs. If a remote build fails with something that looks like stale state (a file “already exists”, a corrupted git ref, etc) rather than a real build error,sshin and look at what’s actually sitting inREMOTE_BUILD_ROOT/<pkgname>/before assuming it’s a new bug – hit both a corruptedbrotligit clone (fatal: bad object refs/remotes/origin/test_902775910, fixed withrm -rfto force a fresh clone) and the$srcdircase above forpacman-staticon eurobuild4/5/14 in the same session, both pre-existing from before this session touched these boards at all. - Stale local sync db right after publishing a dependency
(2026-09-06):
i686-elf-pcc-git(aarch64) failed witherror: target not found: i686-elf-pcc-libseven thoughi686-elf-pcc-libs-git(whichprovides=(i686-elf-pcc-libs)) had just been built+published toarchlinuxabasuccessfully, ~25s earlier. Confirmed viassh build@eurobuild14 "pacman -Ss i686-elf-pcc-libs"– not visible until a manualsudo pacman -Sywas run, after which it resolved immediately (and the built package’s own.PKGINFOdid have the rightprovidesline all along – not a PKGBUILD bug).archlinuxaba’sServer =line points straight atarchlinux32.andreasbaumann.cc(no separate mirror), so this reads as either a CDN/reverse-proxy cache TTL onarchlinuxaba.db.tar.gzin front of that host, or just pacman’s ordinary “sync db isn’t auto-refreshed on every-S” behavior combined with these boards’ sync db legitimately being minutes stale from whenever they last ran-Syon their own. Either way: when a queued build depends on a package published to the same remote-arch earlier in the same session, don’t assume an immediate retry failing on a missing/unresolvable dep means a real problem –sshin and forcesudo pacman -Syon that board first, or just leave a minute or two of gap between publishing a dependency and building something that needs it there.
Build concurrency: local archs (i486/i686/pentium4/x86_64) share this one euronuc host and must run one at a time; the three remote ARM boards are physically separate single-board machines and are safe to build on in parallel with each other (and with whatever’s running locally). Confirmed by the user 2026-08-27. Don’t launch two local chroot builds concurrently on euronuc (e.g. two
repo_release.sh/repo_build_staged.shinvocations that both reach a localarchlinuxaba-<arch>-build) – not a supported pattern here.repo_build.shnow does this automatically within one invocation (fixed 2026-08-27, same session): its per-arch loop still runs local archs one at a time (blocking, as before), but each remote-arch dispatch is launched in the background immediately (output captured to a per-arch log under amktemp -dtmpdir) and all of them arewait-ed on together after the loop, so they run in parallel with each other and with whatever local chroot sequence is still going. This is the preferred way to get parallelism now – don’t manually split a single package’s build into severalREPO_BUILD_ONLY_ARCH-scopedrepo_release.shinvocations launched concurrently (that was the old workaround, e.g. done forpacman-static/libarchive-staticearlier this same session before this fix landed) unless deliberately re-testing one specific arch in isolation.- Still true, unrelated to the above: two invocations of
repo_build_staged.sh/repo_release.shfor the same package at once (e.g. one from a human, one from an agent, run by mistake) would share one local staging dir (/data/INSTALL/<pkgname>on euronuc) and can still race – this fix doesn’t change that, it just removes the need to do that manually for parallelism.
eurobuild4’s bash (5.1.16) parses
if [[ ... ]] then(no;beforethen) as a hard syntax error; bash 5.3.15 (eurobuild5/14, and this host) accepts it. Confirmed 2026-08-27 viapacman-static’s upstream PKGBUILD, which has exactly this idiom in its_git_patch_level_commitcheck –PKGBUILD: line N: syntax error near unexpected token 'then'on eurobuild4 only, everything else (including local i486, also 32-bit) built fine. Reproduced directly:bash -c 'if [[ 1 != 2 ]] then echo yes; fi'fails on 5.1.16, succeeds on 5.3.15 – a real bash grammar change between those versions, not a chroot/toolchain quirk. Fix is always the same and always safe: add the missing;beforethen– valid on every bash version, no behavior change. If a different package’sPKGBUILDfails to even source on an armv6h remote build with a “syntax error near unexpected token” message, check for this exact idiom (grep -n ']] then$'or similar) before assuming it’s the git-checksum issue above or something board-specific.repo_publish.shcouldn’t publish a package with an epoch inpkgver(fixed 2026-08-27, found viaeclipse-java-bin’s2:4.40-1) – the resulting filename has a literal:before the first/(e.g.eclipse-java-bin-2:4.40-1-x86_64.pkg.tar.zst), which rsync parses ashost:pathremote syntax; since the destination arg is also remote, it fails with “The source and destination cannot both be remote.” Fixed by prefixingpkgfile/sigfilewith./before therepo_rsynccall whenever they don’t already start with/(prepending it to an already-absolute path would wrongly root it at$PWDinstead). Affects any package with an epoch, not just this one.repo_build.sh’s untracked-cleanup could delete a staged build’s own fresh logs (fixed 2026-08-28, found viacssh) – the cleanup at the end of a real build is meant only for the git-trackedarch/tree (per its own header comment), and normally skips a/data/INSTALLstaged copy automatically sincegit statusfails there (“fatal: not a git repository”). That protection was only incidental, though:cssh’s staged dir happened to already be a real git checkout (a leftover stand-alone AUR clone predatingrepo_build_staged.shever touching it), so the cleanup ran there too and deleted that run’s own-prepare.log/-build.log/-package.logright aftermakechrootpkgcreated them (it always passes--logtomakepkgitself, so these are produced unconditionally for every chroot build, independent of anything in/etc/makepkg.conf’sBUILDENV). Fixed by skipping the cleanup outright wheneverpkgdiris under/data/INSTALL, rather than relying on it accidentally not being a git repo.scripts/repo_arch_status.sh <pkgdir>(added 2026-08-28) prints a per-arch table (machine / published version / best-effort “building” flag) for one package – see the script’s own header for exactly what the “building” heuristic can and can’t detect (local: any chroot build for that arch, not necessarily this package; remote: precise, via a livemakepkgprocess’s cwd on the mapped board). Queries the live repo db (curl+bsdtaronos/<arch>/<reponame>.db.tar.gz) for the published-version column, so it reflects reality even across separate sessions, not just this one’s own job logs. Skips any arch with no local build command and no mapped remote host (never actually attempted byrepo_build.sheither – alwaysSKIPPEDthere) – catches a leftover genericarmentry some PKGBUILDs still carry alongside the real armv6h/armv7h/aarch64.scripts/check_aur_feedback.shsilently never fetched a single comment when invoked the normal way – fixed 2026-08-28. The script computedscript_dir=$(dirname "$0")(left relative, e.g.arch/scripts) and thencd’d to${script_dir}/..– fine for the RPC-info/flag part, which only used the now-absolute$(pwd). But the laterpython3 "${script_dir}/aur_comments.py" ...call still used the original relativescript_dirstring, now resolved against the new cwd – doubling the prefix (arch/arch/scripts/aur_comments.py, “No such file or directory”). Every single comment-fetch call failed this way and was swallowed intoaur_feedback_state/aur_comments.err(python3: can't open file ...), socheck_aur_feedback.shalways printed “Nothing new to report” for comments (RPC-based OutOfDate flags were unaffected, since that part never depended onscript_dirafter thecd). Reproduces on any invocation with a relative$0from outsidearch/scripts/– i.e. exactly the normalarch/scripts/check_aur_feedback.shinvocation from the toplevel dir. Caught by chasing why a genuinely new (2026-08-28)pacman-staticAUR comment thread never showed up inFEEDBACK.txtdespite the script reporting success. Fix: resolvescript_dirto an absolute path up front,script_dir=$(cd "$(dirname "$0")" && pwd), before thecd "..". Unknown how long this was broken for – treat any pre-2026-08-28 “nothing new” comment result from this script with suspicion; theaur_feedback_state/*.seenfiles may be missing a real backlog for packages that got few/no other RPC-flag changes to mask the failure. Consider a one-time full re-check across every package now that the fix is in, to surface anything swallowed while it was broken.scripts/repo_arch_diff.sh(added 2026-08-28) is the multi-arch counterpart torepo_diff_local_remote.sh’s single-arch check: for every local PKGBUILD, compares its wishedarch=()set (read from.SRCINFO’sarch =lines – note these are tab-indented underpkgbase, so the awk match must NOT anchor with^, unlike the^pkgbase =/^pkgname =lines it also reads; got this wrong on the first pass, silently making every package look likearch=any) against what’s actually published per arch, across every arch this project can actually build (same local-build-command-or-mapped- remote-host filterrepo_arch_status.shalready uses, so a leftover unbuildablearch=()entry like a strayarmdoesn’t show up as a false gap –pacman-static’s PKGBUILD has exactly this, confirmed harmless). Fetches each buildable arch’s remote package-name set ONCE via the same lightweightrepo_ssh+lsrepo_diff_local_ remote.shalready uses (not per-package – 7 ssh round-trips total, not 7×~250), so it stays cheap enough forgenerate_overview.shto call on every run. Feeds the Architectures column there (✅ wished and published, ❌ wished but missing, ➕ published but no longer wished).arch=('any')is resolved to “every buildable arch” before comparison – no special-casing needed beyond that substitution, sincerepo_publish.sh’s own any-package fan-out (upload once toos/x86_64, symlink every other arch’sos/<arch>dir at it) means the per-archlslisting already picks the symlinks up like any other file. Scope matchesrepo_diff_local_remote.sh: thearch/tree only, not theinstall_only_packages/data/INSTALLgap-fillers (those get-in the Architectures column).A
validpgpkeys-related “unknown public key” build failure may just need a plaingpg --recv-keys <fingerprint>as thebuilduser on euronuc (host, outside any chroot) – try that before assuming a deeper chroot-keyring infrastructure fix is needed. Resolved a multi-weekmod_fcgidblocker this way 2026-08-30 (the key wasn’t fetchable fromhkps://keys.openpgp.orgbut was fromhkps://keyserver.ubuntu.com); seememory/mod_fcgid.mdfor the full investigation and the remaining uncertainty about exactly why this works (a host-sidegpg --recv-keysshouldn’t, in principle, reach the ephemeral per-build chroot user’s own keyring, but empirically it did here).scripts/add_maintained.shused to add every vendored-from-AUR package undermaintained/unconditionally – fixed 2026-08-30 after it silently mis-categorizedmod_fcgid/perl-crypt-rijndael(vendored to unblockthruk; neither is actually maintained or co-maintained byAUR_USER_NAME, seememory/mod_fcgid.md’s dated entry for the discovery and the after-the-factgit mvfix). Logic moved into a new sharedscripts/add_aur_package.sh <category> <pkgname>, withadd_maintained.sh/newadd_adapted.shas thin wrappers (exec add_aur_package.sh <category> "$1"). Adding undermaintainednow checks the package’s real AUR HTML page (not the RPC API’sMaintainerfield, which only ever exposes the primary maintainer – AUR renders co-maintainers as “PrimaryName (andreas_baumann)” in the same table cell, so RPC alone would also wrongly refuse a package we’re legitimately a co-maintainer of, e.g. pacman-static) for whetherconfig/global.conf’sAUR_USER_NAMEappears anywhere in the Maintainer table cell, and refuses (not just warns) to add undermaintained/if not, pointing atadd_adapted.shinstead. No check foradapted/owned/private–adaptedis explicitly for packages we don’t maintain upstream, the other two don’t carry the same implication. A fetch failure (network hiccup, or the package genuinely doesn’t exist on AUR) warns and proceeds rather than blocking, sincegit submodule additself will fail loudly right after for a nonexistent package anyway.arch/<category>taxonomy, spelled out plainly after getting it wrong twice in one session (mod_fcgid, perl-crypt-rijndael, 2026-08-30 – see their memory files for the full story):maintained/– git submodule, AUR git remote. We are the AUR maintainer or co-maintainer (able to push there). Added viascripts/add_maintained.sh, which now enforces this.adapted/– plain, directly-tracked files, never a submodule. For a package with a real local diff on top of someone else’s upstream (patches, PKGBUILD edits) – every single entry inarch/adapted/README.mdnames one. Not a submodule because we’re diverging from their history, not tracking it. A package we don’t maintain but also haven’t modified at all does NOT belong here – there’s nothing to diff.owned/– git submodule, AUR git remote, but the upstream software itself is the user’s own project (e.g.cssh) – unlikemaintained/, the actual source isn’t AUR-native, just packaged there.private/– mixed: some are submodules pointing at a private (non-AUR) git remote the user created, specifically to preserve commit history for a package that was later deleted from AUR (gsoap287, notion3); others are plain directly-tracked files, same asadapted/. Which one depends entirely on that package’s own history, not a blanket rule.- Anything else (someone else’s package, zero local
modifications, not installed locally for personal use either –
just a dependency we need built once) – doesn’t belong under
arch/at all. Use theinstall_only_packages+/data/INSTALL/<name>plain-checkout pattern (local-install/prefix) instead.
scripts/install_only_packages– what it is and how it’s read (moved here from the file’s own header comment 2026-08-31, to keep that file a plain scannable list rather than prose): lists packages with noPKGBUILDunderarch/<category>/<name>/– either moved out entirely (upstream absorbed the local patch and thearch/copy was deleted, or it never had one checked in to begin with) – that should still show up inOVERVIEW.mdviagenerate_overview.sh’s/data/INSTALLfallback. One<category>/<name>per line, blank lines and#comments ignored.<name>must exist as/data/INSTALL/<name>/PKGBUILD–generate_overview.shwarns and skips (doesn’t abort) any entry where it doesn’t. An entry for a package that’s since moved back intoarch/<category>/<name>/ PKGBUILDis also silently skipped (normal discovery already covers it), so a stale line is harmless – no need to rush to delete one.- The
local-install/prefix specifically covers plain, unmodified upstream AUR packages – not maintained/adapted/owned by us, just periodic rebuilds of someone else’s PKGBUILD kept out ofarch/on purpose (no local diff to track, soadapted/doesn’t fit either – seememory/mod_fcgid.md’s 2026-08-30 entry for the mistake this convention now prevents). Two origin stories so far: most were installed viayayon the local machine for its own use and rebuilt here so archlinuxaba carries them for the cluster too; a few (e.g.perl-crypt-rijndael) were pulled in purely as AUR dependencies to unblock another package’s build (thruk) and never installed locally at all – both count. (mod_fcgidwas briefly here too, but moved toadapted/once it turned out to need a real local deviation – a vendored PGP key – seememory/mod_fcgid.md.)
- The
A remote ARM board can be up (pingable, SSH-reachable) but still fail
modprobe nbd– check whether it’s just waiting on a reboot after a kernel package upgrade before assuming a deeper problem. Hit oneurobuild142026-08-31 (cssh/perl-crypt-rijndaelARM catch-up after the whole cluster had been down):modprobe: could not insert 'nbd': Unknown symbol in module, root causeuname -r(7.2.0-2) not matching the installedlinux-aarch64package (7.2.2-2) –/lib/modules/only had dirs for6.10.5-3and7.2.2-2, nothing for the actually-running7.2.0-2anymore (a pending upgrade alreadypacman -Syu’d but never booted into). User has authorized rebooting these boards whenever this exact symptom (/datamount failing because of an nbd module mismatch) shows up –ssh build@<host> "sudo reboot", wait for it to come back (ping + a real SSH command succeeding, not just ping – seememory/cssh.md’s 2026-08-31 entry for the wait-loop shape used), thensudo modprobe nbdto confirm before retrying the build.REPO_BUILD_ONLY_ARCHrestricts whatrepo_build.shattempts to build, not whatrepo_publish.shends up publishing. The publish step still globs every*.pkg.tar.*sitting in the pkgdir regardless – for a package with older, already-built files for other archs still present there (e.g. a/data/INSTALL-direct package, which – unlike anarch/-staged one – never gets its old artifacts swept byrepo_build_staged.sh’s defensive pre-clean), those get re-uploaded too. Harmless when the version hasn’t changed (identical bytes, redundant re-publish), but don’t treatREPO_BUILD_ONLY_ARCHas an end-to-end “only touch this one arch” guarantee. Noticed 2026-08-31 rebuildingperl-crypt-rijndael’sarmv7halone –i686/x86_64got silently re-uploaded too.repo_build.shsupports an opt-inMAKEFLAGS="-jN"override for local chroot build parallelism (added 2026-09-04) – but getting this right took two attempts; the first one silently didn’t work. Initial (wrong) understanding: a plainsudo --preserve-env=MAKEFLAGSaround the local build commands would be enough, since the host’s/etc/makepkg.confseemed to play no role (confirmed at the time:systemd-nspawnbinds nothing from/etcinto the chroot). That was incomplete –makechrootpkgitself (not the chroot) callsload_makepkg_config()(from/usr/share/makepkg/util/config.sh) once per invocation, which unconditionally re-sources the HOST’s/etc/makepkg.confon the host side, andMAKEFLAGSis NOT among the vars that function preserves across that reload (PKGDEST/SRCDEST/PACKAGER/etc. are,MAKEFLAGSisn’t – see itsrestore_envvarslist). So our exportedMAKEFLAGSsurvived throughsudo --preserve-envonly to get silently clobbered right back to the host’s own value a few lines later, beforemakechrootpkg’s separate step (the one that actually bakesMAKEFLAGSinto the chroot copy’s/etc/makepkg.conf) ever ran. This was caught, not assumed: a reallinux-lts515pentium4 build was launched withMAKEFLAGS=-j6, left running for ~5 minutes, and only then checked by grepping the actual chroot copy’s baked/etc/makepkg.conf(/var/lib/archbuild/<repo>-<arch>/build/etc/makepkg.conf) – it showedMAKEFLAGS='-j1'(the host’s value), not-j6. Always verify this way (grep the live chroot copy’s own makepkg.conf during a real build) rather than trusting thesudo --preserve-env/printenvchain alone – that chain looked correct in isolation but missed this internal reload.- Fix:
load_makepkg_config()also honors aMAKEPKG_CONFenv var naming an alternate file to source instead of/etc/makepkg.conf. When the caller setsMAKEFLAGS,repo_build.shnow also generates a scratch copy of the host’s/etc/makepkg.confwith just itsMAKEFLAGS=line commented out, symlinks<scratch>.dto the real/etc/makepkg.conf.d(load_makepkg_configalso globs$MAKEPKG_CONF.d/*.conffor e.g.rust.conf/fortran.conf– a relocated path without this symlink would silently lose those), exportsMAKEPKG_CONFpointing at the scratch copy, and preserves bothMAKEFLAGSandMAKEPKG_CONFthrough the localsudocalls. Confirmed working against the real chroot afterward: bakedMAKEFLAGS='-j6'. - This still never touches the real host
/etc/makepkg.conf– the scratch file is generated fresh per invocation and cleaned up via an EXIT trap – so the safety property the user asked for (can’t affect the separate, unrelated Archlinux32 builder daemon also running on this host, since that’s its own process tree with its own environment) still holds. Only the mechanism for reaching that goal changed, not the goal or the constraint. - Only affects the local chroot build path. Remote-board builds
(
repo_build_remote.sh, plainmakepkg -son the board, no chroot) are unaffected either way – recorded with a fixedremoteparallelism label regardless.
- Fix:
repo_build.shnow times every arch it actually builds (local or remote; not REUSED/SKIPPED) and records it via the newscripts/repo_record_build_time.sh <pkgname> <arch> <seconds>, which upserts a<!-- BUILD-TIMES:START/END -->-delimited “Build times (auto-updated)” block near the top ofmemory/<pkgname>.md(added 2026-09-04, at the user’s request, so a future rebuild of the same package can get a rough ETA from the last measured duration instead of an unknown wait – e.g.linux-lts515’s multi-hour x86_64 compile).<pkgname>here is the package directory’s basename, same keygenerate_site.shalready uses to link a package to its memory note (so a split package’s timings land on the shared pkgbase/ dirname note, not any one of its sub-pkgnames). The block only tracks the last measured duration per arch, not a history – intentional, it’s for ETAs, not a build-time log; the existing hand-written prose entries below the block remain the place for that. If the memory note doesn’t exist yet, the script creates a minimal one (just the title + block) rather than skipping – still gets filled in properly by hand afterward per the usual per-package-memory convention.- Each recorded line also carries the parallelism used (added
same day):
repo_record_build_time.shtakes an optional 4th arg, rendered as(<when>, <parallelism>).repo_build.shderives it itself per build path – local chroot builds:MAKEFLAGS=-jNif the caller exportedMAKEFLAGS(see thesudo --preserve-env=MAKEFLAGSnote below), elseserial; remote-board builds: a fixedremotelabel, since that board’s own local config governs its parallelism, not anything this project controls. - The block’s closing
<!-- BUILD-TIMES:END -->is followed by a---(Markdown thematic break) before whatever content already followed the title line (e.g. many notes have a- Path: ...bullet right after the title). Confirmed directly againstlowdown: two bullet lists separated only by a blank line get merged into one continuous<ul>per CommonMark’s own list rules – without the---, the auto-generated Build-times list silently swallowed the very next unrelated bullet (e.g.- Path: ...) into the same rendered list, misrepresenting it as a build-time entry. The---is only ever inserted the one time the block is first created; a later in-place update of an existing arch’s line never touches anything outside the START/END markers, so it’s undisturbed on every subsequent rebuild. If a future template/lowdown-invocation change ever alters list-merging behavior, re-check this withlowdown -s -o out.html in.mdon a memory note that has both a Build-times block and a- Path: ...line right after it.
- Each recorded line also carries the parallelism used (added
same day):
generate_overview.shandcheck_for_updates_maintained.shwere slow (a full run: 20-30+ min) despite the--only <category>/<pkgname>scoping mechanism already documented ingenerate_overview.sh’s own header – the scoping just wasn’t being used for routine single- package publishes. Fixed/improved 2026-09-10:- Use
--only <category>/<pkgname>after every routine single- package build+publish, not a full run – it skips both slow phases below entirely and takes a few seconds. RequiresOVERVIEW_CACHE.tsvto already exist (any prior full run writes it). A full run is still needed after anything a--onlyrun can’t reconcile: a deleted/renamed package (confirmed removingarch/maintained/qt5-examples, a duplicate submodule, needed one to purge its stale row – seememory/qt5-doc.md). check_for_updates_maintained.sh’s main loop parallelized (bounded batches of 8, POSIX-portable – nowait -n/bashisms, each job in its own subshell writing to its own temp file socds and output can’t race, concatenated back in original order afterward): a full ~126-package nvchecker sweep dropped from several minutes serial to 34s measured clean.generate_overview.sh’s own/data/INSTALLgap-filling loop parallelized the same way: mostly ~2-3s/package serially, but a few entries with large generated PKGBUILDs (php74’sarch-phpbs-generated PKGBUILD, hundreds of variables) cost 50s+ of pure fork/CPU time each and dominate a serial run. Not yet cleanly re-measured – the one test run so far (24m30s, barely better) was contaminated by unrelated concurrent package builds (optdb5.3/cyrus-imapd2) hammering the same 8-core host at the same time; re-measure in isolation before trusting that number.- Real correctness bug found and fixed while testing the above,
pre-existing and unrelated to the parallelization itself: a
--onlyrun on any package outsidemaintained/(i.e.private//adapted//owned/, wherecheck_for_updates_ maintained.shlegitimately produces zero output by design) hit a GNU awk 5.4.1 quirk: the merge awk’sFNR==NR {next} {...}idiom, given a truly zero-byte first file argument, silently produces zero output for the second file too – not the “just skip the empty file” behavior every other awk (and other gawk versions) gives. Confirmed directly:awk 'FNR==NR{next}{print}' emptyfile realfileprints nothing on this host, but works the instantemptyfilehas even one blank line. This silently dropped the row for the touched package and fell back to its stale cached entry – caught testing--only private/optdb5.3right after a real rebuild, where the report kept showing the oldpkgrel/arch coverage. Fix: forceupstream_fileto have at least one line (test -s "${upstream_file}" || printf '\n' >"${upstream_file}") right aftercheck_for_updates_maintained.shwrites it – the merge awk’s ownNF < 3guard already discards a blank line harmlessly, so this changes nothing for themaintained/case where the file was never empty to begin with.
- Use
repo_build.sh’s local (euronuc) chroot builds now write a live log into pkgdir as the build happens, 2026-09-10 – requested directly: “It would be nice if I could live review the logfile in a place I am familiar like /data/INSTALL/.” Before this,archbuild/makechrootpkgbuilds inside an ephemeral chroot filesystem and only copy their own<pkgname>-<pkgver>-<pkgrel>- <arch>-build.log(plus-prepare/-packagelogs) back into pkgdir once the whole build finishes – confirmed directly with a real build stuck at 73%/79% progress with zero*.logfiles in pkgdir yet. The remote ARM boards alreadyteetheir own build output live (remote_build.sh), but only onto their own filesystem – that doesn’t reach euronuc’s/data/INSTALL/<pkg>live either, only once the whole remote build finishes and gets rsynced back (confirmed with the user 2026-09-10: the ARM-board case is already fine as-is, since they can just log into the board directly andtail -fthere – only euronuc’s local path needed fixing).- Fix: both local-build call sites in
repo_build.sh(thearch=anybranch and the per-arch loop) now doset -o pipefail; sudo ... "${_cmd}" 2>&1 | tee -- "${_livelog}"instead of a baresudo ... "${_cmd}", where_livelogis a new_live_build_logfile <arch>helper:<pkgname>-<arch>-live- build.log.set -o pipefail(confirmed working in oksh directly:false | truereports exit 1 with it, 0 without) is needed so the real build command’s exit status survives the pipe instead oftee’s own (always-0) status winning –set +o pipefailimmediately after, in both the success and failure branches, so it doesn’t leak into the rest of the script. - Deliberately a different filename from archbuild’s own log,
not a reuse of the same name: the tee’s file handle stays open
(appending) for the whole build, while archbuild’s own copy-back
writes its differently-named log once, synchronously, right before
the
sudocommand returns. Reusing the same name would mean two writers racing one path at the exact moment the build finishes. Confirmed both coexist cleanly with a real test build (bochs-gdb- stub, build-only viaREPO_BUILD_ONLY_ARCH=x86_64 repo_build.sh <tmp-pkgdir>, no publish): the live log (172592 bytes) and archbuild’s ownbochs-gdb-stub-2.8-1-x86_64-build.log(146208 bytes) both ended up present and intact, no corruption, no race – they just capture slightly different scope (the live one includes the outer chroot-sync noise the wrapper prints; archbuild’s own is scoped to just the inner makepkg phases). - No cleanup logic needed for the new file:
/data/INSTALL-staged builds already keep every build byproduct around for inspection (repo_build.sh’s own end-of-run cleanup explicitly skips anything under/data/INSTALL, see this file’s ownprivate_repo_publish_ design-adjacent notes), and a direct in-placearch/<category>/ <pkg>build’s existing git-status-driven untracked-file cleanup picks the live log up automatically like any other build byproduct.
- Fix: both local-build call sites in
pkgname=extraction via a naivesed -n 's/^pkgname=\(.*\)$/\1/p'breaks on a split package’s array-with-variable-interpolation form, found 2026-09-10 buildinggcc10foraarch64.gcc10’s PKGBUILD haspkgname=("${pkgbase}" "${pkgbase}-libs" "${pkgbase}-fortran")– completely standard, correct split-package syntax, not a PKGBUILD bug. The sed just grabs the raw line text verbatim, without evaluating shell arrays/variables, so it produced a literal(${pkgbase} ${pkgbase}-libs ${pkgbase}-fortran)as the “pkgname” – visible directly as a garbled live-build-log filename oneurobuild14(user caught it: “this looks like a variable substitution bug”). Same fragile pattern existed in 3 places across 2 scripts:remote_build.sh’s own live-teelogfile naming (where the user actually saw it), and bothrepo_build.shhelpers added/ touched this session (_live_build_logfile, the pre-existing_existing_pkg_file). A 4th occurrence, inrepo_arch_status.sh, turned out to already be correct – useful confirmation the fix below matches an already-proven pattern in this codebase, not a new invention.- Fix, all 3 broken spots: prefer
pkgbase=(always a plain scalar by Arch packaging convention for a split package) overpkgname=, falling back topkgname=only when nopkgbase=line exists at all (a non-split PKGBUILD).repo_build.shgot a shared_pkgbase_or_pkgname()helper for both its call sites;remote_build.sh(a separate deployed file, self-contained) got the same two-step fallback inlined. Verified directly againstgcc10’s real PKGBUILD (resolves to plaingcc10, not the garbled array text) before relying on it for a real build retry. - The pkgbase-preference fix above wasn’t actually general
enough – hit a second variant of the same bug on the very next
build.
cmake2(built immediately aftergcc10in the same session) has nopkgbase=line at all (not a split package) and a plain-scalar-but-interpolatedpkgname:_pkgname=cmake; pkgname=${_pkgname}2. The pkgbase-preference fallback still hits the same raw-textpkgname=sed for this case, producing a literal${_pkgname}2– visible again as a garbled live-log filename (${_pkgname}2-x86_64-live-build.log), this time caught directly rather than pointed out by the user. - Real fix, superseding the pkgbase-preference patch: no sed
pattern against raw PKGBUILD text generalizes to every
variable/array shape pkgbase=/pkgname= can take. Switched to
makepkg --printsrcinfo | awk -F' = ' '$1 == "pkgbase" { print $2; exit }'–--printsrcinfoalready fully evaluates the PKGBUILD (same tool this project’s own scripts use to regenerate.SRCINFO), so its output’s first line is always the correctly- resolvedpkgbase = <name>, split or scalar, array or plain, interpolated or not. No network access, no source download – confirmed side-effect-free. Verified directly against bothgcc10(gcc10, not the garbled array text) andcmake2(cmake2, not the garbled${_pkgname}2) before trusting it. Applied to bothrepo_build.sh’s shared_pkgbase_or_pkgname()helper andremote_build.sh’s separate inlined copy. - The narrower single-element-array gap
(
pkgname=('foo')) this note originally flagged as “worth fixing if it ever causes a real incident” is now moot – the--printsrcinfo-based fix handles that case correctly too, same as every other shape, since it’s real evaluation rather than pattern-matching against specific textual forms.
- Fix, all 3 broken spots: prefer
2026-09-11: remote-board build times now label MAKEFLAGS/serial, not a bare “remote”
repo_record_build_time.sh’s “Build times” block in each package’s
memory note already labeled local chroot builds with their actual
parallelism (MAKEFLAGS=-jN or serial, derived from repo_build.sh’s
own MAKEFLAGS env var), but remote ARM-board builds
(eurobuild4/5/14) just got a fixed remote – no indication of
whether that board built serially or with some -jN. User asked for
parity with the local labels.
Fix: scripts/remote_build.sh (the agent script deployed to and run
on the board) now resolves its own effective parallelism the same
way makepkg itself would – MAKEFLAGS from the environment if
exported (it currently isn’t, in the non-interactive ssh session this
runs under), else parsed out of the board’s own /etc/makepkg.conf
(last uncommented MAKEFLAGS= line, quotes stripped) – and echoes it
as REMOTE_BUILD_PARALLELISM: MAKEFLAGS=-jN (or ...: serial) to
stdout before starting the build. That line lands in the ssh output
repo_build_remote.sh returns, which repo_build.sh already captures
per-arch into ${_remote_tmpdir}/${arch}.log; on a successful build,
repo_build.sh now greps that line back out and passes
"remote, ${label}" (e.g. remote, MAKEFLAGS=-j2, remote, serial)
to repo_record_build_time.sh instead of the bare remote. Falls back
to plain remote if the line isn’t found (e.g. an older/unpatched
remote_build.sh still cached on some board before its next
self-deploy refresh).
No pkgdir files involved – the label rides through stdout/the existing
log capture, not a synced-back sidecar file, so no new stray-file
cleanup concern (cf. feedback_check_stale_artifacts_before_build.md).
2026-09-11: use MAKEFLAGS=-j6 for local euronuc builds going forward
Local chroot builds (x86_64/i686/pentium4/i486 on euronuc) have
always been single-threaded by default (/etc/makepkg.conf’s
MAKEFLAGS="-j1"), since repo_build.sh’s MAKEFLAGS passthrough
(added 2026-09-04) is an opt-in the caller has to set, not a default.
Came up when asked whether local archs could build in parallel with
each other – they can’t, safely, as-is: every local arch’s chroot
binds the same host pkgdir as both /startdir and /srcdest (no
per-arch isolation the way the remote-board path already has, where
each board gets its own rsynced copy), so two local archs building at
once would race on the same src/ extraction. Cross-arch parallelism
would need real staging work (isolate each local arch into its own
copy, mirroring the remote pattern) – not done.
The safe, immediate win instead: set MAKEFLAGS=-j6 when invoking
repo_release.sh/repo_build_staged.sh for local builds, so each
(still-sequential) arch build at least uses multiple cores to compile.
-j6 (not -j8, euronuc’s full core count) leaves headroom for the
separate Archlinux32 builder daemon that also runs on this same host –
same reasoning repo_build.sh’s own MAKEFLAGS mechanism was built
around in the first place (never touches the real /etc/makepkg.conf,
see the 2026-09-04 entry above). Adopted as a standing convention going
forward, not a one-off.
2026-09-11 (same day, follow-up): MAKEFLAGS=-j6 baked in as an actual script default
Per direct follow-up request, the convention above is no longer just a
“remember to pass it” habit – scripts/repo_build.sh now has
: "${MAKEFLAGS:=-j6}" + export MAKEFLAGS right after its
REPO_BUILD_ONLY_ARCH default. Still fully overridable by an explicit
caller-set MAKEFLAGS (e.g. MAKEFLAGS="-j1" for the old serial
behavior). The explicit export matters: if a caller never sets
MAKEFLAGS at all (now the common case), := alone would only create
a local shell variable that sudo --preserve-env=MAKEFLAGS further
down couldn’t see.
Verified end-to-end against a real chroot build, not just an
env-passthrough test (see this file’s 2026-09-04 MAKEFLAGS entry for
why that alone isn’t trustworthy): ran
scripts/repo_build_staged.sh adapted/gconf with no MAKEFLAGS set,
confirmed MAKEFLAGS=-j6 + the scratch MAKEPKG_CONF in the actual
running makechrootpkg/sudo processes’ environment via
/proc/<pid>/environ, and confirmed the auto-recorded build time
picked up the new label (memory/gconf.md: x86_64 41s,
MAKEFLAGS=-j6, down from a prior serial run’s 55s).
Gotcha hit while verifying: repo_build_staged.sh copies built
.pkg.tar.* back into the git-tracked arch/<category>/<pkg>/ dir by
design (so repo_release.sh can find them to sign/publish) – calling
it directly for a build-only test, with no follow-up repo_release.sh,
leaves those files sitting in the git tree; cleaned them up manually
afterward. Not a bug, just something to remember when testing the
build step in isolation.