Skip to content

Commit cdf677b

Browse files
author
Jeroen Ooms
committed
Fix Path field being ignored when File field is also present
packages_make_target() built the download/cache target from the File field first, and only fell back to Path when File was NA. This meant that PACKAGES entries with both fields set had Path silently dropped instead of combined, producing repodir/file instead of the correct repodir/path/file. Handle all four combinations explicitly: both present, only File, only Path, and neither. See r-universe-org/help#715
1 parent c13b035 commit cdf677b

3 files changed

Lines changed: 75 additions & 26 deletions

File tree

NEWS.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# pkgcache (development version)
22

3+
* Fixed a bug where the `Path` field of a `PACKAGES` entry was silently
4+
ignored when the entry also had a `File` field. The target/download
5+
URL for such entries is now correctly derived from both fields,
6+
as `<repodir>/<path>/<file>`. See
7+
https://github.com/r-universe-org/help/issues/715.
8+
39
* New `PKG_USE_BIOCONDUCTOR` environment variable and new
410
`pkg.use_bioconductor` option to opt out from automatic Bioconductor
511
support.

R/packages-gz.R

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -359,34 +359,41 @@ packages_make_target <- function(
359359
res <- rep(NA_character_, length(package))
360360
ext <- get_cran_extension(platform)
361361

362-
## 'File' field, if present
363-
if (!is.null(file)) {
364-
wh <- !is.na(file)
365-
if (any(wh)) {
366-
res[wh] <- paste0(repodir, "/", file[wh])
367-
}
362+
have_file <- if (is.null(file)) rep(FALSE, length(package)) else !is.na(file)
363+
have_path <- if (is.null(path)) rep(FALSE, length(package)) else !is.na(path)
364+
365+
## Both 'Path' and 'File' fields are present: the file named in 'File'
366+
## lives in the subdirectory named in 'Path'.
367+
wh <- have_path & have_file
368+
if (any(wh)) {
369+
res[wh] <- paste0(repodir, "/", path[wh], "/", file[wh])
368370
}
369371

370-
## 'Path' field, if present
371-
if (!is.null(path)) {
372-
wh <- is.na(res) & !is.na(path)
373-
if (any(wh)) {
374-
res[wh] <- paste0(
375-
repodir,
376-
"/",
377-
path[wh],
378-
"/",
379-
package[wh],
380-
"_",
381-
version[wh],
382-
ext[wh]
383-
)
384-
}
372+
## Only 'File' field is present, use it as is, relative to 'repodir'
373+
wh <- have_file & !have_path
374+
if (any(wh)) {
375+
res[wh] <- paste0(repodir, "/", file[wh])
376+
}
377+
378+
## Only 'Path' field is present, it is a subdirectory of 'repodir', and
379+
## the file name is the default one, from the package name and version
380+
wh <- have_path & !have_file
381+
if (any(wh)) {
382+
res[wh] <- paste0(
383+
repodir,
384+
"/",
385+
path[wh],
386+
"/",
387+
package[wh],
388+
"_",
389+
version[wh],
390+
ext[wh]
391+
)
385392
}
386393

387-
## Otherwise default
388-
if (anyNA(res)) {
389-
wh <- is.na(res)
394+
## Neither is present, use the default target path
395+
wh <- !have_file & !have_path
396+
if (any(wh)) {
390397
res[wh] <- paste0(repodir, "/", package[wh], "_", version[wh], ext[wh])
391398
}
392399

tests/testthat/test-packages-gz.R

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ test_that("packages_make_target", {
2323
c("src/contrib/foo", "src/contrib/bar")
2424
)
2525

26+
# When both 'File' and 'Path' are given, they must be combined into
27+
# repodir/path/file, instead of dropping 'Path'. See
28+
# https://github.com/r-universe-org/help/issues/715
2629
expect_equal(
2730
packages_make_target(
2831
"source",
@@ -32,7 +35,7 @@ test_that("packages_make_target", {
3235
c("foo", "bar"),
3336
c("1", "2")
3437
),
35-
c("src/contrib/foo", "src/contrib/bar")
38+
c("src/contrib/1/foo", "src/contrib/2/bar")
3639
)
3740

3841
expect_equal(
@@ -47,6 +50,8 @@ test_that("packages_make_target", {
4750
c("src/contrib/foo/p1_1.0.tar.gz", "src/contrib/bar/p2_2.0.tar.gz")
4851
)
4952

53+
# Mix of: both 'File' and 'Path' present, only 'Path' present, and
54+
# neither present.
5055
expect_equal(
5156
packages_make_target(
5257
"source",
@@ -57,7 +62,7 @@ test_that("packages_make_target", {
5762
c("foox", "bar", NA)
5863
),
5964
c(
60-
"src/contrib/foo",
65+
"src/contrib/foox/foo",
6166
"src/contrib/bar/p2_2.0.tar.gz",
6267
"src/contrib/p3_3.0.tar.gz"
6368
)
@@ -282,6 +287,37 @@ test_that("rbind_expand", {
282287
expect_identical(m$d, c(NA, NA, 1L, 2L))
283288
})
284289

290+
test_that("read_packages_file combines Path and File fields", {
291+
# Regression test for https://github.com/r-universe-org/help/issues/715
292+
# When a PACKAGES entry has both a 'Path' and a 'File' field, the
293+
# resulting target/download URL must combine them as repodir/path/file,
294+
# instead of silently dropping 'Path'.
295+
pkgs_file <- test_temp_file()
296+
cat(
297+
"Package: foo\n",
298+
"Version: 1.0.0\n",
299+
"Path: Archive/foo\n",
300+
"File: foo_1.0.0.tar.gz\n",
301+
"\n",
302+
file = pkgs_file,
303+
sep = ""
304+
)
305+
306+
data <- read_packages_file(
307+
pkgs_file,
308+
mirror = "https://example.com",
309+
repodir = "src/contrib",
310+
platform = "source",
311+
rversion = "*"
312+
)
313+
314+
expect_equal(data$pkgs$target, "src/contrib/Archive/foo/foo_1.0.0.tar.gz")
315+
expect_equal(
316+
data$pkgs$sources[[1]],
317+
"https://example.com/src/contrib/Archive/foo/foo_1.0.0.tar.gz"
318+
)
319+
})
320+
285321
test_that("empty PACKAGES file", {
286322
pkgs <- test_temp_file()
287323
data <- read_packages_file(

0 commit comments

Comments
 (0)