From e832f438fba62e511a796712d470ab6caeb43693 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Fri, 5 Apr 2024 12:15:24 +0200 Subject: [PATCH] Use dev pkgdepends --- DESCRIPTION | 2 +- src/library/pkgdepends/DESCRIPTION | 8 +- src/library/pkgdepends/R/git-app.R | 7 +- src/library/pkgdepends/R/git-auth.R | 21 +- src/library/pkgdepends/R/git-protocol.R | 74 ++++-- src/library/pkgdepends/R/git-submodules.R | 233 ++++++++++++++++++ src/library/pkgdepends/R/install-plan.R | 4 +- src/library/pkgdepends/R/parse-remotes.R | 11 +- src/library/pkgdepends/R/resolution-df.R | 6 +- src/library/pkgdepends/R/resolution.R | 2 +- src/library/pkgdepends/R/solve.R | 31 +++ src/library/pkgdepends/R/type-git.R | 43 ++-- src/library/pkgdepends/R/type-gitlab.R | 34 ++- src/library/pkgdepends/R/utils.R | 10 +- .../pkgdepends/R/zzz-pkgdepends-config.R | 12 + src/library/pkgdepends/inst/WORDLIST | 2 + .../pkgdepends/inst/docs/download-result.rds | Bin 1561 -> 1577 bytes .../pkgdepends/inst/docs/pak-config-docs.rds | Bin 2302 -> 2422 bytes src/library/pkgdepends/inst/docs/pkg-refs.rds | Bin 5202 -> 5419 bytes .../inst/docs/resolution-result.rds | Bin 1306 -> 1320 bytes 20 files changed, 425 insertions(+), 75 deletions(-) create mode 100644 src/library/pkgdepends/R/git-submodules.R diff --git a/DESCRIPTION b/DESCRIPTION index 3feb15caf..36435eb6c 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -68,7 +68,7 @@ Config/needs/dependencies: jsonlite, pkgbuild, pkgcache, - pkgdepends, + r-lib/pkgdepends, pkgsearch, processx, ps, diff --git a/src/library/pkgdepends/DESCRIPTION b/src/library/pkgdepends/DESCRIPTION index 3bda62fc3..719d640c4 100644 --- a/src/library/pkgdepends/DESCRIPTION +++ b/src/library/pkgdepends/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")) @@ -31,11 +31,9 @@ Config/Needs/website: r-lib/asciicast, pkgdown (>= 2.0.2), tidyverse/tidytemplate Config/testthat/edition: 3 Encoding: UTF-8 -RoxygenNote: 7.2.3 +RoxygenNote: 7.3.1.9000 NeedsCompilation: no -Packaged: 2024-03-17 14:42:39 UTC; gaborcsardi +Packaged: 2024-04-05 10:14:55 UTC; gaborcsardi Author: Gábor Csárdi [aut, cre], Posit Software, PBC [cph, fnd] Maintainer: Gábor Csárdi -Repository: CRAN -Date/Publication: 2024-03-17 15:10:02 UTC diff --git a/src/library/pkgdepends/R/git-app.R b/src/library/pkgdepends/R/git-app.R index 7db82943c..3ee741142 100644 --- a/src/library/pkgdepends/R/git-app.R +++ b/src/library/pkgdepends/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/src/library/pkgdepends/R/git-auth.R b/src/library/pkgdepends/R/git-auth.R index ab49842ee..4f968a86e 100644 --- a/src/library/pkgdepends/R/git-auth.R +++ b/src/library/pkgdepends/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) diff --git a/src/library/pkgdepends/R/git-protocol.R b/src/library/pkgdepends/R/git-protocol.R index 0f41cb7a9..c7306a6b0 100644 --- a/src/library/pkgdepends/R/git-protocol.R +++ b/src/library/pkgdepends/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,30 @@ NULL # ------------------------------------------------------------------------- +git_creds_for_url <- function(url) { + 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(), ...) { + 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 @@ -133,6 +156,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 +525,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 +580,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) + } } } } @@ -788,7 +825,8 @@ async_git_send_message_v2 <- function( "git-protocol" = "version=2", "content-length" = as.character(length(msg)) ) - http_post( + + git_http_post( url2, data = msg, headers = headers @@ -807,7 +845,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 @@ -880,7 +918,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)) } @@ -1006,11 +1044,13 @@ 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)$ + + git_http_get(url1, headers = headers)$ then(http_stop_for_status)$ then(function(res) async_git_list_refs_v2_process_1(res, url, prefixes)) } @@ -1656,9 +1696,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)) @@ -1738,7 +1778,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 @@ -1767,7 +1807,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 @@ -1796,7 +1836,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 diff --git a/src/library/pkgdepends/R/git-submodules.R b/src/library/pkgdepends/R/git-submodules.R new file mode 100644 index 000000000..217955f01 --- /dev/null +++ b/src/library/pkgdepends/R/git-submodules.R @@ -0,0 +1,233 @@ +# From remotes +parse_submodules <- function(file) { + if (grepl("\n", file)) { + # fix windows line endings + file <- gsub("\r\n", "\n", file, fixed = TRUE) + 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)) # 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. 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") + async_update_git_submodules(path) + + } else { + if (is.null(branch) || is.na(branch)) branch <- "HEAD" + # message("getting ", path) + async_git_download_repo( + url, + ref = branch, + output = path, + submodules = TRUE + ) + } +} + +update_git_submodules_r <- function(path, subdir) { + synchronize(async_update_git_submodules_r(path, subdir)) # nocov +} + +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 (nrow(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 (nrow(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/src/library/pkgdepends/R/install-plan.R b/src/library/pkgdepends/R/install-plan.R index fa5d104dc..73e6fb924 100644 --- a/src/library/pkgdepends/R/install-plan.R +++ b/src/library/pkgdepends/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/src/library/pkgdepends/R/parse-remotes.R b/src/library/pkgdepends/R/parse-remotes.R index 2e3142ee2..019cea189 100644 --- a/src/library/pkgdepends/R/parse-remotes.R +++ b/src/library/pkgdepends/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/src/library/pkgdepends/R/resolution-df.R b/src/library/pkgdepends/R/resolution-df.R index 212e84852..33cffabf5 100644 --- a/src/library/pkgdepends/R/resolution-df.R +++ b/src/library/pkgdepends/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/src/library/pkgdepends/R/resolution.R b/src/library/pkgdepends/R/resolution.R index f18d86ba0..18b099fdf 100644 --- a/src/library/pkgdepends/R/resolution.R +++ b/src/library/pkgdepends/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/src/library/pkgdepends/R/solve.R b/src/library/pkgdepends/R/solve.R index 72b74f9f4..9df68309e 100644 --- a/src/library/pkgdepends/R/solve.R +++ b/src/library/pkgdepends/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") @@ -606,6 +621,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 +630,21 @@ 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) + + # 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/src/library/pkgdepends/R/type-git.R b/src/library/pkgdepends/R/type-git.R index f15276c1d..1ddb6aa68 100644 --- a/src/library/pkgdepends/R/type-git.R +++ b/src/library/pkgdepends/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 <- resolution$remote[[1]]$url 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,36 +168,18 @@ git_rx <- function() { ) } -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 <- 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}}." @@ -212,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/src/library/pkgdepends/R/type-gitlab.R b/src/library/pkgdepends/R/type-gitlab.R index 52bd7f56d..bf0346e57 100644 --- a/src/library/pkgdepends/R/type-gitlab.R +++ b/src/library/pkgdepends/R/type-gitlab.R @@ -1,18 +1,17 @@ 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") + 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,]) @@ -24,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 @@ -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(), ")?", "$" ) diff --git a/src/library/pkgdepends/R/utils.R b/src/library/pkgdepends/R/utils.R index 617aabd93..7b57cd78f 100644 --- a/src/library/pkgdepends/R/utils.R +++ b/src/library/pkgdepends/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(...) } @@ -490,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/src/library/pkgdepends/R/zzz-pkgdepends-config.R b/src/library/pkgdepends/R/zzz-pkgdepends-config.R index 022752628..dab0c4392 100644 --- a/src/library/pkgdepends/R/zzz-pkgdepends-config.R +++ b/src/library/pkgdepends/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/src/library/pkgdepends/inst/WORDLIST b/src/library/pkgdepends/inst/WORDLIST index 7337eaeaf..d3182ab03 100644 --- a/src/library/pkgdepends/inst/WORDLIST +++ b/src/library/pkgdepends/inst/WORDLIST @@ -37,5 +37,7 @@ pkgdown prettyunits rprojroot shorthands +submodule +submodules tibbles uncompress diff --git a/src/library/pkgdepends/inst/docs/download-result.rds b/src/library/pkgdepends/inst/docs/download-result.rds index af5af23af4d78bd4a90159b769c1d1bd41c75dd1..af9a60cd644a55bf2b64bb10465b0ce91ef4f11b 100644 GIT binary patch literal 1577 zcmV+^2G;o>iwFP!000001Ep78Z`(E$^|ro@Px}dkpB%u|!+`D~KnHkD+XQRVBFTUO z%Mj2KV{ws0Po(0yf&b%v(#|C*N|x+)z#eQ!#*m6fIXET5Qr;gwX- z&BcdHk|-qC_k5`;QE%B=qz_^x&79xsns0KI<~XSgR}~gYVU?~pUd5wOg;*9c*>fZn zX)f=K6}B<(XOl~qt)1kv7j`g| z@Y#*a0wU*yGM1;hXv!)%85$?M(T0M4*zCnQr?>^rgcZ0JQ9|>zlx+Gj1k`tr(rc!C zDGR+B1gUBSw3pz{S3W~l=12{)wLRe*VYrtsw%n{`ssM^?&JdxmxkJYoKxk!h zWj)YniejV8zz-B%&riJJCaQEKRBGGS*jm&kV#4p-k(Rce=iJD4fZP_Udidj|J93Ar zCPDM()BgMHWVcJ$;jTGwW3ADkf*-zB>3SRC)9Y*z)4q#Fq%hI}%;DI+Zj*~2U;G5s z*XIj7@LZVuKNV)1Ru)q|Q0$@U3&9-nH5C;(n(0kdXpu#{w;4gLvr0mT5w${V7OtdR zqulDo9dFN~sBI2`^P8KGJS~*0Y{FktO%P1{cy!f4qtW$SWqs1u!sZ?_-5^~lJCY;Q zB!Rtl1`GaK)|wZxTETc2phw2>cnn7h;2+wY_r{xR{0)^^EP)Td0{O8gPTwpp-n~AX z4l-{=y^_|U8-9HeBt|?U?HyE(p@fJ46e0@83HCP;t?@mhH4s(?BdaNj=$cr%*rfL{ zG~PZE0J(%OEH5>RLRZvt*+@^X)VtL?TT8j)WrKtAlXAyH;h2YGF8M)?o;~@X9b8R*{vKVgtTx5GFc&qJnHxI~B)rwU1yEo;M5y{z`D{d=r%7bQGV$&xr z4&H&9w1Q^LOzr|Txh6&ufbE+|f1W4&&GBNH`^xLOi!ahpj)leWT9+e28T=7@$&p3T>WV;jQ+aSN{c=E;Aa6moRP+=po_@fbgm(Fw=4ak)j2Ft*4tMNI_Mzz-J#4zkKE)&Ckj#`Q`tBs5qw z3aK1!8squ`NK{268TZC)6#2B4wZhoNjfIm@ARxUquD7u80b-MbWuI z%Czq&9ccqQ`IO4FhuR*Q=d(hu6rwtrvm>;nCo&|;d`97{WF5EMw+K#jW7m!FuYYPp z4eg8zN)XGCdz$EL;1XUmYVbuiSd5%@u-<*Sg$-1mX_f|-5d70ow|7s-dqmS{yZzAY zXQlrQlVeDreDN19j-^cvwuH~6Q+D`s+q0`ahoI3h8gU1Q%wP)As{bYga*%vkr(lOD zqXd8cpeon8wr1C++B7Q=L0T9y-NPL9Yp&@v4rst$v@<@8IK=gL19(z3v^3lw`T6DU b*qCh3R!zAiz#r2`?P&KeWkn@7?hpU~-T4y^ literal 1561 zcmV+!2Il!6iwFP!000001Ep78Z`(E$^^o>qeA-VS{NwkP}dLk9q4g62`V|Ok|QLp-hPA1PzP9`VM@i}?^ z>GsWwpYibn{=S<$n|zPYzdtK0OZ8PgG55tkr#h2Q%SIJ;cgAfl!^&@Nh2JY#Wch?O*Rey?l3$yJ);q%vGpSSW>6y5jgL z9)&8zvXIH1BdJJpd1tJ!je$R#T*7SaYzNKWpi{WF>`o@^($bz+cD2|!FFrrYdikU( zs4WVaot^FCsaoEfeGf9ZzO&o4B=c!5YLQwv@F-IYO^6fwvdUzYZn+bK6Te+#zjN;C8r^<$C!iY?+Wk$>@r_;QC?Z&0rJgfoZGZrqRXY z07irn1C$3yJIK&)O5Sp737&+Dh!S;w2&Ami_83qLmCDMHf$%lDr=fvwC@Zs!b-lQny(rX!Jmr2Lmt`e^vzAVx4THeQ z^pfBreOpSnulTEl15Bl>7o^T<<3=}iN|!B@Rl*CMio$tl=B$gN>sW7e7PX0(@H=;;rLE^AVTU{5 zK;>Ga*#w=w?dWv*Kbaqd6bocBhRYvK)+Ooa1?-+|)T-==RCm+xMmPY0Q|qFzbskP5%P2@)e7 zk@gNM$528;9SRYJoA3LZh}QV}Zw-W%!T4#4BDyA)E;i|X3{A9;1VAp~3(HH5qRs*_Sj`)RJ zzYy6T3f^iv-OU4XRJ9_N{Z34|WJFl@W`x@c{P3XJmZbCvh=X^a8Lglhvy8hyGj51o z1Yr9n(x1%uHKjFadXhpsGPJ2pm{Ykex* z7aWV!EMg<$vqvRDDA)Ye`*Ti@hirGsd>iD~9p}9q8xE*w4RpP!LmrFBoBJ@0B~Id} zD>~uWHZHd)62=x;rl^Tv%=_VDz$aF@rTSl^$GBbzwu1(XMj@5MO=DbN03oV~@Z#Q> zjUr#xvQ`+OxUq0DDx?`lEd@6MN>x#6;H#)WycLagwkSF`NSXE>r6XWq8edYm_E6g+ z=6qJ@l|odfb9RJ+^hAcFm(M7im8|2IdspB@H+JXT{Fi4#)X>hjpaiiDd8CQH243Jr zqXu7OgT=^C2kYG{ENr0iOtUnwgy5f!y1jcs-Xoeu+wG&VpOyZ5B*&0I`Ql%=IF>dw zm=B&lXYBCP*)yd+hoI3h8gU1Q%wP)As(;@BIY_>&Q!qW0QG$Q|peon8wr1C++B7SW zI$9XB*28@B-(1sc9MFKhXlHyFafs`$2Job6XeqTn^6M|VV`H*CTQ%j90Dnv$wWHlX LwYxoc!w>)fKZP1p diff --git a/src/library/pkgdepends/inst/docs/pak-config-docs.rds b/src/library/pkgdepends/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/src/library/pkgdepends/inst/docs/pkg-refs.rds b/src/library/pkgdepends/inst/docs/pkg-refs.rds index b774acf7c761181083ccc3fc043a8932f67616c8..7aa6f2925b2d462c22b25ec29c3ee41ea35afda0 100644 GIT binary patch literal 5419 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 Mzx3T%<2FYC01DqBk^lez diff --git a/src/library/pkgdepends/inst/docs/resolution-result.rds b/src/library/pkgdepends/inst/docs/resolution-result.rds index 30dfae83b40c51371a37a7de1d33dc083e71c46a..79e8764cf063acd1310363b036753c3160220257 100644 GIT binary patch literal 1320 zcmV+@1=so?iwFP!000001C3T)Z`(E$^|roDz<~V(B2NzB`e8u#5TFCRCR>AbNzi7% zfMp0M>BizBks3+Gbp!wRol8oxEZglKY*6I==DFwc&tx*0d_8&b4gT?)OuonOtI3PW zx0A_t*LTWOr9RPf5?10aGdVq{jVk@-O!$J@ou9*wcu-X4;=!6~aCUz2;m!NYo7>Cl zE0!opm6Os}pYlnnQl=%%cLK>|R?xlk z(l-wAtO|l#8+^Bxqr+fuXFF)llS|KM(b&~u6Qa0#BAY%d4YOrQ`Ptc~*Ru5Bb|c8C zzW3{z*nL(=D>IJ(o+$IMggkLhIwzg2MG!*}(u);YN;0FJ%CX9W+mLqaXfCF=p$f=c zl*)OLnX;+${B-P`{q{Z-?8E0E&l%?}MJ~O>wa5yVKM*A+H*G@0@VLD0M5I)j)hJ12 zkDn_q z85ccD)Wac=CffL8KrK~9+OdOnwRcZr2cI!k<*!^*!Pf8RuK+sA9`QLc7?PN=q29=z z4-R-_nY?7Iz_t_`aLM;TJr}nHIf||B#7dPVAS0%(Fb#S?rPCzdGm6de^nLU>HW&mx z3P`np_~ZS%PVmk9#ntp>sUGQ6#B*GhCkCgbAkn44U`$NPaG^*`a}hiKY7qdVjeg1I zf;HhxV>7;NnlI;~G?^?zgl?8>v)D4$ugbq|Qb_x3H)u_iyUbKI>dx3W!c0L-4CHpL zv|>>16}W$QWvnt*`SqY<;=xHO9i2ozjILb~FA zHD*`Vq%ZZzaD--T1a~ObOll4^H!EElnfG|_DuP~5G{J_GR)LyjXsJMyYtsbvP8Ut> z3kbZuy}c1xsYv^|xZs{(n8fiIx`Rh!;9KQm(QE082$}65T`IpP$F5ldXWa~z;uBdT zO43U>ZwKg+alAi<`zJtLbTuE0w?O<2w^`o;*S`VzJtv<0vbcPAaegwYyq9)KKA;ukuy36?an;eB*`Mr73TnEir99bz-8gteT@{u zRe_*!zlf7mAf3jAu)yJ(XEahyd@u5`Caci(sBWv-8|1d+j8Gy>0lnnmjiIFRR#41D z$)enb!NyEXXgf1Njvq6seZ0uwTS81rvsA#)=`1lEt56AWZFmO%k;0eh;9}Ro+jJo&O z*gNjtxx=aqpHKxb3JStsdvQtDSdcYdYiG&f*M21TA%!t=_d4t##z#%ayYWd1Ou zGYlsTzA eKfT@@>(WkFH&x1jKW2~Hck>_lb7@U&4FCWW6p-Qo literal 1306 zcmV+#1?Bo5iwFP!000001C3TqZ`?Kz-NMPC1Pb)t3*nOuY;-7)qA<_`+kDhUQYT0p zpoahfC5>0CB~c|QZ#KsM_r4(|tya66=3qlh4&Qw6%^UtLX0zGJ?9s`|?Bp>%XOBPJ zynOO2K7PdCce6*c?`N|ge)_0ARr(7(i0~ypW+tbHwAH2GTu5I~xAI3=k++)4T;5t! zjrN|uc>nC()!Un^H`i=Yk~Ft6)wQx~(WvZBEy>O0t+8@d=&Zm=?WC@;P${oXE%8&` zD_yFzq+}rQ1#rCCjq)D{Wt6nGn}JVRCHC=IH$K9?)yWVA2W(lwN6kRqQ8WT^5Sxhl?S z>vz`^S!--y)`9F}?NBzaa62;CN|XKrU#=@53BICe*xW6n8*G9-aP1Akbf&zY(1)!C$yT$d{lTzQ&xs3a`EKf{MOTnT~gUKjN%5>yFu4Pxyww| zpzh3#Bgz!ak2T7=ffI4(6QlI~oFw9~0!|5KL8SFc|@Kb=(GE4w5gn2NZ*N)o5;QT8oWjmZ|8O+y%>(K_aAR+~f3uFOGJXyf;3y;r z|GJA4S!*G@czIoj!!P$J)ME)_=I(XaL5@$FkXPgL63jvI$z~Wd7_bTc#e=$PjP-8Q zm)f;U%oJYOADV~9-T#GV8XPd7z3L^V>oDZ?Zwq>IH}n%d9{K&Z&9N@+&(>{~GU1Qm Qar