Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
5de5b53
function to parse REMOTES to a list
b-rodrigues Jan 3, 2025
91338c3
separating imports into CRAN imports and REMOTE imports; core functio…
b-rodrigues Jan 3, 2025
1c72890
fetchpkgs now returning full list of git deps
b-rodrigues Jan 3, 2025
486d7b9
returning list for remote packages
b-rodrigues Jan 3, 2025
722619b
first prototype
b-rodrigues Jan 4, 2025
e28b037
handling of remote dependencies seems to work, need to check tests now
b-rodrigues Jan 4, 2025
44cf22a
correctly handling CRAN archive packages now again
b-rodrigues Jan 4, 2025
92c2093
Style via {styler}
b-rodrigues Jan 4, 2025
e409014
try fix handle_remote_deps
mihem Jan 5, 2025
8e375a9
add comments back
mihem Jan 5, 2025
da8543e
add second comment back
mihem Jan 5, 2025
a0ff8c8
fix bug
mihem Jan 5, 2025
191c661
Merge pull request #383 from mihem/fix_handle_remote_deps
b-rodrigues Jan 5, 2025
56efb98
tests passing
b-rodrigues Jan 5, 2025
0eacddd
Style via {styler}
b-rodrigues Jan 5, 2025
04c3028
try to fix double installation of remote packages
mihem Jan 5, 2025
4e2f114
added tests for handling remote deps
b-rodrigues Jan 5, 2025
f4483a5
Style via {styler}
b-rodrigues Jan 5, 2025
388beb5
try to get git_pgk expression instead of name
mihem Jan 5, 2025
5f2d536
simplify fetchpkgs
mihem Jan 5, 2025
7422f34
support for revisions in DESCRIPTION
b-rodrigues Jan 5, 2025
f9a1383
exclude git_pkgs with one pkgs for correction
mihem Jan 5, 2025
2a7eeba
fix small bug
mihem Jan 5, 2025
8a8ecb6
Style via {styler}
b-rodrigues Jan 5, 2025
6875320
Merge pull request #385 from mihem/fix_double_installation_remote_pac…
b-rodrigues Jan 5, 2025
fed503f
Style via {styler}
b-rodrigues Jan 5, 2025
f39a76f
added test for double entry in renv.lock file
b-rodrigues Jan 5, 2025
9030548
Style via {styler}
b-rodrigues Jan 5, 2025
66721f0
updated vignette to reflect changes
b-rodrigues Jan 7, 2025
d9e38de
finished vignetet
b-rodrigues Jan 7, 2025
d3fe565
changed b-rodrigues/lookup commit
b-rodrigues Jan 8, 2025
35abfd7
updated test and vignett
b-rodrigues Jan 8, 2025
4323348
Style via {styler}
b-rodrigues Jan 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions R/available_r.R
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ available_df <- function() {
#' available_r()
available_r <- function() {
r_versions <- unique(available_df()$`R.version`)
c("bleeding-edge", "frozen-edge", "r-devel", "bioc-devel",
"r-devel-bioc-devel", "latest-upstream", r_versions)
c(
"bleeding-edge", "frozen-edge", "r-devel", "bioc-devel",
"r-devel-bioc-devel", "latest-upstream", r_versions
)
}

#' List available dates.
Expand Down
174 changes: 149 additions & 25 deletions R/fetchers.R
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,56 @@ fetchgit <- function(git_pkg) {

output <- get_sri_hash_deps(repo_url, commit)
sri_hash <- output$sri_hash
imports <- output$deps
imports <- unlist(strsplit(imports, split = " "))
# If package has no remote dependencies

imports <- output$deps$imports
imports <- paste(c("", imports), collapse = "\n ")

remotes <- output$deps$remotes

main_package_expression <- generate_git_nix_expression(
package_name,
repo_url,
commit,
sri_hash,
imports,
remotes
)

if (is.null(remotes)) { # if no remote dependencies

output <- main_package_expression
} else { # if there are remote dependencies, start over
remote_packages_expressions <- fetchgits(remotes)

output <- paste0(remote_packages_expressions,
main_package_expression,
collapse = "\n"
)
}

output
}


generate_git_nix_expression <- function(package_name,
repo_url,
commit,
sri_hash,
imports,
remote_deps = NULL) {
# If there are remote dependencies, pass this string
flag_remote_deps <- if (is.null(remote_deps)) {
""
} else {
# Extract package names
remote_pkgs_names <- sapply(remote_deps, function(x) x$package_name)
paste0(" ++ [ ", paste0(remote_pkgs_names, collapse = " "), " ]")
}

sprintf(
'
(pkgs.rPackages.buildRPackage {
%s = (pkgs.rPackages.buildRPackage {
name = \"%s\";
src = pkgs.fetchgit {
url = \"%s\";
Expand All @@ -27,14 +70,16 @@ fetchgit <- function(git_pkg) {
};
propagatedBuildInputs = builtins.attrValues {
inherit (pkgs.rPackages) %s;
};
})
}%s;
});
',
package_name,
package_name,
repo_url,
commit,
sri_hash,
imports
imports,
flag_remote_deps
)
}

Expand All @@ -60,8 +105,7 @@ fetchzip <- function(archive_pkg, sri_hash = NULL) {
if (is.null(sri_hash)) {
output <- get_sri_hash_deps(repo_url, commit = NULL)
sri_hash <- output$sri_hash
imports <- output$deps
imports <- unlist(strsplit(imports, split = " "))
imports <- output$deps$imports
imports <- paste(c("", imports), collapse = "\n ")
} else {
sri_hash <- sri_hash
Expand All @@ -70,7 +114,7 @@ fetchzip <- function(archive_pkg, sri_hash = NULL) {

sprintf(
'
(pkgs.rPackages.buildRPackage {
%s = (pkgs.rPackages.buildRPackage {
name = \"%s\";
src = pkgs.fetchzip {
url = \"%s\";
Expand All @@ -79,8 +123,9 @@ fetchzip <- function(archive_pkg, sri_hash = NULL) {
propagatedBuildInputs = builtins.attrValues {
inherit (pkgs.rPackages) %s;
};
})
}),
',
package_name,
package_name,
repo_url,
sri_hash,
Expand All @@ -105,7 +150,7 @@ remove_base <- function(list_imports) {
list_imports
)

paste(na.omit(imports_nobase), collapse = " ")
na.omit(imports_nobase)
}


Expand Down Expand Up @@ -145,11 +190,59 @@ get_imports <- function(path) {

columns_of_interest <- c("Depends", "Imports", "LinkingTo")

imports <- as.data.frame(read.dcf(desc_path))

existing_columns <- intersect(columns_of_interest, colnames(imports))
imports_df <- as.data.frame(read.dcf(desc_path))

existing_columns <- intersect(columns_of_interest, colnames(imports_df))

imports <- imports_df[, existing_columns, drop = FALSE]

existing_remotes <- intersect("Remotes", colnames(imports_df))

if (!identical(existing_remotes, character(0))) {
remotes <- imports_df[, existing_remotes, drop = FALSE]
# remotes are of the form username/packagename so we need
# to only keep packagename
remotes <- gsub("\n", "", x = unlist(strsplit(remotes$Remotes, ",")))
# Get user names
remote_pkgs_usernames <- strsplit(remotes, "/") |>
sapply(function(x) x[[1]])

# Now remove user name and
# split at "@" or "#" character to get name and commit or PR separated
remote_pkgs_names_and_refs <- sub(".*?/", "", remotes)
remote_pkgs_names_and_refs <- strsplit(remote_pkgs_names_and_refs, "(@|#)")

remote_pkgs_names <- remote_pkgs_names_and_refs |>
sapply(function(x) x[[1]])

# Check if we have a list of lists of two elements: a package name
# and a ref. If not, add "HEAD" to it.
remote_pkgs_refs <- lapply(remote_pkgs_names_and_refs, function(sublist) {
if (length(sublist) == 1) {
c(sublist, "HEAD")
} else {
sublist
}
}) |>
sapply(function(x) x[[2]])

urls <- paste0(
"https://github.com/",
remote_pkgs_usernames, "/",
remote_pkgs_names
)

imports <- imports[, existing_columns, drop = FALSE]
remote_pkgs <- lapply(seq_along(remote_pkgs_names), function(i) {
list(
"package_name" = remote_pkgs_names[i],
"repo_url" = urls[i],
"commit" = remote_pkgs_refs[i]
)
})
} else {
remote_pkgs_names <- character(0)
remote_pkgs <- NULL
}

if (!is.null(imports) && length(imports) > 0) {
output <- unname(trimws(unlist(strsplit(unlist(imports), split = ","))))
Expand All @@ -165,7 +258,17 @@ get_imports <- function(path) {

output <- remove_base(unique(output))

gsub("\\.", "_", output)
output <- gsub("\\.", "_", output)

# Remote packages are included in imports, so we need
# remove remotes from imports
output_imports <- setdiff(output, remote_pkgs_names)

list(
"package" = imports_df$Package,
"imports" = output_imports,
"remotes" = remote_pkgs
)
}


Expand Down Expand Up @@ -282,18 +385,39 @@ fetchzips <- function(archive_pkgs) {
}
}

#' fetchpkgs Downloads and installs packages hosted in the CRAN archives or
#' Github.
#' @param git_pkgs A list of three elements: "package_name", the name of the
#' package, "repo_url", the repository's url and "commit", the commit hash of
#' interest. This argument can also be a list of lists of these four elements.
#' @param archive_pkgs A character, or an atomic vector of characters.
#' @return A character. The Nix definition to download and build the R package
#' from the CRAN archives.
#' fetchpkgs Downloads and installs packages from CRAN archives or Github
#' @param git_pkgs List of Git packages with name, url and commit
#' @param archive_pkgs Vector of CRAN archive package names
#' @return Nix definition string for building the packages
#' @noRd
fetchpkgs <- function(git_pkgs, archive_pkgs) {
paste(fetchgits(git_pkgs),
# Only include git packages that aren't already remote dependencies
if (all(sapply(git_pkgs, is.list))) {
all_remotes <- unique(unlist(lapply(git_pkgs, get_remote)))
git_pkgs <- git_pkgs[!sapply(git_pkgs, function(pkg) {
pkg$package_name %in% all_remotes
})]
}

# Combine git and archive package definitions
paste(
fetchgits(git_pkgs),
fetchzips(archive_pkgs),
collapse = "\n"
)
}

#' get_remote Retrieves the names of remote dependencies for a given Git package
#' @param git_pkg A list of three elements: "package_name", the name of the
#' package, "repo_url", the repository's URL, and "commit", the commit hash of
#' interest.
#' @return A character vector containing the names of remote dependencies.
#' @noRd
get_remote <- function(git_pkg) {
repo_url <- git_pkg$repo_url
commit <- git_pkg$commit
output <- get_sri_hash_deps(repo_url, commit)
remotes <- output$deps$remotes
remote_package_names <- sapply(remotes, `[[`, "package_name")
return(remote_package_names)
}
8 changes: 5 additions & 3 deletions R/get_latest.R
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@ get_latest <- function(r_version) {
"'bleeding-edge' and 'frozen-edge'."
)
} else if (
!(r_version %in% c("r-devel-bioc-devel", "r-devel", "bioc-devel",
"bleeding-edge", "frozen-edge", available_r()))
) {
!(r_version %in% c(
"r-devel-bioc-devel", "r-devel", "bioc-devel",
"bleeding-edge", "frozen-edge", available_r()
))
) {
stop(
"The provided R version is too recent,\nand not yet included in `nixpkgs`.\n",
"You can list available versions using `available_r()`.\n",
Expand Down
10 changes: 5 additions & 5 deletions R/nix_hash.R
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#' @return list with following elements:
#' - `sri_hash`: string with SRI hash of the NAR serialization of a Github repo
#' at a given deterministic git commit ID (SHA-1)
#' - `deps`: string with R package dependencies separarated by space.
#' - `deps`: list with three elements: 'package', its 'imports' and its 'remotes'
#' @noRd
nix_hash <- function(repo_url, commit) {
if (grepl("(github)|(gitlab)", repo_url)) {
Expand All @@ -27,7 +27,7 @@ nix_hash <- function(repo_url, commit) {
#' @return list with following elements:
#' - `sri_hash`: string with SRI hash of the NAR serialization of a Github repo
#' at a given deterministic git commit ID (SHA-1)
#' - `deps`: string with R package dependencies separarated by space.
#' - `deps`: list with three elements: 'package', its 'imports' and its 'remotes'
#' @noRd
hash_url <- function(url) {
tdir <- tempdir()
Expand Down Expand Up @@ -195,7 +195,7 @@ hash_cran <- function(repo_url) {
#' @return list with following elements:
#' - `sri_hash`: string with SRI hash of the NAR serialization of a Github repo
#' at a given deterministic git commit ID (SHA-1)
#' - `deps`: string with R package dependencies separarated by space.
#' - `deps`: list with three elements: 'package', its 'imports' and its 'remotes'
#' @noRd
hash_git <- function(repo_url, commit) {
trailing_slash <- grepl("/$", repo_url)
Expand Down Expand Up @@ -226,7 +226,7 @@ hash_git <- function(repo_url, commit) {
#' sake, NULL for archived CRAN packages.
#' @return list with following elements:
#' - `sri_hash`: string with SRI hash of the NAR serialization of a Github repo
#' - `deps`: string with R package dependencies separarated by space.
#' - `deps`: list with three elements: 'package', its 'imports' and its 'remotes'
#' @noRd
nix_hash_online <- function(repo_url, commit) {
# handle to get error for status code 404
Expand Down Expand Up @@ -269,7 +269,7 @@ nix_hash_online <- function(repo_url, commit) {
#' @return list with following elements:
#' - `sri_hash`: string with SRI hash of the NAR serialization of a Github repo
#' at a given deterministic git commit ID (SHA-1)
#' - `deps`: string with R package dependencies separarated by space.
#' - `deps`: list with three elements: 'package', its 'imports' and its 'remotes'
#' @noRd
get_sri_hash_deps <- function(repo_url, commit) {
# if no `options(rix.sri_hash=)` is set, default is `"check_nix"`
Expand Down
21 changes: 19 additions & 2 deletions R/rix.R
Original file line number Diff line number Diff line change
Expand Up @@ -282,9 +282,26 @@ for more details."

# If there are R packages from Git, passes the string "git_archive_pkgs" to buildInputs
flag_git_archive <- if (
!is.null(cran_pkgs$archive_pkgs) || !is.null(git_pkgs)
!is.null(git_pkgs) || !is.null(cran_pkgs$archive_pkgs)
) {
"git_archive_pkgs"
# If git_pkgs is a list of lists, then sapply will succeed
# if not, then we can access "package_name" directly
git_pkgs_names <- if (!is.null(git_pkgs)) {
tryCatch(
sapply(git_pkgs, function(x) x$package_name),
error = function(e) git_pkgs$package_name
)
}
# CRAN archive pkgs are written as "AER@123"
# so we need to split at the '@' character and then
# walk through the list to grab the first element
# which will be the name of the package
cran_archive_names <- if (!is.null(cran_pkgs$archive_pkgs)) {
pkgs <- strsplit(cran_pkgs$archive_pkgs, split = "@")
sapply(pkgs, function(x) x[[1]])
}

paste0(c(git_pkgs_names, cran_archive_names), collapse = " ")
} else {
""
}
Expand Down
3 changes: 1 addition & 2 deletions R/rix_helpers.R
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,7 @@ generate_git_archived_pkgs <- function(git_pkgs,
if (flag_git_archive == "") {
NULL
} else {
sprintf("
git_archive_pkgs = [%s ];\n", fetchpkgs(git_pkgs, archive_pkgs))
fetchpkgs(git_pkgs, archive_pkgs)
}
}

Expand Down
Loading