feat: serve R >= 4.6 custom binary types (R_PLATFORM_PKGTYPE) alongside UA routing #227
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Support R ≥ 4.6 custom binary types (
R_PLATFORM_PKGTYPE) on cran.rpkgs.com and the binary store, so clients can find binaries by path instead of relying only on User-Agent sniffing.Background
Simon Urbanek pointed this out in the r-devel thread on the User-Agent patch (https://stat.ethz.ch/pipermail/r-devel/2026-September/084687.html).
It shipped in R 4.6.0, in a series of Simon's commits from 2026-02-03 (R trunk r89368–r89372, plus r89499 on 2026-02-28):
R_PLATFORM_PKGTYPEenv var overrides.Platform$pkgType(src/main/platform.c, r89368).contrib.url()maps<system>.binary.<build>tobin/<system>/<build>/contrib/<x.y>(r89369).install.packages()/write_PACKAGES()support custom binaries named.tar.{gz,bz2,xz,zst,zstd}(r89370).Versionis identical, a newerBuilttimestamp now counts as an update, so a rebuilt binary is picked up without a version bump (r89371).Built:is checked against the running R (r89499,.is.built.compatible()inutils/R/unix/mac.install.R).Verified on R 4.6.1:
With the variable set,
getOption("pkgType")becomes"both".install.packages()then reads bothbin/linux/<build>/contrib/<x.y>andsrc/contriband prefers the binary.Without it, Linux R stays on
"source"and only requestssrc/contrib, which is what the edge router handles today.Proposal
Serve both routes from the same storage, without duplicating tarballs:
/bin/linux/<build>/contrib/<x.y>/…maps to the existing slot (<arch>/<os>/latest/src/contribplus the per-minor<x.y>/union index from the per-minor routing design).This is a deterministic path rewrite, so it needs no
Vary: User-Agentand caches cleanly.edge/rpkgs-router.tsforsrc/contribrequests from R < 4.6 and from R ≥ 4.6 without the env var.Open questions / requirements
<build>naming. It must match[[:alnum:]_-]+.Options: our slot names (
amd64-noble,arm64-alpine324) or Simon's example form (x86_64-ubuntu-noble), which is derived fromR.version$archand os-releaseID+VERSION_CODENAME/VERSION_ID.The derived form is more likely to be adopted by others (rig, rocker, Posit builds) and can be computed from os-release without a lookup table.
The edge can accept aliases.
File:field in PACKAGES. For custom types,download.packages()defaults the filename to<pkg>_<ver>.tar.xzunless the record hasFile:(utils/R/packages.R:901-908).Our tarballs are
.tar.gz, so the index served on the path route must carryFile:, or the edge must alias the name..is.built.compatible()only compares arch and linux vs non-linux.x86_64-pc-linux-muslvsx86_64-pc-linux-gnupasses, so a misrouted glibc binary on Alpine is not caught.Our
Built:stamps (see the Built-triple / paquetier coupling) must stay accurate, and R builds can add a stricteroptions(R.platform.is.compatible = function(b.platform) …).update.packages(), as long asBuiltis bumped.utils/R/packages2.R:579uses[[:lower::]](extra colon), sogrepl()never matches.The
install.packages.check.sourcebranch is therefore skipped for every*.binarytype, includingmac.binary.This is worth reporting on r-devel.
Making the information available by default
The path route only helps when
R_PLATFORM_PKGTYPEis set.To cover as many clients as possible:
Renviron.sitein every image we publish (reg.devxy.io/r/*) and in the bincraft build images.Tasks
<build>naming scheme and aliases./bin/linux/<build>/contrib/<x.y>rewrite inedge/rpkgs-router.tswith tests.File:(or alias.tar.xzto.tar.gz).R_PLATFORM_PKGTYPEon R 4.6 for noble, an el slot and alpine324, on amd64 and arm64.R_PLATFORM_PKGTYPEin our R images.[[:lower::]]typo upstream.Follow-up: backwards compatibility and unconfigured R
Existing paths stay canonical
The existing
/<arch>/<os>/latest/src/contrib[/<x.y>]paths remain the storage layout and keep working unchanged./bin/linux/<build>/contrib/<x.y>is only an edge rewrite onto them; nothing is moved or duplicated.If the
<build>naming uses the os-release form (x86_64-ubuntu-noble), the edge also accepts slot-style aliases (amd64-noble), so every published form resolves.Router tests must cover old paths, new paths and aliases.
What a stock R actually sends (measured)
R 4.6.1,
Rscript --vanilla, defaultlibcurlmethod, against a local header-logging server:libcurl.creplaces anyHTTPUserAgentstarting withR (bylibcurl/<ver>, so an unconfigured Linux R sends no R version, platform or distro.User-Agent routing therefore only works for clients that already set a custom
HTTPUserAgent(R/x.y R (…)).For an unconfigured R, neither route works; both need one piece of client-side configuration.
With
R_PLATFORM_PKGTYPE=linux.binary.x86_64-ubuntu-noble, the same R requests/bin/linux/x86_64-ubuntu-noble/contrib/4.6/PACKAGES.rds, so the path route carries arch, distro, release and R minor without any User-Agent.Consequence for the design
Since some configuration is always needed, set it once per R installation at the distributor level, not per user:
Renviron.site);r-base, Fedora/EPELR, AlpineR), which R's NEWS names as the intended setters;Unconfigured clients keep falling through to CRAN sources, which is no worse than today.