Compare commits

...
Author SHA1 Message Date
6afa4e2405
Merge remote-tracking branch 'origin/main' into t3code/smarter-disk-pruning-macmini
# Conflicts:
#	.crow/build-all-versions-install-deps.yaml
#	.crow/build-all-versions.yaml
2026-07-13 09:30:21 +00:00
ffc2319558 fix(build-all): exclude previously-errored versions in prefilter (#113)
Some checks failed
ci/crow/cron/process-updates/15 Pipeline was canceled
## Motivation

Build jobs were cycling through hundreds of packages that were only ever printed as `Skipping … due to previous build error recorded in metadata DB`, wasting wall-clock on per-package preparation before dropping each one.

## Cause

The prefilter query in `local/build-all.R` selected only successfully-built versions (`error_occurred = FALSE`) into `built`, so line 112 removed only those from the chunk.
Every previously-errored version stayed in the work list and was walked one-by-one, each hitting the internal skip in `build_binary_package()`.
This also explains the misleading `Skipped 0 already-built package versions` line for alphabetical chunks whose leading packages only have error records.

## Changes

- `local/build-all.R`: drop the `AND error_occurred = FALSE` clause so `built` holds every version already attempted (built or errored) for this platform/arch; the existing filter then removes all of them up front.
- Rename the log line to `already-attempted` so the reported count reflects successes and errors.
- Update the surrounding comment to explain why errored versions are excluded.

## Behaviour change

Previously-errored versions are now dropped before the build loop instead of being iterated and individually skipped.
No package that would otherwise build is affected, `build_binary_package()` already skipped these internally.
Retrying errored versions is out of scope and would need a separate opt-in flag on both the prefilter and the in-loop skip.

Reviewed-on: #113
2026-07-13 09:28:45 +00:00
09536cddd6 feat(build): raise BuildKit cache-mount budget for remote builders (#112)
Some checks failed
ci/crow/cron/weekly-rebuild-missing/5 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/10 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/11 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/12 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/13 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/9 Pipeline was canceled
ci/crow/cron/weekly-rebuild-missing/14 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline failed
ci/crow/cron/process-updates/11 Pipeline was canceled
ci/crow/cron/process-updates/16 Pipeline was canceled
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/cron/process-updates/18 Pipeline was successful
ci/crow/cron/process-updates/17 Pipeline was canceled
ci/crow/cron/process-updates/1 Pipeline was canceled
ci/crow/cron/process-updates/2 Pipeline was canceled
ci/crow/cron/process-updates/8 Pipeline was canceled
ci/crow/manual/build-all-versions-install-deps/2 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was canceled
ci/crow/cron/process-updates/3 Pipeline was canceled
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was canceled
ci/crow/manual/build-all-versions/7 Pipeline was canceled
ci/crow/manual/build-all-versions/6 Pipeline failed
ci/crow/manual/build-all-versions/8 Pipeline was canceled
ci/crow/manual/build-all-versions/5 Pipeline was canceled
ci/crow/cron/process-updates/4 Pipeline was canceled
ci/crow/cron/process-updates/14 Pipeline was canceled
ci/crow/cron/process-updates/13 Pipeline was successful
BuildKit's default GC caps the ephemeral cache tier — `RUN --mount=type=cache` mounts, local build context, git checkouts — at a hardcoded **512 MB** (shown as `488.3 MiB` in `buildx inspect`).
Across our 7-distro build matrix that fills instantly and forces re-downloads of system + R packages on every rebuild.

## Changes

- **`docker/buildkitd.toml`** (new) — GC config passed via `--config` when creating the `docker-container` builders `artemis` (amd64) and `gaia` (arm64):
  - cache-mount tier: **512 MB → 8 GB**, retained 7 days
  - total cache bounded at **40 GB** with **20 GB min-free**
- **`justfile`** — document the `--config docker/buildkitd.toml` flag on the builder-create commands so a recreate does not silently revert to the 512 MB default.

## Notes

- Limits are absolute (not `%`) because the two hosts differ ~6× in free space (Hetzner ~42 GiB free vs Mac mini ~279 GiB). The 20 GB min-free is the safety valve on the disk-tight Hetzner host; the old default wanted 64 GiB free, which does not exist there.
- Both live builders were already recreated with this config and verified running.

Reviewed-on: #112
2026-07-08 08:22:03 +00:00
36d3bc8604 fix(patches): force fs to build vendored static libuv (#111)
Some checks failed
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/17 Pipeline was successful
ci/crow/cron/process-updates/18 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/manual/build-all-versions-install-deps/2 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/manual/build-all-versions/8 Pipeline was canceled
ci/crow/manual/build-all-versions/7 Pipeline was canceled
ci/crow/manual/build-all-versions/6 Pipeline was canceled
ci/crow/manual/build-all-versions/5 Pipeline was canceled
ci/crow/cron/process-updates/10 Pipeline was canceled
## Problem

The `fs` 2.1.0 binary links **system libuv** (`readelf -d fs.so` shows `NEEDED libuv.so.1`).
fs's `configure` prefers system libuv whenever `pkg-config` resolves it, and our build images ship `libuv-devel` (installed as a pak build-time system requirement), so the resulting binary is dynamically linked against `libuv.so.1`.

That binary fails to load on any consumer machine without runtime libuv:

```text
unable to load shared object '.../fs/libs/fs.so':
  libuv.so.1: cannot open shared object file: No such file or directory
```

`install.packages()`/renv do **not** install `SystemRequirements` (only `pak` does, and only inside the build container), so most consumers hit this.
Older fs 1.6.x always vendored libuv, so only the 2.x binaries regressed.
Reproduced in a clean `reg.devxy.io/r/r-alma:4.5-9`.

## Fix

Add `local/patches/fs/force-vendored-libuv.patch`, registered for all platforms.
It short-circuits `configure` to `cp -f src/Makevars.vendor src/Makevars; exit 0` before the pkg-config detection, forcing the bundled static libuv build (`tools/libuv-v1.52.0.tar.gz`, built via cmake).
An env/pkg-config override (`PKG_CONFIG_LIBDIR`) was tried first but the rebuilt binary still linked `libuv.so.1` (the registry `env` tier does not reach fs's configure step), so a source patch is used instead.

## Verification

Built end-to-end inside the real `build-env-redhat:9` image (system libuv present):

- patch fires (`Building static libuv (bincraft: forced vendored)`),
- cmake compiles the vendored libuv,
- resulting `fs.so` has **no `libuv.so.1`** in `NEEDED` (only libR, libstdc++, libm, libgcc_s, libc).

`Rscript local/validate-patches.R` passes (2 entries).
cmake confirmed present in the build-env images.

## Follow-up (not in this PR)

- Rebuild `fs 2.1.0` on every affected platform (rhel8/9/10, ubuntu jammy/noble, alpine 3.22/3.23; amd64 + arm64) and purge the CDN binary paths.
- CDN delivery gap: `purge_cdn_cache.sh` only purges `PACKAGES*`, never package binaries, so rebuilt binaries stay masked until their `.tar.gz` path is purged.

Reviewed-on: #111
2026-07-07 18:12:36 +00:00
1e06576084
docs: add CLAUDE.md with B2 storage gotchas and build pipeline conventions for agents
Some checks failed
ci/crow/cron/weekly-rebuild-missing/2 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/10 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/12 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/11 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/13 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/14 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/9 Pipeline was successful
ci/crow/manual/build-all-versions-install-deps/2 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/18 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/manual/build-all-versions/8 Pipeline was canceled
ci/crow/manual/build-all-versions/6 Pipeline was canceled
ci/crow/manual/build-all-versions/5 Pipeline was canceled
ci/crow/manual/build-all-versions/7 Pipeline was canceled
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/17 Pipeline was canceled
ci/crow/cron/process-updates/5 Pipeline was canceled
2026-07-02 08:43:37 +02:00
automation-bot
5f10863a9c chore(deps): update pre-commit hook davidanson/markdownlint-cli2 to v0.23.0
Some checks failed
ci/crow/cron/process-updates/7 Pipeline failed
ci/crow/cron/process-updates/2 Pipeline failed
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
2026-07-02 00:32:11 +00:00
1ad7a6bfe9 chore: resolve latest bincraft release dynamically (no hardcoded pins) (#107)
Some checks failed
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/cron/process-updates/17 Pipeline was successful
ci/crow/cron/process-updates/18 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline failed
ci/crow/cron/process-updates/9 Pipeline failed
ci/crow/cron/process-updates/7 Pipeline failed
ci/crow/cron/process-updates/8 Pipeline failed
ci/crow/manual/build-all-versions-install-deps/2 Pipeline was successful
ci/crow/manual/build-all-versions/5 Pipeline failed
ci/crow/manual/build-all-versions/7 Pipeline failed
ci/crow/manual/build-all-versions/6 Pipeline failed
ci/crow/manual/build-all-versions/8 Pipeline was canceled
## Summary

Stop hardcoding the bincraft version. Every `.crow` workflow and the build-one image pinned `@vX.Y.Z` (and a `packageVersion() != "X.Y.Z"` guard), so each bincraft release meant editing the version in ~8 places — and it was easy to miss one (the Dockerfile lagged at v4.2.1; v4.4.1 shipped without the empty-env fix because of exactly this churn).

## Change

New `local/install-bincraft.R` resolves the **latest release tag dynamically**:

- `git ls-remote --tags` on the public repo (no token),
- keep `vX.Y.Z` tags, pick the highest version (filtered/sorted in R for portability, not via git `--sort`/refspec which behaved inconsistently under `system2()`),
- `pak::pak("git::…@<latest>")` — idempotent on the git ref, so re-runs keep the package unless a newer tag exists.

All call sites now invoke the helper instead of a pinned version:

- `.crow/build-all-versions.yaml` (primary + per-minor pass)
- `.crow/build-all-versions-install-deps.yaml`
- `.crow/process-updates.yaml` (primary + per-minor pass)
- `.crow/weekly-rebuild-missing.yaml`
- `.crow/archive-missed-packages.yaml`
- `docker/build-one.Dockerfile` (ships the helper into the image; `ensure_bincraft` sources it)

## Effect

Tag a new bincraft release → the next CI run / `just rebuild` picks it up automatically. No more pin edits, and no more "forgot to bump the Dockerfile" drift.

## Verified

- Resolver returns the current latest tag (`v4.4.2`) via `git ls-remote` + R-side version sort.
- All five workflow YAMLs parse; helper R parses; air/editorconfig clean.

Note: this tracks the latest **tag**, so cutting a release is still the deliberate gate — CI won't pick up un-tagged main.
Reviewed-on: #107
2026-07-01 08:10:02 +00:00
automation-bot
2cf5714ad9 chore(deps): update pre-commit hook rbubley/mirrors-prettier to v3.9.4
Some checks are pending
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/manual/build-all-versions/8 Pipeline is pending
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/manual/build-all-versions-install-deps/2 Pipeline was successful
ci/crow/manual/build-all-versions/5 Pipeline is running
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/manual/build-all-versions/6 Pipeline is running
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/manual/build-all-versions/7 Pipeline is running
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
2026-07-01 00:32:49 +00:00
b4ec6291a9
chore: bump bincraft to 4.4.2
All checks were successful
ci/crow/cron/weekly-audit-missing/15 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/13 Pipeline was successful
ci/crow/cron/weekly-audit-missing/5 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/3 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/17 Pipeline was successful
ci/crow/cron/process-updates/18 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
2026-06-30 16:09:44 +02:00
d496029a79
chore: bump bincraft to 4.4.1
All checks were successful
ci/crow/cron/process-updates/7 Pipeline was successful
2026-06-30 15:51:07 +02:00
e59590e2d6 fix: RcppParallel disable-TBB source patch (env var was a no-op) (#106)
All checks were successful
ci/crow/cron/process-updates/2 Pipeline was successful
## Summary

Fixes the RcppParallel patch, which was a **no-op** and left the build hanging.

The previous registry entry set `env: { RCPP_PARALLEL_USE_TBB: "0" }`. But `RCPP_PARALLEL_USE_TBB` is a **compile-time `-D` flag** in RcppParallel's Makevars — it is never read from the environment. So the override did nothing: `USE_TBB=Linux` (hardcoded from `uname`) still triggered the **bundled Intel TBB build**, which hangs/fails on musl (Alpine) and newer toolchains (g++ 15 on ubuntu-2604). The `Applying patch …` log only meant the env was set, not that it had any effect.

## Fix

Replace the env entry with a **source patch** (`local/patches/RcppParallel/disable-tbb.patch`) on `src/Makevars.in` that, on Linux:

- leaves `USE_TBB` unset → the whole bundled-TBB build/link path is skipped (no hang), and
- forces `PKG_CXXFLAGS += -DRCPP_PARALLEL_USE_TBB=0` → the sources compile the **TinyThread** backend (needed because `RcppParallel.h` otherwise auto-defaults TBB on for glibc Linux).

## Verification

In a Linux container, applying the patch and running `R CMD INSTALL RcppParallel`:

```
bundled_TBB_build=0      # bundled TBB build never runs
* DONE (RcppParallel)    # installs via TinyThread
```

## Note

bincraft's `apply_source_patch` shells out to `patch`. If a build-env image lacks the `patch` tool (common on Alpine), the patch will report "did not apply cleanly" and fall back to an unpatched (hanging) build. If that happens, the follow-up is to switch bincraft's patch application to `git apply` (git is always present) — happy to do that if needed.

Reviewed-on: #106
2026-06-30 13:27:01 +00:00
b93d1ef6bd chore: silence otelsdk warnings across build paths (#105)
All checks were successful
ci/crow/cron/process-updates/1 Pipeline was successful
## Summary

Silences the recurring `OpenTelemetry error: there is no package called 'otelsdk'` warnings during builds.

## Root cause

The `build-env-*` images configure an OTel exporter (traces/logs/metrics), but `otelsdk` (the R OTel SDK backend) isn't installed. pak's `otel` instrumentation therefore tries to load `otelsdk` on every run and logs the error, falling back to a no-op.

`OTEL_SDK_DISABLED=true` (already set in `build-one.Dockerfile`) does **not** help — the R `otel` package ignores it and gates purely on `OTEL_R_<SIGNAL>_EXPORTER` (then the standard `OTEL_<SIGNAL>_EXPORTER`). When that resolves to a real exporter (`otlp`/`http`/…) with no SDK present, you get the error.

## Fix

Set `OTEL_R_TRACES_EXPORTER`, `OTEL_R_LOGS_EXPORTER`, and `OTEL_R_METRICS_EXPORTER` to `none` so the R otel providers are clean no-ops:

- `docker/build-one.Dockerfile` — exported alongside the existing OTel var.
- `.crow/process-updates.yaml`, `weekly-rebuild-missing.yaml`, `build-all-versions.yaml`, `build-all-versions-install-deps.yaml` — added to each step's `environment` block.

Using the R-specific variables (not the standard `OTEL_*_EXPORTER`) keeps OTel intact for any non-R tooling in the images.

Reviewed-on: #105
2026-06-30 12:41:32 +00:00
b744ae1bb1 fix: build-one image bincraft v4.4.0 + ship patch registry (#104)
## Summary

Fixes the **targeted rebuild** path (`just rebuild` → `docker/build-one.Dockerfile`) so it actually applies patches.

Two problems, both of which would make `build-one.R`'s `patches = "local/patches"` a silent no-op or a hard error:

1. **Stale bincraft pin.** The Dockerfile pinned bincraft `v4.2.1`, which predates the `patches` argument — so `build_binary_package(patches = ...)` would fail with `unused argument`. Bumped to **v4.4.0** to match the `.crow` workflows.
2. **Registry not shipped into the image.** Only `build-one.R` was copied in; `local/patches/registry.json` was absent, so `patches = "local/patches"` resolved to a nonexistent `/work/local/patches` and silently applied nothing. Added `COPY patches /work/local/patches` (build context is `local/`, CWD is `/work`).

## Why

This is the path used to verify the patching end-to-end, e.g.:

```bash
just rebuild alpine 3.23 amd64 rts2 1.0.3
```

rts2 depends on RcppParallel; with this fix the container installs bincraft v4.4.0, ships the registry, and the patched RcppParallel binary (`RCPP_PARALLEL_USE_TBB=0`) is served to pak during dependency install. Expect `Applying patch to RcppParallel …` in the log, RcppParallel installed as a binary (no recompile), then rts2 building and uploading.

Reviewed-on: #104
2026-06-30 12:15:39 +00:00
00db47398d
chore: 4.4.0 instead of 4.3.1
All checks were successful
ci/crow/cron/process-updates/6 Pipeline was successful
2026-06-30 14:07:22 +02:00
55a18fd87d feat: patch registry + wiring for per-package patching (#103)
Some checks failed
ci/crow/cron/process-updates/15 Pipeline failed
ci/crow/cron/process-updates/14 Pipeline failed
ci/crow/cron/process-updates/16 Pipeline failed
ci/crow/cron/process-updates/18 Pipeline failed
ci/crow/cron/process-updates/11 Pipeline failed
ci/crow/cron/process-updates/12 Pipeline failed
ci/crow/cron/process-updates/17 Pipeline failed
ci/crow/cron/process-updates/6 Pipeline failed
ci/crow/cron/process-updates/5 Pipeline failed
## Summary

Adds the curated **patch registry** and wiring that drives bincraft's new package-patching mechanism (see bincraft PR `feat/package-patching`).
Lets specific packages be patched (env/configure/Makevars overrides or source diffs) before pak installs them — including as transitive dependencies — so compiler-/OS-specific failures like RcppParallel's bundled TBB stop cascading.

## What's included

- `local/patches/registry.json` — initial entry: RcppParallel with `RCPP_PARALLEL_USE_TBB=0` for alpine / ubuntu-2604, plus `local/patches/README.md` schema docs.
- `local/validate-patches.R` — validates schema, referenced patch files, and ambiguous overlaps; clean failure + exit 1 (no stacktrace).
- `.pre-commit-config.yaml` — a `validate-patches` hook (re-runs when the registry or the validator changes).
- `local/build-one.R` / `local/build-all.R` — pass `patches = "local/patches"` to `bincraft::build_binary_package()`.
- `specs/2026-06-30-package-patching-design.md` and `plans/2026-06-30-package-patching-implementation.md`.

## ⚠️ Merge ordering (blocker)

This PR adds a `patches = ...` argument to `build_binary_package()` calls.
The `.crow/*.yaml` workflows currently pin bincraft **v4.2.3**, which does not accept that argument — CI will error with `unused argument (patches=...)` until:

1. bincraft **v4.3.0** is released (PR `feat/package-patching`), and
2. the pin is bumped in `.crow/build-all-versions-install-deps.yaml`, `.crow/build-all-versions.yaml`, and `.crow/process-updates.yaml`.

The `.crow` pin bump will be added to this PR once bincraft v4.3.0 is tagged. Do not merge before then.

Reviewed-on: #103
2026-06-30 08:50:19 +00:00
automation-bot
1e910bc703 chore(deps): update pre-commit hook rbubley/mirrors-prettier to v3.9.1
Some checks failed
ci/crow/manual/build-all-versions-install-deps/2 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/18 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/17 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/manual/build-all-versions/6 Pipeline failed
ci/crow/manual/build-all-versions/5 Pipeline failed
ci/crow/manual/build-all-versions/8 Pipeline failed
ci/crow/manual/build-all-versions/7 Pipeline failed
2026-06-29 00:31:40 +00:00
automation-bot
597f759bb2 chore(deps): update pre-commit hook editorconfig-checker/editorconfig-checker to v3.8.0 2026-06-29 00:31:27 +00:00
automation-bot
3ffa25ddac chore(deps): update pre-commit hook rbubley/mirrors-prettier to v3.8.5
Some checks failed
ci/crow/cron/weekly-audit-missing/9 Pipeline was successful
ci/crow/cron/weekly-audit-missing/10 Pipeline failed
ci/crow/cron/weekly-audit-missing/11 Pipeline was successful
ci/crow/cron/weekly-audit-missing/13 Pipeline is running
ci/crow/cron/weekly-rebuild-missing/11 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/13 Pipeline was successful
ci/crow/cron/weekly-audit-missing/12 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/12 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/14 Pipeline was successful
ci/crow/manual/build-all-versions/7 Pipeline is pending
ci/crow/manual/build-all-versions/8 Pipeline is pending
ci/crow/manual/build-all-versions-install-deps/2 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/17 Pipeline was successful
ci/crow/manual/build-all-versions/6 Pipeline was canceled
ci/crow/manual/build-all-versions/5 Pipeline was canceled
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was canceled
ci/crow/cron/process-updates/18 Pipeline was canceled
ci/crow/cron/process-updates/14 Pipeline was canceled
ci/crow/cron/process-updates/2 Pipeline was canceled
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline failed
2026-06-28 00:32:21 +00:00
automation-bot
81ca78edb6 chore(deps): update terraform bunnynet to ~> 0.15
Some checks failed
ci/crow/manual/build-all-versions-install-deps/1 Pipeline was successful
ci/crow/manual/build-all-versions/1 Pipeline failed
ci/crow/manual/build-all-versions/4 Pipeline failed
ci/crow/manual/build-all-versions/3 Pipeline failed
ci/crow/manual/build-all-versions/2 Pipeline was successful
ci/crow/manual/build-all-versions-install-deps/2 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/manual/build-all-versions/5 Pipeline failed
ci/crow/manual/build-all-versions/6 Pipeline failed
ci/crow/manual/build-all-versions/8 Pipeline failed
ci/crow/manual/build-all-versions/7 Pipeline failed
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline failed
ci/crow/cron/process-updates/12 Pipeline failed
ci/crow/cron/process-updates/17 Pipeline failed
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline is running
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/18 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline failed
ci/crow/cron/process-updates/9 Pipeline failed
ci/crow/cron/process-updates/2 Pipeline failed
ci/crow/cron/process-updates/8 Pipeline failed
ci/crow/cron/weekly-audit-missing/3 Pipeline was successful
ci/crow/cron/weekly-audit-missing/4 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline failed
2026-06-23 00:31:42 +00:00
a1d7064fb8
feat(ci): add process-updates rows for alpine-324 and ubuntu resolute
Some checks failed
ci/crow/manual/build-all-versions-install-deps/1 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/17 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/18 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/manual/build-all-versions-install-deps/2 Pipeline was successful
ci/crow/manual/build-all-versions/6 Pipeline was successful
ci/crow/manual/build-all-versions/5 Pipeline was successful
ci/crow/manual/build-all-versions/7 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/manual/build-all-versions/8 Pipeline was successful
ci/crow/manual/build-all-versions/3 Pipeline failed
ci/crow/manual/build-all-versions/4 Pipeline failed
ci/crow/manual/build-all-versions/1 Pipeline failed
ci/crow/manual/build-all-versions/2 Pipeline failed
Add matrix rows and manual dropdown options for alpine 3.24
(alpine-324, PROCESS_NEW=FALSE) and ubuntu resolute / 26.04
(ubuntu-2604, OS_ID resolute, R 4.5.3, PROCESS_NEW=TRUE).
2026-06-21 11:04:24 +02:00
b46472b59e
fix(ci): pass Backblaze B2 credentials to process_unarchived_pkgs
All checks were successful
ci/crow/cron/process-updates/12 Pipeline was successful
The function defaults to Hetzner S3 with HETZNER_S3_*_K3S env vars that
are not set in these workflows, so paws failed with "No compatible
credentials provided". Pass the B2 endpoint/region/bucket and
B2_S3_* secrets explicitly, matching the other S3 calls. Also use
set_codename(NULL) for the build-all-versions codename so it matches
the S3 repo path.
2026-06-21 10:55:22 +02:00
automation-bot
a6788f9044 chore(deps): update pre-commit hook posit-dev/air-pre-commit to v0.10.0
Some checks failed
ci/crow/cron/weekly-audit-missing/15 Pipeline was successful
ci/crow/cron/weekly-audit-missing/16 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/3 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/4 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/1 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/7 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/8 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/5 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/6 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/11 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/12 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/10 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline failed
ci/crow/cron/weekly-rebuild-missing/13 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/14 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/manual/build-all-versions-install-deps/1 Pipeline was successful
ci/crow/manual/build-all-versions/2 Pipeline failed
ci/crow/manual/build-all-versions/4 Pipeline failed
ci/crow/manual/build-all-versions/1 Pipeline failed
ci/crow/manual/build-all-versions/3 Pipeline failed
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/2 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/9 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
2026-06-20 00:31:34 +00:00
3420523849
chore: add all options for OS_VERSION
Some checks failed
ci/crow/manual/build-all-versions-install-deps/1 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline failed
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/manual/build-all-versions/2 Pipeline failed
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline failed
ci/crow/cron/process-updates/6 Pipeline failed
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/manual/build-all-versions/4 Pipeline failed
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/manual/build-all-versions/3 Pipeline failed
ci/crow/manual/build-all-versions/1 Pipeline failed
2026-06-18 13:40:13 +02:00
83c761b736 feat(ci): OS/OS_VERSION manual dropdowns + restore lost crow fix (#97)
## Summary

Two changes:

1. **`OS`/`OS_VERSION` manual-run dropdowns** — give these form variables explicit `options:` lists (like `target_arch` and `R_VERSION`), so the manual-run form shows dropdowns instead of free-text, in both `build-all-versions.yaml` and `build-all-versions-install-deps.yaml`. Crow form variables are independent (no cascading), so the operator still has to pick a coherent `OS` + `OS_VERSION` combination (e.g. `redhat` + `9`, not `alpine` + `jammy`).

2. **Repairs `main`** — the crow fix from PR #96 (`bc2f6f1`) was lost when that PR was squashed (only the first commit was captured). As a result `main` currently carries the `OS: ${OS}` env vars that break Crow parsing (`unable to parse variable name`) and the unfixed `build-all.R`. This PR re-applies that fix: drop the env additions and derive `platform`/`arch` inside `build-all.R` from the container (bincraft codename → platform mapping + `Sys.info()` arch).

## Notes
- `OS_VERSION` options are quoted strings so tags like `8`/`9`/`10` aren't parsed as integers.
- Validated: both YAMLs parse, `build-all.R` parses.

Reviewed-on: #97
2026-06-18 11:39:11 +00:00
0f4330c05c fix(ci): make build-all self-sufficient on agents without install-deps (#96)
## Summary

Fixes the recurring `build-all-*` failure on agents where `build-all-versions-install-deps` did **not** run.

Both symptoms in the logs — `Parameter 3 does not have length 1` (repeated, in the metadata DB queries) and `argument is of length zero` (system-dependency install) — were the same bug: inside bincraft, `platform` was zero-length. `local/build-all.R` calls `build_binary_package()` without passing `platform`, so bincraft resolves it from the container codename. The primary build step never (re)installed/pinned bincraft and relied on whatever sat in the **per-agent** cache volume; `depends_on` only orders steps, it does not co-locate them on the same agent, so a job landing where install-deps never ran got a stale bincraft that left `platform` empty.

## Changes

- **`build-all-versions.yaml`**: pin bincraft `@v4.2.3` in the primary build step (mirroring the R-minor pass and `process-updates.yaml`), so every agent uses a known-good bincraft regardless of where install-deps ran.
- Align the R-minor pass `v4.2.2 → v4.2.3`.
- Export `OS`/`OS_VERSION`/`ARCH` as runtime env vars — previously only available for `${...}` interpolation, so `build-all.R`'s already-built dedup query matched platform `"-"` and skipped nothing.
- Fix the unarchive call: pass the codename via `bincraft::set_codename(NULL)` instead of the malformed `paste(OS, OS_VERSION)` (`"alpine 3.24"`), matching `archive-missed-packages.yaml`.
- **`build-all-versions-install-deps.yaml`**: pin install-deps to `@v4.2.3` (was installing HEAD), so the precomputed snapshot and per-agent library stay consistent pipeline-wide.

Reviewed-on: #96
2026-06-18 11:27:02 +00:00
f9bc72d5ab
chore: bump bincraft to 4.2.3
Some checks failed
ci/crow/manual/build-all-versions-install-deps/1 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/manual/build-all-versions/3 Pipeline failed
ci/crow/manual/build-all-versions/4 Pipeline failed
ci/crow/cron/process-updates/6 Pipeline failed
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/manual/build-all-versions/2 Pipeline failed
ci/crow/manual/build-all-versions/1 Pipeline failed
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
2026-06-18 09:43:05 +02:00
fa955c10bf fix: recompute package snapshot when missing from cache (#95)
Some checks failed
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline failed
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/manual/build-all-versions-install-deps/1 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline failed
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/manual/build-all-versions-install-deps/2 Pipeline was successful
ci/crow/manual/build-all-versions/5 Pipeline was canceled
ci/crow/manual/build-all-versions/6 Pipeline was canceled
ci/crow/manual/build-all-versions/7 Pipeline was canceled
ci/crow/manual/build-all-versions/8 Pipeline was canceled
ci/crow/manual/build-all-versions/4 Pipeline failed
ci/crow/manual/build-all-versions/1 Pipeline failed
ci/crow/manual/build-all-versions/3 Pipeline failed
ci/crow/manual/build-all-versions/2 Pipeline failed
## Summary

`build-all.R` reads three snapshot files from `/mnt/cache/packages/` that the `build-all-versions-install-deps` step precomputes: `pkgs_to_build.rds`, `r_minor_sensitive_pkgs.rds`, and `s3_cache.rds`.
That cache volume is **per-agent**, so a build job scheduled on a different (fresh) agent than the one that ran install-deps finds the snapshot absent and dies at `readRDS` (`cannot open compressed file '/mnt/cache/packages/pkgs_to_build.rds'`).

This adds a conditional guard at the top of `build-all.R`: when any of the three files is missing, it sources `local/packages-to-build.R` (which has all needed creds via `PGPASS` / `B2_S3_*` env, already present in the build step) and writes the derived `.rds` files — exactly mirroring the install-deps command.

- The first build job on a fresh agent repopulates the shared cache, so subsequent jobs on that agent reuse it.
- Concurrent jobs that also miss simply redo the work (accepted tradeoff vs. slow shared storage like NFS).
- Saves use a temp-file + atomic `file.rename`, so a concurrent reader never sees a half-written `.rds`.

Reviewed-on: #95
2026-06-17 17:49:04 +00:00
25 changed files with 2119 additions and 69 deletions

View file

@ -62,9 +62,9 @@ steps:
GIT_USER: pat-s GIT_USER: pat-s
R_VERSION: 4.5.3 R_VERSION: 4.5.3
commands: commands:
- /opt/R/$R_VERSION/bin/R -q -e 'if (!requireNamespace("bincraft", quietly = TRUE) || packageVersion("bincraft") != "4.2.2") pak::pak("git::https://codefloe.com/rpkgs/bincraft.git@v4.2.2", dependencies = TRUE)' - /opt/R/$R_VERSION/bin/Rscript local/install-bincraft.R
- /opt/R/$R_VERSION/bin/R -q -e 'packageVersion("bincraft")' - /opt/R/$R_VERSION/bin/R -q -e 'packageVersion("bincraft")'
- /opt/R/$R_VERSION/bin/R -q -e 'bincraft::process_unarchived_pkgs(Sys.getenv("CODENAME"), Sys.getenv("ARCH"), workers = 2L)' - /opt/R/$R_VERSION/bin/R -q -e 'bincraft::process_unarchived_pkgs(Sys.getenv("CODENAME"), Sys.getenv("ARCH"), s3_endpoint = "https://s3.eu-central-003.backblazeb2.com", s3_region = "eu-central-003", s3_bucket = "devxy-rpkgs-binaries", s3_access_key_id = Sys.getenv("B2_S3_ACCESS_KEY"), s3_secret_access_key = Sys.getenv("B2_S3_SECRET_KEY"), workers = 2L)'
backend_options: backend_options:
kubernetes: kubernetes:
resources: resources:

View file

@ -10,11 +10,22 @@ variables:
- arm64 - arm64
default: amd64 default: amd64
OS: OS:
description: 'Base OS image name (e.g. alpine, redhat, ubuntu).' description: "Base OS image name."
options:
- alpine
- redhat
- ubuntu
default: alpine default: alpine
OS_VERSION: OS_VERSION:
description: 'OS version / image tag (e.g. 3.24, 9, jammy, noble).' description: "OS image tag. Must match OS (alpine: 3.24; redhat: 8/9/10; ubuntu: jammy/noble)."
default: '3.24' options:
- "3.24"
- "8"
- "9"
- "10"
- "jammy"
- "noble"
default: "3.24"
R_VERSION: R_VERSION:
description: 'Primary R version under /opt/R.' description: 'Primary R version under /opt/R.'
options: options:
@ -42,6 +53,9 @@ steps:
image: 'reg.devxy.io/rpkgs/build-env-${OS}:${OS_VERSION}' image: 'reg.devxy.io/rpkgs/build-env-${OS}:${OS_VERSION}'
pull: true pull: true
environment: environment:
OTEL_R_TRACES_EXPORTER: none
OTEL_R_LOGS_EXPORTER: none
OTEL_R_METRICS_EXPORTER: none
REPO_RO_TOKEN: REPO_RO_TOKEN:
from_secret: REPO_RO_TOKEN from_secret: REPO_RO_TOKEN
GITHUB_PAT: GITHUB_PAT:
@ -66,8 +80,9 @@ steps:
- rm -rf /mnt/cache/pkgcache/R/pkgcache/_metadata/patched-* /mnt/cache/pkgcache/R/pkgcache/_metadata/pkgs-*.rds || true - rm -rf /mnt/cache/pkgcache/R/pkgcache/_metadata/patched-* /mnt/cache/pkgcache/R/pkgcache/_metadata/pkgs-*.rds || true
- mkdir -p /mnt/cache/pkgcache /mnt/cache/R-pkgs /mnt/cache/ccache /mnt/cache/packages - mkdir -p /mnt/cache/pkgcache /mnt/cache/R-pkgs /mnt/cache/ccache /mnt/cache/packages
- git clone -q https://pat-s:$$REPO_RO_TOKEN@git.devxy.io/devxy/build-cran-binaries.git . - git clone -q https://pat-s:$$REPO_RO_TOKEN@git.devxy.io/devxy/build-cran-binaries.git .
- git clone -q https://codefloe.com/rpkgs/bincraft.git /tmp/bincraft # Pin the same bincraft version the build steps use, so the precomputed
- /opt/R/$R_VERSION/bin/R -q -e 'pak::sysreqs_db_update(); pak::local_install("/tmp/bincraft"); pak::pak(c("RPostgres", "s3fs", "data.table", "future", "jsonlite")); packageVersion("bincraft")' # snapshot and the per-agent library stay consistent across the pipeline.
- /opt/R/$R_VERSION/bin/R -q -e 'pak::sysreqs_db_update(); source("local/install-bincraft.R"); pak::pak(c("RPostgres", "s3fs", "data.table", "future", "jsonlite")); packageVersion("bincraft")'
- /opt/R/$R_VERSION/bin/R -q -e "source('local/packages-to-build.R'); saveRDS(pkgs, '/mnt/cache/packages/pkgs_to_build.rds'); saveRDS(pkgs[r_minor_sensitive == TRUE], '/mnt/cache/packages/r_minor_sensitive_pkgs.rds'); sprintf('Precomputed %s package versions (%s r-minor-sensitive)', nrow(pkgs), nrow(pkgs[r_minor_sensitive == TRUE]))" - /opt/R/$R_VERSION/bin/R -q -e "source('local/packages-to-build.R'); saveRDS(pkgs, '/mnt/cache/packages/pkgs_to_build.rds'); saveRDS(pkgs[r_minor_sensitive == TRUE], '/mnt/cache/packages/r_minor_sensitive_pkgs.rds'); sprintf('Precomputed %s package versions (%s r-minor-sensitive)', nrow(pkgs), nrow(pkgs[r_minor_sensitive == TRUE]))"
backend_options: backend_options:
docker: docker:

View file

@ -11,11 +11,25 @@ variables:
- arm64 - arm64
default: amd64 default: amd64
OS: OS:
description: 'Base OS image name (e.g. alpine, redhat, ubuntu).' description: "Base OS image name."
options:
- alpine
- redhat
- ubuntu
default: alpine default: alpine
OS_VERSION: OS_VERSION:
description: 'OS version / image tag (e.g. 3.24, 9, jammy, noble).' description: "OS image tag. Must match OS (alpine: 3.24; redhat: 8/9/10; ubuntu: jammy/noble)."
default: '3.24' options:
- "3.22"
- "3.23"
- "3.24"
- "8"
- "9"
- "10"
- "jammy"
- "noble"
- "resolute"
default: "3.24"
R_VERSION: R_VERSION:
description: 'Primary R version under /opt/R.' description: 'Primary R version under /opt/R.'
options: options:
@ -76,6 +90,9 @@ steps:
image: 'reg.devxy.io/rpkgs/build-env-${OS}:${OS_VERSION}' image: 'reg.devxy.io/rpkgs/build-env-${OS}:${OS_VERSION}'
pull: true pull: true
environment: environment:
OTEL_R_TRACES_EXPORTER: none
OTEL_R_LOGS_EXPORTER: none
OTEL_R_METRICS_EXPORTER: none
RED_HAT_DEV_PW: RED_HAT_DEV_PW:
from_secret: RED_HAT_DEV_PW from_secret: RED_HAT_DEV_PW
B2_S3_ACCESS_KEY: B2_S3_ACCESS_KEY:
@ -105,6 +122,14 @@ steps:
# growth is bounded separately by trim_pkgcache_metadata() in build-all.R. # growth is bounded separately by trim_pkgcache_metadata() in build-all.R.
- rm -rf /mnt/cache/pkgcache/R/pkgcache/_metadata/patched-* /mnt/cache/pkgcache/R/pkgcache/_metadata/pkgs-*.rds || true - rm -rf /mnt/cache/pkgcache/R/pkgcache/_metadata/patched-* /mnt/cache/pkgcache/R/pkgcache/_metadata/pkgs-*.rds || true
- mkdir -p /mnt/cache/pkgcache /mnt/cache/R-pkgs /mnt/cache/ccache /mnt/cache/packages - mkdir -p /mnt/cache/pkgcache /mnt/cache/R-pkgs /mnt/cache/ccache /mnt/cache/packages
# The primary pass must not rely on build-all-versions-install-deps having
# run on *this* agent: depends_on only orders the steps, but the cache
# volume is per-agent, so a job landing on an agent where install-deps did
# not run would otherwise use a stale bincraft (which resolves `platform`
# to a zero-length value and breaks every metadata query and the sysdeps
# install). Pin bincraft here, exactly like the R-minor pass below.
- rm -rf /mnt/cache/R-pkgs/00LOCK-*
- /opt/R/$R_VERSION/bin/Rscript local/install-bincraft.R
- XVFB=$(command -v xwfb-run 2>/dev/null || command -v xvfb-run); XVFB_ARGS=""; if command -v xwfb-run >/dev/null 2>&1; then dnf install -y -q weston 2>/dev/null; XVFB_ARGS="-c weston"; fi - XVFB=$(command -v xwfb-run 2>/dev/null || command -v xvfb-run); XVFB_ARGS=""; if command -v xwfb-run >/dev/null 2>&1; then dnf install -y -q weston 2>/dev/null; XVFB_ARGS="-c weston"; fi
- $XVFB $XVFB_ARGS -n $SPLIT_INDEX -- /opt/R/$R_VERSION/bin/Rscript local/build-all.R $SPLIT_INTO $SPLIT_INDEX $NCPUS 2>&1 - $XVFB $XVFB_ARGS -n $SPLIT_INDEX -- /opt/R/$R_VERSION/bin/Rscript local/build-all.R $SPLIT_INTO $SPLIT_INDEX $NCPUS 2>&1
- | - |
@ -116,11 +141,12 @@ steps:
echo "=== R-minor-sensitive pass under R $RV ===" echo "=== R-minor-sensitive pass under R $RV ==="
LIB="/mnt/cache/R-pkgs-$RMINOR" LIB="/mnt/cache/R-pkgs-$RMINOR"
mkdir -p "$LIB" mkdir -p "$LIB"
R_LIBS_USER="$LIB" "$(dirname "$RBIN")/R" -q -e 'if (!requireNamespace("bincraft", quietly = TRUE) || packageVersion("bincraft") != "4.2.2") pak::pak("git::https://codefloe.com/rpkgs/bincraft.git@v4.2.2")' || true R_LIBS_USER="$LIB" "$(dirname "$RBIN")/Rscript" local/install-bincraft.R || true
R_LIBS_USER="$LIB" $XVFB $XVFB_ARGS -n $SPLIT_INDEX -- "$(dirname "$RBIN")/Rscript" local/build-all.R --sensitive-only $SPLIT_INTO $SPLIT_INDEX $NCPUS 2>&1 || true R_LIBS_USER="$LIB" $XVFB $XVFB_ARGS -n $SPLIT_INDEX -- "$(dirname "$RBIN")/Rscript" local/build-all.R --sensitive-only $SPLIT_INTO $SPLIT_INDEX $NCPUS 2>&1 || true
done done
# archive missed packages # archive missed packages; first arg is the codename (e.g. "alpine324"),
- /opt/R/$R_VERSION/bin/R -q -e "bincraft::process_unarchived_pkgs(paste(Sys.getenv('OS'), Sys.getenv('OS_VERSION')), Sys.getenv('ARCH'), workers = $NCPUS)" # derived via bincraft like the upload step, not paste(OS, OS_VERSION).
- /opt/R/$R_VERSION/bin/R -q -e "bincraft::process_unarchived_pkgs(bincraft::set_codename(NULL), Sys.getenv('ARCH'), s3_endpoint = 'https://s3.eu-central-003.backblazeb2.com', s3_region = 'eu-central-003', s3_bucket = 'devxy-rpkgs-binaries', s3_access_key_id = Sys.getenv('B2_S3_ACCESS_KEY'), s3_secret_access_key = Sys.getenv('B2_S3_SECRET_KEY'), workers = $NCPUS)"
backend_options: backend_options:
docker: docker:
resources: resources:
@ -134,6 +160,9 @@ steps:
image: 'reg.devxy.io/rpkgs/build-env-${OS}:${OS_VERSION}' image: 'reg.devxy.io/rpkgs/build-env-${OS}:${OS_VERSION}'
pull: true pull: true
environment: environment:
OTEL_R_TRACES_EXPORTER: none
OTEL_R_LOGS_EXPORTER: none
OTEL_R_METRICS_EXPORTER: none
B2_S3_ACCESS_KEY: B2_S3_ACCESS_KEY:
from_secret: B2_S3_ACCESS_KEY from_secret: B2_S3_ACCESS_KEY
B2_S3_SECRET_KEY: B2_S3_SECRET_KEY:

View file

@ -15,6 +15,8 @@ variables:
- alpine-322-arm64 - alpine-322-arm64
- alpine-323-amd64 - alpine-323-amd64
- alpine-323-arm64 - alpine-323-arm64
- alpine-324-amd64
- alpine-324-arm64
- redhat-8-amd64 - redhat-8-amd64
- redhat-8-arm64 - redhat-8-arm64
- redhat-9-amd64 - redhat-9-amd64
@ -25,6 +27,8 @@ variables:
- ubuntu-2204-arm64 - ubuntu-2204-arm64
- ubuntu-2404-amd64 - ubuntu-2404-amd64
- ubuntu-2404-arm64 - ubuntu-2404-arm64
- ubuntu-2604-amd64
- ubuntu-2604-arm64
default: all default: all
when: when:
@ -64,6 +68,18 @@ matrix:
IMG: alpine:3.24 IMG: alpine:3.24
OS_ID: alpine323 OS_ID: alpine323
PROCESS_NEW: "FALSE" PROCESS_NEW: "FALSE"
- OS: alpine-324
ARCH: amd64
R_VERSION: 4.5.3
IMG: alpine:3.24
OS_ID: alpine324
PROCESS_NEW: "FALSE"
- OS: alpine-324
ARCH: arm64
R_VERSION: 4.5.3
IMG: alpine:3.24
OS_ID: alpine324
PROCESS_NEW: "FALSE"
- OS: redhat-8 - OS: redhat-8
ARCH: amd64 ARCH: amd64
R_VERSION: 4.4.3 R_VERSION: 4.4.3
@ -124,12 +140,27 @@ matrix:
IMG: ubuntu:noble IMG: ubuntu:noble
OS_ID: noble OS_ID: noble
PROCESS_NEW: "TRUE" PROCESS_NEW: "TRUE"
- OS: ubuntu-2604
ARCH: amd64
R_VERSION: 4.5.3
IMG: ubuntu:resolute
OS_ID: resolute
PROCESS_NEW: "TRUE"
- OS: ubuntu-2604
ARCH: arm64
R_VERSION: 4.5.3
IMG: ubuntu:resolute
OS_ID: resolute
PROCESS_NEW: "TRUE"
steps: steps:
- name: 'Processing Updates' - name: 'Processing Updates'
image: reg.devxy.io/rpkgs/build-env-${IMG} image: reg.devxy.io/rpkgs/build-env-${IMG}
pull: true pull: true
environment: environment:
OTEL_R_TRACES_EXPORTER: none
OTEL_R_LOGS_EXPORTER: none
OTEL_R_METRICS_EXPORTER: none
RED_HAT_DEV_PW: RED_HAT_DEV_PW:
from_secret: RED_HAT_DEV_PW from_secret: RED_HAT_DEV_PW
B2_S3_ACCESS_KEY: B2_S3_ACCESS_KEY:
@ -164,13 +195,13 @@ steps:
commands: commands:
- git clone -q https://pat-s:$$REPO_RO_TOKEN@git.devxy.io/devxy/build-cran-binaries.git . - git clone -q https://pat-s:$$REPO_RO_TOKEN@git.devxy.io/devxy/build-cran-binaries.git .
- rm -rf /mnt/cache/R-pkgs/00LOCK-* /mnt/cache/R-pkgs/bincraft /mnt/cache/R-pkgs/pkgcache /mnt/cache/pkgcache/R/pkgcache - rm -rf /mnt/cache/R-pkgs/00LOCK-* /mnt/cache/R-pkgs/bincraft /mnt/cache/R-pkgs/pkgcache /mnt/cache/pkgcache/R/pkgcache
- /opt/R/$R_VERSION/bin/R -q -e 'if (!requireNamespace("bincraft", quietly = TRUE) || packageVersion("bincraft") != "4.2.2") pak::pak("git::https://codefloe.com/rpkgs/bincraft.git@v4.2.2")' - /opt/R/$R_VERSION/bin/Rscript local/install-bincraft.R
- /opt/R/$R_VERSION/bin/R -q -e 'packageVersion("bincraft")' - /opt/R/$R_VERSION/bin/R -q -e 'packageVersion("bincraft")'
- mkdir -p /mnt/cache/pkgcache /mnt/cache/R-pkgs /mnt/cache/ccache /mnt/cache/packages - mkdir -p /mnt/cache/pkgcache /mnt/cache/R-pkgs /mnt/cache/ccache /mnt/cache/packages
# rhel-10 ships xwfb-run (Xwayland) instead of xvfb-run; prefer it and start weston, else fall back to xvfb-run # rhel-10 ships xwfb-run (Xwayland) instead of xvfb-run; prefer it and start weston, else fall back to xvfb-run
- XVFB=$(command -v xwfb-run 2>/dev/null || command -v xvfb-run); XVFB_ARGS=""; if command -v xwfb-run >/dev/null 2>&1; then dnf install -y -q weston 2>/dev/null; XVFB_ARGS="-c weston"; fi - XVFB=$(command -v xwfb-run 2>/dev/null || command -v xvfb-run); XVFB_ARGS=""; if command -v xwfb-run >/dev/null 2>&1; then dnf install -y -q weston 2>/dev/null; XVFB_ARGS="-c weston"; fi
# options(future.globals.onReference = NULL): for some reason s3fs::file_delete() throws 'Error: Detected a non-exportable reference ('externalptr') in one of the globals ('FUN' of class 'function') used in the future expression' otherwise # options(future.globals.onReference = NULL): for some reason s3fs::file_delete() throws 'Error: Detected a non-exportable reference ('externalptr') in one of the globals ('FUN' of class 'function') used in the future expression' otherwise
- $XVFB $XVFB_ARGS -- /opt/R/$R_VERSION/bin/R -q -e "options(crayon.enabled = TRUE, Ncpus = 4, future.globals.onReference = 'error', repos = structure(c(getOption('repos'),INLA='https://inla.r-inla-download.org/R/stable'))); progressr::handlers('cli'); progressr::handlers(global = TRUE); options(future.globals.onReference = NULL); bincraft::process_cran_updates(interval = $INTERVAL, platform = '${OS}', process_updated = TRUE, process_new = ${PROCESS_NEW}, process_removed = TRUE, r_minor_detection = 'classifier', s3_endpoint = 'https://s3.eu-central-003.backblazeb2.com', s3_region = 'eu-central-003', s3_bucket = 'devxy-rpkgs-binaries', s3_access_key_id = Sys.getenv('B2_S3_ACCESS_KEY'), s3_secret_access_key = Sys.getenv('B2_S3_SECRET_KEY'), metadata_db_host = 'r-binaries.devxy.io', metadata_db_name = 'build_metadata', metadata_db_table = 'single_builds', metadata_db_user = 'rpkgs', metadata_db_password = Sys.getenv('PGPASS'), metadata_db_sslmode = 'require', metadata_db_port = 15432, archive = TRUE, upload = TRUE, store_build_metadata = TRUE)" - $XVFB $XVFB_ARGS -- /opt/R/$R_VERSION/bin/R -q -e "options(crayon.enabled = TRUE, Ncpus = 4, future.globals.onReference = 'error', repos = structure(c(getOption('repos'),INLA='https://inla.r-inla-download.org/R/stable'))); progressr::handlers('cli'); progressr::handlers(global = TRUE); options(future.globals.onReference = NULL); bincraft::process_cran_updates(interval = $INTERVAL, platform = '${OS}', process_updated = TRUE, process_new = ${PROCESS_NEW}, process_removed = TRUE, patches = 'local/patches', r_minor_detection = 'classifier',s3_endpoint = 'https://s3.eu-central-003.backblazeb2.com', s3_region = 'eu-central-003', s3_bucket = 'devxy-rpkgs-binaries', s3_access_key_id = Sys.getenv('B2_S3_ACCESS_KEY'), s3_secret_access_key = Sys.getenv('B2_S3_SECRET_KEY'), metadata_db_host = 'r-binaries.devxy.io', metadata_db_name = 'build_metadata', metadata_db_table = 'single_builds', metadata_db_user = 'rpkgs', metadata_db_password = Sys.getenv('PGPASS'), metadata_db_sslmode = 'require', metadata_db_port = 15432, archive = TRUE, upload = TRUE, store_build_metadata = TRUE)"
- | - |
PRIMARY_MINOR=$(echo "$R_VERSION" | cut -d. -f1-2) PRIMARY_MINOR=$(echo "$R_VERSION" | cut -d. -f1-2)
for RBIN in /opt/R/[0-9]*/bin/R; do for RBIN in /opt/R/[0-9]*/bin/R; do
@ -180,8 +211,8 @@ steps:
echo "=== R-minor-sensitive update pass under R $RV ===" echo "=== R-minor-sensitive update pass under R $RV ==="
LIB="/mnt/cache/R-pkgs-$RMINOR" LIB="/mnt/cache/R-pkgs-$RMINOR"
mkdir -p "$LIB" mkdir -p "$LIB"
R_LIBS_USER="$LIB" "$(dirname "$RBIN")/R" -q -e 'if (!requireNamespace("bincraft", quietly = TRUE) || packageVersion("bincraft") != "4.2.2") pak::pak("git::https://codefloe.com/rpkgs/bincraft.git@v4.2.2")' || true R_LIBS_USER="$LIB" "$(dirname "$RBIN")/Rscript" local/install-bincraft.R || true
R_LIBS_USER="$LIB" $XVFB $XVFB_ARGS -- "$(dirname "$RBIN")/R" -q -e "options(crayon.enabled = TRUE, Ncpus = 4, future.globals.onReference = NULL); bincraft::process_cran_updates(interval = $INTERVAL, platform = '${OS}', process_updated = TRUE, process_new = FALSE, process_removed = FALSE, r_minor_detection = 'classifier', r_minor_sensitive_only = TRUE, s3_endpoint = 'https://s3.eu-central-003.backblazeb2.com', s3_region = 'eu-central-003', s3_bucket = 'devxy-rpkgs-binaries', s3_access_key_id = Sys.getenv('B2_S3_ACCESS_KEY'), s3_secret_access_key = Sys.getenv('B2_S3_SECRET_KEY'), metadata_db_host = 'r-binaries.devxy.io', metadata_db_name = 'build_metadata', metadata_db_table = 'single_builds', metadata_db_user = 'rpkgs', metadata_db_password = Sys.getenv('PGPASS'), metadata_db_sslmode = 'require', metadata_db_port = 15432, archive = TRUE, upload = TRUE, store_build_metadata = TRUE)" || true R_LIBS_USER="$LIB" $XVFB $XVFB_ARGS -- "$(dirname "$RBIN")/R" -q -e "options(crayon.enabled = TRUE, Ncpus = 4, future.globals.onReference = NULL); bincraft::process_cran_updates(interval = $INTERVAL, platform = '${OS}', process_updated = TRUE, process_new = FALSE, process_removed = FALSE, patches = 'local/patches', r_minor_detection = 'classifier',r_minor_sensitive_only = TRUE, s3_endpoint = 'https://s3.eu-central-003.backblazeb2.com', s3_region = 'eu-central-003', s3_bucket = 'devxy-rpkgs-binaries', s3_access_key_id = Sys.getenv('B2_S3_ACCESS_KEY'), s3_secret_access_key = Sys.getenv('B2_S3_SECRET_KEY'), metadata_db_host = 'r-binaries.devxy.io', metadata_db_name = 'build_metadata', metadata_db_table = 'single_builds', metadata_db_user = 'rpkgs', metadata_db_password = Sys.getenv('PGPASS'), metadata_db_sslmode = 'require', metadata_db_port = 15432, archive = TRUE, upload = TRUE, store_build_metadata = TRUE)" || true
done done
- /opt/R/$R_VERSION/bin/R -q -e 'library(bincraft); upload_package_index(codename = "${OS_ID}", s3_endpoint = "https://s3.eu-central-003.backblazeb2.com", s3_region = "eu-central-003", s3_bucket = "devxy-rpkgs-binaries", s3_access_key_id = Sys.getenv("B2_S3_ACCESS_KEY"), s3_secret_access_key = Sys.getenv("B2_S3_SECRET_KEY"))' - /opt/R/$R_VERSION/bin/R -q -e 'library(bincraft); upload_package_index(codename = "${OS_ID}", s3_endpoint = "https://s3.eu-central-003.backblazeb2.com", s3_region = "eu-central-003", s3_bucket = "devxy-rpkgs-binaries", s3_access_key_id = Sys.getenv("B2_S3_ACCESS_KEY"), s3_secret_access_key = Sys.getenv("B2_S3_SECRET_KEY"))'
- | - |
@ -202,6 +233,9 @@ steps:
- name: Purge CDN cache - name: Purge CDN cache
image: reg.devxy.io/docker.io/library/alpine:3.24 image: reg.devxy.io/docker.io/library/alpine:3.24
environment: environment:
OTEL_R_TRACES_EXPORTER: none
OTEL_R_LOGS_EXPORTER: none
OTEL_R_METRICS_EXPORTER: none
BUNNYNET_API_KEY: BUNNYNET_API_KEY:
from_secret: BUNNYNET_API_KEY from_secret: BUNNYNET_API_KEY
SUBDOMAIN1: 'cran.devxy.io' SUBDOMAIN1: 'cran.devxy.io'

View file

@ -103,6 +103,9 @@ steps:
image: reg.devxy.io/rpkgs/build-env-${IMG} image: reg.devxy.io/rpkgs/build-env-${IMG}
pull: true pull: true
environment: environment:
OTEL_R_TRACES_EXPORTER: none
OTEL_R_LOGS_EXPORTER: none
OTEL_R_METRICS_EXPORTER: none
RED_HAT_DEV_PW: RED_HAT_DEV_PW:
from_secret: RED_HAT_DEV_PW from_secret: RED_HAT_DEV_PW
B2_S3_ACCESS_KEY: B2_S3_ACCESS_KEY:
@ -129,12 +132,12 @@ steps:
- git clone -q https://pat-s:$$REPO_RO_TOKEN@git.devxy.io/devxy/build-cran-binaries.git . - git clone -q https://pat-s:$$REPO_RO_TOKEN@git.devxy.io/devxy/build-cran-binaries.git .
- mkdir -p /mnt/cache/pkgcache /mnt/cache/R-pkgs /mnt/cache/ccache /mnt/cache/packages - mkdir -p /mnt/cache/pkgcache /mnt/cache/R-pkgs /mnt/cache/ccache /mnt/cache/packages
- rm -rf /mnt/cache/R-pkgs/00LOCK-* - rm -rf /mnt/cache/R-pkgs/00LOCK-*
- /opt/R/$R_VERSION/bin/R -q -e 'if (!requireNamespace("bincraft", quietly = TRUE) || packageVersion("bincraft") != "4.2.2") pak::pak("git::https://codefloe.com/rpkgs/bincraft.git@v4.2.2")' - /opt/R/$R_VERSION/bin/Rscript local/install-bincraft.R
- /opt/R/$R_VERSION/bin/R -q -e 'packageVersion("bincraft")' - /opt/R/$R_VERSION/bin/R -q -e 'packageVersion("bincraft")'
- XVFB=$(command -v xwfb-run 2>/dev/null || command -v xvfb-run); XVFB_ARGS=""; if command -v xwfb-run >/dev/null 2>&1; then dnf install -y -q weston 2>/dev/null; XVFB_ARGS="-c weston"; fi - XVFB=$(command -v xwfb-run 2>/dev/null || command -v xvfb-run); XVFB_ARGS=""; if command -v xwfb-run >/dev/null 2>&1; then dnf install -y -q weston 2>/dev/null; XVFB_ARGS="-c weston"; fi
- /opt/R/$R_VERSION/bin/R -q -e 'pak::pak("httr2")' - /opt/R/$R_VERSION/bin/R -q -e 'pak::pak("httr2")'
- /opt/R/$R_VERSION/bin/R -q -e 'source("local/fetch-rebuild-packages-from-issue.R")' - /opt/R/$R_VERSION/bin/R -q -e 'source("local/fetch-rebuild-packages-from-issue.R")'
- $XVFB $XVFB_ARGS -- /opt/R/$R_VERSION/bin/R -q -e "sink(stdout(), type = 'message'); options(crayon.enabled = TRUE, Ncpus = $NCPUS, future.globals.onReference = NULL); pkgs <- readLines('/tmp/rebuild_pkgs.txt'); if (length(pkgs) == 0) { cat('Nothing to rebuild\n'); q('no') }; excluded <- jsonlite::fromJSON('local/excluded-packages.json')[['package']]; pkgs <- setdiff(pkgs, excluded); cat(sprintf('Rebuilding %d packages\n', length(pkgs))); n <- length(pkgs); for (i in seq_along(pkgs)) { x <- pkgs[i]; cat(sprintf('[%d/%d] %s\n', i, n, x)); tryCatch(bincraft::build_binary_package(x, tag_limit = 1L, s3_endpoint = 'https://s3.eu-central-003.backblazeb2.com', s3_region = 'eu-central-003', s3_bucket = 'devxy-rpkgs-binaries', s3_access_key_id = Sys.getenv('B2_S3_ACCESS_KEY'), s3_secret_access_key = Sys.getenv('B2_S3_SECRET_KEY'), metadata_db_host = 'r-binaries.devxy.io', metadata_db_name = 'build_metadata', metadata_db_table = 'single_builds', metadata_db_user = 'rpkgs', metadata_db_password = Sys.getenv('PGPASS'), metadata_db_sslmode = 'require', metadata_db_port = 15432, archive = TRUE, upload = TRUE, store_build_metadata = TRUE), error = function(e) cat(sprintf('ERROR building %s - %s\n', x, conditionMessage(e)))) }" 2>&1 - $XVFB $XVFB_ARGS -- /opt/R/$R_VERSION/bin/R -q -e "sink(stdout(), type = 'message'); options(crayon.enabled = TRUE, Ncpus = $NCPUS, future.globals.onReference = NULL); pkgs <- readLines('/tmp/rebuild_pkgs.txt'); if (length(pkgs) == 0) { cat('Nothing to rebuild\n'); q('no') }; excluded <- jsonlite::fromJSON('local/excluded-packages.json')[['package']]; pkgs <- setdiff(pkgs, excluded); cat(sprintf('Rebuilding %d packages\n', length(pkgs))); n <- length(pkgs); for (i in seq_along(pkgs)) { x <- pkgs[i]; cat(sprintf('[%d/%d] %s\n', i, n, x)); tryCatch(bincraft::build_binary_package(x, tag_limit = 1L, patches = 'local/patches', s3_endpoint = 'https://s3.eu-central-003.backblazeb2.com', s3_region = 'eu-central-003', s3_bucket = 'devxy-rpkgs-binaries', s3_access_key_id = Sys.getenv('B2_S3_ACCESS_KEY'), s3_secret_access_key = Sys.getenv('B2_S3_SECRET_KEY'), metadata_db_host = 'r-binaries.devxy.io', metadata_db_name = 'build_metadata', metadata_db_table = 'single_builds', metadata_db_user = 'rpkgs', metadata_db_password = Sys.getenv('PGPASS'), metadata_db_sslmode = 'require', metadata_db_port = 15432, archive = TRUE, upload = TRUE, store_build_metadata = TRUE), error = function(e) cat(sprintf('ERROR building %s - %s\n', x, conditionMessage(e)))) }" 2>&1
backend_options: backend_options:
docker: docker:
resources: resources:

3
.gitignore vendored
View file

@ -99,3 +99,6 @@ docs/
local/test.R local/test.R
.DS_Store .DS_Store
docs/ docs/
# Superpowers SDD scratch (briefs, reports, ledger)
.superpowers/

View file

@ -2,3 +2,6 @@
ignores: ignores:
- LICENSE.md - LICENSE.md
- docs/superpowers/** - docs/superpowers/**
# Internal design docs (specs/plans) are not user-facing reference material.
- specs/**
- plans/**

View file

@ -16,19 +16,19 @@ repos:
args: args:
- --markdown-linebreak-ext=md - --markdown-linebreak-ext=md
- repo: https://github.com/DavidAnson/markdownlint-cli2 - repo: https://github.com/DavidAnson/markdownlint-cli2
rev: v0.22.1 rev: v0.23.0
hooks: hooks:
- id: markdownlint-cli2 - id: markdownlint-cli2
- repo: https://github.com/rbubley/mirrors-prettier - repo: https://github.com/rbubley/mirrors-prettier
rev: v3.8.4 rev: v3.9.4
hooks: hooks:
- id: prettier - id: prettier
- repo: https://github.com/posit-dev/air-pre-commit - repo: https://github.com/posit-dev/air-pre-commit
rev: 0.9.0 rev: 0.10.0
hooks: hooks:
- id: air-format - id: air-format
- repo: https://github.com/editorconfig-checker/editorconfig-checker - repo: https://github.com/editorconfig-checker/editorconfig-checker
rev: v3.7.0 rev: v3.8.0
hooks: hooks:
- id: editorconfig-checker - id: editorconfig-checker
- repo: https://github.com/adrienverge/yamllint.git - repo: https://github.com/adrienverge/yamllint.git
@ -43,3 +43,9 @@ repos:
entry: YAML filenames must have .yaml extension. entry: YAML filenames must have .yaml extension.
language: fail language: fail
files: .yml$ files: .yml$
- id: validate-patches
name: validate patch registry
entry: Rscript local/validate-patches.R
language: system
files: ^local/(patches/|validate-patches\.R$)
pass_filenames: false

72
.terraform.lock.hcl generated
View file

@ -38,43 +38,43 @@ provider "registry.opentofu.org/hashicorp/http" {
} }
provider "registry.terraform.io/bunnyway/bunnynet" { provider "registry.terraform.io/bunnyway/bunnynet" {
version = "0.14.3" version = "0.15.1"
constraints = "~> 0.14" constraints = "~> 0.15"
hashes = [ hashes = [
"h1:2VmbbvV/3fVb/dHZ5m3CxSPoptpn/PuhvSgV/RA9Ae8=", "h1:/2NUpbtjkc+w6n5V3kGP0rSzGjN0K2Wdfe2K+CZdmhU=",
"h1:4MANuttWPyJGZlfbx5P4i2Jpbmvda1tfWgd3olK2nhY=", "h1:1TOrpmCR0aT5xX1sjt70zqlYkMJnVe6r0nx2B0DS/mE=",
"h1:AsSfDvm6flYQgjFnFVaRPv7v1/P5pj36dQ4N103Nw+A=", "h1:4uC8r8ILr+vZJ230uGqIUaWQ7uORCrIzoEuYrAq2JuE=",
"h1:D2AK5psWQmZqrOHsbeV70OP/zcG92i++AmGKBz/HVMA=", "h1:6b+2osJUfwcaYZ6mathLPf/58sr/4XkLXQrcSufnkMk=",
"h1:DpJWi/bhHoZa/ccy2YB/c7HJjTlR6CuZBxGFCxU2uJk=", "h1:CPldfjf79QS8mIP+GWoS0FVhrFlyjvN2+39zfyP76Ik=",
"h1:Iz47FCzHBOZC1RrTxKwJwKsH6bdEvdYtO0+RBpbmz8I=", "h1:EvXICHyGIKpoYlDeKHOPzfmpvdRdhgsOMcR2nb6+tKY=",
"h1:RJQm4qEfljAmcJaFf45uXwUhtbRTwfDuiUWZ6Q7X+Cw=", "h1:GZLq+nDxS1CyBH0ELGTSQj9X7ozemJ1jpPA4KwbtR+c=",
"h1:YQBi0MRW+dOfkxQYbjKkzDm7UIcc2FeFm8Cck+W3kgs=", "h1:ISNFqL745IQgZ6yMLy8ofV8ixbYqZYa9JKdi2W3pmNk=",
"h1:bWq/zJ2Chr5TNuz9y3eaGmzrmXsX30pl5HkGpxE1kVM=", "h1:IrNrEuvFd0nYDGQefwmT8d1CSJb9e8LN5w9vw1ODp7E=",
"h1:hwzEskDnFHaJFvKNAGv/wIxRT2SHcXLfwmBb8XNspq4=", "h1:Ms79slY9bZ94+n4cwIHvI9+/cvbucwo6S1+z5KAiznw=",
"h1:jGggry0lZmG0S0inM7Odae3275na9Gp3O97ZlvBiA2s=", "h1:NWA9XSEBcpSkgwwIvl6tHrxGQY3uYhqNS4Vnb9RLyLQ=",
"h1:mJdpVc9qOpqXcPpptWfAET8qloo6qFMb+NzHesazybk=", "h1:UjvxxxggicLtiE3yTe1Gx0oLUTeZpWmgIfXuHzWHn1c=",
"h1:nbpkaopSGlmxkKLtNe9sKx9IqojoicD1+hNRdaYd5ok=", "h1:VgJjo14DGkU4Jwo4D3GT4/5sq1tdjiZscKS5l3cb890=",
"h1:pwuoUqikuVOut3RtPTnu6pNoDnyeXlEX7Rfb2Hr1Ch0=", "h1:dBu3AW5YNLIvbBIMNk3wUHKw4TW+BDbj34a+mCqYhWE=",
"h1:u0naFiWGrBVhI3AsUb/ZfS5N/GeiRk0ZkxjHtA10lF0=", "h1:i5oGD06nQ3JRsBIa2u4wCej+ETgp970CFl75dOKkHno=",
"h1:uozoSPzZ7MJIHj5O62W8n86NIfH4JtF7GvMNI6rKlrM=", "h1:mTqR+vD1AWPx+mu7S0/pzBy71z7WOrjH7arOP77PXh4=",
"h1:vDS308OeXVVgjojMCAAEQ1VshmOLjwra7obliKB5fv8=", "h1:nmTM61G8vYjpofeEqspMORpsNvTGCNZySGfjdXardL0=",
"zh:23200ad919df4c44a720c667c536d3a0ae0c235e1f7b53b9e56f88005bf01891", "zh:0f9bf5aaa47164a4d6ae4433d5e285a9456a5053401b2bad4ed68622f574ddee",
"zh:2fe5445f578c6a244995538fde6dd7ef0dd5f3969686cba3d91fcf28ea31278d", "zh:3039bee421fb8855a919f449fc731d145254371f5f0c39cc4660f3aeed6a8b10",
"zh:3a5a8139ed177ccbee74feb4d19c881e18723e4bf3a64b6d35931420402a2a1a", "zh:36664b08186e0c194747b18dee24ed97327c6e704133d4cf0df27abef1652f86",
"zh:5189bd6c03ec3c428185992f519f3bf520d4e9eba8771c240814adbecdf60140", "zh:3c7eae99d8c5ff65dfb99c8b9c1980147282d68971e1ef1ff0f126a6bff59d8f",
"zh:532ac8eb94a84ccf046d4cb4eded825269effdbb7597f392f848fbfad5dcae1d", "zh:5293cc21abf54f4e5745437ca2d40d206aae323b2e1d41cf45dcc63a8868cbb3",
"zh:5f100279d73ce998c7bf4ffa2bbcd617ee307bf51c4a94146f210aeec268c4d0", "zh:5994e5145e616e7e881010717e4c7def2945eb6d933f62db4ec3167732ccac84",
"zh:80cb58abd2e431386ab1b6ad186a6e6e5347448993bacc831c0251b9016445b9", "zh:7994db9ed3fdb6cbf21f2154ea962cf82f04e425988bedc6657de2497d6cb6c3",
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f", "zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
"zh:9ac734c6aae19ea0832269f1f1dc3c3e100855c09b6168eecd8693958515b228", "zh:93aa863e536ba9376ccf9e614e9edc9b214a2ce8c4316d416a8e249b436f52d2",
"zh:a0e3b75176c71e5f41a6552cef57ad67d11778cb59fd2eb792e69f662b67ae01", "zh:ab5cb4baeda57559686a0ccf0e09158aa64624ee6ba0ef32b769f13b11a43068",
"zh:b4d0e1dd9a80d1ac9a3f1beaefb58d4b944cb0a30bdc672b9037a69b4dc20ec3", "zh:ae9388b62eede8fd9272407bf75f8241a965bd489d45ec9dd3f9fac696d500e1",
"zh:b8309337e966528991cc2dd61ff0247864e4c3c7bef7dcf225f066edb6171050", "zh:caa5befd16960e2f69c7ec483e228e5ff43ab0979c17f1b874c9ffaa1c7c0e43",
"zh:c34ce5fcdd481214697505bceb616a7dfcda7702f1afefa7dc5459965b8e01ca", "zh:cddd3e1067defa06a4e4ad5cb3940c7943e29c42417de57236aa7d3e2aeaae13",
"zh:cb3f662ad06bb86aa763a5644ba318bc3db0ed30b04eb810c478e81f4b012d55", "zh:cdfa44d591d0805116159556947904d70f534c6816188c45cf3a7544d2722ac9",
"zh:cf0f0a459e2b6b1e014af9f53f32b5f555a249b61a0dcaccd3e4fe89178d8aa5", "zh:d607e9f1f3e09f13404f219e1893e3b3c77aece4afb54e999f934c021f41f576",
"zh:d4dfb653a0295bfbbebcb4bb022b490f2c24ca31287ebf77fe9dcaee2e5ea658", "zh:d8a397aca95125c6a0c0c78d2ded5843b9204effa9f5cf7419f017b500ad9228",
"zh:e49ba31aa092a30ea8a1091f7b26dbe41c3998f924f5b0d82810f27fc2f63501", "zh:f5499eaff0d221725ad209d27d87c5b46d5c554caad7dc42947c760377abe3b0",
"zh:ea4d7d5688caf2f9cda3a1721779b61a051db6b43ca7267ae2712bd1262cfcfd", "zh:fc5f5cf433abc83e5169fa222992ec521c0c802075970251e3dd2c1d50c4f5c1",
] ]
} }

14
CLAUDE.md Normal file
View file

@ -0,0 +1,14 @@
# CLAUDE.md
Crow CI pipelines (`.crow/`) and local tooling (`local/`) that build CRAN binary packages (incl. Alpine/musl) and upload them to Backblaze B2.
## Conventions
- **PRs:** the remote is Forgejo on `codefloe.com`; use `fj -H codefloe.com` (not `gh`).
- **Storage:** Backblaze B2 bucket `devxy-r-builds` (endpoints configured in the `.crow/` pipelines).
## Gotchas
- **B2 requires authentication for the list-bucket API.** Anonymous GET only works for individual public-read objects — an empty listing means missing credentials, not an empty bucket.
- Weekly-rebuild pipelines run for hours; watch them as background tasks and fetch Crow logs yourself instead of having the user paste progress.
- musl builds of packages with bundled native deps (e.g. RcppParallel/TBB) recur as failures; check for an existing patch before re-deriving a fix.

View file

@ -53,6 +53,28 @@ For every package+tag combination:
1. Archive old package versions and keep the latest one in the root 1. Archive old package versions and keep the latest one in the root
1. Delete local binaries after successful upload 1. Delete local binaries after successful upload
## Patching packages
Some CRAN packages fail to compile on specific platforms due to compiler- or OS-specific issues unrelated to the package itself.
The canonical example is `RcppParallel`, whose bundled TBB sources fail on musl (Alpine) and newer compiler/OS combinations.
Because such packages are often transitive dependencies of many others, a single failure cascades: all dependents fail even though nothing is wrong with the dependent itself.
To address this, frequently-failing packages can be "patched" before they are installed — whether as a direct build target or a transitive dependency pulled in by `pak`.
The patch registry lives in `local/patches/registry.json`.
Each entry specifies a package and the platforms/versions it applies to, along with either lightweight build-time overrides (environment variables, configure arguments, Makevars) or a source diff (for deeper fixes).
See `local/patches/README.md` for the complete schema.
Patching uses a two-tier approach:
1. **Lightweight overrides:** environment variables, configure arguments, or Makevars settings applied during build — typically version-independent and fast.
2. **Source diffs:** unified diff patches applied to the unpacked source before building — more powerful but version-pinned.
The system is implemented in `bincraft`: when a package needs patching, `bincraft` pre-builds it with the patch and serves the patched binary to `pak`, ensuring transitive dependents receive the fixed package.
This way, the fix cascades to all packages that depend on it.
For the design rationale and architecture, see `specs/2026-06-30-package-patching-design.md`.
## Build Environment ## Build Environment
Binaries are built on a mixed-architecture Kubernetes cluster using CI. Binaries are built on a mixed-architecture Kubernetes cluster using CI.
@ -199,7 +221,7 @@ Tag does not have a NAMESPACE file and hence cannot be built.
Dependency not available: Either because the dependency was not declared or errored itself during installation. Dependency not available: Either because the dependency was not declared or errored itself during installation.
```text ```text
In function '\033[01m\033[KRcpp::List solveRRBLUP(const mat&, const mat&, const mat&)\033[m\033[K':\n\033[01m\033[KMME.cpp:162:61:\033[m\033[K \033[01;31m\033[Kerror: \033[m\033[K'\033[01m\033[KPI\033[m\033[K' was not declared in this scope\n 162 | double ll = -0.5*(double(optRes[\"objective\"])+df+df*log(2*\033[01;31m\033[KPI\033[m\033[K/df));\n | \033[01;31m\033[K^~\033[m\033[K\n\033[01m\033[KMME.cpp:\033[m\033[K In function '\033[01m\033[KRcpp::List solveRRBLUPMV(const mat&, const mat&, const mat&, int, double)\033[m\033[K':\n\033[01m\033[KMME.cpp:277:31:\033[m\033[K \033[01;31m\033[Kerror: \033[m\033[K'\033[01m\033[KPI\033[m\033[K' was not declared in this scope; did you mean '\033[01m\033[KHI\033[m\033[K'?\n 277 | ll -= double(n*m)/2.0*log(2*\033[01;31m\033[KPI\033[m\033[K);\n | \033[01;31m\033[K^~\033[m\033[K\n | \033[32m\033[KHI\033[m\033[K\nmake: *** [/opt/R/4.4.1/lib/R/etc/Makeconf:204: MME.o] Error 1\nERROR: compilation failed for package 'AlphaSimR'\n* removing '/tmp/RtmpclI5CE/temp_libpath11135d215d5/AlphaSimR'\n In function '\033[01m\033[KRcpp::List solveRRBLUP(const mat&, const mat&, const mat&)\033[m\033[K':\n\033[01m\033[KMME.cpp:162:61:\033[m\033[K \033[01;31m\033[Kerror: \033[m\033[K'\033[01m\033[KPI\033[m\033[K' was not declared in this scope\n 162 | double ll = -0.5*(double(optRes[\"objective\"])+df+df*log(2*\033[01;31m\033[KPI\033[m\033[K/df));\n | \033[01;31m\033[K^~\033[m\033[K\n\033[01m\033[KMME.cpp:\033[m\033[K In function '\033[01m\033[KRcpp::List solveRRBLUPMV(const mat&, const mat&, const mat&, int, double)\033[m\033[K':\n\033[01m\033[KMME.cpp:277:31:\033[m\033[K \033[01;31m\033[Kerror: \033[m\033[K'\033[01m\033[KPI\033[m\033[K' was not declared in this scope; did you mean '\033[01m\033[KHI\033[m\033[K'?\n 277 | ll -= double(n*m)/2.0*log(2*\033[01;31m\033[KPI\033[m\033[K);\n | \033[01;31m\033[K^~\033[m\033[K\n | \033[32m\033[KHI\033[m\033[K\nmake: *** [/opt/R/4.4.2/lib/R/etc/Makeconf:204: MME.o] Error 1\nERROR: compilation failed for package 'AlphaSimR'\n* removing '/tmp/RtmpclI5CE/temp_libpath11135d215d5/AlphaSimR'\n
``` ```
Compiler error: Possible reasons: too old CXX code which cannot be compiled anymore with CXX14 or CXX17. Compiler error: Possible reasons: too old CXX code which cannot be compiled anymore with CXX14 or CXX17.

View file

@ -16,6 +16,11 @@ ARG CACHEBUST
WORKDIR /work WORKDIR /work
COPY build-one.R /work/build-one.R COPY build-one.R /work/build-one.R
# Resolve and install the latest bincraft release dynamically (no hardcoded pin).
COPY install-bincraft.R /work/install-bincraft.R
# Ship the patch registry so build-one.R's `patches = "local/patches"` resolves
# (build context is `local/`, CWD is /work).
COPY patches /work/local/patches
RUN --mount=type=secret,id=b2_access,required=true \ RUN --mount=type=secret,id=b2_access,required=true \
--mount=type=secret,id=b2_secret,required=true \ --mount=type=secret,id=b2_secret,required=true \
@ -27,6 +32,9 @@ RUN --mount=type=secret,id=b2_access,required=true \
export GITHUB_PAT="$(cat /run/secrets/github_pat 2>/dev/null || true)" && \ export GITHUB_PAT="$(cat /run/secrets/github_pat 2>/dev/null || true)" && \
export GIT_TERMINAL_PROMPT=0 && \ export GIT_TERMINAL_PROMPT=0 && \
export OTEL_SDK_DISABLED=true && \ export OTEL_SDK_DISABLED=true && \
export OTEL_R_TRACES_EXPORTER=none && \
export OTEL_R_LOGS_EXPORTER=none && \
export OTEL_R_METRICS_EXPORTER=none && \
XVFB=$(command -v xwfb-run 2>/dev/null || command -v xvfb-run || true); \ XVFB=$(command -v xwfb-run 2>/dev/null || command -v xvfb-run || true); \
XVFB_ARGS=""; \ XVFB_ARGS=""; \
if command -v xwfb-run >/dev/null 2>&1; then dnf install -y -q weston 2>/dev/null; XVFB_ARGS="-c weston"; fi; \ if command -v xwfb-run >/dev/null 2>&1; then dnf install -y -q weston 2>/dev/null; XVFB_ARGS="-c weston"; fi; \
@ -37,7 +45,7 @@ RUN --mount=type=secret,id=b2_access,required=true \
echo "No working virtual display; building without xvfb" >&2; \ echo "No working virtual display; building without xvfb" >&2; \
fi; \ fi; \
run_build() { if [ "$USE_XVFB" = 1 ]; then $XVFB -a $XVFB_ARGS -- "$@"; else "$@"; fi; }; \ run_build() { if [ "$USE_XVFB" = 1 ]; then $XVFB -a $XVFB_ARGS -- "$@"; else "$@"; fi; }; \
ensure_bincraft() { "$1" -q -e 'if (!requireNamespace("bincraft", quietly = TRUE) || packageVersion("bincraft") != "4.2.1") pak::pak("git::https://codefloe.com/rpkgs/bincraft.git@v4.2.1")'; }; \ ensure_bincraft() { "$1" -q -e 'source("/work/install-bincraft.R")'; }; \
PRIMARY_MINOR=$(echo "$R_VERSION" | cut -d. -f1-2); \ PRIMARY_MINOR=$(echo "$R_VERSION" | cut -d. -f1-2); \
seen=" $PRIMARY_MINOR "; \ seen=" $PRIMARY_MINOR "; \
prc=0; failed=""; \ prc=0; failed=""; \

41
docker/buildkitd.toml Normal file
View file

@ -0,0 +1,41 @@
# BuildKit GC config for the remote buildx builders (artemis/amd64, gaia/arm64).
#
# Apply when creating the docker-container builders:
# docker buildx create --name artemis --driver docker-container \
# --config docker/buildkitd.toml ssh://<user@host-amd64>
# docker buildx create --name gaia --driver docker-container \
# --config docker/buildkitd.toml ssh://<user@host-arm64>
#
# Why: BuildKit's default GC caps the ephemeral cache tier — RUN
# --mount=type=cache mounts, local build context, git checkouts — at a
# hardcoded 512 MB (shown as "488.3 MiB" in `buildx inspect`). Across our
# 7-distro build matrix that fills instantly and forces re-downloads of
# system + R packages every rebuild. The first rule below raises that tier.
#
# Limits are absolute (not %) on purpose: artemis and gaia have very
# different free space (Hetzner ~42 GiB free vs Mac mini ~279 GiB), so a
# percentage would mean wildly different real budgets. minFreeSpace = 20 GB
# keeps the tight Hetzner host safe while staying modest on the Mac mini.
[worker.oci]
gc = true
# Tier 1 — ephemeral caches (cache mounts, local context, git checkouts).
# Raised from the 512 MB default to 8 GB, retained for 7 days so weekly
# rebuilds reuse downloaded packages instead of re-fetching them.
[[worker.oci.gcpolicy]]
filters = [
"type==source.local",
"type==exec.cachemount",
"type==source.git.checkout",
]
keepDuration = "168h"
maxUsedSpace = "8GB"
# Tier 2 — everything else (image layers, RUN exec results). Bounds the
# whole buildkit cache and always leaves 20 GB free on the host disk.
[[worker.oci.gcpolicy]]
all = true
reservedSpace = "2GB"
maxUsedSpace = "40GB"
minFreeSpace = "20GB"

View file

@ -10,8 +10,10 @@
# - buildx builders named `artemis` (amd64) and `gaia` (arm64), created with the # - buildx builders named `artemis` (amd64) and `gaia` (arm64), created with the
# docker-container driver (runs BuildKit on the remote host's docker daemon over # docker-container driver (runs BuildKit on the remote host's docker daemon over
# SSH). The default `remote` driver does NOT work with an ssh:// docker host. # SSH). The default `remote` driver does NOT work with an ssh:// docker host.
# docker buildx create --name artemis --driver docker-container ssh://<user@host-amd64> # Pass --config docker/buildkitd.toml so BuildKit's GC keeps a usable cache
# docker buildx create --name gaia --driver docker-container ssh://<user@host-arm64> # (the default caps the cache-mount tier at 512 MB, forcing re-downloads).
# docker buildx create --name artemis --driver docker-container --config docker/buildkitd.toml ssh://<user@host-amd64>
# docker buildx create --name gaia --driver docker-container --config docker/buildkitd.toml ssh://<user@host-arm64>
# - exported secrets: B2_S3_ACCESS_KEY, B2_S3_SECRET_KEY, PGPASS (GITHUB_PAT optional) # - exported secrets: B2_S3_ACCESS_KEY, B2_S3_SECRET_KEY, PGPASS (GITHUB_PAT optional)
# #
# Overridable (env or `just VAR=… rebuild …`): # Overridable (env or `just VAR=… rebuild …`):

View file

@ -64,12 +64,38 @@ sprintf("# of package versions for this job: %s", nrow(chunk))
exclude <- jsonlite::fromJSON("local/excluded-packages.json")[["package"]] exclude <- jsonlite::fromJSON("local/excluded-packages.json")[["package"]]
chunk <- chunk[!chunk$Package %in% exclude, ] chunk <- chunk[!chunk$Package %in% exclude, ]
# Skip package versions already built in a previous run. # Skip package versions already attempted in a previous run (built or errored).
# pkgs_to_build.rds is a static snapshot from the install-deps step, so on a # pkgs_to_build.rds is a static snapshot from the install-deps step, so on a
# restart it still lists everything an interrupted run already produced. The # restart it still lists everything an interrupted run already produced. The
# metadata DB reflects that progress, so we re-derive the remaining set here. # metadata DB reflects that progress, so we re-derive the remaining set here.
platform <- paste(Sys.getenv("OS"), gsub("[.]", "", Sys.getenv("OS_VERSION")), sep = "-") # We exclude *all* attempted versions, not just successful ones: a previously
arch <- Sys.getenv("ARCH") # errored version is skipped by build_binary_package() anyway, so leaving it in
# the chunk only makes the job cycle through it one-by-one for no benefit.
# Derive platform + arch from the running container, mirroring the codename ->
# platform mapping bincraft uses internally. The OS/OS_VERSION selectors are
# workflow-level CI variables that are not injected into the container
# environment, so Sys.getenv() would return "" and this pre-filter would query
# platform "-" and skip nothing.
codename <- bincraft::set_codename(NULL)
platform <- switch(
codename,
jammy = "ubuntu-2204",
noble = "ubuntu-2404",
resolute = "ubuntu-2604",
rhel10 = "redhat-10",
rhel9 = "redhat-9",
rhel8 = "redhat-8",
alpine320 = "alpine-320",
alpine321 = "alpine-321",
alpine322 = "alpine-322",
alpine323 = "alpine-323",
alpine324 = "alpine-324",
alpine325 = "alpine-325",
alpine326 = "alpine-326",
NA_character_
)
local_machine <- Sys.info()[["machine"]]
arch <- if (grepl("arm64|aarch64", local_machine)) "arm64" else "amd64"
con <- DBI::dbConnect( con <- DBI::dbConnect(
RPostgres::Postgres(), RPostgres::Postgres(),
dbname = "build_metadata", dbname = "build_metadata",
@ -81,13 +107,13 @@ con <- DBI::dbConnect(
) )
built <- DBI::dbGetQuery( built <- DBI::dbGetQuery(
con, con,
"SELECT name, tag FROM single_builds WHERE platform = $1 AND arch = $2 AND error_occurred = FALSE", "SELECT name, tag FROM single_builds WHERE platform = $1 AND arch = $2",
params = list(platform, arch) params = list(platform, arch)
) )
DBI::dbDisconnect(con) DBI::dbDisconnect(con)
before <- nrow(chunk) before <- nrow(chunk)
chunk <- chunk[!paste(chunk$Package, chunk$Version) %in% paste(built$name, built$tag), ] chunk <- chunk[!paste(chunk$Package, chunk$Version) %in% paste(built$name, built$tag), ]
sprintf("Skipped %d already-built package versions; %d remaining for this job", before - nrow(chunk), nrow(chunk)) sprintf("Skipped %d already-attempted package versions; %d remaining for this job", before - nrow(chunk), nrow(chunk))
# Read pre-computed S3 listing from install-deps step # Read pre-computed S3 listing from install-deps step
# This avoids loading s3fs/reticulate/Python in the build container, # This avoids loading s3fs/reticulate/Python in the build container,
@ -121,6 +147,7 @@ mapply(
metadata_db_sslmode = "require", metadata_db_sslmode = "require",
metadata_db_port = 15432, metadata_db_port = 15432,
archive = TRUE, archive = TRUE,
patches = "local/patches",
upload = TRUE, upload = TRUE,
store_build_metadata = TRUE store_build_metadata = TRUE
) )

View file

@ -103,6 +103,7 @@ for (ver in versions) {
force = TRUE, force = TRUE,
upload = TRUE, upload = TRUE,
archive = TRUE, archive = TRUE,
patches = "local/patches",
store_build_metadata = TRUE, store_build_metadata = TRUE,
s3_endpoint = s3$s3_endpoint, s3_endpoint = s3$s3_endpoint,
s3_region = s3$s3_region, s3_region = s3$s3_region,

52
local/install-bincraft.R Normal file
View file

@ -0,0 +1,52 @@
#!/usr/bin/env Rscript
# Install the latest tagged bincraft release, resolved dynamically, so the CI
# workflows and the build-one image never pin a hardcoded version (no more
# editing `@vX.Y.Z` in many places on every release).
#
# Run with the R whose library should receive bincraft:
# Rscript local/install-bincraft.R
# or, to target a specific R from a shell loop:
# "$RBIN" -q -e 'source("local/install-bincraft.R")'
#
# How it works: list the remote tags with `git ls-remote` (no token needed for
# the public repo), keep the `vX.Y.Z` release tags, pick the highest version,
# and install it with pak. pak is idempotent on the git ref, so re-running keeps
# the package when it is already current and only updates when a newer tag ships.
# Filtering/sorting is done in R (not via git's `--sort`/refspec) so behaviour is
# identical across git versions and `system2()` argument handling.
repo_url <- Sys.getenv(
"BINCRAFT_GIT_URL",
unset = "https://codefloe.com/rpkgs/bincraft.git"
)
# GIT_TERMINAL_PROMPT=0 keeps a non-interactive run from hanging on auth.
refs <- system2(
"git",
c("ls-remote", "--tags", repo_url),
stdout = TRUE,
stderr = FALSE,
env = "GIT_TERMINAL_PROMPT=0"
)
tags <- sub(".*refs/tags/", "", refs)
tags <- tags[!grepl("\\^\\{\\}$", tags)] # drop dereferenced "...^{}" lines
tags <- grep("^v[0-9]", tags, value = TRUE) # only vX.Y.Z release tags
if (length(tags) == 0L) {
stop(
"Could not resolve any bincraft release tag from ",
repo_url,
call. = FALSE
)
}
latest <- tags[order(package_version(sub("^v", "", tags)), decreasing = TRUE)][
1L
]
message(sprintf("Installing latest bincraft release: %s", latest))
pak::pak(sprintf("git::%s@%s", repo_url, latest))
message(sprintf(
"bincraft %s installed (%s)",
as.character(utils::packageVersion("bincraft")),
latest
))

43
local/patches/README.md Normal file
View file

@ -0,0 +1,43 @@
# Patch Registry
This directory contains the curated registry of per-package build-time patches consumed by bincraft's `patches` argument.
## Schema
The registry is defined in `registry.json` as an array of patch entries. Each entry specifies lightweight build-time overrides (environment variables, configure arguments, Makevars) and optionally a source diff to apply before building.
### Field semantics
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `package` | string | yes | CRAN package name. |
| `versions` | string | yes | `"*"` for any, a constraint such as `">=5.1.0"`, or an exact version `"5.1.11-2"`. Env-tier fixes are typically `"*"`; source diffs are normally exact or lower-bounded because a diff is pinned to the source it was generated against. |
| `platforms` | array of strings | yes | Matched against the running build's platform tokens — distro family (`alpine`, `ubuntu`, `redhat`), codename (`ubuntu-2604`, `alpine-324`), and arch (`amd64`, `arm64`). An entry matches if any listed token matches any build token. `["*"]` matches all platforms. |
| `env` | object | no | Environment variables exported only for this package's isolated build. |
| `configure_args` | array | no | Arguments passed as `--configure-args` to the isolated build. |
| `makevars` | object | no | Key/value pairs written into a package-local Makevars for the isolated build. |
| `patch` | string or null | no | Path (relative to `local/patches/`) to a unified diff applied to the unpacked CRAN source before building. |
| `reason` | string | yes | Human explanation, surfaced in logs and metadata. |
## Adding an entry
To add a new patch entry:
1. Add an object to the array in `registry.json` with the fields documented above.
Start with lightweight overrides (environment variables, configure arguments, Makevars) before resorting to source diffs.
2. If a source diff is needed, place it in `local/patches/<package>/<file>.patch` and reference its path in the `patch` field.
For example, a diff for `RcppParallel` would go in `local/patches/RcppParallel/fix.patch` and be referenced as `"patch": "RcppParallel/fix.patch"`.
3. The `reason` field should clearly explain why the patch is needed and what problem it solves.
## Validation
The registry is validated and applied by bincraft during the build process.
For manual validation, run the validator from the repo root:
```bash
Rscript local/validate-patches.R
```
This validates the schema, referenced patch-file existence, and checks for duplicate entries across platforms and versions.

View file

@ -0,0 +1,16 @@
diff --git a/src/Makevars.in b/src/Makevars.in
index be8445f..faee771 100644
--- a/src/Makevars.in
+++ b/src/Makevars.in
@@ -60,7 +60,10 @@ else
endif
ifeq ($(UNAME), Linux)
- USE_TBB=Linux
+ # bincraft patch: the bundled Intel TBB build hangs/fails on musl (Alpine)
+ # and newer toolchains (g++ 15). Skip it (leave USE_TBB unset) and force the
+ # TinyThread backend so RcppParallel still builds.
+ PKG_CXXFLAGS += -DRCPP_PARALLEL_USE_TBB=0
endif
ifeq ($(UNAME), SunOS)

View file

@ -0,0 +1,19 @@
diff --git a/configure b/configure
--- a/configure
+++ b/configure
@@ -11,6 +11,15 @@
PKG_TEST_HEADER="<uv.h>"
PKG_LIBS="-luv"
+# bincraft patch: force the vendored static libuv so the resulting binary
+# is self-contained. fs configure otherwise links system libuv whenever
+# pkg-config finds libuv-devel (installed as a build-time sysreq), yielding
+# an fs.so with NEEDED libuv.so.1 that fails to dyn.load on machines lacking
+# runtime libuv (install.packages/renv do not install SystemRequirements).
+echo "Building static libuv (bincraft: forced vendored)" 1>&2
+cp -f src/Makevars.vendor src/Makevars
+exit 0
+
# Use pkg-config if available
if [ `command -v pkg-config` ]; then
PKGCONFIG_CFLAGS=`pkg-config --cflags --silence-errors ${PKG_CONFIG_NAME}`

Some files were not shown because too many files have changed in this diff Show more