build-cran-binaries/.superpowers/handoff/task-A2-brief.md

123 lines
3.8 KiB
Markdown

### Task A2: Platform matching and version-constraint satisfaction
**Files:**
- Modify: `R/patches.R`
- Test: `tests/testthat/test-patches.R`
**Interfaces:**
- Consumes: normalized entries from Task A1.
- Produces: `build_platform_tokens(platform, arch)` → character vector; `entry_matches_platform(entry, tokens)` → logical; `match_patch_entries(registry, platform, arch)` → filtered list; `version_satisfies(version, constraint)` → logical (constraint forms: `"*"` handled by caller, `"x.y.z"` exact, `">=x"`, `"<=x"`, `">x"`, `"<x"`, `"==x"`).
- [ ] **Step 1: Write the failing test**
```r
test_that("build_platform_tokens expands family and arch", {
expect_setequal(
build_platform_tokens("ubuntu-2604", "amd64"),
c("ubuntu-2604", "ubuntu", "amd64")
)
expect_setequal(
build_platform_tokens("alpine-324", "arm64"),
c("alpine-324", "alpine", "arm64")
)
})
test_that("match_patch_entries matches family, codename, arch, and wildcard", {
reg <- list(
list(package = "A", versions = "*", platforms = "alpine", reason = "r"),
list(package = "B", versions = "*", platforms = "ubuntu-2604", reason = "r"),
list(package = "C", versions = "*", platforms = "*", reason = "r"),
list(package = "D", versions = "*", platforms = "redhat", reason = "r")
)
got <- vapply(
match_patch_entries(reg, "ubuntu-2604", "amd64"),
function(e) e$package, character(1L)
)
expect_setequal(got, c("B", "C"))
})
test_that("version_satisfies handles operators and hyphenated versions", {
expect_true(version_satisfies("5.1.11-2", "5.1.11-2"))
expect_true(version_satisfies("5.1.11-2", "==5.1.11-2"))
expect_true(version_satisfies("5.1.12", ">=5.1.0"))
expect_false(version_satisfies("5.0.0", ">=5.1.0"))
expect_true(version_satisfies("5.1.11-2", "<=5.1.11-2"))
expect_false(version_satisfies("5.1.12", "<=5.1.11-2"))
})
```
- [ ] **Step 2: Run test to verify it fails**
Run: `Rscript -e 'devtools::load_all("."); testthat::test_file("tests/testthat/test-patches.R")'`
Expected: FAIL with "could not find function build_platform_tokens".
- [ ] **Step 3: Write minimal implementation (append to `R/patches.R`)**
```r
#' Build platform tokens for patch matching
#' @keywords internal
build_platform_tokens <- function(platform, arch) {
family <- sub("-.*$", "", platform)
unique(c(platform, family, arch))
}
#' Does a patch entry apply to the current platform tokens?
#' @keywords internal
entry_matches_platform <- function(entry, tokens) {
any(entry$platforms == "*") ||
length(intersect(entry$platforms, tokens)) > 0L
}
#' Filter registry entries applicable to the current build
#' @keywords internal
match_patch_entries <- function(registry, platform, arch) {
if (length(registry) == 0L) {
return(list())
}
tokens <- build_platform_tokens(platform, arch)
Filter(function(e) entry_matches_platform(e, tokens), registry)
}
#' Test whether a version satisfies a single constraint
#'
#' @param version A version string (CRAN style, may contain `-`).
#' @param constraint One of `"x.y.z"`, `"==x"`, `">=x"`, `"<=x"`, `">x"`, `"<x"`.
#' @keywords internal
version_satisfies <- function(version, constraint) {
constraint <- trimws(constraint)
parts <- regmatches(
constraint,
regexec("^(>=|<=|==|>|<)?\\s*(.+)$", constraint)
)[[1L]]
op <- parts[2L]
target <- parts[3L]
v <- package_version(version)
t <- package_version(target)
if (op == "" || op == "==") {
return(v == t)
}
switch(
op,
">=" = v >= t,
"<=" = v <= t,
">" = v > t,
"<" = v < t,
FALSE
)
}
```
- [ ] **Step 4: Run test to verify it passes**
Run: `Rscript -e 'devtools::load_all("."); testthat::test_file("tests/testthat/test-patches.R")'`
Expected: PASS.
- [ ] **Step 5: Commit**
```bash
git add R/patches.R tests/testthat/test-patches.R
git commit -m "feat(patches): platform matching and version-constraint checks"
```
---