feat: R-minor-sensitive binary builds (full + iterative) (#84)
## Summary
Builds R-minor-sensitive CRAN packages once per installed R minor version (into per-minor S3 slots `…/contrib/<x.y>/`) and everything else once into the generic slot, driven by bincraft 4.2.0's ABI classifier. Both the full and iterative pipelines are covered.
## What's in here
**Detection / precompute**
- `local/r-minor-helpers.R` — pure `classify_from_metadata()` (NeedsCompilation / risky `LinkingTo`) + `parse_build_args()`, with unit tests.
- `local/packages-to-build.R` — adds a per-package `r_minor_sensitive` flag: cheap CRAN-metadata rules first, source download + `bincraft::needs_per_minor_recompile()` only for the ambiguous compiled subset (fail-safe to sensitive). Classified once per package, applied to all versions.
**Full build**
- `local/build-all.R` — passes the per-row `is_r_minor_sensitive` flag; new `--sensitive-only` mode builds just the risky subset.
- `.crow/build-all-versions-{amd64,arm64}.yaml` — install-deps persists the sensitive subset; build step runs a sensitive-only pass under each non-primary `/opt/R/*` minor; new step uploads the generic index plus a per-minor index for each minor.
**Iterative build**
- All 14 `.crow/process-updates-*.yaml` — primary pass uses `r_minor_detection = 'classifier'`; a sensitive-only multi-R pass builds risky updates under each other minor; per-minor index upload added.
**Tooling / housekeeping**
- Pins bincraft `v4.1.1` → `v4.2.0` across all workflows; removes the superseded standalone `build-r-minor-sensitive-packages.yaml`.
- Adds prek/pre-commit hooks (prettier, markdownlint, editorconfig-checker, yamllint, air) and applies them repo-wide; excludes the verbatim GPL `LICENSE.md` and auxiliary shell scripts.
- Design + implementation docs under `docs/superpowers/`.
## Requires before merge
- A `v4.2.0` git tag must be pushed on the bincraft repo (codefloe.com/rpkgs/bincraft) — the workflow install steps pin `@v4.2.0`. The full-build install-deps clones `main`, so it is unaffected.
Reviewed-on: #84
This commit is contained in:
parent
f28ccaf008
commit
d558e27c11
1 changed files with 1171 additions and 413 deletions
|
|
@ -17,7 +17,11 @@ suppressPackageStartupMessages(library(data.table))
|
|||
|
||||
arch = Sys.getenv("ARCH")
|
||||
# target: alpine-322, ubuntu-2404, redhat-9, etc.
|
||||
platform = paste(Sys.getenv("OS"), gsub("[.]", "", Sys.getenv("OS_VERSION")), sep = "-")
|
||||
platform = paste(
|
||||
Sys.getenv("OS"),
|
||||
gsub("[.]", "", Sys.getenv("OS_VERSION")),
|
||||
sep = "-"
|
||||
)
|
||||
# Use bincraft's codename detection for S3 paths (e.g. "rhel10" not "redhat10")
|
||||
codename = bincraft::set_codename(NULL)
|
||||
|
||||
|
|
@ -34,7 +38,9 @@ con <- DBI::dbConnect(
|
|||
cran_archive = tools::CRAN_archive_db()
|
||||
cran_release = tools::CRAN_package_db()
|
||||
# Subset cran_archive to only those packages
|
||||
cran_archive_in_release <- cran_archive[names(cran_archive) %in% cran_release$Package]
|
||||
cran_archive_in_release <- cran_archive[
|
||||
names(cran_archive) %in% cran_release$Package
|
||||
]
|
||||
|
||||
archive_versions <- rbindlist(
|
||||
lapply(names(cran_archive), function(pkg) {
|
||||
|
|
@ -126,11 +132,15 @@ query_error <- function(pkg, ver) {
|
|||
# Fetch all relevant columns from the database
|
||||
errored_pkgs <- DBI::dbGetQuery(
|
||||
con,
|
||||
sprintf("SELECT name, tag FROM single_builds WHERE error_occurred = TRUE and platform='%s' and arch='%s'", platform, arch)
|
||||
sprintf(
|
||||
"SELECT name, tag FROM single_builds WHERE error_occurred = TRUE and platform='%s' and arch='%s'",
|
||||
platform,
|
||||
arch
|
||||
)
|
||||
)
|
||||
errored_pkgs <- as.data.table(errored_pkgs)
|
||||
setkey(pkgs_to_build, Package, Version)
|
||||
setnames(errored_pkgs, c("Package","Version"))
|
||||
setnames(errored_pkgs, c("Package", "Version"))
|
||||
setkey(errored_pkgs, Package, Version)
|
||||
|
||||
### Final subsetting
|
||||
|
|
@ -140,3 +150,62 @@ pkgs <- pkgs_no_error[!s3_dt]
|
|||
# Deduplicate
|
||||
pkgs <- unique(pkgs)
|
||||
setorder(pkgs, Package, Version)
|
||||
|
||||
### R-minor sensitivity (classify once per package, applied to all versions)
|
||||
source(file.path("local", "r-minor-helpers.R"))
|
||||
risky_deps <- bincraft::abi_risky_linking_deps()
|
||||
|
||||
release_meta <- data.table(
|
||||
Package = cran_release$Package,
|
||||
NeedsCompilation = cran_release$NeedsCompilation,
|
||||
LinkingTo = cran_release$LinkingTo
|
||||
)
|
||||
|
||||
meta <- release_meta[Package %in% unique(pkgs$Package)]
|
||||
meta[,
|
||||
triage := mapply(
|
||||
classify_from_metadata,
|
||||
NeedsCompilation,
|
||||
LinkingTo,
|
||||
MoreArgs = list(risky_deps = risky_deps)
|
||||
)
|
||||
]
|
||||
|
||||
# Only the "ambiguous" compiled packages need a source grep.
|
||||
ambiguous <- meta[triage == "ambiguous", Package]
|
||||
sensitive_ambiguous <- character()
|
||||
if (length(ambiguous) > 0L) {
|
||||
tmp_src <- file.path(tempdir(), "abi_src")
|
||||
dir.create(tmp_src, showWarnings = FALSE, recursive = TRUE)
|
||||
sens <- vapply(
|
||||
ambiguous,
|
||||
function(pkg) {
|
||||
out <- tryCatch(
|
||||
{
|
||||
dl <- utils::download.packages(
|
||||
pkg,
|
||||
destdir = tmp_src,
|
||||
repos = "https://cloud.r-project.org",
|
||||
quiet = TRUE
|
||||
)
|
||||
isTRUE(as.logical(bincraft::needs_per_minor_recompile(dl[1L, 2L])))
|
||||
},
|
||||
error = function(e) TRUE
|
||||
) # fail safe: treat as sensitive
|
||||
out
|
||||
},
|
||||
logical(1L)
|
||||
)
|
||||
sensitive_ambiguous <- ambiguous[sens]
|
||||
}
|
||||
|
||||
sensitive_pkgs <- unique(c(
|
||||
meta[triage == "sensitive", Package],
|
||||
sensitive_ambiguous
|
||||
))
|
||||
pkgs[, r_minor_sensitive := Package %in% sensitive_pkgs]
|
||||
sprintf(
|
||||
"R-minor-sensitive packages: %s of %s",
|
||||
length(sensitive_pkgs),
|
||||
uniqueN(pkgs$Package)
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in a new issue