From 564cafd2d13fa5f7632d2d180b206cc89bcd1b7b Mon Sep 17 00:00:00 2001 From: dgkf <18220321+dgkf@users.noreply.github.com> Date: Fri, 1 Mar 2024 18:50:37 -0500 Subject: [PATCH 01/23] updating pkgdepends gitlab url parsing; fix authed ls-remotes --- R/git-protocol.R | 29 +++++++++++++++++++++++++++-- R/type-gitlab.R | 26 ++++++++++++++++++++------ 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/R/git-protocol.R b/R/git-protocol.R index 0f41cb7a..fef62632 100644 --- a/R/git-protocol.R +++ b/R/git-protocol.R @@ -788,10 +788,22 @@ async_git_send_message_v2 <- function( "git-protocol" = "version=2", "content-length" = as.character(length(msg)) ) + + options <- list() + tryCatch( + { + creds <- gitcreds_get(url) + options$username <- creds$username + options$password <- creds$password + }, + error = function(e) NULL + ) + http_post( url2, data = msg, - headers = headers + headers = headers, + options = options )$then(http_stop_for_status)$ then(function(res) git_parse_message(res$content)) } @@ -1006,11 +1018,24 @@ async_git_list_refs_v2 <- function(url, prefixes = character()) { url; prefixes url1 <- paste0(url, "/info/refs?service=git-upload-pack") + headers <- c( "User-Agent" = git_ua(), "git-protocol" = "version=2" ) - http_get(url1, headers = headers)$ + + # headers from tracing action with GIT_CURL_VERBOSE=1 GIT_TRACE=1 + options <- list() + tryCatch( + { + creds <- gitcreds_get(url) + options$username <- creds$username + options$password <- creds$password + }, + error = function(e) NULL + ) + + http_get(url1, headers = headers, options = options)$ then(http_stop_for_status)$ then(function(res) async_git_list_refs_v2_process_1(res, url, prefixes)) } diff --git a/R/type-gitlab.R b/R/type-gitlab.R index 52bd7f56..bf085354 100644 --- a/R/type-gitlab.R +++ b/R/type-gitlab.R @@ -1,11 +1,10 @@ parse_remote_gitlab <- function(specs, config, ...) { - pds <- re_match(specs, gitlab_rx()) pds$ref <- pds$.text pds$protocol[pds$protocol == ""] <- "https" pds$host[pds$host == ""] <- "gitlab.com" - pds$path <- paste0("/", pds$username, "/") + pds$path <- paste0("/", pds$projectpath, "/", pds$project) pds$dotgit <- "" pds$commitish[pds$commitish == ""] <- "HEAD" pds$url <- paste0(pds$protocol, "://", pds$host, pds$path, pds$repo, ".git") @@ -55,16 +54,31 @@ installedok_remote_gitlab <- function(installed, solution, config, ...) { installedok_remote_git(installed, solution, config, ...) } +# source: https://docs.gitlab.com/ee/user/reserved_names.html#limitations-on-usernames-project-and-group-names +gitlab_slug_rx <- function() { + "[a-zA-Z0-9][-._a-zA-Z0-9]*[a-zA-Z0-9]" +} + +gitlab_project_rx <- function() { + paste0("(?", gitlab_slug_rx(), ")") +} + +gitlab_project_path_rx <- function() { + paste0("(?", gitlab_slug_rx(), "(?:/", gitlab_slug_rx(), ")*)") +} + gitlab_rx <- function() { paste0( "^", ## Optional package name "(?:(?", package_name_rx(), ")=)?", "gitlab::", - "(?:(?[^/]*)://(?[^/]+))?", - github_username_rx(), "/", - github_repo_rx(), - github_subdir_rx(), "?", + ## Optional protocol::host + "(?:(?[^/]*)://(?[^/]+)/)?", + gitlab_project_path_rx(), "/", + gitlab_project_rx(), + ## Optional subdirectory, prefixed with /-, ie project/-/sub/dir + "(?:/-", github_subdir_rx(), ")?", "(?:", github_commitish_rx(), ")?", "$" ) From 20994a892a89a8a71e15e4f0f5b0e4ecfa450670 Mon Sep 17 00:00:00 2001 From: dgkf <18220321+dgkf@users.noreply.github.com> Date: Mon, 4 Mar 2024 18:48:31 -0500 Subject: [PATCH 02/23] cleaning up tests --- R/errors.R | 26 +- R/install-plan.R | 4 +- R/type-gitlab.R | 8 +- tests/testthat/_snaps/parse-remotes.md | 561 ++++++++++++++++++++++--- tests/testthat/_snaps/type-gitlab.md | 2 +- tests/testthat/helper-install.R | 2 +- tests/testthat/test-parse-remotes.R | 27 +- tests/testthat/test-type-gitlab.R | 4 +- 8 files changed, 543 insertions(+), 91 deletions(-) diff --git a/R/errors.R b/R/errors.R index 3f10eda8..ed61bd2e 100644 --- a/R/errors.R +++ b/R/errors.R @@ -239,7 +239,7 @@ err <- local({ cond <- process_call(cond) if (!is.null(parent)) { - cond$parent <- process_call(parent) + cond$parents <- process_call(parent) } # We can set an option to always add the trace to the thrown @@ -723,23 +723,23 @@ err <- local({ c( paste0(if (add_exp) exp, msg), - if (inherits(cond$parent, "condition")) { - msg <- if (full && inherits(cond$parent, "rlib_error_3_0")) { - format(cond$parent, + if (inherits(cond$parents, "condition")) { + msg <- if (full && inherits(cond$parents, "rlib_error_3_0")) { + format(cond$parents, trace = FALSE, full = TRUE, class = FALSE, header = FALSE, advice = FALSE ) - } else if (inherits(cond$parent, "interrupt")) { + } else if (inherits(cond$parents, "interrupt")) { "interrupt" } else { - conditionMessage(cond$parent) + conditionMessage(cond$parents) } add_exp <- substr(cli::ansi_strip(msg[1]), 1, 1) != "!" if (add_exp) msg[1] <- paste0(exp, msg[1]) - c(format_header_line_cli(cond$parent, prefix = "Caused by error"), + c(format_header_line_cli(cond$parents, prefix = "Caused by error"), msg ) } @@ -753,25 +753,25 @@ err <- local({ add_exp <- is.null(names(cond$message)) c( paste0(if (add_exp) exp, cnd_message_robust(cond)), - if (inherits(cond$parent, "condition")) { - msg <- if (full && inherits(cond$parent, "rlib_error_3_0")) { - format(cond$parent, + if (inherits(cond$parents, "condition")) { + msg <- if (full && inherits(cond$parents, "rlib_error_3_0")) { + format(cond$parents, trace = FALSE, full = TRUE, class = FALSE, header = FALSE, advice = FALSE ) - } else if (inherits(cond$parent, "interrupt")) { + } else if (inherits(cond$parents, "interrupt")) { "interrupt" } else { - conditionMessage(cond$parent) + conditionMessage(cond$parents) } add_exp <- substr(msg[1], 1, 1) != "!" if (add_exp) { msg[1] <- paste0(exp, msg[1]) } - c(format_header_line_plain(cond$parent, prefix = "Caused by error"), + c(format_header_line_plain(cond$parents, prefix = "Caused by error"), msg ) } diff --git a/R/install-plan.R b/R/install-plan.R index fa5d104d..73e6fb92 100644 --- a/R/install-plan.R +++ b/R/install-plan.R @@ -667,7 +667,7 @@ stop_task_package_build <- function(state, worker) { state$cache$add(state$plan$file[pkgidx], state$plan$target[pkgidx], package = pkg, version = version, built = TRUE, sha256 = state$plan$extra[[pkgidx]]$remotesha, - vignettes = state$plan$vignette[pkgidx], + vignettes = state$plan$vignettes[pkgidx], platform = "source"), error = function(err) { alert("warning", "Failed to add {.pkg {pkg}} \\ @@ -744,7 +744,7 @@ stop_task_build <- function(state, worker) { state$cache$add(state$plan$file[pkgidx], target, package = pkg, version = version, built = TRUE, sha256 = state$plan$extra[[pkgidx]]$remotesha, - vignettes = state$plan$vignette[pkgidx], + vignettes = state$plan$vignettes[pkgidx], platform = ptfm, rversion = rv), error = function(err) { alert("warning", "Failed to add {.pkg {pkg}} \\ diff --git a/R/type-gitlab.R b/R/type-gitlab.R index bf085354..bf0346e5 100644 --- a/R/type-gitlab.R +++ b/R/type-gitlab.R @@ -7,11 +7,11 @@ parse_remote_gitlab <- function(specs, config, ...) { pds$path <- paste0("/", pds$projectpath, "/", pds$project) pds$dotgit <- "" pds$commitish[pds$commitish == ""] <- "HEAD" - pds$url <- paste0(pds$protocol, "://", pds$host, pds$path, pds$repo, ".git") + pds$url <- paste0(pds$protocol, "://", pds$host, pds$path, ".git") cn <- setdiff(colnames(pds), c(".match", ".text")) pds <- pds[, cn] pds$type <- "gitlab" - pds$package <- ifelse(nzchar(pds$package), pds$package, pds$repo) + pds$package <- ifelse(nzchar(pds$package), pds$package, pds$project) lapply( seq_len(nrow(pds)), function(i) as.list(pds[i,]) @@ -23,8 +23,8 @@ resolve_remote_gitlab <- function(remote, direct, config, cache, resolve_remote_git(remote, direct, config, cache, dependencies, ...)$ then(function(res) { res$metadata["RemoteHost"] <- remote$host - res$metadata["RemoteRepo"] <- remote$repo - res$metadata["RemoteUsername"] <- remote$username + res$metadata["RemoteRepo"] <- remote$project + res$metadata["RemoteUsername"] <- remote$projectpath res$metadata["RemoteType"] <- "gitlab" if (!is.null(remote$subdir) && remote$subdir != "") { res$metadata["RemoteSubdir"] <- remote$subdir diff --git a/tests/testthat/_snaps/parse-remotes.md b/tests/testthat/_snaps/parse-remotes.md index f0ba8ece..bcda31d0 100644 --- a/tests/testthat/_snaps/parse-remotes.md +++ b/tests/testthat/_snaps/parse-remotes.md @@ -261,10 +261,10 @@ # gitlab Code - parse_pkg_ref("gitlab::user/repo") + parse_pkg_ref("gitlab::user/project") Output $package - [1] "repo" + [1] "project" $protocol [1] "https" @@ -272,11 +272,11 @@ $host [1] "gitlab.com" - $username + $projectpath [1] "user" - $repo - [1] "repo" + $project + [1] "project" $subdir [1] "" @@ -285,16 +285,16 @@ [1] "HEAD" $ref - [1] "gitlab::user/repo" + [1] "gitlab::user/project" $path - [1] "/user/" + [1] "/user/project" $dotgit [1] "" $url - [1] "https://gitlab.com/user/repo.git" + [1] "https://gitlab.com/user/project.git" $type [1] "gitlab" @@ -305,10 +305,10 @@ attr(,"class") [1] "remote_ref_gitlab" "remote_ref" "list" Code - parse_pkg_ref("gitlab::user/repo@ref") + parse_pkg_ref("gitlab::user/project@ref") Output $package - [1] "repo" + [1] "project" $protocol [1] "https" @@ -316,11 +316,11 @@ $host [1] "gitlab.com" - $username + $projectpath [1] "user" - $repo - [1] "repo" + $project + [1] "project" $subdir [1] "" @@ -329,16 +329,16 @@ [1] "ref" $ref - [1] "gitlab::user/repo@ref" + [1] "gitlab::user/project@ref" $path - [1] "/user/" + [1] "/user/project" $dotgit [1] "" $url - [1] "https://gitlab.com/user/repo.git" + [1] "https://gitlab.com/user/project.git" $type [1] "gitlab" @@ -349,10 +349,10 @@ attr(,"class") [1] "remote_ref_gitlab" "remote_ref" "list" Code - parse_pkg_ref("gitlab::user/repo/sub/dir") + parse_pkg_ref("gitlab::user/project/-/sub/dir") Output $package - [1] "repo" + [1] "project" $protocol [1] "https" @@ -360,11 +360,11 @@ $host [1] "gitlab.com" - $username + $projectpath [1] "user" - $repo - [1] "repo" + $project + [1] "project" $subdir [1] "sub/dir" @@ -373,16 +373,16 @@ [1] "HEAD" $ref - [1] "gitlab::user/repo/sub/dir" + [1] "gitlab::user/project/-/sub/dir" $path - [1] "/user/" + [1] "/user/project" $dotgit [1] "" $url - [1] "https://gitlab.com/user/repo.git" + [1] "https://gitlab.com/user/project.git" $type [1] "gitlab" @@ -393,10 +393,10 @@ attr(,"class") [1] "remote_ref_gitlab" "remote_ref" "list" Code - parse_pkg_ref("gitlab::user/repo/sub/dir@ref") + parse_pkg_ref("gitlab::user/project/-/sub/dir@ref") Output $package - [1] "repo" + [1] "project" $protocol [1] "https" @@ -404,11 +404,11 @@ $host [1] "gitlab.com" - $username + $projectpath [1] "user" - $repo - [1] "repo" + $project + [1] "project" $subdir [1] "sub/dir" @@ -417,16 +417,16 @@ [1] "ref" $ref - [1] "gitlab::user/repo/sub/dir@ref" + [1] "gitlab::user/project/-/sub/dir@ref" $path - [1] "/user/" + [1] "/user/project" $dotgit [1] "" $url - [1] "https://gitlab.com/user/repo.git" + [1] "https://gitlab.com/user/project.git" $type [1] "gitlab" @@ -437,7 +437,227 @@ attr(,"class") [1] "remote_ref_gitlab" "remote_ref" "list" Code - parse_pkg_ref("pkg=gitlab::user/repo") + parse_pkg_ref("gitlab::group/subgroup/project") + Output + $package + [1] "project" + + $protocol + [1] "https" + + $host + [1] "gitlab.com" + + $projectpath + [1] "group/subgroup" + + $project + [1] "project" + + $subdir + [1] "" + + $commitish + [1] "HEAD" + + $ref + [1] "gitlab::group/subgroup/project" + + $path + [1] "/group/subgroup/project" + + $dotgit + [1] "" + + $url + [1] "https://gitlab.com/group/subgroup/project.git" + + $type + [1] "gitlab" + + $params + character(0) + + attr(,"class") + [1] "remote_ref_gitlab" "remote_ref" "list" + Code + parse_pkg_ref("gitlab::group/subgroup/project@ref") + Output + $package + [1] "project" + + $protocol + [1] "https" + + $host + [1] "gitlab.com" + + $projectpath + [1] "group/subgroup" + + $project + [1] "project" + + $subdir + [1] "" + + $commitish + [1] "ref" + + $ref + [1] "gitlab::group/subgroup/project@ref" + + $path + [1] "/group/subgroup/project" + + $dotgit + [1] "" + + $url + [1] "https://gitlab.com/group/subgroup/project.git" + + $type + [1] "gitlab" + + $params + character(0) + + attr(,"class") + [1] "remote_ref_gitlab" "remote_ref" "list" + Code + parse_pkg_ref("gitlab::group/subgroup/project/-/sub/dir") + Output + $package + [1] "project" + + $protocol + [1] "https" + + $host + [1] "gitlab.com" + + $projectpath + [1] "group/subgroup" + + $project + [1] "project" + + $subdir + [1] "sub/dir" + + $commitish + [1] "HEAD" + + $ref + [1] "gitlab::group/subgroup/project/-/sub/dir" + + $path + [1] "/group/subgroup/project" + + $dotgit + [1] "" + + $url + [1] "https://gitlab.com/group/subgroup/project.git" + + $type + [1] "gitlab" + + $params + character(0) + + attr(,"class") + [1] "remote_ref_gitlab" "remote_ref" "list" + Code + parse_pkg_ref("gitlab::group/subgroup/project/-/sub/dir@ref") + Output + $package + [1] "project" + + $protocol + [1] "https" + + $host + [1] "gitlab.com" + + $projectpath + [1] "group/subgroup" + + $project + [1] "project" + + $subdir + [1] "sub/dir" + + $commitish + [1] "ref" + + $ref + [1] "gitlab::group/subgroup/project/-/sub/dir@ref" + + $path + [1] "/group/subgroup/project" + + $dotgit + [1] "" + + $url + [1] "https://gitlab.com/group/subgroup/project.git" + + $type + [1] "gitlab" + + $params + character(0) + + attr(,"class") + [1] "remote_ref_gitlab" "remote_ref" "list" + Code + parse_pkg_ref("gitlab::https://acme.co/group/subgroup/project/-/sub/dir@ref") + Output + $package + [1] "project" + + $protocol + [1] "https" + + $host + [1] "acme.co" + + $projectpath + [1] "group/subgroup" + + $project + [1] "project" + + $subdir + [1] "sub/dir" + + $commitish + [1] "ref" + + $ref + [1] "gitlab::https://acme.co/group/subgroup/project/-/sub/dir@ref" + + $path + [1] "/group/subgroup/project" + + $dotgit + [1] "" + + $url + [1] "https://acme.co/group/subgroup/project.git" + + $type + [1] "gitlab" + + $params + character(0) + + attr(,"class") + [1] "remote_ref_gitlab" "remote_ref" "list" + Code + parse_pkg_ref("pkg=gitlab::user/project") Output $package [1] "pkg" @@ -448,11 +668,11 @@ $host [1] "gitlab.com" - $username + $projectpath [1] "user" - $repo - [1] "repo" + $project + [1] "project" $subdir [1] "" @@ -461,16 +681,16 @@ [1] "HEAD" $ref - [1] "pkg=gitlab::user/repo" + [1] "pkg=gitlab::user/project" $path - [1] "/user/" + [1] "/user/project" $dotgit [1] "" $url - [1] "https://gitlab.com/user/repo.git" + [1] "https://gitlab.com/user/project.git" $type [1] "gitlab" @@ -481,7 +701,7 @@ attr(,"class") [1] "remote_ref_gitlab" "remote_ref" "list" Code - parse_pkg_ref("pkg=gitlab::user/repo@ref") + parse_pkg_ref("pkg=gitlab::user/project@ref") Output $package [1] "pkg" @@ -492,11 +712,11 @@ $host [1] "gitlab.com" - $username + $projectpath [1] "user" - $repo - [1] "repo" + $project + [1] "project" $subdir [1] "" @@ -505,16 +725,16 @@ [1] "ref" $ref - [1] "pkg=gitlab::user/repo@ref" + [1] "pkg=gitlab::user/project@ref" $path - [1] "/user/" + [1] "/user/project" $dotgit [1] "" $url - [1] "https://gitlab.com/user/repo.git" + [1] "https://gitlab.com/user/project.git" $type [1] "gitlab" @@ -525,7 +745,7 @@ attr(,"class") [1] "remote_ref_gitlab" "remote_ref" "list" Code - parse_pkg_ref("pkg=gitlab::user/repo/sub/dir") + parse_pkg_ref("pkg=gitlab::user/project/-/sub/dir") Output $package [1] "pkg" @@ -536,11 +756,11 @@ $host [1] "gitlab.com" - $username + $projectpath [1] "user" - $repo - [1] "repo" + $project + [1] "project" $subdir [1] "sub/dir" @@ -549,16 +769,16 @@ [1] "HEAD" $ref - [1] "pkg=gitlab::user/repo/sub/dir" + [1] "pkg=gitlab::user/project/-/sub/dir" $path - [1] "/user/" + [1] "/user/project" $dotgit [1] "" $url - [1] "https://gitlab.com/user/repo.git" + [1] "https://gitlab.com/user/project.git" $type [1] "gitlab" @@ -569,7 +789,7 @@ attr(,"class") [1] "remote_ref_gitlab" "remote_ref" "list" Code - parse_pkg_ref("pkg=gitlab::user/repo/sub/dir@ref") + parse_pkg_ref("pkg=gitlab::user/project/-/sub/dir@ref") Output $package [1] "pkg" @@ -580,11 +800,232 @@ $host [1] "gitlab.com" - $username + $projectpath [1] "user" - $repo - [1] "repo" + $project + [1] "project" + + $subdir + [1] "sub/dir" + + $commitish + [1] "ref" + + $ref + [1] "pkg=gitlab::user/project/-/sub/dir@ref" + + $path + [1] "/user/project" + + $dotgit + [1] "" + + $url + [1] "https://gitlab.com/user/project.git" + + $type + [1] "gitlab" + + $params + character(0) + + attr(,"class") + [1] "remote_ref_gitlab" "remote_ref" "list" + Code + parse_pkg_ref("pkg=gitlab::group/subgroup/project") + Output + $package + [1] "pkg" + + $protocol + [1] "https" + + $host + [1] "gitlab.com" + + $projectpath + [1] "group/subgroup" + + $project + [1] "project" + + $subdir + [1] "" + + $commitish + [1] "HEAD" + + $ref + [1] "pkg=gitlab::group/subgroup/project" + + $path + [1] "/group/subgroup/project" + + $dotgit + [1] "" + + $url + [1] "https://gitlab.com/group/subgroup/project.git" + + $type + [1] "gitlab" + + $params + character(0) + + attr(,"class") + [1] "remote_ref_gitlab" "remote_ref" "list" + Code + parse_pkg_ref("pkg=gitlab::group/subgroup/project@ref") + Output + $package + [1] "pkg" + + $protocol + [1] "https" + + $host + [1] "gitlab.com" + + $projectpath + [1] "group/subgroup" + + $project + [1] "project" + + $subdir + [1] "" + + $commitish + [1] "ref" + + $ref + [1] "pkg=gitlab::group/subgroup/project@ref" + + $path + [1] "/group/subgroup/project" + + $dotgit + [1] "" + + $url + [1] "https://gitlab.com/group/subgroup/project.git" + + $type + [1] "gitlab" + + $params + character(0) + + attr(,"class") + [1] "remote_ref_gitlab" "remote_ref" "list" + Code + parse_pkg_ref("pkg=gitlab::group/subgroup/project/-/sub/dir") + Output + $package + [1] "pkg" + + $protocol + [1] "https" + + $host + [1] "gitlab.com" + + $projectpath + [1] "group/subgroup" + + $project + [1] "project" + + $subdir + [1] "sub/dir" + + $commitish + [1] "HEAD" + + $ref + [1] "pkg=gitlab::group/subgroup/project/-/sub/dir" + + $path + [1] "/group/subgroup/project" + + $dotgit + [1] "" + + $url + [1] "https://gitlab.com/group/subgroup/project.git" + + $type + [1] "gitlab" + + $params + character(0) + + attr(,"class") + [1] "remote_ref_gitlab" "remote_ref" "list" + Code + parse_pkg_ref("pkg=gitlab::group/subgroup/project/-/sub/dir@ref") + Output + $package + [1] "pkg" + + $protocol + [1] "https" + + $host + [1] "gitlab.com" + + $projectpath + [1] "group/subgroup" + + $project + [1] "project" + + $subdir + [1] "sub/dir" + + $commitish + [1] "ref" + + $ref + [1] "pkg=gitlab::group/subgroup/project/-/sub/dir@ref" + + $path + [1] "/group/subgroup/project" + + $dotgit + [1] "" + + $url + [1] "https://gitlab.com/group/subgroup/project.git" + + $type + [1] "gitlab" + + $params + character(0) + + attr(,"class") + [1] "remote_ref_gitlab" "remote_ref" "list" + Code + parse_pkg_ref( + "pkg=gitlab::https://acme.co/group/subgroup/project/-/sub/dir@ref") + Output + $package + [1] "pkg" + + $protocol + [1] "https" + + $host + [1] "acme.co" + + $projectpath + [1] "group/subgroup" + + $project + [1] "project" $subdir [1] "sub/dir" @@ -593,16 +1034,16 @@ [1] "ref" $ref - [1] "pkg=gitlab::user/repo/sub/dir@ref" + [1] "pkg=gitlab::https://acme.co/group/subgroup/project/-/sub/dir@ref" $path - [1] "/user/" + [1] "/group/subgroup/project" $dotgit [1] "" $url - [1] "https://gitlab.com/user/repo.git" + [1] "https://acme.co/group/subgroup/project.git" $type [1] "gitlab" diff --git a/tests/testthat/_snaps/type-gitlab.md b/tests/testthat/_snaps/type-gitlab.md index 9fe80373..f7847769 100644 --- a/tests/testthat/_snaps/type-gitlab.md +++ b/tests/testthat/_snaps/type-gitlab.md @@ -130,7 +130,7 @@ RemoteUrl "https://gitlab.com/gaborcsardi/feather.git" RemotePkgRef - "gitlab::gaborcsardi/feather/R" + "gitlab::gaborcsardi/feather/-/R" RemoteRef "HEAD" RemoteSha diff --git a/tests/testthat/helper-install.R b/tests/testthat/helper-install.R index 3f622fd2..e2f6bcb2 100644 --- a/tests/testthat/helper-install.R +++ b/tests/testthat/helper-install.R @@ -115,7 +115,7 @@ make_dummy_worker_process <- function(n_iter = 10, sleep = 1, status = 0) { } make_install_plan <- function(ref, lib = .libPaths()[1]) { - r <- pkg_plan$new(ref, lib = lib) + r <- pkg_plan$new(ref, library = lib) r$resolve() r$solve() r$download_solution() diff --git a/tests/testthat/test-parse-remotes.R b/tests/testthat/test-parse-remotes.R index 5caef05f..0b1e727b 100644 --- a/tests/testthat/test-parse-remotes.R +++ b/tests/testthat/test-parse-remotes.R @@ -300,13 +300,24 @@ test_that("explicit package names", { test_that("gitlab", { expect_snapshot({ - parse_pkg_ref("gitlab::user/repo") - parse_pkg_ref("gitlab::user/repo@ref") - parse_pkg_ref("gitlab::user/repo/sub/dir") - parse_pkg_ref("gitlab::user/repo/sub/dir@ref") - parse_pkg_ref("pkg=gitlab::user/repo") - parse_pkg_ref("pkg=gitlab::user/repo@ref") - parse_pkg_ref("pkg=gitlab::user/repo/sub/dir") - parse_pkg_ref("pkg=gitlab::user/repo/sub/dir@ref") + parse_pkg_ref("gitlab::user/project") + parse_pkg_ref("gitlab::user/project@ref") + parse_pkg_ref("gitlab::user/project/-/sub/dir") + parse_pkg_ref("gitlab::user/project/-/sub/dir@ref") + parse_pkg_ref("gitlab::group/subgroup/project") + parse_pkg_ref("gitlab::group/subgroup/project@ref") + parse_pkg_ref("gitlab::group/subgroup/project/-/sub/dir") + parse_pkg_ref("gitlab::group/subgroup/project/-/sub/dir@ref") + parse_pkg_ref("gitlab::https://acme.co/group/subgroup/project/-/sub/dir@ref") + + parse_pkg_ref("pkg=gitlab::user/project") + parse_pkg_ref("pkg=gitlab::user/project@ref") + parse_pkg_ref("pkg=gitlab::user/project/-/sub/dir") + parse_pkg_ref("pkg=gitlab::user/project/-/sub/dir@ref") + parse_pkg_ref("pkg=gitlab::group/subgroup/project") + parse_pkg_ref("pkg=gitlab::group/subgroup/project@ref") + parse_pkg_ref("pkg=gitlab::group/subgroup/project/-/sub/dir") + parse_pkg_ref("pkg=gitlab::group/subgroup/project/-/sub/dir@ref") + parse_pkg_ref("pkg=gitlab::https://acme.co/group/subgroup/project/-/sub/dir@ref") }) }) diff --git a/tests/testthat/test-type-gitlab.R b/tests/testthat/test-type-gitlab.R index ba4b257e..ccc070c5 100644 --- a/tests/testthat/test-type-gitlab.R +++ b/tests/testthat/test-type-gitlab.R @@ -47,7 +47,7 @@ test_that("resolve", { # subdirectory p <- suppressMessages(new_pkg_installation_proposal( - "gitlab::gaborcsardi/feather/R", + "gitlab::gaborcsardi/feather/-/R", config = list(library = tmp, dependencies = FALSE) )) suppressMessages(p$resolve()) @@ -67,7 +67,7 @@ test_that("download", { # subdirectory p <- suppressMessages(new_pkg_installation_proposal( - "gitlab::gaborcsardi/feather/R", + "gitlab::gaborcsardi/feather/-/R", config = list(library = tmp, dependencies = FALSE) )) suppressMessages(p$resolve()) From 3e63f3b57e84f5a152dec502a62a633ee91b7229 Mon Sep 17 00:00:00 2001 From: dgkf <18220321+dgkf@users.noreply.github.com> Date: Mon, 4 Mar 2024 19:05:21 -0500 Subject: [PATCH 03/23] revert fix to partial match on cond$parent --- R/errors.R | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/R/errors.R b/R/errors.R index ed61bd2e..3f10eda8 100644 --- a/R/errors.R +++ b/R/errors.R @@ -239,7 +239,7 @@ err <- local({ cond <- process_call(cond) if (!is.null(parent)) { - cond$parents <- process_call(parent) + cond$parent <- process_call(parent) } # We can set an option to always add the trace to the thrown @@ -723,23 +723,23 @@ err <- local({ c( paste0(if (add_exp) exp, msg), - if (inherits(cond$parents, "condition")) { - msg <- if (full && inherits(cond$parents, "rlib_error_3_0")) { - format(cond$parents, + if (inherits(cond$parent, "condition")) { + msg <- if (full && inherits(cond$parent, "rlib_error_3_0")) { + format(cond$parent, trace = FALSE, full = TRUE, class = FALSE, header = FALSE, advice = FALSE ) - } else if (inherits(cond$parents, "interrupt")) { + } else if (inherits(cond$parent, "interrupt")) { "interrupt" } else { - conditionMessage(cond$parents) + conditionMessage(cond$parent) } add_exp <- substr(cli::ansi_strip(msg[1]), 1, 1) != "!" if (add_exp) msg[1] <- paste0(exp, msg[1]) - c(format_header_line_cli(cond$parents, prefix = "Caused by error"), + c(format_header_line_cli(cond$parent, prefix = "Caused by error"), msg ) } @@ -753,25 +753,25 @@ err <- local({ add_exp <- is.null(names(cond$message)) c( paste0(if (add_exp) exp, cnd_message_robust(cond)), - if (inherits(cond$parents, "condition")) { - msg <- if (full && inherits(cond$parents, "rlib_error_3_0")) { - format(cond$parents, + if (inherits(cond$parent, "condition")) { + msg <- if (full && inherits(cond$parent, "rlib_error_3_0")) { + format(cond$parent, trace = FALSE, full = TRUE, class = FALSE, header = FALSE, advice = FALSE ) - } else if (inherits(cond$parents, "interrupt")) { + } else if (inherits(cond$parent, "interrupt")) { "interrupt" } else { - conditionMessage(cond$parents) + conditionMessage(cond$parent) } add_exp <- substr(msg[1], 1, 1) != "!" if (add_exp) { msg[1] <- paste0(exp, msg[1]) } - c(format_header_line_plain(cond$parents, prefix = "Caused by error"), + c(format_header_line_plain(cond$parent, prefix = "Caused by error"), msg ) } From 07b84da90d47596347f71aacae5dd0ac4ca8516f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Fri, 8 Mar 2024 08:31:01 +0100 Subject: [PATCH 04/23] Fix tests on Windows R 3.6.x magick does not support R 3.6.x any more, so there is no asciicast package. --- .github/workflows/R-CMD-check.yaml | 8 ++++++++ tests/testthat/test-assertions.R | 13 +++++++++++++ tests/testthat/test-assertthat.R | 1 + 3 files changed, 22 insertions(+) diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index 4f12df5c..1918f3f6 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -54,10 +54,18 @@ jobs: use-public-rspm: true - uses: r-lib/actions/setup-r-dependencies@v2 + if: runner.os != 'Windows' with: extra-packages: any::rcmdcheck needs: check + - uses: r-lib/actions/setup-r-dependencies@v2 + if: runner.os == 'Windows' + with: + extra-packages: any::rcmdcheck, asciicast=?ignore-before-r=4.0.0 + needs: check + + - name: "Set environmental variables" run: | cat(paste0("R_USER_CACHE_DIR=", Sys.getenv("GITHUB_WORKSPACE"), "/.github/cache\n"), file = Sys.getenv("GITHUB_ENV"), append = TRUE) diff --git a/tests/testthat/test-assertions.R b/tests/testthat/test-assertions.R index d311631b..adac0344 100644 --- a/tests/testthat/test-assertions.R +++ b/tests/testthat/test-assertions.R @@ -7,6 +7,7 @@ test_that("is_character", { }) test_that("is_character errors", { + if (is_windows() && getRversion() < "4.0.0") skip("No magick") asciicast::expect_snapshot_r_process( fn <- function(x) assert_that(is_character(x)), fn(1:2), @@ -19,6 +20,7 @@ test_that("is_character errors", { }) test_that("is_character errors, noninteractive", { + if (is_windows() && getRversion() < "4.0.0") skip("No magick") asciicast::expect_snapshot_r_process( interactive = FALSE, fn <- function(x) assert_that(is_character(x)), @@ -57,6 +59,7 @@ test_that("is_string", { }) test_that("is_string errors", { + if (is_windows() && getRversion() < "4.0.0") skip("No magick") asciicast::expect_snapshot_r_process( transform = transform_show_cursor, fn <- function(x) assert_that(is_string(x)), @@ -76,6 +79,7 @@ test_that("is_optional_string", { }) test_that("is_optional_string errors", { + if (is_windows() && getRversion() < "4.0.0") skip("No magick") asciicast::expect_snapshot_r_process( transform = transform_show_cursor, fn <- function(x) assert_that(is_optional_string(x)), @@ -93,6 +97,7 @@ test_that("is_flag", { }) test_that("is_flag errors", { + if (is_windows() && getRversion() < "4.0.0") skip("No magick") asciicast::expect_snapshot_r_process( transform = transform_show_cursor, fn <- function(x) assert_that(is_flag(x)), @@ -110,6 +115,7 @@ test_that("is_path", { }) test_that("is_path errors", { + if (is_windows() && getRversion() < "4.0.0") skip("No magick") asciicast::expect_snapshot_r_process( transform = transform_show_cursor, fn <- function(x) assert_that(is_path(x)), @@ -128,6 +134,7 @@ test_that("is_optional_path", { }) test_that("is_optional path errors", { + if (is_windows() && getRversion() < "4.0.0") skip("No magick") asciicast::expect_snapshot_r_process( transform = transform_show_cursor, fn <- function(x) assert_that(is_optional_path(x)), @@ -145,6 +152,7 @@ test_that("all_named", { }) test_that("all_named errors", { + if (is_windows() && getRversion() < "4.0.0") skip("No magick") asciicast::expect_snapshot_r_process( transform = transform_show_cursor, fn <- function(x) assert_that(all_named(x)), @@ -164,6 +172,7 @@ test_that("is_existing_file", { }) test_that("is_existing_file errors", { + if (is_windows() && getRversion() < "4.0.0") skip("No magick") asciicast::expect_snapshot_r_process( transform = function(x) transform_no_links(transform_show_cursor(x)), fn <- function(x) assert_that(is_existing_file(x)), @@ -181,6 +190,7 @@ test_that("is_platform_list", { }) test_that("is_platform_list errors", { + if (is_windows() && getRversion() < "4.0.0") skip("No magick") asciicast::expect_snapshot_r_process( transform = transform_show_cursor, fn <- function(x) assert_that(is_platform_list(x)), @@ -201,6 +211,7 @@ test_that("is_dependencies", { }) test_that("is_dependencies errors", { + if (is_windows() && getRversion() < "4.0.0") skip("No magick") asciicast::expect_snapshot_r_process( transform = transform_show_cursor, fn <- function(x) assert_that(is_dependencies(x)), @@ -218,6 +229,7 @@ test_that("is_r_version_list", { }) test_that("is_r_version_list errors", { + if (is_windows() && getRversion() < "4.0.0") skip("No magick") asciicast::expect_snapshot_r_process( transform = function(x) transform_show_cursor(transform_no_srcref(x)), fn <- function(x) assert_that(is_r_version_list(x)), @@ -233,6 +245,7 @@ test_that("is_difftime", { }) test_that("is_difftime errors", { + if (is_windows() && getRversion() < "4.0.0") skip("No magick") asciicast::expect_snapshot_r_process( transform = transform_show_cursor, fn <- function(x) assert_that(is_difftime(x)), diff --git a/tests/testthat/test-assertthat.R b/tests/testthat/test-assertthat.R index 3a284181..fd9523ca 100644 --- a/tests/testthat/test-assertthat.R +++ b/tests/testthat/test-assertthat.R @@ -47,6 +47,7 @@ test_that("assertion returns invalid value", { }) test_that("default messages", { + if (is_windows() && getRversion() < "4.0.0") skip("No magick") asciicast::expect_snapshot_r_process( transform = function(x) { transform_no_srcref(transform_no_links(transform_show_cursor(x))) From ee3a4367313df93183c0c872763d2032530f6e1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Sun, 17 Mar 2024 15:26:05 +0100 Subject: [PATCH 05/23] Update NEWS [ci skip] --- NEWS.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/NEWS.md b/NEWS.md index 6868031a..cf14a522 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,9 @@ # pkgdepends (development version) +* pkgdepends now supports the `*` wildcard for parameter specifications, + for paramrters applied to all packages. E.g. `*=?source` means + compiling all packages from source. + # pkgdepends 0.7.1 * pkgdepends now does not import the glue, rprojroot and prettyunits From 5ed51046a36a98df274ea71e3081087f95f6c776 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Sun, 17 Mar 2024 15:42:16 +0100 Subject: [PATCH 06/23] Increment version number to 0.7.2 --- DESCRIPTION | 2 +- NEWS.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 80973d3a..23f275eb 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: pkgdepends Title: Package Dependency Resolution and Downloads -Version: 0.7.1.9000 +Version: 0.7.2 Authors@R: c( person("Gábor", "Csárdi", , "csardi.gabor@gmail.com", role = c("aut", "cre")), person("Posit Software, PBC", role = c("cph", "fnd")) diff --git a/NEWS.md b/NEWS.md index cf14a522..5a8cf885 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,4 @@ -# pkgdepends (development version) +# pkgdepends 0.7.2 * pkgdepends now supports the `*` wildcard for parameter specifications, for paramrters applied to all packages. E.g. `*=?source` means From b704a10213d0c5a24c40cad47f7d706c92a8bc3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Sun, 17 Mar 2024 18:59:15 +0100 Subject: [PATCH 07/23] Increment version number to 0.7.2.9000 --- DESCRIPTION | 2 +- NEWS.md | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 23f275eb..7af1449c 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: pkgdepends Title: Package Dependency Resolution and Downloads -Version: 0.7.2 +Version: 0.7.2.9000 Authors@R: c( person("Gábor", "Csárdi", , "csardi.gabor@gmail.com", role = c("aut", "cre")), person("Posit Software, PBC", role = c("cph", "fnd")) diff --git a/NEWS.md b/NEWS.md index 5a8cf885..d424f0d4 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,5 @@ +# pkgdepends (development version) + # pkgdepends 0.7.2 * pkgdepends now supports the `*` wildcard for parameter specifications, From 3343d1316deef836015d217452b845074fa0201f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Wed, 3 Apr 2024 16:05:47 +0200 Subject: [PATCH 08/23] Support git:: (and gitlab::) submodules --- DESCRIPTION | 2 +- NEWS.md | 2 +- R/git-app.R | 7 +- R/git-protocol.R | 28 ++- R/git-submodules.R | 249 +++++++++++++++++++++ R/type-git.R | 23 +- R/utils.R | 4 + R/zzz-pkgdepends-config.R | 12 + inst/WORDLIST | 2 + inst/docs/pak-config-docs.rds | Bin 2302 -> 2422 bytes man/pkg_config.Rd | 5 + tests/testthat/_snaps/git-submodules.md | 30 +++ tests/testthat/_snaps/pkg-dependencies.md | 22 +- tests/testthat/_snaps/pkg-downloads.md | 22 +- tests/testthat/_snaps/pkg-installation.md | 22 +- tests/testthat/_snaps/pkgdepends-config.md | 22 +- tests/testthat/fixtures/git-repo.tar.gz | Bin 25723 -> 37732 bytes tests/testthat/test-git-submodules.R | 39 ++++ tests/testthat/test-type-git.R | 10 +- tools/doc/pak-config-docs.md | 3 + 20 files changed, 435 insertions(+), 69 deletions(-) create mode 100644 R/git-submodules.R create mode 100644 tests/testthat/_snaps/git-submodules.md create mode 100644 tests/testthat/test-git-submodules.R diff --git a/DESCRIPTION b/DESCRIPTION index 7af1449c..23b7106b 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -64,4 +64,4 @@ Config/Needs/website: tidyverse/tidytemplate Config/testthat/edition: 3 Encoding: UTF-8 -RoxygenNote: 7.2.3 +RoxygenNote: 7.3.1.9000 diff --git a/NEWS.md b/NEWS.md index d424f0d4..416c5187 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,7 +3,7 @@ # pkgdepends 0.7.2 * pkgdepends now supports the `*` wildcard for parameter specifications, - for paramrters applied to all packages. E.g. `*=?source` means + for parameters applied to all packages. E.g. `*=?source` means compiling all packages from source. # pkgdepends 0.7.1 diff --git a/R/git-app.R b/R/git-app.R index 7db82943..3ee74114 100644 --- a/R/git-app.R +++ b/R/git-app.R @@ -192,8 +192,9 @@ parse_url <- function(url) { re_url <- paste0( "^(?[a-zA-Z0-9]+)://", "(?:(?[^@/:]+)(?::(?[^@/]+))?@)?", - "(?[^/]+)", - "(?.*)$" # don't worry about query params here... + "(?(?[^:/]+)", + "(?::(?[0-9]+))?", + "(?/.*))$" # don't worry about query params here... ) - re_match(url, re_url)$groups + re_match(url, re_url) } diff --git a/R/git-protocol.R b/R/git-protocol.R index 0f41cb7a..220aed6c 100644 --- a/R/git-protocol.R +++ b/R/git-protocol.R @@ -133,6 +133,7 @@ async_git_resolve_ref <- function(url, ref) { paste0(c("", "refs/heads/", "refs/tags/"), ref) } async_git_list_refs(url, filt)$ + catch(error = function(e) async_git_list_refs_v1(url))$ then(function(refs) { result <- if (ref %in% refs$refs$ref) { refs$refs$hash[refs$refs$ref == ref] @@ -501,20 +502,30 @@ git_fetch_process <- function(reply, url, sha) { # ------------------------------------------------------------------------- -git_download_repo <- function(url, ref = "HEAD", output = ref) { - synchronize(async_git_download_repo(url, ref, output)) +git_download_repo <- function(url, ref = "HEAD", output = ref, + submodules = FALSE) { + synchronize(async_git_download_repo(url, ref, output, submodules)) } -async_git_download_repo <- function(url, ref = "HEAD", output = ref) { +async_git_download_repo <- function(url, ref = "HEAD", output = ref, + submodules = FALSE) { url; ref async_git_resolve_ref(url, ref)$ - then(function(sha) async_git_download_repo_sha(url, sha, output)) + then(function(sha) { + async_git_download_repo_sha(url, sha, output, submodules) + }) } -async_git_download_repo_sha <- function(url, sha, output) { +async_git_download_repo_sha <- function(url, sha, output, + submodules = FALSE) { url; sha; output - async_git_fetch(url, sha, blobs = TRUE)$ + p <- async_git_fetch(url, sha, blobs = TRUE)$ then(function(packfile) unpack_packfile_repo(packfile, output, url)) + if (!submodules) { + p + } else { + p$then(function() async_update_git_submodules(output)) + } } unpack_packfile_repo <- function(parsed, output, url) { @@ -546,7 +557,10 @@ unpack_packfile_repo <- function(parsed, output, url) { process_tree(tidx) wd <<- utils::head(wd, -1) } else if (tr$type[l] == "blob") { - writeBin(parsed[[tr$hash[l]]]$raw, opath) + # for submodules this is NULL + if (!is.null(parsed[[tr$hash[l]]])) { + writeBin(parsed[[tr$hash[l]]]$raw, opath) + } } } } diff --git a/R/git-submodules.R b/R/git-submodules.R new file mode 100644 index 00000000..4ff44c05 --- /dev/null +++ b/R/git-submodules.R @@ -0,0 +1,249 @@ +# From remotes +parse_submodules <- function(file) { + if (grepl("\n", file)) { + x <- strsplit(file, "\n")[[1]] + } else { + x <- readLines(file) + } + + # https://git-scm.com/docs/git-config#_syntax + # Subsection names are case sensitive and can contain any characters except + # newline and the null byte. Doublequote " and backslash can be included by + # escaping them as \" and \\ + double_quoted_string_with_escapes <- '(?:\\\\.|[^"])*' + + # Otherwise extract section names + section_names <- re_match( + x, + sprintf( + '^[[:space:]]*\\[submodule "(?%s)"\\][[:space:]]*$', + double_quoted_string_with_escapes + ) + )$submodule + + # If no sections found return the empty list + if (all(is.na(section_names))) { + return(list()) + } + + # Extract name = value + # The variable names are case-insensitive, allow only alphanumeric characters + # and -, and must start with an alphabetic character. + variable_name <- "[[:alpha:]][[:alnum:]\\-]*" + mapping_values <- re_match( + x, + sprintf( + '^[[:space:]]*(?%s)[[:space:]]*=[[:space:]]*(?.*)[[:space:]]*$', + variable_name + ) + ) + + values <- cbind( + submodule = fill(section_names), mapping_values[c("name", "value")], + stringsAsFactors = FALSE + ) + values <- values[!is.na(mapping_values$.match), ] + + # path and valid url are required + if (!all(c("path", "url") %in% values$name)) { + warning( + "Invalid submodule definition, skipping submodule installation", + immediate. = TRUE, + call. = FALSE + ) + return(list()) + } + + # Roughly equivalent to tidyr::spread(values, name, value) + res <- stats::reshape( + values, + idvar = "submodule", + timevar = "name", + v.name = "value", + direction = "wide" + ) + + # Set the column names, reshape prepends `value.` to path, url and branch + colnames(res) <- gsub("value[.]", "", colnames(res)) + + # path and valid url are required + if (any(is.na(res$url), is.na(res$path))) { + warning( + "Invalid submodule definition, skipping submodule installation", + immediate. = TRUE, + call. = FALSE + ) + return(list()) + } + + # branch is optional + if (!exists("branch", res)) { + res$branch <- NA_character_ + } + + # Remove unneeded attribute + attr(res, "reshapeWide") <- NULL + + # Remove rownames + rownames(res) <- NULL + + res +} + +# Adapted from https://stackoverflow.com/a/9517731/2055486 +fill <- function(x) { + not_missing <- !is.na(x) + + res <- x[not_missing] + res[cumsum(not_missing)] +} + +update_submodule <- function(url, path, branch) { + synchronize(async_update_submodule(url, path, branch)) +} + +async_update_submodule <- function(url, path, branch) { + url; path; branch + # if the directory already exists and not empty, we assume that + # it was already downloaded. We still to update the submodules + # recursively + if (file.exists(path) && + length(dir(path, all.files = TRUE, no.. = TRUE)) > 0) { + # message(path, " exists") + async_update_git_submodules(path) + + } else { + if (is.null(branch) || is.na(branch)) branch <- "HEAD" + # message("getting ", path) + async_git_download_repo( + git_auth_url(url), + ref = branch, + output = path, + submodules = TRUE + ) + } +} + +git_auth_url <- function(url) { + parsed <- parse_url(url) + auth <- tryCatch(gitcreds_get(url), error = function(err) NULL) + if (is.null(auth)) { + url + } else { + paste0( + parsed$protocol, + "://", + auth$username, + ":", + auth$password, + "@", + sub(paste0("^", parsed$protocol, "://"), "", parsed$url), + # gitlab needs .git suffix + if (parsed$host == "gitlab.com" && !endsWith(parsed$url, ".git")) { + ".git" + } + ) + } +} + +update_git_submodules_r <- function(path, subdir) { + synchronize(async_update_git_submodules_r(path)) +} + +async_update_git_submodules_r <- function(path, subdir) { + subdir <- subdir %||% "." + smfile <- file.path(path, ".gitmodules") + if (!file.exists(smfile)) return() + + info <- parse_submodules(smfile) + if (length(info) == 0) return() + + to_ignore <- in_r_build_ignore(info$path, file.path(path, subdir, ".Rbuildignore")) + info <- info[!to_ignore, ] + if (length(info) == 0) return() + + async_map(seq_len(nrow(info)), function(i) { + async_update_submodule( + info$url[i], + file.path(path, + info$path[i]), + info$branch[i] + ) + })$ + then(function() invisible()) +} + +update_git_submodules <- function(path) { + synchronize(async_update_git_submodules(path)) +} + +async_update_git_submodules <- function(path) { + smfile <- file.path(path, ".gitmodules") + if (!file.exists(smfile)) return() + + info <- parse_submodules(smfile) + if (length(info) == 0) return() + + async_map(seq_len(nrow(info)), function(i) { + async_update_submodule( + info$url[i], + file.path(path, + info$path[i]), + info$branch[i] + ) + })$ + then(function() invisible()) +} + +r_build_ignore_patterns <- c( + "^\\.Rbuildignore$", + "(^|/)\\.DS_Store$", + "^\\.(RData|Rhistory)$", + "~$", + "\\.bak$", + "\\.swp$", + "(^|/)\\.#[^/]*$", + "(^|/)#[^/]*#$", + "^TITLE$", + "^data/00Index$", + "^inst/doc/00Index\\.dcf$", + "^config\\.(cache|log|status)$", + "(^|/)autom4te\\.cache$", + "^src/.*\\.d$", + "^src/Makedeps$", + "^src/so_locations$", + "^inst/doc/Rplots\\.(ps|pdf)$" +) + +in_r_build_ignore <- function(paths, ignore_file) { + ignore <- tryCatch( + asNamespace("tools")$get_exclude_patterns(), + error = function(e) r_build_ignore_patterns + ) + + if (file.exists(ignore_file)) { + ignore <- c(ignore, readLines(ignore_file, warn = FALSE)) + } + + matches_ignores <- function(x) { + any(vlapply(ignore, grepl, x, perl = TRUE, ignore.case = TRUE)) + } + + # We need to search for the paths as well as directories in the path, so + # `^foo$` matches `foo/bar` + should_ignore <- function(path) { + any(vlapply(c(path, directories(path)), matches_ignores)) + } + + vlapply(paths, should_ignore) +} + +directories <- function (paths) { + dirs <- unique(dirname(paths)) + out <- dirs[dirs != "."] + while (length(dirs) > 0 && any(dirs != ".")) { + out <- unique(c(out, dirs[dirs != "."])) + dirs <- unique(dirname(dirs)) + } + sort(out) +} diff --git a/R/type-git.R b/R/type-git.R index f15276c1..15ff687e 100644 --- a/R/type-git.R +++ b/R/type-git.R @@ -77,8 +77,8 @@ download_remote_git <- function(resolution, target, target_tree, ## 3. Check if we have a repo snapshot in the cache. rel_target <- resolution$target + subdir <- resolution$remote[[1]]$subdir if (!nocache) { - subdir <- resolution$remote[[1]]$subdir hit <- cache$package$copy_to( target_tree, package = package, sha256 = sha, built = FALSE) if (nrow(hit)) { @@ -88,14 +88,21 @@ download_remote_git <- function(resolution, target, target_tree, ## 4. Need to download the repo - url <- git_auth_url(resolution$remote[[1]]) + url <- type_git_auth_url(resolution$remote[[1]]) sha <- resolution$metadata[[1]][["RemoteSha"]] pkgdir <- file.path(target_tree, resolution$package) mkdirp(pkgdir) - async_git_download_repo(url, ref = sha, output = pkgdir)$ - then(function() { - "Got" - }) + p <- async_git_download_repo(url, ref = sha, output = pkgdir) + + # submodules? + submodules <- config$get("git-submodules") + if (submodules) { + p <- p$then(function(x) async_update_git_submodules_r(pkgdir, subdir)) + } + + p$then(function() { + "Got" + }) } satisfy_remote_git <- function(resolution, candidate, @@ -161,7 +168,7 @@ git_rx <- function() { ) } -git_auth_url <- function(remote) { +type_git_auth_url <- function(remote) { url <- remote$url auth <- tryCatch(gitcreds_get(url), error = function(err) NULL) if (is.null(auth)) { @@ -183,7 +190,7 @@ type_git_get_data <- function(remote) { remote sha <- NULL dsc <- NULL - auth_url <- git_auth_url(remote) + auth_url <- type_git_auth_url(remote) desc_path <- if (is.null(remote$subdir) || remote$subdir == "") { "DESCRIPTION" } else { diff --git a/R/utils.R b/R/utils.R index 617aabd9..c29c6e51 100644 --- a/R/utils.R +++ b/R/utils.R @@ -315,6 +315,10 @@ new_async_timer <- function(...) { asNamespace("pkgcache")$async_timer$new(...) } +async_delay <- function(...) { + asNamespace("pkgcache")$delay(...) +} + external_process <- function(...) { asNamespace("pkgcache")$external_process(...) } diff --git a/R/zzz-pkgdepends-config.R b/R/zzz-pkgdepends-config.R index 02275262..dab0c439 100644 --- a/R/zzz-pkgdepends-config.R +++ b/R/zzz-pkgdepends-config.R @@ -123,6 +123,18 @@ pkgdepends_config <- sort_by_name(list( details." ), + # ----------------------------------------------------------------------- + git_submodules = list( + type = "flag", + default = FALSE, + docs = + "Whether or not to update submodules in git repositories. This + affects `git::` and `gitlab::` package sources only. + If the R package is in a subdirectory then only the submodules + within that directory are updated. If a submodule appears in + `.Rbuildignore`, then it is skipped." + ), + # ----------------------------------------------------------------------- include_linkingto = list( type = "flag", diff --git a/inst/WORDLIST b/inst/WORDLIST index 7337eaea..d3182ab0 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -37,5 +37,7 @@ pkgdown prettyunits rprojroot shorthands +submodule +submodules tibbles uncompress diff --git a/inst/docs/pak-config-docs.rds b/inst/docs/pak-config-docs.rds index fa21c7bbee86fa4fdb3f9ab2e157d8504ef02a32..eff5493c984b85719e0aa9d702481a161a3b1218 100644 GIT binary patch literal 2422 zcmV-+35oU}iwFP!000001I<`VZyd)FUQ0?0bzaH~Ms6KlLIKO6t;mM6H(H_U{Ep<1TW&ez=j0y*$T6oNRn^_|+NBcT0*E4~AJtV~ zRee?6zhRTfRJC8!Crg}9L1HXyQIi<%4yCplDPiv*p_#HCQV zSmtudg~jz&wi>C@)*{bA^0HN&Cyg<(tn*DYbim}#&y@ar?$i14XS`6xXbPMLLGLSwI=BOjthC*7UDcosJAjk<&dF}lhJ*bl z9{gzP;!D&&vxKd4sVv#~r8LW%bzN6>c65{&QAWnrO{#R1=wci3*Km@^tsWd#iHjL( z6pJ+d;s(FkPdtu8aI(GYSF-M}hfiETg5_bzB|rt0MP#Z})EHXJLZ?j*z61}gRLuz& z1@2IgRvgoci7W#LS?)}OMY9=c)D1wy;aErzmpd*QBX*j3*Y{Ep4ik8I7bFz=l)bpP z(~Gsy1M%N2$C!3Dq?A^o+rmXvNn!91k6ARQT!F;VMsBC>EU*<6u@?$fr{h3+&|@Ew zUx^J$OY$ZSQSt)3pvu)kZy}Q^S*Ef~ltYp9*Lg#Mr87dxr=GyEDVLXcKEdKF!F0#8 zl!<_l9po6p`7U#borsWH|BxBFkhLm60ob24Ii(Vp(JEr+jmg`11YfP2B}U?rIn34a z2twybS=&f^^yK3Yw?wU?lFZEA&hPNv43=0N(+)Vtl{S2OMi@E=7)vFF47%NmZ8NBrx3aOE@qBj4wbp z@Q+V@P>{8tk$o7FE-N$@7Dzc)y)e#XTQR80!l&3^*$oMC_N(Xd%ag_Nv*X2a{N@aP zoy5nVE>7lKF3U@0bXh=|;g=A&Se~G=Z6Mx}HyNO1B{)5`{J;qVVzy0|scYcbLX{2H zRX%EiSk$G;3QX>LmZCX{mrLqVFau){E|WlwW@$qAg2n~ zOF*owZ$hcwBHgNkM@*~XdPE(blzDz^Jql3c~D@B1+ zH7>(pK49w`kuGVbu%xjb)Q7I7JRB#%WHm-*3KGD*D8UXo7f{aQz*@c`7=WYFk#e0f zUewqbf9)5Drq%_-NdlrbJlFaHa;#7L+-@x7F;LT24WvINf~C6HZ~k0W>OgkMS`WF^ zOGufQ7!08r=%jsm{Ni;hZqLC~aBQs*27}a*@&i}fkZ)hT?#LM8+cp*O7OrVM4SBb0 zsM*=Doz601T~F+}q-WzT5~oZJLjWp;!L2xEwDtqk^jmwSO?n88L6B^l6pApkDZn6^ zT0yT&Rc1%vIB@>h^Poq$W5&I}AyXnLQxRs*RsBmSrQEkSes2ctxAowY2AIhdd-z3d z$RYG4tthY@>*6py5UjDfpDlpRH2@!Md#i>{n~3$LW^iW-L_3yl_Xi`C3~I?JP;CEL z=pYJ#QCe&EmMC|zl4|L?WO*%<#vxpcRruGUPYSMiCu8>+ib>W~5r0*3=){`qDRvHU z{kbjP+gnZ-e^ZRlqOmoWA!r|K>^Cro@REqB;JF>fm(2ue6*fxiZ| z?KSI@s+0J^jF>)c2J!f&RM!LB_7X1TM|cg9bd^IQa2%Vm zQT45iPLNxbOW59h8T_=}OQe6fl}JZL%H82G9d~X3Pz^_b4vlzv>V?@^FvYESdOCzXXc7VxW*iOM!ed{=9gtlcYD4bcJ>)v{hAbrj+fvkrXo zxhi1_TM#(5ZU5jt(zrLN89N6#h5DVmaeoB{tc=X0IlTS|m~qCR%TgLL(~WZ&@7;7y zM_nQdSF1MSVSOlES8`Wd6xX&(>|jApV{K>_YPGIiTZHwX01VY(AA(kupFUz^UHFbJ z>gOMS^cH0X4JcpgdIYz>*gK{0ih}jFQaM(rZYw?o_-9HVZ|sGD( z#Jm2P$AA7{_%6~r>c{PjD*>^{!2dzKckIrt`|VZ04=@vlD_qb3xEOf2)zp8+>C&I% zCw{Us5!bG94xqIQ%qBKX>4zVL;h>5i|4|q>wkl$JV^!&R56v|u_v7CV<5bxRol03|KAj{pDw literal 2302 zcmV8_qB)ZNvthonIOOReh&YD2#%ZxGV9UP-7^w!BVx5u*CQ+Q z%gisc>epm68ofPw_yGQYfPelF{`&xa9>dRDqlcqM@ayX@m)tD5qDIoW6=hDZ#G>ZL za7_!TXv4Bgw&2t#&UHd&OQ9+JlXbbGR`Z;Sg2MiG9nQ@S6E#c~N>-HhM2rcmb6QIi zC$+RH<8%*>nv0sL)qcC4scb2(ctSs0(VQ2|mWFJUV~RUDsI;M?1})(1jA__#QqYyO zRCD7;!M2M`=KOXxeRI4X6HvHzD{2mE!feGZIn@?Knk6&Npm>r;g||q!lL@5+u)C#c5`h;&+c^c>wHC78ETrwiF-&se0l6qeefgU?pfq zT+`q+ElcZQk_BoK1Bv0-nDQ$KTAytzA8Qc27-T$S;DBDl5S-t{q02RwUT|7MV-jmw zaU&{F0QMKQbbvPj5T5>0C6a^wp<@R`{d_qM-;54{DxIc z$x)h5#6hUrvyj;!!-XW^6qM}8`iVjHocA2ZfPBJA#aX`USk-R1#&pggWCY|X;M)Ut zsKh^B$;=^20cEhC<;*Y&UM)q&V65-|%SFbrC7)n`mEw}8aYyRLAtvIAyOu!q{9onn zuZ}4C9B?#TU9l4Ri%}=*HWx*KlaR0T-@<_jV0;O>fq!fRCb=LZEoja@3`ybqB^^yd zvU)DYIO8qWw{v0Q;sJVBON_;ga6VxzLx6q_+4b1{RWy`#aUPsvruS zH)AZh{N*J$$=8_}heLON`}vY72CEdkav_9THNYv5QSRFup z;=79{!z36jhNz4|0=O3?=w2NLPHFU;bx&^`-SwWm+AbLeh zDK8<%y0lOAN<$t4HGOR%{V@@s0fW}2+se3NNH-w+WHo(m4H9w^Bt}DAqvWN1e)Q_R z6}RJHS8%iu2!lfE$myQ1ZOFH$=NmGH_|~=o-oiDlry=j=)|KuR+3J%Lvgz;wmvn5r zL*kf-eh5INP`DMxl$2q>wXj-WOO+p#5F$acwmB4Gp$RZZAr{d2xhk_Ia2Pm$=y))o zykW+jz#&s2DZ3&}UJCOID5VHIZU}n|XeM<4-)VrE>|zhUTmyO_YSM}V%dsx@(*wa8 zs{6$Z*jxhe(YAXv^x7n(E46?QJQD3ty51d(P%_;0zy*r#9t#~r#V|^ZB=`A@HB{lBvo0z4R@520%TP=*+a&a~rqGGmn=y6{(9GWz?`_Y%iN7(%XJxg) zG6c65gZ%~u5ng#P6#}=z_}uk!6p75GwF0&Vl(B+0Kt6%D8NjcX34sceOahuu?A+GI z9z1=TeE94M;EI&&XVj9H2cK>e+TYHk2F+rF^_tc2OVK@qg)6XNdhVLz;fj6g8gzlZ z1rd1{LD%Eo2jhU71Lsc9&t9j~w4Ah-|EDnNkkaNpJBjqqcM|EKNckH%rsLKP0IJ~t(7qARPl7N#iKh4!&rf=hNxI&1H_Rx?D9g7T z@cWMHJX`wO4+@?@<@#~adJ z3JuP9@W)Npq(L@=Uk%Shu|ndzUW#n#-)sy-3sh81I*rs}j7!Wq@XeQ^hAC`8;MlhP zgZqf}FDw&s0dgwwJAUi`iVWB&UT}4A^D!{vgudi8SI$g7PGP)r(>)n+fvk46vQ?r_4l+$Aa`@dsh> z`>vf#+lSOJ{K#K5bD_e(yZD}w`ZvBX^j>()N=yHaWn`FmCp_qc&mZ((KsrL-Z)ZH& zr>p=^NAbahTe}{$O@A05Dvg)5r~$ApFmC*OFMOu?Je(9Je!Ml28s8#Ec-jSOl`30@ z;m2_}suIS36vvfrs?@y=ihQ`o%~@53@$bZOtl44gdvUC%ZL1763R1`6$3W@nyhG<< Y{JYmayiyEr^!va54K)|0MgtfC04Du@EC2ui diff --git a/man/pkg_config.Rd b/man/pkg_config.Rd index 3ddcd2e1..a81ab8ed 100644 --- a/man/pkg_config.Rd +++ b/man/pkg_config.Rd @@ -54,6 +54,11 @@ supported in the \code{PKG_DEPENDENCIES} environment variable: \code{"TRUE"}, \code{"FALSE"}, \code{"NA"}, or a semicolon separated list of dependency types. See \code{\link[=as_pkg_dependencies]{as_pkg_dependencies()}} for details. +\item \code{git_submodules}: Whether or not to update submodules in git repositories. This +affects \verb{git::} and \verb{gitlab::} package sources only. +If the R package is in a subdirectory then only the submodules +within that directory are updated. If a submodule appears in +\code{.Rbuildignore}, then it is skipped. \item \code{include_linkingto}: Whether to always include \code{LinkingTo} dependencies in the solution of and installation, even if they are needed because the packages are installed from binaries. This is sometimes useful, see e.g. diff --git a/tests/testthat/_snaps/git-submodules.md b/tests/testthat/_snaps/git-submodules.md new file mode 100644 index 00000000..870092c0 --- /dev/null +++ b/tests/testthat/_snaps/git-submodules.md @@ -0,0 +1,30 @@ +# git_download_repo with submodules + + Code + dir(tmp, recursive = TRUE) + Output + [1] "v1/DESCRIPTION" "v1/NAMESPACE" "v1/R/foo.R" "v1/README.md" + [5] "v1/submod/README" "v1/wipe.R" + +--- + + Code + readLines(file.path(output, "submod", "README")) + Output + [1] "A git submodule" "Another commit" + +--- + + Code + dir(tmp, recursive = TRUE) + Output + [1] "v1/DESCRIPTION" "v1/NAMESPACE" "v1/R/foo.R" "v1/README.md" + [5] "v1/submod/README" "v1/wipe.R" + +--- + + Code + readLines(file.path(output, "submod", "README")) + Output + [1] "A git submodule" "Another commit" "Third commit" + diff --git a/tests/testthat/_snaps/pkg-dependencies.md b/tests/testthat/_snaps/pkg-dependencies.md index 7f7b76db..db26aad0 100644 --- a/tests/testthat/_snaps/pkg-dependencies.md +++ b/tests/testthat/_snaps/pkg-dependencies.md @@ -23,17 +23,17 @@ Output [1] "build_vignettes" "cache_dir" [3] "cran_mirror" "dependencies" - [5] "goal" "include_linkingto" - [7] "library" "metadata_cache_dir" - [9] "metadata_update_after" "package_cache_dir" - [11] "platforms" "r_versions" - [13] "sysreqs" "sysreqs_db_update" - [15] "sysreqs_db_update_timeout" "sysreqs_dry_run" - [17] "sysreqs_lookup_system" "sysreqs_platform" - [19] "sysreqs_rspm_repo_id" "sysreqs_rspm_url" - [21] "sysreqs_sudo" "sysreqs_update" - [23] "sysreqs_verbose" "use_bioconductor" - [25] "windows_archs" + [5] "git_submodules" "goal" + [7] "include_linkingto" "library" + [9] "metadata_cache_dir" "metadata_update_after" + [11] "package_cache_dir" "platforms" + [13] "r_versions" "sysreqs" + [15] "sysreqs_db_update" "sysreqs_db_update_timeout" + [17] "sysreqs_dry_run" "sysreqs_lookup_system" + [19] "sysreqs_platform" "sysreqs_rspm_repo_id" + [21] "sysreqs_rspm_url" "sysreqs_sudo" + [23] "sysreqs_update" "sysreqs_verbose" + [25] "use_bioconductor" "windows_archs" --- diff --git a/tests/testthat/_snaps/pkg-downloads.md b/tests/testthat/_snaps/pkg-downloads.md index bf1057aa..81a93de1 100644 --- a/tests/testthat/_snaps/pkg-downloads.md +++ b/tests/testthat/_snaps/pkg-downloads.md @@ -22,17 +22,17 @@ Output [1] "build_vignettes" "cache_dir" [3] "cran_mirror" "dependencies" - [5] "goal" "include_linkingto" - [7] "library" "metadata_cache_dir" - [9] "metadata_update_after" "package_cache_dir" - [11] "platforms" "r_versions" - [13] "sysreqs" "sysreqs_db_update" - [15] "sysreqs_db_update_timeout" "sysreqs_dry_run" - [17] "sysreqs_lookup_system" "sysreqs_platform" - [19] "sysreqs_rspm_repo_id" "sysreqs_rspm_url" - [21] "sysreqs_sudo" "sysreqs_update" - [23] "sysreqs_verbose" "use_bioconductor" - [25] "windows_archs" + [5] "git_submodules" "goal" + [7] "include_linkingto" "library" + [9] "metadata_cache_dir" "metadata_update_after" + [11] "package_cache_dir" "platforms" + [13] "r_versions" "sysreqs" + [15] "sysreqs_db_update" "sysreqs_db_update_timeout" + [17] "sysreqs_dry_run" "sysreqs_lookup_system" + [19] "sysreqs_platform" "sysreqs_rspm_repo_id" + [21] "sysreqs_rspm_url" "sysreqs_sudo" + [23] "sysreqs_update" "sysreqs_verbose" + [25] "use_bioconductor" "windows_archs" --- diff --git a/tests/testthat/_snaps/pkg-installation.md b/tests/testthat/_snaps/pkg-installation.md index bcdb76f7..df8e314d 100644 --- a/tests/testthat/_snaps/pkg-installation.md +++ b/tests/testthat/_snaps/pkg-installation.md @@ -23,17 +23,17 @@ Output [1] "build_vignettes" "cache_dir" [3] "cran_mirror" "dependencies" - [5] "goal" "include_linkingto" - [7] "library" "metadata_cache_dir" - [9] "metadata_update_after" "package_cache_dir" - [11] "platforms" "r_versions" - [13] "sysreqs" "sysreqs_db_update" - [15] "sysreqs_db_update_timeout" "sysreqs_dry_run" - [17] "sysreqs_lookup_system" "sysreqs_platform" - [19] "sysreqs_rspm_repo_id" "sysreqs_rspm_url" - [21] "sysreqs_sudo" "sysreqs_update" - [23] "sysreqs_verbose" "use_bioconductor" - [25] "windows_archs" + [5] "git_submodules" "goal" + [7] "include_linkingto" "library" + [9] "metadata_cache_dir" "metadata_update_after" + [11] "package_cache_dir" "platforms" + [13] "r_versions" "sysreqs" + [15] "sysreqs_db_update" "sysreqs_db_update_timeout" + [17] "sysreqs_dry_run" "sysreqs_lookup_system" + [19] "sysreqs_platform" "sysreqs_rspm_repo_id" + [21] "sysreqs_rspm_url" "sysreqs_sudo" + [23] "sysreqs_update" "sysreqs_verbose" + [25] "use_bioconductor" "windows_archs" --- diff --git a/tests/testthat/_snaps/pkgdepends-config.md b/tests/testthat/_snaps/pkgdepends-config.md index 3906a408..de6947b0 100644 --- a/tests/testthat/_snaps/pkgdepends-config.md +++ b/tests/testthat/_snaps/pkgdepends-config.md @@ -91,15 +91,15 @@ Output [1] "build_vignettes" "cache_dir" [3] "cran_mirror" "dependencies" - [5] "goal" "include_linkingto" - [7] "library" "metadata_cache_dir" - [9] "metadata_update_after" "package_cache_dir" - [11] "platforms" "r_versions" - [13] "sysreqs" "sysreqs_db_update" - [15] "sysreqs_db_update_timeout" "sysreqs_dry_run" - [17] "sysreqs_lookup_system" "sysreqs_platform" - [19] "sysreqs_rspm_repo_id" "sysreqs_rspm_url" - [21] "sysreqs_sudo" "sysreqs_update" - [23] "sysreqs_verbose" "use_bioconductor" - [25] "windows_archs" + [5] "git_submodules" "goal" + [7] "include_linkingto" "library" + [9] "metadata_cache_dir" "metadata_update_after" + [11] "package_cache_dir" "platforms" + [13] "r_versions" "sysreqs" + [15] "sysreqs_db_update" "sysreqs_db_update_timeout" + [17] "sysreqs_dry_run" "sysreqs_lookup_system" + [19] "sysreqs_platform" "sysreqs_rspm_repo_id" + [21] "sysreqs_rspm_url" "sysreqs_sudo" + [23] "sysreqs_update" "sysreqs_verbose" + [25] "use_bioconductor" "windows_archs" diff --git a/tests/testthat/fixtures/git-repo.tar.gz b/tests/testthat/fixtures/git-repo.tar.gz index 07b1be4f1996ee3f91073ff9c67d58f20457a792..660fd72a63301be7db601192748e56f5a8566cbb 100644 GIT binary patch delta 34094 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 CQy7B) delta 22030 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 diff --git a/tests/testthat/test-git-submodules.R b/tests/testthat/test-git-submodules.R new file mode 100644 index 00000000..cff5f699 --- /dev/null +++ b/tests/testthat/test-git-submodules.R @@ -0,0 +1,39 @@ +withr::local_envvar(GITHUB_PAT="FAIL") + +test_that("git_download_repo with submodules", { + skip_on_cran() + if (Sys.which("git") == "") skip("Needs git") + + dir.create(tmp <- tempfile()) + on.exit(unlink(tmp, recursive = TRUE), add = TRUE) + + output <- file.path(tmp, "v1") + git_download_repo( + fake_git$url("/pak-test.git"), + output = output + ) + + # tag + writeLines(c( + "[submodule \"submod\"]", + "\tpath = submod", + paste0("\turl = ", fake_git$url("/submod")), + "\tbranch = v2" + ), file.path(output, ".gitmodules")) + + update_git_submodules(output) + expect_snapshot(dir(tmp, recursive = TRUE)) + expect_snapshot(readLines(file.path(output, "submod", "README"))) + + # HEAD + unlink(file.path(output, "submod"), recursive = TRUE) + writeLines(c( + "[submodule \"submod\"]", + "\tpath = submod", + paste0("\turl = ", fake_git$url("/submod")) + ), file.path(output, ".gitmodules")) + + update_git_submodules(output) + expect_snapshot(dir(tmp, recursive = TRUE)) + expect_snapshot(readLines(file.path(output, "submod", "README"))) +}) diff --git a/tests/testthat/test-type-git.R b/tests/testthat/test-type-git.R index 3b6c9b2b..e1f6595f 100644 --- a/tests/testthat/test-type-git.R +++ b/tests/testthat/test-type-git.R @@ -167,20 +167,20 @@ test_that("installedok_remote_git", { ) }) -test_that("git_auth_url", { - mockery::stub(git_auth_url, "gitcreds_get", function(...) stop("oops")) +test_that("type_git_auth_url", { + mockery::stub(type_git_auth_url, "gitcreds_get", function(...) stop("oops")) expect_equal( - git_auth_url(list(url = "https://github.com/r-lib/cli.git")), + type_git_auth_url(list(url = "https://github.com/r-lib/cli.git")), "https://github.com/r-lib/cli.git" ) mockery::stub( - git_auth_url, + type_git_auth_url, "gitcreds_get", list(username = "user", password = "secret") ) expect_equal( - git_auth_url(list( + type_git_auth_url(list( protocol = "https", url = "https://github.com/r-lib/cli.git" )), diff --git a/tools/doc/pak-config-docs.md b/tools/doc/pak-config-docs.md index 0b50888b..e7b9d067 100644 --- a/tools/doc/pak-config-docs.md +++ b/tools/doc/pak-config-docs.md @@ -7,6 +7,9 @@ $cache_dir $cran_mirror [1] "CRAN mirror to use. Defaults to the \\code{repos} option\n(see \\code{\\link[base:options]{base::options()}}), if that's not set then\n\\verb{https://cran.rstudio.com}. See also \\code{\\link[pak:repo_add]{pak::repo_add()}} and\n\\code{\\link[pak:repo_get]{pak::repo_get()}}" +$git_submodules +[1] "Whether or not to update submodules in git repositories. This\naffects \\verb{git::} and \\verb{gitlab::} package sources only.\nIf the R package is in a subdirectory then only the submodules\nwithin that directory are updated. If a submodule appears in\n\\code{.Rbuildignore}, then it is skipped." + $include_linkingto [1] "Whether to always include \\code{LinkingTo} dependencies in the solution\nof and installation, even if they are needed because the packages\nare installed from binaries. This is sometimes useful, see e.g.\n\\url{https://github.com/r-lib/pak/issues/485} for an example use case." From 01305a0ca438d96b1e15e0e04bfa0a69cbb292e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Thu, 4 Apr 2024 10:35:27 +0200 Subject: [PATCH 09/23] Tests for submodules --- R/git-submodules.R | 14 ++- tests/testthat/_snaps/git-protocol.md | 41 ++++--- tests/testthat/_snaps/git-submodules.md | 147 ++++++++++++++++++++++++ tests/testthat/fixtures/git-repo.tar.gz | Bin 37732 -> 39524 bytes tests/testthat/fixtures/submodules.ini | 12 ++ tests/testthat/fixtures/submodules2.ini | 11 ++ tests/testthat/fixtures/submodules3.ini | 6 + tests/testthat/test-git-submodules.R | 121 +++++++++++++++++++ tools/doc/resolution-result.md | 14 +++ 9 files changed, 342 insertions(+), 24 deletions(-) create mode 100644 tests/testthat/fixtures/submodules.ini create mode 100644 tests/testthat/fixtures/submodules2.ini create mode 100644 tests/testthat/fixtures/submodules3.ini diff --git a/R/git-submodules.R b/R/git-submodules.R index 4ff44c05..c9e01b84 100644 --- a/R/git-submodules.R +++ b/R/git-submodules.R @@ -99,14 +99,18 @@ fill <- function(x) { } update_submodule <- function(url, path, branch) { - synchronize(async_update_submodule(url, path, branch)) + synchronize(async_update_submodule(url, path, branch)) # nocov } async_update_submodule <- function(url, path, branch) { url; path; branch # if the directory already exists and not empty, we assume that # it was already downloaded. We still to update the submodules - # recursively + # recursively. This is problematic if a git download is interrupted + # and then stated again with the same output, but that does not happen + # during normal operation of pkgdepends, I think. A better solution + # would be to download the submodule to a temporary directory, and if + # successful, then move the temporary directory to the correct place. if (file.exists(path) && length(dir(path, all.files = TRUE, no.. = TRUE)) > 0) { # message(path, " exists") @@ -147,7 +151,7 @@ git_auth_url <- function(url) { } update_git_submodules_r <- function(path, subdir) { - synchronize(async_update_git_submodules_r(path)) + synchronize(async_update_git_submodules_r(path, subdir)) # nocov } async_update_git_submodules_r <- function(path, subdir) { @@ -160,7 +164,7 @@ async_update_git_submodules_r <- function(path, subdir) { to_ignore <- in_r_build_ignore(info$path, file.path(path, subdir, ".Rbuildignore")) info <- info[!to_ignore, ] - if (length(info) == 0) return() + if (nrow(info) == 0) return() async_map(seq_len(nrow(info)), function(i) { async_update_submodule( @@ -182,7 +186,7 @@ async_update_git_submodules <- function(path) { if (!file.exists(smfile)) return() info <- parse_submodules(smfile) - if (length(info) == 0) return() + if (nrow(info) == 0) return() async_map(seq_len(nrow(info)), function(i) { async_update_submodule( diff --git a/tests/testthat/_snaps/git-protocol.md b/tests/testthat/_snaps/git-protocol.md index 487a6841..0434fd61 100644 --- a/tests/testthat/_snaps/git-protocol.md +++ b/tests/testthat/_snaps/git-protocol.md @@ -3,24 +3,26 @@ Code git_list_refs(fake_git$url("/pak-test.git"))$refs Output - # A data frame: 4 x 2 - ref hash - - 1 HEAD 3f3b0b4ee8a0ff4563073924e5fe069da67a6d8b - 2 refs/heads/main 3f3b0b4ee8a0ff4563073924e5fe069da67a6d8b - 3 refs/heads/subdir cefdc0eebcd7f757efb9a80652fd8aaf1a87508e - 4 refs/tags/v1 cefdc0eebcd7f757efb9a80652fd8aaf1a87508e + # A data frame: 5 x 2 + ref hash + + 1 HEAD 3f3b0b4ee8a0ff4563073924e5fe069da67a6d8b + 2 refs/heads/build-ignore a9ffc55f59e0567ecdc67fb3f0333eca49be8d03 + 3 refs/heads/main 3f3b0b4ee8a0ff4563073924e5fe069da67a6d8b + 4 refs/heads/subdir cefdc0eebcd7f757efb9a80652fd8aaf1a87508e + 5 refs/tags/v1 cefdc0eebcd7f757efb9a80652fd8aaf1a87508e --- Code git_list_refs_v2(fake_git$url("/pak-test.git"), "refs/heads/")$refs Output - # A data frame: 2 x 2 - ref hash - - 1 refs/heads/main 3f3b0b4ee8a0ff4563073924e5fe069da67a6d8b - 2 refs/heads/subdir cefdc0eebcd7f757efb9a80652fd8aaf1a87508e + # A data frame: 3 x 2 + ref hash + + 1 refs/heads/build-ignore a9ffc55f59e0567ecdc67fb3f0333eca49be8d03 + 2 refs/heads/main 3f3b0b4ee8a0ff4563073924e5fe069da67a6d8b + 3 refs/heads/subdir cefdc0eebcd7f757efb9a80652fd8aaf1a87508e # git_list_files @@ -230,13 +232,14 @@ Code git_list_refs_v1(fake_git$url("/pak-test.git"))$refs Output - # A data frame: 4 x 2 - ref hash - - 1 HEAD 3f3b0b4ee8a0ff4563073924e5fe069da67a6d8b - 2 refs/heads/main 3f3b0b4ee8a0ff4563073924e5fe069da67a6d8b - 3 refs/heads/subdir cefdc0eebcd7f757efb9a80652fd8aaf1a87508e - 4 refs/tags/v1 cefdc0eebcd7f757efb9a80652fd8aaf1a87508e + # A data frame: 5 x 2 + ref hash + + 1 HEAD 3f3b0b4ee8a0ff4563073924e5fe069da67a6d8b + 2 refs/heads/build-ignore a9ffc55f59e0567ecdc67fb3f0333eca49be8d03 + 3 refs/heads/main 3f3b0b4ee8a0ff4563073924e5fe069da67a6d8b + 4 refs/heads/subdir cefdc0eebcd7f757efb9a80652fd8aaf1a87508e + 5 refs/tags/v1 cefdc0eebcd7f757efb9a80652fd8aaf1a87508e # git_list_refs_v1_process_1 diff --git a/tests/testthat/_snaps/git-submodules.md b/tests/testthat/_snaps/git-submodules.md index 870092c0..ba32ad5f 100644 --- a/tests/testthat/_snaps/git-submodules.md +++ b/tests/testthat/_snaps/git-submodules.md @@ -1,3 +1,56 @@ +# parse_submodules + + Code + parse_submodules(sm) + Output + submodule path + 1 dependencies/fast_double_parser dependencies/fast_double_parser + 2 dependencies/fmt dependencies/fmt + 3 dependencies/boost_math dependencies/boost_math + 4 dependencies/eigen dependencies/eigen + url branch + 1 https://github.com/lemire/fast_double_parser/ + 2 https://github.com/fmtlib/fmt/ + 3 https://github.com/boostorg/math + 4 https://gitlab.com/libeigen/eigen + Code + parse_submodules(read_char(sm)) + Output + submodule path + 1 dependencies/fast_double_parser dependencies/fast_double_parser + 2 dependencies/fmt dependencies/fmt + 3 dependencies/boost_math dependencies/boost_math + 4 dependencies/eigen dependencies/eigen + url branch + 1 https://github.com/lemire/fast_double_parser/ + 2 https://github.com/fmtlib/fmt/ + 3 https://github.com/boostorg/math + 4 https://gitlab.com/libeigen/eigen + +--- + + Code + parse_submodules(tmp) + Output + list() + +--- + + Code + parse_submodules(sm2) + Condition + Warning: + Invalid submodule definition, skipping submodule installation + Output + list() + Code + parse_submodules(sm3) + Condition + Warning: + Invalid submodule definition, skipping submodule installation + Output + list() + # git_download_repo with submodules Code @@ -28,3 +81,97 @@ Output [1] "A git submodule" "Another commit" "Third commit" +# git_download_repo R package with submodules + + Code + dir(tmp, recursive = TRUE) + Output + [1] "v1/DESCRIPTION" "v1/NAMESPACE" "v1/R/foo.R" "v1/README.md" + [5] "v1/submod/README" "v1/wipe.R" + +--- + + Code + readLines(file.path(output, "submod", "README")) + Output + [1] "A git submodule" "Another commit" + +--- + + Code + dir(tmp, recursive = TRUE) + Output + [1] "v1/DESCRIPTION" "v1/NAMESPACE" "v1/R/foo.R" "v1/README.md" + [5] "v1/submod/README" "v1/wipe.R" + +--- + + Code + readLines(file.path(output, "submod", "README")) + Output + [1] "A git submodule" "Another commit" "Third commit" + +--- + + Code + dir(tmp, recursive = TRUE) + Output + [1] "v1/DESCRIPTION" "v1/NAMESPACE" "v1/R/foo.R" "v1/README.md" + [5] "v1/wipe.R" + +--- + + Code + dir(tmp, recursive = TRUE) + Output + [1] "v1/DESCRIPTION" "v1/NAMESPACE" "v1/R/foo.R" "v1/README.md" + [5] "v1/wipe.R" + +# git_download_repo R package with ignored submodule + + Code + dir(tmp, recursive = TRUE, all.files = TRUE, no.. = TRUE) + Output + [1] "v1/.Rbuildignore" + [2] "v1/.github/actions/parameters/action.yml" + [3] "v1/.github/workflows/inputtest.yml" + [4] "v1/.gitignore" + [5] "v1/.gitmodules" + [6] "v1/DESCRIPTION" + [7] "v1/NAMESPACE" + [8] "v1/R/foo.R" + [9] "v1/README.md" + [10] "v1/wipe.R" + +# git_auth_url + + Code + git_auth_url("https://github.com/r-lib/pak") + Output + [1] "https://github.com/r-lib/pak" + +--- + + Code + git_auth_url("https://github.com/r-lib/pak") + Output + [1] "https://user:pass@github.com/r-lib/pak" + +--- + + Code + git_auth_url("https://gitlab.com/gaborcsardi/vli") + Output + [1] "https://user:pass@gitlab.com/gaborcsardi/vli.git" + +# directories + + Code + directories("a") + Output + character(0) + Code + directories("a/b/c/d") + Output + [1] "a" "a/b" "a/b/c" + diff --git a/tests/testthat/fixtures/git-repo.tar.gz b/tests/testthat/fixtures/git-repo.tar.gz index 660fd72a63301be7db601192748e56f5a8566cbb..3f39fcec6437021f0070c491b68697af4e38a339 100644 GIT binary patch literal 39524 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 Date: Thu, 4 Apr 2024 10:52:02 +0200 Subject: [PATCH 10/23] Fix git submodules for windows line endings If passing the parsed content. --- R/git-submodules.R | 2 ++ 1 file changed, 2 insertions(+) diff --git a/R/git-submodules.R b/R/git-submodules.R index c9e01b84..8f99eaac 100644 --- a/R/git-submodules.R +++ b/R/git-submodules.R @@ -1,6 +1,8 @@ # From remotes parse_submodules <- function(file) { if (grepl("\n", file)) { + # fix windows line endings + file <- sub("\r\n", "\n", file, fixed = TRUE) x <- strsplit(file, "\n")[[1]] } else { x <- readLines(file) From 2a01507ea6f489c8a91e3735c46ed408bd4857ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Thu, 4 Apr 2024 11:13:39 +0200 Subject: [PATCH 11/23] Fix submodule test on Windows, really --- R/git-submodules.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/git-submodules.R b/R/git-submodules.R index 8f99eaac..5d0fcf0a 100644 --- a/R/git-submodules.R +++ b/R/git-submodules.R @@ -2,7 +2,7 @@ parse_submodules <- function(file) { if (grepl("\n", file)) { # fix windows line endings - file <- sub("\r\n", "\n", file, fixed = TRUE) + file <- gsub("\r\n", "\n", file, fixed = TRUE) x <- strsplit(file, "\n")[[1]] } else { x <- readLines(file) From ebf8759c78a7543fda087523a3c87426e66ae956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Thu, 4 Apr 2024 12:31:39 +0200 Subject: [PATCH 12/23] Remove auth from type-git We push it down to the git protocol functions. --- R/type-git.R | 26 ++++---------------------- tests/testthat/test-type-git.R | 21 --------------------- 2 files changed, 4 insertions(+), 43 deletions(-) diff --git a/R/type-git.R b/R/type-git.R index 15ff687e..1ddb6aa6 100644 --- a/R/type-git.R +++ b/R/type-git.R @@ -88,7 +88,7 @@ download_remote_git <- function(resolution, target, target_tree, ## 4. Need to download the repo - url <- type_git_auth_url(resolution$remote[[1]]) + url <- resolution$remote[[1]]$url sha <- resolution$metadata[[1]][["RemoteSha"]] pkgdir <- file.path(target_tree, resolution$package) mkdirp(pkgdir) @@ -168,36 +168,18 @@ git_rx <- function() { ) } -type_git_auth_url <- function(remote) { - url <- remote$url - auth <- tryCatch(gitcreds_get(url), error = function(err) NULL) - if (is.null(auth)) { - url - } else { - paste0( - remote$protocol, - "://", - auth$username, - ":", - auth$password, - "@", - sub(paste0("^", remote$protocol, "://"), "", remote$url) - ) - } -} - type_git_get_data <- function(remote) { remote + url <- remote$url sha <- NULL dsc <- NULL - auth_url <- type_git_auth_url(remote) desc_path <- if (is.null(remote$subdir) || remote$subdir == "") { "DESCRIPTION" } else { paste0(remote$subdir, "/", "DESCRIPTION") } - async_git_list_files(auth_url, remote$commitish)$ + async_git_list_files(url, remote$commitish)$ catch(error = function(err) { throw(pkg_error( "Failed to download {.path {desc_path}} from git repo at {.url {remote$url}}." @@ -219,7 +201,7 @@ type_git_get_data <- function(remote) { files$files$hash[desc_idx] })$ then(function(desc_hash) { - async_git_download_file(auth_url, desc_hash, output = NULL)$ + async_git_download_file(url, desc_hash, output = NULL)$ catch(error = function(err) { throw(pkg_error( "Failed to download {.path {desc_path}} from git repo at {.url {remote$url}}." diff --git a/tests/testthat/test-type-git.R b/tests/testthat/test-type-git.R index e1f6595f..c3ac71f9 100644 --- a/tests/testthat/test-type-git.R +++ b/tests/testthat/test-type-git.R @@ -167,27 +167,6 @@ test_that("installedok_remote_git", { ) }) -test_that("type_git_auth_url", { - mockery::stub(type_git_auth_url, "gitcreds_get", function(...) stop("oops")) - expect_equal( - type_git_auth_url(list(url = "https://github.com/r-lib/cli.git")), - "https://github.com/r-lib/cli.git" - ) - - mockery::stub( - type_git_auth_url, - "gitcreds_get", - list(username = "user", password = "secret") - ) - expect_equal( - type_git_auth_url(list( - protocol = "https", - url = "https://github.com/r-lib/cli.git" - )), - "https://user:secret@github.com/r-lib/cli.git" - ) -}) - test_that("type_git_get_data", { # TODO expect_true(TRUE) From a63559433afac536425d2c6ce2e4ef34b86fa863 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Thu, 4 Apr 2024 12:33:59 +0200 Subject: [PATCH 13/23] Remove git auth from submodule code Will be pushed down to the git protocol. --- R/git-submodules.R | 24 +----------------------- tests/testthat/_snaps/git-submodules.md | 21 --------------------- tests/testthat/test-git-submodules.R | 11 ----------- 3 files changed, 1 insertion(+), 55 deletions(-) diff --git a/R/git-submodules.R b/R/git-submodules.R index 5d0fcf0a..217955f0 100644 --- a/R/git-submodules.R +++ b/R/git-submodules.R @@ -122,7 +122,7 @@ async_update_submodule <- function(url, path, branch) { if (is.null(branch) || is.na(branch)) branch <- "HEAD" # message("getting ", path) async_git_download_repo( - git_auth_url(url), + url, ref = branch, output = path, submodules = TRUE @@ -130,28 +130,6 @@ async_update_submodule <- function(url, path, branch) { } } -git_auth_url <- function(url) { - parsed <- parse_url(url) - auth <- tryCatch(gitcreds_get(url), error = function(err) NULL) - if (is.null(auth)) { - url - } else { - paste0( - parsed$protocol, - "://", - auth$username, - ":", - auth$password, - "@", - sub(paste0("^", parsed$protocol, "://"), "", parsed$url), - # gitlab needs .git suffix - if (parsed$host == "gitlab.com" && !endsWith(parsed$url, ".git")) { - ".git" - } - ) - } -} - update_git_submodules_r <- function(path, subdir) { synchronize(async_update_git_submodules_r(path, subdir)) # nocov } diff --git a/tests/testthat/_snaps/git-submodules.md b/tests/testthat/_snaps/git-submodules.md index ba32ad5f..6991ddb7 100644 --- a/tests/testthat/_snaps/git-submodules.md +++ b/tests/testthat/_snaps/git-submodules.md @@ -143,27 +143,6 @@ [9] "v1/README.md" [10] "v1/wipe.R" -# git_auth_url - - Code - git_auth_url("https://github.com/r-lib/pak") - Output - [1] "https://github.com/r-lib/pak" - ---- - - Code - git_auth_url("https://github.com/r-lib/pak") - Output - [1] "https://user:pass@github.com/r-lib/pak" - ---- - - Code - git_auth_url("https://gitlab.com/gaborcsardi/vli") - Output - [1] "https://user:pass@gitlab.com/gaborcsardi/vli.git" - # directories Code diff --git a/tests/testthat/test-git-submodules.R b/tests/testthat/test-git-submodules.R index 6f6def98..914835ae 100644 --- a/tests/testthat/test-git-submodules.R +++ b/tests/testthat/test-git-submodules.R @@ -133,17 +133,6 @@ test_that("git_download_repo R package with ignored submodule", { expect_snapshot(dir(tmp, recursive = TRUE, all.files = TRUE, no.. = TRUE)) }) -test_that("git_auth_url", { - mockery::stub(git_auth_url, "gitcreds_get", function(...) stop("no")) - expect_snapshot(git_auth_url("https://github.com/r-lib/pak")) - - mockery::stub(git_auth_url, "gitcreds_get", function(...) { - list(username = "user", password = "pass") - }) - expect_snapshot(git_auth_url("https://github.com/r-lib/pak")) - expect_snapshot(git_auth_url("https://gitlab.com/gaborcsardi/vli")) -}) - test_that("directories", { dir.create(tmp <- tempfile()) on.exit(unlink(tmp, recursive = TRUE), add = TRUE) From 9e33037a860619abf86369e81250245858ca561b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Thu, 4 Apr 2024 13:10:52 +0200 Subject: [PATCH 14/23] Add auth to all git HTTP queries --- R/git-protocol.R | 60 ++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/R/git-protocol.R b/R/git-protocol.R index 263b8af7..2771799b 100644 --- a/R/git-protocol.R +++ b/R/git-protocol.R @@ -1,4 +1,3 @@ - #' git protocol notes, for developers #' #' Assumptions, they might be relaxed or checked for later: @@ -39,6 +38,23 @@ NULL # ------------------------------------------------------------------------- +git_creds_for_url <- function(url) { + tryCatch( + gitcreds_get(url)[c("username", "password")], + error = function(e) NULL + ) +} + +git_http_get <- function(url, options = list(), ...) { + options <- c(options, git_creds_for_url(url)) + http_get(url, options = options, ...) +} + +git_http_post <- function(url, options = list(), ...) { + options <- c(options, git_creds_for_url(url)) + http_post( url, options = options, ...) +} + #' List references in a remote git repository #' #' @details @@ -803,21 +819,10 @@ async_git_send_message_v2 <- function( "content-length" = as.character(length(msg)) ) - options <- list() - tryCatch( - { - creds <- gitcreds_get(url) - options$username <- creds$username - options$password <- creds$password - }, - error = function(e) NULL - ) - - http_post( + git_http_post( url2, data = msg, - headers = headers, - options = options + headers = headers )$then(http_stop_for_status)$ then(function(res) git_parse_message(res$content)) } @@ -833,7 +838,7 @@ async_git_send_message_v1 <- function(url, args, caps) { "accept" = "application/x-git-upload-pack-result", "content-length" = as.character(length(msg)) ) - http_post( + git_http_post( url2, data = msg, headers = headers @@ -906,7 +911,7 @@ git_list_refs_v1 <- function(url) { async_git_list_refs_v1 <- function(url) { url url1 <- paste0(url, "/info/refs?service=git-upload-pack") - http_get(url1, headers = c("User-Agent" = git_ua()))$ + git_http_get(url1, headers = c("User-Agent" = git_ua()))$ then(http_stop_for_status)$ then(function(response) git_list_refs_v1_process(response, url)) } @@ -1038,18 +1043,7 @@ async_git_list_refs_v2 <- function(url, prefixes = character()) { "git-protocol" = "version=2" ) - # headers from tracing action with GIT_CURL_VERBOSE=1 GIT_TRACE=1 - options <- list() - tryCatch( - { - creds <- gitcreds_get(url) - options$username <- creds$username - options$password <- creds$password - }, - error = function(e) NULL - ) - - http_get(url1, headers = headers, options = options)$ + git_http_get(url1, headers = headers)$ then(http_stop_for_status)$ then(function(res) async_git_list_refs_v2_process_1(res, url, prefixes)) } @@ -1695,9 +1689,9 @@ async_git_dumb_list_refs <- function(url) { "User-Agent" = git_ua() ) when_all( - http_get(url1, headers = headers)$ + git_http_get(url1, headers = headers)$ then(http_stop_for_status), - http_get(url2, headers = headers)$ + git_http_get(url2, headers = headers)$ then(http_stop_for_status) )$ then(function(res) async_git_dumb_list_refs_process(res, url)) @@ -1777,7 +1771,7 @@ async_git_dumb_get_commit <- function(url, sha) { "User-Agent" = git_ua(), "accept-encoding" = "deflate, gzip" ) - http_get(url = url1, headers = headers)$ + git_http_get(url = url1, headers = headers)$ then(http_stop_for_status)$ then(function(res) { cmt <- zip::inflate(res$content)$output @@ -1806,7 +1800,7 @@ async_git_dumb_get_tree <- function(url, sha) { "User-Agent" = git_ua(), "accept-encoding" = "deflate, gzip" ) - http_get(url = url1, headers = headers)$ + git_http_get(url = url1, headers = headers)$ then(http_stop_for_status)$ then(function(res) { cmt <- zip::inflate(res$content)$output @@ -1835,7 +1829,7 @@ async_git_dumb_get_blob <- function(url, sha) { "User-Agent" = git_ua(), "accept-encoding" = "deflate, gzip" ) - http_get(url = url1, headers = headers)$ + git_http_get(url = url1, headers = headers)$ then(http_stop_for_status)$ then(function(res) { cmt <- zip::inflate(res$content)$output From 4de9160a224cedeb3cf7629ef4e20435f0aa5b61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Thu, 4 Apr 2024 13:41:59 +0200 Subject: [PATCH 15/23] Update embedded gitcreds --- R/git-auth.R | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/R/git-auth.R b/R/git-auth.R index ab49842e..4f968a86 100644 --- a/R/git-auth.R +++ b/R/git-auth.R @@ -1,4 +1,3 @@ - # nocov start gitcreds_get <- NULL @@ -379,15 +378,23 @@ gitcreds_run <- function(command, input, args = character()) { git_run <- function(args, input = NULL) { stderr_file <- tempfile("gitcreds-stderr-") on.exit(unlink(stderr_file, recursive = TRUE), add = TRUE) + if (!is.null(input)) { + stdin_file <- tempfile("gitcreds-stdin-") + on.exit(unlink(stdin_file, recursive = TRUE), add = TRUE) + writeBin(charToRaw(input), stdin_file) + stdin <- stdin_file + } else { + stdin <- "" + } out <- tryCatch( suppressWarnings(system2( - "git", args, input = input, stdout = TRUE, stderr = stderr_file + "git", args, stdin = stdin, stdout = TRUE, stderr = stderr_file )), error = function(e) NULL ) if (!is.null(attr(out, "status")) && attr(out, "status") != 0) { - throw(new_error( + throw(new_git_error( "git_error", args = args, stdout = out, @@ -416,7 +423,7 @@ ack <- function(url, current, what = "Replace") { msg(paste0(format(current, header = FALSE), collapse = "\n"), "\n") choices <- c( - "Keep these credentials", + "Abort update with error, and keep the existing credentials", paste(what, "these credentials"), if (has_password(current)) "See the password / token" ) @@ -578,6 +585,12 @@ new_error <- function(class, ..., message = "", call. = TRUE, domain = NULL) { cond } +new_git_error <- function(class, ..., stderr) { + cond <- new_error(class, ..., stderr = stderr) + cond$message <- paste0(cond$message, ": ", stderr) + cond +} + new_warning <- function(class, ..., message = "", call. = TRUE, domain = NULL) { if (message == "") message <- gitcred_errors()[[class]] message <- .makeMessage(message, domain = domain) From e5e84fde15bb1432c4bea884c7a2a1250d812f00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Thu, 4 Apr 2024 14:33:19 +0200 Subject: [PATCH 16/23] Cache git credential lookup failure --- R/git-protocol.R | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/R/git-protocol.R b/R/git-protocol.R index 2771799b..c7306a6b 100644 --- a/R/git-protocol.R +++ b/R/git-protocol.R @@ -39,10 +39,17 @@ NULL # ------------------------------------------------------------------------- git_creds_for_url <- function(url) { - tryCatch( + creds <- tryCatch( gitcreds_get(url)[c("username", "password")], error = function(e) NULL ) + if (is.null(creds)) { + do.call( + Sys.setenv, + structure(list("FAIL"), names = gitcreds_cache_envvar(url)) + ) + } + creds } git_http_get <- function(url, options = list(), ...) { @@ -52,7 +59,7 @@ git_http_get <- function(url, options = list(), ...) { git_http_post <- function(url, options = list(), ...) { options <- c(options, git_creds_for_url(url)) - http_post( url, options = options, ...) + http_post(url, options = options, ...) } #' List references in a remote git repository From 019393c9c8d155e386595c70298608cc87a739e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Thu, 4 Apr 2024 16:03:02 +0200 Subject: [PATCH 17/23] Document changes in gitlab:: package sources --- NEWS.md | 3 +++ inst/docs/pkg-refs.rds | Bin 5202 -> 5366 bytes man/pkg_refs.Rd | 18 ++++++++++++++---- tools/doc/pkg-refs.Rmd | 18 ++++++++++++++---- tools/doc/pkg-refs.md | 18 ++++++++++++++---- 5 files changed, 45 insertions(+), 12 deletions(-) diff --git a/NEWS.md b/NEWS.md index 416c5187..39646d17 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,8 @@ # pkgdepends (development version) +* pkgdepends now supports `gitlab::` package sources better, by adding + explicit syntax to specify subdirectories (#353, @dgkf). + # pkgdepends 0.7.2 * pkgdepends now supports the `*` wildcard for parameter specifications, diff --git a/inst/docs/pkg-refs.rds b/inst/docs/pkg-refs.rds index b774acf7c761181083ccc3fc043a8932f67616c8..ba139340e52a971207f52d4ff6463738fef31f84 100644 GIT binary patch delta 5028 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 delta 4864 zcmV+b6aVb?Dbgr^ABzY80000000Zq@>2ushc2|=9lKzyB`PfBQ?UJb>M$#&_G9f7{ zl6I|%50#`X$0e#2U%-H*4sNAf65|U-Q4j zojZ5_{?70I0saer@7(z(`1^Nves|{|@7($GKcCe)ZA@8zynmt6bG6j6(hFVbBGq;G zUVN{Lt=yb1GriG8R!dc6a-+`WqAjRbEgN;N;T88S)LKI$_){(0wJw@E5zmrkBG1w? z)9<0@YzCwKVv4#^dA@(pQGXa^~(){X5`Yrj01szR!~E_sUAZeU{bZXz#Dvw}zF>1@`CT5nXP8e~U*v}b9hirH+v1%`KWtyRHH=8yKZ zn{-i?Yx(5m;~#*k$GwG1gHsckD&J)Ru1q!3tT(wyO_Oi!ij1xW&X$(N!YtcLXEgl& zVQ$X#0rcOLwE>C^OWhcI_J4xzAU*KW#H52r6`88CZrI~Myej+4gMRw2t+`M+NHlIt ze+18e9j6?5S)QXURUKz&^uxL7_u# zT88Gv>yAv@3U-ueZ8w{;YIHVWFf0(Z>^&DD6@@6>MFUPIuLlJN3MLh=%%ox0FZVFr_H32ewrrPJMRZAG05`Ind9u`+Id zN(1&A#XZcfs&r*820XOpS!bvL(m#ze9Bp<-lHv`qVQc+~1cM56kx2>GwApSnuRx`# z-Zb^j&Vuqd>+nkJp165ORjKtA!EGKLkN-_*8zf@Z=?HZVk z?xM{j6R~Rx1MbiUbb0M9d4@fzrmm-Wwo5vRXT+z zrm4()nj}ewCU3{+IirmhZ#M@d*J{fan&U_U=&s8|sti!BR10_l8~E2&*Vss`Rdt?- zr)ELJG*K5qgErFuJ?9w9O10j=C)A&PR*2tse+P)NE0sbYh~b^>gXM3X8AHw?1poH+ z>lf(mZ7K?AfHq-5@QxxZl9mHjd6BE7Q+`*S_8OPlLMe{|;od`78ZdQpdwN={)ZZ=h`JMNK?IO%r^ zf1$Hrzt&uqu{&j!2J|$84K|DSt7e^d@6Q19yg$m!g-k)&>*GB(SWjS@y_2pxL&XD7 zpc>c=o9Y2~(I8_Uans)yAnO1<#OT*!q}4T{2hj~@pThJo*A-&N&I=+Y;I39{pRhx5 zB%_w+=(VkmApbWv_MHeeH394eV`GsHf1sS}(ovj)b4Z6i6R02hE}xkTZZeGT0-v73 zz;?~ci^!h?)Pu+kQ5u?tOU3a5C>DVV+mplaXsH1-Btk?oGKmtV(i#e;&KjLcyRVoQ zOmpMCM1(_-lC*5|jPi#;GVOpdkcSbDANfIjgd~Cq!KI?FX=oij&50`-k_3YRf4ILu z?72W7h5C}idb4d5Mh{KclhKq@WY)$LNuY%g=XMO_(H?|OpqfSyAhFujmC>muPeAa?!*)OvoPCV*^!-IKe(ni5Y>xd&ZM(}e(hnIm= z&LhAI0XR@huZj>&AbX*`X7^@+!S@R6>^sLQPt);(e+fzcAtVP$ zM<{<$i#{<{*ML{cCHY|(<1dG_lA0mf#0=AJx!I#b1sOdXM*8+b@~_=-G$ zRZ2dTAU_g2o#^zT2D}&3eSp{{oPUK=G5Mz!xLI$DM!oxdnD&OJe|hUM&70FVC&zD( ztkFA>|07TBF%15QLEhVIP}$Hq_VH48Rbn;iw|A2dJO?FT-2*D30saGFXE}??r7Q7g=`ML;S<(LI9>3;4rVv-;84U3U4V1tJa#j> zP{)A>>biore?@Q(gBZFFhp{N4gOM9S59a#o z`**+Tzh%05@4k9)uiwTp#?7V=7xQ%f zuMZyTe?Q*)n!5Mo{H8&$@$?(+=*0Y{KDJ#wg~c)5cdyy>$HA!(M7QbIovn_m>!@C3 zLY~$pz-Hm-_%x7ZH;~kxXJ}$r~h|>x8eekm9Yz4R%N^SZTr5+ zV|}87`YpH%ryNT)FRQc$cxt9;ZiIVZ9fIIae=(Vmm+ATG8a)3;LsGA5!0TSIo9QX1 z)682}yKwIK2&~)Dssxw+f2&^ON40i*qHm{IrT-ECXRCmzOto3LK?c=?@)aJ04Y@A( zu+k^B$&7*mEl_^(uw-J>a1>opnKZC=X)a(HUycoD;uZkjZ$zoa54;E1?8Zj8KOfyN ze_*+f?qPA>usvu#wI3J-qUQR{iY+=-=eD$v@`{I6|6vG_dQM7Wt^|xlQ#6Vk+ zMnk-mPriRjud|NJB1Ld&G#1thfD%R(v$q6kEcHi7_Q?&ne_rVe(`>m?0>NL28W^md zFYRy_8BD)MM-@WN>8y*Zl_uvVgs0uRB1q0sO8_rYnwLuvlzR1MOtZ<|eV) z1ZRy(qHn?GScXm)WjUQIK>9rSFM!tJUs!3f{8j8UI$yeXiI_TuPmw$01AO3bxCv9_ zyhx^wr}RZ6*T}`73~PiVw8t}lXn`s~${m(O3ke*WVR?(&1+G8~91#)@!8 zPxx!Dag1sN_k=ylA80T|sQdA$18MEgR-Vze^o}H8cG6<}feTqs8L`qToCvzo`&#hg zHdVRNRldDm%@0V=5jIr1#@NY84tjK0pc|ZTLh;B{Q+e&6iMNx2O`ycee_Bw(xb(4V zi;=!~JR5^-DuZ*^Nur|}cTiM2xWQ5s7aki?)ZrY~a9mpv&o`-=rVGX}r zv=ybF-Sk8`VJ$2yq9R;&e^IWS#f^ygq`DRL|D-Ci$1H{D)A4U##d{+~;Gr?u7IB@P za!6lItuRl&efIb%?&GJZ{@^YLReFDt0T8}=@o!}So)7Q9cyr(ZM>vsiRX|)tVlx~K z2EvFN=y+%+1;T2agZ;l1_Z(5hE_&)imd}WFpuZ1v05w*s>X$a+e}X-OnliZ|R_Y%* zhGWB9S?-7F%jqAJuN|`f#Q3yd2yM3*Z#cQ#{mWIm3PvJCKjQ`E?L4(11eG&G<%7pi&cg% zGcd;z`Eyi0Xxj^{?~AhF6MnEIG91(8rsKY3VFm-pCD*zFMSTLnIT?t3qi}s`3tXd^ zO5wc;JoB!(YDXXv0mz3}A_!b?9?jJ`A+dHq%7)-`PfK8ve=c-hZm@!2IJJ-66&0E+ zOriZC_Sw%V=)87h0M$TT@Z*1CVP45qci^ELL^x4n9Fc-h1Q@Jr2y1u@@>LCnkiMf0vWJgM(`{m!KTWG65orqZfFe7m%TqI45wSCTqV|+XGkk>~R844Uv~a zYTl6#es_Qkr-;ywWe-d&EDWVdIqbL>j?cN}1jBko@f+Xr%}v_GQQv@&ME+>6B@$M{ ztBSYGYLb9Y)lDTj^z+t12#6&h&yVfAz|4 zpYpG)=v*=5^ECw&{`pnAT%rg@xAC48u($Y&F9hF^LK&KCl#{;w1+gj0;;_c9rs*Xt>0hBZgT0lqrVF^>s|rk+;iyX{gJU)_6f zKQwk1LQd1Kzqxzw;X*z5w{NaH<$e88zih%?akpuJh$&78Sw$(1j&T->GTxS7k}}\preformatted{[=][github::]/[/][] +\if{html}{\out{
}}\preformatted{[=][github::]/[/-/][] }\if{html}{\out{
}} \itemize{ \item \verb{} is the name of the package. If this is missing, then the name of the repository is used. -\item \verb{} is a GitLab username or group name. -\item \verb{} is the name of the repository. +\item \verb{} is a typically the GitLab username or group name, but +it may contain subgroups. +\item \verb{} is the name of the repository, or the project in GitLab +terminology. \item \verb{} optional subdirectory, if the package is within a -subdirectory in the repository. +subdirectory in the repository. Note that for GitLab, this must come +after a \verb{/-} prefix, to be able to distinguish it from subgroups. \item \verb{} may specify a git branch, tag or (prefix of) a commit hash. } If \verb{} is missing, then the latest commit of the \emph{default} branch is used. +\verb{gitlab::} supports git submodules, see the \code{git-submodules} configuration +entry. + Examples: \if{html}{\out{
}}\preformatted{gitlab::gaborcsardi/cli gitlab::r-hub/filelock@main +gitlab::group/subgroup/subsubgroup/project/-/subdir@ref }\if{html}{\out{
}} } @@ -306,6 +313,9 @@ a git branch, tag or (prefix of) a commit hash: \verb{@}. If \verb{} is missing, then the latest commit of the \emph{default} branch is used. +\verb{git::} supports git submodules, see the \code{git-submodules} configuration +entry. + Examples: \if{html}{\out{
}}\preformatted{git::https://github.com/r-lib/crayon diff --git a/tools/doc/pkg-refs.Rmd b/tools/doc/pkg-refs.Rmd index fb81738f..afe52451 100644 --- a/tools/doc/pkg-refs.Rmd +++ b/tools/doc/pkg-refs.Rmd @@ -260,24 +260,31 @@ A GitHub remote string can also be used instead of an URL, for example: Packages from a GitLab repository. Full syntax: ``` -[=][github::]/[/][] +[=][github::]/[/-/][] ``` - `` is the name of the package. If this is missing, then the name of the repository is used. -- `` is a GitLab username or group name. -- `` is the name of the repository. +- `` is a typically the GitLab username or group name, but + it may contain subgroups. +- `` is the name of the repository, or the project in GitLab + terminology. - `` optional subdirectory, if the package is within a - subdirectory in the repository. + subdirectory in the repository. Note that for GitLab, this must come + after a `/-` prefix, to be able to distinguish it from subgroups. - `` may specify a git branch, tag or (prefix of) a commit hash. If `` is missing, then the latest commit of the _default_ branch is used. +`gitlab::` supports git submodules, see the `git-submodules` configuration +entry. + Examples: ``` gitlab::gaborcsardi/cli gitlab::r-hub/filelock@main +gitlab::group/subgroup/subsubgroup/project/-/subdir@ref ``` ### Packages in git repositories (`git::`) @@ -298,6 +305,9 @@ Full syntax: If `` is missing, then the latest commit of the _default_ branch is used. +`git::` supports git submodules, see the `git-submodules` configuration +entry. + Examples: ``` git::https://github.com/r-lib/crayon diff --git a/tools/doc/pkg-refs.md b/tools/doc/pkg-refs.md index 90e703e1..3ea75778 100644 --- a/tools/doc/pkg-refs.md +++ b/tools/doc/pkg-refs.md @@ -256,25 +256,32 @@ A GitHub remote string can also be used instead of an URL, for example: Packages from a GitLab repository. Full syntax: -\if{html}{\out{
}}\preformatted{[=][github::]/[/][] +\if{html}{\out{
}}\preformatted{[=][github::]/[/-/][] }\if{html}{\out{
}} \itemize{ \item \verb{} is the name of the package. If this is missing, then the name of the repository is used. -\item \verb{} is a GitLab username or group name. -\item \verb{} is the name of the repository. +\item \verb{} is a typically the GitLab username or group name, but +it may contain subgroups. +\item \verb{} is the name of the repository, or the project in GitLab +terminology. \item \verb{} optional subdirectory, if the package is within a -subdirectory in the repository. +subdirectory in the repository. Note that for GitLab, this must come +after a \verb{/-} prefix, to be able to distinguish it from subgroups. \item \verb{} may specify a git branch, tag or (prefix of) a commit hash. } If \verb{} is missing, then the latest commit of the \emph{default} branch is used. +\verb{gitlab::} supports git submodules, see the \code{git-submodules} configuration +entry. + Examples: \if{html}{\out{
}}\preformatted{gitlab::gaborcsardi/cli gitlab::r-hub/filelock@main +gitlab::group/subgroup/subsubgroup/project/-/subdir@ref }\if{html}{\out{
}} } @@ -296,6 +303,9 @@ a git branch, tag or (prefix of) a commit hash: \verb{@}. If \verb{} is missing, then the latest commit of the \emph{default} branch is used. +\verb{git::} supports git submodules, see the \code{git-submodules} configuration +entry. + Examples: \if{html}{\out{
}}\preformatted{git::https://github.com/r-lib/crayon From 1ea0659362ac088858b82759900f102766a296cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Thu, 4 Apr 2024 16:10:39 +0200 Subject: [PATCH 18/23] Add NEWS entry for git submodule support [ci skip] --- NEWS.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/NEWS.md b/NEWS.md index 39646d17..75be7c22 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,6 +3,10 @@ * pkgdepends now supports `gitlab::` package sources better, by adding explicit syntax to specify subdirectories (#353, @dgkf). +* `gitlab::` and `git::` package sources now support git submodules if + the `git-submodules` configuration option is set to `TRUE`. See + `?"pkgdepends-config"` (#354). + # pkgdepends 0.7.2 * pkgdepends now supports the `*` wildcard for parameter specifications, From bfdbd01bc51a245c764f09c66d620c61e004b518 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Fri, 5 Apr 2024 10:54:44 +0200 Subject: [PATCH 19/23] Ignore soft deps with bad OS_type, for installation --- NEWS.md | 4 + R/resolution-df.R | 6 +- R/resolution.R | 2 +- R/solve.R | 21 +++++ R/utils.R | 6 +- .../testthat/_snaps/pillar-1.9.0/type-bioc.md | 3 + .../testthat/_snaps/pillar-1.9.0/type-git.md | 3 + tests/testthat/_snaps/type-cran.md | 84 +++++++++---------- 8 files changed, 83 insertions(+), 46 deletions(-) diff --git a/NEWS.md b/NEWS.md index 75be7c22..e041072b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -7,6 +7,10 @@ the `git-submodules` configuration option is set to `TRUE`. See `?"pkgdepends-config"` (#354). +* pkgdepends now automatically ignores soft dependencies that have an + incompatible OS type (`OS_type` entry in `DESCRIPTION`) when installing + packages. + # pkgdepends 0.7.2 * pkgdepends now supports the `*` wildcard for parameter specifications, diff --git a/R/resolution-df.R b/R/resolution-df.R index 212e8485..33cffabf 100644 --- a/R/resolution-df.R +++ b/R/resolution-df.R @@ -33,7 +33,8 @@ res_make_empty_df <- local({ extra = list(), # any extra data (e.g. GitHub sha) dep_types= list(), params = list(), - sysreqs = character() + sysreqs = character(), + os_type = character() ) } data @@ -70,7 +71,8 @@ res_df_defaults <- local({ extra = list(list()), dep_types= list("default"), params = list(character()), - sysreqs = NA_character_ + sysreqs = NA_character_, + os_type = NA_character_ ) } data diff --git a/R/resolution.R b/R/resolution.R index f18d86ba..18b099fd 100644 --- a/R/resolution.R +++ b/R/resolution.R @@ -667,7 +667,7 @@ resolve_from_metadata <- function(remotes, direct, config, cache, "ref", "type", "status", "package", "version", "license", "needscompilation", "priority", "md5sum", "platform", "rversion", "repodir", "target", "deps", "sources", "mirror", - "filesize", "sha256", "sysreqs") + "filesize", "sha256", "sysreqs", "os_type") cols <- intersect(names(data), cols) diff --git a/R/solve.R b/R/solve.R index 72b74f9f..869cbea4 100644 --- a/R/solve.R +++ b/R/solve.R @@ -211,6 +211,7 @@ pkgplan_i_create_lp_problem <- function(pkgs, config, policy) { lp <- pkgplan_i_lp_init(pkgs, config, policy) lp <- pkgplan_i_lp_objectives(lp) + lp <- pkgplan_i_lp_os_type(config, lp) lp <- pkgplan_i_lp_force_source(lp) lp <- pkgplan_i_lp_failures(lp) lp <- pkgplan_i_lp_ignore(lp) @@ -301,6 +302,20 @@ pkgplan_i_lp_objectives <- function(lp) { lp } +pkgplan_i_lp_os_type <- function(config, lp) { + if (config$get("goal") != "install") return(lp) + if (! "os_type" %in% names(lp$pkgs)) return(lp) + os <- os_type() + bad <- which(!is.na(lp$pkgs$os_type) & lp$pkgs$os_type != os) + for (wh in bad) { + lp <- pkgplan_i_lp_add_cond(lp, wh, op = "==", rhs = 0, + type = "matching-platform") + } + lp$ruled_out <- c(lp$ruled_out, bad) + + lp +} + pkgplan_i_lp_force_source <- function(lp) { # if source package is forced, then rule out binaries src_req <- vlapply(lp$pkgs$params, is_true_param, "source") @@ -614,6 +629,12 @@ pkgplan_i_lp_dependencies <- function(lp, config) { ignored2 <- package_version(ignore_rver) > current ignored <- ignored | ignored2 } + # ignore packages with the wrong OS type + if (config$get("goal") == "install") { + os <- os_type() + bad <- which(!is.na(pkgs$os_type) & pkgs$os_type != os) + if (length(bad) > 0) ignored[bad] <- TRUE + } soft_deps <- tolower(pkg_dep_types_soft()) ## 4. Package dependencies must be satisfied diff --git a/R/utils.R b/R/utils.R index c29c6e51..7b57cd78 100644 --- a/R/utils.R +++ b/R/utils.R @@ -494,4 +494,8 @@ backtick <- function(x) { collapse <- function(x, ...) { cli::ansi_collapse(x, ...) -} \ No newline at end of file +} + +na_omit <- function(x) { + x[!is.na(x)] +} diff --git a/tests/testthat/_snaps/pillar-1.9.0/type-bioc.md b/tests/testthat/_snaps/pillar-1.9.0/type-bioc.md index 245d1323..8a626b8b 100644 --- a/tests/testthat/_snaps/pillar-1.9.0/type-bioc.md +++ b/tests/testthat/_snaps/pillar-1.9.0/type-bioc.md @@ -121,4 +121,7 @@ $sysreqs [1] NA + $os_type + [1] NA + diff --git a/tests/testthat/_snaps/pillar-1.9.0/type-git.md b/tests/testthat/_snaps/pillar-1.9.0/type-git.md index d8db24e0..84137c79 100644 --- a/tests/testthat/_snaps/pillar-1.9.0/type-git.md +++ b/tests/testthat/_snaps/pillar-1.9.0/type-git.md @@ -166,6 +166,9 @@ $sysreqs [1] "" + $os_type + [1] NA + $cache_status [1] "miss" diff --git a/tests/testthat/_snaps/type-cran.md b/tests/testthat/_snaps/type-cran.md index cda95a0b..0b79f65e 100644 --- a/tests/testthat/_snaps/type-cran.md +++ b/tests/testthat/_snaps/type-cran.md @@ -3,7 +3,7 @@ Code snapshot(res, extra = "all") Output - # A data frame: 1 x 30 + # A data frame: 1 x 31 ref type direct directpkg status package version license 1 pkg1 standard TRUE TRUE OK pkg1 1.0.0 @@ -16,9 +16,9 @@ mirror sources remote error metadata 1 http://127.0.0.1:/ - extra dep_types params sysreqs cache_status - - 1 miss + extra dep_types params sysreqs os_type cache_status + + 1 miss + sources: http://127.0.0.1://src/contrib/pkg1_1.0.0.tar.gz, http://127.0.0.1://src/contrib/Archive/pkg1/pkg1_1.0.0.tar.gz + remote: @@ -35,7 +35,7 @@ Code snapshot(res, extra = "all") Output - # A data frame: 3 x 30 + # A data frame: 3 x 31 ref type direct directpkg status package version license 1 pkg2 standard FALSE FALSE OK pkg2 1.0.0 @@ -56,11 +56,11 @@ 1 http://127.0.0.1:/ 2 http://127.0.0.1:/ 3 http://127.0.0.1:/ - extra dep_types params sysreqs cache_status - - 1 miss - 2 miss - 3 miss + extra dep_types params sysreqs os_type cache_status + + 1 miss + 2 miss + 3 miss + sources: http://127.0.0.1://src/contrib/pkg2_1.0.0.tar.gz, http://127.0.0.1://src/contrib/Archive/pkg2/pkg2_1.0.0.tar.gz http://127.0.0.1://src/contrib/pkg3_1.0.0.tar.gz, http://127.0.0.1://src/contrib/Archive/pkg3/pkg3_1.0.0.tar.gz @@ -87,7 +87,7 @@ Code snapshot(res, extra = "all") Output - # A data frame: 3 x 30 + # A data frame: 3 x 31 ref type direct directpkg status package version license 1 pkg1 standard FALSE FALSE OK pkg1 1.0.0 @@ -108,11 +108,11 @@ 1 http://127.0.0.1:/ 2 http://127.0.0.1:/ 3 http://127.0.0.1:/ - extra dep_types params sysreqs cache_status - - 1 miss - 2 miss - 3 miss + extra dep_types params sysreqs os_type cache_status + + 1 miss + 2 miss + 3 miss + sources: http://127.0.0.1://src/contrib/pkg1_1.0.0.tar.gz, http://127.0.0.1://src/contrib/Archive/pkg1/pkg1_1.0.0.tar.gz http://127.0.0.1://src/contrib/pkg2_1.0.0.tar.gz, http://127.0.0.1://src/contrib/Archive/pkg2/pkg2_1.0.0.tar.gz @@ -139,7 +139,7 @@ Code snapshot(res, extra = "all") Output - # A data frame: 1 x 30 + # A data frame: 1 x 31 ref type direct directpkg status package 1 cran::xxyyzzqwertyqwerty cran TRUE TRUE FAILED xxyyzzqwertyqwerty @@ -155,9 +155,9 @@ remote error metadata extra dep_types params sysreqs 1 - cache_status - - 1 miss + os_type cache_status + + 1 miss + sources: NA + remote: @@ -174,7 +174,7 @@ Code snapshot(res, extra = "all") Output - # A data frame: 2 x 30 + # A data frame: 2 x 31 ref type direct directpkg status package 1 cran::pkg1 cran TRUE TRUE OK pkg1 @@ -195,10 +195,10 @@ 1 2 - sysreqs cache_status - - 1 miss - 2 miss + sysreqs os_type cache_status + + 1 miss + 2 miss + sources: http://127.0.0.1://src/contrib/pkg1_1.0.0.tar.gz, http://127.0.0.1://src/contrib/Archive/pkg1/pkg1_1.0.0.tar.gz NA @@ -220,7 +220,7 @@ Code snapshot(res, extra = "all") Output - # A data frame: 1 x 30 + # A data frame: 1 x 31 ref type direct directpkg status package version license 1 cran::pkg1@current cran TRUE TRUE OK pkg1 1.0.0 @@ -233,9 +233,9 @@ mirror sources remote error metadata 1 http://127.0.0.1:/ - extra dep_types params sysreqs cache_status - - 1 miss + extra dep_types params sysreqs os_type cache_status + + 1 miss + sources: http://127.0.0.1://src/contrib/pkg1_1.0.0.tar.gz, http://127.0.0.1://src/contrib/Archive/pkg1/pkg1_1.0.0.tar.gz + remote: @@ -252,7 +252,7 @@ Code snapshot(res, extra = "all") Output - # A data frame: 2 x 30 + # A data frame: 2 x 31 ref type direct directpkg status package version license 1 pkg1@0.9.0 standard TRUE TRUE OK pkg1 0.9.0 @@ -269,10 +269,10 @@ 1 2 http://127.0.0.1:/ - extra dep_types params sysreqs cache_status - - 1 "" miss - 2 miss + extra dep_types params sysreqs os_type cache_status + + 1 "" miss + 2 miss + sources: http://127.0.0.1://src/contrib/Archive/pkg1/pkg1_0.9.0.tar.gz http://127.0.0.1://src/contrib/pkg1_1.0.0.tar.gz, http://127.0.0.1://src/contrib/Archive/pkg1/pkg1_1.0.0.tar.gz @@ -294,7 +294,7 @@ Code snapshot(res, extra = "all") Output - # A data frame: 1 x 30 + # A data frame: 1 x 31 ref type direct directpkg status package version license 1 pkg1@1.0.0 standard TRUE TRUE OK pkg1 1.0.0 @@ -307,9 +307,9 @@ mirror sources remote error metadata 1 http://127.0.0.1:/ - extra dep_types params sysreqs cache_status - - 1 miss + extra dep_types params sysreqs os_type cache_status + + 1 miss + sources: http://127.0.0.1://src/contrib/pkg1_1.0.0.tar.gz, http://127.0.0.1://src/contrib/Archive/pkg1/pkg1_1.0.0.tar.gz + remote: @@ -326,7 +326,7 @@ Code snapshot(res, extra = "all") Output - # A data frame: 1 x 30 + # A data frame: 1 x 31 ref type direct directpkg status package version license 1 pkg1@>=0.9.0 standard TRUE TRUE FAILED pkg1 @@ -339,9 +339,9 @@ remote error metadata extra dep_types params sysreqs 1 - cache_status - - 1 miss + os_type cache_status + + 1 miss + sources: NA + remote: From b021072cbfb79d9a476357eea0941060a1638aec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Fri, 5 Apr 2024 11:57:46 +0200 Subject: [PATCH 20/23] Add ?ignore-unavailable for ignore missing soft deps Closes https://github.com/r-lib/pak/issues/606 --- NEWS.md | 4 ++++ R/parse-remotes.R | 11 +++++++++-- R/solve.R | 9 +++++++++ inst/docs/pkg-refs.rds | Bin 5366 -> 5419 bytes man/pkg_refs.Rd | 4 ++++ tools/doc/pkg-refs.Rmd | 4 ++++ tools/doc/pkg-refs.md | 4 ++++ 7 files changed, 34 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index 75be7c22..45488c93 100644 --- a/NEWS.md +++ b/NEWS.md @@ -7,6 +7,10 @@ the `git-submodules` configuration option is set to `TRUE`. See `?"pkgdepends-config"` (#354). +* The new `?ignore-unavailable` parameter makes it easy to ignore soft + dependencies that are unavailable + (https://github.com/r-lib/pak/issues/606). + # pkgdepends 0.7.2 * pkgdepends now supports the `*` wildcard for parameter specifications, diff --git a/R/parse-remotes.R b/R/parse-remotes.R index 2e3142ee..019cea18 100644 --- a/R/parse-remotes.R +++ b/R/parse-remotes.R @@ -272,8 +272,15 @@ add_ref_params <- function(res, params) { res } -known_query_params <- c("ignore", "ignore-before-r", "ignore-build-errors", - "nocache", "reinstall", "source") +known_query_params <- c( + "ignore", + "ignore-before-r", + "ignore-build-errors", + "ignore-unavailable", + "nocache", + "reinstall", + "source" +) parse_query <- function(ref) { query <- sub("^[^?]*(\\?|$)", "", ref) diff --git a/R/solve.R b/R/solve.R index 72b74f9f..143765a8 100644 --- a/R/solve.R +++ b/R/solve.R @@ -606,6 +606,7 @@ pkgplan_i_lp_dependencies <- function(lp, config) { num_candidates <- lp$num_candidates ruled_out <- lp$ruled_out base <- base_packages() + ignored <- vlapply(pkgs$params, is_true_param, "ignore") ignore_rver <- vcapply(pkgs$params, get_param_value, "ignore-before-r") if (any(!is.na(ignore_rver))) { @@ -614,6 +615,14 @@ pkgplan_i_lp_dependencies <- function(lp, config) { ignored2 <- package_version(ignore_rver) > current ignored <- ignored | ignored2 } + ignore_unavail <- vlapply( + pkgs$params, + is_true_param, + "ignore-unavailable" + ) + failed <- pkgs$status == "FAILED" + ignored <- ignored | (ignore_unavail & failed) + soft_deps <- tolower(pkg_dep_types_soft()) ## 4. Package dependencies must be satisfied diff --git a/inst/docs/pkg-refs.rds b/inst/docs/pkg-refs.rds index ba139340e52a971207f52d4ff6463738fef31f84..7aa6f2925b2d462c22b25ec29c3ee41ea35afda0 100644 GIT binary patch literal 5419 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 E09lq<0{{R3 diff --git a/man/pkg_refs.Rd b/man/pkg_refs.Rd index 7363a72d..4dffcaf9 100644 --- a/man/pkg_refs.Rd +++ b/man/pkg_refs.Rd @@ -145,6 +145,10 @@ ignored on R versions that are older than the specified one. E.g. \verb{Matrix=?ignore-before-r=4.1.2} will ignore the Matrix package on R versions that are older than 4.1.2. This parameter really only makes sense in the \code{packgename=?ignore} form. +\item \code{ignore-unavailable} is a flag. It can only be specified for soft +dependencies. If specified and the package is not available, it will be +ignored. This parameter really only makes sense in the +\code{packagename=?ignore-unavailable} form. \item \code{source} is a flag parameter. If specified, then a source R package is requested from a CRAN-like repository. For package installations \code{source} always triggers a re-install. In other words, \code{source} implies the diff --git a/tools/doc/pkg-refs.Rmd b/tools/doc/pkg-refs.Rmd index afe52451..f066873e 100644 --- a/tools/doc/pkg-refs.Rmd +++ b/tools/doc/pkg-refs.Rmd @@ -143,6 +143,10 @@ it is already installed. `Matrix=?ignore-before-r=4.1.2` will ignore the Matrix package on R versions that are older than 4.1.2. This parameter really only makes sense in the `packgename=?ignore` form. +- `ignore-unavailable` is a flag. It can only be specified for soft + dependencies. If specified and the package is not available, it will be + ignored. This parameter really only makes sense in the + `packagename=?ignore-unavailable` form. - `source` is a flag parameter. If specified, then a source R package is requested from a CRAN-like repository. For package installations `source` always triggers a re-install. In other words, `source` implies the diff --git a/tools/doc/pkg-refs.md b/tools/doc/pkg-refs.md index 3ea75778..c6a9422f 100644 --- a/tools/doc/pkg-refs.md +++ b/tools/doc/pkg-refs.md @@ -135,6 +135,10 @@ ignored on R versions that are older than the specified one. E.g. \verb{Matrix=?ignore-before-r=4.1.2} will ignore the Matrix package on R versions that are older than 4.1.2. This parameter really only makes sense in the \code{packgename=?ignore} form. +\item \code{ignore-unavailable} is a flag. It can only be specified for soft +dependencies. If specified and the package is not available, it will be +ignored. This parameter really only makes sense in the +\code{packagename=?ignore-unavailable} form. \item \code{source} is a flag parameter. If specified, then a source R package is requested from a CRAN-like repository. For package installations \code{source} always triggers a re-install. In other words, \code{source} implies the From 34120b06d2050d3a70d79029b8c0d2542209d755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Tue, 23 Apr 2024 23:38:33 +0200 Subject: [PATCH 21/23] Do not duplicate PATH in install process on Windows --- R/install-plan.R | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/R/install-plan.R b/R/install-plan.R index 73e6fb92..76667b31 100644 --- a/R/install-plan.R +++ b/R/install-plan.R @@ -358,14 +358,7 @@ make_build_process <- function(path, pkg, tmp_dir, lib, vignettes, if (is_windows()) { zip_tool_path <- asNamespace("zip")$get_tool("zip") rtools <- get_rtools_path() - withr_local_path( - paste0( - dirname(zip_tool_path), - .Platform$path.sep, - if (!is.null(rtools)) paste0(rtools, .Platform$path.sep), - Sys.getenv("PATH") - ) - ) + withr_local_path(c(dirname(zip_tool_path), rtools)) } # nocov end From 1ecfde9b31d84719ed331f704ff6279a8a780689 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Mon, 6 May 2024 15:06:41 +0200 Subject: [PATCH 22/23] Fix cli message on error Closes https://github.com/r-lib/pak/issues/626 --- R/parse-remotes.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/parse-remotes.R b/R/parse-remotes.R index 019cea18..e661f564 100644 --- a/R/parse-remotes.R +++ b/R/parse-remotes.R @@ -210,7 +210,7 @@ parse_pkg_refs <- function(refs, remote_types = NULL, ...) { if (length(bad <- setdiff(unique_types, names(remote_types)))) { throw(pkg_error( - "Unknown package source{?}: {.val {bad}}.", + "Unknown package source{?s}: {.val {bad}}.", i = msg_package_sources() )) } From d348629c9c0b328e76204b71d058c043ce7dbfbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Thu, 30 May 2024 12:03:21 +0200 Subject: [PATCH 23/23] Fix `git::` for git v2 server w/o 'filter' capability Closes #366. --- R/git-protocol.R | 5 +++++ tests/testthat/_snaps/git-protocol.md | 8 ++++++++ tests/testthat/_snaps/pillar-1.9.0/type-git.md | 2 ++ 3 files changed, 15 insertions(+) diff --git a/R/git-protocol.R b/R/git-protocol.R index c7306a6b..159a70a4 100644 --- a/R/git-protocol.R +++ b/R/git-protocol.R @@ -187,6 +187,7 @@ async_git_resolve_ref <- function(url, ref) { } attr(result, "protocol") <- if ("version 2" %in% refs$caps) 2 else 1 + attr(result, "filter") <- any(grepl("\\bfilter\\b", refs$caps)) result }) @@ -384,6 +385,10 @@ async_git_fetch_v1 <- function(url, sha, blobs) { } async_git_fetch_v2 <- function(url, sha, blobs) { + # If 'filter' is not supported, then we need to get the blobs + if (!is.null(attr(sha, "filter")) && !attr(sha, "filter")) { + blobs <- TRUE + } async_git_send_message_v2( url, "fetch", diff --git a/tests/testthat/_snaps/git-protocol.md b/tests/testthat/_snaps/git-protocol.md index 0434fd61..95b2d534 100644 --- a/tests/testthat/_snaps/git-protocol.md +++ b/tests/testthat/_snaps/git-protocol.md @@ -77,6 +77,8 @@ [1] "cefdc0eebcd7f757efb9a80652fd8aaf1a87508e" attr(,"protocol") [1] 2 + attr(,"filter") + [1] TRUE $commit tree @@ -664,6 +666,8 @@ [1] "3f3b0b4ee8a0ff4563073924e5fe069da67a6d8b" attr(,"protocol") [1] 2 + attr(,"filter") + [1] TRUE --- @@ -673,6 +677,8 @@ [1] "cefdc0eebcd7f757efb9a80652fd8aaf1a87508e" attr(,"protocol") [1] 2 + attr(,"filter") + [1] TRUE --- @@ -682,6 +688,8 @@ [1] "3f3b0b4ee8a0ff4563073924e5fe069da67a6d8b" attr(,"protocol") [1] 2 + attr(,"filter") + [1] TRUE --- diff --git a/tests/testthat/_snaps/pillar-1.9.0/type-git.md b/tests/testthat/_snaps/pillar-1.9.0/type-git.md index 84137c79..45eb7175 100644 --- a/tests/testthat/_snaps/pillar-1.9.0/type-git.md +++ b/tests/testthat/_snaps/pillar-1.9.0/type-git.md @@ -150,6 +150,8 @@ [1] "4cc6312883f2842e948f34a816ce8e846f323a6e" attr(,"protocol") [1] 2 + attr(,"filter") + [1] TRUE