3.9 KiB
Final Fix Report: bincraft package-patching branch
C1 Fix — prepare_patched_repo() src/contrib layout (R/patches.R)
Problem: cranlike::add_PACKAGES was being called for local file indexing, but it delegates to s3fs::s3_file_exists internally which only works for S3 paths, not local filesystem paths. Additionally, the tarball and index were placed flat in repo_dir, but R/pak resolve file:// repos via contrib.url() which appends src/contrib — so the flat layout was invisible to pak.
Fix applied in R/patches.R prepare_patched_repo():
- After creating
repo_dir, createscontrib <- file.path(repo_dir, "src", "contrib")anddir.create(contrib, recursive = TRUE, showWarnings = FALSE). targetis nowfile.path(contrib, ...)instead offile.path(repo_dir, ...).build_patched_binary(entry, version, contrib)— builds directly into contrib.- Replaced
cranlike::add_PACKAGES(list.files(repo_dir, ...), repo_dir)withtools::write_PACKAGES(contrib, type = "source")— cranlike usess3fsinternally and does not work for local paths;tools::write_PACKAGESis the correct CRAN-standard indexer for local repos. - Returns
repo_dir(the root) unchanged sorun_pak_install_with_mutexkeeps prependingfile://<repo_dir>and pak'scontrib.url()resolves to<repo_dir>/src/contrib. - Cache (
cache_dir) stays flat — only the served repo uses src/contrib.
RED/GREEN Evidence for available.packages() test
RED (flat layout, pre-fix):
Warning: cannot open compressed file '.../flat_repo_.../src/contrib/PACKAGES',
probable reason 'No such file or directory'
pkgfoo found via available.packages(): FALSE
GREEN (src/contrib layout, post-fix):
pkgfoo found via available.packages(): TRUE
This directly demonstrates that the flat layout was invisible to R's available.packages() / pak resolution.
New Test — test-patches.R
Added test: "prepare_patched_repo src/contrib layout is resolvable by available.packages"
- Builds a minimal valid source package tarball (
pkgfoo_1.0.0.tar.gz) using realutils::tar(). - Mocks only
resolve_patch_version(→ "1.0.0") andbuild_patched_binary(copies real tarball todest_dir, returns path). - Does NOT mock
cranlike::add_PACKAGESortools::write_PACKAGES— uses the real indexer. - Asserts:
file.exists(file.path(out, "src", "contrib", "pkgfoo_1.0.0.tar.gz"))is TRUE."pkgfoo" %in% rownames(available.packages(repos = paste0("file://", out), type = "source"))is TRUE.ap["pkgfoo", "Version"] == "1.0.0".
- This test FAILS on the flat layout (warning + empty matrix) and PASSES after the fix.
Also updated the existing A5 test ("prepare_patched_repo serves a cached binary and writes an index") to:
- Check
file.path(repo, "src", "contrib", "glue_1.0.0.tar.gz")andfile.path(repo, "src", "contrib", "PACKAGES")(formerly flat paths). - Mock
tools::write_PACKAGESinstead ofcranlike::add_PACKAGES.
Test Results
[ FAIL 0 | WARN 0 | SKIP 1 | PASS 41 ]
(1 skip: E2E test gated on BINCRAFT_PATCH_E2E env var, by design.)
Doc Changes
R/build_binaries.R:
- Added
#' @template param-patchestoexecute_package_buildsroxygen block. - Added
#' @template param-patchestohandle_system_dependenciesroxygen block.
R/install_helpers.R:
- Added
#' @param patched_repo Optional path to a local patched-binary repo to prepend to pak's repos for this install (internal).torun_pak_install_with_mutexroxygen block.
devtools::document() output:
Writing 'execute_package_builds.Rd'
Writing 'handle_system_dependencies.Rd'
Writing 'run_pak_install_with_mutex.Rd'
All three Rd files regenerated successfully.
Deferred: I2
Duplicate registry entries resolving to the same package_version silently overwrite each other in prepare_patched_repo — the last one wins because both write to the same target path. This is a known limitation and is deferred; no action taken.