95 lines
3.8 KiB
Markdown
95 lines
3.8 KiB
Markdown
### Task A0: Proof of mechanism — pak installs a patched binary from a prepended `file://` repo
|
|
|
|
This de-risks the core assumption before building anything on top: that `pak` installs a binary from a local `file://` repo in preference to CRAN for an equal version, and does so without recompiling. If this fails, the contingency (documented in Step 4) is to serve patched *source* and rely on `pkgcache` build-caching — the rest of the plan changes only inside `build_patched_binary()`.
|
|
|
|
**Files:**
|
|
- Create: `tools/verify-patch-mechanism.R`
|
|
|
|
**Interfaces:**
|
|
- Produces: a runnable script proving `pak::pkg_install()` resolves a local patched binary over CRAN. No package API.
|
|
|
|
- [ ] **Step 1: Write the verification script**
|
|
|
|
```r
|
|
# tools/verify-patch-mechanism.R
|
|
# Proves pak installs a patched binary from a prepended file:// repo instead of
|
|
# CRAN's, without recompiling. Run inside a Linux build-env container:
|
|
# Rscript tools/verify-patch-mechanism.R
|
|
# Exits 0 on success, 1 on failure.
|
|
|
|
pkg <- "glue" # small, pure-R CRAN package
|
|
sentinel <- "PatchMechanismProof"
|
|
|
|
work <- tempfile("verify_")
|
|
repo <- file.path(work, "repo", "src", "contrib")
|
|
lib <- file.path(work, "lib")
|
|
dir.create(repo, recursive = TRUE)
|
|
dir.create(lib, recursive = TRUE)
|
|
|
|
# 1. Download CRAN source for the current version.
|
|
ap <- available.packages(repos = "https://cloud.r-project.org")
|
|
ver <- ap[pkg, "Version"]
|
|
src <- file.path(work, sprintf("%s_%s.tar.gz", pkg, ver))
|
|
download.file(
|
|
sprintf("https://cloud.r-project.org/src/contrib/%s_%s.tar.gz", pkg, ver),
|
|
src, mode = "wb"
|
|
)
|
|
|
|
# 2. Unpack, inject a sentinel field into DESCRIPTION, build a binary.
|
|
untar(src, exdir = work)
|
|
desc <- file.path(work, pkg, "DESCRIPTION")
|
|
writeLines(c(readLines(desc), sprintf("%s: yes", sentinel)), desc)
|
|
pkgbuild::build(
|
|
file.path(work, pkg), binary = TRUE, vignettes = FALSE,
|
|
dest_path = repo, quiet = TRUE
|
|
)
|
|
built <- list.files(repo, pattern = sprintf("^%s_.*\\.tar\\.gz$", pkg), full.names = TRUE)
|
|
file.rename(built[1L], file.path(repo, sprintf("%s_%s.tar.gz", pkg, ver)))
|
|
cranlike::add_PACKAGES(sprintf("%s_%s.tar.gz", pkg, ver), repo)
|
|
|
|
# 3. Install with the local repo prepended; assert our patched build won.
|
|
withr::with_options(
|
|
list(repos = c(patched = sprintf("file://%s", dirname(dirname(repo))),
|
|
CRAN = "https://cloud.r-project.org")),
|
|
pak::pkg_install(pkg, lib = lib, ask = FALSE, upgrade = FALSE)
|
|
)
|
|
|
|
installed_desc <- file.path(lib, pkg, "DESCRIPTION")
|
|
ok <- file.exists(installed_desc) &&
|
|
any(grepl(sentinel, readLines(installed_desc)))
|
|
|
|
if (ok) {
|
|
cat("PROOF PASSED: pak installed the patched local binary.\n")
|
|
quit(status = 0L)
|
|
} else {
|
|
cat("PROOF FAILED: pak did not install the patched local binary.\n")
|
|
quit(status = 1L)
|
|
}
|
|
```
|
|
|
|
- [ ] **Step 2: Run the proof in a build-env container**
|
|
|
|
Run (amd64 example; use any supported build-env image):
|
|
|
|
```bash
|
|
just build-single ubuntu 2604 amd64 4.5.0 glue 1.0.0 1 || true # warms the env
|
|
docker run --rm -v "$PWD":/work -w /work reg.devxy.io/rpkgs/build-env-ubuntu:2604 \
|
|
Rscript tools/verify-patch-mechanism.R
|
|
```
|
|
|
|
Expected: final line `PROOF PASSED: pak installed the patched local binary.` and exit status 0.
|
|
|
|
- [ ] **Step 3: Commit**
|
|
|
|
```bash
|
|
git add tools/verify-patch-mechanism.R
|
|
git commit -m "test(patches): prove pak installs a patched binary from a local file:// repo"
|
|
```
|
|
|
|
- [ ] **Step 4: Record the outcome / contingency**
|
|
|
|
If the proof PASSED, proceed to Task A1 unchanged.
|
|
If it FAILED (pak recompiled or picked CRAN's), the mechanism switches to serving patched *source*: in Task A4 `build_patched_binary()` skips `pkgbuild::build()` and instead repackages the patched source tree with `pkgbuild::build(binary = FALSE)`; everything else (registry, matching, cache, repo prepend) is unchanged because `pak` build-caches the compiled result via `pkgcache`. Note the chosen path in the commit message and continue.
|
|
|
|
---
|
|
|