From bf7d19e33aa00b46e5d68fd740d4901311ea0e66 Mon Sep 17 00:00:00 2001 From: dgkf-roche Date: Tue, 3 Sep 2024 14:03:45 -0400 Subject: [PATCH 01/62] wip: refactor updates --- R/check_process.R | 10 ++++++---- R/checks_df.R | 19 ++++++++++--------- R/task_graph.R | 2 ++ R/utils.R | 13 ++++++++++++- 4 files changed, 30 insertions(+), 14 deletions(-) diff --git a/R/check_process.R b/R/check_process.R index 615fd39..dfea009 100644 --- a/R/check_process.R +++ b/R/check_process.R @@ -14,19 +14,19 @@ RE_CHECK <- paste0( ) # nolint end, styler: on -DEFAULT_R_CMD_CHECK_VARIABLES <- c( # nolint +DEFAULT_R_CMD_CHECK_ENVVARS <- c( # nolint "_R_CHECK_FORCE_SUGGESTS_" = FALSE, "_R_CHECK_RD_XREFS_" = FALSE, "_R_CHECK_SYSTEM_CLOCK_" = FALSE, "_R_CHECK_SUGGESTS_ONLY_" = TRUE ) -DEFAULT_BUILD_ARGS <- c( # nolint +DEFAULT_R_CMD_BUILD_ARGS <- c( # nolint "--no-build-vignettes", "--no-manual" ) -DEFAULT_CHECK_ARGS <- c( # nolint +DEFAULT_R_CMD_CHECK_ARGS <- c( # nolint "--timings", "--ignore-vignettes", "--no-manual" @@ -52,7 +52,9 @@ check_process <- R6::R6Class( private$throttle <- throttle() private$spinners <- list( check = silent_spinner("circleHalves"), - starting = silent_spinner(list(frames = c("\u2834", "\u2826", "\u2816", "\u2832"))) + starting = silent_spinner(list( + frames = c("\u2834", "\u2826", "\u2816", "\u2832") + )) ) super$initialize(...) diff --git a/R/checks_df.R b/R/checks_df.R index 6efb6b4..e0b9948 100644 --- a/R/checks_df.R +++ b/R/checks_df.R @@ -153,9 +153,9 @@ rev_dep_check_tasks_specs <- function(packages, repos, aliases, revdep) { revdep_check_task_spec( alias = a, package_spec = package_spec(name = p, repos = repos), - env = DEFAULT_R_CMD_CHECK_VARIABLES, - args = DEFAULT_CHECK_ARGS, - build_args = DEFAULT_BUILD_ARGS, + env = DEFAULT_R_CMD_CHECK_ENVVARS, + args = DEFAULT_R_CMD_CHECK_ARGS, + build_args = DEFAULT_R_CMD_BUILD_ARGS, revdep = revdep ) }, @@ -177,9 +177,9 @@ rev_dep_check_tasks_specs_development <- function( check_task_spec( alias = a, package_spec = package_spec(name = p, repos = repos), - env = DEFAULT_R_CMD_CHECK_VARIABLES, - args = DEFAULT_CHECK_ARGS, - build_args = DEFAULT_BUILD_ARGS + env = DEFAULT_R_CMD_CHECK_ENVVARS, + args = DEFAULT_R_CMD_CHECK_ARGS, + build_args = DEFAULT_R_CMD_BUILD_ARGS ) }, packages, @@ -223,6 +223,7 @@ source_check_tasks_df <- function(path) { df$package <- list_of_task_spec( source_check_tasks_specs(package, path, alias) ) + df$custom <- list_of_task_spec( rep(list(custom_install_task_spec()), times = NROW(df)) ) @@ -236,9 +237,9 @@ source_check_tasks_specs <- function(packages, path, aliases) { check_task_spec( alias = a, package_spec = package_spec_source(name = p, path = path, repos = NULL), - env = DEFAULT_R_CMD_CHECK_VARIABLES, - args = DEFAULT_CHECK_ARGS, - build_args = DEFAULT_BUILD_ARGS + env = DEFAULT_R_CMD_CHECK_ENVVARS, + args = DEFAULT_R_CMD_CHECK_ARGS, + build_args = DEFAULT_R_CMD_BUILD_ARGS ) }, packages, diff --git a/R/task_graph.R b/R/task_graph.R index ac04720..8c45e5b 100644 --- a/R/task_graph.R +++ b/R/task_graph.R @@ -46,6 +46,8 @@ task_edges_df <- function(df, repos) { # Drop potential duplicates desc <- unique(desc) + browser() + # Adding checks to db and custom packages as Depends link checks <- drlapply(df$package, function(x) { p <- df[df$alias == x$alias, ] diff --git a/R/utils.R b/R/utils.R index ad5a5a8..3173bd1 100644 --- a/R/utils.R +++ b/R/utils.R @@ -19,7 +19,18 @@ replace_with_map <- function(x, value, replacement) { x } -hash_alias <- function(x) { +hash_alias <- function(x, n = 24) { + x <- charToRaw(x) + if (length(x) < n * 4) x <- rep_len(x, n * 4) + hash <- vapply( + suppressWarnings(split(x, seq_len(n))), + Reduce, + raw(1), + f = xor + ) + paste(as.character(hash), collapse = "") + + as.integer(charToRaw(x)) paste0(c("hash", as.character(charToRaw(x))), collapse = "") } From 647d55cf27bc26d1491555db2a02ecff10aacef4 Mon Sep 17 00:00:00 2001 From: dgkf-roche Date: Wed, 4 Sep 2024 14:50:06 -0400 Subject: [PATCH 02/62] refactoring --- R/check.R | 3 +-- R/reporter_ansi_tty.R | 2 +- R/task_graph.R | 8 +++----- R/utils-paths.R | 2 +- R/utils.R | 21 +++++++-------------- tests/testthat/test-check-reverse.R | 28 ++++++++++++++++++++-------- tests/testthat/test-check.R | 18 ++++++++++++------ tests/testthat/test-checks_df.R | 6 +++--- tests/testthat/test-results.R | 24 +++++++++++++++++------- 9 files changed, 65 insertions(+), 47 deletions(-) diff --git a/R/check.R b/R/check.R index 623c3d1..6d32847 100644 --- a/R/check.R +++ b/R/check.R @@ -58,11 +58,10 @@ check_rev_deps <- function( path, n = 2L, output = tempfile(paste(utils::packageName(), Sys.Date(), sep = "-")), - lib.loc = .libPaths(), # nolint object_name_linter + lib.loc = .libPaths(), # nolint: object_name_linter. repos = getOption("repos"), reverse_repos = repos, restore = TRUE, - reporter = reporter_default(), ...) { checks <- rev_dep_check_tasks_df(path = path, repos = reverse_repos) diff --git a/R/reporter_ansi_tty.R b/R/reporter_ansi_tty.R index 15ee0e4..cb74f5e 100644 --- a/R/reporter_ansi_tty.R +++ b/R/reporter_ansi_tty.R @@ -109,7 +109,7 @@ report_initialize.reporter_ansi_tty <- function( report_status.reporter_ansi_tty <- function(reporter, design, envir) { # nolint v <- igraph::V(design$graph) v_checks <- v[v$type == "check"] - n_char_titles <- max(nchar(v_checks$name)) + n_char_titles <- max(nchar(v_checks$name), 0) failed_tasks <- design$failed_tasks() failed_packages <- failed_tasks[vlapply(failed_tasks, function(x) x$type == "install")] diff --git a/R/task_graph.R b/R/task_graph.R index 8c45e5b..0fd776e 100644 --- a/R/task_graph.R +++ b/R/task_graph.R @@ -20,7 +20,6 @@ task_graph_create <- function(df, repos = getOption("repos")) { } task_edges_df <- function(df, repos) { - if (NROW(df) == 0) { return(empty_edge) } @@ -31,10 +30,10 @@ task_edges_df <- function(df, repos) { # Add custom packages to db custom_aliases_idx <- which(vlapply(df$custom, function(x) !is.null(x$alias))) - custom_aliases <- vcapply(df$custom[custom_aliases_idx], `[[`, "alias") + custom_aliases <- unique(vcapply(df$custom[custom_aliases_idx], `[[`, "alias")) custom_aliases_map <- unique(data.frame( value = custom_aliases, - hash = vcapply(custom_aliases, hash_alias) + hash = vcapply(custom_aliases, unique_alias) )) desc <- drlapply(df$custom, function(x) { @@ -43,11 +42,10 @@ task_edges_df <- function(df, repos) { row[, "Package"] <- hash row }) + # Drop potential duplicates desc <- unique(desc) - browser() - # Adding checks to db and custom packages as Depends link checks <- drlapply(df$package, function(x) { p <- df[df$alias == x$alias, ] diff --git a/R/utils-paths.R b/R/utils-paths.R index ac54073..3bea2ee 100644 --- a/R/utils-paths.R +++ b/R/utils-paths.R @@ -13,7 +13,7 @@ path_lib <- function(path) { } path_custom_lib <- function(path, custom) { - valid_name <- hash_alias(custom) + valid_name <- unique_alias(custom) dir_create(p <- file.path(path_libs(path), valid_name)) normalizePath(p) } diff --git a/R/utils.R b/R/utils.R index 3173bd1..e362e99 100644 --- a/R/utils.R +++ b/R/utils.R @@ -19,20 +19,13 @@ replace_with_map <- function(x, value, replacement) { x } -hash_alias <- function(x, n = 24) { - x <- charToRaw(x) - if (length(x) < n * 4) x <- rep_len(x, n * 4) - hash <- vapply( - suppressWarnings(split(x, seq_len(n))), - Reduce, - raw(1), - f = xor - ) - paste(as.character(hash), collapse = "") - - as.integer(charToRaw(x)) - paste0(c("hash", as.character(charToRaw(x))), collapse = "") -} +unique_alias <- local({ + n <- 0 + function(x) { + n <<- n + length(x) + sprintf("pkg-id-%08d", n - rev(seq_len(length(x))) + 1) + } +}) dir_create <- function(path) { if (!dir.exists(path)) { diff --git a/tests/testthat/test-check-reverse.R b/tests/testthat/test-check-reverse.R index 978d22d..dfba6f0 100644 --- a/tests/testthat/test-check-reverse.R +++ b/tests/testthat/test-check-reverse.R @@ -1,8 +1,9 @@ create_temp_repo <- function(dir, repo_path) { - dir.create(ctburl <- utils::contrib.url(repo_path, type = "source"), recursive = TRUE) + contrib_url <- utils::contrib.url(repo_path, type = "source") + dir.create(contrib_url, recursive = TRUE) sources <- list.files(dir, pattern = "^.*\\.tar\\.gz$", full.names = TRUE) - vapply(sources, file.copy, FUN.VALUE = logical(1), to = ctburl) - tools::write_PACKAGES(ctburl, type = "source") + vapply(sources, file.copy, FUN.VALUE = logical(1), to = contrib_url) + tools::write_PACKAGES(contrib_url, type = "source") } sources_old <- test_path("testing_pkgs", "revdeps", "v1") @@ -15,9 +16,14 @@ create_temp_repo(sources_old, repo_dir) test_that("check_rev_deps works for package with no revdeps", { # Ensure source installation to make sure test works also on mac and windows withr::with_options(list(pkgType = "source"), { - expect_no_error(design <- check_rev_deps( - file.path(sources_new, "pkg.none"), - n = 2L, repos = repo)) + expect_no_error( + design <- check_rev_deps( + file.path(sources_new, "pkg.none"), + n = 2L, + repos = repo, + reporter = NULL + ) + ) }) r <- results(design) @@ -31,7 +37,10 @@ test_that("check_rev_deps works for package with one breaking change", { withr::with_options(list(pkgType = "source"), { design <- check_rev_deps( file.path(sources_new, "pkg.ok.error"), - n = 2L, repos = repo) + n = 2L, + repos = repo, + reporter = NULL + ) }) r <- results(design) @@ -88,7 +97,10 @@ test_that("check_rev_deps works for a package without release version", { withr::with_options(list(pkgType = "source"), { expect_warning(design <- check_rev_deps( file.path(sources_new, "pkg.suggests"), - n = 2L, repos = repo)) + n = 2L, + repos = repo, + reporter = NULL + )) }) r <- results(design) diff --git a/tests/testthat/test-check.R b/tests/testthat/test-check.R index b96807f..fe369db 100644 --- a/tests/testthat/test-check.R +++ b/tests/testthat/test-check.R @@ -1,10 +1,15 @@ test_that("check_pkgs works as expected", { examples_path <- system.file("example_packages", package = "checked") # WIP - expect_no_error(check_pkgs(c( - file.path(examples_path, "exampleGood"), - file.path(examples_path, "exampleBad") - ), n = 2L, repos = "https://cran.r-project.org/")) + expect_no_error(check_pkgs( + c( + file.path(examples_path, "exampleGood"), + file.path(examples_path, "exampleBad") + ), + n = 2L, + repos = "https://cran.r-project.org/", + reporter = NULL + )) }) test_that("check_pkgs works as expected", { @@ -15,7 +20,8 @@ test_that("check_pkgs works as expected", { file.path(examples_path, "exampleGood"), file.path(examples_path, "exampleBad") ), - n = 2L, repos = "https://cran.r-project.org/", - reporter = checked:::reporter_ansi_tty() + n = 2L, + repos = "https://cran.r-project.org/", + reporter = NULL )) }) diff --git a/tests/testthat/test-checks_df.R b/tests/testthat/test-checks_df.R index 678c95b..b279195 100644 --- a/tests/testthat/test-checks_df.R +++ b/tests/testthat/test-checks_df.R @@ -21,9 +21,9 @@ test_that("rev_dep_check_tasks_df works with deafult params", { expect_true(all(endsWith(df$alias[seq(2, NROW(df), by = 2)], "(v2.3.0)"))) # Test displayes - expect_no_error(print(df)) - expect_no_error(print(df$package)) - expect_no_error(print(df$custom)) + expect_no_error(expect_output(print(df))) + expect_no_error(expect_output(print(df$package))) + expect_no_error(expect_output(print(df$custom))) }) test_that("rev_dep_check_tasks_df development_only = TRUE", { diff --git a/tests/testthat/test-results.R b/tests/testthat/test-results.R index dff53ed..1edab35 100644 --- a/tests/testthat/test-results.R +++ b/tests/testthat/test-results.R @@ -1,19 +1,29 @@ test_that("results_to_file works as expected", { examples_path <- system.file("example_packages", package = "checked") + # WIP - expect_no_error(plan <- check_pkgs(c( - file.path(examples_path, "exampleGood"), - file.path(examples_path, "exampleBad") - ), n = 2L, repos = "https://cran.r-project.org/")) + expect_no_error( + plan <- check_pkgs( + file.path(examples_path, c("exampleGood", "exampleBad")), + n = 2L, + repos = "https://cran.r-project.org/", + reporter = NULL + ) + ) r <- results(plan) r_file <- tempfile() expect_no_error(results_to_file(r, r_file)) expect_true(!identical(readLines(r_file), "No issues identified.")) - expect_no_error(plan <- check_rev_deps(c( - file.path(examples_path, "exampleBad") - ), n = 2L, repos = "https://cran.r-project.org/")) + expect_no_error( + plan <- check_rev_deps( + file.path(examples_path, "exampleBad"), + n = 2L, + repos = "https://cran.r-project.org/", + reporter = NULL + ) + ) r <- results(plan) r_file <- tempfile() From 11e54c088a7bee4b8c7347ab0824ce7d9191b2d0 Mon Sep 17 00:00:00 2001 From: dgkf-roche Date: Wed, 4 Sep 2024 14:55:06 -0400 Subject: [PATCH 03/62] revert hashing changes --- R/utils.R | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/R/utils.R b/R/utils.R index e362e99..7b67357 100644 --- a/R/utils.R +++ b/R/utils.R @@ -19,13 +19,9 @@ replace_with_map <- function(x, value, replacement) { x } -unique_alias <- local({ - n <- 0 - function(x) { - n <<- n + length(x) - sprintf("pkg-id-%08d", n - rev(seq_len(length(x))) + 1) - } -}) +unique_alias <- function(x) { + paste0(c("pkg-id-", as.character(charToRaw(x))), collapse = "") +} dir_create <- function(path) { if (!dir.exists(path)) { From 1ce51e5003ce156dae3cf3f4d8e97daad0e47b40 Mon Sep 17 00:00:00 2001 From: dgkf-roche Date: Wed, 4 Sep 2024 15:55:27 -0400 Subject: [PATCH 04/62] chore: refactor package_source => pkg_origin --- NAMESPACE | 65 +++++----- R/checks_df.R | 70 +++++------ R/next_task.R | 22 ++-- R/package_spec.R | 115 ------------------ R/pkg_origin.R | 113 +++++++++++++++++ R/results.R | 26 ++-- R/task.R | 99 +++++++++++++++ R/task_graph.R | 12 +- R/task_spec.R | 112 ----------------- man/check_rev_deps.Rd | 4 - man/{check_task_spec.Rd => check_task.Rd} | 20 +-- man/checked-task-df.Rd | 14 +-- ...ll_task_spec.Rd => custom_install_task.Rd} | 18 +-- man/{install_task_spec.Rd => install_task.Rd} | 18 +-- man/{package_spec.Rd => pkg_origin.Rd} | 23 ++-- man/print.checked_results.Rd | 8 +- man/rev_dep_check_tasks_df.Rd | 14 +-- ...heck_task_spec.Rd => revdep_check_task.Rd} | 18 +-- man/source_check_tasks_df.Rd | 14 +-- man/{task_spec.Rd => task.Rd} | 18 +-- .../DALEXtra/DESCRIPTION | 0 .../rd2markdown/DESCRIPTION | 0 .../revdeps/v1/pkg.none_1.0.0.tar.gz | Bin .../revdeps/v1/pkg.ok.error_1.0.0.tar.gz | Bin .../v1/rev.both.dependency_1.0.0.tar.gz | Bin .../revdeps/v1/rev.both.error_1.0.0.tar.gz | Bin .../revdeps/v1/rev.both.ok_1.0.0.tar.gz | Bin .../revdeps/v2/pkg.none/DESCRIPTION | 0 .../revdeps/v2/pkg.none/LICENSE | 0 .../revdeps/v2/pkg.none/NAMESPACE | 0 .../revdeps/v2/pkg.none/R/hw.R | 0 .../revdeps/v2/pkg.none/man/hello_world.Rd | 0 .../revdeps/v2/pkg.none/tests/test-hw.R | 0 .../revdeps/v2/pkg.ok.error/DESCRIPTION | 0 .../revdeps/v2/pkg.ok.error/LICENSE | 0 .../revdeps/v2/pkg.ok.error/NAMESPACE | 0 .../revdeps/v2/pkg.ok.error/R/hw.R | 0 .../v2/pkg.ok.error/man/hello_world.Rd | 0 .../v2/pkg.ok.error/man/hello_world_loud.Rd | 0 .../revdeps/v2/pkg.ok.error/tests/test-hw.R | 0 .../revdeps/v2/pkg.suggests/DESCRIPTION | 0 .../revdeps/v2/pkg.suggests/LICENSE | 0 .../revdeps/v2/pkg.suggests/NAMESPACE | 0 .../revdeps/v2/pkg.suggests/R/hw.R | 0 .../v2/pkg.suggests/man/hello_world.Rd | 0 .../revdeps/v2/pkg.suggests/tests/test-hw.R | 0 tests/testthat/test-check-reverse.R | 74 +++++------ tests/testthat/test-checks_df.R | 57 +++++---- 48 files changed, 464 insertions(+), 470 deletions(-) delete mode 100644 R/package_spec.R create mode 100644 R/pkg_origin.R create mode 100644 R/task.R delete mode 100644 R/task_spec.R rename man/{check_task_spec.Rd => check_task.Rd} (77%) rename man/{custom_install_task_spec.Rd => custom_install_task.Rd} (72%) rename man/{install_task_spec.Rd => install_task.Rd} (70%) rename man/{package_spec.Rd => pkg_origin.Rd} (64%) rename man/{revdep_check_task_spec.Rd => revdep_check_task.Rd} (59%) rename man/{task_spec.Rd => task.Rd} (60%) rename tests/testthat/{testing_pkgs => fixtures}/DALEXtra/DESCRIPTION (100%) rename tests/testthat/{testing_pkgs => fixtures}/rd2markdown/DESCRIPTION (100%) rename tests/testthat/{testing_pkgs => fixtures}/revdeps/v1/pkg.none_1.0.0.tar.gz (100%) rename tests/testthat/{testing_pkgs => fixtures}/revdeps/v1/pkg.ok.error_1.0.0.tar.gz (100%) rename tests/testthat/{testing_pkgs => fixtures}/revdeps/v1/rev.both.dependency_1.0.0.tar.gz (100%) rename tests/testthat/{testing_pkgs => fixtures}/revdeps/v1/rev.both.error_1.0.0.tar.gz (100%) rename tests/testthat/{testing_pkgs => fixtures}/revdeps/v1/rev.both.ok_1.0.0.tar.gz (100%) rename tests/testthat/{testing_pkgs => fixtures}/revdeps/v2/pkg.none/DESCRIPTION (100%) rename tests/testthat/{testing_pkgs => fixtures}/revdeps/v2/pkg.none/LICENSE (100%) rename tests/testthat/{testing_pkgs => fixtures}/revdeps/v2/pkg.none/NAMESPACE (100%) rename tests/testthat/{testing_pkgs => fixtures}/revdeps/v2/pkg.none/R/hw.R (100%) rename tests/testthat/{testing_pkgs => fixtures}/revdeps/v2/pkg.none/man/hello_world.Rd (100%) rename tests/testthat/{testing_pkgs => fixtures}/revdeps/v2/pkg.none/tests/test-hw.R (100%) rename tests/testthat/{testing_pkgs => fixtures}/revdeps/v2/pkg.ok.error/DESCRIPTION (100%) rename tests/testthat/{testing_pkgs => fixtures}/revdeps/v2/pkg.ok.error/LICENSE (100%) rename tests/testthat/{testing_pkgs => fixtures}/revdeps/v2/pkg.ok.error/NAMESPACE (100%) rename tests/testthat/{testing_pkgs => fixtures}/revdeps/v2/pkg.ok.error/R/hw.R (100%) rename tests/testthat/{testing_pkgs => fixtures}/revdeps/v2/pkg.ok.error/man/hello_world.Rd (100%) rename tests/testthat/{testing_pkgs => fixtures}/revdeps/v2/pkg.ok.error/man/hello_world_loud.Rd (100%) rename tests/testthat/{testing_pkgs => fixtures}/revdeps/v2/pkg.ok.error/tests/test-hw.R (100%) rename tests/testthat/{testing_pkgs => fixtures}/revdeps/v2/pkg.suggests/DESCRIPTION (100%) rename tests/testthat/{testing_pkgs => fixtures}/revdeps/v2/pkg.suggests/LICENSE (100%) rename tests/testthat/{testing_pkgs => fixtures}/revdeps/v2/pkg.suggests/NAMESPACE (100%) rename tests/testthat/{testing_pkgs => fixtures}/revdeps/v2/pkg.suggests/R/hw.R (100%) rename tests/testthat/{testing_pkgs => fixtures}/revdeps/v2/pkg.suggests/man/hello_world.Rd (100%) rename tests/testthat/{testing_pkgs => fixtures}/revdeps/v2/pkg.suggests/tests/test-hw.R (100%) diff --git a/NAMESPACE b/NAMESPACE index 8870e66..57dae95 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,31 +1,31 @@ # Generated by roxygen2: do not edit by hand S3method("[",checked_results) -S3method(check_path,package_spec) -S3method(check_path,package_spec_archive_source) -S3method(check_path,package_spec_source) +S3method(check_path,pkg_origin) +S3method(check_path,pkg_origin_archive) +S3method(check_path,pkg_origin_local) S3method(count,default) S3method(count,issues) S3method(count,potential_issues) -S3method(format,list_of_task_spec) -S3method(format,task_spec) +S3method(format,list_of_task) +S3method(format,task) S3method(format_status_line_ansi,check_process) S3method(format_status_line_ansi,default) -S3method(get_package_spec_dependencies,default) -S3method(get_package_spec_dependencies,package_spec) -S3method(get_package_spec_dependencies,package_spec_archive_source) -S3method(get_package_spec_dependencies,package_spec_source) -S3method(install_parameters,package_spec) -S3method(install_parameters,package_spec_archive_source) -S3method(install_parameters,package_spec_source) +S3method(install_params,pkg_origin_archive) +S3method(install_params,pkg_origin_local) +S3method(install_params,pkg_origin_source) +S3method(pkg_deps,default) +S3method(pkg_deps,pkg_origin_archive) +S3method(pkg_deps,pkg_origin_local) +S3method(pkg_deps,pkg_origin_source) S3method(print,check_design) S3method(print,checked_results) -S3method(print,checked_results_check_task_spec) -S3method(print,checked_results_revdep_check_task_spec) +S3method(print,checked_results_check_task) +S3method(print,checked_results_revdep_check_task) S3method(print,issues) S3method(print,potential_issues) S3method(print,rcmdcheck_diff) -S3method(print,task_spec) +S3method(print,task) S3method(report_finalize,"NULL") S3method(report_finalize,reporter_ansi_tty) S3method(report_finalize,reporter_basic_tty) @@ -38,42 +38,43 @@ S3method(report_status,"NULL") S3method(report_status,reporter_ansi_tty) S3method(report_status,reporter_basic_tty) S3method(results,check_design) -S3method(results,check_task_spec) -S3method(results,list_check_task_spec) -S3method(results,list_revdep_check_task_spec) -S3method(results,revdep_check_task_spec) +S3method(results,check_task) +S3method(results,list_check_task) +S3method(results,list_revdep_check_task) +S3method(results,revdep_check_task) S3method(run,character) S3method(run,check_design) -S3method(start_task,check_task_spec) -S3method(start_task,custom_install_task_spec) -S3method(start_task,install_task_spec) +S3method(start_task,check_task) +S3method(start_task,custom_install_task) +S3method(start_task,install_task) S3method(summary,check_design) S3method(summary,checked_results) -S3method(summary,checked_results_check_task_spec) -S3method(summary,checked_results_revdep_check_task_spec) +S3method(summary,checked_results_check_task) +S3method(summary,checked_results_revdep_check_task) export(check_design) export(check_dev_rev_deps) export(check_dir) export(check_pkgs) export(check_rev_deps) -export(check_task_spec) -export(custom_install_task_spec) -export(install_task_spec) +export(check_task) +export(custom_install_task) +export(install_task) export(new_check_design) export(new_rev_dep_check_design) -export(package_spec) -export(package_spec_archive_source) -export(package_spec_source) +export(pkg_origin) +export(pkg_origin_archive) +export(pkg_origin_local) +export(pkg_origin_repo) export(reporter_ansi_tty) export(reporter_basic_tty) export(reporter_default) export(results) export(results_to_file) export(rev_dep_check_tasks_df) -export(revdep_check_task_spec) +export(revdep_check_task) export(run) export(source_check_tasks_df) -export(task_spec) +export(task) import(cli) importFrom(R6,R6Class) importFrom(callr,r_process) diff --git a/R/checks_df.R b/R/checks_df.R index e0b9948..a70a815 100644 --- a/R/checks_df.R +++ b/R/checks_df.R @@ -27,9 +27,9 @@ empty_checks_df <- data.frame( #' * `alias`: The alias of the check to run. It also serves the purpose of #' providing a unique identifier and node name in the task graph. #' * `version`: Version of the package to be checked. -#' * `package`: Object that inherits from [`check_task_spec()`]. +#' * `package`: Object that inherits from [`check_task()`]. #' Defines how package to be checked can be acquired. -#' * `custom`: Object that inherits from [`custom_install_task_spec()`]. +#' * `custom`: Object that inherits from [`custom_install_task()`]. #' Defines custom package, for instance only available from local source, that #' should be installed before checking the package. #' @@ -105,18 +105,18 @@ rev_dep_check_tasks_df <- function( } } - task_specs_function <- if (all(c("dev", "release") %in% versions)) { - rev_dep_check_tasks_specs + tasks_function <- if (all(c("dev", "release") %in% versions)) { + rev_dep_check_taskss } else { - rev_dep_check_tasks_specs_development + rev_dep_check_taskss_development } if ("dev" %in% versions) { df_dev$alias <- paste0(df_dev$alias, " (dev)") - df_dev$package <- task_specs_function(revdeps, repos, df_dev$alias, "new") - df_dev$custom <- rep(list(custom_install_task_spec( + df_dev$package <- tasks_function(revdeps, repos, df_dev$alias, "new") + df_dev$custom <- rep(list(custom_install_task( alias = paste0(package, " (dev)"), - package_spec = package_spec_source(name = package, path = path), + package = pkg_origin_local(name = package, path = path), type = "source" )), times = NROW(df_dev)) } @@ -124,10 +124,10 @@ rev_dep_check_tasks_df <- function( if ("release" %in% versions) { package_v <- ap[package, "Version"] df_rel$alias <- paste0(df_rel$alias, " (v", package_v, ")") - df_rel$package <- task_specs_function(revdeps, repos, df_rel$alias, "old") - df_rel$custom <- rep(list(custom_install_task_spec( + df_rel$package <- tasks_function(revdeps, repos, df_rel$alias, "old") + df_rel$custom <- rep(list(custom_install_task( alias = paste0(package, " (release)"), - package_spec = package_spec(name = package, repos = repos), + package = pkg_origin_repo(name = package, repos = repos), # make sure to use the release version built against the same system type = "source" )), times = NROW(df_dev)) @@ -142,17 +142,17 @@ rev_dep_check_tasks_df <- function( df <- rbind(df_dev, df_rel)[idx, ] } - df$package <- list_of_task_spec(df$package) - df$custom <- list_of_task_spec(df$custom) + df$package <- list_of_task(df$package) + df$custom <- list_of_task(df$custom) df } -rev_dep_check_tasks_specs <- function(packages, repos, aliases, revdep) { - list_of_task_spec(mapply( - function(p, a) { - revdep_check_task_spec( - alias = a, - package_spec = package_spec(name = p, repos = repos), +rev_dep_check_taskss <- function(packages, repos, aliases, revdep) { + list_of_task(mapply( + function(package, alias) { + revdep_check_task( + alias = alias, + package = pkg_origin_repo(name = package, repos = repos), env = DEFAULT_R_CMD_CHECK_ENVVARS, args = DEFAULT_R_CMD_CHECK_ARGS, build_args = DEFAULT_R_CMD_BUILD_ARGS, @@ -166,17 +166,17 @@ rev_dep_check_tasks_specs <- function(packages, repos, aliases, revdep) { )) } -rev_dep_check_tasks_specs_development <- function( +rev_dep_check_taskss_development <- function( packages, repos, aliases, ... ) { - list_of_task_spec(mapply( - function(p, a) { - check_task_spec( - alias = a, - package_spec = package_spec(name = p, repos = repos), + list_of_task(mapply( + function(package, alias) { + check_task( + alias = alias, + package = pkg_origin_repo(name = package, repos = repos), env = DEFAULT_R_CMD_CHECK_ENVVARS, args = DEFAULT_R_CMD_CHECK_ARGS, build_args = DEFAULT_R_CMD_BUILD_ARGS @@ -220,23 +220,23 @@ source_check_tasks_df <- function(path) { version = version ) - df$package <- list_of_task_spec( - source_check_tasks_specs(package, path, alias) + df$package <- list_of_task( + source_check_tasks(package, path, alias) ) - df$custom <- list_of_task_spec( - rep(list(custom_install_task_spec()), times = NROW(df)) + df$custom <- list_of_task( + rep(list(custom_install_task()), times = NROW(df)) ) df } -source_check_tasks_specs <- function(packages, path, aliases) { - list_of_task_spec(mapply( - function(p, path, a) { - check_task_spec( - alias = a, - package_spec = package_spec_source(name = p, path = path, repos = NULL), +source_check_tasks <- function(packages, path, aliases) { + list_of_task(mapply( + function(package, path, alias) { + check_task( + alias = alias, + package = pkg_origin_local(name = package, path = path), env = DEFAULT_R_CMD_CHECK_ENVVARS, args = DEFAULT_R_CMD_CHECK_ARGS, build_args = DEFAULT_R_CMD_BUILD_ARGS diff --git a/R/next_task.R b/R/next_task.R index 522ff3e..05a3126 100644 --- a/R/next_task.R +++ b/R/next_task.R @@ -37,18 +37,18 @@ task_get_install_lib <- function(g, node, output) { } start_task <- function(task, g, ...) { - UseMethod("start_task", task_graph_task_spec(g, task)) + UseMethod("start_task", task_graph_task(g, task)) } #' @export -start_task.install_task_spec <- function( +start_task.install_task <- function( task, g, output, lib.loc, # nolint object_name_linter ...) { - spec <- task_graph_task_spec(g, task) - install_parameters <- install_parameters(spec$package_spec) + spec <- task_graph_task(g, task) + install_parameters <- install_params(spec$package) libpaths <- c(task_get_lib_loc(g, task, output), lib.loc) install_packages_process$new( install_parameters$package, @@ -64,14 +64,14 @@ start_task.install_task_spec <- function( } #' @export -start_task.custom_install_task_spec <- function( +start_task.custom_install_task <- function( task, g, output, lib.loc, # nolint object_name_linter ...) { - spec <- task_graph_task_spec(g, task) - install_parameters <- install_parameters(spec$package_spec) + spec <- task_graph_task(g, task) + install_parameters <- install_params(spec$package) libpaths <- c(task_get_lib_loc(g, task, output), lib.loc) install_packages_process$new( install_parameters$package, @@ -87,21 +87,21 @@ start_task.custom_install_task_spec <- function( } #' @export -start_task.check_task_spec <- function( +start_task.check_task <- function( task, g, output, lib.loc, # nolint object_name_linter ...) { - spec <- task_graph_task_spec(g, task) + spec <- task_graph_task(g, task) libpaths <- c(task_get_lib_loc(g, task, output), lib.loc) - path <- check_path(spec$package_spec, output = path_sources()) + path <- check_path(spec$package, output = path_sources()) check_process$new( path = path, check_dir = path_check_output(output, spec$alias), libpath = libpaths, - repos = spec$package_spec$repos, + repos = spec$package$repos, args = spec$args, build_args = spec$build_args, env = spec$env diff --git a/R/package_spec.R b/R/package_spec.R deleted file mode 100644 index ccad4ff..0000000 --- a/R/package_spec.R +++ /dev/null @@ -1,115 +0,0 @@ -#' Package specification -#' -#' Create package specification list which consists of all the details required -#' to identify and acquire source of the package. -#' -#' @param name name of the package. -#' @param repos repository where package with given name should identified. -#' @param path path to the source of the package (either bundled or not). URLs -#' are acceptable. -#' @param ... parameters passed to downstream constructors -#' -#' @family specs -#' @export -package_spec <- function(name = NULL, repos = NULL) { - structure( - list( - name = name, - repos = repos - ), - class = "package_spec" - ) -} - -#' @export -#' @rdname package_spec -package_spec_source <- function(path = NULL, ...) { - package_spec <- package_spec(...) - package_spec["path"] <- list(path) - class(package_spec) <- c("package_spec_source", class(package_spec)) - package_spec -} - -#' @export -#' @rdname package_spec -package_spec_archive_source <- function(path = NULL, ...) { - package_spec <- package_spec_source(path, ...) - - class(package_spec) <- c("package_spec_archive_source", class(package_spec)) - package_spec -} - -get_package_spec_dependencies <- function(package_spec) { - UseMethod("get_package_spec_dependencies") -} - -#' @export -get_package_spec_dependencies.default <- function(package_spec) { - NULL -} - -#' @export -get_package_spec_dependencies.package_spec <- function(package_spec) { - db <- utils::available.packages(repos = package_spec$repos) - row <- db[package_spec$name, , drop = FALSE] - row[, DB_COLNAMES, drop = FALSE] -} - -#' @export -get_package_spec_dependencies.package_spec_source <- function(package_spec) { - row <- as.data.frame(read.dcf(file.path(package_spec$path, "DESCRIPTION"))) - row <- row[, intersect(DB_COLNAMES, colnames(row)), drop = FALSE] - row[setdiff(DB_COLNAMES, colnames(row))] <- NA_character_ - row -} - -#' @export -get_package_spec_dependencies.package_spec_archive_source <- function(package_spec) { - path <- if (!file.exists(package_spec$path)) { - fetch_package_source(package_spec$path, path_sources()) - } else { - package_spec$path - } - utils::untar(path, exdir = dir) - package_spec$path <- file.path(path, package_spec$name) - get_package_spec_dependencies.package_spec_source(package_spec) -} - - -install_parameters <- function(package_spec) { - UseMethod("install_parameters") -} - -#' @export -install_parameters.package_spec <- function(package_spec) { - list(package = package_spec$name, repos = package_spec$repos) -} - -#' @export -install_parameters.package_spec_source <- function(package_spec) { - list(package = package_spec$path, repos = NULL) -} - -#' @export -install_parameters.package_spec_archive_source <- function(package_spec) { - list(package = package_spec$path, repos = NULL) -} - -check_path <- function(package_spec, ...) { - UseMethod("check_path") -} - -#' @export -check_path.package_spec <- function(package_spec, output, ...) { - get_package_source(package_spec$name, package_spec$repos, destdir = output) -} - -#' @export -check_path.package_spec_source <- function(package_spec, ...) { - package_spec$path -} - -#' @export -check_path.package_spec_archive_source <- function(package_spec, ...) { - package_spec$path -} diff --git a/R/pkg_origin.R b/R/pkg_origin.R new file mode 100644 index 0000000..06d8273 --- /dev/null +++ b/R/pkg_origin.R @@ -0,0 +1,113 @@ +#' Package specification +#' +#' Create package specification list which consists of all the details required +#' to identify and acquire source of the package. +#' +#' @param name name of the package. +#' @param repos repository where package with given name should identified. +#' @param path path to the source of the package (either bundled or not). URLs +#' are acceptable. +#' @param ... parameters passed to downstream constructors +#' +#' @family specs +#' @export +pkg_origin <- function(name, ..., .class = c()) { + structure(list(name = name, ...), class = c(.class, "pkg_origin_source")) +} + +#' @export +#' @rdname pkg_origin +pkg_origin_repo <- function(repos, ...) { + pkg_origin(..., repos = repos, .class = "pkg_origin_repo") +} + +#' @export +#' @rdname pkg_origin +pkg_origin_local <- function(path = NULL, ...) { + pkg_origin(..., path = path, .class = "pkg_origin_local") +} + +#' @export +#' @rdname pkg_origin +pkg_origin_archive <- function(path = NULL, ...) { + pkg_origin(..., path = path, .class = "pkg_origin_archive") +} + +pkg_deps <- function(x) { + UseMethod("pkg_deps") +} + +#' @export +pkg_deps.default <- function(x) { + NULL +} + +#' @export +pkg_deps.pkg_origin_source <- function(x) { + db <- utils::available.packages(repos = x$repos) + row <- db[x$name, , drop = FALSE] + row[, DB_COLNAMES, drop = FALSE] +} + +#' @export +pkg_deps.pkg_origin_local <- function(x) { + row <- as.data.frame(read.dcf(file.path(x$path, "DESCRIPTION"))) + row <- row[, intersect(DB_COLNAMES, colnames(row)), drop = FALSE] + row[setdiff(DB_COLNAMES, colnames(row))] <- NA_character_ + row +} + +#' @export +pkg_deps.pkg_origin_archive <- function(x) { + path <- if (!file.exists(x$path)) { + fetch_package_source(x$path, path_sources()) + } else { + x$path + } + utils::untar(path, exdir = dir) + x$path <- file.path(path, x$name) + pkg_deps.pkg_origin_local(x) +} + + +install_params <- function(x) { + UseMethod("install_params") +} + +#' @export +install_params.pkg_origin_source <- function(x) { + list(package = x$name, repos = x$repos) +} + +#' @export +install_params.pkg_origin_local <- function(x) { + list(package = x$path, repos = NULL) +} + +#' @export +install_params.pkg_origin_archive <- function(x) { + list(package = x$path, repos = NULL) +} + +check_path <- function(package_source, ...) { + UseMethod("check_path") +} + +#' @export +check_path.pkg_origin <- function(x, output, ...) { + stop(sprintf("Can't determine origin of package '%s'", x$name)) +} + +check_path.pkg_origin_repo <- function(x, output, ...) { + get_package_source(x$name, x$repos, destdir = output) +} + +#' @export +check_path.pkg_origin_local <- function(x, ...) { + x$path +} + +#' @export +check_path.pkg_origin_archive <- function(x, ...) { + x$path +} diff --git a/R/results.R b/R/results.R index 94b6bce..a5ce22e 100644 --- a/R/results.R +++ b/R/results.R @@ -69,8 +69,8 @@ results.check_design <- function( } #' @export -results.list_revdep_check_task_spec <- function(x, output, ...) { - name <- vcapply(x, function(y) y$package_spec$name) +results.list_revdep_check_task <- function(x, output, ...) { + name <- vcapply(x, function(y) y$package$name) revdep <- vcapply(x, `[[`, "revdep") count <- table(name, revdep) is_complete_pair <- vlapply(name, function(y) { @@ -79,7 +79,6 @@ results.list_revdep_check_task_spec <- function(x, output, ...) { names_complete <- sort(unique(name[is_complete_pair])) - new <- lapply(names_complete, function(y) { x[[which(name == y & revdep == "new")]] }) @@ -95,7 +94,7 @@ results.list_revdep_check_task_spec <- function(x, output, ...) { } #' @export -results.revdep_check_task_spec <- function(x, y, output, ...) { +results.revdep_check_task <- function(x, y, output, ...) { new <- rcmdcheck_from_json(file.path(path_check_output(output, x$alias), "result.json")) old <- rcmdcheck_from_json(file.path(path_check_output(output, y$alias), "result.json")) @@ -140,7 +139,7 @@ results.revdep_check_task_spec <- function(x, y, output, ...) { } #' @export -results.list_check_task_spec <- function(x, output, ...) { +results.list_check_task <- function(x, output, ...) { alias <- vcapply(x, `[[`, "alias") structure( lapply(x, results, output = output), @@ -149,8 +148,9 @@ results.list_check_task_spec <- function(x, output, ...) { } #' @export -results.check_task_spec <- function(x, output, ...) { - x <- rcmdcheck_from_json(file.path(path_check_output(output, x$alias), "result.json")) +results.check_task <- function(x, output, ...) { + json_path <- file.path(path_check_output(output, x$alias), "result.json") + x <- rcmdcheck_from_json(json_path) structure( lapply(CHECK_ISSUES_TYPES, function(i) { @@ -248,12 +248,12 @@ summary.checked_results <- function(object, ...) { } #' @export -summary.checked_results_revdep_check_task_spec <- function(object, ...) { - summary.checked_results_check_task_spec(object, ...) +summary.checked_results_revdep_check_task <- function(object, ...) { + summary.checked_results_check_task(object, ...) } #' @export -summary.checked_results_check_task_spec <- function(object, ...) { +summary.checked_results_check_task <- function(object, ...) { results_to_df(object, ...) } @@ -280,7 +280,7 @@ print.checked_results <- function(x, ...) { #' @name print.checked_results #' @export -print.checked_results_check_task_spec <- function( +print.checked_results_check_task <- function( x, keep = Sys.getenv("CHECKED_RESULTS_KEEP", c("all", "issues", "potential_issues")[1]), ...) { @@ -300,8 +300,8 @@ print.checked_results_check_task_spec <- function( #' @name print.checked_results #' @export -print.checked_results_revdep_check_task_spec <- function(x, ...) { - print.checked_results_check_task_spec(x, ...) +print.checked_results_revdep_check_task <- function(x, ...) { + print.checked_results_check_task(x, ...) } get_issue_header <- function(x) { diff --git a/R/task.R b/R/task.R new file mode 100644 index 0000000..66468a0 --- /dev/null +++ b/R/task.R @@ -0,0 +1,99 @@ +#' Task specification +#' +#' Create task specification list which consists of all the details required +#' to run specific task. +#' +#' @param alias task alias which also serves as unique identifier of the task. +#' @param package \code{\link[checked]{package}} object +#' @param env environmental variables to be set in separate process running +#' specific task. +#' +#' @family tasks +#' @export +task <- function(alias = NULL, package = NULL, env = NULL) { + structure(list(alias = alias, package = package, env = env), class = "task") +} + +list_of_task <- function(x, ...) { + structure(x, class = c("list_of_task", "list")) +} + +#' @family tasks +#' @export +print.task <- function(x, ...) { + cat(format(x, ...), "\n") +} + +#' @family tasks +#' @export +format.task <- function(x, ...) { + paste0("") +} + +#' @family tasks +#' @export +format.list_of_task <- function(x, ...) { + vcapply(x, format) +} + +#' Create a task to install a package and dependencies +#' +#' @param ... Additional parameters passed to [`task()`] +#' @inheritParams utils::install.packages +#' +#' @family tasks +#' @export +install_task <- function( + type = getOption("pkgType"), + INSTALL_opts = NULL, # nolint: object_name_linter. + ... +) { + task <- task(...) + task$type <- type + task$INSTALL_opts <- INSTALL_opts + class(task) <- c("install_task", class(task)) + task +} + +#' Create a custom install task +#' +#' @inheritDotParams install_task +#' +#' @family tasks +#' @export +custom_install_task <- function(...) { + task <- install_task(...) + class(task) <- c("custom_install_task", class(task)) + task +} + +#' Create a task to run `R CMD check` +#' +#' @inheritParams rcmdcheck::rcmdcheck +#' @inheritDotParams task +#' +#' @family tasks +#' @export +check_task <- function(args = NULL, build_args = NULL, ...) { + task <- task(...) + task$args <- args + task$build_args <- build_args + class(task) <- c("check_task", class(task)) + task +} + +#' Create a task to run reverse dependency checks +#' +#' @param revdep character indicating whether the task specification describes +#' check associated with the development (new) or release (old) version of the +#' for which reverse dependency check is run. +#' @param ... Additional parameters passed to [`task()`] +#' +#' @family tasks +#' @export +revdep_check_task <- function(revdep, ...) { + task <- check_task(...) + task["revdep"] <- list(revdep) + class(task) <- c("revdep_check_task", class(task)) + task +} diff --git a/R/task_graph.R b/R/task_graph.R index 0fd776e..5e2c668 100644 --- a/R/task_graph.R +++ b/R/task_graph.R @@ -37,7 +37,7 @@ task_edges_df <- function(df, repos) { )) desc <- drlapply(df$custom, function(x) { - row <- get_package_spec_dependencies(x$package_spec) + row <- pkg_deps(x$package) hash <- custom_aliases_map[custom_aliases_map$value == x$alias, ]$hash row[, "Package"] <- hash row @@ -49,7 +49,7 @@ task_edges_df <- function(df, repos) { # Adding checks to db and custom packages as Depends link checks <- drlapply(df$package, function(x) { p <- df[df$alias == x$alias, ] - row <- get_package_spec_dependencies(x$package_spec) + row <- pkg_deps(x$package) row[, "Package"] <- x$alias if (!is.null(p$custom[[1]]$alias)) { row_idx <- custom_aliases_map$value == p$custom[[1]]$alias @@ -94,7 +94,7 @@ task_edges_df <- function(df, repos) { dependencies <- dependencies[!dependencies %in% base_pkgs()] edges <- drlapply(dependencies, function(p) { - edges_per_type <- drlapply(uulist(DEP), function(type) { + drlapply(uulist(DEP), function(type) { deps <- try(db[db[, "Package"] == p, type], silent = TRUE) if (inherits(deps, "try-error") || length(deps) == 0) { empty_edge @@ -126,9 +126,9 @@ task_vertices_df <- function(df, edges, repos) { } else if (v %in% custom_pkgs_aliases) { df$custom[[utils::head(which(as.character(lapply(df$custom, `[[`, "alias")) == v), 1)]] } else { - install_task_spec( + install_task( alias = v, - package_spec = package_spec(name = v, repos = repos) + package = pkg_origin_repo(name = v, repos = repos) ) } }) @@ -311,7 +311,7 @@ task_graph_package_status <- function(g, v) { } -task_graph_task_spec <- function(g, v) { +task_graph_task <- function(g, v) { igraph::vertex_attr(g, "spec", v)[[1]] } diff --git a/R/task_spec.R b/R/task_spec.R deleted file mode 100644 index 43a38b0..0000000 --- a/R/task_spec.R +++ /dev/null @@ -1,112 +0,0 @@ -#' Task specification -#' -#' Create task specification list which consists of all the details required -#' to run specific task. -#' -#' @param alias task alias which also serves as unique identifier of the task. -#' @param package_spec \code{\link[checked]{package_spec}} object -#' @param env environmental variables to be set in separate process running -#' specific task. -#' -#' @family tasks -#' @export -task_spec <- function(alias = NULL, package_spec = NULL, env = NULL) { - structure( - list( - alias = alias, - package_spec = package_spec, - env = env - ), - class = "task_spec" - ) -} - -list_of_task_spec <- function(x, ...) { - structure(x, class = c("list_of_task_spec", "list")) -} - -#' @family tasks -#' @export -print.task_spec <- function(x, ...) { - cat(format(x, ...), "\n") -} - -#' @family tasks -#' @export -format.task_spec <- function(x, ...) { - paste0("") -} - -#' @family tasks -#' @export -format.list_of_task_spec <- function(x, ...) { - vcapply(x, format) -} - -#' Create a task to install a package and dependencies -#' -#' @param ... Additional parameters passed to [`task_spec()`] -#' @inheritParams utils::install.packages -#' -#' @family tasks -#' @export -install_task_spec <- function(type = getOption("pkgType"), INSTALL_opts = NULL, ...) { - task_spec <- task_spec(...) - install_spec <- list( - type = type, - INSTALL_opts = INSTALL_opts - ) - structure( - c(install_spec, task_spec), - class = c("install_task_spec", class(task_spec)) - ) -} - -#' Create a custom install task -#' -#' @inheritDotParams install_task_spec -#' -#' @family tasks -#' @export -custom_install_task_spec <- function(...) { - task_spec <- install_task_spec(...) - class(task_spec) <- c("custom_install_task_spec", class(task_spec)) - task_spec -} - -#' Create a task to run `R CMD check` -#' -#' @inheritParams rcmdcheck::rcmdcheck -#' @inheritDotParams task_spec -#' -#' @family tasks -#' @export -check_task_spec <- function(args = NULL, build_args = NULL, ...) { - task_spec <- task_spec(...) - check_spec <- list( - args = args, - build_args = build_args - ) - - structure( - c(check_spec, task_spec), - class = c("check_task_spec", class(task_spec)) - ) -} - -#' Create a task to run reverse dependency checks -#' -#' @param revdep character indicating whether the task specification describes -#' check associated with the development (new) or release (old) version of the -#' for which reverse dependency check is run. -#' @param ... Additional parameters passed to [`task_spec()`] -#' -#' @family tasks -#' @export -revdep_check_task_spec <- function(revdep, ...) { - task_spec <- check_task_spec(...) - task_spec["revdep"] <- list(revdep) - class(task_spec) <- c("revdep_check_task_spec", class(task_spec)) - - task_spec -} diff --git a/man/check_rev_deps.Rd b/man/check_rev_deps.Rd index 3f3715b..503f601 100644 --- a/man/check_rev_deps.Rd +++ b/man/check_rev_deps.Rd @@ -12,7 +12,6 @@ check_rev_deps( repos = getOption("repos"), reverse_repos = repos, restore = TRUE, - reporter = reporter_default(), ... ) } @@ -40,9 +39,6 @@ sources to check and different when installing dependencies.} unlinked before running checks. If \code{FALSE}, an attempt will me made to restore previous progress from the same \code{output}} -\item{reporter}{A reporter to provide progress updates. Will default to the -most expressive command-line reporter given your terminal capabilities.} - \item{...}{Additional arguments passed to \code{\link[=run]{run()}}} } \value{ diff --git a/man/check_task_spec.Rd b/man/check_task.Rd similarity index 77% rename from man/check_task_spec.Rd rename to man/check_task.Rd index 893382f..8ed1068 100644 --- a/man/check_task_spec.Rd +++ b/man/check_task.Rd @@ -1,10 +1,10 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/task_spec.R -\name{check_task_spec} -\alias{check_task_spec} +% Please edit documentation in R/task.R +\name{check_task} +\alias{check_task} \title{Create a task to run \verb{R CMD check}} \usage{ -check_task_spec(args = NULL, build_args = NULL, ...) +check_task(args = NULL, build_args = NULL, ...) } \arguments{ \item{args}{Character vector of arguments to pass to \verb{R CMD check}. Pass each @@ -22,10 +22,10 @@ spaces to delimit arguments like you would in the shell). For example, \code{build_args = "--force --keep-empty-dirs"} is incorrect.} \item{...}{ - Arguments passed on to \code{\link[=task_spec]{task_spec}} + Arguments passed on to \code{\link[=task]{task}} \describe{ \item{\code{alias}}{task alias which also serves as unique identifier of the task.} - \item{\code{package_spec}}{\code{\link[checked]{package_spec}} object} + \item{\code{package}}{\code{\link[checked]{package}} object} \item{\code{env}}{environmental variables to be set in separate process running specific task.} }} @@ -36,11 +36,11 @@ Create a task to run \verb{R CMD check} \seealso{ Other tasks: \code{\link{checked-task-df}}, -\code{\link{custom_install_task_spec}()}, -\code{\link{install_task_spec}()}, +\code{\link{custom_install_task}()}, +\code{\link{install_task}()}, \code{\link{rev_dep_check_tasks_df}()}, -\code{\link{revdep_check_task_spec}()}, +\code{\link{revdep_check_task}()}, \code{\link{source_check_tasks_df}()}, -\code{\link{task_spec}()} +\code{\link{task}()} } \concept{tasks} diff --git a/man/checked-task-df.Rd b/man/checked-task-df.Rd index 8c46cea..e6303dd 100644 --- a/man/checked-task-df.Rd +++ b/man/checked-task-df.Rd @@ -14,9 +14,9 @@ The check schedule \code{data.frame} with the following columns: \item \code{alias}: The alias of the check to run. It also serves the purpose of providing a unique identifier and node name in the task graph. \item \code{version}: Version of the package to be checked. -\item \code{package}: Object that inherits from \code{\link[=check_task_spec]{check_task_spec()}}. +\item \code{package}: Object that inherits from \code{\link[=check_task]{check_task()}}. Defines how package to be checked can be acquired. -\item \code{custom}: Object that inherits from \code{\link[=custom_install_task_spec]{custom_install_task_spec()}}. +\item \code{custom}: Object that inherits from \code{\link[=custom_install_task]{custom_install_task()}}. Defines custom package, for instance only available from local source, that should be installed before checking the package. } @@ -34,12 +34,12 @@ a vector of an arbitrary length. } \seealso{ Other tasks: -\code{\link{check_task_spec}()}, -\code{\link{custom_install_task_spec}()}, -\code{\link{install_task_spec}()}, +\code{\link{check_task}()}, +\code{\link{custom_install_task}()}, +\code{\link{install_task}()}, \code{\link{rev_dep_check_tasks_df}()}, -\code{\link{revdep_check_task_spec}()}, +\code{\link{revdep_check_task}()}, \code{\link{source_check_tasks_df}()}, -\code{\link{task_spec}()} +\code{\link{task}()} } \concept{tasks} diff --git a/man/custom_install_task_spec.Rd b/man/custom_install_task.Rd similarity index 72% rename from man/custom_install_task_spec.Rd rename to man/custom_install_task.Rd index 5e23cc8..c678f5f 100644 --- a/man/custom_install_task_spec.Rd +++ b/man/custom_install_task.Rd @@ -1,14 +1,14 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/task_spec.R -\name{custom_install_task_spec} -\alias{custom_install_task_spec} +% Please edit documentation in R/task.R +\name{custom_install_task} +\alias{custom_install_task} \title{Create a custom install task} \usage{ -custom_install_task_spec(...) +custom_install_task(...) } \arguments{ \item{...}{ - Arguments passed on to \code{\link[=install_task_spec]{install_task_spec}} + Arguments passed on to \code{\link[=install_task]{install_task}} \describe{ \item{\code{type}}{character, indicating the type of package to download and install. Will be \code{"source"} except on Windows and some macOS @@ -29,12 +29,12 @@ Create a custom install task } \seealso{ Other tasks: -\code{\link{check_task_spec}()}, +\code{\link{check_task}()}, \code{\link{checked-task-df}}, -\code{\link{install_task_spec}()}, +\code{\link{install_task}()}, \code{\link{rev_dep_check_tasks_df}()}, -\code{\link{revdep_check_task_spec}()}, +\code{\link{revdep_check_task}()}, \code{\link{source_check_tasks_df}()}, -\code{\link{task_spec}()} +\code{\link{task}()} } \concept{tasks} diff --git a/man/install_task_spec.Rd b/man/install_task.Rd similarity index 70% rename from man/install_task_spec.Rd rename to man/install_task.Rd index d1c4e96..a31af1c 100644 --- a/man/install_task_spec.Rd +++ b/man/install_task.Rd @@ -1,10 +1,10 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/task_spec.R -\name{install_task_spec} -\alias{install_task_spec} +% Please edit documentation in R/task.R +\name{install_task} +\alias{install_task} \title{Create a task to install a package and dependencies} \usage{ -install_task_spec(type = getOption("pkgType"), INSTALL_opts = NULL, ...) +install_task(type = getOption("pkgType"), INSTALL_opts = NULL, ...) } \arguments{ \item{type}{character, indicating the type of package to download and @@ -21,19 +21,19 @@ install_task_spec(type = getOption("pkgType"), INSTALL_opts = NULL, ...) additional options, with names the respective package names. } -\item{...}{Additional parameters passed to \code{\link[=task_spec]{task_spec()}}} +\item{...}{Additional parameters passed to \code{\link[=task]{task()}}} } \description{ Create a task to install a package and dependencies } \seealso{ Other tasks: -\code{\link{check_task_spec}()}, +\code{\link{check_task}()}, \code{\link{checked-task-df}}, -\code{\link{custom_install_task_spec}()}, +\code{\link{custom_install_task}()}, \code{\link{rev_dep_check_tasks_df}()}, -\code{\link{revdep_check_task_spec}()}, +\code{\link{revdep_check_task}()}, \code{\link{source_check_tasks_df}()}, -\code{\link{task_spec}()} +\code{\link{task}()} } \concept{tasks} diff --git a/man/package_spec.Rd b/man/pkg_origin.Rd similarity index 64% rename from man/package_spec.Rd rename to man/pkg_origin.Rd index 8319eb1..5a5d5f7 100644 --- a/man/package_spec.Rd +++ b/man/pkg_origin.Rd @@ -1,26 +1,29 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/package_spec.R -\name{package_spec} -\alias{package_spec} -\alias{package_spec_source} -\alias{package_spec_archive_source} +% Please edit documentation in R/pkg_origin.R +\name{pkg_origin} +\alias{pkg_origin} +\alias{pkg_origin_repo} +\alias{pkg_origin_local} +\alias{pkg_origin_archive} \title{Package specification} \usage{ -package_spec(name = NULL, repos = NULL) +pkg_origin(name = NULL) -package_spec_source(path = NULL, ...) +pkg_origin_repo(repos, ...) -package_spec_archive_source(path = NULL, ...) +pkg_origin_local(path = NULL, ...) + +pkg_origin_archive(path = NULL, ...) } \arguments{ \item{name}{name of the package.} \item{repos}{repository where package with given name should identified.} +\item{...}{parameters passed to downstream constructors} + \item{path}{path to the source of the package (either bundled or not). URLs are acceptable.} - -\item{...}{parameters passed to downstream constructors} } \description{ Create package specification list which consists of all the details required diff --git a/man/print.checked_results.Rd b/man/print.checked_results.Rd index e9820c0..5b7c18d 100644 --- a/man/print.checked_results.Rd +++ b/man/print.checked_results.Rd @@ -2,19 +2,19 @@ % Please edit documentation in R/results.R \name{print.checked_results} \alias{print.checked_results} -\alias{print.checked_results_check_task_spec} -\alias{print.checked_results_revdep_check_task_spec} +\alias{print.checked_results_check_task} +\alias{print.checked_results_revdep_check_task} \title{Print checked results} \usage{ \method{print}{checked_results}(x, ...) -\method{print}{checked_results_check_task_spec}( +\method{print}{checked_results_check_task}( x, keep = Sys.getenv("CHECKED_RESULTS_KEEP", c("all", "issues", "potential_issues")[1]), ... ) -\method{print}{checked_results_revdep_check_task_spec}(x, ...) +\method{print}{checked_results_revdep_check_task}(x, ...) } \arguments{ \item{x}{an object to be printed.} diff --git a/man/rev_dep_check_tasks_df.Rd b/man/rev_dep_check_tasks_df.Rd index faa5097..1ffdc89 100644 --- a/man/rev_dep_check_tasks_df.Rd +++ b/man/rev_dep_check_tasks_df.Rd @@ -36,9 +36,9 @@ The check schedule \code{data.frame} with the following columns: \item \code{alias}: The alias of the check to run. It also serves the purpose of providing a unique identifier and node name in the task graph. \item \code{version}: Version of the package to be checked. -\item \code{package}: Object that inherits from \code{\link[=check_task_spec]{check_task_spec()}}. +\item \code{package}: Object that inherits from \code{\link[=check_task]{check_task()}}. Defines how package to be checked can be acquired. -\item \code{custom}: Object that inherits from \code{\link[=custom_install_task_spec]{custom_install_task_spec()}}. +\item \code{custom}: Object that inherits from \code{\link[=custom_install_task]{custom_install_task()}}. Defines custom package, for instance only available from local source, that should be installed before checking the package. } @@ -56,12 +56,12 @@ a vector of an arbitrary length. } \seealso{ Other tasks: -\code{\link{check_task_spec}()}, +\code{\link{check_task}()}, \code{\link{checked-task-df}}, -\code{\link{custom_install_task_spec}()}, -\code{\link{install_task_spec}()}, -\code{\link{revdep_check_task_spec}()}, +\code{\link{custom_install_task}()}, +\code{\link{install_task}()}, +\code{\link{revdep_check_task}()}, \code{\link{source_check_tasks_df}()}, -\code{\link{task_spec}()} +\code{\link{task}()} } \concept{tasks} diff --git a/man/revdep_check_task_spec.Rd b/man/revdep_check_task.Rd similarity index 59% rename from man/revdep_check_task_spec.Rd rename to man/revdep_check_task.Rd index 96420ec..dbb9943 100644 --- a/man/revdep_check_task_spec.Rd +++ b/man/revdep_check_task.Rd @@ -1,29 +1,29 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/task_spec.R -\name{revdep_check_task_spec} -\alias{revdep_check_task_spec} +% Please edit documentation in R/task.R +\name{revdep_check_task} +\alias{revdep_check_task} \title{Create a task to run reverse dependency checks} \usage{ -revdep_check_task_spec(revdep, ...) +revdep_check_task(revdep, ...) } \arguments{ \item{revdep}{character indicating whether the task specification describes check associated with the development (new) or release (old) version of the for which reverse dependency check is run.} -\item{...}{Additional parameters passed to \code{\link[=task_spec]{task_spec()}}} +\item{...}{Additional parameters passed to \code{\link[=task]{task()}}} } \description{ Create a task to run reverse dependency checks } \seealso{ Other tasks: -\code{\link{check_task_spec}()}, +\code{\link{check_task}()}, \code{\link{checked-task-df}}, -\code{\link{custom_install_task_spec}()}, -\code{\link{install_task_spec}()}, +\code{\link{custom_install_task}()}, +\code{\link{install_task}()}, \code{\link{rev_dep_check_tasks_df}()}, \code{\link{source_check_tasks_df}()}, -\code{\link{task_spec}()} +\code{\link{task}()} } \concept{tasks} diff --git a/man/source_check_tasks_df.Rd b/man/source_check_tasks_df.Rd index 8fbde3b..2885dd4 100644 --- a/man/source_check_tasks_df.Rd +++ b/man/source_check_tasks_df.Rd @@ -17,9 +17,9 @@ The check schedule \code{data.frame} with the following columns: \item \code{alias}: The alias of the check to run. It also serves the purpose of providing a unique identifier and node name in the task graph. \item \code{version}: Version of the package to be checked. -\item \code{package}: Object that inherits from \code{\link[=check_task_spec]{check_task_spec()}}. +\item \code{package}: Object that inherits from \code{\link[=check_task]{check_task()}}. Defines how package to be checked can be acquired. -\item \code{custom}: Object that inherits from \code{\link[=custom_install_task_spec]{custom_install_task_spec()}}. +\item \code{custom}: Object that inherits from \code{\link[=custom_install_task]{custom_install_task()}}. Defines custom package, for instance only available from local source, that should be installed before checking the package. } @@ -37,12 +37,12 @@ a vector of an arbitrary length. } \seealso{ Other tasks: -\code{\link{check_task_spec}()}, +\code{\link{check_task}()}, \code{\link{checked-task-df}}, -\code{\link{custom_install_task_spec}()}, -\code{\link{install_task_spec}()}, +\code{\link{custom_install_task}()}, +\code{\link{install_task}()}, \code{\link{rev_dep_check_tasks_df}()}, -\code{\link{revdep_check_task_spec}()}, -\code{\link{task_spec}()} +\code{\link{revdep_check_task}()}, +\code{\link{task}()} } \concept{tasks} diff --git a/man/task_spec.Rd b/man/task.Rd similarity index 60% rename from man/task_spec.Rd rename to man/task.Rd index 5489234..3964188 100644 --- a/man/task_spec.Rd +++ b/man/task.Rd @@ -1,15 +1,15 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/task_spec.R -\name{task_spec} -\alias{task_spec} +% Please edit documentation in R/task.R +\name{task} +\alias{task} \title{Task specification} \usage{ -task_spec(alias = NULL, package_spec = NULL, env = NULL) +task(alias = NULL, package = NULL, env = NULL) } \arguments{ \item{alias}{task alias which also serves as unique identifier of the task.} -\item{package_spec}{\code{\link[checked]{package_spec}} object} +\item{package}{\code{\link[checked]{package}} object} \item{env}{environmental variables to be set in separate process running specific task.} @@ -20,12 +20,12 @@ to run specific task. } \seealso{ Other tasks: -\code{\link{check_task_spec}()}, +\code{\link{check_task}()}, \code{\link{checked-task-df}}, -\code{\link{custom_install_task_spec}()}, -\code{\link{install_task_spec}()}, +\code{\link{custom_install_task}()}, +\code{\link{install_task}()}, \code{\link{rev_dep_check_tasks_df}()}, -\code{\link{revdep_check_task_spec}()}, +\code{\link{revdep_check_task}()}, \code{\link{source_check_tasks_df}()} } \concept{tasks} diff --git a/tests/testthat/testing_pkgs/DALEXtra/DESCRIPTION b/tests/testthat/fixtures/DALEXtra/DESCRIPTION similarity index 100% rename from tests/testthat/testing_pkgs/DALEXtra/DESCRIPTION rename to tests/testthat/fixtures/DALEXtra/DESCRIPTION diff --git a/tests/testthat/testing_pkgs/rd2markdown/DESCRIPTION b/tests/testthat/fixtures/rd2markdown/DESCRIPTION similarity index 100% rename from tests/testthat/testing_pkgs/rd2markdown/DESCRIPTION rename to tests/testthat/fixtures/rd2markdown/DESCRIPTION diff --git a/tests/testthat/testing_pkgs/revdeps/v1/pkg.none_1.0.0.tar.gz b/tests/testthat/fixtures/revdeps/v1/pkg.none_1.0.0.tar.gz similarity index 100% rename from tests/testthat/testing_pkgs/revdeps/v1/pkg.none_1.0.0.tar.gz rename to tests/testthat/fixtures/revdeps/v1/pkg.none_1.0.0.tar.gz diff --git a/tests/testthat/testing_pkgs/revdeps/v1/pkg.ok.error_1.0.0.tar.gz b/tests/testthat/fixtures/revdeps/v1/pkg.ok.error_1.0.0.tar.gz similarity index 100% rename from tests/testthat/testing_pkgs/revdeps/v1/pkg.ok.error_1.0.0.tar.gz rename to tests/testthat/fixtures/revdeps/v1/pkg.ok.error_1.0.0.tar.gz diff --git a/tests/testthat/testing_pkgs/revdeps/v1/rev.both.dependency_1.0.0.tar.gz b/tests/testthat/fixtures/revdeps/v1/rev.both.dependency_1.0.0.tar.gz similarity index 100% rename from tests/testthat/testing_pkgs/revdeps/v1/rev.both.dependency_1.0.0.tar.gz rename to tests/testthat/fixtures/revdeps/v1/rev.both.dependency_1.0.0.tar.gz diff --git a/tests/testthat/testing_pkgs/revdeps/v1/rev.both.error_1.0.0.tar.gz b/tests/testthat/fixtures/revdeps/v1/rev.both.error_1.0.0.tar.gz similarity index 100% rename from tests/testthat/testing_pkgs/revdeps/v1/rev.both.error_1.0.0.tar.gz rename to tests/testthat/fixtures/revdeps/v1/rev.both.error_1.0.0.tar.gz diff --git a/tests/testthat/testing_pkgs/revdeps/v1/rev.both.ok_1.0.0.tar.gz b/tests/testthat/fixtures/revdeps/v1/rev.both.ok_1.0.0.tar.gz similarity index 100% rename from tests/testthat/testing_pkgs/revdeps/v1/rev.both.ok_1.0.0.tar.gz rename to tests/testthat/fixtures/revdeps/v1/rev.both.ok_1.0.0.tar.gz diff --git a/tests/testthat/testing_pkgs/revdeps/v2/pkg.none/DESCRIPTION b/tests/testthat/fixtures/revdeps/v2/pkg.none/DESCRIPTION similarity index 100% rename from tests/testthat/testing_pkgs/revdeps/v2/pkg.none/DESCRIPTION rename to tests/testthat/fixtures/revdeps/v2/pkg.none/DESCRIPTION diff --git a/tests/testthat/testing_pkgs/revdeps/v2/pkg.none/LICENSE b/tests/testthat/fixtures/revdeps/v2/pkg.none/LICENSE similarity index 100% rename from tests/testthat/testing_pkgs/revdeps/v2/pkg.none/LICENSE rename to tests/testthat/fixtures/revdeps/v2/pkg.none/LICENSE diff --git a/tests/testthat/testing_pkgs/revdeps/v2/pkg.none/NAMESPACE b/tests/testthat/fixtures/revdeps/v2/pkg.none/NAMESPACE similarity index 100% rename from tests/testthat/testing_pkgs/revdeps/v2/pkg.none/NAMESPACE rename to tests/testthat/fixtures/revdeps/v2/pkg.none/NAMESPACE diff --git a/tests/testthat/testing_pkgs/revdeps/v2/pkg.none/R/hw.R b/tests/testthat/fixtures/revdeps/v2/pkg.none/R/hw.R similarity index 100% rename from tests/testthat/testing_pkgs/revdeps/v2/pkg.none/R/hw.R rename to tests/testthat/fixtures/revdeps/v2/pkg.none/R/hw.R diff --git a/tests/testthat/testing_pkgs/revdeps/v2/pkg.none/man/hello_world.Rd b/tests/testthat/fixtures/revdeps/v2/pkg.none/man/hello_world.Rd similarity index 100% rename from tests/testthat/testing_pkgs/revdeps/v2/pkg.none/man/hello_world.Rd rename to tests/testthat/fixtures/revdeps/v2/pkg.none/man/hello_world.Rd diff --git a/tests/testthat/testing_pkgs/revdeps/v2/pkg.none/tests/test-hw.R b/tests/testthat/fixtures/revdeps/v2/pkg.none/tests/test-hw.R similarity index 100% rename from tests/testthat/testing_pkgs/revdeps/v2/pkg.none/tests/test-hw.R rename to tests/testthat/fixtures/revdeps/v2/pkg.none/tests/test-hw.R diff --git a/tests/testthat/testing_pkgs/revdeps/v2/pkg.ok.error/DESCRIPTION b/tests/testthat/fixtures/revdeps/v2/pkg.ok.error/DESCRIPTION similarity index 100% rename from tests/testthat/testing_pkgs/revdeps/v2/pkg.ok.error/DESCRIPTION rename to tests/testthat/fixtures/revdeps/v2/pkg.ok.error/DESCRIPTION diff --git a/tests/testthat/testing_pkgs/revdeps/v2/pkg.ok.error/LICENSE b/tests/testthat/fixtures/revdeps/v2/pkg.ok.error/LICENSE similarity index 100% rename from tests/testthat/testing_pkgs/revdeps/v2/pkg.ok.error/LICENSE rename to tests/testthat/fixtures/revdeps/v2/pkg.ok.error/LICENSE diff --git a/tests/testthat/testing_pkgs/revdeps/v2/pkg.ok.error/NAMESPACE b/tests/testthat/fixtures/revdeps/v2/pkg.ok.error/NAMESPACE similarity index 100% rename from tests/testthat/testing_pkgs/revdeps/v2/pkg.ok.error/NAMESPACE rename to tests/testthat/fixtures/revdeps/v2/pkg.ok.error/NAMESPACE diff --git a/tests/testthat/testing_pkgs/revdeps/v2/pkg.ok.error/R/hw.R b/tests/testthat/fixtures/revdeps/v2/pkg.ok.error/R/hw.R similarity index 100% rename from tests/testthat/testing_pkgs/revdeps/v2/pkg.ok.error/R/hw.R rename to tests/testthat/fixtures/revdeps/v2/pkg.ok.error/R/hw.R diff --git a/tests/testthat/testing_pkgs/revdeps/v2/pkg.ok.error/man/hello_world.Rd b/tests/testthat/fixtures/revdeps/v2/pkg.ok.error/man/hello_world.Rd similarity index 100% rename from tests/testthat/testing_pkgs/revdeps/v2/pkg.ok.error/man/hello_world.Rd rename to tests/testthat/fixtures/revdeps/v2/pkg.ok.error/man/hello_world.Rd diff --git a/tests/testthat/testing_pkgs/revdeps/v2/pkg.ok.error/man/hello_world_loud.Rd b/tests/testthat/fixtures/revdeps/v2/pkg.ok.error/man/hello_world_loud.Rd similarity index 100% rename from tests/testthat/testing_pkgs/revdeps/v2/pkg.ok.error/man/hello_world_loud.Rd rename to tests/testthat/fixtures/revdeps/v2/pkg.ok.error/man/hello_world_loud.Rd diff --git a/tests/testthat/testing_pkgs/revdeps/v2/pkg.ok.error/tests/test-hw.R b/tests/testthat/fixtures/revdeps/v2/pkg.ok.error/tests/test-hw.R similarity index 100% rename from tests/testthat/testing_pkgs/revdeps/v2/pkg.ok.error/tests/test-hw.R rename to tests/testthat/fixtures/revdeps/v2/pkg.ok.error/tests/test-hw.R diff --git a/tests/testthat/testing_pkgs/revdeps/v2/pkg.suggests/DESCRIPTION b/tests/testthat/fixtures/revdeps/v2/pkg.suggests/DESCRIPTION similarity index 100% rename from tests/testthat/testing_pkgs/revdeps/v2/pkg.suggests/DESCRIPTION rename to tests/testthat/fixtures/revdeps/v2/pkg.suggests/DESCRIPTION diff --git a/tests/testthat/testing_pkgs/revdeps/v2/pkg.suggests/LICENSE b/tests/testthat/fixtures/revdeps/v2/pkg.suggests/LICENSE similarity index 100% rename from tests/testthat/testing_pkgs/revdeps/v2/pkg.suggests/LICENSE rename to tests/testthat/fixtures/revdeps/v2/pkg.suggests/LICENSE diff --git a/tests/testthat/testing_pkgs/revdeps/v2/pkg.suggests/NAMESPACE b/tests/testthat/fixtures/revdeps/v2/pkg.suggests/NAMESPACE similarity index 100% rename from tests/testthat/testing_pkgs/revdeps/v2/pkg.suggests/NAMESPACE rename to tests/testthat/fixtures/revdeps/v2/pkg.suggests/NAMESPACE diff --git a/tests/testthat/testing_pkgs/revdeps/v2/pkg.suggests/R/hw.R b/tests/testthat/fixtures/revdeps/v2/pkg.suggests/R/hw.R similarity index 100% rename from tests/testthat/testing_pkgs/revdeps/v2/pkg.suggests/R/hw.R rename to tests/testthat/fixtures/revdeps/v2/pkg.suggests/R/hw.R diff --git a/tests/testthat/testing_pkgs/revdeps/v2/pkg.suggests/man/hello_world.Rd b/tests/testthat/fixtures/revdeps/v2/pkg.suggests/man/hello_world.Rd similarity index 100% rename from tests/testthat/testing_pkgs/revdeps/v2/pkg.suggests/man/hello_world.Rd rename to tests/testthat/fixtures/revdeps/v2/pkg.suggests/man/hello_world.Rd diff --git a/tests/testthat/testing_pkgs/revdeps/v2/pkg.suggests/tests/test-hw.R b/tests/testthat/fixtures/revdeps/v2/pkg.suggests/tests/test-hw.R similarity index 100% rename from tests/testthat/testing_pkgs/revdeps/v2/pkg.suggests/tests/test-hw.R rename to tests/testthat/fixtures/revdeps/v2/pkg.suggests/tests/test-hw.R diff --git a/tests/testthat/test-check-reverse.R b/tests/testthat/test-check-reverse.R index dfba6f0..015f442 100644 --- a/tests/testthat/test-check-reverse.R +++ b/tests/testthat/test-check-reverse.R @@ -6,8 +6,8 @@ create_temp_repo <- function(dir, repo_path) { tools::write_PACKAGES(contrib_url, type = "source") } -sources_old <- test_path("testing_pkgs", "revdeps", "v1") -sources_new <- test_path("testing_pkgs", "revdeps", "v2") +sources_old <- test_path("fixtures", "revdeps", "v1") +sources_new <- test_path("fixtures", "revdeps", "v2") dir.create(repo_dir <- tempfile("repo")) repo <- paste0("file:///", repo_dir) @@ -48,47 +48,47 @@ test_that("check_rev_deps works for package with one breaking change", { expect_true(is.list(r)) expect_named(r) expect_length(r, 1L) - expect_length(r$revdep_check_task_spec, 2L) + expect_length(r$revdep_check_task, 2L) # rev.both.error - expect_length(r$revdep_check_task_spec$rev.both.error$notes$issues, 0L) - expect_length(r$revdep_check_task_spec$rev.both.error$notes$potential_issues$new, 0L) - expect_length(r$revdep_check_task_spec$rev.both.error$notes$potential_issues$old, 0L) + expect_length(r$revdep_check_task$rev.both.error$notes$issues, 0L) + expect_length(r$revdep_check_task$rev.both.error$notes$potential_issues$new, 0L) + expect_length(r$revdep_check_task$rev.both.error$notes$potential_issues$old, 0L) - expect_length(r$revdep_check_task_spec$rev.both.error$warnings$issues, 1L) + expect_length(r$revdep_check_task$rev.both.error$warnings$issues, 1L) expect_true( grepl("Namespace in Imports field not imported from", - r$revdep_check_task_spec$rev.both.error$warnings$issues), + r$revdep_check_task$rev.both.error$warnings$issues), grepl("Missing or unexported object", - r$revdep_check_task_spec$rev.both.error$warnings$issues) + r$revdep_check_task$rev.both.error$warnings$issues) ) - expect_length(r$revdep_check_task_spec$rev.both.error$warnings$potential_issues$new, 0L) - expect_length(r$revdep_check_task_spec$rev.both.error$warnings$potential_issues$old, 0L) + expect_length(r$revdep_check_task$rev.both.error$warnings$potential_issues$new, 0L) + expect_length(r$revdep_check_task$rev.both.error$warnings$potential_issues$old, 0L) - expect_length(r$revdep_check_task_spec$rev.both.error$errors$issues, 1L) + expect_length(r$revdep_check_task$rev.both.error$errors$issues, 1L) expect_true( grepl("Running the tests in", - r$revdep_check_task_spec$rev.both.error$errors$issues), + r$revdep_check_task$rev.both.error$errors$issues), grepl("is not an exported object from", - r$revdep_check_task_spec$rev.both.error$errors$issues) + r$revdep_check_task$rev.both.error$errors$issues) ) - expect_length(r$revdep_check_task_spec$rev.both.error$errors$potential_issues$new, 0L) - expect_length(r$revdep_check_task_spec$rev.both.error$errors$potential_issues$old, 0L) + expect_length(r$revdep_check_task$rev.both.error$errors$potential_issues$new, 0L) + expect_length(r$revdep_check_task$rev.both.error$errors$potential_issues$old, 0L) # rev.both.ok - expect_length(r$revdep_check_task_spec$rev.both.ok$notes$issues, 0L) - expect_length(r$revdep_check_task_spec$rev.both.ok$notes$potential_issues$new, 0L) - expect_length(r$revdep_check_task_spec$rev.both.ok$notes$potential_issues$old, 0L) + expect_length(r$revdep_check_task$rev.both.ok$notes$issues, 0L) + expect_length(r$revdep_check_task$rev.both.ok$notes$potential_issues$new, 0L) + expect_length(r$revdep_check_task$rev.both.ok$notes$potential_issues$old, 0L) - expect_length(r$revdep_check_task_spec$rev.both.ok$warnings$issues, 0L) - expect_length(r$revdep_check_task_spec$rev.both.ok$warnings$potential_issues$new, 0L) - expect_length(r$revdep_check_task_spec$rev.both.ok$warnings$potential_issues$old, 0L) + expect_length(r$revdep_check_task$rev.both.ok$warnings$issues, 0L) + expect_length(r$revdep_check_task$rev.both.ok$warnings$potential_issues$new, 0L) + expect_length(r$revdep_check_task$rev.both.ok$warnings$potential_issues$old, 0L) - expect_length(r$revdep_check_task_spec$rev.both.ok$errors$issues, 0L) - expect_length(r$revdep_check_task_spec$rev.both.ok$errors$potential_issues$new, 0L) - expect_length(r$revdep_check_task_spec$rev.both.ok$errors$potential_issues$old, 0L) + expect_length(r$revdep_check_task$rev.both.ok$errors$issues, 0L) + expect_length(r$revdep_check_task$rev.both.ok$errors$potential_issues$new, 0L) + expect_length(r$revdep_check_task$rev.both.ok$errors$potential_issues$old, 0L) }) test_that("check_rev_deps works for a package without release version", { @@ -108,24 +108,24 @@ test_that("check_rev_deps works for a package without release version", { expect_true(is.list(r)) expect_named(r) expect_length(r, 1L) - expect_length(r$check_task_spec, 1L) + expect_length(r$check_task, 1L) - expect_length(r$check_task_spec$`pkg.none (dev)`$notes$issues, 0L) - expect_length(r$check_task_spec$`pkg.none (dev)`$notes$potential_issues$new, 0L) - expect_length(r$check_task_spec$`pkg.none (dev)`$notes$potential_issues$old, 0L) + expect_length(r$check_task$`pkg.none (dev)`$notes$issues, 0L) + expect_length(r$check_task$`pkg.none (dev)`$notes$potential_issues$new, 0L) + expect_length(r$check_task$`pkg.none (dev)`$notes$potential_issues$old, 0L) - expect_length(r$check_task_spec$`pkg.none (dev)`$warnings$issues, 0L) - expect_length(r$check_task_spec$`pkg.none (dev)`$warnings$potential_issues$new, 0L) - expect_length(r$check_task_spec$`pkg.none (dev)`$warnings$potential_issues$old, 0L) + expect_length(r$check_task$`pkg.none (dev)`$warnings$issues, 0L) + expect_length(r$check_task$`pkg.none (dev)`$warnings$potential_issues$new, 0L) + expect_length(r$check_task$`pkg.none (dev)`$warnings$potential_issues$old, 0L) - expect_length(r$check_task_spec$`pkg.none (dev)`$errors$issues, 1L) + expect_length(r$check_task$`pkg.none (dev)`$errors$issues, 1L) expect_true( grepl("Running the tests in", - r$check_task_spec$`pkg.none (dev)`$errors$issues), + r$check_task$`pkg.none (dev)`$errors$issues), grepl("\"hello world\" is not TRUE", - r$check_task_spec$`pkg.none (dev)`$errors$issues) + r$check_task$`pkg.none (dev)`$errors$issues) ) - expect_length(r$check_task_spec$`pkg.none (dev)`$errors$potential_issues$new, 0L) - expect_length(r$check_task_spec$`pkg.none (dev)`$errors$potential_issues$old, 0L) + expect_length(r$check_task$`pkg.none (dev)`$errors$potential_issues$new, 0L) + expect_length(r$check_task$`pkg.none (dev)`$errors$potential_issues$old, 0L) }) diff --git a/tests/testthat/test-checks_df.R b/tests/testthat/test-checks_df.R index b279195..1060b51 100644 --- a/tests/testthat/test-checks_df.R +++ b/tests/testthat/test-checks_df.R @@ -1,21 +1,26 @@ test_that("rev_dep_check_tasks_df works with deafult params", { expect_silent( df <- rev_dep_check_tasks_df( - test_path("testing_pkgs", "DALEXtra"), + test_path("fixtures", "DALEXtra"), repos = "https://cran.r-project.org/" ) ) + expect_s3_class(df, "data.frame") expect_true(NROW(df) >= 8) expect_named(df, c("alias", "version", "package", "custom")) - expect_s3_class(df$package, "list_of_task_spec") - expect_equal(unique(vcapply(df$package, function(x) class(x)[[1]])), "revdep_check_task_spec") - expect_equal(unique(vcapply(df$package, function(x) class(x$package_spec)[[1]])), "package_spec") + expect_s3_class(df$package, "list_of_task") + task_classes <- vcapply(df$package, function(x) class(x)[[1]]) + expect_equal(unique(package_classes), "revdep_check_task") + package_sub_classes <- vcapply(df$package, function(x) class(x$package)[[1]]) + expect_equal(unique(package_sub_classes), "pkg_origin_repo") - expect_s3_class(df$custom, "list_of_task_spec") - expect_equal(unique(vcapply(df$custom, function(x) class(x)[[1]])), "custom_install_task_spec") - expect_equal(unique(vcapply(df$custom, function(x) class(x$package_spec)[[1]])), c("package_spec_source", "package_spec")) + expect_s3_class(df$custom, "list_of_task") + task_classes <- vcapply(df$custom, function(x) class(x)[[1]]) + expect_equal(unique(task_classes), "custom_install_task") + package_sub_classes <- vcapply(df$custom, function(x) class(x$package)[[1]]) + expect_equal(unique(package_sub_classes), c("pkg_origin_local", "pkg_origin_repo")) expect_true(all(endsWith(df$alias[seq(1, NROW(df), by = 2)], "(dev)"))) expect_true(all(endsWith(df$alias[seq(2, NROW(df), by = 2)], "(v2.3.0)"))) @@ -29,7 +34,7 @@ test_that("rev_dep_check_tasks_df works with deafult params", { test_that("rev_dep_check_tasks_df development_only = TRUE", { expect_silent( df <- rev_dep_check_tasks_df( - test_path("testing_pkgs", "DALEXtra"), + test_path("fixtures", "DALEXtra"), repos = "https://cran.r-project.org/", versions = "dev" ) @@ -38,13 +43,17 @@ test_that("rev_dep_check_tasks_df development_only = TRUE", { expect_true(NROW(df) >= 4) expect_named(df, c("alias", "version", "package", "custom")) - expect_s3_class(df$package, "list_of_task_spec") - expect_equal(unique(vcapply(df$package, function(x) class(x)[[1]])), "check_task_spec") - expect_equal(unique(vcapply(df$package, function(x) class(x$package_spec)[[1]])), "package_spec") + expect_s3_class(df$package, "list_of_task") + task_classes <- vcapply(df$package, function(x) class(x)[[1]]) + expect_equal(unique(package_classes), "revdep_check_task") + package_sub_classes <- vcapply(df$package, function(x) class(x$package)[[1]]) + expect_equal(unique(package_sub_classes), "pkg_origin_repo") - expect_s3_class(df$custom, "list_of_task_spec") - expect_equal(unique(vcapply(df$custom, function(x) class(x)[[1]])), "custom_install_task_spec") - expect_equal(unique(vcapply(df$custom, function(x) class(x$package_spec)[[1]])), "package_spec_source") + expect_s3_class(df$custom, "list_of_task") + task_classes <- vcapply(df$custom, function(x) class(x)[[1]]) + expect_equal(unique(task_classes), "custom_install_task") + package_sub_classes <- vcapply(df$custom, function(x) class(x$package)[[1]]) + expect_equal(unique(package_sub_classes), c("pkg_origin_local")) expect_true(all(endsWith(df$alias, "(dev)"))) expect_true(all(!endsWith(df$alias, "(v2.3.0)"))) @@ -55,8 +64,8 @@ test_that("source_check_tasks_df works as expected", { expect_silent( df <- source_check_tasks_df( c( - test_path("testing_pkgs", "DALEXtra"), - test_path("testing_pkgs", "rd2markdown"), + test_path("fixtures", "DALEXtra"), + test_path("fixtures", "rd2markdown"), file.path(examples_path, "exampleGood"), file.path(examples_path, "exampleOkay"), file.path(examples_path, "exampleBad") @@ -67,13 +76,13 @@ test_that("source_check_tasks_df works as expected", { expect_equal(NROW(df), 5) expect_named(df, c("alias", "version", "package", "custom")) - expect_s3_class(df$package, "list_of_task_spec") - expect_equal(unique(vcapply(df$package, function(x) class(x)[[1]])), "check_task_spec") - expect_equal(unique(vcapply(df$package, function(x) class(x$package_spec)[[1]])), "package_spec_source") + expect_s3_class(df$package, "list_of_task") + expect_equal(unique(vcapply(df$package, function(x) class(x)[[1]])), "check_task") + expect_equal(unique(vcapply(df$package, function(x) class(x$package)[[1]])), "pkg_origin_local") - expect_s3_class(df$custom, "list_of_task_spec") - expect_equal(unique(vcapply(df$custom, function(x) class(x)[[1]])), "custom_install_task_spec") - expect_equal(unique(vcapply(df$custom, function(x) class(x$package_spec)[[1]])), "NULL") + expect_s3_class(df$custom, "list_of_task") + expect_equal(unique(vcapply(df$custom, function(x) class(x)[[1]])), "custom_install_task") + expect_equal(unique(vcapply(df$custom, function(x) class(x$package)[[1]])), "NULL") expect_true(all(endsWith(df$alias, "(source)"))) }) @@ -82,8 +91,8 @@ test_that("source_check_tasks_df aliases are properly handled", { examples_path <- system.file("example_packages", package = "checked") names <- c("DALEXtra_new", "rd2markdown_new", "exampleGood_new", "exampleOkay_new", "exampleBad_new") path <- c( - test_path("testing_pkgs", "DALEXtra"), - test_path("testing_pkgs", "rd2markdown"), + test_path("fixtures", "DALEXtra"), + test_path("fixtures", "rd2markdown"), file.path(examples_path, "exampleGood"), file.path(examples_path, "exampleOkay"), file.path(examples_path, "exampleBad") From b3ac7e51650dcc8df7ede0db44e0d12ac547fcba Mon Sep 17 00:00:00 2001 From: dgkf-roche Date: Wed, 4 Sep 2024 17:44:00 -0400 Subject: [PATCH 05/62] chore: refactor checks_df => plan --- NAMESPACE | 5 +- R/check.R | 31 +++---- R/check_design.R | 12 +-- R/pkg_origin.R | 1 + R/{checks_df.R => plan.R} | 80 +++++++------------ man/check_design.Rd | 8 +- man/check_task.Rd | 3 - man/custom_install_task.Rd | 3 - man/install_task.Rd | 3 - man/pkg_origin.Rd | 6 +- man/{source_check_tasks_df.Rd => plan.Rd} | 36 +++------ man/{checked-task-df.Rd => plan_checks.Rd} | 36 ++++----- ...eck_tasks_df.Rd => plan_rev_dep_checks.Rd} | 41 +++------- man/revdep_check_task.Rd | 3 - man/task.Rd | 5 +- tests/testthat/test-check.R | 12 +-- .../{test-checks_df.R => test-plan.R} | 63 +++++++++------ 17 files changed, 140 insertions(+), 208 deletions(-) rename R/{checks_df.R => plan.R} (76%) rename man/{source_check_tasks_df.Rd => plan.Rd} (50%) rename man/{checked-task-df.Rd => plan_checks.Rd} (52%) rename man/{rev_dep_check_tasks_df.Rd => plan_rev_dep_checks.Rd} (55%) rename tests/testthat/{test-checks_df.R => test-plan.R} (66%) diff --git a/NAMESPACE b/NAMESPACE index 57dae95..fb88e0b 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -4,6 +4,7 @@ S3method("[",checked_results) S3method(check_path,pkg_origin) S3method(check_path,pkg_origin_archive) S3method(check_path,pkg_origin_local) +S3method(check_path,pkg_origin_repo) S3method(count,default) S3method(count,issues) S3method(count,potential_issues) @@ -65,15 +66,15 @@ export(pkg_origin) export(pkg_origin_archive) export(pkg_origin_local) export(pkg_origin_repo) +export(plan_checks) +export(plan_rev_dep_checks) export(reporter_ansi_tty) export(reporter_basic_tty) export(reporter_default) export(results) export(results_to_file) -export(rev_dep_check_tasks_df) export(revdep_check_task) export(run) -export(source_check_tasks_df) export(task) import(cli) importFrom(R6,R6Class) diff --git a/R/check.R b/R/check.R index 6d32847..9c4d7e3 100644 --- a/R/check.R +++ b/R/check.R @@ -63,18 +63,16 @@ check_rev_deps <- function( reverse_repos = repos, restore = TRUE, ...) { - checks <- rev_dep_check_tasks_df(path = path, repos = reverse_repos) - - plan <- check_design$new( - checks, + checks <- check_design$new( + plan_rev_dep_checks(path = path, repos = reverse_repos), n = n, output = output, lib.loc = lib.loc, repos = repos, ) - run(plan, ...) - plan + run(checks, ...) + checks } #' Run reverse dependency checks against a development version only @@ -100,10 +98,8 @@ check_dev_rev_deps <- function( repos = getOption("repos"), restore = TRUE, ...) { - checks <- rev_dep_check_tasks_df(path = path, repos = repos, versions = "dev") - - plan <- check_design$new( - checks, + checks <- check_design$new( + plan_rev_dep_checks(path = path, repos = repos, versions = "dev"), n = n, output = output, lib.loc = lib.loc, @@ -111,8 +107,8 @@ check_dev_rev_deps <- function( restore = restore ) - run(plan, ...) - plan + run(checks, ...) + checks } #' Check one or more package source directories @@ -136,10 +132,8 @@ check_pkgs <- function( repos = getOption("repos"), restore = TRUE, ...) { - checks <- source_check_tasks_df(path) - - plan <- check_design$new( - checks, + checks <- check_design$new( + plan_checks(path), n = n, output = output, lib.loc = lib.loc, @@ -147,8 +141,8 @@ check_pkgs <- function( restore = restore ) - run(plan, ...) - plan + run(checks, ...) + checks } #' Check all package source directories in current directory @@ -173,7 +167,6 @@ check_dir <- function( ...) { dirs <- list.dirs(path, full.names = TRUE, recursive = FALSE) r_packages <- dirs[vlapply(dirs, path_is_pkg)] - check_pkgs( r_packages, n = n, diff --git a/R/check_design.R b/R/check_design.R index fee59c9..fe15172 100644 --- a/R/check_design.R +++ b/R/check_design.R @@ -15,8 +15,8 @@ new_check_design <- function(...) { #' @name new_check_design #' @export new_rev_dep_check_design <- function(x, ...) { - tasks <- rev_dep_check_tasks_df(x) - new_check_design(tasks, ...) + plan <- plan_rev_dep_checks(x) + new_check_design(plan, ...) } #' `R6` Checks Coordinator @@ -28,14 +28,14 @@ new_rev_dep_check_design <- function(x, ...) { #' @examples #' \dontrun{ #' library(checked) -#' df <- source_check_tasks_df(c( +#' plan <- plan_checks(c( #' system.file("example_packages", "exampleBad", package = "checked"), #' system.file("example_packages", "exampleGood", package = "checked") #' )) #' -#' plan <- check_design$new(df, n = 10, repos = "https://cran.r-project.org/") -#' while (!plan$is_done()) { -#' plan$start_next_task() +#' checks <- check_design$new(plan, n = 10, repos = "https://cran.r-project.org/") +#' while (!checks$is_done()) { +#' checks$start_next_task() #' } #' } #' diff --git a/R/pkg_origin.R b/R/pkg_origin.R index 06d8273..cd56ee3 100644 --- a/R/pkg_origin.R +++ b/R/pkg_origin.R @@ -98,6 +98,7 @@ check_path.pkg_origin <- function(x, output, ...) { stop(sprintf("Can't determine origin of package '%s'", x$name)) } +#' @export check_path.pkg_origin_repo <- function(x, output, ...) { get_package_source(x$name, x$repos, destdir = output) } diff --git a/R/checks_df.R b/R/plan.R similarity index 76% rename from R/checks_df.R rename to R/plan.R index a70a815..c074243 100644 --- a/R/checks_df.R +++ b/R/plan.R @@ -5,18 +5,11 @@ empty_checks_df <- data.frame( custom = character(0) ) -#' Check schedule data frame +#' Check Plan #' -#' Create data.frame which each row defines a package for which R CMD check -#' should be run. Such data.frame is a prerequisite for generating -#' [`check_design()`] which orchestrates all the processes -#' including dependencies installation. -#' -#' @details -#' -#' `_tasks_df()` functions generate check task `data.frame` for -#' all source packages specified by the `path`. Therefore it accepts it to be -#' a vector of an arbitrary length. +#' Plans are pre-specified sets of checks. Plans are simple `data.frame`s +#' where each row defines a package for which `R CMD check` +#' should be run. #' #' @param path path to the package source. Can be either a single source #' code directory or a directory containing multiple package source code @@ -33,20 +26,19 @@ empty_checks_df <- data.frame( #' Defines custom package, for instance only available from local source, that #' should be installed before checking the package. #' -#' @family tasks -#' @name checked-task-df +#' @family plan +#' @name plan NULL -#' Build Tasks for Reverse Dependency Checks -#" -#' Generates checks schedule data.frame appropriate for running reverse -#' dependency check for certain source package. In such case `path` parameter -#' should point to the source of the development version of the package and -#' `repos` should be a repository for which reverse dependencies should be -#' identified. +#' Plan Reverse Dependency Checks #' -#' @inherit checked-task-df -#' @inheritParams checked-task-df +#' Generates a plan for running reverse dependency check for certain +#' source package. In such case `path` should be proivded with a directory +#' path to the development version of the package and `repos` should be a +#' repository for which reverse dependencies should be identified. +#' +#' @inherit plan +#' @inheritParams plan #' @param repos repository used to identify reverse dependencies. #' @param versions character vector indicating against which versions of the #' package reverse dependency should be checked. `c("dev", "release")` @@ -56,18 +48,13 @@ NULL #' packages already in the repository and take the package as suggests #' dependency. #' -#' @family tasks +#' @family plan #' @export -rev_dep_check_tasks_df <- function( +plan_rev_dep_checks <- function( path, repos = getOption("repos"), versions = c("dev", "release") ) { - stopifnot( - "rev_dep_check_tasks_df requires path argument of length 1" = - length(path) == 1 - ) - versions <- match.arg(versions, c("dev", "release"), several.ok = TRUE) ap <- utils::available.packages(repos = repos) path <- check_path_is_pkg_source(path) @@ -106,9 +93,9 @@ rev_dep_check_tasks_df <- function( } tasks_function <- if (all(c("dev", "release") %in% versions)) { - rev_dep_check_taskss + rev_dep_check_tasks } else { - rev_dep_check_taskss_development + rev_dep_check_tasks_development } if ("dev" %in% versions) { @@ -147,7 +134,7 @@ rev_dep_check_tasks_df <- function( df } -rev_dep_check_taskss <- function(packages, repos, aliases, revdep) { +rev_dep_check_tasks <- function(packages, repos, aliases, revdep) { list_of_task(mapply( function(package, alias) { revdep_check_task( @@ -166,7 +153,7 @@ rev_dep_check_taskss <- function(packages, repos, aliases, revdep) { )) } -rev_dep_check_taskss_development <- function( +rev_dep_check_tasks_development <- function( packages, repos, aliases, @@ -189,17 +176,18 @@ rev_dep_check_taskss_development <- function( )) } -#' Create a Task to Check a Package from Source +#' Plan multiple R CMD checks from source package paths #' -#' @inherit checked-task-df -#' @inheritParams checked-task-df +#' @inherit plan +#' @inheritParams plan #' -#' @family tasks +#' @family plan #' @export -source_check_tasks_df <- function(path) { +plan_checks <- function(path) { name <- names(path) path <- vcapply(path, check_path_is_pkg_source, USE.NAMES = FALSE) package <- vcapply(path, get_package_name) + alias <- if (is.null(name)) { unlist(lapply(unique(package), function(p) { idx <- package == p @@ -213,20 +201,12 @@ source_check_tasks_df <- function(path) { } else { name } - version <- vcapply(path, get_package_version) - df <- data.frame( - alias = alias, - version = version - ) - - df$package <- list_of_task( - source_check_tasks(package, path, alias) - ) + version <- vcapply(path, get_package_version) - df$custom <- list_of_task( - rep(list(custom_install_task()), times = NROW(df)) - ) + df <- data.frame(alias = alias, version = version) + df$package <- list_of_task(source_check_tasks(package, path, alias)) + df$custom <- list_of_task(rep(list(custom_install_task()), times = NROW(df))) df } diff --git a/man/check_design.Rd b/man/check_design.Rd index 11a193d..fdd2401 100644 --- a/man/check_design.Rd +++ b/man/check_design.Rd @@ -10,14 +10,14 @@ manage installation, library setup and run \verb{R CMD check}s in sequence. \examples{ \dontrun{ library(checked) -df <- source_check_tasks_df(c( +plan <- plan_checks(c( system.file("example_packages", "exampleBad", package = "checked"), system.file("example_packages", "exampleGood", package = "checked") )) -plan <- check_design$new(df, n = 10, repos = "https://cran.r-project.org/") -while (!plan$is_done()) { - plan$start_next_task() +checks <- check_design$new(plan, n = 10, repos = "https://cran.r-project.org/") +while (!checks$is_done()) { + checks$start_next_task() } } diff --git a/man/check_task.Rd b/man/check_task.Rd index 8ed1068..48037b0 100644 --- a/man/check_task.Rd +++ b/man/check_task.Rd @@ -35,12 +35,9 @@ Create a task to run \verb{R CMD check} } \seealso{ Other tasks: -\code{\link{checked-task-df}}, \code{\link{custom_install_task}()}, \code{\link{install_task}()}, -\code{\link{rev_dep_check_tasks_df}()}, \code{\link{revdep_check_task}()}, -\code{\link{source_check_tasks_df}()}, \code{\link{task}()} } \concept{tasks} diff --git a/man/custom_install_task.Rd b/man/custom_install_task.Rd index c678f5f..e32f301 100644 --- a/man/custom_install_task.Rd +++ b/man/custom_install_task.Rd @@ -30,11 +30,8 @@ Create a custom install task \seealso{ Other tasks: \code{\link{check_task}()}, -\code{\link{checked-task-df}}, \code{\link{install_task}()}, -\code{\link{rev_dep_check_tasks_df}()}, \code{\link{revdep_check_task}()}, -\code{\link{source_check_tasks_df}()}, \code{\link{task}()} } \concept{tasks} diff --git a/man/install_task.Rd b/man/install_task.Rd index a31af1c..0995435 100644 --- a/man/install_task.Rd +++ b/man/install_task.Rd @@ -29,11 +29,8 @@ Create a task to install a package and dependencies \seealso{ Other tasks: \code{\link{check_task}()}, -\code{\link{checked-task-df}}, \code{\link{custom_install_task}()}, -\code{\link{rev_dep_check_tasks_df}()}, \code{\link{revdep_check_task}()}, -\code{\link{source_check_tasks_df}()}, \code{\link{task}()} } \concept{tasks} diff --git a/man/pkg_origin.Rd b/man/pkg_origin.Rd index 5a5d5f7..56e126c 100644 --- a/man/pkg_origin.Rd +++ b/man/pkg_origin.Rd @@ -7,7 +7,7 @@ \alias{pkg_origin_archive} \title{Package specification} \usage{ -pkg_origin(name = NULL) +pkg_origin(name, ..., .class = c()) pkg_origin_repo(repos, ...) @@ -18,10 +18,10 @@ pkg_origin_archive(path = NULL, ...) \arguments{ \item{name}{name of the package.} -\item{repos}{repository where package with given name should identified.} - \item{...}{parameters passed to downstream constructors} +\item{repos}{repository where package with given name should identified.} + \item{path}{path to the source of the package (either bundled or not). URLs are acceptable.} } diff --git a/man/source_check_tasks_df.Rd b/man/plan.Rd similarity index 50% rename from man/source_check_tasks_df.Rd rename to man/plan.Rd index 2885dd4..dd7d1cc 100644 --- a/man/source_check_tasks_df.Rd +++ b/man/plan.Rd @@ -1,11 +1,8 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/checks_df.R -\name{source_check_tasks_df} -\alias{source_check_tasks_df} -\title{Create a Task to Check a Package from Source} -\usage{ -source_check_tasks_df(path) -} +% Please edit documentation in R/plan.R +\name{plan} +\alias{plan} +\title{Check Plan} \arguments{ \item{path}{path to the package source. Can be either a single source code directory or a directory containing multiple package source code @@ -25,24 +22,13 @@ should be installed before checking the package. } } \description{ -Create data.frame which each row defines a package for which R CMD check -should be run. Such data.frame is a prerequisite for generating -\code{\link[=check_design]{check_design()}} which orchestrates all the processes -including dependencies installation. -} -\details{ -\verb{_tasks_df()} functions generate check task \code{data.frame} for -all source packages specified by the \code{path}. Therefore it accepts it to be -a vector of an arbitrary length. +Plans are pre-specified sets of checks. Plans are simple \code{data.frame}s +where each row defines a package for which \verb{R CMD check} +should be run. } \seealso{ -Other tasks: -\code{\link{check_task}()}, -\code{\link{checked-task-df}}, -\code{\link{custom_install_task}()}, -\code{\link{install_task}()}, -\code{\link{rev_dep_check_tasks_df}()}, -\code{\link{revdep_check_task}()}, -\code{\link{task}()} +Other plan: +\code{\link{plan_checks}()}, +\code{\link{plan_rev_dep_checks}()} } -\concept{tasks} +\concept{plan} diff --git a/man/checked-task-df.Rd b/man/plan_checks.Rd similarity index 52% rename from man/checked-task-df.Rd rename to man/plan_checks.Rd index e6303dd..dbbfa31 100644 --- a/man/checked-task-df.Rd +++ b/man/plan_checks.Rd @@ -1,8 +1,11 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/checks_df.R -\name{checked-task-df} -\alias{checked-task-df} -\title{Check schedule data frame} +% Please edit documentation in R/plan.R +\name{plan_checks} +\alias{plan_checks} +\title{Plan multiple R CMD checks from source package paths} +\usage{ +plan_checks(path) +} \arguments{ \item{path}{path to the package source. Can be either a single source code directory or a directory containing multiple package source code @@ -22,24 +25,13 @@ should be installed before checking the package. } } \description{ -Create data.frame which each row defines a package for which R CMD check -should be run. Such data.frame is a prerequisite for generating -\code{\link[=check_design]{check_design()}} which orchestrates all the processes -including dependencies installation. -} -\details{ -\verb{_tasks_df()} functions generate check task \code{data.frame} for -all source packages specified by the \code{path}. Therefore it accepts it to be -a vector of an arbitrary length. +Plans are pre-specified sets of checks. Plans are simple \code{data.frame}s +where each row defines a package for which \verb{R CMD check} +should be run. } \seealso{ -Other tasks: -\code{\link{check_task}()}, -\code{\link{custom_install_task}()}, -\code{\link{install_task}()}, -\code{\link{rev_dep_check_tasks_df}()}, -\code{\link{revdep_check_task}()}, -\code{\link{source_check_tasks_df}()}, -\code{\link{task}()} +Other plan: +\code{\link{plan}}, +\code{\link{plan_rev_dep_checks}()} } -\concept{tasks} +\concept{plan} diff --git a/man/rev_dep_check_tasks_df.Rd b/man/plan_rev_dep_checks.Rd similarity index 55% rename from man/rev_dep_check_tasks_df.Rd rename to man/plan_rev_dep_checks.Rd index 1ffdc89..a9ba363 100644 --- a/man/rev_dep_check_tasks_df.Rd +++ b/man/plan_rev_dep_checks.Rd @@ -1,15 +1,10 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/checks_df.R -\name{rev_dep_check_tasks_df} -\alias{rev_dep_check_tasks_df} -\title{Build Tasks for Reverse Dependency Checks -Generates checks schedule data.frame appropriate for running reverse -dependency check for certain source package. In such case \code{path} parameter -should point to the source of the development version of the package and -\code{repos} should be a repository for which reverse dependencies should be -identified.} +% Please edit documentation in R/plan.R +\name{plan_rev_dep_checks} +\alias{plan_rev_dep_checks} +\title{Plan Reverse Dependency Checks} \usage{ -rev_dep_check_tasks_df( +plan_rev_dep_checks( path, repos = getOption("repos"), versions = c("dev", "release") @@ -44,24 +39,14 @@ should be installed before checking the package. } } \description{ -Create data.frame which each row defines a package for which R CMD check -should be run. Such data.frame is a prerequisite for generating -\code{\link[=check_design]{check_design()}} which orchestrates all the processes -including dependencies installation. -} -\details{ -\verb{_tasks_df()} functions generate check task \code{data.frame} for -all source packages specified by the \code{path}. Therefore it accepts it to be -a vector of an arbitrary length. +Generates a plan for running reverse dependency check for certain +source package. In such case \code{path} should be proivded with a directory +path to the development version of the package and \code{repos} should be a +repository for which reverse dependencies should be identified. } \seealso{ -Other tasks: -\code{\link{check_task}()}, -\code{\link{checked-task-df}}, -\code{\link{custom_install_task}()}, -\code{\link{install_task}()}, -\code{\link{revdep_check_task}()}, -\code{\link{source_check_tasks_df}()}, -\code{\link{task}()} +Other plan: +\code{\link{plan}}, +\code{\link{plan_checks}()} } -\concept{tasks} +\concept{plan} diff --git a/man/revdep_check_task.Rd b/man/revdep_check_task.Rd index dbb9943..71177bc 100644 --- a/man/revdep_check_task.Rd +++ b/man/revdep_check_task.Rd @@ -19,11 +19,8 @@ Create a task to run reverse dependency checks \seealso{ Other tasks: \code{\link{check_task}()}, -\code{\link{checked-task-df}}, \code{\link{custom_install_task}()}, \code{\link{install_task}()}, -\code{\link{rev_dep_check_tasks_df}()}, -\code{\link{source_check_tasks_df}()}, \code{\link{task}()} } \concept{tasks} diff --git a/man/task.Rd b/man/task.Rd index 3964188..a631f1d 100644 --- a/man/task.Rd +++ b/man/task.Rd @@ -21,11 +21,8 @@ to run specific task. \seealso{ Other tasks: \code{\link{check_task}()}, -\code{\link{checked-task-df}}, \code{\link{custom_install_task}()}, \code{\link{install_task}()}, -\code{\link{rev_dep_check_tasks_df}()}, -\code{\link{revdep_check_task}()}, -\code{\link{source_check_tasks_df}()} +\code{\link{revdep_check_task}()} } \concept{tasks} diff --git a/tests/testthat/test-check.R b/tests/testthat/test-check.R index fe369db..3af567d 100644 --- a/tests/testthat/test-check.R +++ b/tests/testthat/test-check.R @@ -1,11 +1,9 @@ test_that("check_pkgs works as expected", { examples_path <- system.file("example_packages", package = "checked") + # WIP expect_no_error(check_pkgs( - c( - file.path(examples_path, "exampleGood"), - file.path(examples_path, "exampleBad") - ), + file.path(examples_path, c("exampleGood", "exampleBad")), n = 2L, repos = "https://cran.r-project.org/", reporter = NULL @@ -14,12 +12,10 @@ test_that("check_pkgs works as expected", { test_that("check_pkgs works as expected", { examples_path <- system.file("example_packages", package = "checked") + # WIP expect_no_error(check_pkgs( - c( - file.path(examples_path, "exampleGood"), - file.path(examples_path, "exampleBad") - ), + file.path(examples_path, c("exampleGood", "exampleBad")), n = 2L, repos = "https://cran.r-project.org/", reporter = NULL diff --git a/tests/testthat/test-checks_df.R b/tests/testthat/test-plan.R similarity index 66% rename from tests/testthat/test-checks_df.R rename to tests/testthat/test-plan.R index 1060b51..a4b9d99 100644 --- a/tests/testthat/test-checks_df.R +++ b/tests/testthat/test-plan.R @@ -1,6 +1,6 @@ test_that("rev_dep_check_tasks_df works with deafult params", { expect_silent( - df <- rev_dep_check_tasks_df( + df <- plan_rev_dep_checks( test_path("fixtures", "DALEXtra"), repos = "https://cran.r-project.org/" ) @@ -12,15 +12,15 @@ test_that("rev_dep_check_tasks_df works with deafult params", { expect_s3_class(df$package, "list_of_task") task_classes <- vcapply(df$package, function(x) class(x)[[1]]) - expect_equal(unique(package_classes), "revdep_check_task") - package_sub_classes <- vcapply(df$package, function(x) class(x$package)[[1]]) - expect_equal(unique(package_sub_classes), "pkg_origin_repo") + expect_equal(unique(task_classes), "revdep_check_task") + pkg_sub_classes <- vcapply(df$package, function(x) class(x$package)[[1]]) + expect_equal(unique(pkg_sub_classes), "pkg_origin_repo") expect_s3_class(df$custom, "list_of_task") task_classes <- vcapply(df$custom, function(x) class(x)[[1]]) expect_equal(unique(task_classes), "custom_install_task") - package_sub_classes <- vcapply(df$custom, function(x) class(x$package)[[1]]) - expect_equal(unique(package_sub_classes), c("pkg_origin_local", "pkg_origin_repo")) + pkg_sub_classes <- vcapply(df$custom, function(x) class(x$package)[[1]]) + expect_equal(unique(pkg_sub_classes), c("pkg_origin_local", "pkg_origin_repo")) expect_true(all(endsWith(df$alias[seq(1, NROW(df), by = 2)], "(dev)"))) expect_true(all(endsWith(df$alias[seq(2, NROW(df), by = 2)], "(v2.3.0)"))) @@ -33,36 +33,37 @@ test_that("rev_dep_check_tasks_df works with deafult params", { test_that("rev_dep_check_tasks_df development_only = TRUE", { expect_silent( - df <- rev_dep_check_tasks_df( + plan <- plan_rev_dep_checks( test_path("fixtures", "DALEXtra"), repos = "https://cran.r-project.org/", versions = "dev" ) ) - expect_s3_class(df, "data.frame") - expect_true(NROW(df) >= 4) - expect_named(df, c("alias", "version", "package", "custom")) - expect_s3_class(df$package, "list_of_task") - task_classes <- vcapply(df$package, function(x) class(x)[[1]]) - expect_equal(unique(package_classes), "revdep_check_task") - package_sub_classes <- vcapply(df$package, function(x) class(x$package)[[1]]) - expect_equal(unique(package_sub_classes), "pkg_origin_repo") + expect_s3_class(plan, "data.frame") + expect_true(NROW(plan) >= 4) + expect_named(plan, c("alias", "version", "package", "custom")) - expect_s3_class(df$custom, "list_of_task") - task_classes <- vcapply(df$custom, function(x) class(x)[[1]]) + expect_s3_class(plan$package, "list_of_task") + task_classes <- vcapply(plan$package, function(x) class(x)[[1]]) + expect_equal(unique(task_classes), "check_task") + pkg_sub_classes <- vcapply(plan$package, function(x) class(x$package)[[1]]) + expect_equal(unique(pkg_sub_classes), "pkg_origin_repo") + + expect_s3_class(plan$custom, "list_of_task") + task_classes <- vcapply(plan$custom, function(x) class(x)[[1]]) expect_equal(unique(task_classes), "custom_install_task") - package_sub_classes <- vcapply(df$custom, function(x) class(x$package)[[1]]) + package_sub_classes <- vcapply(plan$custom, function(x) class(x$package)[[1]]) expect_equal(unique(package_sub_classes), c("pkg_origin_local")) - expect_true(all(endsWith(df$alias, "(dev)"))) - expect_true(all(!endsWith(df$alias, "(v2.3.0)"))) + expect_true(all(endsWith(plan$alias, "(dev)"))) + expect_true(all(!endsWith(plan$alias, "(v2.3.0)"))) }) test_that("source_check_tasks_df works as expected", { examples_path <- system.file("example_packages", package = "checked") expect_silent( - df <- source_check_tasks_df( + df <- plan_checks( c( test_path("fixtures", "DALEXtra"), test_path("fixtures", "rd2markdown"), @@ -89,7 +90,14 @@ test_that("source_check_tasks_df works as expected", { test_that("source_check_tasks_df aliases are properly handled", { examples_path <- system.file("example_packages", package = "checked") - names <- c("DALEXtra_new", "rd2markdown_new", "exampleGood_new", "exampleOkay_new", "exampleBad_new") + names <- c( + "DALEXtra_new", + "rd2markdown_new", + "exampleGood_new", + "exampleOkay_new", + "exampleBad_new" + ) + path <- c( test_path("fixtures", "DALEXtra"), test_path("fixtures", "rd2markdown"), @@ -100,14 +108,14 @@ test_that("source_check_tasks_df aliases are properly handled", { names(path) <- names expect_silent( - df <- source_check_tasks_df(path) + df <- plan_checks(path) ) expect_true(all(endsWith(df$alias, "_new"))) expect_equal(df$alias, names) expect_silent( - df <- source_check_tasks_df(c( + df <- plan_checks(c( file.path(examples_path, "exampleGood"), file.path(examples_path, "exampleGood"), file.path(examples_path, "exampleGood") @@ -115,6 +123,11 @@ test_that("source_check_tasks_df aliases are properly handled", { ) expect_equal( - df$alias, c("exampleGood (source_1)", "exampleGood (source_2)", "exampleGood (source_3)") + df$alias, + c( + "exampleGood (source_1)", + "exampleGood (source_2)", + "exampleGood (source_3)" + ) ) }) From 97b8dbd12051cfc4e795bcd8203e01200eb8c596 Mon Sep 17 00:00:00 2001 From: dgkf-roche Date: Thu, 5 Sep 2024 16:28:49 -0400 Subject: [PATCH 06/62] chore: rename check_design => checker --- NAMESPACE | 8 +- R/check.R | 8 +- R/{check_design.R => checker.R} | 64 ++++++++------- R/reporter.R | 4 +- R/results.R | 15 ++-- R/run.R | 32 ++++---- man/check_dev_rev_deps.Rd | 5 +- man/check_dir.Rd | 5 +- man/check_pkgs.Rd | 5 +- man/check_rev_deps.Rd | 5 +- man/{check_design.Rd => checker.Rd} | 90 +++++++++++---------- man/{new_check_design.Rd => new_checker.Rd} | 23 ++---- man/run.Rd | 10 +-- tests/testthat/test-check-reverse.R | 4 +- 14 files changed, 144 insertions(+), 134 deletions(-) rename R/{check_design.R => checker.R} (82%) rename man/{check_design.Rd => checker.Rd} (59%) rename man/{new_check_design.Rd => new_checker.Rd} (55%) diff --git a/NAMESPACE b/NAMESPACE index fb88e0b..3b1b2e1 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -44,7 +44,7 @@ S3method(results,list_check_task) S3method(results,list_revdep_check_task) S3method(results,revdep_check_task) S3method(run,character) -S3method(run,check_design) +S3method(run,checker) S3method(start_task,check_task) S3method(start_task,custom_install_task) S3method(start_task,install_task) @@ -52,16 +52,16 @@ S3method(summary,check_design) S3method(summary,checked_results) S3method(summary,checked_results_check_task) S3method(summary,checked_results_revdep_check_task) -export(check_design) export(check_dev_rev_deps) export(check_dir) export(check_pkgs) export(check_rev_deps) export(check_task) +export(checker) export(custom_install_task) export(install_task) -export(new_check_design) -export(new_rev_dep_check_design) +export(new_checker) +export(new_rev_dep_checker) export(pkg_origin) export(pkg_origin_archive) export(pkg_origin_local) diff --git a/R/check.R b/R/check.R index 9c4d7e3..c5c963a 100644 --- a/R/check.R +++ b/R/check.R @@ -25,7 +25,7 @@ #' @param ... Additional arguments passed to [`run()`] #' #' @return -#' [`check_design()`] R6 class storing all the details +#' [`checker()`] R6 class storing all the details #' regarding checks that run. Can be combined with #' [`results`] and [`summary()`] methods to generate results. #' @@ -63,7 +63,7 @@ check_rev_deps <- function( reverse_repos = repos, restore = TRUE, ...) { - checks <- check_design$new( + checks <- checker$new( plan_rev_dep_checks(path = path, repos = reverse_repos), n = n, output = output, @@ -98,7 +98,7 @@ check_dev_rev_deps <- function( repos = getOption("repos"), restore = TRUE, ...) { - checks <- check_design$new( + checks <- checker$new( plan_rev_dep_checks(path = path, repos = repos, versions = "dev"), n = n, output = output, @@ -132,7 +132,7 @@ check_pkgs <- function( repos = getOption("repos"), restore = TRUE, ...) { - checks <- check_design$new( + checks <- checker$new( plan_checks(path), n = n, output = output, diff --git a/R/check_design.R b/R/checker.R similarity index 82% rename from R/check_design.R rename to R/checker.R index fe15172..12ea15b 100644 --- a/R/check_design.R +++ b/R/checker.R @@ -3,20 +3,20 @@ #' Instantiate a check design from a path or directory. #' #' @param x A file path, passed to [`rev_dep_check_tasks_df()`] -#' @param ... Additional arguments passed to [`new_check_design()`] +#' @param ... Additional arguments passed to [`new_checker()`] #' #' @family checks #' @export -new_check_design <- function(...) { - check_design$new(...) +new_checker <- function(...) { + checker$new(...) } #' @family checks -#' @name new_check_design +#' @name new_checker #' @export -new_rev_dep_check_design <- function(x, ...) { +new_rev_dep_checker <- function(x, ...) { plan <- plan_rev_dep_checks(x) - new_check_design(plan, ...) + new_checker(plan, ...) } #' `R6` Checks Coordinator @@ -33,16 +33,21 @@ new_rev_dep_check_design <- function(x, ...) { #' system.file("example_packages", "exampleGood", package = "checked") #' )) #' -#' checks <- check_design$new(plan, n = 10, repos = "https://cran.r-project.org/") -#' while (!checks$is_done()) { -#' checks$start_next_task() +#' orchestrator <- checker$new( +#' plan, +#' n = 10, +#' repos = "https://cran.r-project.org/" +#' ) +#' +#' while (!orchestrator$is_done()) { +#' orchestrator$start_next_task() #' } #' } #' #' @family checks #' @export -check_design <- R6::R6Class( # nolint cyclocomp_linter - "check_design", +checker <- R6::R6Class( # nolint: cyclocomp_linter. + "checker", public = list( #' @field graph (`igraph::igraph()`)\cr #' A dependency graph, storing information about which dependencies @@ -50,9 +55,9 @@ check_design <- R6::R6Class( # nolint cyclocomp_linter #' Created with [`task_graph_create()`] graph = NULL, - #' @field input (`data.frame()`)\cr + #' @field plan (`data.frame()`)\cr #' Checks task `data.frame` which is the source of all the checks. - input = NULL, + plan = NULL, #' @field output (`character(1)`)\cr #' Output directory where raw results and temporary library will @@ -65,7 +70,7 @@ check_design <- R6::R6Class( # nolint cyclocomp_linter #' Use checks data.frame to generate task graph in which all dependencies #' and installation order are embedded. #' - #' @param df `check_design` data.frame. + #' @param plan `plan` `data.frame`. #' @param n `integer` value indicating maximum number of subprocesses that #' can be simultaneously spawned when executing tasks. #' @param output `character` value specifying path where the output should @@ -79,36 +84,39 @@ check_design <- R6::R6Class( # nolint cyclocomp_linter #' restore previous progress from the same `output`. #' @param ... Additional arguments unused #' - #' @return [check_design]. + #' @return [checker]. initialize = function( - df, + plan, n = 2L, output = tempfile(paste(packageName(), Sys.Date(), sep = "-")), - lib.loc = .libPaths(), # nolint object_name_linter + lib.loc = .libPaths(), # nolint: object_name_linter. repos = getOption("repos"), restore = TRUE, ... ) { + ap <- available.packages(repos = repos) + custom_alias <- uulist(drlapply(plan$custom, `[[`, "alias")) + all_alias_unique <- !any(duplicated(plan$alias)) + all_alias_distinct <- !any(plan$alias %in% ap[, "Package"]) + all_custom_distinct <- !any(custom_alias %in% plan$alias) + # Make sure all aliases are unique stopifnot( - "Check task aliases has to be unique" = - !any(duplicated(df$alias)), - "Check task aliases cannot have the same name as any of the available packages" = # nolint - !any(df$alias %in% available.packages(repos = repos)[, "Package"]), - "Custom package aliases cannot be duplicates of check aliases" = - !any(uulist(drlapply(df$custom, `[[`, "alias")) %in% df$alias) + "Task aliases have to be unique" = all_alias_unique, + "Task aliases cannot have the same name as any available package" = all_alias_distinct, # nolint: line_length_linter. + "Custom package aliases cannot be duplicates of check aliases" = all_custom_distinct # nolint: line_length_linter. ) if (!restore) unlink(output, recursive = TRUE, force = TRUE) dir_create(output) - self$input <- df + self$plan <- plan self$output <- output private$n <- n private$lib.loc <- lib.loc private$repos <- repos - g <- task_graph_create(df, repos) + g <- task_graph_create(plan, repos) self$graph <- task_graph_update_done(g, c(path_lib(output), lib.loc)) private$restore_complete_checks() }, @@ -224,7 +232,7 @@ check_design <- R6::R6Class( # nolint cyclocomp_linter TRUE }, restore_complete_checks = function() { - checks <- self$input$alias + checks <- self$plan$alias check_done <- vlapply(checks, function(check) { file.exists(file.path( path_check_output(self$output, check), @@ -244,11 +252,11 @@ check_design <- R6::R6Class( # nolint cyclocomp_linter ) #' @export -print.check_design <- function(x, ...) { +print.checker <- function(x, ...) { if (x$is_done()) { print(results(x, ...), ...) } else { - print(x$input, ...) + print(x$plan, ...) } invisible(x) } diff --git a/R/reporter.R b/R/reporter.R index 545b5ae..82587c1 100644 --- a/R/reporter.R +++ b/R/reporter.R @@ -1,7 +1,7 @@ #' Check Design Runner Reporters #' #' Reporters are used to configure how output is communicated while running -#' a [`check_design`]. They range from glossy command-line tools intended for +#' a [`checker`]. They range from glossy command-line tools intended for #' displaying progress in an interactive R session, to line-feed logs which #' may be better suited for automated execution, such as in continuous #' itegration. @@ -63,7 +63,7 @@ reporter_default <- function() { #' thin wrapper around an environment with a class name for dispatch. The #' reporter is mutable and captures any necessary state that needs to be #' tracked while reporting. -#' @param design [`check_design`] The check design to report as it evaluates. +#' @param design [`checker`] The check design to report as it evaluates. #' @param envir `environment` An environment to attach to, to leverage on-exit #' hooks. #' @param sleep `numeric` An interval to pause between reporter steps. diff --git a/R/results.R b/R/results.R index a5ce22e..495d282 100644 --- a/R/results.R +++ b/R/results.R @@ -4,12 +4,13 @@ CHECK_ISSUES_TYPES <- c("notes", "warnings", "errors") #' #' Get R CMD check results #' -#' @param x \code{\link[checked]{check_design}} object. +#' @param x [`checker`] object. #' @param error_on character vector indicating whether R error should be thrown -#' when issues are discovered when generating results. "never" means that no -#' errors are thrown. If "issues" then errors are emitted only on issues, whereas -#' "potential issues" stands for error on both issues and potential issues. Users -#' can set the default value via env variable \code{CHECKED_RESULTS_ERROR_ON}. +#' when issues are discovered when generating results. "never" means that no +#' errors are thrown. If "issues" then errors are emitted only on issues, +#' whereas "potential issues" stands for error on both issues and potential +#' issues. Users can set the default value via env variable +#' `CHECKED_RESULTS_ERROR_ON`. #' @param ... other parameters. #' #' @family results @@ -20,7 +21,7 @@ results <- function(x, ...) { #' @export #' @rdname results -results.check_design <- function( +results.checker <- function( x, error_on = Sys.getenv("CHECKED_RESULTS_ERROR_ON", c("never", "issues", "potential_issues")[1]), ...) { @@ -238,7 +239,7 @@ count.potential_issues <- function(d, issues_type = "potential_issues", ...) { } #' @export -summary.check_design <- function(object, ...) { +summary.checker <- function(object, ...) { summary(results(object), ...) } diff --git a/R/run.R b/R/run.R index 063be82..4a79d9b 100644 --- a/R/run.R +++ b/R/run.R @@ -1,39 +1,39 @@ #' Run a Series of `R CMD check`s #' #' [`run()`] provides a generic, and is the central interface for executing -#' [`check_design`]s. If a path is provided, a new reverse dependency check +#' [`checker`]s. If a path is provided, a new reverse dependency check #' plan is generated from the source code path. Otherwise a plan can be #' built separately and executed using [`run()`]. #' -#' @param design `character` or `check_design` If a `character` value is -#' provided, it is first coerced into a `check_design` using -#' [`new_rev_dep_check_design()`]. -#' @param ... Additional arguments passed to [`new_rev_dep_check_design()`] +#' @param checks `character` or `checker` If a `character` value is +#' provided, it is first coerced into a `checker` using +#' [`new_rev_dep_checker()`]. +#' @param ... Additional arguments passed to [`new_rev_dep_checker()`] #' @param reporter A reporter to provide progress updates. Will default to the #' most expressive command-line reporter given your terminal capabilities. #' #' @export -run <- function(design, ..., reporter = reporter_default()) { +run <- function(checker, ..., reporter = reporter_default()) { UseMethod("run") } #' @export -run.character <- function(design, ..., reporter = reporter_default()) { - run(new_rev_dep_check_design(design, ...), reporter = reporter) +run.character <- function(checker, ..., reporter = reporter_default()) { + run(new_rev_dep_checker(checker, ...), reporter = reporter) } #' @export -run.check_design <- function(design, ..., reporter = reporter_default()) { +run.checker <- function(checker, ..., reporter = reporter_default()) { on.exit(add = TRUE, { - design$terminate() - report_finalize(reporter, design) + checker$terminate() + report_finalize(reporter, checker) }) - report_initialize(reporter, design) - while (design$start_next_task() >= 0) { - report_status(reporter, design) - report_sleep(reporter, design) + report_initialize(reporter, checker) + while (checker$start_next_task() >= 0) { + report_status(reporter, checker) + report_sleep(reporter, checker) } - invisible(design) + invisible(checker) } diff --git a/man/check_dev_rev_deps.Rd b/man/check_dev_rev_deps.Rd index a80ac9e..4808151 100644 --- a/man/check_dev_rev_deps.Rd +++ b/man/check_dev_rev_deps.Rd @@ -49,10 +49,11 @@ as a \code{Suggests} dependency. } \seealso{ Other checks: -\code{\link{check_design}}, \code{\link{check_dir}()}, \code{\link{check_pkgs}()}, \code{\link{check_rev_deps}()}, -\code{\link{new_check_design}()} +\code{\link{checker}}, +\code{\link{new_check_design}}, +\code{\link{new_checker}()} } \concept{checks} diff --git a/man/check_dir.Rd b/man/check_dir.Rd index ca70c71..6985004 100644 --- a/man/check_dir.Rd +++ b/man/check_dir.Rd @@ -46,10 +46,11 @@ regarding checks that run. Can be combined with } \seealso{ Other checks: -\code{\link{check_design}}, \code{\link{check_dev_rev_deps}()}, \code{\link{check_pkgs}()}, \code{\link{check_rev_deps}()}, -\code{\link{new_check_design}()} +\code{\link{checker}}, +\code{\link{new_check_design}}, +\code{\link{new_checker}()} } \concept{checks} diff --git a/man/check_pkgs.Rd b/man/check_pkgs.Rd index 7d84631..0d3fa26 100644 --- a/man/check_pkgs.Rd +++ b/man/check_pkgs.Rd @@ -47,10 +47,11 @@ in parallel for all source packages whose source code is found in the } \seealso{ Other checks: -\code{\link{check_design}}, \code{\link{check_dev_rev_deps}()}, \code{\link{check_dir}()}, \code{\link{check_rev_deps}()}, -\code{\link{new_check_design}()} +\code{\link{checker}}, +\code{\link{new_check_design}}, +\code{\link{new_checker}()} } \concept{checks} diff --git a/man/check_rev_deps.Rd b/man/check_rev_deps.Rd index 503f601..646f352 100644 --- a/man/check_rev_deps.Rd +++ b/man/check_rev_deps.Rd @@ -62,10 +62,11 @@ identify changes in reverse dependency behaviors. } \seealso{ Other checks: -\code{\link{check_design}}, \code{\link{check_dev_rev_deps}()}, \code{\link{check_dir}()}, \code{\link{check_pkgs}()}, -\code{\link{new_check_design}()} +\code{\link{checker}}, +\code{\link{new_check_design}}, +\code{\link{new_checker}()} } \concept{checks} diff --git a/man/check_design.Rd b/man/checker.Rd similarity index 59% rename from man/check_design.Rd rename to man/checker.Rd index fdd2401..690a0d1 100644 --- a/man/check_design.Rd +++ b/man/checker.Rd @@ -1,7 +1,7 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/check_design.R -\name{check_design} -\alias{check_design} +% Please edit documentation in R/checker.R +\name{checker} +\alias{checker} \title{\code{R6} Checks Coordinator} \description{ A stateful object that orchestrates all separate processes required to @@ -15,9 +15,14 @@ plan <- plan_checks(c( system.file("example_packages", "exampleGood", package = "checked") )) -checks <- check_design$new(plan, n = 10, repos = "https://cran.r-project.org/") -while (!checks$is_done()) { - checks$start_next_task() +orchestrator <- checker$new( + plan, + n = 10, + repos = "https://cran.r-project.org/" +) + +while (!orchestrator$is_done()) { + orchestrator$start_next_task() } } @@ -28,7 +33,8 @@ Other checks: \code{\link{check_dir}()}, \code{\link{check_pkgs}()}, \code{\link{check_rev_deps}()}, -\code{\link{new_check_design}()} +\code{\link{new_check_design}}, +\code{\link{new_checker}()} } \concept{checks} \section{Public fields}{ @@ -39,7 +45,7 @@ A dependency graph, storing information about which dependencies are required prior to execution of each check task. Created with \code{\link[=task_graph_create]{task_graph_create()}}} -\item{\code{input}}{(\code{data.frame()})\cr +\item{\code{plan}}{(\code{data.frame()})\cr Checks task \code{data.frame} which is the source of all the checks.} \item{\code{output}}{(\code{character(1)})\cr @@ -51,27 +57,27 @@ be created and stored.} \section{Methods}{ \subsection{Public methods}{ \itemize{ -\item \href{#method-check_design-new}{\code{check_design$new()}} -\item \href{#method-check_design-active_processes}{\code{check_design$active_processes()}} -\item \href{#method-check_design-failed_tasks}{\code{check_design$failed_tasks()}} -\item \href{#method-check_design-terminate}{\code{check_design$terminate()}} -\item \href{#method-check_design-step}{\code{check_design$step()}} -\item \href{#method-check_design-start_next_task}{\code{check_design$start_next_task()}} -\item \href{#method-check_design-is_done}{\code{check_design$is_done()}} -\item \href{#method-check_design-clone}{\code{check_design$clone()}} +\item \href{#method-checker-new}{\code{checker$new()}} +\item \href{#method-checker-active_processes}{\code{checker$active_processes()}} +\item \href{#method-checker-failed_tasks}{\code{checker$failed_tasks()}} +\item \href{#method-checker-terminate}{\code{checker$terminate()}} +\item \href{#method-checker-step}{\code{checker$step()}} +\item \href{#method-checker-start_next_task}{\code{checker$start_next_task()}} +\item \href{#method-checker-is_done}{\code{checker$is_done()}} +\item \href{#method-checker-clone}{\code{checker$clone()}} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-check_design-new}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-checker-new}{}}} \subsection{Method \code{new()}}{ Initialize a new check design Use checks data.frame to generate task graph in which all dependencies and installation order are embedded. \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{check_design$new( - df, +\if{html}{\out{
}}\preformatted{checker$new( + plan, n = 2L, output = tempfile(paste(packageName(), Sys.Date(), sep = "-")), lib.loc = .libPaths(), @@ -84,7 +90,7 @@ and installation order are embedded. \subsection{Arguments}{ \if{html}{\out{
}} \describe{ -\item{\code{df}}{\code{check_design} data.frame.} +\item{\code{plan}}{\code{plan} \code{data.frame}.} \item{\code{n}}{\code{integer} value indicating maximum number of subprocesses that can be simultaneously spawned when executing tasks.} @@ -111,44 +117,44 @@ restore previous progress from the same \code{output}.} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-check_design-active_processes}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-checker-active_processes}{}}} \subsection{Method \code{active_processes()}}{ Get Active Processes list \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{check_design$active_processes()}\if{html}{\out{
}} +\if{html}{\out{
}}\preformatted{checker$active_processes()}\if{html}{\out{
}} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-check_design-failed_tasks}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-checker-failed_tasks}{}}} \subsection{Method \code{failed_tasks()}}{ Get Failed Tasks list \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{check_design$failed_tasks()}\if{html}{\out{
}} +\if{html}{\out{
}}\preformatted{checker$failed_tasks()}\if{html}{\out{
}} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-check_design-terminate}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-checker-terminate}{}}} \subsection{Method \code{terminate()}}{ Kill All Active Design Processes Immediately terminates all the active processes. \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{check_design$terminate()}\if{html}{\out{
}} +\if{html}{\out{
}}\preformatted{checker$terminate()}\if{html}{\out{
}} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-check_design-step}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-checker-step}{}}} \subsection{Method \code{step()}}{ Fill Available Processes with Tasks \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{check_design$step()}\if{html}{\out{
}} +\if{html}{\out{
}}\preformatted{checker$step()}\if{html}{\out{
}} } \subsection{Returns}{ @@ -157,12 +163,12 @@ running. } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-check_design-start_next_task}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-checker-start_next_task}{}}} \subsection{Method \code{start_next_task()}}{ Start Next Task \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{check_design$start_next_task()}\if{html}{\out{
}} +\if{html}{\out{
}}\preformatted{checker$start_next_task()}\if{html}{\out{
}} } \subsection{Returns}{ @@ -171,24 +177,24 @@ process was spawned, or \code{-1} if all tasks have finished. } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-check_design-is_done}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-checker-is_done}{}}} \subsection{Method \code{is_done()}}{ Check if checks are done Checks whether all the scheduled tasks were successfully executed. \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{check_design$is_done()}\if{html}{\out{
}} +\if{html}{\out{
}}\preformatted{checker$is_done()}\if{html}{\out{
}} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-check_design-clone}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-checker-clone}{}}} \subsection{Method \code{clone()}}{ The objects of this class are cloneable with this method. \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{check_design$clone(deep = FALSE)}\if{html}{\out{
}} +\if{html}{\out{
}}\preformatted{checker$clone(deep = FALSE)}\if{html}{\out{
}} } \subsection{Arguments}{ diff --git a/man/new_check_design.Rd b/man/new_checker.Rd similarity index 55% rename from man/new_check_design.Rd rename to man/new_checker.Rd index 0e061d2..1aee87d 100644 --- a/man/new_check_design.Rd +++ b/man/new_checker.Rd @@ -1,13 +1,10 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/check_design.R -\name{new_check_design} -\alias{new_check_design} -\alias{new_rev_dep_check_design} +% Please edit documentation in R/checker.R +\name{new_checker} +\alias{new_checker} \title{Creating new Check Design Objects} \usage{ -new_check_design(...) - -new_rev_dep_check_design(x, ...) +new_checker(...) } \arguments{ \item{...}{Additional arguments passed to \code{\link[=new_check_design]{new_check_design()}}} @@ -19,17 +16,11 @@ Instantiate a check design from a path or directory. } \seealso{ Other checks: -\code{\link{check_design}}, -\code{\link{check_dev_rev_deps}()}, -\code{\link{check_dir}()}, -\code{\link{check_pkgs}()}, -\code{\link{check_rev_deps}()} - -Other checks: -\code{\link{check_design}}, \code{\link{check_dev_rev_deps}()}, \code{\link{check_dir}()}, \code{\link{check_pkgs}()}, -\code{\link{check_rev_deps}()} +\code{\link{check_rev_deps}()}, +\code{\link{checker}}, +\code{\link{new_check_design}} } \concept{checks} diff --git a/man/run.Rd b/man/run.Rd index 5a0cd26..836dd23 100644 --- a/man/run.Rd +++ b/man/run.Rd @@ -4,17 +4,17 @@ \alias{run} \title{Run a Series of \verb{R CMD check}s} \usage{ -run(design, ..., reporter = reporter_default()) +run(checker, ..., reporter = reporter_default()) } \arguments{ -\item{design}{\code{character} or \code{check_design} If a \code{character} value is -provided, it is first coerced into a \code{check_design} using -\code{\link[=new_rev_dep_check_design]{new_rev_dep_check_design()}}.} - \item{...}{Additional arguments passed to \code{\link[=new_rev_dep_check_design]{new_rev_dep_check_design()}}} \item{reporter}{A reporter to provide progress updates. Will default to the most expressive command-line reporter given your terminal capabilities.} + +\item{checks}{\code{character} or \code{check_design} If a \code{character} value is +provided, it is first coerced into a \code{check_design} using +\code{\link[=new_rev_dep_check_design]{new_rev_dep_check_design()}}.} } \description{ \code{\link[=run]{run()}} provides a generic, and is the central interface for executing diff --git a/tests/testthat/test-check-reverse.R b/tests/testthat/test-check-reverse.R index 015f442..c406e0b 100644 --- a/tests/testthat/test-check-reverse.R +++ b/tests/testthat/test-check-reverse.R @@ -17,7 +17,7 @@ test_that("check_rev_deps works for package with no revdeps", { # Ensure source installation to make sure test works also on mac and windows withr::with_options(list(pkgType = "source"), { expect_no_error( - design <- check_rev_deps( + checks <- check_rev_deps( file.path(sources_new, "pkg.none"), n = 2L, repos = repo, @@ -26,7 +26,7 @@ test_that("check_rev_deps works for package with no revdeps", { ) }) - r <- results(design) + r <- results(checks) expect_s3_class(r, "checked_results") expect_true(is.list(r)) expect_length(r, 0L) From c7633c43e1df12d6aaffce5c25809ef74dcaa9c1 Mon Sep 17 00:00:00 2001 From: dgkf-roche Date: Thu, 5 Sep 2024 16:40:55 -0400 Subject: [PATCH 07/62] chore: rebuilding docs --- NAMESPACE | 6 +++--- R/checker.R | 10 +++++++--- man/check_dev_rev_deps.Rd | 3 +-- man/check_dir.Rd | 3 +-- man/check_functions.Rd | 2 +- man/check_pkgs.Rd | 3 +-- man/check_rev_deps.Rd | 3 +-- man/checker.Rd | 3 +-- man/new_checker.Rd | 15 ++++++++++++--- man/reporters-internal.Rd | 2 +- man/reporters.Rd | 2 +- man/results.Rd | 13 +++++++------ man/run.Rd | 10 +++++----- 13 files changed, 42 insertions(+), 33 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 3b1b2e1..66b8c4e 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -19,10 +19,10 @@ S3method(pkg_deps,default) S3method(pkg_deps,pkg_origin_archive) S3method(pkg_deps,pkg_origin_local) S3method(pkg_deps,pkg_origin_source) -S3method(print,check_design) S3method(print,checked_results) S3method(print,checked_results_check_task) S3method(print,checked_results_revdep_check_task) +S3method(print,checker) S3method(print,issues) S3method(print,potential_issues) S3method(print,rcmdcheck_diff) @@ -38,8 +38,8 @@ S3method(report_sleep,reporter_ansi_tty) S3method(report_status,"NULL") S3method(report_status,reporter_ansi_tty) S3method(report_status,reporter_basic_tty) -S3method(results,check_design) S3method(results,check_task) +S3method(results,checker) S3method(results,list_check_task) S3method(results,list_revdep_check_task) S3method(results,revdep_check_task) @@ -48,10 +48,10 @@ S3method(run,checker) S3method(start_task,check_task) S3method(start_task,custom_install_task) S3method(start_task,install_task) -S3method(summary,check_design) S3method(summary,checked_results) S3method(summary,checked_results_check_task) S3method(summary,checked_results_revdep_check_task) +S3method(summary,checker) export(check_dev_rev_deps) export(check_dir) export(check_pkgs) diff --git a/R/checker.R b/R/checker.R index 12ea15b..d1966c6 100644 --- a/R/checker.R +++ b/R/checker.R @@ -193,6 +193,7 @@ checker <- R6::R6Class( # nolint: cyclocomp_linter. finished <- (length(private$active) == 0) && self$is_done() return(-finished) }, + #' @description #' Check if checks are done #' @@ -203,19 +204,20 @@ checker <- R6::R6Class( # nolint: cyclocomp_linter. } ), private = list( - # Values - # maximum child process count n = 2L, + # lib.loc of allowed packages, lib.loc = NULL, + # repositories to fetch dependencies from repos = getOption("repos"), + # active processes active = list(), + # failed tasks failed = list(), - # Methods push_process = function(task, x) { task_graph_task_process(self$graph, task) <- x @@ -231,6 +233,7 @@ checker <- R6::R6Class( # nolint: cyclocomp_linter. private$active[[name]] <- x TRUE }, + restore_complete_checks = function() { checks <- self$plan$alias check_done <- vlapply(checks, function(check) { @@ -245,6 +248,7 @@ checker <- R6::R6Class( # nolint: cyclocomp_linter. STATUS$done ) }, + pop_process = function(name) { private$active[[name]] <- NULL } diff --git a/man/check_dev_rev_deps.Rd b/man/check_dev_rev_deps.Rd index 4808151..1d87c1a 100644 --- a/man/check_dev_rev_deps.Rd +++ b/man/check_dev_rev_deps.Rd @@ -36,7 +36,7 @@ restore previous progress from the same \code{output}} \item{...}{Additional arguments passed to \code{\link[=run]{run()}}} } \value{ -\code{\link[=check_design]{check_design()}} R6 class storing all the details +\code{\link[=checker]{checker()}} R6 class storing all the details regarding checks that run. Can be combined with \code{\link{results}} and \code{\link[=summary]{summary()}} methods to generate results. } @@ -53,7 +53,6 @@ Other checks: \code{\link{check_pkgs}()}, \code{\link{check_rev_deps}()}, \code{\link{checker}}, -\code{\link{new_check_design}}, \code{\link{new_checker}()} } \concept{checks} diff --git a/man/check_dir.Rd b/man/check_dir.Rd index 6985004..d50554b 100644 --- a/man/check_dir.Rd +++ b/man/check_dir.Rd @@ -36,7 +36,7 @@ restore previous progress from the same \code{output}} \item{...}{Additional arguments passed to \code{\link[=run]{run()}}} } \value{ -\code{\link[=check_design]{check_design()}} R6 class storing all the details +\code{\link[=checker]{checker()}} R6 class storing all the details regarding checks that run. Can be combined with \code{\link{results}} and \code{\link[=summary]{summary()}} methods to generate results. } @@ -50,7 +50,6 @@ Other checks: \code{\link{check_pkgs}()}, \code{\link{check_rev_deps}()}, \code{\link{checker}}, -\code{\link{new_check_design}}, \code{\link{new_checker}()} } \concept{checks} diff --git a/man/check_functions.Rd b/man/check_functions.Rd index 2d50611..2ad0b62 100644 --- a/man/check_functions.Rd +++ b/man/check_functions.Rd @@ -30,7 +30,7 @@ restore previous progress from the same \code{output}} \item{...}{Additional arguments passed to \code{\link[=run]{run()}}} } \value{ -\code{\link[=check_design]{check_design()}} R6 class storing all the details +\code{\link[=checker]{checker()}} R6 class storing all the details regarding checks that run. Can be combined with \code{\link{results}} and \code{\link[=summary]{summary()}} methods to generate results. } diff --git a/man/check_pkgs.Rd b/man/check_pkgs.Rd index 0d3fa26..e278c62 100644 --- a/man/check_pkgs.Rd +++ b/man/check_pkgs.Rd @@ -36,7 +36,7 @@ restore previous progress from the same \code{output}} \item{...}{Additional arguments passed to \code{\link[=run]{run()}}} } \value{ -\code{\link[=check_design]{check_design()}} R6 class storing all the details +\code{\link[=checker]{checker()}} R6 class storing all the details regarding checks that run. Can be combined with \code{\link{results}} and \code{\link[=summary]{summary()}} methods to generate results. } @@ -51,7 +51,6 @@ Other checks: \code{\link{check_dir}()}, \code{\link{check_rev_deps}()}, \code{\link{checker}}, -\code{\link{new_check_design}}, \code{\link{new_checker}()} } \concept{checks} diff --git a/man/check_rev_deps.Rd b/man/check_rev_deps.Rd index 646f352..9ee2cc6 100644 --- a/man/check_rev_deps.Rd +++ b/man/check_rev_deps.Rd @@ -42,7 +42,7 @@ restore previous progress from the same \code{output}} \item{...}{Additional arguments passed to \code{\link[=run]{run()}}} } \value{ -\code{\link[=check_design]{check_design()}} R6 class storing all the details +\code{\link[=checker]{checker()}} R6 class storing all the details regarding checks that run. Can be combined with \code{\link{results}} and \code{\link[=summary]{summary()}} methods to generate results. } @@ -66,7 +66,6 @@ Other checks: \code{\link{check_dir}()}, \code{\link{check_pkgs}()}, \code{\link{checker}}, -\code{\link{new_check_design}}, \code{\link{new_checker}()} } \concept{checks} diff --git a/man/checker.Rd b/man/checker.Rd index 690a0d1..4820417 100644 --- a/man/checker.Rd +++ b/man/checker.Rd @@ -33,7 +33,6 @@ Other checks: \code{\link{check_dir}()}, \code{\link{check_pkgs}()}, \code{\link{check_rev_deps}()}, -\code{\link{new_check_design}}, \code{\link{new_checker}()} } \concept{checks} @@ -113,7 +112,7 @@ restore previous progress from the same \code{output}.} \if{html}{\out{
}} } \subsection{Returns}{ -\link{check_design}. +\link{checker}. } } \if{html}{\out{
}} diff --git a/man/new_checker.Rd b/man/new_checker.Rd index 1aee87d..49584c1 100644 --- a/man/new_checker.Rd +++ b/man/new_checker.Rd @@ -2,12 +2,15 @@ % Please edit documentation in R/checker.R \name{new_checker} \alias{new_checker} +\alias{new_rev_dep_checker} \title{Creating new Check Design Objects} \usage{ new_checker(...) + +new_rev_dep_checker(x, ...) } \arguments{ -\item{...}{Additional arguments passed to \code{\link[=new_check_design]{new_check_design()}}} +\item{...}{Additional arguments passed to \code{\link[=new_checker]{new_checker()}}} \item{x}{A file path, passed to \code{\link[=rev_dep_check_tasks_df]{rev_dep_check_tasks_df()}}} } @@ -20,7 +23,13 @@ Other checks: \code{\link{check_dir}()}, \code{\link{check_pkgs}()}, \code{\link{check_rev_deps}()}, -\code{\link{checker}}, -\code{\link{new_check_design}} +\code{\link{checker}} + +Other checks: +\code{\link{check_dev_rev_deps}()}, +\code{\link{check_dir}()}, +\code{\link{check_pkgs}()}, +\code{\link{check_rev_deps}()}, +\code{\link{checker}} } \concept{checks} diff --git a/man/reporters-internal.Rd b/man/reporters-internal.Rd index a00d14d..35a9f62 100644 --- a/man/reporters-internal.Rd +++ b/man/reporters-internal.Rd @@ -25,7 +25,7 @@ thin wrapper around an environment with a class name for dispatch. The reporter is mutable and captures any necessary state that needs to be tracked while reporting.} -\item{design}{\code{\link{check_design}} The check design to report as it evaluates.} +\item{design}{\code{\link{checker}} The check design to report as it evaluates.} \item{sleep}{\code{numeric} An interval to pause between reporter steps.} diff --git a/man/reporters.Rd b/man/reporters.Rd index e008911..e3f558f 100644 --- a/man/reporters.Rd +++ b/man/reporters.Rd @@ -15,7 +15,7 @@ reporter_default() } \description{ Reporters are used to configure how output is communicated while running -a \code{\link{check_design}}. They range from glossy command-line tools intended for +a \code{\link{checker}}. They range from glossy command-line tools intended for displaying progress in an interactive R session, to line-feed logs which may be better suited for automated execution, such as in continuous itegration. diff --git a/man/results.Rd b/man/results.Rd index a9b9f62..2f61644 100644 --- a/man/results.Rd +++ b/man/results.Rd @@ -2,12 +2,12 @@ % Please edit documentation in R/results.R \name{results} \alias{results} -\alias{results.check_design} +\alias{results.checker} \title{Check results} \usage{ results(x, ...) -\method{results}{check_design}( +\method{results}{checker}( x, error_on = Sys.getenv("CHECKED_RESULTS_ERROR_ON", c("never", "issues", "potential_issues")[1]), @@ -15,15 +15,16 @@ results(x, ...) ) } \arguments{ -\item{x}{\code{\link[checked]{check_design}} object.} +\item{x}{\code{\link{checker}} object.} \item{...}{other parameters.} \item{error_on}{character vector indicating whether R error should be thrown when issues are discovered when generating results. "never" means that no -errors are thrown. If "issues" then errors are emitted only on issues, whereas -"potential issues" stands for error on both issues and potential issues. Users -can set the default value via env variable \code{CHECKED_RESULTS_ERROR_ON}.} +errors are thrown. If "issues" then errors are emitted only on issues, +whereas "potential issues" stands for error on both issues and potential +issues. Users can set the default value via env variable +\code{CHECKED_RESULTS_ERROR_ON}.} } \description{ Get R CMD check results diff --git a/man/run.Rd b/man/run.Rd index 836dd23..76ffafd 100644 --- a/man/run.Rd +++ b/man/run.Rd @@ -7,18 +7,18 @@ run(checker, ..., reporter = reporter_default()) } \arguments{ -\item{...}{Additional arguments passed to \code{\link[=new_rev_dep_check_design]{new_rev_dep_check_design()}}} +\item{...}{Additional arguments passed to \code{\link[=new_rev_dep_checker]{new_rev_dep_checker()}}} \item{reporter}{A reporter to provide progress updates. Will default to the most expressive command-line reporter given your terminal capabilities.} -\item{checks}{\code{character} or \code{check_design} If a \code{character} value is -provided, it is first coerced into a \code{check_design} using -\code{\link[=new_rev_dep_check_design]{new_rev_dep_check_design()}}.} +\item{checks}{\code{character} or \code{checker} If a \code{character} value is +provided, it is first coerced into a \code{checker} using +\code{\link[=new_rev_dep_checker]{new_rev_dep_checker()}}.} } \description{ \code{\link[=run]{run()}} provides a generic, and is the central interface for executing -\code{\link{check_design}}s. If a path is provided, a new reverse dependency check +\code{\link{checker}}s. If a path is provided, a new reverse dependency check plan is generated from the source code path. Otherwise a plan can be built separately and executed using \code{\link[=run]{run()}}. } From c83059f0009a116cad95557a18bd2de889c3f31b Mon Sep 17 00:00:00 2001 From: dgkf-roche Date: Fri, 6 Sep 2024 21:20:45 -0400 Subject: [PATCH 08/62] wip: refactor task_edges_df, prioritize early DESCRIPTION modification --- DESCRIPTION | 2 + NAMESPACE | 12 +++ R/checker.R | 16 +--- R/pkg_origin.R | 61 +++++++++++-- R/plan.R | 117 +++++++++++++------------ R/task.R | 110 +++++++++++++++++++++--- R/task_graph.R | 160 ++++++++++++++++------------------- R/utils-available-packages.R | 44 ++++++++++ R/utils-cli.R | 5 ++ R/utils-formatting.R | 8 ++ R/utils-paths.R | 51 +++++++++++ R/utils-pkg-source.R | 70 +++++++++++++++ R/utils.R | 1 - man/check_task.Rd | 20 ++--- man/install_task.Rd | 2 +- man/path_parts.Rd | 15 ++++ man/pkg_origin.Rd | 8 +- man/task.Rd | 9 +- man/task_edges_df.Rd | 28 ++++++ 19 files changed, 539 insertions(+), 200 deletions(-) create mode 100644 R/utils-available-packages.R create mode 100644 R/utils-formatting.R create mode 100644 man/path_parts.Rd create mode 100644 man/task_edges_df.Rd diff --git a/DESCRIPTION b/DESCRIPTION index 4bca9db..cb7db6f 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -36,8 +36,10 @@ Imports: cli, igraph, jsonlite, + memoise, R6, rcmdcheck, + rlang, utils (>= 3.6.2), tools Roxygen: list(markdown = TRUE) diff --git a/NAMESPACE b/NAMESPACE index 66b8c4e..da17f27 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,6 +1,12 @@ # Generated by roxygen2: do not edit by hand S3method("[",checked_results) +S3method(as_desc,character) +S3method(as_desc,check_task) +S3method(as_desc,install_task) +S3method(as_desc,list) +S3method(as_desc,pkg_origin_local) +S3method(as_desc,pkg_origin_repo) S3method(check_path,pkg_origin) S3method(check_path,pkg_origin_archive) S3method(check_path,pkg_origin_local) @@ -8,8 +14,14 @@ S3method(check_path,pkg_origin_repo) S3method(count,default) S3method(count,issues) S3method(count,potential_issues) +S3method(format,check_task) +S3method(format,filepath) +S3method(format,install_task) S3method(format,list_of_task) +S3method(format,listof) +S3method(format,pkg_origin) S3method(format,task) +S3method(format,tasks) S3method(format_status_line_ansi,check_process) S3method(format_status_line_ansi,default) S3method(install_params,pkg_origin_archive) diff --git a/R/checker.R b/R/checker.R index d1966c6..bacf9ec 100644 --- a/R/checker.R +++ b/R/checker.R @@ -94,20 +94,10 @@ checker <- R6::R6Class( # nolint: cyclocomp_linter. restore = TRUE, ... ) { - ap <- available.packages(repos = repos) - custom_alias <- uulist(drlapply(plan$custom, `[[`, "alias")) - all_alias_unique <- !any(duplicated(plan$alias)) - all_alias_distinct <- !any(plan$alias %in% ap[, "Package"]) - all_custom_distinct <- !any(custom_alias %in% plan$alias) - - # Make sure all aliases are unique - stopifnot( - "Task aliases have to be unique" = all_alias_unique, - "Task aliases cannot have the same name as any available package" = all_alias_distinct, # nolint: line_length_linter. - "Custom package aliases cannot be duplicates of check aliases" = all_custom_distinct # nolint: line_length_linter. - ) + if (!restore) { + unlink(output, recursive = TRUE, force = TRUE) + } - if (!restore) unlink(output, recursive = TRUE, force = TRUE) dir_create(output) self$plan <- plan diff --git a/R/pkg_origin.R b/R/pkg_origin.R index cd56ee3..2a22b22 100644 --- a/R/pkg_origin.R +++ b/R/pkg_origin.R @@ -11,20 +11,65 @@ #' #' @family specs #' @export -pkg_origin <- function(name, ..., .class = c()) { - structure(list(name = name, ...), class = c(.class, "pkg_origin_source")) +pkg_origin <- function(package, ..., .class = c()) { + structure(list(package = package, ...), class = c(.class, "pkg_origin")) +} + +#' @export +format.pkg_origin <- function(x, ...) { + paste(collapse = " ", c( + x$package, + if (!is.null(x$version)) { + switch(class(x$version)[[1]], + package_version = paste0("(v", format(x$version), ")"), + x$version + ) + }, + if (!is.null(x$source)) { + paste0("from ", if (is.null(names(x$source))) { + format(x$source, pretty = TRUE) + } else { + names(x$source) + }) + } + )) } #' @export #' @rdname pkg_origin -pkg_origin_repo <- function(repos, ...) { - pkg_origin(..., repos = repos, .class = "pkg_origin_repo") +pkg_origin_repo <- function(package, repos, ...) { + ap_pkg <- available_packages(repos = repos)[package, ] + + version <- package_version(ap_pkg["Version"]) + source <- strip_src_contrib(ap_pkg["Repository"]) + if (any(which <- startsWith(repos, source))) { + source <- repos[which][1] + } + + pkg_origin( + package = package, + version = version, + source = source, + repos = repos, + ..., + .class = "pkg_origin_repo" + ) } #' @export #' @rdname pkg_origin pkg_origin_local <- function(path = NULL, ...) { - pkg_origin(..., path = path, .class = "pkg_origin_local") + package <- get_package_name(path) + version <- package_version(get_package_version(path)) + source <- filepath(normalizePath(path)) + + pkg_origin( + package = package, + version = version, + source = source, + ..., + .class = "pkg_origin_local" + ) } #' @export @@ -43,9 +88,9 @@ pkg_deps.default <- function(x) { } #' @export -pkg_deps.pkg_origin_source <- function(x) { - db <- utils::available.packages(repos = x$repos) - row <- db[x$name, , drop = FALSE] +pkg_deps.pkg_origin_local <- function(x) { + db <- available_packages(repos = x$repos) + row <- db[x$package, , drop = FALSE] row[, DB_COLNAMES, drop = FALSE] } diff --git a/R/plan.R b/R/plan.R index c074243..e0e49a7 100644 --- a/R/plan.R +++ b/R/plan.R @@ -55,9 +55,10 @@ plan_rev_dep_checks <- function( repos = getOption("repos"), versions = c("dev", "release") ) { - versions <- match.arg(versions, c("dev", "release"), several.ok = TRUE) - ap <- utils::available.packages(repos = repos) + version_types <- match.arg(versions, c("dev", "release"), several.ok = TRUE) path <- check_path_is_pkg_source(path) + ap <- available_packages(repos = repos) + package <- get_package_name(path) revdeps <- tools::package_dependencies( package, @@ -70,68 +71,69 @@ plan_rev_dep_checks <- function( return(empty_checks_df) } - version <- ap[revdeps, "Version"] - df_dev <- df_rel <- data.frame( - alias = revdeps, - version = version - ) - - if (!package %in% ap[, "Package"] && "release" %in% versions) { - warning( - sprintf( - "Package `%s` not found in repositories `%s`. Skipping 'release' in 'versions'", - package, - paste0(repos, collapse = ", ") - ), - immediate. = TRUE + if ("release" %in% version_types && !package %in% ap[, "Package"]) { + msg <- sprintf( + "Skipping 'release' checks. Package `%s` not found in repositories: \n", + package, + paste0(" * ", repos, collapse = "\n") ) - if ("dev" %in% versions) { - versions <- "dev" - } else { - return(empty_checks_df) - } - } - tasks_function <- if (all(c("dev", "release") %in% versions)) { - rev_dep_check_tasks - } else { - rev_dep_check_tasks_development + warning(msg, immediate. = TRUE) + version_types <- setdiff(version_types, "release") } - if ("dev" %in% versions) { - df_dev$alias <- paste0(df_dev$alias, " (dev)") - df_dev$package <- tasks_function(revdeps, repos, df_dev$alias, "new") - df_dev$custom <- rep(list(custom_install_task( - alias = paste0(package, " (dev)"), - package = pkg_origin_local(name = package, path = path), - type = "source" - )), times = NROW(df_dev)) + if (length(version_types) == 0) { + return(empty_checks_df) } - if ("release" %in% versions) { - package_v <- ap[package, "Version"] - df_rel$alias <- paste0(df_rel$alias, " (v", package_v, ")") - df_rel$package <- tasks_function(revdeps, repos, df_rel$alias, "old") - df_rel$custom <- rep(list(custom_install_task( - alias = paste0(package, " (release)"), - package = pkg_origin_repo(name = package, repos = repos), - # make sure to use the release version built against the same system + unlist(recursive = FALSE, lapply( + revdeps, + plan_single_rev_dep_check, + path = path, + package = package, + repos = repos + )) +} + +plan_single_rev_dep_check <- function( + path, + package, + revdep, + repos +) { + task_sets <- list() + + # development version, testing revdeps against local source + task_sets[[1]] <- task(list( + install_task( + origin = pkg_origin_local(path = path), type = "source" - )), times = NROW(df_dev)) - } + ), + check_task( + origin = pkg_origin_repo(package = revdep, repos = repos), + env = DEFAULT_R_CMD_CHECK_ENVVARS, + args = DEFAULT_R_CMD_CHECK_ARGS, + build_args = DEFAULT_R_CMD_BUILD_ARGS + ) + )) - if (identical(versions, "dev")) { - df <- df_dev - } else if (identical(versions, "release")) { - df <- df_rel - } else { - idx <- rep(seq_len(nrow(df_rel)), each = 2) + c(0, nrow(df_rel)) - df <- rbind(df_dev, df_rel)[idx, ] + # release version, testing revdep against repo source + if (package %in% available_packages(repos = repos)[, "Package"]) { + task_sets[[length(task_sets) + 1]] <- task(list( + install_task( + origin = pkg_origin_repo(package = package, repos = repos), + type = "source" + ), + check_task( + origin = pkg_origin_repo(package = revdep, repos = repos), + env = DEFAULT_R_CMD_CHECK_ENVVARS, + args = DEFAULT_R_CMD_CHECK_ARGS, + build_args = DEFAULT_R_CMD_BUILD_ARGS + ) + )) } - df$package <- list_of_task(df$package) - df$custom <- list_of_task(df$custom) - df + task_sets } rev_dep_check_tasks <- function(packages, repos, aliases, revdep) { @@ -153,12 +155,7 @@ rev_dep_check_tasks <- function(packages, repos, aliases, revdep) { )) } -rev_dep_check_tasks_development <- function( - packages, - repos, - aliases, - ... -) { +rev_dep_check_tasks_development <- function(packages, repos, aliases, ...) { list_of_task(mapply( function(package, alias) { check_task( diff --git a/R/task.R b/R/task.R index 66468a0..f85b6b5 100644 --- a/R/task.R +++ b/R/task.R @@ -3,19 +3,16 @@ #' Create task specification list which consists of all the details required #' to run specific task. #' +#' Tasks can be nested, representing either a singular task, or a set of +#' related tasks. +#' #' @param alias task alias which also serves as unique identifier of the task. #' @param package \code{\link[checked]{package}} object -#' @param env environmental variables to be set in separate process running -#' specific task. #' #' @family tasks #' @export -task <- function(alias = NULL, package = NULL, env = NULL) { - structure(list(alias = alias, package = package, env = env), class = "task") -} - -list_of_task <- function(x, ...) { - structure(x, class = c("list_of_task", "list")) +task <- function(x, ...) { + structure(x, class = c("task", class(x))) } #' @family tasks @@ -27,7 +24,12 @@ print.task <- function(x, ...) { #' @family tasks #' @export format.task <- function(x, ...) { - paste0("") + if (is.list(x)) { + fmt_tasks <- paste0(vcapply(x, function(xi) format(xi)), collapse = ", ") + return(paste0("[", fmt_tasks, "]")) + } + + NextMethod() } #' @family tasks @@ -44,17 +46,28 @@ format.list_of_task <- function(x, ...) { #' @family tasks #' @export install_task <- function( + origin, type = getOption("pkgType"), INSTALL_opts = NULL, # nolint: object_name_linter. ... ) { - task <- task(...) + task <- task(list(origin = origin, ...)) task$type <- type task$INSTALL_opts <- INSTALL_opts class(task) <- c("install_task", class(task)) task } +is_install_task <- function(x) { + inherits(x, "install_task") +} + +#' @family tasks +#' @export +format.install_task <- function(x, ...) { + paste0("") +} + #' Create a custom install task #' #' @inheritDotParams install_task @@ -74,14 +87,25 @@ custom_install_task <- function(...) { #' #' @family tasks #' @export -check_task <- function(args = NULL, build_args = NULL, ...) { - task <- task(...) +check_task <- function(build_args = NULL, args = NULL, env = NULL, ...) { + task <- task(list(...)) + task$env <- env task$args <- args task$build_args <- build_args class(task) <- c("check_task", class(task)) task } +is_check_task <- function(x) { + inherits(x, "check_task") +} + +#' @family tasks +#' @export +format.check_task <- function(x, ...) { + paste0("") +} + #' Create a task to run reverse dependency checks #' #' @param revdep character indicating whether the task specification describes @@ -97,3 +121,65 @@ revdep_check_task <- function(revdep, ...) { class(task) <- c("revdep_check_task", class(task)) task } + +tasks <- function(x) { + structure(x, class = "tasks") +} + +#' @export +format.tasks <- function(x, ...) { + elems <- lapply(x, function(xi) format(xi, ...)) + paste0("[", paste0(elems, collapse = ", "), "]") +} + +as_desc <- function(x, ...) { + UseMethod("as_desc") +} + +#' @export +as_desc.list <- function(x, ...) { + descs <- list() + length(descs) <- length(x) + for (i in seq_along(x)) descs[[i]] <- as_desc(x[[i]]) + descs <- bind_descs(descs) + descs <- sub_aliased_desc(descs) + descs +} + +#' @export +as_desc.install_task <- function(x, ...) { + as_desc(x$origin) +} + +#' @export +as_desc.check_task <- function(x, ...) { + as_desc(x$origin) +} + +#' @export +as_desc.character <- function(x) { + desc <- read.dcf(x) + read.dcf(x, fields = unique(c(colnames(desc), names(DEP)))) +} + +#' @export +as_desc.pkg_origin_local <- function(x) { + desc <- as_desc(file.path(x$source, "DESCRIPTION")) + + # generate a local alias to differentiate package from same package + # installed from other sources + local_alias <- substring(cli::hash_obj_sha256(task), 1, 12) + + # update the Package field, replacing actual name with an alias + desc <- cbind(desc, Alias = x$package) + desc[, "Package"] <- local_alias + rownames(desc) <- local_alias + + desc +} + +#' @export +as_desc.pkg_origin_repo <- function(x) { + ap <- available_packages(repos = x$repos) + ap[x$package, , drop = FALSE] +} diff --git a/R/task_graph.R b/R/task_graph.R index 5e2c668..2c40186 100644 --- a/R/task_graph.R +++ b/R/task_graph.R @@ -10,8 +10,8 @@ #' @keywords internal #' @importFrom igraph V task_graph_create <- function(df, repos = getOption("repos")) { - edges <- task_edges_df(df, repos) - vertices <- task_vertices_df(df, edges, repos) + edges <- task_graph_edges(df, repos) + vertices <- task_graph_vertices(df, edges, repos) g <- igraph::graph_from_data_frame(edges, vertices = vertices) igraph::V(g)$status <- STATUS$pending # nolint object_name_linter @@ -19,103 +19,89 @@ task_graph_create <- function(df, repos = getOption("repos")) { task_graph_sort(g) } -task_edges_df <- function(df, repos) { - if (NROW(df) == 0) { - return(empty_edge) - } - - db <- utils::available.packages(repos = repos)[, DB_COLNAMES] - - # For checks alias has to have different name than package name - - # Add custom packages to db - custom_aliases_idx <- which(vlapply(df$custom, function(x) !is.null(x$alias))) - custom_aliases <- unique(vcapply(df$custom[custom_aliases_idx], `[[`, "alias")) - custom_aliases_map <- unique(data.frame( - value = custom_aliases, - hash = vcapply(custom_aliases, unique_alias) - )) - - desc <- drlapply(df$custom, function(x) { - row <- pkg_deps(x$package) - hash <- custom_aliases_map[custom_aliases_map$value == x$alias, ]$hash - row[, "Package"] <- hash - row - }) - - # Drop potential duplicates - desc <- unique(desc) - - # Adding checks to db and custom packages as Depends link - checks <- drlapply(df$package, function(x) { - p <- df[df$alias == x$alias, ] - row <- pkg_deps(x$package) - row[, "Package"] <- x$alias - if (!is.null(p$custom[[1]]$alias)) { - row_idx <- custom_aliases_map$value == p$custom[[1]]$alias - hash <- custom_aliases_map[row_idx, ]$hash - row[, "Depends"] <- ifelse( - is.na(row[, "Depends"]), - hash, - paste0(row[, "Depends"], ", ", hash) - ) - } - row - }) - - db <- rbind(db, desc, checks) - - # Get suggests end enhances dependencies first so we can derive hard - # dependencies for them as well - suggests_dependencies <- uulist(package_deps( - df$alias, +#' Build task graph edges +#' +#' Edges describe relationships between tasks. Often, this is a dependency +#' between packages, requiring that some package be installed before a latter +#' task can be executed. +#' +#' [`tools::package_dependencies()`] is used to calculate these relationships. +#' However, the package data returned by [`utils::available.packages()`], +#' that is used internally to determine dependencies does not know about +#' local or remote packages, so those are first appended to this data set +#' prior to calculating edges. The bulk of this function serves to join this +#' data. +#' +#' @param plan a `plan` object, containing a list of related steps. +#' @param repos `repos`, as expected by [`tools::package_dependencies()`] to +#' determine package relationships. +#' @value A `data.frame` that can be used to build [`igraph`] edges. +#' +#' @keywords internal +task_graph_edges <- function(plan, repos = getOption("repos")) { + if (NROW(plan) == 0) return(empty_edge) + + # build supplementary database entries for package tasks + desc_db <- lapply(plan, function(x) as_desc(x)) + desc_db <- unique(bind_descs(desc_db)) + packages <- desc_db[, "Package"] + + # add task package origin descriptions into database + db <- available_packages(repos = repos)[, DB_COLNAMES] + db <- rbind(desc_db[, colnames(db)], db) + db <- db[!duplicated(db[, "Package"]), ] + + # only first-order suggested dependencies needed + soft_deps <- unique(as.character(unlist(package_deps( + packages, db = db, which = c("Suggests", "Enhances"), recursive = FALSE - )) + )))) - # Get recursively strong dependencies for all packages - core_dependencies <- package_deps( - c(df$alias, custom_aliases_map$hash, suggests_dependencies), + # for all packages and first-order suggests packages, get recursive hard deps + hard_deps <- unique(as.character(unlist(package_deps( + c(packages, soft_deps), db = db, which = "strong", recursive = TRUE - ) + )))) + + deps <- unique(c(packages, soft_deps, hard_deps)) + deps <- deps[!deps %in% base_pkgs()] + in_db <- which(deps %in% db[, "Package"]) + packages_edges(db[deps[in_db], ]) +} - dependencies <- uulist(c( - # tools::package_dependencies do not include package itself. - # we add it at this stage - df$alias, - custom_aliases_map$hash, - suggests_dependencies, - core_dependencies - )) - - dependencies <- dependencies[!dependencies %in% base_pkgs()] - - edges <- drlapply(dependencies, function(p) { - drlapply(uulist(DEP), function(type) { - deps <- try(db[db[, "Package"] == p, type], silent = TRUE) - if (inherits(deps, "try-error") || length(deps) == 0) { - empty_edge - } else { - deps <- split_packages_names(deps) - deps <- deps[deps %in% dependencies] - data.frame( - dep = deps, - root = rep(p, times = length(deps)), - type = rep(type, times = length(deps)) - ) - } - }) +#' Produce Graph Edges from Packages Index +#' +#' @param ap `matrix`, as produced by [`utils::available.packages()`] +#' @return `character` `matrix` of columns `package`, `dep` and `type` with +#' one row for each dependency relationship. +#' +packages_edges <- function(ap) { + deps_by_type <- lapply(names(DEP), function(deptype) { + is_na <- is.na(ap[, deptype]) + + # filter for available packages with at least one dep of deptype + deps <- ap[!is_na, deptype] + names(deps) <- ap[!is_na, "Package"] + + # split deps of deptype + deps <- lapply(deps, .tools$.split_dependencies) + + # and structure + data.frame( + package = rep(names(deps), times = viapply(deps, length)), + dep = unlist(lapply(deps, names), use.names = FALSE), + type = deptype + ) }) - edges$dep <- replace_with_map(edges$dep, custom_aliases_map$hash, custom_aliases_map$value) - edges$root <- replace_with_map(edges$root, custom_aliases_map$hash, custom_aliases_map$value) - edges + do.call(rbind, deps_by_type) } -task_vertices_df <- function(df, edges, repos) { +task_graph_vertices <- function(df, edges, repos) { vertices <- unique(c(edges$dep, edges$root)) custom_pkgs_aliases <- uulist(lapply(df$custom, `[[`, "alias")) task_type <- ifelse(vertices %in% df$alias, "check", "install") diff --git a/R/utils-available-packages.R b/R/utils-available-packages.R new file mode 100644 index 0000000..5daad73 --- /dev/null +++ b/R/utils-available-packages.R @@ -0,0 +1,44 @@ +#' Available Packages +#' +#' Functionally Equivalent to [`utils::available.packages()`], assuming +#' `utils`'s cache doesn't expire in the middle of a top-level callback. +#' Modifications were made so that the results for queries with unique +#' arguments are only called once for each top-level expression. +#' +#' Though [`utils::available.packages()`] will cache the `PACKAGES` index, +#' it must still be parsed with each call. Since this can happen hundreds of +#' times when building a `R CMD check` plan, this can cause a signficiant +#' bottleneck to the responsiveness of this package. +#' +#' system.time({ for (i in 1:10) available.packages() }) +#' #> user system elapsed +#' #> 3.453 0.196 3.655 +#' +#' system.time({ for (i in 1:10) available_packages() }) +#' #> user system elapsed +#' #> 0.003 0.000 0.003 +#' +#' @keywords internal +available_packages <- local({ + callback_name <- paste0(packageName(), "-last-top-level-time") + callback_time <- NULL + + callback <- function(...) { + last_top_level_callback <<- Sys.time() + FALSE + } + + maybe_add_callback <- function() { + if (!callback_name %in% getTaskCallbackNames()) { + addTaskCallback(name = callback_name, callback) + } + } + + memoise::memoise( + hash = function(x) rlang::hash(list(x, callback_time)), + function(...) { + maybe_add_callback() + utils::available.packages(...) + } + ) +}) diff --git a/R/utils-cli.R b/R/utils-cli.R index 6102a57..c0bb25b 100644 --- a/R/utils-cli.R +++ b/R/utils-cli.R @@ -42,3 +42,8 @@ str_pad <- function(x, n) { x <- format(x) paste0(strrep(" ", n - nchar(x)), x) } + +emoji <- list( + dev = "\U0001F6A7", + release = "\U0001F680" +) diff --git a/R/utils-formatting.R b/R/utils-formatting.R new file mode 100644 index 0000000..0cc02b3 --- /dev/null +++ b/R/utils-formatting.R @@ -0,0 +1,8 @@ +listof <- function(x) { + structure(x, class = "listof") +} + +#' @export +format.listof <- function(x, ...) { + vcapply(x, function(xi) format(xi, ...)) +} diff --git a/R/utils-paths.R b/R/utils-paths.R index 3bea2ee..a80846b 100644 --- a/R/utils-paths.R +++ b/R/utils-paths.R @@ -1,3 +1,54 @@ +filepath <- function(x) { + structure(x, class = "filepath") +} + +#' @export +format.filepath <- function(x, ..., pretty = FALSE) { + if (!pretty) { + return(as.character(x)) + } + + wp <- path_parts(getwd()) + xp <- path_parts(normalizePath(x)) + min_len <- min(length(wp), length(xp)) + first_diff <- Position(identity, head(wp, min_len) != head(xp, min_len)) + + if (is.na(first_diff)) { + parts <- utils::tail(xp, -min_len) + if (length(parts) == 0) { + parts <- "." + } + return(format(do.call(file.path, as.list(parts)))) + } + + if (first_diff > min_len) { + parts <- utils::tail(xp, -first_diff + 1) + format(do.call(file.path, as.list(parts))) + } else if (first_diff <= min_len) { + parents <- rep_len("..", length(xp) - first_diff + 1) + parts <- c(parents, utils::tail(xp, -first_diff + 1)) + format(do.call(file.path, as.list(parts))) + } else { + format(x) + } +} + +#' Split a Filepath into Parts +#' +#' @param x A `character(1L)` or `filepath` +#' @value A `character` vector of path parts +#' +#' @keywords internal +path_parts <- function(x) { + parts <- character() + repeat { + parts[[length(parts) + 1L]] <- basename(x) + if (x == dirname(x)) break + x <- dirname(x) + } + rev(parts) +} + path_default <- function() { file.path(tempdir(), utils::packageName()) } diff --git a/R/utils-pkg-source.R b/R/utils-pkg-source.R index d810e58..0c8b1db 100644 --- a/R/utils-pkg-source.R +++ b/R/utils-pkg-source.R @@ -1,3 +1,7 @@ +strip_src_contrib <- function(x) { + sub("/src/contrib$", "", x) +} + split_packages_names <- function(x) { if (is.na(x)) { return(x) @@ -33,6 +37,25 @@ check_dependencies <- function(dependencies) { dependencies } +bind_descs <- function(x, fields = NULL) { + all_colnames <- unique(unlist(lapply(x, colnames))) + if (!is.null(fields)) { + all_colnames <- intersect(all_colnames, fields) + } + for (i in seq_along(x)) { + missing_cols <- setdiff(all_colnames, colnames(x[[i]])) + new_cols <- rep_len(NA, length(missing_cols)) + names(new_cols) <- missing_cols + x[[i]] <- do.call(cbind, c(list(x[[i]]), new_cols)) + x[[i]] <- x[[i]][, all_colnames, drop = FALSE] + } + do.call(rbind, x) +} + +get_desc <- function(origin) { + UseMethod("get_desc") +} + get_desc_field <- function(path, field) { desc <- file.path(path, "DESCRIPTION") if (!file.exists(desc)) { @@ -41,6 +64,53 @@ get_desc_field <- function(path, field) { read.dcf(desc)[, field] } +sub_aliased_desc <- function(desc) { + if (!"Alias" %in% colnames(desc)) return(desc) + + # create mapping from package name to aliased name + has_alias <- !is.na(desc[, "Alias"]) + alias_map <- desc[has_alias, "Package"] + names(alias_map) <- desc[has_alias, "Alias"] + + for (deptype in names(DEP)) { + for (i in seq_len(nrow(desc))) { + desc[[i, deptype]] <- sub_aliased_deps(desc[[i, deptype]], alias_map) + } + } + + desc +} + +#' Substitute Aliased Dependencies String +#' +#' @param deps `character(1L)`, as provided by a `DESCRIPTION` file's +#' dependency listing. +#' @param aliases (named vector), a mapping of package names to aliases for +#' substitution. +#' @return `deps`, substituting package names with associated aliases. +#' +sub_aliased_deps <- function(deps, aliases) { + if (is.na(deps)) { + return(deps) + } + + deps <- .tools$.split_dependencies(deps) + for (i in seq_along(deps)) { + if (deps[[i]]$name %in% names(aliases)) { + deps[[i]]$name <- aliases[[deps[[i]]$name]] + } + } + + paste(collapse = ", ", vcapply(deps, function(dep) { + paste0( + dep$name, + if (!is.null(dep$version)) { + paste0(" (", dep$op, " ", dep$version, ")") + } + ) + })) +} + get_package_name <- function(path) { get_desc_field(path, "Package") } diff --git a/R/utils.R b/R/utils.R index 7b67357..698ca65 100644 --- a/R/utils.R +++ b/R/utils.R @@ -39,7 +39,6 @@ drmapply <- function(...) { do.call(rbind, mapply(..., USE.NAMES = FALSE, SIMPLIFY = FALSE)) } -uulist <- function(...) unique(as.character(unlist(...))) vcapply <- function(...) vapply(..., FUN.VALUE = character(1L)) vlapply <- function(...) vapply(..., FUN.VALUE = logical(1L)) viapply <- function(...) vapply(..., FUN.VALUE = integer(1L)) diff --git a/man/check_task.Rd b/man/check_task.Rd index 48037b0..fb0d474 100644 --- a/man/check_task.Rd +++ b/man/check_task.Rd @@ -4,9 +4,15 @@ \alias{check_task} \title{Create a task to run \verb{R CMD check}} \usage{ -check_task(args = NULL, build_args = NULL, ...) +check_task(build_args = NULL, args = NULL, env = NULL, ...) } \arguments{ +\item{build_args}{Character vector of arguments to pass to \verb{R CMD build}. +Pass each argument as a single element of this character vector (do not use +spaces to delimit arguments like you would in the shell). For example, +\code{build_args = c("--force", "--keep-empty-dirs")} is a correct usage and +\code{build_args = "--force --keep-empty-dirs"} is incorrect.} + \item{args}{Character vector of arguments to pass to \verb{R CMD check}. Pass each argument as a single element of this character vector (do not use spaces to delimit arguments like you would in the shell). For example, to skip @@ -15,19 +21,13 @@ instead of the \code{--output} option you should use the \code{check_dir} argume because \code{--output} cannot deal with spaces and other special characters on Windows.)} -\item{build_args}{Character vector of arguments to pass to \verb{R CMD build}. -Pass each argument as a single element of this character vector (do not use -spaces to delimit arguments like you would in the shell). For example, -\code{build_args = c("--force", "--keep-empty-dirs")} is a correct usage and -\code{build_args = "--force --keep-empty-dirs"} is incorrect.} +\item{env}{A named character vector, extra environment variables to +set in the check process.} \item{...}{ Arguments passed on to \code{\link[=task]{task}} \describe{ - \item{\code{alias}}{task alias which also serves as unique identifier of the task.} - \item{\code{package}}{\code{\link[checked]{package}} object} - \item{\code{env}}{environmental variables to be set in separate process running -specific task.} + \item{\code{}}{} }} } \description{ diff --git a/man/install_task.Rd b/man/install_task.Rd index 0995435..5e24502 100644 --- a/man/install_task.Rd +++ b/man/install_task.Rd @@ -4,7 +4,7 @@ \alias{install_task} \title{Create a task to install a package and dependencies} \usage{ -install_task(type = getOption("pkgType"), INSTALL_opts = NULL, ...) +install_task(origin, type = getOption("pkgType"), INSTALL_opts = NULL, ...) } \arguments{ \item{type}{character, indicating the type of package to download and diff --git a/man/path_parts.Rd b/man/path_parts.Rd new file mode 100644 index 0000000..1c93446 --- /dev/null +++ b/man/path_parts.Rd @@ -0,0 +1,15 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils-paths.R +\name{path_parts} +\alias{path_parts} +\title{Split a Filepath into Parts} +\usage{ +path_parts(x) +} +\arguments{ +\item{x}{A \code{character(1L)} or \code{filepath}} +} +\description{ +Split a Filepath into Parts +} +\keyword{internal} diff --git a/man/pkg_origin.Rd b/man/pkg_origin.Rd index 56e126c..9a8e1fd 100644 --- a/man/pkg_origin.Rd +++ b/man/pkg_origin.Rd @@ -7,23 +7,23 @@ \alias{pkg_origin_archive} \title{Package specification} \usage{ -pkg_origin(name, ..., .class = c()) +pkg_origin(package, ..., .class = c()) -pkg_origin_repo(repos, ...) +pkg_origin_repo(package, repos, ...) pkg_origin_local(path = NULL, ...) pkg_origin_archive(path = NULL, ...) } \arguments{ -\item{name}{name of the package.} - \item{...}{parameters passed to downstream constructors} \item{repos}{repository where package with given name should identified.} \item{path}{path to the source of the package (either bundled or not). URLs are acceptable.} + +\item{name}{name of the package.} } \description{ Create package specification list which consists of all the details required diff --git a/man/task.Rd b/man/task.Rd index a631f1d..bbaedeb 100644 --- a/man/task.Rd +++ b/man/task.Rd @@ -4,20 +4,21 @@ \alias{task} \title{Task specification} \usage{ -task(alias = NULL, package = NULL, env = NULL) +task(x, ...) } \arguments{ \item{alias}{task alias which also serves as unique identifier of the task.} \item{package}{\code{\link[checked]{package}} object} - -\item{env}{environmental variables to be set in separate process running -specific task.} } \description{ Create task specification list which consists of all the details required to run specific task. } +\details{ +Tasks can be nested, representing either a singular task, or a set of +related tasks. +} \seealso{ Other tasks: \code{\link{check_task}()}, diff --git a/man/task_edges_df.Rd b/man/task_edges_df.Rd new file mode 100644 index 0000000..529f721 --- /dev/null +++ b/man/task_edges_df.Rd @@ -0,0 +1,28 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/task_graph.R +\name{task_edges_df} +\alias{task_edges_df} +\title{Build task graph edges} +\usage{ +task_edges_df(plan, repos) +} +\arguments{ +\item{plan}{a \code{plan} object, containing a list of related steps.} + +\item{repos}{\code{repos}, as excepted by \code{\link[tools:package_dependencies]{tools::package_dependencies()}} to +determine package relationships.} +} +\description{ +Edges describe relationships between tasks. Often, this is a dependency +between packages, requiring that some package be installed before a latter +task can be executed. +} +\details{ +\code{\link[tools:package_dependencies]{tools::package_dependencies()}} is used to calculate these relationships. +However, the package data returned by \code{\link[utils:available.packages]{utils::available.packages()}}, +that is used internally to determine dependencies does not know about +local or remote packages, so those are first appended to this data set +prior to calculating edges. The bulk of this function serves to join this +data. +} +\keyword{internal} From 51f7072f1b517805235df92b85ae6476f3da0ef3 Mon Sep 17 00:00:00 2001 From: dgkf-roche Date: Wed, 11 Sep 2024 09:39:21 -0400 Subject: [PATCH 09/62] wip: reworking task graph building --- DESCRIPTION | 10 ++-- NAMESPACE | 3 +- R/checker.R | 3 +- R/plan.R | 8 +-- R/task.R | 47 ++++++++++----- R/task_graph.R | 112 +++++++++++++++++++++++------------ R/utils-available-packages.R | 20 ++++--- R/utils-deps.R | 51 ++++++++++++++++ R/utils-paths.R | 2 +- man/as_pkg_dependencies.Rd | 24 ++++++++ man/available_packages.Rd | 35 +++++++++++ man/packages_edges.Rd | 18 ++++++ man/path_parts.Rd | 3 + man/sub_aliased_deps.Rd | 21 +++++++ man/task_edges_df.Rd | 28 --------- man/task_graph_create.Rd | 26 +++++--- 16 files changed, 302 insertions(+), 109 deletions(-) create mode 100644 R/utils-deps.R create mode 100644 man/as_pkg_dependencies.Rd create mode 100644 man/available_packages.Rd create mode 100644 man/packages_edges.Rd create mode 100644 man/sub_aliased_deps.Rd delete mode 100644 man/task_edges_df.Rd diff --git a/DESCRIPTION b/DESCRIPTION index cb7db6f..dc04695 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -11,8 +11,8 @@ Authors@R: comment = c(ORCID = "0000-0002-3120-1601") ), person( - "Doug", "Kelkhoff", , - "doug.kelkhoff@gmail.com", + "Doug", "Kelkhoff", + email = "doug.kelkhoff@gmail.com", role = c("aut"), comment = c(ORCID = "0009-0003-7845-4061") ), @@ -31,15 +31,17 @@ URL: BugReports: https://github.com/Genentech/checked/issues License: MIT + file LICENSE Encoding: UTF-8 +Depends: + R (>= 3.6.2) Imports: callr, cli, igraph, jsonlite, - memoise, + memoise, R6, rcmdcheck, - rlang, + rlang, utils (>= 3.6.2), tools Roxygen: list(markdown = TRUE) diff --git a/NAMESPACE b/NAMESPACE index da17f27..cd63552 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -14,6 +14,8 @@ S3method(check_path,pkg_origin_repo) S3method(count,default) S3method(count,issues) S3method(count,potential_issues) +S3method(flatten,default) +S3method(flatten,list) S3method(format,check_task) S3method(format,filepath) S3method(format,install_task) @@ -30,7 +32,6 @@ S3method(install_params,pkg_origin_source) S3method(pkg_deps,default) S3method(pkg_deps,pkg_origin_archive) S3method(pkg_deps,pkg_origin_local) -S3method(pkg_deps,pkg_origin_source) S3method(print,checked_results) S3method(print,checked_results_check_task) S3method(print,checked_results_revdep_check_task) diff --git a/R/checker.R b/R/checker.R index bacf9ec..0c2a4b0 100644 --- a/R/checker.R +++ b/R/checker.R @@ -189,7 +189,8 @@ checker <- R6::R6Class( # nolint: cyclocomp_linter. #' #' Checks whether all the scheduled tasks were successfully executed. is_done = function() { - checks <- igraph::V(self$graph)[igraph::V(self$graph)$type == "check"] + is_check <- vlapply(igraph::V(self$graph)$task, inherits, "check_task") + checks <- igraph::V(self$graph)[is_check] all(checks$status == STATUS$done) } ), diff --git a/R/plan.R b/R/plan.R index e0e49a7..e83a02d 100644 --- a/R/plan.R +++ b/R/plan.R @@ -104,7 +104,7 @@ plan_single_rev_dep_check <- function( task_sets <- list() # development version, testing revdeps against local source - task_sets[[1]] <- task(list( + task_sets[[1]] <- list( install_task( origin = pkg_origin_local(path = path), type = "source" @@ -115,11 +115,11 @@ plan_single_rev_dep_check <- function( args = DEFAULT_R_CMD_CHECK_ARGS, build_args = DEFAULT_R_CMD_BUILD_ARGS ) - )) + ) # release version, testing revdep against repo source if (package %in% available_packages(repos = repos)[, "Package"]) { - task_sets[[length(task_sets) + 1]] <- task(list( + task_sets[[length(task_sets) + 1]] <- list( install_task( origin = pkg_origin_repo(package = package, repos = repos), type = "source" @@ -130,7 +130,7 @@ plan_single_rev_dep_check <- function( args = DEFAULT_R_CMD_CHECK_ARGS, build_args = DEFAULT_R_CMD_BUILD_ARGS ) - )) + ) } task_sets diff --git a/R/task.R b/R/task.R index f85b6b5..6c81e3b 100644 --- a/R/task.R +++ b/R/task.R @@ -3,7 +3,7 @@ #' Create task specification list which consists of all the details required #' to run specific task. #' -#' Tasks can be nested, representing either a singular task, or a set of +#' Tasks can be nested, representing either a singular task, or a set of #' related tasks. #' #' @param alias task alias which also serves as unique identifier of the task. @@ -11,8 +11,12 @@ #' #' @family tasks #' @export -task <- function(x, ...) { - structure(x, class = c("task", class(x))) +task <- function(...) { + structure(list(...), class = "task") +} + +hash_task <- function(x, n = 12) { + substring(cli::hash_obj_sha256(x), 1, n) } #' @family tasks @@ -51,7 +55,7 @@ install_task <- function( INSTALL_opts = NULL, # nolint: object_name_linter. ... ) { - task <- task(list(origin = origin, ...)) + task <- task(origin = origin, ...) task$type <- type task$INSTALL_opts <- INSTALL_opts class(task) <- c("install_task", class(task)) @@ -88,7 +92,7 @@ custom_install_task <- function(...) { #' @family tasks #' @export check_task <- function(build_args = NULL, args = NULL, env = NULL, ...) { - task <- task(list(...)) + task <- task(...) task$env <- env task$args <- args task$build_args <- build_args @@ -140,7 +144,11 @@ as_desc <- function(x, ...) { as_desc.list <- function(x, ...) { descs <- list() length(descs) <- length(x) - for (i in seq_along(x)) descs[[i]] <- as_desc(x[[i]]) + + for (i in seq_along(x)) { + descs[[i]] <- as_desc(x[[i]]) + } + descs <- bind_descs(descs) descs <- sub_aliased_desc(descs) descs @@ -148,12 +156,12 @@ as_desc.list <- function(x, ...) { #' @export as_desc.install_task <- function(x, ...) { - as_desc(x$origin) + cbind(as_desc(x$origin), Task = hash_task(x)) } #' @export as_desc.check_task <- function(x, ...) { - as_desc(x$origin) + cbind(as_desc(x$origin), Task = hash_task(x)) } #' @export @@ -166,14 +174,9 @@ as_desc.character <- function(x) { as_desc.pkg_origin_local <- function(x) { desc <- as_desc(file.path(x$source, "DESCRIPTION")) - # generate a local alias to differentiate package from same package - # installed from other sources - local_alias <- substring(cli::hash_obj_sha256(task), 1, 12) - # update the Package field, replacing actual name with an alias desc <- cbind(desc, Alias = x$package) - desc[, "Package"] <- local_alias - rownames(desc) <- local_alias + rownames(desc) <- desc[, "Package"] <- hash_task(x) desc } @@ -183,3 +186,19 @@ as_desc.pkg_origin_repo <- function(x) { ap <- available_packages(repos = x$repos) ap[x$package, , drop = FALSE] } + +flatten <- function(x) { + UseMethod("flatten") +} + +#' @export +flatten.default <- function(x) { + list(x) +} + +#' @export +flatten.list <- function(x) { + if (!inherits(x, "list")) return(x) + unlist(recursive = FALSE, lapply(x, function(xi) flatten(xi))) +} + diff --git a/R/task_graph.R b/R/task_graph.R index 2c40186..c8bdb0b 100644 --- a/R/task_graph.R +++ b/R/task_graph.R @@ -1,23 +1,23 @@ -#' Create Task Graph -#' -#' @param df data.frame listing -#' @param repos repositories which will be used to identify dependencies chain -#' to run R CMD checks -#' @return A dependency graph with vertex attributes "root" (a logical value -#' indicating whether the package as one of the roots used to create the -#' graph), "status" (installation status) and "order" (installation order). -#' -#' @keywords internal -#' @importFrom igraph V -task_graph_create <- function(df, repos = getOption("repos")) { - edges <- task_graph_edges(df, repos) - vertices <- task_graph_vertices(df, edges, repos) - - g <- igraph::graph_from_data_frame(edges, vertices = vertices) - igraph::V(g)$status <- STATUS$pending # nolint object_name_linter - igraph::V(g)$process <- rep_len(list(), length(g)) - task_graph_sort(g) -} +# #' Create Task Graph +# #' +# #' @param df data.frame listing +# #' @param repos repositories which will be used to identify dependencies chain +# #' to run R CMD checks +# #' @return A dependency graph with vertex attributes "root" (a logical value +# #' indicating whether the package as one of the roots used to create the +# #' graph), "status" (installation status) and "order" (installation order). +# #' +# #' @keywords internal +# #' @importFrom igraph V +# task_graph_create <- function(df, repos = getOption("repos")) { +# edges <- task_graph_edges(df, repos) +# vertices <- task_graph_vertices(df, edges, repos) + +# g <- igraph::graph_from_data_frame(edges, vertices = vertices) +# igraph::V(g)$status <- STATUS$pending # nolint object_name_linter +# igraph::V(g)$process <- rep_len(list(), length(g)) +# task_graph_sort(g) +# } #' Build task graph edges #' @@ -35,48 +35,83 @@ task_graph_create <- function(df, repos = getOption("repos")) { #' @param plan a `plan` object, containing a list of related steps. #' @param repos `repos`, as expected by [`tools::package_dependencies()`] to #' determine package relationships. -#' @value A `data.frame` that can be used to build [`igraph`] edges. +#' @return A `data.frame` that can be used to build [`igraph`] edges. #' #' @keywords internal -task_graph_edges <- function(plan, repos = getOption("repos")) { +task_graph_create <- function(plan, repos = getOption("repos")) { if (NROW(plan) == 0) return(empty_edge) + # build task hashmap, allowing for graph analysis using description files + taskmap <- unique(flatten(plan)) + names(taskmap) <- vcapply(taskmap, hash_task) + # build supplementary database entries for package tasks + # tasks receive an additional "Task" column, containing a hash of the task desc_db <- lapply(plan, function(x) as_desc(x)) desc_db <- unique(bind_descs(desc_db)) packages <- desc_db[, "Package"] # add task package origin descriptions into database db <- available_packages(repos = repos)[, DB_COLNAMES] + db <- cbind(db, Task = NA_character_) db <- rbind(desc_db[, colnames(db)], db) db <- db[!duplicated(db[, "Package"]), ] - # only first-order suggested dependencies needed - soft_deps <- unique(as.character(unlist(package_deps( + # create dependencies graph + g <- package_graph(db, packages) + + # populate install tasks for new dependencies, installing from repos + v_db_idx <- match(V(g)$name, db[, "Package"]) + V(g)$task <- taskmap[db[v_db_idx, "Task"]] + + no_task <- vlapply(V(g)$task, is.null) + is_base <- V(g)$name %in% base_pkgs() + is_known <- V(g)$name %in% db[, "Package"] + needs_install <- no_task & !is_base & is_known + + V(g)$task[needs_install] <- lapply( + V(g)$name[needs_install], + function(package) { + install_task(origin = pkg_origin_repo(package = package, repos = repos)) + } + ) + + # standardize graph fields + igraph::V(g)$status <- STATUS$pending # nolint: object_name_linter. + igraph::V(g)$process <- rep_len(list(), length(g)) + + g +} + +package_graph <- function(db, packages = db[, "Package"], dependencies = TRUE) { + dependencies <- as_pkg_dependencies(dependencies) + + direct_deps <- unique(as.character(unlist(package_deps( packages, db = db, - which = c("Suggests", "Enhances"), + which = dependencies$direct, recursive = FALSE )))) - # for all packages and first-order suggests packages, get recursive hard deps - hard_deps <- unique(as.character(unlist(package_deps( - c(packages, soft_deps), + indirect_deps <- unique(as.character(unlist(package_deps( + c(packages, direct_deps), db = db, - which = "strong", + which = dependencies$indirect, recursive = TRUE )))) - deps <- unique(c(packages, soft_deps, hard_deps)) - deps <- deps[!deps %in% base_pkgs()] - in_db <- which(deps %in% db[, "Package"]) - packages_edges(db[deps[in_db], ]) + deps <- unique(c(packages, direct_deps, indirect_deps)) + deps <- deps[!deps %in% base_pkgs() & deps %in% db[, "Package"]] + + edges <- packages_edges(db[deps, ]) + vertices <- data.frame(name = unique(c(edges$package, edges$dep))) + igraph::graph_from_data_frame(edges, vertices = vertices) } #' Produce Graph Edges from Packages Index #' #' @param ap `matrix`, as produced by [`utils::available.packages()`] -#' @return `character` `matrix` of columns `package`, `dep` and `type` with +#' @return `data.frame` with columns `package`, `dep` and `type` and #' one row for each dependency relationship. #' packages_edges <- function(ap) { @@ -101,7 +136,7 @@ packages_edges <- function(ap) { do.call(rbind, deps_by_type) } -task_graph_vertices <- function(df, edges, repos) { +task_graph_vertices <- function(plan, df, edges, repos) { vertices <- unique(c(edges$dep, edges$root)) custom_pkgs_aliases <- uulist(lapply(df$custom, `[[`, "alias")) task_type <- ifelse(vertices %in% df$alias, "check", "install") @@ -161,7 +196,7 @@ task_graph_neighborhoods <- function(g, nodes) { #' @return The [igraph::graph] `g`, with vertices sorted in preferred #' installation order. #' -#' @importFrom igraph vertex_attr neighborhood subgraph.edges permute topo_sort E V E<- V<- +#' @importFrom igraph vertex_attr neighborhood subgraph.edges permute topo_sort E V E<- V<- # nolint #' @keywords internal task_graph_sort <- function(g) { roots <- which(igraph::vertex_attr(g, "type") == "check") @@ -313,14 +348,13 @@ task_graph_set_task_process <- function(g, v, process) { igraph::set_vertex_attr(g, "process", v, list(process)) } -task_graph_update_done <- function(g, lib.loc) { +task_graph_update_done <- function(g, lib.loc) { # nolint: object_name_linter. v <- igraph::V(g)[igraph::V(g)$type == "install"] which_done <- which(vlapply(v$name, is_package_done, lib.loc = lib.loc)) task_graph_set_package_status(g, v[which_done], STATUS$done) } -is_package_done <- function(pkg, lib.loc) { # nolint object_name_linter +is_package_done <- function(pkg, lib.loc) { # nolint object_name_linter path <- find.package(pkg, lib.loc = lib.loc, quiet = TRUE) length(path) > 0 } - diff --git a/R/utils-available-packages.R b/R/utils-available-packages.R index 5daad73..2427a27 100644 --- a/R/utils-available-packages.R +++ b/R/utils-available-packages.R @@ -1,7 +1,7 @@ #' Available Packages #' #' Functionally Equivalent to [`utils::available.packages()`], assuming -#' `utils`'s cache doesn't expire in the middle of a top-level callback. +#' `utils`'s cache doesn't expire in the middle of a top-level call evaluation. #' Modifications were made so that the results for queries with unique #' arguments are only called once for each top-level expression. #' @@ -16,26 +16,30 @@ #' #' system.time({ for (i in 1:10) available_packages() }) #' #> user system elapsed -#' #> 0.003 0.000 0.003 +#' #> 0.325 0.002 0.328 +#' +#' @note This _could_ be removed by propagating the `available.packages()` +#' database matrix through all the calls that need to use it, though this +#' would be a sizable refactor. #' #' @keywords internal available_packages <- local({ - callback_name <- paste0(packageName(), "-last-top-level-time") - callback_time <- NULL + callback_name <- paste0(packageName(), "-top-level-ap") + callback_index <- 0L - callback <- function(...) { - last_top_level_callback <<- Sys.time() + increment_index <- function(...) { + callback_index <<- callback_index + 1L FALSE } maybe_add_callback <- function() { if (!callback_name %in% getTaskCallbackNames()) { - addTaskCallback(name = callback_name, callback) + addTaskCallback(name = callback_name, increment_index) } } memoise::memoise( - hash = function(x) rlang::hash(list(x, callback_time)), + hash = function(x) rlang::hash(list(x, callback_index)), function(...) { maybe_add_callback() utils::available.packages(...) diff --git a/R/utils-deps.R b/R/utils-deps.R new file mode 100644 index 0000000..e845891 --- /dev/null +++ b/R/utils-deps.R @@ -0,0 +1,51 @@ +#' Convert a value to a set of dependency types +#' +#' Implements conventions established by both [`tools::package_dependencies()`] +#' and [`pkgdepends::as_pkg_dependencies()`], following +#' [`pkgdepends::as_pkg_dependencies()`] return type structure of a list +#' including `$direct` and `$indirect` dependency types. Reimplemented to +#' avoid dependence on [`pkgdepends`] compilation requirements. +#' +#' @param x A `logical` scalar, `character` string of `"all"`, `"most"`, +#' `"hard"` or `"soft"`, `NA` or a vector of dependency types. +#' +#' @note locally defined and bespoke dispatch system to avoid registering +#' methods when loaded in combination with `pkgdepends` +#' +#' @keywords internal +as_pkg_dependencies <- function(x) { + into_deptype_vec <- function(x) { + if (is.na(x)) { + x <- "hard" + } else if (identical(x, TRUE)) { + x <- "most" + } else if (identical(x, FALSE)) { + x <- character(0L) + } + + deptypes <- c("Depends", "Imports", "LinkingTo", "Suggests", "Enhances") + if (is.character(x)) { + x <- switch(x, + "all" = deptypes, + "most" = c("Depends", "Imports", "LinkingTo", "Suggests"), + "hard" = c("Depends", "Imports", "LinkingTo"), + "soft" = c("Suggests", "Enhances"), + x + ) + } + + stopifnot(all(x %in% deptypes)) + + x + } + + into_deptype_list <- function(direct = "all", indirect = "hard") { + list( + direct = into_deptype_vec(direct), + indirect = into_deptype_vec(indirect) + ) + } + + if (!is.list(x)) x <- list(x) + do.call(into_deptype_list, x) +} diff --git a/R/utils-paths.R b/R/utils-paths.R index a80846b..e2f37a6 100644 --- a/R/utils-paths.R +++ b/R/utils-paths.R @@ -36,7 +36,7 @@ format.filepath <- function(x, ..., pretty = FALSE) { #' Split a Filepath into Parts #' #' @param x A `character(1L)` or `filepath` -#' @value A `character` vector of path parts +#' @return A `character` vector of path parts #' #' @keywords internal path_parts <- function(x) { diff --git a/man/as_pkg_dependencies.Rd b/man/as_pkg_dependencies.Rd new file mode 100644 index 0000000..b689413 --- /dev/null +++ b/man/as_pkg_dependencies.Rd @@ -0,0 +1,24 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils-deps.R +\name{as_pkg_dependencies} +\alias{as_pkg_dependencies} +\title{Convert a value to a set of dependency types} +\usage{ +as_pkg_dependencies(x) +} +\arguments{ +\item{x}{A \code{logical} scalar, \code{character} string of \code{"all"}, \code{"most"}, +\code{"hard"} or \code{"soft"}, \code{NA} or a vector of dependency types.} +} +\description{ +Implements conventions established by both \code{\link[tools:package_dependencies]{tools::package_dependencies()}} +and \code{\link[pkgdepends:as_pkg_dependencies]{pkgdepends::as_pkg_dependencies()}}, following +\code{\link[pkgdepends:as_pkg_dependencies]{pkgdepends::as_pkg_dependencies()}} return type structure of a list +including \verb{$direct} and \verb{$indirect} dependency types. Reimplemented to +avoid dependence on \code{\link{pkgdepends}} compilation requirements. +} +\note{ +locally defined and bespoke dispatch system to avoid registering +methods when loaded in combination with \code{pkgdepends} +} +\keyword{internal} diff --git a/man/available_packages.Rd b/man/available_packages.Rd new file mode 100644 index 0000000..c0e619c --- /dev/null +++ b/man/available_packages.Rd @@ -0,0 +1,35 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils-available-packages.R +\name{available_packages} +\alias{available_packages} +\title{Available Packages} +\usage{ +available_packages(...) +} +\description{ +Functionally Equivalent to \code{\link[utils:available.packages]{utils::available.packages()}}, assuming +\code{utils}'s cache doesn't expire in the middle of a top-level call evaluation. +Modifications were made so that the results for queries with unique +arguments are only called once for each top-level expression. +} +\details{ +Though \code{\link[utils:available.packages]{utils::available.packages()}} will cache the \code{PACKAGES} index, +it must still be parsed with each call. Since this can happen hundreds of +times when building a \verb{R CMD check} plan, this can cause a signficiant +bottleneck to the responsiveness of this package. + +\if{html}{\out{
}}\preformatted{system.time(\{ for (i in 1:10) available.packages() \}) +#> user system elapsed +#> 3.453 0.196 3.655 + +system.time(\{ for (i in 1:10) available_packages() \}) +#> user system elapsed +#> 0.325 0.002 0.328 +}\if{html}{\out{
}} +} +\note{ +This \emph{could} be removed by propagating the \code{available.packages()} +database matrix through all the calls that need to use it, though this +would be a sizable refactor. +} +\keyword{internal} diff --git a/man/packages_edges.Rd b/man/packages_edges.Rd new file mode 100644 index 0000000..2052fd3 --- /dev/null +++ b/man/packages_edges.Rd @@ -0,0 +1,18 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/task_graph.R +\name{packages_edges} +\alias{packages_edges} +\title{Produce Graph Edges from Packages Index} +\usage{ +packages_edges(ap) +} +\arguments{ +\item{ap}{\code{matrix}, as produced by \code{\link[utils:available.packages]{utils::available.packages()}}} +} +\value{ +\code{data.frame} with columns \code{package}, \code{dep} and \code{type} and +one row for each dependency relationship. +} +\description{ +Produce Graph Edges from Packages Index +} diff --git a/man/path_parts.Rd b/man/path_parts.Rd index 1c93446..93aa803 100644 --- a/man/path_parts.Rd +++ b/man/path_parts.Rd @@ -9,6 +9,9 @@ path_parts(x) \arguments{ \item{x}{A \code{character(1L)} or \code{filepath}} } +\value{ +A \code{character} vector of path parts +} \description{ Split a Filepath into Parts } diff --git a/man/sub_aliased_deps.Rd b/man/sub_aliased_deps.Rd new file mode 100644 index 0000000..749729a --- /dev/null +++ b/man/sub_aliased_deps.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils-pkg-source.R +\name{sub_aliased_deps} +\alias{sub_aliased_deps} +\title{Substitute Aliased Dependencies String} +\usage{ +sub_aliased_deps(deps, aliases) +} +\arguments{ +\item{deps}{\code{character(1L)}, as provided by a \code{DESCRIPTION} file's +dependency listing.} + +\item{aliases}{(named vector), a mapping of package names to aliases for +substitution.} +} +\value{ +\code{deps}, substituting package names with associated aliases. +} +\description{ +Substitute Aliased Dependencies String +} diff --git a/man/task_edges_df.Rd b/man/task_edges_df.Rd deleted file mode 100644 index 529f721..0000000 --- a/man/task_edges_df.Rd +++ /dev/null @@ -1,28 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/task_graph.R -\name{task_edges_df} -\alias{task_edges_df} -\title{Build task graph edges} -\usage{ -task_edges_df(plan, repos) -} -\arguments{ -\item{plan}{a \code{plan} object, containing a list of related steps.} - -\item{repos}{\code{repos}, as excepted by \code{\link[tools:package_dependencies]{tools::package_dependencies()}} to -determine package relationships.} -} -\description{ -Edges describe relationships between tasks. Often, this is a dependency -between packages, requiring that some package be installed before a latter -task can be executed. -} -\details{ -\code{\link[tools:package_dependencies]{tools::package_dependencies()}} is used to calculate these relationships. -However, the package data returned by \code{\link[utils:available.packages]{utils::available.packages()}}, -that is used internally to determine dependencies does not know about -local or remote packages, so those are first appended to this data set -prior to calculating edges. The bulk of this function serves to join this -data. -} -\keyword{internal} diff --git a/man/task_graph_create.Rd b/man/task_graph_create.Rd index aed0a69..ab247e6 100644 --- a/man/task_graph_create.Rd +++ b/man/task_graph_create.Rd @@ -2,22 +2,30 @@ % Please edit documentation in R/task_graph.R \name{task_graph_create} \alias{task_graph_create} -\title{Create Task Graph} +\title{Build task graph edges} \usage{ -task_graph_create(df, repos = getOption("repos")) +task_graph_create(plan, repos = getOption("repos")) } \arguments{ -\item{df}{data.frame listing} +\item{plan}{a \code{plan} object, containing a list of related steps.} -\item{repos}{repositories which will be used to identify dependencies chain -to run R CMD checks} +\item{repos}{\code{repos}, as expected by \code{\link[tools:package_dependencies]{tools::package_dependencies()}} to +determine package relationships.} } \value{ -A dependency graph with vertex attributes "root" (a logical value -indicating whether the package as one of the roots used to create the -graph), "status" (installation status) and "order" (installation order). +A \code{data.frame} that can be used to build \code{\link{igraph}} edges. } \description{ -Create Task Graph +Edges describe relationships between tasks. Often, this is a dependency +between packages, requiring that some package be installed before a latter +task can be executed. +} +\details{ +\code{\link[tools:package_dependencies]{tools::package_dependencies()}} is used to calculate these relationships. +However, the package data returned by \code{\link[utils:available.packages]{utils::available.packages()}}, +that is used internally to determine dependencies does not know about +local or remote packages, so those are first appended to this data set +prior to calculating edges. The bulk of this function serves to join this +data. } \keyword{internal} From ed60341f87f824dc7cc6bc83afbc279bf8406b84 Mon Sep 17 00:00:00 2001 From: dgkf-roche Date: Wed, 11 Sep 2024 17:34:40 -0400 Subject: [PATCH 10/62] wip: more work towards libpaths refactor --- .lintr | 6 +++ NAMESPACE | 12 +++++- R/check.R | 62 ++++++++++++++-------------- R/checker.R | 6 +-- R/lib.R | 80 +++++++++++++++++++++++++++++++++++++ R/next_task.R | 75 +++++++++++++++++++++++----------- R/plan.R | 2 + R/reporter_ansi_tty.R | 49 ++++++++++++++--------- R/reporter_basic_tty.R | 18 ++++----- R/task.R | 67 ++++++++++++++++++++++++------- R/task_graph.R | 57 +++++++++++++++----------- R/utils-enums.R | 8 ++-- man/custom_install_task.Rd | 2 + man/install_task.Rd | 11 ++++- man/lib.NULL.Rd | 11 +++++ man/lib.Rd | 17 ++++++++ man/lib.character.Rd | 16 ++++++++ man/lib.lib_loc_default.Rd | 18 +++++++++ man/lib.lib_loc_isolated.Rd | 20 ++++++++++ man/lib_loc.Rd | 19 +++++++++ man/task.Rd | 2 +- 21 files changed, 428 insertions(+), 130 deletions(-) create mode 100644 .lintr create mode 100644 R/lib.R create mode 100644 man/lib.NULL.Rd create mode 100644 man/lib.Rd create mode 100644 man/lib.character.Rd create mode 100644 man/lib.lib_loc_default.Rd create mode 100644 man/lib.lib_loc_isolated.Rd create mode 100644 man/lib_loc.Rd diff --git a/.lintr b/.lintr new file mode 100644 index 0000000..476b548 --- /dev/null +++ b/.lintr @@ -0,0 +1,6 @@ +linters: + linters_with_defaults( + object_length_linter = NULL, + object_name_linter = NULL, + cyclocomp_linter = NULL + ) diff --git a/NAMESPACE b/NAMESPACE index cd63552..7adcab7 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -19,16 +19,25 @@ S3method(flatten,list) S3method(format,check_task) S3method(format,filepath) S3method(format,install_task) -S3method(format,list_of_task) S3method(format,listof) S3method(format,pkg_origin) S3method(format,task) S3method(format,tasks) S3method(format_status_line_ansi,check_process) S3method(format_status_line_ansi,default) +S3method(friendly_name,check_task) +S3method(friendly_name,default) +S3method(friendly_name,install_task) S3method(install_params,pkg_origin_archive) S3method(install_params,pkg_origin_local) S3method(install_params,pkg_origin_source) +S3method(lib,"NULL") +S3method(lib,character) +S3method(lib,check_task) +S3method(lib,install_task) +S3method(lib,lib_loc_default) +S3method(lib,lib_loc_isolated) +S3method(lib,task) S3method(pkg_deps,default) S3method(pkg_deps,pkg_origin_archive) S3method(pkg_deps,pkg_origin_local) @@ -88,6 +97,7 @@ export(results) export(results_to_file) export(revdep_check_task) export(run) +export(start_task.igraph.vs) export(task) import(cli) importFrom(R6,R6Class) diff --git a/R/check.R b/R/check.R index c5c963a..0c35255 100644 --- a/R/check.R +++ b/R/check.R @@ -55,14 +55,15 @@ NULL #' @family checks #' @export check_rev_deps <- function( - path, - n = 2L, - output = tempfile(paste(utils::packageName(), Sys.Date(), sep = "-")), - lib.loc = .libPaths(), # nolint: object_name_linter. - repos = getOption("repos"), - reverse_repos = repos, - restore = TRUE, - ...) { + path, + n = 2L, + output = tempfile(paste(utils::packageName(), Sys.Date(), sep = "-")), + lib.loc = .libPaths(), + repos = getOption("repos"), + reverse_repos = repos, + restore = TRUE, + ... +) { checks <- checker$new( plan_rev_dep_checks(path = path, repos = reverse_repos), n = n, @@ -91,13 +92,14 @@ check_rev_deps <- function( #' @family checks #' @export check_dev_rev_deps <- function( - path, - n = 2L, - output = tempfile(paste(utils::packageName(), Sys.Date(), sep = "-")), - lib.loc = .libPaths(), # nolint object_name_linter - repos = getOption("repos"), - restore = TRUE, - ...) { + path, + n = 2L, + output = tempfile(paste(utils::packageName(), Sys.Date(), sep = "-")), + lib.loc = .libPaths(), + repos = getOption("repos"), + restore = TRUE, + ... +) { checks <- checker$new( plan_rev_dep_checks(path = path, repos = repos, versions = "dev"), n = n, @@ -125,13 +127,14 @@ check_dev_rev_deps <- function( #' @family checks #' @export check_pkgs <- function( - path, - n = 2L, - output = tempfile(paste(utils::packageName(), Sys.Date(), sep = "-")), - lib.loc = .libPaths(), # nolint object_name_linter - repos = getOption("repos"), - restore = TRUE, - ...) { + path, + n = 2L, + output = tempfile(paste(utils::packageName(), Sys.Date(), sep = "-")), + lib.loc = .libPaths(), + repos = getOption("repos"), + restore = TRUE, + ... +) { checks <- checker$new( plan_checks(path), n = n, @@ -158,13 +161,14 @@ check_pkgs <- function( #' @family checks #' @export check_dir <- function( - path, - n = 2L, - output = tempfile(paste(utils::packageName(), Sys.Date(), sep = "-")), - lib.loc = .libPaths(), # nolint object_name_linter - repos = getOption("repos"), - restore = TRUE, - ...) { + path, + n = 2L, + output = tempfile(paste(utils::packageName(), Sys.Date(), sep = "-")), + lib.loc = .libPaths(), + repos = getOption("repos"), + restore = TRUE, + ... +) { dirs <- list.dirs(path, full.names = TRUE, recursive = FALSE) r_packages <- dirs[vlapply(dirs, path_is_pkg)] check_pkgs( diff --git a/R/checker.R b/R/checker.R index 0c2a4b0..54fc520 100644 --- a/R/checker.R +++ b/R/checker.R @@ -46,7 +46,7 @@ new_rev_dep_checker <- function(x, ...) { #' #' @family checks #' @export -checker <- R6::R6Class( # nolint: cyclocomp_linter. +checker <- R6::R6Class( "checker", public = list( #' @field graph (`igraph::igraph()`)\cr @@ -89,7 +89,7 @@ checker <- R6::R6Class( # nolint: cyclocomp_linter. plan, n = 2L, output = tempfile(paste(packageName(), Sys.Date(), sep = "-")), - lib.loc = .libPaths(), # nolint: object_name_linter. + lib.loc = .libPaths(), repos = getOption("repos"), restore = TRUE, ... @@ -170,7 +170,7 @@ checker <- R6::R6Class( # nolint: cyclocomp_linter. next_task <- next_task_to_run(self$graph) if (length(next_task) > 0) { process <- start_task( - task = next_task, + node = next_task, g = self$graph, output = self$output, lib.loc = private$lib.loc diff --git a/R/lib.R b/R/lib.R new file mode 100644 index 0000000..c7ef9ef --- /dev/null +++ b/R/lib.R @@ -0,0 +1,80 @@ +#' Make a Library Location +#' +#' A description of where packages should be installed. This object provides +#' necessary information to determine where a package should be installed. +#' +#' @param x Any additional metadata that can be prescribed when describing +#' a library location and used when building the path. Defaults to an empty +#' [`list()`]. +#' @param .class An optional subclass, used primarily for dispatch. +#' +lib_loc <- function(x = list(), .class = c()) { + structure(x, class = c(.class, "lib_loc")) +} + +lib_loc_default <- function() { + lib_loc(.class = "lib_loc_default") +} + +lib_loc_isolated <- function() { + lib_loc(.class = "lib_loc_isolated") +} + +#' Get Library Location +#' +#' @param x An object describing a library location +#' @param lib.loc A set of library locations, used as defaults for objects +#' that may make use of them. +#' +lib <- function(x, ..., lib.loc = c()) { # nolint: object_name_linter. + UseMethod("lib") +} + +#' Null Library Path +#' +#' @export +lib.NULL <- function(x, ...) { + character(0L) +} + +#' Produce a Library from a Path +#' +#' @param x A `character` object +#' @param ...,lib.loc Additional arguments unused +#' +#' @export +lib.character <- function(x, ..., lib.loc = c()) { + x +} + +#' Produce an Isolated Library Path +#' +#' @param x A `lib_loc_isolated` object. +#' @param name A name for the library, defaults to a random hash. +#' @param lib.root A root directory for the isolated library. +#' @param ... Additional arguments unused +#' +#' @export +lib.lib_loc_isolated <- function( + x, + name = rlang::hash(runif(1)), + lib.root = tempdir(), + ... +) { + file.path(lib.root, name) +} + +#' Produce a Default Library Path +#' +#' @param x A `lib_loc_default` object. +#' @param ... Additional arguments unused +#' @param lib.loc Library paths, defaulting to [`.libPaths()`]. +#' +#' @export +lib.lib_loc_default <- function( + x, + ..., + lib.loc = .libPaths() +) { + lib.loc[[1]] +} diff --git a/R/next_task.R b/R/next_task.R index 05a3126..c0984b6 100644 --- a/R/next_task.R +++ b/R/next_task.R @@ -10,7 +10,7 @@ next_task_to_run <- function(g) { #' @importFrom igraph .env task_get_lib_loc <- function(g, node, output) { nhood <- task_graph_neighborhoods(g, node)[[1]] - name <- names(node) %||% node # nolint + name <- names(node) %||% node # nolint (used via non-standard-evaluation) nhood <- nhood[names(nhood) != .env$name] # Custom packages are possible only for the check type nodes which are @@ -25,6 +25,22 @@ task_get_lib_loc <- function(g, node, output) { unique(paths[order(attributes$custom, decreasing = TRUE)]) } +task_graph_libpaths <- function(g, node = NULL, lib.loc = .libPaths()) { + vs <- if (is.null(node)) { + igraph::V(g) + } else { + task_graph_neighborhoods(g, node)[[1]] + } + + # iterate over tasks and derive a library location + task_lib <- lapply( + vs$task, + function(x, ...) lib(x, ...), lib.loc = lib.loc + ) + + unique(unlist(task_lib)) +} + task_get_install_lib <- function(g, node, output) { attributes <- igraph::vertex.attributes(g, index = node) if (attributes$type == "check") { @@ -36,20 +52,27 @@ task_get_install_lib <- function(g, node, output) { } } -start_task <- function(task, g, ...) { - UseMethod("start_task", task_graph_task(g, task)) +start_task <- function(node, g, ...) { + UseMethod("start_task") +} + +#' @export +start_task.igraph.vs <- function(node, g, ...) { + stopifnot(length(node) == 1L) + UseMethod("start_task", node$task[[1]]) } #' @export start_task.install_task <- function( - task, - g, - output, - lib.loc, # nolint object_name_linter - ...) { + node, + g, + output, + lib.loc, + ... +) { spec <- task_graph_task(g, task) install_parameters <- install_params(spec$package) - libpaths <- c(task_get_lib_loc(g, task, output), lib.loc) + libpaths <- c(task_graph_libpaths(g, node, output), lib.loc) install_packages_process$new( install_parameters$package, lib = path_lib(output), @@ -65,14 +88,15 @@ start_task.install_task <- function( #' @export start_task.custom_install_task <- function( - task, - g, - output, - lib.loc, # nolint object_name_linter - ...) { + node, + g, + output, + lib.loc, + ... +) { spec <- task_graph_task(g, task) install_parameters <- install_params(spec$package) - libpaths <- c(task_get_lib_loc(g, task, output), lib.loc) + libpaths <- c(task_get_lib_loc(g, node, output), lib.loc) install_packages_process$new( install_parameters$package, lib = path_custom_lib(output, spec$alias), @@ -88,18 +112,21 @@ start_task.custom_install_task <- function( #' @export start_task.check_task <- function( - task, - g, - output, - lib.loc, # nolint object_name_linter - ...) { - spec <- task_graph_task(g, task) - libpaths <- c(task_get_lib_loc(g, task, output), lib.loc) - path <- check_path(spec$package, output = path_sources()) + node, + g, + output, + lib.loc, + ... +) { + task <- node$task[[1]] + + libpaths <- task_graph_libpaths(g, node, lib.loc = lib.loc) + browser() + path <- check_path(node$package, output = path_sources()) check_process$new( path = path, - check_dir = path_check_output(output, spec$alias), + check_dir = path_check_output(output, friendly_name(task)), libpath = libpaths, repos = spec$package$repos, args = spec$args, diff --git a/R/plan.R b/R/plan.R index e83a02d..ee6a3ae 100644 --- a/R/plan.R +++ b/R/plan.R @@ -105,8 +105,10 @@ plan_single_rev_dep_check <- function( # development version, testing revdeps against local source task_sets[[1]] <- list( + # isolate installation of development version install_task( origin = pkg_origin_local(path = path), + lib = lib_loc_isolated(), type = "source" ), check_task( diff --git a/R/reporter_ansi_tty.R b/R/reporter_ansi_tty.R index cb74f5e..b91f8cd 100644 --- a/R/reporter_ansi_tty.R +++ b/R/reporter_ansi_tty.R @@ -77,9 +77,10 @@ report_sleep.reporter_ansi_tty <- function( #' @export report_initialize.reporter_ansi_tty <- function( - reporter, - design, - envir = parent.frame()) { + reporter, + design, + envir = parent.frame() +) { # named factor vector, names as task aliases and value of last reported status reporter$header <- TRUE reporter$status <- STATUS$done[c()] @@ -106,12 +107,15 @@ report_initialize.reporter_ansi_tty <- function( #' @importFrom igraph V #' @export -report_status.reporter_ansi_tty <- function(reporter, design, envir) { # nolint +report_status.reporter_ansi_tty <- function(reporter, design, envir) { v <- igraph::V(design$graph) v_checks <- v[v$type == "check"] n_char_titles <- max(nchar(v_checks$name), 0) failed_tasks <- design$failed_tasks() - failed_packages <- failed_tasks[vlapply(failed_tasks, function(x) x$type == "install")] + failed_packages <- failed_tasks[vlapply( + failed_tasks, + function(x) x$type == "install" + )] # add newly started task status new_idx <- which(v_checks$status > STATUS$pending) @@ -149,15 +153,18 @@ report_status.reporter_ansi_tty <- function(reporter, design, envir) { # nolint ) }))) - reporter$failures_buffer <- vcapply(seq_along(failures_buffer), function(i) { - paste0( - ansi_move_line_rel(i), - ansi_line_erase(), - failures_buffer[i], - ansi_move_line_rel(-i), - sep = "" - ) - }) + reporter$failures_buffer <- vcapply( + seq_along(failures_buffer), + function(i) { + paste0( + ansi_move_line_rel(i), + ansi_line_erase(), + failures_buffer[i], + ansi_move_line_rel(-i), + sep = "" + ) + } + ) # For performance store these value in the environment to redraw warnings # buffer only when necessary @@ -192,7 +199,12 @@ report_status.reporter_ansi_tty <- function(reporter, design, envir) { # nolint cat(paste0(buffer, reporter$failures_buffer)) - is_inst <- vlapply(design$active_processes(), inherits, "install_package_process") # nolint + is_inst <- vlapply( + design$active_processes(), + inherits, + "install_package_process" + ) + inst_pkgs <- names(design$active_processes()[is_inst]) if (length(inst_pkgs)) { inst_msg <- paste0("installing ", paste0(inst_pkgs, collapse = ", ")) @@ -201,17 +213,16 @@ report_status.reporter_ansi_tty <- function(reporter, design, envir) { # nolint } n_finished <- sum(v$status[v$type == "check"] >= STATUS$done) + print(unique(v$status)) cli::cli_progress_update( set = n_finished, - extra = list( - message = inst_msg - ), + extra = list(message = inst_msg), .envir = reporter ) } #' @export -report_finalize.reporter_ansi_tty <- function(reporter, design) { # nolint +report_finalize.reporter_ansi_tty <- function(reporter, design) { report_status(reporter, design) # report completions of final processes cli::ansi_show_cursor() } diff --git a/R/reporter_basic_tty.R b/R/reporter_basic_tty.R index 2c6a64a..6a95259 100644 --- a/R/reporter_basic_tty.R +++ b/R/reporter_basic_tty.R @@ -1,9 +1,9 @@ #' @export report_initialize.reporter_basic_tty <- function( - # nolint - reporter, - design, - envir = parent.frame()) { + reporter, + design, + envir = parent.frame() +) { # start with initialized-as-completed tasks v <- igraph::V(design$graph) which_done <- v$status == STATUS$done @@ -18,7 +18,7 @@ report_initialize.reporter_basic_tty <- function( } #' @export -report_status.reporter_basic_tty <- function(reporter, design, envir) { # nolint +report_status.reporter_basic_tty <- function(reporter, design, envir) { cli_theme() for (i in seq_along(igraph::V(design$graph))) { node <- igraph::V(design$graph)[[i]] @@ -30,7 +30,7 @@ report_status.reporter_basic_tty <- function(reporter, design, envir) { # nolint # report stating of new checks if (!identical(node$status, reporter$statuses[[node$name]])) { - status <- switch(as.character(node$status), # nolint + status <- switch(as.character(node$status), # nolint (used via glue) "pending" = "queued", "in progress" = cli::cli_fmt(cli::cli_text("started")), "done" = { @@ -68,7 +68,7 @@ report_status.reporter_basic_tty <- function(reporter, design, envir) { # nolint } ) - time <- Sys.time() - reporter$time_start # nolint + time <- Sys.time() - reporter$time_start # nolint (used via glue) prefix <- cli::col_cyan("[{format_time(time)}][{node$type}] ") cli::cli_text(prefix, "{.pkg {node$name}} {status}") reporter$statuses[[node$name]] <- node$status @@ -77,9 +77,9 @@ report_status.reporter_basic_tty <- function(reporter, design, envir) { # nolint } #' @export -report_finalize.reporter_basic_tty <- function(reporter, design) { # nolint +report_finalize.reporter_basic_tty <- function(reporter, design) { cli_theme() report_status(reporter, design) # report completions of final processes - time <- format_time(Sys.time() - reporter$time_start) # nolint + time <- format_time(Sys.time() - reporter$time_start) # nolint (used via glue) cli::cli_text("Finished in {.time_taken {time}}") } diff --git a/R/task.R b/R/task.R index 6c81e3b..4883e52 100644 --- a/R/task.R +++ b/R/task.R @@ -15,10 +15,16 @@ task <- function(...) { structure(list(...), class = "task") } -hash_task <- function(x, n = 12) { +task_hash <- function(x, n = 12) { substring(cli::hash_obj_sha256(x), 1, n) } +#' @family tasks +#' @export +lib.task <- function(x, ...) { + stop("Don't know how to determine a library path for generic task") +} + #' @family tasks #' @export print.task <- function(x, ...) { @@ -29,22 +35,32 @@ print.task <- function(x, ...) { #' @export format.task <- function(x, ...) { if (is.list(x)) { - fmt_tasks <- paste0(vcapply(x, function(xi) format(xi)), collapse = ", ") - return(paste0("[", fmt_tasks, "]")) + fmt_tasks <- lapply(x, function(xi) format(xi, ...)) + return(paste0("[", paste0(fmt_tasks, collapse = ", "), "]")) } NextMethod() } +friendly_name <- function(x) { + UseMethod("friendly_name") +} + #' @family tasks #' @export -format.list_of_task <- function(x, ...) { - vcapply(x, format) +friendly_name.default <- function(x) { + stop( + "Dont' know how to name object with class(es) `", + deparse(class(x)), + "`" + ) } #' Create a task to install a package and dependencies #' #' @param ... Additional parameters passed to [`task()`] +#' @param lib Any object that can be passed to [`lib()`] to generate a library +#' path. #' @inheritParams utils::install.packages #' #' @family tasks @@ -52,24 +68,35 @@ format.list_of_task <- function(x, ...) { install_task <- function( origin, type = getOption("pkgType"), - INSTALL_opts = NULL, # nolint: object_name_linter. + INSTALL_opts = NULL, + lib = lib_loc_default(), ... ) { task <- task(origin = origin, ...) task$type <- type task$INSTALL_opts <- INSTALL_opts + task$lib <- lib class(task) <- c("install_task", class(task)) task } -is_install_task <- function(x) { - inherits(x, "install_task") +#' @export +lib.install_task <- function(x, ...) { + lib(x$lib, name = task_hash(x), ...) } -#' @family tasks #' @export format.install_task <- function(x, ...) { - paste0("") + paste0("<", friendly_name(x), ">") +} + +#' @export +friendly_name.install_task <- function(x, ...) { + paste0("install ", format(x$origin)) +} + +is_install_task <- function(x) { + inherits(x, "install_task") } #' Create a custom install task @@ -100,14 +127,24 @@ check_task <- function(build_args = NULL, args = NULL, env = NULL, ...) { task } +#' @export +lib.check_task <- function(x, ...) { + character(0L) # no additional libraries needed for checkign +} + +#' @export +format.check_task <- function(x, ...) { + paste0("<", friendly_name(x), ">") +} + is_check_task <- function(x) { inherits(x, "check_task") } #' @family tasks #' @export -format.check_task <- function(x, ...) { - paste0("") +friendly_name.check_task <- function(x, ...) { + paste0("check ", format(x$origin)) } #' Create a task to run reverse dependency checks @@ -156,12 +193,12 @@ as_desc.list <- function(x, ...) { #' @export as_desc.install_task <- function(x, ...) { - cbind(as_desc(x$origin), Task = hash_task(x)) + cbind(as_desc(x$origin), Task = task_hash(x)) } #' @export as_desc.check_task <- function(x, ...) { - cbind(as_desc(x$origin), Task = hash_task(x)) + cbind(as_desc(x$origin), Task = task_hash(x)) } #' @export @@ -176,7 +213,7 @@ as_desc.pkg_origin_local <- function(x) { # update the Package field, replacing actual name with an alias desc <- cbind(desc, Alias = x$package) - rownames(desc) <- desc[, "Package"] <- hash_task(x) + rownames(desc) <- desc[, "Package"] <- task_hash(x) desc } diff --git a/R/task_graph.R b/R/task_graph.R index c8bdb0b..e2d1bf9 100644 --- a/R/task_graph.R +++ b/R/task_graph.R @@ -43,7 +43,7 @@ task_graph_create <- function(plan, repos = getOption("repos")) { # build task hashmap, allowing for graph analysis using description files taskmap <- unique(flatten(plan)) - names(taskmap) <- vcapply(taskmap, hash_task) + names(taskmap) <- vcapply(taskmap, task_hash) # build supplementary database entries for package tasks # tasks receive an additional "Task" column, containing a hash of the task @@ -55,7 +55,9 @@ task_graph_create <- function(plan, repos = getOption("repos")) { db <- available_packages(repos = repos)[, DB_COLNAMES] db <- cbind(db, Task = NA_character_) db <- rbind(desc_db[, colnames(db)], db) - db <- db[!duplicated(db[, "Package"]), ] + db <- db[!duplicated(db[, c("Package", DB_COLNAMES)]), ] + + browser() # create dependencies graph g <- package_graph(db, packages) @@ -72,12 +74,15 @@ task_graph_create <- function(plan, repos = getOption("repos")) { V(g)$task[needs_install] <- lapply( V(g)$name[needs_install], function(package) { - install_task(origin = pkg_origin_repo(package = package, repos = repos)) + install_task( + origin = pkg_origin_repo(package = package, repos = repos), + lib = lib_loc_default() + ) } ) # standardize graph fields - igraph::V(g)$status <- STATUS$pending # nolint: object_name_linter. + igraph::V(g)$status <- STATUS$pending igraph::V(g)$process <- rep_len(list(), length(g)) g @@ -177,7 +182,7 @@ task_graph_neighborhoods <- function(g, nodes) { g, order = length(g), nodes = nodes, - mode = "in" + mode = "out" ) } @@ -196,7 +201,8 @@ task_graph_neighborhoods <- function(g, nodes) { #' @return The [igraph::graph] `g`, with vertices sorted in preferred #' installation order. #' -#' @importFrom igraph vertex_attr neighborhood subgraph.edges permute topo_sort E V E<- V<- # nolint +#' @importFrom igraph vertex_attr neighborhood subgraph.edges permute topo_sort +#' @importFrom igraph E V E<- V<- #' @keywords internal task_graph_sort <- function(g) { roots <- which(igraph::vertex_attr(g, "type") == "check") @@ -220,8 +226,8 @@ task_graph_sort <- function(g) { priority_topo[match(topo$name, igraph::V(g)$name)] <- rev(seq_along(topo)) # combine priorities, prioritize first by total, footprint then topology - priorities <- rbind(priority_footprint, priority_topo) - order <- rank(length(igraph::V(g))^seq(nrow(priorities) - 1, 0) %*% priorities) + priority <- rbind(priority_footprint, priority_topo) + order <- rank(length(igraph::V(g))^seq(nrow(priority) - 1, 0) %*% priority) g <- igraph::permute(g, order) g @@ -256,10 +262,11 @@ task_graph_sort <- function(g) { #' @importFrom igraph incident_edges tail_of #' @keywords internal task_graph_which_satisfied <- function( - g, - v = igraph::V(g), - dependencies = TRUE, - status = STATUS$pending) { + g, + v = igraph::V(g), + dependencies = TRUE, + status = STATUS$pending +) { if (is.character(status)) status <- STATUS[[status]] dependencies <- check_dependencies(dependencies) if (length(status) > 0) { @@ -281,13 +288,14 @@ task_graph_which_satisfied_strong <- function(..., dependencies = "strong") { # } task_graph_which_check_satisfied <- function( - g, - ..., - dependencies = "all", - status = STATUS$pending) { + g, + ..., + dependencies = "all", + status = STATUS$pending +) { task_graph_which_satisfied( g, - igraph::V(g)[igraph::V(g)$type == "check"], + igraph::V(g)[vlapply(igraph::V(g)$task, inherits, "check_task")], ..., dependencies = dependencies, status = status @@ -295,13 +303,14 @@ task_graph_which_check_satisfied <- function( } task_graph_which_install_satisfied <- function( - g, - ..., - dependencies = "strong", - status = STATUS$pending) { + g, + ..., + dependencies = "strong", + status = STATUS$pending +) { task_graph_which_satisfied( g, - igraph::V(g)[igraph::V(g)$type == "install"], + igraph::V(g)[vlapply(igraph::V(g)$task, inherits, "install_task")], ..., dependencies = dependencies, status = status @@ -348,13 +357,13 @@ task_graph_set_task_process <- function(g, v, process) { igraph::set_vertex_attr(g, "process", v, list(process)) } -task_graph_update_done <- function(g, lib.loc) { # nolint: object_name_linter. +task_graph_update_done <- function(g, lib.loc) { v <- igraph::V(g)[igraph::V(g)$type == "install"] which_done <- which(vlapply(v$name, is_package_done, lib.loc = lib.loc)) task_graph_set_package_status(g, v[which_done], STATUS$done) } -is_package_done <- function(pkg, lib.loc) { # nolint object_name_linter +is_package_done <- function(pkg, lib.loc) { path <- find.package(pkg, lib.loc = lib.loc, quiet = TRUE) length(path) > 0 } diff --git a/R/utils-enums.R b/R/utils-enums.R index 60f44e0..5467886 100644 --- a/R/utils-enums.R +++ b/R/utils-enums.R @@ -27,7 +27,7 @@ Ops.factor <- function(e1, e2) { #' Check execution status categories #' @keywords internal -STATUS <- enum( # nolint +STATUS <- enum( "pending", "in progress", "done" @@ -35,7 +35,7 @@ STATUS <- enum( # nolint #' Dependencies categories #' @keywords internal -DEP <- enum( # nolint +DEP <- enum( "Imports", "Depends", "LinkingTo", @@ -45,11 +45,11 @@ DEP <- enum( # nolint #' Strong dependencies categories #' @keywords internal -DEP_STRONG <- unlist(DEP[1:3]) # nolint +DEP_STRONG <- unlist(DEP[1:3]) #' Available packages database dependencies columns #' @keywords internal -DB_COLNAMES <- c( # nolint +DB_COLNAMES <- c( "Package", "Depends", "Imports", diff --git a/man/custom_install_task.Rd b/man/custom_install_task.Rd index e32f301..3167a90 100644 --- a/man/custom_install_task.Rd +++ b/man/custom_install_task.Rd @@ -10,6 +10,8 @@ custom_install_task(...) \item{...}{ Arguments passed on to \code{\link[=install_task]{install_task}} \describe{ + \item{\code{lib}}{Any object that can be passed to \code{\link[=lib]{lib()}} to generate a library +path.} \item{\code{type}}{character, indicating the type of package to download and install. Will be \code{"source"} except on Windows and some macOS builds: see the section on \sQuote{Binary packages} for those. diff --git a/man/install_task.Rd b/man/install_task.Rd index 5e24502..83c1338 100644 --- a/man/install_task.Rd +++ b/man/install_task.Rd @@ -4,7 +4,13 @@ \alias{install_task} \title{Create a task to install a package and dependencies} \usage{ -install_task(origin, type = getOption("pkgType"), INSTALL_opts = NULL, ...) +install_task( + origin, + type = getOption("pkgType"), + INSTALL_opts = NULL, + lib = lib_loc_default(), + ... +) } \arguments{ \item{type}{character, indicating the type of package to download and @@ -21,6 +27,9 @@ install_task(origin, type = getOption("pkgType"), INSTALL_opts = NULL, ...) additional options, with names the respective package names. } +\item{lib}{Any object that can be passed to \code{\link[=lib]{lib()}} to generate a library +path.} + \item{...}{Additional parameters passed to \code{\link[=task]{task()}}} } \description{ diff --git a/man/lib.NULL.Rd b/man/lib.NULL.Rd new file mode 100644 index 0000000..51cf31c --- /dev/null +++ b/man/lib.NULL.Rd @@ -0,0 +1,11 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lib.R +\name{lib.NULL} +\alias{lib.NULL} +\title{Null Library Path} +\usage{ +\method{lib}{`NULL`}(x, ...) +} +\description{ +Null Library Path +} diff --git a/man/lib.Rd b/man/lib.Rd new file mode 100644 index 0000000..13d9660 --- /dev/null +++ b/man/lib.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lib.R +\name{lib} +\alias{lib} +\title{Get Library Location} +\usage{ +lib(x, ..., lib.loc = c()) +} +\arguments{ +\item{x}{An object describing a library location} + +\item{lib.loc}{A set of library locations, used as defaults for objects +that may make use of them.} +} +\description{ +Get Library Location +} diff --git a/man/lib.character.Rd b/man/lib.character.Rd new file mode 100644 index 0000000..b0744a0 --- /dev/null +++ b/man/lib.character.Rd @@ -0,0 +1,16 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lib.R +\name{lib.character} +\alias{lib.character} +\title{Produce a Library from a Path} +\usage{ +\method{lib}{character}(x, ..., lib.loc = c()) +} +\arguments{ +\item{x}{A \code{character} object} + +\item{..., lib.loc}{Additional arguments unused} +} +\description{ +Produce a Library from a Path +} diff --git a/man/lib.lib_loc_default.Rd b/man/lib.lib_loc_default.Rd new file mode 100644 index 0000000..8e61ce4 --- /dev/null +++ b/man/lib.lib_loc_default.Rd @@ -0,0 +1,18 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lib.R +\name{lib.lib_loc_default} +\alias{lib.lib_loc_default} +\title{Produce a Default Library Path} +\usage{ +\method{lib}{lib_loc_default}(x, ..., lib.loc = .libPaths()) +} +\arguments{ +\item{x}{A \code{lib_loc_default} object.} + +\item{...}{Additional arguments unused} + +\item{lib.loc}{Library paths, defaulting to \code{\link[=.libPaths]{.libPaths()}}.} +} +\description{ +Produce a Default Library Path +} diff --git a/man/lib.lib_loc_isolated.Rd b/man/lib.lib_loc_isolated.Rd new file mode 100644 index 0000000..2bc2c0a --- /dev/null +++ b/man/lib.lib_loc_isolated.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lib.R +\name{lib.lib_loc_isolated} +\alias{lib.lib_loc_isolated} +\title{Produce an Isolated Library Path} +\usage{ +\method{lib}{lib_loc_isolated}(x, name = rlang::hash(runif(1)), lib.root = tempdir(), ...) +} +\arguments{ +\item{x}{A \code{lib_loc_isolated} object.} + +\item{name}{A name for the library, defaults to a random hash.} + +\item{lib.root}{A root directory for the isolated library.} + +\item{...}{Additional arguments unused} +} +\description{ +Produce an Isolated Library Path +} diff --git a/man/lib_loc.Rd b/man/lib_loc.Rd new file mode 100644 index 0000000..16805d9 --- /dev/null +++ b/man/lib_loc.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lib.R +\name{lib_loc} +\alias{lib_loc} +\title{Make a Library Location} +\usage{ +lib_loc(x = list(), .class = c()) +} +\arguments{ +\item{x}{Any additional metadata that can be prescribed when describing +a library location and used when building the path. Defaults to an empty +\code{\link[=list]{list()}}.} + +\item{.class}{An optional subclass, used primarily for dispatch.} +} +\description{ +A description of where packages should be installed. This object provides +necessary information to determine where a package should be installed. +} diff --git a/man/task.Rd b/man/task.Rd index bbaedeb..c4000a7 100644 --- a/man/task.Rd +++ b/man/task.Rd @@ -4,7 +4,7 @@ \alias{task} \title{Task specification} \usage{ -task(x, ...) +task(...) } \arguments{ \item{alias}{task alias which also serves as unique identifier of the task.} From c6d853584e45cacae6a0906faa55bc2ccf2e7a5b Mon Sep 17 00:00:00 2001 From: dgkf-roche Date: Mon, 16 Sep 2024 14:30:48 -0400 Subject: [PATCH 11/62] wip: task hierarchy --- NAMESPACE | 11 ++-- R/lib.R | 2 +- R/plan.R | 73 +++++++++++++----------- R/plot.R | 3 + R/task.R | 114 ++++++++++++++++++++++--------------- R/task_graph.R | 7 +-- R/utils-pkg-source.R | 7 ++- R/utils.R | 4 ++ man/check_task.Rd | 3 +- man/custom_install_task.Rd | 3 +- man/install_task.Rd | 3 +- man/revdep_check_task.Rd | 3 +- man/task.Rd | 6 +- man/with_subtasks.Rd | 20 +++++++ 14 files changed, 162 insertions(+), 97 deletions(-) create mode 100644 R/plot.R create mode 100644 man/with_subtasks.Rd diff --git a/NAMESPACE b/NAMESPACE index 7adcab7..498c444 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -3,10 +3,11 @@ S3method("[",checked_results) S3method(as_desc,character) S3method(as_desc,check_task) +S3method(as_desc,default) S3method(as_desc,install_task) -S3method(as_desc,list) S3method(as_desc,pkg_origin_local) S3method(as_desc,pkg_origin_repo) +S3method(as_desc,subtasks_task) S3method(check_path,pkg_origin) S3method(check_path,pkg_origin_archive) S3method(check_path,pkg_origin_local) @@ -15,19 +16,17 @@ S3method(count,default) S3method(count,issues) S3method(count,potential_issues) S3method(flatten,default) -S3method(flatten,list) -S3method(format,check_task) +S3method(flatten,subtasks_task) S3method(format,filepath) -S3method(format,install_task) S3method(format,listof) S3method(format,pkg_origin) S3method(format,task) -S3method(format,tasks) S3method(format_status_line_ansi,check_process) S3method(format_status_line_ansi,default) S3method(friendly_name,check_task) S3method(friendly_name,default) S3method(friendly_name,install_task) +S3method(friendly_name,task) S3method(install_params,pkg_origin_archive) S3method(install_params,pkg_origin_local) S3method(install_params,pkg_origin_source) @@ -98,7 +97,9 @@ export(results_to_file) export(revdep_check_task) export(run) export(start_task.igraph.vs) +export(subtasks) export(task) +export(with_subtasks) import(cli) importFrom(R6,R6Class) importFrom(callr,r_process) diff --git a/R/lib.R b/R/lib.R index c7ef9ef..f6c2579 100644 --- a/R/lib.R +++ b/R/lib.R @@ -26,7 +26,7 @@ lib_loc_isolated <- function() { #' @param lib.loc A set of library locations, used as defaults for objects #' that may make use of them. #' -lib <- function(x, ..., lib.loc = c()) { # nolint: object_name_linter. +lib <- function(x, ..., lib.loc = c()) { UseMethod("lib") } diff --git a/R/plan.R b/R/plan.R index ee6a3ae..bbf6e6b 100644 --- a/R/plan.R +++ b/R/plan.R @@ -86,7 +86,7 @@ plan_rev_dep_checks <- function( return(empty_checks_df) } - unlist(recursive = FALSE, lapply( + subtasks(paste(package, "rev dep checks"), tasks = lapply( revdeps, plan_single_rev_dep_check, path = path, @@ -101,41 +101,46 @@ plan_single_rev_dep_check <- function( revdep, repos ) { - task_sets <- list() - - # development version, testing revdeps against local source - task_sets[[1]] <- list( - # isolate installation of development version - install_task( - origin = pkg_origin_local(path = path), - lib = lib_loc_isolated(), - type = "source" - ), - check_task( - origin = pkg_origin_repo(package = revdep, repos = repos), - env = DEFAULT_R_CMD_CHECK_ENVVARS, - args = DEFAULT_R_CMD_CHECK_ARGS, - build_args = DEFAULT_R_CMD_BUILD_ARGS - ) - ) - - # release version, testing revdep against repo source - if (package %in% available_packages(repos = repos)[, "Package"]) { - task_sets[[length(task_sets) + 1]] <- list( - install_task( - origin = pkg_origin_repo(package = package, repos = repos), - type = "source" + subtasks( + paste(revdep, "checks"), + tasks = Filter(Negate(is.null), list( + # development version, testing revdeps against local source + with_subtasks( + check_task( + origin = pkg_origin_repo(package = revdep, repos = repos), + env = DEFAULT_R_CMD_CHECK_ENVVARS, + args = DEFAULT_R_CMD_CHECK_ARGS, + build_args = DEFAULT_R_CMD_BUILD_ARGS + ), + list( + # isolate installation of development version + install_task( + origin = pkg_origin_local(path = path), + lib = lib_loc_isolated(), + type = "source" + ) + ) ), - check_task( - origin = pkg_origin_repo(package = revdep, repos = repos), - env = DEFAULT_R_CMD_CHECK_ENVVARS, - args = DEFAULT_R_CMD_CHECK_ARGS, - build_args = DEFAULT_R_CMD_BUILD_ARGS - ) - ) - } - task_sets + # release version, testing revdep against repo source + if (package %in% available_packages(repos = repos)[, "Package"]) { + with_subtasks( + check_task( + origin = pkg_origin_repo(package = revdep, repos = repos), + env = DEFAULT_R_CMD_CHECK_ENVVARS, + args = DEFAULT_R_CMD_CHECK_ARGS, + build_args = DEFAULT_R_CMD_BUILD_ARGS + ), + list( + install_task( + origin = pkg_origin_repo(package = package, repos = repos), + type = "source" + ) + ) + ) + } + )) + ) } rev_dep_check_tasks <- function(packages, repos, aliases, revdep) { diff --git a/R/plot.R b/R/plot.R new file mode 100644 index 0000000..accca58 --- /dev/null +++ b/R/plot.R @@ -0,0 +1,3 @@ +task_graph <- function(g) { + +} diff --git a/R/task.R b/R/task.R index 4883e52..ce3c361 100644 --- a/R/task.R +++ b/R/task.R @@ -8,6 +8,8 @@ #' #' @param alias task alias which also serves as unique identifier of the task. #' @param package \code{\link[checked]{package}} object +#' @param tasks Optional additional tasks that are pre-requisites for running +#' this task. #' #' @family tasks #' @export @@ -15,10 +17,6 @@ task <- function(...) { structure(list(...), class = "task") } -task_hash <- function(x, n = 12) { - substring(cli::hash_obj_sha256(x), 1, n) -} - #' @family tasks #' @export lib.task <- function(x, ...) { @@ -31,31 +29,50 @@ print.task <- function(x, ...) { cat(format(x, ...), "\n") } -#' @family tasks #' @export -format.task <- function(x, ...) { - if (is.list(x)) { - fmt_tasks <- lapply(x, function(xi) format(xi, ...)) - return(paste0("[", paste0(fmt_tasks, collapse = ", "), "]")) - } +format.task <- function(x, ..., indent = 0L) { + paste(collapse = "\n", c( + paste0(strrep(" ", indent * 2), "<", friendly_name(x), ">"), + vcapply(x$tasks, function(xi) format(xi, ..., indent = indent + 1)) + )) +} - NextMethod() +#' @export +friendly_name.task <- function(x) { + "task" } friendly_name <- function(x) { UseMethod("friendly_name") } -#' @family tasks #' @export friendly_name.default <- function(x) { stop( - "Dont' know how to name object with class(es) `", + "Dont' know how to name object with class(es) `", deparse(class(x)), "`" ) } +#' @family tasks +#' @export +subtasks <- function(name, tasks, ...) { + task <- task(name = name, tasks = tasks, ...) + class(task) <- c("subtasks_task", class(task)) + task +} + +#' Attach Subtasks to an Existing Task +#' +#' @family tasks +#' @export +with_subtasks <- function(task, tasks) { + task$tasks <- tasks + class(task) <- c("subtasks_task", class(task)) + task +} + #' Create a task to install a package and dependencies #' #' @param ... Additional parameters passed to [`task()`] @@ -82,12 +99,7 @@ install_task <- function( #' @export lib.install_task <- function(x, ...) { - lib(x$lib, name = task_hash(x), ...) -} - -#' @export -format.install_task <- function(x, ...) { - paste0("<", friendly_name(x), ">") + lib(x$lib, name = hash(x), ...) } #' @export @@ -132,11 +144,6 @@ lib.check_task <- function(x, ...) { character(0L) # no additional libraries needed for checkign } -#' @export -format.check_task <- function(x, ...) { - paste0("<", friendly_name(x), ">") -} - is_check_task <- function(x) { inherits(x, "check_task") } @@ -147,6 +154,10 @@ friendly_name.check_task <- function(x, ...) { paste0("check ", format(x$origin)) } +friendly_name.subtasks_task <- function(x, ...) { + if (!is.null(x$name)) x$name else NextMethod() +} + #' Create a task to run reverse dependency checks #' #' @param revdep character indicating whether the task specification describes @@ -163,42 +174,54 @@ revdep_check_task <- function(revdep, ...) { task } -tasks <- function(x) { - structure(x, class = "tasks") +# TODO: +# Convert plan to graph +# +# This can probably be avoided if we were to build a task graph from +# the start. Plans may be better represented as declarative graphs, which +# are then hydrated into imparative graphs. Then the hierarchical +# relationships are already encoded in the graph and need not be +# rediscovered by building a dependency graph post-hoc. +# +as_desc <- function(x, ...) { + UseMethod("as_desc") } #' @export -format.tasks <- function(x, ...) { - elems <- lapply(x, function(xi) format(xi, ...)) - paste0("[", paste0(elems, collapse = ", "), "]") -} - -as_desc <- function(x, ...) { - UseMethod("as_desc") +as_desc.default <- function(x, ...) { + NULL } #' @export -as_desc.list <- function(x, ...) { +as_desc.subtasks_task <- function(x, ...) { descs <- list() - length(descs) <- length(x) + length(descs) <- length(x$tasks) - for (i in seq_along(x)) { - descs[[i]] <- as_desc(x[[i]]) + for (i in seq_along(x$tasks)) { + descs[[i]] <- as_desc(x$tasks[[i]], ...) } descs <- bind_descs(descs) - descs <- sub_aliased_desc(descs) + + # if this subtask is also a task of itself, add to descriptions collection + # after substituting aliased package names in dependencies + task_desc <- NextMethod() + if (!is.null(task_desc)) { + descs <- bind_descs(list(task_desc, descs)) + descs <- sub_desc_aliases(descs) + } + descs } #' @export as_desc.install_task <- function(x, ...) { - cbind(as_desc(x$origin), Task = task_hash(x)) + cbind(as_desc(x$origin), Task = hash(x)) } #' @export as_desc.check_task <- function(x, ...) { - cbind(as_desc(x$origin), Task = task_hash(x)) + cbind(as_desc(x$origin), Task = hash(x)) } #' @export @@ -213,7 +236,7 @@ as_desc.pkg_origin_local <- function(x) { # update the Package field, replacing actual name with an alias desc <- cbind(desc, Alias = x$package) - rownames(desc) <- desc[, "Package"] <- task_hash(x) + rownames(desc) <- desc[, "Package"] <- hash(x) desc } @@ -234,8 +257,9 @@ flatten.default <- function(x) { } #' @export -flatten.list <- function(x) { - if (!inherits(x, "list")) return(x) - unlist(recursive = FALSE, lapply(x, function(xi) flatten(xi))) +flatten.subtasks_task <- function(x) { + unlist(recursive = FALSE, c( + list(list(x)), + lapply(x$tasks, function(xi) flatten(xi)) + )) } - diff --git a/R/task_graph.R b/R/task_graph.R index e2d1bf9..73ef554 100644 --- a/R/task_graph.R +++ b/R/task_graph.R @@ -43,12 +43,11 @@ task_graph_create <- function(plan, repos = getOption("repos")) { # build task hashmap, allowing for graph analysis using description files taskmap <- unique(flatten(plan)) - names(taskmap) <- vcapply(taskmap, task_hash) + names(taskmap) <- vcapply(taskmap, hash) # build supplementary database entries for package tasks # tasks receive an additional "Task" column, containing a hash of the task - desc_db <- lapply(plan, function(x) as_desc(x)) - desc_db <- unique(bind_descs(desc_db)) + desc_db <- unique(as_desc(plan)) packages <- desc_db[, "Package"] # add task package origin descriptions into database @@ -57,8 +56,6 @@ task_graph_create <- function(plan, repos = getOption("repos")) { db <- rbind(desc_db[, colnames(db)], db) db <- db[!duplicated(db[, c("Package", DB_COLNAMES)]), ] - browser() - # create dependencies graph g <- package_graph(db, packages) diff --git a/R/utils-pkg-source.R b/R/utils-pkg-source.R index 0c8b1db..338d929 100644 --- a/R/utils-pkg-source.R +++ b/R/utils-pkg-source.R @@ -64,8 +64,11 @@ get_desc_field <- function(path, field) { read.dcf(desc)[, field] } -sub_aliased_desc <- function(desc) { - if (!"Alias" %in% colnames(desc)) return(desc) +sub_desc_aliases <- function( + desc, + aliases = if ("Alias" %in% colnames(desc)) desc[, "Alias"] +) { + if (is.null(aliases)) return(desc) # create mapping from package name to aliased name has_alias <- !is.na(desc[, "Alias"]) diff --git a/R/utils.R b/R/utils.R index 698ca65..472a16a 100644 --- a/R/utils.R +++ b/R/utils.R @@ -1,6 +1,10 @@ #' @import cli NULL +hash <- function(x, n = 12) { + substring(cli::hash_obj_sha256(x), 1, n) +} + base_pkgs <- function() { c("R", utils::installed.packages(priority = "base")[, "Package"]) } diff --git a/man/check_task.Rd b/man/check_task.Rd index fb0d474..024d979 100644 --- a/man/check_task.Rd +++ b/man/check_task.Rd @@ -38,6 +38,7 @@ Other tasks: \code{\link{custom_install_task}()}, \code{\link{install_task}()}, \code{\link{revdep_check_task}()}, -\code{\link{task}()} +\code{\link{task}()}, +\code{\link{with_subtasks}()} } \concept{tasks} diff --git a/man/custom_install_task.Rd b/man/custom_install_task.Rd index 3167a90..f4b5310 100644 --- a/man/custom_install_task.Rd +++ b/man/custom_install_task.Rd @@ -34,6 +34,7 @@ Other tasks: \code{\link{check_task}()}, \code{\link{install_task}()}, \code{\link{revdep_check_task}()}, -\code{\link{task}()} +\code{\link{task}()}, +\code{\link{with_subtasks}()} } \concept{tasks} diff --git a/man/install_task.Rd b/man/install_task.Rd index 83c1338..5e0e915 100644 --- a/man/install_task.Rd +++ b/man/install_task.Rd @@ -40,6 +40,7 @@ Other tasks: \code{\link{check_task}()}, \code{\link{custom_install_task}()}, \code{\link{revdep_check_task}()}, -\code{\link{task}()} +\code{\link{task}()}, +\code{\link{with_subtasks}()} } \concept{tasks} diff --git a/man/revdep_check_task.Rd b/man/revdep_check_task.Rd index 71177bc..179dfc7 100644 --- a/man/revdep_check_task.Rd +++ b/man/revdep_check_task.Rd @@ -21,6 +21,7 @@ Other tasks: \code{\link{check_task}()}, \code{\link{custom_install_task}()}, \code{\link{install_task}()}, -\code{\link{task}()} +\code{\link{task}()}, +\code{\link{with_subtasks}()} } \concept{tasks} diff --git a/man/task.Rd b/man/task.Rd index c4000a7..1d7429f 100644 --- a/man/task.Rd +++ b/man/task.Rd @@ -10,6 +10,9 @@ task(...) \item{alias}{task alias which also serves as unique identifier of the task.} \item{package}{\code{\link[checked]{package}} object} + +\item{tasks}{Optional additional tasks that are pre-requisites for running +this task.} } \description{ Create task specification list which consists of all the details required @@ -24,6 +27,7 @@ Other tasks: \code{\link{check_task}()}, \code{\link{custom_install_task}()}, \code{\link{install_task}()}, -\code{\link{revdep_check_task}()} +\code{\link{revdep_check_task}()}, +\code{\link{with_subtasks}()} } \concept{tasks} diff --git a/man/with_subtasks.Rd b/man/with_subtasks.Rd new file mode 100644 index 0000000..b6ac8af --- /dev/null +++ b/man/with_subtasks.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/task.R +\name{with_subtasks} +\alias{with_subtasks} +\title{Attach Subtasks to an Existing Task} +\usage{ +with_subtasks(task, tasks) +} +\description{ +Attach Subtasks to an Existing Task +} +\seealso{ +Other tasks: +\code{\link{check_task}()}, +\code{\link{custom_install_task}()}, +\code{\link{install_task}()}, +\code{\link{revdep_check_task}()}, +\code{\link{task}()} +} +\concept{tasks} From 30258f910a25feb2c96fa47dc0afb90d1766ecaf Mon Sep 17 00:00:00 2001 From: dgkf-roche Date: Mon, 16 Sep 2024 17:34:42 -0400 Subject: [PATCH 12/62] wip: plan as declarative task graph --- NAMESPACE | 3 ++ R/lib.R | 5 +++ R/pkg_origin.R | 19 +++++---- R/plan.R | 102 ++++++++++++++++++++++---------------------- R/task.R | 39 +++++++++++++++++ R/task_graph.R | 52 ++++++++++++++++++++++ R/utils-deps.R | 22 ++++++++++ R/utils-igraph.R | 21 +++++++++ Rplots.pdf | Bin 0 -> 5619 bytes man/library_task.Rd | 14 ++++++ 10 files changed, 218 insertions(+), 59 deletions(-) create mode 100644 R/utils-igraph.R create mode 100644 Rplots.pdf create mode 100644 man/library_task.Rd diff --git a/NAMESPACE b/NAMESPACE index 498c444..a0d9fb0 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -18,6 +18,7 @@ S3method(count,potential_issues) S3method(flatten,default) S3method(flatten,subtasks_task) S3method(format,filepath) +S3method(format,lib_loc) S3method(format,listof) S3method(format,pkg_origin) S3method(format,task) @@ -26,6 +27,7 @@ S3method(format_status_line_ansi,default) S3method(friendly_name,check_task) S3method(friendly_name,default) S3method(friendly_name,install_task) +S3method(friendly_name,library_task) S3method(friendly_name,task) S3method(install_params,pkg_origin_archive) S3method(install_params,pkg_origin_local) @@ -40,6 +42,7 @@ S3method(lib,task) S3method(pkg_deps,default) S3method(pkg_deps,pkg_origin_archive) S3method(pkg_deps,pkg_origin_local) +S3method(plot,task_graph) S3method(print,checked_results) S3method(print,checked_results_check_task) S3method(print,checked_results_revdep_check_task) diff --git a/R/lib.R b/R/lib.R index f6c2579..cefadf3 100644 --- a/R/lib.R +++ b/R/lib.R @@ -12,6 +12,11 @@ lib_loc <- function(x = list(), .class = c()) { structure(x, class = c(.class, "lib_loc")) } +#' @export +format.lib_loc <- function(x, ...) { + "library" +} + lib_loc_default <- function() { lib_loc(.class = "lib_loc_default") } diff --git a/R/pkg_origin.R b/R/pkg_origin.R index 2a22b22..7bdc82c 100644 --- a/R/pkg_origin.R +++ b/R/pkg_origin.R @@ -16,21 +16,24 @@ pkg_origin <- function(package, ..., .class = c()) { } #' @export -format.pkg_origin <- function(x, ...) { +format.pkg_origin <- function(x, ..., short = FALSE) { paste(collapse = " ", c( - x$package, - if (!is.null(x$version)) { + if (!short) x$package, + if (!short && !is.null(x$version)) { switch(class(x$version)[[1]], package_version = paste0("(v", format(x$version), ")"), x$version ) }, if (!is.null(x$source)) { - paste0("from ", if (is.null(names(x$source))) { - format(x$source, pretty = TRUE) - } else { - names(x$source) - }) + paste0( + if (!short) "from ", + if (is.null(names(x$source))) { + format(x$source, pretty = TRUE) + } else { + names(x$source) + } + ) } )) } diff --git a/R/plan.R b/R/plan.R index bbf6e6b..abc4419 100644 --- a/R/plan.R +++ b/R/plan.R @@ -86,61 +86,61 @@ plan_rev_dep_checks <- function( return(empty_checks_df) } - subtasks(paste(package, "rev dep checks"), tasks = lapply( - revdeps, - plan_single_rev_dep_check, - path = path, - package = package, - repos = repos + g <- merge_subgraphs(c( + lapply( + revdeps, + plan_rev_dep_dev_check, + path = path, + repos = repos + ), + lapply( + revdeps[revdeps %in% ap[, "Package"]], + plan_rev_dep_release_check, + repos = repos + ) )) + + class(g) <- c("task_graph", class(g)) + g } -plan_single_rev_dep_check <- function( - path, - package, - revdep, - repos -) { - subtasks( - paste(revdep, "checks"), - tasks = Filter(Negate(is.null), list( - # development version, testing revdeps against local source - with_subtasks( - check_task( - origin = pkg_origin_repo(package = revdep, repos = repos), - env = DEFAULT_R_CMD_CHECK_ENVVARS, - args = DEFAULT_R_CMD_CHECK_ARGS, - build_args = DEFAULT_R_CMD_BUILD_ARGS - ), - list( - # isolate installation of development version - install_task( - origin = pkg_origin_local(path = path), - lib = lib_loc_isolated(), - type = "source" - ) - ) - ), - - # release version, testing revdep against repo source - if (package %in% available_packages(repos = repos)[, "Package"]) { - with_subtasks( - check_task( - origin = pkg_origin_repo(package = revdep, repos = repos), - env = DEFAULT_R_CMD_CHECK_ENVVARS, - args = DEFAULT_R_CMD_CHECK_ARGS, - build_args = DEFAULT_R_CMD_BUILD_ARGS - ), - list( - install_task( - origin = pkg_origin_repo(package = package, repos = repos), - type = "source" - ) - ) - ) - } - )) +plan_rev_dep_dev_check <- function(path, revdep, repos) { + check_revdep <- make_unique_task(seed = "dev", check_task( + origin = pkg_origin_repo(package = revdep, repos = repos), + env = DEFAULT_R_CMD_CHECK_ENVVARS, + args = DEFAULT_R_CMD_CHECK_ARGS, + build_args = DEFAULT_R_CMD_BUILD_ARGS + )) + + install_dev <- library_task( + packages = list(pkg_origin_local(path = path)), + loc = lib_loc_isolated() + ) + + install_deps <- library_task( + packages = NULL + ) + + tasks <- list(check_revdep, install_dev, install_deps) + names(tasks) <- lapply(tasks, hash) + sequence_graph(name = names(tasks), task = tasks) +} + +plan_rev_dep_release_check <- function(revdep, repos) { + check_revdep <- make_unique_task(seed = "release", check_task( + origin = pkg_origin_repo(package = revdep, repos = repos), + env = DEFAULT_R_CMD_CHECK_ENVVARS, + args = DEFAULT_R_CMD_CHECK_ARGS, + build_args = DEFAULT_R_CMD_BUILD_ARGS + )) + + install_deps <- library_task( + packages = NULL ) + + tasks <- list(check_revdep, install_deps) + names(tasks) <- lapply(tasks, hash) + sequence_graph(name = names(tasks), task = tasks) } rev_dep_check_tasks <- function(packages, repos, aliases, revdep) { diff --git a/R/task.R b/R/task.R index ce3c361..025a6ec 100644 --- a/R/task.R +++ b/R/task.R @@ -17,6 +17,11 @@ task <- function(...) { structure(list(...), class = "task") } +make_unique_task <- function(task, seed = runif(1)) { + task$id <- hash(seed) + task +} + #' @family tasks #' @export lib.task <- function(x, ...) { @@ -158,6 +163,40 @@ friendly_name.subtasks_task <- function(x, ...) { if (!is.null(x$name)) x$name else NextMethod() } +#' Specify a library install +#' +#' A declarative task that specifies a set of packages that should be installed +#' to a given location. This task is typically used during planning of checks, +#' but does not spawn a process. It is used primarily for organizing the +#' library precedence for check tasks. +#' +library_task <- function(packages, loc = lib_loc_default(), ...) { + task <- task(...) + task$packages <- packages + task$loc <- loc + class(task) <- c("library_task", class(task)) + task +} + +#' @export +friendly_name.library_task <- function(x, ...) { + fmt_pkgs <- if (is.null(x$packages)) { + "all other packages" + } else if (length(x$packages) <= 3) { + paste0( + "package(s) ", + paste0(collapse = ", ", vcapply( + x$packages, + function(pkg) format(pkg, short = TRUE) + )) + ) + } else { + paste0(length(x$packages), " packages") + } + + paste(format(x$loc), "with", fmt_pkgs) +} + #' Create a task to run reverse dependency checks #' #' @param revdep character indicating whether the task specification describes diff --git a/R/task_graph.R b/R/task_graph.R index 73ef554..68ad47c 100644 --- a/R/task_graph.R +++ b/R/task_graph.R @@ -364,3 +364,55 @@ is_package_done <- function(pkg, lib.loc) { path <- find.package(pkg, lib.loc = lib.loc, quiet = TRUE) length(path) > 0 } + +#' @export +plot.task_graph <- function(x, ...) { + color_by_task_type <- c( + "check_task" = "lightblue", + "library_task" = "lightgreen", + "install_task" = "cornflowerblue", + "red" + ) + + shape_by_task_type <- c( + "library_task" = "square", + "circle" + ) + + size_by_task_type <- c( + "install_task" = 5, + 15 + ) + + task_type <- vcapply(igraph::V(x)$task, function(task) class(task)[[1]]) + label <- vcapply(igraph::V(x)$task, function(task) friendly_name(task)) + + color <- color_by_task_type[match( + task_type, + names(color_by_task_type), + nomatch = length(color_by_task_type) + )] + + shape <- shape_by_task_type[match( + task_type, + names(shape_by_task_type), + nomatch = length(shape_by_task_type) + )] + + size <- size_by_task_type[match( + task_type, + names(size_by_task_type), + nomatch = length(size_by_task_type) + )] + + igraph::plot.igraph( + x, + vertex.label.family = "sans", + vertex.label.color = "gray4", + vertex.label.dist = 2.5, + vertex.label = label, + vertex.color = color, + vertex.shape = shape, + vertex.size = size + ) +} diff --git a/R/utils-deps.R b/R/utils-deps.R index e845891..1d0cc0a 100644 --- a/R/utils-deps.R +++ b/R/utils-deps.R @@ -49,3 +49,25 @@ as_pkg_dependencies <- function(x) { if (!is.list(x)) x <- list(x) do.call(into_deptype_list, x) } + +pkg_dependencies <- function( + packages, + dependencies = TRUE, + repos = getOption("repos") +) { + dependencies <- as_pkg_dependencies(dependencies) + unique(unlist(c( + tools::package_dependencies( + packages = packages, + db = available_packages(repos = repos), + recursive = FALSE, + which = dependencies$direct + ), + tools::package_dependencies( + packages = packages, + db = available_packages(repos = repos), + recursive = TRUE, + which = dependencies$indirect + ) + ))) +} diff --git a/R/utils-igraph.R b/R/utils-igraph.R new file mode 100644 index 0000000..83d14c7 --- /dev/null +++ b/R/utils-igraph.R @@ -0,0 +1,21 @@ +sequence_graph <- function(name, ...) { + dots <- list(...) + vertices <- data.frame(name = name) + vertices[names(dots)] <- dots + + edges <- data.frame( + from = utils::head(vertices$name, -1L), + to = utils::tail(vertices$name, -1L) + ) + + igraph::graph_from_data_frame( + edges, + vertices = vertices + ) +} + +merge_subgraphs <- function(gs) { + es <- do.call(rbind, lapply(gs, igraph::as_data_frame)) + vs <- do.call(rbind, lapply(gs, igraph::as_data_frame, what = "vertices")) + igraph::graph_from_data_frame(es, vertices = unique(vs)) +} diff --git a/Rplots.pdf b/Rplots.pdf new file mode 100644 index 0000000000000000000000000000000000000000..da0c6a54b9a81200285902e04e1fd42451ef7553 GIT binary patch literal 5619 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 literal 0 HcmV?d00001 diff --git a/man/library_task.Rd b/man/library_task.Rd new file mode 100644 index 0000000..8167979 --- /dev/null +++ b/man/library_task.Rd @@ -0,0 +1,14 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/task.R +\name{library_task} +\alias{library_task} +\title{Specify a library install} +\usage{ +library_task(packages, loc = lib_loc_default(), ...) +} +\description{ +A declarative task that specifies a set of packages that should be installed +to a given location. This task is typically used during planning of checks, +but does not spawn a process. It is used primarily for organizing the +library precedence for check tasks. +} From 1e84ac7b6ea48148d1c9ef91bf9677d9f48af222 Mon Sep 17 00:00:00 2001 From: dgkf-roche Date: Fri, 24 Jan 2025 17:10:10 -0500 Subject: [PATCH 13/62] wip: continuing task graph refactor --- NAMESPACE | 12 ++- R/checker.R | 2 +- R/lib.R | 4 +- R/next_task.R | 28 +++-- R/pkg_origin.R | 115 ++++++++++++++++++--- R/plan.R | 56 +++++----- R/plot.R | 3 - R/reporter_ansi_tty.R | 5 +- R/task.R | 51 +++------ R/task_graph.R | 206 ++++++++++++++++++++++++++----------- R/utils-igraph.R | 35 +++++-- Rplots.pdf | Bin 5619 -> 0 bytes man/check_task.Rd | 3 +- man/custom_install_task.Rd | 3 +- man/graph_project.Rd | 17 +++ man/install_task.Rd | 3 +- man/library_task.Rd | 2 +- man/pkg_origin.Rd | 6 ++ man/revdep_check_task.Rd | 3 +- man/task.Rd | 3 +- man/task_graph_create.Rd | 5 + man/task_graph_sort.Rd | 4 +- man/with_subtasks.Rd | 20 ---- 23 files changed, 379 insertions(+), 207 deletions(-) delete mode 100644 R/plot.R delete mode 100644 Rplots.pdf create mode 100644 man/graph_project.Rd delete mode 100644 man/with_subtasks.Rd diff --git a/NAMESPACE b/NAMESPACE index a0d9fb0..8b512e5 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -15,6 +15,10 @@ S3method(check_path,pkg_origin_repo) S3method(count,default) S3method(count,issues) S3method(count,potential_issues) +S3method(dep_tree,character) +S3method(dep_tree,check_task) +S3method(dep_tree,install_task) +S3method(dep_tree,pkg_origin) S3method(flatten,default) S3method(flatten,subtasks_task) S3method(format,filepath) @@ -29,9 +33,10 @@ S3method(friendly_name,default) S3method(friendly_name,install_task) S3method(friendly_name,library_task) S3method(friendly_name,task) +S3method(install_params,pkg_origin) S3method(install_params,pkg_origin_archive) S3method(install_params,pkg_origin_local) -S3method(install_params,pkg_origin_source) +S3method(install_params,pkg_origin_repo) S3method(lib,"NULL") S3method(lib,character) S3method(lib,check_task) @@ -76,6 +81,7 @@ S3method(summary,checked_results) S3method(summary,checked_results_check_task) S3method(summary,checked_results_revdep_check_task) S3method(summary,checker) +export(as_visNetwork) export(check_dev_rev_deps) export(check_dir) export(check_pkgs) @@ -90,6 +96,7 @@ export(pkg_origin) export(pkg_origin_archive) export(pkg_origin_local) export(pkg_origin_repo) +export(pkg_origin_unknown) export(plan_checks) export(plan_rev_dep_checks) export(reporter_ansi_tty) @@ -100,9 +107,8 @@ export(results_to_file) export(revdep_check_task) export(run) export(start_task.igraph.vs) -export(subtasks) export(task) -export(with_subtasks) +export(try_pkg_origin_repo) import(cli) importFrom(R6,R6Class) importFrom(callr,r_process) diff --git a/R/checker.R b/R/checker.R index 54fc520..4ec2378 100644 --- a/R/checker.R +++ b/R/checker.R @@ -106,7 +106,7 @@ checker <- R6::R6Class( private$lib.loc <- lib.loc private$repos <- repos - g <- task_graph_create(plan, repos) + g <- task_graph_create(self$plan, repos) self$graph <- task_graph_update_done(g, c(path_lib(output), lib.loc)) private$restore_complete_checks() }, diff --git a/R/lib.R b/R/lib.R index cefadf3..aee48e7 100644 --- a/R/lib.R +++ b/R/lib.R @@ -21,8 +21,8 @@ lib_loc_default <- function() { lib_loc(.class = "lib_loc_default") } -lib_loc_isolated <- function() { - lib_loc(.class = "lib_loc_isolated") +lib_loc_isolated <- function(seed = NULL) { + lib_loc(list(seed = seed), .class = "lib_loc_isolated") } #' Get Library Location diff --git a/R/next_task.R b/R/next_task.R index c0984b6..c008a2f 100644 --- a/R/next_task.R +++ b/R/next_task.R @@ -70,19 +70,19 @@ start_task.install_task <- function( lib.loc, ... ) { - spec <- task_graph_task(g, task) - install_parameters <- install_params(spec$package) - libpaths <- c(task_graph_libpaths(g, node, output), lib.loc) + task <- node$task[[1]] + install_parameters <- install_params(task$origin) + libpaths <- task_graph_libpaths(g, node, lib.loc = lib.loc) install_packages_process$new( install_parameters$package, lib = path_lib(output), libpaths = libpaths, - repos = install_parameters$repos, + repos = task$origin$repos, dependencies = FALSE, - type = spec$type, - INSTALL_opts = spec$INSTALL_opts, - log = path_package_install_log(output, spec$alias), - env = spec$env + type = task$type, + INSTALL_opts = c(), # TODO + log = path_package_install_log(output, friendly_name(task)), + env = c() # TODO ) } @@ -119,18 +119,16 @@ start_task.check_task <- function( ... ) { task <- node$task[[1]] - libpaths <- task_graph_libpaths(g, node, lib.loc = lib.loc) - browser() - path <- check_path(node$package, output = path_sources()) + path <- check_path(task$origin, output = path_sources()) check_process$new( path = path, check_dir = path_check_output(output, friendly_name(task)), libpath = libpaths, - repos = spec$package$repos, - args = spec$args, - build_args = spec$build_args, - env = spec$env + repos = task$repos, + args = task$args, + build_args = task$build_args, + env = task$env ) } diff --git a/R/pkg_origin.R b/R/pkg_origin.R index 7bdc82c..6ad8f4e 100644 --- a/R/pkg_origin.R +++ b/R/pkg_origin.R @@ -15,25 +15,28 @@ pkg_origin <- function(package, ..., .class = c()) { structure(list(package = package, ...), class = c(.class, "pkg_origin")) } +fmt_pkg_origin_source <- function(x, ...) { + if (is.null(x$source)) { + "" + } else if (is.null(names(x$source))) { + format(x$source, ..., pretty = TRUE) + } else { + names(x$source) + } +} + #' @export format.pkg_origin <- function(x, ..., short = FALSE) { paste(collapse = " ", c( - if (!short) x$package, + x$package, if (!short && !is.null(x$version)) { switch(class(x$version)[[1]], package_version = paste0("(v", format(x$version), ")"), x$version ) }, - if (!is.null(x$source)) { - paste0( - if (!short) "from ", - if (is.null(names(x$source))) { - format(x$source, pretty = TRUE) - } else { - names(x$source) - } - ) + if (!short && !is.null(x$source)) { + paste0("from ", fmt_pkg_origin_source(x)) } )) } @@ -59,6 +62,27 @@ pkg_origin_repo <- function(package, repos, ...) { ) } + +#' @export +#' @rdname pkg_origin +try_pkg_origin_repo <- function(package, repos, ...) { + if (package %in% available_packages(repos = repos)[, "Package"]) { + pkg_origin_repo(package = package, repos = repos, ...) + } else { + pkg_origin_unknown(package = package, ...) + } +} + + +#' @export +#' @rdname pkg_origin +pkg_origin_unknown <- function(package, ...) { + pkg_origin( + package = package, + .class = "pkg_origin_unknown" + ) +} + #' @export #' @rdname pkg_origin pkg_origin_local <- function(path = NULL, ...) { @@ -123,7 +147,12 @@ install_params <- function(x) { } #' @export -install_params.pkg_origin_source <- function(x) { +install_params.pkg_origin <- function(x, output, ...) { + stop(sprintf("Can't determine origin of package '%s'", x$name)) +} + +#' @export +install_params.pkg_origin_repo <- function(x) { list(package = x$name, repos = x$repos) } @@ -148,7 +177,7 @@ check_path.pkg_origin <- function(x, output, ...) { #' @export check_path.pkg_origin_repo <- function(x, output, ...) { - get_package_source(x$name, x$repos, destdir = output) + get_package_source(x$package, x$repos, destdir = output) } #' @export @@ -160,3 +189,65 @@ check_path.pkg_origin_local <- function(x, ...) { check_path.pkg_origin_archive <- function(x, ...) { x$path } + +dep_tree <- function(x, ...) { + UseMethod("dep_tree") +} + +#' @export +dep_tree.check_task <- function(x, ...) { + dep_tree(x$origin) +} + +#' @export +dep_tree.install_task <- function(x, ...) { + dep_tree(x$origin) +} + +#' @export +dep_tree.pkg_origin <- function( + x, + ..., + db = available_packages(), + dependencies = TRUE +) { + dep_tree(x$package, ..., db = db, dependencies = dependencies) +} + +#' @export +dep_tree.character <- function( + x, + ..., + db = available_packages(), + dependencies = TRUE +) { + dependencies <- as_pkg_dependencies(dependencies) + direct_deps <- tools::package_dependencies( + x, + db = db, + which = dependencies$direct, + recursive = FALSE + ) + + indirect_deps <- tools::package_dependencies( + x, + db = db, + which = dependencies$indirect, + recursive = TRUE + ) + + all_deps <- tools::package_dependencies( + unique(unlist(c(x, direct_deps, indirect_deps))), + db = db, + which = "strong", + recursive = FALSE + ) + + edges <- data.frame( + from = rep(names(all_deps), times = viapply(all_deps, length)), + to = unlist(all_deps) + ) + + igraph::graph_from_data_frame(edges) +} + diff --git a/R/plan.R b/R/plan.R index abc4419..953b0d5 100644 --- a/R/plan.R +++ b/R/plan.R @@ -105,42 +105,42 @@ plan_rev_dep_checks <- function( } plan_rev_dep_dev_check <- function(path, revdep, repos) { - check_revdep <- make_unique_task(seed = "dev", check_task( - origin = pkg_origin_repo(package = revdep, repos = repos), - env = DEFAULT_R_CMD_CHECK_ENVVARS, - args = DEFAULT_R_CMD_CHECK_ARGS, - build_args = DEFAULT_R_CMD_BUILD_ARGS - )) - - install_dev <- library_task( - packages = list(pkg_origin_local(path = path)), - loc = lib_loc_isolated() + origin <- pkg_origin_local(path = path) + + tasks <- list( + make_unique_task(seed = "dev", check_task( + origin = pkg_origin_repo(package = revdep, repos = repos), + env = DEFAULT_R_CMD_CHECK_ENVVARS, + args = DEFAULT_R_CMD_CHECK_ARGS, + build_args = DEFAULT_R_CMD_BUILD_ARGS + )), + install_task(origin = origin) ) - install_deps <- library_task( - packages = NULL + sequence_graph( + name = vcapply(tasks, hash), + task = tasks, + task_type = lapply(tasks, function(task) class(task)[[1]]), + package = c(revdep, origin$package) ) - - tasks <- list(check_revdep, install_dev, install_deps) - names(tasks) <- lapply(tasks, hash) - sequence_graph(name = names(tasks), task = tasks) } plan_rev_dep_release_check <- function(revdep, repos) { - check_revdep <- make_unique_task(seed = "release", check_task( - origin = pkg_origin_repo(package = revdep, repos = repos), - env = DEFAULT_R_CMD_CHECK_ENVVARS, - args = DEFAULT_R_CMD_CHECK_ARGS, - build_args = DEFAULT_R_CMD_BUILD_ARGS - )) - - install_deps <- library_task( - packages = NULL + tasks <- list( + make_unique_task(seed = "release", check_task( + origin = pkg_origin_repo(package = revdep, repos = repos), + env = DEFAULT_R_CMD_CHECK_ENVVARS, + args = DEFAULT_R_CMD_CHECK_ARGS, + build_args = DEFAULT_R_CMD_BUILD_ARGS + )) ) - tasks <- list(check_revdep, install_deps) - names(tasks) <- lapply(tasks, hash) - sequence_graph(name = names(tasks), task = tasks) + sequence_graph( + name = vcapply(tasks, hash), + task = tasks, + task_type = lapply(tasks, function(task) class(task)[[1]]), + package = revdep + ) } rev_dep_check_tasks <- function(packages, repos, aliases, revdep) { diff --git a/R/plot.R b/R/plot.R deleted file mode 100644 index accca58..0000000 --- a/R/plot.R +++ /dev/null @@ -1,3 +0,0 @@ -task_graph <- function(g) { - -} diff --git a/R/reporter_ansi_tty.R b/R/reporter_ansi_tty.R index b91f8cd..1f941b7 100644 --- a/R/reporter_ansi_tty.R +++ b/R/reporter_ansi_tty.R @@ -100,7 +100,8 @@ report_initialize.reporter_ansi_tty <- function( format_done = "Finished in {cli::pb_elapsed}", total = sum(igraph::V(design$graph)$type == "check"), clear = FALSE, - auto_terminate = TRUE, + auto_terminate = FALSE, + .auto_close = FALSE, .envir = reporter, ) } @@ -213,7 +214,6 @@ report_status.reporter_ansi_tty <- function(reporter, design, envir) { } n_finished <- sum(v$status[v$type == "check"] >= STATUS$done) - print(unique(v$status)) cli::cli_progress_update( set = n_finished, extra = list(message = inst_msg), @@ -224,5 +224,6 @@ report_status.reporter_ansi_tty <- function(reporter, design, envir) { #' @export report_finalize.reporter_ansi_tty <- function(reporter, design) { report_status(reporter, design) # report completions of final processes + cli::cli_progress_done(.envir = reporter) cli::ansi_show_cursor() } diff --git a/R/task.R b/R/task.R index 025a6ec..1614d44 100644 --- a/R/task.R +++ b/R/task.R @@ -37,7 +37,7 @@ print.task <- function(x, ...) { #' @export format.task <- function(x, ..., indent = 0L) { paste(collapse = "\n", c( - paste0(strrep(" ", indent * 2), "<", friendly_name(x), ">"), + paste0(strrep(" ", indent * 2), "<", friendly_name(x, ...), ">"), vcapply(x$tasks, function(xi) format(xi, ..., indent = indent + 1)) )) } @@ -47,12 +47,12 @@ friendly_name.task <- function(x) { "task" } -friendly_name <- function(x) { +friendly_name <- function(x, ...) { UseMethod("friendly_name") } #' @export -friendly_name.default <- function(x) { +friendly_name.default <- function(x, ...) { stop( "Dont' know how to name object with class(es) `", deparse(class(x)), @@ -60,24 +60,6 @@ friendly_name.default <- function(x) { ) } -#' @family tasks -#' @export -subtasks <- function(name, tasks, ...) { - task <- task(name = name, tasks = tasks, ...) - class(task) <- c("subtasks_task", class(task)) - task -} - -#' Attach Subtasks to an Existing Task -#' -#' @family tasks -#' @export -with_subtasks <- function(task, tasks) { - task$tasks <- tasks - class(task) <- c("subtasks_task", class(task)) - task -} - #' Create a task to install a package and dependencies #' #' @param ... Additional parameters passed to [`task()`] @@ -108,8 +90,8 @@ lib.install_task <- function(x, ...) { } #' @export -friendly_name.install_task <- function(x, ...) { - paste0("install ", format(x$origin)) +friendly_name.install_task <- function(x, ..., short = FALSE) { + paste0(if (!short) "install ", format(x$origin, ..., short = short)) } is_install_task <- function(x) { @@ -156,11 +138,7 @@ is_check_task <- function(x) { #' @family tasks #' @export friendly_name.check_task <- function(x, ...) { - paste0("check ", format(x$origin)) -} - -friendly_name.subtasks_task <- function(x, ...) { - if (!is.null(x$name)) x$name else NextMethod() + paste0("check ", format(x$origin, ...)) } #' Specify a library install @@ -170,9 +148,9 @@ friendly_name.subtasks_task <- function(x, ...) { #' but does not spawn a process. It is used primarily for organizing the #' library precedence for check tasks. #' -library_task <- function(packages, loc = lib_loc_default(), ...) { +library_task <- function(origins = list(), loc = lib_loc_default(), ...) { task <- task(...) - task$packages <- packages + task$origins <- origins task$loc <- loc class(task) <- c("library_task", class(task)) task @@ -180,21 +158,20 @@ library_task <- function(packages, loc = lib_loc_default(), ...) { #' @export friendly_name.library_task <- function(x, ...) { - fmt_pkgs <- if (is.null(x$packages)) { - "all other packages" - } else if (length(x$packages) <= 3) { + fmt_pkgs <- if (length(x$origins) == 0) { + } else if (length(x$origins) <= 3) { paste0( - "package(s) ", + " with ", paste0(collapse = ", ", vcapply( - x$packages, + x$origins, function(pkg) format(pkg, short = TRUE) )) ) } else { - paste0(length(x$packages), " packages") + paste0(" with ", length(x$origins), " packages") } - paste(format(x$loc), "with", fmt_pkgs) + paste0(format(x$loc), fmt_pkgs) } #' Create a task to run reverse dependency checks diff --git a/R/task_graph.R b/R/task_graph.R index 68ad47c..cc1d7d5 100644 --- a/R/task_graph.R +++ b/R/task_graph.R @@ -1,24 +1,3 @@ -# #' Create Task Graph -# #' -# #' @param df data.frame listing -# #' @param repos repositories which will be used to identify dependencies chain -# #' to run R CMD checks -# #' @return A dependency graph with vertex attributes "root" (a logical value -# #' indicating whether the package as one of the roots used to create the -# #' graph), "status" (installation status) and "order" (installation order). -# #' -# #' @keywords internal -# #' @importFrom igraph V -# task_graph_create <- function(df, repos = getOption("repos")) { -# edges <- task_graph_edges(df, repos) -# vertices <- task_graph_vertices(df, edges, repos) - -# g <- igraph::graph_from_data_frame(edges, vertices = vertices) -# igraph::V(g)$status <- STATUS$pending # nolint object_name_linter -# igraph::V(g)$process <- rep_len(list(), length(g)) -# task_graph_sort(g) -# } - #' Build task graph edges #' #' Edges describe relationships between tasks. Often, this is a dependency @@ -37,52 +16,103 @@ #' determine package relationships. #' @return A `data.frame` that can be used to build [`igraph`] edges. #' +#' @examples +#' \dontrun{ +# # requires that source code directory is for a package with revdeps +#' task_graph_create(plan_rev_dep_checks(".")) +#' } #' @keywords internal task_graph_create <- function(plan, repos = getOption("repos")) { - if (NROW(plan) == 0) return(empty_edge) - - # build task hashmap, allowing for graph analysis using description files - taskmap <- unique(flatten(plan)) - names(taskmap) <- vcapply(taskmap, hash) - - # build supplementary database entries for package tasks - # tasks receive an additional "Task" column, containing a hash of the task - desc_db <- unique(as_desc(plan)) - packages <- desc_db[, "Package"] - - # add task package origin descriptions into database - db <- available_packages(repos = repos)[, DB_COLNAMES] - db <- cbind(db, Task = NA_character_) - db <- rbind(desc_db[, colnames(db)], db) - db <- db[!duplicated(db[, c("Package", DB_COLNAMES)]), ] - - # create dependencies graph - g <- package_graph(db, packages) - - # populate install tasks for new dependencies, installing from repos - v_db_idx <- match(V(g)$name, db[, "Package"]) - V(g)$task <- taskmap[db[v_db_idx, "Task"]] - - no_task <- vlapply(V(g)$task, is.null) - is_base <- V(g)$name %in% base_pkgs() - is_known <- V(g)$name %in% db[, "Package"] - needs_install <- no_task & !is_base & is_known - - V(g)$task[needs_install] <- lapply( - V(g)$name[needs_install], - function(package) { - install_task( - origin = pkg_origin_repo(package = package, repos = repos), - lib = lib_loc_default() - ) - } + plan_tasks <- igraph::V(plan)[igraph::V(plan)$task_type == "check_task"] + plan_neighborhoods <- igraph::neighborhood( + plan, + order = length(plan), + mode = "out", + nodes = plan_tasks ) - # standardize graph fields + # for each check task in the plan, build a dependency tree and merge it + # into the existing check task subtree + plan_neighborhoods <- lapply(plan_neighborhoods, function(nh) { + subtree <- igraph::induced_subgraph(plan, nh) + deps <- dep_tree(nh[[1]]$task) + igraph::reverse_edges(deps) + + subtree <- graph_project( + x = deps, + onto = subtree, + where = c("name" = "package") + ) + + # set missing dependencies to be installed from repo + missing_task <- is.na(igraph::V(subtree)$task) + igraph::V(subtree)$task[missing_task] <- lapply( + igraph::V(subtree)$package[missing_task], + function(package) { + origin <- try_pkg_origin_repo(package = package, repos = repos) + install_task(origin = origin) + } + ) + + # re-hash tasks as vertex names (populate missing vertex names) + igraph::V(subtree)$name <- vcapply(igraph::V(subtree)$task, hash) + igraph::V(subtree)$task_type <- vcapply( + igraph::V(subtree)$task, + function(task) class(task)[[1]] + ) + + subtree + }) + + # then merge all the full check task task trees into a single graph + g <- merge_subgraphs(plan_neighborhoods) + class(g) <- c("task_graph", class(g)) + igraph::V(g)$status <- STATUS$pending igraph::V(g)$process <- rep_len(list(), length(g)) + task_graph_sort(g) +} - g +lib_node_tasks <- function(g, nodes) { + install_nodes <- igraph::adjacent_vertices(g, nodes, mode = "out") + lapply(install_nodes, function(nodes) { + nodes$task[vlapply(nodes$task, inherits, "install_task")] + }) +} + +lib_node_pkgs <- function(g, nodes) { + install_nodes <- igraph::adjacent_vertices(g, nodes, mode = "out") + lapply(install_nodes, function(nodes) { + tasks <- nodes$task[vlapply(nodes$task, inherits, "install_task")] + vcapply(tasks, function(task) task$origin$package) + }) +} + +#' Project one graph onto another +#' +#' Project graph `x` onto graph `onto`, making a single graph with merged +#' vertices where the attributes in `where` from `onto` map to the associated +#' attributes in `x` given by the names of `where`. `where` _must_ contain +#' an element called `name`, used to map vertices. +#' +#' The resulting graph will have the combined vertices and edges of both graphs. +#' +graph_project <- function(x, onto, where = c("name" = "name")) { + igraph::vertex.attributes(x)[where] <- + igraph::vertex.attributes(x)[names(where)] + + projection <- match( + igraph::V(x)$name, + igraph::vertex_attr(onto, where[["name"]]) + ) + + igraph::V(x)$name <- ifelse( + is.na(projection), + seq_along(igraph::V(x)), + igraph::V(onto)$name[projection] + ) + + merge_subgraphs(list(onto, x)) } package_graph <- function(db, packages = db[, "Package"], dependencies = TRUE) { @@ -365,12 +395,51 @@ is_package_done <- function(pkg, lib.loc) { length(path) > 0 } +#' @export +as_visNetwork <- function(x, ...) { + color_by_task_type <- c( + "check_task" = "lightblue", + "library_task" = "lightgreen", + "install_task" = "cornflowerblue", + "pkg_origin_repo" = "cornflowerblue", + "pkg_origin_unknown" = "red", + "pkg_origin_local" = "blue", + "red" + ) + + nodes <- igraph::as_data_frame(x, what = "vertices") + task_type <- vcapply(igraph::V(x)$task, function(task) { + if (inherits(task, "install_task")) return(class(task$origin)[[1]]) + class(task)[[1]] + }) + + nodes$id <- nodes$name + + nodes$label <- vcapply(igraph::V(g)$task, function(task) { + friendly_name(task, short = TRUE) + }) + + nodes$color <- color_by_task_type[match( + task_type, + names(color_by_task_type), + nomatch = length(color_by_task_type) + )] + + edges <- igraph::as_data_frame(x) + + nodes$task <- NULL # work around for visNetwork infinite recursion issue? + visNetwork::visNetwork(nodes = nodes, edges = edges) +} + #' @export plot.task_graph <- function(x, ...) { color_by_task_type <- c( "check_task" = "lightblue", "library_task" = "lightgreen", "install_task" = "cornflowerblue", + "pkg_origin_repo" = "cornflowerblue", + "pkg_origin_unknown" = "red", + "pkg_origin_local" = "blue", "red" ) @@ -381,11 +450,20 @@ plot.task_graph <- function(x, ...) { size_by_task_type <- c( "install_task" = 5, + "pkg_origin_repo" = 5, + "pkg_origin_unknown" = 5, + "pkg_origin_local" = 5, 15 ) - task_type <- vcapply(igraph::V(x)$task, function(task) class(task)[[1]]) - label <- vcapply(igraph::V(x)$task, function(task) friendly_name(task)) + task_type <- vcapply(igraph::V(x)$task, function(task) { + if (inherits(task, "install_task")) return(class(task$origin)[[1]]) + class(task)[[1]] + }) + + label <- vcapply(igraph::V(x)$task, function(task) { + friendly_name(task, short = TRUE) + }) color <- color_by_task_type[match( task_type, @@ -405,6 +483,10 @@ plot.task_graph <- function(x, ...) { nomatch = length(size_by_task_type) )] + tail_ids <- igraph::ends(x, igraph::E(x))[, 2L] + is_install <- vlapply(igraph::V(x)[tail_ids]$task, inherits, "install_task") + igraph::E(x)$weights <- (1 + !is_install * 9) + igraph::plot.igraph( x, vertex.label.family = "sans", diff --git a/R/utils-igraph.R b/R/utils-igraph.R index 83d14c7..5f7cc18 100644 --- a/R/utils-igraph.R +++ b/R/utils-igraph.R @@ -1,21 +1,38 @@ -sequence_graph <- function(name, ...) { +vertex_df <- function(name, ...) { dots <- list(...) vertices <- data.frame(name = name) vertices[names(dots)] <- dots + vertices[] <- lapply(vertices, `names<-`, NULL) + vertices +} +sequence_graph <- function(name, ...) { + vertices <- vertex_df(name = name, ...) edges <- data.frame( from = utils::head(vertices$name, -1L), to = utils::tail(vertices$name, -1L) ) - - igraph::graph_from_data_frame( - edges, - vertices = vertices - ) + igraph::graph_from_data_frame(edges, vertices = vertices) } merge_subgraphs <- function(gs) { - es <- do.call(rbind, lapply(gs, igraph::as_data_frame)) - vs <- do.call(rbind, lapply(gs, igraph::as_data_frame, what = "vertices")) - igraph::graph_from_data_frame(es, vertices = unique(vs)) + edfs <- lapply(gs, igraph::as_data_frame) + all_cols <- unique(unlist(lapply(edfs, colnames))) + edfs <- lapply(edfs, complete_columns, all_cols) + es <- unique(do.call(rbind, edfs)) + rownames(es) <- NULL + + vdfs <- lapply(gs, igraph::as_data_frame, what = "vertices") + all_cols <- unique(unlist(lapply(vdfs, colnames))) + vdfs <- lapply(vdfs, complete_columns, all_cols) + vs <- do.call(rbind, vdfs) + vs <- vs[!duplicated(vs$name), ] + rownames(vs) <- NULL + + igraph::graph_from_data_frame(es, vertices = vs) +} + +complete_columns <- function(df, cols) { + for (col in setdiff(cols, colnames(df))) df[[col]] <- NA + df[, cols] } diff --git a/Rplots.pdf b/Rplots.pdf deleted file mode 100644 index da0c6a54b9a81200285902e04e1fd42451ef7553..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5619 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 diff --git a/man/check_task.Rd b/man/check_task.Rd index 024d979..fb0d474 100644 --- a/man/check_task.Rd +++ b/man/check_task.Rd @@ -38,7 +38,6 @@ Other tasks: \code{\link{custom_install_task}()}, \code{\link{install_task}()}, \code{\link{revdep_check_task}()}, -\code{\link{task}()}, -\code{\link{with_subtasks}()} +\code{\link{task}()} } \concept{tasks} diff --git a/man/custom_install_task.Rd b/man/custom_install_task.Rd index f4b5310..3167a90 100644 --- a/man/custom_install_task.Rd +++ b/man/custom_install_task.Rd @@ -34,7 +34,6 @@ Other tasks: \code{\link{check_task}()}, \code{\link{install_task}()}, \code{\link{revdep_check_task}()}, -\code{\link{task}()}, -\code{\link{with_subtasks}()} +\code{\link{task}()} } \concept{tasks} diff --git a/man/graph_project.Rd b/man/graph_project.Rd new file mode 100644 index 0000000..481acb8 --- /dev/null +++ b/man/graph_project.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/task_graph.R +\name{graph_project} +\alias{graph_project} +\title{Project one graph onto another} +\usage{ +graph_project(x, onto, where = c(name = "name")) +} +\description{ +Project graph \code{x} onto graph \code{onto}, making a single graph with merged +vertices where the attributes in \code{where} from \code{onto} map to the associated +attributes in \code{x} given by the names of \code{where}. \code{where} \emph{must} contain +an element called \code{name}, used to map vertices. +} +\details{ +The resulting graph will have the combined vertices and edges of both graphs. +} diff --git a/man/install_task.Rd b/man/install_task.Rd index 5e0e915..83c1338 100644 --- a/man/install_task.Rd +++ b/man/install_task.Rd @@ -40,7 +40,6 @@ Other tasks: \code{\link{check_task}()}, \code{\link{custom_install_task}()}, \code{\link{revdep_check_task}()}, -\code{\link{task}()}, -\code{\link{with_subtasks}()} +\code{\link{task}()} } \concept{tasks} diff --git a/man/library_task.Rd b/man/library_task.Rd index 8167979..3eebfb7 100644 --- a/man/library_task.Rd +++ b/man/library_task.Rd @@ -4,7 +4,7 @@ \alias{library_task} \title{Specify a library install} \usage{ -library_task(packages, loc = lib_loc_default(), ...) +library_task(origins = list(), loc = lib_loc_default(), ...) } \description{ A declarative task that specifies a set of packages that should be installed diff --git a/man/pkg_origin.Rd b/man/pkg_origin.Rd index 9a8e1fd..527eea2 100644 --- a/man/pkg_origin.Rd +++ b/man/pkg_origin.Rd @@ -3,6 +3,8 @@ \name{pkg_origin} \alias{pkg_origin} \alias{pkg_origin_repo} +\alias{try_pkg_origin_repo} +\alias{pkg_origin_unknown} \alias{pkg_origin_local} \alias{pkg_origin_archive} \title{Package specification} @@ -11,6 +13,10 @@ pkg_origin(package, ..., .class = c()) pkg_origin_repo(package, repos, ...) +try_pkg_origin_repo(package, repos, ...) + +pkg_origin_unknown(package, ...) + pkg_origin_local(path = NULL, ...) pkg_origin_archive(path = NULL, ...) diff --git a/man/revdep_check_task.Rd b/man/revdep_check_task.Rd index 179dfc7..71177bc 100644 --- a/man/revdep_check_task.Rd +++ b/man/revdep_check_task.Rd @@ -21,7 +21,6 @@ Other tasks: \code{\link{check_task}()}, \code{\link{custom_install_task}()}, \code{\link{install_task}()}, -\code{\link{task}()}, -\code{\link{with_subtasks}()} +\code{\link{task}()} } \concept{tasks} diff --git a/man/task.Rd b/man/task.Rd index 1d7429f..18a65ad 100644 --- a/man/task.Rd +++ b/man/task.Rd @@ -27,7 +27,6 @@ Other tasks: \code{\link{check_task}()}, \code{\link{custom_install_task}()}, \code{\link{install_task}()}, -\code{\link{revdep_check_task}()}, -\code{\link{with_subtasks}()} +\code{\link{revdep_check_task}()} } \concept{tasks} diff --git a/man/task_graph_create.Rd b/man/task_graph_create.Rd index ab247e6..2b1407f 100644 --- a/man/task_graph_create.Rd +++ b/man/task_graph_create.Rd @@ -28,4 +28,9 @@ local or remote packages, so those are first appended to this data set prior to calculating edges. The bulk of this function serves to join this data. } +\examples{ +\dontrun{ +task_graph_create(plan_rev_dep_checks(".")) +} +} \keyword{internal} diff --git a/man/task_graph_sort.Rd b/man/task_graph_sort.Rd index 93063ab..f7dbfc0 100644 --- a/man/task_graph_sort.Rd +++ b/man/task_graph_sort.Rd @@ -7,10 +7,10 @@ task_graph_sort(g) } \arguments{ -\item{g}{A \link[igraph:make_graph]{igraph::graph}, expected to contain node attribute \code{type}.} +\item{g}{A \link[igraph:graph]{igraph::graph}, expected to contain node attribute \code{type}.} } \value{ -The \link[igraph:make_graph]{igraph::graph} \code{g}, with vertices sorted in preferred +The \link[igraph:graph]{igraph::graph} \code{g}, with vertices sorted in preferred installation order. } \description{ diff --git a/man/with_subtasks.Rd b/man/with_subtasks.Rd deleted file mode 100644 index b6ac8af..0000000 --- a/man/with_subtasks.Rd +++ /dev/null @@ -1,20 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/task.R -\name{with_subtasks} -\alias{with_subtasks} -\title{Attach Subtasks to an Existing Task} -\usage{ -with_subtasks(task, tasks) -} -\description{ -Attach Subtasks to an Existing Task -} -\seealso{ -Other tasks: -\code{\link{check_task}()}, -\code{\link{custom_install_task}()}, -\code{\link{install_task}()}, -\code{\link{revdep_check_task}()}, -\code{\link{task}()} -} -\concept{tasks} From 4836f08a4d8e8dffce605528588f6f5ab8539d07 Mon Sep 17 00:00:00 2001 From: maksymis <32574056+maksymiuks@users.noreply.github.com> Date: Tue, 23 Jul 2024 13:05:17 +0200 Subject: [PATCH 14/62] Restart CI From 68e3dcf4e89ab5e82ba6b52c3fbcc13acb4e5142 Mon Sep 17 00:00:00 2001 From: dgkf-roche Date: Wed, 29 Jan 2025 13:10:32 -0500 Subject: [PATCH 15/62] rebasing changes --- NAMESPACE | 4 +++ R/pkg_origin.R | 27 ++++++++++++++- R/plan.R | 14 +++++--- R/task.R | 40 ++++++++++++++++++++-- R/task_graph.R | 87 +++++++++++++++++++++++------------------------- R/utils-enums.R | 7 ++++ R/utils-igraph.R | 24 +++++++++++-- man/PLAN.Rd | 16 +++++++++ man/planned.Rd | 11 ++++++ 9 files changed, 175 insertions(+), 55 deletions(-) create mode 100644 man/PLAN.Rd create mode 100644 man/planned.Rd diff --git a/NAMESPACE b/NAMESPACE index 8b512e5..56a0803 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -28,6 +28,7 @@ S3method(format,pkg_origin) S3method(format,task) S3method(format_status_line_ansi,check_process) S3method(format_status_line_ansi,default) +S3method(friendly_class,task) S3method(friendly_name,check_task) S3method(friendly_name,default) S3method(friendly_name,install_task) @@ -37,6 +38,9 @@ S3method(install_params,pkg_origin) S3method(install_params,pkg_origin_archive) S3method(install_params,pkg_origin_local) S3method(install_params,pkg_origin_repo) +S3method(is_type,list) +S3method(is_type,process) +S3method(is_type,task) S3method(lib,"NULL") S3method(lib,character) S3method(lib,check_task) diff --git a/R/pkg_origin.R b/R/pkg_origin.R index 6ad8f4e..3f2ff0b 100644 --- a/R/pkg_origin.R +++ b/R/pkg_origin.R @@ -66,7 +66,9 @@ pkg_origin_repo <- function(package, repos, ...) { #' @export #' @rdname pkg_origin try_pkg_origin_repo <- function(package, repos, ...) { - if (package %in% available_packages(repos = repos)[, "Package"]) { + if (isTRUE(pkg_origin_is_base(package))) { + return(pkg_origin_base(package, ...)) + } else if (package %in% available_packages(repos = repos)[, "Package"]) { pkg_origin_repo(package = package, repos = repos, ...) } else { pkg_origin_unknown(package = package, ...) @@ -74,6 +76,24 @@ try_pkg_origin_repo <- function(package, repos, ...) { } +#' @export +#' @rdname pkg_origin +pkg_origin_is_base <- function(package, ...) { + package %in% installed.packages()[, "Package"] && + installed.packages()[package, "Priority"] == "base" +} + + +#' @export +#' @rdname pkg_origin +pkg_origin_base <- function(package, ...) { + pkg_origin( + package = package, + .class = "pkg_origin_base" + ) +} + + #' @export #' @rdname pkg_origin pkg_origin_unknown <- function(package, ...) { @@ -151,6 +171,11 @@ install_params.pkg_origin <- function(x, output, ...) { stop(sprintf("Can't determine origin of package '%s'", x$name)) } +#' @export +install_params.pkg_origin_base <- function(x) { + list() # no installation needed, distributed with R +} + #' @export install_params.pkg_origin_repo <- function(x) { list(package = x$name, repos = x$repos) diff --git a/R/plan.R b/R/plan.R index 953b0d5..9525f7d 100644 --- a/R/plan.R +++ b/R/plan.R @@ -30,6 +30,12 @@ empty_checks_df <- data.frame( #' @name plan NULL +#' Tag edges as 'planned' +planned <- function(graph) { + igraph::E(graph)$plan <- PLAN$planned + graph +} + #' Plan Reverse Dependency Checks #' #' Generates a plan for running reverse dependency check for certain @@ -117,12 +123,12 @@ plan_rev_dep_dev_check <- function(path, revdep, repos) { install_task(origin = origin) ) - sequence_graph( + planned(sequence_graph( name = vcapply(tasks, hash), task = tasks, task_type = lapply(tasks, function(task) class(task)[[1]]), package = c(revdep, origin$package) - ) + )) } plan_rev_dep_release_check <- function(revdep, repos) { @@ -135,12 +141,12 @@ plan_rev_dep_release_check <- function(revdep, repos) { )) ) - sequence_graph( + planned(sequence_graph( name = vcapply(tasks, hash), task = tasks, task_type = lapply(tasks, function(task) class(task)[[1]]), package = revdep - ) + )) } rev_dep_check_tasks <- function(packages, repos, aliases, revdep) { diff --git a/R/task.R b/R/task.R index 1614d44..63d68ed 100644 --- a/R/task.R +++ b/R/task.R @@ -60,6 +60,19 @@ friendly_name.default <- function(x, ...) { ) } +#' @export +friendly_class.task <- function(x) { + if (length(class(x)) > 1) { + sub("_task$", "", class(x)[[1]]) + } else { + class(x)[[1]] + } +} + +friendly_class <- function(x, ...) { + UseMethod("friendly_class") +} + #' Create a task to install a package and dependencies #' #' @param ... Additional parameters passed to [`task()`] @@ -94,8 +107,31 @@ friendly_name.install_task <- function(x, ..., short = FALSE) { paste0(if (!short) "install ", format(x$origin, ..., short = short)) } -is_install_task <- function(x) { - inherits(x, "install_task") +is_type <- function(x, type) { + UseMethod("is_type") +} + +#' @export +is_type.list <- function(x, type) { + vlapply(x, is_type, type = type) +} + +#' @export +is_type.task <- function(x, type) { + inherits(x, paste0(type, "_task")) +} + +#' @export +is_type.process <- function(x, type) { + inherits(x, paste0(type, "_process")) +} + +is_install <- function(x) { + is_type(x, "install") +} + +is_check <- function(x) { + is_type(x, "check") } #' Create a custom install task diff --git a/R/task_graph.R b/R/task_graph.R index cc1d7d5..7209a6d 100644 --- a/R/task_graph.R +++ b/R/task_graph.R @@ -70,20 +70,22 @@ task_graph_create <- function(plan, repos = getOption("repos")) { igraph::V(g)$status <- STATUS$pending igraph::V(g)$process <- rep_len(list(), length(g)) + igraph::E(g)$plan[is.na(igraph::E(g)$plan)] <- PLAN$inferred + task_graph_sort(g) } lib_node_tasks <- function(g, nodes) { install_nodes <- igraph::adjacent_vertices(g, nodes, mode = "out") lapply(install_nodes, function(nodes) { - nodes$task[vlapply(nodes$task, inherits, "install_task")] + nodes$task[is_install(nodes$task)] }) } lib_node_pkgs <- function(g, nodes) { install_nodes <- igraph::adjacent_vertices(g, nodes, mode = "out") lapply(install_nodes, function(nodes) { - tasks <- nodes$task[vlapply(nodes$task, inherits, "install_task")] + tasks <- nodes$task[is_install(nodes$task)] vcapply(tasks, function(task) task$origin$package) }) } @@ -322,7 +324,7 @@ task_graph_which_check_satisfied <- function( ) { task_graph_which_satisfied( g, - igraph::V(g)[vlapply(igraph::V(g)$task, inherits, "check_task")], + igraph::V(g)[vlapply(igraph::V(g)$task, is_check)], ..., dependencies = dependencies, status = status @@ -337,7 +339,7 @@ task_graph_which_install_satisfied <- function( ) { task_graph_which_satisfied( g, - igraph::V(g)[vlapply(igraph::V(g)$task, inherits, "install_task")], + igraph::V(g)[is_install(igraph::V(g)$task)], ..., dependencies = dependencies, status = status @@ -386,7 +388,7 @@ task_graph_set_task_process <- function(g, v, process) { task_graph_update_done <- function(g, lib.loc) { v <- igraph::V(g)[igraph::V(g)$type == "install"] - which_done <- which(vlapply(v$name, is_package_done, lib.loc = lib.loc)) + which_done <- which(vlapply(v$name, is_package_installed, lib.loc = lib.loc)) task_graph_set_package_status(g, v[which_done], STATUS$done) } @@ -409,7 +411,7 @@ as_visNetwork <- function(x, ...) { nodes <- igraph::as_data_frame(x, what = "vertices") task_type <- vcapply(igraph::V(x)$task, function(task) { - if (inherits(task, "install_task")) return(class(task$origin)[[1]]) + if (is_install(task)) return(class(task$origin)[[1]]) class(task)[[1]] }) @@ -433,68 +435,63 @@ as_visNetwork <- function(x, ...) { #' @export plot.task_graph <- function(x, ...) { - color_by_task_type <- c( + style <- function(attr, ...) { + map <- simplify2array(list(...)) + nomatch <- if (names(map[length(map)]) == "") length(map) else NA + map[match(attr, names(map), nomatch = nomatch)] + } + + task_type <- vcapply(igraph::V(x)$task, function(task) { + if (is_install(task)) return(class(task$origin)[[1]]) + class(task)[[1]] + }) + + vertex.color <- style( + task_type, "check_task" = "lightblue", "library_task" = "lightgreen", "install_task" = "cornflowerblue", "pkg_origin_repo" = "cornflowerblue", + "pkg_origin_base" = "lightgray", "pkg_origin_unknown" = "red", "pkg_origin_local" = "blue", "red" ) - shape_by_task_type <- c( - "library_task" = "square", - "circle" + vertex.label <- vcapply( + igraph::V(x)$task, + friendly_name, + short = TRUE ) - size_by_task_type <- c( + vertex.size <- style( + task_type, "install_task" = 5, "pkg_origin_repo" = 5, "pkg_origin_unknown" = 5, "pkg_origin_local" = 5, - 15 + "pkg_origin_base" = 5, + 8 ) - task_type <- vcapply(igraph::V(x)$task, function(task) { - if (inherits(task, "install_task")) return(class(task$origin)[[1]]) - class(task)[[1]] - }) - - label <- vcapply(igraph::V(x)$task, function(task) { - friendly_name(task, short = TRUE) - }) - - color <- color_by_task_type[match( - task_type, - names(color_by_task_type), - nomatch = length(color_by_task_type) - )] - - shape <- shape_by_task_type[match( - task_type, - names(shape_by_task_type), - nomatch = length(shape_by_task_type) - )] - - size <- size_by_task_type[match( - task_type, - names(size_by_task_type), - nomatch = length(size_by_task_type) - )] + edge.lty <- style( + igraph::E(x)$plan, + "planned" = 1, # solid + "inferred" = 3 # dotted + ) tail_ids <- igraph::ends(x, igraph::E(x))[, 2L] - is_install <- vlapply(igraph::V(x)[tail_ids]$task, inherits, "install_task") - igraph::E(x)$weights <- (1 + !is_install * 9) + is_inst <- is_install(igraph::V(x)[tail_ids]$task) + igraph::E(x)$weights <- 1 + !is_inst * 9 igraph::plot.igraph( x, vertex.label.family = "sans", vertex.label.color = "gray4", - vertex.label.dist = 2.5, - vertex.label = label, - vertex.color = color, - vertex.shape = shape, - vertex.size = size + vertex.label.dist = 1, + vertex.label = vertex.label, + vertex.color = vertex.color, + vertex.size = vertex.size, + edge.lty = edge.lty ) } diff --git a/R/utils-enums.R b/R/utils-enums.R index 5467886..5075c69 100644 --- a/R/utils-enums.R +++ b/R/utils-enums.R @@ -33,6 +33,13 @@ STATUS <- enum( "done" ) +#' Check execution status categories +#' @keywords internal +PLAN <- enum( + "planned", + "inferred" +) + #' Dependencies categories #' @keywords internal DEP <- enum( diff --git a/R/utils-igraph.R b/R/utils-igraph.R index 5f7cc18..d51adb2 100644 --- a/R/utils-igraph.R +++ b/R/utils-igraph.R @@ -16,20 +16,38 @@ sequence_graph <- function(name, ...) { } merge_subgraphs <- function(gs) { - edfs <- lapply(gs, igraph::as_data_frame) + # NOTE: igraph::as_data_frame will coerce factor variables to character + edfs <- lapply(gs, function(g) { + df <- igraph::as_data_frame(g) + attrs <- igraph::edge.attributes(g) + df[names(attrs)] <- attrs + df + }) + all_cols <- unique(unlist(lapply(edfs, colnames))) edfs <- lapply(edfs, complete_columns, all_cols) es <- unique(do.call(rbind, edfs)) rownames(es) <- NULL - vdfs <- lapply(gs, igraph::as_data_frame, what = "vertices") + vdfs <- lapply(gs, function(g) { + df <- igraph::as_data_frame(g, what = "vertices") + attrs <- igraph::vertex.attributes(g) + df[names(attrs)] <- attrs + df + }) + all_cols <- unique(unlist(lapply(vdfs, colnames))) vdfs <- lapply(vdfs, complete_columns, all_cols) vs <- do.call(rbind, vdfs) vs <- vs[!duplicated(vs$name), ] rownames(vs) <- NULL - igraph::graph_from_data_frame(es, vertices = vs) + g <- igraph::graph_from_data_frame(es, vertices = vs) + + igraph::vertex.attributes(g) <- vs + igraph::edge.attributes(g) <- es[, -(1:2), drop = FALSE] + + g } complete_columns <- function(df, cols) { diff --git a/man/PLAN.Rd b/man/PLAN.Rd new file mode 100644 index 0000000..4455be3 --- /dev/null +++ b/man/PLAN.Rd @@ -0,0 +1,16 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils-enums.R +\docType{data} +\name{PLAN} +\alias{PLAN} +\title{Check execution status categories} +\format{ +An object of class \code{list} of length 2. +} +\usage{ +PLAN +} +\description{ +Check execution status categories +} +\keyword{internal} diff --git a/man/planned.Rd b/man/planned.Rd new file mode 100644 index 0000000..41192a4 --- /dev/null +++ b/man/planned.Rd @@ -0,0 +1,11 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/plan.R +\name{planned} +\alias{planned} +\title{Tag edges as 'planned'} +\usage{ +planned(graph) +} +\description{ +Tag edges as 'planned' +} From fb1f36701b55abaf75e6bb400e92ce4fe1db6c6a Mon Sep 17 00:00:00 2001 From: dgkf-roche Date: Fri, 24 Jan 2025 17:02:49 -0500 Subject: [PATCH 16/62] wip: continuing task graph refactor --- NAMESPACE | 3 +++ R/task_graph.R | 2 +- man/pkg_origin.Rd | 6 ++++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/NAMESPACE b/NAMESPACE index 56a0803..3265afe 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -36,6 +36,7 @@ S3method(friendly_name,library_task) S3method(friendly_name,task) S3method(install_params,pkg_origin) S3method(install_params,pkg_origin_archive) +S3method(install_params,pkg_origin_base) S3method(install_params,pkg_origin_local) S3method(install_params,pkg_origin_repo) S3method(is_type,list) @@ -98,6 +99,8 @@ export(new_checker) export(new_rev_dep_checker) export(pkg_origin) export(pkg_origin_archive) +export(pkg_origin_base) +export(pkg_origin_is_base) export(pkg_origin_local) export(pkg_origin_repo) export(pkg_origin_unknown) diff --git a/R/task_graph.R b/R/task_graph.R index 7209a6d..e4816f4 100644 --- a/R/task_graph.R +++ b/R/task_graph.R @@ -411,7 +411,7 @@ as_visNetwork <- function(x, ...) { nodes <- igraph::as_data_frame(x, what = "vertices") task_type <- vcapply(igraph::V(x)$task, function(task) { - if (is_install(task)) return(class(task$origin)[[1]]) + if (inherits(task, "install_task")) return(class(task$origin)[[1]]) class(task)[[1]] }) diff --git a/man/pkg_origin.Rd b/man/pkg_origin.Rd index 527eea2..f6a2432 100644 --- a/man/pkg_origin.Rd +++ b/man/pkg_origin.Rd @@ -4,6 +4,8 @@ \alias{pkg_origin} \alias{pkg_origin_repo} \alias{try_pkg_origin_repo} +\alias{pkg_origin_is_base} +\alias{pkg_origin_base} \alias{pkg_origin_unknown} \alias{pkg_origin_local} \alias{pkg_origin_archive} @@ -15,6 +17,10 @@ pkg_origin_repo(package, repos, ...) try_pkg_origin_repo(package, repos, ...) +pkg_origin_is_base(package, ...) + +pkg_origin_base(package, ...) + pkg_origin_unknown(package, ...) pkg_origin_local(path = NULL, ...) From 4e438d830fd891a7ef0a5bd2e137841220a0d0ff Mon Sep 17 00:00:00 2001 From: dgkf-roche Date: Tue, 28 Jan 2025 18:15:13 -0500 Subject: [PATCH 17/62] wip: getting reporters working --- NEWS.md | 2 +- R/checker.R | 21 +++++++++++++++++---- R/install.R | 8 ++++---- R/next_task.R | 19 ++++++++++++++++--- R/plan.R | 4 ++-- R/reporter_ansi_tty.R | 14 +++----------- R/reporter_basic_tty.R | 21 ++++++++++++++------- R/run.R | 2 +- R/task_graph.R | 7 +------ R/utils-igraph.R | 1 + R/utils.R | 9 +++++++++ 11 files changed, 69 insertions(+), 39 deletions(-) diff --git a/NEWS.md b/NEWS.md index b327284..dd6fbc7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -15,7 +15,7 @@ * Add tests for the reverse dependency check use case. -* Make `install_packages_process` capture session's `available_packages_filters` +* Make `install_process` capture session's `available_packages_filters` and reuse them when installing packages to ensure consistency with the main session filtering. diff --git a/R/checker.R b/R/checker.R index 4ec2378..21316be 100644 --- a/R/checker.R +++ b/R/checker.R @@ -176,6 +176,11 @@ checker <- R6::R6Class( lib.loc = private$lib.loc ) + if (is.null(process)) { + private$finish_task(next_task) + return(1L) + } + success <- private$push_process(next_task, process) return(as.integer(success)) } @@ -189,8 +194,8 @@ checker <- R6::R6Class( #' #' Checks whether all the scheduled tasks were successfully executed. is_done = function() { - is_check <- vlapply(igraph::V(self$graph)$task, inherits, "check_task") - checks <- igraph::V(self$graph)[is_check] + is_check_node <- is_check(igraph::V(self$graph)$task) + checks <- igraph::V(self$graph)[is_check_node] all(checks$status == STATUS$done) } ), @@ -210,16 +215,24 @@ checker <- R6::R6Class( # failed tasks failed = list(), + start_task = function(task) { + task_graph_package_status(self$graph, task) <- STATUS$`in progress` + }, + + finish_task = function(task) { + task_graph_package_status(self$graph, task) <- STATUS$`done` + }, + push_process = function(task, x) { task_graph_task_process(self$graph, task) <- x name <- task_graph_task_name(self$graph, task) - task_graph_package_status(self$graph, task) <- STATUS$`in progress` + private$start_task(task) x$set_finisher(function(process) { if (process$get_r_exit_status() != 0) { private$failed[[name]] <- task } private$pop_process(name) - task_graph_package_status(self$graph, task) <- STATUS$done + private$finish_task(task) }) private$active[[name]] <- x TRUE diff --git a/R/install.R b/R/install.R index acd4d6a..f7afb1b 100644 --- a/R/install.R +++ b/R/install.R @@ -1,8 +1,8 @@ #' @importFrom utils packageName install.packages #' @importFrom R6 R6Class #' @importFrom callr r_process -install_packages_process <- R6::R6Class( - "install_package_process", +install_process <- R6::R6Class( + "install_process", inherit = callr::r_process, public = list( log = NULL, @@ -28,14 +28,14 @@ install_packages_process <- R6::R6Class( ) }, args = list( - pkgs, + private$package, ..., lib = lib, escalate_warning = is_install_failure_warning, available_packages_filters = available_packages_filters ), libpath = libpaths, - stdout = log, + stdout = self$log, stderr = "2>&1", system_profile = TRUE ) diff --git a/R/next_task.R b/R/next_task.R index c008a2f..1b42332 100644 --- a/R/next_task.R +++ b/R/next_task.R @@ -73,7 +73,16 @@ start_task.install_task <- function( task <- node$task[[1]] install_parameters <- install_params(task$origin) libpaths <- task_graph_libpaths(g, node, lib.loc = lib.loc) - install_packages_process$new( + + if (inherits(task$origin, "pkg_origin_base")) { + return(NULL) + } + + if (is_package_installed(install_parameters$package, libpaths)) { + return(NULL) + } + + install_process$new( install_parameters$package, lib = path_lib(output), libpaths = libpaths, @@ -97,7 +106,7 @@ start_task.custom_install_task <- function( spec <- task_graph_task(g, task) install_parameters <- install_params(spec$package) libpaths <- c(task_get_lib_loc(g, node, output), lib.loc) - install_packages_process$new( + install_process$new( install_parameters$package, lib = path_custom_lib(output, spec$alias), libpaths = libpaths, @@ -122,9 +131,13 @@ start_task.check_task <- function( libpaths <- task_graph_libpaths(g, node, lib.loc = lib.loc) path <- check_path(task$origin, output = path_sources()) + # TODO: make output directory names more user-friendly, for now the vertex + # hash id is used to disambiguate output + output_dirname <- paste0(friendly_name(task), " <", node$name[[1]], ">") + check_process$new( path = path, - check_dir = path_check_output(output, friendly_name(task)), + check_dir = path_check_output(output, output_dirname), libpath = libpaths, repos = task$repos, args = task$args, diff --git a/R/plan.R b/R/plan.R index 9525f7d..47dc1fc 100644 --- a/R/plan.R +++ b/R/plan.R @@ -124,7 +124,7 @@ plan_rev_dep_dev_check <- function(path, revdep, repos) { ) planned(sequence_graph( - name = vcapply(tasks, hash), + name = hashes(tasks), task = tasks, task_type = lapply(tasks, function(task) class(task)[[1]]), package = c(revdep, origin$package) @@ -142,7 +142,7 @@ plan_rev_dep_release_check <- function(revdep, repos) { ) planned(sequence_graph( - name = vcapply(tasks, hash), + name = hashes(tasks), task = tasks, task_type = lapply(tasks, function(task) class(task)[[1]]), package = revdep diff --git a/R/reporter_ansi_tty.R b/R/reporter_ansi_tty.R index 1f941b7..c012cee 100644 --- a/R/reporter_ansi_tty.R +++ b/R/reporter_ansi_tty.R @@ -110,13 +110,10 @@ report_initialize.reporter_ansi_tty <- function( #' @export report_status.reporter_ansi_tty <- function(reporter, design, envir) { v <- igraph::V(design$graph) - v_checks <- v[v$type == "check"] + v_checks <- v[is_check(v$task)] n_char_titles <- max(nchar(v_checks$name), 0) failed_tasks <- design$failed_tasks() - failed_packages <- failed_tasks[vlapply( - failed_tasks, - function(x) x$type == "install" - )] + failed_packages <- failed_tasks[is_install(failed_tasks)] # add newly started task status new_idx <- which(v_checks$status > STATUS$pending) @@ -200,12 +197,7 @@ report_status.reporter_ansi_tty <- function(reporter, design, envir) { cat(paste0(buffer, reporter$failures_buffer)) - is_inst <- vlapply( - design$active_processes(), - inherits, - "install_package_process" - ) - + is_inst <- is_install(design$active_processes()) inst_pkgs <- names(design$active_processes()[is_inst]) if (length(inst_pkgs)) { inst_msg <- paste0("installing ", paste0(inst_pkgs, collapse = ", ")) diff --git a/R/reporter_basic_tty.R b/R/reporter_basic_tty.R index 6a95259..dc73453 100644 --- a/R/reporter_basic_tty.R +++ b/R/reporter_basic_tty.R @@ -48,29 +48,36 @@ report_status.reporter_basic_tty <- function(reporter, design, envir) { dur <- if (!is.null(p$get_duration)) { p$get_duration() } - if (node$type == "check") { + + if (is_check(node$task)) { ewn <- c("ERROR", "WARNING", "NOTE") ewn <- table(p$get_checks())[ewn] } else { ewn <- c(0, 0, 0) } + + fmt_error <- "{.err {ewn[[1]]} ERROR{?/S}}" + fmt_warning <- "{.warn {ewn[[2]]} WARNING{?/S}}" + fmt_note <- "{.note {ewn[[3]]} NOTE{?/S}}" + fmt_duration <- " {.time_taken ({format_time(dur)})}" cli::cli_fmt(cli::cli_text( "finished", if (sum(ewn) > 0) " with ", paste(collapse = ", ", c( - if (ewn[[1]] > 0) cli::format_inline("{.err {ewn[[1]]} ERROR{?/S}}"), - if (ewn[[2]] > 0) cli::format_inline("{.warn {ewn[[2]]} WARNING{?/S}}"), - if (ewn[[3]] > 0) cli::format_inline("{.note {ewn[[3]]} NOTE{?/S}}") + if (ewn[[1]] > 0) cli::format_inline(fmt_error), + if (ewn[[2]] > 0) cli::format_inline(fmt_warning), + if (ewn[[3]] > 0) cli::format_inline(fmt_note) )), - if (!is.null(dur)) cli::format_inline(" {.time_taken ({format_time(dur)})}") + if (!is.null(dur)) cli::format_inline(fmt_duration) )) } } ) time <- Sys.time() - reporter$time_start # nolint (used via glue) - prefix <- cli::col_cyan("[{format_time(time)}][{node$type}] ") - cli::cli_text(prefix, "{.pkg {node$name}} {status}") + type <- friendly_class(node$task) # nolint (used via glue) + prefix <- cli::col_cyan("[{format_time(time)}][{type}] ") + cli::cli_text(prefix, "{.pkg {node$package}} {status}") reporter$statuses[[node$name]] <- node$status } } diff --git a/R/run.R b/R/run.R index 4a79d9b..636148c 100644 --- a/R/run.R +++ b/R/run.R @@ -30,7 +30,7 @@ run.checker <- function(checker, ..., reporter = reporter_default()) { }) report_initialize(reporter, checker) - while (checker$start_next_task() >= 0) { + while (checker$step()) { report_status(reporter, checker) report_sleep(reporter, checker) } diff --git a/R/task_graph.R b/R/task_graph.R index e4816f4..c378fbe 100644 --- a/R/task_graph.R +++ b/R/task_graph.R @@ -392,11 +392,6 @@ task_graph_update_done <- function(g, lib.loc) { task_graph_set_package_status(g, v[which_done], STATUS$done) } -is_package_done <- function(pkg, lib.loc) { - path <- find.package(pkg, lib.loc = lib.loc, quiet = TRUE) - length(path) > 0 -} - #' @export as_visNetwork <- function(x, ...) { color_by_task_type <- c( @@ -411,7 +406,7 @@ as_visNetwork <- function(x, ...) { nodes <- igraph::as_data_frame(x, what = "vertices") task_type <- vcapply(igraph::V(x)$task, function(task) { - if (inherits(task, "install_task")) return(class(task$origin)[[1]]) + if (is_install(task)) return(class(task$origin)[[1]]) class(task)[[1]] }) diff --git a/R/utils-igraph.R b/R/utils-igraph.R index d51adb2..87e1fb7 100644 --- a/R/utils-igraph.R +++ b/R/utils-igraph.R @@ -44,6 +44,7 @@ merge_subgraphs <- function(gs) { g <- igraph::graph_from_data_frame(es, vertices = vs) + # re-assign vertex and edge attributes to preserve class igraph::vertex.attributes(g) <- vs igraph::edge.attributes(g) <- es[, -(1:2), drop = FALSE] diff --git a/R/utils.R b/R/utils.R index 472a16a..5cefbcc 100644 --- a/R/utils.R +++ b/R/utils.R @@ -5,10 +5,19 @@ hash <- function(x, n = 12) { substring(cli::hash_obj_sha256(x), 1, n) } +hashes <- function(x, ...) { + vcapply(x, hash, ...) +} + base_pkgs <- function() { c("R", utils::installed.packages(priority = "base")[, "Package"]) } +is_package_installed <- function(pkg, lib.loc = .libPaths()) { + path <- find.package(pkg, lib.loc = lib.loc, quiet = TRUE) + length(path) > 0 +} + .callr <- as.list(getNamespace("callr"), all.names = TRUE)[c( "default_load_hook" )] From 99d7746aaaf8666db711bc25f6497496b8f647db Mon Sep 17 00:00:00 2001 From: dgkf-roche Date: Wed, 29 Jan 2025 10:12:25 -0500 Subject: [PATCH 18/62] wip: getting reporters working --- NOTES.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 NOTES.md diff --git a/NOTES.md b/NOTES.md new file mode 100644 index 0000000..45439f1 --- /dev/null +++ b/NOTES.md @@ -0,0 +1,3 @@ +# Considering + +* moving task class into a separate vector attribute From 958204de724cc2865e720027387b30c90c688615 Mon Sep 17 00:00:00 2001 From: dgkf-roche Date: Wed, 29 Jan 2025 18:55:28 -0500 Subject: [PATCH 19/62] produce dependency tree instead of dependency list --- R/pkg_origin.R | 40 ++++++------------------- R/task_graph.R | 9 ++++-- R/utils-deps.R | 66 ++++++++++++++++++++++++++++++++--------- R/utils-igraph.R | 9 ++++-- man/pkg_dependencies.Rd | 18 +++++++++++ 5 files changed, 92 insertions(+), 50 deletions(-) create mode 100644 man/pkg_dependencies.Rd diff --git a/R/pkg_origin.R b/R/pkg_origin.R index 3f2ff0b..006c796 100644 --- a/R/pkg_origin.R +++ b/R/pkg_origin.R @@ -221,12 +221,12 @@ dep_tree <- function(x, ...) { #' @export dep_tree.check_task <- function(x, ...) { - dep_tree(x$origin) + dep_tree(x$origin, ...) } #' @export dep_tree.install_task <- function(x, ...) { - dep_tree(x$origin) + dep_tree(x$origin, ...) } #' @export @@ -246,33 +246,11 @@ dep_tree.character <- function( db = available_packages(), dependencies = TRUE ) { - dependencies <- as_pkg_dependencies(dependencies) - direct_deps <- tools::package_dependencies( - x, - db = db, - which = dependencies$direct, - recursive = FALSE - ) - - indirect_deps <- tools::package_dependencies( - x, - db = db, - which = dependencies$indirect, - recursive = TRUE - ) - - all_deps <- tools::package_dependencies( - unique(unlist(c(x, direct_deps, indirect_deps))), - db = db, - which = "strong", - recursive = FALSE - ) - - edges <- data.frame( - from = rep(names(all_deps), times = viapply(all_deps, length)), - to = unlist(all_deps) - ) - - igraph::graph_from_data_frame(edges) + df <- pkg_dependencies(x, dependencies = dependencies, db = db, ...) + colmap <- c("package" = "from", "name" = "to") + rename <- match(names(df), names(colmap)) + to_rename <- !is.na(rename) + names(df)[to_rename] <- colmap[rename[to_rename]] + df <- df[, c(which(to_rename), which(!to_rename)), drop = FALSE] + igraph::graph_from_data_frame(df) } - diff --git a/R/task_graph.R b/R/task_graph.R index c378fbe..1fcc1ec 100644 --- a/R/task_graph.R +++ b/R/task_graph.R @@ -477,7 +477,7 @@ plot.task_graph <- function(x, ...) { tail_ids <- igraph::ends(x, igraph::E(x))[, 2L] is_inst <- is_install(igraph::V(x)[tail_ids]$task) - igraph::E(x)$weights <- 1 + !is_inst * 9 + is_check <- is_check(igraph::V(x)$task) igraph::plot.igraph( x, @@ -487,6 +487,11 @@ plot.task_graph <- function(x, ...) { vertex.label = vertex.label, vertex.color = vertex.color, vertex.size = vertex.size, - edge.lty = edge.lty + edge.lty = edge.lty, + layout = igraph::layout_with_sugiyama( + x, + hgap = 200, + maxiter = 1000 + ) ) } diff --git a/R/utils-deps.R b/R/utils-deps.R index 1d0cc0a..8a24b95 100644 --- a/R/utils-deps.R +++ b/R/utils-deps.R @@ -50,24 +50,62 @@ as_pkg_dependencies <- function(x) { do.call(into_deptype_list, x) } +#' Build Package Dependencies Table +#' +#' Inspired by `tools::package_dependencies`, but with the added benefit +#' of recording the dependency type and relationships throughout the +#' dependency tree. +#' pkg_dependencies <- function( packages, dependencies = TRUE, - repos = getOption("repos") + db = available.packages(), + verbose = FALSE ) { dependencies <- as_pkg_dependencies(dependencies) - unique(unlist(c( - tools::package_dependencies( - packages = packages, - db = available_packages(repos = repos), - recursive = FALSE, - which = dependencies$direct - ), - tools::package_dependencies( - packages = packages, - db = available_packages(repos = repos), - recursive = TRUE, - which = dependencies$indirect + na_version <- package_version(NA_character_, strict = FALSE) + proto_df <- data.frame( + package = character(0L), + type = character(0L), + name = character(0L), + op = character(0L), + version = na_version[c()] + ) + + depth <- 0L + out <- list() + while (length(packages) > 0L) { + depth <- depth + 1L + deptypes <- if (depth == 1L) dependencies$direct else dependencies$indirect + depstrs <- db[packages, deptypes, drop = FALSE] + + n <- length(out) + 1 + out[[n]] <- Map( + package = rep(packages, times = length(deptypes)), + depstr = as.vector(depstrs), + deptype = rep(deptypes, each = length(packages)), + f = function(package, depstr, deptype) { + if (is.na(depstr)) return() + deps <- tools:::.split_dependencies(depstr) + out <- proto_df[seq_along(deps), , drop = FALSE] + rownames(out) <- NULL + + out$package <- package + out$type <- deptype + out$name <- vcapply(deps, `[[`, "name") + out$op <- vcapply(deps, function(i) i$op %||% NA_character_) + out$version <- lapply(deps, function(i) i$version %||% na_version) + + out + } ) - ))) + + old_deps <- unlist(lapply(out, names)) + new_deps <- unlist(lapply(out[[n]], `[[`, "name")) + packages <- setdiff(new_deps, c(old_deps, base_pkgs())) + } + + out <- do.call(rbind, unlist(out, recursive = FALSE)) + rownames(out) <- NULL + out } diff --git a/R/utils-igraph.R b/R/utils-igraph.R index 87e1fb7..50fc743 100644 --- a/R/utils-igraph.R +++ b/R/utils-igraph.R @@ -16,7 +16,9 @@ sequence_graph <- function(name, ...) { } merge_subgraphs <- function(gs) { - # NOTE: igraph::as_data_frame will coerce factor variables to character + # NOTE: igraph::as_data_frame will coerce factor variables to character, + # reassign columns from attributes to avoid coercion + edfs <- lapply(gs, function(g) { df <- igraph::as_data_frame(g) attrs <- igraph::edge.attributes(g) @@ -52,6 +54,7 @@ merge_subgraphs <- function(gs) { } complete_columns <- function(df, cols) { - for (col in setdiff(cols, colnames(df))) df[[col]] <- NA - df[, cols] + n_gtz <- nrow(df) > 0 + for (col in setdiff(cols, colnames(df))) df[[col]] <- NA[n_gtz] + df[, cols, drop = FALSE] } diff --git a/man/pkg_dependencies.Rd b/man/pkg_dependencies.Rd new file mode 100644 index 0000000..6a7ecac --- /dev/null +++ b/man/pkg_dependencies.Rd @@ -0,0 +1,18 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils-deps.R +\name{pkg_dependencies} +\alias{pkg_dependencies} +\title{Build Package Dependencies Table} +\usage{ +pkg_dependencies( + packages, + dependencies = TRUE, + db = available.packages(), + verbose = FALSE +) +} +\description{ +Inspired by \code{tools::package_dependencies}, but with the added benefit +of recording the dependency type and relationships throughout the +dependency tree. +} From d9e833f9c5f43aeec783be0832fb85381bcaf09f Mon Sep 17 00:00:00 2001 From: Doug Kelkhoff Date: Fri, 31 Jan 2025 13:58:36 -0500 Subject: [PATCH 20/62] fix: igraph df attribute issues --- R/reporter_ansi_tty.R | 4 ++-- R/task.R | 4 ++-- R/utils-deps.R | 9 +++++++-- R/utils-igraph.R | 23 ++++------------------- man/plan.Rd | 40 +++++++++++----------------------------- 5 files changed, 26 insertions(+), 54 deletions(-) diff --git a/R/reporter_ansi_tty.R b/R/reporter_ansi_tty.R index c012cee..9c2895c 100644 --- a/R/reporter_ansi_tty.R +++ b/R/reporter_ansi_tty.R @@ -111,7 +111,7 @@ report_initialize.reporter_ansi_tty <- function( report_status.reporter_ansi_tty <- function(reporter, design, envir) { v <- igraph::V(design$graph) v_checks <- v[is_check(v$task)] - n_char_titles <- max(nchar(v_checks$name), 0) + n_char_titles <- max(nchar(vcapply(v_checks$task, friendly_name, short = 2L))) failed_tasks <- design$failed_tasks() failed_packages <- failed_tasks[is_install(failed_tasks)] @@ -180,7 +180,7 @@ report_status.reporter_ansi_tty <- function(reporter, design, envir) { # derive reporter information n_lines <- length(reporter$status) - idx + 1L width <- cli::console_width() - n_char_titles - 2L - task_name <- v_checks$name[[v_idx]] + task_name <- friendly_name(v_checks[[v_idx]]$task, short = 2L) process <- task_graph_task_process(design$graph, v_checks[[v_idx]]) # report status line diff --git a/R/task.R b/R/task.R index 63d68ed..92777e2 100644 --- a/R/task.R +++ b/R/task.R @@ -173,8 +173,8 @@ is_check_task <- function(x) { #' @family tasks #' @export -friendly_name.check_task <- function(x, ...) { - paste0("check ", format(x$origin, ...)) +friendly_name.check_task <- function(x, ..., short = FALSE) { + paste0(if (short <= 1) "check ", format(x$origin, ..., short = short)) } #' Specify a library install diff --git a/R/utils-deps.R b/R/utils-deps.R index 8a24b95..7593150 100644 --- a/R/utils-deps.R +++ b/R/utils-deps.R @@ -88,14 +88,19 @@ pkg_dependencies <- function( if (is.na(depstr)) return() deps <- tools:::.split_dependencies(depstr) out <- proto_df[seq_along(deps), , drop = FALSE] - rownames(out) <- NULL out$package <- package out$type <- deptype out$name <- vcapply(deps, `[[`, "name") out$op <- vcapply(deps, function(i) i$op %||% NA_character_) - out$version <- lapply(deps, function(i) i$version %||% na_version) + out$version <- mapply( + function(i) i$version %||% na_version, + deps, + USE.NAMES = FALSE, + SIMPLIFY = FALSE + ) + rownames(out) <- paste0(out$package, "-", out$name) out } ) diff --git a/R/utils-igraph.R b/R/utils-igraph.R index 50fc743..04d25a6 100644 --- a/R/utils-igraph.R +++ b/R/utils-igraph.R @@ -16,28 +16,13 @@ sequence_graph <- function(name, ...) { } merge_subgraphs <- function(gs) { - # NOTE: igraph::as_data_frame will coerce factor variables to character, - # reassign columns from attributes to avoid coercion - - edfs <- lapply(gs, function(g) { - df <- igraph::as_data_frame(g) - attrs <- igraph::edge.attributes(g) - df[names(attrs)] <- attrs - df - }) - + edfs <- lapply(gs, igraph::as_data_frame) all_cols <- unique(unlist(lapply(edfs, colnames))) edfs <- lapply(edfs, complete_columns, all_cols) es <- unique(do.call(rbind, edfs)) rownames(es) <- NULL - vdfs <- lapply(gs, function(g) { - df <- igraph::as_data_frame(g, what = "vertices") - attrs <- igraph::vertex.attributes(g) - df[names(attrs)] <- attrs - df - }) - + vdfs <- lapply(gs, igraph::as_data_frame, what = "vertices") all_cols <- unique(unlist(lapply(vdfs, colnames))) vdfs <- lapply(vdfs, complete_columns, all_cols) vs <- do.call(rbind, vdfs) @@ -47,8 +32,8 @@ merge_subgraphs <- function(gs) { g <- igraph::graph_from_data_frame(es, vertices = vs) # re-assign vertex and edge attributes to preserve class - igraph::vertex.attributes(g) <- vs - igraph::edge.attributes(g) <- es[, -(1:2), drop = FALSE] + igraph::vertex.attributes(g) <- as.list(vs) + igraph::edge.attributes(g) <- as.list(es[, -(1:2), drop = FALSE]) g } diff --git a/man/plan.Rd b/man/plan.Rd index dd7d1cc..4455be3 100644 --- a/man/plan.Rd +++ b/man/plan.Rd @@ -1,34 +1,16 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/plan.R -\name{plan} -\alias{plan} -\title{Check Plan} -\arguments{ -\item{path}{path to the package source. Can be either a single source -code directory or a directory containing multiple package source code -directories.} -} -\value{ -The check schedule \code{data.frame} with the following columns: -\itemize{ -\item \code{alias}: The alias of the check to run. It also serves the purpose of -providing a unique identifier and node name in the task graph. -\item \code{version}: Version of the package to be checked. -\item \code{package}: Object that inherits from \code{\link[=check_task]{check_task()}}. -Defines how package to be checked can be acquired. -\item \code{custom}: Object that inherits from \code{\link[=custom_install_task]{custom_install_task()}}. -Defines custom package, for instance only available from local source, that -should be installed before checking the package. +% Please edit documentation in R/utils-enums.R +\docType{data} +\name{PLAN} +\alias{PLAN} +\title{Check execution status categories} +\format{ +An object of class \code{list} of length 2. } +\usage{ +PLAN } \description{ -Plans are pre-specified sets of checks. Plans are simple \code{data.frame}s -where each row defines a package for which \verb{R CMD check} -should be run. -} -\seealso{ -Other plan: -\code{\link{plan_checks}()}, -\code{\link{plan_rev_dep_checks}()} +Check execution status categories } -\concept{plan} +\keyword{internal} From 271f4ac45274caf0f0f79502418c30990ef88f51 Mon Sep 17 00:00:00 2001 From: Doug Kelkhoff Date: Fri, 31 Jan 2025 15:59:36 -0500 Subject: [PATCH 21/62] fix: remove unnecessary attr copying --- R/utils-igraph.R | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/R/utils-igraph.R b/R/utils-igraph.R index 04d25a6..d4795f2 100644 --- a/R/utils-igraph.R +++ b/R/utils-igraph.R @@ -29,13 +29,7 @@ merge_subgraphs <- function(gs) { vs <- vs[!duplicated(vs$name), ] rownames(vs) <- NULL - g <- igraph::graph_from_data_frame(es, vertices = vs) - - # re-assign vertex and edge attributes to preserve class - igraph::vertex.attributes(g) <- as.list(vs) - igraph::edge.attributes(g) <- as.list(es[, -(1:2), drop = FALSE]) - - g + igraph::graph_from_data_frame(es, vertices = vs) } complete_columns <- function(df, cols) { From 5b033080b73a067d5498086c4a3098eaf6b39f55 Mon Sep 17 00:00:00 2001 From: dgkf-roche Date: Mon, 3 Feb 2025 12:17:16 -0500 Subject: [PATCH 22/62] wip: meta tasks --- R/plan.R | 68 +++++++++++++++++++++++++++++++++++--------------------- R/task.R | 56 +++++++++++++++++++++++++++++++++------------- 2 files changed, 83 insertions(+), 41 deletions(-) diff --git a/R/plan.R b/R/plan.R index 47dc1fc..66a19a5 100644 --- a/R/plan.R +++ b/R/plan.R @@ -92,30 +92,55 @@ plan_rev_dep_checks <- function( return(empty_checks_df) } - g <- merge_subgraphs(c( - lapply( - revdeps, - plan_rev_dep_dev_check, - path = path, - repos = repos - ), - lapply( - revdeps[revdeps %in% ap[, "Package"]], - plan_rev_dep_release_check, - repos = repos + task <- make_unique_task( + seed = path, + meta_task( + origin = pkg_origin_local(path), + .subclass = "rev_dep_dep" ) + ) + + task <- sequence_graph(name = hashes(list(task)), task = list(task)) + + rev_dep_dev_check_tasks <- lapply( + revdeps, + plan_rev_dep_dev_check, + path = path, + repos = repos + ) + + rev_dep_release_check_tasks <- lapply( + revdeps[revdeps %in% ap[, "Package"]], + plan_rev_dep_release_check, + repos = repos + ) + + task_id <- V(task)[[1]]$name + rev_dep_meta_task_ids <- unique(c( + vcapply(rev_dep_dev_check_tasks, function(g) V(g)[[1]]$name), + vcapply(rev_dep_release_check_tasks, function(g) V(g)[[1]]$name) )) + g <- merge_subgraphs(c( + task, + rev_dep_dev_check_tasks, + rev_dep_release_check_tasks + )) + + igraph::add_edges(g, ) + class(g) <- c("task_graph", class(g)) g } plan_rev_dep_dev_check <- function(path, revdep, repos) { + rev_dep_origin <- pkg_origin_repo(package = revdep, repos = repos) origin <- pkg_origin_local(path = path) tasks <- list( + make_unique_task(seed = revdep, meta_task(.subclass = "rev_dep_check")), make_unique_task(seed = "dev", check_task( - origin = pkg_origin_repo(package = revdep, repos = repos), + origin = rev_dep_origin, env = DEFAULT_R_CMD_CHECK_ENVVARS, args = DEFAULT_R_CMD_CHECK_ARGS, build_args = DEFAULT_R_CMD_BUILD_ARGS @@ -123,30 +148,23 @@ plan_rev_dep_dev_check <- function(path, revdep, repos) { install_task(origin = origin) ) - planned(sequence_graph( - name = hashes(tasks), - task = tasks, - task_type = lapply(tasks, function(task) class(task)[[1]]), - package = c(revdep, origin$package) - )) + sequence_graph(name = hashes(tasks), task = tasks) } plan_rev_dep_release_check <- function(revdep, repos) { + rev_dep_origin <- pkg_origin_repo(package = revdep, repos = repos) + tasks <- list( + make_unique_task(seed = revdep, meta_task(.subclass = "rev_dep_check")), make_unique_task(seed = "release", check_task( - origin = pkg_origin_repo(package = revdep, repos = repos), + origin = rev_dep_origin, env = DEFAULT_R_CMD_CHECK_ENVVARS, args = DEFAULT_R_CMD_CHECK_ARGS, build_args = DEFAULT_R_CMD_BUILD_ARGS )) ) - planned(sequence_graph( - name = hashes(tasks), - task = tasks, - task_type = lapply(tasks, function(task) class(task)[[1]]), - package = revdep - )) + sequence_graph(name = hashes(tasks), task = tasks) } rev_dep_check_tasks <- function(packages, repos, aliases, revdep) { diff --git a/R/task.R b/R/task.R index 92777e2..80b73a0 100644 --- a/R/task.R +++ b/R/task.R @@ -13,8 +13,17 @@ #' #' @family tasks #' @export -task <- function(...) { - structure(list(...), class = "task") +task <- function(..., .subclass = NULL) { + structure(list(...), class = c(sprintf("%s_task", .subclass), "task")) +} + +#' Construct a 'Meta' Task +#' +#' Meta tasks are tasks which are not intended to perform computation. They +#' exist simply to provide relationships among computational tasks. +#' +meta_task <- function(..., .subclass = NULL) { + task(..., .subclass = c(sprintf("%s_meta", .subclass), "meta")) } make_unique_task <- function(task, seed = runif(1)) { @@ -43,7 +52,7 @@ format.task <- function(x, ..., indent = 0L) { } #' @export -friendly_name.task <- function(x) { +friendly_name.task <- function(x, ...) { "task" } @@ -61,7 +70,7 @@ friendly_name.default <- function(x, ...) { } #' @export -friendly_class.task <- function(x) { +friendly_class.task <- function(x, ...) { if (length(class(x)) > 1) { sub("_task$", "", class(x)[[1]]) } else { @@ -89,12 +98,14 @@ install_task <- function( lib = lib_loc_default(), ... ) { - task <- task(origin = origin, ...) - task$type <- type - task$INSTALL_opts <- INSTALL_opts - task$lib <- lib - class(task) <- c("install_task", class(task)) - task + task( + origin = origin, + type = type, + INSTALL_opts = INSTALL_opts, + lib = lib, + ..., + .subclass = "install" + ) } #' @export @@ -154,12 +165,13 @@ custom_install_task <- function(...) { #' @family tasks #' @export check_task <- function(build_args = NULL, args = NULL, env = NULL, ...) { - task <- task(...) - task$env <- env - task$args <- args - task$build_args <- build_args - class(task) <- c("check_task", class(task)) - task + task( + env = env, + args = args, + build_args = build_args, + ..., + .subclass = "check" + ) } #' @export @@ -210,6 +222,18 @@ friendly_name.library_task <- function(x, ...) { paste0(format(x$loc), fmt_pkgs) } +friendly_name.rev_dep_dep_meta_task <- function(x, ..., short = FALSE) { + paste0( + "check ", + format(x$origin, ..., short = short), + if (!short) " reverse-dependencies" + ) +} + +friendly_name.rev_dep_check_meta_task <- function(x, ..., short = FALSE) { + paste0("check ", if (short) "revdep" else "reverse-dependency") +} + #' Create a task to run reverse dependency checks #' #' @param revdep character indicating whether the task specification describes From 0bdbe9fc6ca726c39c978d1e66b28c8de694aa9d Mon Sep 17 00:00:00 2001 From: dgkf-roche Date: Mon, 3 Feb 2025 12:18:21 -0500 Subject: [PATCH 23/62] fix: igraph df attribute issues --- R/reporter_ansi_tty.R | 4 ++-- R/task.R | 4 ++-- R/utils-deps.R | 9 +++++++-- R/utils-igraph.R | 23 ++++------------------- man/plan.Rd | 40 +++++++++++----------------------------- 5 files changed, 26 insertions(+), 54 deletions(-) diff --git a/R/reporter_ansi_tty.R b/R/reporter_ansi_tty.R index c012cee..9c2895c 100644 --- a/R/reporter_ansi_tty.R +++ b/R/reporter_ansi_tty.R @@ -111,7 +111,7 @@ report_initialize.reporter_ansi_tty <- function( report_status.reporter_ansi_tty <- function(reporter, design, envir) { v <- igraph::V(design$graph) v_checks <- v[is_check(v$task)] - n_char_titles <- max(nchar(v_checks$name), 0) + n_char_titles <- max(nchar(vcapply(v_checks$task, friendly_name, short = 2L))) failed_tasks <- design$failed_tasks() failed_packages <- failed_tasks[is_install(failed_tasks)] @@ -180,7 +180,7 @@ report_status.reporter_ansi_tty <- function(reporter, design, envir) { # derive reporter information n_lines <- length(reporter$status) - idx + 1L width <- cli::console_width() - n_char_titles - 2L - task_name <- v_checks$name[[v_idx]] + task_name <- friendly_name(v_checks[[v_idx]]$task, short = 2L) process <- task_graph_task_process(design$graph, v_checks[[v_idx]]) # report status line diff --git a/R/task.R b/R/task.R index 63d68ed..92777e2 100644 --- a/R/task.R +++ b/R/task.R @@ -173,8 +173,8 @@ is_check_task <- function(x) { #' @family tasks #' @export -friendly_name.check_task <- function(x, ...) { - paste0("check ", format(x$origin, ...)) +friendly_name.check_task <- function(x, ..., short = FALSE) { + paste0(if (short <= 1) "check ", format(x$origin, ..., short = short)) } #' Specify a library install diff --git a/R/utils-deps.R b/R/utils-deps.R index 8a24b95..7593150 100644 --- a/R/utils-deps.R +++ b/R/utils-deps.R @@ -88,14 +88,19 @@ pkg_dependencies <- function( if (is.na(depstr)) return() deps <- tools:::.split_dependencies(depstr) out <- proto_df[seq_along(deps), , drop = FALSE] - rownames(out) <- NULL out$package <- package out$type <- deptype out$name <- vcapply(deps, `[[`, "name") out$op <- vcapply(deps, function(i) i$op %||% NA_character_) - out$version <- lapply(deps, function(i) i$version %||% na_version) + out$version <- mapply( + function(i) i$version %||% na_version, + deps, + USE.NAMES = FALSE, + SIMPLIFY = FALSE + ) + rownames(out) <- paste0(out$package, "-", out$name) out } ) diff --git a/R/utils-igraph.R b/R/utils-igraph.R index 50fc743..04d25a6 100644 --- a/R/utils-igraph.R +++ b/R/utils-igraph.R @@ -16,28 +16,13 @@ sequence_graph <- function(name, ...) { } merge_subgraphs <- function(gs) { - # NOTE: igraph::as_data_frame will coerce factor variables to character, - # reassign columns from attributes to avoid coercion - - edfs <- lapply(gs, function(g) { - df <- igraph::as_data_frame(g) - attrs <- igraph::edge.attributes(g) - df[names(attrs)] <- attrs - df - }) - + edfs <- lapply(gs, igraph::as_data_frame) all_cols <- unique(unlist(lapply(edfs, colnames))) edfs <- lapply(edfs, complete_columns, all_cols) es <- unique(do.call(rbind, edfs)) rownames(es) <- NULL - vdfs <- lapply(gs, function(g) { - df <- igraph::as_data_frame(g, what = "vertices") - attrs <- igraph::vertex.attributes(g) - df[names(attrs)] <- attrs - df - }) - + vdfs <- lapply(gs, igraph::as_data_frame, what = "vertices") all_cols <- unique(unlist(lapply(vdfs, colnames))) vdfs <- lapply(vdfs, complete_columns, all_cols) vs <- do.call(rbind, vdfs) @@ -47,8 +32,8 @@ merge_subgraphs <- function(gs) { g <- igraph::graph_from_data_frame(es, vertices = vs) # re-assign vertex and edge attributes to preserve class - igraph::vertex.attributes(g) <- vs - igraph::edge.attributes(g) <- es[, -(1:2), drop = FALSE] + igraph::vertex.attributes(g) <- as.list(vs) + igraph::edge.attributes(g) <- as.list(es[, -(1:2), drop = FALSE]) g } diff --git a/man/plan.Rd b/man/plan.Rd index dd7d1cc..4455be3 100644 --- a/man/plan.Rd +++ b/man/plan.Rd @@ -1,34 +1,16 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/plan.R -\name{plan} -\alias{plan} -\title{Check Plan} -\arguments{ -\item{path}{path to the package source. Can be either a single source -code directory or a directory containing multiple package source code -directories.} -} -\value{ -The check schedule \code{data.frame} with the following columns: -\itemize{ -\item \code{alias}: The alias of the check to run. It also serves the purpose of -providing a unique identifier and node name in the task graph. -\item \code{version}: Version of the package to be checked. -\item \code{package}: Object that inherits from \code{\link[=check_task]{check_task()}}. -Defines how package to be checked can be acquired. -\item \code{custom}: Object that inherits from \code{\link[=custom_install_task]{custom_install_task()}}. -Defines custom package, for instance only available from local source, that -should be installed before checking the package. +% Please edit documentation in R/utils-enums.R +\docType{data} +\name{PLAN} +\alias{PLAN} +\title{Check execution status categories} +\format{ +An object of class \code{list} of length 2. } +\usage{ +PLAN } \description{ -Plans are pre-specified sets of checks. Plans are simple \code{data.frame}s -where each row defines a package for which \verb{R CMD check} -should be run. -} -\seealso{ -Other plan: -\code{\link{plan_checks}()}, -\code{\link{plan_rev_dep_checks}()} +Check execution status categories } -\concept{plan} +\keyword{internal} From 8bc46b1763d72bcea2b462624100690d18166c95 Mon Sep 17 00:00:00 2001 From: dgkf-roche Date: Mon, 3 Feb 2025 12:18:21 -0500 Subject: [PATCH 24/62] fix: remove unnecessary attr copying --- R/utils-igraph.R | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/R/utils-igraph.R b/R/utils-igraph.R index 04d25a6..d4795f2 100644 --- a/R/utils-igraph.R +++ b/R/utils-igraph.R @@ -29,13 +29,7 @@ merge_subgraphs <- function(gs) { vs <- vs[!duplicated(vs$name), ] rownames(vs) <- NULL - g <- igraph::graph_from_data_frame(es, vertices = vs) - - # re-assign vertex and edge attributes to preserve class - igraph::vertex.attributes(g) <- as.list(vs) - igraph::edge.attributes(g) <- as.list(es[, -(1:2), drop = FALSE]) - - g + igraph::graph_from_data_frame(es, vertices = vs) } complete_columns <- function(df, cols) { From ccc6dcc0927ee2c37fd1ea4818c81edff209e65c Mon Sep 17 00:00:00 2001 From: dgkf-roche Date: Tue, 4 Feb 2025 11:52:06 -0500 Subject: [PATCH 25/62] wip: meta tasks --- NAMESPACE | 3 +- R/plan.R | 54 ++++++++------- R/reporter.R | 6 ++ R/reporter_ansi_tty.R | 7 +- R/reporter_ansi_tty2.R | 153 +++++++++++++++++++++++++++++++++++++++++ R/task.R | 8 ++- R/task_graph.R | 119 ++++++++++++++++---------------- R/utils-enums.R | 21 ++++-- R/utils-igraph.R | 2 +- man/meta_task.Rd | 12 ++++ man/plan.Rd | 40 ++++++++--- man/task.Rd | 2 +- 12 files changed, 313 insertions(+), 114 deletions(-) create mode 100644 R/reporter_ansi_tty2.R create mode 100644 man/meta_task.Rd diff --git a/NAMESPACE b/NAMESPACE index 3265afe..981e15e 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -33,6 +33,8 @@ S3method(friendly_name,check_task) S3method(friendly_name,default) S3method(friendly_name,install_task) S3method(friendly_name,library_task) +S3method(friendly_name,rev_dep_check_meta_task) +S3method(friendly_name,rev_dep_dep_meta_task) S3method(friendly_name,task) S3method(install_params,pkg_origin) S3method(install_params,pkg_origin_archive) @@ -86,7 +88,6 @@ S3method(summary,checked_results) S3method(summary,checked_results_check_task) S3method(summary,checked_results_revdep_check_task) S3method(summary,checker) -export(as_visNetwork) export(check_dev_rev_deps) export(check_dir) export(check_pkgs) diff --git a/R/plan.R b/R/plan.R index 66a19a5..85673c3 100644 --- a/R/plan.R +++ b/R/plan.R @@ -30,12 +30,6 @@ empty_checks_df <- data.frame( #' @name plan NULL -#' Tag edges as 'planned' -planned <- function(graph) { - igraph::E(graph)$plan <- PLAN$planned - graph -} - #' Plan Reverse Dependency Checks #' #' Generates a plan for running reverse dependency check for certain @@ -92,16 +86,13 @@ plan_rev_dep_checks <- function( return(empty_checks_df) } - task <- make_unique_task( - seed = path, - meta_task( - origin = pkg_origin_local(path), - .subclass = "rev_dep_dep" - ) - ) - - task <- sequence_graph(name = hashes(list(task)), task = list(task)) + # root meta task, indicating a reverse-dependency check plan + task <- sequence_graph(task = list(meta_task( + origin = pkg_origin_local(path), + .subclass = "rev_dep_dep" + ))) + # build individual plans for development version reverse-dependency checks rev_dep_dev_check_tasks <- lapply( revdeps, plan_rev_dep_dev_check, @@ -109,35 +100,39 @@ plan_rev_dep_checks <- function( repos = repos ) + # build individual plans for release version reverse-dependency checks rev_dep_release_check_tasks <- lapply( revdeps[revdeps %in% ap[, "Package"]], plan_rev_dep_release_check, repos = repos ) + # store vertex names so that we can build edges after merging task_id <- V(task)[[1]]$name rev_dep_meta_task_ids <- unique(c( vcapply(rev_dep_dev_check_tasks, function(g) V(g)[[1]]$name), vcapply(rev_dep_release_check_tasks, function(g) V(g)[[1]]$name) )) + # combine component plans into an overall plan g <- merge_subgraphs(c( - task, + list(task), rev_dep_dev_check_tasks, rev_dep_release_check_tasks )) - igraph::add_edges(g, ) - + # reconstruct edges from planned root node to individual checks + edges <- as.vector(rbind(task_id, rev_dep_meta_task_ids)) + g <- igraph::add_edges(g, edges = edges, attr = list(type = EDGE$dep)) class(g) <- c("task_graph", class(g)) g } + plan_rev_dep_dev_check <- function(path, revdep, repos) { rev_dep_origin <- pkg_origin_repo(package = revdep, repos = repos) origin <- pkg_origin_local(path = path) - - tasks <- list( + g <- sequence_graph(task = list( make_unique_task(seed = revdep, meta_task(.subclass = "rev_dep_check")), make_unique_task(seed = "dev", check_task( origin = rev_dep_origin, @@ -146,15 +141,18 @@ plan_rev_dep_dev_check <- function(path, revdep, repos) { build_args = DEFAULT_R_CMD_BUILD_ARGS )), install_task(origin = origin) - ) + )) + + # this check is reported through a rev dep check meta task + E(g)$type <- EDGE$dep + g <- igraph::add_edges(g, edges = c(2, 1), attr = list(type = EDGE$report)) - sequence_graph(name = hashes(tasks), task = tasks) + g } plan_rev_dep_release_check <- function(revdep, repos) { rev_dep_origin <- pkg_origin_repo(package = revdep, repos = repos) - - tasks <- list( + g <- sequence_graph(task = list( make_unique_task(seed = revdep, meta_task(.subclass = "rev_dep_check")), make_unique_task(seed = "release", check_task( origin = rev_dep_origin, @@ -162,9 +160,13 @@ plan_rev_dep_release_check <- function(revdep, repos) { args = DEFAULT_R_CMD_CHECK_ARGS, build_args = DEFAULT_R_CMD_BUILD_ARGS )) - ) + )) - sequence_graph(name = hashes(tasks), task = tasks) + # this check is reported through a rev dep check meta task + E(g)$type <- EDGE$dep + g <- igraph::add_edges(g, edges = c(2, 1), attr = list(type = EDGE$report)) + + g } rev_dep_check_tasks <- function(packages, repos, aliases, revdep) { diff --git a/R/reporter.R b/R/reporter.R index 82587c1..c3d8299 100644 --- a/R/reporter.R +++ b/R/reporter.R @@ -36,6 +36,12 @@ reporter_ansi_tty <- function() { reporter("ansi_tty") } +#' @rdname reporters +#' @export +reporter_ansi_tty2 <- function() { + reporter("ansi_tty2") +} + #' @rdname reporters #' @export reporter_basic_tty <- function() { diff --git a/R/reporter_ansi_tty.R b/R/reporter_ansi_tty.R index 9c2895c..c789d3d 100644 --- a/R/reporter_ansi_tty.R +++ b/R/reporter_ansi_tty.R @@ -4,9 +4,10 @@ format_status_line_ansi <- function(process, ...) { #' @export format_status_line_ansi.check_process <- function( - process, - ..., - width = getOption("width", 80L)) { + process, + ..., + width = getOption("width", 80L) +) { checks <- process$get_checks() # runtime of process diff --git a/R/reporter_ansi_tty2.R b/R/reporter_ansi_tty2.R new file mode 100644 index 0000000..b195b41 --- /dev/null +++ b/R/reporter_ansi_tty2.R @@ -0,0 +1,153 @@ +#' @export +report_sleep.reporter_ansi_tty2 <- function( + reporter, + checker, + sleep = default_tty_tick_interval() +) { + Sys.sleep(sleep) +} + +#' @export +report_initialize.reporter_ansi_tty2 <- function( + reporter, + checker, + envir = parent.frame() +) { + # named factor vector, names as task aliases and value of last reported status + reporter$header <- TRUE + reporter$status <- STATUS$done[c()] + + # hide cursor when initializer enters, ensure its restored even if interrupted + cli::ansi_hide_cursor() + do.call( + on.exit, + list(quote(cli::ansi_show_cursor()), add = TRUE), + envir = envir + ) + + cli::cli_progress_bar( + type = "custom", + extra = list(message = ""), + format = "ETA {cli::pb_eta} ({cli::pb_current}/{cli::pb_total}) [{cli::pb_elapsed}] {cli::pb_extra$message}", # nolint + format_done = "Finished in {cli::pb_elapsed}", + total = sum(igraph::V(checker$graph)$type == "check"), + clear = FALSE, + auto_terminate = FALSE, + .auto_close = FALSE, + .envir = reporter, + ) +} + +#' @importFrom igraph V +#' @export +report_status.reporter_ansi_tty2 <- function(reporter, checker, envir) { + v <- igraph::V(checker$graph) + v_checks <- v[is_check(v$task)] + n_char_titles <- max(nchar(vcapply(v_checks$task, friendly_name, short = 2L))) + failed_tasks <- checker$failed_tasks() + failed_packages <- failed_tasks[is_install(failed_tasks)] + + # add newly started task status + new_idx <- which(v_checks$status > STATUS$pending) + new_idx <- new_idx[!v_checks$name[new_idx] %in% names(reporter$status)] + if (length(new_idx) > 0) { + # print header if this is the first status line of the reporter + if (reporter$header) { + cat( + ansi_line_erase(), + strrep(" ", n_char_titles + 2), + cli_table_row("S", "OK", "N", "W", "E", title = TRUE), + "\n", + sep = "" + ) + reporter$header <- FALSE + } + + # always start by reporting in progress, even if finished before reporting + new <- rep_len(STATUS$`in progress`, length(new_idx)) + names(new) <- v_checks$name[new_idx] + reporter$status <- c(reporter$status, new) + cat(strrep("\n", length(new_idx))) + } + + if (length(reporter$failed_packaged) != length(failed_packages)) { + # Add failed packages warning to the buffer + failures_buffer <- rev(unlist(lapply(failed_packages, function(x) { + list( + cli_wrap_lines(cli::cli_fmt(cli::cli_alert_danger( + sprintf("%s package installation had non-zero exit status", x$name) + ))), + cli_wrap_lines(as.character(cli::style_dim( + sprintf("log: %s", x$process[[1]]$log) + ))) + ) + }))) + + reporter$failures_buffer <- vcapply( + seq_along(failures_buffer), + function(i) { + paste0( + ansi_move_line_rel(i), + ansi_line_erase(), + failures_buffer[i], + ansi_move_line_rel(-i), + sep = "" + ) + } + ) + + # For performance store these value in the environment to redraw warnings + # buffer only when necessary + reporter$failed_packaged <- failed_packages + } + + # for each not-yet finished task, report status + buffer <- "" + for (idx in seq_along(reporter$status)) { + # update reported status + alias <- names(reporter$status)[[idx]] + v_idx <- which(v_checks$name == alias) + reporter$status[[idx]] <- v_checks$status[[v_idx]] + + # derive reporter information + n_lines <- length(reporter$status) - idx + 1L + width <- cli::console_width() - n_char_titles - 2L + task_name <- friendly_name(v_checks[[v_idx]]$task, short = 2L) + process <- task_graph_task_process(checker$graph, v_checks[[v_idx]]) + + # report status line + buffer <- paste0( + buffer, + ansi_move_line_rel(n_lines + length(reporter$failures_buffer)), + ansi_line_erase(), + " ", strrep(" ", n_char_titles - nchar(task_name)), task_name, " ", + format_status_line_ansi(process, width = width), + ansi_move_line_rel(-(n_lines + length(reporter$failures_buffer))), + sep = "" + ) + } + + cat(paste0(buffer, reporter$failures_buffer)) + + is_inst <- is_install(checker$active_processes()) + inst_pkgs <- names(checker$active_processes()[is_inst]) + if (length(inst_pkgs)) { + inst_msg <- paste0("installing ", paste0(inst_pkgs, collapse = ", ")) + } else { + inst_msg <- "" + } + + n_finished <- sum(v$status[v$type == "check"] >= STATUS$done) + cli::cli_progress_update( + set = n_finished, + extra = list(message = inst_msg), + .envir = reporter + ) +} + +#' @export +report_finalize.reporter_ansi_tty2 <- function(reporter, checker) { + report_status(reporter, checker) # report completions of final processes + cli::cli_progress_done(.envir = reporter) + cli::ansi_show_cursor() +} diff --git a/R/task.R b/R/task.R index 80b73a0..2289ecb 100644 --- a/R/task.R +++ b/R/task.R @@ -185,8 +185,8 @@ is_check_task <- function(x) { #' @family tasks #' @export -friendly_name.check_task <- function(x, ..., short = FALSE) { - paste0(if (short <= 1) "check ", format(x$origin, ..., short = short)) +friendly_name.check_task <- function(x, ...) { + paste0("check ", format(x$origin, ...)) } #' Specify a library install @@ -222,14 +222,16 @@ friendly_name.library_task <- function(x, ...) { paste0(format(x$loc), fmt_pkgs) } +#' @export friendly_name.rev_dep_dep_meta_task <- function(x, ..., short = FALSE) { paste0( "check ", format(x$origin, ..., short = short), - if (!short) " reverse-dependencies" + if (short) " revdeps" else " reverse-dependencies" ) } +#' @export friendly_name.rev_dep_check_meta_task <- function(x, ..., short = FALSE) { paste0("check ", if (short) "revdep" else "reverse-dependency") } diff --git a/R/task_graph.R b/R/task_graph.R index 1fcc1ec..69b64c3 100644 --- a/R/task_graph.R +++ b/R/task_graph.R @@ -23,18 +23,23 @@ #' } #' @keywords internal task_graph_create <- function(plan, repos = getOption("repos")) { - plan_tasks <- igraph::V(plan)[igraph::V(plan)$task_type == "check_task"] - plan_neighborhoods <- igraph::neighborhood( + check_tasks <- igraph::V(plan)[is_check(igraph::V(plan)$task)] + check_task_neighborhoods <- igraph::neighborhood( plan, order = length(plan), mode = "out", - nodes = plan_tasks + nodes = check_tasks ) # for each check task in the plan, build a dependency tree and merge it # into the existing check task subtree - plan_neighborhoods <- lapply(plan_neighborhoods, function(nh) { + check_task_neighborhoods <- lapply(check_task_neighborhoods, function(nh) { subtree <- igraph::induced_subgraph(plan, nh) + V(subtree)$package <- vcapply( + V(subtree)$task, + function(i) i$origin$package %||% NA_character_ + ) + deps <- dep_tree(nh[[1]]$task) igraph::reverse_edges(deps) @@ -65,12 +70,11 @@ task_graph_create <- function(plan, repos = getOption("repos")) { }) # then merge all the full check task task trees into a single graph - g <- merge_subgraphs(plan_neighborhoods) + g <- merge_subgraphs(c(list(plan), check_task_neighborhoods)) class(g) <- c("task_graph", class(g)) igraph::V(g)$status <- STATUS$pending igraph::V(g)$process <- rep_len(list(), length(g)) - igraph::E(g)$plan[is.na(igraph::E(g)$plan)] <- PLAN$inferred task_graph_sort(g) } @@ -393,43 +397,7 @@ task_graph_update_done <- function(g, lib.loc) { } #' @export -as_visNetwork <- function(x, ...) { - color_by_task_type <- c( - "check_task" = "lightblue", - "library_task" = "lightgreen", - "install_task" = "cornflowerblue", - "pkg_origin_repo" = "cornflowerblue", - "pkg_origin_unknown" = "red", - "pkg_origin_local" = "blue", - "red" - ) - - nodes <- igraph::as_data_frame(x, what = "vertices") - task_type <- vcapply(igraph::V(x)$task, function(task) { - if (is_install(task)) return(class(task$origin)[[1]]) - class(task)[[1]] - }) - - nodes$id <- nodes$name - - nodes$label <- vcapply(igraph::V(g)$task, function(task) { - friendly_name(task, short = TRUE) - }) - - nodes$color <- color_by_task_type[match( - task_type, - names(color_by_task_type), - nomatch = length(color_by_task_type) - )] - - edges <- igraph::as_data_frame(x) - - nodes$task <- NULL # work around for visNetwork infinite recursion issue? - visNetwork::visNetwork(nodes = nodes, edges = edges) -} - -#' @export -plot.task_graph <- function(x, ...) { +plot.task_graph <- function(x, ..., interactive = FALSE) { style <- function(attr, ...) { map <- simplify2array(list(...)) nomatch <- if (names(map[length(map)]) == "") length(map) else NA @@ -441,8 +409,13 @@ plot.task_graph <- function(x, ...) { class(task)[[1]] }) - vertex.color <- style( + vertex <- igraph::as_data_frame(x, what = "vertices") + edge <- igraph::as_data_frame(x, what = "edges") + + vertex$color <- style( task_type, + "rev_dep_dep_meta_task" = "blueviolet", + "rev_dep_check_meta_task" = "blueviolet", "check_task" = "lightblue", "library_task" = "lightgreen", "install_task" = "cornflowerblue", @@ -453,13 +426,13 @@ plot.task_graph <- function(x, ...) { "red" ) - vertex.label <- vcapply( + vertex$label <- vcapply( igraph::V(x)$task, friendly_name, short = TRUE ) - vertex.size <- style( + vertex$size <- style( task_type, "install_task" = 5, "pkg_origin_repo" = 5, @@ -469,29 +442,53 @@ plot.task_graph <- function(x, ...) { 8 ) - edge.lty <- style( - igraph::E(x)$plan, - "planned" = 1, # solid - "inferred" = 3 # dotted - ) - - tail_ids <- igraph::ends(x, igraph::E(x))[, 2L] - is_inst <- is_install(igraph::V(x)[tail_ids]$task) - is_check <- is_check(igraph::V(x)$task) + if (interactive) { + plot_interactive_task_graph(x, vertex = vertex, edge = edge) + } else { + plot_static_task_graph(x, vertex = vertex, edge = edge) + } +} +plot_static_task_graph <- function( + g, + vertex = igraph::as_data_frame(g, what = "vertices"), + edge = igraph::as_data_frame(g, what = "edges") +) { igraph::plot.igraph( - x, + g, vertex.label.family = "sans", vertex.label.color = "gray4", vertex.label.dist = 1, - vertex.label = vertex.label, - vertex.color = vertex.color, - vertex.size = vertex.size, - edge.lty = edge.lty, + vertex.label = vertex$label, + vertex.color = vertex$color, + vertex.size = vertex$size, + edge.lty = edge$lty, layout = igraph::layout_with_sugiyama( - x, + g, hgap = 200, maxiter = 1000 ) ) } + +plot_interactive_task_graph <- function( + g, + vertex = igraph::as_data_frame(g, what = "vertices"), + edge = igraph::as_data_frame(g, what = "edges") +) { + # visNetwork hates non-atomic vectors + vertex$task <- NULL + edge$version <- format(edge$version) + + vertex$id <- seq_len(nrow(vertex)) + edge$from <- vertex$id[match(edge$from, vertex$name)] + edge$to <- vertex$id[match(edge$to, vertex$name)] + edge$arrows <- "to" + + visNetwork::visNetwork( + nodes = vertex, + edges = edge, + width = "100vw", + height = "100vh" + ) +} diff --git a/R/utils-enums.R b/R/utils-enums.R index 5075c69..a7ad7f2 100644 --- a/R/utils-enums.R +++ b/R/utils-enums.R @@ -25,6 +25,20 @@ Ops.factor <- function(e1, e2) { NextMethod() } +#' Edge types +#' +#' Edges may have multiple relations. Most commonly, this relationship +#' represents a dependency, meaning that a node's task must be performed before +#' another node. However, this may also be a relationship that is used for +#' grouping behaviors together during reporting, allowing a single task to +#' redirect to another node. +#' +#' @keywords internal +EDGE <- enum( + "dep", # for task dependencies + "report" # for reporting graph, from task to reporting node +) + #' Check execution status categories #' @keywords internal STATUS <- enum( @@ -33,13 +47,6 @@ STATUS <- enum( "done" ) -#' Check execution status categories -#' @keywords internal -PLAN <- enum( - "planned", - "inferred" -) - #' Dependencies categories #' @keywords internal DEP <- enum( diff --git a/R/utils-igraph.R b/R/utils-igraph.R index d4795f2..66350bc 100644 --- a/R/utils-igraph.R +++ b/R/utils-igraph.R @@ -6,7 +6,7 @@ vertex_df <- function(name, ...) { vertices } -sequence_graph <- function(name, ...) { +sequence_graph <- function(..., name_by = ..1, name = hashes(name_by)) { vertices <- vertex_df(name = name, ...) edges <- data.frame( from = utils::head(vertices$name, -1L), diff --git a/man/meta_task.Rd b/man/meta_task.Rd new file mode 100644 index 0000000..87c57e7 --- /dev/null +++ b/man/meta_task.Rd @@ -0,0 +1,12 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/task.R +\name{meta_task} +\alias{meta_task} +\title{Construct a 'Meta' Task} +\usage{ +meta_task(..., .subclass = NULL) +} +\description{ +Meta tasks are tasks which are not intended to perform computation. They +exist simply to provide relationships among computational tasks. +} diff --git a/man/plan.Rd b/man/plan.Rd index 4455be3..dd7d1cc 100644 --- a/man/plan.Rd +++ b/man/plan.Rd @@ -1,16 +1,34 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/utils-enums.R -\docType{data} -\name{PLAN} -\alias{PLAN} -\title{Check execution status categories} -\format{ -An object of class \code{list} of length 2. +% Please edit documentation in R/plan.R +\name{plan} +\alias{plan} +\title{Check Plan} +\arguments{ +\item{path}{path to the package source. Can be either a single source +code directory or a directory containing multiple package source code +directories.} +} +\value{ +The check schedule \code{data.frame} with the following columns: +\itemize{ +\item \code{alias}: The alias of the check to run. It also serves the purpose of +providing a unique identifier and node name in the task graph. +\item \code{version}: Version of the package to be checked. +\item \code{package}: Object that inherits from \code{\link[=check_task]{check_task()}}. +Defines how package to be checked can be acquired. +\item \code{custom}: Object that inherits from \code{\link[=custom_install_task]{custom_install_task()}}. +Defines custom package, for instance only available from local source, that +should be installed before checking the package. } -\usage{ -PLAN } \description{ -Check execution status categories +Plans are pre-specified sets of checks. Plans are simple \code{data.frame}s +where each row defines a package for which \verb{R CMD check} +should be run. +} +\seealso{ +Other plan: +\code{\link{plan_checks}()}, +\code{\link{plan_rev_dep_checks}()} } -\keyword{internal} +\concept{plan} diff --git a/man/task.Rd b/man/task.Rd index 18a65ad..22579f5 100644 --- a/man/task.Rd +++ b/man/task.Rd @@ -4,7 +4,7 @@ \alias{task} \title{Task specification} \usage{ -task(...) +task(..., .subclass = NULL) } \arguments{ \item{alias}{task alias which also serves as unique identifier of the task.} From b662dbf4498e687098dfcded4edd95fec697ca59 Mon Sep 17 00:00:00 2001 From: dgkf-roche Date: Tue, 4 Feb 2025 11:53:53 -0500 Subject: [PATCH 26/62] fix: removed edge type from plot --- R/task_graph.R | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/R/task_graph.R b/R/task_graph.R index 1fcc1ec..d7fa499 100644 --- a/R/task_graph.R +++ b/R/task_graph.R @@ -469,16 +469,6 @@ plot.task_graph <- function(x, ...) { 8 ) - edge.lty <- style( - igraph::E(x)$plan, - "planned" = 1, # solid - "inferred" = 3 # dotted - ) - - tail_ids <- igraph::ends(x, igraph::E(x))[, 2L] - is_inst <- is_install(igraph::V(x)[tail_ids]$task) - is_check <- is_check(igraph::V(x)$task) - igraph::plot.igraph( x, vertex.label.family = "sans", @@ -487,7 +477,6 @@ plot.task_graph <- function(x, ...) { vertex.label = vertex.label, vertex.color = vertex.color, vertex.size = vertex.size, - edge.lty = edge.lty, layout = igraph::layout_with_sugiyama( x, hgap = 200, From 72140fee678854c33a317a51e48ac2c07ea6f091 Mon Sep 17 00:00:00 2001 From: dgkf-roche Date: Thu, 22 May 2025 12:59:43 -0400 Subject: [PATCH 27/62] implement ansi tty reporting --- NAMESPACE | 38 ++- R/cli.R | 53 ++-- R/next_task.R | 10 +- R/package.R | 2 + R/pkg_origin.R | 40 +-- R/plan.R | 36 ++- R/report_ansi_tty.R | 449 ++++++++++++++++++++++++++++++++ R/reporter.R | 9 +- R/reporter_ansi_tty.R | 222 ---------------- R/reporter_ansi_tty2.R | 153 ----------- R/reporter_basic_tty.R | 2 +- R/run.R | 3 +- R/task-formatting.R | 55 ++++ R/task.R | 87 +------ R/task_graph.R | 120 +++++---- R/utils-cli.R | 125 +++++++++ R/utils-enums.R | 27 +- R/utils-igraph.R | 59 ++++- R/utils-paths.R | 20 +- Rplots.pdf | Bin 0 -> 25458 bytes man/DEP.Rd | 2 +- man/DEP_STRONG.Rd | 2 +- man/PLAN.Rd | 16 -- man/RELATION.Rd | 16 ++ man/STATUS.Rd | 2 +- man/checked-package.Rd | 33 +++ man/cli.Rd | 5 +- man/fmt.Rd | 22 ++ man/graph_dedup_attrs.Rd | 14 + man/graph_project.Rd | 17 -- man/planned.Rd | 11 - man/reporters-internal.Rd | 7 +- man/reporters.Rd | 3 + man/task_formats.Rd | 13 + man/task_graph_neighborhoods.Rd | 2 +- 35 files changed, 1004 insertions(+), 671 deletions(-) create mode 100644 R/package.R create mode 100644 R/report_ansi_tty.R delete mode 100644 R/reporter_ansi_tty.R delete mode 100644 R/reporter_ansi_tty2.R create mode 100644 R/task-formatting.R create mode 100644 Rplots.pdf delete mode 100644 man/PLAN.Rd create mode 100644 man/RELATION.Rd create mode 100644 man/checked-package.Rd create mode 100644 man/fmt.Rd create mode 100644 man/graph_dedup_attrs.Rd delete mode 100644 man/graph_project.Rd delete mode 100644 man/planned.Rd create mode 100644 man/task_formats.Rd diff --git a/NAMESPACE b/NAMESPACE index 981e15e..7d8563b 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,6 +1,8 @@ # Generated by roxygen2: do not edit by hand +S3method("$",enum) S3method("[",checked_results) +S3method(Ops,enum) S3method(as_desc,character) S3method(as_desc,check_task) S3method(as_desc,default) @@ -21,26 +23,30 @@ S3method(dep_tree,install_task) S3method(dep_tree,pkg_origin) S3method(flatten,default) S3method(flatten,subtasks_task) -S3method(format,filepath) S3method(format,lib_loc) S3method(format,listof) S3method(format,pkg_origin) +S3method(format,pkg_origin_base) +S3method(format,pkg_origin_local) +S3method(format,pkg_origin_source) +S3method(format,reporter_cell) +S3method(format,reporter_line) S3method(format,task) S3method(format_status_line_ansi,check_process) S3method(format_status_line_ansi,default) -S3method(friendly_class,task) -S3method(friendly_name,check_task) -S3method(friendly_name,default) -S3method(friendly_name,install_task) -S3method(friendly_name,library_task) -S3method(friendly_name,rev_dep_check_meta_task) -S3method(friendly_name,rev_dep_dep_meta_task) -S3method(friendly_name,task) +S3method(format_task_name,check_task) +S3method(format_task_name,default) +S3method(format_task_name,install_task) +S3method(format_task_name,rev_dep_check_meta_task) +S3method(format_task_name,rev_dep_dep_meta_task) +S3method(format_task_name,task) +S3method(format_task_type,task) S3method(install_params,pkg_origin) S3method(install_params,pkg_origin_archive) S3method(install_params,pkg_origin_base) S3method(install_params,pkg_origin_local) S3method(install_params,pkg_origin_repo) +S3method(is_type,default) S3method(is_type,list) S3method(is_type,process) S3method(is_type,task) @@ -66,14 +72,15 @@ S3method(print,task) S3method(report_finalize,"NULL") S3method(report_finalize,reporter_ansi_tty) S3method(report_finalize,reporter_basic_tty) -S3method(report_initialize,"NULL") -S3method(report_initialize,reporter_ansi_tty) -S3method(report_initialize,reporter_basic_tty) S3method(report_sleep,default) S3method(report_sleep,reporter_ansi_tty) +S3method(report_start_checks,reporter_ansi_tty) +S3method(report_start_setup,reporter_ansi_tty) S3method(report_status,"NULL") S3method(report_status,reporter_ansi_tty) S3method(report_status,reporter_basic_tty) +S3method(report_task_ansi_tty,check_task) +S3method(report_task_ansi_tty,rev_dep_check_meta_task) S3method(results,check_task) S3method(results,checker) S3method(results,list_check_task) @@ -95,6 +102,7 @@ export(check_rev_deps) export(check_task) export(checker) export(custom_install_task) +export(format_simplify_path) export(install_task) export(new_checker) export(new_rev_dep_checker) @@ -107,9 +115,15 @@ export(pkg_origin_repo) export(pkg_origin_unknown) export(plan_checks) export(plan_rev_dep_checks) +export(report_initialize.NULL) +export(report_initialize.reporter_basic_tty) +export(report_task.reporter_ansi_tty) export(reporter_ansi_tty) +export(reporter_ansi_tty2) export(reporter_basic_tty) +export(reporter_cell) export(reporter_default) +export(reporter_line) export(results) export(results_to_file) export(revdep_check_task) diff --git a/R/cli.R b/R/cli.R index f50c559..9014ccf 100644 --- a/R/cli.R +++ b/R/cli.R @@ -16,14 +16,19 @@ NULL #' @name cli cli_table_row <- function( - status, - ok = "OK", - notes = "N", - warnings = "W", - errors = "E", - msg = "", - title = FALSE) { + status = "", + ok = "OK", + notes = "N", + warnings = "W", + errors = "E", + msg = "", + style = c("row", "title", "header"), + symbols = list(bar = "\u2502") +) { + style <- match.arg(style) + cli_theme() + status <- trimws(as.character(status)) status <- switch(status, "1" = , @@ -37,7 +42,11 @@ cli_table_row <- function( "WARNING" = cli::format_inline("{.warn ?}"), "6" = , "ERROR" = cli::format_inline("{.err \u2a2f}"), - if (title) cli::col_none(cli::style_bold(status)) else status + switch(style, + "title" = cli::col_none(cli::style_bold(status)), + "header" = " ", + status + ) ) ok <- str_pad(ok, n = 2) @@ -45,19 +54,23 @@ cli_table_row <- function( warnings <- str_pad(warnings, n = 2) errors <- str_pad(errors, n = 2) - if (title) { - ok <- cli::col_none(cli::style_bold(ok)) - notes <- cli::col_none(cli::style_bold(notes)) - warnings <- cli::col_none(cli::style_bold(warnings)) - errors <- cli::col_none(cli::style_bold(errors)) - } else { - ok <- cli::format_inline("{.ok {ok}}") - notes <- cli::format_inline("{.note {notes}}") - warnings <- cli::format_inline("{.warn {warnings}}") - errors <- cli::format_inline("{.err {errors}}") - } + switch( + style, + "title" = { + ok <- cli::col_none(cli::style_bold(ok)) + notes <- cli::col_none(cli::style_bold(notes)) + warnings <- cli::col_none(cli::style_bold(warnings)) + errors <- cli::col_none(cli::style_bold(errors)) + }, + "row" = { + ok <- cli::format_inline("{.ok {ok}}") + notes <- cli::format_inline("{.note {notes}}") + warnings <- cli::format_inline("{.warn {warnings}}") + errors <- cli::format_inline("{.err {errors}}") + } + ) - fmt <- "\u2502 {status} \u2502 {ok} {notes} {warnings} {errors} \u2502 {msg}" + fmt <- "{symbols$bar} {status} {symbols$bar} {ok} {notes} {warnings} {errors} {symbols$bar} {msg}" # nolint cli::format_inline(fmt) } diff --git a/R/next_task.R b/R/next_task.R index 1b42332..ef28804 100644 --- a/R/next_task.R +++ b/R/next_task.R @@ -33,11 +33,7 @@ task_graph_libpaths <- function(g, node = NULL, lib.loc = .libPaths()) { } # iterate over tasks and derive a library location - task_lib <- lapply( - vs$task, - function(x, ...) lib(x, ...), lib.loc = lib.loc - ) - + task_lib <- lapply(vs$task, lib, lib.loc = lib.loc) unique(unlist(task_lib)) } @@ -90,7 +86,7 @@ start_task.install_task <- function( dependencies = FALSE, type = task$type, INSTALL_opts = c(), # TODO - log = path_package_install_log(output, friendly_name(task)), + log = path_package_install_log(output, format_task_name(task)), env = c() # TODO ) } @@ -133,7 +129,7 @@ start_task.check_task <- function( # TODO: make output directory names more user-friendly, for now the vertex # hash id is used to disambiguate output - output_dirname <- paste0(friendly_name(task), " <", node$name[[1]], ">") + output_dirname <- paste0(format_task_name(task), " <", node$name[[1]], ">") check_process$new( path = path, diff --git a/R/package.R b/R/package.R new file mode 100644 index 0000000..2eeb36f --- /dev/null +++ b/R/package.R @@ -0,0 +1,2 @@ +#' @importFrom igraph E V +"_PACKAGE" diff --git a/R/pkg_origin.R b/R/pkg_origin.R index 006c796..0c6159e 100644 --- a/R/pkg_origin.R +++ b/R/pkg_origin.R @@ -15,30 +15,32 @@ pkg_origin <- function(package, ..., .class = c()) { structure(list(package = package, ...), class = c(.class, "pkg_origin")) } -fmt_pkg_origin_source <- function(x, ...) { +#' @export +format.pkg_origin_source <- function(x, ...) { if (is.null(x$source)) { - "" + character(0L) } else if (is.null(names(x$source))) { - format(x$source, ..., pretty = TRUE) + format(x$source, ...) } else { names(x$source) } } #' @export -format.pkg_origin <- function(x, ..., short = FALSE) { - paste(collapse = " ", c( - x$package, - if (!short && !is.null(x$version)) { - switch(class(x$version)[[1]], - package_version = paste0("(v", format(x$version), ")"), - x$version - ) - }, - if (!short && !is.null(x$source)) { - paste0("from ", fmt_pkg_origin_source(x)) - } - )) +format.pkg_origin_local <- function(x, ...) { + simple_paths <- format_simplify_path(x$source) + names(x$source) <- simple_paths + x$source +} + +#' @export +format.pkg_origin_base <- function(x, ...) { + character(0L) +} + +#' @export +format.pkg_origin <- function(x, ...) { + format(x$source, ...) } #' @export @@ -79,8 +81,10 @@ try_pkg_origin_repo <- function(package, repos, ...) { #' @export #' @rdname pkg_origin pkg_origin_is_base <- function(package, ...) { - package %in% installed.packages()[, "Package"] && - installed.packages()[package, "Priority"] == "base" + is_base <- package == "R" + is_inst <- package %in% installed.packages()[, "Package"] + is_base[is_inst] <- installed.packages()[package[is_inst], "Priority"] == "base" # nolint + is_base } diff --git a/R/plan.R b/R/plan.R index 85673c3..fb7e2b1 100644 --- a/R/plan.R +++ b/R/plan.R @@ -96,7 +96,7 @@ plan_rev_dep_checks <- function( rev_dep_dev_check_tasks <- lapply( revdeps, plan_rev_dep_dev_check, - path = path, + origin = pkg_origin_local(path), repos = repos ) @@ -104,6 +104,7 @@ plan_rev_dep_checks <- function( rev_dep_release_check_tasks <- lapply( revdeps[revdeps %in% ap[, "Package"]], plan_rev_dep_release_check, + origin = pkg_origin_local(path), repos = repos ) @@ -115,25 +116,27 @@ plan_rev_dep_checks <- function( )) # combine component plans into an overall plan - g <- merge_subgraphs(c( - list(task), + g <- graph_dedup_attrs(igraph::union( + task, rev_dep_dev_check_tasks, rev_dep_release_check_tasks )) # reconstruct edges from planned root node to individual checks edges <- as.vector(rbind(task_id, rev_dep_meta_task_ids)) - g <- igraph::add_edges(g, edges = edges, attr = list(type = EDGE$dep)) + g <- igraph::add_edges(g, edges = edges, attr = list(relation = RELATION$dep)) class(g) <- c("task_graph", class(g)) g } -plan_rev_dep_dev_check <- function(path, revdep, repos) { +plan_rev_dep_dev_check <- function(origin, revdep, repos) { rev_dep_origin <- pkg_origin_repo(package = revdep, repos = repos) - origin <- pkg_origin_local(path = path) g <- sequence_graph(task = list( - make_unique_task(seed = revdep, meta_task(.subclass = "rev_dep_check")), + make_unique_task(seed = revdep, meta_task( + origin = origin, + .subclass = "rev_dep_check" + )), make_unique_task(seed = "dev", check_task( origin = rev_dep_origin, env = DEFAULT_R_CMD_CHECK_ENVVARS, @@ -144,16 +147,21 @@ plan_rev_dep_dev_check <- function(path, revdep, repos) { )) # this check is reported through a rev dep check meta task - E(g)$type <- EDGE$dep - g <- igraph::add_edges(g, edges = c(2, 1), attr = list(type = EDGE$report)) + .to <- NULL # used by igraph NSE + g <- igraph::add_edges(g, edges = c(2, 1)) # NOTE: coerces factor to numeric + igraph::E(g)$relation <- RELATION$dep + igraph::E(g)[.to(1)]$relation <- RELATION$report g } -plan_rev_dep_release_check <- function(revdep, repos) { +plan_rev_dep_release_check <- function(origin, revdep, repos) { rev_dep_origin <- pkg_origin_repo(package = revdep, repos = repos) g <- sequence_graph(task = list( - make_unique_task(seed = revdep, meta_task(.subclass = "rev_dep_check")), + make_unique_task(seed = revdep, meta_task( + origin = origin, + .subclass = "rev_dep_check" + )), make_unique_task(seed = "release", check_task( origin = rev_dep_origin, env = DEFAULT_R_CMD_CHECK_ENVVARS, @@ -163,8 +171,10 @@ plan_rev_dep_release_check <- function(revdep, repos) { )) # this check is reported through a rev dep check meta task - E(g)$type <- EDGE$dep - g <- igraph::add_edges(g, edges = c(2, 1), attr = list(type = EDGE$report)) + .to <- NULL # used by igraph + g <- igraph::add_edges(g, edges = c(2, 1)) # NOTE: coerces factor to numeric + igraph::E(g)$relation <- RELATION$dep + igraph::E(g)[.to(1)]$relation <- RELATION$report g } diff --git a/R/report_ansi_tty.R b/R/report_ansi_tty.R new file mode 100644 index 0000000..40f7f42 --- /dev/null +++ b/R/report_ansi_tty.R @@ -0,0 +1,449 @@ +report_task <- function(reporter, g, v) { + UseMethod("report_task") +} + +#' @export +report_task.reporter_ansi_tty <- function(reporter, g, v) { + UseMethod("report_task_ansi_tty", v$task) +} + +report_task_ansi_tty <- report_task.reporter_ansi_tty + +format_status_line_ansi <- function(process, ...) { + UseMethod("format_status_line_ansi") +} + +#' @export +format_status_line_ansi.check_process <- function( + process, + ..., + width = getOption("width", 80L)) { + checks <- process$get_checks() + + # runtime of process + process_time <- paste0(format_time(process$get_duration()), " ") + + # runtime of current check (only displayed if >30s) + check_time <- Sys.time() - process$get_time_last_check_start() + if (length(check_time) == 0 || check_time < difftime(30, 0)) { + check_time <- "" + } else { + check_time <- cli::col_grey("(", format_time(check_time), ") ") + } + + msg <- "" + status <- max(as.numeric(checks), -1) + if (length(checks) == 0) { + # have not hit checks yet + msg <- "starting ..." + status <- process$spin() + } else if (process$is_alive()) { + # processing checks + msg <- paste("checking", names(utils::tail(checks, 1)), "...") + status <- process$spin() + process_time <- cli::col_cyan(process_time) + } else { + # done + process_time <- cli::col_grey(process_time) + } + + msg <- cli::format_inline("{process_time}{check_time}{msg}") + counts <- table(process$get_checks()) + out <- cli_table_row( + status = status, + ok = counts[["NONE"]] + counts[["OK"]], + notes = counts[["NOTE"]], + warnings = counts[["WARNING"]], + errors = counts[["ERROR"]], + msg + ) + + cli::ansi_substring(out, 1, width) +} + +#' @export +format_status_line_ansi.default <- function( + process, + ..., + width = getOption("width", 80L)) { + out <- cli_table_row( + status = "NONE", + ok = 0, + notes = 0, + warnings = 0, + errors = 0, + "restored from system file." + ) + + cli::ansi_substring(out, 1, width) +} + +#' @export +reporter_line <- function(label, status, style = NA_character_) { + structure( + list(label = label, status = status, style = style), + class = "reporter_line" + ) +} + +#' @export +format.reporter_line <- function(x, width = cli::console_width()) { + rule <- switch(x$style, + "h1" = "\u2550", + " " + ) + + label <- format(x$label, pad = rule) + + status <- switch( + x$style, + "h1" = gsub(" ", rule, cli_table_row( + ok = "", + notes = "", + warnings = "", + errors = "", + style = "header", + symbols = list(bar = "\u256A") + )), + x$status + ) + + out <- paste0(label, status, strrep(rule, width)) + out <- cli::ansi_substr(out, 1, width) + + out +} + +#' @export +reporter_cell <- function( + content, + justify = "left", + padding = c(0, 0), + width = Inf +) { + structure( + content, + justify = justify, + padding = padding, + width = width, + class = "reporter_cell" + ) +} + +#' @export +format.reporter_cell <- function(x, + padding = attr(x, "padding") %||% c(0, 0), + justify = attr(x, "justify") %||% "right", + width = attr(x, "width") %||% cli::console_width(), + pad = " " +) { + n <- width - sum(padding) - cli::ansi_nchar(x) + paste0( + if (!is.null(justify) && justify == "right") strrep(pad, n), + if (!is.null(justify) && justify == "center") strrep(pad, (n - n %/% 2)), + strrep(pad, padding[[1]]), + x, + strrep(pad, padding[[2]]), + if (!is.null(justify) && justify == "center") strrep(pad, n %/% 2), + if (!is.null(justify) && justify == "left") strrep(pad, n) + ) +} + +#' @export +report_task_ansi_tty.rev_dep_check_meta_task <- function(reporter, g, v) { + # package being rev-dep-check'ed + package <- v$task$origin$package + + # subset for dependency edges from rev dep task + dep_edges <- E(g)$relation == as.numeric(RELATION$dep) + dep_g <- igraph::subgraph_from_edges(g, which(dep_edges)) + + # get individual rev dep checks, and get their trees + check_nodes <- igraph::neighbors(dep_g, v$name, "out") + check_neighborhoods <- igraph::make_neighborhood_graph( + dep_g, + order = length(dep_g), + check_nodes, + mode = "out" + ) + + # TODO: would be nice to reintroduce `package` as a vertex attribute, maybe + # remove from `pkg_origin`? + package_tasks <- lapply( + check_neighborhoods, + function(g) { + is_dep <- vlapply(V(g)$task, function(i) i$origin$package == package) + V(g)[is_dep][[1]]$task + } + ) + + package_task_labels <- lapply( + package_tasks, + function(t) { + reporter_cell( + fmt(task = t, "+{package} {version} {source.type}"), + width = reporter$label_nchar + ) + } + ) + + rev_dep_check_nodes <- get_reporter_node(g, v, mode = "in") + rev_dep <- fmt(task = rev_dep_check_nodes[[1]]$task, " {package} ") + to_report <- mapply( + function(label, i) { + x <- report_task_ansi_tty(reporter = reporter, g = g, v = V(g)[[i]]) + x$label <- label + x + }, + package_task_labels, + rev_dep_check_nodes, + SIMPLIFY = FALSE + ) + + to_report <- append( + to_report, + after = 0L, + list(reporter_line( + style = "h1", + label = reporter_cell( + rev_dep, + width = reporter$label_nchar, + padding = c(2, 2) + ), + status = NA_character_ + )) + ) + + to_report +} + +#' @export +report_task_ansi_tty.check_task <- function(reporter, g, v) { + package <- fmt(task = v$task, "{package}") + reporter_line( + label = reporter_cell( + package, + justify = "right", + width = reporter$label_nchar + ), + status = format_status_line_ansi(v$process) + ) +} + +#' @export +report_sleep.reporter_ansi_tty <- function( + reporter, + checker, + sleep = default_tty_tick_interval() +) { + Sys.sleep(sleep) +} + +#' @export +report_start_setup.reporter_ansi_tty <- function( + reporter, + checker, + message, + envir = parent.frame() +) { + # hide cursor when initializer enters, ensure its restored even if interrupted + cli::ansi_hide_cursor() + do.call( + on.exit, + list(quote(cli::ansi_show_cursor()), add = TRUE), + envir = envir + ) + + cli::cli_progress_message( + message, + clear = FALSE, + auto_terminate = FALSE, + .auto_close = FALSE, + .envir = reporter, + ) +} + +get_reporter_node <- function(g, v, mode = "out") { + end <- if (mode == "out") igraph::head_of else igraph::tail_of + v_es <- igraph::incident_edges(g, v, mode = mode) + v_rep <- simplify2array(lapply(v_es, function(es) { + eidx <- es$relation == RELATION$report + as.numeric(end(g, es[eidx])) + })) + V(g)[ifelse(is.na(v_rep), as.numeric(v), v_rep)] +} + +reporter_ansi_tty_get_label_nchar <- function( + reporter, + checker, + envir = parent.frame() +) { + # pre-calculate the maximum space needed for label column + v <- igraph::V(checker$graph) + v_report <- unique(get_reporter_node(checker$graph, v[is_check(v$task)])) + + # for each reporter, produce output + output <- unlist(recursive = FALSE, lapply( + v_report, + function(v) report_task(reporter, checker$graph, V(checker$graph)[[v]]) + )) + + labels <- unlist(lapply(output, function(x) format(x$label, justify = NULL))) + max(cli::ansi_nchar(labels)) +} + +#' @export +report_start_checks.reporter_ansi_tty <- function( + reporter, + checker, + envir = parent.frame() +) { + # store our current console width, used to trigger complete re-draw + reporter$width <- cli::console_width() + + # derive the longest label, used for spacing table + reporter$label_nchar <- + reporter_ansi_tty_get_label_nchar(reporter, checker, envir) + + # helper function for adding new buffer entries + reporter$buffer_proto <- function(node = "") { + df <- data.frame( + # tracking columns + node = node, # reporter node name + new = TRUE, # whether node is newly added (requires newlines) + updated = NA # whether output needs to be updated + ) + + # output columns + df$line <- list(NULL) + df + } + + # initialize our buffer of output + reporter$buffer <- reporter$buffer_proto()[c(), ] + + reporter$buffer_update <- function(node, lines) { + if (!node %in% reporter$buffer$node) { + proto_df <- reporter$buffer_proto(node)[rep_len(1L, length(lines)), ] + reporter$buffer <- rbind(reporter$buffer, proto_df) + } + + is_node <- which(reporter$buffer$node == node) + reporter$buffer$updated[is_node] <- TRUE + reporter$buffer$line[is_node] <- lines + } + + # helper to update buffer for a specific node + reporter$buffer_report <- function(node) { + node <- V(checker$graph)[node][[1]] + to_report <- report_task(reporter, checker$graph, node) + output <- vcapply(to_report, format) + reporter$buffer_update(node, output) + } + + # hide cursor when initializer enters, ensure its restored even if interrupted + cli::ansi_hide_cursor() + do.call( + on.exit, + list(quote(cli::ansi_show_cursor()), add = TRUE), + envir = envir + ) + + cli::cli_progress_bar( + type = "custom", + extra = list(message = ""), + format = paste( + "ETA {cli::pb_eta}", + "({cli::pb_current}/{cli::pb_total})", + "[{cli::pb_elapsed}]", + "{cli::pb_extra$message}" + ), + format_done = "Finished in {cli::pb_elapsed}", + total = sum(igraph::V(checker$graph)$type == "check"), + clear = FALSE, + auto_terminate = FALSE, + .auto_close = FALSE, + .envir = reporter, + ) +} + +#' @importFrom igraph V +#' @export +report_status.reporter_ansi_tty <- function(reporter, checker, envir) { + v <- igraph::V(checker$graph) + v_checks <- v[is_check(v$task)] + + # add newly started task status + updated <- which( + v_checks$status > STATUS$pending | ( + v_checks$status == STATUS$done & + !v_checks$name %in% reporter$buffer$node + ) + ) + + # skip if no updates + if (length(updated) <= 0L) { + return() + } + + # find any reporter nodes for updated checks + updated <- unique(get_reporter_node(checker$graph, v_checks[updated])) + + # print header if this is the first status line of the reporter + if (nrow(reporter$buffer) == 0L) { + reporter$buffer_update( + node = "HEADER", + list(reporter_line( + label = reporter_cell("", width = reporter$label_nchar), + status = cli_table_row("S", "OK", "N", "W", "E", style = "title") + )) + ) + } + + for (node_name in updated$name) { + reporter$buffer_report(node_name) + } + + # if console width has changed, redraw all + if (identical(reporter$width, cli::console_width)) { + reporter$buffer$updated <- TRUE + } + + # introduce newlines for newly added reporter rows + buffer <- strrep("\n", sum(reporter$buffer$new)) + reporter$buffer$new <- FALSE + + # for each not-yet finished task, report status + for (idx in which(reporter$buffer$updated)) { + # derive reporter information + n_lines <- nrow(reporter$buffer) - idx + 1L + + # report status line + buffer <- paste0( + buffer, + ansi_move_line_rel(n_lines), + ansi_line_erase(), + format(reporter$buffer$line[[idx]]), + ansi_move_line_rel(-n_lines), + sep = "" + ) + } + + reporter$width <- cli::console_width() + reporter$buffer$updated <- FALSE + cat(buffer) + + n_finished <- sum(v$status[v$type == "check"] >= STATUS$done) + cli::cli_progress_update( + set = n_finished, + extra = list(message = ""), + .envir = reporter + ) +} + +#' @export +report_finalize.reporter_ansi_tty <- function(reporter, checker) { + report_status(reporter, checker) # report completions of final processes + cli::cli_progress_done(.envir = reporter) + cli::ansi_show_cursor() +} diff --git a/R/reporter.R b/R/reporter.R index c3d8299..d07f954 100644 --- a/R/reporter.R +++ b/R/reporter.R @@ -91,8 +91,13 @@ report_sleep.default <- function(reporter, design, sleep = 1) { } #' @rdname reporters-internal -report_initialize <- function(reporter, design, envir = parent.frame()) { - UseMethod("report_initialize") +report_start_setup <- function(reporter, design, ..., envir = parent.frame()) { + UseMethod("report_start_setup") +} + +#' @rdname reporters-internal +report_start_checks <- function(reporter, design, ..., envir = parent.frame()) { + UseMethod("report_start_checks") } #' @rdname reporters-internal diff --git a/R/reporter_ansi_tty.R b/R/reporter_ansi_tty.R deleted file mode 100644 index c789d3d..0000000 --- a/R/reporter_ansi_tty.R +++ /dev/null @@ -1,222 +0,0 @@ -format_status_line_ansi <- function(process, ...) { - UseMethod("format_status_line_ansi") -} - -#' @export -format_status_line_ansi.check_process <- function( - process, - ..., - width = getOption("width", 80L) -) { - checks <- process$get_checks() - - # runtime of process - process_time <- paste0(format_time(process$get_duration()), " ") - - # runtime of current check (only displayed if >30s) - check_time <- Sys.time() - process$get_time_last_check_start() - if (length(check_time) == 0 || check_time < difftime(30, 0)) { - check_time <- "" - } else { - check_time <- cli::col_grey("(", format_time(check_time), ") ") - } - - msg <- "" - status <- max(as.numeric(checks), -1) - if (length(checks) == 0) { - # have not hit checks yet - msg <- "starting ..." - status <- process$spin() - } else if (process$is_alive()) { - # processing checks - msg <- paste("checking", names(utils::tail(checks, 1)), "...") - status <- process$spin() - process_time <- cli::col_cyan(process_time) - } else { - # done - process_time <- cli::col_grey(process_time) - } - - msg <- cli::format_inline("{process_time}{check_time}{msg}") - counts <- table(process$get_checks()) - out <- cli_table_row( - status = status, - ok = counts[["NONE"]] + counts[["OK"]], - notes = counts[["NOTE"]], - warnings = counts[["WARNING"]], - errors = counts[["ERROR"]], - msg - ) - - cli::ansi_substring(out, 1, width) -} - -#' @export -format_status_line_ansi.default <- function( - process, - ..., - width = getOption("width", 80L)) { - out <- cli_table_row( - status = "NONE", - ok = 0, - notes = 0, - warnings = 0, - errors = 0, - "restored from system file." - ) - - cli::ansi_substring(out, 1, width) -} - -#' @export -report_sleep.reporter_ansi_tty <- function( - reporter, - design, - sleep = default_tty_tick_interval()) { - Sys.sleep(sleep) -} - -#' @export -report_initialize.reporter_ansi_tty <- function( - reporter, - design, - envir = parent.frame() -) { - # named factor vector, names as task aliases and value of last reported status - reporter$header <- TRUE - reporter$status <- STATUS$done[c()] - - # hide cursor when initializer enters, ensure its restored even if interrupted - cli::ansi_hide_cursor() - do.call( - on.exit, - list(quote(cli::ansi_show_cursor()), add = TRUE), - envir = envir - ) - - cli::cli_progress_bar( - type = "custom", - extra = list(message = ""), - format = "ETA {cli::pb_eta} ({cli::pb_current}/{cli::pb_total}) [{cli::pb_elapsed}] {cli::pb_extra$message}", # nolint - format_done = "Finished in {cli::pb_elapsed}", - total = sum(igraph::V(design$graph)$type == "check"), - clear = FALSE, - auto_terminate = FALSE, - .auto_close = FALSE, - .envir = reporter, - ) -} - -#' @importFrom igraph V -#' @export -report_status.reporter_ansi_tty <- function(reporter, design, envir) { - v <- igraph::V(design$graph) - v_checks <- v[is_check(v$task)] - n_char_titles <- max(nchar(vcapply(v_checks$task, friendly_name, short = 2L))) - failed_tasks <- design$failed_tasks() - failed_packages <- failed_tasks[is_install(failed_tasks)] - - # add newly started task status - new_idx <- which(v_checks$status > STATUS$pending) - new_idx <- new_idx[!v_checks$name[new_idx] %in% names(reporter$status)] - if (length(new_idx) > 0) { - # print header if this is the first status line of the reporter - if (reporter$header) { - cat( - ansi_line_erase(), - strrep(" ", n_char_titles + 2), - cli_table_row("S", "OK", "N", "W", "E", title = TRUE), - "\n", - sep = "" - ) - reporter$header <- FALSE - } - - # always start by reporting in progress, even if finished before reporting - new <- rep_len(STATUS$`in progress`, length(new_idx)) - names(new) <- v_checks$name[new_idx] - reporter$status <- c(reporter$status, new) - cat(strrep("\n", length(new_idx))) - } - - if (length(reporter$failed_packaged) != length(failed_packages)) { - # Add failed packages warning to the buffer - failures_buffer <- rev(unlist(lapply(failed_packages, function(x) { - list( - cli_wrap_lines(cli::cli_fmt(cli::cli_alert_danger( - sprintf("%s package installation had non-zero exit status", x$name) - ))), - cli_wrap_lines(as.character(cli::style_dim( - sprintf("log: %s", x$process[[1]]$log) - ))) - ) - }))) - - reporter$failures_buffer <- vcapply( - seq_along(failures_buffer), - function(i) { - paste0( - ansi_move_line_rel(i), - ansi_line_erase(), - failures_buffer[i], - ansi_move_line_rel(-i), - sep = "" - ) - } - ) - - # For performance store these value in the environment to redraw warnings - # buffer only when necessary - reporter$failed_packaged <- failed_packages - } - - # for each not-yet finished task, report status - buffer <- "" - for (idx in seq_along(reporter$status)) { - # update reported status - alias <- names(reporter$status)[[idx]] - v_idx <- which(v_checks$name == alias) - reporter$status[[idx]] <- v_checks$status[[v_idx]] - - # derive reporter information - n_lines <- length(reporter$status) - idx + 1L - width <- cli::console_width() - n_char_titles - 2L - task_name <- friendly_name(v_checks[[v_idx]]$task, short = 2L) - process <- task_graph_task_process(design$graph, v_checks[[v_idx]]) - - # report status line - buffer <- paste0( - buffer, - ansi_move_line_rel(n_lines + length(reporter$failures_buffer)), - ansi_line_erase(), - " ", strrep(" ", n_char_titles - nchar(task_name)), task_name, " ", - format_status_line_ansi(process, width = width), - ansi_move_line_rel(-(n_lines + length(reporter$failures_buffer))), - sep = "" - ) - } - - cat(paste0(buffer, reporter$failures_buffer)) - - is_inst <- is_install(design$active_processes()) - inst_pkgs <- names(design$active_processes()[is_inst]) - if (length(inst_pkgs)) { - inst_msg <- paste0("installing ", paste0(inst_pkgs, collapse = ", ")) - } else { - inst_msg <- "" - } - - n_finished <- sum(v$status[v$type == "check"] >= STATUS$done) - cli::cli_progress_update( - set = n_finished, - extra = list(message = inst_msg), - .envir = reporter - ) -} - -#' @export -report_finalize.reporter_ansi_tty <- function(reporter, design) { - report_status(reporter, design) # report completions of final processes - cli::cli_progress_done(.envir = reporter) - cli::ansi_show_cursor() -} diff --git a/R/reporter_ansi_tty2.R b/R/reporter_ansi_tty2.R deleted file mode 100644 index b195b41..0000000 --- a/R/reporter_ansi_tty2.R +++ /dev/null @@ -1,153 +0,0 @@ -#' @export -report_sleep.reporter_ansi_tty2 <- function( - reporter, - checker, - sleep = default_tty_tick_interval() -) { - Sys.sleep(sleep) -} - -#' @export -report_initialize.reporter_ansi_tty2 <- function( - reporter, - checker, - envir = parent.frame() -) { - # named factor vector, names as task aliases and value of last reported status - reporter$header <- TRUE - reporter$status <- STATUS$done[c()] - - # hide cursor when initializer enters, ensure its restored even if interrupted - cli::ansi_hide_cursor() - do.call( - on.exit, - list(quote(cli::ansi_show_cursor()), add = TRUE), - envir = envir - ) - - cli::cli_progress_bar( - type = "custom", - extra = list(message = ""), - format = "ETA {cli::pb_eta} ({cli::pb_current}/{cli::pb_total}) [{cli::pb_elapsed}] {cli::pb_extra$message}", # nolint - format_done = "Finished in {cli::pb_elapsed}", - total = sum(igraph::V(checker$graph)$type == "check"), - clear = FALSE, - auto_terminate = FALSE, - .auto_close = FALSE, - .envir = reporter, - ) -} - -#' @importFrom igraph V -#' @export -report_status.reporter_ansi_tty2 <- function(reporter, checker, envir) { - v <- igraph::V(checker$graph) - v_checks <- v[is_check(v$task)] - n_char_titles <- max(nchar(vcapply(v_checks$task, friendly_name, short = 2L))) - failed_tasks <- checker$failed_tasks() - failed_packages <- failed_tasks[is_install(failed_tasks)] - - # add newly started task status - new_idx <- which(v_checks$status > STATUS$pending) - new_idx <- new_idx[!v_checks$name[new_idx] %in% names(reporter$status)] - if (length(new_idx) > 0) { - # print header if this is the first status line of the reporter - if (reporter$header) { - cat( - ansi_line_erase(), - strrep(" ", n_char_titles + 2), - cli_table_row("S", "OK", "N", "W", "E", title = TRUE), - "\n", - sep = "" - ) - reporter$header <- FALSE - } - - # always start by reporting in progress, even if finished before reporting - new <- rep_len(STATUS$`in progress`, length(new_idx)) - names(new) <- v_checks$name[new_idx] - reporter$status <- c(reporter$status, new) - cat(strrep("\n", length(new_idx))) - } - - if (length(reporter$failed_packaged) != length(failed_packages)) { - # Add failed packages warning to the buffer - failures_buffer <- rev(unlist(lapply(failed_packages, function(x) { - list( - cli_wrap_lines(cli::cli_fmt(cli::cli_alert_danger( - sprintf("%s package installation had non-zero exit status", x$name) - ))), - cli_wrap_lines(as.character(cli::style_dim( - sprintf("log: %s", x$process[[1]]$log) - ))) - ) - }))) - - reporter$failures_buffer <- vcapply( - seq_along(failures_buffer), - function(i) { - paste0( - ansi_move_line_rel(i), - ansi_line_erase(), - failures_buffer[i], - ansi_move_line_rel(-i), - sep = "" - ) - } - ) - - # For performance store these value in the environment to redraw warnings - # buffer only when necessary - reporter$failed_packaged <- failed_packages - } - - # for each not-yet finished task, report status - buffer <- "" - for (idx in seq_along(reporter$status)) { - # update reported status - alias <- names(reporter$status)[[idx]] - v_idx <- which(v_checks$name == alias) - reporter$status[[idx]] <- v_checks$status[[v_idx]] - - # derive reporter information - n_lines <- length(reporter$status) - idx + 1L - width <- cli::console_width() - n_char_titles - 2L - task_name <- friendly_name(v_checks[[v_idx]]$task, short = 2L) - process <- task_graph_task_process(checker$graph, v_checks[[v_idx]]) - - # report status line - buffer <- paste0( - buffer, - ansi_move_line_rel(n_lines + length(reporter$failures_buffer)), - ansi_line_erase(), - " ", strrep(" ", n_char_titles - nchar(task_name)), task_name, " ", - format_status_line_ansi(process, width = width), - ansi_move_line_rel(-(n_lines + length(reporter$failures_buffer))), - sep = "" - ) - } - - cat(paste0(buffer, reporter$failures_buffer)) - - is_inst <- is_install(checker$active_processes()) - inst_pkgs <- names(checker$active_processes()[is_inst]) - if (length(inst_pkgs)) { - inst_msg <- paste0("installing ", paste0(inst_pkgs, collapse = ", ")) - } else { - inst_msg <- "" - } - - n_finished <- sum(v$status[v$type == "check"] >= STATUS$done) - cli::cli_progress_update( - set = n_finished, - extra = list(message = inst_msg), - .envir = reporter - ) -} - -#' @export -report_finalize.reporter_ansi_tty2 <- function(reporter, checker) { - report_status(reporter, checker) # report completions of final processes - cli::cli_progress_done(.envir = reporter) - cli::ansi_show_cursor() -} diff --git a/R/reporter_basic_tty.R b/R/reporter_basic_tty.R index dc73453..b915034 100644 --- a/R/reporter_basic_tty.R +++ b/R/reporter_basic_tty.R @@ -75,7 +75,7 @@ report_status.reporter_basic_tty <- function(reporter, design, envir) { ) time <- Sys.time() - reporter$time_start # nolint (used via glue) - type <- friendly_class(node$task) # nolint (used via glue) + type <- format_task_type(node$task) # nolint (used via glue) prefix <- cli::col_cyan("[{format_time(time)}][{type}] ") cli::cli_text(prefix, "{.pkg {node$package}} {status}") reporter$statuses[[node$name]] <- node$status diff --git a/R/run.R b/R/run.R index 636148c..f9a0ff4 100644 --- a/R/run.R +++ b/R/run.R @@ -19,6 +19,7 @@ run <- function(checker, ..., reporter = reporter_default()) { #' @export run.character <- function(checker, ..., reporter = reporter_default()) { + report_start_setup(reporter, checker, message = "planning checks ...") run(new_rev_dep_checker(checker, ...), reporter = reporter) } @@ -29,7 +30,7 @@ run.checker <- function(checker, ..., reporter = reporter_default()) { report_finalize(reporter, checker) }) - report_initialize(reporter, checker) + report_start_checks(reporter, checker) while (checker$step()) { report_status(reporter, checker) report_sleep(reporter, checker) diff --git a/R/task-formatting.R b/R/task-formatting.R new file mode 100644 index 0000000..383ec98 --- /dev/null +++ b/R/task-formatting.R @@ -0,0 +1,55 @@ +#' @export +format.task <- function(x, ..., indent = 0L) { + fmt(task = x, "{action} {package} {version} {source}") +} + +#' @export +format_task_name.task <- function(x, ...) { + "task" +} + +format_task_name <- function(x, ...) { + UseMethod("format_task_name") +} + +#' @export +format_task_name.default <- function(x, ...) { + stop( + "Dont' know how to name object with class(es) `", + deparse(class(x)), + "`" + ) +} + +format_task_type <- function(x, ...) { + UseMethod("format_task_type") +} + +#' @export +format_task_type.task <- function(x, ...) { + sub("_task$", "", class(x)[[1]]) +} + +#' @export +format_task_name.install_task <- function(x, ..., short = FALSE) { + paste0(if (!short) "install ", format(x$origin, ..., short = short)) +} + +#' @export +format_task_name.check_task <- function(x, ...) { + paste0("check ", format(x$origin, ...)) +} + +#' @export +format_task_name.rev_dep_dep_meta_task <- function(x, ..., short = FALSE) { + paste0( + "check ", + format(x$origin, ..., short = short), + if (short) " revdeps" else " reverse-dependencies" + ) +} + +#' @export +format_task_name.rev_dep_check_meta_task <- function(x, ..., short = FALSE) { + paste0("check ", if (short) "revdep" else "reverse-dependency") +} diff --git a/R/task.R b/R/task.R index 2289ecb..dfc9432 100644 --- a/R/task.R +++ b/R/task.R @@ -34,7 +34,7 @@ make_unique_task <- function(task, seed = runif(1)) { #' @family tasks #' @export lib.task <- function(x, ...) { - stop("Don't know how to determine a library path for generic task") + character(0L) } #' @family tasks @@ -43,45 +43,6 @@ print.task <- function(x, ...) { cat(format(x, ...), "\n") } -#' @export -format.task <- function(x, ..., indent = 0L) { - paste(collapse = "\n", c( - paste0(strrep(" ", indent * 2), "<", friendly_name(x, ...), ">"), - vcapply(x$tasks, function(xi) format(xi, ..., indent = indent + 1)) - )) -} - -#' @export -friendly_name.task <- function(x, ...) { - "task" -} - -friendly_name <- function(x, ...) { - UseMethod("friendly_name") -} - -#' @export -friendly_name.default <- function(x, ...) { - stop( - "Dont' know how to name object with class(es) `", - deparse(class(x)), - "`" - ) -} - -#' @export -friendly_class.task <- function(x, ...) { - if (length(class(x)) > 1) { - sub("_task$", "", class(x)[[1]]) - } else { - class(x)[[1]] - } -} - -friendly_class <- function(x, ...) { - UseMethod("friendly_class") -} - #' Create a task to install a package and dependencies #' #' @param ... Additional parameters passed to [`task()`] @@ -113,15 +74,13 @@ lib.install_task <- function(x, ...) { lib(x$lib, name = hash(x), ...) } -#' @export -friendly_name.install_task <- function(x, ..., short = FALSE) { - paste0(if (!short) "install ", format(x$origin, ..., short = short)) -} - is_type <- function(x, type) { UseMethod("is_type") } +#' @export +is_type.default <- inherits + #' @export is_type.list <- function(x, type) { vlapply(x, is_type, type = type) @@ -183,12 +142,6 @@ is_check_task <- function(x) { inherits(x, "check_task") } -#' @family tasks -#' @export -friendly_name.check_task <- function(x, ...) { - paste0("check ", format(x$origin, ...)) -} - #' Specify a library install #' #' A declarative task that specifies a set of packages that should be installed @@ -204,38 +157,6 @@ library_task <- function(origins = list(), loc = lib_loc_default(), ...) { task } -#' @export -friendly_name.library_task <- function(x, ...) { - fmt_pkgs <- if (length(x$origins) == 0) { - } else if (length(x$origins) <= 3) { - paste0( - " with ", - paste0(collapse = ", ", vcapply( - x$origins, - function(pkg) format(pkg, short = TRUE) - )) - ) - } else { - paste0(" with ", length(x$origins), " packages") - } - - paste0(format(x$loc), fmt_pkgs) -} - -#' @export -friendly_name.rev_dep_dep_meta_task <- function(x, ..., short = FALSE) { - paste0( - "check ", - format(x$origin, ..., short = short), - if (short) " revdeps" else " reverse-dependencies" - ) -} - -#' @export -friendly_name.rev_dep_check_meta_task <- function(x, ..., short = FALSE) { - paste0("check ", if (short) "revdep" else "reverse-dependency") -} - #' Create a task to run reverse dependency checks #' #' @param revdep character indicating whether the task specification describes diff --git a/R/task_graph.R b/R/task_graph.R index 69b64c3..3c8aaf7 100644 --- a/R/task_graph.R +++ b/R/task_graph.R @@ -23,10 +23,13 @@ #' } #' @keywords internal task_graph_create <- function(plan, repos = getOption("repos")) { - check_tasks <- igraph::V(plan)[is_check(igraph::V(plan)$task)] + # only use dependency edges when populating graph + dep_g <- dep_subgraph(plan) + check_tasks <- igraph::V(dep_g)[is_check(igraph::V(dep_g)$task)] + check_task_neighborhoods <- igraph::neighborhood( - plan, - order = length(plan), + dep_g, + order = length(dep_g), mode = "out", nodes = check_tasks ) @@ -34,32 +37,30 @@ task_graph_create <- function(plan, repos = getOption("repos")) { # for each check task in the plan, build a dependency tree and merge it # into the existing check task subtree check_task_neighborhoods <- lapply(check_task_neighborhoods, function(nh) { - subtree <- igraph::induced_subgraph(plan, nh) - V(subtree)$package <- vcapply( + subtree <- igraph::induced_subgraph(dep_g, nh) + V(subtree)$name <- vcapply( V(subtree)$task, function(i) i$origin$package %||% NA_character_ ) + # build dependency graph, with fallback installation task + # TODO: if this is too slow, could move after all neighborhoods are merged deps <- dep_tree(nh[[1]]$task) igraph::reverse_edges(deps) - - subtree <- graph_project( - x = deps, - onto = subtree, - where = c("name" = "package") - ) - - # set missing dependencies to be installed from repo - missing_task <- is.na(igraph::V(subtree)$task) - igraph::V(subtree)$task[missing_task] <- lapply( - igraph::V(subtree)$package[missing_task], + igraph::E(deps)$relation <- RELATION$dep + igraph::V(deps)$task <- lapply( + igraph::V(deps)$name, function(package) { origin <- try_pkg_origin_repo(package = package, repos = repos) install_task(origin = origin) } ) - # re-hash tasks as vertex names (populate missing vertex names) + # merge trees on package names + # NOTE: attributes (tasks) are preserved in the order they appear + subtree <- graph_dedup_attrs(igraph::union(subtree, deps)) + + # re-hash tasks as vertex names igraph::V(subtree)$name <- vcapply(igraph::V(subtree)$task, hash) igraph::V(subtree)$task_type <- vcapply( igraph::V(subtree)$task, @@ -70,7 +71,7 @@ task_graph_create <- function(plan, repos = getOption("repos")) { }) # then merge all the full check task task trees into a single graph - g <- merge_subgraphs(c(list(plan), check_task_neighborhoods)) + g <- graph_dedup_attrs(igraph::union(plan, check_task_neighborhoods)) class(g) <- c("task_graph", class(g)) igraph::V(g)$status <- STATUS$pending @@ -79,6 +80,13 @@ task_graph_create <- function(plan, repos = getOption("repos")) { task_graph_sort(g) } +dep_subgraph <- function(g) { + igraph::subgraph_from_edges( + g, + igraph::E(g)[igraph::E(g)$relation == RELATION$dep] + ) +} + lib_node_tasks <- function(g, nodes) { install_nodes <- igraph::adjacent_vertices(g, nodes, mode = "out") lapply(install_nodes, function(nodes) { @@ -94,33 +102,6 @@ lib_node_pkgs <- function(g, nodes) { }) } -#' Project one graph onto another -#' -#' Project graph `x` onto graph `onto`, making a single graph with merged -#' vertices where the attributes in `where` from `onto` map to the associated -#' attributes in `x` given by the names of `where`. `where` _must_ contain -#' an element called `name`, used to map vertices. -#' -#' The resulting graph will have the combined vertices and edges of both graphs. -#' -graph_project <- function(x, onto, where = c("name" = "name")) { - igraph::vertex.attributes(x)[where] <- - igraph::vertex.attributes(x)[names(where)] - - projection <- match( - igraph::V(x)$name, - igraph::vertex_attr(onto, where[["name"]]) - ) - - igraph::V(x)$name <- ifelse( - is.na(projection), - seq_along(igraph::V(x)), - igraph::V(onto)$name[projection] - ) - - merge_subgraphs(list(onto, x)) -} - package_graph <- function(db, packages = db[, "Package"], dependencies = TRUE) { dependencies <- as_pkg_dependencies(dependencies) @@ -210,12 +191,13 @@ task_graph_vertices <- function(plan, df, edges, repos) { #' #' @importFrom igraph neighborhood #' @keywords internal -task_graph_neighborhoods <- function(g, nodes) { +task_graph_neighborhoods <- function(g, nodes, ...) { igraph::neighborhood( g, order = length(g), nodes = nodes, - mode = "out" + mode = "out", + ... ) } @@ -328,7 +310,7 @@ task_graph_which_check_satisfied <- function( ) { task_graph_which_satisfied( g, - igraph::V(g)[vlapply(igraph::V(g)$task, is_check)], + igraph::V(g)[is_check(igraph::V(g)$task)], ..., dependencies = dependencies, status = status @@ -401,7 +383,7 @@ plot.task_graph <- function(x, ..., interactive = FALSE) { style <- function(attr, ...) { map <- simplify2array(list(...)) nomatch <- if (names(map[length(map)]) == "") length(map) else NA - map[match(attr, names(map), nomatch = nomatch)] + map[match(as.character(attr), names(map), nomatch = nomatch)] } task_type <- vcapply(igraph::V(x)$task, function(task) { @@ -428,7 +410,7 @@ plot.task_graph <- function(x, ..., interactive = FALSE) { vertex$label <- vcapply( igraph::V(x)$task, - friendly_name, + format_task_name, short = TRUE ) @@ -442,6 +424,19 @@ plot.task_graph <- function(x, ..., interactive = FALSE) { 8 ) + edge$lty <- style( + RELATION[igraph::E(x)$relation], + "dep" = 1, + "report" = 2, + 1 + ) + + edge$color <- style( + RELATION[igraph::E(x)$relation], + "report" = "lightgray", + NA + ) + if (interactive) { plot_interactive_task_graph(x, vertex = vertex, edge = edge) } else { @@ -476,19 +471,36 @@ plot_interactive_task_graph <- function( vertex = igraph::as_data_frame(g, what = "vertices"), edge = igraph::as_data_frame(g, what = "edges") ) { - # visNetwork hates non-atomic vectors - vertex$task <- NULL - edge$version <- format(edge$version) + vertex$title <- gsub("<|>", "", vcapply(vertex$task, format)) + edge_titles <- paste0( + edge$type, + ifelse(vlapply(edge$version, is.na), + "", + paste0( + "(", + ifelse(is.na(edge$op), "", paste0(edge$op, " ")), + format(edge$version), + ")" + ) + ) + ) + if (length(edge_titles) > 0) edge$title <- edge_titles vertex$id <- seq_len(nrow(vertex)) edge$from <- vertex$id[match(edge$from, vertex$name)] edge$to <- vertex$id[match(edge$to, vertex$name)] edge$arrows <- "to" + edge$dashes <- edge$lty != 1 + + # visNetwork hates non-atomic vectors + vertex$task <- NULL + edge$version <- format(edge$version) visNetwork::visNetwork( nodes = vertex, edges = edge, width = "100vw", - height = "100vh" + height = "100vh", + tooltipDelay = 0 ) } diff --git a/R/utils-cli.R b/R/utils-cli.R index c0bb25b..fbfb7fb 100644 --- a/R/utils-cli.R +++ b/R/utils-cli.R @@ -1,3 +1,128 @@ +#' task formatter bindings +#' +#' This bit of code is intended for use with [`cli_task()`], and allows for us +#' to layer symbol bindings on top of the environment used for string +#' interpolation which provide syntactic sugar for common formatting components. +#' +task_formats <- function( + g = NULL, + nodes = V(g), + task = NULL, + tasks = list(task) +) { + if (is.null(task)) { + task <- nodes$task + } + + # # NOTE: currently unused, vestigial vectorized alternative + # if (length(tasks) == 1 && is.null(tasks[[1]])) { + # tasks <- V(g)$task + # } + + makeActiveBinding("source", env = environment(), function() { + src <- task$origin %||% character(0L) + src <- format(src) + if (!is.null(names(src))) src <- names(src) + cli_type("path", src) + }) + + makeActiveBinding("source.full", env = environment(), function() { + src <- task$origin$source %||% character(0L) + cli_type("path", format(src)) + }) + + makeActiveBinding("source.type", env = environment(), function() { + src_type <- class(task$origin)[[1]] + src_type_str <- switch(src_type, + "pkg_origin_local" = "local", + "pkg_origin_repo" = source, + "remote" + ) + + cli_type("path", format(src_type_str)) + }) + + makeActiveBinding("package", env = environment(), function() { + pkg <- task$origin$package %||% character(0L) + cli_type("package", pkg) + }) + + makeActiveBinding("version", env = environment(), function() { + cli_type("version", format(task$origin$version %||% character(0L))) + }) + + makeActiveBinding("action", env = environment(), function() { + cli_type("task_type", format_task_type(task)) + }) + + makeActiveBinding("dep.sources", env = environment(), function() { + # get nodes dependencies + dep_edges <- E(g)$relation == as.numeric(RELATION$dep) + dep_g <- igraph::subgraph_from_edges(g, which(dep_edges)) + vs <- task_graph_neighborhoods(dep_g, nodes = nodes$name, mindist = 1) + vs <- unlist(vs) + + # get dependency source names + sources <- lapply(V(g)[vs]$task, function(task) format(task$origin)) + sources <- unlist(Filter(length, sources)) + + if (!is.null(names(sources))) { + is_unnamed <- names(sources) == "" + names(sources[is_unnamed]) <- sources[is_unnamed] + } + + # filter for only novel dependencies + sources <- setdiff(names(sources), names(getOption("repos"))) + cli_type("dep_sources", sources) + }) + + environment() +} + +#' Produce cli output for a task +#' +#' Provided a task, allows for use of a handful of shorthand symbols which will +#' use the task as a context for formatting task fields. +#' +#' @examples +#' task <- install_task(origin = pkg_origin( +#' package = "pkg", +#' version = package_version("1.2.3"), +#' source = "../../Programming/options" +#' )) +#' +#' fmt(task = task, "{action} {package} ({version}) from {source}") +#' +fmt <- function(..., g, nodes, task = NULL, .envir = parent.frame()) { + env <- task_formats(g = g, nodes = nodes, task = task, tasks = NULL) + parent.env(env) <- .envir + + cli::cli_div( + theme = list( + div = list( + "class-map" = list( + "cli_path" = "path", + "cli_task_type" = "class", + "cli_package" = "pkg", + "cli_version" = "pkg-version" + ) + ), + ".pkg-version" = list( + "font-style" = "italic", + "transform" = function(x) sprintf("v%s", x) + ) + ) + ) + + cli::format_inline(..., .envir = env) +} + +glu <- function(..., g, nodes, task = NULL, .envir = parent.frame()) { + env <- task_formats(g = g, nodes = nodes, task = task, tasks = NULL) + parent.env(env) <- .envir + glue::glue(..., .envir = env) +} + #' Create a 'cli' Spinner With Suppressed Output #' #' 'cli' will implicitly push spinner output to various output streams, diff --git a/R/utils-enums.R b/R/utils-enums.R index a7ad7f2..5abdda6 100644 --- a/R/utils-enums.R +++ b/R/utils-enums.R @@ -7,16 +7,15 @@ enum <- function(...) { x <- c(...) f <- factor(x, levels = x) - structure( - lapply(f, identity), - names = levels(f) - ) + names(f) <- as.character(f) + structure(f, class = c("enum", "factor")) } #' Internally provide extended mathematical operators for enums #' @noRd +#' @export #' @keywords internal -Ops.factor <- function(e1, e2) { +Ops.enum <- function(e1, e2) { # nolint start, styler: off switch(.Generic, ">" = , ">=" = , "==" = , "<" = , "<=" = { return(do.call(.Generic, list(as.numeric(e1), as.numeric(e2)))) @@ -25,16 +24,20 @@ Ops.factor <- function(e1, e2) { NextMethod() } -#' Edge types +#' Internally provide `$` for enum factors +#' @noRd +#' @keywords internal +#' @export +`$.enum` <- function(x, i) { + x[[i]] +} + +#' Relation types #' -#' Edges may have multiple relations. Most commonly, this relationship -#' represents a dependency, meaning that a node's task must be performed before -#' another node. However, this may also be a relationship that is used for -#' grouping behaviors together during reporting, allowing a single task to -#' redirect to another node. +#' A flag for edges that articulate different relations between nodes. #' #' @keywords internal -EDGE <- enum( +RELATION <- enum( "dep", # for task dependencies "report" # for reporting graph, from task to reporting node ) diff --git a/R/utils-igraph.R b/R/utils-igraph.R index 66350bc..a9b3d4a 100644 --- a/R/utils-igraph.R +++ b/R/utils-igraph.R @@ -15,21 +15,54 @@ sequence_graph <- function(..., name_by = ..1, name = hashes(name_by)) { igraph::graph_from_data_frame(edges, vertices = vertices) } -merge_subgraphs <- function(gs) { - edfs <- lapply(gs, igraph::as_data_frame) - all_cols <- unique(unlist(lapply(edfs, colnames))) - edfs <- lapply(edfs, complete_columns, all_cols) - es <- unique(do.call(rbind, edfs)) - rownames(es) <- NULL +#' Deduplicate attributes +#' +#' Primarily intended for cleaning up the result of an [`igraph::union()`], +#' which adds duplicated attributes when attributes of the same name exist in +#' multiple graphs. Searches for suffixes and consolidates attributes, +#' taking the attribute from the first non-NA value observed. +#' +graph_dedup_attrs <- function(g) { + # pattern appended to duplicated attributes + re <- "_\\d+$" - vdfs <- lapply(gs, igraph::as_data_frame, what = "vertices") - all_cols <- unique(unlist(lapply(vdfs, colnames))) - vdfs <- lapply(vdfs, complete_columns, all_cols) - vs <- do.call(rbind, vdfs) - vs <- vs[!duplicated(vs$name), ] - rownames(vs) <- NULL + # de-duplicate vertex attributes + v_attrs <- igraph::vertex_attr_names(g) + v_dup_attrs <- grep(re, v_attrs, value = TRUE) + v_dup_group <- sub(re, "", v_dup_attrs) + v_dup_attrs <- split(v_dup_attrs, v_dup_group) + for (i in seq_along(v_dup_attrs)) { + attr_name <- names(v_dup_attrs[i]) + attr_value <- igraph::vertex_attr(g, v_dup_attrs[[i]][[1L]]) + g <- igraph::remove.vertex.attribute(g, v_dup_attrs[[i]][[1L]]) + for (attr_dup_name in v_dup_attrs[[i]][-1L]) { + if (!anyNA(attr_value)) break + is_na <- is.na(attr_value) + attr_value[is_na] <- igraph::vertex_attr(g, attr_dup_name)[is_na] + g <- igraph::remove.vertex.attribute(g, attr_dup_name) + } + g <- igraph::set_vertex_attr(g, attr_name, value = attr_value) + } - igraph::graph_from_data_frame(es, vertices = vs) + # de-duplicate edge attributes + e_attrs <- igraph::edge_attr_names(g) + e_dup_attrs <- grep(re, e_attrs, value = TRUE) + e_dup_group <- sub(re, "", e_dup_attrs) + e_dup_attrs <- split(e_dup_attrs, e_dup_group) + for (i in seq_along(e_dup_attrs)) { + attr_name <- names(e_dup_attrs[i]) + attr_value <- igraph::edge_attr(g, e_dup_attrs[[i]][[1L]]) + g <- igraph::remove.edge.attribute(g, e_dup_attrs[[i]][[1L]]) + for (attr_dup_name in e_dup_attrs[[i]][-1L]) { + if (!anyNA(attr_value)) break + is_na <- is.na(attr_value) + attr_value[is_na] <- igraph::edge_attr(g, attr_dup_name)[is_na] + g <- igraph::remove.edge.attribute(g, attr_dup_name) + } + g <- igraph::set_edge_attr(g, attr_name, value = attr_value) + } + + g } complete_columns <- function(df, cols) { diff --git a/R/utils-paths.R b/R/utils-paths.R index e2f37a6..4d0a784 100644 --- a/R/utils-paths.R +++ b/R/utils-paths.R @@ -2,14 +2,18 @@ filepath <- function(x) { structure(x, class = "filepath") } +cli_type <- function(types, x) { + structure(x, class = paste0("cli_", types)) +} + #' @export -format.filepath <- function(x, ..., pretty = FALSE) { - if (!pretty) { - return(as.character(x)) +format_simplify_path <- function(x, ..., full.path = FALSE) { + if (full.path) { + return(normalizePath(x, mustWork = FALSE)) } wp <- path_parts(getwd()) - xp <- path_parts(normalizePath(x)) + xp <- path_parts(normalizePath(x, mustWork = FALSE)) min_len <- min(length(wp), length(xp)) first_diff <- Position(identity, head(wp, min_len) != head(xp, min_len)) @@ -18,18 +22,18 @@ format.filepath <- function(x, ..., pretty = FALSE) { if (length(parts) == 0) { parts <- "." } - return(format(do.call(file.path, as.list(parts)))) + do.call(file.path, as.list(parts)) } if (first_diff > min_len) { parts <- utils::tail(xp, -first_diff + 1) - format(do.call(file.path, as.list(parts))) + do.call(file.path, as.list(parts)) } else if (first_diff <= min_len) { parents <- rep_len("..", length(xp) - first_diff + 1) parts <- c(parents, utils::tail(xp, -first_diff + 1)) - format(do.call(file.path, as.list(parts))) + do.call(file.path, as.list(parts)) } else { - format(x) + x } } diff --git a/Rplots.pdf b/Rplots.pdf new file mode 100644 index 0000000000000000000000000000000000000000..03d5b3f94aaa0575716326a2b6e5cfa7c3a1cc0d GIT binary patch literal 25458 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 Z`1m?{`~K04jGVNb60@+d4oH{z{{g$i{n-Ej literal 0 HcmV?d00001 diff --git a/man/DEP.Rd b/man/DEP.Rd index 34df58c..c21dfd5 100644 --- a/man/DEP.Rd +++ b/man/DEP.Rd @@ -5,7 +5,7 @@ \alias{DEP} \title{Dependencies categories} \format{ -An object of class \code{list} of length 5. +An object of class \code{enum} (inherits from \code{factor}) of length 5. } \usage{ DEP diff --git a/man/DEP_STRONG.Rd b/man/DEP_STRONG.Rd index 1ff19ed..bb530c0 100644 --- a/man/DEP_STRONG.Rd +++ b/man/DEP_STRONG.Rd @@ -5,7 +5,7 @@ \alias{DEP_STRONG} \title{Strong dependencies categories} \format{ -An object of class \code{factor} of length 3. +An object of class \code{enum} (inherits from \code{factor}) of length 3. } \usage{ DEP_STRONG diff --git a/man/PLAN.Rd b/man/PLAN.Rd deleted file mode 100644 index 4455be3..0000000 --- a/man/PLAN.Rd +++ /dev/null @@ -1,16 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/utils-enums.R -\docType{data} -\name{PLAN} -\alias{PLAN} -\title{Check execution status categories} -\format{ -An object of class \code{list} of length 2. -} -\usage{ -PLAN -} -\description{ -Check execution status categories -} -\keyword{internal} diff --git a/man/RELATION.Rd b/man/RELATION.Rd new file mode 100644 index 0000000..95d510e --- /dev/null +++ b/man/RELATION.Rd @@ -0,0 +1,16 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils-enums.R +\docType{data} +\name{RELATION} +\alias{RELATION} +\title{Relation types} +\format{ +An object of class \code{enum} (inherits from \code{factor}) of length 2. +} +\usage{ +RELATION +} +\description{ +A flag for edges that articulate different relations between nodes. +} +\keyword{internal} diff --git a/man/STATUS.Rd b/man/STATUS.Rd index 380da65..0c24e5e 100644 --- a/man/STATUS.Rd +++ b/man/STATUS.Rd @@ -5,7 +5,7 @@ \alias{STATUS} \title{Check execution status categories} \format{ -An object of class \code{list} of length 3. +An object of class \code{enum} (inherits from \code{factor}) of length 3. } \usage{ STATUS diff --git a/man/checked-package.Rd b/man/checked-package.Rd new file mode 100644 index 0000000..2a4a1ac --- /dev/null +++ b/man/checked-package.Rd @@ -0,0 +1,33 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/package.R +\docType{package} +\name{checked-package} +\alias{checked} +\alias{checked-package} +\title{checked: Systematically Run R CMD Checks} +\description{ +Systematically Run R checks against multiple packages. Checks are run in parallel with strategies to minimize dependency installation. Provides out of the box interface for running reverse dependency check. +} +\seealso{ +Useful links: +\itemize{ + \item \url{https://Genentech.github.io/checked/} + \item \url{https://github.com/Genentech/checked} + \item Report bugs at \url{https://github.com/Genentech/checked/issues} +} + +} +\author{ +\strong{Maintainer}: Szymon Maksymiuk \email{sz.maksymiuk@gmail.com} (\href{https://orcid.org/0000-0002-3120-1601}{ORCID}) + +Authors: +\itemize{ + \item Doug Kelkhoff \email{doug.kelkhoff@gmail.com} (\href{https://orcid.org/0009-0003-7845-4061}{ORCID}) +} + +Other contributors: +\itemize{ + \item F. Hoffmann-La Roche AG [copyright holder, funder] +} + +} diff --git a/man/cli.Rd b/man/cli.Rd index ff0e85f..6f0762c 100644 --- a/man/cli.Rd +++ b/man/cli.Rd @@ -7,13 +7,14 @@ \title{Internal Utilities for Command-line Output} \usage{ cli_table_row( - status, + status = "", ok = "OK", notes = "N", warnings = "W", errors = "E", msg = "", - title = FALSE + style = c("row", "title", "header"), + symbols = list(bar = "│") ) cli_theme(..., .envir = parent.frame()) diff --git a/man/fmt.Rd b/man/fmt.Rd new file mode 100644 index 0000000..e9c4739 --- /dev/null +++ b/man/fmt.Rd @@ -0,0 +1,22 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils-cli.R +\name{fmt} +\alias{fmt} +\title{Produce cli output for a task} +\usage{ +fmt(..., g, nodes, task = NULL, .envir = parent.frame()) +} +\description{ +Provided a task, allows for use of a handful of shorthand symbols which will +use the task as a context for formatting task fields. +} +\examples{ +task <- install_task(origin = pkg_origin( + package = "pkg", + version = package_version("1.2.3"), + source = "../../Programming/options" +)) + +fmt(task = task, "{action} {package} ({version}) from {source}") + +} diff --git a/man/graph_dedup_attrs.Rd b/man/graph_dedup_attrs.Rd new file mode 100644 index 0000000..fad46da --- /dev/null +++ b/man/graph_dedup_attrs.Rd @@ -0,0 +1,14 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils-igraph.R +\name{graph_dedup_attrs} +\alias{graph_dedup_attrs} +\title{Deduplicate attributes} +\usage{ +graph_dedup_attrs(g) +} +\description{ +Primarily intended for cleaning up the result of an \code{\link[igraph:union]{igraph::union()}}, +which adds duplicated attributes when attributes of the same name exist in +multiple graphs. Searches for suffixes and consolidates attributes, +taking the attribute from the first non-NA value observed. +} diff --git a/man/graph_project.Rd b/man/graph_project.Rd deleted file mode 100644 index 481acb8..0000000 --- a/man/graph_project.Rd +++ /dev/null @@ -1,17 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/task_graph.R -\name{graph_project} -\alias{graph_project} -\title{Project one graph onto another} -\usage{ -graph_project(x, onto, where = c(name = "name")) -} -\description{ -Project graph \code{x} onto graph \code{onto}, making a single graph with merged -vertices where the attributes in \code{where} from \code{onto} map to the associated -attributes in \code{x} given by the names of \code{where}. \code{where} \emph{must} contain -an element called \code{name}, used to map vertices. -} -\details{ -The resulting graph will have the combined vertices and edges of both graphs. -} diff --git a/man/planned.Rd b/man/planned.Rd deleted file mode 100644 index 41192a4..0000000 --- a/man/planned.Rd +++ /dev/null @@ -1,11 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/plan.R -\name{planned} -\alias{planned} -\title{Tag edges as 'planned'} -\usage{ -planned(graph) -} -\description{ -Tag edges as 'planned' -} diff --git a/man/reporters-internal.Rd b/man/reporters-internal.Rd index 35a9f62..a3571e3 100644 --- a/man/reporters-internal.Rd +++ b/man/reporters-internal.Rd @@ -4,7 +4,8 @@ \alias{reporters-internal} \alias{report_sleep} \alias{report_sleep.default} -\alias{report_initialize} +\alias{report_start_setup} +\alias{report_start_checks} \alias{report_status} \alias{report_finalize} \title{Reporter Internal Methods} @@ -13,7 +14,9 @@ report_sleep(reporter, design, sleep) \method{report_sleep}{default}(reporter, design, sleep = 1) -report_initialize(reporter, design, envir = parent.frame()) +report_start_setup(reporter, design, ..., envir = parent.frame()) + +report_start_checks(reporter, design, ..., envir = parent.frame()) report_status(reporter, design, envir = parent.frame()) diff --git a/man/reporters.Rd b/man/reporters.Rd index e3f558f..1f7faa0 100644 --- a/man/reporters.Rd +++ b/man/reporters.Rd @@ -3,12 +3,15 @@ \name{reporters} \alias{reporters} \alias{reporter_ansi_tty} +\alias{reporter_ansi_tty2} \alias{reporter_basic_tty} \alias{reporter_default} \title{Check Design Runner Reporters} \usage{ reporter_ansi_tty() +reporter_ansi_tty2() + reporter_basic_tty() reporter_default() diff --git a/man/task_formats.Rd b/man/task_formats.Rd new file mode 100644 index 0000000..0892b3a --- /dev/null +++ b/man/task_formats.Rd @@ -0,0 +1,13 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils-cli.R +\name{task_formats} +\alias{task_formats} +\title{task formatter bindings} +\usage{ +task_formats(g = NULL, nodes = V(g), task = NULL, tasks = list(task)) +} +\description{ +This bit of code is intended for use with \code{\link[=cli_task]{cli_task()}}, and allows for us +to layer symbol bindings on top of the environment used for string +interpolation which provide syntactic sugar for common formatting components. +} diff --git a/man/task_graph_neighborhoods.Rd b/man/task_graph_neighborhoods.Rd index 0b56d8d..2150d1f 100644 --- a/man/task_graph_neighborhoods.Rd +++ b/man/task_graph_neighborhoods.Rd @@ -4,7 +4,7 @@ \alias{task_graph_neighborhoods} \title{Find Task Neighborhood} \usage{ -task_graph_neighborhoods(g, nodes) +task_graph_neighborhoods(g, nodes, ...) } \arguments{ \item{g}{A task graph, as produced with \code{\link[=task_graph_create]{task_graph_create()}}} From 740e0d1bcf7c6b4c8749934ee97127c96b1ee4b8 Mon Sep 17 00:00:00 2001 From: dgkf-roche Date: Mon, 26 May 2025 16:53:42 -0400 Subject: [PATCH 28/62] fix(wip): task satisfied calculations --- NAMESPACE | 2 + R/check_process.R | 9 ++- R/checker.R | 6 +- R/next_task.R | 7 +- R/plan.R | 21 +++++- R/{report_ansi_tty.R => reporter_ansi_tty.R} | 0 R/run.R | 5 ++ R/task-formatting.R | 30 ++++++--- R/task.R | 2 +- R/task_graph.R | 67 ++++++++++++++------ R/utils-cli.R | 18 +++++- R/utils-deps.R | 2 +- R/utils-igraph.R | 10 ++- man/fmt.Rd | 2 +- 14 files changed, 134 insertions(+), 47 deletions(-) rename R/{report_ansi_tty.R => reporter_ansi_tty.R} (100%) diff --git a/NAMESPACE b/NAMESPACE index 7d8563b..568c9cc 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -40,6 +40,8 @@ S3method(format_task_name,install_task) S3method(format_task_name,rev_dep_check_meta_task) S3method(format_task_name,rev_dep_dep_meta_task) S3method(format_task_name,task) +S3method(format_task_type,rev_dep_check_meta_task) +S3method(format_task_type,rev_dep_dep_meta_task) S3method(format_task_type,task) S3method(install_params,pkg_origin) S3method(install_params,pkg_origin_archive) diff --git a/R/check_process.R b/R/check_process.R index dfea009..c7fe4f5 100644 --- a/R/check_process.R +++ b/R/check_process.R @@ -148,7 +148,14 @@ check_process <- R6::R6Class( args = list(), time_last_check_start = NULL, time_finish = NULL, - parsed_checks = factor(levels = c("", "NONE", "OK", "NOTE", "WARNING", "ERROR")), + parsed_checks = factor(levels = c( + "", + "NONE", + "OK", + "NOTE", + "WARNING", + "ERROR" + )), parsed_partial_check_output = "", throttle = NULL, spinners = NULL, diff --git a/R/checker.R b/R/checker.R index 21316be..cfd9f0e 100644 --- a/R/checker.R +++ b/R/checker.R @@ -168,7 +168,10 @@ checker <- R6::R6Class( } next_task <- next_task_to_run(self$graph) + if (length(next_task) > 0) { + print(next_task$task[[1]]) + process <- start_task( node = next_task, g = self$graph, @@ -186,7 +189,8 @@ checker <- R6::R6Class( } finished <- (length(private$active) == 0) && self$is_done() - return(-finished) + + -finished }, #' @description diff --git a/R/next_task.R b/R/next_task.R index ef28804..132b010 100644 --- a/R/next_task.R +++ b/R/next_task.R @@ -4,6 +4,7 @@ next_task_to_run <- function(g) { # Prioritize checks overs installs v <- igraph::V(g)[c(checks, installs)] + utils::head(v, 1L) } @@ -127,13 +128,9 @@ start_task.check_task <- function( libpaths <- task_graph_libpaths(g, node, lib.loc = lib.loc) path <- check_path(task$origin, output = path_sources()) - # TODO: make output directory names more user-friendly, for now the vertex - # hash id is used to disambiguate output - output_dirname <- paste0(format_task_name(task), " <", node$name[[1]], ">") - check_process$new( path = path, - check_dir = path_check_output(output, output_dirname), + check_dir = path_check_output(output, node$name[[1]]), libpath = libpaths, repos = task$repos, args = task$args, diff --git a/R/plan.R b/R/plan.R index fb7e2b1..3e4cd36 100644 --- a/R/plan.R +++ b/R/plan.R @@ -124,8 +124,19 @@ plan_rev_dep_checks <- function( # reconstruct edges from planned root node to individual checks edges <- as.vector(rbind(task_id, rev_dep_meta_task_ids)) - g <- igraph::add_edges(g, edges = edges, attr = list(relation = RELATION$dep)) + + # meta tasks take dependency relationship with subtasks + g <- igraph::add_edges(g, edges = edges, attr = list( + relation = RELATION$dep, + type = DEP$Depends + )) + + # recover coerced factor types + E(g)$relation <- RELATION[E(g)$relation] + E(g)$type <- DEP[E(g)$type] + class(g) <- c("task_graph", class(g)) + g } @@ -147,8 +158,10 @@ plan_rev_dep_dev_check <- function(origin, revdep, repos) { )) # this check is reported through a rev dep check meta task - .to <- NULL # used by igraph NSE g <- igraph::add_edges(g, edges = c(2, 1)) # NOTE: coerces factor to numeric + + .to <- NULL # used by igraph NSE + igraph::E(g)$type <- DEP$Depends igraph::E(g)$relation <- RELATION$dep igraph::E(g)[.to(1)]$relation <- RELATION$report @@ -171,8 +184,10 @@ plan_rev_dep_release_check <- function(origin, revdep, repos) { )) # this check is reported through a rev dep check meta task - .to <- NULL # used by igraph g <- igraph::add_edges(g, edges = c(2, 1)) # NOTE: coerces factor to numeric + + .to <- NULL # used by igraph + igraph::E(g)$type <- DEP$Depends igraph::E(g)$relation <- RELATION$dep igraph::E(g)[.to(1)]$relation <- RELATION$report diff --git a/R/report_ansi_tty.R b/R/reporter_ansi_tty.R similarity index 100% rename from R/report_ansi_tty.R rename to R/reporter_ansi_tty.R diff --git a/R/run.R b/R/run.R index f9a0ff4..5f1b008 100644 --- a/R/run.R +++ b/R/run.R @@ -32,6 +32,11 @@ run.checker <- function(checker, ..., reporter = reporter_default()) { report_start_checks(reporter, checker) while (checker$step()) { + if (length(checker$active) == 0 && !checker$is_done()) { + warning("some tasks not executed due to unsolved dependency requirements") + break + } + report_status(reporter, checker) report_sleep(reporter, checker) } diff --git a/R/task-formatting.R b/R/task-formatting.R index 383ec98..866081e 100644 --- a/R/task-formatting.R +++ b/R/task-formatting.R @@ -1,13 +1,29 @@ #' @export format.task <- function(x, ..., indent = 0L) { - fmt(task = x, "{action} {package} {version} {source}") + fmt(task = x, "{action} {package} {version} from {source}", ...) +} + +format_task_type <- function(x, ...) { + UseMethod("format_task_type") } #' @export -format_task_name.task <- function(x, ...) { - "task" +format_task_type.task <- function(x, ...) { + sub("_task$", "", class(x)[[1]]) +} + +#' @export +format_task_type.rev_dep_dep_meta_task <- function(x, ...) { + "check revdeps of" +} + +#' @export +format_task_type.rev_dep_check_meta_task <- function(x, ..., g = NULL) { + "check revdep of" } + + format_task_name <- function(x, ...) { UseMethod("format_task_name") } @@ -21,13 +37,9 @@ format_task_name.default <- function(x, ...) { ) } -format_task_type <- function(x, ...) { - UseMethod("format_task_type") -} - #' @export -format_task_type.task <- function(x, ...) { - sub("_task$", "", class(x)[[1]]) +format_task_name.task <- function(x, ...) { + "task" } #' @export diff --git a/R/task.R b/R/task.R index dfc9432..1ddaa7b 100644 --- a/R/task.R +++ b/R/task.R @@ -27,7 +27,7 @@ meta_task <- function(..., .subclass = NULL) { } make_unique_task <- function(task, seed = runif(1)) { - task$id <- hash(seed) + task$seed <- seed task } diff --git a/R/task_graph.R b/R/task_graph.R index 3c8aaf7..0155977 100644 --- a/R/task_graph.R +++ b/R/task_graph.R @@ -48,6 +48,7 @@ task_graph_create <- function(plan, repos = getOption("repos")) { deps <- dep_tree(nh[[1]]$task) igraph::reverse_edges(deps) igraph::E(deps)$relation <- RELATION$dep + igraph::E(deps)$type <- DEP[igraph::E(deps)$type] igraph::V(deps)$task <- lapply( igraph::V(deps)$name, function(package) { @@ -60,31 +61,41 @@ task_graph_create <- function(plan, repos = getOption("repos")) { # NOTE: attributes (tasks) are preserved in the order they appear subtree <- graph_dedup_attrs(igraph::union(subtree, deps)) + # fill new edges with dependency relation - between check task and installs + is_na <- is.na(E(subtree)$relation) + E(subtree)$relation[is_na] <- RELATION$dep + E(subtree)$type[is_na] <- DEP$Depends + # re-hash tasks as vertex names igraph::V(subtree)$name <- vcapply(igraph::V(subtree)$task, hash) - igraph::V(subtree)$task_type <- vcapply( - igraph::V(subtree)$task, - function(task) class(task)[[1]] - ) subtree }) # then merge all the full check task task trees into a single graph g <- graph_dedup_attrs(igraph::union(plan, check_task_neighborhoods)) - class(g) <- c("task_graph", class(g)) + igraph::E(g)$relation <- RELATION[igraph::E(g)$relation] + igraph::E(g)$type <- DEP[igraph::E(g)$type] igraph::V(g)$status <- STATUS$pending igraph::V(g)$process <- rep_len(list(), length(g)) - task_graph_sort(g) + g <- task_graph_sort(g) + class(g) <- c("task_graph", class(g)) + + g +} + +dep_edges <- function(edges, dependencies = TRUE) { + if (!is.logical(dependencies)) { + dependencies <- edges$type %in% check_dependencies(dependencies) + } + + edges$relation == RELATION$dep & dependencies } dep_subgraph <- function(g) { - igraph::subgraph_from_edges( - g, - igraph::E(g)[igraph::E(g)$relation == RELATION$dep] - ) + igraph::subgraph_from_edges(g, igraph::E(g)[dep_edges(igraph::E(g))]) } lib_node_tasks <- function(g, nodes) { @@ -234,7 +245,7 @@ task_graph_sort <- function(g) { } # use only strong dependencies to prioritize by topology (leafs first) - strong_edges <- igraph::E(g)[igraph::E(g)$type %in% DEP_STRONG] + strong_edges <- igraph::E(g)[dep_edges(E(g), "strong")] g_strong <- igraph::subgraph.edges(g, strong_edges, delete.vertices = FALSE) topo <- igraph::topo_sort(g_strong, mode = "in") priority_topo <- integer(length(g)) @@ -282,19 +293,25 @@ task_graph_which_satisfied <- function( dependencies = TRUE, status = STATUS$pending ) { - if (is.character(status)) status <- STATUS[[status]] + if (is.character(status)) { + status <- STATUS[[status]] + } + dependencies <- check_dependencies(dependencies) + if (length(status) > 0) { idx <- v$status %in% status v <- v[idx] } + deps_met <- vlapply( - igraph::incident_edges(g, v, mode = "in"), + igraph::incident_edges(g, v, mode = "out"), function(edges) { - edges <- edges[edges$type %in% dependencies] - all(igraph::tail_of(g, edges)$status == STATUS$done) + is_dep <- edges$relation == RELATION$dep & edges$type %in% dependencies + all(igraph::tail_of(g, edges[is_dep])$status == STATUS$done) } ) + names(deps_met[deps_met]) } @@ -391,6 +408,7 @@ plot.task_graph <- function(x, ..., interactive = FALSE) { class(task)[[1]] }) + x <- dep_subgraph(x) vertex <- igraph::as_data_frame(x, what = "vertices") edge <- igraph::as_data_frame(x, what = "edges") @@ -408,10 +426,19 @@ plot.task_graph <- function(x, ..., interactive = FALSE) { "red" ) - vertex$label <- vcapply( - igraph::V(x)$task, - format_task_name, - short = TRUE + vertex$label <- cli::ansi_strip(vcapply(igraph::V(x)$task, format, g = x)) + + vertex$frame.color <- style( + STATUS[igraph::V(x)$status], + "done" = "green", + "in progress" = "lightgreen", + "black" + ) + + vertex$frame.width <- style( + STATUS[igraph::V(x)$status], + "done" = 3L, + 1L ) vertex$size <- style( @@ -457,6 +484,8 @@ plot_static_task_graph <- function( vertex.label = vertex$label, vertex.color = vertex$color, vertex.size = vertex$size, + vertex.frame.color = vertex$frame.color, + vertex.frame.width = vertex$frame.width, edge.lty = edge$lty, layout = igraph::layout_with_sugiyama( g, diff --git a/R/utils-cli.R b/R/utils-cli.R index fbfb7fb..23f31cb 100644 --- a/R/utils-cli.R +++ b/R/utils-cli.R @@ -52,7 +52,7 @@ task_formats <- function( }) makeActiveBinding("action", env = environment(), function() { - cli_type("task_type", format_task_type(task)) + cli_type("task_type", format_task_type(task, g = g)) }) makeActiveBinding("dep.sources", env = environment(), function() { @@ -93,7 +93,14 @@ task_formats <- function( #' #' fmt(task = task, "{action} {package} ({version}) from {source}") #' -fmt <- function(..., g, nodes, task = NULL, .envir = parent.frame()) { +fmt <- function( + ..., + g, + nodes, + task = NULL, + .envir = parent.frame(), + ansi = TRUE +) { env <- task_formats(g = g, nodes = nodes, task = task, tasks = NULL) parent.env(env) <- .envir @@ -114,7 +121,12 @@ fmt <- function(..., g, nodes, task = NULL, .envir = parent.frame()) { ) ) - cli::format_inline(..., .envir = env) + out <- cli::format_inline(..., .envir = env) + + # ideally would use `options(cli.ansi)`, but it seems to be unused + if (!ansi) out <- cli::ansi_strip(out) + + out } glu <- function(..., g, nodes, task = NULL, .envir = parent.frame()) { diff --git a/R/utils-deps.R b/R/utils-deps.R index 7593150..206e6ee 100644 --- a/R/utils-deps.R +++ b/R/utils-deps.R @@ -90,7 +90,7 @@ pkg_dependencies <- function( out <- proto_df[seq_along(deps), , drop = FALSE] out$package <- package - out$type <- deptype + out$type <- DEP[deptype] out$name <- vcapply(deps, `[[`, "name") out$op <- vcapply(deps, function(i) i$op %||% NA_character_) out$version <- mapply( diff --git a/R/utils-igraph.R b/R/utils-igraph.R index a9b3d4a..f7537b4 100644 --- a/R/utils-igraph.R +++ b/R/utils-igraph.R @@ -6,7 +6,13 @@ vertex_df <- function(name, ...) { vertices } -sequence_graph <- function(..., name_by = ..1, name = hashes(name_by)) { +sequence_graph <- function( + ..., + vertex_attrs = list(...), + edge_attrs = list(), + name_by = vertex_attrs[[1]], + name = hashes(name_by) +) { vertices <- vertex_df(name = name, ...) edges <- data.frame( from = utils::head(vertices$name, -1L), @@ -36,7 +42,6 @@ graph_dedup_attrs <- function(g) { attr_value <- igraph::vertex_attr(g, v_dup_attrs[[i]][[1L]]) g <- igraph::remove.vertex.attribute(g, v_dup_attrs[[i]][[1L]]) for (attr_dup_name in v_dup_attrs[[i]][-1L]) { - if (!anyNA(attr_value)) break is_na <- is.na(attr_value) attr_value[is_na] <- igraph::vertex_attr(g, attr_dup_name)[is_na] g <- igraph::remove.vertex.attribute(g, attr_dup_name) @@ -54,7 +59,6 @@ graph_dedup_attrs <- function(g) { attr_value <- igraph::edge_attr(g, e_dup_attrs[[i]][[1L]]) g <- igraph::remove.edge.attribute(g, e_dup_attrs[[i]][[1L]]) for (attr_dup_name in e_dup_attrs[[i]][-1L]) { - if (!anyNA(attr_value)) break is_na <- is.na(attr_value) attr_value[is_na] <- igraph::edge_attr(g, attr_dup_name)[is_na] g <- igraph::remove.edge.attribute(g, attr_dup_name) diff --git a/man/fmt.Rd b/man/fmt.Rd index e9c4739..d593a92 100644 --- a/man/fmt.Rd +++ b/man/fmt.Rd @@ -4,7 +4,7 @@ \alias{fmt} \title{Produce cli output for a task} \usage{ -fmt(..., g, nodes, task = NULL, .envir = parent.frame()) +fmt(..., g, nodes, task = NULL, .envir = parent.frame(), ansi = TRUE) } \description{ Provided a task, allows for use of a handful of shorthand symbols which will From 1af22df5826661f8691c0d72ac98a59bb3aaad56 Mon Sep 17 00:00:00 2001 From: dgkf-roche Date: Tue, 27 May 2025 16:42:17 -0400 Subject: [PATCH 29/62] fix: task satisfied checks; install libs --- R/checker.R | 7 ++++--- R/lib.R | 2 +- R/next_task.R | 6 +++--- R/pkg_origin.R | 2 +- R/reporter_ansi_tty.R | 5 ++--- R/run.R | 2 +- R/task_graph.R | 6 +++--- R/utils-paths.R | 2 +- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/R/checker.R b/R/checker.R index cfd9f0e..2cbb484 100644 --- a/R/checker.R +++ b/R/checker.R @@ -88,7 +88,10 @@ checker <- R6::R6Class( initialize = function( plan, n = 2L, - output = tempfile(paste(packageName(), Sys.Date(), sep = "-")), + output = file.path( + tempdir(), + paste(packageName(), Sys.Date(), sep = "-") + ), lib.loc = .libPaths(), repos = getOption("repos"), restore = TRUE, @@ -170,8 +173,6 @@ checker <- R6::R6Class( next_task <- next_task_to_run(self$graph) if (length(next_task) > 0) { - print(next_task$task[[1]]) - process <- start_task( node = next_task, g = self$graph, diff --git a/R/lib.R b/R/lib.R index aee48e7..42225d7 100644 --- a/R/lib.R +++ b/R/lib.R @@ -36,7 +36,7 @@ lib <- function(x, ..., lib.loc = c()) { } #' Null Library Path -#' +#' #' @export lib.NULL <- function(x, ...) { character(0L) diff --git a/R/next_task.R b/R/next_task.R index 132b010..aa2022c 100644 --- a/R/next_task.R +++ b/R/next_task.R @@ -81,13 +81,13 @@ start_task.install_task <- function( install_process$new( install_parameters$package, - lib = path_lib(output), + lib = lib(task$lib, lib.loc = lib.loc), libpaths = libpaths, repos = task$origin$repos, dependencies = FALSE, type = task$type, INSTALL_opts = c(), # TODO - log = path_package_install_log(output, format_task_name(task)), + log = path_install_log(output, node$name[[1]]), env = c() # TODO ) } @@ -111,7 +111,7 @@ start_task.custom_install_task <- function( dependencies = FALSE, type = spec$type, INSTALL_opts = spec$INSTALL_opts, - log = path_package_install_log(output, spec$alias), + log = path_install_log(output, spec$alias), env = spec$env ) } diff --git a/R/pkg_origin.R b/R/pkg_origin.R index 0c6159e..8b547ce 100644 --- a/R/pkg_origin.R +++ b/R/pkg_origin.R @@ -182,7 +182,7 @@ install_params.pkg_origin_base <- function(x) { #' @export install_params.pkg_origin_repo <- function(x) { - list(package = x$name, repos = x$repos) + list(package = x$package, repos = x$repos) } #' @export diff --git a/R/reporter_ansi_tty.R b/R/reporter_ansi_tty.R index 40f7f42..7d4b20f 100644 --- a/R/reporter_ansi_tty.R +++ b/R/reporter_ansi_tty.R @@ -155,14 +155,13 @@ report_task_ansi_tty.rev_dep_check_meta_task <- function(reporter, g, v) { package <- v$task$origin$package # subset for dependency edges from rev dep task - dep_edges <- E(g)$relation == as.numeric(RELATION$dep) - dep_g <- igraph::subgraph_from_edges(g, which(dep_edges)) + dep_g <- dep_subgraph(g) # get individual rev dep checks, and get their trees check_nodes <- igraph::neighbors(dep_g, v$name, "out") check_neighborhoods <- igraph::make_neighborhood_graph( dep_g, - order = length(dep_g), + order = 1, # NOTE: do we only want to check _direct_ reverse dependencies? check_nodes, mode = "out" ) diff --git a/R/run.R b/R/run.R index 5f1b008..0967c8b 100644 --- a/R/run.R +++ b/R/run.R @@ -32,7 +32,7 @@ run.checker <- function(checker, ..., reporter = reporter_default()) { report_start_checks(reporter, checker) while (checker$step()) { - if (length(checker$active) == 0 && !checker$is_done()) { + if (length(checker$active_processes()) == 0 && !checker$is_done()) { warning("some tasks not executed due to unsolved dependency requirements") break } diff --git a/R/task_graph.R b/R/task_graph.R index 0155977..2563a38 100644 --- a/R/task_graph.R +++ b/R/task_graph.R @@ -308,7 +308,7 @@ task_graph_which_satisfied <- function( igraph::incident_edges(g, v, mode = "out"), function(edges) { is_dep <- edges$relation == RELATION$dep & edges$type %in% dependencies - all(igraph::tail_of(g, edges[is_dep])$status == STATUS$done) + all(igraph::head_of(g, edges[is_dep])$status == STATUS$done) } ) @@ -429,14 +429,14 @@ plot.task_graph <- function(x, ..., interactive = FALSE) { vertex$label <- cli::ansi_strip(vcapply(igraph::V(x)$task, format, g = x)) vertex$frame.color <- style( - STATUS[igraph::V(x)$status], + STATUS[igraph::V(x)$status %||% 1], "done" = "green", "in progress" = "lightgreen", "black" ) vertex$frame.width <- style( - STATUS[igraph::V(x)$status], + STATUS[igraph::V(x)$status %||% 1], "done" = 3L, 1L ) diff --git a/R/utils-paths.R b/R/utils-paths.R index 4d0a784..f62b6b8 100644 --- a/R/utils-paths.R +++ b/R/utils-paths.R @@ -73,7 +73,7 @@ path_custom_lib <- function(path, custom) { normalizePath(p) } -path_package_install_log <- function(path, package, name = "lib") { +path_install_log <- function(path, package, name = "lib") { dir_create(p <- file.path(path_logs(path), name)) normalizePath(file.path(p, sprintf("%s.log", package)), mustWork = FALSE) } From 712ba53c8a82414c529aba22fe20f8f4d64983dd Mon Sep 17 00:00:00 2001 From: dgkf-roche Date: Wed, 28 May 2025 16:21:14 -0400 Subject: [PATCH 30/62] fix: various ansi output hiccups --- R/reporter_ansi_tty.R | 102 ++++++++++++++++++++++++------------------ R/run.R | 8 +++- R/task.R | 4 ++ R/utils-cli.R | 4 ++ man/checker.Rd | 2 +- 5 files changed, 74 insertions(+), 46 deletions(-) diff --git a/R/reporter_ansi_tty.R b/R/reporter_ansi_tty.R index 7d4b20f..496ee3c 100644 --- a/R/reporter_ansi_tty.R +++ b/R/reporter_ansi_tty.R @@ -242,9 +242,12 @@ report_sleep.reporter_ansi_tty <- function( report_start_setup.reporter_ansi_tty <- function( reporter, checker, - message, + ..., envir = parent.frame() ) { + if (cli_env_has_pb(reporter$cli)) return() + reporter$cli <- new.env(parent = reporter) + # hide cursor when initializer enters, ensure its restored even if interrupted cli::ansi_hide_cursor() do.call( @@ -253,23 +256,36 @@ report_start_setup.reporter_ansi_tty <- function( envir = envir ) - cli::cli_progress_message( - message, + cli::cli_progress_bar( + type = "custom", + format = paste( + "ETA {cli::pb_eta}", + "({cli::pb_current}/{cli::pb_total})", + "[{cli::pb_elapsed}]", + "{cli::pb_extra$message}" + ), + format_done = "Finished in {cli::pb_elapsed}", + ..., clear = FALSE, auto_terminate = FALSE, .auto_close = FALSE, - .envir = reporter, + .envir = reporter$cli ) + + cli::cli_progress_update(force = TRUE, .envir = reporter$cli) } get_reporter_node <- function(g, v, mode = "out") { end <- if (mode == "out") igraph::head_of else igraph::tail_of v_es <- igraph::incident_edges(g, v, mode = mode) - v_rep <- simplify2array(lapply(v_es, function(es) { - eidx <- es$relation == RELATION$report - as.numeric(end(g, es[eidx])) + v_rep <- simplify2array(lapply(seq_along(v), function(i) { + if (any(eidx <- v_es[[i]]$relation == RELATION$report)) { + as.numeric(end(g, v_es[[i]][eidx])) + } else { + as.numeric(v[[i]]) + } })) - V(g)[ifelse(is.na(v_rep), as.numeric(v), v_rep)] + V(g)[ifelse(is.na(v_rep), as.numeric(v), unlist(v_rep))] } reporter_ansi_tty_get_label_nchar <- function( @@ -340,44 +356,30 @@ report_start_checks.reporter_ansi_tty <- function( reporter$buffer_update(node, output) } - # hide cursor when initializer enters, ensure its restored even if interrupted - cli::ansi_hide_cursor() - do.call( - on.exit, - list(quote(cli::ansi_show_cursor()), add = TRUE), - envir = envir - ) - - cli::cli_progress_bar( - type = "custom", - extra = list(message = ""), - format = paste( - "ETA {cli::pb_eta}", - "({cli::pb_current}/{cli::pb_total})", - "[{cli::pb_elapsed}]", - "{cli::pb_extra$message}" - ), - format_done = "Finished in {cli::pb_elapsed}", - total = sum(igraph::V(checker$graph)$type == "check"), - clear = FALSE, - auto_terminate = FALSE, - .auto_close = FALSE, - .envir = reporter, - ) + extra <- list(message = "") + if (cli_env_has_pb(reporter$cli)) { + cli::cli_progress_update(extra = extra, .envir = reporter$cli) + } else { + report_start_setup( + reporter, + checker, + extra = extra, + total = sum(is_check(igraph::V(checker$graph)$task)), + envir = envir + ) + } } #' @importFrom igraph V #' @export report_status.reporter_ansi_tty <- function(reporter, checker, envir) { + msg <- c() v <- igraph::V(checker$graph) - v_checks <- v[is_check(v$task)] # add newly started task status updated <- which( - v_checks$status > STATUS$pending | ( - v_checks$status == STATUS$done & - !v_checks$name %in% reporter$buffer$node - ) + v$status > STATUS$pending | + (v$status == STATUS$done & !v$name %in% reporter$buffer$node) ) # skip if no updates @@ -385,8 +387,8 @@ report_status.reporter_ansi_tty <- function(reporter, checker, envir) { return() } - # find any reporter nodes for updated checks - updated <- unique(get_reporter_node(checker$graph, v_checks[updated])) + # find reporter nodes for updated tasks + updated <- unique(get_reporter_node(checker$graph, updated)) # print header if this is the first status line of the reporter if (nrow(reporter$buffer) == 0L) { @@ -399,10 +401,22 @@ report_status.reporter_ansi_tty <- function(reporter, checker, envir) { ) } - for (node_name in updated$name) { + # report check tasks in cli output + to_report <- is_meta(updated$task) | is_check(updated$task) + for (node_name in updated[to_report]$name) { reporter$buffer_report(node_name) } + # report non-check tasks in status line + to_report <- is_install(updated$task) & + updated$status > STATUS$pending & + updated$status < STATUS$done + + if (any(to_report)) msg[length(msg) + 1L] <- "installing" + for (node_name in updated[to_report]$name) { + msg[length(msg) + 1L] <- fmt("{package}", task = updated[[node_name]]$task) + } + # if console width has changed, redraw all if (identical(reporter$width, cli::console_width)) { reporter$buffer$updated <- TRUE @@ -432,17 +446,17 @@ report_status.reporter_ansi_tty <- function(reporter, checker, envir) { reporter$buffer$updated <- FALSE cat(buffer) - n_finished <- sum(v$status[v$type == "check"] >= STATUS$done) + n_finished <- sum(v[is_check(v$task)]$status >= STATUS$done) cli::cli_progress_update( set = n_finished, - extra = list(message = ""), - .envir = reporter + extra = list(message = paste(msg, collapse = " ")), + .envir = reporter$cli ) } #' @export report_finalize.reporter_ansi_tty <- function(reporter, checker) { report_status(reporter, checker) # report completions of final processes - cli::cli_progress_done(.envir = reporter) + cli::cli_progress_done(.envir = reporter$cli) cli::ansi_show_cursor() } diff --git a/R/run.R b/R/run.R index 0967c8b..5401934 100644 --- a/R/run.R +++ b/R/run.R @@ -19,7 +19,12 @@ run <- function(checker, ..., reporter = reporter_default()) { #' @export run.character <- function(checker, ..., reporter = reporter_default()) { - report_start_setup(reporter, checker, message = "planning checks ...") + report_start_setup( + reporter, + checker, + extra = list(message = "planning checks ...") + ) + run(new_rev_dep_checker(checker, ...), reporter = reporter) } @@ -30,6 +35,7 @@ run.checker <- function(checker, ..., reporter = reporter_default()) { report_finalize(reporter, checker) }) + report_start_setup(reporter, checker) report_start_checks(reporter, checker) while (checker$step()) { if (length(checker$active_processes()) == 0 && !checker$is_done()) { diff --git a/R/task.R b/R/task.R index 1ddaa7b..3b2a283 100644 --- a/R/task.R +++ b/R/task.R @@ -104,6 +104,10 @@ is_check <- function(x) { is_type(x, "check") } +is_meta <- function(x) { + is_type(x, "meta") +} + #' Create a custom install task #' #' @inheritDotParams install_task diff --git a/R/utils-cli.R b/R/utils-cli.R index 23f31cb..815145c 100644 --- a/R/utils-cli.R +++ b/R/utils-cli.R @@ -184,3 +184,7 @@ emoji <- list( dev = "\U0001F6A7", release = "\U0001F680" ) + +cli_env_has_pb <- function(env) { + !is.null(attr(env, "withr_handlers")) +} diff --git a/man/checker.Rd b/man/checker.Rd index 4820417..2d5f708 100644 --- a/man/checker.Rd +++ b/man/checker.Rd @@ -78,7 +78,7 @@ and installation order are embedded. \if{html}{\out{
}}\preformatted{checker$new( plan, n = 2L, - output = tempfile(paste(packageName(), Sys.Date(), sep = "-")), + output = file.path(tempdir(), paste(packageName(), Sys.Date(), sep = "-")), lib.loc = .libPaths(), repos = getOption("repos"), restore = TRUE, From 2c532d0eb07bbbede1249ab839a0e763fa8f0972 Mon Sep 17 00:00:00 2001 From: dgkf-roche Date: Mon, 16 Jun 2025 12:10:19 -0400 Subject: [PATCH 31/62] feat(devx): improve readability of vertex names --- NAMESPACE | 2 ++ R/plan.R | 10 ++++++---- R/task-formatting.R | 4 ++-- R/task_graph.R | 2 +- R/utils-igraph.R | 2 +- R/utils.R | 17 +++++++++++++++++ man/custom_install_task.Rd | 3 ++- man/install_task.Rd | 3 ++- 8 files changed, 33 insertions(+), 10 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 568c9cc..5a87f2f 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -10,6 +10,8 @@ S3method(as_desc,install_task) S3method(as_desc,pkg_origin_local) S3method(as_desc,pkg_origin_repo) S3method(as_desc,subtasks_task) +S3method(as_vertex_name,default) +S3method(as_vertex_name,task) S3method(check_path,pkg_origin) S3method(check_path,pkg_origin_archive) S3method(check_path,pkg_origin_local) diff --git a/R/plan.R b/R/plan.R index 3e4cd36..932b9fd 100644 --- a/R/plan.R +++ b/R/plan.R @@ -144,10 +144,11 @@ plan_rev_dep_checks <- function( plan_rev_dep_dev_check <- function(origin, revdep, repos) { rev_dep_origin <- pkg_origin_repo(package = revdep, repos = repos) g <- sequence_graph(task = list( - make_unique_task(seed = revdep, meta_task( + meta_task( origin = origin, + revdep = revdep, .subclass = "rev_dep_check" - )), + ), make_unique_task(seed = "dev", check_task( origin = rev_dep_origin, env = DEFAULT_R_CMD_CHECK_ENVVARS, @@ -171,10 +172,11 @@ plan_rev_dep_dev_check <- function(origin, revdep, repos) { plan_rev_dep_release_check <- function(origin, revdep, repos) { rev_dep_origin <- pkg_origin_repo(package = revdep, repos = repos) g <- sequence_graph(task = list( - make_unique_task(seed = revdep, meta_task( + meta_task( origin = origin, + revdep = revdep, .subclass = "rev_dep_check" - )), + ), make_unique_task(seed = "release", check_task( origin = rev_dep_origin, env = DEFAULT_R_CMD_CHECK_ENVVARS, diff --git a/R/task-formatting.R b/R/task-formatting.R index 866081e..bed6b78 100644 --- a/R/task-formatting.R +++ b/R/task-formatting.R @@ -14,12 +14,12 @@ format_task_type.task <- function(x, ...) { #' @export format_task_type.rev_dep_dep_meta_task <- function(x, ...) { - "check revdeps of" + "meta revdeps of" } #' @export format_task_type.rev_dep_check_meta_task <- function(x, ..., g = NULL) { - "check revdep of" + fmt(task = x, "meta revdep {.pkg {x$revdep}} of") } diff --git a/R/task_graph.R b/R/task_graph.R index 2563a38..6fc2e8d 100644 --- a/R/task_graph.R +++ b/R/task_graph.R @@ -67,7 +67,7 @@ task_graph_create <- function(plan, repos = getOption("repos")) { E(subtree)$type[is_na] <- DEP$Depends # re-hash tasks as vertex names - igraph::V(subtree)$name <- vcapply(igraph::V(subtree)$task, hash) + igraph::V(subtree)$name <- vcapply(igraph::V(subtree)$task, as_vertex_name) subtree }) diff --git a/R/utils-igraph.R b/R/utils-igraph.R index f7537b4..5707c64 100644 --- a/R/utils-igraph.R +++ b/R/utils-igraph.R @@ -11,7 +11,7 @@ sequence_graph <- function( vertex_attrs = list(...), edge_attrs = list(), name_by = vertex_attrs[[1]], - name = hashes(name_by) + name = vcapply(name_by, as_vertex_name) ) { vertices <- vertex_df(name = name, ...) edges <- data.frame( diff --git a/R/utils.R b/R/utils.R index 5cefbcc..81b7733 100644 --- a/R/utils.R +++ b/R/utils.R @@ -1,6 +1,23 @@ #' @import cli NULL +as_vertex_name <- function(x, ...) { + UseMethod("as_vertex_name") +} + +#' @export +as_vertex_name.default <- function(x, ...) { + hash(x, ...) +} + +#' @export +as_vertex_name.task <- function(x, ...) { + paste0( + hash(x, ...), + gsub("\\s+", "-", fmt(task = x, "-{action}-{package}", ansi = FALSE)) + ) +} + hash <- function(x, n = 12) { substring(cli::hash_obj_sha256(x), 1, n) } diff --git a/man/custom_install_task.Rd b/man/custom_install_task.Rd index 3167a90..fbefb7f 100644 --- a/man/custom_install_task.Rd +++ b/man/custom_install_task.Rd @@ -19,7 +19,8 @@ path.} \item{\code{INSTALL_opts}}{ an optional character vector of additional option(s) to be passed to \command{R CMD INSTALL} for a source package install. E.g., - \code{c("--html", "--no-multiarch", "--no-test-load")}. + \code{c("--html", "--no-multiarch", "--no-test-load")} or, for + macOS, \code{"--dsym"}. Can also be a named list of character vectors to be used as additional options, with names the respective package names. diff --git a/man/install_task.Rd b/man/install_task.Rd index 83c1338..9797ede 100644 --- a/man/install_task.Rd +++ b/man/install_task.Rd @@ -21,7 +21,8 @@ install_task( \item{INSTALL_opts}{ an optional character vector of additional option(s) to be passed to \command{R CMD INSTALL} for a source package install. E.g., - \code{c("--html", "--no-multiarch", "--no-test-load")}. + \code{c("--html", "--no-multiarch", "--no-test-load")} or, for + macOS, \code{"--dsym"}. Can also be a named list of character vectors to be used as additional options, with names the respective package names. From 61ec2d74a4581391a2a9e3f327b1f36f3dc97fc2 Mon Sep 17 00:00:00 2001 From: dgkf-roche Date: Wed, 18 Jun 2025 11:57:56 -0400 Subject: [PATCH 32/62] wip --- R/reporter_ansi_tty.R | 15 ++++++++------- man/custom_install_task.Rd | 3 ++- man/install_task.Rd | 3 ++- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/R/reporter_ansi_tty.R b/R/reporter_ansi_tty.R index 496ee3c..6cb3e0b 100644 --- a/R/reporter_ansi_tty.R +++ b/R/reporter_ansi_tty.R @@ -378,8 +378,8 @@ report_status.reporter_ansi_tty <- function(reporter, checker, envir) { # add newly started task status updated <- which( - v$status > STATUS$pending | - (v$status == STATUS$done & !v$name %in% reporter$buffer$node) + (v$status > STATUS$pending & v$status < STATUS$done) | + (v$status >= STATUS$done & !v$name %in% reporter$buffer$node) ) # skip if no updates @@ -402,18 +402,18 @@ report_status.reporter_ansi_tty <- function(reporter, checker, envir) { } # report check tasks in cli output - to_report <- is_meta(updated$task) | is_check(updated$task) - for (node_name in updated[to_report]$name) { + to_report_main <- is_meta(updated$task) + for (node_name in updated[to_report_main]$name) { reporter$buffer_report(node_name) } # report non-check tasks in status line - to_report <- is_install(updated$task) & + to_report_bar <- is_install(updated$task) & updated$status > STATUS$pending & updated$status < STATUS$done - if (any(to_report)) msg[length(msg) + 1L] <- "installing" - for (node_name in updated[to_report]$name) { + if (any(to_report_bar)) msg[length(msg) + 1L] <- "installing" + for (node_name in updated[to_report_bar]$name) { msg[length(msg) + 1L] <- fmt("{package}", task = updated[[node_name]]$task) } @@ -458,5 +458,6 @@ report_status.reporter_ansi_tty <- function(reporter, checker, envir) { report_finalize.reporter_ansi_tty <- function(reporter, checker) { report_status(reporter, checker) # report completions of final processes cli::cli_progress_done(.envir = reporter$cli) + cat(ansi_line_erase()) # clear lingering progress bar output cli::ansi_show_cursor() } diff --git a/man/custom_install_task.Rd b/man/custom_install_task.Rd index 3167a90..fbefb7f 100644 --- a/man/custom_install_task.Rd +++ b/man/custom_install_task.Rd @@ -19,7 +19,8 @@ path.} \item{\code{INSTALL_opts}}{ an optional character vector of additional option(s) to be passed to \command{R CMD INSTALL} for a source package install. E.g., - \code{c("--html", "--no-multiarch", "--no-test-load")}. + \code{c("--html", "--no-multiarch", "--no-test-load")} or, for + macOS, \code{"--dsym"}. Can also be a named list of character vectors to be used as additional options, with names the respective package names. diff --git a/man/install_task.Rd b/man/install_task.Rd index 83c1338..9797ede 100644 --- a/man/install_task.Rd +++ b/man/install_task.Rd @@ -21,7 +21,8 @@ install_task( \item{INSTALL_opts}{ an optional character vector of additional option(s) to be passed to \command{R CMD INSTALL} for a source package install. E.g., - \code{c("--html", "--no-multiarch", "--no-test-load")}. + \code{c("--html", "--no-multiarch", "--no-test-load")} or, for + macOS, \code{"--dsym"}. Can also be a named list of character vectors to be used as additional options, with names the respective package names. From 5b90e667a2e9b9238e7732226ca04817fa16684e Mon Sep 17 00:00:00 2001 From: dgkf-roche Date: Wed, 18 Jun 2025 15:34:08 -0400 Subject: [PATCH 33/62] removing node relation edge type --- NAMESPACE | 1 + R/checker.R | 56 +++++++++++++++++++++++++++++++----------- R/next_task.R | 2 +- R/plan.R | 32 +++--------------------- R/reporter_ansi_tty.R | 46 ++++++++++++---------------------- R/task_graph.R | 43 ++++++-------------------------- Rplots.pdf | Bin 25458 -> 0 bytes 7 files changed, 70 insertions(+), 110 deletions(-) delete mode 100644 Rplots.pdf diff --git a/NAMESPACE b/NAMESPACE index 5a87f2f..4946d29 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -84,6 +84,7 @@ S3method(report_status,"NULL") S3method(report_status,reporter_ansi_tty) S3method(report_status,reporter_basic_tty) S3method(report_task_ansi_tty,check_task) +S3method(report_task_ansi_tty,default) S3method(report_task_ansi_tty,rev_dep_check_meta_task) S3method(results,check_task) S3method(results,checker) diff --git a/R/checker.R b/R/checker.R index 2cbb484..404690d 100644 --- a/R/checker.R +++ b/R/checker.R @@ -170,22 +170,21 @@ checker <- R6::R6Class( return(0L) } - next_task <- next_task_to_run(self$graph) - - if (length(next_task) > 0) { + next_node <- next_node_to_run(self$graph) + if (length(next_node) > 0) { process <- start_task( - node = next_task, + node = next_node, g = self$graph, output = self$output, lib.loc = private$lib.loc ) if (is.null(process)) { - private$finish_task(next_task) + private$finish_node(next_node) return(1L) } - success <- private$push_process(next_task, process) + success <- private$push_process(next_node, process) return(as.integer(success)) } @@ -220,24 +219,51 @@ checker <- R6::R6Class( # failed tasks failed = list(), - start_task = function(task) { - task_graph_package_status(self$graph, task) <- STATUS$`in progress` + start_node = function(node) { + task_graph_package_status(self$graph, node) <- STATUS$`in progress` + private$start_node_meta_parents(node) + }, + + start_node_meta_parents = function(node) { + # start parent meta tasks recursively once a child starts + parent_nodes <- igraph::adjacent_vertices(self$graph, node, mode = "in") + parent_nodes <- unlist(parent_nodes, use.names = FALSE) + parent_nodes <- V(self$graph)[parent_nodes] + meta_parent_nodes <- parent_nodes[is_meta(parent_nodes$task)] + for (meta in meta_parent_nodes) { + task_graph_package_status(self$graph, meta) <- STATUS$`in progress` + private$start_node_meta_parents(meta) + } }, - finish_task = function(task) { + finish_node = function(task) { task_graph_package_status(self$graph, task) <- STATUS$`done` + private$finish_node_meta_parents(task) + }, + + finish_node_meta_parents = function(node) { + # parent meta tasks finish once _all_ children are finished + parent_nodes <- igraph::adjacent_vertices(self$graph, node, mode = "in") + parent_nodes <- unlist(parent_nodes, use.names = FALSE) + parent_nodes <- V(self$graph)[parent_nodes] + meta_parent_nodes <- parent_nodes[is_meta(parent_nodes$task)] + for (meta in meta_parent_nodes) { + siblings <- igraph::adjacent_vertices(self$graph, meta, "out") + if (!all(siblings$status == STATUS$`done`)) next + task_graph_package_status(self$graph, meta) <- STATUS$`done` + } }, - push_process = function(task, x) { - task_graph_task_process(self$graph, task) <- x - name <- task_graph_task_name(self$graph, task) - private$start_task(task) + push_process = function(node, x) { + task_graph_task_process(self$graph, node) <- x + name <- task_graph_task_name(self$graph, node) + private$start_node(node) x$set_finisher(function(process) { if (process$get_r_exit_status() != 0) { - private$failed[[name]] <- task + private$failed[[name]] <- node } private$pop_process(name) - private$finish_task(task) + private$finish_node(node) }) private$active[[name]] <- x TRUE diff --git a/R/next_task.R b/R/next_task.R index aa2022c..d682b9e 100644 --- a/R/next_task.R +++ b/R/next_task.R @@ -1,4 +1,4 @@ -next_task_to_run <- function(g) { +next_node_to_run <- function(g) { checks <- task_graph_which_check_satisfied(g) installs <- task_graph_which_install_satisfied(g) diff --git a/R/plan.R b/R/plan.R index 932b9fd..173aa61 100644 --- a/R/plan.R +++ b/R/plan.R @@ -126,13 +126,7 @@ plan_rev_dep_checks <- function( edges <- as.vector(rbind(task_id, rev_dep_meta_task_ids)) # meta tasks take dependency relationship with subtasks - g <- igraph::add_edges(g, edges = edges, attr = list( - relation = RELATION$dep, - type = DEP$Depends - )) - - # recover coerced factor types - E(g)$relation <- RELATION[E(g)$relation] + g <- igraph::add_edges(g, edges = edges, attr = list(type = DEP$Depends)) E(g)$type <- DEP[E(g)$type] class(g) <- c("task_graph", class(g)) @@ -143,7 +137,7 @@ plan_rev_dep_checks <- function( plan_rev_dep_dev_check <- function(origin, revdep, repos) { rev_dep_origin <- pkg_origin_repo(package = revdep, repos = repos) - g <- sequence_graph(task = list( + sequence_graph(task = list( meta_task( origin = origin, revdep = revdep, @@ -157,21 +151,11 @@ plan_rev_dep_dev_check <- function(origin, revdep, repos) { )), install_task(origin = origin) )) - - # this check is reported through a rev dep check meta task - g <- igraph::add_edges(g, edges = c(2, 1)) # NOTE: coerces factor to numeric - - .to <- NULL # used by igraph NSE - igraph::E(g)$type <- DEP$Depends - igraph::E(g)$relation <- RELATION$dep - igraph::E(g)[.to(1)]$relation <- RELATION$report - - g } plan_rev_dep_release_check <- function(origin, revdep, repos) { rev_dep_origin <- pkg_origin_repo(package = revdep, repos = repos) - g <- sequence_graph(task = list( + sequence_graph(task = list( meta_task( origin = origin, revdep = revdep, @@ -184,16 +168,6 @@ plan_rev_dep_release_check <- function(origin, revdep, repos) { build_args = DEFAULT_R_CMD_BUILD_ARGS )) )) - - # this check is reported through a rev dep check meta task - g <- igraph::add_edges(g, edges = c(2, 1)) # NOTE: coerces factor to numeric - - .to <- NULL # used by igraph - igraph::E(g)$type <- DEP$Depends - igraph::E(g)$relation <- RELATION$dep - igraph::E(g)[.to(1)]$relation <- RELATION$report - - g } rev_dep_check_tasks <- function(packages, repos, aliases, revdep) { diff --git a/R/reporter_ansi_tty.R b/R/reporter_ansi_tty.R index 6cb3e0b..082c14e 100644 --- a/R/reporter_ansi_tty.R +++ b/R/reporter_ansi_tty.R @@ -149,19 +149,23 @@ format.reporter_cell <- function(x, ) } +#' @export +report_task_ansi_tty.default <- function(reporter, g, v) { + NULL +} + #' @export report_task_ansi_tty.rev_dep_check_meta_task <- function(reporter, g, v) { # package being rev-dep-check'ed package <- v$task$origin$package - # subset for dependency edges from rev dep task - dep_g <- dep_subgraph(g) - # get individual rev dep checks, and get their trees - check_nodes <- igraph::neighbors(dep_g, v$name, "out") + check_nodes <- igraph::neighbors(g, v$name, "out") + + # NOTE: do we only want to check _direct_ reverse dependencies? check_neighborhoods <- igraph::make_neighborhood_graph( - dep_g, - order = 1, # NOTE: do we only want to check _direct_ reverse dependencies? + g, + order = 1, check_nodes, mode = "out" ) @@ -186,8 +190,7 @@ report_task_ansi_tty.rev_dep_check_meta_task <- function(reporter, g, v) { } ) - rev_dep_check_nodes <- get_reporter_node(g, v, mode = "in") - rev_dep <- fmt(task = rev_dep_check_nodes[[1]]$task, " {package} ") + rev_dep <- paste0(" ", v$task$revdep, " ") to_report <- mapply( function(label, i) { x <- report_task_ansi_tty(reporter = reporter, g = g, v = V(g)[[i]]) @@ -195,7 +198,7 @@ report_task_ansi_tty.rev_dep_check_meta_task <- function(reporter, g, v) { x }, package_task_labels, - rev_dep_check_nodes, + check_nodes, SIMPLIFY = FALSE ) @@ -275,19 +278,6 @@ report_start_setup.reporter_ansi_tty <- function( cli::cli_progress_update(force = TRUE, .envir = reporter$cli) } -get_reporter_node <- function(g, v, mode = "out") { - end <- if (mode == "out") igraph::head_of else igraph::tail_of - v_es <- igraph::incident_edges(g, v, mode = mode) - v_rep <- simplify2array(lapply(seq_along(v), function(i) { - if (any(eidx <- v_es[[i]]$relation == RELATION$report)) { - as.numeric(end(g, v_es[[i]][eidx])) - } else { - as.numeric(v[[i]]) - } - })) - V(g)[ifelse(is.na(v_rep), as.numeric(v), unlist(v_rep))] -} - reporter_ansi_tty_get_label_nchar <- function( reporter, checker, @@ -295,7 +285,7 @@ reporter_ansi_tty_get_label_nchar <- function( ) { # pre-calculate the maximum space needed for label column v <- igraph::V(checker$graph) - v_report <- unique(get_reporter_node(checker$graph, v[is_check(v$task)])) + v_report <- v[is_meta(v$task)] # for each reporter, produce output output <- unlist(recursive = FALSE, lapply( @@ -377,19 +367,15 @@ report_status.reporter_ansi_tty <- function(reporter, checker, envir) { v <- igraph::V(checker$graph) # add newly started task status - updated <- which( - (v$status > STATUS$pending & v$status < STATUS$done) | - (v$status >= STATUS$done & !v$name %in% reporter$buffer$node) - ) + is_running <- v$status > STATUS$pending & v$status < STATUS$done + is_newly_done <- v$status >= STATUS$done & !v$name %in% reporter$buffer$node + updated <- v[is_running | is_newly_done] # skip if no updates if (length(updated) <= 0L) { return() } - # find reporter nodes for updated tasks - updated <- unique(get_reporter_node(checker$graph, updated)) - # print header if this is the first status line of the reporter if (nrow(reporter$buffer) == 0L) { reporter$buffer_update( diff --git a/R/task_graph.R b/R/task_graph.R index 6fc2e8d..8ca350a 100644 --- a/R/task_graph.R +++ b/R/task_graph.R @@ -24,12 +24,11 @@ #' @keywords internal task_graph_create <- function(plan, repos = getOption("repos")) { # only use dependency edges when populating graph - dep_g <- dep_subgraph(plan) - check_tasks <- igraph::V(dep_g)[is_check(igraph::V(dep_g)$task)] + check_tasks <- igraph::V(plan)[is_check(igraph::V(plan)$task)] check_task_neighborhoods <- igraph::neighborhood( - dep_g, - order = length(dep_g), + plan, + order = length(plan), mode = "out", nodes = check_tasks ) @@ -37,7 +36,7 @@ task_graph_create <- function(plan, repos = getOption("repos")) { # for each check task in the plan, build a dependency tree and merge it # into the existing check task subtree check_task_neighborhoods <- lapply(check_task_neighborhoods, function(nh) { - subtree <- igraph::induced_subgraph(dep_g, nh) + subtree <- igraph::induced_subgraph(plan, nh) V(subtree)$name <- vcapply( V(subtree)$task, function(i) i$origin$package %||% NA_character_ @@ -47,7 +46,6 @@ task_graph_create <- function(plan, repos = getOption("repos")) { # TODO: if this is too slow, could move after all neighborhoods are merged deps <- dep_tree(nh[[1]]$task) igraph::reverse_edges(deps) - igraph::E(deps)$relation <- RELATION$dep igraph::E(deps)$type <- DEP[igraph::E(deps)$type] igraph::V(deps)$task <- lapply( igraph::V(deps)$name, @@ -62,8 +60,7 @@ task_graph_create <- function(plan, repos = getOption("repos")) { subtree <- graph_dedup_attrs(igraph::union(subtree, deps)) # fill new edges with dependency relation - between check task and installs - is_na <- is.na(E(subtree)$relation) - E(subtree)$relation[is_na] <- RELATION$dep + is_na <- is.na(E(subtree)$type) E(subtree)$type[is_na] <- DEP$Depends # re-hash tasks as vertex names @@ -75,7 +72,6 @@ task_graph_create <- function(plan, repos = getOption("repos")) { # then merge all the full check task task trees into a single graph g <- graph_dedup_attrs(igraph::union(plan, check_task_neighborhoods)) - igraph::E(g)$relation <- RELATION[igraph::E(g)$relation] igraph::E(g)$type <- DEP[igraph::E(g)$type] igraph::V(g)$status <- STATUS$pending igraph::V(g)$process <- rep_len(list(), length(g)) @@ -87,15 +83,7 @@ task_graph_create <- function(plan, repos = getOption("repos")) { } dep_edges <- function(edges, dependencies = TRUE) { - if (!is.logical(dependencies)) { - dependencies <- edges$type %in% check_dependencies(dependencies) - } - - edges$relation == RELATION$dep & dependencies -} - -dep_subgraph <- function(g) { - igraph::subgraph_from_edges(g, igraph::E(g)[dep_edges(igraph::E(g))]) + edges[edges$type %in% dependencies] } lib_node_tasks <- function(g, nodes) { @@ -245,7 +233,7 @@ task_graph_sort <- function(g) { } # use only strong dependencies to prioritize by topology (leafs first) - strong_edges <- igraph::E(g)[dep_edges(E(g), "strong")] + strong_edges <- dep_edges(E(g), "strong") g_strong <- igraph::subgraph.edges(g, strong_edges, delete.vertices = FALSE) topo <- igraph::topo_sort(g_strong, mode = "in") priority_topo <- integer(length(g)) @@ -307,7 +295,7 @@ task_graph_which_satisfied <- function( deps_met <- vlapply( igraph::incident_edges(g, v, mode = "out"), function(edges) { - is_dep <- edges$relation == RELATION$dep & edges$type %in% dependencies + is_dep <- edges$type %in% dependencies all(igraph::head_of(g, edges[is_dep])$status == STATUS$done) } ) @@ -408,7 +396,6 @@ plot.task_graph <- function(x, ..., interactive = FALSE) { class(task)[[1]] }) - x <- dep_subgraph(x) vertex <- igraph::as_data_frame(x, what = "vertices") edge <- igraph::as_data_frame(x, what = "edges") @@ -451,19 +438,6 @@ plot.task_graph <- function(x, ..., interactive = FALSE) { 8 ) - edge$lty <- style( - RELATION[igraph::E(x)$relation], - "dep" = 1, - "report" = 2, - 1 - ) - - edge$color <- style( - RELATION[igraph::E(x)$relation], - "report" = "lightgray", - NA - ) - if (interactive) { plot_interactive_task_graph(x, vertex = vertex, edge = edge) } else { @@ -486,7 +460,6 @@ plot_static_task_graph <- function( vertex.size = vertex$size, vertex.frame.color = vertex$frame.color, vertex.frame.width = vertex$frame.width, - edge.lty = edge$lty, layout = igraph::layout_with_sugiyama( g, hgap = 200, diff --git a/Rplots.pdf b/Rplots.pdf deleted file mode 100644 index 03d5b3f94aaa0575716326a2b6e5cfa7c3a1cc0d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25458 zcmZ_#V~{0G6E%u9rmbn)wyo)D+xBkTwr$(mt!dk~ZQJ&F-Y?F*H{zZ+KPz*std;qr zsv=etxq^roJu?FvEP23wz(K%Fz=Dn=EHe=kksZJimX8mXQP|PM(AmPyR>aWRgosLn zhlPoSor#5sgPE0ug_VUGmQmKu`2RJhV&QE4A4`cy+|kh9+``C-NZ!TS-o^Ppnu4R9 zv5S$3-^u+iHPg}&>59Xoa|g2jsC00 z_WxJ!e}MnbIAlz0&794NSeV(FIf)p>EUcaXYk^VB`oHOjm>Ag^oBU6>lkkF&%RuXr0l&qaPD319T$SrCf3l^+J*%pN8y;Qfrb$O;;6aN=m=K_{^{l#&Alu zJ+XVPXdR}7zsNCXa}79!j@tQsr0)3sJPQhb;{S9#Jux@6C<-<|FFSs4jcen-88O=V zeSTm4cz)as=zo2_{2bNpd><1E6vwTo?o9Xm+;aY0eY-ri_)L^(3v2ENx45^D^D= zI_401b>v~)*={=`3F^MkKOL~&}`fHfuX}aNJB^ny)=@(_0n=m&Y_Ke5GSKhpW)!Y<@HxAD?~GuBn7*Mmn2L zkGbvK9h`gt9t=Ym>` z$U6@xI)2eGHElW9x@{H@EP;+~)9QB(zZ74j0+-sC?=#SQZv?eqV9j9fZ7$Jtv;sh`ndetft1 zZLX!-D7!Y1Ql9Q;D7xwWA!Y~JN3M7rKo{4JYwWVU_UQdUB@b-@j2o#YO-s1htxf_wBU-wJT=(b^OrN`Z@je09H4K}c+$igmn~>;N^HkGE|E%(9yF z=e|y@dwfpfTVA8{*fn_qP1x1mhR~*=VSyIUGojgZt;Z*dA*n)k+SoOWo?Vum;(1AE zJ;LkmR$*N3jQgmSG9%Vq^3qZfHESgc+T2*)nqq2;>_q-ukwS#fIksKxb%=q}?jjGD z-l~JxfbP^MZwmd@67>~xTMn1&T#hzLtAC9e-8hvy>r+rgwNF@bxA7;u zyS>EH6Q7&{D#QpZ)KY}NK6s~DG( z*z48$vL!)Gmv5vM=QOBnJ4DTm0j56- zr;=T{)NR<{rdLY(xEAaDXS;wt6Ctao(&D*3lMB6G+E;~1+OfN1fhc}Sy_}D`X$YPC z5xBqnrM{D40FZY8RZBCa?dINgLZeei6d{ z@6fncJE317?cND5t3Nr^Gd5S5(mBZ;MF#$fv?#2})N3*5tmRwxaQ;4qD04+z*NoG` zFiyCL(!wyZ$p{T}>3|`y^r5~kk8m^KDj7rx)7v?5nh>=rI!Mi;xkeUV_q<2d08CQZ z!fbE-tvb1jCKx47=M~K3>gR71b)oc%=&!MA6-{QUz^KI<>V^pF z{;LvCWvAt3`2La)m1ZuTCIZ@sp5j%8abKI;lpzGidTON&7F8HTBNiARs<6#M(}x(P zYdV&D5f$k+<92Yk9B6@EH=DjWWmCJFS#WK(As!<(=JM~-tDD)>udG`OuP>aPc8ce! zQl&e?GvigJkxSBJId`PvSVXc#wKwa4xiA!zbMR27L-s^;lZ#<;rv@ zEZoY8WD3zZl|$HKojYqLL-M#q42+g_Sy$PfvvbF_+Vy?3D)jtTz?#w=@S)gmDaK;vE6iYEASI&*(^dbbV&MP?fAnP z>!SDDw+wc+4&6Xth`##I^w46{0lf*q)=^@Q`6~W8DTlMVo8A6E=r+bn^adeqMc@rS z+LC3xRPoP#>XvoA*Ho2U&=}8jM$RS^Ioqk3 z#y?kWt(r!tTL3zaIgH;0)6oOBuMMC>a@HsKbrIte_?Xp4|C#`(OYOl&NN$`QBw(KMai5n>FhG`33C92f<{f1D! zk=wi*1U`%85&=ZYSuEC;k?rbYu~~I{Qsbfe&6=F~IxRCpQrn;A%p60kBsp`xDJHb} z_bY7?%~Y1B*(>~Y3!Q#=Og+#Vb{PI`YaCve@%5@Oi{_Ezs3%6F7&p?Dpcp%!iioJ9#8j zTcbPS(bp+(dha=#(BJ>GlK(k6`!Vf-LR;+nODjpN97Y}2jHzSP-PBuN`R;i0!n4v4 z0m#v}#qOh-(S~02dw*jDc^340zZ3o!?zJXN1f_LHti}YgB|{H-g}kCXY1`QM366uv z1%8!(FOrXP)my6k^6;m@3E1m3dp)FvmWf$@ef?~98>0|<-NCvemQNYbEfB<=0?F>P zdqo@oYc0DiSU@jwbG=cBK!MtYH0RJlOBCN4grz96XgX7n%aD z!hPWd+QV@gkvG=^0^7f8{F5JXnB@q&tu9nKckN98V%7N81#3VaHO~bFu3^{BY4!VZ ztK0waX;QUPYbckkG{6SMDb%ATXjc>*DdHLIo}e7*{rBGz!`Rnum}F$FNfm7^*)hwo zdxssrH{WPv)ujtKYxUr+2t+BNz^aGv~~LTxC*n6<8SWO@UwiGOL8uLrORNC zfP2&o?Ddzxpyz+66cT*qNxVj2aS*L(OL9V$5bMYm%;wx4Wgus|tL~~|EYJe0&TT-#^nR`K55q`e*PD zv@NpYKUNV{L%auH8{tHC$dJ2eaL`(44fW?%I>e zA+7MCHTq{NumQDn-Y?7wrdDxpLEmi^CIh*@%%=+Q49Y`80!WwLbg8&D zRqtr%@S_ds>Pnz37FE(co238+AX|V3_6wPW#H(K>uj?#4dWga=9yOn9^f3+9`NgSZ z%l?&G=gHYEULbkjB98ehaKE;N1c}`&1Jjx16UOa&3XaD)+g$nfSrRG{;sQdMe_aL5 zmX{-V{a2q@2UtjV2aiXWkzE*~(KeX9OCoSK*Id5)hoy(U)tCKt#6r)h$Io#Iw-!?m z>T!re4gZwv1FCG7#4p+vx{BOn?31Z`?H2KVKVj;(EjP$SCt57Xu_wjjt=e$SP(S2G0{t!~5>II#xy zpugXoj6kur-oM~I5q7`cp~tO?vu|O+K^sed>t)|7*dl5)2HZb+gR4dlVFw`&o8w*j zHd3yq-?jEkw5U9F59P2XcGrSn-!7aocB(^fy++>!bD%Fn<|3tJXM(w_Gt9!>@jC_m z&IsYF2O$0}P7G7CBF*WLzv|msYDJt4so-~*H4DuzBY6*SECt$dclW_!|?J=-?D2Qq$(< zMKWStI3)E9*OX`Dcn2A_wlxhuY9YEwYCxSSrLp2aL)ixEW>!kw)KsGL<(=o*Jz>53 z!Sdnd5L<}A3J53N-ihNbY{|J=h11n?Z8Vzdcn7z&_aiko2>{>PBm#Ft+5#~Ocdc3g zqrtlRbUbJOL7&!86*Vxvie(?oKr%VRm{%STege%HHXaX zhy;$J=!Jfjf2|q)ONv>`A3i-m8$(}P|1~fj&q47VwPiDzL&WExP}uc?RQNgLDMbjl z_CEPLt+|^ulO(Sgk$84bF_otHwn%!3AKaIxNg2~>IkdQPF68^vF+7XQxeJjts6C$@ zTx=Qw7u?uDwg3X<7CRG+j_|D9kQ%}driejW8M>0#07VMGBz0+`EyZla$@nLacF)8; zB5GaOFhn%dKeu-I7g%{ASCTO$qeOEsh~nsbv}-{rlSfye;C3g`M*T%&@_8uy->LlK z9&>8lVz3~?m&0C~o%(dI4C|zN4)5EF_2!Cn;WsDZN@1_I>Te~PHV7=CdYbqmO>Z}% zr}&)DbOJe!;6G@RWD+^hzri*hH+O7Yo8h!si)Y~^xdi{tSvrR8xGLlIORf3di6X!Io|fM$UA<0OfL=9|(%F z2kAgniDy&Qi&XLg7&4$O_VgW%Evk)sm4RJ7{@jJ=F46UjbA|O%jok^4O5d&f&Wjn) zGcwK?4<#`Bz|$J*IgGgU#djaLW2wmHYt;mV`GCoU?cqc&SL5}7k3@@z=7v*EFwjTe{YO?v!j%J5H}m@YYl;DREfJij?s^Vmm*&tR1> zW%C*Y1X_Zrl)78~->t8}vQOW-5iglYdAn`cT4VG+r%28b`L!(1r~;fCCZ|C#YHnXU zIi%MRo=FpKkEB04TW+wxT)zCP`(uW`FpzD4f%xs^E2wT=;rX@`@OO4ZMA^Z$+KH>Q z+;`zH++25>8x-=q_|9kE=C?!ej8Dw?X{%rpQrdZyKrr$<5N$59N z+uCKI3OK#q=XW9nNZ5~P92&sTn1v6h7^Im{VB;;6H{udFoRVmYlX}Ec7S-!qKma|X zkBXF}LpEUr&myInDGK4Fm4;0*ueD76v?fm(gtyc_-3VBw;$*CyB^#9q;R?p=>5ep` z3KCqYz)n17;t2Pq?Y+|u4ZI!Fgk&boJ`!rB$1+pIt@l_LR4KQrep4KT&^JW+?J#yNgA4-IZg~jqJ|&{pBV6sMRw$|-OxhK9>|mKH z)pi7DC{I0v?t{$Ub2a*DPGePcS~CFL&g5Fx+v~r`$b#%1_?P~hD*jE>*WiSVzIi1I zY_)#pP=Z(~;ZQ35x6iz60Dw1ZR=SIO9phCzR;3g&NMFI5?Sj0Y)!CpLb;?PA^kd)rE`^_h@klbbi znaRyz$}2>ORatDUNWqXDEO;J-A00)y{js|r-tOw#%8ns>RQgPmr{%h3PKee*NeY{( z%N}Fku+wQz)Qnqz0nQ4d1CF~&+Rhska9zEDWw)?65?+cED1F2O1Ida{j$CJyhRM%% zIQe=|+Pt5UxTVU@l2m#a1coYJZ?tKZRIcLNVdn3xEwFd-Om407d1vcIrQ+_8s5}(fj?+ zWAcIhHP*kHROF|f>H&-+ZuCUDW)k`(R-{7O2p)@%C6i$-QlbeM&Jj8dJC}gP#l2-~ zep33u3r<_M)8hVP?8h*#$#N->F*j^X`S=6K`sx{RLv(;o2 zd5l=i8G<00CJ_x=ZR>RNyX5rt10apwBvdK6`G;C(C0Qk!j&EpRy-C;(X$Py8RD@;O zzj5Y|Ahg{r9HimU$C=a>yau66vv9e3Fm)Wsw|&4afDs%r%3xXJVUA#gl19>t`kzhv(}X9AK74iRbCANfKS?ot z--rTi5j%EQjv;LVq079(s%6^x3jplt2~XVJs(K!QhtLgVfiWHU%QDw>gEx zmeaVxrUW_~VXLnhr7&l~h!!2P%~l(xpl`*Hwj}3DT$`GC7O)`&BdHo!jdta*Dg|R$ z99Nx8^pEhr%#!PdRD{M{a|+7k0;V>M$eIvT3K7dONCZ@R5ZpiaN!%dU{=KXWn^5ky z-xMG`yI=N|5cmqIy7nTF`1Xvtw|{sPlk;7;HW|Y4r+*x?Cm7 zb_v*Wi~`$&wAS=oU6fqMzpYcNV>rClki%l0X-z1x7D|KqPXn+BZA!vLr1SsNHyXs3 zkYLt`X++aVh#ZNmytEbTVvz8wnUvbk`XjO6MqAK4+-}$r_Xp-{e|E<|QGo z1I8H%?#Fa-(4OmRl5~AF(-?HCkQ(lNPt?tdWQ#gW@Nh5K1NiDJd_`MyK}Zw(2&VPLDIZ>l**tYpJROj8w$ zC^7T*H_NH-zZz`}VaIx5m`F=_=wQ0Y$CK;Y!}N;P3UM=YrE={~SqV2cZ4JRDnMl%K z7_XjX)xG&tEpXx|*niSVu+Zlo6A*P8RkXekk7;rWOc0;j&GPHxaPI!uC~$Ps`vvYj z)a7b4z`6~hMx=7-BdX9&Am^^+&alo_({0R7oO)D19V71=34)!$J_ zd5EfGjIo@DT}qaiC*Ucj;qBWJ=?1Zkv3Zf?Rb zU#oXTv(8QJuMfd?YUHtTEP~7^@5B0wfYvhYrb6<}y@o0QWvf++;+TcX{x8U%7watjW&ZBkEEOhEl%UMN#~V?z}3dhcFR|jmw`@zUkrUyHZyOqIM+&_rPPkhjKD76i{k)2=~Nn!fG$Gf08N$D~E{4 z*QI>Af{jQ+rPIRKq)by6Z;S`X8N)K`|5#qkm5GI9yBvEw6;a~|T)mQ(fdrWPPLWZc zO|l8KUr5J;ej04zPWd)T*(6jJ?zWg*RI>0nm@M%71oY9KujR(+Ut7kxfoT0|0vr32 z8logdMCEbk%l*h*v?tMwF)I<0#&1=qWTCVXsra$JjYN8ve~-#fVwrEB${3%p+os#s z3$YJFa7d2rkzmH?m7Qd4kPtn%&6paI)G15_LIz#_C#x--olnU}A*|fFvgjlzCaOnEC}yLW)T(( zN+F#oEgB|SbV@7&j>)(H9Zj57))L~mLUFcybuf?H~{#3a#+=9F&Th@hic z21@#gzi1QF=t49_=%!7AwaT6z)Tbqx5q5VCR4oxI6)8mMI@z#^8_R0~e6L@7T5ySp ziU8>3jC~87wJ91;v9m%fA5Rv@wk!1kOm(=?n;E#PtG-7{2qUD!@KGX}f^ot!p@yy- zh!Is(#UZ_=)lvv zZY<$TP*^oLf)=-nbL$X(oSJ43iCIgUp_Bu9I+eXR67?byk}b$`y2q}Vfrkuf1HClN z%M*AVa}?`%?}dKccCzHGRVy0JK!NZBRwi4m3#?Hk(3eR|N_Rbi`e8$~>u~F|d#HZ{G6e84bctlCEZYOiS=mm_8db$bVK~NQS$vGlo(M z(c`##XVyK*52|GPWIW|mkHl~A==D#*1w}_yJj&Si?C4df?F_|dTG#fi8}tr z+FpgoFAh2w?5ld0qW-V$Mz>xhh8A4rx$odi7eMJ+qaX9PhydO)7>!&Tb~Gb(Buk{L z$xm+l6ohYaR|tzR4a9KszDeRnZ}dk%#vtFxK*KUhb*M4H(8XA41ZrLByAEd8ep-$C z*z@xsI@$1y%fnY16X|6JdoEjTVe)`O)%`(TZRd3kdNM=BmAfc8gLSgi>`!%$*aq{M z1hKerqt0-Z&l(=ZA%HcEo88nDWDwpQz0~LOqrI~dDJ-dUx0qr%7kk4Qwz4rM}I#G&hXiVm(I6wAXq`q&Dx5dtxp z<50{@Y2`UydToy|J-8xPedXrBpL?&^|)2iS_rl3vL^6p|_IBYx84-gdca z9l2qI=6Zsl?a^ERoj%W@K8>KE8n zO8JhU{9CRV33Kc_1iTi|oR$4kQXcW-tDT7{kEISP6X4UaK7i@{lMp1NU% zjg>QKbE{ZT?{t}K=-|NOxp?P_2@94f*F+R$h6D4Udmk=}8VATw<{~XLUg)G3IG{Y+ zyO634Sgb7(R=8KI88fqs9XBHQUA$aYdB{!Wy_4GTqC9c4s&7g`7va?yhf$R!rIwbD zUxU7=4aMY4pU(-F7Ae)7T%%!XrM}K%W%;@&g_aJYA5M^jKRU^=rBdW1d2G+&f|K>e zdPLo(b|uaRDU!a3^2@gVN-k;DfRc_4N{`MXs?3lm+Oh3$I`s->(ZA9!_zOV$A<9kL z2Brt{7uy~Gdu;uU-5{bD&&E{&c=ABTB4HmAFBUe(uPbSc^(xW#laz9OQ=4O|es;s2 z`WZ|jYJb$lT3RbzJ)~~nyk6;f3O0mFe9DT=*|{DMj2b zn`=U72?_QMMYeKaYmklTAf8KEg(4ykhR1{V5Q$x0Q62pU9(t6HM!)w6$$*z)uEt@Z zXKAeH@Pjy=qhU@Ll#L2slTktf&})!ng0aIWffzhi!+6x66oZ@XbakS(Zqz_vHotV= zKBT1rsp==E)VClW z?E!J7x#xH?sLwm~8jnJ>jzXM>{O7TZ3>?bk7ujB5i&@!wzEV=$xe+UCa1poy>| zSWBan>+Heqz`>C`RfgLP5Ekszxq&?mp3z{6?LiIxQS%Wb_;)n73aBAc4)u(-@JH1R zc+9%S&Vy-|rxqCQdx)!XtcYo6YmBuVhU~(|4G(VJ4%{cXXt<(S9F~Bytttbyqmf{s zZicT<1%HO`R^@fxV2aqv3kn>mfxf8U?boHV?NE_f4fOm>3eQw4>)U=x2lClw3=7Q_ z+B1mpDYgXu*#_oI&1ZS}ZU1Jt;*#7&dXm^Lm+^<}rrJ`47a4DqAtELU$ow!oW5Od= z+(>eMJCnk%u_DpYnN=gisvCKn#m4`WoERtjT5dgCYg6)Yc@;i#kTqE>C2I*O=^6JvsoZaU+e7N3}KN=)zx6&)EB9nm3OskG?` zm~U8-S!Q?w4QyF(1<~iQMl{C#Uz=z@${q&(%^(|?8yDmU@-WNc4`x5f0b$Crf!8%T znDKuwdD%IwOG@dKjqyxPA7!5~pN)9Z}-K0W_hr($=ge{^3hyP`yEgw`R` z6%QRDcb*lEQOTv4qHM2aH8R7Yw4m!GqpMz@D3$1ZV1j6m8bLK;!bu=D+l;pH&>a>^ zhWO`$83gmvfmi^5ZFXBz+I9$v(l{$11hWauXg<^>h#YA0O~v+GtGdv6Tq7gRw#XJB z53cGhYix)`VK%*RE4oe`CQMFoeogoH>Ma|5nK)@|pzkF-@ZyzcWxCe-^j!s=6EuVk zx=XvdW2hZ4Grg%N5#BE+Gk})W6l)xZqu-}Ms8Tsr;Pm3`m~dbp$(Qv^%j%lIoNyx# z`o$wK!feJ@O1e=>IO$4(kLhWq)KKQi10|KaT_=6PwS7_O%C@QIE9KZx{(YdiUB*so zDH5ym+1u7^fftS^Z73M7Tf*Lo+~tYP$hLpt_@}v(=I?J#1C0VjYpy!E{g9)vUTR95 zwZw@u_5~g8Ihi4H+s1|f4J4l)9K|lzX;Z~TF#DWdcohh=}4(EPwP5{qZ=0x|{}P(QM|y*2gzNZG*^2_ByvTckXZ`NvF)6xa?Kb8%-lB zh7pAt`HiFAU&>Nwd~6R`Z_{=i(So1m4NvVw`uYtYympvM=K_$7tF=T#UGbEak@}m| z?xnheRN4`hywi+H3BJ3LDChPGE1C1o>2%|47C>)yNyX|dep!`7pE#oeqVwyb&gZ|` zT&-9*41oKUj<#6W@l_qsu;&#tspu3At$d?xb?KQ$Y?L9@DAS{=rr|NgCue;l})|uFCl|B58l?cy%=j#non0VI^ zWD7C*VUojE-~h`sfMCf8Zf0z4$)w<|s_dPPPwb#VF6uDPT)DuKQ_jT2c{{M8v+@Qb7tmVy&>!WYawFQk>k0e-#JWD|-+*7^r*^#kEk2?O z3j(JaR%R&sw|~k|RU&T(a)&4<6B&PpE%08(vUq}kcgw4Qx1lKAitf!fk z*j;^$G^7Vm^~amlv6e?D;su?miW&G~-CL5n5X0L^HBF-2ugx7}C+LHc#p7a3Dr`Lk z!WMceHts2X0Nz}NIKY;|_ld{WEn=G+f?#*8LBPjmFrQ~`I?8y4Nqv&a+>MJYqI04f zpx;qF)WStLZ+@AxIu=XAD#6{v?nX!?S^BQ=G}(^yvMxd!`b#J4L=-EJD@uV%>RZyz zi-gnmbH|RdzBZ^*Nvwn%GB#0?N~e-eppZ@h8{GE&yKSDF%PqhrVu(pnKQ$YWHiTI6S_8U28JcIljUAe+C33UJA&AE=AjNtrww@pTKMm+U2 z2}b+Nd+#Hi*~4NB+^{o!E;(lm2wyh*!rXAxo*S5;Xmi{?iq8f0kBF93x#wTF2{Anm zIXyz7Ofb{Hf_@HCl82PFzwMY2$WR`N4pLm!QvyqR^x7LoJ@tHI=5ojgfY}b)J#(;pfe=>#<>nd0u zfg4>*xxqz)e?*F#;bNOoeMuvD%dBFmc-QG)-zxX40l<%}d{>$NP>k!*H($uyci>Mq zQ$NDab}Q742B~`fmp?TS9^TzFSTv|IRWdJ)?p#767~i?1X_O+4tmcJAvxk7zZgI}& zeybGm5GflQC@1eLWkg}74C#c9q8JlPjEW!;QACO3vF{xGuQSR_@^;s-;}AgUm{^6N zqUu(^0<11uM~z1_tx;Rp0*F1D)T-4`%0qT)0~^?W{yy6C0M+|YGVFkKXV%|Bn#pIn zlObijCUbfW_75X`u9zt{n8z7M*KolA7scU8(k4JoDT+kboN3M^7@kYQNWY(`FMel0AD-m3eGfTnaLDg$FzwjXx{Yq%5LQu8e zFL-Ku)5(k;ud3q=cRtqr<=O@$iU)h+IyLNc6`*t`gVj6q$|dMmHU6R$t$b*J>PYAWROUIzF_UY_2u8A-vM*<7c#lb<2+QMbH{NPQd>FhoYCdto zMid^){ybX6-)n{0MJPeoJzS^RS**ZHJU$_uFj5QC+SrIL@w;UcFc;IK|J4e8oR09I z$(W0bb5WousQ}ywzwf`>OM2q-xwdVUv%6|C3EZfmpV=Q%H;JT9&IG+w2D3JTTINKn zQ)y=zdl8Q}Wi@13Y`Ie=PE9 zp+t?Q=^NhCXKD{vN?9Eu&xzWr3)iL;i7DkSBoVls=P*h}2^alz{go|I@1 z3-Ng}iPJ?E$Ge(Uz=NS^xh17SOYL=eOo{bH1kq4&ulhY1x0EXDk5ygqZIk4`ju zER09)jF)RSM(7L((}=AY-y6!=7XZfL%{sTGfrwIow;IOD9YD3nQ9V-LYU)-hS*eJ< zhsVjB?qMJAj4fH3S6Xv0={G^OM%yi~xM4i!Wp-#EXIso32Ae9qj<&R~c)lAY)4>&JS?Bh)p+> zvE9lTiyo`y^-N@La}keWqTt+~*_uh$q1Mg&kNs67HkQ7r(4J^yFHCWC_O2Q}29bI0 zT@sI)p~mw3cQiqYmfMcj=`RDuIQ=gUHFZDuwqSwEXX{Z(Jnt=f@jaCQ9kO}oA8nTs z^+w*KeRA${QVow}csLomM{-uq&xEW;8+CP!xI46QNrDR{LtpTcAiV0B)2KtH1aQ1I z#U#1xXaSHu)`-!918mllKQ7NKarr9_0K+$7j0v{{7&G;irWs8MVb@NRBP`BL z9{$qn7c&Cdot`=T^<~j=+JAC}XJW8P3BgLwZx?8542cF||GxSOH?K`MQm*t&9J84{ZPLH;onP;%=&c zmR7!8^7sYSQQ54VDdRJ3_voCMTs1oi1Fu(zEyi4anS3df$&9sOkGViO@Wsamt^TUX zu#IAVc2neU1oKtU5LA5*i5EJBn)-Ms%uN)^<4W1#9B7E;d_^Cy7QQB z=R?J|@j%I6$gepqc~M_Z(rxDNzwhzhRIjK42d;l-c$mz*z|yUo>mMVnJT+Dj8hbAB z@XLgRoq*Cwr@Ew=izHOh-nW~KG4R!-!US?a7BYIAmlZ(S!a|7;b`nnFf{`maz zDy!UjN8WHlSZ;MLy@Me92%^$Y(&JPo>Cj-UbzPy=!rO6Cc{4!d+PBl#321A*2+yaB z9+4C?XSv{~yQq<7cggY0$B~$LLPslNyLzduiWvJaV*!>5qhiCc`Y;SG&Z&ygVE6tg z!7-Be;Zcd2;NE)Ja}4aKfcjxiUmu6CprOi%woW?3=S zeN0F2Dh6zMAQF3+9x@}SwmNMqnflUN;i@c`yXrdRr!A&1wut+lCk{xfS9IW1;~k-c zP9J39V7{^EwY;q0VDhY=Ic`?E*v%wdebziH#K2AD41XueX&L>v(WBu@RZ<0{2c;$u zk-EMg*{XXArf@HYUqbMPAOw-lRxB9wwD46ZM__2{EgF*fX;Uv!qP;9=Q2(AWYk|6h z-|;&d=~$N{=_b)_PdHK2E}=*Ayi+NndUsRw^N&IQ>M0le<7d&P=%+a|#?$ZK;&feCc>C)P+^%k-zK0$4!4bPhGY~)oN+3-w{gTgqv!#l}wt` z@{;yuwZJ{yMv!ugb2*+<3G+ox=n>7c0%%%UKQqF1F=bmHNr<&K*!O%wu^teaI&^UXr0v*(SjE zXgR~p1w_7c$H9(!-nVFM2{xmh9Y~&ccn+MM$8W1;g?wH^aJCYtdr0x%FjI5Ns5Q6r z8H!)`9J5sOsncChL??BX6<^96?}&sxDCuA(Tk657k(!@zV#aBRcDD_!3V~52uCg#V zpHo{R%z@g`W%dsr9ZX$AM=Y$Kq%;+h9~NzvE`z9>r1iF*U8is*CArdXW=4i>{m^%Ad{)884vFyZO}gBi5&h4Y^Ir< zceI%d)QtQq5}HY4%oHJ5&U%qSkSyl2LUM7AySxGVD<9 z(hE${oR5C97Osx#?_ zW7!Nh4v^)`5Y`Mse0P7@^!Xe9DVo~7ZZ3>MJh95*kRq`fP^3)fHXo%7&cljfou@~55mygmUnV^Cgu8;4O??m5uF+Z|U#CO%V${!)I&0o5F zOS|8GjOYqK$r(IVFkFf9wAsV{tTXf2wjGGXS0($T=MOb$Zn;xj8b(JEty@E}k(vBm z?ilYp$5x{k?(P^WS4MgN8t>}}j4p#(a>Tn;#>UV`Gx;RNmV{%2Q`Rs^lZiRq1ECa| zQgfi<;eDI2%3Lb$ZB1gNvtNa{o3QlDJf&me@uQv0+hFW@<Ap?vN2Z9*&fxBObW3f?uW6N-K6 z=fZ%cE1%y)@AO}tr)XQ^3N>z9aiNiN$#M#H5lt67iFQzl(F{#HFWfU2 z8+tDJ){V9?$yT$|0bi;b>*B>obpYU3kpHoAy_7tO5TMh&4WV?L1s8^k2P?fTpPJ$8 zi&10s@T5%S^8TAGueyf*xyJ%gp0KDFJ+Sx?k1XDSs;I=_(+E{<`VR9k)XF^a$2nJq zHTe$rN-{37@J+D@Lp%J1QS0mAmZ|!3y$zj!f&e?9^_QArg&1N*MFae(B6=w=Z@Ahe ziFj6xPRDUgtc7vy91lhWcB)D1^e*s&M8{YxLs_s01RXNoXeGJ7YNEP(5ZnlVex6`NtCVD$lte=mY)fJ#;Po9r~dl0QO(!YrBLy2l5_{Aio1 zoA9pnDMGfkILJp%&xlXY2~v%8>&!XtFWV4ai~8^ZkCjN-6TIrLm}fwzt4%X7_ba!FkmtqASNb4`4+hhMHW=2>0ay$JD9SmBg%!f9Wj8^ni8 zQA>(VVbN`k{|Lc0`mJ#@@7(&~D1zyeUL;n$8wB4^LbOPqrMl}!3iicOXLKc#(;DTY zPL;3b#DQdI`dW5$sq659nir%tuN+o8gIZ7W3f!rs;GC+ipj@GlbtXSLaJ!AQqV`Hs zqUKmLqhU6>8S#jY>!I{iq(ofsJucE-MP^B!W*SjPrk2Zt@%!N}hHQFi#?&dU3%rDSf#U8jC z+GtLybcY8pZq(6K8nuOaaqT89<8B$zqH1j3l3hd$m+&1jm`m47%!uYMzxC9+xX447 zw{_-V#SE{$${+13P&AZ9j@czHo>z4{Xu1lEOXb~Zm)TWH?D9M*Yt0>W{1jDt$#V5I z5bjydXUF$Uu%rD~_0okd-MlQ&&^s!BEA@lCxM+XL9}7h2CD$9mUVmNb3O8=r ztqMgvtKj8RG+VL9NaC62MfK7IwBem3VU|la$vX`8zh?W6-BZuj1UfR9p@_Sx*$J>i z;8i~F%b51Exr{KT4(5=>2^mZ61R;!{e0VflZE5mAWGK5hr3JFlUj9;R7qVBs3_j%H zty6C2wiMz6>z?`U&#dyvv*>rP%E_%!j?Uqh z+iMAdLf#y{CTw%>9yhCUD191#37Wg2$U(U~cYNhbzda|P41de1kq|*&mNEQe()(aJ zZ=ZC@f$Z;o1RjvK(aoU~-W;>7hi{#*ddG_6Yk|ndsKqP?h4MQq26zit$SLMXV)$ zH;I`YoFi`C$O~BXv=DOHIjzIXC$&#$>#Dy1mO`NMB!;HTKdj?OPd<^ft3+lQ&)pgh zxOaR@;wrFkh)Wi_ib?jzDUqNgN1V6X#gG>sGD~q*SGZ^6c;G!fmSMC<&E4r8V^V*2f zQYGTmHtjo(NV#_&PZEgvEkJc-TImCS)WQZxI#+ntgE}I*U_}*aylCTM|E9det&u^a z>gtEtQNOp`IvQ26&x@Xpd}H@99#W9zUhC#sP5|3hc_A8#jKkmFc>H=KRvG{u%E*)N zd%Pff<3=6CN5;4jcf9FIt&wtYl$T3eLW;;+m4yevGHuFT@)w`NfbW0SS~d^szib9E zvS@w84&S-4SNICy3^zOx^y_FlTaauz>Pt^vIuEQCTZdJ*iGEEp)nOZjbH+Sj01O>F zR^A>rMExOOG{>LclU})%!BW_Fd%v?|1lS45C_Ls@lWE3(@a5a%>HH%!G?owII=1?8 z_e*5&lE<5}d;E;e9DUE@)p>Z*=Gfwym!i>^o3q@qXKOagSIWTYJ+0iIj|0uZxIeO} zrKgR1?-=|2nswTLa$WVR38BLNwg0ZWg<8SnV&j^!dy_GtwPR4pM`PowCdKoU(UBZ( zG8$M7B=`?M1nzz7J0Zr<+=Y7k+*iiRSf?T>L@`c0gX*8$Q=I&w9Q) zXM~89lX>-~JJZZIC&Yt=<-DKdB0VTWghl#i2X~aoSB`R;eo1xn5xnvFx@@z-f+n@4 z_GYg70^bjkeM{wna!#QhkB3>5_JV&%No|;uk;`YHvl9KDJK;D%?YgWWnSzwNnLlrz zHu&T?(^_!R0pUy-O6%_h@6N68ss*;%I8$L?3N&~90%X_DyM7U!o~~#(rlziDHf6dS zp5@eJ(WXzSpCw1S1y!}1@ui>@3&OTCD*BDnG7YshquQl5mat+e&1y33 zie2sc2k(;FBz&xyJz2R6P{^I#&qSLE>Y`uA0?odo&ox2JzF%o{AsT%TYuC1sdL|7~AkG=e&gcB* z(LEsAef!g$ba$C^{^PY@T~#RJlnE=Ih3;67;IC?Cxgybnbvtuct=Y0N5h=EM>eqIh z`jDpkt*P#VQmpAi)rBG_uwC0N%hcz;o!l-wPxb5OMWYKL7COttn&VB=P+{hS0ITLX zo_B;YR`cp%d-G>ps`lnw{fPR)4s1YAvYyhelWtZFOuLo~Zcf^~zS{!w$J(!!ikyK|lZ0cfc6x$)dcOYCM%+ z-d=2CviC&H40#*+D{yPiqJ}+?G3oN?94H2_Cz(~wRy3&=*0#Hu?Q#($!b+Tz z^gG?~{_303pZ7st2bZ_vCowl7j`=K z7!#+hl3B7MV4ac<_pq<+b8L!~aDc>LTU_fj0vFd(5M{6LxuDRy8|X~b!8DvU8d~! zQVVSY6xIiUPXU!#{M^m${^gDS+oQF`$fe;_Wb;X-%bK8O%l+6UEwvU%dNV5&|1mW{ z{2q#6*{|I61KcmDwo@+0+?^*80k`^S25b z)qyYvu(&|(^{8@HiF#iD?bMS6Vn4Anfbv!U&yD^!p0yA4lu%cP;YD11U$E$T@K+7X z(7|941@eO|^sDJ_V?&=b_N*$i(C@(&8asuAgbBo|1j1%$0H{Xk#Yb-48<@7@KKN0y z_Ua-KXZI3WXpmj#(9K5{%Lq)#-z{W8ZH{eOVO1s(#Vi z4ijo#;)_K&qO>y2#~z6Sc*slADb_L&r$F>MU6XD4TuWEMq9eQFlx2Sn$YwRdPHmq4 zfC#mr`ItZR(GuX>Rv%rd{lb+|B6i0VTjp0Bi|nc0uc(k6{Yqh62bYfe6x6m4koCbafR9~Tf^UtP4OcMME?bwDL8_1>O zoPgi`mOBQwPj@@>IcZ+7a!iS_CQZzRk(9rkrEj9i&bnO|sf!wKk_PAf%XL`0;48Jk zZ7?v|<6@qiSFh!8(pqU*e9e&&is)-(ujPHdA{X%_g{Y?A%C2`YQAVUf*C@O?Q5{3q z$fqndN)Z}c=H6UO;_fPnQFohgL+!pe9AXE_AWhk#!BQ|`ciqQz#;ST_9fEP3YNTqdyI8l-V7@^CBBZT(Ob zx64){kgOx~c5CNGd+M({+mRvHB7a>|6`e~o+%=2b1ls7Tax~)A=VBX*R@M*qZS~#- zF%lo72e^#A+s`#TbPBYnlro%I9=7s}hbnGEH+B|E9&Eq@O}X&zJ}%;KBbHeXpT=!F zku#MYK1Bi--IS$mhm6x&v9-J1X{bw?i&i~}6Nv7#LqXhs45T-pVJz2X9h@Ur73LJU zln`$QXB#gwvwqsp)n~d>Xk$~|5A0>zE%enxQ@SN~4_(MUeM2avd^9CKj6D=qO#RX* zL^&AXVo~Ua#O7Z7R@FEbJM&y5)v#u5X2RZS-lNSR{<$bAjD5<6bb&mrnc7$z5Qy#5R8)| z08gvBq|QnJBO>eXaUDHDXo&vu#DrMxx%Om{+mF6~^Mi=eXA!|*y+7(l8#F0IHPUoA z>sWtjO)CTI-U&o8K3*#|AS*;gAcqfcBPOV227^y5KZ1ibo3k%-#g>vH85h7VIz^4w zrC%;Y@4+K0K=C;63VA+Rt2xB_c?A*p@^_GVuPt6(Tnb^sl}6EFS$#hV99wyrNS+_A z1`XCJb(G>7pZKa_^oRDZHwvu3S1W;`aeM1N*zH5Z_e2_#6*$Tsn@a^=d56k<`FZHt zk-(j)YnOPB3Wa1gukKk@3!GX4i_Y(h3+GHy_4QFIly3f=Sh^=1g=jYI+=kF}T))TR zAAgcCPf;)2Z|k^bX8~nbTN#ARQ~uk@(2u_IN!=u?VB)6fDmX32Boxxh$u7EaJwIQl zYav2GYslaH6x}9+ukW*<&mdE>PGTsVrlh}zrh!Vr)DCxiFD7weT4hp3N_A~pCr{hm zIIy_-0tNiI6tI<3#W`}~Rdsdi> zEY3wuEBF7%I8tm3rA?JSdzF8jqI~1*KK*RENaiknnl*57X}tO3@?UWa&kH+)hUb&-dIlDFHF@^fM;Oh89sKf^HE;Qxa{+RfCPx-X3)rCZ4Yt zF1}7>!I|^0ye3*|~&@e1AJ zqX#~N+;EAz#lHpg4qE&e^rBN#yqTEzij|458yo%>HW1X(hH3Ho4qNM=ssrVp!2Hu? zRzCq{cn69{Ag5lkew%#lo^nq;<-xbj`OhDTE4beQDOwtj?(Ah;eFIlZ37gz8Bj{rJ z5yBelM9aK_c4lMegVB@h^%b9&|T9|Fxj~~rPmd=0w(I?UD6n=JSm&Nbo{$aR> z9|VdY`2gFV_0ING(iJ+4Xbv5=f7}Lsf`*I4&;}wgZ_MWOOV@5%Wqr{9P7TEb%lC0ff0d}#vwe4M&9+GL{R7H4GyL?4w$n^r~p03OHZSZ zIuKQ8o7~w*A~pYD^BD$HKRi4NY&h5j9#BS0XoN|M7L(pSiumK?%-kjZPYy3pBtZ;y zzt0~-BeHRPZw7MiHiN*(B35c0tl-RO*J`r{Z6CgeaZ!4n0C|rs zLt-K=+GjgoP#pt%EYv^~+O6vHr*4nuBZ*7fC8!`!zVFB`_3d{hGB~?|wu$ra0IjQj zbq~m-&F5=`9L%cNe-ppXr<1i22AV|B_M83dbHdoNd^W)tN)Tr1AZm{^4W77Bq*~8& z+cLd`yvv5!>jdIi;26?UHuAuT9Kp$D&S<~8cLKdc0UeN+wu$(_;ek&OAtLLW>E{{< zG7Xn~Ft674>op3idO)URYoKv~S(4X)kZt1AJc zNIO&vM(-6)Os8@F-8I@=W-BXIOkoJ5(eN2kfI9I}U73K@2%(M#FM8RFD@Lxa2YiQ5 zlx7zs=w^z36963$wzDUsubo`Pl`d9?C*V*A+aL`jZF)szf<00`_w+Rri&Ei(jmV72 z^86<;&-#{yEcSk?d;sLH5qVz-Px`1G45728yinxzm0$wMvPmm|+JqW8J)>r-;%6^Y zmbjS}VCcIxk%&2%1!*7<*!FW%!`X&Z>QKo6IbRS(A`67M>gy>TpD#g?){4&7LmI3a z)-y6esI8q4BzDm1>`}Hg@1Tv>c;x})8s=ddnPTiS>BS~v2zqLF~ zFCI)1FK=Jj_VLRW4t%~97VehSSbOC*&7pz%6N?`idbKxynk&|ry1!fJ?~(N@EL0-e zxG{~ET+=BLk3@ptX?G6Rj^Dn&KiwBRasK=;r(3=oy_!~w4nc_H9cf4{RgY)Us}_Du$cl4T%CLXHh@DGQxkw4o$VCvM`taS1^^AA zPOgqx@Bn~~6#X+fDcQr9-G30D9uk-SB`T%!t3vKWeE~K=I>Ren0yMzajv1&+Cp`tI zsseQt0Mdtp{Gm++>IC@e-S<5tcvV$B9F8v19qxVqkt5^}0`xJ_(*nr-ZT@ef)kEk| zo(=H!ty@}-K2Rrs{9!A*ztpXVcYoKYc}SJ&c_;*^4SnnifgTPDG@{e70{@b#$|=eJ ze>qhT=kza5)yx!s)BD3*kyx|>`reDPF)zE_TuhGYpF!&(M#hl-o{4Jd^c-_|7+zf<&ZSHX1t)!y^W3 z84~xOGXA)0c`EdDuI0IDTw_#xEX?7=k<%Lt$J`mF9+j7CaglV7rXLOY9p|3TN#aJ= zvI6!f*ZVZ$zB3$TzpSwml4iJ<7Khs+4cqc?w<@YxWC&M-TGOgz4ZEc7bO~97$(Sem zY>C^15YnM+O4~BwsyyvJT{F;)xiOL1cqNX8xFiQ2Zrn*yjZDK;$W!0j&u%us=Sq1( zjN}zwl?juW4P=>CPk@Vk|4Ks?@THD+`-i)LyD616Eu2w|=~~ZjlCocu*nZO94cDYZkC52A zQ!J0ZzjW~?Qh-79Iy>N0u#;Ff9>LP2cWkdSwkJI;lY$MSAuPV$rL}NfK_x)+v}L|> z7d2IP6@8U7eZ^x^?v43S?n>uz>Q#9(hmxJ_F*tx_b+5qlzp_Mro zUWOGph)_~`3jyb=Q=OiEQWN1nKho|vxlB# zSAH8S#m@CZS1T#t$|?3spA$LW9d*4qk|^*_uqH-7DZj<$9FvZY^u4<;S=t28N6frU z$u-ZF&nqxKaWC_udcRq}=tJgRc0*max1Bv*iwwTv$~>8|lDZZ-Z@T#x%NN;q6v^kA zp5{X0q!TWn?($tdUw*Wlr<}JhK`DZ#DbDdjsb!(^Am2*NnMUs~58S1zn1jy-a|AQ0 zBp{w%p7DKDr3kiFHHs4ZWj1B~NaT^lBhIfp^&Ast@o{X8+Z*khP?By48}g(^LiQz5 z&bU*>;rd$F9VK#Kbn7Y_d^HHryuz^?W%TRO+t9DiEN`o7tAhB18-$JZov+AWdvfKH z$E7uqOrdchG$6TE*NM$r)#~nqmgm*%OOqlPKmnvD4kR;expPq_v+EqN~mE9YJZ@6L0OHW|Yk;~qi7r{&8P45U9x^U6ea z@^>&U)OAKmbaNSTX~iOHTjk4o$G`m3S(_B2g!vZN+2RXyZ}7TupZIfMYbq|J4t&{kbSzVyLQ#Fk-u9J6ZD?_ZW-tgn2esk3#(WvK|UPzvG9AiVUW$7h1hv$ES72q_nF#AD!p%T`T zA$J(z4&fU7*C@8`S8#Xa4Cnm)HJ?cftio{hfPWiy0v<7W4OM|kJdi)&Jz{-iEOa6C z)6M2@ubv<@-{mlB4rsE4b%yDDSG)8`-=T$&Shsx!$Aa^Z2L)*k5s>_=PFKRy&rOl;&ls&;H>QMW*t`woGJsM|n*7yY`IKHCuUM zW)3;%t>M_Rx<=VyY=7u4?J|3r*Rv`2lee!bC=>OwytAa>4mHDDhV3F-h;5Ah6YKAG zJvKQuU#c8@-{acIX59tvKL=T?lt@~uH8jCHpHzldy1Jo6D@gI zy;oVejPSd&s~>M+7+mDM_F-hGF0ig-b@O+hdA^y2HPN%g0pA&fA$Kw5J&Qr4A(SWr z^12EHR42K%=62qvilv{(Y2?zAsAGuEgw9Th*Amd8N1xyMZ8`k--aZ+C>Kkuz{|wKs zP8B#Bc_mT+^@g;z`%^PA`1zNF3IvQ~=W(Jk?;Yo|?S#_6t6t%?gcSkxivbnY&F}MP zgWK^$!9F!}AKUqW;Zr}N-*RRfEo5h?zw%pNTAJ&FpbdiX8PRG!MZkLahI{w$HZBC4 zxkOym2%Om6FJFR~V>VzJSEQdsrAMvpDBqIkAu22 zf6f~<_)@%>MjCQ)@50XJdVU-z8+nWvzD@Z*p|;Y$!cgXaRuItfq;vJVdeTb>9EPp` zzO!)k)b#Xm{R=PywOyT^q4cr=hjjsL0J3sG4_8k=AApiP(8~|*3w4J&`!Y+*$^xC> z^hyUlKCS>D%-iuXJ;rr}_#KA25La)ApNF$MGynkfb#-^5LmrM0Z@4D__`n-_*pS}S z5dxuCB47qOxza`XxcUHqlAds1C#W+3=>2Ds5PIbA?(X;>xQm}B%+cG=!`;!(7XXCA z;GR%7x-`c>Bl{di?sorCLg7!W|2Gi-M-7EPnE>#<-vi%2B^3@qdWvD>=s}+nJv;cL zmw&X;hq^z8`np0KnSp=x0yxy@f0kSb@P;}wO97;%nWg@90p#W6ZpZh6P#-`OINTRN@9+=Z Z`1m?{`~K04jGVNb60@+d4oH{z{{g$i{n-Ej From e5434c363181db1ddba6bc7e35607b29e260ab8d Mon Sep 17 00:00:00 2001 From: Szymon Maksymiuk <32574056+maksymiuks@users.noreply.github.com> Date: Wed, 9 Jul 2025 14:29:43 +0200 Subject: [PATCH 34/62] Polish edge cases (#64) * Decycle graph * Decycle the graph * Make sure paths are properly dispatched * Polish typos * Add comments and fix lintr * Add comments and fix lintr * chore: refactor task_graph_sort (#65) * Implement source dependencies management * Revert sorting --------- Co-authored-by: dgkf-roche <91694157+dgkf-roche@users.noreply.github.com> --- .lintr | 11 + DESCRIPTION | 4 +- NAMESPACE | 29 +- R/check.R | 69 ----- R/checker.R | 34 ++- R/cli.R | 4 +- R/install.R | 5 +- R/lib.R | 50 ++-- R/next_task.R | 91 ++----- R/pkg_origin.R | 132 ++++----- R/plan.R | 91 ------- R/reporter_ansi_tty.R | 4 +- R/reporter_basic_tty.R | 14 +- R/task.R | 64 ++--- R/task_graph.R | 250 ++++++++---------- R/utils-cli.R | 8 +- R/utils-deps.R | 31 ++- R/utils-enums.R | 1 + R/utils-igraph.R | 20 ++ R/utils-paths.R | 10 +- R/utils-pkg-source.R | 2 +- man/STATUS.Rd | 2 +- man/check_dev_rev_deps.Rd | 2 - man/check_dir.Rd | 55 ---- man/check_pkgs.Rd | 56 ---- man/check_rev_deps.Rd | 2 - man/check_task.Rd | 1 - man/checker.Rd | 2 - man/custom_install_task.Rd | 40 --- man/install_task.Rd | 5 +- man/lib.NULL.Rd | 2 +- ...loc_default.Rd => lib.lib_path_default.Rd} | 8 +- ...c_isolated.Rd => lib.lib_path_isolated.Rd} | 12 +- man/{lib_loc.Rd => lib_path.Rd} | 10 +- man/library_task.Rd | 14 - man/new_checker.Rd | 4 - man/packages_edges.Rd | 18 -- man/plan.Rd | 1 - man/plan_checks.Rd | 37 --- man/plan_rev_dep_checks.Rd | 3 +- man/revdep_check_task.Rd | 1 - man/task.Rd | 1 - man/{task_graph_create.Rd => task_graph.Rd} | 10 +- ...atisfied.Rd => task_graph_update_ready.Rd} | 8 +- man/task_graph_which_ready.Rd | 19 ++ tests/testthat/test-dep-graph-next-package.R | 8 +- 46 files changed, 448 insertions(+), 797 deletions(-) delete mode 100644 man/check_dir.Rd delete mode 100644 man/check_pkgs.Rd delete mode 100644 man/custom_install_task.Rd rename man/{lib.lib_loc_default.Rd => lib.lib_path_default.Rd} (66%) rename man/{lib.lib_loc_isolated.Rd => lib.lib_path_isolated.Rd} (65%) rename man/{lib_loc.Rd => lib_path.Rd} (60%) delete mode 100644 man/library_task.Rd delete mode 100644 man/packages_edges.Rd delete mode 100644 man/plan_checks.Rd rename man/{task_graph_create.Rd => task_graph.Rd} (84%) rename man/{task_graph_which_satisfied.Rd => task_graph_update_ready.Rd} (91%) create mode 100644 man/task_graph_which_ready.Rd diff --git a/.lintr b/.lintr index 476b548..4e1a485 100644 --- a/.lintr +++ b/.lintr @@ -1,6 +1,17 @@ linters: linters_with_defaults( + defaults = default_linters, object_length_linter = NULL, object_name_linter = NULL, cyclocomp_linter = NULL ) +exclusions: + list( + "tests/testthat/testing_pkgs", + "tests/testthat/fixtures", + "inst/", + # TODO: These files need major refactor, skip until then + "R/results.R", + "tests/" + ) + diff --git a/DESCRIPTION b/DESCRIPTION index dc04695..aa7eca9 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -36,6 +36,7 @@ Depends: Imports: callr, cli, + glue, igraph, jsonlite, memoise, @@ -46,8 +47,9 @@ Imports: tools Roxygen: list(markdown = TRUE) RoxygenNote: 7.3.2 -Suggests: +Suggests: testthat (>= 3.0.0), + visNetwork, withr Config/Needs/website: r-lib/asciicast diff --git a/NAMESPACE b/NAMESPACE index 4946d29..0fc4a78 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -19,13 +19,9 @@ S3method(check_path,pkg_origin_repo) S3method(count,default) S3method(count,issues) S3method(count,potential_issues) -S3method(dep_tree,character) -S3method(dep_tree,check_task) -S3method(dep_tree,install_task) -S3method(dep_tree,pkg_origin) S3method(flatten,default) S3method(flatten,subtasks_task) -S3method(format,lib_loc) +S3method(format,lib_path) S3method(format,listof) S3method(format,pkg_origin) S3method(format,pkg_origin_base) @@ -50,6 +46,7 @@ S3method(install_params,pkg_origin_archive) S3method(install_params,pkg_origin_base) S3method(install_params,pkg_origin_local) S3method(install_params,pkg_origin_repo) +S3method(install_params,pkg_origin_unknown) S3method(is_type,default) S3method(is_type,list) S3method(is_type,process) @@ -58,10 +55,20 @@ S3method(lib,"NULL") S3method(lib,character) S3method(lib,check_task) S3method(lib,install_task) -S3method(lib,lib_loc_default) -S3method(lib,lib_loc_isolated) +S3method(lib,lib_path_default) +S3method(lib,lib_path_isolated) S3method(lib,task) +S3method(lib_path,default) +S3method(lib_path,pkg_origin_local) +S3method(lib_path,pkg_origin_repo) +S3method(package,check_task) +S3method(package,default) +S3method(package,install_task) +S3method(package,pkg_origin) +S3method(package_install_type,pkg_origin) +S3method(package_install_type,pkg_origin_local) S3method(pkg_deps,default) +S3method(pkg_deps,pkg_origin) S3method(pkg_deps,pkg_origin_archive) S3method(pkg_deps,pkg_origin_local) S3method(plot,task_graph) @@ -94,19 +101,17 @@ S3method(results,revdep_check_task) S3method(run,character) S3method(run,checker) S3method(start_task,check_task) -S3method(start_task,custom_install_task) S3method(start_task,install_task) S3method(summary,checked_results) S3method(summary,checked_results_check_task) S3method(summary,checked_results_revdep_check_task) S3method(summary,checker) +S3method(task_graph,task) +S3method(task_graph,task_graph) export(check_dev_rev_deps) -export(check_dir) -export(check_pkgs) export(check_rev_deps) export(check_task) export(checker) -export(custom_install_task) export(format_simplify_path) export(install_task) export(new_checker) @@ -118,7 +123,6 @@ export(pkg_origin_is_base) export(pkg_origin_local) export(pkg_origin_repo) export(pkg_origin_unknown) -export(plan_checks) export(plan_rev_dep_checks) export(report_initialize.NULL) export(report_initialize.reporter_basic_tty) @@ -142,7 +146,6 @@ importFrom(callr,r_process) importFrom(cli,make_spinner) importFrom(igraph,"E<-") importFrom(igraph,"V<-") -importFrom(igraph,.env) importFrom(igraph,E) importFrom(igraph,V) importFrom(igraph,incident_edges) diff --git a/R/check.R b/R/check.R index 0c35255..12f1111 100644 --- a/R/check.R +++ b/R/check.R @@ -112,72 +112,3 @@ check_dev_rev_deps <- function( run(checks, ...) checks } - -#' Check one or more package source directories -#' -#' [`check_pkgs()`] Installs all dependencies and runs `R CMD check`s -#' in parallel for all source packages whose source code is found in the -#' `path` directory -#' -#' @inheritParams check_functions -#' @inheritParams run -#' -#' @inherit check_functions return -#' -#' @family checks -#' @export -check_pkgs <- function( - path, - n = 2L, - output = tempfile(paste(utils::packageName(), Sys.Date(), sep = "-")), - lib.loc = .libPaths(), - repos = getOption("repos"), - restore = TRUE, - ... -) { - checks <- checker$new( - plan_checks(path), - n = n, - output = output, - lib.loc = lib.loc, - repos = repos, - restore = restore - ) - - run(checks, ...) - checks -} - -#' Check all package source directories in current directory -#' -#' [`check_dir()`] Identifies all R packages in the given directory -#' (non-recursively) and passes them to the [`check_pkgs()`] -#' -#' @inheritParams check_functions -#' @inheritParams run -#' -#' @inherit check_functions return -#' -#' @family checks -#' @export -check_dir <- function( - path, - n = 2L, - output = tempfile(paste(utils::packageName(), Sys.Date(), sep = "-")), - lib.loc = .libPaths(), - repos = getOption("repos"), - restore = TRUE, - ... -) { - dirs <- list.dirs(path, full.names = TRUE, recursive = FALSE) - r_packages <- dirs[vlapply(dirs, path_is_pkg)] - check_pkgs( - r_packages, - n = n, - output = output, - lib.loc = lib.loc, - repos = repos, - restore = restore, - ... - ) -} diff --git a/R/checker.R b/R/checker.R index 404690d..75afef9 100644 --- a/R/checker.R +++ b/R/checker.R @@ -106,11 +106,14 @@ checker <- R6::R6Class( self$plan <- plan self$output <- output private$n <- n - private$lib.loc <- lib.loc + private$lib.loc <- c( + # Append checker designated library + path_checker_lib(output), + lib.loc + ) private$repos <- repos - g <- task_graph_create(self$plan, repos) - self$graph <- task_graph_update_done(g, c(path_lib(output), lib.loc)) + self$graph <- task_graph(self$plan, repos) private$restore_complete_checks() }, @@ -170,8 +173,9 @@ checker <- R6::R6Class( return(0L) } - next_node <- next_node_to_run(self$graph) - if (length(next_node) > 0) { + next_node <- private$get_next_node() + + if (length(next_node) != 0) { process <- start_task( node = next_node, g = self$graph, @@ -198,8 +202,8 @@ checker <- R6::R6Class( #' #' Checks whether all the scheduled tasks were successfully executed. is_done = function() { - is_check_node <- is_check(igraph::V(self$graph)$task) - checks <- igraph::V(self$graph)[is_check_node] + is_check_node <- is_check(V(self$graph)$task) + checks <- V(self$graph)[is_check_node] all(checks$status == STATUS$done) } ), @@ -270,8 +274,8 @@ checker <- R6::R6Class( }, restore_complete_checks = function() { - checks <- self$plan$alias - check_done <- vlapply(checks, function(check) { + checks <- V(self$graph)[is_check(V(self$graph)$task)] + check_done <- vlapply(checks$name, function(check) { file.exists(file.path( path_check_output(self$output, check), "result.json" @@ -286,6 +290,18 @@ checker <- R6::R6Class( pop_process = function(name) { private$active[[name]] <- NULL + }, + # With these approach we deviate slightly from always prioritizing check + # tasks across the entire graph in favor of prioritizing them on the given + # layer. We do that due to significant performance gain in graph searching. + get_next_node = function(force = FALSE) { + ready_nodes <- task_graph_which_ready(self$graph) + if (length(ready_nodes) == 0 || force) { + self$graph <- task_graph_update_check_ready(self$graph) + self$graph <- task_graph_update_install_ready(self$graph) + ready_nodes <- task_graph_which_ready(self$graph) + } + utils::head(ready_nodes, 1L) } ) ) diff --git a/R/cli.R b/R/cli.R index 9014ccf..7f3b31f 100644 --- a/R/cli.R +++ b/R/cli.R @@ -89,5 +89,7 @@ cli_theme <- function(..., .envir = parent.frame()) { cli_wrap_lines <- function(text, w = cli::console_width()) { n <- cli::ansi_nchar(text) - cli::ansi_substring(text, seq_len(ceiling(n / w)) * w - w + 1, seq_len(ceiling(n / w)) * w) + cli::ansi_substring( + text, seq_len(ceiling(n / w)) * w - w + 1, seq_len(ceiling(n / w)) * w + ) } diff --git a/R/install.R b/R/install.R index f7afb1b..cb5f2d2 100644 --- a/R/install.R +++ b/R/install.R @@ -9,17 +9,18 @@ install_process <- R6::R6Class( initialize = function( pkgs, ..., - lib = .libPaths(), + lib = .libPaths()[[1]], libpaths = .libPaths(), available_packages_filters = getOption("available_packages_filters"), log ) { + if (!dir.exists(lib)) dir.create(lib, recursive = TRUE) private$package <- pkgs self$log <- log private$callr_r_bg( function(..., escalate_warning, available_packages_filters) { options(available_packages_filters = available_packages_filters) - tryCatch( + withCallingHandlers( utils::install.packages(...), warning = function(w) { if (escalate_warning(w)) stop(w$message) diff --git a/R/lib.R b/R/lib.R index 42225d7..9af878e 100644 --- a/R/lib.R +++ b/R/lib.R @@ -3,26 +3,33 @@ #' A description of where packages should be installed. This object provides #' necessary information to determine where a package should be installed. #' -#' @param x Any additional metadata that can be prescribed when describing -#' a library location and used when building the path. Defaults to an empty -#' [`list()`]. +#' @param x A [`pkg_origin()`] object #' @param .class An optional subclass, used primarily for dispatch. -#' -lib_loc <- function(x = list(), .class = c()) { - structure(x, class = c(.class, "lib_loc")) +lib_path <- function(x, ..., .class = c()) { + UseMethod("lib_path") } #' @export -format.lib_loc <- function(x, ...) { - "library" +lib_path.default <- function(x, ..., .class = c()) { + structure(list(), class = c(.class, "lib_path_default")) } -lib_loc_default <- function() { - lib_loc(.class = "lib_loc_default") +#' @export +lib_path.pkg_origin_repo <- function(x, ..., .class = c()) { + lib_path.default(x, ..., .class = .class) } -lib_loc_isolated <- function(seed = NULL) { - lib_loc(list(seed = seed), .class = "lib_loc_isolated") +#' @export +lib_path.pkg_origin_local <- function(x, ..., .class = c()) { + structure( + list(source = x$source), + class = c(.class, "lib_path_isolated") + ) +} + +#' @export +format.lib_path <- function(x, ...) { + "library" } #' Get Library Location @@ -38,7 +45,7 @@ lib <- function(x, ..., lib.loc = c()) { #' Null Library Path #' #' @export -lib.NULL <- function(x, ...) { +lib.NULL <- function(x, ..., lib.loc = c()) { character(0L) } @@ -54,32 +61,33 @@ lib.character <- function(x, ..., lib.loc = c()) { #' Produce an Isolated Library Path #' -#' @param x A `lib_loc_isolated` object. +#' @param x A `lib_path_isolated` object. #' @param name A name for the library, defaults to a random hash. #' @param lib.root A root directory for the isolated library. #' @param ... Additional arguments unused #' #' @export -lib.lib_loc_isolated <- function( +lib.lib_path_isolated <- function( x, - name = rlang::hash(runif(1)), lib.root = tempdir(), - ... + ..., + lib.loc = c() ) { - file.path(lib.root, name) + file.path(lib.root, hash(x$source)) } #' Produce a Default Library Path #' -#' @param x A `lib_loc_default` object. +#' @param x A `lib_path_default` object. #' @param ... Additional arguments unused #' @param lib.loc Library paths, defaulting to [`.libPaths()`]. #' #' @export -lib.lib_loc_default <- function( +lib.lib_path_default <- function( x, ..., - lib.loc = .libPaths() + lib.loc = c() ) { + # In most cases this assumes checker library was appended to the lib.loc lib.loc[[1]] } diff --git a/R/next_task.R b/R/next_task.R index d682b9e..f01eb16 100644 --- a/R/next_task.R +++ b/R/next_task.R @@ -1,54 +1,27 @@ -next_node_to_run <- function(g) { - checks <- task_graph_which_check_satisfied(g) - installs <- task_graph_which_install_satisfied(g) - - # Prioritize checks overs installs - v <- igraph::V(g)[c(checks, installs)] - - utils::head(v, 1L) -} - -#' @importFrom igraph .env -task_get_lib_loc <- function(g, node, output) { - nhood <- task_graph_neighborhoods(g, node)[[1]] - name <- names(node) %||% node # nolint (used via non-standard-evaluation) - nhood <- nhood[names(nhood) != .env$name] - - # Custom packages are possible only for the check type nodes which are - # always terminal. Therefore if we sort nhood making custom packages appear - # first, their lib will always be prioritized - attributes <- igraph::vertex.attributes(g, index = nhood) - - paths <- vcapply(nhood, function(v) { - task_get_install_lib(g, v, output) - }) - - unique(paths[order(attributes$custom, decreasing = TRUE)]) -} - -task_graph_libpaths <- function(g, node = NULL, lib.loc = .libPaths()) { - vs <- if (is.null(node)) { +task_graph_libpaths <- function( + g, + node = NULL, + lib.loc = .libPaths(), + output = tempdir() +) { + # Maintain original vertices order to make sure libpaths are properly + # constructed + vs <- sort(if (is.null(node)) { igraph::V(g) } else { task_graph_neighborhoods(g, node)[[1]] - } + }, decreasing = TRUE) # iterate over tasks and derive a library location - task_lib <- lapply(vs$task, lib, lib.loc = lib.loc) + task_lib <- lapply( + vs$task, + lib, + lib.loc = lib.loc, + lib.root = path_libs(output) + ) unique(unlist(task_lib)) } -task_get_install_lib <- function(g, node, output) { - attributes <- igraph::vertex.attributes(g, index = node) - if (attributes$type == "check") { - path_check_output(output, attributes$spec[[1]]$alias) - } else if (attributes$custom) { - path_custom_lib(output, attributes$spec[[1]]$alias) - } else { - path_lib(output) - } -} - start_task <- function(node, g, ...) { UseMethod("start_task") } @@ -68,10 +41,10 @@ start_task.install_task <- function( ... ) { task <- node$task[[1]] + libpaths <- task_graph_libpaths(g, node, lib.loc = lib.loc, output = output) install_parameters <- install_params(task$origin) - libpaths <- task_graph_libpaths(g, node, lib.loc = lib.loc) - if (inherits(task$origin, "pkg_origin_base")) { + if (any(inherits(task$origin, c("pkg_origin_base", "pkg_origin_unknown")))) { return(NULL) } @@ -81,7 +54,7 @@ start_task.install_task <- function( install_process$new( install_parameters$package, - lib = lib(task$lib, lib.loc = lib.loc), + lib = lib(task$lib, lib.loc = lib.loc, lib.root = path_libs(output)), libpaths = libpaths, repos = task$origin$repos, dependencies = FALSE, @@ -92,30 +65,6 @@ start_task.install_task <- function( ) } -#' @export -start_task.custom_install_task <- function( - node, - g, - output, - lib.loc, - ... -) { - spec <- task_graph_task(g, task) - install_parameters <- install_params(spec$package) - libpaths <- c(task_get_lib_loc(g, node, output), lib.loc) - install_process$new( - install_parameters$package, - lib = path_custom_lib(output, spec$alias), - libpaths = libpaths, - repos = install_parameters$repos, - dependencies = FALSE, - type = spec$type, - INSTALL_opts = spec$INSTALL_opts, - log = path_install_log(output, spec$alias), - env = spec$env - ) -} - #' @export start_task.check_task <- function( node, @@ -125,7 +74,7 @@ start_task.check_task <- function( ... ) { task <- node$task[[1]] - libpaths <- task_graph_libpaths(g, node, lib.loc = lib.loc) + libpaths <- task_graph_libpaths(g, node, lib.loc = lib.loc, output = output) path <- check_path(task$origin, output = path_sources()) check_process$new( diff --git a/R/pkg_origin.R b/R/pkg_origin.R index 8b547ce..8967edd 100644 --- a/R/pkg_origin.R +++ b/R/pkg_origin.R @@ -69,7 +69,7 @@ pkg_origin_repo <- function(package, repos, ...) { #' @rdname pkg_origin try_pkg_origin_repo <- function(package, repos, ...) { if (isTRUE(pkg_origin_is_base(package))) { - return(pkg_origin_base(package, ...)) + pkg_origin_base(package, ...) } else if (package %in% available_packages(repos = repos)[, "Package"]) { pkg_origin_repo(package = package, repos = repos, ...) } else { @@ -129,40 +129,69 @@ pkg_origin_archive <- function(path = NULL, ...) { pkg_origin(..., path = path, .class = "pkg_origin_archive") } -pkg_deps <- function(x) { +pkg_deps <- function( + x, + repos = getOption("repos"), + dependencies = TRUE, + db = available_packages(repos = repos) +) { UseMethod("pkg_deps") } #' @export -pkg_deps.default <- function(x) { +pkg_deps.default <- function( + x, + repos = getOption("repos"), + dependencies = TRUE, + db = available_packages(repos = repos) +) { NULL } #' @export -pkg_deps.pkg_origin_local <- function(x) { - db <- available_packages(repos = x$repos) - row <- db[x$package, , drop = FALSE] - row[, DB_COLNAMES, drop = FALSE] +pkg_deps.pkg_origin <- function( + x, + repos = getOption("repos"), + dependencies = TRUE, + db = available_packages(repos = repos) +) { + pkg_dependencies(package(x), db = db, dependencies = dependencies) } #' @export -pkg_deps.pkg_origin_local <- function(x) { - row <- as.data.frame(read.dcf(file.path(x$path, "DESCRIPTION"))) - row <- row[, intersect(DB_COLNAMES, colnames(row)), drop = FALSE] - row[setdiff(DB_COLNAMES, colnames(row))] <- NA_character_ - row +pkg_deps.pkg_origin_local <- function( + x, + repos = getOption("repos"), + dependencies = TRUE, + db = available_packages(repos = repos) +) { + # We need to temporarily switch the object to data.frame, as subsetting + # assignemnt for matrix does not have drop parameter and always simplifies + # one row matrices to vectors. + row <- read.dcf(file.path(x$source, "DESCRIPTION")) + rownames(row) <- package(x) + direct_deps <- pkg_dependencies( + packages = package(x), + dependencies = dependencies, + db = row + ) + undirect_deps <- pkg_dependencies( + packages = direct_deps$name, + dependencies = dependencies, + db = db + ) + rbind(direct_deps, undirect_deps) } #' @export -pkg_deps.pkg_origin_archive <- function(x) { - path <- if (!file.exists(x$path)) { - fetch_package_source(x$path, path_sources()) - } else { - x$path - } - utils::untar(path, exdir = dir) - x$path <- file.path(path, x$name) - pkg_deps.pkg_origin_local(x) +pkg_deps.pkg_origin_archive <- function( + x, + repos = getOption("repos"), + dependencies = TRUE +) { + # TODO: Implement it by fetching tarball, untarring it and dispatching + # TODO: to origin_local + pkg_deps.pkg_origin_local(x = x, repos = repos, dependencies = dependencies) } @@ -175,6 +204,11 @@ install_params.pkg_origin <- function(x, output, ...) { stop(sprintf("Can't determine origin of package '%s'", x$name)) } +#' @export +install_params.pkg_origin_unknown <- function(x, output, ...) { + list() # no source identified, installation shall be skipped +} + #' @export install_params.pkg_origin_base <- function(x) { list() # no installation needed, distributed with R @@ -187,7 +221,7 @@ install_params.pkg_origin_repo <- function(x) { #' @export install_params.pkg_origin_local <- function(x) { - list(package = x$path, repos = NULL) + list(package = x$source, repos = NULL) } #' @export @@ -195,6 +229,20 @@ install_params.pkg_origin_archive <- function(x) { list(package = x$path, repos = NULL) } +package_install_type <- function(x) { + UseMethod("package_install_type") +} + +#' @export +package_install_type.pkg_origin <- function(x, output, ...) { + getOption("pkgType") +} + +#' @export +package_install_type.pkg_origin_local <- function(x) { + "source" +} + check_path <- function(package_source, ...) { UseMethod("check_path") } @@ -218,43 +266,3 @@ check_path.pkg_origin_local <- function(x, ...) { check_path.pkg_origin_archive <- function(x, ...) { x$path } - -dep_tree <- function(x, ...) { - UseMethod("dep_tree") -} - -#' @export -dep_tree.check_task <- function(x, ...) { - dep_tree(x$origin, ...) -} - -#' @export -dep_tree.install_task <- function(x, ...) { - dep_tree(x$origin, ...) -} - -#' @export -dep_tree.pkg_origin <- function( - x, - ..., - db = available_packages(), - dependencies = TRUE -) { - dep_tree(x$package, ..., db = db, dependencies = dependencies) -} - -#' @export -dep_tree.character <- function( - x, - ..., - db = available_packages(), - dependencies = TRUE -) { - df <- pkg_dependencies(x, dependencies = dependencies, db = db, ...) - colmap <- c("package" = "from", "name" = "to") - rename <- match(names(df), names(colmap)) - to_rename <- !is.na(rename) - names(df)[to_rename] <- colmap[rename[to_rename]] - df <- df[, c(which(to_rename), which(!to_rename)), drop = FALSE] - igraph::graph_from_data_frame(df) -} diff --git a/R/plan.R b/R/plan.R index 173aa61..5636c45 100644 --- a/R/plan.R +++ b/R/plan.R @@ -169,94 +169,3 @@ plan_rev_dep_release_check <- function(origin, revdep, repos) { )) )) } - -rev_dep_check_tasks <- function(packages, repos, aliases, revdep) { - list_of_task(mapply( - function(package, alias) { - revdep_check_task( - alias = alias, - package = pkg_origin_repo(name = package, repos = repos), - env = DEFAULT_R_CMD_CHECK_ENVVARS, - args = DEFAULT_R_CMD_CHECK_ARGS, - build_args = DEFAULT_R_CMD_BUILD_ARGS, - revdep = revdep - ) - }, - packages, - aliases, - SIMPLIFY = FALSE, - USE.NAMES = FALSE - )) -} - -rev_dep_check_tasks_development <- function(packages, repos, aliases, ...) { - list_of_task(mapply( - function(package, alias) { - check_task( - alias = alias, - package = pkg_origin_repo(name = package, repos = repos), - env = DEFAULT_R_CMD_CHECK_ENVVARS, - args = DEFAULT_R_CMD_CHECK_ARGS, - build_args = DEFAULT_R_CMD_BUILD_ARGS - ) - }, - packages, - aliases, - SIMPLIFY = FALSE, - USE.NAMES = FALSE - )) -} - -#' Plan multiple R CMD checks from source package paths -#' -#' @inherit plan -#' @inheritParams plan -#' -#' @family plan -#' @export -plan_checks <- function(path) { - name <- names(path) - path <- vcapply(path, check_path_is_pkg_source, USE.NAMES = FALSE) - package <- vcapply(path, get_package_name) - - alias <- if (is.null(name)) { - unlist(lapply(unique(package), function(p) { - idx <- package == p - suffixes <- if (sum(idx) > 1) { - paste0("_", seq(sum(idx))) - } else { - "" - } - paste0(p, " (source", suffixes, ")") - })) - } else { - name - } - - version <- vcapply(path, get_package_version) - - df <- data.frame(alias = alias, version = version) - df$package <- list_of_task(source_check_tasks(package, path, alias)) - df$custom <- list_of_task(rep(list(custom_install_task()), times = NROW(df))) - - df -} - -source_check_tasks <- function(packages, path, aliases) { - list_of_task(mapply( - function(package, path, alias) { - check_task( - alias = alias, - package = pkg_origin_local(name = package, path = path), - env = DEFAULT_R_CMD_CHECK_ENVVARS, - args = DEFAULT_R_CMD_CHECK_ARGS, - build_args = DEFAULT_R_CMD_BUILD_ARGS - ) - }, - packages, - path, - aliases, - SIMPLIFY = FALSE, - USE.NAMES = FALSE - )) -} diff --git a/R/reporter_ansi_tty.R b/R/reporter_ansi_tty.R index 082c14e..88a1292 100644 --- a/R/reporter_ansi_tty.R +++ b/R/reporter_ansi_tty.R @@ -367,7 +367,7 @@ report_status.reporter_ansi_tty <- function(reporter, checker, envir) { v <- igraph::V(checker$graph) # add newly started task status - is_running <- v$status > STATUS$pending & v$status < STATUS$done + is_running <- v$status > STATUS$ready & v$status < STATUS$done is_newly_done <- v$status >= STATUS$done & !v$name %in% reporter$buffer$node updated <- v[is_running | is_newly_done] @@ -395,7 +395,7 @@ report_status.reporter_ansi_tty <- function(reporter, checker, envir) { # report non-check tasks in status line to_report_bar <- is_install(updated$task) & - updated$status > STATUS$pending & + updated$status > STATUS$ready & updated$status < STATUS$done if (any(to_report_bar)) msg[length(msg) + 1L] <- "installing" diff --git a/R/reporter_basic_tty.R b/R/reporter_basic_tty.R index b915034..a43b2fa 100644 --- a/R/reporter_basic_tty.R +++ b/R/reporter_basic_tty.R @@ -20,8 +20,18 @@ report_initialize.reporter_basic_tty <- function( #' @export report_status.reporter_basic_tty <- function(reporter, design, envir) { cli_theme() - for (i in seq_along(igraph::V(design$graph))) { - node <- igraph::V(design$graph)[[i]] + g <- design$graph + tasks_names <- names(igraph::V(g)) + # skip if queued, but not started or already finished + reported_statuses <- sapply(reporter$statuses, `[[`, 1) + reported_done <- names(reported_statuses[reported_statuses == STATUS$done]) + tasks_not_started <- + names(igraph::V(g)[igraph::V(g)$status <= STATUS$`ready`]) + tasks_to_report <- + tasks_names[!tasks_names %in% c(reported_done, tasks_not_started)] + + for (i in igraph::V(g)[tasks_to_report]) { + node <- igraph::V(g)[[i]] # skip if queued, but not started if (node$status <= STATUS$`pending`) next diff --git a/R/task.R b/R/task.R index 3b2a283..668a634 100644 --- a/R/task.R +++ b/R/task.R @@ -54,9 +54,9 @@ print.task <- function(x, ...) { #' @export install_task <- function( origin, - type = getOption("pkgType"), + type = package_install_type(origin), INSTALL_opts = NULL, - lib = lib_loc_default(), + lib = lib_path(origin), ... ) { task( @@ -71,7 +71,7 @@ install_task <- function( #' @export lib.install_task <- function(x, ...) { - lib(x$lib, name = hash(x), ...) + lib(x$lib, ...) } is_type <- function(x, type) { @@ -104,20 +104,12 @@ is_check <- function(x) { is_type(x, "check") } -is_meta <- function(x) { - is_type(x, "meta") +is_actionable_task <- function(x) { + is_type(x, "check") | is_type(x, "install") } -#' Create a custom install task -#' -#' @inheritDotParams install_task -#' -#' @family tasks -#' @export -custom_install_task <- function(...) { - task <- install_task(...) - class(task) <- c("custom_install_task", class(task)) - task +is_meta <- function(x) { + is_type(x, "meta") } #' Create a task to run `R CMD check` @@ -139,28 +131,13 @@ check_task <- function(build_args = NULL, args = NULL, env = NULL, ...) { #' @export lib.check_task <- function(x, ...) { - character(0L) # no additional libraries needed for checkign + character(0L) # no additional libraries needed for checking } is_check_task <- function(x) { inherits(x, "check_task") } -#' Specify a library install -#' -#' A declarative task that specifies a set of packages that should be installed -#' to a given location. This task is typically used during planning of checks, -#' but does not spawn a process. It is used primarily for organizing the -#' library precedence for check tasks. -#' -library_task <- function(origins = list(), loc = lib_loc_default(), ...) { - task <- task(...) - task$origins <- origins - task$loc <- loc - class(task) <- c("library_task", class(task)) - task -} - #' Create a task to run reverse dependency checks #' #' @param revdep character indicating whether the task specification describes @@ -266,3 +243,28 @@ flatten.subtasks_task <- function(x) { lapply(x$tasks, function(xi) flatten(xi)) )) } + + +package <- function(x) { + UseMethod("package") +} + +#' @export +package.default <- function(x) { + stop("Unrecognized type") +} + +#' @export +package.check_task <- function(x) { + package(x$origin) +} + +#' @export +package.install_task <- function(x) { + package(x$origin) +} + +#' @export +package.pkg_origin <- function(x) { + x$package +} diff --git a/R/task_graph.R b/R/task_graph.R index 8ca350a..fb40849 100644 --- a/R/task_graph.R +++ b/R/task_graph.R @@ -11,9 +11,10 @@ #' prior to calculating edges. The bulk of this function serves to join this #' data. #' -#' @param plan a `plan` object, containing a list of related steps. +#' @param x a `plan` object, containing a list of related steps. #' @param repos `repos`, as expected by [`tools::package_dependencies()`] to #' determine package relationships. +#' @param ... params passed to helper methods. #' @return A `data.frame` that can be used to build [`igraph`] edges. #' #' @examples @@ -22,38 +23,68 @@ #' task_graph_create(plan_rev_dep_checks(".")) #' } #' @keywords internal -task_graph_create <- function(plan, repos = getOption("repos")) { +#' +#' @importFrom igraph V E +task_graph <- function(x, repos = getOption("repos"), ...) { + UseMethod("task_graph") +} + +#' @export +task_graph.task <- function(x, repos = getOption("repos"), ...) { + df <- pkg_deps(x$origin, repos = repos, dependencies = TRUE) + colmap <- c("package" = "from", "name" = "to") + rename <- match(names(df), names(colmap)) + to_rename <- !is.na(rename) + names(df)[to_rename] <- colmap[rename[to_rename]] + df <- df[, c(which(to_rename), which(!to_rename)), drop = FALSE] + g_dep <- igraph::graph_from_data_frame(df) + + E(g_dep)$relation <- RELATION$dep + E(g_dep)$type <- DEP[E(g_dep)$type] + V(g_dep)$task <- lapply( + V(g_dep)$name, + function(p) { + origin <- try_pkg_origin_repo(package = p, repos = repos) + install_task(origin = origin) + } + ) + + # Add the root node + g_dep <- igraph::add_vertices( + g_dep, 1, attr = list(name = "root-vertex", task = list(x)) + ) + + g_dep <- copy_edges_from_vertex( + g_dep, + v_to = "root-vertex", + v_from = package(x), + mode = "out" + ) + + V(g_dep)$name <- vcapply(V(g_dep)$task, as_vertex_name) + + g_dep +} + +#' @export +task_graph.task_graph <- function(x, repos = getOption("repos"), ...) { # only use dependency edges when populating graph - check_tasks <- igraph::V(plan)[is_check(igraph::V(plan)$task)] + nodes <- V(x)[is_actionable_task(V(x)$task)] check_task_neighborhoods <- igraph::neighborhood( - plan, - order = length(plan), + x, + order = length(x), mode = "out", - nodes = check_tasks + nodes = nodes ) # for each check task in the plan, build a dependency tree and merge it # into the existing check task subtree check_task_neighborhoods <- lapply(check_task_neighborhoods, function(nh) { - subtree <- igraph::induced_subgraph(plan, nh) - V(subtree)$name <- vcapply( - V(subtree)$task, - function(i) i$origin$package %||% NA_character_ - ) + subtree <- igraph::induced_subgraph(x, nh) # build dependency graph, with fallback installation task - # TODO: if this is too slow, could move after all neighborhoods are merged - deps <- dep_tree(nh[[1]]$task) - igraph::reverse_edges(deps) - igraph::E(deps)$type <- DEP[igraph::E(deps)$type] - igraph::V(deps)$task <- lapply( - igraph::V(deps)$name, - function(package) { - origin <- try_pkg_origin_repo(package = package, repos = repos) - install_task(origin = origin) - } - ) + deps <- task_graph(nh[[1]]$task, repos = repos) # merge trees on package names # NOTE: attributes (tasks) are preserved in the order they appear @@ -63,22 +94,26 @@ task_graph_create <- function(plan, repos = getOption("repos")) { is_na <- is.na(E(subtree)$type) E(subtree)$type[is_na] <- DEP$Depends - # re-hash tasks as vertex names - igraph::V(subtree)$name <- vcapply(igraph::V(subtree)$task, as_vertex_name) - subtree }) # then merge all the full check task task trees into a single graph - g <- graph_dedup_attrs(igraph::union(plan, check_task_neighborhoods)) + g <- graph_dedup_attrs(igraph::union(x, check_task_neighborhoods)) - igraph::E(g)$type <- DEP[igraph::E(g)$type] - igraph::V(g)$status <- STATUS$pending - igraph::V(g)$process <- rep_len(list(), length(g)) + E(g)$type <- DEP[E(g)$type] + V(g)$status <- STATUS$pending + V(g)$process <- rep_len(list(), length(g)) g <- task_graph_sort(g) - class(g) <- c("task_graph", class(g)) + n_g <- length(V(g)) + x_ids <- as.numeric(V(g)[names(V(x))]) + g_ids <- numeric(n_g) + g_ids[x_ids] <- seq(from = n_g, length.out = length(x_ids), by = -1) + g_ids[g_ids == 0] <- setdiff(seq_along(V(g)), g_ids) + g <- igraph::permute(g, g_ids) + + class(g) <- c("task_graph", class(g)) g } @@ -101,87 +136,6 @@ lib_node_pkgs <- function(g, nodes) { }) } -package_graph <- function(db, packages = db[, "Package"], dependencies = TRUE) { - dependencies <- as_pkg_dependencies(dependencies) - - direct_deps <- unique(as.character(unlist(package_deps( - packages, - db = db, - which = dependencies$direct, - recursive = FALSE - )))) - - indirect_deps <- unique(as.character(unlist(package_deps( - c(packages, direct_deps), - db = db, - which = dependencies$indirect, - recursive = TRUE - )))) - - deps <- unique(c(packages, direct_deps, indirect_deps)) - deps <- deps[!deps %in% base_pkgs() & deps %in% db[, "Package"]] - - edges <- packages_edges(db[deps, ]) - vertices <- data.frame(name = unique(c(edges$package, edges$dep))) - igraph::graph_from_data_frame(edges, vertices = vertices) -} - -#' Produce Graph Edges from Packages Index -#' -#' @param ap `matrix`, as produced by [`utils::available.packages()`] -#' @return `data.frame` with columns `package`, `dep` and `type` and -#' one row for each dependency relationship. -#' -packages_edges <- function(ap) { - deps_by_type <- lapply(names(DEP), function(deptype) { - is_na <- is.na(ap[, deptype]) - - # filter for available packages with at least one dep of deptype - deps <- ap[!is_na, deptype] - names(deps) <- ap[!is_na, "Package"] - - # split deps of deptype - deps <- lapply(deps, .tools$.split_dependencies) - - # and structure - data.frame( - package = rep(names(deps), times = viapply(deps, length)), - dep = unlist(lapply(deps, names), use.names = FALSE), - type = deptype - ) - }) - - do.call(rbind, deps_by_type) -} - -task_graph_vertices <- function(plan, df, edges, repos) { - vertices <- unique(c(edges$dep, edges$root)) - custom_pkgs_aliases <- uulist(lapply(df$custom, `[[`, "alias")) - task_type <- ifelse(vertices %in% df$alias, "check", "install") - - spec <- lapply(vertices, function(v) { - if (v %in% df$alias) { - df$package[[which(df$alias == v)]] - } else if (v %in% custom_pkgs_aliases) { - df$custom[[utils::head(which(as.character(lapply(df$custom, `[[`, "alias")) == v), 1)]] - } else { - install_task( - alias = v, - package = pkg_origin_repo(name = v, repos = repos) - ) - } - }) - - out <- data.frame( - name = vertices, - type = task_type, - custom = vertices %in% custom_pkgs_aliases - ) - - out$spec <- spec - out -} - #' Find Task Neighborhood #' #' @param g A task graph, as produced with [task_graph_create()] @@ -219,29 +173,34 @@ task_graph_neighborhoods <- function(g, nodes, ...) { #' @importFrom igraph E V E<- V<- #' @keywords internal task_graph_sort <- function(g) { - roots <- which(igraph::vertex_attr(g, "type") == "check") + roots <- which(is_check(V(g)$task)) - # split into neighborhoods by root (revdep) - nhood <- task_graph_neighborhoods(g, roots) + # calculcate check task neighborhood sizes + nh_sizes <- igraph::neighborhood_size( + g, + nodes = roots, + order = length(g), + mode = "out" + ) # prioritize by neighborhood size (small to large) - priority <- length(nhood) + priority <- length(roots) priority_footprint <- integer(length(g)) - for (i in order(-vapply(nhood, length, integer(1L)))) { - priority_footprint[nhood[[i]]] <- priority + for (i in order(-nh_sizes)) { + priority_footprint[roots[[i]]] <- priority priority <- priority - 1 } # use only strong dependencies to prioritize by topology (leafs first) - strong_edges <- dep_edges(E(g), "strong") + strong_edges <- dep_edges(E(g), check_dependencies("strong")) g_strong <- igraph::subgraph.edges(g, strong_edges, delete.vertices = FALSE) - topo <- igraph::topo_sort(g_strong, mode = "in") + topo <- igraph::topo_sort(g_strong, mode = "out") priority_topo <- integer(length(g)) - priority_topo[match(topo$name, igraph::V(g)$name)] <- rev(seq_along(topo)) + priority_topo[match(topo$name, V(g)$name)] <- rev(seq_along(topo)) # combine priorities, prioritize first by total, footprint then topology priority <- rbind(priority_footprint, priority_topo) - order <- rank(length(igraph::V(g))^seq(nrow(priority) - 1, 0) %*% priority) + order <- rank(length(V(g))^seq(nrow(priority) - 1, 0) %*% priority) g <- igraph::permute(g, order) g @@ -275,9 +234,9 @@ task_graph_sort <- function(g) { #' #' @importFrom igraph incident_edges tail_of #' @keywords internal -task_graph_which_satisfied <- function( +task_graph_update_ready <- function( g, - v = igraph::V(g), + v = V(g), dependencies = TRUE, status = STATUS$pending ) { @@ -300,43 +259,55 @@ task_graph_which_satisfied <- function( } ) - names(deps_met[deps_met]) + task_graph_set_package_status(g, names(deps_met[deps_met]), STATUS$ready) } -task_graph_which_satisfied_strong <- function(..., dependencies = "strong") { # nolint - task_graph_which_satisfied(..., dependencies = dependencies) -} - -task_graph_which_check_satisfied <- function( +task_graph_update_check_ready <- function( g, ..., dependencies = "all", status = STATUS$pending ) { - task_graph_which_satisfied( + task_graph_update_ready( g, - igraph::V(g)[is_check(igraph::V(g)$task)], + V(g)[is_check(V(g)$task)], ..., dependencies = dependencies, status = status ) } -task_graph_which_install_satisfied <- function( +task_graph_update_install_ready <- function( g, ..., dependencies = "strong", status = STATUS$pending ) { - task_graph_which_satisfied( + task_graph_update_ready( g, - igraph::V(g)[is_install(igraph::V(g)$task)], + V(g)[is_install(V(g)$task)], ..., dependencies = dependencies, status = status ) } +#' Find nodes with ready state +#' +#' List nodes which have ready state prioritizing check task nodes over +#' install task nodes. +#' +#' @param g A dependency graph, as produced with [task_graph()]. +#' +#' @return The names of packages with ready state. +#' +#' @keywords internal +task_graph_which_ready <- function(g) { + nodes <- V(g)[is_actionable_task(V(g)$task)] + statuses <- igraph::vertex.attributes(g, nodes)$status + nodes[statuses == STATUS["ready"]] +} + empty_edge <- data.frame( dep = character(0), root = character(0), @@ -378,7 +349,7 @@ task_graph_set_task_process <- function(g, v, process) { } task_graph_update_done <- function(g, lib.loc) { - v <- igraph::V(g)[igraph::V(g)$type == "install"] + v <- V(g)[V(g)$type == "install"] which_done <- which(vlapply(v$name, is_package_installed, lib.loc = lib.loc)) task_graph_set_package_status(g, v[which_done], STATUS$done) } @@ -391,7 +362,7 @@ plot.task_graph <- function(x, ..., interactive = FALSE) { map[match(as.character(attr), names(map), nomatch = nomatch)] } - task_type <- vcapply(igraph::V(x)$task, function(task) { + task_type <- vcapply(V(x)$task, function(task) { if (is_install(task)) return(class(task$origin)[[1]]) class(task)[[1]] }) @@ -413,17 +384,17 @@ plot.task_graph <- function(x, ..., interactive = FALSE) { "red" ) - vertex$label <- cli::ansi_strip(vcapply(igraph::V(x)$task, format, g = x)) + vertex$label <- cli::ansi_strip(vcapply(V(x)$task, format, g = x)) vertex$frame.color <- style( - STATUS[igraph::V(x)$status %||% 1], + STATUS[V(x)$status %||% 1], "done" = "green", "in progress" = "lightgreen", "black" ) vertex$frame.width <- style( - STATUS[igraph::V(x)$status %||% 1], + STATUS[V(x)$status %||% 1], "done" = 3L, 1L ) @@ -492,7 +463,6 @@ plot_interactive_task_graph <- function( edge$from <- vertex$id[match(edge$from, vertex$name)] edge$to <- vertex$id[match(edge$to, vertex$name)] edge$arrows <- "to" - edge$dashes <- edge$lty != 1 # visNetwork hates non-atomic vectors vertex$task <- NULL diff --git a/R/utils-cli.R b/R/utils-cli.R index 815145c..d4b803e 100644 --- a/R/utils-cli.R +++ b/R/utils-cli.R @@ -14,10 +14,10 @@ task_formats <- function( task <- nodes$task } - # # NOTE: currently unused, vestigial vectorized alternative - # if (length(tasks) == 1 && is.null(tasks[[1]])) { - # tasks <- V(g)$task - # } + # # NOTE: currently unused, vestigial vectorized alternative # nolint + # if (length(tasks) == 1 && is.null(tasks[[1]])) { # nolint + # tasks <- V(g)$task # nolint + # } # nolint makeActiveBinding("source", env = environment(), function() { src <- task$origin %||% character(0L) diff --git a/R/utils-deps.R b/R/utils-deps.R index 206e6ee..06caf76 100644 --- a/R/utils-deps.R +++ b/R/utils-deps.R @@ -77,7 +77,9 @@ pkg_dependencies <- function( while (length(packages) > 0L) { depth <- depth + 1L deptypes <- if (depth == 1L) dependencies$direct else dependencies$indirect - depstrs <- db[packages, deptypes, drop = FALSE] + # db does not need to have all the dependencies types. + deptypes <- intersect(colnames(db), deptypes) + depstrs <- safe_db_subset(db, packages, deptypes, drop = FALSE) n <- length(out) + 1 out[[n]] <- Map( @@ -86,7 +88,7 @@ pkg_dependencies <- function( deptype = rep(deptypes, each = length(packages)), f = function(package, depstr, deptype) { if (is.na(depstr)) return() - deps <- tools:::.split_dependencies(depstr) + deps <- .tools$.split_dependencies(depstr) out <- proto_df[seq_along(deps), , drop = FALSE] out$package <- package @@ -100,6 +102,12 @@ pkg_dependencies <- function( SIMPLIFY = FALSE ) + # TODO: Although CRAN does not seem to officially support < and <= + # TODO: requirements for hard dependencies, as of 01.07.2025 + # TODO: there is a singe package MatrixModels which specifies it. + # TODO: For now we decided to skip such requirements to assess + # TODO: the severity of this. + out <- out[!out$op %in% c("<", "<="), ] rownames(out) <- paste0(out$package, "-", out$name) out } @@ -114,3 +122,22 @@ pkg_dependencies <- function( rownames(out) <- NULL out } + +safe_db_subset <- function(db, r, c, drop = FALSE) { + if (is.character(r) && !all(r %in% rownames(db))) { + missing <- r[!r %in% rownames(db)] + missing <- matrix( + NA, + nrow = length(missing), + ncol = NCOL(db), + dimnames = list( + missing, + colnames(db) + ) + ) + db <- rbind(db, missing) + } + + c <- intersect(colnames(db), c) + db[r, c, drop = drop] +} diff --git a/R/utils-enums.R b/R/utils-enums.R index 5abdda6..0852eee 100644 --- a/R/utils-enums.R +++ b/R/utils-enums.R @@ -46,6 +46,7 @@ RELATION <- enum( #' @keywords internal STATUS <- enum( "pending", + "ready", "in progress", "done" ) diff --git a/R/utils-igraph.R b/R/utils-igraph.R index 5707c64..377ab8b 100644 --- a/R/utils-igraph.R +++ b/R/utils-igraph.R @@ -74,3 +74,23 @@ complete_columns <- function(df, cols) { for (col in setdiff(cols, colnames(df))) df[[col]] <- NA[n_gtz] df[, cols, drop = FALSE] } + +copy_edges_from_vertex <- function(g, v_to, v_from, mode = "all") { + for (e in igraph::incident(g, v_from, mode)) { + v_ends <- igraph::ends(g, e) + if (v_ends[1] == v_from) { + g <- igraph::add_edges( + g, + c(v_to, v_ends[2]), + attr = igraph::edge.attributes(g, e) + ) + } else { + g <- igraph::add_edges( + g, + c(v_ends[1], v_to), + attr = igraph::edge.attributes(g, e) + ) + } + } + g +} diff --git a/R/utils-paths.R b/R/utils-paths.R index f62b6b8..4513aa2 100644 --- a/R/utils-paths.R +++ b/R/utils-paths.R @@ -62,14 +62,8 @@ path_libs <- function(path) { normalizePath(p) } -path_lib <- function(path) { - dir_create(p <- file.path(path_libs(path), "lib")) - normalizePath(p) -} - -path_custom_lib <- function(path, custom) { - valid_name <- unique_alias(custom) - dir_create(p <- file.path(path_libs(path), valid_name)) +path_checker_lib <- function(path) { + dir_create(p <- file.path(path_libs(path), "checker_lib")) normalizePath(p) } diff --git a/R/utils-pkg-source.R b/R/utils-pkg-source.R index 338d929..12781a3 100644 --- a/R/utils-pkg-source.R +++ b/R/utils-pkg-source.R @@ -65,7 +65,7 @@ get_desc_field <- function(path, field) { } sub_desc_aliases <- function( - desc, + desc, aliases = if ("Alias" %in% colnames(desc)) desc[, "Alias"] ) { if (is.null(aliases)) return(desc) diff --git a/man/STATUS.Rd b/man/STATUS.Rd index 0c24e5e..c723d11 100644 --- a/man/STATUS.Rd +++ b/man/STATUS.Rd @@ -5,7 +5,7 @@ \alias{STATUS} \title{Check execution status categories} \format{ -An object of class \code{enum} (inherits from \code{factor}) of length 3. +An object of class \code{enum} (inherits from \code{factor}) of length 4. } \usage{ STATUS diff --git a/man/check_dev_rev_deps.Rd b/man/check_dev_rev_deps.Rd index 1d87c1a..5c0ff93 100644 --- a/man/check_dev_rev_deps.Rd +++ b/man/check_dev_rev_deps.Rd @@ -49,8 +49,6 @@ as a \code{Suggests} dependency. } \seealso{ Other checks: -\code{\link{check_dir}()}, -\code{\link{check_pkgs}()}, \code{\link{check_rev_deps}()}, \code{\link{checker}}, \code{\link{new_checker}()} diff --git a/man/check_dir.Rd b/man/check_dir.Rd deleted file mode 100644 index d50554b..0000000 --- a/man/check_dir.Rd +++ /dev/null @@ -1,55 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/check.R -\name{check_dir} -\alias{check_dir} -\title{Check all package source directories in current directory} -\usage{ -check_dir( - path, - n = 2L, - output = tempfile(paste(utils::packageName(), Sys.Date(), sep = "-")), - lib.loc = .libPaths(), - repos = getOption("repos"), - restore = TRUE, - ... -) -} -\arguments{ -\item{path}{file path to the package source directory} - -\item{n}{\code{integer} value indicating maximum number of subprocesses that can -be simultaneously spawned when executing tasks.} - -\item{output}{\code{character} value specifying path where the output should be -stored.} - -\item{lib.loc}{\code{character} vector with libraries allowed to be used when -checking packages, defaults to entire \code{\link[=.libPaths]{.libPaths()}}.} - -\item{repos}{\code{character} vector of repositories which will be used when -generating task graph and later pulling dependencies.} - -\item{restore}{\code{logical} indicating whether output directory should be -unlinked before running checks. If \code{FALSE}, an attempt will me made to -restore previous progress from the same \code{output}} - -\item{...}{Additional arguments passed to \code{\link[=run]{run()}}} -} -\value{ -\code{\link[=checker]{checker()}} R6 class storing all the details -regarding checks that run. Can be combined with -\code{\link{results}} and \code{\link[=summary]{summary()}} methods to generate results. -} -\description{ -\code{\link[=check_dir]{check_dir()}} Identifies all R packages in the given directory -(non-recursively) and passes them to the \code{\link[=check_pkgs]{check_pkgs()}} -} -\seealso{ -Other checks: -\code{\link{check_dev_rev_deps}()}, -\code{\link{check_pkgs}()}, -\code{\link{check_rev_deps}()}, -\code{\link{checker}}, -\code{\link{new_checker}()} -} -\concept{checks} diff --git a/man/check_pkgs.Rd b/man/check_pkgs.Rd deleted file mode 100644 index e278c62..0000000 --- a/man/check_pkgs.Rd +++ /dev/null @@ -1,56 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/check.R -\name{check_pkgs} -\alias{check_pkgs} -\title{Check one or more package source directories} -\usage{ -check_pkgs( - path, - n = 2L, - output = tempfile(paste(utils::packageName(), Sys.Date(), sep = "-")), - lib.loc = .libPaths(), - repos = getOption("repos"), - restore = TRUE, - ... -) -} -\arguments{ -\item{path}{file path to the package source directory} - -\item{n}{\code{integer} value indicating maximum number of subprocesses that can -be simultaneously spawned when executing tasks.} - -\item{output}{\code{character} value specifying path where the output should be -stored.} - -\item{lib.loc}{\code{character} vector with libraries allowed to be used when -checking packages, defaults to entire \code{\link[=.libPaths]{.libPaths()}}.} - -\item{repos}{\code{character} vector of repositories which will be used when -generating task graph and later pulling dependencies.} - -\item{restore}{\code{logical} indicating whether output directory should be -unlinked before running checks. If \code{FALSE}, an attempt will me made to -restore previous progress from the same \code{output}} - -\item{...}{Additional arguments passed to \code{\link[=run]{run()}}} -} -\value{ -\code{\link[=checker]{checker()}} R6 class storing all the details -regarding checks that run. Can be combined with -\code{\link{results}} and \code{\link[=summary]{summary()}} methods to generate results. -} -\description{ -\code{\link[=check_pkgs]{check_pkgs()}} Installs all dependencies and runs \verb{R CMD check}s -in parallel for all source packages whose source code is found in the -\code{path} directory -} -\seealso{ -Other checks: -\code{\link{check_dev_rev_deps}()}, -\code{\link{check_dir}()}, -\code{\link{check_rev_deps}()}, -\code{\link{checker}}, -\code{\link{new_checker}()} -} -\concept{checks} diff --git a/man/check_rev_deps.Rd b/man/check_rev_deps.Rd index 9ee2cc6..80d6afd 100644 --- a/man/check_rev_deps.Rd +++ b/man/check_rev_deps.Rd @@ -63,8 +63,6 @@ identify changes in reverse dependency behaviors. \seealso{ Other checks: \code{\link{check_dev_rev_deps}()}, -\code{\link{check_dir}()}, -\code{\link{check_pkgs}()}, \code{\link{checker}}, \code{\link{new_checker}()} } diff --git a/man/check_task.Rd b/man/check_task.Rd index fb0d474..688f808 100644 --- a/man/check_task.Rd +++ b/man/check_task.Rd @@ -35,7 +35,6 @@ Create a task to run \verb{R CMD check} } \seealso{ Other tasks: -\code{\link{custom_install_task}()}, \code{\link{install_task}()}, \code{\link{revdep_check_task}()}, \code{\link{task}()} diff --git a/man/checker.Rd b/man/checker.Rd index 2d5f708..9eb2578 100644 --- a/man/checker.Rd +++ b/man/checker.Rd @@ -30,8 +30,6 @@ while (!orchestrator$is_done()) { \seealso{ Other checks: \code{\link{check_dev_rev_deps}()}, -\code{\link{check_dir}()}, -\code{\link{check_pkgs}()}, \code{\link{check_rev_deps}()}, \code{\link{new_checker}()} } diff --git a/man/custom_install_task.Rd b/man/custom_install_task.Rd deleted file mode 100644 index fbefb7f..0000000 --- a/man/custom_install_task.Rd +++ /dev/null @@ -1,40 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/task.R -\name{custom_install_task} -\alias{custom_install_task} -\title{Create a custom install task} -\usage{ -custom_install_task(...) -} -\arguments{ -\item{...}{ - Arguments passed on to \code{\link[=install_task]{install_task}} - \describe{ - \item{\code{lib}}{Any object that can be passed to \code{\link[=lib]{lib()}} to generate a library -path.} - \item{\code{type}}{character, indicating the type of package to download and - install. Will be \code{"source"} except on Windows and some macOS - builds: see the section on \sQuote{Binary packages} for those. - } - \item{\code{INSTALL_opts}}{ - an optional character vector of additional option(s) to be passed to - \command{R CMD INSTALL} for a source package install. E.g., - \code{c("--html", "--no-multiarch", "--no-test-load")} or, for - macOS, \code{"--dsym"}. - - Can also be a named list of character vectors to be used as - additional options, with names the respective package names. - } - }} -} -\description{ -Create a custom install task -} -\seealso{ -Other tasks: -\code{\link{check_task}()}, -\code{\link{install_task}()}, -\code{\link{revdep_check_task}()}, -\code{\link{task}()} -} -\concept{tasks} diff --git a/man/install_task.Rd b/man/install_task.Rd index 9797ede..c75b45d 100644 --- a/man/install_task.Rd +++ b/man/install_task.Rd @@ -6,9 +6,9 @@ \usage{ install_task( origin, - type = getOption("pkgType"), + type = package_install_type(origin), INSTALL_opts = NULL, - lib = lib_loc_default(), + lib = lib_path(origin), ... ) } @@ -39,7 +39,6 @@ Create a task to install a package and dependencies \seealso{ Other tasks: \code{\link{check_task}()}, -\code{\link{custom_install_task}()}, \code{\link{revdep_check_task}()}, \code{\link{task}()} } diff --git a/man/lib.NULL.Rd b/man/lib.NULL.Rd index 51cf31c..e5e3406 100644 --- a/man/lib.NULL.Rd +++ b/man/lib.NULL.Rd @@ -4,7 +4,7 @@ \alias{lib.NULL} \title{Null Library Path} \usage{ -\method{lib}{`NULL`}(x, ...) +\method{lib}{`NULL`}(x, ..., lib.loc = c()) } \description{ Null Library Path diff --git a/man/lib.lib_loc_default.Rd b/man/lib.lib_path_default.Rd similarity index 66% rename from man/lib.lib_loc_default.Rd rename to man/lib.lib_path_default.Rd index 8e61ce4..ba5e4f4 100644 --- a/man/lib.lib_loc_default.Rd +++ b/man/lib.lib_path_default.Rd @@ -1,13 +1,13 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/lib.R -\name{lib.lib_loc_default} -\alias{lib.lib_loc_default} +\name{lib.lib_path_default} +\alias{lib.lib_path_default} \title{Produce a Default Library Path} \usage{ -\method{lib}{lib_loc_default}(x, ..., lib.loc = .libPaths()) +\method{lib}{lib_path_default}(x, ..., lib.loc = c()) } \arguments{ -\item{x}{A \code{lib_loc_default} object.} +\item{x}{A \code{lib_path_default} object.} \item{...}{Additional arguments unused} diff --git a/man/lib.lib_loc_isolated.Rd b/man/lib.lib_path_isolated.Rd similarity index 65% rename from man/lib.lib_loc_isolated.Rd rename to man/lib.lib_path_isolated.Rd index 2bc2c0a..e253a4a 100644 --- a/man/lib.lib_loc_isolated.Rd +++ b/man/lib.lib_path_isolated.Rd @@ -1,19 +1,19 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/lib.R -\name{lib.lib_loc_isolated} -\alias{lib.lib_loc_isolated} +\name{lib.lib_path_isolated} +\alias{lib.lib_path_isolated} \title{Produce an Isolated Library Path} \usage{ -\method{lib}{lib_loc_isolated}(x, name = rlang::hash(runif(1)), lib.root = tempdir(), ...) +\method{lib}{lib_path_isolated}(x, lib.root = tempdir(), ..., lib.loc = c()) } \arguments{ -\item{x}{A \code{lib_loc_isolated} object.} - -\item{name}{A name for the library, defaults to a random hash.} +\item{x}{A \code{lib_path_isolated} object.} \item{lib.root}{A root directory for the isolated library.} \item{...}{Additional arguments unused} + +\item{name}{A name for the library, defaults to a random hash.} } \description{ Produce an Isolated Library Path diff --git a/man/lib_loc.Rd b/man/lib_path.Rd similarity index 60% rename from man/lib_loc.Rd rename to man/lib_path.Rd index 16805d9..0a42126 100644 --- a/man/lib_loc.Rd +++ b/man/lib_path.Rd @@ -1,15 +1,13 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/lib.R -\name{lib_loc} -\alias{lib_loc} +\name{lib_path} +\alias{lib_path} \title{Make a Library Location} \usage{ -lib_loc(x = list(), .class = c()) +lib_path(x, ..., .class = c()) } \arguments{ -\item{x}{Any additional metadata that can be prescribed when describing -a library location and used when building the path. Defaults to an empty -\code{\link[=list]{list()}}.} +\item{x}{A \code{\link[=pkg_origin]{pkg_origin()}} object} \item{.class}{An optional subclass, used primarily for dispatch.} } diff --git a/man/library_task.Rd b/man/library_task.Rd deleted file mode 100644 index 3eebfb7..0000000 --- a/man/library_task.Rd +++ /dev/null @@ -1,14 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/task.R -\name{library_task} -\alias{library_task} -\title{Specify a library install} -\usage{ -library_task(origins = list(), loc = lib_loc_default(), ...) -} -\description{ -A declarative task that specifies a set of packages that should be installed -to a given location. This task is typically used during planning of checks, -but does not spawn a process. It is used primarily for organizing the -library precedence for check tasks. -} diff --git a/man/new_checker.Rd b/man/new_checker.Rd index 49584c1..c460ab6 100644 --- a/man/new_checker.Rd +++ b/man/new_checker.Rd @@ -20,15 +20,11 @@ Instantiate a check design from a path or directory. \seealso{ Other checks: \code{\link{check_dev_rev_deps}()}, -\code{\link{check_dir}()}, -\code{\link{check_pkgs}()}, \code{\link{check_rev_deps}()}, \code{\link{checker}} Other checks: \code{\link{check_dev_rev_deps}()}, -\code{\link{check_dir}()}, -\code{\link{check_pkgs}()}, \code{\link{check_rev_deps}()}, \code{\link{checker}} } diff --git a/man/packages_edges.Rd b/man/packages_edges.Rd deleted file mode 100644 index 2052fd3..0000000 --- a/man/packages_edges.Rd +++ /dev/null @@ -1,18 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/task_graph.R -\name{packages_edges} -\alias{packages_edges} -\title{Produce Graph Edges from Packages Index} -\usage{ -packages_edges(ap) -} -\arguments{ -\item{ap}{\code{matrix}, as produced by \code{\link[utils:available.packages]{utils::available.packages()}}} -} -\value{ -\code{data.frame} with columns \code{package}, \code{dep} and \code{type} and -one row for each dependency relationship. -} -\description{ -Produce Graph Edges from Packages Index -} diff --git a/man/plan.Rd b/man/plan.Rd index dd7d1cc..66b4a1a 100644 --- a/man/plan.Rd +++ b/man/plan.Rd @@ -28,7 +28,6 @@ should be run. } \seealso{ Other plan: -\code{\link{plan_checks}()}, \code{\link{plan_rev_dep_checks}()} } \concept{plan} diff --git a/man/plan_checks.Rd b/man/plan_checks.Rd deleted file mode 100644 index dbbfa31..0000000 --- a/man/plan_checks.Rd +++ /dev/null @@ -1,37 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/plan.R -\name{plan_checks} -\alias{plan_checks} -\title{Plan multiple R CMD checks from source package paths} -\usage{ -plan_checks(path) -} -\arguments{ -\item{path}{path to the package source. Can be either a single source -code directory or a directory containing multiple package source code -directories.} -} -\value{ -The check schedule \code{data.frame} with the following columns: -\itemize{ -\item \code{alias}: The alias of the check to run. It also serves the purpose of -providing a unique identifier and node name in the task graph. -\item \code{version}: Version of the package to be checked. -\item \code{package}: Object that inherits from \code{\link[=check_task]{check_task()}}. -Defines how package to be checked can be acquired. -\item \code{custom}: Object that inherits from \code{\link[=custom_install_task]{custom_install_task()}}. -Defines custom package, for instance only available from local source, that -should be installed before checking the package. -} -} -\description{ -Plans are pre-specified sets of checks. Plans are simple \code{data.frame}s -where each row defines a package for which \verb{R CMD check} -should be run. -} -\seealso{ -Other plan: -\code{\link{plan}}, -\code{\link{plan_rev_dep_checks}()} -} -\concept{plan} diff --git a/man/plan_rev_dep_checks.Rd b/man/plan_rev_dep_checks.Rd index a9ba363..0859c21 100644 --- a/man/plan_rev_dep_checks.Rd +++ b/man/plan_rev_dep_checks.Rd @@ -46,7 +46,6 @@ repository for which reverse dependencies should be identified. } \seealso{ Other plan: -\code{\link{plan}}, -\code{\link{plan_checks}()} +\code{\link{plan}} } \concept{plan} diff --git a/man/revdep_check_task.Rd b/man/revdep_check_task.Rd index 71177bc..107bf74 100644 --- a/man/revdep_check_task.Rd +++ b/man/revdep_check_task.Rd @@ -19,7 +19,6 @@ Create a task to run reverse dependency checks \seealso{ Other tasks: \code{\link{check_task}()}, -\code{\link{custom_install_task}()}, \code{\link{install_task}()}, \code{\link{task}()} } diff --git a/man/task.Rd b/man/task.Rd index 22579f5..5759900 100644 --- a/man/task.Rd +++ b/man/task.Rd @@ -25,7 +25,6 @@ related tasks. \seealso{ Other tasks: \code{\link{check_task}()}, -\code{\link{custom_install_task}()}, \code{\link{install_task}()}, \code{\link{revdep_check_task}()} } diff --git a/man/task_graph_create.Rd b/man/task_graph.Rd similarity index 84% rename from man/task_graph_create.Rd rename to man/task_graph.Rd index 2b1407f..e0d06a0 100644 --- a/man/task_graph_create.Rd +++ b/man/task_graph.Rd @@ -1,16 +1,18 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/task_graph.R -\name{task_graph_create} -\alias{task_graph_create} +\name{task_graph} +\alias{task_graph} \title{Build task graph edges} \usage{ -task_graph_create(plan, repos = getOption("repos")) +task_graph(x, repos = getOption("repos"), ...) } \arguments{ -\item{plan}{a \code{plan} object, containing a list of related steps.} +\item{x}{a \code{plan} object, containing a list of related steps.} \item{repos}{\code{repos}, as expected by \code{\link[tools:package_dependencies]{tools::package_dependencies()}} to determine package relationships.} + +\item{...}{params passed to helper methods.} } \value{ A \code{data.frame} that can be used to build \code{\link{igraph}} edges. diff --git a/man/task_graph_which_satisfied.Rd b/man/task_graph_update_ready.Rd similarity index 91% rename from man/task_graph_which_satisfied.Rd rename to man/task_graph_update_ready.Rd index f92b515..e1da281 100644 --- a/man/task_graph_which_satisfied.Rd +++ b/man/task_graph_update_ready.Rd @@ -1,12 +1,12 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/task_graph.R -\name{task_graph_which_satisfied} -\alias{task_graph_which_satisfied} +\name{task_graph_update_ready} +\alias{task_graph_update_ready} \title{Find the Next Packages Not Dependent on an Unavailable Package} \usage{ -task_graph_which_satisfied( +task_graph_update_ready( g, - v = igraph::V(g), + v = V(g), dependencies = TRUE, status = STATUS$pending ) diff --git a/man/task_graph_which_ready.Rd b/man/task_graph_which_ready.Rd new file mode 100644 index 0000000..985eec1 --- /dev/null +++ b/man/task_graph_which_ready.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/task_graph.R +\name{task_graph_which_ready} +\alias{task_graph_which_ready} +\title{Find nodes with ready state} +\usage{ +task_graph_which_ready(g) +} +\arguments{ +\item{g}{A dependency graph, as produced with \code{\link[=task_graph]{task_graph()}}.} +} +\value{ +The names of packages with ready state. +} +\description{ +List nodes which have ready state prioritizing check task nodes over +install task nodes. +} +\keyword{internal} diff --git a/tests/testthat/test-dep-graph-next-package.R b/tests/testthat/test-dep-graph-next-package.R index 0b11b07..3a95b6a 100644 --- a/tests/testthat/test-dep-graph-next-package.R +++ b/tests/testthat/test-dep-graph-next-package.R @@ -17,12 +17,16 @@ test_that("dep_graph_next_package finds next installable package", { # initialize graph, such that "D" is not completed when "E" would be next # by order due to "D" having a long install time V(g)$status <- STATUS[["pending"]] + V(g)$type <- "install" V(g)["D"]$status <- STATUS[["in progress"]] V(g)["C"]$status <- STATUS[["done"]] - expect_equal(task_graph_which_satisfied(g), "B") + g <- task_graph_update_ready(g) + expect_equal(names(task_graph_which_ready(g)), "B") # if the order is reversed, now "F" and "E" should be next + V(g)$status <- STATUS[["pending"]] V(g)["D"]$status <- STATUS[["done"]] V(g)["C"]$status <- STATUS[["in progress"]] - expect_equal(task_graph_which_satisfied(g), c("F", "E")) + g <- task_graph_update_ready(g) + expect_equal(names(task_graph_which_ready(g)), c("F", "E")) }) From f306030178f436fda159e6b0552b319b35a4ae1e Mon Sep 17 00:00:00 2001 From: Szymon Maksymiuk <32574056+maksymiuks@users.noreply.github.com> Date: Mon, 25 Aug 2025 01:30:46 +0200 Subject: [PATCH 35/62] Remotes support (#67) * Initial remotes support * Reintroduce options package * 68 adjust results generation to new meta tasks structure (#71) * Refactor results generation * Add local plans (#70) * Add local plans * Remove line added by accident * Make lintr happy * Enhance source path check * Polish results generation. Remove results_to_df * Deduplicate graph * Add edges types to remotes packages * Fix lintr * Make check pass * Update rd names --- .Rbuildignore | 1 + .lintr | 1 - DESCRIPTION | 4 +- NAMESPACE | 68 ++++--- NOTES.md | 3 - R/check_process.R | 18 -- R/checker.R | 40 +++- R/lib.R | 83 ++++---- R/next_task.R | 6 +- R/options.R | 73 ++++++- R/package.R | 2 + R/pkg_origin.R | 103 ++++++++-- R/plan.R | 140 ++++++++----- R/remotes.R | 128 ++++++++++++ R/reporter.R | 23 ++- R/reporter_ansi_tty.R | 15 +- R/reporter_basic_tty.R | 15 +- R/reporter_null.R | 3 - R/results.R | 335 +++++++++++++++++--------------- R/run.R | 2 +- R/task-formatting.R | 10 +- R/task.R | 137 ++----------- R/task_graph.R | 88 +++++---- R/utils-cli.R | 24 ++- R/utils-deps.R | 9 +- R/utils-igraph.R | 25 ++- R/utils-paths.R | 11 +- R/utils-pkg-source.R | 2 +- R/utils-remotes.R | 34 ++++ R/utils.R | 19 ++ _pkgdown.yml | 4 + man/as.package.remotes.Rd | 22 +++ man/as_pkg_dependencies.Rd | 2 +- man/check_task.Rd | 3 +- man/checker.Rd | 4 +- man/fmt.Rd | 23 ++- man/graph_dedup_attrs.Rd | 3 + man/install_task.Rd | 10 +- man/lib.NULL.Rd | 11 -- man/lib.Rd | 42 +++- man/lib.character.Rd | 16 -- man/lib.lib_path_default.Rd | 18 -- man/lib.lib_path_isolated.Rd | 20 -- man/lib_path.Rd | 12 +- man/meta_task.Rd | 6 + man/new_checker.Rd | 2 +- man/options.Rd | 92 +++++++++ man/options_params.Rd | 41 ++++ man/pkg_dependencies.Rd | 19 +- man/pkg_origin.Rd | 12 +- man/plan.Rd | 33 ---- man/plan_local_checks.Rd | 32 +++ man/plan_rev_dep_checks.Rd | 19 +- man/print.checked_results.Rd | 26 ++- man/reporters-internal.Rd | 19 +- man/reporters.Rd | 2 +- man/results.Rd | 39 ++-- man/results_to_file.Rd | 31 --- man/revdep_check_task.Rd | 25 --- man/run.Rd | 8 +- man/task.Rd | 10 +- man/task_formats.Rd | 13 +- man/task_graph.Rd | 5 +- man/task_graph_neighborhoods.Rd | 2 +- man/task_graph_update_ready.Rd | 11 +- tests/testthat.R | 2 +- 66 files changed, 1276 insertions(+), 785 deletions(-) delete mode 100644 NOTES.md create mode 100644 R/remotes.R create mode 100644 R/utils-remotes.R create mode 100644 man/as.package.remotes.Rd delete mode 100644 man/lib.NULL.Rd delete mode 100644 man/lib.character.Rd delete mode 100644 man/lib.lib_path_default.Rd delete mode 100644 man/lib.lib_path_isolated.Rd create mode 100644 man/options.Rd create mode 100644 man/options_params.Rd delete mode 100644 man/plan.Rd create mode 100644 man/plan_local_checks.Rd delete mode 100644 man/results_to_file.Rd delete mode 100644 man/revdep_check_task.Rd diff --git a/.Rbuildignore b/.Rbuildignore index a1c747a..3da6c38 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -11,3 +11,4 @@ ^codecov\.yml$ ^README\.html$ ^README_cache$ +^\.lintr diff --git a/.lintr b/.lintr index 4e1a485..c597280 100644 --- a/.lintr +++ b/.lintr @@ -11,7 +11,6 @@ exclusions: "tests/testthat/fixtures", "inst/", # TODO: These files need major refactor, skip until then - "R/results.R", "tests/" ) diff --git a/DESCRIPTION b/DESCRIPTION index aa7eca9..8b830bc 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: checked Title: Systematically Run R CMD Checks -Version: 0.2.3.9004 +Version: 1.0.9000 Authors@R: c( person( @@ -40,6 +40,7 @@ Imports: igraph, jsonlite, memoise, + options, R6, rcmdcheck, rlang, @@ -48,6 +49,7 @@ Imports: Roxygen: list(markdown = TRUE) RoxygenNote: 7.3.2 Suggests: + remotes, testthat (>= 3.0.0), visNetwork, withr diff --git a/NAMESPACE b/NAMESPACE index 0fc4a78..edf1580 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,31 +1,25 @@ # Generated by roxygen2: do not edit by hand S3method("$",enum) -S3method("[",checked_results) S3method(Ops,enum) -S3method(as_desc,character) -S3method(as_desc,check_task) -S3method(as_desc,default) -S3method(as_desc,install_task) -S3method(as_desc,pkg_origin_local) -S3method(as_desc,pkg_origin_repo) -S3method(as_desc,subtasks_task) S3method(as_vertex_name,default) +S3method(as_vertex_name,local_check_meta_task) S3method(as_vertex_name,task) S3method(check_path,pkg_origin) S3method(check_path,pkg_origin_archive) S3method(check_path,pkg_origin_local) +S3method(check_path,pkg_origin_remote) S3method(check_path,pkg_origin_repo) S3method(count,default) S3method(count,issues) S3method(count,potential_issues) -S3method(flatten,default) -S3method(flatten,subtasks_task) S3method(format,lib_path) S3method(format,listof) +S3method(format,local_check_meta_task) S3method(format,pkg_origin) S3method(format,pkg_origin_base) S3method(format,pkg_origin_local) +S3method(format,pkg_origin_remote) S3method(format,pkg_origin_source) S3method(format,reporter_cell) S3method(format,reporter_line) @@ -38,13 +32,19 @@ S3method(format_task_name,install_task) S3method(format_task_name,rev_dep_check_meta_task) S3method(format_task_name,rev_dep_dep_meta_task) S3method(format_task_name,task) +S3method(format_task_type,local_check_meta_task) S3method(format_task_type,rev_dep_check_meta_task) S3method(format_task_type,rev_dep_dep_meta_task) S3method(format_task_type,task) +S3method(get_remote_tasks,default) +S3method(get_remote_tasks,pkg_origin_local) +S3method(get_remote_tasks,pkg_origin_remote) +S3method(get_remote_tasks,task) S3method(install_params,pkg_origin) S3method(install_params,pkg_origin_archive) S3method(install_params,pkg_origin_base) S3method(install_params,pkg_origin_local) +S3method(install_params,pkg_origin_remote) S3method(install_params,pkg_origin_repo) S3method(install_params,pkg_origin_unknown) S3method(is_type,default) @@ -60,26 +60,35 @@ S3method(lib,lib_path_isolated) S3method(lib,task) S3method(lib_path,default) S3method(lib_path,pkg_origin_local) +S3method(lib_path,pkg_origin_remote) S3method(lib_path,pkg_origin_repo) -S3method(package,check_task) S3method(package,default) -S3method(package,install_task) S3method(package,pkg_origin) +S3method(package,task) S3method(package_install_type,pkg_origin) S3method(package_install_type,pkg_origin_local) S3method(pkg_deps,default) S3method(pkg_deps,pkg_origin) S3method(pkg_deps,pkg_origin_archive) S3method(pkg_deps,pkg_origin_local) +S3method(pkg_deps,pkg_origin_remote) S3method(plot,task_graph) S3method(print,checked_results) -S3method(print,checked_results_check_task) -S3method(print,checked_results_revdep_check_task) S3method(print,checker) S3method(print,issues) +S3method(print,local_check_results) S3method(print,potential_issues) -S3method(print,rcmdcheck_diff) +S3method(print,rcmdcheck_check_results) +S3method(print,rcmdcheck_results) +S3method(print,rcmdcheck_rev_dep_results) +S3method(print,rev_dep_dep_results) S3method(print,task) +S3method(remotes_graph,check_task) +S3method(remotes_graph,igraph.vs) +S3method(remotes_graph,install_task) +S3method(remotes_graph,integer) +S3method(remotes_graph,task) +S3method(remotes_graph,task_graph) S3method(report_finalize,"NULL") S3method(report_finalize,reporter_ansi_tty) S3method(report_finalize,reporter_basic_tty) @@ -90,29 +99,27 @@ S3method(report_start_setup,reporter_ansi_tty) S3method(report_status,"NULL") S3method(report_status,reporter_ansi_tty) S3method(report_status,reporter_basic_tty) +S3method(report_task,reporter_ansi_tty) S3method(report_task_ansi_tty,check_task) S3method(report_task_ansi_tty,default) S3method(report_task_ansi_tty,rev_dep_check_meta_task) -S3method(results,check_task) S3method(results,checker) -S3method(results,list_check_task) -S3method(results,list_revdep_check_task) -S3method(results,revdep_check_task) +S3method(results,igraph.vs) +S3method(results,integer) +S3method(results,local_check_meta_task) +S3method(results,rev_dep_check_meta_task) +S3method(results,rev_dep_dep_meta_task) S3method(run,character) S3method(run,checker) S3method(start_task,check_task) +S3method(start_task,igraph.vs) S3method(start_task,install_task) -S3method(summary,checked_results) -S3method(summary,checked_results_check_task) -S3method(summary,checked_results_revdep_check_task) -S3method(summary,checker) S3method(task_graph,task) S3method(task_graph,task_graph) export(check_dev_rev_deps) export(check_rev_deps) export(check_task) export(checker) -export(format_simplify_path) export(install_task) export(new_checker) export(new_rev_dep_checker) @@ -121,26 +128,21 @@ export(pkg_origin_archive) export(pkg_origin_base) export(pkg_origin_is_base) export(pkg_origin_local) +export(pkg_origin_remote) export(pkg_origin_repo) export(pkg_origin_unknown) +export(plan_local_checks) export(plan_rev_dep_checks) -export(report_initialize.NULL) -export(report_initialize.reporter_basic_tty) -export(report_task.reporter_ansi_tty) export(reporter_ansi_tty) export(reporter_ansi_tty2) export(reporter_basic_tty) -export(reporter_cell) export(reporter_default) -export(reporter_line) export(results) -export(results_to_file) -export(revdep_check_task) export(run) -export(start_task.igraph.vs) export(task) export(try_pkg_origin_repo) import(cli) +import(options) importFrom(R6,R6Class) importFrom(callr,r_process) importFrom(cli,make_spinner) @@ -155,6 +157,8 @@ importFrom(igraph,subgraph.edges) importFrom(igraph,tail_of) importFrom(igraph,topo_sort) importFrom(igraph,vertex_attr) +importFrom(memoise,memoise) importFrom(rcmdcheck,rcmdcheck_process) +importFrom(rlang,hash) importFrom(utils,install.packages) importFrom(utils,packageName) diff --git a/NOTES.md b/NOTES.md deleted file mode 100644 index 45439f1..0000000 --- a/NOTES.md +++ /dev/null @@ -1,3 +0,0 @@ -# Considering - -* moving task class into a separate vector attribute diff --git a/R/check_process.R b/R/check_process.R index c7fe4f5..00603a3 100644 --- a/R/check_process.R +++ b/R/check_process.R @@ -14,24 +14,6 @@ RE_CHECK <- paste0( ) # nolint end, styler: on -DEFAULT_R_CMD_CHECK_ENVVARS <- c( # nolint - "_R_CHECK_FORCE_SUGGESTS_" = FALSE, - "_R_CHECK_RD_XREFS_" = FALSE, - "_R_CHECK_SYSTEM_CLOCK_" = FALSE, - "_R_CHECK_SUGGESTS_ONLY_" = TRUE -) - -DEFAULT_R_CMD_BUILD_ARGS <- c( # nolint - "--no-build-vignettes", - "--no-manual" -) - -DEFAULT_R_CMD_CHECK_ARGS <- c( # nolint - "--timings", - "--ignore-vignettes", - "--no-manual" -) - #' @importFrom R6 R6Class #' @importFrom rcmdcheck rcmdcheck_process check_process <- R6::R6Class( diff --git a/R/checker.R b/R/checker.R index 75afef9..5551f08 100644 --- a/R/checker.R +++ b/R/checker.R @@ -2,7 +2,7 @@ #' #' Instantiate a check design from a path or directory. #' -#' @param x A file path, passed to [`rev_dep_check_tasks_df()`] +#' @param x A file path, passed to [`plan_rev_dep_checks()`] #' @param ... Additional arguments passed to [`new_checker()`] #' #' @family checks @@ -52,7 +52,7 @@ checker <- R6::R6Class( #' @field graph (`igraph::igraph()`)\cr #' A dependency graph, storing information about which dependencies #' are required prior to execution of each check task. - #' Created with [`task_graph_create()`] + #' Created with [`task_graph()`] graph = NULL, #' @field plan (`data.frame()`)\cr @@ -94,12 +94,10 @@ checker <- R6::R6Class( ), lib.loc = .libPaths(), repos = getOption("repos"), - restore = TRUE, + restore = options::opt("restore"), ... ) { - if (!restore) { - unlink(output, recursive = TRUE, force = TRUE) - } + check_past_output(output, restore, ask = interactive()) dir_create(output) @@ -167,6 +165,9 @@ checker <- R6::R6Class( return(-1L) } + # force garbage collection to free memory from terminated processes + gc(verbose = FALSE, reset = FALSE, full = TRUE) + # if all available processes are in use, terminate early n_active <- length(private$active) if (n_active >= private$n) { @@ -315,3 +316,30 @@ print.checker <- function(x, ...) { } invisible(x) } + +check_past_output <- function(output, restore, ask = interactive()) { + if (dir.exists(output)) { + if (is.na(restore)) { + restore <- if (ask) { + switch( + restore_menu(), + "1" = TRUE, + "2" = FALSE + ) + } else { + FALSE + } + } + + if (!restore) { + unlink(output, recursive = TRUE, force = TRUE) + } + } +} + +restore_menu <- function() { + utils::menu( + c("Yes", "No"), + title = "Do you want to restore previous results?" + ) +} diff --git a/R/lib.R b/R/lib.R index 9af878e..5a5c0f3 100644 --- a/R/lib.R +++ b/R/lib.R @@ -2,8 +2,11 @@ #' #' A description of where packages should be installed. This object provides #' necessary information to determine where a package should be installed. +#' lib_path method creates default path handlers for given pkg origin while +#' lib_path_x creates an actual object. #' -#' @param x A [`pkg_origin()`] object +#' @param x A [`pkg_origin()`] object used for default dispatch. +#' @param ... Additional values #' @param .class An optional subclass, used primarily for dispatch. lib_path <- function(x, ..., .class = c()) { UseMethod("lib_path") @@ -11,20 +14,33 @@ lib_path <- function(x, ..., .class = c()) { #' @export lib_path.default <- function(x, ..., .class = c()) { - structure(list(), class = c(.class, "lib_path_default")) + lib_path_default(.class = .class) } #' @export lib_path.pkg_origin_repo <- function(x, ..., .class = c()) { - lib_path.default(x, ..., .class = .class) + lib_path_default(.class = .class) } #' @export lib_path.pkg_origin_local <- function(x, ..., .class = c()) { - structure( - list(source = x$source), - class = c(.class, "lib_path_isolated") - ) + lib_path_isolated(.class = .class) +} + +#' @export +lib_path.pkg_origin_remote <- function(x, ..., .class = c()) { + x <- sanitize_pkg_origin_remote(x) + NextMethod() +} + +#' @rdname lib_path +lib_path_default <- function(.class = c()) { + structure(list(), class = c(.class, "lib_path_default")) +} + +#' @rdname lib_path +lib_path_isolated <- function(.class = c()) { + structure(list(), class = c(.class, "lib_path_isolated")) } #' @export @@ -35,58 +51,51 @@ format.lib_path <- function(x, ...) { #' Get Library Location #' #' @param x An object describing a library location -#' @param lib.loc A set of library locations, used as defaults for objects -#' that may make use of them. -#' -lib <- function(x, ..., lib.loc = c()) { +#' @param ... additional parameters passed to methods +#' @param lib.loc Library paths, defaulting to [`.libPaths()`]. +#' @param lib.root A root directory for the isolated library. +#' @param dir_hash unique identifier of the isolated library +#' @param name human-readable subname of the isolated library +lib <- function(x, ...) { UseMethod("lib") } -#' Null Library Path -#' +#' @method lib NULL #' @export -lib.NULL <- function(x, ..., lib.loc = c()) { +#' @rdname lib +lib.NULL <- function(x, ...) { character(0L) } -#' Produce a Library from a Path -#' -#' @param x A `character` object -#' @param ...,lib.loc Additional arguments unused -#' #' @export -lib.character <- function(x, ..., lib.loc = c()) { +#' @rdname lib +lib.character <- function(x, ...) { x } -#' Produce an Isolated Library Path -#' -#' @param x A `lib_path_isolated` object. -#' @param name A name for the library, defaults to a random hash. -#' @param lib.root A root directory for the isolated library. -#' @param ... Additional arguments unused -#' #' @export +#' @rdname lib lib.lib_path_isolated <- function( x, - lib.root = tempdir(), ..., - lib.loc = c() + lib.root = tempdir(), + dir_hash = hash(Sys.time(), n = 8), + name = "" ) { - file.path(lib.root, hash(x$source)) + dirname <- if (nzchar(name)) { + paste0(name, "-", dir_hash) + } else { + dir_hash + } + file.path(lib.root, dirname) } -#' Produce a Default Library Path -#' -#' @param x A `lib_path_default` object. -#' @param ... Additional arguments unused -#' @param lib.loc Library paths, defaulting to [`.libPaths()`]. -#' #' @export +#' @rdname lib lib.lib_path_default <- function( x, ..., - lib.loc = c() + lib.loc = .libPaths() ) { # In most cases this assumes checker library was appended to the lib.loc lib.loc[[1]] diff --git a/R/next_task.R b/R/next_task.R index f01eb16..ec0cc15 100644 --- a/R/next_task.R +++ b/R/next_task.R @@ -27,6 +27,7 @@ start_task <- function(node, g, ...) { } #' @export +#' @method start_task igraph.vs start_task.igraph.vs <- function(node, g, ...) { stopifnot(length(node) == 1L) UseMethod("start_task", node$task[[1]]) @@ -48,13 +49,16 @@ start_task.install_task <- function( return(NULL) } + # install_parameters$package is a valid package name only for + # pkg_origin_local. Otherwise it's a path to the source package in which case + # is_package_installed returns FALSE (as it should) if (is_package_installed(install_parameters$package, libpaths)) { return(NULL) } install_process$new( install_parameters$package, - lib = lib(task$lib, lib.loc = lib.loc, lib.root = path_libs(output)), + lib = lib(task, lib.loc = lib.loc, lib.root = path_libs(output)), libpaths = libpaths, repos = task$origin$repos, dependencies = FALSE, diff --git a/R/options.R b/R/options.R index 2c9106c..c31e56e 100644 --- a/R/options.R +++ b/R/options.R @@ -1,4 +1,69 @@ -default_tty_tick_interval <- function() { - # refresh interval in milliseconds - getOption(paste0(utils::packageName(), ".tty_tick_interval"), 100) / 1000 -} +#' @import options +options::define_options( + "tty refresh interval when reporting results in milliseconds", + tty_tick_interval = 0.1, + + "character vector indicating whether R error should be thrown when issues + are discovered when generating results. \"never\" means that no errors + are thrown. If \"issues\" then errors are emitted only on issues, whereas + \"potential issues\" stands for error on both issues and potential issues.", + results_error_on = "never", + + "character vector indicating which packages should be included in the results. + \"all\" means that all packages are kept. If \"issues\" then only packages + with issues identified, whereas \"potential_issues\" stands for keeping + packages with both \"issues\" and \"potential_issues\".", + results_keep = "all", + + "`logical` indicating whether output directory should be unlinked before + running checks. If `FALSE`, an attempt will me made to restore previous + progress from the same `output`", + restore = NA, + + "`logical` indicating whether origins inheriting from `pkg_origin_local`, + should be scanned for packages in the `remotes` field and added while + constrocuting a plan `task_grap`", + add_remotes = TRUE, + + "named `character` vector of environment variables to use during + the R CMD check.", + check_envvars = c( + "_R_CHECK_FORCE_SUGGESTS_" = FALSE, + "_R_CHECK_RD_XREFS_" = FALSE, + "_R_CHECK_SYSTEM_CLOCK_" = FALSE, + "_R_CHECK_SUGGESTS_ONLY_" = TRUE + ), + + "`character` vector of args passed to the R CMD build.", + check_build_args = c( + "--no-build-vignettes", + "--no-manual" + ), + envvar_fn = structure( + function(raw, ...) trimws(strsplit(raw, " ")[[1]]), + desc = "space-separated R CMD build flags" + ), + + "`character` vector of args passed to the R CMD check.", + check_args = c( + "--timings", + "--ignore-vignettes", + "--no-manual" + ), + envvar_fn = structure( + function(raw, ...) trimws(strsplit(raw, " ")[[1]]), + desc = "space-separated R CMD check flags" + ) +) + +#' @eval options::as_roxygen_docs() +#' +#' @family documentation +NULL + +#' Checked Options +#' @eval options::as_params() +#' @name options_params +#' +#' @family documentation +NULL diff --git a/R/package.R b/R/package.R index 2eeb36f..6206b3b 100644 --- a/R/package.R +++ b/R/package.R @@ -1,2 +1,4 @@ #' @importFrom igraph E V +#' @importFrom memoise memoise +#' @importFrom rlang hash "_PACKAGE" diff --git a/R/pkg_origin.R b/R/pkg_origin.R index 8967edd..98f1106 100644 --- a/R/pkg_origin.R +++ b/R/pkg_origin.R @@ -3,11 +3,14 @@ #' Create package specification list which consists of all the details required #' to identify and acquire source of the package. #' -#' @param name name of the package. +#' @param package name of the package. #' @param repos repository where package with given name should identified. #' @param path path to the source of the package (either bundled or not). URLs #' are acceptable. -#' @param ... parameters passed to downstream constructors +#' @param remote remote object from the `remotes` package used to identify +#' non-standard packages. +#' @param .class Additional subclasses. +#' @param ... parameters passed to downstream constructors. #' #' @family specs #' @export @@ -43,6 +46,11 @@ format.pkg_origin <- function(x, ...) { format(x$source, ...) } +#' @export +format.pkg_origin_remote <- function(x, ...) { + format(class(x$remote)[[1]]) +} + #' @export #' @rdname pkg_origin pkg_origin_repo <- function(package, repos, ...) { @@ -82,8 +90,8 @@ try_pkg_origin_repo <- function(package, repos, ...) { #' @rdname pkg_origin pkg_origin_is_base <- function(package, ...) { is_base <- package == "R" - is_inst <- package %in% installed.packages()[, "Package"] - is_base[is_inst] <- installed.packages()[package[is_inst], "Priority"] == "base" # nolint + is_inst <- package %in% utils::installed.packages()[, "Package"] + is_base[is_inst] <- utils::installed.packages()[package[is_inst], "Priority"] == "base" # nolint is_base } @@ -123,6 +131,30 @@ pkg_origin_local <- function(path = NULL, ...) { ) } +#' @export +#' @rdname pkg_origin +pkg_origin_remote <- function(remote = NULL, ...) { + source <- get_remote_package_source(remote) + package <- get_package_name(source) + version <- package_version(get_package_version(source)) + + pkg_origin( + package = package, + version = version, + remote = remote, + source = source, + ..., + .class = c("pkg_origin_remote", "pkg_origin_local") + ) +} + +sanitize_pkg_origin_remote <- function(x) { + if (is.null(x$source) || !dir.exists(x$source)) { + x$source <- get_remote_package_source(x$remote) + } + x +} + #' @export #' @rdname pkg_origin pkg_origin_archive <- function(path = NULL, ...) { @@ -155,7 +187,11 @@ pkg_deps.pkg_origin <- function( dependencies = TRUE, db = available_packages(repos = repos) ) { - pkg_dependencies(package(x), db = db, dependencies = dependencies) + df <- pkg_dependencies(package(x), db = db, dependencies = dependencies) + # Packages here come from CRAN only hence we can assume that all entries + # with the name the same as the x are direct dependencies + df$depth <- ifelse(df$package == package(x), "direct", "indirect") + df } #' @export @@ -166,28 +202,45 @@ pkg_deps.pkg_origin_local <- function( db = available_packages(repos = repos) ) { # We need to temporarily switch the object to data.frame, as subsetting - # assignemnt for matrix does not have drop parameter and always simplifies + # assignment for matrix does not have drop parameter and always simplifies # one row matrices to vectors. row <- read.dcf(file.path(x$source, "DESCRIPTION")) + rownames(row) <- package(x) direct_deps <- pkg_dependencies( packages = package(x), dependencies = dependencies, db = row ) - undirect_deps <- pkg_dependencies( + direct_deps$depth <- "direct" + + indirect_deps <- pkg_dependencies( packages = direct_deps$name, dependencies = dependencies, db = db ) - rbind(direct_deps, undirect_deps) + indirect_deps$depth <- "indirect" + + rbind(direct_deps, indirect_deps) +} + +#' @export +pkg_deps.pkg_origin_remote <- function( + x, + repos = getOption("repos"), + dependencies = TRUE, + db = available_packages(repos = repos) +) { + x <- sanitize_pkg_origin_remote(x) + NextMethod() } #' @export pkg_deps.pkg_origin_archive <- function( x, repos = getOption("repos"), - dependencies = TRUE + dependencies = TRUE, + db = available_packages(repos = repos) ) { # TODO: Implement it by fetching tarball, untarring it and dispatching # TODO: to origin_local @@ -195,7 +248,7 @@ pkg_deps.pkg_origin_archive <- function( } -install_params <- function(x) { +install_params <- function(x, ...) { UseMethod("install_params") } @@ -210,26 +263,32 @@ install_params.pkg_origin_unknown <- function(x, output, ...) { } #' @export -install_params.pkg_origin_base <- function(x) { +install_params.pkg_origin_base <- function(x, ...) { list() # no installation needed, distributed with R } #' @export -install_params.pkg_origin_repo <- function(x) { +install_params.pkg_origin_repo <- function(x, ...) { list(package = x$package, repos = x$repos) } #' @export -install_params.pkg_origin_local <- function(x) { +install_params.pkg_origin_local <- function(x, ...) { list(package = x$source, repos = NULL) } #' @export -install_params.pkg_origin_archive <- function(x) { +install_params.pkg_origin_remote <- function(x, ...) { + x <- sanitize_pkg_origin_remote(x) + NextMethod() +} + +#' @export +install_params.pkg_origin_archive <- function(x, ...) { list(package = x$path, repos = NULL) } -package_install_type <- function(x) { +package_install_type <- function(x, ...) { UseMethod("package_install_type") } @@ -239,11 +298,11 @@ package_install_type.pkg_origin <- function(x, output, ...) { } #' @export -package_install_type.pkg_origin_local <- function(x) { +package_install_type.pkg_origin_local <- function(x, ...) { "source" } -check_path <- function(package_source, ...) { +check_path <- function(x, ...) { UseMethod("check_path") } @@ -259,10 +318,16 @@ check_path.pkg_origin_repo <- function(x, output, ...) { #' @export check_path.pkg_origin_local <- function(x, ...) { - x$path + x$source +} + +#' @export +check_path.pkg_origin_remote <- function(x, ...) { + x <- sanitize_pkg_origin_remote(x) + NextMethod() } #' @export check_path.pkg_origin_archive <- function(x, ...) { - x$path + x$source } diff --git a/R/plan.R b/R/plan.R index 5636c45..21ab237 100644 --- a/R/plan.R +++ b/R/plan.R @@ -1,35 +1,3 @@ -empty_checks_df <- data.frame( - alias = character(0), - version = character(0), - package = character(0), - custom = character(0) -) - -#' Check Plan -#' -#' Plans are pre-specified sets of checks. Plans are simple `data.frame`s -#' where each row defines a package for which `R CMD check` -#' should be run. -#' -#' @param path path to the package source. Can be either a single source -#' code directory or a directory containing multiple package source code -#' directories. -#' -#' @return The check schedule `data.frame` with the following columns: -#' -#' * `alias`: The alias of the check to run. It also serves the purpose of -#' providing a unique identifier and node name in the task graph. -#' * `version`: Version of the package to be checked. -#' * `package`: Object that inherits from [`check_task()`]. -#' Defines how package to be checked can be acquired. -#' * `custom`: Object that inherits from [`custom_install_task()`]. -#' Defines custom package, for instance only available from local source, that -#' should be installed before checking the package. -#' -#' @family plan -#' @name plan -NULL - #' Plan Reverse Dependency Checks #' #' Generates a plan for running reverse dependency check for certain @@ -37,8 +5,7 @@ NULL #' path to the development version of the package and `repos` should be a #' repository for which reverse dependencies should be identified. #' -#' @inherit plan -#' @inheritParams plan +#' @param path path to the package source. #' @param repos repository used to identify reverse dependencies. #' @param versions character vector indicating against which versions of the #' package reverse dependency should be checked. `c("dev", "release")` @@ -68,7 +35,7 @@ plan_rev_dep_checks <- function( )[[1]] if (length(revdeps) == 0) { - return(empty_checks_df) + return(igraph::make_empty_graph()) } if ("release" %in% version_types && !package %in% ap[, "Package"]) { @@ -83,7 +50,7 @@ plan_rev_dep_checks <- function( } if (length(version_types) == 0) { - return(empty_checks_df) + return(igraph::make_empty_graph()) } # root meta task, indicating a reverse-dependency check plan @@ -129,12 +96,15 @@ plan_rev_dep_checks <- function( g <- igraph::add_edges(g, edges = edges, attr = list(type = DEP$Depends)) E(g)$type <- DEP[E(g)$type] - class(g) <- c("task_graph", class(g)) + g <- task_graph_class(g) - g + if (remotes_permitted()) { + remotes_graph(g) + } else { + g + } } - plan_rev_dep_dev_check <- function(origin, revdep, repos) { rev_dep_origin <- pkg_origin_repo(package = revdep, repos = repos) sequence_graph(task = list( @@ -145,9 +115,9 @@ plan_rev_dep_dev_check <- function(origin, revdep, repos) { ), make_unique_task(seed = "dev", check_task( origin = rev_dep_origin, - env = DEFAULT_R_CMD_CHECK_ENVVARS, - args = DEFAULT_R_CMD_CHECK_ARGS, - build_args = DEFAULT_R_CMD_BUILD_ARGS + env = options::opt("check_envvars"), + args = options::opt("check_args"), + build_args = options::opt("check_build_args") )), install_task(origin = origin) )) @@ -155,6 +125,10 @@ plan_rev_dep_dev_check <- function(origin, revdep, repos) { plan_rev_dep_release_check <- function(origin, revdep, repos) { rev_dep_origin <- pkg_origin_repo(package = revdep, repos = repos) + repo_root_origin <- try_pkg_origin_repo( + package = package(origin), + repos = repos + ) sequence_graph(task = list( meta_task( origin = origin, @@ -163,9 +137,83 @@ plan_rev_dep_release_check <- function(origin, revdep, repos) { ), make_unique_task(seed = "release", check_task( origin = rev_dep_origin, - env = DEFAULT_R_CMD_CHECK_ENVVARS, - args = DEFAULT_R_CMD_CHECK_ARGS, - build_args = DEFAULT_R_CMD_BUILD_ARGS - )) + env = options::opt("check_envvars"), + args = options::opt("check_args"), + build_args = options::opt("check_build_args") + )), + install_task( + origin = repo_root_origin, + lib = lib_path_isolated() + ) )) } + +#' Plan R CMD Checks +#' +#' Generates a plan for running R CMD check for a specified set of packages. +#' +#' @param package A path to either package, directory with packages or name +#' of the package (details) +#' @param repos repository used to identify packages when name is provided. +#' +#' @details +#' `package` parameter has two different allowed values: +#' * Package - checked looks for a DESCRIPTION file in the provided path, if +#' found treats it like a source package. +#' * If the specified value does not correspond to a source package, the +#' parameter is treated as the name and `repos` parameter is used to identify +#' the source. +#' +#' +#' @family plan +#' @export +plan_local_checks <- function( + package, + repos = getOption("repos") +) { + + task <- meta_task( + origin = NULL, + .subclass = "local_check" + ) + + # build individual plans for each package value + local_checks_tasks <- lapply( + package, + function(x, repos) { + if (path_is_pkg(x)) { + check_task( + origin = pkg_origin_local(x), + env = options::opt("check_envvars"), + args = options::opt("check_args"), + build_args = options::opt("check_build_args") + ) + } else { + check_task( + origin = pkg_origin_repo(package = x, repos = repos), + env = options::opt("check_envvars"), + args = options::opt("check_args"), + build_args = options::opt("check_build_args") + ) + } + }, + repos = repos + ) + + g <- star_graph( + task = c( + list(task), + local_checks_tasks + ) + ) + + E(g)$type <- rep(DEP$Depends, times = length(E(g))) + + g <- task_graph_class(g) + + if (remotes_permitted()) { + remotes_graph(g) + } else { + g + } +} diff --git a/R/remotes.R b/R/remotes.R new file mode 100644 index 0000000..198dafc --- /dev/null +++ b/R/remotes.R @@ -0,0 +1,128 @@ +remotes_graph <- function(x, ...) { + UseMethod("remotes_graph") +} + +#' @export +remotes_graph.task_graph <- function(x, ...) { + vs <- V(x) + remotes_subgraphs <- lapply(vs, remotes_graph, vs = vs) + + task_graph_class( + suppressWarningsRegex( + graph_dedup_attrs( + igraph::union( + x, + do.call(igraph::union, remotes_subgraphs) + ) + ), + "Some, but not all graphs are named, not using vertex names", + fixed = TRUE + ) + ) +} + +#' @export +remotes_graph.integer <- function(x, ..., vs) { + remotes_graph(vs[[x]]) +} + +#' @export +#' @method remotes_graph igraph.vs +remotes_graph.igraph.vs <- function(x, ...) { + remotes_graph(x$task) +} + +#' @export +remotes_graph.task <- function(x, ...) { + # By default does not allow remotes for a task unless an explicit method + # has been defined for that type of task + igraph::make_empty_graph() +} + +#' @export +remotes_graph.install_task <- function(x, ...) { + remote_tasks <- get_remote_tasks(x) + if (length(remote_tasks) == 0) return(igraph::make_empty_graph()) + remote_tasks_names <- vcapply(remote_tasks, package) + + x_deps <- pkg_deps(x$origin) + x_remote_deps <- x_deps[ + x_deps$package == package(x) & x_deps$name %in% remote_tasks_names, + ] + + # Sort tasks according to same key + remote_tasks <- remote_tasks[order(remote_tasks_names)] + remote_tasks_types <- x_remote_deps[order(x_remote_deps$name), ]$type + + g <- star_graph( + task = c( + list(x), + remote_tasks + ), + edge_attrs = list(type = remote_tasks_types) + ) + + # Recursively get remote_tasks of remote_tasks + remote_subgraphs <- lapply(remote_tasks, remotes_graph) + suppressWarningsRegex( + graph_dedup_attrs( + igraph::union( + g, + do.call(igraph::union, remote_subgraphs) + ) + ), + "Some, but not all graphs are named, not using vertex names", + fixed = TRUE + ) +} + +#' @export +remotes_graph.check_task <- remotes_graph.install_task + +get_remote_tasks <- function(x) { + UseMethod("get_remote_tasks") +} + +#' @export +get_remote_tasks.default <- function(x) { + NULL +} + +#' @export +get_remote_tasks.task <- function(x) { + get_remote_tasks(x$origin) +} + +#' @export +get_remote_tasks.pkg_origin_local <- function(x) { + pkgs <- .remotes()$extra_deps(as.package.remotes(x$source), "remotes") + + lapply(seq_len(NROW(pkgs)), function(i) { + install_task( + pkg_origin_remote(remote = pkgs$remote[[i]]) + ) + }) +} + +#' @export +get_remote_tasks.pkg_origin_remote <- function(x) { + x <- sanitize_pkg_origin_remote(x) + NextMethod() +} + +get_remote_package_source <- function(remote) { + path <- file.path(path_remotes(), hash(remote)) + if (dir.exists(path)) return(path) + dir_create(path) + tmp <- remotes::remote_download(remote, quiet = TRUE) + file.copy( + from = list.files(tmp, full.names = TRUE, recursive = FALSE), + to = path, + recursive = TRUE + ) + path +} + +remotes_permitted <- function() { + options::opt("add_remotes") && requireNamespace("remotes", quietly = TRUE) +} diff --git a/R/reporter.R b/R/reporter.R index d07f954..823d931 100644 --- a/R/reporter.R +++ b/R/reporter.R @@ -1,4 +1,4 @@ -#' Check Design Runner Reporters +#' Check checker Runner Reporters #' #' Reporters are used to configure how output is communicated while running #' a [`checker`]. They range from glossy command-line tools intended for @@ -63,13 +63,13 @@ reporter_default <- function() { #' Reporter Internal Methods #' #' Each of the internal methods for reporters take a reporter, the check -#' design object and a calling environment. +#' checker object and a calling environment. #' #' @param reporter A object produced using [`reporters`]. Each reporter is a #' thin wrapper around an environment with a class name for dispatch. The #' reporter is mutable and captures any necessary state that needs to be #' tracked while reporting. -#' @param design [`checker`] The check design to report as it evaluates. +#' @param checker [`checker`] The check checker to report as it evaluates. #' @param envir `environment` An environment to attach to, to leverage on-exit #' hooks. #' @param sleep `numeric` An interval to pause between reporter steps. @@ -80,32 +80,37 @@ reporter_default <- function() { NULL #' @rdname reporters-internal -report_sleep <- function(reporter, design, sleep) { +report_sleep <- function(reporter, checker, sleep) { UseMethod("report_sleep") } #' @rdname reporters-internal #' @export -report_sleep.default <- function(reporter, design, sleep = 1) { +report_sleep.default <- function(reporter, checker, sleep = 1) { Sys.sleep(sleep) } #' @rdname reporters-internal -report_start_setup <- function(reporter, design, ..., envir = parent.frame()) { +report_start_setup <- function(reporter, checker, ..., envir = parent.frame()) { UseMethod("report_start_setup") } #' @rdname reporters-internal -report_start_checks <- function(reporter, design, ..., envir = parent.frame()) { +report_start_checks <- function(reporter, checker, ..., envir = parent.frame()) { # nolint UseMethod("report_start_checks") } #' @rdname reporters-internal -report_status <- function(reporter, design, envir = parent.frame()) { +report_status <- function(reporter, checker, envir = parent.frame()) { UseMethod("report_status") } #' @rdname reporters-internal -report_finalize <- function(reporter, design) { +report_finalize <- function(reporter, checker) { UseMethod("report_finalize") } + +#' @rdname reporters-internal +report_task <- function(reporter, g, v) { + UseMethod("report_task") +} diff --git a/R/reporter_ansi_tty.R b/R/reporter_ansi_tty.R index 88a1292..a598939 100644 --- a/R/reporter_ansi_tty.R +++ b/R/reporter_ansi_tty.R @@ -1,8 +1,5 @@ -report_task <- function(reporter, g, v) { - UseMethod("report_task") -} - #' @export +#' @method report_task reporter_ansi_tty report_task.reporter_ansi_tty <- function(reporter, g, v) { UseMethod("report_task_ansi_tty", v$task) } @@ -78,7 +75,6 @@ format_status_line_ansi.default <- function( cli::ansi_substring(out, 1, width) } -#' @export reporter_line <- function(label, status, style = NA_character_) { structure( list(label = label, status = status, style = style), @@ -87,7 +83,7 @@ reporter_line <- function(label, status, style = NA_character_) { } #' @export -format.reporter_line <- function(x, width = cli::console_width()) { +format.reporter_line <- function(x, width = cli::console_width(), ...) { rule <- switch(x$style, "h1" = "\u2550", " " @@ -114,7 +110,6 @@ format.reporter_line <- function(x, width = cli::console_width()) { out } -#' @export reporter_cell <- function( content, justify = "left", @@ -135,7 +130,8 @@ format.reporter_cell <- function(x, padding = attr(x, "padding") %||% c(0, 0), justify = attr(x, "justify") %||% "right", width = attr(x, "width") %||% cli::console_width(), - pad = " " + pad = " ", + ... ) { n <- width - sum(padding) - cli::ansi_nchar(x) paste0( @@ -236,7 +232,7 @@ report_task_ansi_tty.check_task <- function(reporter, g, v) { report_sleep.reporter_ansi_tty <- function( reporter, checker, - sleep = default_tty_tick_interval() + sleep = options::opt("tty_tick_interval") ) { Sys.sleep(sleep) } @@ -301,6 +297,7 @@ reporter_ansi_tty_get_label_nchar <- function( report_start_checks.reporter_ansi_tty <- function( reporter, checker, + ..., envir = parent.frame() ) { # store our current console width, used to trigger complete re-draw diff --git a/R/reporter_basic_tty.R b/R/reporter_basic_tty.R index a43b2fa..33fb499 100644 --- a/R/reporter_basic_tty.R +++ b/R/reporter_basic_tty.R @@ -1,11 +1,12 @@ -#' @export +# TODO: Refactor entire reporter + report_initialize.reporter_basic_tty <- function( reporter, - design, + checker, envir = parent.frame() ) { # start with initialized-as-completed tasks - v <- igraph::V(design$graph) + v <- igraph::V(checker$graph) which_done <- v$status == STATUS$done done <- v[which_done]$status names(done) <- v$name[which_done] @@ -18,9 +19,9 @@ report_initialize.reporter_basic_tty <- function( } #' @export -report_status.reporter_basic_tty <- function(reporter, design, envir) { +report_status.reporter_basic_tty <- function(reporter, checker, envir) { cli_theme() - g <- design$graph + g <- checker$graph tasks_names <- names(igraph::V(g)) # skip if queued, but not started or already finished reported_statuses <- sapply(reporter$statuses, `[[`, 1) @@ -94,9 +95,9 @@ report_status.reporter_basic_tty <- function(reporter, design, envir) { } #' @export -report_finalize.reporter_basic_tty <- function(reporter, design) { +report_finalize.reporter_basic_tty <- function(reporter, checker) { cli_theme() - report_status(reporter, design) # report completions of final processes + report_status(reporter, checker) # report completions of final processes time <- format_time(Sys.time() - reporter$time_start) # nolint (used via glue) cli::cli_text("Finished in {.time_taken {time}}") } diff --git a/R/reporter_null.R b/R/reporter_null.R index 2751c20..301bf78 100644 --- a/R/reporter_null.R +++ b/R/reporter_null.R @@ -1,6 +1,3 @@ -#' @export -report_initialize.NULL <- function(...) {} - #' @export report_status.NULL <- function(...) {} diff --git a/R/results.R b/R/results.R index 495d282..05c33f4 100644 --- a/R/results.R +++ b/R/results.R @@ -4,13 +4,9 @@ CHECK_ISSUES_TYPES <- c("notes", "warnings", "errors") #' #' Get R CMD check results #' -#' @param x [`checker`] object. -#' @param error_on character vector indicating whether R error should be thrown -#' when issues are discovered when generating results. "never" means that no -#' errors are thrown. If "issues" then errors are emitted only on issues, -#' whereas "potential issues" stands for error on both issues and potential -#' issues. Users can set the default value via env variable -#' `CHECKED_RESULTS_ERROR_ON`. +#' @param x object which results should be presented. +#' @param checker_obj [`checker`] object. +#' @eval options::as_params("error_on" = "results_error_on") #' @param ... other parameters. #' #' @family results @@ -23,29 +19,24 @@ results <- function(x, ...) { #' @rdname results results.checker <- function( x, - error_on = Sys.getenv("CHECKED_RESULTS_ERROR_ON", c("never", "issues", "potential_issues")[1]), + error_on = options::opt("results_error_on"), ...) { error_on <- match.arg(error_on, c("never", "issues", "potential_issues")) - checks_nodes <- igraph::V(x$graph)[ - igraph::vertex.attributes(x$graph)$type == "check" & igraph::vertex.attributes(x$graph)$status == STATUS$done + + stopifnot( + "checker object does not represnet a completed run" = x$is_done() + ) + + vs <- V(x$graph) + # Find root's of meta nodes + meta_nodes <- vs[is_meta(vs$task)] + root_meta_nodes_idx <- meta_nodes[ + igraph::ego_size(x$graph, nodes = meta_nodes, mode = "in") == 1 ] - checks_classes <- vcapply(checks_nodes$spec, function(x) class(x)[[1]]) - classes <- unique(checks_classes) - res <- lapply(classes, function(x) { - structure( - checks_nodes$spec[checks_classes == x], - class = paste0("list_", x) - ) - }) res <- structure( - lapply(res, function(y, output) { - structure( - results(y, output), - class = paste0("checked_results_", utils::head(class(y[[1]]), 1L)) - ) - }, output = x$output), - names = classes, + lapply(root_meta_nodes_idx, results, checker_obj = x), + names = vs[root_meta_nodes_idx]$name, class = "checked_results" ) @@ -65,68 +56,110 @@ results.checker <- function( } #' @export -`[.checked_results` <- function(x, ...) { - structure(NextMethod(), class = class(x)) +#' @rdname results +results.integer <- function(x, checker_obj, ...) { + results(V(checker_obj$graph)[[x]], checker_obj = checker_obj) } #' @export -results.list_revdep_check_task <- function(x, output, ...) { - name <- vcapply(x, function(y) y$package$name) - revdep <- vcapply(x, `[[`, "revdep") - count <- table(name, revdep) - is_complete_pair <- vlapply(name, function(y) { - identical(unname(count[y, ]), c(1L, 1L)) - }) - - names_complete <- sort(unique(name[is_complete_pair])) +#' @method results igraph.vs +#' @rdname results +results.igraph.vs <- function(x, ...) { + UseMethod("results", structure(0L, class = class(x$task))) +} - new <- lapply(names_complete, function(y) { - x[[which(name == y & revdep == "new")]] - }) +#' @export +#' @rdname results +results.rev_dep_dep_meta_task <- function(x, checker_obj, ...) { + # x is a igraph.vs with rev_dep_dep_meta_task task + nh <- igraph::neighbors(checker_obj$graph, x, mode = "out") + structure( + lapply(nh, results, checker_obj = checker_obj), + names = nh$name, + package = package(x$task), + class = "rev_dep_dep_results" + ) +} - old <- lapply(names_complete, function(y) { - x[[which(name == y & revdep == "old")]] +#' @export +#' @rdname results +results.rev_dep_check_meta_task <- function(x, checker_obj, ...) { + # x is a igraph.vs with rev_dep_dep_meta_task task + checks <- igraph::neighbors(checker_obj$graph, x, mode = "out") + seeds <- vcapply(checks, function(v) { + V(checker_obj$graph)[[v]]$task$seed }) + # seeds are dev and release, sort alphanumerical to make sure dev is always + # at the first index + checks <- checks[order(seeds)] + + results_revdep_check( + dev = checks[[1]]$name, + release = checks[[2]]$name, + output = checker_obj$output + ) +} +#' @export +#' @rdname results +results.local_check_meta_task <- function(x, checker_obj, ...) { + # x is a igraph.vs with rev_dep_dep_meta_task task + nh <- igraph::neighbors(checker_obj$graph, x, mode = "out") structure( - mapply(results, x = new, y = old, output = output, SIMPLIFY = FALSE), - names = names_complete + lapply(nh$name, results_check, output = checker_obj$output), + names = nh$name, + class = "local_check_results" ) } -#' @export -results.revdep_check_task <- function(x, y, output, ...) { - new <- rcmdcheck_from_json(file.path(path_check_output(output, x$alias), "result.json")) - old <- rcmdcheck_from_json(file.path(path_check_output(output, y$alias), "result.json")) +results_revdep_check <- function(dev, release, output = NULL, ...) { + # Make it work either with full path or name of the package + dev_path <- if (is.null(output) || file.exists(dev)) { + dev + } else { + file.path(path_check_output(output, dev), "result.json") + } + + release_path <- if (is.null(output) || file.exists(release)) { + release + } else { + file.path(path_check_output(output, release), "result.json") + } + dev_check <- rcmdcheck_from_json(dev_path) + release_check <- rcmdcheck_from_json(release_path) structure( lapply(CHECK_ISSUES_TYPES, function(i) { - new_i <- structure( - new[[i]], - names = get_issue_header(new[[i]]) + dev_check_i <- structure( + # If no issues identified, object is an empty list instead of + # a character vector. Changing it to empty character for consistency. + if (is.list(dev_check[[i]])) character(0) else dev_check[[i]], + names = get_issue_header(dev_check[[i]]) ) - old_i <- structure( - old[[i]], - names = get_issue_header(old[[i]]) + release_check_i <- structure( + if (is.list(release_check[[i]])) character(0) else release_check[[i]], + names = get_issue_header(release_check[[i]]) ) - matching_headers_idx <- names(new_i) %in% names(old_i) + matching_headers_idx <- names(dev_check_i) %in% names(release_check_i) # Create temporary object with "See for details" path # stripped out as well as all whitespaces. As they will always emit # potential issues due to the path or screen differences - new_i_tmp <- strip_details_from_issue(new_i) - old_i_tmp <- strip_details_from_issue(old_i) - matching_messages_idx <- new_i_tmp %in% old_i_tmp + dev_check_i_tmp <- strip_details_from_issue(dev_check_i) + release_check_i_tmp <- strip_details_from_issue(release_check_i) + matching_messages_idx <- dev_check_i_tmp %in% release_check_i_tmp new_issues <- structure( - unname(new_i[!matching_headers_idx]), + unname(dev_check_i[!matching_headers_idx]), class = "issues" ) - new_potential_issues <- new_i[matching_headers_idx & !matching_messages_idx] + new_potential_issues <- dev_check_i[ + matching_headers_idx & !matching_messages_idx + ] new_potential_issues <- structure( list( new = unname(new_potential_issues), - old = unname(old_i[names(new_potential_issues)]) + old = unname(release_check_i[names(new_potential_issues)]) ), class = "potential_issues" ) @@ -134,73 +167,38 @@ results.revdep_check_task <- function(x, y, output, ...) { list("issues" = new_issues, "potential_issues" = new_potential_issues) }), names = CHECK_ISSUES_TYPES, - package = new$package, - class = "rcmdcheck_diff" + package = dev_check$package, + class = c("rcmdcheck_rev_dep_results", "rcmdcheck_results") ) } -#' @export -results.list_check_task <- function(x, output, ...) { - alias <- vcapply(x, `[[`, "alias") - structure( - lapply(x, results, output = output), - names = alias - ) -} +results_check <- function(x, output, ...) { + # Make it work either with full path or name of the package + x_path <- if (is.null(output) || file.exists(x)) { + x + } else { + file.path(path_check_output(output, x), "result.json") + } -#' @export -results.check_task <- function(x, output, ...) { - json_path <- file.path(path_check_output(output, x$alias), "result.json") - x <- rcmdcheck_from_json(json_path) + x_check <- rcmdcheck_from_json(x_path) structure( lapply(CHECK_ISSUES_TYPES, function(i) { - x_i <- x[[i]] + x_check_i <- x_check[[i]] new_issues <- structure( - unname(x_i), + unname(x_check_i), class = "issues" ) list("issues" = new_issues) }), names = CHECK_ISSUES_TYPES, - package = x$package, - class = "rcmdcheck_diff" + package = x_check$package, + class = c("rcmdcheck_check_results", "rcmdcheck_results") ) } -#' Results to file -#' -#' Write \code{checked_results} object to the text file. When converting results -#' to text, \code{\link[checked]{print.checked_results}} method is used. -#' -#' -#' @param results \code{\link[checked]{results}} object. -#' @param file A connection or character path. -#' @inheritParams print.checked_results -#' -#' @family results -#' @export -results_to_file <- function(results, file, keep = "all", ...) { - text <- c() - for (i in seq_along(results)) { - df <- results_to_df(results[[i]], issues_type = keep) - if (keep == "all" || any(rowSums(df) > 0)) { - text <- c( - text, - utils::capture.output(print(results[i], keep = keep)) - ) - } - } - - if (!any(nzchar(text))) { - text <- "No issues identified." - } - - writeLines(text, file) -} - results_to_df <- function(results, ...) { if (length(results) == 0) { data.frame( @@ -219,6 +217,19 @@ results_to_df <- function(results, ...) { } } +filter_results <- function(x, keep, ...) { + keep <- match.arg(keep, c("all", "issues", "potential_issues")) + + if (keep != "all") { + df <- results_to_df(x, issues_type = keep) + issues <- rowSums(df) != 0 + x[issues] + } else { + x + } + +} + count <- function(d, ...) { UseMethod("count") } @@ -238,59 +249,38 @@ count.potential_issues <- function(d, issues_type = "potential_issues", ...) { if (issues_type == "issues") 0 else length(d$new) } -#' @export -summary.checker <- function(object, ...) { - summary(results(object), ...) -} - -#' @export -summary.checked_results <- function(object, ...) { - lapply(object, summary, ...) -} - -#' @export -summary.checked_results_revdep_check_task <- function(object, ...) { - summary.checked_results_check_task(object, ...) -} - -#' @export -summary.checked_results_check_task <- function(object, ...) { - results_to_df(object, ...) -} - #' Print checked results #' #' @param x an object to be printed. -#' @param keep character vector indicating which packages should be included -#' in the results. "all" means that all packages are kept. If "issues" then -#' only packages with issues identified, whereas "potential_issues" stands for -#' keeping packages with both "issues" and "potential_issues". Users can set -#' the default value via env variable \code{CHECKED_RESULTS_KEEP}. +#' @eval options::as_params("keep" = "results_keep") +#' @param name character name of the `rev_dep_dep` package #' @param ... other parameters. #' #' @family results #' @export print.checked_results <- function(x, ...) { for (i in seq_along(x)) { - cat("#", tools::toTitleCase(strsplit(names(x)[i], "_")[[1]]), "\n\n") - print(x[[i]], ...) - cat("\n") + print(x[[i]], ..., name = names(x)[[i]]) + cat("\n\n\n") } invisible(x) } #' @name print.checked_results #' @export -print.checked_results_check_task <- function( - x, - keep = Sys.getenv("CHECKED_RESULTS_KEEP", c("all", "issues", "potential_issues")[1]), - ...) { - keep <- match.arg(keep, c("all", "issues", "potential_issues")) - if (keep != "all") { - df <- results_to_df(x, issues_type = keep) - issues <- rowSums(df) != 0 - x <- x[issues] - } +print.rev_dep_dep_results <- function( + x, + ..., + name = NULL, + keep = options::opt("results_keep") +) { + cat(sprintf( + "# %s reverse dependency check results (%s) \n\n", + attr(x, "package"), + name + )) + + x <- filter_results(x, keep = keep) for (i in seq_along(x)) { print(x[[i]], ...) @@ -301,8 +291,24 @@ print.checked_results_check_task <- function( #' @name print.checked_results #' @export -print.checked_results_revdep_check_task <- function(x, ...) { - print.checked_results_check_task(x, ...) +print.local_check_results <- function( + x, + ..., + name = NULL, + keep = options::opt("results_keep") +) { + cat(sprintf( + "# Local check results (%s) \n\n", + name + )) + + x <- filter_results(x, keep = keep) + + for (i in seq_along(x)) { + print(x[[i]], ...) + cat("\n") + } + invisible(x) } get_issue_header <- function(x) { @@ -341,8 +347,19 @@ rcmdcheck_from_json <- function(file) { } #' @export -print.rcmdcheck_diff <- function(x, ...) { +print.rcmdcheck_rev_dep_results <- function(x, ...) { cat(sprintf("%s package R CMD check diff \n", attr(x, "package"))) + NextMethod() +} + +#' @export +print.rcmdcheck_check_results <- function(x, ...) { + cat(sprintf("%s package R CMD check \n", attr(x, "package"))) + NextMethod() +} + +#' @export +print.rcmdcheck_results <- function(x, ...) { for (i in CHECK_ISSUES_TYPES) { status <- if (length(x[[i]]$issues) > 0) { sprintf("NEW ISSUES [%s]", length(x[[i]]$issues)) @@ -381,10 +398,22 @@ print.potential_issues <- function(x, ...) { } strip_details_from_issue <- function(x) { - x <- gsub("See(.*?)for details", "See for details", "", x) - gsub("[[:space:]]", "", x) + x <- gsub( + x = x, + pattern = "See(.*?)for details", + replacement = "See for details" + ) + gsub( + x = x, + pattern = "[[:space:]]", + replacement = "" + ) } collapse_new_lines <- function(x) { - gsub("(\\n\\s*){2,}", "\n\n", x) + gsub( + x = x, + pattern = "(\\n\\s*){2,}", + replacement = "\n\n", + ) } diff --git a/R/run.R b/R/run.R index 5401934..c1f31bd 100644 --- a/R/run.R +++ b/R/run.R @@ -5,7 +5,7 @@ #' plan is generated from the source code path. Otherwise a plan can be #' built separately and executed using [`run()`]. #' -#' @param checks `character` or `checker` If a `character` value is +#' @param checker `character` or `checker` If a `character` value is #' provided, it is first coerced into a `checker` using #' [`new_rev_dep_checker()`]. #' @param ... Additional arguments passed to [`new_rev_dep_checker()`] diff --git a/R/task-formatting.R b/R/task-formatting.R index bed6b78..50d9125 100644 --- a/R/task-formatting.R +++ b/R/task-formatting.R @@ -3,6 +3,11 @@ format.task <- function(x, ..., indent = 0L) { fmt(task = x, "{action} {package} {version} from {source}", ...) } +#' @export +format.local_check_meta_task <- function(x, ..., indent = 0L) { + fmt(task = x, "{action}", ...) +} + format_task_type <- function(x, ...) { UseMethod("format_task_type") } @@ -22,7 +27,10 @@ format_task_type.rev_dep_check_meta_task <- function(x, ..., g = NULL) { fmt(task = x, "meta revdep {.pkg {x$revdep}} of") } - +#' @export +format_task_type.local_check_meta_task <- function(x, ...) { + "meta checks" +} format_task_name <- function(x, ...) { UseMethod("format_task_name") diff --git a/R/task.R b/R/task.R index 668a634..67f2e3b 100644 --- a/R/task.R +++ b/R/task.R @@ -6,10 +6,8 @@ #' Tasks can be nested, representing either a singular task, or a set of #' related tasks. #' -#' @param alias task alias which also serves as unique identifier of the task. -#' @param package \code{\link[checked]{package}} object -#' @param tasks Optional additional tasks that are pre-requisites for running -#' this task. +#' @param ... parameters passed to downstream constructors. +#' @param .subclass Additional subclasses. #' #' @family tasks #' @export @@ -22,17 +20,20 @@ task <- function(..., .subclass = NULL) { #' Meta tasks are tasks which are not intended to perform computation. They #' exist simply to provide relationships among computational tasks. #' +#' @param ... Objects passed to specified class functions +#' @param .subclass character name of the subclass. It will be appended with +#' "_meta" suffix. meta_task <- function(..., .subclass = NULL) { task(..., .subclass = c(sprintf("%s_meta", .subclass), "meta")) } -make_unique_task <- function(task, seed = runif(1)) { +make_unique_task <- function(task, seed = stats::runif(1)) { task$seed <- seed task } -#' @family tasks #' @export +#' @rdname lib lib.task <- function(x, ...) { character(0L) } @@ -45,7 +46,7 @@ print.task <- function(x, ...) { #' Create a task to install a package and dependencies #' -#' @param ... Additional parameters passed to [`task()`] +#' @param origin [`pkg_origin()`] object. #' @param lib Any object that can be passed to [`lib()`] to generate a library #' path. #' @inheritParams utils::install.packages @@ -70,8 +71,9 @@ install_task <- function( } #' @export +#' @rdname lib lib.install_task <- function(x, ...) { - lib(x$lib, ...) + lib(x$lib, dir_hash = hash(x$origin, n = 8), name = package(x), ...) } is_type <- function(x, type) { @@ -79,7 +81,9 @@ is_type <- function(x, type) { } #' @export -is_type.default <- inherits +is_type.default <- function(x, type) { + inherits(x, type) +} #' @export is_type.list <- function(x, type) { @@ -130,6 +134,7 @@ check_task <- function(build_args = NULL, args = NULL, env = NULL, ...) { } #' @export +#' @rdname lib lib.check_task <- function(x, ...) { character(0L) # no additional libraries needed for checking } @@ -138,113 +143,6 @@ is_check_task <- function(x) { inherits(x, "check_task") } -#' Create a task to run reverse dependency checks -#' -#' @param revdep character indicating whether the task specification describes -#' check associated with the development (new) or release (old) version of the -#' for which reverse dependency check is run. -#' @param ... Additional parameters passed to [`task()`] -#' -#' @family tasks -#' @export -revdep_check_task <- function(revdep, ...) { - task <- check_task(...) - task["revdep"] <- list(revdep) - class(task) <- c("revdep_check_task", class(task)) - task -} - -# TODO: -# Convert plan to graph -# -# This can probably be avoided if we were to build a task graph from -# the start. Plans may be better represented as declarative graphs, which -# are then hydrated into imparative graphs. Then the hierarchical -# relationships are already encoded in the graph and need not be -# rediscovered by building a dependency graph post-hoc. -# -as_desc <- function(x, ...) { - UseMethod("as_desc") -} - -#' @export -as_desc.default <- function(x, ...) { - NULL -} - -#' @export -as_desc.subtasks_task <- function(x, ...) { - descs <- list() - length(descs) <- length(x$tasks) - - for (i in seq_along(x$tasks)) { - descs[[i]] <- as_desc(x$tasks[[i]], ...) - } - - descs <- bind_descs(descs) - - # if this subtask is also a task of itself, add to descriptions collection - # after substituting aliased package names in dependencies - task_desc <- NextMethod() - if (!is.null(task_desc)) { - descs <- bind_descs(list(task_desc, descs)) - descs <- sub_desc_aliases(descs) - } - - descs -} - -#' @export -as_desc.install_task <- function(x, ...) { - cbind(as_desc(x$origin), Task = hash(x)) -} - -#' @export -as_desc.check_task <- function(x, ...) { - cbind(as_desc(x$origin), Task = hash(x)) -} - -#' @export -as_desc.character <- function(x) { - desc <- read.dcf(x) - read.dcf(x, fields = unique(c(colnames(desc), names(DEP)))) -} - -#' @export -as_desc.pkg_origin_local <- function(x) { - desc <- as_desc(file.path(x$source, "DESCRIPTION")) - - # update the Package field, replacing actual name with an alias - desc <- cbind(desc, Alias = x$package) - rownames(desc) <- desc[, "Package"] <- hash(x) - - desc -} - -#' @export -as_desc.pkg_origin_repo <- function(x) { - ap <- available_packages(repos = x$repos) - ap[x$package, , drop = FALSE] -} - -flatten <- function(x) { - UseMethod("flatten") -} - -#' @export -flatten.default <- function(x) { - list(x) -} - -#' @export -flatten.subtasks_task <- function(x) { - unlist(recursive = FALSE, c( - list(list(x)), - lapply(x$tasks, function(xi) flatten(xi)) - )) -} - - package <- function(x) { UseMethod("package") } @@ -255,12 +153,7 @@ package.default <- function(x) { } #' @export -package.check_task <- function(x) { - package(x$origin) -} - -#' @export -package.install_task <- function(x) { +package.task <- function(x) { package(x$origin) } diff --git a/R/task_graph.R b/R/task_graph.R index fb40849..8388429 100644 --- a/R/task_graph.R +++ b/R/task_graph.R @@ -15,12 +15,13 @@ #' @param repos `repos`, as expected by [`tools::package_dependencies()`] to #' determine package relationships. #' @param ... params passed to helper methods. -#' @return A `data.frame` that can be used to build [`igraph`] edges. +#' @return A `data.frame` that can be used to build +#' [`igraph::make_graph`] edges. #' #' @examples #' \dontrun{ # # requires that source code directory is for a package with revdeps -#' task_graph_create(plan_rev_dep_checks(".")) +#' task_graph(plan_rev_dep_checks(".")) #' } #' @keywords internal #' @@ -32,6 +33,11 @@ task_graph <- function(x, repos = getOption("repos"), ...) { #' @export task_graph.task <- function(x, repos = getOption("repos"), ...) { df <- pkg_deps(x$origin, repos = repos, dependencies = TRUE) + # Distinguish direct dependencies of the package form possible indirect + # in the same data.frame which could come from suggested loops. This ensures + # there is a separate node for the root task. + df$package[df$depth == "direct"] <- + paste(df$package[df$depth == "direct"], "root", sep = "-") colmap <- c("package" = "from", "name" = "to") rename <- match(names(df), names(colmap)) to_rename <- !is.na(rename) @@ -44,23 +50,15 @@ task_graph.task <- function(x, repos = getOption("repos"), ...) { V(g_dep)$task <- lapply( V(g_dep)$name, function(p) { - origin <- try_pkg_origin_repo(package = p, repos = repos) - install_task(origin = origin) + if (endsWith(p, "-root")) { + x + } else { + origin <- try_pkg_origin_repo(package = p, repos = repos) + install_task(origin = origin) + } } ) - # Add the root node - g_dep <- igraph::add_vertices( - g_dep, 1, attr = list(name = "root-vertex", task = list(x)) - ) - - g_dep <- copy_edges_from_vertex( - g_dep, - v_to = "root-vertex", - v_from = package(x), - mode = "out" - ) - V(g_dep)$name <- vcapply(V(g_dep)$task, as_vertex_name) g_dep @@ -94,9 +92,8 @@ task_graph.task_graph <- function(x, repos = getOption("repos"), ...) { is_na <- is.na(E(subtree)$type) E(subtree)$type[is_na] <- DEP$Depends - subtree + deduplicate_task_graph(subtree) }) - # then merge all the full check task task trees into a single graph g <- graph_dedup_attrs(igraph::union(x, check_task_neighborhoods)) @@ -106,6 +103,7 @@ task_graph.task_graph <- function(x, repos = getOption("repos"), ...) { g <- task_graph_sort(g) + # Restore the original (defined by the plan) order of primary tasks n_g <- length(V(g)) x_ids <- as.numeric(V(g)[names(V(x))]) g_ids <- numeric(n_g) @@ -113,32 +111,42 @@ task_graph.task_graph <- function(x, repos = getOption("repos"), ...) { g_ids[g_ids == 0] <- setdiff(seq_along(V(g)), g_ids) g <- igraph::permute(g, g_ids) - class(g) <- c("task_graph", class(g)) - g + task_graph_class(g) } -dep_edges <- function(edges, dependencies = TRUE) { - edges[edges$type %in% dependencies] +task_graph_class <- function(g) { + class(g) <- c("task_graph", class(g)) + g } -lib_node_tasks <- function(g, nodes) { - install_nodes <- igraph::adjacent_vertices(g, nodes, mode = "out") - lapply(install_nodes, function(nodes) { - nodes$task[is_install(nodes$task)] - }) +deduplicate_task_graph <- function(g) { + vs <- V(g) + for (i in vs) { + # Task graph is allowed to have multi-edges in which case neighbors + # would multiply the same nodes. Therefore we call unique. + children <- unique(igraph::neighbors(g, i, "out")) + children_names <- vcapply(children$task, package) + duplicated_names <- children_names[duplicated(children_names)] + for (p in duplicated_names) { + duplicated_nodes <- children[children_names == p] + g <- igraph::delete_edges( + g, + # Always keep lowest ID node + paste(vs$name[[i]], duplicated_nodes[-1]$name, sep = "|") + ) + } + } + isolated <- which(igraph::degree(g) == 0) + igraph::delete_vertices(g, isolated) } -lib_node_pkgs <- function(g, nodes) { - install_nodes <- igraph::adjacent_vertices(g, nodes, mode = "out") - lapply(install_nodes, function(nodes) { - tasks <- nodes$task[is_install(nodes$task)] - vcapply(tasks, function(task) task$origin$package) - }) +dep_edges <- function(edges, dependencies = TRUE) { + edges[edges$type %in% dependencies] } #' Find Task Neighborhood #' -#' @param g A task graph, as produced with [task_graph_create()] +#' @param g A task graph, as produced with [task_graph()] #' @param nodes Names or nodes objects of packages whose neighborhoods #' should be calculated. #' @@ -213,16 +221,15 @@ task_graph_sort <- function(g) { #' #' @details #' There are helpers defined for particular use cases that strictly rely on the -#' [`task_graph_which_satisfied()`], they are: +#' [`task_graph_which_ready()`], they are: #' -#' * `task_graph_which_satisfied_strong()` - List vertices whose strong +#' * `task_graph_update_check_ready()` - Updates check vertices whose all #' dependencies are satisfied. -#' * `task_graph_which_check_satisfied()` - List root vertices whose all +#' * `task_graph_update_install_ready()` - Update install vertices whose all #' dependencies are satisfied. -#' * `task_graph_which_install_satisfied()` - List install vertices whose -#' dependencies are all satisfied +#' * `task_graph_which_ready()` - List vertices whose wit ready status. #' -#' @param g A dependency graph, as produced with [task_graph_create()]. +#' @param g A dependency graph, as produced with [task_graph()]. #' @param v Names or nodes objects of packages whose satisfiability should be #' checked. #' @param dependencies Which dependencies types should be met for a node to be @@ -381,6 +388,7 @@ plot.task_graph <- function(x, ..., interactive = FALSE) { "pkg_origin_base" = "lightgray", "pkg_origin_unknown" = "red", "pkg_origin_local" = "blue", + "pkg_origin_remote" = "orange", "red" ) diff --git a/R/utils-cli.R b/R/utils-cli.R index d4b803e..d8dd458 100644 --- a/R/utils-cli.R +++ b/R/utils-cli.R @@ -1,9 +1,13 @@ -#' task formatter bindings +#' Task formatter bindings #' -#' This bit of code is intended for use with [`cli_task()`], and allows for us +#' This bit of code is intended for use with [`fmt()`], and allows for us #' to layer symbol bindings on top of the environment used for string #' interpolation which provide syntactic sugar for common formatting components. #' +#' @param g task_graph object. +#' @param nodes graph nodes to format. +#' @param task task to format. +#' @param tasks currently unused. task_formats <- function( g = NULL, nodes = V(g), @@ -34,6 +38,7 @@ task_formats <- function( makeActiveBinding("source.type", env = environment(), function() { src_type <- class(task$origin)[[1]] src_type_str <- switch(src_type, + "pkg_origin_remote" = source, "pkg_origin_local" = "local", "pkg_origin_repo" = source, "remote" @@ -84,15 +89,24 @@ task_formats <- function( #' Provided a task, allows for use of a handful of shorthand symbols which will #' use the task as a context for formatting task fields. #' +#' @param ... params passed to [`cli::format_inline`]. +#' @param .envir output environment. +#' @param ansi logical whether ansi should be stripped. +#' @inheritParams task_formats +#' #' @examples #' task <- install_task(origin = pkg_origin( #' package = "pkg", #' version = package_version("1.2.3"), -#' source = "../../Programming/options" +#' source = system.file( +#' "example_packages", +#' "exampleGood", +#' package = "checked" +#' ) #' )) #' -#' fmt(task = task, "{action} {package} ({version}) from {source}") -#' +#' # Examples for unexported functions are not supported +#' # fmt(task = task, "{action} {package} ({version}) from {source}") fmt <- function( ..., g, diff --git a/R/utils-deps.R b/R/utils-deps.R index 06caf76..7881450 100644 --- a/R/utils-deps.R +++ b/R/utils-deps.R @@ -4,7 +4,7 @@ #' and [`pkgdepends::as_pkg_dependencies()`], following #' [`pkgdepends::as_pkg_dependencies()`] return type structure of a list #' including `$direct` and `$indirect` dependency types. Reimplemented to -#' avoid dependence on [`pkgdepends`] compilation requirements. +#' avoid dependence on `pkgdepends` compilation requirements. #' #' @param x A `logical` scalar, `character` string of `"all"`, `"most"`, #' `"hard"` or `"soft"`, `NA` or a vector of dependency types. @@ -56,10 +56,15 @@ as_pkg_dependencies <- function(x) { #' of recording the dependency type and relationships throughout the #' dependency tree. #' +#' @inheritParams tools::package_dependencies +#' @param dependencies A `logical` scalar, `character` string of +#' `"all"`, `"most"`, `"hard"` or `"soft"`, `NA` or a vector of dependency +#' types compatible with [`as_pkg_dependencies()`] function. +#' pkg_dependencies <- function( packages, dependencies = TRUE, - db = available.packages(), + db = available_packages(), verbose = FALSE ) { dependencies <- as_pkg_dependencies(dependencies) diff --git a/R/utils-igraph.R b/R/utils-igraph.R index 377ab8b..40ac815 100644 --- a/R/utils-igraph.R +++ b/R/utils-igraph.R @@ -6,21 +6,39 @@ vertex_df <- function(name, ...) { vertices } -sequence_graph <- function( +new_graph <- function( ..., vertex_attrs = list(...), edge_attrs = list(), name_by = vertex_attrs[[1]], - name = vcapply(name_by, as_vertex_name) + name = vcapply(name_by, as_vertex_name), + type = c("sequence", "star") ) { + type <- match.arg(type) vertices <- vertex_df(name = name, ...) + edges_orientation <- switch( + type, + sequence = -1L, + star = 1 + ) edges <- data.frame( - from = utils::head(vertices$name, -1L), + from = utils::head(vertices$name, edges_orientation), to = utils::tail(vertices$name, -1L) ) + if (length(edge_attrs) > 0) { + edges <- cbind(edges, edge_attrs) + } igraph::graph_from_data_frame(edges, vertices = vertices) } +sequence_graph <- function(...) { + new_graph(..., type = "sequence") +} + +star_graph <- function(...) { + new_graph(..., type = "star") +} + #' Deduplicate attributes #' #' Primarily intended for cleaning up the result of an [`igraph::union()`], @@ -28,6 +46,7 @@ sequence_graph <- function( #' multiple graphs. Searches for suffixes and consolidates attributes, #' taking the attribute from the first non-NA value observed. #' +#' @param g task_graph object graph_dedup_attrs <- function(g) { # pattern appended to duplicated attributes re <- "_\\d+$" diff --git a/R/utils-paths.R b/R/utils-paths.R index 4513aa2..586b82c 100644 --- a/R/utils-paths.R +++ b/R/utils-paths.R @@ -6,7 +6,6 @@ cli_type <- function(types, x) { structure(x, class = paste0("cli_", types)) } -#' @export format_simplify_path <- function(x, ..., full.path = FALSE) { if (full.path) { return(normalizePath(x, mustWork = FALSE)) @@ -15,7 +14,10 @@ format_simplify_path <- function(x, ..., full.path = FALSE) { wp <- path_parts(getwd()) xp <- path_parts(normalizePath(x, mustWork = FALSE)) min_len <- min(length(wp), length(xp)) - first_diff <- Position(identity, head(wp, min_len) != head(xp, min_len)) + first_diff <- Position( + identity, + utils::head(wp, min_len) != utils::head(xp, min_len) + ) if (is.na(first_diff)) { parts <- utils::tail(xp, -min_len) @@ -82,6 +84,11 @@ path_sources <- function() { normalizePath(p) } +path_remotes <- function() { + dir_create(p <- file.path(tempdir(), "checked_remotes")) + normalizePath(p) +} + path_check_output <- function(path, check) { dir_create(p <- file.path(path, "checks")) normalizePath(file.path(p, check), mustWork = FALSE) diff --git a/R/utils-pkg-source.R b/R/utils-pkg-source.R index 12781a3..c76044a 100644 --- a/R/utils-pkg-source.R +++ b/R/utils-pkg-source.R @@ -133,7 +133,7 @@ fetch_package_source <- function(archive_url, destdir) { get_package_source <- function(package, repos, db = NULL, destdir = NULL) { if (is.null(db)) { - db <- utils::available.packages(repos = repos) + db <- available_packages(repos = repos) } pkg <- db[package, ] archive_url <- sprintf( diff --git a/R/utils-remotes.R b/R/utils-remotes.R new file mode 100644 index 0000000..641376d --- /dev/null +++ b/R/utils-remotes.R @@ -0,0 +1,34 @@ +#' A simple alternative to `devtools::as.package` +#' +#' Functionally identical to `devtools`' `as.package`, but without interactive +#' options for package creation. +#' +#' Function required for communicating with the `remotes` package interface +#' +#' @note Code inspired by `devtools` `load_pkg_description` with very minor +#' edits to further reduce `devtools` dependencies. +#' +#' @param x A package object to coerce +#' +as.package.remotes <- function(x) { + if (inherits(x, "package")) { + return(x) + } + info <- read.dcf(file.path(x, "DESCRIPTION"))[1L, ] + Encoding(info) <- "UTF-8" + desc <- as.list(info) + names(desc) <- tolower(names(desc)) + desc$path <- x + structure(desc, class = "package") +} + + +.remotes <- function() { + if (requireNamespace("remotes", quietly = TRUE)) { + as.list(getNamespace("remotes"), all.names = TRUE)[c( + "extra_deps" + )] + } else { + "remotes package not available" + } +} diff --git a/R/utils.R b/R/utils.R index 81b7733..16c06b4 100644 --- a/R/utils.R +++ b/R/utils.R @@ -18,6 +18,14 @@ as_vertex_name.task <- function(x, ...) { ) } +#' @export +as_vertex_name.local_check_meta_task <- function(x, ...) { + paste0( + hash(x, ...), + gsub("\\s+", "-", fmt(task = x, "-{action}", ansi = FALSE)) + ) +} + hash <- function(x, n = 12) { substring(cli::hash_obj_sha256(x), 1, n) } @@ -73,3 +81,14 @@ vcapply <- function(...) vapply(..., FUN.VALUE = character(1L)) vlapply <- function(...) vapply(..., FUN.VALUE = logical(1L)) viapply <- function(...) vapply(..., FUN.VALUE = integer(1L)) vnapply <- function(...) vapply(..., FUN.VALUE = numeric(1L)) + +suppressWarningsRegex <- function(expr, regex, ...) { + withCallingHandlers( + expr, + warning = function(w) { + if (grepl(pattern = regex, x = conditionMessage(w), ...)) { + invokeRestart("muffleWarning") + } + } + ) +} diff --git a/_pkgdown.yml b/_pkgdown.yml index fb54940..d74d436 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -28,3 +28,7 @@ reference: - title: Reporters contents: - has_concept("reporters") + + - title: Documentation + contents: + - has_concept("documentation") diff --git a/man/as.package.remotes.Rd b/man/as.package.remotes.Rd new file mode 100644 index 0000000..c774495 --- /dev/null +++ b/man/as.package.remotes.Rd @@ -0,0 +1,22 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils-remotes.R +\name{as.package.remotes} +\alias{as.package.remotes} +\title{A simple alternative to \code{devtools::as.package}} +\usage{ +as.package.remotes(x) +} +\arguments{ +\item{x}{A package object to coerce} +} +\description{ +Functionally identical to \code{devtools}' \code{as.package}, but without interactive +options for package creation. +} +\details{ +Function required for communicating with the \code{remotes} package interface +} +\note{ +Code inspired by \code{devtools} \code{load_pkg_description} with very minor +edits to further reduce \code{devtools} dependencies. +} diff --git a/man/as_pkg_dependencies.Rd b/man/as_pkg_dependencies.Rd index b689413..ebd4f13 100644 --- a/man/as_pkg_dependencies.Rd +++ b/man/as_pkg_dependencies.Rd @@ -15,7 +15,7 @@ Implements conventions established by both \code{\link[tools:package_dependencie and \code{\link[pkgdepends:as_pkg_dependencies]{pkgdepends::as_pkg_dependencies()}}, following \code{\link[pkgdepends:as_pkg_dependencies]{pkgdepends::as_pkg_dependencies()}} return type structure of a list including \verb{$direct} and \verb{$indirect} dependency types. Reimplemented to -avoid dependence on \code{\link{pkgdepends}} compilation requirements. +avoid dependence on \code{pkgdepends} compilation requirements. } \note{ locally defined and bespoke dispatch system to avoid registering diff --git a/man/check_task.Rd b/man/check_task.Rd index 688f808..128f112 100644 --- a/man/check_task.Rd +++ b/man/check_task.Rd @@ -27,7 +27,7 @@ set in the check process.} \item{...}{ Arguments passed on to \code{\link[=task]{task}} \describe{ - \item{\code{}}{} + \item{\code{.subclass}}{Additional subclasses.} }} } \description{ @@ -36,7 +36,6 @@ Create a task to run \verb{R CMD check} \seealso{ Other tasks: \code{\link{install_task}()}, -\code{\link{revdep_check_task}()}, \code{\link{task}()} } \concept{tasks} diff --git a/man/checker.Rd b/man/checker.Rd index 9eb2578..f874878 100644 --- a/man/checker.Rd +++ b/man/checker.Rd @@ -40,7 +40,7 @@ Other checks: \item{\code{graph}}{(\code{igraph::igraph()})\cr A dependency graph, storing information about which dependencies are required prior to execution of each check task. -Created with \code{\link[=task_graph_create]{task_graph_create()}}} +Created with \code{\link[=task_graph]{task_graph()}}} \item{\code{plan}}{(\code{data.frame()})\cr Checks task \code{data.frame} which is the source of all the checks.} @@ -79,7 +79,7 @@ and installation order are embedded. output = file.path(tempdir(), paste(packageName(), Sys.Date(), sep = "-")), lib.loc = .libPaths(), repos = getOption("repos"), - restore = TRUE, + restore = options::opt("restore"), ... )}\if{html}{\out{
}} } diff --git a/man/fmt.Rd b/man/fmt.Rd index d593a92..70cc961 100644 --- a/man/fmt.Rd +++ b/man/fmt.Rd @@ -6,17 +6,20 @@ \usage{ fmt(..., g, nodes, task = NULL, .envir = parent.frame(), ansi = TRUE) } +\arguments{ +\item{...}{params passed to \code{\link[cli:format_inline]{cli::format_inline}}.} + +\item{g}{task_graph object.} + +\item{nodes}{graph nodes to format.} + +\item{task}{task to format.} + +\item{.envir}{output environment.} + +\item{ansi}{logical whether ansi should be stripped.} +} \description{ Provided a task, allows for use of a handful of shorthand symbols which will use the task as a context for formatting task fields. } -\examples{ -task <- install_task(origin = pkg_origin( - package = "pkg", - version = package_version("1.2.3"), - source = "../../Programming/options" -)) - -fmt(task = task, "{action} {package} ({version}) from {source}") - -} diff --git a/man/graph_dedup_attrs.Rd b/man/graph_dedup_attrs.Rd index fad46da..9518308 100644 --- a/man/graph_dedup_attrs.Rd +++ b/man/graph_dedup_attrs.Rd @@ -6,6 +6,9 @@ \usage{ graph_dedup_attrs(g) } +\arguments{ +\item{g}{task_graph object} +} \description{ Primarily intended for cleaning up the result of an \code{\link[igraph:union]{igraph::union()}}, which adds duplicated attributes when attributes of the same name exist in diff --git a/man/install_task.Rd b/man/install_task.Rd index c75b45d..5747ab0 100644 --- a/man/install_task.Rd +++ b/man/install_task.Rd @@ -13,6 +13,8 @@ install_task( ) } \arguments{ +\item{origin}{\code{\link[=pkg_origin]{pkg_origin()}} object.} + \item{type}{character, indicating the type of package to download and install. Will be \code{"source"} except on Windows and some macOS builds: see the section on \sQuote{Binary packages} for those. @@ -31,7 +33,12 @@ install_task( \item{lib}{Any object that can be passed to \code{\link[=lib]{lib()}} to generate a library path.} -\item{...}{Additional parameters passed to \code{\link[=task]{task()}}} +\item{...}{ + further arguments to be passed to \code{\link[utils]{download.file}}, + \code{\link[utils]{available.packages}}, or to the functions for binary + installs on macOS and Windows (which accept an argument \code{"lock"}: + see the section on \sQuote{Locking}). + } } \description{ Create a task to install a package and dependencies @@ -39,7 +46,6 @@ Create a task to install a package and dependencies \seealso{ Other tasks: \code{\link{check_task}()}, -\code{\link{revdep_check_task}()}, \code{\link{task}()} } \concept{tasks} diff --git a/man/lib.NULL.Rd b/man/lib.NULL.Rd deleted file mode 100644 index e5e3406..0000000 --- a/man/lib.NULL.Rd +++ /dev/null @@ -1,11 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/lib.R -\name{lib.NULL} -\alias{lib.NULL} -\title{Null Library Path} -\usage{ -\method{lib}{`NULL`}(x, ..., lib.loc = c()) -} -\description{ -Null Library Path -} diff --git a/man/lib.Rd b/man/lib.Rd index 13d9660..8797a13 100644 --- a/man/lib.Rd +++ b/man/lib.Rd @@ -1,16 +1,50 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/lib.R +% Please edit documentation in R/lib.R, R/task.R \name{lib} \alias{lib} +\alias{lib.NULL} +\alias{lib.character} +\alias{lib.lib_path_isolated} +\alias{lib.lib_path_default} +\alias{lib.task} +\alias{lib.install_task} +\alias{lib.check_task} \title{Get Library Location} \usage{ -lib(x, ..., lib.loc = c()) +lib(x, ...) + +\method{lib}{`NULL`}(x, ...) + +\method{lib}{character}(x, ...) + +\method{lib}{lib_path_isolated}( + x, + ..., + lib.root = tempdir(), + dir_hash = hash(Sys.time(), n = 8), + name = "" +) + +\method{lib}{lib_path_default}(x, ..., lib.loc = .libPaths()) + +\method{lib}{task}(x, ...) + +\method{lib}{install_task}(x, ...) + +\method{lib}{check_task}(x, ...) } \arguments{ \item{x}{An object describing a library location} -\item{lib.loc}{A set of library locations, used as defaults for objects -that may make use of them.} +\item{...}{additional parameters passed to methods} + +\item{lib.root}{A root directory for the isolated library.} + +\item{dir_hash}{unique identifier of the isolated library} + +\item{name}{human-readable subname of the isolated library} + +\item{lib.loc}{Library paths, defaulting to \code{\link[=.libPaths]{.libPaths()}}.} } \description{ Get Library Location diff --git a/man/lib.character.Rd b/man/lib.character.Rd deleted file mode 100644 index b0744a0..0000000 --- a/man/lib.character.Rd +++ /dev/null @@ -1,16 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/lib.R -\name{lib.character} -\alias{lib.character} -\title{Produce a Library from a Path} -\usage{ -\method{lib}{character}(x, ..., lib.loc = c()) -} -\arguments{ -\item{x}{A \code{character} object} - -\item{..., lib.loc}{Additional arguments unused} -} -\description{ -Produce a Library from a Path -} diff --git a/man/lib.lib_path_default.Rd b/man/lib.lib_path_default.Rd deleted file mode 100644 index ba5e4f4..0000000 --- a/man/lib.lib_path_default.Rd +++ /dev/null @@ -1,18 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/lib.R -\name{lib.lib_path_default} -\alias{lib.lib_path_default} -\title{Produce a Default Library Path} -\usage{ -\method{lib}{lib_path_default}(x, ..., lib.loc = c()) -} -\arguments{ -\item{x}{A \code{lib_path_default} object.} - -\item{...}{Additional arguments unused} - -\item{lib.loc}{Library paths, defaulting to \code{\link[=.libPaths]{.libPaths()}}.} -} -\description{ -Produce a Default Library Path -} diff --git a/man/lib.lib_path_isolated.Rd b/man/lib.lib_path_isolated.Rd deleted file mode 100644 index e253a4a..0000000 --- a/man/lib.lib_path_isolated.Rd +++ /dev/null @@ -1,20 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/lib.R -\name{lib.lib_path_isolated} -\alias{lib.lib_path_isolated} -\title{Produce an Isolated Library Path} -\usage{ -\method{lib}{lib_path_isolated}(x, lib.root = tempdir(), ..., lib.loc = c()) -} -\arguments{ -\item{x}{A \code{lib_path_isolated} object.} - -\item{lib.root}{A root directory for the isolated library.} - -\item{...}{Additional arguments unused} - -\item{name}{A name for the library, defaults to a random hash.} -} -\description{ -Produce an Isolated Library Path -} diff --git a/man/lib_path.Rd b/man/lib_path.Rd index 0a42126..b5975e3 100644 --- a/man/lib_path.Rd +++ b/man/lib_path.Rd @@ -2,16 +2,26 @@ % Please edit documentation in R/lib.R \name{lib_path} \alias{lib_path} +\alias{lib_path_default} +\alias{lib_path_isolated} \title{Make a Library Location} \usage{ lib_path(x, ..., .class = c()) + +lib_path_default(.class = c()) + +lib_path_isolated(.class = c()) } \arguments{ -\item{x}{A \code{\link[=pkg_origin]{pkg_origin()}} object} +\item{x}{A \code{\link[=pkg_origin]{pkg_origin()}} object used for default dispatch.} + +\item{...}{Additional values} \item{.class}{An optional subclass, used primarily for dispatch.} } \description{ A description of where packages should be installed. This object provides necessary information to determine where a package should be installed. +lib_path method creates default path handlers for given pkg origin while +lib_path_x creates an actual object. } diff --git a/man/meta_task.Rd b/man/meta_task.Rd index 87c57e7..c8e34e6 100644 --- a/man/meta_task.Rd +++ b/man/meta_task.Rd @@ -6,6 +6,12 @@ \usage{ meta_task(..., .subclass = NULL) } +\arguments{ +\item{...}{Objects passed to specified class functions} + +\item{.subclass}{character name of the subclass. It will be appended with +"_meta" suffix.} +} \description{ Meta tasks are tasks which are not intended to perform computation. They exist simply to provide relationships among computational tasks. diff --git a/man/new_checker.Rd b/man/new_checker.Rd index c460ab6..80ae561 100644 --- a/man/new_checker.Rd +++ b/man/new_checker.Rd @@ -12,7 +12,7 @@ new_rev_dep_checker(x, ...) \arguments{ \item{...}{Additional arguments passed to \code{\link[=new_checker]{new_checker()}}} -\item{x}{A file path, passed to \code{\link[=rev_dep_check_tasks_df]{rev_dep_check_tasks_df()}}} +\item{x}{A file path, passed to \code{\link[=plan_rev_dep_checks]{plan_rev_dep_checks()}}} } \description{ Instantiate a check design from a path or directory. diff --git a/man/options.Rd b/man/options.Rd new file mode 100644 index 0000000..bb8bbb0 --- /dev/null +++ b/man/options.Rd @@ -0,0 +1,92 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/options.R +\name{options} +\alias{options} +\title{checked Options} +\description{ +Internally used, package-specific options. All options will prioritize R options() values, and fall back to environment variables if undefined. If neither the option nor the environment variable is set, a default value is used. +} +\section{Checking Option Values}{ + +Option values specific to \code{checked} can be +accessed by passing the package name to \code{env}. + +\if{html}{\out{
}}\preformatted{options::opts(env = "checked") + +options::opt(x, default, env = "checked") +}\if{html}{\out{
}} +} + +\section{Options}{ + +\describe{ +\item{tty_tick_interval}{\describe{ +tty refresh interval when reporting results in milliseconds\item{default: }{\preformatted{0.1}} +\item{option: }{checked.tty_tick_interval} +\item{envvar: }{R_CHECKED_TTY_TICK_INTERVAL (evaluated if possible, raw string otherwise)} +}} + +\item{results_error_on}{\describe{ +character vector indicating whether R error should be thrown when issues +are discovered when generating results. "never" means that no errors +are thrown. If "issues" then errors are emitted only on issues, whereas +"potential issues" stands for error on both issues and potential issues.\item{default: }{\preformatted{"never"}} +\item{option: }{checked.results_error_on} +\item{envvar: }{R_CHECKED_RESULTS_ERROR_ON (evaluated if possible, raw string otherwise)} +}} + +\item{results_keep}{\describe{ +character vector indicating which packages should be included in the results. +"all" means that all packages are kept. If "issues" then only packages +with issues identified, whereas "potential_issues" stands for keeping +packages with both "issues" and "potential_issues".\item{default: }{\preformatted{"all"}} +\item{option: }{checked.results_keep} +\item{envvar: }{R_CHECKED_RESULTS_KEEP (evaluated if possible, raw string otherwise)} +}} + +\item{restore}{\describe{ +\code{logical} indicating whether output directory should be unlinked before +running checks. If \code{FALSE}, an attempt will me made to restore previous +progress from the same \code{output}\item{default: }{\preformatted{NA}} +\item{option: }{checked.restore} +\item{envvar: }{R_CHECKED_RESTORE (evaluated if possible, raw string otherwise)} +}} + +\item{add_remotes}{\describe{ +\code{logical} indicating whether origins inheriting from \code{pkg_origin_local}, +should be scanned for packages in the \code{remotes} field and added while +constrocuting a plan \code{task_grap}\item{default: }{\preformatted{TRUE}} +\item{option: }{checked.add_remotes} +\item{envvar: }{R_CHECKED_ADD_REMOTES (evaluated if possible, raw string otherwise)} +}} + +\item{check_envvars}{\describe{ +named \code{character} vector of environment variables to use during +the R CMD check.\item{default: }{\preformatted{c(`_R_CHECK_FORCE_SUGGESTS_` = FALSE, `_R_CHECK_RD_XREFS_` = FALSE, + `_R_CHECK_SYSTEM_CLOCK_` = FALSE, `_R_CHECK_SUGGESTS_ONLY_` = TRUE)}} +\item{option: }{checked.check_envvars} +\item{envvar: }{R_CHECKED_CHECK_ENVVARS (evaluated if possible, raw string otherwise)} +}} + +\item{check_build_args}{\describe{ +\code{character} vector of args passed to the R CMD build.\item{default: }{\preformatted{c("--no-build-vignettes", "--no-manual")}} +\item{option: }{checked.check_build_args} +\item{envvar: }{R_CHECKED_CHECK_BUILD_ARGS (space-separated R CMD build flags)} +}} + +\item{check_args}{\describe{ +\code{character} vector of args passed to the R CMD check.\item{default: }{\preformatted{c("--timings", "--ignore-vignettes", "--no-manual")}} +\item{option: }{checked.check_args} +\item{envvar: }{R_CHECKED_CHECK_ARGS (space-separated R CMD check flags)} +}} + +} +} + +\seealso{ +options getOption Sys.setenv Sys.getenv + +Other documentation: +\code{\link{options_params}} +} +\concept{documentation} diff --git a/man/options_params.Rd b/man/options_params.Rd new file mode 100644 index 0000000..8a058d9 --- /dev/null +++ b/man/options_params.Rd @@ -0,0 +1,41 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/options.R +\name{options_params} +\alias{options_params} +\title{Checked Options} +\arguments{ +\item{results_error_on}{character vector indicating whether R error should be thrown when issues +are discovered when generating results. "never" means that no errors +are thrown. If "issues" then errors are emitted only on issues, whereas +"potential issues" stands for error on both issues and potential issues. (Defaults to \code{"never"}, overwritable using option 'checked.results_error_on' or environment variable 'R_CHECKED_RESULTS_ERROR_ON')} + +\item{check_args}{\code{character} vector of args passed to the R CMD check. (Defaults to \code{c("--timings", "--ignore-vignettes", "--no-manual")}, overwritable using option 'checked.check_args' or environment variable 'R_CHECKED_CHECK_ARGS')} + +\item{results_keep}{character vector indicating which packages should be included in the results. +"all" means that all packages are kept. If "issues" then only packages +with issues identified, whereas "potential_issues" stands for keeping +packages with both "issues" and "potential_issues". (Defaults to \code{"all"}, overwritable using option 'checked.results_keep' or environment variable 'R_CHECKED_RESULTS_KEEP')} + +\item{add_remotes}{\code{logical} indicating whether origins inheriting from \code{pkg_origin_local}, +should be scanned for packages in the \code{remotes} field and added while +constrocuting a plan \code{task_grap} (Defaults to \code{TRUE}, overwritable using option 'checked.add_remotes' or environment variable 'R_CHECKED_ADD_REMOTES')} + +\item{check_envvars}{named \code{character} vector of environment variables to use during +the R CMD check. (Defaults to \verb{c(}\emph{R_CHECK_FORCE_SUGGESTS}\verb{= FALSE,}\emph{R_CHECK_RD_XREFS}\verb{= FALSE, ; }\emph{R_CHECK_SYSTEM_CLOCK}\verb{= FALSE,}\emph{R_CHECK_SUGGESTS_ONLY}\verb{ = TRUE)}, overwritable using option 'checked.check_envvars' or environment variable 'R_CHECKED_CHECK_ENVVARS')} + +\item{tty_tick_interval}{tty refresh interval when reporting results in milliseconds (Defaults to \code{0.1}, overwritable using option 'checked.tty_tick_interval' or environment variable 'R_CHECKED_TTY_TICK_INTERVAL')} + +\item{check_build_args}{\code{character} vector of args passed to the R CMD build. (Defaults to \code{c("--no-build-vignettes", "--no-manual")}, overwritable using option 'checked.check_build_args' or environment variable 'R_CHECKED_CHECK_BUILD_ARGS')} + +\item{restore}{\code{logical} indicating whether output directory should be unlinked before +running checks. If \code{FALSE}, an attempt will me made to restore previous +progress from the same \code{output} (Defaults to \code{NA}, overwritable using option 'checked.restore' or environment variable 'R_CHECKED_RESTORE')} +} +\description{ +Checked Options +} +\seealso{ +Other documentation: +\code{\link{options}()} +} +\concept{documentation} diff --git a/man/pkg_dependencies.Rd b/man/pkg_dependencies.Rd index 6a7ecac..6ee86bb 100644 --- a/man/pkg_dependencies.Rd +++ b/man/pkg_dependencies.Rd @@ -7,10 +7,27 @@ pkg_dependencies( packages, dependencies = TRUE, - db = available.packages(), + db = available_packages(), verbose = FALSE ) } +\arguments{ +\item{packages}{a character vector of package names.} + +\item{dependencies}{A \code{logical} scalar, \code{character} string of +\code{"all"}, \code{"most"}, \code{"hard"} or \code{"soft"}, \code{NA} or a vector of dependency +types compatible with \code{\link[=as_pkg_dependencies]{as_pkg_dependencies()}} function.} + +\item{db}{character matrix as from \code{\link{available.packages}()} + (with the default \code{NULL} the results of this call) + or data frame variants thereof. Alternatively, a package database + like the one available from + \url{https://cran.r-project.org/web/packages/packages.rds}. + } + +\item{verbose}{logical indicating if output should monitor the package + search cycles.} +} \description{ Inspired by \code{tools::package_dependencies}, but with the added benefit of recording the dependency type and relationships throughout the diff --git a/man/pkg_origin.Rd b/man/pkg_origin.Rd index f6a2432..2877d6b 100644 --- a/man/pkg_origin.Rd +++ b/man/pkg_origin.Rd @@ -8,6 +8,7 @@ \alias{pkg_origin_base} \alias{pkg_origin_unknown} \alias{pkg_origin_local} +\alias{pkg_origin_remote} \alias{pkg_origin_archive} \title{Package specification} \usage{ @@ -25,17 +26,24 @@ pkg_origin_unknown(package, ...) pkg_origin_local(path = NULL, ...) +pkg_origin_remote(remote = NULL, ...) + pkg_origin_archive(path = NULL, ...) } \arguments{ -\item{...}{parameters passed to downstream constructors} +\item{package}{name of the package.} + +\item{...}{parameters passed to downstream constructors.} + +\item{.class}{Additional subclasses.} \item{repos}{repository where package with given name should identified.} \item{path}{path to the source of the package (either bundled or not). URLs are acceptable.} -\item{name}{name of the package.} +\item{remote}{remote object from the \code{remotes} package used to identify +non-standard packages.} } \description{ Create package specification list which consists of all the details required diff --git a/man/plan.Rd b/man/plan.Rd deleted file mode 100644 index 66b4a1a..0000000 --- a/man/plan.Rd +++ /dev/null @@ -1,33 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/plan.R -\name{plan} -\alias{plan} -\title{Check Plan} -\arguments{ -\item{path}{path to the package source. Can be either a single source -code directory or a directory containing multiple package source code -directories.} -} -\value{ -The check schedule \code{data.frame} with the following columns: -\itemize{ -\item \code{alias}: The alias of the check to run. It also serves the purpose of -providing a unique identifier and node name in the task graph. -\item \code{version}: Version of the package to be checked. -\item \code{package}: Object that inherits from \code{\link[=check_task]{check_task()}}. -Defines how package to be checked can be acquired. -\item \code{custom}: Object that inherits from \code{\link[=custom_install_task]{custom_install_task()}}. -Defines custom package, for instance only available from local source, that -should be installed before checking the package. -} -} -\description{ -Plans are pre-specified sets of checks. Plans are simple \code{data.frame}s -where each row defines a package for which \verb{R CMD check} -should be run. -} -\seealso{ -Other plan: -\code{\link{plan_rev_dep_checks}()} -} -\concept{plan} diff --git a/man/plan_local_checks.Rd b/man/plan_local_checks.Rd new file mode 100644 index 0000000..dd874dd --- /dev/null +++ b/man/plan_local_checks.Rd @@ -0,0 +1,32 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/plan.R +\name{plan_local_checks} +\alias{plan_local_checks} +\title{Plan R CMD Checks} +\usage{ +plan_local_checks(package, repos = getOption("repos")) +} +\arguments{ +\item{package}{A path to either package, directory with packages or name +of the package (details)} + +\item{repos}{repository used to identify packages when name is provided.} +} +\description{ +Generates a plan for running R CMD check for a specified set of packages. +} +\details{ +\code{package} parameter has two different allowed values: +\itemize{ +\item Package - checked looks for a DESCRIPTION file in the provided path, if +found treats it like a source package. +\item If the specified value does not correspond to a source package, the +parameter is treated as the name and \code{repos} parameter is used to identify +the source. +} +} +\seealso{ +Other plan: +\code{\link{plan_rev_dep_checks}()} +} +\concept{plan} diff --git a/man/plan_rev_dep_checks.Rd b/man/plan_rev_dep_checks.Rd index 0859c21..47ceab0 100644 --- a/man/plan_rev_dep_checks.Rd +++ b/man/plan_rev_dep_checks.Rd @@ -11,9 +11,7 @@ plan_rev_dep_checks( ) } \arguments{ -\item{path}{path to the package source. Can be either a single source -code directory or a directory containing multiple package source code -directories.} +\item{path}{path to the package source.} \item{repos}{repository used to identify reverse dependencies.} @@ -25,19 +23,6 @@ mostly when checking whether adding new package would break tests of packages already in the repository and take the package as suggests dependency.} } -\value{ -The check schedule \code{data.frame} with the following columns: -\itemize{ -\item \code{alias}: The alias of the check to run. It also serves the purpose of -providing a unique identifier and node name in the task graph. -\item \code{version}: Version of the package to be checked. -\item \code{package}: Object that inherits from \code{\link[=check_task]{check_task()}}. -Defines how package to be checked can be acquired. -\item \code{custom}: Object that inherits from \code{\link[=custom_install_task]{custom_install_task()}}. -Defines custom package, for instance only available from local source, that -should be installed before checking the package. -} -} \description{ Generates a plan for running reverse dependency check for certain source package. In such case \code{path} should be proivded with a directory @@ -46,6 +31,6 @@ repository for which reverse dependencies should be identified. } \seealso{ Other plan: -\code{\link{plan}} +\code{\link{plan_local_checks}()} } \concept{plan} diff --git a/man/print.checked_results.Rd b/man/print.checked_results.Rd index 5b7c18d..bc7cf46 100644 --- a/man/print.checked_results.Rd +++ b/man/print.checked_results.Rd @@ -2,37 +2,33 @@ % Please edit documentation in R/results.R \name{print.checked_results} \alias{print.checked_results} -\alias{print.checked_results_check_task} -\alias{print.checked_results_revdep_check_task} +\alias{print.rev_dep_dep_results} +\alias{print.local_check_results} \title{Print checked results} \usage{ \method{print}{checked_results}(x, ...) -\method{print}{checked_results_check_task}( - x, - keep = Sys.getenv("CHECKED_RESULTS_KEEP", c("all", "issues", "potential_issues")[1]), - ... -) +\method{print}{rev_dep_dep_results}(x, ..., name = NULL, keep = options::opt("results_keep")) -\method{print}{checked_results_revdep_check_task}(x, ...) +\method{print}{local_check_results}(x, ..., name = NULL, keep = options::opt("results_keep")) } \arguments{ \item{x}{an object to be printed.} \item{...}{other parameters.} -\item{keep}{character vector indicating which packages should be included -in the results. "all" means that all packages are kept. If "issues" then -only packages with issues identified, whereas "potential_issues" stands for -keeping packages with both "issues" and "potential_issues". Users can set -the default value via env variable \code{CHECKED_RESULTS_KEEP}.} +\item{name}{character name of the \code{rev_dep_dep} package} + +\item{keep}{character vector indicating which packages should be included in the results. +"all" means that all packages are kept. If "issues" then only packages +with issues identified, whereas "potential_issues" stands for keeping +packages with both "issues" and "potential_issues". (Defaults to \code{"all"}, overwritable using option 'checked.results_keep' or environment variable 'R_CHECKED_RESULTS_KEEP')} } \description{ Print checked results } \seealso{ Other results: -\code{\link{results}()}, -\code{\link{results_to_file}()} +\code{\link{results}()} } \concept{results} diff --git a/man/reporters-internal.Rd b/man/reporters-internal.Rd index a3571e3..91021e3 100644 --- a/man/reporters-internal.Rd +++ b/man/reporters-internal.Rd @@ -8,19 +8,22 @@ \alias{report_start_checks} \alias{report_status} \alias{report_finalize} +\alias{report_task} \title{Reporter Internal Methods} \usage{ -report_sleep(reporter, design, sleep) +report_sleep(reporter, checker, sleep) -\method{report_sleep}{default}(reporter, design, sleep = 1) +\method{report_sleep}{default}(reporter, checker, sleep = 1) -report_start_setup(reporter, design, ..., envir = parent.frame()) +report_start_setup(reporter, checker, ..., envir = parent.frame()) -report_start_checks(reporter, design, ..., envir = parent.frame()) +report_start_checks(reporter, checker, ..., envir = parent.frame()) -report_status(reporter, design, envir = parent.frame()) +report_status(reporter, checker, envir = parent.frame()) -report_finalize(reporter, design) +report_finalize(reporter, checker) + +report_task(reporter, g, v) } \arguments{ \item{reporter}{A object produced using \code{\link{reporters}}. Each reporter is a @@ -28,7 +31,7 @@ thin wrapper around an environment with a class name for dispatch. The reporter is mutable and captures any necessary state that needs to be tracked while reporting.} -\item{design}{\code{\link{checker}} The check design to report as it evaluates.} +\item{checker}{\code{\link{checker}} The check checker to report as it evaluates.} \item{sleep}{\code{numeric} An interval to pause between reporter steps.} @@ -37,6 +40,6 @@ hooks.} } \description{ Each of the internal methods for reporters take a reporter, the check -design object and a calling environment. +checker object and a calling environment. } \keyword{internal} diff --git a/man/reporters.Rd b/man/reporters.Rd index 1f7faa0..b2f8c13 100644 --- a/man/reporters.Rd +++ b/man/reporters.Rd @@ -6,7 +6,7 @@ \alias{reporter_ansi_tty2} \alias{reporter_basic_tty} \alias{reporter_default} -\title{Check Design Runner Reporters} +\title{Check checker Runner Reporters} \usage{ reporter_ansi_tty() diff --git a/man/results.Rd b/man/results.Rd index 2f61644..b888004 100644 --- a/man/results.Rd +++ b/man/results.Rd @@ -3,35 +3,44 @@ \name{results} \alias{results} \alias{results.checker} +\alias{results.integer} +\alias{results.igraph.vs} +\alias{results.rev_dep_dep_meta_task} +\alias{results.rev_dep_check_meta_task} +\alias{results.local_check_meta_task} \title{Check results} \usage{ results(x, ...) -\method{results}{checker}( - x, - error_on = Sys.getenv("CHECKED_RESULTS_ERROR_ON", c("never", "issues", - "potential_issues")[1]), - ... -) +\method{results}{checker}(x, error_on = options::opt("results_error_on"), ...) + +\method{results}{integer}(x, checker_obj, ...) + +\method{results}{igraph.vs}(x, ...) + +\method{results}{rev_dep_dep_meta_task}(x, checker_obj, ...) + +\method{results}{rev_dep_check_meta_task}(x, checker_obj, ...) + +\method{results}{local_check_meta_task}(x, checker_obj, ...) } \arguments{ -\item{x}{\code{\link{checker}} object.} +\item{x}{object which results should be presented.} \item{...}{other parameters.} -\item{error_on}{character vector indicating whether R error should be thrown -when issues are discovered when generating results. "never" means that no -errors are thrown. If "issues" then errors are emitted only on issues, -whereas "potential issues" stands for error on both issues and potential -issues. Users can set the default value via env variable -\code{CHECKED_RESULTS_ERROR_ON}.} +\item{error_on}{character vector indicating whether R error should be thrown when issues +are discovered when generating results. "never" means that no errors +are thrown. If "issues" then errors are emitted only on issues, whereas +"potential issues" stands for error on both issues and potential issues. (Defaults to \code{"never"}, overwritable using option 'checked.results_error_on' or environment variable 'R_CHECKED_RESULTS_ERROR_ON')} + +\item{checker_obj}{\code{\link{checker}} object.} } \description{ Get R CMD check results } \seealso{ Other results: -\code{\link{print.checked_results}()}, -\code{\link{results_to_file}()} +\code{\link{print.checked_results}()} } \concept{results} diff --git a/man/results_to_file.Rd b/man/results_to_file.Rd deleted file mode 100644 index 4642aa4..0000000 --- a/man/results_to_file.Rd +++ /dev/null @@ -1,31 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/results.R -\name{results_to_file} -\alias{results_to_file} -\title{Results to file} -\usage{ -results_to_file(results, file, keep = "all", ...) -} -\arguments{ -\item{results}{\code{\link[checked]{results}} object.} - -\item{file}{A connection or character path.} - -\item{keep}{character vector indicating which packages should be included -in the results. "all" means that all packages are kept. If "issues" then -only packages with issues identified, whereas "potential_issues" stands for -keeping packages with both "issues" and "potential_issues". Users can set -the default value via env variable \code{CHECKED_RESULTS_KEEP}.} - -\item{...}{other parameters.} -} -\description{ -Write \code{checked_results} object to the text file. When converting results -to text, \code{\link[checked]{print.checked_results}} method is used. -} -\seealso{ -Other results: -\code{\link{print.checked_results}()}, -\code{\link{results}()} -} -\concept{results} diff --git a/man/revdep_check_task.Rd b/man/revdep_check_task.Rd deleted file mode 100644 index 107bf74..0000000 --- a/man/revdep_check_task.Rd +++ /dev/null @@ -1,25 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/task.R -\name{revdep_check_task} -\alias{revdep_check_task} -\title{Create a task to run reverse dependency checks} -\usage{ -revdep_check_task(revdep, ...) -} -\arguments{ -\item{revdep}{character indicating whether the task specification describes -check associated with the development (new) or release (old) version of the -for which reverse dependency check is run.} - -\item{...}{Additional parameters passed to \code{\link[=task]{task()}}} -} -\description{ -Create a task to run reverse dependency checks -} -\seealso{ -Other tasks: -\code{\link{check_task}()}, -\code{\link{install_task}()}, -\code{\link{task}()} -} -\concept{tasks} diff --git a/man/run.Rd b/man/run.Rd index 76ffafd..f1597a2 100644 --- a/man/run.Rd +++ b/man/run.Rd @@ -7,14 +7,14 @@ run(checker, ..., reporter = reporter_default()) } \arguments{ +\item{checker}{\code{character} or \code{checker} If a \code{character} value is +provided, it is first coerced into a \code{checker} using +\code{\link[=new_rev_dep_checker]{new_rev_dep_checker()}}.} + \item{...}{Additional arguments passed to \code{\link[=new_rev_dep_checker]{new_rev_dep_checker()}}} \item{reporter}{A reporter to provide progress updates. Will default to the most expressive command-line reporter given your terminal capabilities.} - -\item{checks}{\code{character} or \code{checker} If a \code{character} value is -provided, it is first coerced into a \code{checker} using -\code{\link[=new_rev_dep_checker]{new_rev_dep_checker()}}.} } \description{ \code{\link[=run]{run()}} provides a generic, and is the central interface for executing diff --git a/man/task.Rd b/man/task.Rd index 5759900..cad6a36 100644 --- a/man/task.Rd +++ b/man/task.Rd @@ -7,12 +7,9 @@ task(..., .subclass = NULL) } \arguments{ -\item{alias}{task alias which also serves as unique identifier of the task.} +\item{...}{parameters passed to downstream constructors.} -\item{package}{\code{\link[checked]{package}} object} - -\item{tasks}{Optional additional tasks that are pre-requisites for running -this task.} +\item{.subclass}{Additional subclasses.} } \description{ Create task specification list which consists of all the details required @@ -25,7 +22,6 @@ related tasks. \seealso{ Other tasks: \code{\link{check_task}()}, -\code{\link{install_task}()}, -\code{\link{revdep_check_task}()} +\code{\link{install_task}()} } \concept{tasks} diff --git a/man/task_formats.Rd b/man/task_formats.Rd index 0892b3a..66ef536 100644 --- a/man/task_formats.Rd +++ b/man/task_formats.Rd @@ -2,12 +2,21 @@ % Please edit documentation in R/utils-cli.R \name{task_formats} \alias{task_formats} -\title{task formatter bindings} +\title{Task formatter bindings} \usage{ task_formats(g = NULL, nodes = V(g), task = NULL, tasks = list(task)) } +\arguments{ +\item{g}{task_graph object.} + +\item{nodes}{graph nodes to format.} + +\item{task}{task to format.} + +\item{tasks}{currently unused.} +} \description{ -This bit of code is intended for use with \code{\link[=cli_task]{cli_task()}}, and allows for us +This bit of code is intended for use with \code{\link[=fmt]{fmt()}}, and allows for us to layer symbol bindings on top of the environment used for string interpolation which provide syntactic sugar for common formatting components. } diff --git a/man/task_graph.Rd b/man/task_graph.Rd index e0d06a0..e01a62f 100644 --- a/man/task_graph.Rd +++ b/man/task_graph.Rd @@ -15,7 +15,8 @@ determine package relationships.} \item{...}{params passed to helper methods.} } \value{ -A \code{data.frame} that can be used to build \code{\link{igraph}} edges. +A \code{data.frame} that can be used to build +\code{\link[igraph:make_graph]{igraph::make_graph}} edges. } \description{ Edges describe relationships between tasks. Often, this is a dependency @@ -32,7 +33,7 @@ data. } \examples{ \dontrun{ -task_graph_create(plan_rev_dep_checks(".")) +task_graph(plan_rev_dep_checks(".")) } } \keyword{internal} diff --git a/man/task_graph_neighborhoods.Rd b/man/task_graph_neighborhoods.Rd index 2150d1f..5bd9d8b 100644 --- a/man/task_graph_neighborhoods.Rd +++ b/man/task_graph_neighborhoods.Rd @@ -7,7 +7,7 @@ task_graph_neighborhoods(g, nodes, ...) } \arguments{ -\item{g}{A task graph, as produced with \code{\link[=task_graph_create]{task_graph_create()}}} +\item{g}{A task graph, as produced with \code{\link[=task_graph]{task_graph()}}} \item{nodes}{Names or nodes objects of packages whose neighborhoods should be calculated.} diff --git a/man/task_graph_update_ready.Rd b/man/task_graph_update_ready.Rd index e1da281..6671fd2 100644 --- a/man/task_graph_update_ready.Rd +++ b/man/task_graph_update_ready.Rd @@ -12,7 +12,7 @@ task_graph_update_ready( ) } \arguments{ -\item{g}{A dependency graph, as produced with \code{\link[=task_graph_create]{task_graph_create()}}.} +\item{g}{A dependency graph, as produced with \code{\link[=task_graph]{task_graph()}}.} \item{v}{Names or nodes objects of packages whose satisfiability should be checked.} @@ -32,14 +32,13 @@ already has its dependencies done. } \details{ There are helpers defined for particular use cases that strictly rely on the -\code{\link[=task_graph_which_satisfied]{task_graph_which_satisfied()}}, they are: +\code{\link[=task_graph_which_ready]{task_graph_which_ready()}}, they are: \itemize{ -\item \code{task_graph_which_satisfied_strong()} - List vertices whose strong +\item \code{task_graph_update_check_ready()} - Updates check vertices whose all dependencies are satisfied. -\item \code{task_graph_which_check_satisfied()} - List root vertices whose all +\item \code{task_graph_update_install_ready()} - Update install vertices whose all dependencies are satisfied. -\item \code{task_graph_which_install_satisfied()} - List install vertices whose -dependencies are all satisfied +\item \code{task_graph_which_ready()} - List vertices whose wit ready status. } } \keyword{internal} diff --git a/tests/testthat.R b/tests/testthat.R index 78ec056..6d04abf 100644 --- a/tests/testthat.R +++ b/tests/testthat.R @@ -9,4 +9,4 @@ library(testthat) library(checked) -test_check("checked") +#test_check("checked") From ffdef8bad86cff4ba94accae1b6c38b0362d077b Mon Sep 17 00:00:00 2001 From: Szymon Maksymiuk <32574056+maksymiuks@users.noreply.github.com> Date: Fri, 3 Oct 2025 13:28:43 +0200 Subject: [PATCH 36/62] Add install local plan (#74) --- DESCRIPTION | 2 +- R/checker.R | 9 +++++++- R/plan.R | 44 ++++++++++++++++++++++++++++++++++---- man/plan_local_checks.Rd | 1 + man/plan_local_install.Rd | 25 ++++++++++++++++++++++ man/plan_rev_dep_checks.Rd | 3 ++- 6 files changed, 77 insertions(+), 7 deletions(-) create mode 100644 man/plan_local_install.Rd diff --git a/DESCRIPTION b/DESCRIPTION index 8b830bc..2d01dab 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: checked Title: Systematically Run R CMD Checks -Version: 1.0.9000 +Version: 0.0.5.9000 Authors@R: c( person( diff --git a/R/checker.R b/R/checker.R index 5551f08..0cbc80f 100644 --- a/R/checker.R +++ b/R/checker.R @@ -205,7 +205,14 @@ checker <- R6::R6Class( is_done = function() { is_check_node <- is_check(V(self$graph)$task) checks <- V(self$graph)[is_check_node] - all(checks$status == STATUS$done) + if (length(checks) > 0) { + all(checks$status == STATUS$done) + } else { + # If there is not a single check tasks, we need to make sure all + # the task finished + all(V(self$graph)$status == STATUS$done) + } + } ), private = list( diff --git a/R/plan.R b/R/plan.R index 21ab237..f81a575 100644 --- a/R/plan.R +++ b/R/plan.R @@ -200,11 +200,47 @@ plan_local_checks <- function( repos = repos ) + star_plan_template(c( + list(task), + local_checks_tasks + )) +} + + +#' Plan source package installation +#' +#' Generates a plan for running installing a package from source. +#' +#' @param package A path to package source. +#' @param repos repository used to identify packages when name is provided. +#' @param dependencies either character vector or logical value specifying +#' which dependencies should be installed. +#' +#' +#' @family plan +plan_local_install <- function( + package, + repos = getOption("repos") +) { + + m_task <- meta_task( + origin = NULL, + .subclass = "local_install" + ) + + i_task <- install_task( + origin = pkg_origin_local(package) + ) + + star_plan_template(list( + m_task, + i_task + )) +} + +star_plan_template <- function(tasks) { g <- star_graph( - task = c( - list(task), - local_checks_tasks - ) + task = tasks ) E(g)$type <- rep(DEP$Depends, times = length(E(g))) diff --git a/man/plan_local_checks.Rd b/man/plan_local_checks.Rd index dd874dd..34f3e14 100644 --- a/man/plan_local_checks.Rd +++ b/man/plan_local_checks.Rd @@ -27,6 +27,7 @@ the source. } \seealso{ Other plan: +\code{\link{plan_local_install}()}, \code{\link{plan_rev_dep_checks}()} } \concept{plan} diff --git a/man/plan_local_install.Rd b/man/plan_local_install.Rd new file mode 100644 index 0000000..b663750 --- /dev/null +++ b/man/plan_local_install.Rd @@ -0,0 +1,25 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/plan.R +\name{plan_local_install} +\alias{plan_local_install} +\title{Plan source package installation} +\usage{ +plan_local_install(package, repos = getOption("repos")) +} +\arguments{ +\item{package}{A path to package source.} + +\item{repos}{repository used to identify packages when name is provided.} + +\item{dependencies}{either character vector or logical value specifying +which dependencies should be installed.} +} +\description{ +Generates a plan for running installing a package from source. +} +\seealso{ +Other plan: +\code{\link{plan_local_checks}()}, +\code{\link{plan_rev_dep_checks}()} +} +\concept{plan} diff --git a/man/plan_rev_dep_checks.Rd b/man/plan_rev_dep_checks.Rd index 47ceab0..40bcfb4 100644 --- a/man/plan_rev_dep_checks.Rd +++ b/man/plan_rev_dep_checks.Rd @@ -31,6 +31,7 @@ repository for which reverse dependencies should be identified. } \seealso{ Other plan: -\code{\link{plan_local_checks}()} +\code{\link{plan_local_checks}()}, +\code{\link{plan_local_install}()} } \concept{plan} From 0b797ff596cdc7aa0bdb708360804d879e3ef5ac Mon Sep 17 00:00:00 2001 From: Szymon Maksymiuk <32574056+maksymiuks@users.noreply.github.com> Date: Fri, 17 Oct 2025 14:42:48 +0200 Subject: [PATCH 37/62] 72 update basic tty to work with a new tasks structure (#75) * Initial basic tty suport * Fix ansi and basic reporters --- NAMESPACE | 3 +++ R/checker.R | 4 ++++ R/reporter.R | 10 ++++++++++ R/reporter_ansi_tty.R | 17 +++++++++++++++-- R/reporter_basic_tty.R | 33 ++++++++++++++++++--------------- R/run.R | 7 +------ man/reporters-internal.Rd | 6 ++++++ 7 files changed, 57 insertions(+), 23 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index edf1580..10eb364 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -96,9 +96,12 @@ S3method(report_sleep,default) S3method(report_sleep,reporter_ansi_tty) S3method(report_start_checks,reporter_ansi_tty) S3method(report_start_setup,reporter_ansi_tty) +S3method(report_start_setup,reporter_basic_tty) S3method(report_status,"NULL") S3method(report_status,reporter_ansi_tty) S3method(report_status,reporter_basic_tty) +S3method(report_step,reporter_ansi_tty) +S3method(report_step,reporter_basic_tty) S3method(report_task,reporter_ansi_tty) S3method(report_task_ansi_tty,check_task) S3method(report_task_ansi_tty,default) diff --git a/R/checker.R b/R/checker.R index 0cbc80f..54cfdce 100644 --- a/R/checker.R +++ b/R/checker.R @@ -193,6 +193,10 @@ checker <- R6::R6Class( return(as.integer(success)) } + if (length(private$active) == 0 && !self$is_done()) { + stop("some tasks not executed due to unsolved dependency requirements") + } + finished <- (length(private$active) == 0) && self$is_done() -finished diff --git a/R/reporter.R b/R/reporter.R index 823d931..ace72b6 100644 --- a/R/reporter.R +++ b/R/reporter.R @@ -100,6 +100,11 @@ report_start_checks <- function(reporter, checker, ..., envir = parent.frame()) UseMethod("report_start_checks") } +#' @rdname reporters-internal +report_start_checks.default <- function(reporter, checker, ..., envir = parent.frame()) { # nolint + NULL +} + #' @rdname reporters-internal report_status <- function(reporter, checker, envir = parent.frame()) { UseMethod("report_status") @@ -114,3 +119,8 @@ report_finalize <- function(reporter, checker) { report_task <- function(reporter, g, v) { UseMethod("report_task") } + +#' @rdname reporters-internal +report_step <- function(reporter, checker) { + UseMethod("report_step") +} diff --git a/R/reporter_ansi_tty.R b/R/reporter_ansi_tty.R index a598939..000df72 100644 --- a/R/reporter_ansi_tty.R +++ b/R/reporter_ansi_tty.R @@ -62,14 +62,22 @@ format_status_line_ansi.check_process <- function( format_status_line_ansi.default <- function( process, ..., + status, width = getOption("width", 80L)) { + + msg <- if (status == STATUS$done) { + "restored from system file." + } else { + "starting ..." + } + out <- cli_table_row( status = "NONE", ok = 0, notes = 0, warnings = 0, errors = 0, - "restored from system file." + msg ) cli::ansi_substring(out, 1, width) @@ -224,7 +232,7 @@ report_task_ansi_tty.check_task <- function(reporter, g, v) { justify = "right", width = reporter$label_nchar ), - status = format_status_line_ansi(v$process) + status = format_status_line_ansi(v$process, status = v$status) ) } @@ -444,3 +452,8 @@ report_finalize.reporter_ansi_tty <- function(reporter, checker) { cat(ansi_line_erase()) # clear lingering progress bar output cli::ansi_show_cursor() } + +#' @export +report_step.reporter_ansi_tty <- function(reporter, checker) { + checker$step() +} diff --git a/R/reporter_basic_tty.R b/R/reporter_basic_tty.R index 33fb499..56360ef 100644 --- a/R/reporter_basic_tty.R +++ b/R/reporter_basic_tty.R @@ -1,18 +1,18 @@ -# TODO: Refactor entire reporter - -report_initialize.reporter_basic_tty <- function( +#' @export +report_start_setup.reporter_basic_tty <- function( reporter, checker, + ..., envir = parent.frame() ) { - # start with initialized-as-completed tasks + # start with all tasks initialized as pending v <- igraph::V(checker$graph) - which_done <- v$status == STATUS$done - done <- v[which_done]$status - names(done) <- v$name[which_done] + v_actionable <- v[is_actionable_task(v$task)] # named factor vector, names as task aliases and value of last reported status - reporter$status <- done + reporter$status <- rep(STATUS$pending, times = length(v_actionable)) + names(reporter$status) <- v_actionable$name + reporter$time_start <- Sys.time() cli::cli_text("<", utils::packageName(), "> Checks") @@ -22,10 +22,8 @@ report_initialize.reporter_basic_tty <- function( report_status.reporter_basic_tty <- function(reporter, checker, envir) { cli_theme() g <- checker$graph - tasks_names <- names(igraph::V(g)) - # skip if queued, but not started or already finished - reported_statuses <- sapply(reporter$statuses, `[[`, 1) - reported_done <- names(reported_statuses[reported_statuses == STATUS$done]) + tasks_names <- names(reporter$status) + reported_done <- names(reporter$status[reporter$status == STATUS$done]) tasks_not_started <- names(igraph::V(g)[igraph::V(g)$status <= STATUS$`ready`]) tasks_to_report <- @@ -40,7 +38,7 @@ report_status.reporter_basic_tty <- function(reporter, checker, envir) { p <- node$process # report stating of new checks - if (!identical(node$status, reporter$statuses[[node$name]])) { + if (!identical(node$status, reporter$status[[node$name]])) { status <- switch(as.character(node$status), # nolint (used via glue) "pending" = "queued", "in progress" = cli::cli_fmt(cli::cli_text("started")), @@ -88,8 +86,8 @@ report_status.reporter_basic_tty <- function(reporter, checker, envir) { time <- Sys.time() - reporter$time_start # nolint (used via glue) type <- format_task_type(node$task) # nolint (used via glue) prefix <- cli::col_cyan("[{format_time(time)}][{type}] ") - cli::cli_text(prefix, "{.pkg {node$package}} {status}") - reporter$statuses[[node$name]] <- node$status + cli::cli_text(prefix, "{.pkg {package(node$task)}} {status}") + reporter$status[[node$name]] <- node$status } } } @@ -101,3 +99,8 @@ report_finalize.reporter_basic_tty <- function(reporter, checker) { time <- format_time(Sys.time() - reporter$time_start) # nolint (used via glue) cli::cli_text("Finished in {.time_taken {time}}") } + +#' @export +report_step.reporter_basic_tty <- function(reporter, checker) { + checker$start_next_task() >= 0 +} diff --git a/R/run.R b/R/run.R index c1f31bd..49658be 100644 --- a/R/run.R +++ b/R/run.R @@ -37,12 +37,7 @@ run.checker <- function(checker, ..., reporter = reporter_default()) { report_start_setup(reporter, checker) report_start_checks(reporter, checker) - while (checker$step()) { - if (length(checker$active_processes()) == 0 && !checker$is_done()) { - warning("some tasks not executed due to unsolved dependency requirements") - break - } - + while (report_step(reporter, checker)) { report_status(reporter, checker) report_sleep(reporter, checker) } diff --git a/man/reporters-internal.Rd b/man/reporters-internal.Rd index 91021e3..ce4e7ab 100644 --- a/man/reporters-internal.Rd +++ b/man/reporters-internal.Rd @@ -6,9 +6,11 @@ \alias{report_sleep.default} \alias{report_start_setup} \alias{report_start_checks} +\alias{report_start_checks.default} \alias{report_status} \alias{report_finalize} \alias{report_task} +\alias{report_step} \title{Reporter Internal Methods} \usage{ report_sleep(reporter, checker, sleep) @@ -19,11 +21,15 @@ report_start_setup(reporter, checker, ..., envir = parent.frame()) report_start_checks(reporter, checker, ..., envir = parent.frame()) +\method{report_start_checks}{default}(reporter, checker, ..., envir = parent.frame()) + report_status(reporter, checker, envir = parent.frame()) report_finalize(reporter, checker) report_task(reporter, g, v) + +report_step(reporter, checker) } \arguments{ \item{reporter}{A object produced using \code{\link{reporters}}. Each reporter is a From fc93f8652e7e561fd04474d45f59c862e27e080f Mon Sep 17 00:00:00 2001 From: Szymon Maksymiuk <32574056+maksymiuks@users.noreply.github.com> Date: Fri, 31 Oct 2025 13:16:31 +0100 Subject: [PATCH 38/62] Cleanup code base (#77) --- NAMESPACE | 1 - R/task.R | 4 -- R/task_graph.R | 6 --- R/utils-formatting.R | 8 ---- R/utils-igraph.R | 26 ------------- R/utils-pkg-source.R | 84 ----------------------------------------- R/utils.R | 18 --------- man/sub_aliased_deps.Rd | 21 ----------- 8 files changed, 168 deletions(-) delete mode 100644 R/utils-formatting.R delete mode 100644 man/sub_aliased_deps.Rd diff --git a/NAMESPACE b/NAMESPACE index 10eb364..4bc7c9d 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -14,7 +14,6 @@ S3method(count,default) S3method(count,issues) S3method(count,potential_issues) S3method(format,lib_path) -S3method(format,listof) S3method(format,local_check_meta_task) S3method(format,pkg_origin) S3method(format,pkg_origin_base) diff --git a/R/task.R b/R/task.R index 67f2e3b..464e089 100644 --- a/R/task.R +++ b/R/task.R @@ -139,10 +139,6 @@ lib.check_task <- function(x, ...) { character(0L) # no additional libraries needed for checking } -is_check_task <- function(x) { - inherits(x, "check_task") -} - package <- function(x) { UseMethod("package") } diff --git a/R/task_graph.R b/R/task_graph.R index 8388429..7f383b0 100644 --- a/R/task_graph.R +++ b/R/task_graph.R @@ -315,12 +315,6 @@ task_graph_which_ready <- function(g) { nodes[statuses == STATUS["ready"]] } -empty_edge <- data.frame( - dep = character(0), - root = character(0), - type = character(0) -) - task_graph_set_package_status <- function(g, v, status) { if (is.character(status)) status <- STATUS[[status]] igraph::set_vertex_attr(g, "status", v, status) diff --git a/R/utils-formatting.R b/R/utils-formatting.R deleted file mode 100644 index 0cc02b3..0000000 --- a/R/utils-formatting.R +++ /dev/null @@ -1,8 +0,0 @@ -listof <- function(x) { - structure(x, class = "listof") -} - -#' @export -format.listof <- function(x, ...) { - vcapply(x, function(xi) format(xi, ...)) -} diff --git a/R/utils-igraph.R b/R/utils-igraph.R index 40ac815..8162763 100644 --- a/R/utils-igraph.R +++ b/R/utils-igraph.R @@ -87,29 +87,3 @@ graph_dedup_attrs <- function(g) { g } - -complete_columns <- function(df, cols) { - n_gtz <- nrow(df) > 0 - for (col in setdiff(cols, colnames(df))) df[[col]] <- NA[n_gtz] - df[, cols, drop = FALSE] -} - -copy_edges_from_vertex <- function(g, v_to, v_from, mode = "all") { - for (e in igraph::incident(g, v_from, mode)) { - v_ends <- igraph::ends(g, e) - if (v_ends[1] == v_from) { - g <- igraph::add_edges( - g, - c(v_to, v_ends[2]), - attr = igraph::edge.attributes(g, e) - ) - } else { - g <- igraph::add_edges( - g, - c(v_ends[1], v_to), - attr = igraph::edge.attributes(g, e) - ) - } - } - g -} diff --git a/R/utils-pkg-source.R b/R/utils-pkg-source.R index c76044a..48719d5 100644 --- a/R/utils-pkg-source.R +++ b/R/utils-pkg-source.R @@ -2,13 +2,6 @@ strip_src_contrib <- function(x) { sub("/src/contrib$", "", x) } -split_packages_names <- function(x) { - if (is.na(x)) { - return(x) - } - vcapply(.tools$.split_dependencies(x), "[[", "name", USE.NAMES = FALSE) -} - check_dependencies <- function(dependencies) { is_all <- isTRUE(dependencies) is_strong <- length(dependencies) == 1 && is.na(dependencies) @@ -37,25 +30,6 @@ check_dependencies <- function(dependencies) { dependencies } -bind_descs <- function(x, fields = NULL) { - all_colnames <- unique(unlist(lapply(x, colnames))) - if (!is.null(fields)) { - all_colnames <- intersect(all_colnames, fields) - } - for (i in seq_along(x)) { - missing_cols <- setdiff(all_colnames, colnames(x[[i]])) - new_cols <- rep_len(NA, length(missing_cols)) - names(new_cols) <- missing_cols - x[[i]] <- do.call(cbind, c(list(x[[i]]), new_cols)) - x[[i]] <- x[[i]][, all_colnames, drop = FALSE] - } - do.call(rbind, x) -} - -get_desc <- function(origin) { - UseMethod("get_desc") -} - get_desc_field <- function(path, field) { desc <- file.path(path, "DESCRIPTION") if (!file.exists(desc)) { @@ -64,56 +38,6 @@ get_desc_field <- function(path, field) { read.dcf(desc)[, field] } -sub_desc_aliases <- function( - desc, - aliases = if ("Alias" %in% colnames(desc)) desc[, "Alias"] -) { - if (is.null(aliases)) return(desc) - - # create mapping from package name to aliased name - has_alias <- !is.na(desc[, "Alias"]) - alias_map <- desc[has_alias, "Package"] - names(alias_map) <- desc[has_alias, "Alias"] - - for (deptype in names(DEP)) { - for (i in seq_len(nrow(desc))) { - desc[[i, deptype]] <- sub_aliased_deps(desc[[i, deptype]], alias_map) - } - } - - desc -} - -#' Substitute Aliased Dependencies String -#' -#' @param deps `character(1L)`, as provided by a `DESCRIPTION` file's -#' dependency listing. -#' @param aliases (named vector), a mapping of package names to aliases for -#' substitution. -#' @return `deps`, substituting package names with associated aliases. -#' -sub_aliased_deps <- function(deps, aliases) { - if (is.na(deps)) { - return(deps) - } - - deps <- .tools$.split_dependencies(deps) - for (i in seq_along(deps)) { - if (deps[[i]]$name %in% names(aliases)) { - deps[[i]]$name <- aliases[[deps[[i]]$name]] - } - } - - paste(collapse = ", ", vcapply(deps, function(dep) { - paste0( - dep$name, - if (!is.null(dep$version)) { - paste0(" (", dep$op, " ", dep$version, ")") - } - ) - })) -} - get_package_name <- function(path) { get_desc_field(path, "Package") } @@ -149,11 +73,3 @@ get_package_source <- function(package, repos, db = NULL, destdir = NULL) { archive_url } } - -package_deps <- function(packages = NULL, ...) { - if (length(packages) == 0) { - NULL - } else { - tools::package_dependencies(packages = packages, ...) - } -} diff --git a/R/utils.R b/R/utils.R index 16c06b4..9f45281 100644 --- a/R/utils.R +++ b/R/utils.R @@ -51,16 +51,6 @@ is_package_installed <- function(pkg, lib.loc = .libPaths()) { ".split_dependencies" )] -replace_with_map <- function(x, value, replacement) { - m <- match(x, value) - x[which(!is.na(m))] <- replacement[m[!is.na(m)]] - x -} - -unique_alias <- function(x) { - paste0(c("pkg-id-", as.character(charToRaw(x))), collapse = "") -} - dir_create <- function(path) { if (!dir.exists(path)) { dir.create(path, showWarnings = FALSE, recursive = TRUE) @@ -69,14 +59,6 @@ dir_create <- function(path) { `%||%` <- function(lhs, rhs) if (is.null(lhs)) rhs else lhs -drlapply <- function(...) { - do.call(rbind, lapply(...)) -} - -drmapply <- function(...) { - do.call(rbind, mapply(..., USE.NAMES = FALSE, SIMPLIFY = FALSE)) -} - vcapply <- function(...) vapply(..., FUN.VALUE = character(1L)) vlapply <- function(...) vapply(..., FUN.VALUE = logical(1L)) viapply <- function(...) vapply(..., FUN.VALUE = integer(1L)) diff --git a/man/sub_aliased_deps.Rd b/man/sub_aliased_deps.Rd deleted file mode 100644 index 749729a..0000000 --- a/man/sub_aliased_deps.Rd +++ /dev/null @@ -1,21 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/utils-pkg-source.R -\name{sub_aliased_deps} -\alias{sub_aliased_deps} -\title{Substitute Aliased Dependencies String} -\usage{ -sub_aliased_deps(deps, aliases) -} -\arguments{ -\item{deps}{\code{character(1L)}, as provided by a \code{DESCRIPTION} file's -dependency listing.} - -\item{aliases}{(named vector), a mapping of package names to aliases for -substitution.} -} -\value{ -\code{deps}, substituting package names with associated aliases. -} -\description{ -Substitute Aliased Dependencies String -} From e7d7c2d2bd5d63beb8b218fed87bf02895d82650 Mon Sep 17 00:00:00 2001 From: Szymon Maksymiuk <32574056+maksymiuks@users.noreply.github.com> Date: Tue, 3 Feb 2026 01:40:35 +0100 Subject: [PATCH 39/62] Rework ansi reporter (#79) * Add ansi tty errors * Rework ansi reporter * Make lintr happy * Change version * Update R/checker.R Co-authored-by: Doug Kelkhoff <18220321+dgkf@users.noreply.github.com> * gc when needed * Apply suggestions --------- Co-authored-by: Doug Kelkhoff <18220321+dgkf@users.noreply.github.com> --- DESCRIPTION | 2 +- NAMESPACE | 1 + NEWS.md | 9 +++- R/checker.R | 28 +++++++---- R/options.R | 12 +++++ R/plan.R | 3 -- R/reporter_ansi_tty.R | 99 +++++++++++++++++++++++++++++++-------- R/reporter_basic_tty.R | 10 ++++ R/utils-ansi.R | 11 +++++ man/ansi.Rd | 5 ++ man/options.Rd | 18 +++++++ man/options_params.Rd | 10 ++++ man/plan_local_install.Rd | 3 -- 13 files changed, 174 insertions(+), 37 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 2d01dab..6b4ed4d 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: checked Title: Systematically Run R CMD Checks -Version: 0.0.5.9000 +Version: 0.5.0.9000 Authors@R: c( person( diff --git a/NAMESPACE b/NAMESPACE index 4bc7c9d..ff40220 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -93,6 +93,7 @@ S3method(report_finalize,reporter_ansi_tty) S3method(report_finalize,reporter_basic_tty) S3method(report_sleep,default) S3method(report_sleep,reporter_ansi_tty) +S3method(report_sleep,reporter_basic_tty) S3method(report_start_checks,reporter_ansi_tty) S3method(report_start_setup,reporter_ansi_tty) S3method(report_start_setup,reporter_basic_tty) diff --git a/NEWS.md b/NEWS.md index dd6fbc7..e0264e7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,8 @@ -# checked 0.2.3 (dev) +# checked 0.5.0 + +* Entire package refactor + +# checked 0.2.3 * Fix check processes hanging forever in some system configurations. @@ -21,6 +25,9 @@ * Prettify output by stripping excessive new lines. +* Force garbage collection before scheduling task, to make sure any already + finished processes are removed from the memory. + # checked 0.2.3 * Use custom `checked` `finisher`'s instead of the `processx` `finalizer`'s diff --git a/R/checker.R b/R/checker.R index 54cfdce..b87e95e 100644 --- a/R/checker.R +++ b/R/checker.R @@ -155,6 +155,7 @@ checker <- R6::R6Class( for (process in private$active) { if (!process$is_alive()) { process$finish() + private$gc_needed <- TRUE } else if (inherits(process, "check_process")) { # NOTE: check process never finishes unless we poll checks process$poll_output() @@ -165,8 +166,10 @@ checker <- R6::R6Class( return(-1L) } - # force garbage collection to free memory from terminated processes - gc(verbose = FALSE, reset = FALSE, full = TRUE) + if (options::opt("proactive_gc") && private$gc_needed) { + gc(verbose = FALSE, reset = FALSE, full = TRUE) + private$gc_needed <- FALSE + } # if all available processes are in use, terminate early n_active <- length(private$active) @@ -235,6 +238,9 @@ checker <- R6::R6Class( # failed tasks failed = list(), + # task loop counter + gc_needed = FALSE, + start_node = function(node) { task_graph_package_status(self$graph, node) <- STATUS$`in progress` private$start_node_meta_parents(node) @@ -264,9 +270,12 @@ checker <- R6::R6Class( parent_nodes <- V(self$graph)[parent_nodes] meta_parent_nodes <- parent_nodes[is_meta(parent_nodes$task)] for (meta in meta_parent_nodes) { - siblings <- igraph::adjacent_vertices(self$graph, meta, "out") - if (!all(siblings$status == STATUS$`done`)) next - task_graph_package_status(self$graph, meta) <- STATUS$`done` + siblings_by_meta_parent <- + igraph::adjacent_vertices(self$graph, meta, "out") + for (siblings in siblings_by_meta_parent) { + if (!all(siblings$status == STATUS$`done`)) next + task_graph_package_status(self$graph, meta) <- STATUS$`done` + } } }, @@ -293,11 +302,10 @@ checker <- R6::R6Class( "result.json" )) }) - self$graph <- task_graph_set_package_status( - self$graph, - checks[check_done], - STATUS$done - ) + + for (task in checks[check_done]) { + private$finish_node(task) + } }, pop_process = function(name) { diff --git a/R/options.R b/R/options.R index c31e56e..ec80dfa 100644 --- a/R/options.R +++ b/R/options.R @@ -3,6 +3,18 @@ options::define_options( "tty refresh interval when reporting results in milliseconds", tty_tick_interval = 0.1, + "deafult tty height used for the ANSI reporter. Used only + if correct values could not be acquired with system('tput lines')", + tty_default_height = 50, + + "`logical`, indicating whether additional garbage collection should be + performed before starting a new task, if at least one process recently + finalized. This can cause the checker to orchestrate tasks slower but + is recommended to be used for designs with many sub-processes required as + native garbage collection can lag leading to memory issues. Disable only + when maximum prefromance is required and memory is not the issue.", + proactive_gc = TRUE, + "character vector indicating whether R error should be thrown when issues are discovered when generating results. \"never\" means that no errors are thrown. If \"issues\" then errors are emitted only on issues, whereas diff --git a/R/plan.R b/R/plan.R index f81a575..7db8a8f 100644 --- a/R/plan.R +++ b/R/plan.R @@ -213,9 +213,6 @@ plan_local_checks <- function( #' #' @param package A path to package source. #' @param repos repository used to identify packages when name is provided. -#' @param dependencies either character vector or logical value specifying -#' which dependencies should be installed. -#' #' #' @family plan plan_local_install <- function( diff --git a/R/reporter_ansi_tty.R b/R/reporter_ansi_tty.R index 000df72..a23dc43 100644 --- a/R/reporter_ansi_tty.R +++ b/R/reporter_ansi_tty.R @@ -65,14 +65,18 @@ format_status_line_ansi.default <- function( status, width = getOption("width", 80L)) { - msg <- if (status == STATUS$done) { - "restored from system file." + if (status == STATUS$done) { + msg <- "restored from system file." + status <- "NONE" } else { - "starting ..." + msg <- "starting ..." + status <- silent_spinner(list( + frames = c("\u2834", "\u2826", "\u2816", "\u2832") + ))$spin() } out <- cli_table_row( - status = "NONE", + status = status, ok = 0, notes = 0, warnings = 0, @@ -255,6 +259,10 @@ report_start_setup.reporter_ansi_tty <- function( if (cli_env_has_pb(reporter$cli)) return() reporter$cli <- new.env(parent = reporter) + reporter$tty_height <- ansi_tty_height() + # Buffer is shorter than actual tty by one line due to progress bar existance + reporter$buffer_height <- reporter$tty_height - 1 + # hide cursor when initializer enters, ensure its restored even if interrupted cli::ansi_hide_cursor() do.call( @@ -319,9 +327,10 @@ report_start_checks.reporter_ansi_tty <- function( reporter$buffer_proto <- function(node = "") { df <- data.frame( # tracking columns - node = node, # reporter node name - new = TRUE, # whether node is newly added (requires newlines) - updated = NA # whether output needs to be updated + node = node, # reporter node name + new = TRUE, # whether node is newly added (requires newlines) + updated = NA, # whether output needs to be updated + final = FALSE # whether element is no longer a subject to change ) # output columns @@ -332,7 +341,7 @@ report_start_checks.reporter_ansi_tty <- function( # initialize our buffer of output reporter$buffer <- reporter$buffer_proto()[c(), ] - reporter$buffer_update <- function(node, lines) { + reporter$buffer_update <- function(node, lines, final = FALSE) { if (!node %in% reporter$buffer$node) { proto_df <- reporter$buffer_proto(node)[rep_len(1L, length(lines)), ] reporter$buffer <- rbind(reporter$buffer, proto_df) @@ -340,6 +349,7 @@ report_start_checks.reporter_ansi_tty <- function( is_node <- which(reporter$buffer$node == node) reporter$buffer$updated[is_node] <- TRUE + reporter$buffer$final[is_node] <- final reporter$buffer$line[is_node] <- lines } @@ -348,7 +358,8 @@ report_start_checks.reporter_ansi_tty <- function( node <- V(checker$graph)[node][[1]] to_report <- report_task(reporter, checker$graph, node) output <- vcapply(to_report, format) - reporter$buffer_update(node, output) + final <- node$status == STATUS$done + reporter$buffer_update(node, output, final = final) } extra <- list(message = "") @@ -373,7 +384,16 @@ report_status.reporter_ansi_tty <- function(reporter, checker, envir) { # add newly started task status is_running <- v$status > STATUS$ready & v$status < STATUS$done - is_newly_done <- v$status >= STATUS$done & !v$name %in% reporter$buffer$node + + is_done <- v$status >= STATUS$done + is_non_final_in_buffer <- vlapply(v, function(n) { + if (n %in% reporter$buffer$node) { + reporter$buffer$final[which(reporter$buffer$node == n)[[1]]] + } else { + FALSE + } + }) + is_newly_done <- is_done & !is_non_final_in_buffer updated <- v[is_running | is_newly_done] # skip if no updates @@ -388,7 +408,8 @@ report_status.reporter_ansi_tty <- function(reporter, checker, envir) { list(reporter_line( label = reporter_cell("", width = reporter$label_nchar), status = cli_table_row("S", "OK", "N", "W", "E", style = "title") - )) + )), + final = TRUE ) } @@ -413,16 +434,31 @@ report_status.reporter_ansi_tty <- function(reporter, checker, envir) { reporter$buffer$updated <- TRUE } + # Get number of lines that are final and didn't update since the last pass + finalized_lines <- + cumprod(!reporter$buffer$updated & reporter$buffer$final) == 1 + # Finalized lines as well as lines that are in progress but would exceed + # the maximum height of the tty should be skipped from reporting until + # the number of finished tasks allows to fit new ones. + reportable_lines <- !finalized_lines + # Which max returns the position of first TRUE, then we allow folloiwng + # reporter$buffer_height lines to be reported at the time + if (sum(reportable_lines) > reporter$buffer_height) { + reportable_lines[seq(which.max(reportable_lines) + reporter$buffer_height, + length(reportable_lines))] <- FALSE + } + # introduce newlines for newly added reporter rows - buffer <- strrep("\n", sum(reporter$buffer$new)) - reporter$buffer$new <- FALSE + buffer <- strrep( + "\n", sum(reporter$buffer$new & reportable_lines) + ) + reporter$buffer$new[reportable_lines] <- FALSE # for each not-yet finished task, report status - for (idx in which(reporter$buffer$updated)) { + for (idx in which(reporter$buffer$updated & reportable_lines)) { # derive reporter information - n_lines <- nrow(reporter$buffer) - idx + 1L + n_lines <- sum(reportable_lines) - idx + 1L + sum(finalized_lines) - # report status line buffer <- paste0( buffer, ansi_move_line_rel(n_lines), @@ -431,10 +467,11 @@ report_status.reporter_ansi_tty <- function(reporter, checker, envir) { ansi_move_line_rel(-n_lines), sep = "" ) + + reporter$buffer$updated[idx] <- FALSE } reporter$width <- cli::console_width() - reporter$buffer$updated <- FALSE cat(buffer) n_finished <- sum(v[is_check(v$task)]$status >= STATUS$done) @@ -447,13 +484,37 @@ report_status.reporter_ansi_tty <- function(reporter, checker, envir) { #' @export report_finalize.reporter_ansi_tty <- function(reporter, checker) { - report_status(reporter, checker) # report completions of final processes + # Init buffer + report_status(reporter, checker) + # Iterate until buffer is fully processed from final results + while (!all(!reporter$buffer$updated & reporter$buffer$final)) { + report_status(reporter, checker) + } cli::cli_progress_done(.envir = reporter$cli) cat(ansi_line_erase()) # clear lingering progress bar output + + # Display failures + failed_tasks <- checker$failed_tasks() + failed_packages <- + failed_tasks[vlapply(failed_tasks, function(x) is_install(x$task))] + + failures_output <- vcapply(failed_packages, function(x) { + paste0(cli_wrap_lines(cli::cli_fmt(cli::cli_alert_danger( + sprintf( + "%s package installation had non-zero exit status", + package(x$task[[1]]) + ), + ))), "\n", + cli_wrap_lines(as.character(cli::style_dim( + sprintf("log: %s", x$process[[1]]$log) + )))) + }) + + cat(failures_output, "\n") cli::ansi_show_cursor() } #' @export report_step.reporter_ansi_tty <- function(reporter, checker) { - checker$step() + checker$start_next_task() >= 0 } diff --git a/R/reporter_basic_tty.R b/R/reporter_basic_tty.R index 56360ef..efa4760 100644 --- a/R/reporter_basic_tty.R +++ b/R/reporter_basic_tty.R @@ -100,6 +100,16 @@ report_finalize.reporter_basic_tty <- function(reporter, checker) { cli::cli_text("Finished in {.time_taken {time}}") } +#' @export +report_sleep.reporter_basic_tty <- function( + reporter, + checker, + sleep = 0 +) { + # Basci tty does not need sleep + NULL +} + #' @export report_step.reporter_basic_tty <- function(reporter, checker) { checker$start_next_task() >= 0 diff --git a/R/utils-ansi.R b/R/utils-ansi.R index 72ae670..a5e8625 100644 --- a/R/utils-ansi.R +++ b/R/utils-ansi.R @@ -19,3 +19,14 @@ ansi_line_erase <- function(n = "") { ansi_move_line_rel <- function(n) { paste0("\033[", abs(n), if (n > 0L) "F" else "E") } + +#' @describeIn ansi +#' Get the height of the ansi tty using 'tput lines' interface +ansi_tty_height <- function() { + tryCatch( + as.numeric(system("tput lines", intern = TRUE, ignore.stderr = TRUE)), + warning = function(w) { + options::opt("tty_default_height") + } + ) +} diff --git a/man/ansi.Rd b/man/ansi.Rd index eaa6993..d12059c 100644 --- a/man/ansi.Rd +++ b/man/ansi.Rd @@ -4,11 +4,14 @@ \alias{ansi} \alias{ansi_line_erase} \alias{ansi_move_line_rel} +\alias{ansi_tty_height} \title{Various utilities for formatting ANSI output} \usage{ ansi_line_erase(n = "") ansi_move_line_rel(n) + +ansi_tty_height() } \arguments{ \item{n}{The number of lines to move. Positive is up, negative is down.} @@ -22,5 +25,7 @@ Various utilities for formatting ANSI output \item \code{ansi_move_line_rel()}: Offset the cursor by a relative number of lines +\item \code{ansi_tty_height()}: Get the height of the ansi tty using 'tput lines' interface + }} \keyword{internal} diff --git a/man/options.Rd b/man/options.Rd index bb8bbb0..d39b1f0 100644 --- a/man/options.Rd +++ b/man/options.Rd @@ -26,6 +26,24 @@ tty refresh interval when reporting results in milliseconds\item{default: }{\pre \item{envvar: }{R_CHECKED_TTY_TICK_INTERVAL (evaluated if possible, raw string otherwise)} }} +\item{tty_default_height}{\describe{ +deafult tty height used for the ANSI reporter. Used only +if correct values could not be acquired with system('tput lines')\item{default: }{\preformatted{50}} +\item{option: }{checked.tty_default_height} +\item{envvar: }{R_CHECKED_TTY_DEFAULT_HEIGHT (evaluated if possible, raw string otherwise)} +}} + +\item{proactive_gc}{\describe{ +\code{logical}, indicating whether additional garbage collection should be +performed before starting a new task, if at least one process recently +finalized. This can cause the checker to orchestrate tasks slower but +is recommended to be used for designs with many sub-processes required as +native garbage collection can lag leading to memory issues. Disable only +when maximum prefromance is required and memory is not the issue.\item{default: }{\preformatted{TRUE}} +\item{option: }{checked.proactive_gc} +\item{envvar: }{R_CHECKED_PROACTIVE_GC (evaluated if possible, raw string otherwise)} +}} + \item{results_error_on}{\describe{ character vector indicating whether R error should be thrown when issues are discovered when generating results. "never" means that no errors diff --git a/man/options_params.Rd b/man/options_params.Rd index 8a058d9..a109c74 100644 --- a/man/options_params.Rd +++ b/man/options_params.Rd @@ -4,6 +4,13 @@ \alias{options_params} \title{Checked Options} \arguments{ +\item{proactive_gc}{\code{logical}, indicating whether additional garbage collection should be +performed before starting a new task, if at least one process recently +finalized. This can cause the checker to orchestrate tasks slower but +is recommended to be used for designs with many sub-processes required as +native garbage collection can lag leading to memory issues. Disable only +when maximum prefromance is required and memory is not the issue. (Defaults to \code{TRUE}, overwritable using option 'checked.proactive_gc' or environment variable 'R_CHECKED_PROACTIVE_GC')} + \item{results_error_on}{character vector indicating whether R error should be thrown when issues are discovered when generating results. "never" means that no errors are thrown. If "issues" then errors are emitted only on issues, whereas @@ -30,6 +37,9 @@ the R CMD check. (Defaults to \verb{c(}\emph{R_CHECK_FORCE_SUGGESTS}\verb{= FALS \item{restore}{\code{logical} indicating whether output directory should be unlinked before running checks. If \code{FALSE}, an attempt will me made to restore previous progress from the same \code{output} (Defaults to \code{NA}, overwritable using option 'checked.restore' or environment variable 'R_CHECKED_RESTORE')} + +\item{tty_default_height}{deafult tty height used for the ANSI reporter. Used only +if correct values could not be acquired with system('tput lines') (Defaults to \code{50}, overwritable using option 'checked.tty_default_height' or environment variable 'R_CHECKED_TTY_DEFAULT_HEIGHT')} } \description{ Checked Options diff --git a/man/plan_local_install.Rd b/man/plan_local_install.Rd index b663750..8346cb5 100644 --- a/man/plan_local_install.Rd +++ b/man/plan_local_install.Rd @@ -10,9 +10,6 @@ plan_local_install(package, repos = getOption("repos")) \item{package}{A path to package source.} \item{repos}{repository used to identify packages when name is provided.} - -\item{dependencies}{either character vector or logical value specifying -which dependencies should be installed.} } \description{ Generates a plan for running installing a package from source. From 9a8297675ab8877d03f4d840e040e54e4c35b34f Mon Sep 17 00:00:00 2001 From: Szymon Maksymiuk <32574056+maksymiuks@users.noreply.github.com> Date: Mon, 16 Feb 2026 17:30:41 +0100 Subject: [PATCH 40/62] Reintroduce tests (#81) * Reintroduce tests * Refactor rcmd check process output * Fix accidental too big incrementation * Update tests * fix lintr --- NAMESPACE | 7 +- R/check.R | 18 +- R/check_process.R | 79 ++++++-- R/checker.R | 1 - R/install.R | 9 +- R/next_task.R | 12 +- R/pkg_origin.R | 4 +- R/plan.R | 28 +-- R/reporter_ansi_tty.R | 27 ++- R/reporter_null.R | 19 ++ R/results.R | 1 - R/task.R | 5 + R/task_graph.R | 6 +- R/utils-deps.R | 3 +- R/utils-igraph.R | 8 +- R/utils-paths.R | 4 +- inst/example_packages/exampleGood/DESCRIPTION | 2 +- .../example_packages/exampleGood/R/reexport.R | 1 + .../exampleGood/man/reexport_help.Rd | 32 +++ man/{check_dev_rev_deps.Rd => check_pkgs.Rd} | 21 +- man/check_rev_deps.Rd | 2 +- man/checker.Rd | 2 +- man/new_checker.Rd | 4 +- man/plan_rev_dep_checks.Rd | 14 +- tests/testthat.R | 2 +- tests/testthat/_snaps/deps.md | 187 ++++++++++++++++++ tests/testthat/_snaps/reporters.md | 28 +++ .../fixtures/revdeps/v1/pkg.none_1.0.0.tar.gz | Bin 889 -> 938 bytes tests/testthat/test-check-reverse.R | 89 +++++---- tests/testthat/test-check.R | 61 ++++-- tests/testthat/test-dep-graph-next-package.R | 14 +- tests/testthat/test-deps.R | 22 +++ tests/testthat/test-plan.R | 176 +++++++---------- tests/testthat/test-reporters.R | 95 +++++++++ tests/testthat/test-results-utils.R | 26 +++ tests/testthat/test-results.R | 32 --- 36 files changed, 735 insertions(+), 306 deletions(-) rename man/{check_dev_rev_deps.Rd => check_pkgs.Rd} (70%) create mode 100644 tests/testthat/_snaps/deps.md create mode 100644 tests/testthat/_snaps/reporters.md create mode 100644 tests/testthat/test-deps.R create mode 100644 tests/testthat/test-reporters.R create mode 100644 tests/testthat/test-results-utils.R delete mode 100644 tests/testthat/test-results.R diff --git a/NAMESPACE b/NAMESPACE index ff40220..95fccd5 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -61,6 +61,7 @@ S3method(lib_path,default) S3method(lib_path,pkg_origin_local) S3method(lib_path,pkg_origin_remote) S3method(lib_path,pkg_origin_repo) +S3method(package,"NULL") S3method(package,default) S3method(package,pkg_origin) S3method(package,task) @@ -91,15 +92,19 @@ S3method(remotes_graph,task_graph) S3method(report_finalize,"NULL") S3method(report_finalize,reporter_ansi_tty) S3method(report_finalize,reporter_basic_tty) +S3method(report_sleep,"NULL") S3method(report_sleep,default) S3method(report_sleep,reporter_ansi_tty) S3method(report_sleep,reporter_basic_tty) +S3method(report_start_checks,"NULL") S3method(report_start_checks,reporter_ansi_tty) +S3method(report_start_setup,"NULL") S3method(report_start_setup,reporter_ansi_tty) S3method(report_start_setup,reporter_basic_tty) S3method(report_status,"NULL") S3method(report_status,reporter_ansi_tty) S3method(report_status,reporter_basic_tty) +S3method(report_step,"NULL") S3method(report_step,reporter_ansi_tty) S3method(report_step,reporter_basic_tty) S3method(report_task,reporter_ansi_tty) @@ -119,7 +124,7 @@ S3method(start_task,igraph.vs) S3method(start_task,install_task) S3method(task_graph,task) S3method(task_graph,task_graph) -export(check_dev_rev_deps) +export(check_pkgs) export(check_rev_deps) export(check_task) export(checker) diff --git a/R/check.R b/R/check.R index 12f1111..a5a19ab 100644 --- a/R/check.R +++ b/R/check.R @@ -70,29 +70,29 @@ check_rev_deps <- function( output = output, lib.loc = lib.loc, repos = repos, + restore = restore ) run(checks, ...) checks } -#' Run reverse dependency checks against a development version only +#' Check packages #' -#' [`check_dev_rev_deps()`] works similarly to [`check_rev_deps()`] but it runs -#' R CMD check only once for each package, with the development version of the -#' package installed. It is advantageous to check whether adding a new package -#' into a repository breaks existing packages that possibly take said package -#' as a `Suggests` dependency. +#' Runs classical `R CMD check` for the given source package. It +#' first identifies and installs, in parallel, all dependencies required +#' to check the package. Then, it runs `R CMD check` for each specified package. #' #' @inheritParams check_functions #' @inheritParams run +#' @inheritParams plan_local_checks #' #' @inherit check_functions return #' #' @family checks #' @export -check_dev_rev_deps <- function( - path, +check_pkgs <- function( + package, n = 2L, output = tempfile(paste(utils::packageName(), Sys.Date(), sep = "-")), lib.loc = .libPaths(), @@ -101,7 +101,7 @@ check_dev_rev_deps <- function( ... ) { checks <- checker$new( - plan_rev_dep_checks(path = path, repos = repos, versions = "dev"), + plan_local_checks(package = package, repos = repos), n = n, output = output, lib.loc = lib.loc, diff --git a/R/check_process.R b/R/check_process.R index 00603a3..916306b 100644 --- a/R/check_process.R +++ b/R/check_process.R @@ -1,17 +1,35 @@ # Regular Expression for Parsing R CMD check checks # nolint start, styler: off RE_CHECK <- paste0( - "(?<=^|\n)", # starts on a new line (or start of string) - "\\* checking ", # literal "* checking " - "(?.*?)", # capture any check content as "check" - " \\.\\.\\.", # until literal "..." - "(?:", # ignore additional check details: - "[\\s\\*]{2,}", # any content starting with two or more of spaces or "*" - ".*?(?:\n|$)", # until a newline (or end of string) - ")*", # repeating until - "(?.*?)", # capturing a status as "status" - "(?=\n|$)" # terminated by a new line (or end of string) + "(?<=^|\\n)", # must start at beginning of string OR right after a newline + "\\* checking ", # literal "* checking " + "(?.*?)", # capture check name/content (non-greedy) as "check" + " \\.\\.\\.", # followed by literal " ..." + "(?:", # zero or more "detail" lines that belong to this check + "\\n[ \\t]*(?=\\n)", # a blank line (newline + optional spaces/tabs + next newline) + "|", + "\\n", # or: a normal detail line starting on the next line + "(?:[ \\t]{2,}", # either indented (2+ spaces/tabs) + "|\\*(?! (?:DONE|checking )))", # or a '*' line that is NOT "* DONE" and NOT "* checking ..." + "[^\\n]*(?:\\n|$)", # consume the rest of that detail line (to newline/end) + ")*", + "[ \\t]*", # allow extra spaces/tabs after "..." on the SAME line + "(?:", # position the engine right before a status token if one exists + # Case 1: status token is on the current line (possibly preceded by comment text) + "(?:[^\\n]*[ \\t]+)?(?=(?:[A-Z]{2}[A-Z0-9_-]*)\\s*(?:\\n|$))", + "|", + # Case 2: status token is on the next line: + # consume remainder of current line + newline + optional indent, + # but only if the next thing is a status token at end-of-line + "[^\\n]*\\n[ \\t]*(?=(?:[A-Z]{2}[A-Z0-9_-]*)\\s*(?:\\n|$))", + "|", + # Case 3: no status token (eat remainder/comment and stop here) + "[^\\n]*", + ")", + "(?(?:[A-Z]{2}[A-Z0-9_-]*)|)", # capture status token, or capture empty string if absent + "(?=\\s*(?:\\n|$))" # must end at newline/end (allow trailing whitespace) ) + # nolint end, styler: on #' @importFrom R6 R6Class @@ -23,6 +41,10 @@ check_process <- R6::R6Class( checks = function() { self$poll_output() private$parsed_checks + }, + results = function() { + private$cache_parsed_results() + private$parsed_results } ), public = list( @@ -46,9 +68,19 @@ check_process <- R6::R6Class( if (!self$is_alive()) callback(self) }, finish = function() { - self$poll_output() - self$save_results() - if (is.function(f <- private$finish_callback)) f(self) + # self$checks active binding calls poll_output so there is not need + # to call it explicitly + checks <- self$checks + # In some cases, check subprocess might suffer from a race condition, when + # process itself finished, but the final results of the last subcheck + # are not yet available to parse. Therefore we allow the process to + # finalize only if the last subcheck has reported status. + if (checks[length(checks)] != "") { + self$save_results() + private$cache_parsed_results() + private$free_file_descriptors() + if (is.function(f <- private$finish_callback)) f(self) + } }, get_time_last_check_start = function() { private$time_last_check_start @@ -124,6 +156,14 @@ check_process <- R6::R6Class( save_results = function() { path <- file.path(private$check_dir, "result.json") try(rcmdcheck_to_json(self$parse_results(), path), silent = TRUE) + }, + safe_parse_results = function() { + r <- try(self$parse_results(), silent = TRUE) + if (!inherits(r, "try-error")) { + r + } else { + NULL + } } ), private = list( @@ -138,10 +178,21 @@ check_process <- R6::R6Class( "WARNING", "ERROR" )), + parsed_results = NULL, parsed_partial_check_output = "", throttle = NULL, spinners = NULL, - finish_callback = NULL + finish_callback = NULL, + cache_parsed_results = function() { + r <- self$safe_parse_results() + private$parsed_results <- r %||% private$parsed_results + }, + free_file_descriptors = function() { + if (self$has_output_connection()) close(self$get_output_connection()) + if (self$has_error_connection()) close(self$get_error_connection()) + if (self$has_poll_connection()) close(self$get_poll_connection()) + if (self$has_input_connection()) close(self$get_input_connection()) + } ) ) diff --git a/R/checker.R b/R/checker.R index b87e95e..16adfb5 100644 --- a/R/checker.R +++ b/R/checker.R @@ -151,7 +151,6 @@ checker <- R6::R6Class( #' @return A integer value, coercible to logical to indicate whether a new #' process was spawned, or `-1` if all tasks have finished. start_next_task = function() { - # finish any finished processes for (process in private$active) { if (!process$is_alive()) { process$finish() diff --git a/R/install.R b/R/install.R index cb5f2d2..34bda88 100644 --- a/R/install.R +++ b/R/install.R @@ -12,7 +12,7 @@ install_process <- R6::R6Class( lib = .libPaths()[[1]], libpaths = .libPaths(), available_packages_filters = getOption("available_packages_filters"), - log + log = NULL ) { if (!dir.exists(lib)) dir.create(lib, recursive = TRUE) private$package <- pkgs @@ -53,6 +53,7 @@ install_process <- R6::R6Class( }, finish = function() { private$time_finish <- Sys.time() + private$free_file_descriptors() if (is.function(f <- private$finish_callback)) f(self) }, get_r_exit_status = function() { @@ -81,6 +82,12 @@ install_process <- R6::R6Class( private$options <- options super$initialize(options = options) + }, + free_file_descriptors = function() { + if (self$has_output_connection()) close(self$get_output_connection()) + if (self$has_error_connection()) close(self$get_error_connection()) + if (self$has_poll_connection()) close(self$get_poll_connection()) + if (self$has_input_connection()) close(self$get_input_connection()) } ) ) diff --git a/R/next_task.R b/R/next_task.R index ec0cc15..070035d 100644 --- a/R/next_task.R +++ b/R/next_task.R @@ -42,7 +42,10 @@ start_task.install_task <- function( ... ) { task <- node$task[[1]] - libpaths <- task_graph_libpaths(g, node, lib.loc = lib.loc, output = output) + libpaths <- unique(c( + task_graph_libpaths(g, node, lib.loc = lib.loc, output = output), + lib.loc + )) install_parameters <- install_params(task$origin) if (any(inherits(task$origin, c("pkg_origin_base", "pkg_origin_unknown")))) { @@ -50,7 +53,7 @@ start_task.install_task <- function( } # install_parameters$package is a valid package name only for - # pkg_origin_local. Otherwise it's a path to the source package in which case + # pkg_origin_repo. Otherwise it's a path to the source package in which case # is_package_installed returns FALSE (as it should) if (is_package_installed(install_parameters$package, libpaths)) { return(NULL) @@ -78,7 +81,10 @@ start_task.check_task <- function( ... ) { task <- node$task[[1]] - libpaths <- task_graph_libpaths(g, node, lib.loc = lib.loc, output = output) + libpaths <- unique(c( + task_graph_libpaths(g, node, lib.loc = lib.loc, output = output), + lib.loc + )) path <- check_path(task$origin, output = path_sources()) check_process$new( diff --git a/R/pkg_origin.R b/R/pkg_origin.R index 98f1106..bbbf1c4 100644 --- a/R/pkg_origin.R +++ b/R/pkg_origin.R @@ -212,14 +212,14 @@ pkg_deps.pkg_origin_local <- function( dependencies = dependencies, db = row ) - direct_deps$depth <- "direct" + direct_deps$depth <- rep.int("direct", NROW(direct_deps)) indirect_deps <- pkg_dependencies( packages = direct_deps$name, dependencies = dependencies, db = db ) - indirect_deps$depth <- "indirect" + indirect_deps$depth <- rep.int("indirect", NROW(indirect_deps)) rbind(direct_deps, indirect_deps) } diff --git a/R/plan.R b/R/plan.R index 7db8a8f..eda9c32 100644 --- a/R/plan.R +++ b/R/plan.R @@ -7,22 +7,13 @@ #' #' @param path path to the package source. #' @param repos repository used to identify reverse dependencies. -#' @param versions character vector indicating against which versions of the -#' package reverse dependency should be checked. `c("dev", "release")` -#' (default) stands for the classical reverse dependency check. `"dev"` -#' checks only against development version of the package which is applicable -#' mostly when checking whether adding new package would break tests of -#' packages already in the repository and take the package as suggests -#' dependency. #' #' @family plan #' @export plan_rev_dep_checks <- function( path, - repos = getOption("repos"), - versions = c("dev", "release") + repos = getOption("repos") ) { - version_types <- match.arg(versions, c("dev", "release"), several.ok = TRUE) path <- check_path_is_pkg_source(path) ap <- available_packages(repos = repos) @@ -35,22 +26,7 @@ plan_rev_dep_checks <- function( )[[1]] if (length(revdeps) == 0) { - return(igraph::make_empty_graph()) - } - - if ("release" %in% version_types && !package %in% ap[, "Package"]) { - msg <- sprintf( - "Skipping 'release' checks. Package `%s` not found in repositories: \n", - package, - paste0(" * ", repos, collapse = "\n") - ) - - warning(msg, immediate. = TRUE) - version_types <- setdiff(version_types, "release") - } - - if (length(version_types) == 0) { - return(igraph::make_empty_graph()) + return(task_graph_class(igraph::make_empty_graph())) } # root meta task, indicating a reverse-dependency check plan diff --git a/R/reporter_ansi_tty.R b/R/reporter_ansi_tty.R index a23dc43..db24e77 100644 --- a/R/reporter_ansi_tty.R +++ b/R/reporter_ansi_tty.R @@ -499,15 +499,24 @@ report_finalize.reporter_ansi_tty <- function(reporter, checker) { failed_tasks[vlapply(failed_tasks, function(x) is_install(x$task))] failures_output <- vcapply(failed_packages, function(x) { - paste0(cli_wrap_lines(cli::cli_fmt(cli::cli_alert_danger( - sprintf( - "%s package installation had non-zero exit status", - package(x$task[[1]]) - ), - ))), "\n", - cli_wrap_lines(as.character(cli::style_dim( - sprintf("log: %s", x$process[[1]]$log) - )))) + msg <- paste0( + cli_wrap_lines(cli::cli_fmt(cli::cli_alert_danger( + sprintf( + "%s package installation had non-zero exit status", + package(x$task[[1]]) + ) + ))), + collapse = "\n" + ) + log <- paste0( + cli_wrap_lines(cli::cli_fmt(cli::cli_alert_danger( + sprintf("log: %s", x$process[[1]]$log) + ))), + collapse = "\n" + ) + paste0( + msg, "\n", log + ) }) cat(failures_output, "\n") diff --git a/R/reporter_null.R b/R/reporter_null.R index 301bf78..347a1d5 100644 --- a/R/reporter_null.R +++ b/R/reporter_null.R @@ -1,5 +1,24 @@ +#' @export +report_start_setup.NULL <- function(...) {} + +#' @export +report_start_checks.NULL <- function(...) {} + +#' @export +report_finalize.NULL <- function(...) {} + #' @export report_status.NULL <- function(...) {} #' @export report_finalize.NULL <- function(...) {} + +#' @export +report_step.NULL <- function(reporter, checker) { + checker$start_next_task() >= 0 +} + +#' @export +report_sleep.NULL <- function(reporter, checker, sleep = 0) { + Sys.sleep(sleep) +} diff --git a/R/results.R b/R/results.R index 05c33f4..eb61cc1 100644 --- a/R/results.R +++ b/R/results.R @@ -227,7 +227,6 @@ filter_results <- function(x, keep, ...) { } else { x } - } count <- function(d, ...) { diff --git a/R/task.R b/R/task.R index 464e089..4c9cd47 100644 --- a/R/task.R +++ b/R/task.R @@ -148,6 +148,11 @@ package.default <- function(x) { stop("Unrecognized type") } +#' @export +package.NULL <- function(x) { + "" +} + #' @export package.task <- function(x) { package(x$origin) diff --git a/R/task_graph.R b/R/task_graph.R index 7f383b0..3bf9d6a 100644 --- a/R/task_graph.R +++ b/R/task_graph.R @@ -201,7 +201,11 @@ task_graph_sort <- function(g) { # use only strong dependencies to prioritize by topology (leafs first) strong_edges <- dep_edges(E(g), check_dependencies("strong")) - g_strong <- igraph::subgraph.edges(g, strong_edges, delete.vertices = FALSE) + g_strong <- igraph::subgraph_from_edges( + g, + strong_edges, + delete.vertices = FALSE + ) topo <- igraph::topo_sort(g_strong, mode = "out") priority_topo <- integer(length(g)) priority_topo[match(topo$name, V(g)$name)] <- rev(seq_along(topo)) diff --git a/R/utils-deps.R b/R/utils-deps.R index 7881450..16cb37b 100644 --- a/R/utils-deps.R +++ b/R/utils-deps.R @@ -68,6 +68,7 @@ pkg_dependencies <- function( verbose = FALSE ) { dependencies <- as_pkg_dependencies(dependencies) + na_version <- package_version(NA_character_, strict = FALSE) proto_df <- data.frame( package = character(0L), @@ -78,7 +79,7 @@ pkg_dependencies <- function( ) depth <- 0L - out <- list() + out <- list(list(proto_df)) while (length(packages) > 0L) { depth <- depth + 1L deptypes <- if (depth == 1L) dependencies$direct else dependencies$indirect diff --git a/R/utils-igraph.R b/R/utils-igraph.R index 8162763..e199a4f 100644 --- a/R/utils-igraph.R +++ b/R/utils-igraph.R @@ -59,11 +59,11 @@ graph_dedup_attrs <- function(g) { for (i in seq_along(v_dup_attrs)) { attr_name <- names(v_dup_attrs[i]) attr_value <- igraph::vertex_attr(g, v_dup_attrs[[i]][[1L]]) - g <- igraph::remove.vertex.attribute(g, v_dup_attrs[[i]][[1L]]) + g <- igraph::delete_vertex_attr(g, v_dup_attrs[[i]][[1L]]) for (attr_dup_name in v_dup_attrs[[i]][-1L]) { is_na <- is.na(attr_value) attr_value[is_na] <- igraph::vertex_attr(g, attr_dup_name)[is_na] - g <- igraph::remove.vertex.attribute(g, attr_dup_name) + g <- igraph::delete_vertex_attr(g, attr_dup_name) } g <- igraph::set_vertex_attr(g, attr_name, value = attr_value) } @@ -76,11 +76,11 @@ graph_dedup_attrs <- function(g) { for (i in seq_along(e_dup_attrs)) { attr_name <- names(e_dup_attrs[i]) attr_value <- igraph::edge_attr(g, e_dup_attrs[[i]][[1L]]) - g <- igraph::remove.edge.attribute(g, e_dup_attrs[[i]][[1L]]) + g <- igraph::delete_edge_attr(g, e_dup_attrs[[i]][[1L]]) for (attr_dup_name in e_dup_attrs[[i]][-1L]) { is_na <- is.na(attr_value) attr_value[is_na] <- igraph::edge_attr(g, attr_dup_name)[is_na] - g <- igraph::remove.edge.attribute(g, attr_dup_name) + g <- igraph::delete_edge_attr(g, attr_dup_name) } g <- igraph::set_edge_attr(g, attr_name, value = attr_value) } diff --git a/R/utils-paths.R b/R/utils-paths.R index 586b82c..1ff40a1 100644 --- a/R/utils-paths.R +++ b/R/utils-paths.R @@ -25,9 +25,7 @@ format_simplify_path <- function(x, ..., full.path = FALSE) { parts <- "." } do.call(file.path, as.list(parts)) - } - - if (first_diff > min_len) { + } else if (first_diff > min_len) { parts <- utils::tail(xp, -first_diff + 1) do.call(file.path, as.list(parts)) } else if (first_diff <= min_len) { diff --git a/inst/example_packages/exampleGood/DESCRIPTION b/inst/example_packages/exampleGood/DESCRIPTION index dce9fc7..c9b9d5c 100644 --- a/inst/example_packages/exampleGood/DESCRIPTION +++ b/inst/example_packages/exampleGood/DESCRIPTION @@ -10,7 +10,7 @@ Authors@R: Description: What the package does (one paragraph). Imports: methods, - DBI + R6 License: file LICENSE Encoding: UTF-8 LazyData: true diff --git a/inst/example_packages/exampleGood/R/reexport.R b/inst/example_packages/exampleGood/R/reexport.R index d124949..8b3fd37 100644 --- a/inst/example_packages/exampleGood/R/reexport.R +++ b/inst/example_packages/exampleGood/R/reexport.R @@ -1,5 +1,6 @@ #' Reexport utils::help #' #' @importFrom utils help +#' @inheritParams utils::help #' @export reexport_help <- utils::help diff --git a/inst/example_packages/exampleGood/man/reexport_help.Rd b/inst/example_packages/exampleGood/man/reexport_help.Rd index 3607d44..8329f07 100644 --- a/inst/example_packages/exampleGood/man/reexport_help.Rd +++ b/inst/example_packages/exampleGood/man/reexport_help.Rd @@ -13,6 +13,38 @@ reexport_help( help_type = getOption("help_type") ) } +\arguments{ +\item{topic}{usually, a \link{name} or character string specifying the + topic for which help is sought. A character string (enclosed in + explicit single or double quotes) is always taken as naming a topic. + + If the value of \code{topic} is a length-one + character vector the topic is taken to be the value of the only + element. Otherwise \code{topic} must be a name or a \link{reserved} + word (if syntactically valid) or character string. + + See \sQuote{Details} for what happens if this is omitted. + } + +\item{package}{a name or character vector giving the packages to look + into for documentation, or \code{NULL}. By default, all packages + whose namespaces are loaded are used. To avoid a name being deparsed use e.g. + \code{(pkg_ref)} (see the examples).} + +\item{lib.loc}{a character vector of directory names of \R libraries, + or \code{NULL}. The default value of \code{NULL} corresponds to all + libraries currently known. If the default is used, the loaded + packages are searched before the libraries. This is not used for + HTML help (see \sQuote{Details}).} + +\item{verbose}{logical; if \code{TRUE}, the file name is reported.} + +\item{try.all.packages}{logical; see \code{Note}.} + +\item{help_type}{character string: the type of help required. + Possible values are \code{"text"}, \code{"html"} and \code{"pdf"}. + Case is ignored, and partial matching is allowed.} +} \description{ Reexport utils::help } diff --git a/man/check_dev_rev_deps.Rd b/man/check_pkgs.Rd similarity index 70% rename from man/check_dev_rev_deps.Rd rename to man/check_pkgs.Rd index 5c0ff93..3f3fd6c 100644 --- a/man/check_dev_rev_deps.Rd +++ b/man/check_pkgs.Rd @@ -1,11 +1,11 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/check.R -\name{check_dev_rev_deps} -\alias{check_dev_rev_deps} -\title{Run reverse dependency checks against a development version only} +\name{check_pkgs} +\alias{check_pkgs} +\title{Check packages} \usage{ -check_dev_rev_deps( - path, +check_pkgs( + package, n = 2L, output = tempfile(paste(utils::packageName(), Sys.Date(), sep = "-")), lib.loc = .libPaths(), @@ -15,7 +15,8 @@ check_dev_rev_deps( ) } \arguments{ -\item{path}{file path to the package source directory} +\item{package}{A path to either package, directory with packages or name +of the package (details)} \item{n}{\code{integer} value indicating maximum number of subprocesses that can be simultaneously spawned when executing tasks.} @@ -41,11 +42,9 @@ regarding checks that run. Can be combined with \code{\link{results}} and \code{\link[=summary]{summary()}} methods to generate results. } \description{ -\code{\link[=check_dev_rev_deps]{check_dev_rev_deps()}} works similarly to \code{\link[=check_rev_deps]{check_rev_deps()}} but it runs -R CMD check only once for each package, with the development version of the -package installed. It is advantageous to check whether adding a new package -into a repository breaks existing packages that possibly take said package -as a \code{Suggests} dependency. +Runs classical \verb{R CMD check} for the given source package. It +first identifies and installs, in parallel, all dependencies required +to check the package. Then, it runs \verb{R CMD check} for each specified package. } \seealso{ Other checks: diff --git a/man/check_rev_deps.Rd b/man/check_rev_deps.Rd index 80d6afd..e729aee 100644 --- a/man/check_rev_deps.Rd +++ b/man/check_rev_deps.Rd @@ -62,7 +62,7 @@ identify changes in reverse dependency behaviors. } \seealso{ Other checks: -\code{\link{check_dev_rev_deps}()}, +\code{\link{check_pkgs}()}, \code{\link{checker}}, \code{\link{new_checker}()} } diff --git a/man/checker.Rd b/man/checker.Rd index f874878..1dbab10 100644 --- a/man/checker.Rd +++ b/man/checker.Rd @@ -29,7 +29,7 @@ while (!orchestrator$is_done()) { } \seealso{ Other checks: -\code{\link{check_dev_rev_deps}()}, +\code{\link{check_pkgs}()}, \code{\link{check_rev_deps}()}, \code{\link{new_checker}()} } diff --git a/man/new_checker.Rd b/man/new_checker.Rd index 80ae561..6e8c94d 100644 --- a/man/new_checker.Rd +++ b/man/new_checker.Rd @@ -19,12 +19,12 @@ Instantiate a check design from a path or directory. } \seealso{ Other checks: -\code{\link{check_dev_rev_deps}()}, +\code{\link{check_pkgs}()}, \code{\link{check_rev_deps}()}, \code{\link{checker}} Other checks: -\code{\link{check_dev_rev_deps}()}, +\code{\link{check_pkgs}()}, \code{\link{check_rev_deps}()}, \code{\link{checker}} } diff --git a/man/plan_rev_dep_checks.Rd b/man/plan_rev_dep_checks.Rd index 40bcfb4..a61a5a6 100644 --- a/man/plan_rev_dep_checks.Rd +++ b/man/plan_rev_dep_checks.Rd @@ -4,24 +4,12 @@ \alias{plan_rev_dep_checks} \title{Plan Reverse Dependency Checks} \usage{ -plan_rev_dep_checks( - path, - repos = getOption("repos"), - versions = c("dev", "release") -) +plan_rev_dep_checks(path, repos = getOption("repos")) } \arguments{ \item{path}{path to the package source.} \item{repos}{repository used to identify reverse dependencies.} - -\item{versions}{character vector indicating against which versions of the -package reverse dependency should be checked. \code{c("dev", "release")} -(default) stands for the classical reverse dependency check. \code{"dev"} -checks only against development version of the package which is applicable -mostly when checking whether adding new package would break tests of -packages already in the repository and take the package as suggests -dependency.} } \description{ Generates a plan for running reverse dependency check for certain diff --git a/tests/testthat.R b/tests/testthat.R index 6d04abf..78ec056 100644 --- a/tests/testthat.R +++ b/tests/testthat.R @@ -9,4 +9,4 @@ library(testthat) library(checked) -#test_check("checked") +test_check("checked") diff --git a/tests/testthat/_snaps/deps.md b/tests/testthat/_snaps/deps.md new file mode 100644 index 0000000..8830e13 --- /dev/null +++ b/tests/testthat/_snaps/deps.md @@ -0,0 +1,187 @@ +# pkg_dependencies works as expected for local package + + Code + local_deps + Output + package type name op version + 1 checked Depends R >= 3, 6, 2 + 2 checked Imports callr + 3 checked Imports cli + 4 checked Imports glue + 5 checked Imports igraph + 6 checked Imports jsonlite + 7 checked Imports memoise + 8 checked Imports options + 9 checked Imports R6 + 10 checked Imports rcmdcheck + 11 checked Imports rlang + 12 checked Imports utils >= 3, 6, 2 + 13 checked Imports tools + 14 checked Suggests remotes + 15 checked Suggests testthat >= 3, 0, 0 + 16 checked Suggests visNetwork + 17 checked Suggests withr + +# pkg_dependencies works as expected for cran package + + Code + df + Output + package type name op version + 1 checked Imports callr + 2 checked Imports cli + 3 checked Imports igraph + 4 checked Imports jsonlite + 5 checked Imports options + 6 checked Imports R6 + 7 checked Imports rcmdcheck + 8 checked Imports utils >= 3, 6, 2 + 9 checked Imports tools + 10 checked Suggests testthat >= 3, 0, 0 + 11 checked Suggests withr + 12 callr Depends R >= 3, 4 + 13 cli Depends R >= 3, 4 + 14 igraph Depends methods + 15 igraph Depends R >= 3, 5, 0 + 16 jsonlite Depends methods + 17 R6 Depends R >= 3, 6 + 18 testthat Depends R >= 4, 1, 0 + 19 withr Depends R >= 3, 6, 0 + 20 callr Imports processx >= 3, 6, 1 + 21 callr Imports R6 + 22 callr Imports utils + 23 cli Imports utils + 24 igraph Imports cli + 25 igraph Imports graphics + 26 igraph Imports grDevices + 27 igraph Imports lifecycle + 28 igraph Imports magrittr + 29 igraph Imports Matrix + 30 igraph Imports pkgconfig >= 2, 0, 0 + 31 igraph Imports rlang >= 1, 1, 0 + 32 igraph Imports stats + 33 igraph Imports utils + 34 igraph Imports vctrs + 35 options Imports utils + 36 rcmdcheck Imports callr >= 3, 1, 1, 9000 + 37 rcmdcheck Imports cli >= 3, 0, 0 + 38 rcmdcheck Imports curl + 39 rcmdcheck Imports desc >= 1, 2, 0 + 40 rcmdcheck Imports digest + 41 rcmdcheck Imports pkgbuild + 42 rcmdcheck Imports prettyunits + 43 rcmdcheck Imports R6 + 44 rcmdcheck Imports rprojroot + 45 rcmdcheck Imports sessioninfo >= 1, 1, 1 + 46 rcmdcheck Imports utils + 47 rcmdcheck Imports withr + 48 rcmdcheck Imports xopen + 49 testthat Imports brio >= 1, 1, 5 + 50 testthat Imports callr >= 3, 7, 6 + 51 testthat Imports cli >= 3, 6, 5 + 52 testthat Imports desc >= 1, 4, 3 + 53 testthat Imports evaluate >= 1, 0, 4 + 54 testthat Imports jsonlite >= 2, 0, 0 + 55 testthat Imports lifecycle >= 1, 0, 4 + 56 testthat Imports magrittr >= 2, 0, 3 + 57 testthat Imports methods + 58 testthat Imports pkgload >= 1, 4, 0 + 59 testthat Imports praise >= 1, 0, 0 + 60 testthat Imports processx >= 3, 8, 6 + 61 testthat Imports ps >= 1, 9, 1 + 62 testthat Imports R6 >= 2, 6, 1 + 63 testthat Imports rlang >= 1, 1, 6 + 64 testthat Imports utils + 65 testthat Imports waldo >= 0, 6, 2 + 66 testthat Imports withr >= 3, 0, 2 + 67 withr Imports graphics + 68 withr Imports grDevices + 69 igraph LinkingTo cpp11 >= 0, 5, 0 + 70 processx Depends R >= 3, 4, 0 + 71 lifecycle Depends R >= 3, 6 + 72 magrittr Depends R >= 3, 4, 0 + 73 Matrix Depends R >= 4, 4 + 74 Matrix Depends methods + 75 rlang Depends R >= 4, 0, 0 + 76 vctrs Depends R >= 4, 0, 0 + 77 curl Depends R >= 3, 0, 0 + 78 desc Depends R >= 3, 4 + 79 digest Depends R >= 3, 3, 0 + 80 pkgbuild Depends R >= 3, 5 + 81 prettyunits Depends R >= 2, 10 + 82 rprojroot Depends R >= 3, 0, 0 + 83 sessioninfo Depends R >= 3, 4 + 84 xopen Depends R >= 3, 1 + 85 brio Depends R >= 3, 6 + 86 evaluate Depends R >= 3, 6, 0 + 87 pkgload Depends R >= 3, 4, 0 + 88 ps Depends R >= 3, 4 + 89 waldo Depends R >= 4, 0 + 90 cpp11 Depends R >= 4, 0, 0 + 91 processx Imports ps >= 1, 2, 0 + 92 processx Imports R6 + 93 processx Imports utils + 94 lifecycle Imports cli >= 3, 4, 0 + 95 lifecycle Imports rlang >= 1, 1, 0 + 96 Matrix Imports grDevices + 97 Matrix Imports graphics + 98 Matrix Imports grid + 99 Matrix Imports lattice + 100 Matrix Imports stats + 101 Matrix Imports utils + 102 pkgconfig Imports utils + 103 rlang Imports utils + 104 vctrs Imports cli >= 3, 4, 0 + 105 vctrs Imports glue + 106 vctrs Imports lifecycle >= 1, 0, 3 + 107 vctrs Imports rlang >= 1, 1, 7 + 108 desc Imports cli + 109 desc Imports R6 + 110 desc Imports utils + 111 digest Imports utils + 112 pkgbuild Imports callr >= 3, 2, 0 + 113 pkgbuild Imports cli >= 3, 4, 0 + 114 pkgbuild Imports desc + 115 pkgbuild Imports processx + 116 pkgbuild Imports R6 + 117 sessioninfo Imports cli >= 3, 1, 0 + 118 sessioninfo Imports tools + 119 sessioninfo Imports utils + 120 xopen Imports processx + 121 pkgload Imports cli >= 3, 3, 0 + 122 pkgload Imports desc + 123 pkgload Imports fs + 124 pkgload Imports glue + 125 pkgload Imports lifecycle + 126 pkgload Imports methods + 127 pkgload Imports pkgbuild + 128 pkgload Imports processx + 129 pkgload Imports rlang >= 1, 1, 1 + 130 pkgload Imports rprojroot + 131 pkgload Imports utils + 132 ps Imports utils + 133 waldo Imports cli + 134 waldo Imports diffobj >= 0, 3, 4 + 135 waldo Imports glue + 136 waldo Imports methods + 137 waldo Imports rlang >= 1, 1, 0 + 138 lattice Depends R >= 4, 0, 0 + 139 glue Depends R >= 3, 6 + 140 fs Depends R >= 3, 6 + 141 diffobj Depends R >= 3, 1, 0 + 142 lattice Imports grid + 143 lattice Imports grDevices + 144 lattice Imports graphics + 145 lattice Imports stats + 146 lattice Imports utils + 147 glue Imports methods + 148 fs Imports methods + 149 diffobj Imports crayon >= 1, 3, 2 + 150 diffobj Imports tools + 151 diffobj Imports methods + 152 diffobj Imports utils + 153 diffobj Imports stats + 154 crayon Imports grDevices + 155 crayon Imports methods + 156 crayon Imports utils + diff --git a/tests/testthat/_snaps/reporters.md b/tests/testthat/_snaps/reporters.md new file mode 100644 index 0000000..6806e4f --- /dev/null +++ b/tests/testthat/_snaps/reporters.md @@ -0,0 +1,28 @@ +# reporter_basic_tty works as expected for pkg.none + + Code + run(design, reporter = reporter) + Message + +# reporter_basic_tty works as expected for pkg.ok.error + + Code + run(design, reporter = reporter) + Message + Checks + [][install] rev.both.dependency started + [][install] rev.both.dependency finished () + [][install] pkg.ok.error started + [][install] pkg.ok.error finished () + [][install] pkg.ok.error started + [][check] rev.both.ok started + [][install] pkg.ok.error finished () + [][check] rev.both.ok finished with 1 NOTE () + [][check] rev.both.error started + [][check] rev.both.error finished with 1 NOTE () + [][check] rev.both.ok started + [][check] rev.both.ok finished with 1 NOTE () + [][check] rev.both.error started + [][check] rev.both.error finished with 1 ERROR, 1 WARNING () + Finished in + diff --git a/tests/testthat/fixtures/revdeps/v1/pkg.none_1.0.0.tar.gz b/tests/testthat/fixtures/revdeps/v1/pkg.none_1.0.0.tar.gz index 1822907aab9b94878770094665451f027d368316..69565551d8e51aa7d9606375f0045ac71f2e7500 100644 GIT binary patch literal 938 zcmV;b16BMViwFP!000001MOM;Z`wE*=4byE?`4{n=pZyO3`u0+}T$#rPjFQ=noF+Y->vxCDJ7IE)g(n^2X59+TW4zw<&SndpLL zQj?P7m5Q@M9tB+>fXFdB6T0>`DWuYxpp97d#L&D?FL92?jhJDR2NT18FNOD#6@5@)^+pmhM zufp%fl!7e^mdA!kMoGwpL@S&QXYe!36YR@q*c*(`24o<@EK0i(m)jT_a~{cFw#<{1ZF(y* zvbBEH1)JJ_i`p&ffaP{Q+Qq>6toJM2&fKlpyHJ@KN*lwUXuKw%>HY%!E6W(SVY$9<`L;)0ANk*LI$q8Hhrq?)IHxezBm3}$MI|aKLlRFJB|{NDIUS!H>kQRwQ6@!7^D1Dz@tQ! z88H(Pc?r{$qu}49Mp?Kj^>-y!ArTO?<0~^D?*&`(_0C-SMBcMBVe(#@DmM`8lQIo% z(^eA2?wafr)D42^(Vd82lbtG_ByoIe+M4_a`E2V`2Q#WTkbdef4koQABO*5 z!LFQo@d__E+VK3Y41?D#n6E@wDlpxEH387#yNW+)wG#V(`@bsxgKqE5{~x*k_Z+L{ z{~s{^<^97`F9Z+rzu&n#|FgVu|L@p#&Ho1(f2QJ!+Y=F)+e0y3+dY@kn(%RzaP{Rx zE183yaam9JZBlQxWl8;!W`oW14~MMtRl5Tcbve8b27H M0apjyI{+jA0Imo41poj5 literal 889 zcmV-<1BUz`iwFP!000001MOJ-Z`wE*=4byE?`4{n=t^(`fht?4R=`#y3Mi#_s(*FW!igUNI-9@U;1 z6wz+A%4?_Xlvir6(+GoWZ&vAM zRzW!{oHyoVY@V@nVVGnX`aH=o3TJ~U{0XxV$1)sr`=j$d=_kGj!es8k#q>k{ka*(e zcFwWyD9oiEv+ODm*9i_~>Rt4WZShD*?5<;4rcKV5^EuCDz7Bf6Ns$rfLEaT{8b)kA z+C-2|^aB@cq)eS2)@>Us+ogxDW#I_AZ(+N0H(__73^NolhEEv01HjOI0sUTN406W8 zMB=jZ&V^dbMPmR$o!@xR*jU+^dr zU#~?L1*R8NrvFW9KUjaK(`+mKuL7^(BS#C!BoE-*ExPW~t=cXcW3-V8N1r zyoO1{(eSTx1K}?V|6Q6@2ovxci)+&(pA#1I)y`h}hkRyH$npnyvN%AjPK!L)<}GtH zyDPF&Q8x(Y2X`iZMRuBCnbPoQ;s5C5tbaZ^>F&V+KE{9RJN`GFPDk;-3cPv>{|UcI zMJDwfdK!v##0NUcN;UAiEV!t>4W$_<$V{iO_;`!fcT1x-_hxIRh zzdrYi;Bo)|aQ&U8O_lyv0e~p{ma*(s-|hqhr9GD-4QJ^8^?N6AI6Atg`kHe83JMAe PzbpO)%6Tcp03-ka1;xfN diff --git a/tests/testthat/test-check-reverse.R b/tests/testthat/test-check-reverse.R index c406e0b..25af09b 100644 --- a/tests/testthat/test-check-reverse.R +++ b/tests/testthat/test-check-reverse.R @@ -48,54 +48,58 @@ test_that("check_rev_deps works for package with one breaking change", { expect_true(is.list(r)) expect_named(r) expect_length(r, 1L) - expect_length(r$revdep_check_task, 2L) + expect_length(r[[1]], 2L) + + expect_s3_class(r[[1]], "rev_dep_dep_results") + expect_s3_class(r[[1]][[1]], "rcmdcheck_rev_dep_results") + expect_s3_class(r[[1]][[2]], "rcmdcheck_rev_dep_results") # rev.both.error - expect_length(r$revdep_check_task$rev.both.error$notes$issues, 0L) - expect_length(r$revdep_check_task$rev.both.error$notes$potential_issues$new, 0L) - expect_length(r$revdep_check_task$rev.both.error$notes$potential_issues$old, 0L) + expect_length(r[[1]][[2]]$notes$issues, 0L) + expect_length(r[[1]][[2]]$notes$potential_issues$new, 0L) + expect_length(r[[1]][[2]]$notes$potential_issues$old, 0L) - expect_length(r$revdep_check_task$rev.both.error$warnings$issues, 1L) + expect_length(r[[1]][[2]]$warnings$issues, 1L) expect_true( grepl("Namespace in Imports field not imported from", - r$revdep_check_task$rev.both.error$warnings$issues), + r[[1]][[2]]$warnings$issues), grepl("Missing or unexported object", - r$revdep_check_task$rev.both.error$warnings$issues) + r[[1]][[2]]$warnings$issues) ) - expect_length(r$revdep_check_task$rev.both.error$warnings$potential_issues$new, 0L) - expect_length(r$revdep_check_task$rev.both.error$warnings$potential_issues$old, 0L) + expect_length(r[[1]][[2]]$warnings$potential_issues$new, 0L) + expect_length(r[[1]][[2]]$warnings$potential_issues$old, 0L) - expect_length(r$revdep_check_task$rev.both.error$errors$issues, 1L) + expect_length(r[[1]][[2]]$errors$issues, 1L) expect_true( grepl("Running the tests in", - r$revdep_check_task$rev.both.error$errors$issues), + r[[1]][[2]]$errors$issues), grepl("is not an exported object from", - r$revdep_check_task$rev.both.error$errors$issues) + r[[1]][[2]]$errors$issues) ) - expect_length(r$revdep_check_task$rev.both.error$errors$potential_issues$new, 0L) - expect_length(r$revdep_check_task$rev.both.error$errors$potential_issues$old, 0L) + expect_length(r[[1]][[2]]$errors$potential_issues$new, 0L) + expect_length(r[[1]][[2]]$errors$potential_issues$old, 0L) # rev.both.ok - expect_length(r$revdep_check_task$rev.both.ok$notes$issues, 0L) - expect_length(r$revdep_check_task$rev.both.ok$notes$potential_issues$new, 0L) - expect_length(r$revdep_check_task$rev.both.ok$notes$potential_issues$old, 0L) + expect_length(r[[1]][[1]]$notes$issues, 0L) + expect_length(r[[1]][[1]]$notes$potential_issues$new, 0L) + expect_length(r[[1]][[1]]$notes$potential_issues$old, 0L) - expect_length(r$revdep_check_task$rev.both.ok$warnings$issues, 0L) - expect_length(r$revdep_check_task$rev.both.ok$warnings$potential_issues$new, 0L) - expect_length(r$revdep_check_task$rev.both.ok$warnings$potential_issues$old, 0L) + expect_length(r[[1]][[1]]$warnings$issues, 0L) + expect_length(r[[1]][[1]]$warnings$potential_issues$new, 0L) + expect_length(r[[1]][[1]]$warnings$potential_issues$old, 0L) - expect_length(r$revdep_check_task$rev.both.ok$errors$issues, 0L) - expect_length(r$revdep_check_task$rev.both.ok$errors$potential_issues$new, 0L) - expect_length(r$revdep_check_task$rev.both.ok$errors$potential_issues$old, 0L) + expect_length(r[[1]][[1]]$errors$issues, 0L) + expect_length(r[[1]][[1]]$errors$potential_issues$new, 0L) + expect_length(r[[1]][[1]]$errors$potential_issues$old, 0L) }) -test_that("check_rev_deps works for a package without release version", { +test_that("check_rev_deps works for a package without a version in repos", { # Ensure source installation to make sure test works also on mac and windows withr::with_options(list(pkgType = "source"), { - expect_warning(design <- check_rev_deps( + expect_no_error(design <- check_rev_deps( file.path(sources_new, "pkg.suggests"), n = 2L, repos = repo, @@ -106,26 +110,33 @@ test_that("check_rev_deps works for a package without release version", { r <- results(design) expect_s3_class(r, "checked_results") expect_true(is.list(r)) + expect_length( + list.dirs(file.path(design$output, "checks"), recursive = FALSE), + 2 + ) expect_named(r) expect_length(r, 1L) - expect_length(r$check_task, 1L) + expect_length(r[[1]], 1L) + + expect_s3_class(r[[1]], "rev_dep_dep_results") + expect_s3_class(r[[1]][[1]], "rcmdcheck_rev_dep_results") - expect_length(r$check_task$`pkg.none (dev)`$notes$issues, 0L) - expect_length(r$check_task$`pkg.none (dev)`$notes$potential_issues$new, 0L) - expect_length(r$check_task$`pkg.none (dev)`$notes$potential_issues$old, 0L) + expect_length(r[[1]][[1]]$notes$issues, 0L) + expect_length(r[[1]][[1]]$notes$potential_issues$new, 0L) + expect_length(r[[1]][[1]]$notes$potential_issues$old, 0L) - expect_length(r$check_task$`pkg.none (dev)`$warnings$issues, 0L) - expect_length(r$check_task$`pkg.none (dev)`$warnings$potential_issues$new, 0L) - expect_length(r$check_task$`pkg.none (dev)`$warnings$potential_issues$old, 0L) + expect_length(r[[1]][[1]]$warnings$issues, 0L) + expect_length(r[[1]][[1]]$warnings$potential_issues$new, 0L) + expect_length(r[[1]][[1]]$warnings$potential_issues$old, 0L) - expect_length(r$check_task$`pkg.none (dev)`$errors$issues, 1L) + expect_length(r[[1]][[1]]$errors$issues, 1L) expect_true( - grepl("Running the tests in", - r$check_task$`pkg.none (dev)`$errors$issues), - grepl("\"hello world\" is not TRUE", - r$check_task$`pkg.none (dev)`$errors$issues) + grepl("Running the tests in", r[[1]][[1]]$errors$issues) + ) + expect_true( + grepl("Reverse suggested deps detected", r[[1]][[1]]$errors$issues) ) - expect_length(r$check_task$`pkg.none (dev)`$errors$potential_issues$new, 0L) - expect_length(r$check_task$`pkg.none (dev)`$errors$potential_issues$old, 0L) + expect_length(r[[1]][[1]]$errors$potential_issues$new, 0L) + expect_length(r[[1]][[1]]$errors$potential_issues$old, 0L) }) diff --git a/tests/testthat/test-check.R b/tests/testthat/test-check.R index 3af567d..9dcf61f 100644 --- a/tests/testthat/test-check.R +++ b/tests/testthat/test-check.R @@ -1,23 +1,50 @@ test_that("check_pkgs works as expected", { examples_path <- system.file("example_packages", package = "checked") - # WIP - expect_no_error(check_pkgs( - file.path(examples_path, c("exampleGood", "exampleBad")), - n = 2L, - repos = "https://cran.r-project.org/", - reporter = NULL - )) -}) + expect_no_error( + plan <- check_pkgs( + file.path(examples_path, c("exampleGood", "exampleBad")), + n = 2L, + repos = "https://cran.r-project.org/", + reporter = NULL, + lib.loc = .libPaths() + ) + ) + + r <- results(plan) + expect_s3_class(r, "checked_results") + expect_true(is.list(r)) + expect_length( + list.dirs(file.path(plan$output, "checks"), recursive = FALSE), + 2 + ) + expect_named(r) + expect_length(r, 1L) + expect_length(r[[1]], 2L) -test_that("check_pkgs works as expected", { - examples_path <- system.file("example_packages", package = "checked") + expect_s3_class(r[[1]], "local_check_results") + + expect_length(r[[1]][[1]]$notes$issues, 1L) + expect_length(r[[1]][[1]]$notes$potential_issues$new, 0L) + expect_length(r[[1]][[1]]$notes$potential_issues$old, 0L) + + expect_length(r[[1]][[1]]$warnings$issues, 3L) + expect_length(r[[1]][[1]]$warnings$potential_issues$new, 0L) + expect_length(r[[1]][[1]]$warnings$potential_issues$old, 0L) + + expect_length(r[[1]][[1]]$errors$issues, 0L) + expect_length(r[[1]][[1]]$errors$potential_issues$new, 0L) + expect_length(r[[1]][[1]]$errors$potential_issues$old, 0L) + + expect_length(r[[1]][[2]]$notes$issues, 0L) + expect_length(r[[1]][[2]]$notes$potential_issues$new, 0L) + expect_length(r[[1]][[2]]$notes$potential_issues$old, 0L) + + expect_length(r[[1]][[2]]$warnings$issues, 0L) + expect_length(r[[1]][[2]]$warnings$potential_issues$new, 0L) + expect_length(r[[1]][[2]]$warnings$potential_issues$old, 0L) - # WIP - expect_no_error(check_pkgs( - file.path(examples_path, c("exampleGood", "exampleBad")), - n = 2L, - repos = "https://cran.r-project.org/", - reporter = NULL - )) + expect_length(r[[1]][[2]]$errors$issues, 0L) + expect_length(r[[1]][[2]]$errors$potential_issues$new, 0L) + expect_length(r[[1]][[2]]$errors$potential_issues$old, 0L) }) diff --git a/tests/testthat/test-dep-graph-next-package.R b/tests/testthat/test-dep-graph-next-package.R index 3a95b6a..8375f1e 100644 --- a/tests/testthat/test-dep-graph-next-package.R +++ b/tests/testthat/test-dep-graph-next-package.R @@ -1,10 +1,10 @@ test_that("dep_graph_next_package finds next installable package", { # nolint start, styler: off g <- igraph::make_graph(~ - A +- B +- C, - A +------ D, - A +- E +- D, - A +- F +- D + A -+ B -+ C, + A ------+ D, + A -+ E -+ D, + A -+ F -+ D ) # nolint end, styler: on @@ -21,12 +21,14 @@ test_that("dep_graph_next_package finds next installable package", { V(g)["D"]$status <- STATUS[["in progress"]] V(g)["C"]$status <- STATUS[["done"]] g <- task_graph_update_ready(g) - expect_equal(names(task_graph_which_ready(g)), "B") + ready_nodes <- V(g)[V(g)$status == STATUS$ready] + expect_equal(names(ready_nodes), "B") # if the order is reversed, now "F" and "E" should be next V(g)$status <- STATUS[["pending"]] V(g)["D"]$status <- STATUS[["done"]] V(g)["C"]$status <- STATUS[["in progress"]] g <- task_graph_update_ready(g) - expect_equal(names(task_graph_which_ready(g)), c("F", "E")) + ready_nodes <- V(g)[V(g)$status == STATUS$ready] + expect_equal(names(ready_nodes), c("F", "E")) }) diff --git a/tests/testthat/test-deps.R b/tests/testthat/test-deps.R new file mode 100644 index 0000000..bdaa058 --- /dev/null +++ b/tests/testthat/test-deps.R @@ -0,0 +1,22 @@ +test_that("pkg_dependencies works as expected for local package", { + desc <- read.dcf(system.file("DESCRIPTION", package = "checked")) + rownames(desc) <- "checked" + + local_deps <- pkg_dependencies( + packages = "checked", + dependencies = TRUE, + db = desc + ) + expect_snapshot(local_deps) +}) + +test_that("pkg_dependencies works as expected for cran package", { + skip_on_cran() + df <- pkg_dependencies( + "checked", + db = available_packages( + repos = "https://packagemanager.posit.co/cran/2026-02-01" + ) + ) + expect_snapshot(df) +}) \ No newline at end of file diff --git a/tests/testthat/test-plan.R b/tests/testthat/test-plan.R index a4b9d99..5a78db4 100644 --- a/tests/testthat/test-plan.R +++ b/tests/testthat/test-plan.R @@ -1,69 +1,58 @@ -test_that("rev_dep_check_tasks_df works with deafult params", { - expect_silent( - df <- plan_rev_dep_checks( - test_path("fixtures", "DALEXtra"), - repos = "https://cran.r-project.org/" - ) - ) - - expect_s3_class(df, "data.frame") - expect_true(NROW(df) >= 8) - expect_named(df, c("alias", "version", "package", "custom")) - - expect_s3_class(df$package, "list_of_task") - task_classes <- vcapply(df$package, function(x) class(x)[[1]]) - expect_equal(unique(task_classes), "revdep_check_task") - pkg_sub_classes <- vcapply(df$package, function(x) class(x$package)[[1]]) - expect_equal(unique(pkg_sub_classes), "pkg_origin_repo") - - expect_s3_class(df$custom, "list_of_task") - task_classes <- vcapply(df$custom, function(x) class(x)[[1]]) - expect_equal(unique(task_classes), "custom_install_task") - pkg_sub_classes <- vcapply(df$custom, function(x) class(x$package)[[1]]) - expect_equal(unique(pkg_sub_classes), c("pkg_origin_local", "pkg_origin_repo")) - - expect_true(all(endsWith(df$alias[seq(1, NROW(df), by = 2)], "(dev)"))) - expect_true(all(endsWith(df$alias[seq(2, NROW(df), by = 2)], "(v2.3.0)"))) - - # Test displayes - expect_no_error(expect_output(print(df))) - expect_no_error(expect_output(print(df$package))) - expect_no_error(expect_output(print(df$custom))) -}) +default_env <- options::opt("check_envvars", env = "checked") +default_args <- options::opt("check_args", env = "checked") +default_build_args <- options::opt("check_build_args", env = "checked") -test_that("rev_dep_check_tasks_df development_only = TRUE", { +test_that("rev_dep_check_tasks_df works with deafult params", { expect_silent( plan <- plan_rev_dep_checks( test_path("fixtures", "DALEXtra"), - repos = "https://cran.r-project.org/", - versions = "dev" + repos = "https://packagemanager.posit.co/cran/2026-02-01" ) ) - expect_s3_class(plan, "data.frame") - expect_true(NROW(plan) >= 4) - expect_named(plan, c("alias", "version", "package", "custom")) - - expect_s3_class(plan$package, "list_of_task") - task_classes <- vcapply(plan$package, function(x) class(x)[[1]]) - expect_equal(unique(task_classes), "check_task") - pkg_sub_classes <- vcapply(plan$package, function(x) class(x$package)[[1]]) - expect_equal(unique(pkg_sub_classes), "pkg_origin_repo") - - expect_s3_class(plan$custom, "list_of_task") - task_classes <- vcapply(plan$custom, function(x) class(x)[[1]]) - expect_equal(unique(task_classes), "custom_install_task") - package_sub_classes <- vcapply(plan$custom, function(x) class(x$package)[[1]]) - expect_equal(unique(package_sub_classes), c("pkg_origin_local")) + expect_s3_class(plan, "task_graph") + expect_true(length(plan) >= 15) - expect_true(all(endsWith(plan$alias, "(dev)"))) - expect_true(all(!endsWith(plan$alias, "(v2.3.0)"))) + expect_all_true( + c( + "rev_dep_dep_meta_task", + "rev_dep_check_meta_task", + "check_task", + "install_task" + ) %in% vcapply(V(plan)$task, function(x) + class(x)[[1]]) + ) + expect_s3_class(V(plan)$task[[1]], "rev_dep_dep_meta_task") + expect_s3_class(V(plan)$task[[1]]$origin, "pkg_origin_local") + expect_true(V(plan)$task[[1]]$origin$package == "DALEXtra") + expect_s3_class(V(plan)$task[[1]]$origin$version, "package_version") + expect_true(V(plan)$task[[1]]$origin$version == "2.3.0") + + + expect_s3_class(V(plan)$task[[3]], "check_task") + expect_equal( + names(V(plan)$task[[3]]), + c("env", "args", "build_args", "origin", "seed") + ) + expect_s3_class(V(plan)$task[[3]]$origin, "pkg_origin_repo") + expect_equal(V(plan)$task[[3]]$env, default_env) + expect_equal(V(plan)$task[[3]]$args, default_args) + expect_equal(V(plan)$task[[3]]$build_args, default_build_args) + expect_true(V(plan)$task[[3]]$origin$package == "marginaleffects") + expect_s3_class(V(plan)$task[[3]]$origin$version, "package_version") + expect_true(V(plan)$task[[3]]$origin$version == "0.31.0") + + # Test displayes + expect_no_error(expect_output(print(plan))) + expect_no_error(expect_output(print(V(plan)$task[[1]]))) + expect_no_error(expect_output(print(V(plan)$task[[3]]))) + expect_no_error(expect_output(print(V(plan)$task[[3]]$origin))) }) test_that("source_check_tasks_df works as expected", { examples_path <- system.file("example_packages", package = "checked") expect_silent( - df <- plan_checks( + plan <- plan_local_checks( c( test_path("fixtures", "DALEXtra"), test_path("fixtures", "rd2markdown"), @@ -73,61 +62,36 @@ test_that("source_check_tasks_df works as expected", { ) ) ) - expect_s3_class(df, "data.frame") - expect_equal(NROW(df), 5) - expect_named(df, c("alias", "version", "package", "custom")) - - expect_s3_class(df$package, "list_of_task") - expect_equal(unique(vcapply(df$package, function(x) class(x)[[1]])), "check_task") - expect_equal(unique(vcapply(df$package, function(x) class(x$package)[[1]])), "pkg_origin_local") - - expect_s3_class(df$custom, "list_of_task") - expect_equal(unique(vcapply(df$custom, function(x) class(x)[[1]])), "custom_install_task") - expect_equal(unique(vcapply(df$custom, function(x) class(x$package)[[1]])), "NULL") - - expect_true(all(endsWith(df$alias, "(source)"))) -}) - -test_that("source_check_tasks_df aliases are properly handled", { - examples_path <- system.file("example_packages", package = "checked") - names <- c( - "DALEXtra_new", - "rd2markdown_new", - "exampleGood_new", - "exampleOkay_new", - "exampleBad_new" - ) - - path <- c( - test_path("fixtures", "DALEXtra"), - test_path("fixtures", "rd2markdown"), - file.path(examples_path, "exampleGood"), - file.path(examples_path, "exampleOkay"), - file.path(examples_path, "exampleBad") - ) - names(path) <- names - - expect_silent( - df <- plan_checks(path) - ) - - expect_true(all(endsWith(df$alias, "_new"))) - expect_equal(df$alias, names) - - expect_silent( - df <- plan_checks(c( - file.path(examples_path, "exampleGood"), - file.path(examples_path, "exampleGood"), - file.path(examples_path, "exampleGood") - )) + expect_s3_class(plan, "task_graph") + expect_true(length(plan) == 6) + + expect_all_true( + c( + "local_check_meta_task", + "check_task" + ) %in% vcapply(V(plan)$task, function(x) + class(x)[[1]]) ) + expect_s3_class(V(plan)$task[[1]], "local_check_meta_task") + expect_null(V(plan)$task[[1]]$origin) + + expect_s3_class(V(plan)$task[[2]], "check_task") expect_equal( - df$alias, - c( - "exampleGood (source_1)", - "exampleGood (source_2)", - "exampleGood (source_3)" - ) + names(V(plan)$task[[3]]), + c("env", "args", "build_args", "origin") ) + expect_s3_class(V(plan)$task[[3]]$origin, "pkg_origin_local") + expect_equal(V(plan)$task[[3]]$env, default_env) + expect_equal(V(plan)$task[[3]]$args, default_args) + expect_equal(V(plan)$task[[3]]$build_args, default_build_args) + expect_true(V(plan)$task[[3]]$origin$package == "rd2markdown") + expect_s3_class(V(plan)$task[[3]]$origin$version, "package_version") + expect_true(V(plan)$task[[3]]$origin$version == "0.0.8") + + # Test displayes + expect_no_error(expect_output(print(plan))) + expect_no_error(expect_output(print(V(plan)$task[[1]]))) + expect_no_error(expect_output(print(V(plan)$task[[3]]))) + expect_no_error(expect_output(print(V(plan)$task[[3]]$origin))) }) diff --git a/tests/testthat/test-reporters.R b/tests/testthat/test-reporters.R new file mode 100644 index 0000000..6413c74 --- /dev/null +++ b/tests/testthat/test-reporters.R @@ -0,0 +1,95 @@ +create_temp_repo <- function(dir, repo_path) { + contrib_url <- utils::contrib.url(repo_path, type = "source") + dir.create(contrib_url, recursive = TRUE) + sources <- list.files(dir, pattern = "^.*\\.tar\\.gz$", full.names = TRUE) + vapply(sources, file.copy, FUN.VALUE = logical(1), to = contrib_url) + tools::write_PACKAGES(contrib_url, type = "source") +} + +sources_old <- test_path("fixtures", "revdeps", "v1") +sources_new <- test_path("fixtures", "revdeps", "v2") + +dir.create(repo_dir <- tempfile("repo")) +repo <- paste0("file:///", repo_dir) +create_temp_repo(sources_old, repo_dir) +old <- getOption("pkgType") +options(pkgType = "source") + +test_that("reporter_basic_tty works as expected for pkg.none", { + plan <- plan_rev_dep_checks( + file.path(sources_new, "pkg.none"), + repos = repo + ) + + design <- checker$new( + plan, + n = 1L, + repos = repo, + restore = FALSE + ) + + reporter <- reporter_basic_tty() + + expect_snapshot( + run(design, reporter = reporter), + # We remove the last line as it reports the time which can change + transform = function(lines) { + lines[-length(lines)] + } + ) +}) + +test_that("reporter_basic_tty works as expected for pkg.ok.error", { + + plan <- plan_rev_dep_checks( + file.path(sources_new, "pkg.ok.error"), + repos = repo + ) + + design <- checker$new( + plan, + n = 1L, + repos = repo, + restore = FALSE + ) + + reporter <- reporter_basic_tty() + + expect_snapshot( + run(design, reporter = reporter), + # We remove the last line as it reports the time which can change + transform = function(lines) { + lines <- gsub("\\d+(?:\\.\\d+)?(?:ms|s|m)", "", lines) + lines[!startsWith(lines, "ETA")] + } + ) +}) + +test_that("reporter_ansi_tty works as expected for pkg.ok.error", { + plan <- plan_rev_dep_checks( + file.path(sources_new, "pkg.ok.error"), + repos = repo + ) + + design <- checker$new( + plan, + n = 1L, + repos = repo, + restore = FALSE + ) + reporter <- reporter_ansi_tty() + + expect_no_error(suppressMessages( + capture.output( + run(design, reporter = reporter) + ) + )) + + expect_s3_class(reporter$buffer, "data.frame") + expect_equal(NROW(reporter$buffer), 7) + expect_all_true(reporter$buffer$final) + expect_all_false(reporter$buffer$updated) + expect_all_false(reporter$buffer$new) +}) + +options(pkgType = old) diff --git a/tests/testthat/test-results-utils.R b/tests/testthat/test-results-utils.R new file mode 100644 index 0000000..d5a6434 --- /dev/null +++ b/tests/testthat/test-results-utils.R @@ -0,0 +1,26 @@ +test_that("results_to_df works as expected", { + examples_path <- system.file("example_packages", package = "checked") + + expect_no_error( + plan <- check_pkgs( + file.path(examples_path, c("exampleGood", "exampleBad")), + n = 2L, + repos = "https://cran.r-project.org/", + reporter = NULL + ) + ) + + r <- results(plan) + df <- results_to_df(r[[1]]) + expect_equal(NROW(df), 2) + expect_equal(names(df), c("notes", "warnings", "errors")) + expect_equal(df$notes, c(1, 0)) + expect_equal(df$warnings, c(3, 0)) + expect_equal(df$errors, c(0, 0)) + expect_true( + all( + endsWith(row.names(df)[[1]], "check-exampleBad"), + endsWith(row.names(df)[[2]], "check-exampleGood") + ) + ) +}) diff --git a/tests/testthat/test-results.R b/tests/testthat/test-results.R deleted file mode 100644 index 1edab35..0000000 --- a/tests/testthat/test-results.R +++ /dev/null @@ -1,32 +0,0 @@ -test_that("results_to_file works as expected", { - examples_path <- system.file("example_packages", package = "checked") - - # WIP - expect_no_error( - plan <- check_pkgs( - file.path(examples_path, c("exampleGood", "exampleBad")), - n = 2L, - repos = "https://cran.r-project.org/", - reporter = NULL - ) - ) - - r <- results(plan) - r_file <- tempfile() - expect_no_error(results_to_file(r, r_file)) - expect_true(!identical(readLines(r_file), "No issues identified.")) - - expect_no_error( - plan <- check_rev_deps( - file.path(examples_path, "exampleBad"), - n = 2L, - repos = "https://cran.r-project.org/", - reporter = NULL - ) - ) - - r <- results(plan) - r_file <- tempfile() - expect_no_error(results_to_file(r, r_file)) - expect_true(identical(readLines(r_file), "No issues identified.")) -}) From 6bd072b505f2f8cec51202087eca465f3b4415c2 Mon Sep 17 00:00:00 2001 From: Szymon Maksymiuk <32574056+maksymiuks@users.noreply.github.com> Date: Mon, 16 Feb 2026 21:39:18 +0100 Subject: [PATCH 41/62] 82 update documentation and readme (#83) * Reintroduce tests * Refactor rcmd check process output * Update documentation and readme * Fix accidental too big incrementation * Update readme and documentation --- NAMESPACE | 1 - R/next_task.R | 21 ++++++++++++ R/pkg_origin.R | 2 -- R/run.R | 3 +- README.Rmd | 35 +++++++++++++------- README.md | 16 ++++----- man/figures/README/ansi-tty-example-dark.svg | 2 +- man/figures/README/ansi-tty-example.svg | 2 +- man/pkg_origin.Rd | 3 -- man/start_task.Rd | 20 +++++++++++ man/task_graph_libpaths.Rd | 22 ++++++++++++ 11 files changed, 98 insertions(+), 29 deletions(-) create mode 100644 man/start_task.Rd create mode 100644 man/task_graph_libpaths.Rd diff --git a/NAMESPACE b/NAMESPACE index 95fccd5..426b05d 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -148,7 +148,6 @@ export(reporter_default) export(results) export(run) export(task) -export(try_pkg_origin_repo) import(cli) import(options) importFrom(R6,R6Class) diff --git a/R/next_task.R b/R/next_task.R index 070035d..ef0049b 100644 --- a/R/next_task.R +++ b/R/next_task.R @@ -1,3 +1,14 @@ +#' Libpaths from task graph +#' +#' Function that traverses over the task dependency task to acquire libpaths +#' for given nodes. It ensures that when runing a node, a libpath is +#' constructed which has all the required packages on it. +#' +#' @param g `task_graph` object +#' @param node Node(s) for which libpath should be constructed based on `g` +#' @param output Path to the checked output directory +#' @inheritParams lib + task_graph_libpaths <- function( g, node = NULL, @@ -22,6 +33,14 @@ task_graph_libpaths <- function( unique(unlist(task_lib)) } +#' Start a new task +#' +#' Starts task based on the `task` object encapsulated in the `node` taken +#' from then `task_graph` `g`. It returns an `install_process` or +#' `check_process` `R6` object. +#' +#' @inheritParams task_graph_libpaths +#' @param ... additional params passed to downstream methods start_task <- function(node, g, ...) { UseMethod("start_task") } @@ -34,6 +53,7 @@ start_task.igraph.vs <- function(node, g, ...) { } #' @export +#' @method start_task install_task start_task.install_task <- function( node, g, @@ -73,6 +93,7 @@ start_task.install_task <- function( } #' @export +#' @method start_task check_task start_task.check_task <- function( node, g, diff --git a/R/pkg_origin.R b/R/pkg_origin.R index bbbf1c4..40ebedd 100644 --- a/R/pkg_origin.R +++ b/R/pkg_origin.R @@ -73,8 +73,6 @@ pkg_origin_repo <- function(package, repos, ...) { } -#' @export -#' @rdname pkg_origin try_pkg_origin_repo <- function(package, repos, ...) { if (isTRUE(pkg_origin_is_base(package))) { pkg_origin_base(package, ...) diff --git a/R/run.R b/R/run.R index 49658be..b2615ca 100644 --- a/R/run.R +++ b/R/run.R @@ -19,13 +19,14 @@ run <- function(checker, ..., reporter = reporter_default()) { #' @export run.character <- function(checker, ..., reporter = reporter_default()) { + checker <- new_rev_dep_checker(checker, ...) report_start_setup( reporter, checker, extra = list(message = "planning checks ...") ) - run(new_rev_dep_checker(checker, ...), reporter = reporter) + run(checker, reporter = reporter) } #' @export diff --git a/README.Rmd b/README.Rmd index 4b3eb0c..276ceea 100644 --- a/README.Rmd +++ b/README.Rmd @@ -6,6 +6,12 @@ always_allow_html: yes +```{sh clone-dev-praise, echo = FALSE, results = "hide"} +# praise chosen for having few direct and reverse dependencies +rm -rf /tmp/praise +git clone https://github.com/gaborcsardi/praise /tmp/praise +``` + ```{r, include = FALSE, cache = FALSE} knitr::opts_chunk$set( collapse = TRUE, @@ -22,8 +28,17 @@ knitr::opts_chunk$set( asciicast::init_knitr_engine( startup = bquote({ options(repos = .(getOption("repos"))) + plan <- checked::plan_rev_dep_checks("/tmp/praise") + design <- checked::checker$new( + plan, + n = 10, + lib.loc = .libPaths(), + restore = FALSE + ) }), - echo_input = FALSE + echo_input = FALSE, + timeout = 300, + interactive = FALSE ) ``` @@ -35,12 +50,6 @@ asciicast::init_knitr_engine( [![coverage](https://codecov.io/gh/Genentech/checked/branch/main/graph/badge.svg)](https://app.codecov.io/gh/Genentech/checked/tree/main) -```{sh clone-dev-praise, echo = FALSE, results = "hide"} -# praise chosen for having few direct and reverse dependencies -rm -rf /tmp/praise -git clone https://github.com/gaborcsardi/praise /tmp/praise -``` - # Running Checks Although `checked` is broadly capable of running arbitrary sets of `R CMD check` @@ -51,7 +60,7 @@ Running reverse dependency checks is as easy as ```r library(checked) -x <- run("/home/dev/praise") +x <- run("/home/dev/praise", n = 4) results(x) ``` ```{r, echo = FALSE} @@ -77,10 +86,12 @@ run("/home/dev/praise") ``` ```{asciicast ansi-tty-example, cache = FALSE} #| asciicast_knitr_output = "svg", -#| asciicast_at = "all", #| asciicast_cursor = FALSE, -#| asciicast_speed = 2 -options(checked.tty_tick_interval = 200) -checked::run("/tmp/praise") +#| asciicast_speed = 2, +#| asciicast_timeout = 300, +#| asciicast_at = "all", +#| asciicast_idle_time_limit = 2 +options(checked.tty_tick_interval = 0.01) +checked::run(design) cat() ``` diff --git a/README.md b/README.md index 87a9cf6..5d44fec 100644 --- a/README.md +++ b/README.md @@ -14,26 +14,26 @@ checked # Running Checks -Although `checked` is broadly capable of running arbitrary sets of `R -CMD check` tasks, reverse dependency checking is one of the most common -use cases where batch `R CMD check`s are needed. +Although `checked` is broadly capable of running arbitrary sets of +`R CMD check` tasks, reverse dependency checking is one of the most +common use cases where batch `R CMD check`s are needed. Running reverse dependency checks is as easy as ``` r library(checked) -x <- run("/home/dev/praise") +x <- run("/home/dev/praise", n = 4) results(x) ``` - #> # Revdep Check Task Spec + #> # praise reverse dependency check results (1c999505a831-meta-revdeps-of-praise) #> - #> goodpractice package R CMD check diff + #> testthat package R CMD check diff #> notes: OK #> warnings: OK #> errors: OK #> - #> testthat package R CMD check diff + #> goodpractice package R CMD check diff #> notes: OK #> warnings: OK #> errors: OK @@ -57,5 +57,5 @@ run("/home/dev/praise") - + diff --git a/man/figures/README/ansi-tty-example-dark.svg b/man/figures/README/ansi-tty-example-dark.svg index f524fd4..7d22c89 100644 --- a/man/figures/README/ansi-tty-example-dark.svg +++ b/man/figures/README/ansi-tty-example-dark.svg @@ -1 +1 @@ -ETA?(0/4)[1.1s]installingpraise(release),diffviewerETA?(0/4)[1.4s]installingpraise(release),diffviewerETA?(0/4)[1.6s]installingpraise(release),diffviewerETA?(0/4)[1.8s]installingpraise(release),diffviewerETA?(0/4)[2.1s]installingpraise(release),diffviewerETA?(0/4)[2.3s]installingpraise(release),diffviewerETA?(0/4)[2.5s]installingpraise(release),diffviewerETA?(0/4)[2.7s]installingpraise(release),diffviewerETA?(0/4)[3s]installingpraise(release),diffviewerETA?(0/4)[3.2s]installingpraise(release),diffviewerETA?(0/4)[3.4s]installingpraise(release),diffviewerETA?(0/4)[3.6s]installingpraise(release),diffviewerETA?(0/4)[3.9s]installingdiffviewer,praise(dev)ETA?(0/4)[4.2s]installingdiffviewer,praise(dev)SOKNWEtestthat(v1.0.0)00000.9sstarting...ETA?(0/4)[7.3s]installingpraise(dev)testthat(v1.0.0)20002.7scheckingpackagenamespaceinfortestthat(dev)00001.0sstarting...ETA?(0/4)[9.2s]testthat(v1.0.0)50003.1scheckingifthereisanamespacetestthat(dev)00001.4sstarting...ETA?(0/4)[9.7s]testthat(v1.0.0)50003.6scheckingifthereisanamespacetestthat(dev)00001.8sstarting...ETA?(0/4)[10s]testthat(v1.0.0)50003.9scheckingifthereisanamespacetestthat(dev)20002.1scheckingpackagenamespaceinforETA?(0/4)[10.3s]testthat(v1.0.0)50004.3scheckingifthereisanamespacetestthat(dev)20002.5scheckingpackagenamespaceinforETA?(0/4)[10.7s]testthat(v1.0.0)50004.6scheckingifthereisanamespacetestthat(dev)20002.9scheckingpackagenamespaceinforETA?(0/4)[11.1s]testthat(v1.0.0)90005.0scheckingforsufficient/correcttestthat(dev)20003.3scheckingpackagenamespaceinforETA?(0/4)[11.5s]testthat(v1.0.0)90005.4scheckingforsufficient/correcttestthat(dev)50003.6scheckingifthereisanamespaceETA?(0/4)[11.8s]testthat(v1.0.0)90005.7scheckingforsufficient/correcttestthat(dev)50003.9scheckingifthereisanamespaceETA?(0/4)[12.1s]testthat(v1.0.0)90006.1scheckingforsufficient/correcttestthat(dev)50004.3scheckingifthereisanamespaceETA?(0/4)[12.5s]testthat(v1.0.0)90006.4scheckingforsufficient/correcttestthat(dev)50004.7scheckingifthereisanamespaceETA?(0/4)[12.9s]testthat(v1.0.0)90006.8scheckingforsufficient/correcttestthat(dev)50005.0scheckingifthereisanamespaceETA?(0/4)[13.2s]testthat(v1.0.0)90007.1scheckingforsufficient/correcttestthat(dev)90005.3scheckingforsufficient/correctETA?(0/4)[13.5s]testthat(v1.0.0)90007.5scheckingforsufficient/correcttestthat(dev)90005.7scheckingforsufficient/correctETA?(0/4)[14s]testthat(v1.0.0)90007.9scheckingforsufficient/correcttestthat(dev)90006.1scheckingforsufficient/correctETA?(0/4)[14.3s]testthat(v1.0.0)90008.3scheckingforsufficient/correcttestthat(dev)90006.5scheckingforsufficient/correctETA?(0/4)[14.7s]testthat(v1.0.0)90008.6scheckingforsufficient/correcttestthat(dev)90006.8scheckingforsufficient/correctETA?(0/4)[15s]testthat(v1.0.0)90008.9scheckingforsufficient/correcttestthat(dev)90007.1scheckingforsufficient/correctETA?(0/4)[15.3s]testthat(v1.0.0)90009.3scheckingforsufficient/correcttestthat(dev)90007.5scheckingforsufficient/correctETA?(0/4)[15.7s]testthat(v1.0.0)90009.6scheckingforsufficient/correcttestthat(dev)90007.8scheckingforsufficient/correctETA?(0/4)[16s]testthat(v1.0.0)90009.9scheckingforsufficient/correcttestthat(dev)90008.1scheckingforsufficient/correctETA?(0/4)[16.3s]testthat(v1.0.0)900010.3scheckingforsufficient/correcttestthat(dev)90008.5scheckingforsufficient/correctETA?(0/4)[16.7s]testthat(v1.0.0)900010.6scheckingforsufficient/correcttestthat(dev)90008.8scheckingforsufficient/correctETA?(0/4)[17s]testthat(v1.0.0)900011.0scheckingforsufficient/correcttestthat(dev)90009.2scheckingforsufficient/correctETA?(0/4)[17.4s]testthat(v1.0.0)900011.4scheckingforsufficient/correcttestthat(dev)90009.6scheckingforsufficient/correctETA?(0/4)[17.8s]testthat(v1.0.0)900011.8scheckingforsufficient/correcttestthat(dev)900010.0scheckingforsufficient/correctETA?(0/4)[18.2s]testthat(v1.0.0)900012.1scheckingforsufficient/correcttestthat(dev)900010.3scheckingforsufficient/correctETA?(0/4)[18.6s]testthat(v1.0.0)900012.5scheckingforsufficient/correcttestthat(dev)900010.7scheckingforsufficient/correctETA?(0/4)[18.9s]testthat(v1.0.0)900012.8scheckingforsufficient/correcttestthat(dev)900011.0scheckingforsufficient/correctETA?(0/4)[19.2s]testthat(v1.0.0)900013.2scheckingforsufficient/correcttestthat(dev)900011.4scheckingforsufficient/correctETA?(0/4)[19.6s]testthat(v1.0.0)900013.5scheckingforsufficient/correcttestthat(dev)900011.7scheckingforsufficient/correctETA?(0/4)[19.9s]testthat(v1.0.0)900013.9scheckingforsufficient/correcttestthat(dev)900012.0scheckingforsufficient/correctETA?(0/4)[20.2s]testthat(v1.0.0)900014.2scheckingforsufficient/correcttestthat(dev)900012.4scheckingforsufficient/correctETA?(0/4)[20.6s]testthat(v1.0.0)900014.5scheckingforsufficient/correcttestthat(dev)900012.7scheckingforsufficient/correctETA?(0/4)[20.9s]testthat(v1.0.0)900014.8scheckingforsufficient/correcttestthat(dev)900013.0scheckingforsufficient/correctETA?(0/4)[21.2s]testthat(v1.0.0)900015.2scheckingforsufficient/correcttestthat(dev)900013.4scheckingforsufficient/correctETA?(0/4)[21.6s]testthat(v1.0.0)900015.5scheckingforsufficient/correcttestthat(dev)900013.8scheckingforsufficient/correctETA?(0/4)[22s]testthat(v1.0.0)900015.9scheckingforsufficient/correcttestthat(dev)900014.1scheckingforsufficient/correctETA?(0/4)[22.3s]testthat(v1.0.0)900016.2scheckingforsufficient/correcttestthat(dev)900014.4scheckingforsufficient/correctETA?(0/4)[22.6s]testthat(v1.0.0)900016.6scheckingforsufficient/correcttestthat(dev)900014.8scheckingforsufficient/correctETA?(0/4)[23s]testthat(v1.0.0)900016.9scheckingforsufficient/correcttestthat(dev)900015.1scheckingforsufficient/correctETA?(0/4)[23.3s]testthat(v1.0.0)900017.3scheckingforsufficient/correcttestthat(dev)900015.5scheckingforsufficient/correctETA?(0/4)[23.6s]testthat(v1.0.0)900017.6scheckingforsufficient/correcttestthat(dev)900015.8scheckingforsufficient/correctETA?(0/4)[24s]testthat(v1.0.0)900018.0scheckingforsufficient/correcttestthat(dev)900016.1scheckingforsufficient/correctETA?(0/4)[24.3s]testthat(v1.0.0)900018.3scheckingforsufficient/correcttestthat(dev)900016.5scheckingforsufficient/correctETA?(0/4)[24.7s]testthat(v1.0.0)900018.6scheckingforsufficient/correcttestthat(dev)900016.8scheckingforsufficient/correctETA?(0/4)[25s]testthat(v1.0.0)900019.0scheckingforsufficient/correcttestthat(dev)900017.2scheckingforsufficient/correctETA?(0/4)[25.4s]testthat(v1.0.0)900019.3scheckingforsufficient/correcttestthat(dev)900017.5scheckingforsufficient/correctETA?(0/4)[25.8s]testthat(v1.0.0)900019.8scheckingforsufficient/correcttestthat(dev)900018.0scheckingforsufficient/correctETA?(0/4)[26.3s]testthat(v1.0.0)900020.2scheckingforsufficient/correcttestthat(dev)900018.4scheckingforsufficient/correctETA?(0/4)[26.6s]testthat(v1.0.0)900020.6scheckingforsufficient/correcttestthat(dev)900018.8scheckingforsufficient/correctETA?(0/4)[27s]testthat(v1.0.0)900021.0scheckingforsufficient/correcttestthat(dev)900019.2scheckingforsufficient/correctETA?(0/4)[27.5s]testthat(v1.0.0)900021.4scheckingforsufficient/correcttestthat(dev)900019.6scheckingforsufficient/correctETA?(0/4)[27.9s]testthat(v1.0.0)900021.8scheckingforsufficient/correcttestthat(dev)900020.1scheckingforsufficient/correctETA?(0/4)[28.3s]testthat(v1.0.0)900022.2scheckingforsufficient/correcttestthat(dev)900020.5scheckingforsufficient/correctETA?(0/4)[28.8s]testthat(v1.0.0)900022.7scheckingforsufficient/correcttestthat(dev)900020.9scheckingforsufficient/correctETA?(0/4)[29.2s]testthat(v1.0.0)900023.1scheckingforsufficient/correcttestthat(dev)900021.4scheckingforsufficient/correctETA?(0/4)[29.6s]testthat(v1.0.0)900023.6scheckingforsufficient/correcttestthat(dev)900021.8scheckingforsufficient/correctETA?(0/4)[30s]testthat(v1.0.0)900024.0scheckingforsufficient/correcttestthat(dev)900022.2scheckingforsufficient/correctETA?(0/4)[30.4s]testthat(v1.0.0)900024.3scheckingforsufficient/correcttestthat(dev)900022.5scheckingforsufficient/correctETA?(0/4)[30.7s]testthat(v1.0.0)900024.6scheckingforsufficient/correcttestthat(dev)900022.9scheckingforsufficient/correctETA?(0/4)[31.1s]testthat(v1.0.0)900025.0scheckingforsufficient/correcttestthat(dev)900023.2scheckingforsufficient/correctETA?(0/4)[31.4s]testthat(v1.0.0)900025.3scheckingforsufficient/correcttestthat(dev)900023.6scheckingforsufficient/correctETA?(0/4)[31.8s]testthat(v1.0.0)900025.7scheckingforsufficient/correcttestthat(dev)900023.9scheckingforsufficient/correctETA?(0/4)[32.2s]testthat(v1.0.0)900026.1scheckingforsufficient/correcttestthat(dev)900024.3scheckingforsufficient/correctETA?(0/4)[32.5s]testthat(v1.0.0)900026.4scheckingforsufficient/correcttestthat(dev)900024.6scheckingforsufficient/correctETA?(0/4)[32.8s]testthat(v1.0.0)900026.8scheckingforsufficient/correcttestthat(dev)900025.0scheckingforsufficient/correctETA?(0/4)[33.2s]testthat(v1.0.0)900027.1scheckingforsufficient/correcttestthat(dev)900025.3scheckingforsufficient/correctETA?(0/4)[33.5s]testthat(v1.0.0)900027.5scheckingforsufficient/correcttestthat(dev)900025.7scheckingforsufficient/correctETA?(0/4)[33.9s]testthat(v1.0.0)900027.8scheckingforsufficient/correcttestthat(dev)900026.0scheckingforsufficient/correctETA?(0/4)[34.2s]testthat(v1.0.0)900028.1scheckingforsufficient/correcttestthat(dev)900026.3scheckingforsufficient/correctETA?(0/4)[34.5s]testthat(v1.0.0)900028.4scheckingforsufficient/correcttestthat(dev)900026.6scheckingforsufficient/correctETA?(0/4)[34.8s]testthat(v1.0.0)900028.8scheckingforsufficient/correcttestthat(dev)900027.0scheckingforsufficient/correctETA?(0/4)[35.2s]testthat(v1.0.0)900029.2scheckingforsufficient/correcttestthat(dev)900027.4scheckingforsufficient/correctETA?(0/4)[35.6s]testthat(v1.0.0)900029.6scheckingforsufficient/correcttestthat(dev)900027.8scheckingforsufficient/correctETA?(0/4)[36s]testthat(v1.0.0)900030.0scheckingforsufficient/correcttestthat(dev)900028.2scheckingforsufficient/correctETA?(0/4)[36.4s]testthat(v1.0.0)900030.3scheckingforsufficient/correcttestthat(dev)900028.5scheckingforsufficient/correctETA?(0/4)[36.7s]testthat(v1.0.0)900030.7scheckingforsufficient/correcttestthat(dev)900028.9scheckingforsufficient/correctETA?(0/4)[37.1s]testthat(v1.0.0)900031.0scheckingforsufficient/correcttestthat(dev)900029.2scheckingforsufficient/correctETA?(0/4)[37.4s]testthat(v1.0.0)900031.3scheckingforsufficient/correcttestthat(dev)900029.5scheckingforsufficient/correctETA?(0/4)[37.7s]testthat(v1.0.0)900031.7scheckingforsufficient/correcttestthat(dev)900029.9scheckingforsufficient/correctETA?(0/4)[38.2s]testthat(v1.0.0)900032.1scheckingforsufficient/correcttestthat(dev)900030.3scheckingforsufficient/correctETA?(0/4)[38.5s]testthat(v1.0.0)900032.4scheckingforsufficient/correcttestthat(dev)900030.6scheckingforsufficient/correctETA?(0/4)[38.8s]testthat(v1.0.0)900032.7scheckingforsufficient/correcttestthat(dev)900030.9scheckingforsufficient/correctETA?(0/4)[39.1s]testthat(v1.0.0)900033.1scheckingforsufficient/correcttestthat(dev)900031.3scheckingforsufficient/correctETA?(0/4)[39.5s]testthat(v1.0.0)900033.5scheckingforsufficient/correcttestthat(dev)900031.7scheckingforsufficient/correctETA?(0/4)[39.9s]testthat(v1.0.0)900033.8scheckingforsufficient/correcttestthat(dev)900032.0scheckingforsufficient/correctETA?(0/4)[40.2s]testthat(v1.0.0)900034.1scheckingforsufficient/correcttestthat(dev)900032.3scheckingforsufficient/correctETA?(0/4)[40.5s]testthat(v1.0.0)900034.5scheckingforsufficient/correcttestthat(dev)900032.7scheckingforsufficient/correctETA?(0/4)[40.9s]testthat(v1.0.0)900034.8scheckingforsufficient/correcttestthat(dev)900033.0scheckingforsufficient/correctETA?(0/4)[41.2s]testthat(v1.0.0)900035.1s(30.1s)checkingforsufficienttestthat(dev)900033.3scheckingforsufficient/correctETA?(0/4)[41.5s]testthat(v1.0.0)900035.5s(30.4s)checkingforsufficienttestthat(dev)900033.7scheckingforsufficient/correctETA?(0/4)[41.9s]testthat(v1.0.0)900035.8s(30.8s)checkingforsufficienttestthat(dev)900034.0scheckingforsufficient/correctETA?(0/4)[42.2s]testthat(v1.0.0)900036.2s(31.1s)checkingforsufficienttestthat(dev)900034.4scheckingforsufficient/correctETA?(0/4)[42.6s]testthat(v1.0.0)900036.5s(31.5s)checkingforsufficienttestthat(dev)900034.7scheckingforsufficient/correctETA?(0/4)[42.9s]testthat(v1.0.0)900036.9s(31.8s)checkingforsufficienttestthat(dev)900035.1scheckingforsufficient/correctETA?(0/4)[43.3s]testthat(v1.0.0)900037.2s(32.2s)checkingforsufficienttestthat(dev)900035.4s(30.1s)checkingforsufficientETA?(0/4)[43.6s]testthat(v1.0.0)900037.5s(32.5s)checkingforsufficienttestthat(dev)900035.7s(30.5s)checkingforsufficientETA?(0/4)[43.9s]testthat(v1.0.0)900037.9s(32.8s)checkingforsufficienttestthat(dev)900036.1s(30.8s)checkingforsufficientETA?(0/4)[44.3s]testthat(v1.0.0)900038.2s(33.2s)checkingforsufficienttestthat(dev)900036.4s(31.1s)checkingforsufficientETA?(0/4)[44.6s]testthat(v1.0.0)900038.5s(33.5s)checkingforsufficienttestthat(dev)900036.7s(31.4s)checkingforsufficientETA?(0/4)[44.9s]testthat(v1.0.0)900038.8s(33.8s)checkingforsufficienttestthat(dev)900037.0s(31.8s)checkingforsufficientETA?(0/4)[45.2s]testthat(v1.0.0)900039.2s(34.1s)checkingforsufficienttestthat(dev)900037.4s(32.1s)checkingforsufficientETA?(0/4)[45.6s]testthat(v1.0.0)900039.6s(34.5s)checkingforsufficienttestthat(dev)900037.8s(32.5s)checkingforsufficientETA?(0/4)[46s]testthat(v1.0.0)900039.9s(34.9s)checkingforsufficienttestthat(dev)900038.1s(32.8s)checkingforsufficientETA?(0/4)[46.3s]testthat(v1.0.0)900040.2s(35.2s)checkingforsufficienttestthat(dev)900038.4s(33.2s)checkingforsufficientETA?(0/4)[46.6s]testthat(v1.0.0)900040.6s(35.5s)checkingforsufficienttestthat(dev)900038.8s(33.5s)checkingforsufficientETA?(0/4)[47s]testthat(v1.0.0)900040.9s(35.9s)checkingforsufficienttestthat(dev)900039.1s(33.8s)checkingforsufficientETA?(0/4)[47.3s]testthat(v1.0.0)900041.2s(36.2s)checkingforsufficienttestthat(dev)900039.5s(34.2s)checkingforsufficientETA?(0/4)[47.7s]testthat(v1.0.0)900041.7s(36.6s)checkingforsufficienttestthat(dev)900039.9s(34.6s)checkingforsufficientETA?(0/4)[48.1s]testthat(v1.0.0)900042.1s(37.0s)checkingforsufficienttestthat(dev)900040.3s(35.0s)checkingforsufficientETA?(0/4)[48.5s]testthat(v1.0.0)900042.5s(37.4s)checkingforsufficienttestthat(dev)900040.7s(35.4s)checkingforsufficientETA?(0/4)[48.9s]testthat(v1.0.0)900042.8s(37.8s)checkingforsufficienttestthat(dev)900041.0s(35.8s)checkingforsufficientETA?(0/4)[49.2s]testthat(v1.0.0)900043.2s(38.1s)checkingforsufficienttestthat(dev)900041.4s(36.1s)checkingforsufficientETA?(0/4)[49.6s]testthat(v1.0.0)900043.5s(38.5s)checkingforsufficienttestthat(dev)900041.7s(36.4s)checkingforsufficientETA?(0/4)[49.9s]testthat(v1.0.0)900043.8s(38.8s)checkingforsufficienttestthat(dev)900042.0s(36.8s)checkingforsufficientETA?(0/4)[50.2s]testthat(v1.0.0)900044.1s(39.1s)checkingforsufficienttestthat(dev)900042.3s(37.1s)checkingforsufficientETA?(0/4)[50.6s]testthat(v1.0.0)900044.5s(39.5s)checkingforsufficienttestthat(dev)900042.7s(37.4s)checkingforsufficientETA?(0/4)[50.9s]testthat(v1.0.0)1010044.8scheckinginstalledpackagesizetestthat(dev)900043.0s(37.7s)checkingforsufficientETA?(0/4)[51.3s]testthat(v1.0.0)1110045.2scheckingpackagedirectory...testthat(dev)900043.4s(38.2s)checkingforsufficientETA?(0/4)[51.6s]testthat(v1.0.0)1410045.6scheckingforleft-overfiles..testthat(dev)900043.8s(38.6s)checkingforsufficientETA?(0/4)[52s]testthat(v1.0.0)1510046.0scheckingindexinformation...testthat(dev)900044.2s(39.0s)checkingforsufficientETA?(0/4)[52.4s]testthat(v1.0.0)1510046.4scheckingindexinformation...testthat(dev)900044.7s(39.4s)checkingforsufficientETA?(0/4)[52.9s]testthat(v1.0.0)1510046.8scheckingindexinformation...testthat(dev)900045.0s(39.7s)checkingforsufficientETA?(0/4)[53.2s]testthat(v1.0.0)1510047.1scheckingindexinformation...testthat(dev)900045.4s(40.1s)checkingforsufficientETA?(0/4)[53.6s]testthat(v1.0.0)1710047.5scheckingcodefilesfornon-ASCtestthat(dev)1010045.7scheckinginstalledpackagesizeETA?(0/4)[54s]testthat(v1.0.0)1810047.9scheckingRfilesforsyntaxerrtestthat(dev)1110046.2scheckingpackagedirectory...ETA?(0/4)[54.4s]testthat(v1.0.0)1910048.3scheckingwhetherthepackagecatestthat(dev)1510046.6scheckingindexinformation...ETA?(0/4)[54.8s]testthat(v1.0.0)2010048.7scheckingwhetherthepackagecatestthat(dev)1510046.9scheckingindexinformation...ETA?(0/4)[55.1s]testthat(v1.0.0)2110049.1scheckingwhetherthepackagecatestthat(dev)1510047.3scheckingindexinformation...ETA?(0/4)[55.6s]testthat(v1.0.0)2210049.5scheckingwhetherthenamespacetestthat(dev)1510047.8scheckingindexinformation...ETA?(0/4)[56s]testthat(v1.0.0)2210049.9scheckingwhetherthenamespacetestthat(dev)1610048.1scheckingpackagesubdirectoriesETA?(0/4)[56.3s]testthat(v1.0.0)2310050.3scheckingwhetherthenamespacetestthat(dev)1810048.5scheckingRfilesforsyntaxerrETA?(0/4)[56.7s]testthat(v1.0.0)2410050.6scheckingloadingwithoutbeingtestthat(dev)1910048.8scheckingwhetherthepackagecaETA?(0/4)[57s]testthat(v1.0.0)2410051.0scheckingloadingwithoutbeingtestthat(dev)1910049.3scheckingwhetherthepackagecaETA?(0/4)[57.5s]testthat(v1.0.0)2410051.4scheckingloadingwithoutbeingtestthat(dev)2010049.7scheckingwhetherthepackagecaETA?(0/4)[58s]testthat(v1.0.0)2410051.9scheckingloadingwithoutbeingtestthat(dev)2110050.1scheckingwhetherthepackagecaETA?(0/4)[58.3s]testthat(v1.0.0)2410052.3scheckingloadingwithoutbeingtestthat(dev)2210050.5scheckingwhetherthenamespaceETA?(0/4)[58.7s]testthat(v1.0.0)2410052.7scheckingloadingwithoutbeingtestthat(dev)2310050.9scheckingwhetherthenamespaceETA?(0/4)[59.1s]testthat(v1.0.0)2410053.1scheckingloadingwithoutbeingtestthat(dev)2310051.3scheckingwhetherthenamespaceETA?(0/4)[59.5s]testthat(v1.0.0)2410053.4scheckingloadingwithoutbeingtestthat(dev)2410051.7scheckingloadingwithoutbeingETA?(0/4)[59.9s]testthat(v1.0.0)2510053.8scheckingdependenciesinRcodetestthat(dev)2410052.0scheckingloadingwithoutbeingETA?(0/4)[1m0.2s]testthat(v1.0.0)2510054.2scheckingdependenciesinRcodetestthat(dev)2410052.4scheckingloadingwithoutbeingETA?(0/4)[1m0.6s]testthat(v1.0.0)2510054.5scheckingdependenciesinRcodetestthat(dev)2410052.7scheckingloadingwithoutbeingETA?(0/4)[1m1s]testthat(v1.0.0)2610054.9scheckingS3generic/methodconstestthat(dev)2410053.1scheckingloadingwithoutbeingETA?(0/4)[1m1.3s]testthat(v1.0.0)2610055.2scheckingS3generic/methodconstestthat(dev)2410053.4scheckingloadingwithoutbeingETA?(0/4)[1m1.6s]testthat(v1.0.0)2710055.6scheckingreplacementfunctionstestthat(dev)2410053.8scheckingloadingwithoutbeingETA?(0/4)[1m2s]testthat(v1.0.0)2710055.9scheckingreplacementfunctionstestthat(dev)2410054.2scheckingloadingwithoutbeingETA?(0/4)[1m2.4s]testthat(v1.0.0)2710056.3scheckingreplacementfunctionstestthat(dev)2510054.5scheckingdependenciesinRcodeETA?(0/4)[1m2.7s]testthat(v1.0.0)2810056.7scheckingforeignfunctioncallstestthat(dev)2510054.9scheckingdependenciesinRcodeETA?(0/4)[1m3.1s]testthat(v1.0.0)2810057.0scheckingforeignfunctioncallstestthat(dev)2510055.3scheckingdependenciesinRcodeETA?(0/4)[1m3.5s]testthat(v1.0.0)2810057.5scheckingforeignfunctioncallstestthat(dev)2610055.7scheckingS3generic/methodconsETA?(0/4)[1m3.9s]testthat(v1.0.0)2810057.8scheckingforeignfunctioncallstestthat(dev)2710056.1scheckingreplacementfunctionsETA?(0/4)[1m4.3s]testthat(v1.0.0)2810058.2scheckingforeignfunctioncallstestthat(dev)2710056.4scheckingreplacementfunctionsETA?(0/4)[1m4.7s]testthat(v1.0.0)2810058.6scheckingforeignfunctioncallstestthat(dev)2710056.8scheckingreplacementfunctionsETA?(0/4)[1m5s]testthat(v1.0.0)2810058.9scheckingforeignfunctioncallstestthat(dev)2710057.1scheckingreplacementfunctionsETA?(0/4)[1m5.3s]testthat(v1.0.0)2810059.3scheckingforeignfunctioncallstestthat(dev)2810057.5scheckingforeignfunctioncallsETA?(0/4)[1m5.7s]testthat(v1.0.0)2810059.6scheckingforeignfunctioncallstestthat(dev)2810057.8scheckingforeignfunctioncallsETA?(0/4)[1m6s]testthat(v1.0.0)2810060.0scheckingforeignfunctioncallstestthat(dev)2810058.2scheckingforeignfunctioncallsETA?(0/4)[1m6.4s]testthat(v1.0.0)281001.0mcheckingforeignfunctioncallstestthat(dev)2810058.5scheckingforeignfunctioncallsETA?(0/4)[1m6.7s]testthat(v1.0.0)281001.0mcheckingforeignfunctioncallstestthat(dev)2810058.8scheckingforeignfunctioncallsETA?(0/4)[1m7s]testthat(v1.0.0)281001.0mcheckingforeignfunctioncallstestthat(dev)2810059.2scheckingforeignfunctioncallsETA?(0/4)[1m7.4s]testthat(v1.0.0)281001.0mcheckingforeignfunctioncallstestthat(dev)2810059.5scheckingforeignfunctioncallsETA?(0/4)[1m7.7s]testthat(dev)2810059.9scheckingforeignfunctioncallsETA?(0/4)[1m8.1s]testthat(dev)281001.0mcheckingforeignfunctioncallsETA?(0/4)[1m8.5s]testthat(dev)281001.0mcheckingforeignfunctioncallsETA?(0/4)[1m8.9s]testthat(dev)281001.0mcheckingforeignfunctioncallsETA?(0/4)[1m9.2s]testthat(v1.0.0)281001.1mcheckingforeignfunctioncallstestthat(dev)281001.0mcheckingforeignfunctioncallsETA?(0/4)[1m9.7s]testthat(v1.0.0)281001.1mcheckingforeignfunctioncallsETA?(0/4)[1m10.2s]testthat(v1.0.0)281001.1mcheckingforeignfunctioncallsETA?(0/4)[1m10.5s]testthat(v1.0.0)281001.1mcheckingforeignfunctioncallsETA?(0/4)[1m10.8s]testthat(dev)281001.1mcheckingforeignfunctioncallsETA?(0/4)[1m11.2s]testthat(dev)281001.1mcheckingforeignfunctioncallsETA?(0/4)[1m11.6s]testthat(dev)281001.1mcheckingforeignfunctioncallsETA?(0/4)[1m11.9s]testthat(dev)281001.1mcheckingforeignfunctioncallsETA?(0/4)[1m12.4s]ETA?(0/4)[1m12.7s]testthat(v1.0.0)291001.1mcheckingRcodeforpossibleproETA?(0/4)[1m13s]testthat(v1.0.0)291001.1mcheckingRcodeforpossibleproETA?(0/4)[1m13.4s]testthat(v1.0.0)311001.1mcheckingRdmetadata...ETA?(0/4)[1m13.8s]testthat(v1.0.0)311001.1mcheckingRdmetadata...ETA?(0/4)[1m14.1s]testthat(v1.0.0)311001.1mcheckingRdmetadata...ETA?(0/4)[1m14.5s]testthat(v1.0.0)321001.1mcheckingformissingdocumentatitestthat(dev)291001.1mcheckingRcodeforpossibleproETA?(0/4)[1m14.8s]testthat(v1.0.0)321001.1mcheckingformissingdocumentatitestthat(dev)291001.1mcheckingRcodeforpossibleproETA?(0/4)[1m15.2s]testthat(v1.0.0)321001.2mcheckingformissingdocumentatitestthat(dev)301001.1mcheckingRdfiles...ETA?(0/4)[1m15.6s]testthat(v1.0.0)321001.2mcheckingformissingdocumentatitestthat(dev)311001.1mcheckingRdmetadata...ETA?(0/4)[1m16s]testthat(v1.0.0)321001.2mcheckingformissingdocumentatitestthat(dev)311001.1mcheckingRdmetadata...ETA?(0/4)[1m16.4s]testthat(v1.0.0)331001.2mcheckingforcode/documentationtestthat(dev)321001.1mcheckingformissingdocumentatiETA?(0/4)[1m16.8s]testthat(v1.0.0)331001.2mcheckingforcode/documentationtestthat(dev)321001.1mcheckingformissingdocumentatiETA?(0/4)[1m17.1s]testthat(v1.0.0)331001.2mcheckingforcode/documentationtestthat(dev)321001.2mcheckingformissingdocumentatiETA?(0/4)[1m17.4s]testthat(v1.0.0)331001.2mcheckingforcode/documentationtestthat(dev)321001.2mcheckingformissingdocumentatiETA?(0/4)[1m17.8s]testthat(dev)321001.2mcheckingformissingdocumentatiETA?(0/4)[1m18.2s]testthat(v1.0.0)341001.2mcheckingRd\usagesections...testthat(dev)321001.2mcheckingformissingdocumentatiETA?(0/4)[1m18.6s]testthat(v1.0.0)381001.2mcheckinglineendingsinMakefiltestthat(dev)331001.2mcheckingforcode/documentationETA?(0/4)[1m19s]testthat(v1.0.0)431001.2mcheckingcompiledcode...testthat(dev)331001.2mcheckingforcode/documentationETA?(0/4)[1m19.4s]testthat(v1.0.0)451001.2mcheckingfilesin‘vignettes’..testthat(dev)331001.2mcheckingforcode/documentationETA?(0/4)[1m19.8s]testthat(v1.0.0)451001.2mcheckingfilesin‘vignettes’..testthat(dev)331001.2mcheckingforcode/documentationETA?(0/4)[1m20.1s]testthat(v1.0.0)451001.2mcheckingfilesin‘vignettes’..testthat(dev)341001.2mcheckingRd\usagesections...ETA?(0/4)[1m20.4s]testthat(v1.0.0)451001.2mcheckingfilesin‘vignettes’..testthat(dev)351001.2mcheckingRdcontents...ETA?(0/4)[1m20.7s]testthat(dev)381001.2mcheckinglineendingsinMakefilETA?(0/4)[1m21.1s]testthat(v1.0.0)451001.3mcheckingfilesin‘vignettes’..testthat(dev)431001.2mcheckingcompiledcode...ETA?(0/4)[1m21.5s]testthat(v1.0.0)451001.3mcheckingfilesin‘vignettes’..testthat(dev)451001.2mcheckingfilesin‘vignettes’..ETA?(0/4)[1m21.8s]testthat(v1.0.0)451001.3mcheckingfilesin‘vignettes’..testthat(dev)451001.2mcheckingfilesin‘vignettes’..ETA?(0/4)[1m22.1s]testthat(v1.0.0)451001.3mcheckingfilesin‘vignettes’..testthat(dev)451001.2mcheckingfilesin‘vignettes’..ETA?(0/4)[1m22.5s]testthat(dev)451001.2mcheckingfilesin‘vignettes’..ETA?(0/4)[1m22.8s]ETA?(0/4)[1m23.2s]testthat(dev)451001.3mcheckingfilesin‘vignettes’..ETA?(0/4)[1m23.6s]testthat(dev)451001.3mcheckingfilesin‘vignettes’..ETA?(0/4)[1m23.9s]testthat(dev)451001.3mcheckingfilesin‘vignettes’..ETA?(0/4)[1m24.3s]testthat(v1.0.0)461001.3mcheckingexamples...testthat(dev)451001.3mcheckingfilesin‘vignettes’..ETA?(0/4)[1m24.7s]testthat(v1.0.0)471001.3mcheckingtests...ETA?(0/4)[1m25.1s]testthat(v1.0.0)471001.3mcheckingtests...ETA?(0/4)[1m25.5s]testthat(v1.0.0)471001.3mcheckingtests...ETA?(0/4)[1m25.9s]testthat(v1.0.0)471001.3mcheckingtests...ETA?(0/4)[1m26.3s]testthat(dev)471001.3mcheckingforunstateddependenciETA?(0/4)[1m26.6s]testthat(dev)471001.3mcheckingtests...ETA?(0/4)[1m27s]testthat(dev)471001.3mcheckingtests...ETA?(0/4)[1m27.5s]testthat(v1.0.0)471001.4mcheckingtests...testthat(dev)471001.3mcheckingtests...ETA?(0/4)[1m27.9s]testthat(v1.0.0)471001.4mcheckingtests...testthat(dev)471001.3mcheckingtests...ETA?(0/4)[1m28.3s]testthat(v1.0.0)471001.4mcheckingtests...ETA?(0/4)[1m28.6s]testthat(v1.0.0)471001.4mcheckingtests...ETA?(0/4)[1m29s]testthat(dev)471001.4mcheckingtests...ETA?(0/4)[1m29.4s]testthat(dev)471001.4mcheckingtests...ETA?(0/4)[1m29.8s]testthat(dev)471001.4mcheckingtests...ETA?(0/4)[1m30.1s]testthat(dev)471001.4mcheckingtests...ETA?(0/4)[1m30.4s]ETA?(0/4)[1m30.8s]ETA?(0/4)[1m31.1s]ETA?(0/4)[1m31.4s]ETA?(0/4)[1m31.8s]ETA?(0/4)[1m32.1s]ETA?(0/4)[1m32.5s]ETA?(0/4)[1m32.8s]ETA?(0/4)[1m33.1s]testthat(v1.0.0)471001.5mcheckingtests...ETA?(0/4)[1m33.5s]testthat(v1.0.0)471001.5mcheckingtests...ETA?(0/4)[1m33.9s]testthat(v1.0.0)471001.5mcheckingtests...ETA?(0/4)[1m34.3s]testthat(v1.0.0)471001.5mcheckingtests...ETA?(0/4)[1m34.7s]ETA?(0/4)[1m35s]testthat(dev)471001.5mcheckingtests...ETA?(0/4)[1m35.3s]testthat(dev)471001.5mcheckingtests...ETA?(0/4)[1m35.6s]testthat(dev)471001.5mcheckingtests...ETA?(0/4)[1m36s]testthat(dev)471001.5mcheckingtests...ETA?(0/4)[1m36.3s]ETA?(0/4)[1m36.7s]ETA?(0/4)[1m37.1s]ETA?(0/4)[1m37.5s]ETA?(0/4)[1m37.8s]ETA?(0/4)[1m38.2s]ETA?(0/4)[1m38.6s]ETA?(0/4)[1m39s]ETA?(0/4)[1m39.3s]testthat(v1.0.0)471001.6mcheckingtests...ETA?(0/4)[1m39.8s]testthat(v1.0.0)471001.6mcheckingtests...ETA?(0/4)[1m40.1s]testthat(v1.0.0)471001.6mcheckingtests...ETA?(0/4)[1m40.5s]testthat(v1.0.0)471001.6mcheckingtests...ETA?(0/4)[1m40.8s]ETA?(0/4)[1m41.2s]testthat(dev)471001.6mcheckingtests...ETA?(0/4)[1m41.5s]testthat(dev)471001.6mcheckingtests...ETA?(0/4)[1m41.8s]testthat(dev)471001.6mcheckingtests...ETA?(0/4)[1m42.2s]testthat(dev)471001.6mcheckingtests...ETA?(0/4)[1m42.5s]ETA?(0/4)[1m42.9s]ETA?(0/4)[1m43.3s]ETA?(0/4)[1m43.7s]ETA?(0/4)[1m44.1s]ETA?(0/4)[1m44.5s]ETA?(0/4)[1m44.9s]ETA?(0/4)[1m45.2s]testthat(v1.0.0)471001.7mcheckingtests...ETA?(0/4)[1m45.5s]testthat(v1.0.0)471001.7mcheckingtests...ETA?(0/4)[1m46s]testthat(v1.0.0)471001.7mcheckingtests...ETA?(0/4)[1m46.3s]testthat(v1.0.0)471001.7mcheckingtests...ETA?(0/4)[1m46.7s]ETA?(0/4)[1m47.1s]testthat(dev)471001.7mcheckingtests...ETA?(0/4)[1m47.4s]testthat(dev)471001.7mcheckingtests...ETA?(0/4)[1m47.8s]testthat(dev)471001.7mcheckingtests...ETA?(0/4)[1m48.2s]testthat(dev)471001.7mcheckingtests...ETA?(0/4)[1m48.5s]ETA?(0/4)[1m49s]ETA?(0/4)[1m49.7s]ETA?(0/4)[1m50.2s]ETA?(0/4)[1m50.7s]ETA?(0/4)[1m51.2s]testthat(v1.0.0)471001.8mcheckingtests...ETA?(0/4)[1m51.7s]testthat(v1.0.0)471001.8mcheckingtests...ETA?(0/4)[1m52.3s]testthat(v1.0.0)471001.8mcheckingtests...ETA?(0/4)[1m52.6s]testthat(v1.0.0)471001.8mcheckingtests...ETA?(0/4)[1m53.1s]testthat(dev)471001.8mcheckingtests...ETA?(0/4)[1m54s]testthat(dev)471001.8mcheckingtests...ETA?(0/4)[1m54.5s]testthat(dev)471001.8mcheckingtests...ETA?(0/4)[1m54.9s]testthat(dev)471001.8mcheckingtests...ETA?(0/4)[1m55.3s]ETA?(0/4)[1m55.8s]ETA?(0/4)[1m56.3s]ETA?(0/4)[1m57.1s]testthat(v1.0.0)471001.9mcheckingtests...ETA?(0/4)[1m58.3s]testthat(v1.0.0)471001.9mcheckingtests...ETA?(0/4)[1m58.9s]testthat(v1.0.0)471001.9mcheckingtests...testthat(dev)471001.9mcheckingtests...ETA?(0/4)[1m59.8s]testthat(v1.0.0)471001.9mcheckingtests...testthat(dev)471001.9mcheckingtests...ETA?(0/4)[2m0.3s]testthat(dev)471001.9mcheckingtests...ETA?(0/4)[2m1s]testthat(dev)471001.9mcheckingtests...ETA?(0/4)[2m1.5s]ETA?(0/4)[2m2.1s]ETA?(0/4)[2m2.6s]ETA?(0/4)[2m3s]ETA?(0/4)[2m3.6s]testthat(v1.0.0)471002.0mcheckingtests...ETA?(0/4)[2m4.5s]testthat(v1.0.0)471002.0mcheckingtests...ETA?(0/4)[2m5s]testthat(v1.0.0)471002.0mcheckingtests...testthat(dev)471002.0mcheckingtests...ETA?(0/4)[2m5.6s]testthat(v1.0.0)471002.0mcheckingtests...testthat(dev)471002.0mcheckingtests...ETA?(0/4)[2m6.3s]testthat(dev)471002.0mcheckingtests...ETA?(0/4)[2m7s]testthat(dev)471002.0mcheckingtests...ETA?(0/4)[2m7.6s]ETA?(0/4)[2m8.1s]ETA?(0/4)[2m8.5s]ETA?(0/4)[2m8.9s]ETA?(0/4)[2m9.5s]testthat(v1.0.0)471002.1mcheckingtests...ETA?(0/4)[2m10.1s]testthat(v1.0.0)471002.1mcheckingtests...ETA?(0/4)[2m10.9s]testthat(v1.0.0)471002.1mcheckingtests...testthat(dev)471002.1mcheckingtests...ETA?(0/4)[2m11.8s]testthat(v1.0.0)471002.1mcheckingtests...testthat(dev)471002.1mcheckingtests...ETA?(0/4)[2m12.3s]testthat(dev)471002.1mcheckingtests...ETA?(0/4)[2m12.6s]testthat(dev)471002.1mcheckingtests...ETA?(0/4)[2m12.9s]ETA?(0/4)[2m13.3s]ETA?(0/4)[2m14.1s]ETA?(0/4)[2m14.6s]ETA?(0/4)[2m15.1s]testthat(v1.0.0)471002.2mcheckingtests...ETA?(0/4)[2m15.9s]testthat(v1.0.0)471002.2mcheckingtests...ETA?(0/4)[2m16.4s]testthat(v1.0.0)471002.2mcheckingtests...ETA?(0/4)[2m17.3s]testthat(v1.0.0)471002.2mcheckingtests...testthat(dev)471002.2mcheckingtests...ETA?(0/4)[2m18s]testthat(dev)471002.2mcheckingtests...ETA?(0/4)[2m18.6s]testthat(dev)471002.2mcheckingtests...ETA?(0/4)[2m19.2s]testthat(dev)471002.2mcheckingtests...ETA?(0/4)[2m19.9s]ETA?(0/4)[2m20.4s]ETA?(0/4)[2m21s]ETA?(0/4)[2m21.6s]testthat(v1.0.0)471002.3mcheckingtests...ETA?(0/4)[2m22.5s]testthat(v1.0.0)471002.3mcheckingtests...ETA?(0/4)[2m23.1s]testthat(v1.0.0)471002.3mcheckingtests...testthat(dev)471002.3mcheckingtests...ETA?(0/4)[2m23.7s]testthat(v1.0.0)471002.3mcheckingtests...testthat(dev)471002.3mcheckingtests...ETA?(0/4)[2m24.2s]testthat(dev)471002.3mcheckingtests...ETA?(0/4)[2m24.7s]testthat(dev)471002.3mcheckingtests...ETA?(0/4)[2m25.4s]ETA?(0/4)[2m25.9s]ETA?(0/4)[2m26.6s]ETA?(0/4)[2m27s]ETA?(0/4)[2m27.6s]testthat(v1.0.0)471002.4mcheckingtests...ETA?(0/4)[2m28.2s]testthat(v1.0.0)471002.4mcheckingtests...ETA?(0/4)[2m28.7s]testthat(v1.0.0)471002.4mcheckingtests...testthat(dev)471002.4mcheckingtests...ETA?(0/4)[2m29.4s]testthat(v1.0.0)471002.4mcheckingtests...testthat(dev)471002.4mcheckingtests...ETA?(0/4)[2m30s]testthat(dev)471002.4mcheckingtests...ETA?(0/4)[2m30.5s]testthat(dev)471002.4mcheckingtests...ETA?(0/4)[2m31.1s]ETA?(0/4)[2m31.6s]ETA?(0/4)[2m32.1s]ETA?(0/4)[2m32.5s]ETA?(0/4)[2m32.9s]ETA?(0/4)[2m33.5s]testthat(v1.0.0)471002.5mcheckingtests...ETA?(0/4)[2m34s]testthat(v1.0.0)471002.5mcheckingtests...ETA?(0/4)[2m34.4s]testthat(v1.0.0)471002.5mcheckingtests...ETA?(0/4)[2m34.8s]testthat(v1.0.0)471002.5mcheckingtests...ETA?(0/4)[2m35.2s]testthat(dev)471002.5mcheckingtests...ETA?(0/4)[2m35.6s]testthat(dev)471002.5mcheckingtests...ETA?(0/4)[2m36s]testthat(dev)471002.5mcheckingtests...ETA?(0/4)[2m36.5s]testthat(dev)471002.5mcheckingtests...ETA?(0/4)[2m36.9s]ETA?(0/4)[2m37.4s]ETA?(0/4)[2m37.9s]ETA?(0/4)[2m38.2s]ETA?(0/4)[2m38.6s]ETA?(0/4)[2m39s]ETA?(0/4)[2m39.6s]testthat(v1.0.0)471002.6mcheckingtests...ETA?(0/4)[2m40.1s]testthat(v1.0.0)471002.6mcheckingtests...ETA?(0/4)[2m40.8s]testthat(v1.0.0)471002.6mcheckingtests...testthat(dev)471002.6mcheckingtests...ETA?(0/4)[2m41.3s]testthat(v1.0.0)471002.6mcheckingtests...testthat(dev)471002.6mcheckingtests...ETA?(0/4)[2m41.7s]testthat(dev)471002.6mcheckingtests...ETA?(0/4)[2m42.3s]testthat(dev)471002.6mcheckingtests...ETA?(0/4)[2m42.8s]ETA?(0/4)[2m43.1s]ETA?(0/4)[2m43.5s]ETA?(0/4)[2m43.8s]ETA?(0/4)[2m44.2s]ETA?(0/4)[2m44.5s]ETA?(0/4)[2m44.8s]ETA?(0/4)[2m45.1s]testthat(v1.0.0)471002.7mcheckingtests...ETA?(0/4)[2m45.5s]testthat(v1.0.0)471002.7mcheckingtests...ETA?(0/4)[2m45.9s]testthat(v1.0.0)481002.7mcheckingtests...ETA?(0/4)[2m46.2s]testthat(v1.0.0)!481002.7mETA8m(1/4)[2m46.8s]installingclisymbolsETA8m(1/4)[2m47.2s]installingclisymbolstestthat(dev)481002.7mcheckingtests...ETA8m(1/4)[2m47.6s]installingclisymbolstestthat(dev)!481002.7mETA3m(2/4)[2m48s]installingclisymbolsETA3m(2/4)[2m48.4s]installingclisymbolsETA3m(2/4)[2m48.7s]installingclisymbolsETA3m(2/4)[2m49.2s]installingclisymbolsETA3m(2/4)[2m49.6s]installingclisymbolsETA3m(2/4)[2m50s]installingclisymbolsETA3m(2/4)[2m50.3s]installingclisymbolsgoodpractice(v1.0.0)00001.1sstarting...ETA3m(2/4)[2m51.9s]goodpractice(v1.0.0)20002.5scheckingpackagenamespaceinforgoodpractice(dev)00001.1sstarting...ETA3m(2/4)[2m53.4s]goodpractice(v1.0.0)20003.0scheckingpackagenamespaceinforgoodpractice(dev)20001.7scheckingpackagenamespaceinforETA3m(2/4)[2m53.9s]goodpractice(v1.0.0)50003.5scheckingifthereisanamespacegoodpractice(dev)20002.1scheckingpackagenamespaceinforETA3m(2/4)[2m54.4s]goodpractice(v1.0.0)90003.9scheckingforsufficient/correctgoodpractice(dev)20002.6scheckingpackagenamespaceinforETA3m(2/4)[2m54.8s]goodpractice(v1.0.0)90004.4scheckingforsufficient/correctgoodpractice(dev)20003.0scheckingpackagenamespaceinforETA3m(2/4)[2m55.3s]goodpractice(v1.0.0)90005.0scheckingforsufficient/correctgoodpractice(dev)50003.7scheckingifthereisanamespaceETA3m(2/4)[2m56s]goodpractice(v1.0.0)90005.6scheckingforsufficient/correctgoodpractice(dev)90004.2scheckingforsufficient/correctETA3m(2/4)[2m56.5s]goodpractice(v1.0.0)90006.1scheckingforsufficient/correctgoodpractice(dev)90004.8scheckingforsufficient/correctETA3m(2/4)[2m57s]goodpractice(v1.0.0)90006.8scheckingforsufficient/correctgoodpractice(dev)90005.5scheckingforsufficient/correctETA3m(2/4)[2m57.8s]goodpractice(v1.0.0)90007.4scheckingforsufficient/correctgoodpractice(dev)90006.0scheckingforsufficient/correctETA3m(2/4)[2m58.2s]goodpractice(v1.0.0)90008.0scheckingforsufficient/correctgoodpractice(dev)90006.6scheckingforsufficient/correctETA3m(2/4)[2m58.8s]goodpractice(v1.0.0)90008.5scheckingforsufficient/correctgoodpractice(dev)90007.1scheckingforsufficient/correctETA3m(2/4)[2m59.3s]goodpractice(v1.0.0)90009.0scheckingforsufficient/correctgoodpractice(dev)90007.6scheckingforsufficient/correctETA3m(2/4)[2m59.8s]goodpractice(v1.0.0)90009.4scheckingforsufficient/correctgoodpractice(dev)90008.1scheckingforsufficient/correctETA3m(2/4)[3m0.3s]goodpractice(v1.0.0)900010.0scheckingforsufficient/correctgoodpractice(dev)90008.6scheckingforsufficient/correctETA3m(2/4)[3m0.9s]goodpractice(v1.0.0)900010.5scheckingforsufficient/correctgoodpractice(dev)90009.1scheckingforsufficient/correctETA3m(2/4)[3m1.3s]goodpractice(v1.0.0)900011.0scheckingforsufficient/correctgoodpractice(dev)90009.6scheckingforsufficient/correctETA3m(2/4)[3m1.9s]goodpractice(v1.0.0)1500011.6scheckingforleft-overfiles..goodpractice(dev)900010.3scheckingforsufficient/correctETA3m(2/4)[3m2.6s]goodpractice(v1.0.0)1600012.3scheckingindexinformation...goodpractice(dev)900010.9scheckingforsufficient/correctETA3m(2/4)[3m3.2s]goodpractice(v1.0.0)1600012.8scheckingindexinformation...goodpractice(dev)900011.4scheckingforsufficient/correctETA3m(2/4)[3m3.6s]goodpractice(v1.0.0)1800013.3scheckingcodefilesfornon-ASCgoodpractice(dev)900011.9scheckingforsufficient/correctETA3m(2/4)[3m4.2s]goodpractice(v1.0.0)1900013.8scheckingRfilesforsyntaxerrgoodpractice(dev)900012.4scheckingforsufficient/correctETA3m(2/4)[3m4.7s]goodpractice(v1.0.0)1900014.4scheckingRfilesforsyntaxerrgoodpractice(dev)1600013.0scheckingindexinformation...ETA3m(2/4)[3m5.3s]goodpractice(v1.0.0)2000015.0scheckingwhetherthepackagecagoodpractice(dev)1600013.6scheckingindexinformation...ETA3m(2/4)[3m5.9s]goodpractice(v1.0.0)2000015.5scheckingwhetherthepackagecagoodpractice(dev)1900014.2scheckingRfilesforsyntaxerrETA3m(2/4)[3m6.5s]goodpractice(v1.0.0)2100016.1scheckingwhetherthepackagecagoodpractice(dev)1900014.7scheckingRfilesforsyntaxerrETA3m(2/4)[3m7s]goodpractice(v1.0.0)2100016.6scheckingwhetherthepackagecagoodpractice(dev)1900015.2scheckingRfilesforsyntaxerrETA3m(2/4)[3m7.4s]goodpractice(v1.0.0)2200017.1scheckingwhetherthepackagecagoodpractice(dev)2000015.7scheckingwhetherthepackagecaETA3m(2/4)[3m8s]goodpractice(v1.0.0)2200017.6scheckingwhetherthepackagecagoodpractice(dev)2100016.3scheckingwhetherthepackagecaETA3m(2/4)[3m8.5s]goodpractice(v1.0.0)2300018.1scheckingwhetherthenamespacegoodpractice(dev)2100016.8scheckingwhetherthepackagecaETA3m(2/4)[3m9s]goodpractice(v1.0.0)2300018.6scheckingwhetherthenamespacegoodpractice(dev)2200017.2scheckingwhetherthepackagecaETA3m(2/4)[3m9.5s]goodpractice(v1.0.0)2400019.2scheckingwhetherthenamespacegoodpractice(dev)2200017.8scheckingwhetherthepackagecaETA3m(2/4)[3m10.1s]goodpractice(v1.0.0)2400019.9scheckingwhetherthenamespacegoodpractice(dev)2300018.5scheckingwhetherthenamespaceETA3m(2/4)[3m10.8s]goodpractice(v1.0.0)2500020.4scheckingloadingwithoutbeinggoodpractice(dev)2300019.0scheckingwhetherthenamespaceETA3m(2/4)[3m11.2s]goodpractice(v1.0.0)2500020.8scheckingloadingwithoutbeinggoodpractice(dev)2300019.4scheckingwhetherthenamespaceETA3m(2/4)[3m11.7s]goodpractice(v1.0.0)2500021.3scheckingloadingwithoutbeinggoodpractice(dev)2400019.9scheckingwhetherthenamespaceETA3m(2/4)[3m12.1s]goodpractice(v1.0.0)2500021.8scheckingloadingwithoutbeinggoodpractice(dev)2400020.4scheckingwhetherthenamespaceETA3m(2/4)[3m12.6s]goodpractice(v1.0.0)2600022.3scheckingdependenciesinRcodegoodpractice(dev)2500020.9scheckingloadingwithoutbeingETA3m(2/4)[3m13.1s]goodpractice(v1.0.0)2600022.7scheckingdependenciesinRcodegoodpractice(dev)2500021.3scheckingloadingwithoutbeingETA3m(2/4)[3m13.5s]goodpractice(v1.0.0)2600023.2scheckingdependenciesinRcodegoodpractice(dev)2500021.9scheckingloadingwithoutbeingETA3m(2/4)[3m14.1s]goodpractice(v1.0.0)2700023.8scheckingS3generic/methodconsgoodpractice(dev)2500022.4scheckingloadingwithoutbeingETA3m(2/4)[3m14.7s]goodpractice(v1.0.0)2700024.4scheckingS3generic/methodconsgoodpractice(dev)2600023.0scheckingdependenciesinRcodeETA3m(2/4)[3m15.2s]goodpractice(v1.0.0)2800024.9scheckingreplacementfunctionsgoodpractice(dev)2600023.5scheckingdependenciesinRcodeETA3m(2/4)[3m15.8s]goodpractice(v1.0.0)2800025.4scheckingreplacementfunctionsgoodpractice(dev)2700024.0scheckingS3generic/methodconsETA3m(2/4)[3m16.4s]goodpractice(v1.0.0)2900026.0scheckingforeignfunctioncallsgoodpractice(dev)2700024.6scheckingS3generic/methodconsETA3m(2/4)[3m16.8s]goodpractice(v1.0.0)2900026.5scheckingforeignfunctioncallsgoodpractice(dev)2800025.1scheckingreplacementfunctionsETA3m(2/4)[3m17.4s]goodpractice(v1.0.0)2900027.0scheckingforeignfunctioncallsgoodpractice(dev)2800025.6scheckingreplacementfunctionsETA3m(2/4)[3m17.8s]goodpractice(v1.0.0)2900027.4scheckingforeignfunctioncallsgoodpractice(dev)2900026.1scheckingforeignfunctioncallsETA3m(2/4)[3m18.3s]goodpractice(v1.0.0)2900028.0scheckingforeignfunctioncallsgoodpractice(dev)2900026.6scheckingforeignfunctioncallsETA3m(2/4)[3m18.8s]goodpractice(v1.0.0)2900028.5scheckingforeignfunctioncallsgoodpractice(dev)2900027.1scheckingforeignfunctioncallsETA3m(2/4)[3m19.4s]goodpractice(v1.0.0)2900029.0scheckingforeignfunctioncallsgoodpractice(dev)2900027.7scheckingforeignfunctioncallsETA3m(2/4)[3m19.9s]goodpractice(v1.0.0)2900029.5scheckingforeignfunctioncallsgoodpractice(dev)2900028.1scheckingforeignfunctioncallsETA3m(2/4)[3m20.4s]goodpractice(v1.0.0)3200030.1scheckingRdmetadata...goodpractice(dev)2900028.7scheckingforeignfunctioncallsETA3m(2/4)[3m20.9s]goodpractice(v1.0.0)3200030.5scheckingRdmetadata...goodpractice(dev)2900029.1scheckingforeignfunctioncallsETA3m(2/4)[3m21.4s]goodpractice(v1.0.0)3200031.0scheckingRdmetadata...goodpractice(dev)2900029.6scheckingforeignfunctioncallsETA3m(2/4)[3m21.9s]goodpractice(v1.0.0)3300031.5scheckingformissingdocumentatgoodpractice(dev)3000030.1scheckingRcodeforpossibleprETA3m(2/4)[3m22.4s]goodpractice(v1.0.0)3300032.0scheckingformissingdocumentatgoodpractice(dev)3200030.6scheckingRdmetadata...ETA3m(2/4)[3m22.9s]goodpractice(v1.0.0)3300032.5scheckingformissingdocumentatgoodpractice(dev)3200031.1scheckingRdmetadata...ETA3m(2/4)[3m23.3s]goodpractice(v1.0.0)3300032.9scheckingformissingdocumentatgoodpractice(dev)3300031.6scheckingformissingdocumentatETA3m(2/4)[3m23.8s]goodpractice(v1.0.0)3300033.5scheckingformissingdocumentatgoodpractice(dev)3300032.1scheckingformissingdocumentatETA3m(2/4)[3m24.3s]goodpractice(v1.0.0)3400034.0scheckingformissingdocumentatgoodpractice(dev)3300032.6scheckingformissingdocumentatETA3m(2/4)[3m24.9s]goodpractice(v1.0.0)3400034.6scheckingforcode/documentationgoodpractice(dev)3300033.3scheckingformissingdocumentatETA3m(2/4)[3m25.6s]goodpractice(v1.0.0)3400035.3scheckingforcode/documentationgoodpractice(dev)3300033.9scheckingformissingdocumentatETA3m(2/4)[3m26.2s]goodpractice(v1.0.0)3500035.8scheckingRd\usagesections...goodpractice(dev)3400034.4scheckingforcode/documentationETA3m(2/4)[3m26.7s]goodpractice(v1.0.0)3700036.3scheckingforunstateddependencgoodpractice(dev)3400034.9scheckingforcode/documentationETA3m(2/4)[3m27.2s]goodpractice(v1.0.0)3900036.8scheckingfilesin‘vignettes’.goodpractice(dev)3400035.4scheckingforcode/documentationETA3m(2/4)[3m27.7s]goodpractice(v1.0.0)3900037.4scheckingfilesin‘vignettes’.goodpractice(dev)3500036.0scheckingRd\usagesections...ETA3m(2/4)[3m28.3s]goodpractice(v1.0.0)3900038.1scheckingfilesin‘vignettes’.goodpractice(dev)3700036.7scheckingforunstateddependencETA3m(2/4)[3m29s]goodpractice(v1.0.0)3900038.7scheckingfilesin‘vignettes’.goodpractice(dev)3900037.4scheckingfilesin‘vignettes’.ETA3m(2/4)[3m29.7s]goodpractice(v1.0.0)4100039.3scheckingforunstateddependencgoodpractice(dev)3900037.9scheckingfilesin‘vignettes’.ETA4m(2/4)[3m30.2s]goodpractice(v1.0.0)4100039.8scheckingtests...goodpractice(dev)3900038.4scheckingfilesin‘vignettes’.ETA4m(2/4)[3m30.7s]goodpractice(v1.0.0)4100040.3scheckingtests...goodpractice(dev)4000038.9scheckingfilesin‘vignettes’.ETA4m(2/4)[3m31.1s]goodpractice(v1.0.0)4100040.8scheckingtests...goodpractice(dev)4100039.4scheckingtests...ETA4m(2/4)[3m31.7s]goodpractice(v1.0.0)4100041.4scheckingtests...goodpractice(dev)4100040.0scheckingtests...ETA4m(2/4)[3m32.2s]goodpractice(v1.0.0)4100041.9scheckingtests...goodpractice(dev)4100040.5scheckingtests...ETA4m(2/4)[3m32.7s]goodpractice(v1.0.0)4100042.5scheckingtests...goodpractice(dev)4100041.3scheckingtests...ETA4m(2/4)[3m33.5s]goodpractice(v1.0.0)4100043.2scheckingtests...goodpractice(dev)4100041.8scheckingtests...ETA4m(2/4)[3m34.1s]goodpractice(v1.0.0)4100043.7scheckingtests...goodpractice(dev)4100042.4scheckingtests...ETA4m(2/4)[3m34.6s]goodpractice(v1.0.0)4100044.2scheckingtests...goodpractice(dev)4100042.8scheckingtests...ETA4m(2/4)[3m35.1s]goodpractice(v1.0.0)4100044.8scheckingtests...goodpractice(dev)4100043.4scheckingtests...ETA4m(2/4)[3m35.6s]goodpractice(v1.0.0)4100045.2scheckingtests...goodpractice(dev)4100043.8scheckingtests...ETA4m(2/4)[3m36.1s]goodpractice(v1.0.0)4100045.7scheckingtests...goodpractice(dev)4100044.3scheckingtests...ETA4m(2/4)[3m36.5s]goodpractice(v1.0.0)4100046.1scheckingtests...goodpractice(dev)4100044.8scheckingtests...ETA4m(2/4)[3m37s]goodpractice(v1.0.0)4100046.6scheckingtests...goodpractice(dev)4100045.3scheckingtests...ETA4m(2/4)[3m37.5s]goodpractice(v1.0.0)4100047.2scheckingtests...goodpractice(dev)4100045.8scheckingtests...ETA4m(2/4)[3m38s]goodpractice(v1.0.0)4100047.6scheckingtests...goodpractice(dev)4100046.3scheckingtests...ETA4m(2/4)[3m38.5s]goodpractice(v1.0.0)4100048.1scheckingtests...goodpractice(dev)4100046.8scheckingtests...ETA4m(2/4)[3m39s]goodpractice(v1.0.0)4100048.6scheckingtests...goodpractice(dev)4100047.3scheckingtests...ETA4m(2/4)[3m39.5s]goodpractice(v1.0.0)4100049.2scheckingtests...goodpractice(dev)4100047.8scheckingtests...ETA4m(2/4)[3m40.1s]goodpractice(v1.0.0)4200049.7sgoodpractice(dev)4100048.3scheckingtests...ETA4m(2/4)[3m40.6s]goodpractice(v1.0.0)4200050.0sgoodpractice(dev)4200048.8sETA1m(3/4)[3m41s]goodpractice(dev)4200049.0sFinishedin3m41.5sETA?(0/4)[4.4s]installingdiffviewer,praise(dev) \ No newline at end of file +ETA?(1/NA)[30ms]SOKNWEETA?(0/4)[1.1s]installingfastmapsysyamlETA?(0/4)[1.4s]installingfastmapsysyamlzipETA?(0/4)[1.8s]installingfastmapsysyamlziprstudioapiETA?(0/4)[2.1s]installingfastmapsysyamlziprstudioapiiniETA?(0/4)[2.3s]installingfastmapsysyamlziprstudioapiiniwhiskerETA?(0/4)[2.7s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[3s]installingfastmapsysyamlziprstudioapiiniwhiskercommonmETA?(0/4)[3.3s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[3.5s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[3.8s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[3.9s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[4.1s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[4.3s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[4.5s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[4.7s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[4.9s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[5.1s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[5.4s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[5.6s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[5.7s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[6s]installingfastmapsysyamlziprstudioapiiniwhiskercommonmETA?(0/4)[6.2s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[6.4s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[6.6s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[6.7s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[6.9s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[7.2s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[7.4s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[7.6s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[7.8s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[8s]installingfastmapsysyamlziprstudioapiiniwhiskercommonmETA?(0/4)[8.2s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[8.4s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[8.6s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[9.1s]installingfastmapsysziprstudioapiinicommonmarkpraiseETA?(0/4)[9.4s]installingpraisepraiseETA?(0/4)[9.8s]installingbase64encpraisepraiseETA?(0/4)[10.1s]installingbase64encrlangpraisepraiseETA?(0/4)[10.5s]installingbase64encrlangdigestpraisepraiseETA?(0/4)[10.8s]installingbase64encrlangdigestclipraisepraiseETA?(0/4)[11.2s]installingbase64encrlangdigestclirappdirspraisepraisETA?(0/4)[11.6s]installingbase64encrlangdigestclirappdirsfspraiseprETA?(0/4)[12s]installingbase64encrlangdigestclirappdirsfsR6praisepETA?(0/4)[12.6s]installingbase64encrlangdigestclirappdirsfsR6xfunpETA?(0/4)[13.3s]installingbase64encrlangdigestclirappdirsfsR6xfunpETA?(0/4)[13.9s]installingbase64encrlangdigestclirappdirsfsR6xfunpETA?(0/4)[14.4s]installingrlangdigestclirappdirsfsR6xfunpsaskpassETA?(0/4)[14.5s]installingrlangdigestclirappdirsfsR6xfunpsaskpassETA?(0/4)[15.2s]installingclirappdirsfsR6xfunpsaskpassglueRcppETA?(0/4)[15.9s]installingrappdirsfsR6xfunpsaskpassglueRcppmimeETA?(0/4)[16.5s]installingfsR6xfunpsaskpassglueRcppmimejsonliteETA?(0/4)[17.1s]installingxfunpsaskpassglueRcppmimejsonliteevaluateETA?(0/4)[17.7s]installingpsaskpassglueRcppmimejsonliteevaluatecurlETA?(0/4)[18.1s]installingglueRcppmimejsonliteevaluatecurlmagrittrETA?(0/4)[18.6s]installingglueRcppmimejsonliteevaluatecurlmagrittrwETA?(0/4)[19.5s]installingRcppmimejsonliteevaluatecurlmagrittrwithrETA?(0/4)[20.1s]installingRcppjsonliteevaluatecurlmagrittrwithrotelETA?(0/4)[20.6s]installingjsonliteevaluatecurlmagrittrwithrotelcrayoETA?(0/4)[21.2s]installingjsonliteevaluatecurlmagrittrwithrotelcrayoETA?(0/4)[21.7s]installingevaluatecurlmagrittrwithrotelcrayonlazyevaETA?(0/4)[22.3s]installingcurlmagrittrwithrotelcrayonlazyevalgitcredETA?(0/4)[22.8s]installingwithrotelcrayonlazyevalgitcredsrprojrootprETA?(0/4)[23.3s]installingwithrotelcrayonlazyevalgitcredsrprojrootprETA?(0/4)[23.8s]installingwithrotelcrayonlazyevalgitcredsrprojrootprETA?(0/4)[24.4s]installingcrayonlazyevalgitcredsrprojrootprettyunitsrETA?(0/4)[25s]installinglazyevalgitcredsrprojrootprettyunitsremotescoETA?(0/4)[25.6s]installinggitcredsrprojrootprettyunitsremotescodetoolsETA?(0/4)[26.1s]installingprettyunitsremotescodetoolsbackportsxmlparseETA?(0/4)[26.6s]installingremotescodetoolsbackportsxmlparsedatacliprxETA?(0/4)[27.1s]installingremotescodetoolsbackportsxmlparsedatacliprxETA?(0/4)[27.7s]installinghtmltoolsbackportsxmlparsedatacliprxtablesoETA?(0/4)[28.1s]installinghtmltoolscachembackportsxmlparsedatacliprxtETA?(0/4)[28.7s]installinghtmltoolscachemlifecyclexmlparsedatacliprxtETA?(0/4)[29.2s]installinghtmltoolscachemlifecyclehighrcliprxtablesoETA?(0/4)[29.7s]installinghtmltoolscachemlifecyclehighrprocessxxtableETA?(0/4)[30.5s]installinghtmltoolscachemlifecyclehighrprocessxopenssETA?(0/4)[31s]installinghtmltoolscachemlifecyclehighrprocessxopensslETA?(0/4)[31.5s]installinghtmltoolscachemlifecyclehighrprocessxopenssETA?(0/4)[32s]installinghtmltoolscachemlifecyclehighrprocessxopensslETA?(0/4)[32.5s]installinglifecyclehighrprocessxopenssllatertinytexdETA?(0/4)[33.1s]installinghighrprocessxopenssllatertinytexdescdiffobETA?(0/4)[33.6s]installingprocessxopenssllatertinytexdescdiffobjsessETA?(0/4)[34s]installingprocessxopenssllatertinytexdescdiffobjsessioETA?(0/4)[34.5s]installingprocessxopenssllatertinytexdescdiffobjsessETA?(0/4)[35.3s]installingsassopenssllatertinytexdescdiffobjsessioniETA?(0/4)[36s]installingsassmemoisetinytexdescdiffobjsessioninforexETA?(0/4)[36.5s]installingsassmemoisejquerylibtinytexdescdiffobjsessETA?(0/4)[36.7s]installingsassmemoisejquerylibtinytexdescdiffobjsessETA?(0/4)[37s]installingsassmemoisejquerylibtinytexdescdiffobjsessioETA?(0/4)[37.1s]installingsassmemoisejquerylibtinytexdescdiffobjsessETA?(0/4)[37.8s]installingsassmemoisejquerylibvctrstinytexdescsessioETA?(0/4)[38.4s]installingsassmemoisejquerylibvctrstinytexfontawesomeETA?(0/4)[38.9s]installingsassmemoisejquerylibvctrstinytexfontawesomeETA?(0/4)[39.4s]installingsassmemoisejquerylibvctrsfontawesomeknitrcETA?(0/4)[40.1s]installingsassmemoisejquerylibvctrsfontawesomeknitrcETA?(0/4)[40.7s]installingsassmemoisejquerylibvctrsfontawesomeknitrcETA?(0/4)[41.4s]installingsassjquerylibvctrsfontawesomeknitrcallrcreETA?(0/4)[42s]installingsassjquerylibvctrsfontawesomeknitrcallrcredeETA?(0/4)[42.1s]installingsassjquerylibvctrsfontawesomeknitrcallrcreETA?(0/4)[42.3s]installingsassjquerylibvctrsfontawesomeknitrcallrcreETA?(0/4)[42.5s]installingsassjquerylibvctrsfontawesomeknitrcallrcreETA?(0/4)[42.8s]installingsassjquerylibvctrsfontawesomeknitrcallrcreETA?(0/4)[42.9s]installingsassjquerylibvctrsfontawesomeknitrcallrcreETA?(0/4)[43.1s]installingsassjquerylibvctrsfontawesomeknitrcallrcreETA?(0/4)[43.3s]installingsassjquerylibvctrsfontawesomeknitrcallrcreETA?(0/4)[43.5s]installingsassjquerylibvctrsfontawesomeknitrcallrcreETA?(0/4)[44.2s]installingjquerylibfontawesomeknitrcallrcredentialsprETA?(0/4)[44.8s]installingbslibcallrcredentialspromiseshttrxopenwaldETA?(0/4)[45.2s]installingbslibcredentialshttr2promiseshttrxopenwaldETA?(0/4)[45.8s]installingbslibcredentialshttr2promiseshttrpurrrwaldETA?(0/4)[46.2s]installingbslibcredentialshttr2promiseshttrpurrrwaldETA?(0/4)[46.7s]installingbslibhttr2promisespkgbuildhttrpurrrwaldolETA?(0/4)[47.3s]installingbslibhttr2pkgbuildhttrgertpurrrwaldolintrETA?(0/4)[47.8s]installingbslibhttr2pkgbuildhttrgertpurrrwaldocycloETA?(0/4)[48.4s]installingbslibhttr2pkgbuildhttrgertpurrrhttpuvwaldETA?(0/4)[48.7s]installingbslibhttr2pkgbuildhttrgertpurrrhttpuvwaldETA?(0/4)[49.3s]installingbslibhttr2pkgbuildgertpurrrhttpuvwaldowhoETA?(0/4)[49.9s]installingbslibhttr2pkgbuildgertpurrrhttpuvwhoamicyETA?(0/4)[50.3s]installingbslibhttr2pkgbuildgertpurrrhttpuvwhoamicyETA?(0/4)[51s]installingbslibpkgbuildgertpurrrghhttpuvwhoamicyclocoETA?(0/4)[51.6s]installingrmarkdownpkgbuildgertghhttpuvwhoamicyclocoETA?(0/4)[52.1s]installingrmarkdowngertghhttpuvpkgloadwhoamicyclocomETA?(0/4)[52.5s]installingrmarkdowngertghhttpuvpkgloadwhoamircmdchecETA?(0/4)[52.9s]installingrmarkdowngertghhttpuvpkgloadwhoamircmdchecETA?(0/4)[53.1s]installingrmarkdowngertghhttpuvpkgloadwhoamircmdchecETA?(0/4)[53.4s]installingrmarkdowngertghhttpuvpkgloadwhoamircmdchecETA?(0/4)[53.6s]installingrmarkdowngertghhttpuvpkgloadwhoamircmdchecETA?(0/4)[53.8s]installingrmarkdowngertghhttpuvpkgloadwhoamircmdchecETA?(0/4)[53.9s]installingrmarkdowngertghhttpuvpkgloadwhoamircmdchecETA?(0/4)[54.3s]installingrmarkdowngertghhttpuvpkgloadrcmdcheckcovrETA?(0/4)[54.5s]installingrmarkdownghhttpuvpkgloadrcmdcheckcovrETA?(0/4)[54.6s]installingrmarkdownghhttpuvpkgloadrcmdcheckcovrETA?(0/4)[55s]installingrmarkdownghpkgloadrcmdcheckcovrshinyETA?(0/4)[55.2s]installingrmarkdownghpkgloadrcmdcheckcovrshinyETA?(0/4)[55.4s]installingrmarkdownghpkgloadrcmdcheckcovrshinyETA?(0/4)[55.8s]installingrmarkdownpkgloadrcmdcheckcovrusethisshinyETA?(0/4)[56.1s]installingrmarkdownpkgloadrcmdcheckcovrusethisshinyETA?(0/4)[56.3s]installingrmarkdownpkgloadrcmdcheckusethisshinyETA?(0/4)[56.4s]installingrmarkdownpkgloadrcmdcheckusethisshinyETA?(0/4)[56.9s]installingrmarkdownrcmdcheckusethisshinytestthatETA?(0/4)[57.1s]installingrmarkdownrcmdcheckusethisshinytestthatETA?(0/4)[57.2s]installingrmarkdownrcmdcheckusethisshinytestthatETA?(0/4)[57.7s]installinghtmlwidgetsrcmdcheckusethisshinytestthatETA?(0/4)[57.8s]installinghtmlwidgetsrcmdcheckusethisshinytestthatETA?(0/4)[58.1s]installinghtmlwidgetsrcmdcheckusethisshinytestthatETA?(0/4)[58.2s]installinghtmlwidgetsrcmdcheckusethisshinytestthatETA?(0/4)[58.6s]installinghtmlwidgetsusethisshinytestthatETA?(0/4)[58.7s]installinghtmlwidgetsusethisshinytestthatETA?(0/4)[58.9s]installinghtmlwidgetsusethisshinytestthatETA?(0/4)[59.1s]installinghtmlwidgetsusethisshinytestthatETA?(0/4)[59.3s]installinghtmlwidgetsusethisshinytestthatETA?(0/4)[59.5s]installinghtmlwidgetsusethisshinytestthatETA?(0/4)[59.7s]installinghtmlwidgetsusethisshinytestthatETA?(0/4)[59.9s]installinghtmlwidgetsusethisshinytestthatETA?(0/4)[1m0.1s]installinghtmlwidgetsshinytestthatETA?(0/4)[1m0.3s]installinghtmlwidgetsshinytestthatETA?(0/4)[1m0.5s]installinghtmlwidgetsshinytestthat══goodpractice═════════════════════════╪═══╪═════════════╪════════════════════+praisev1.0.0https://cran.r-project.org00000.1sstarting...+praisev1.0.0local0000starting...ETA?(0/4)[1m3.4s]installinghtmlwidgetsshiny+praisev1.0.0https://cran.r-project.org00002.7sstarting...+praisev1.0.0local00000.2sstarting...ETA?(0/4)[1m5.9s]installingshiny+praisev1.0.0https://cran.r-project.org20003.4scheckingpacka+praisev1.0.0local00000.9sstarting...ETA?(0/4)[1m6.6s]installingshinydiffviewer+praisev1.0.0https://cran.r-project.org20003.6scheckingpacka+praisev1.0.0local00001.1sstarting...ETA?(0/4)[1m6.8s]installingshinydiffviewer+praisev1.0.0https://cran.r-project.org20003.9scheckingpacka+praisev1.0.0local00001.3sstarting...ETA?(0/4)[1m7s]installingshinydiffviewer+praisev1.0.0https://cran.r-project.org20004.1scheckingpacka+praisev1.0.0local00001.6sstarting...ETA?(0/4)[1m7.3s]installingshinydiffviewer+praisev1.0.0https://cran.r-project.org20004.5scheckingpacka+praisev1.0.0local20002.0scheckingpackaETA?(0/4)[1m7.7s]installingshinydiffviewer+praisev1.0.0https://cran.r-project.org20004.7scheckingpacka+praisev1.0.0local20002.2scheckingpackaETA?(0/4)[1m7.9s]installingshinydiffviewer+praisev1.0.0https://cran.r-project.org50005.0scheckingifth+praisev1.0.0local20002.5scheckingpackaETA?(0/4)[1m8.2s]installingshinydiffviewer+praisev1.0.0https://cran.r-project.org50005.2scheckingifth+praisev1.0.0local50002.7scheckingifthETA?(0/4)[1m8.5s]installingshinydiffviewer+praisev1.0.0https://cran.r-project.org50005.5scheckingifth+praisev1.0.0local50003.0scheckingifthETA?(0/4)[1m8.8s]installingshinydiffviewer+praisev1.0.0https://cran.r-project.org50005.8scheckingifth+praisev1.0.0local50003.3scheckingifthETA?(0/4)[1m9.1s]installingshinydiffviewer+praisev1.0.0https://cran.r-project.org90006.2scheckingfors+praisev1.0.0local90003.7scheckingforsETA?(0/4)[1m9.4s]installingdiffviewer+praisev1.0.0https://cran.r-project.org90006.5scheckingfors+praisev1.0.0local90003.9scheckingforsETA?(0/4)[1m9.7s]installingdiffviewer+praisev1.0.0https://cran.r-project.org90006.7scheckingfors+praisev1.0.0local90004.2scheckingforsETA?(0/4)[1m9.9s]installingdiffviewer+praisev1.0.0https://cran.r-project.org90006.9scheckingfors+praisev1.0.0local90004.4scheckingforsETA?(0/4)[1m10.1s]installingdiffviewer+praisev1.0.0https://cran.r-project.org90007.2scheckingfors+praisev1.0.0local90004.7scheckingforsETA?(0/4)[1m10.4s]installingdiffviewer+praisev1.0.0https://cran.r-project.org90007.5scheckingfors+praisev1.0.0local90004.9scheckingforsETA?(0/4)[1m10.7s]installingdiffviewer+praisev1.0.0https://cran.r-project.org90007.7scheckingfors+praisev1.0.0local90005.2scheckingforsETA?(0/4)[1m10.9s]installingdiffviewer+praisev1.0.0https://cran.r-project.org90007.9scheckingfors+praisev1.0.0local90005.4scheckingfors+praisev1.0.0https://cran.r-project.org900011.1scheckingfor+praisev1.0.0local90008.6scheckingfors══testthat═════════════════════════════╪═══╪═════════════╪════════════════════ETA?(0/4)[1m14.3s]+praisev1.0.0https://cran.r-project.org900014.5scheckingfor+praisev1.0.0local900012.0scheckingfor+praisev1.0.0https://cran.r-project.org00003.5sstarting...ETA?(0/4)[1m17.7s]+praisev1.0.0https://cran.r-project.org900015.0scheckingfor+praisev1.0.0local900012.5scheckingfor+praisev1.0.0https://cran.r-project.org00004.0sstarting...+praisev1.0.0local00000.7sstarting...ETA?(0/4)[1m18.3s]+praisev1.0.0https://cran.r-project.org900015.4scheckingfor+praisev1.0.0local900012.9scheckingfor+praisev1.0.0local00001.2sstarting...ETA?(0/4)[1m18.6s]+praisev1.0.0https://cran.r-project.org900015.8scheckingfor+praisev1.0.0local900013.3scheckingfor+praisev1.0.0https://cran.r-project.org20004.9scheckingpacka+praisev1.0.0local00001.6sstarting...ETA?(0/4)[1m19s]+praisev1.0.0https://cran.r-project.org900016.2scheckingfor+praisev1.0.0local900013.6scheckingfor+praisev1.0.0https://cran.r-project.org20005.2scheckingpacka+praisev1.0.0local00001.9sstarting...ETA?(0/4)[1m19.4s]+praisev1.0.0https://cran.r-project.org900016.5scheckingfor+praisev1.0.0local900014.0scheckingfor+praisev1.0.0https://cran.r-project.org20005.6scheckingpacka+praisev1.0.0local00002.3sstarting...ETA?(0/4)[1m19.8s]+praisev1.0.0https://cran.r-project.org900017.0scheckingfor+praisev1.0.0local900014.5scheckingfor+praisev1.0.0https://cran.r-project.org20006.0scheckingpacka+praisev1.0.0local00002.7sstarting...ETA?(0/4)[1m20.3s]+praisev1.0.0https://cran.r-project.org900017.5scheckingfor+praisev1.0.0local900015.0scheckingfor+praisev1.0.0https://cran.r-project.org50006.5scheckingifth+praisev1.0.0local00003.3sstarting...ETA?(0/4)[1m20.7s]+praisev1.0.0https://cran.r-project.org900017.9scheckingfor+praisev1.0.0local900015.4scheckingfor+praisev1.0.0https://cran.r-project.org50007.0scheckingifth+praisev1.0.0local20003.7scheckingpackaETA?(0/4)[1m21.1s]+praisev1.0.0https://cran.r-project.org900018.3scheckingfor+praisev1.0.0local900015.8scheckingfor+praisev1.0.0https://cran.r-project.org50007.3scheckingifth+praisev1.0.0local20004.1scheckingpackaETA?(0/4)[1m21.5s]+praisev1.0.0https://cran.r-project.org900018.6scheckingfor+praisev1.0.0local900016.1scheckingfor+praisev1.0.0https://cran.r-project.org50007.7scheckingifth+praisev1.0.0local20004.4scheckingpackaETA?(0/4)[1m21.8s]+praisev1.0.0https://cran.r-project.org900019.0scheckingfor+praisev1.0.0local900016.5scheckingfor+praisev1.0.0https://cran.r-project.org50008.0scheckingifth+praisev1.0.0local20004.7scheckingpackaETA?(0/4)[1m22.2s]+praisev1.0.0https://cran.r-project.org900019.5scheckingfor+praisev1.0.0local900016.9scheckingfor+praisev1.0.0https://cran.r-project.org50008.5scheckingifth+praisev1.0.0local20005.2scheckingpackaETA?(0/4)[1m22.7s]+praisev1.0.0https://cran.r-project.org900019.9scheckingfor+praisev1.0.0local900017.4scheckingfor+praisev1.0.0https://cran.r-project.org50008.9scheckingifth+praisev1.0.0local20005.6scheckingpackaETA?(0/4)[1m23.1s]+praisev1.0.0https://cran.r-project.org900020.3scheckingfor+praisev1.0.0local900017.8scheckingfor+praisev1.0.0https://cran.r-project.org50009.3scheckingifth+praisev1.0.0local20006.1scheckingpackaETA?(0/4)[1m23.6s]+praisev1.0.0https://cran.r-project.org900020.8scheckingfor+praisev1.0.0local1200018.3scheckingpack+praisev1.0.0https://cran.r-project.org50009.8scheckingifth+praisev1.0.0local20006.5scheckingpackaETA?(0/4)[1m24s]+praisev1.0.0https://cran.r-project.org900021.3scheckingfor+praisev1.0.0local1500018.8scheckingfor+praisev1.0.0https://cran.r-project.org500010.3scheckingift+praisev1.0.0local20007.0scheckingpackaETA?(0/4)[1m24.5s]+praisev1.0.0https://cran.r-project.org1200021.7scheckingpack+praisev1.0.0local1500019.2scheckingfor+praisev1.0.0https://cran.r-project.org500010.8scheckingift+praisev1.0.0local20007.5scheckingpackaETA?(0/4)[1m24.9s]+praisev1.0.0https://cran.r-project.org1200022.1scheckingpack+praisev1.0.0local1500019.6scheckingfor+praisev1.0.0https://cran.r-project.org500011.2scheckingift+praisev1.0.0local20007.9scheckingpackaETA?(0/4)[1m25.3s]+praisev1.0.0https://cran.r-project.org1200022.6scheckingpack+praisev1.0.0local1500020.0scheckingfor+praisev1.0.0https://cran.r-project.org900011.6scheckingfor+praisev1.0.0local20008.3scheckingpackaETA?(0/4)[1m25.8s]+praisev1.0.0https://cran.r-project.org1200023.0scheckingpack+praisev1.0.0local1500020.5scheckingfor+praisev1.0.0https://cran.r-project.org900012.0scheckingfor+praisev1.0.0local20008.7scheckingpackaETA?(0/4)[1m26.3s]+praisev1.0.0https://cran.r-project.org1200023.5scheckingpack+praisev1.0.0local1500020.9scheckingfor+praisev1.0.0https://cran.r-project.org900012.5scheckingfor+praisev1.0.0local20009.2scheckingpackaETA?(0/4)[1m26.7s]+praisev1.0.0https://cran.r-project.org1200023.9scheckingpack+praisev1.0.0local1600021.4scheckinginde+praisev1.0.0https://cran.r-project.org900012.9scheckingfor+praisev1.0.0local20009.7scheckingpackaETA?(0/4)[1m27.1s]+praisev1.0.0https://cran.r-project.org1500024.4scheckingfor+praisev1.0.0local1600021.9scheckinginde+praisev1.0.0https://cran.r-project.org900013.4scheckingfor+praisev1.0.0local200010.1scheckingpackETA?(0/4)[1m27.6s]+praisev1.0.0https://cran.r-project.org1500024.8scheckingfor+praisev1.0.0local1600022.3scheckinginde+praisev1.0.0https://cran.r-project.org900013.8scheckingfor+praisev1.0.0local200010.5scheckingpackETA?(0/4)[1m28.1s]+praisev1.0.0https://cran.r-project.org1500025.4scheckingfor+praisev1.0.0local1600022.9scheckinginde+praisev1.0.0https://cran.r-project.org900014.4scheckingfor+praisev1.0.0local500011.1scheckingiftETA?(0/4)[1m28.6s]+praisev1.0.0https://cran.r-project.org1500025.8scheckingfor+praisev1.0.0local1600023.3scheckinginde+praisev1.0.0https://cran.r-project.org900014.8scheckingfor+praisev1.0.0local500011.6scheckingiftETA?(0/4)[1m29s]+praisev1.0.0https://cran.r-project.org1500026.2scheckingfor+praisev1.0.0local1600023.7scheckinginde+praisev1.0.0https://cran.r-project.org900015.2scheckingfor+praisev1.0.0local500011.9scheckingiftETA?(0/4)[1m29.4s]+praisev1.0.0https://cran.r-project.org1500026.6scheckingfor+praisev1.0.0local1600024.1scheckinginde+praisev1.0.0https://cran.r-project.org900015.6scheckingfor+praisev1.0.0local500012.4scheckingiftETA?(0/4)[1m29.8s]+praisev1.0.0https://cran.r-project.org1500027.0scheckingfor+praisev1.0.0local1600024.5scheckinginde+praisev1.0.0https://cran.r-project.org900016.0scheckingfor+praisev1.0.0local500012.7scheckingiftETA?(0/4)[1m30.2s]+praisev1.0.0https://cran.r-project.org1500027.4scheckingfor+praisev1.0.0local1600024.8scheckinginde+praisev1.0.0https://cran.r-project.org900016.4scheckingfor+praisev1.0.0local500013.1scheckingiftETA?(0/4)[1m30.6s]+praisev1.0.0https://cran.r-project.org1500027.8scheckingfor+praisev1.0.0local1600025.2scheckinginde+praisev1.0.0https://cran.r-project.org900016.8scheckingfor+praisev1.0.0local500013.5scheckingiftETA?(0/4)[1m31s]+praisev1.0.0https://cran.r-project.org1500028.2scheckingfor+praisev1.0.0local1600025.6scheckinginde+praisev1.0.0https://cran.r-project.org900017.2scheckingfor+praisev1.0.0local500013.9scheckingiftETA?(0/4)[1m31.4s]+praisev1.0.0https://cran.r-project.org1500028.6scheckingfor+praisev1.0.0local1600026.0scheckinginde+praisev1.0.0https://cran.r-project.org900017.6scheckingfor+praisev1.0.0local500014.3scheckingiftETA?(0/4)[1m31.7s]+praisev1.0.0https://cran.r-project.org1500029.0scheckingfor+praisev1.0.0local1600026.4scheckinginde+praisev1.0.0https://cran.r-project.org900018.0scheckingfor+praisev1.0.0local500014.7scheckingiftETA?(0/4)[1m32.2s]+praisev1.0.0https://cran.r-project.org1500029.4scheckingfor+praisev1.0.0local1600026.8scheckinginde+praisev1.0.0https://cran.r-project.org900018.4scheckingfor+praisev1.0.0local500015.1scheckingiftETA?(0/4)[1m32.5s]+praisev1.0.0https://cran.r-project.org1500029.7scheckingfor+praisev1.0.0local1600027.2scheckinginde+praisev1.0.0https://cran.r-project.org900018.8scheckingfor+praisev1.0.0local900015.5scheckingforETA?(0/4)[1m32.9s]+praisev1.0.0https://cran.r-project.org1500030.1scheckingfor+praisev1.0.0local1600027.6scheckinginde+praisev1.0.0https://cran.r-project.org900019.2scheckingfor+praisev1.0.0local900015.9scheckingforETA?(0/4)[1m33.3s]+praisev1.0.0https://cran.r-project.org1500030.5scheckingfor+praisev1.0.0local1600028.0scheckinginde+praisev1.0.0https://cran.r-project.org900019.6scheckingfor+praisev1.0.0local900016.3scheckingforETA?(0/4)[1m33.7s]+praisev1.0.0https://cran.r-project.org1500031.0scheckingfor+praisev1.0.0local1600028.5scheckinginde+praisev1.0.0https://cran.r-project.org900020.0scheckingfor+praisev1.0.0local900016.8scheckingforETA?(0/4)[1m34.3s]+praisev1.0.0https://cran.r-project.org1500031.5scheckingfor+praisev1.0.0local1600029.0scheckinginde+praisev1.0.0https://cran.r-project.org900020.6scheckingfor+praisev1.0.0local900017.3scheckingforETA?(0/4)[1m34.7s]+praisev1.0.0https://cran.r-project.org1500032.0scheckingfor+praisev1.0.0local1600029.5scheckinginde+praisev1.0.0https://cran.r-project.org900021.0scheckingfor+praisev1.0.0local900017.7scheckingforETA?(0/4)[1m35.2s]+praisev1.0.0https://cran.r-project.org1500032.5scheckingfor+praisev1.0.0local1600030.0scheckinginde+praisev1.0.0https://cran.r-project.org900021.5scheckingfor+praisev1.0.0local900018.2scheckingforETA?(0/4)[1m35.7s]+praisev1.0.0https://cran.r-project.org1500033.0scheckingfor+praisev1.0.0local1600030.5scheckinginde+praisev1.0.0https://cran.r-project.org900022.0scheckingfor+praisev1.0.0local900018.7scheckingforETA?(0/4)[1m36.2s]+praisev1.0.0https://cran.r-project.org1500033.5scheckingfor+praisev1.0.0local1600031.0scheckinginde+praisev1.0.0https://cran.r-project.org900022.5scheckingfor+praisev1.0.0local900019.2scheckingforETA?(0/4)[1m36.7s]+praisev1.0.0https://cran.r-project.org1500033.9scheckingfor+praisev1.0.0local1600031.4scheckinginde+praisev1.0.0https://cran.r-project.org900023.0scheckingfor+praisev1.0.0local900019.7scheckingforETA?(0/4)[1m37.1s]+praisev1.0.0https://cran.r-project.org1500034.3scheckingfor+praisev1.0.0local1600031.8scheckinginde+praisev1.0.0https://cran.r-project.org900023.4scheckingfor+praisev1.0.0local900020.1scheckingforETA?(0/4)[1m37.5s]+praisev1.0.0https://cran.r-project.org1600034.8scheckinginde+praisev1.0.0local1600032.3scheckinginde+praisev1.0.0https://cran.r-project.org900023.8scheckingfor+praisev1.0.0local900020.5scheckingforETA?(0/4)[1m38s]+praisev1.0.0https://cran.r-project.org1600035.3scheckinginde+praisev1.0.0local1600032.8scheckinginde+praisev1.0.0https://cran.r-project.org900024.3scheckingfor+praisev1.0.0local900021.0scheckingforETA?(0/4)[1m38.5s]+praisev1.0.0https://cran.r-project.org1600035.8scheckinginde+praisev1.0.0local1600033.3scheckinginde+praisev1.0.0https://cran.r-project.org900024.8scheckingfor+praisev1.0.0local900021.5scheckingforETA?(0/4)[1m39.2s]+praisev1.0.0https://cran.r-project.org1600036.5scheckinginde+praisev1.0.0local1600034.0scheckinginde+praisev1.0.0https://cran.r-project.org900025.5scheckingfor+praisev1.0.0local900022.2scheckingforETA?(0/4)[1m39.8s]+praisev1.0.0https://cran.r-project.org1600037.0scheckinginde+praisev1.0.0local1600034.5scheckinginde+praisev1.0.0https://cran.r-project.org900026.1scheckingfor+praisev1.0.0local900022.8scheckingforETA?(0/4)[1m40.3s]+praisev1.0.0https://cran.r-project.org1600037.5scheckinginde+praisev1.0.0local1600035.0scheckinginde+praisev1.0.0https://cran.r-project.org900026.6scheckingfor+praisev1.0.0local900023.3scheckingforETA?(0/4)[1m40.8s]+praisev1.0.0https://cran.r-project.org1700038.0scheckingpack+praisev1.0.0local1600035.5scheckinginde+praisev1.0.0https://cran.r-project.org900027.0scheckingfor+praisev1.0.0local900023.7scheckingforETA?(0/4)[1m41.2s]+praisev1.0.0https://cran.r-project.org1900038.5scheckingRfi+praisev1.0.0local1600035.9scheckinginde+praisev1.0.0https://cran.r-project.org900027.5scheckingfor+praisev1.0.0local900024.2scheckingforETA?(0/4)[1m41.7s]+praisev1.0.0https://cran.r-project.org1900038.9scheckingRfi+praisev1.0.0local1600036.4scheckinginde+praisev1.0.0https://cran.r-project.org900028.0scheckingfor+praisev1.0.0local900024.7scheckingforETA?(0/4)[1m42.1s]+praisev1.0.0https://cran.r-project.org1900039.4scheckingRfi+praisev1.0.0local1600036.9scheckinginde+praisev1.0.0https://cran.r-project.org900028.4scheckingfor+praisev1.0.0local900025.1scheckingforETA?(0/4)[1m42.6s]+praisev1.0.0https://cran.r-project.org2000039.8scheckingwhet+praisev1.0.0local1600037.3scheckinginde+praisev1.0.0https://cran.r-project.org900028.9scheckingfor+praisev1.0.0local900025.6scheckingforETA?(0/4)[1m43.1s]+praisev1.0.0https://cran.r-project.org2000040.3scheckingwhet+praisev1.0.0local1700037.8scheckingpack+praisev1.0.0https://cran.r-project.org900029.3scheckingfor+praisev1.0.0local900026.0scheckingforETA?(0/4)[1m43.5s]+praisev1.0.0https://cran.r-project.org2000040.8scheckingwhet+praisev1.0.0local1900038.4scheckingRfi+praisev1.0.0https://cran.r-project.org900029.8scheckingfor+praisev1.0.0local900026.5scheckingforETA?(0/4)[1m44.1s]+praisev1.0.0https://cran.r-project.org2000041.3scheckingwhet+praisev1.0.0local1900038.8scheckingRfi+praisev1.0.0https://cran.r-project.org900030.3scheckingfor+praisev1.0.0local900027.1scheckingforETA?(0/4)[1m44.5s]+praisev1.0.0https://cran.r-project.org2000041.7scheckingwhet+praisev1.0.0local1900039.1scheckingRfi+praisev1.0.0https://cran.r-project.org900030.7scheckingfor+praisev1.0.0local900027.4scheckingforETA?(0/4)[1m44.8s]+praisev1.0.0https://cran.r-project.org2000042.1scheckingwhet+praisev1.0.0local1900039.6scheckingRfi+praisev1.0.0https://cran.r-project.org900031.1scheckingfor+praisev1.0.0local900027.8scheckingforETA?(0/4)[1m45.3s]+praisev1.0.0https://cran.r-project.org2000042.6scheckingwhet+praisev1.0.0local1900040.0scheckingRfi+praisev1.0.0https://cran.r-project.org900031.6scheckingfor+praisev1.0.0local900028.3scheckingforETA?(0/4)[1m45.8s]+praisev1.0.0https://cran.r-project.org2100043.0scheckingwhet+praisev1.0.0local1900040.5scheckingRfi+praisev1.0.0https://cran.r-project.org900032.1scheckingfor+praisev1.0.0local900028.8scheckingforETA?(0/4)[1m46.2s]+praisev1.0.0https://cran.r-project.org2100043.4scheckingwhet+praisev1.0.0local1900040.9scheckingRfi+praisev1.0.0https://cran.r-project.org900032.5scheckingfor+praisev1.0.0local900029.2scheckingforETA?(0/4)[1m46.7s]+praisev1.0.0https://cran.r-project.org2200043.9scheckingwhet+praisev1.0.0local1900041.4scheckingRfi+praisev1.0.0https://cran.r-project.org900032.9scheckingfor+praisev1.0.0local900029.6scheckingforETA?(0/4)[1m47.1s]+praisev1.0.0https://cran.r-project.org2200044.3scheckingwhet+praisev1.0.0local1900041.8scheckingRfi+praisev1.0.0https://cran.r-project.org900033.3scheckingfor+praisev1.0.0local900030.1scheckingforETA?(0/4)[1m47.5s]+praisev1.0.0https://cran.r-project.org2200044.7scheckingwhet+praisev1.0.0local1900042.2scheckingRfi+praisev1.0.0https://cran.r-project.org900033.8scheckingfor+praisev1.0.0local900030.5scheckingforETA?(0/4)[1m48s]+praisev1.0.0https://cran.r-project.org2200045.2scheckingwhet+praisev1.0.0local2000042.7scheckingwhet+praisev1.0.0https://cran.r-project.org900034.2scheckingfor+praisev1.0.0local900030.9scheckingforETA?(0/4)[1m48.4s]+praisev1.0.0https://cran.r-project.org2200045.6scheckingwhet+praisev1.0.0local2000043.1scheckingwhet+praisev1.0.0https://cran.r-project.org900034.7scheckingfor+praisev1.0.0local900031.4scheckingforETA?(0/4)[1m48.9s]+praisev1.0.0https://cran.r-project.org2300046.1scheckingwhet+praisev1.0.0local2100043.6scheckingwhet+praisev1.0.0https://cran.r-project.org900035.1scheckingfor+praisev1.0.0local900031.8scheckingforETA?(0/4)[1m49.3s]+praisev1.0.0https://cran.r-project.org2300046.6scheckingwhet+praisev1.0.0local2100044.1scheckingwhet+praisev1.0.0https://cran.r-project.org900035.6scheckingfor+praisev1.0.0local900032.4scheckingforETA?(0/4)[1m49.8s]+praisev1.0.0https://cran.r-project.org2400047.0scheckingwhet+praisev1.0.0local2100044.5scheckingwhet+praisev1.0.0https://cran.r-project.org900036.1scheckingfor+praisev1.0.0local900032.8scheckingforETA?(0/4)[1m50.2s]+praisev1.0.0https://cran.r-project.org2400047.5scheckingwhet+praisev1.0.0local2100044.9scheckingwhet+praisev1.0.0https://cran.r-project.org900036.5scheckingfor+praisev1.0.0local900033.2scheckingforETA?(0/4)[1m50.7s]+praisev1.0.0https://cran.r-project.org2400047.9scheckingwhet+praisev1.0.0local2200045.4scheckingwhet+praisev1.0.0https://cran.r-project.org900036.9scheckingfor+praisev1.0.0local900033.6scheckingforETA?(0/4)[1m51.1s]+praisev1.0.0https://cran.r-project.org2400048.4scheckingwhet+praisev1.0.0local2200045.9scheckingwhet+praisev1.0.0https://cran.r-project.org900037.4scheckingfor+praisev1.0.0local900034.1scheckingforETA?(0/4)[1m51.6s]+praisev1.0.0https://cran.r-project.org2500048.9scheckingload+praisev1.0.0local2200046.4scheckingwhet+praisev1.0.0https://cran.r-project.org900037.9scheckingfor+praisev1.0.0local900034.6scheckingforETA?(0/4)[1m52.1s]+praisev1.0.0https://cran.r-project.org2500049.3scheckingload+praisev1.0.0local2200046.8scheckingwhet+praisev1.0.0https://cran.r-project.org900038.4scheckingfor+praisev1.0.0local900035.1scheckingforETA?(0/4)[1m52.6s]+praisev1.0.0https://cran.r-project.org2500049.8scheckingload+praisev1.0.0local2300047.3scheckingwhet+praisev1.0.0https://cran.r-project.org900038.8scheckingfor+praisev1.0.0local900035.5scheckingforETA?(0/4)[1m53s]+praisev1.0.0https://cran.r-project.org2500050.3scheckingload+praisev1.0.0local2300047.8scheckingwhet+praisev1.0.0https://cran.r-project.org900039.3scheckingfor+praisev1.0.0local900036.0scheckingforETA?(0/4)[1m53.5s]+praisev1.0.0https://cran.r-project.org2500050.8scheckingload+praisev1.0.0local2300048.2scheckingwhet+praisev1.0.0https://cran.r-project.org900039.8scheckingfor+praisev1.0.0local900036.5scheckingforETA?(0/4)[1m54s]+praisev1.0.0https://cran.r-project.org2500051.4scheckingload+praisev1.0.0local2400048.9scheckingwhet+praisev1.0.0https://cran.r-project.org900040.3scheckingfor+praisev1.0.0local900037.0scheckingforETA?(0/4)[1m54.6s]+praisev1.0.0https://cran.r-project.org2600051.9scheckingdepe+praisev1.0.0local2400049.4scheckingwhet+praisev1.0.0https://cran.r-project.org900040.9scheckingfor+praisev1.0.0local900037.6scheckingforETA?(0/4)[1m55.2s]+praisev1.0.0https://cran.r-project.org2600052.5scheckingdepe+praisev1.0.0local2500049.9scheckingload+praisev1.0.0https://cran.r-project.org900041.4scheckingfor+praisev1.0.0local900038.2scheckingforETA?(0/4)[1m55.7s]+praisev1.0.0https://cran.r-project.org2600052.9scheckingdepe+praisev1.0.0local2500050.4scheckingload+praisev1.0.0https://cran.r-project.org900041.9s(30.4s)check+praisev1.0.0local900038.7scheckingforETA?(0/4)[1m56.1s]+praisev1.0.0https://cran.r-project.org2700053.4scheckingS3g+praisev1.0.0local2500050.9scheckingload+praisev1.0.0https://cran.r-project.org900042.4s(30.9s)check+praisev1.0.0local900039.1scheckingforETA?(0/4)[1m56.7s]+praisev1.0.0https://cran.r-project.org2700054.0scheckingS3g+praisev1.0.0local2500051.5scheckingload+praisev1.0.0https://cran.r-project.org900042.9s(31.4s)check+praisev1.0.0local900039.7scheckingforETA?(0/4)[1m57.2s]+praisev1.0.0https://cran.r-project.org2700054.5scheckingS3g+praisev1.0.0local2600052.0scheckingdepe+praisev1.0.0https://cran.r-project.org900043.5s(32.0s)check+praisev1.0.0local900040.2scheckingforETA?(0/4)[1m57.7s]+praisev1.0.0https://cran.r-project.org2700055.0scheckingS3g+praisev1.0.0local2600052.4scheckingdepe+praisev1.0.0https://cran.r-project.org900044.0s(32.5s)check+praisev1.0.0local900040.7scheckingforETA?(0/4)[1m58.2s]+praisev1.0.0https://cran.r-project.org2700055.4scheckingS3g+praisev1.0.0local2700052.9scheckingS3g+praisev1.0.0https://cran.r-project.org900044.4s(32.9s)check+praisev1.0.0local900041.2scheckingforETA?(0/4)[1m58.6s]+praisev1.0.0https://cran.r-project.org2700055.9scheckingS3g+praisev1.0.0local2700053.3scheckingS3g+praisev1.0.0https://cran.r-project.org900044.9s(33.4s)check+praisev1.0.0local900041.6scheckingforETA?(0/4)[1m59.1s]+praisev1.0.0https://cran.r-project.org2800056.3scheckingrepl+praisev1.0.0local2700053.8scheckingS3g+praisev1.0.0https://cran.r-project.org900045.3s(33.8s)check+praisev1.0.0local900042.0scheckingforETA?(0/4)[1m59.5s]+praisev1.0.0https://cran.r-project.org2800056.8scheckingrepl+praisev1.0.0local2700054.3scheckingS3g+praisev1.0.0https://cran.r-project.org900045.8s(34.3s)check+praisev1.0.0local900042.5scheckingforETA?(0/4)[2m0.1s]+praisev1.0.0https://cran.r-project.org2800057.3scheckingrepl+praisev1.0.0local2800054.7scheckingrepl+praisev1.0.0https://cran.r-project.org900046.3s(34.8s)check+praisev1.0.0local900043.0scheckingforETA?(0/4)[2m0.5s]+praisev1.0.0https://cran.r-project.org2800057.7scheckingrepl+praisev1.0.0local2800055.1scheckingrepl+praisev1.0.0https://cran.r-project.org900046.7s(35.2s)check+praisev1.0.0local900043.4scheckingforETA?(0/4)[2m0.8s]+praisev1.0.0https://cran.r-project.org2900058.1scheckingfore+praisev1.0.0local2900055.6scheckingfore+praisev1.0.0https://cran.r-project.org900047.1s(35.6s)check+praisev1.0.0local900043.8scheckingforETA?(0/4)[2m1.3s]+praisev1.0.0https://cran.r-project.org2900058.6scheckingfore+praisev1.0.0local2900056.0scheckingfore+praisev1.0.0https://cran.r-project.org900047.6s(36.0s)check+praisev1.0.0local900044.3scheckingforETA?(0/4)[2m1.8s]+praisev1.0.0https://cran.r-project.org2900059.0scheckingfore+praisev1.0.0local2900056.5scheckingfore+praisev1.0.0https://cran.r-project.org900048.0s(36.5s)check+praisev1.0.0local900044.8scheckingforETA?(0/4)[2m2.3s]+praisev1.0.0https://cran.r-project.org2900059.6scheckingfore+praisev1.0.0local2900057.1scheckingfore+praisev1.0.0https://cran.r-project.org900048.5s(37.0s)check+praisev1.0.0local900045.3scheckingforETA?(0/4)[2m2.8s]+praisev1.0.0https://cran.r-project.org290001.0mcheckingforei+praisev1.0.0local2900057.6scheckingfore+praisev1.0.0https://cran.r-project.org900049.1s(37.6s)check+praisev1.0.0local900045.9s(30.5s)checkETA?(0/4)[2m3.3s]+praisev1.0.0https://cran.r-project.org290001.0mcheckingforei+praisev1.0.0local2900058.0scheckingfore+praisev1.0.0https://cran.r-project.org900049.6s(38.1s)check+praisev1.0.0local900046.3s(30.9s)checkETA?(0/4)[2m3.8s]+praisev1.0.0https://cran.r-project.org290001.0mcheckingforei+praisev1.0.0local2900058.5scheckingfore+praisev1.0.0https://cran.r-project.org900050.1s(38.5s)check+praisev1.0.0local900046.8s(31.4s)checkETA?(0/4)[2m4.3s]+praisev1.0.0https://cran.r-project.org290001.0mcheckingforei+praisev1.0.0local2900059.0scheckingfore+praisev1.0.0https://cran.r-project.org900050.5s(39.0s)check+praisev1.0.0local900047.3s(31.9s)checkETA?(0/4)[2m4.7s]+praisev1.0.0local2900059.5scheckingfore+praisev1.0.0https://cran.r-project.org900051.0s(39.5s)check+praisev1.0.0local900047.7s(32.3s)checkETA?(0/4)[2m5.2s]+praisev1.0.0local300001.0mcheckingRcod+praisev1.0.0https://cran.r-project.org900051.5s(40.0s)check+praisev1.0.0local900048.2s(32.9s)checkETA?(0/4)[2m5.8s]+praisev1.0.0https://cran.r-project.org290001.1mcheckingforei+praisev1.0.0local320001.0mcheckingRdme+praisev1.0.0https://cran.r-project.org900052.1s(40.5s)check+praisev1.0.0local900048.8s(33.4s)checkETA?(0/4)[2m6.3s]+praisev1.0.0https://cran.r-project.org290001.1mcheckingforei+praisev1.0.0local320001.0mcheckingRdme+praisev1.0.0https://cran.r-project.org900052.6s(41.1s)check+praisev1.0.0local900049.3s(33.9s)checkETA?(0/4)[2m6.8s]+praisev1.0.0https://cran.r-project.org290001.1mcheckingforei+praisev1.0.0local330001.0mcheckingform+praisev1.0.0https://cran.r-project.org900053.0s(41.5s)check+praisev1.0.0local900049.7s(34.3s)checkETA?(0/4)[2m7.2s]+praisev1.0.0https://cran.r-project.org290001.1mcheckingforei+praisev1.0.0local330001.0mcheckingform+praisev1.0.0https://cran.r-project.org900053.4s(41.9s)check+praisev1.0.0local900050.1s(34.7s)checkETA?(0/4)[2m7.5s]+praisev1.0.0local330001.0mcheckingform+praisev1.0.0https://cran.r-project.org900053.8s(42.3s)check+praisev1.0.0local900050.5s(35.1s)checkETA?(0/4)[2m7.9s]+praisev1.0.0local330001.0mcheckingform+praisev1.0.0https://cran.r-project.org900054.2s(42.6s)check+praisev1.0.0local900050.9s(35.5s)checkETA?(0/4)[2m8.3s]+praisev1.0.0local330001.1mcheckingform+praisev1.0.0https://cran.r-project.org900054.6s(43.1s)check+praisev1.0.0local900051.3s(36.0s)checkETA?(0/4)[2m8.8s]+praisev1.0.0local330001.1mcheckingform+praisev1.0.0https://cran.r-project.org900055.1s(43.6s)check+praisev1.0.0local900051.8s(36.4s)checkETA?(0/4)[2m9.2s]+praisev1.0.0local330001.1mcheckingform+praisev1.0.0https://cran.r-project.org900055.5s(44.0s)check+praisev1.0.0local900052.2s(36.8s)checkETA?(0/4)[2m9.7s]+praisev1.0.0local330001.1mcheckingform+praisev1.0.0https://cran.r-project.org900055.9s(44.4s)check+praisev1.0.0local900052.7s(37.3s)checkETA?(0/4)[2m10.1s]+praisev1.0.0https://cran.r-project.org900056.4s(44.9s)check+praisev1.0.0local900053.1s(37.7s)checkETA?(0/4)[2m10.5s]+praisev1.0.0https://cran.r-project.org900056.8s(45.2s)check+praisev1.0.0local900053.5s(38.1s)checkETA?(0/4)[2m10.9s]+praisev1.0.0https://cran.r-project.org900057.2s(45.6s)check+praisev1.0.0local900053.9s(38.5s)checkETA?(0/4)[2m11.3s]+praisev1.0.0https://cran.r-project.org900057.6s(46.1s)check+praisev1.0.0local900054.3s(38.9s)checkETA?(0/4)[2m11.8s]+praisev1.0.0https://cran.r-project.org900058.1s(46.5s)check+praisev1.0.0local900054.8s(39.4s)checkETA?(0/4)[2m12.2s]+praisev1.0.0https://cran.r-project.org290001.2mcheckingforei+praisev1.0.0https://cran.r-project.org900058.4s(46.9s)check+praisev1.0.0local900055.1s(39.7s)checkETA?(0/4)[2m12.6s]+praisev1.0.0https://cran.r-project.org290001.2mcheckingforei+praisev1.0.0https://cran.r-project.org900058.8s(47.3s)check+praisev1.0.0local900055.5s(40.1s)checkETA?(0/4)[2m13s]+praisev1.0.0https://cran.r-project.org300001.2mcheckingRcod+praisev1.0.0https://cran.r-project.org900059.3s(47.7s)check+praisev1.0.0local900056.0s(40.6s)checkETA?(0/4)[2m13.5s]+praisev1.0.0https://cran.r-project.org310001.2mcheckingRdfi+praisev1.0.0https://cran.r-project.org1200059.7scheckingpack+praisev1.0.0local900056.5s(41.1s)checkETA?(0/4)[2m14s]+praisev1.0.0https://cran.r-project.org320001.2mcheckingRdme+praisev1.0.0https://cran.r-project.org120001.0mcheckingpacka+praisev1.0.0local900057.0s(41.6s)checkETA?(0/4)[2m14.5s]+praisev1.0.0https://cran.r-project.org320001.2mcheckingRdme+praisev1.0.0local330001.2mcheckingform+praisev1.0.0https://cran.r-project.org120001.0mcheckingpacka+praisev1.0.0local900057.5s(42.1s)checkETA?(0/4)[2m15.1s]+praisev1.0.0https://cran.r-project.org320001.2mcheckingRdme+praisev1.0.0local330001.2mcheckingform+praisev1.0.0https://cran.r-project.org150001.0mcheckingforl+praisev1.0.0local900058.1s(42.7s)checkETA?(0/4)[2m15.7s]+praisev1.0.0https://cran.r-project.org330001.2mcheckingform+praisev1.0.0local330001.2mcheckingform+praisev1.0.0https://cran.r-project.org150001.0mcheckingforl+praisev1.0.0local900058.6s(43.2s)checkETA?(0/4)[2m16.1s]+praisev1.0.0https://cran.r-project.org330001.2mcheckingform+praisev1.0.0local340001.2mcheckingforc+praisev1.0.0https://cran.r-project.org160001.0mcheckingindex+praisev1.0.0local900059.0s(43.6s)checkETA?(0/4)[2m16.5s]+praisev1.0.0https://cran.r-project.org330001.2mcheckingform+praisev1.0.0local340001.2mcheckingforc+praisev1.0.0https://cran.r-project.org160001.0mcheckingindex+praisev1.0.0local900059.4s(44.1s)checkETA?(0/4)[2m16.9s]+praisev1.0.0https://cran.r-project.org330001.2mcheckingform+praisev1.0.0local340001.2mcheckingforc+praisev1.0.0https://cran.r-project.org160001.1mcheckingindex+praisev1.0.0local900059.8s(44.5s)checkETA?(0/4)[2m17.3s]+praisev1.0.0local340001.2mcheckingforc+praisev1.0.0https://cran.r-project.org160001.1mcheckingindex+praisev1.0.0local90001.0m(44.8s)checkiETA?(0/4)[2m17.7s]+praisev1.0.0https://cran.r-project.org160001.1mcheckingindex+praisev1.0.0local90001.0m(45.3s)checkiETA?(0/4)[2m18.1s]+praisev1.0.0https://cran.r-project.org330001.3mcheckingform+praisev1.0.0https://cran.r-project.org160001.1mcheckingindex+praisev1.0.0local120001.0mcheckingpackaETA?(0/4)[2m18.4s]+praisev1.0.0https://cran.r-project.org330001.3mcheckingform+praisev1.0.0local120001.0mcheckingpackaETA?(0/4)[2m18.8s]+praisev1.0.0https://cran.r-project.org330001.3mcheckingform+praisev1.0.0local120001.0mcheckingpackaETA?(0/4)[2m19.2s]+praisev1.0.0https://cran.r-project.org330001.3mcheckingform+praisev1.0.0local120001.0mcheckingpackaETA?(0/4)[2m19.6s]+praisev1.0.0https://cran.r-project.org170001.1mcheckingpackaETA?(0/4)[2m20s]+praisev1.0.0https://cran.r-project.org190001.1mcheckingRfil+praisev1.0.0local150001.1mcheckingforlETA?(0/4)[2m20.5s]+praisev1.0.0local340001.3mcheckingforc+praisev1.0.0https://cran.r-project.org190001.1mcheckingRfil+praisev1.0.0local150001.1mcheckingforlETA?(0/4)[2m20.9s]+praisev1.0.0local360001.3mcheckingRdco+praisev1.0.0https://cran.r-project.org190001.1mcheckingRfil+praisev1.0.0local150001.1mcheckingforlETA?(0/4)[2m21.4s]+praisev1.0.0local370001.3mcheckingforu+praisev1.0.0https://cran.r-project.org190001.1mcheckingRfil+praisev1.0.0local150001.1mcheckingforlETA?(0/4)[2m21.8s]+praisev1.0.0local370001.3mcheckingforu+praisev1.0.0local160001.1mcheckingindexETA?(0/4)[2m22.2s]+praisev1.0.0local390001.3mcheckingfiles+praisev1.0.0https://cran.r-project.org200001.1mcheckingwheth+praisev1.0.0local160001.1mcheckingindexETA?(0/4)[2m22.6s]+praisev1.0.0https://cran.r-project.org340001.3mcheckingforc+praisev1.0.0local390001.3mcheckingfiles+praisev1.0.0https://cran.r-project.org200001.1mcheckingwheth+praisev1.0.0local160001.1mcheckingindexETA?(0/4)[2m23s]+praisev1.0.0https://cran.r-project.org340001.3mcheckingforc+praisev1.0.0local390001.3mcheckingfiles+praisev1.0.0https://cran.r-project.org200001.2mcheckingwheth+praisev1.0.0local160001.1mcheckingindexETA?(0/4)[2m23.4s]+praisev1.0.0https://cran.r-project.org340001.3mcheckingforc+praisev1.0.0local390001.3mcheckingfiles+praisev1.0.0https://cran.r-project.org200001.2mcheckingwhethETA?(0/4)[2m23.8s]+praisev1.0.0https://cran.r-project.org340001.4mcheckingforc+praisev1.0.0https://cran.r-project.org210001.2mcheckingwhethETA?(0/4)[2m24.2s]+praisev1.0.0https://cran.r-project.org360001.4mcheckingRdco+praisev1.0.0https://cran.r-project.org210001.2mcheckingwhethETA?(0/4)[2m24.6s]+praisev1.0.0https://cran.r-project.org370001.4mcheckingforu+praisev1.0.0https://cran.r-project.org210001.2mcheckingwhethETA?(0/4)[2m25.1s]+praisev1.0.0https://cran.r-project.org370001.4mcheckingforu+praisev1.0.0local410001.3mcheckingforu+praisev1.0.0https://cran.r-project.org210001.2mcheckingwhethETA?(0/4)[2m25.5s]+praisev1.0.0https://cran.r-project.org370001.4mcheckingforu+praisev1.0.0local410001.3mcheckingforu+praisev1.0.0https://cran.r-project.org220001.2mcheckingwhethETA?(0/4)[2m25.9s]+praisev1.0.0https://cran.r-project.org370001.4mcheckingforu+praisev1.0.0local410001.3mcheckingforu+praisev1.0.0https://cran.r-project.org220001.2mcheckingwhethETA?(0/4)[2m26.3s]+praisev1.0.0local410001.3mcheckingforu+praisev1.0.0https://cran.r-project.org220001.2mcheckingwheth+praisev1.0.0local160001.2mcheckingindexETA?(0/4)[2m26.7s]+praisev1.0.0local410001.4mcheckingtests+praisev1.0.0https://cran.r-project.org220001.2mcheckingwheth+praisev1.0.0local160001.2mcheckingindexETA?(0/4)[2m27.1s]+praisev1.0.0local410001.4mcheckingtests+praisev1.0.0local160001.2mcheckingindexETA?(0/4)[2m27.5s]+praisev1.0.0https://cran.r-project.org390001.4mcheckingfiles+praisev1.0.0local410001.4mcheckingtests+praisev1.0.0https://cran.r-project.org230001.2mcheckingwheth+praisev1.0.0local160001.2mcheckingindexETA?(0/4)[2m28s]+praisev1.0.0https://cran.r-project.org390001.4mcheckingfiles+praisev1.0.0local410001.4mcheckingtests+praisev1.0.0https://cran.r-project.org230001.2mcheckingwhethETA?(0/4)[2m28.5s]+praisev1.0.0https://cran.r-project.org390001.4mcheckingfiles+praisev1.0.0https://cran.r-project.org240001.2mcheckingwhethETA?(0/4)[2m29s]+praisev1.0.0https://cran.r-project.org390001.4mcheckingfiles+praisev1.0.0https://cran.r-project.org250001.3mcheckingloadiETA?(0/4)[2m29.5s]+praisev1.0.0https://cran.r-project.org250001.3mcheckingloadiETA?(0/4)[2m29.9s]+praisev1.0.0https://cran.r-project.org390001.5mcheckingfiles+praisev1.0.0https://cran.r-project.org250001.3mcheckingloadiETA?(0/4)[2m30.2s]+praisev1.0.0https://cran.r-project.org390001.5mcheckingfiles+praisev1.0.0https://cran.r-project.org250001.3mcheckingloadiETA?(0/4)[2m30.6s]+praisev1.0.0https://cran.r-project.org390001.5mcheckingfilesETA?(0/4)[2m31s]+praisev1.0.0https://cran.r-project.org390001.5mcheckingfiles+praisev1.0.0https://cran.r-project.org260001.3mcheckingwhethETA?(0/4)[2m31.4s]+praisev1.0.0https://cran.r-project.org260001.3mcheckingwheth+praisev1.0.0local170001.2mcheckingpackaETA?(0/4)[2m31.9s]+praisev1.0.0https://cran.r-project.org260001.3mcheckingwheth+praisev1.0.0local180001.2mcheckingcodeETA?(0/4)[2m32.3s]+praisev1.0.0https://cran.r-project.org260001.3mcheckingwheth+praisev1.0.0local180001.3mcheckingcodeETA?(0/4)[2m32.7s]+praisev1.0.0local410001.5mcheckingtests+praisev1.0.0local190001.3mcheckingRfilETA?(0/4)[2m33.1s]+praisev1.0.0local410001.5mcheckingtests+praisev1.0.0local190001.3mcheckingRfilETA?(0/4)[2m33.5s]+praisev1.0.0local410001.5mcheckingtests+praisev1.0.0local190001.3mcheckingRfilETA?(0/4)[2m33.8s]+praisev1.0.0local410001.5mcheckingtests+praisev1.0.0local190001.3mcheckingRfilETA?(0/4)[2m34.3s]ETA?(0/4)[2m34.7s]+praisev1.0.0https://cran.r-project.org400001.5mcheckingexampETA?(0/4)[2m35.2s]+praisev1.0.0https://cran.r-project.org400001.5mcheckingexamp+praisev1.0.0https://cran.r-project.org260001.4mcheckingwhethETA?(0/4)[2m35.7s]+praisev1.0.0https://cran.r-project.org400001.6mcheckingexamp+praisev1.0.0https://cran.r-project.org260001.4mcheckingwhethETA?(0/4)[2m36.3s]+praisev1.0.0https://cran.r-project.org400001.6mcheckingexamp+praisev1.0.0https://cran.r-project.org260001.4mcheckingwhethETA?(0/4)[2m36.7s]+praisev1.0.0https://cran.r-project.org410001.6mcheckingforu+praisev1.0.0https://cran.r-project.org260001.4mcheckingwhethETA?(0/4)[2m37.1s]+praisev1.0.0https://cran.r-project.org410001.6mcheckingforuETA?(0/4)[2m37.6s]+praisev1.0.0https://cran.r-project.org410001.6mcheckingforuETA?(0/4)[2m38s]+praisev1.0.0https://cran.r-project.org410001.6mcheckingtests+praisev1.0.0local190001.4mcheckingRfilETA?(0/4)[2m38.5s]+praisev1.0.0https://cran.r-project.org410001.6mcheckingtests+praisev1.0.0local410001.6mcheckingtests+praisev1.0.0local190001.4mcheckingRfilETA?(0/4)[2m39.1s]+praisev1.0.0https://cran.r-project.org410001.6mcheckingtests+praisev1.0.0local410001.6mcheckingtests+praisev1.0.0https://cran.r-project.org270001.4mcheckingdepen+praisev1.0.0local190001.4mcheckingRfilETA?(0/4)[2m39.6s]+praisev1.0.0https://cran.r-project.org410001.6mcheckingtests+praisev1.0.0local410001.6mcheckingtests+praisev1.0.0https://cran.r-project.org270001.4mcheckingdepen+praisev1.0.0local200001.4mcheckingwhethETA?(0/4)[2m40.2s]+praisev1.0.0local410001.6mcheckingtests+praisev1.0.0https://cran.r-project.org270001.4mcheckingdepen+praisev1.0.0local200001.4mcheckingwhethETA?(0/4)[2m40.7s]+praisev1.0.0https://cran.r-project.org270001.4mcheckingdepen+praisev1.0.0local200001.4mcheckingwhethETA?(0/4)[2m41.2s]+praisev1.0.0https://cran.r-project.org280001.5mcheckingS3ge+praisev1.0.0local200001.4mcheckingwhethETA?(0/4)[2m41.7s]+praisev1.0.0https://cran.r-project.org280001.5mcheckingS3ge+praisev1.0.0local210001.4mcheckingwhethETA?(0/4)[2m42.2s]+praisev1.0.0https://cran.r-project.org410001.7mcheckingtests+praisev1.0.0https://cran.r-project.org280001.5mcheckingS3ge+praisev1.0.0local210001.4mcheckingwhethETA?(0/4)[2m42.7s]+praisev1.0.0https://cran.r-project.org410001.7mcheckingtests+praisev1.0.0https://cran.r-project.org280001.5mcheckingS3ge+praisev1.0.0local210001.4mcheckingwhethETA?(0/4)[2m43.1s]+praisev1.0.0https://cran.r-project.org410001.7mcheckingtests+praisev1.0.0local220001.4mcheckingwhethETA?(0/4)[2m43.7s]+praisev1.0.0https://cran.r-project.org410001.7mcheckingtests+praisev1.0.0https://cran.r-project.org290001.5mcheckingrepla+praisev1.0.0local220001.4mcheckingwhethETA?(0/4)[2m44.2s]+praisev1.0.0local410001.7mcheckingtests+praisev1.0.0https://cran.r-project.org290001.5mcheckingrepla+praisev1.0.0local220001.5mcheckingwhethETA?(0/4)[2m44.7s]+praisev1.0.0local410001.7mcheckingtests+praisev1.0.0https://cran.r-project.org290001.5mcheckingrepla+praisev1.0.0local230001.5mcheckingwhethETA?(0/4)[2m45.2s]+praisev1.0.0local420001.7mcheckingtests+praisev1.0.0https://cran.r-project.org290001.5mcheckingrepla+praisev1.0.0local240001.5mcheckingwhethETA?(0/4)[2m45.8s]+praisev1.0.0local420001.7m+praisev1.0.0local240001.5mcheckingwhethETA?(0/4)[2m46.2s]+praisev1.0.0local240001.5mcheckingwhethETA8m(1/4)[2m46.7s]+praisev1.0.0local240001.5mcheckingwhethETA8m(1/4)[2m47.1s]+praisev1.0.0https://cran.r-project.org290001.6mcheckingreplaETA8m(1/4)[2m47.5s]+praisev1.0.0https://cran.r-project.org290001.6mcheckingrepla+praisev1.0.0local250001.5mcheckingloadiETA8m(1/4)[2m47.9s]+praisev1.0.0https://cran.r-project.org410001.8mcheckingtests+praisev1.0.0https://cran.r-project.org290001.6mcheckingrepla+praisev1.0.0local250001.5mcheckingloadiETA8m(1/4)[2m48.4s]+praisev1.0.0https://cran.r-project.org410001.8mcheckingtests+praisev1.0.0https://cran.r-project.org290001.6mcheckingrepla+praisev1.0.0local250001.5mcheckingloadiETA8m(1/4)[2m48.8s]+praisev1.0.0https://cran.r-project.org410001.8mcheckingtests+praisev1.0.0local250001.5mcheckingloadiETA8m(1/4)[2m49.2s]+praisev1.0.0https://cran.r-project.org410001.8mcheckingtests+praisev1.0.0https://cran.r-project.org300001.6mcheckingforeiETA8m(1/4)[2m49.7s]+praisev1.0.0https://cran.r-project.org300001.6mcheckingforeiETA9m(1/4)[2m50s]+praisev1.0.0https://cran.r-project.org300001.6mcheckingforei+praisev1.0.0local250001.6mcheckingloadiETA9m(1/4)[2m50.5s]+praisev1.0.0https://cran.r-project.org300001.6mcheckingforei+praisev1.0.0local250001.6mcheckingloadiETA9m(1/4)[2m50.9s]+praisev1.0.0local250001.6mcheckingloadiETA9m(1/4)[2m51.3s]+praisev1.0.0local250001.6mcheckingloadiETA9m(1/4)[2m51.7s]ETA9m(1/4)[2m52.1s]ETA9m(1/4)[2m52.6s]ETA9m(1/4)[2m53s]+praisev1.0.0https://cran.r-project.org300001.7mcheckingforeiETA9m(1/4)[2m53.4s]+praisev1.0.0https://cran.r-project.org420001.8mcheckingtests+praisev1.0.0https://cran.r-project.org300001.7mcheckingforeiETA9m(1/4)[2m53.9s]+praisev1.0.0https://cran.r-project.org420001.9mcheckingtests+praisev1.0.0https://cran.r-project.org300001.7mcheckingforeiETA9m(1/4)[2m54.3s]+praisev1.0.0https://cran.r-project.org420001.9m+praisev1.0.0https://cran.r-project.org300001.7mcheckingforeiETA3m(2/4)[2m54.9s]ETA3m(2/4)[2m55.1s]ETA3m(2/4)[2m55.3s]ETA3m(2/4)[2m55.5s]ETA3m(2/4)[2m55.8s]ETA3m(2/4)[2m56s]ETA3m(2/4)[2m56.2s]+praisev1.0.0local250001.7mcheckingloadiETA3m(2/4)[2m56.4s]+praisev1.0.0local250001.7mcheckingloadiETA3m(2/4)[2m56.6s]+praisev1.0.0local250001.7mcheckingloadiETA3m(2/4)[2m56.8s]+praisev1.0.0local250001.7mcheckingloadiETA3m(2/4)[2m57s]ETA3m(2/4)[2m57.2s]ETA3m(2/4)[2m57.4s]ETA3m(2/4)[2m57.8s]ETA3m(2/4)[2m58s]ETA3m(2/4)[2m58.2s]ETA3m(2/4)[2m58.4s]ETA3m(2/4)[2m58.6s]+praisev1.0.0local260001.7mcheckingwhethETA3m(2/4)[2m59s]+praisev1.0.0https://cran.r-project.org300001.8mcheckingforei+praisev1.0.0local260001.7mcheckingwhethETA3m(2/4)[2m59.1s]+praisev1.0.0https://cran.r-project.org300001.8mcheckingforei+praisev1.0.0local260001.7mcheckingwhethETA3m(2/4)[2m59.3s]+praisev1.0.0https://cran.r-project.org300001.8mcheckingforei+praisev1.0.0local260001.7mcheckingwhethETA3m(2/4)[2m59.5s]+praisev1.0.0https://cran.r-project.org300001.8mcheckingforeiETA3m(2/4)[2m59.7s]ETA3m(2/4)[2m59.9s]ETA3m(2/4)[3m0.1s]ETA3m(2/4)[3m0.5s]+praisev1.0.0https://cran.r-project.org310001.8mcheckingRcodETA3m(2/4)[3m0.7s]+praisev1.0.0https://cran.r-project.org310001.8mcheckingRcodETA3m(2/4)[3m0.9s]+praisev1.0.0https://cran.r-project.org310001.8mcheckingRcodETA3m(2/4)[3m1.2s]+praisev1.0.0https://cran.r-project.org310001.8mcheckingRcodETA3m(2/4)[3m1.4s]+praisev1.0.0https://cran.r-project.org330001.8mcheckingRdmeETA3m(2/4)[3m1.6s]+praisev1.0.0https://cran.r-project.org330001.8mcheckingRdmeETA3m(2/4)[3m1.8s]+praisev1.0.0https://cran.r-project.org330001.8mcheckingRdmeETA3m(2/4)[3m2s]+praisev1.0.0https://cran.r-project.org330001.8mcheckingRdmeETA3m(2/4)[3m2.2s]+praisev1.0.0local260001.8mcheckingwhethETA3m(2/4)[3m2.4s]+praisev1.0.0local260001.8mcheckingwhethETA3m(2/4)[3m2.6s]+praisev1.0.0local260001.8mcheckingwhethETA3m(2/4)[3m2.8s]+praisev1.0.0local260001.8mcheckingwhethETA3m(2/4)[3m3s]ETA3m(2/4)[3m3.2s]+praisev1.0.0local270001.8mcheckingdepenETA3m(2/4)[3m3.4s]+praisev1.0.0local270001.8mcheckingdepenETA3m(2/4)[3m3.6s]+praisev1.0.0local270001.8mcheckingdepenETA3m(2/4)[3m3.8s]+praisev1.0.0local270001.8mcheckingdepenETA3m(2/4)[3m4s]ETA3m(2/4)[3m4.2s]+praisev1.0.0local280001.8mcheckingS3geETA3m(2/4)[3m4.4s]+praisev1.0.0local280001.8mcheckingS3geETA3m(2/4)[3m4.7s]+praisev1.0.0local280001.8mcheckingS3geETA3m(2/4)[3m4.9s]+praisev1.0.0https://cran.r-project.org330001.9mcheckingRdme+praisev1.0.0local280001.8mcheckingS3geETA3m(2/4)[3m5.1s]+praisev1.0.0https://cran.r-project.org340001.9mcheckingformETA3m(2/4)[3m5.4s]+praisev1.0.0https://cran.r-project.org340001.9mcheckingformETA3m(2/4)[3m5.6s]+praisev1.0.0https://cran.r-project.org340001.9mcheckingformETA3m(2/4)[3m5.9s]+praisev1.0.0https://cran.r-project.org340001.9mcheckingformETA3m(2/4)[3m6.1s]ETA3m(2/4)[3m6.4s]ETA3m(2/4)[3m6.6s]+praisev1.0.0local290001.8mcheckingreplaETA3m(2/4)[3m6.9s]+praisev1.0.0local290001.8mcheckingreplaETA3m(2/4)[3m7.1s]+praisev1.0.0local290001.8mcheckingreplaETA3m(2/4)[3m7.3s]+praisev1.0.0local290001.8mcheckingreplaETA3m(2/4)[3m7.5s]ETA3m(2/4)[3m7.8s]ETA3m(2/4)[3m8s]ETA3m(2/4)[3m8.2s]+praisev1.0.0local300001.9mcheckingforeiETA3m(2/4)[3m8.4s]+praisev1.0.0local300001.9mcheckingforeiETA3m(2/4)[3m8.7s]+praisev1.0.0local300001.9mcheckingforeiETA3m(2/4)[3m8.9s]+praisev1.0.0local300001.9mcheckingforeiETA3m(2/4)[3m9.1s]ETA3m(2/4)[3m9.3s]ETA3m(2/4)[3m9.5s]ETA3m(2/4)[3m10s]ETA3m(2/4)[3m10.2s]ETA3m(2/4)[3m10.4s]ETA3m(2/4)[3m10.7s]ETA3m(2/4)[3m10.9s]+praisev1.0.0https://cran.r-project.org340002.0mcheckingformETA3m(2/4)[3m11.1s]+praisev1.0.0https://cran.r-project.org340002.0mcheckingformETA3m(2/4)[3m11.3s]+praisev1.0.0https://cran.r-project.org340002.0mcheckingformETA3m(2/4)[3m11.5s]+praisev1.0.0https://cran.r-project.org340002.0mcheckingformETA3m(2/4)[3m11.7s]ETA3m(2/4)[3m11.9s]ETA3m(2/4)[3m12.1s]ETA3m(2/4)[3m12.4s]ETA3m(2/4)[3m12.6s]ETA3m(2/4)[3m12.8s]ETA3m(2/4)[3m13s]ETA3m(2/4)[3m13.2s]ETA3m(2/4)[3m13.4s]ETA3m(2/4)[3m13.6s]ETA3m(2/4)[3m13.8s]ETA3m(2/4)[3m14s]ETA3m(2/4)[3m14.2s]+praisev1.0.0local300002.0mcheckingforeiETA3m(2/4)[3m14.4s]+praisev1.0.0local300002.0mcheckingforeiETA3m(2/4)[3m14.7s]+praisev1.0.0local300002.0mcheckingforeiETA3m(2/4)[3m14.9s]+praisev1.0.0local300002.0mcheckingforeiETA3m(2/4)[3m15.1s]ETA3m(2/4)[3m15.3s]ETA3m(2/4)[3m15.5s]ETA3m(2/4)[3m15.7s]ETA3m(2/4)[3m15.9s]ETA3m(2/4)[3m16.2s]+praisev1.0.0https://cran.r-project.org350002.0mcheckingforcETA3m(2/4)[3m16.4s]+praisev1.0.0https://cran.r-project.org350002.0mcheckingforcETA3m(2/4)[3m16.6s]+praisev1.0.0https://cran.r-project.org350002.0mcheckingforcETA3m(2/4)[3m16.8s]+praisev1.0.0https://cran.r-project.org350002.1mcheckingforcETA3m(2/4)[3m17s]+praisev1.0.0https://cran.r-project.org350002.1mcheckingforcETA3m(2/4)[3m17.2s]+praisev1.0.0https://cran.r-project.org350002.1mcheckingforc+praisev1.0.0local310002.0mcheckingRcodETA3m(2/4)[3m17.5s]+praisev1.0.0https://cran.r-project.org350002.1mcheckingforc+praisev1.0.0local310002.0mcheckingRcodETA3m(2/4)[3m17.7s]+praisev1.0.0https://cran.r-project.org360002.1mcheckingRd\u+praisev1.0.0local310002.0mcheckingRcodETA3m(2/4)[3m18s]+praisev1.0.0https://cran.r-project.org370002.1mcheckingRdco+praisev1.0.0local310002.0mcheckingRcodETA3m(2/4)[3m18.3s]+praisev1.0.0https://cran.r-project.org370002.1mcheckingRdco+praisev1.0.0local320002.0mcheckingRdfiETA3m(2/4)[3m18.6s]+praisev1.0.0https://cran.r-project.org400002.1mcheckingline+praisev1.0.0local330002.0mcheckingRdmeETA3m(2/4)[3m18.9s]+praisev1.0.0https://cran.r-project.org440002.1mcheckinguseo+praisev1.0.0local330002.0mcheckingRdmeETA3m(2/4)[3m19.2s]+praisev1.0.0https://cran.r-project.org440002.1mcheckinguseo+praisev1.0.0local330002.0mcheckingRdmeETA3m(2/4)[3m19.5s]+praisev1.0.0https://cran.r-project.org450002.1mcheckingcompi+praisev1.0.0local340002.0mcheckingformETA3m(2/4)[3m19.7s]+praisev1.0.0https://cran.r-project.org450002.1mcheckingcompi+praisev1.0.0local340002.0mcheckingformETA3m(2/4)[3m20s]+praisev1.0.0https://cran.r-project.org450002.1mcheckingcompi+praisev1.0.0local340002.0mcheckingformETA3m(2/4)[3m20.2s]+praisev1.0.0https://cran.r-project.org450002.1mcheckingcompi+praisev1.0.0local340002.1mcheckingformETA3m(2/4)[3m20.4s]+praisev1.0.0local340002.1mcheckingformETA3m(2/4)[3m20.7s]+praisev1.0.0local340002.1mcheckingformETA3m(2/4)[3m20.9s]+praisev1.0.0local340002.1mcheckingformETA3m(2/4)[3m21.1s]+praisev1.0.0https://cran.r-project.org470002.1mcheckingfilesETA3m(2/4)[3m21.3s]+praisev1.0.0https://cran.r-project.org470002.1mcheckingfilesETA3m(2/4)[3m21.6s]+praisev1.0.0https://cran.r-project.org470002.1mcheckingfilesETA3m(2/4)[3m21.8s]+praisev1.0.0https://cran.r-project.org470002.1mcheckingfilesETA3m(2/4)[3m22s]ETA3m(2/4)[3m22.2s]ETA3m(2/4)[3m22.4s]ETA3m(2/4)[3m22.7s]+praisev1.0.0https://cran.r-project.org470002.2mcheckingfilesETA3m(2/4)[3m23s]+praisev1.0.0https://cran.r-project.org470002.2mcheckingfilesETA3m(2/4)[3m23.2s]+praisev1.0.0https://cran.r-project.org470002.2mcheckingfilesETA3m(2/4)[3m23.4s]+praisev1.0.0https://cran.r-project.org470002.2mcheckingfilesETA3m(2/4)[3m23.6s]+praisev1.0.0local350002.1mcheckingforcETA3m(2/4)[3m23.8s]+praisev1.0.0local350002.1mcheckingforcETA3m(2/4)[3m24.1s]+praisev1.0.0local350002.1mcheckingforcETA3m(2/4)[3m24.3s]+praisev1.0.0local350002.1mcheckingforcETA3m(2/4)[3m24.6s]ETA3m(2/4)[3m24.8s]ETA3m(2/4)[3m25s]ETA3m(2/4)[3m25.2s]+praisev1.0.0local360002.1mcheckingRd\uETA3m(2/4)[3m25.5s]+praisev1.0.0local360002.1mcheckingRd\uETA3m(2/4)[3m25.7s]+praisev1.0.0local370002.1mcheckingRdcoETA3m(2/4)[3m25.9s]+praisev1.0.0local370002.1mcheckingRdcoETA3m(2/4)[3m26.2s]+praisev1.0.0local400002.2mcheckinglineETA3m(2/4)[3m26.4s]+praisev1.0.0local440002.2mcheckinguseoETA3m(2/4)[3m26.7s]+praisev1.0.0local450002.2mcheckingcompiETA3m(2/4)[3m26.9s]+praisev1.0.0https://cran.r-project.org490002.2mcheckingforu+praisev1.0.0local450002.2mcheckingcompiETA3m(2/4)[3m27.2s]+praisev1.0.0https://cran.r-project.org490002.2mcheckingforu+praisev1.0.0local450002.2mcheckingcompiETA3m(2/4)[3m27.5s]+praisev1.0.0https://cran.r-project.org490002.2mcheckingforu+praisev1.0.0local470002.2mcheckingfilesETA3m(2/4)[3m27.7s]+praisev1.0.0https://cran.r-project.org490002.2mcheckingforu+praisev1.0.0local470002.2mcheckingfilesETA3m(2/4)[3m27.9s]+praisev1.0.0local470002.2mcheckingfilesETA3m(2/4)[3m28.1s]+praisev1.0.0local470002.2mcheckingfilesETA3m(2/4)[3m28.3s]ETA3m(2/4)[3m28.5s]ETA3m(2/4)[3m28.7s]ETA3m(2/4)[3m29s]+praisev1.0.0https://cran.r-project.org490002.3mcheckingforuETA3m(2/4)[3m29.2s]+praisev1.0.0https://cran.r-project.org490002.3mcheckingforuETA3m(2/4)[3m29.4s]+praisev1.0.0https://cran.r-project.org490002.3mcheckingforuETA3m(2/4)[3m29.7s]+praisev1.0.0https://cran.r-project.org490002.3mcheckingforuETA3m(2/4)[3m29.9s]ETA4m(2/4)[3m30.2s]ETA4m(2/4)[3m30.4s]+praisev1.0.0https://cran.r-project.org490002.3mcheckingtestsETA4m(2/4)[3m30.7s]+praisev1.0.0https://cran.r-project.org490002.3mcheckingtestsETA4m(2/4)[3m30.9s]+praisev1.0.0https://cran.r-project.org490002.3mcheckingtestsETA4m(2/4)[3m31.2s]+praisev1.0.0https://cran.r-project.org490002.3mcheckingtestsETA4m(2/4)[3m31.4s]ETA4m(2/4)[3m31.7s]ETA4m(2/4)[3m31.9s]ETA4m(2/4)[3m32.1s]+praisev1.0.0local470002.3mcheckingfilesETA4m(2/4)[3m32.4s]+praisev1.0.0local470002.3mcheckingfilesETA4m(2/4)[3m32.6s]+praisev1.0.0local470002.3mcheckingfilesETA4m(2/4)[3m32.8s]+praisev1.0.0local470002.3mcheckingfilesETA4m(2/4)[3m33.1s]ETA4m(2/4)[3m33.3s]ETA4m(2/4)[3m33.6s]ETA4m(2/4)[3m33.8s]ETA4m(2/4)[3m34.1s]ETA4m(2/4)[3m34.3s]ETA4m(2/4)[3m34.5s]ETA4m(2/4)[3m34.8s]+praisev1.0.0https://cran.r-project.org490002.4mcheckingtestsETA4m(2/4)[3m35s]+praisev1.0.0https://cran.r-project.org490002.4mcheckingtestsETA4m(2/4)[3m35.4s]+praisev1.0.0https://cran.r-project.org490002.4mcheckingtestsETA4m(2/4)[3m35.7s]+praisev1.0.0https://cran.r-project.org490002.4mcheckingtestsETA4m(2/4)[3m36s]ETA4m(2/4)[3m36.3s]ETA4m(2/4)[3m36.5s]ETA4m(2/4)[3m36.7s]ETA4m(2/4)[3m36.9s]ETA4m(2/4)[3m37.1s]ETA4m(2/4)[3m37.3s]ETA4m(2/4)[3m37.6s]ETA4m(2/4)[3m37.8s]ETA4m(2/4)[3m38.2s]+praisev1.0.0local470002.4mcheckingfilesETA4m(2/4)[3m38.4s]+praisev1.0.0local470002.4mcheckingfilesETA4m(2/4)[3m38.6s]+praisev1.0.0local470002.4mcheckingfilesETA4m(2/4)[3m38.8s]+praisev1.0.0local470002.4mcheckingfilesETA4m(2/4)[3m39.1s]ETA4m(2/4)[3m39.3s]ETA4m(2/4)[3m39.5s]ETA4m(2/4)[3m39.7s]ETA4m(2/4)[3m40s]ETA4m(2/4)[3m40.2s]ETA4m(2/4)[3m40.4s]ETA4m(2/4)[3m40.6s]ETA4m(2/4)[3m40.9s]+praisev1.0.0https://cran.r-project.org490002.5mcheckingtestsETA4m(2/4)[3m41.1s]+praisev1.0.0https://cran.r-project.org490002.5mcheckingtestsETA4m(2/4)[3m41.4s]+praisev1.0.0https://cran.r-project.org490002.5mcheckingtestsETA4m(2/4)[3m41.6s]+praisev1.0.0https://cran.r-project.org490002.5mcheckingtestsETA4m(2/4)[3m41.9s]ETA4m(2/4)[3m42.2s]ETA4m(2/4)[3m42.4s]ETA4m(2/4)[3m42.6s]ETA4m(2/4)[3m42.9s]ETA4m(2/4)[3m43.1s]ETA4m(2/4)[3m43.4s]ETA4m(2/4)[3m43.6s]ETA4m(2/4)[3m43.8s]ETA4m(2/4)[3m44.1s]ETA4m(2/4)[3m44.3s]+praisev1.0.0local470002.5mcheckingfilesETA4m(2/4)[3m44.5s]+praisev1.0.0local490002.5mcheckingforuETA4m(2/4)[3m44.9s]+praisev1.0.0local490002.5mcheckingforuETA4m(2/4)[3m45.1s]+praisev1.0.0local490002.5mcheckingforuETA4m(2/4)[3m45.4s]+praisev1.0.0local490002.5mcheckingforuETA4m(2/4)[3m45.7s]ETA4m(2/4)[3m46s]ETA4m(2/4)[3m46.3s]ETA4m(2/4)[3m46.6s]ETA4m(2/4)[3m46.9s]+praisev1.0.0https://cran.r-project.org490002.6mcheckingtestsETA4m(2/4)[3m47.2s]+praisev1.0.0https://cran.r-project.org490002.6mcheckingtestsETA4m(2/4)[3m47.6s]+praisev1.0.0https://cran.r-project.org490002.6mcheckingtestsETA4m(2/4)[3m47.8s]+praisev1.0.0https://cran.r-project.org490002.6mcheckingtestsETA4m(2/4)[3m48.1s]ETA4m(2/4)[3m48.4s]+praisev1.0.0local490002.5mcheckingtestsETA4m(2/4)[3m48.8s]+praisev1.0.0local490002.5mcheckingtestsETA4m(2/4)[3m49.2s]+praisev1.0.0local490002.5mcheckingtestsETA4m(2/4)[3m49.4s]+praisev1.0.0local490002.5mcheckingtestsETA4m(2/4)[3m49.7s]ETA4m(2/4)[3m50s]ETA4m(2/4)[3m50.3s]+praisev1.0.0local490002.6mcheckingtestsETA4m(2/4)[3m50.5s]+praisev1.0.0local490002.6mcheckingtestsETA4m(2/4)[3m50.9s]+praisev1.0.0local490002.6mcheckingtestsETA4m(2/4)[3m51.2s]+praisev1.0.0local490002.6mcheckingtestsETA4m(2/4)[3m51.5s]ETA4m(2/4)[3m51.8s]ETA4m(2/4)[3m52.1s]ETA4m(2/4)[3m52.3s]ETA4m(2/4)[3m52.6s]ETA4m(2/4)[3m53s]+praisev1.0.0https://cran.r-project.org490002.7mcheckingtestsETA4m(2/4)[3m53.3s]+praisev1.0.0https://cran.r-project.org490002.7mcheckingtestsETA4m(2/4)[3m53.6s]+praisev1.0.0https://cran.r-project.org490002.7mcheckingtestsETA4m(2/4)[3m53.9s]+praisev1.0.0https://cran.r-project.org490002.7mcheckingtestsETA4m(2/4)[3m54.2s]ETA4m(2/4)[3m54.5s]ETA4m(2/4)[3m54.7s]ETA4m(2/4)[3m55s]ETA4m(2/4)[3m55.3s]ETA4m(2/4)[3m55.7s]ETA4m(2/4)[3m55.9s]ETA4m(2/4)[3m56.3s]+praisev1.0.0local490002.7mcheckingtestsETA4m(2/4)[3m56.6s]+praisev1.0.0local490002.7mcheckingtestsETA4m(2/4)[3m57s]+praisev1.0.0local490002.7mcheckingtestsETA4m(2/4)[3m57.3s]+praisev1.0.0local490002.7mcheckingtestsETA4m(2/4)[3m57.6s]ETA4m(2/4)[3m57.9s]ETA4m(2/4)[3m58.3s]ETA4m(2/4)[3m58.6s]ETA4m(2/4)[3m58.9s]+praisev1.0.0https://cran.r-project.org490002.8mcheckingtestsETA4m(2/4)[3m59.4s]+praisev1.0.0https://cran.r-project.org490002.8mcheckingtestsETA4m(2/4)[3m59.7s]+praisev1.0.0https://cran.r-project.org490002.8mcheckingtestsETA4m(2/4)[4m0.1s]+praisev1.0.0https://cran.r-project.org490002.8mcheckingtestsETA4m(2/4)[4m0.4s]ETA4m(2/4)[4m0.7s]ETA4m(2/4)[4m1s]ETA4m(2/4)[4m1.3s]ETA4m(2/4)[4m1.6s]ETA4m(2/4)[4m2s]ETA4m(2/4)[4m2.3s]+praisev1.0.0local490002.8mcheckingtestsETA4m(2/4)[4m2.6s]+praisev1.0.0local490002.8mcheckingtestsETA4m(2/4)[4m2.9s]+praisev1.0.0local490002.8mcheckingtestsETA4m(2/4)[4m3.2s]+praisev1.0.0local490002.8mcheckingtestsETA4m(2/4)[4m3.5s]ETA4m(2/4)[4m3.9s]ETA4m(2/4)[4m4.2s]ETA4m(2/4)[4m4.6s]ETA4m(2/4)[4m5.2s]+praisev1.0.0https://cran.r-project.org490002.9mcheckingtestsETA4m(2/4)[4m5.7s]+praisev1.0.0https://cran.r-project.org490002.9mcheckingtestsETA4m(2/4)[4m6s]+praisev1.0.0https://cran.r-project.org490002.9mcheckingtestsETA4m(2/4)[4m6.3s]+praisev1.0.0https://cran.r-project.org490002.9mcheckingtestsETA4m(2/4)[4m6.6s]ETA4m(2/4)[4m7s]ETA4m(2/4)[4m7.2s]ETA4m(2/4)[4m7.5s]ETA4m(2/4)[4m7.8s]ETA4m(2/4)[4m8s]ETA4m(2/4)[4m8.3s]+praisev1.0.0local490002.9mcheckingtestsETA4m(2/4)[4m8.6s]+praisev1.0.0local490002.9mcheckingtestsETA4m(2/4)[4m8.9s]+praisev1.0.0local490002.9mcheckingtestsETA4m(2/4)[4m9.2s]+praisev1.0.0local490002.9mcheckingtestsETA4m(2/4)[4m9.4s]ETA4m(2/4)[4m9.7s]ETA4m(2/4)[4m10s]ETA4m(2/4)[4m10.3s]ETA4m(2/4)[4m10.6s]ETA4m(2/4)[4m11s]+praisev1.0.0https://cran.r-project.org490003.0mcheckingtestsETA4m(2/4)[4m11.3s]+praisev1.0.0https://cran.r-project.org490003.0mcheckingtestsETA4m(2/4)[4m11.5s]+praisev1.0.0https://cran.r-project.org490003.0mcheckingtestsETA4m(2/4)[4m11.8s]+praisev1.0.0https://cran.r-project.org490003.0mcheckingtestsETA4m(2/4)[4m12.1s]ETA4m(2/4)[4m12.4s]ETA4m(2/4)[4m12.6s]ETA4m(2/4)[4m12.9s]ETA4m(2/4)[4m13.2s]ETA4m(2/4)[4m13.5s]ETA4m(2/4)[4m13.8s]ETA4m(2/4)[4m14s]ETA4m(2/4)[4m14.3s]+praisev1.0.0local490003.0mcheckingtestsETA4m(2/4)[4m14.6s]+praisev1.0.0local490003.0mcheckingtestsETA4m(2/4)[4m14.9s]+praisev1.0.0local490003.0mcheckingtestsETA4m(2/4)[4m15.3s]+praisev1.0.0local490003.0mcheckingtestsETA4m(2/4)[4m15.7s]ETA4m(2/4)[4m16s]ETA4m(2/4)[4m16.5s]ETA4m(2/4)[4m17s]+praisev1.0.0https://cran.r-project.org490003.1mcheckingtestsETA4m(2/4)[4m17.4s]+praisev1.0.0https://cran.r-project.org490003.1mcheckingtestsETA4m(2/4)[4m17.8s]+praisev1.0.0https://cran.r-project.org490003.1mcheckingtestsETA4m(2/4)[4m18.3s]+praisev1.0.0https://cran.r-project.org490003.1mcheckingtestsETA4m(2/4)[4m18.7s]ETA4m(2/4)[4m19.1s]ETA4m(2/4)[4m19.6s]ETA4m(2/4)[4m19.9s]ETA4m(2/4)[4m20.3s]+praisev1.0.0local490003.1mcheckingtestsETA4m(2/4)[4m20.6s]+praisev1.0.0local490003.1mcheckingtestsETA4m(2/4)[4m21s]+praisev1.0.0local490003.1mcheckingtestsETA4m(2/4)[4m21.3s]+praisev1.0.0local490003.1mcheckingtestsETA4m(2/4)[4m21.6s]ETA4m(2/4)[4m22s]ETA4m(2/4)[4m22.5s]ETA4m(2/4)[4m22.8s]ETA4m(2/4)[4m23.1s]+praisev1.0.0https://cran.r-project.org490003.2mcheckingtestsETA4m(2/4)[4m23.4s]+praisev1.0.0https://cran.r-project.org490003.2mcheckingtestsETA4m(2/4)[4m23.7s]+praisev1.0.0https://cran.r-project.org490003.2mcheckingtestsETA4m(2/4)[4m24.1s]+praisev1.0.0https://cran.r-project.org490003.2mcheckingtestsETA4m(2/4)[4m24.5s]ETA4m(2/4)[4m24.9s]ETA4m(2/4)[4m25.5s]ETA4m(2/4)[4m25.8s]ETA4m(2/4)[4m26.2s]+praisev1.0.0local490003.2mcheckingtestsETA4m(2/4)[4m26.5s]+praisev1.0.0local490003.2mcheckingtestsETA4m(2/4)[4m26.9s]+praisev1.0.0local490003.2mcheckingtestsETA4m(2/4)[4m27.2s]+praisev1.0.0local490003.2mcheckingtestsETA4m(2/4)[4m27.6s]ETA4m(2/4)[4m27.9s]ETA4m(2/4)[4m28.4s]ETA4m(2/4)[4m28.8s]+praisev1.0.0https://cran.r-project.org490003.3mcheckingtestsETA4m(2/4)[4m29.2s]+praisev1.0.0https://cran.r-project.org490003.3mcheckingtestsETA4m(2/4)[4m29.5s]+praisev1.0.0https://cran.r-project.org490003.3mcheckingtestsETA4m(2/4)[4m29.9s]+praisev1.0.0https://cran.r-project.org490003.3mcheckingtestsETA5m(2/4)[4m30.1s]ETA5m(2/4)[4m30.5s]ETA5m(2/4)[4m30.8s]ETA5m(2/4)[4m31.1s]ETA5m(2/4)[4m31.5s]ETA5m(2/4)[4m31.8s]ETA5m(2/4)[4m32.3s]+praisev1.0.0local490003.3mcheckingtestsETA5m(2/4)[4m32.6s]+praisev1.0.0local490003.3mcheckingtestsETA5m(2/4)[4m33.1s]+praisev1.0.0local490003.3mcheckingtestsETA5m(2/4)[4m33.6s]+praisev1.0.0local490003.3mcheckingtestsETA5m(2/4)[4m34.3s]ETA5m(2/4)[4m34.7s]ETA5m(2/4)[4m35.1s]+praisev1.0.0https://cran.r-project.org490003.4mcheckingtestsETA5m(2/4)[4m35.7s]+praisev1.0.0https://cran.r-project.org490003.4mcheckingtestsETA5m(2/4)[4m36.4s]+praisev1.0.0https://cran.r-project.org490003.4mcheckingtestsETA5m(2/4)[4m36.8s]+praisev1.0.0https://cran.r-project.org490003.4mcheckingtestsETA5m(2/4)[4m37.4s]ETA5m(2/4)[4m37.8s]ETA5m(2/4)[4m38.3s]+praisev1.0.0local490003.4mcheckingtestsETA5m(2/4)[4m38.9s]+praisev1.0.0local490003.4mcheckingtestsETA5m(2/4)[4m39.3s]+praisev1.0.0local490003.4mcheckingtestsETA5m(2/4)[4m39.6s]+praisev1.0.0local490003.4mcheckingtestsETA5m(2/4)[4m40s]ETA5m(2/4)[4m40.3s]ETA5m(2/4)[4m40.7s]ETA5m(2/4)[4m41.2s]+praisev1.0.0https://cran.r-project.org490003.5mcheckingtestsETA5m(2/4)[4m41.7s]+praisev1.0.0https://cran.r-project.org490003.5mcheckingtestsETA5m(2/4)[4m42.3s]+praisev1.0.0https://cran.r-project.org490003.5mcheckingtestsETA5m(2/4)[4m42.8s]+praisev1.0.0https://cran.r-project.org490003.5mcheckingtestsETA5m(2/4)[4m43.4s]ETA5m(2/4)[4m44.1s]+praisev1.0.0local490003.5mcheckingtestsETA5m(2/4)[4m44.8s]+praisev1.0.0local490003.5mcheckingtestsETA5m(2/4)[4m45.3s]+praisev1.0.0local490003.5mcheckingtestsETA5m(2/4)[4m45.8s]+praisev1.0.0local490003.5mcheckingtestsETA5m(2/4)[4m46.5s]ETA5m(2/4)[4m46.9s]+praisev1.0.0https://cran.r-project.org490003.6mcheckingtestsETA5m(2/4)[4m47.4s]+praisev1.0.0https://cran.r-project.org490003.6mcheckingtestsETA5m(2/4)[4m47.8s]+praisev1.0.0https://cran.r-project.org490003.6mcheckingtestsETA5m(2/4)[4m48.1s]+praisev1.0.0https://cran.r-project.org490003.6mcheckingtestsETA5m(2/4)[4m48.6s]ETA5m(2/4)[4m49.1s]ETA5m(2/4)[4m49.5s]ETA5m(2/4)[4m50s]ETA5m(2/4)[4m50.5s]+praisev1.0.0local490003.6mcheckingtestsETA5m(2/4)[4m50.9s]+praisev1.0.0local490003.6mcheckingtestsETA5m(2/4)[4m51.4s]+praisev1.0.0local490003.6mcheckingtestsETA5m(2/4)[4m51.8s]+praisev1.0.0local490003.6mcheckingtestsETA5m(2/4)[4m52.1s]ETA5m(2/4)[4m52.5s]ETA5m(2/4)[4m52.9s]+praisev1.0.0https://cran.r-project.org490003.7mcheckingtestsETA5m(2/4)[4m53.2s]+praisev1.0.0https://cran.r-project.org490003.7mcheckingtestsETA5m(2/4)[4m53.6s]+praisev1.0.0https://cran.r-project.org490003.7mcheckingtestsETA5m(2/4)[4m54s]+praisev1.0.0https://cran.r-project.org490003.7mcheckingtestsETA5m(2/4)[4m54.4s]ETA5m(2/4)[4m54.8s]ETA5m(2/4)[4m55.1s]ETA5m(2/4)[4m55.6s]ETA5m(2/4)[4m55.9s]ETA5m(2/4)[4m56.3s]+praisev1.0.0local490003.7mcheckingtestsETA5m(2/4)[4m56.8s]+praisev1.0.0local490003.7mcheckingtestsETA5m(2/4)[4m57.3s]+praisev1.0.0local490003.7mcheckingtestsETA5m(2/4)[4m57.7s]+praisev1.0.0local490003.7mcheckingtestsETA5m(2/4)[4m58.1s]ETA5m(2/4)[4m58.5s]ETA5m(2/4)[4m58.9s]+praisev1.0.0https://cran.r-project.org490003.8mcheckingtestsETA5m(2/4)[4m59.4s]+praisev1.0.0https://cran.r-project.org490003.8mcheckingtestsETA5m(2/4)[4m59.7s]+praisev1.0.0https://cran.r-project.org490003.8mcheckingtestsETA5m(2/4)[5m0.1s]+praisev1.0.0https://cran.r-project.org490003.8mcheckingtestsETA5m(2/4)[5m0.5s]ETA5m(2/4)[5m1s]ETA5m(2/4)[5m1.4s]ETA5m(2/4)[5m1.9s]+praisev1.0.0local490003.8mcheckingtestsETA5m(2/4)[5m2.6s]+praisev1.0.0local490003.8mcheckingtestsETA5m(2/4)[5m3.1s]+praisev1.0.0local490003.8mcheckingtestsETA5m(2/4)[5m3.5s]+praisev1.0.0local490003.8mcheckingtestsETA5m(2/4)[5m3.9s]ETA5m(2/4)[5m4.3s]ETA5m(2/4)[5m4.7s]ETA5m(2/4)[5m5.3s]+praisev1.0.0https://cran.r-project.org490003.9mcheckingtestsETA5m(2/4)[5m5.8s]+praisev1.0.0https://cran.r-project.org490003.9mcheckingtestsETA5m(2/4)[5m6.5s]+praisev1.0.0https://cran.r-project.org490003.9mcheckingtestsETA5m(2/4)[5m7s]+praisev1.0.0https://cran.r-project.org490003.9mcheckingtestsETA5m(2/4)[5m7.6s]ETA5m(2/4)[5m7.9s]ETA5m(2/4)[5m8.3s]+praisev1.0.0local490003.9mcheckingtestsETA5m(2/4)[5m8.7s]+praisev1.0.0local490003.9mcheckingtestsETA5m(2/4)[5m9.2s]+praisev1.0.0local490003.9mcheckingtestsETA5m(2/4)[5m9.6s]+praisev1.0.0local490003.9mcheckingtestsETA5m(2/4)[5m9.9s]ETA5m(2/4)[5m10.3s]ETA5m(2/4)[5m10.6s]ETA5m(2/4)[5m11s]+praisev1.0.0https://cran.r-project.org490004.0mcheckingtestsETA5m(2/4)[5m11.4s]+praisev1.0.0https://cran.r-project.org490004.0mcheckingtestsETA5m(2/4)[5m11.8s]+praisev1.0.0https://cran.r-project.org490004.0mcheckingtestsETA5m(2/4)[5m12.1s]+praisev1.0.0https://cran.r-project.org490004.0mcheckingtestsETA5m(2/4)[5m12.5s]ETA5m(2/4)[5m12.9s]ETA5m(2/4)[5m13.2s]ETA5m(2/4)[5m13.6s]ETA5m(2/4)[5m13.9s]ETA5m(2/4)[5m14.3s]+praisev1.0.0local490004.0mcheckingtestsETA5m(2/4)[5m14.6s]+praisev1.0.0local490004.0mcheckingtestsETA5m(2/4)[5m15.1s]+praisev1.0.0local490004.0mcheckingtestsETA5m(2/4)[5m15.5s]+praisev1.0.0https://cran.r-project.org490014.0mcheckingtests+praisev1.0.0local490004.0mcheckingtestsETA5m(2/4)[5m15.8s]+praisev1.0.0https://cran.r-project.org490014.0mcheckingtestsETA5m(2/4)[5m16.1s]+praisev1.0.0https://cran.r-project.org490014.0mETA2m(3/4)[5m16.6s]ETA2m(3/4)[5m16.9s]ETA2m(3/4)[5m17.2s]ETA2m(3/4)[5m17.6s]ETA2m(3/4)[5m17.9s]ETA2m(3/4)[5m18.2s]ETA2m(3/4)[5m18.6s]ETA2m(3/4)[5m18.9s]ETA2m(3/4)[5m19.2s]ETA2m(3/4)[5m19.6s]ETA2m(3/4)[5m19.9s]ETA2m(3/4)[5m20.3s]+praisev1.0.0local490004.1mcheckingtestsETA2m(3/4)[5m20.7s]+praisev1.0.0local490004.1mcheckingtestsETA2m(3/4)[5m21s]+praisev1.0.0local490004.1mcheckingtestsETA2m(3/4)[5m21.4s]+praisev1.0.0local490004.1mcheckingtestsETA2m(3/4)[5m21.7s]ETA2m(3/4)[5m22.1s]ETA2m(3/4)[5m22.4s]ETA2m(3/4)[5m22.8s]ETA2m(3/4)[5m23.2s]ETA2m(3/4)[5m23.5s]ETA2m(3/4)[5m23.9s]ETA2m(3/4)[5m24.3s]ETA2m(3/4)[5m24.6s]ETA2m(3/4)[5m25s]ETA2m(3/4)[5m25.3s]ETA2m(3/4)[5m25.8s]ETA2m(3/4)[5m26.2s]+praisev1.0.0local490004.2mcheckingtestsETA2m(3/4)[5m26.5s]+praisev1.0.0local490004.2mcheckingtestsETA2m(3/4)[5m26.9s]+praisev1.0.0local490004.2mcheckingtestsETA2m(3/4)[5m27.2s]+praisev1.0.0local490004.2mcheckingtestsETA2m(3/4)[5m27.5s]ETA2m(3/4)[5m27.9s]ETA2m(3/4)[5m28.2s]ETA2m(3/4)[5m28.5s]ETA2m(3/4)[5m28.8s]ETA2m(3/4)[5m29.1s]+praisev1.0.0local490014.2mcheckingtestsETA2m(3/4)[5m29.5s]+praisev1.0.0local490014.2mcheckingtestsETA2m(3/4)[5m29.8s]+praisev1.0.0local490014.2mETA2m(3/4)[5m30.1s]Finishedin5m30.5sETA0s(1/4)[3ms]ETA?(0/4)[1m0.7s]installinghtmlwidgetsshinytestthatETA?(0/4)[1m11.1s]installingdiffviewerETA0s(4/4)[5m30.5s] \ No newline at end of file diff --git a/man/figures/README/ansi-tty-example.svg b/man/figures/README/ansi-tty-example.svg index 8a3162b..a443e0e 100644 --- a/man/figures/README/ansi-tty-example.svg +++ b/man/figures/README/ansi-tty-example.svg @@ -1 +1 @@ -ETA?(0/4)[1.1s]installingpraise(release),diffviewerETA?(0/4)[1.4s]installingpraise(release),diffviewerETA?(0/4)[1.6s]installingpraise(release),diffviewerETA?(0/4)[1.8s]installingpraise(release),diffviewerETA?(0/4)[2.1s]installingpraise(release),diffviewerETA?(0/4)[2.3s]installingpraise(release),diffviewerETA?(0/4)[2.5s]installingpraise(release),diffviewerETA?(0/4)[2.7s]installingpraise(release),diffviewerETA?(0/4)[3s]installingpraise(release),diffviewerETA?(0/4)[3.2s]installingpraise(release),diffviewerETA?(0/4)[3.4s]installingpraise(release),diffviewerETA?(0/4)[3.6s]installingpraise(release),diffviewerETA?(0/4)[3.9s]installingdiffviewer,praise(dev)ETA?(0/4)[4.2s]installingdiffviewer,praise(dev)SOKNWEtestthat(v1.0.0)00000.9sstarting...ETA?(0/4)[7.3s]installingpraise(dev)testthat(v1.0.0)20002.7scheckingpackagenamespaceinfortestthat(dev)00001.0sstarting...ETA?(0/4)[9.2s]testthat(v1.0.0)50003.1scheckingifthereisanamespacetestthat(dev)00001.4sstarting...ETA?(0/4)[9.7s]testthat(v1.0.0)50003.6scheckingifthereisanamespacetestthat(dev)00001.8sstarting...ETA?(0/4)[10s]testthat(v1.0.0)50003.9scheckingifthereisanamespacetestthat(dev)20002.1scheckingpackagenamespaceinforETA?(0/4)[10.3s]testthat(v1.0.0)50004.3scheckingifthereisanamespacetestthat(dev)20002.5scheckingpackagenamespaceinforETA?(0/4)[10.7s]testthat(v1.0.0)50004.6scheckingifthereisanamespacetestthat(dev)20002.9scheckingpackagenamespaceinforETA?(0/4)[11.1s]testthat(v1.0.0)90005.0scheckingforsufficient/correcttestthat(dev)20003.3scheckingpackagenamespaceinforETA?(0/4)[11.5s]testthat(v1.0.0)90005.4scheckingforsufficient/correcttestthat(dev)50003.6scheckingifthereisanamespaceETA?(0/4)[11.8s]testthat(v1.0.0)90005.7scheckingforsufficient/correcttestthat(dev)50003.9scheckingifthereisanamespaceETA?(0/4)[12.1s]testthat(v1.0.0)90006.1scheckingforsufficient/correcttestthat(dev)50004.3scheckingifthereisanamespaceETA?(0/4)[12.5s]testthat(v1.0.0)90006.4scheckingforsufficient/correcttestthat(dev)50004.7scheckingifthereisanamespaceETA?(0/4)[12.9s]testthat(v1.0.0)90006.8scheckingforsufficient/correcttestthat(dev)50005.0scheckingifthereisanamespaceETA?(0/4)[13.2s]testthat(v1.0.0)90007.1scheckingforsufficient/correcttestthat(dev)90005.3scheckingforsufficient/correctETA?(0/4)[13.5s]testthat(v1.0.0)90007.5scheckingforsufficient/correcttestthat(dev)90005.7scheckingforsufficient/correctETA?(0/4)[14s]testthat(v1.0.0)90007.9scheckingforsufficient/correcttestthat(dev)90006.1scheckingforsufficient/correctETA?(0/4)[14.3s]testthat(v1.0.0)90008.3scheckingforsufficient/correcttestthat(dev)90006.5scheckingforsufficient/correctETA?(0/4)[14.7s]testthat(v1.0.0)90008.6scheckingforsufficient/correcttestthat(dev)90006.8scheckingforsufficient/correctETA?(0/4)[15s]testthat(v1.0.0)90008.9scheckingforsufficient/correcttestthat(dev)90007.1scheckingforsufficient/correctETA?(0/4)[15.3s]testthat(v1.0.0)90009.3scheckingforsufficient/correcttestthat(dev)90007.5scheckingforsufficient/correctETA?(0/4)[15.7s]testthat(v1.0.0)90009.6scheckingforsufficient/correcttestthat(dev)90007.8scheckingforsufficient/correctETA?(0/4)[16s]testthat(v1.0.0)90009.9scheckingforsufficient/correcttestthat(dev)90008.1scheckingforsufficient/correctETA?(0/4)[16.3s]testthat(v1.0.0)900010.3scheckingforsufficient/correcttestthat(dev)90008.5scheckingforsufficient/correctETA?(0/4)[16.7s]testthat(v1.0.0)900010.6scheckingforsufficient/correcttestthat(dev)90008.8scheckingforsufficient/correctETA?(0/4)[17s]testthat(v1.0.0)900011.0scheckingforsufficient/correcttestthat(dev)90009.2scheckingforsufficient/correctETA?(0/4)[17.4s]testthat(v1.0.0)900011.4scheckingforsufficient/correcttestthat(dev)90009.6scheckingforsufficient/correctETA?(0/4)[17.8s]testthat(v1.0.0)900011.8scheckingforsufficient/correcttestthat(dev)900010.0scheckingforsufficient/correctETA?(0/4)[18.2s]testthat(v1.0.0)900012.1scheckingforsufficient/correcttestthat(dev)900010.3scheckingforsufficient/correctETA?(0/4)[18.6s]testthat(v1.0.0)900012.5scheckingforsufficient/correcttestthat(dev)900010.7scheckingforsufficient/correctETA?(0/4)[18.9s]testthat(v1.0.0)900012.8scheckingforsufficient/correcttestthat(dev)900011.0scheckingforsufficient/correctETA?(0/4)[19.2s]testthat(v1.0.0)900013.2scheckingforsufficient/correcttestthat(dev)900011.4scheckingforsufficient/correctETA?(0/4)[19.6s]testthat(v1.0.0)900013.5scheckingforsufficient/correcttestthat(dev)900011.7scheckingforsufficient/correctETA?(0/4)[19.9s]testthat(v1.0.0)900013.9scheckingforsufficient/correcttestthat(dev)900012.0scheckingforsufficient/correctETA?(0/4)[20.2s]testthat(v1.0.0)900014.2scheckingforsufficient/correcttestthat(dev)900012.4scheckingforsufficient/correctETA?(0/4)[20.6s]testthat(v1.0.0)900014.5scheckingforsufficient/correcttestthat(dev)900012.7scheckingforsufficient/correctETA?(0/4)[20.9s]testthat(v1.0.0)900014.8scheckingforsufficient/correcttestthat(dev)900013.0scheckingforsufficient/correctETA?(0/4)[21.2s]testthat(v1.0.0)900015.2scheckingforsufficient/correcttestthat(dev)900013.4scheckingforsufficient/correctETA?(0/4)[21.6s]testthat(v1.0.0)900015.5scheckingforsufficient/correcttestthat(dev)900013.8scheckingforsufficient/correctETA?(0/4)[22s]testthat(v1.0.0)900015.9scheckingforsufficient/correcttestthat(dev)900014.1scheckingforsufficient/correctETA?(0/4)[22.3s]testthat(v1.0.0)900016.2scheckingforsufficient/correcttestthat(dev)900014.4scheckingforsufficient/correctETA?(0/4)[22.6s]testthat(v1.0.0)900016.6scheckingforsufficient/correcttestthat(dev)900014.8scheckingforsufficient/correctETA?(0/4)[23s]testthat(v1.0.0)900016.9scheckingforsufficient/correcttestthat(dev)900015.1scheckingforsufficient/correctETA?(0/4)[23.3s]testthat(v1.0.0)900017.3scheckingforsufficient/correcttestthat(dev)900015.5scheckingforsufficient/correctETA?(0/4)[23.6s]testthat(v1.0.0)900017.6scheckingforsufficient/correcttestthat(dev)900015.8scheckingforsufficient/correctETA?(0/4)[24s]testthat(v1.0.0)900018.0scheckingforsufficient/correcttestthat(dev)900016.1scheckingforsufficient/correctETA?(0/4)[24.3s]testthat(v1.0.0)900018.3scheckingforsufficient/correcttestthat(dev)900016.5scheckingforsufficient/correctETA?(0/4)[24.7s]testthat(v1.0.0)900018.6scheckingforsufficient/correcttestthat(dev)900016.8scheckingforsufficient/correctETA?(0/4)[25s]testthat(v1.0.0)900019.0scheckingforsufficient/correcttestthat(dev)900017.2scheckingforsufficient/correctETA?(0/4)[25.4s]testthat(v1.0.0)900019.3scheckingforsufficient/correcttestthat(dev)900017.5scheckingforsufficient/correctETA?(0/4)[25.8s]testthat(v1.0.0)900019.8scheckingforsufficient/correcttestthat(dev)900018.0scheckingforsufficient/correctETA?(0/4)[26.3s]testthat(v1.0.0)900020.2scheckingforsufficient/correcttestthat(dev)900018.4scheckingforsufficient/correctETA?(0/4)[26.6s]testthat(v1.0.0)900020.6scheckingforsufficient/correcttestthat(dev)900018.8scheckingforsufficient/correctETA?(0/4)[27s]testthat(v1.0.0)900021.0scheckingforsufficient/correcttestthat(dev)900019.2scheckingforsufficient/correctETA?(0/4)[27.5s]testthat(v1.0.0)900021.4scheckingforsufficient/correcttestthat(dev)900019.6scheckingforsufficient/correctETA?(0/4)[27.9s]testthat(v1.0.0)900021.8scheckingforsufficient/correcttestthat(dev)900020.1scheckingforsufficient/correctETA?(0/4)[28.3s]testthat(v1.0.0)900022.2scheckingforsufficient/correcttestthat(dev)900020.5scheckingforsufficient/correctETA?(0/4)[28.8s]testthat(v1.0.0)900022.7scheckingforsufficient/correcttestthat(dev)900020.9scheckingforsufficient/correctETA?(0/4)[29.2s]testthat(v1.0.0)900023.1scheckingforsufficient/correcttestthat(dev)900021.4scheckingforsufficient/correctETA?(0/4)[29.6s]testthat(v1.0.0)900023.6scheckingforsufficient/correcttestthat(dev)900021.8scheckingforsufficient/correctETA?(0/4)[30s]testthat(v1.0.0)900024.0scheckingforsufficient/correcttestthat(dev)900022.2scheckingforsufficient/correctETA?(0/4)[30.4s]testthat(v1.0.0)900024.3scheckingforsufficient/correcttestthat(dev)900022.5scheckingforsufficient/correctETA?(0/4)[30.7s]testthat(v1.0.0)900024.6scheckingforsufficient/correcttestthat(dev)900022.9scheckingforsufficient/correctETA?(0/4)[31.1s]testthat(v1.0.0)900025.0scheckingforsufficient/correcttestthat(dev)900023.2scheckingforsufficient/correctETA?(0/4)[31.4s]testthat(v1.0.0)900025.3scheckingforsufficient/correcttestthat(dev)900023.6scheckingforsufficient/correctETA?(0/4)[31.8s]testthat(v1.0.0)900025.7scheckingforsufficient/correcttestthat(dev)900023.9scheckingforsufficient/correctETA?(0/4)[32.2s]testthat(v1.0.0)900026.1scheckingforsufficient/correcttestthat(dev)900024.3scheckingforsufficient/correctETA?(0/4)[32.5s]testthat(v1.0.0)900026.4scheckingforsufficient/correcttestthat(dev)900024.6scheckingforsufficient/correctETA?(0/4)[32.8s]testthat(v1.0.0)900026.8scheckingforsufficient/correcttestthat(dev)900025.0scheckingforsufficient/correctETA?(0/4)[33.2s]testthat(v1.0.0)900027.1scheckingforsufficient/correcttestthat(dev)900025.3scheckingforsufficient/correctETA?(0/4)[33.5s]testthat(v1.0.0)900027.5scheckingforsufficient/correcttestthat(dev)900025.7scheckingforsufficient/correctETA?(0/4)[33.9s]testthat(v1.0.0)900027.8scheckingforsufficient/correcttestthat(dev)900026.0scheckingforsufficient/correctETA?(0/4)[34.2s]testthat(v1.0.0)900028.1scheckingforsufficient/correcttestthat(dev)900026.3scheckingforsufficient/correctETA?(0/4)[34.5s]testthat(v1.0.0)900028.4scheckingforsufficient/correcttestthat(dev)900026.6scheckingforsufficient/correctETA?(0/4)[34.8s]testthat(v1.0.0)900028.8scheckingforsufficient/correcttestthat(dev)900027.0scheckingforsufficient/correctETA?(0/4)[35.2s]testthat(v1.0.0)900029.2scheckingforsufficient/correcttestthat(dev)900027.4scheckingforsufficient/correctETA?(0/4)[35.6s]testthat(v1.0.0)900029.6scheckingforsufficient/correcttestthat(dev)900027.8scheckingforsufficient/correctETA?(0/4)[36s]testthat(v1.0.0)900030.0scheckingforsufficient/correcttestthat(dev)900028.2scheckingforsufficient/correctETA?(0/4)[36.4s]testthat(v1.0.0)900030.3scheckingforsufficient/correcttestthat(dev)900028.5scheckingforsufficient/correctETA?(0/4)[36.7s]testthat(v1.0.0)900030.7scheckingforsufficient/correcttestthat(dev)900028.9scheckingforsufficient/correctETA?(0/4)[37.1s]testthat(v1.0.0)900031.0scheckingforsufficient/correcttestthat(dev)900029.2scheckingforsufficient/correctETA?(0/4)[37.4s]testthat(v1.0.0)900031.3scheckingforsufficient/correcttestthat(dev)900029.5scheckingforsufficient/correctETA?(0/4)[37.7s]testthat(v1.0.0)900031.7scheckingforsufficient/correcttestthat(dev)900029.9scheckingforsufficient/correctETA?(0/4)[38.2s]testthat(v1.0.0)900032.1scheckingforsufficient/correcttestthat(dev)900030.3scheckingforsufficient/correctETA?(0/4)[38.5s]testthat(v1.0.0)900032.4scheckingforsufficient/correcttestthat(dev)900030.6scheckingforsufficient/correctETA?(0/4)[38.8s]testthat(v1.0.0)900032.7scheckingforsufficient/correcttestthat(dev)900030.9scheckingforsufficient/correctETA?(0/4)[39.1s]testthat(v1.0.0)900033.1scheckingforsufficient/correcttestthat(dev)900031.3scheckingforsufficient/correctETA?(0/4)[39.5s]testthat(v1.0.0)900033.5scheckingforsufficient/correcttestthat(dev)900031.7scheckingforsufficient/correctETA?(0/4)[39.9s]testthat(v1.0.0)900033.8scheckingforsufficient/correcttestthat(dev)900032.0scheckingforsufficient/correctETA?(0/4)[40.2s]testthat(v1.0.0)900034.1scheckingforsufficient/correcttestthat(dev)900032.3scheckingforsufficient/correctETA?(0/4)[40.5s]testthat(v1.0.0)900034.5scheckingforsufficient/correcttestthat(dev)900032.7scheckingforsufficient/correctETA?(0/4)[40.9s]testthat(v1.0.0)900034.8scheckingforsufficient/correcttestthat(dev)900033.0scheckingforsufficient/correctETA?(0/4)[41.2s]testthat(v1.0.0)900035.1s(30.1s)checkingforsufficienttestthat(dev)900033.3scheckingforsufficient/correctETA?(0/4)[41.5s]testthat(v1.0.0)900035.5s(30.4s)checkingforsufficienttestthat(dev)900033.7scheckingforsufficient/correctETA?(0/4)[41.9s]testthat(v1.0.0)900035.8s(30.8s)checkingforsufficienttestthat(dev)900034.0scheckingforsufficient/correctETA?(0/4)[42.2s]testthat(v1.0.0)900036.2s(31.1s)checkingforsufficienttestthat(dev)900034.4scheckingforsufficient/correctETA?(0/4)[42.6s]testthat(v1.0.0)900036.5s(31.5s)checkingforsufficienttestthat(dev)900034.7scheckingforsufficient/correctETA?(0/4)[42.9s]testthat(v1.0.0)900036.9s(31.8s)checkingforsufficienttestthat(dev)900035.1scheckingforsufficient/correctETA?(0/4)[43.3s]testthat(v1.0.0)900037.2s(32.2s)checkingforsufficienttestthat(dev)900035.4s(30.1s)checkingforsufficientETA?(0/4)[43.6s]testthat(v1.0.0)900037.5s(32.5s)checkingforsufficienttestthat(dev)900035.7s(30.5s)checkingforsufficientETA?(0/4)[43.9s]testthat(v1.0.0)900037.9s(32.8s)checkingforsufficienttestthat(dev)900036.1s(30.8s)checkingforsufficientETA?(0/4)[44.3s]testthat(v1.0.0)900038.2s(33.2s)checkingforsufficienttestthat(dev)900036.4s(31.1s)checkingforsufficientETA?(0/4)[44.6s]testthat(v1.0.0)900038.5s(33.5s)checkingforsufficienttestthat(dev)900036.7s(31.4s)checkingforsufficientETA?(0/4)[44.9s]testthat(v1.0.0)900038.8s(33.8s)checkingforsufficienttestthat(dev)900037.0s(31.8s)checkingforsufficientETA?(0/4)[45.2s]testthat(v1.0.0)900039.2s(34.1s)checkingforsufficienttestthat(dev)900037.4s(32.1s)checkingforsufficientETA?(0/4)[45.6s]testthat(v1.0.0)900039.6s(34.5s)checkingforsufficienttestthat(dev)900037.8s(32.5s)checkingforsufficientETA?(0/4)[46s]testthat(v1.0.0)900039.9s(34.9s)checkingforsufficienttestthat(dev)900038.1s(32.8s)checkingforsufficientETA?(0/4)[46.3s]testthat(v1.0.0)900040.2s(35.2s)checkingforsufficienttestthat(dev)900038.4s(33.2s)checkingforsufficientETA?(0/4)[46.6s]testthat(v1.0.0)900040.6s(35.5s)checkingforsufficienttestthat(dev)900038.8s(33.5s)checkingforsufficientETA?(0/4)[47s]testthat(v1.0.0)900040.9s(35.9s)checkingforsufficienttestthat(dev)900039.1s(33.8s)checkingforsufficientETA?(0/4)[47.3s]testthat(v1.0.0)900041.2s(36.2s)checkingforsufficienttestthat(dev)900039.5s(34.2s)checkingforsufficientETA?(0/4)[47.7s]testthat(v1.0.0)900041.7s(36.6s)checkingforsufficienttestthat(dev)900039.9s(34.6s)checkingforsufficientETA?(0/4)[48.1s]testthat(v1.0.0)900042.1s(37.0s)checkingforsufficienttestthat(dev)900040.3s(35.0s)checkingforsufficientETA?(0/4)[48.5s]testthat(v1.0.0)900042.5s(37.4s)checkingforsufficienttestthat(dev)900040.7s(35.4s)checkingforsufficientETA?(0/4)[48.9s]testthat(v1.0.0)900042.8s(37.8s)checkingforsufficienttestthat(dev)900041.0s(35.8s)checkingforsufficientETA?(0/4)[49.2s]testthat(v1.0.0)900043.2s(38.1s)checkingforsufficienttestthat(dev)900041.4s(36.1s)checkingforsufficientETA?(0/4)[49.6s]testthat(v1.0.0)900043.5s(38.5s)checkingforsufficienttestthat(dev)900041.7s(36.4s)checkingforsufficientETA?(0/4)[49.9s]testthat(v1.0.0)900043.8s(38.8s)checkingforsufficienttestthat(dev)900042.0s(36.8s)checkingforsufficientETA?(0/4)[50.2s]testthat(v1.0.0)900044.1s(39.1s)checkingforsufficienttestthat(dev)900042.3s(37.1s)checkingforsufficientETA?(0/4)[50.6s]testthat(v1.0.0)900044.5s(39.5s)checkingforsufficienttestthat(dev)900042.7s(37.4s)checkingforsufficientETA?(0/4)[50.9s]testthat(v1.0.0)1010044.8scheckinginstalledpackagesizetestthat(dev)900043.0s(37.7s)checkingforsufficientETA?(0/4)[51.3s]testthat(v1.0.0)1110045.2scheckingpackagedirectory...testthat(dev)900043.4s(38.2s)checkingforsufficientETA?(0/4)[51.6s]testthat(v1.0.0)1410045.6scheckingforleft-overfiles..testthat(dev)900043.8s(38.6s)checkingforsufficientETA?(0/4)[52s]testthat(v1.0.0)1510046.0scheckingindexinformation...testthat(dev)900044.2s(39.0s)checkingforsufficientETA?(0/4)[52.4s]testthat(v1.0.0)1510046.4scheckingindexinformation...testthat(dev)900044.7s(39.4s)checkingforsufficientETA?(0/4)[52.9s]testthat(v1.0.0)1510046.8scheckingindexinformation...testthat(dev)900045.0s(39.7s)checkingforsufficientETA?(0/4)[53.2s]testthat(v1.0.0)1510047.1scheckingindexinformation...testthat(dev)900045.4s(40.1s)checkingforsufficientETA?(0/4)[53.6s]testthat(v1.0.0)1710047.5scheckingcodefilesfornon-ASCtestthat(dev)1010045.7scheckinginstalledpackagesizeETA?(0/4)[54s]testthat(v1.0.0)1810047.9scheckingRfilesforsyntaxerrtestthat(dev)1110046.2scheckingpackagedirectory...ETA?(0/4)[54.4s]testthat(v1.0.0)1910048.3scheckingwhetherthepackagecatestthat(dev)1510046.6scheckingindexinformation...ETA?(0/4)[54.8s]testthat(v1.0.0)2010048.7scheckingwhetherthepackagecatestthat(dev)1510046.9scheckingindexinformation...ETA?(0/4)[55.1s]testthat(v1.0.0)2110049.1scheckingwhetherthepackagecatestthat(dev)1510047.3scheckingindexinformation...ETA?(0/4)[55.6s]testthat(v1.0.0)2210049.5scheckingwhetherthenamespacetestthat(dev)1510047.8scheckingindexinformation...ETA?(0/4)[56s]testthat(v1.0.0)2210049.9scheckingwhetherthenamespacetestthat(dev)1610048.1scheckingpackagesubdirectoriesETA?(0/4)[56.3s]testthat(v1.0.0)2310050.3scheckingwhetherthenamespacetestthat(dev)1810048.5scheckingRfilesforsyntaxerrETA?(0/4)[56.7s]testthat(v1.0.0)2410050.6scheckingloadingwithoutbeingtestthat(dev)1910048.8scheckingwhetherthepackagecaETA?(0/4)[57s]testthat(v1.0.0)2410051.0scheckingloadingwithoutbeingtestthat(dev)1910049.3scheckingwhetherthepackagecaETA?(0/4)[57.5s]testthat(v1.0.0)2410051.4scheckingloadingwithoutbeingtestthat(dev)2010049.7scheckingwhetherthepackagecaETA?(0/4)[58s]testthat(v1.0.0)2410051.9scheckingloadingwithoutbeingtestthat(dev)2110050.1scheckingwhetherthepackagecaETA?(0/4)[58.3s]testthat(v1.0.0)2410052.3scheckingloadingwithoutbeingtestthat(dev)2210050.5scheckingwhetherthenamespaceETA?(0/4)[58.7s]testthat(v1.0.0)2410052.7scheckingloadingwithoutbeingtestthat(dev)2310050.9scheckingwhetherthenamespaceETA?(0/4)[59.1s]testthat(v1.0.0)2410053.1scheckingloadingwithoutbeingtestthat(dev)2310051.3scheckingwhetherthenamespaceETA?(0/4)[59.5s]testthat(v1.0.0)2410053.4scheckingloadingwithoutbeingtestthat(dev)2410051.7scheckingloadingwithoutbeingETA?(0/4)[59.9s]testthat(v1.0.0)2510053.8scheckingdependenciesinRcodetestthat(dev)2410052.0scheckingloadingwithoutbeingETA?(0/4)[1m0.2s]testthat(v1.0.0)2510054.2scheckingdependenciesinRcodetestthat(dev)2410052.4scheckingloadingwithoutbeingETA?(0/4)[1m0.6s]testthat(v1.0.0)2510054.5scheckingdependenciesinRcodetestthat(dev)2410052.7scheckingloadingwithoutbeingETA?(0/4)[1m1s]testthat(v1.0.0)2610054.9scheckingS3generic/methodconstestthat(dev)2410053.1scheckingloadingwithoutbeingETA?(0/4)[1m1.3s]testthat(v1.0.0)2610055.2scheckingS3generic/methodconstestthat(dev)2410053.4scheckingloadingwithoutbeingETA?(0/4)[1m1.6s]testthat(v1.0.0)2710055.6scheckingreplacementfunctionstestthat(dev)2410053.8scheckingloadingwithoutbeingETA?(0/4)[1m2s]testthat(v1.0.0)2710055.9scheckingreplacementfunctionstestthat(dev)2410054.2scheckingloadingwithoutbeingETA?(0/4)[1m2.4s]testthat(v1.0.0)2710056.3scheckingreplacementfunctionstestthat(dev)2510054.5scheckingdependenciesinRcodeETA?(0/4)[1m2.7s]testthat(v1.0.0)2810056.7scheckingforeignfunctioncallstestthat(dev)2510054.9scheckingdependenciesinRcodeETA?(0/4)[1m3.1s]testthat(v1.0.0)2810057.0scheckingforeignfunctioncallstestthat(dev)2510055.3scheckingdependenciesinRcodeETA?(0/4)[1m3.5s]testthat(v1.0.0)2810057.5scheckingforeignfunctioncallstestthat(dev)2610055.7scheckingS3generic/methodconsETA?(0/4)[1m3.9s]testthat(v1.0.0)2810057.8scheckingforeignfunctioncallstestthat(dev)2710056.1scheckingreplacementfunctionsETA?(0/4)[1m4.3s]testthat(v1.0.0)2810058.2scheckingforeignfunctioncallstestthat(dev)2710056.4scheckingreplacementfunctionsETA?(0/4)[1m4.7s]testthat(v1.0.0)2810058.6scheckingforeignfunctioncallstestthat(dev)2710056.8scheckingreplacementfunctionsETA?(0/4)[1m5s]testthat(v1.0.0)2810058.9scheckingforeignfunctioncallstestthat(dev)2710057.1scheckingreplacementfunctionsETA?(0/4)[1m5.3s]testthat(v1.0.0)2810059.3scheckingforeignfunctioncallstestthat(dev)2810057.5scheckingforeignfunctioncallsETA?(0/4)[1m5.7s]testthat(v1.0.0)2810059.6scheckingforeignfunctioncallstestthat(dev)2810057.8scheckingforeignfunctioncallsETA?(0/4)[1m6s]testthat(v1.0.0)2810060.0scheckingforeignfunctioncallstestthat(dev)2810058.2scheckingforeignfunctioncallsETA?(0/4)[1m6.4s]testthat(v1.0.0)281001.0mcheckingforeignfunctioncallstestthat(dev)2810058.5scheckingforeignfunctioncallsETA?(0/4)[1m6.7s]testthat(v1.0.0)281001.0mcheckingforeignfunctioncallstestthat(dev)2810058.8scheckingforeignfunctioncallsETA?(0/4)[1m7s]testthat(v1.0.0)281001.0mcheckingforeignfunctioncallstestthat(dev)2810059.2scheckingforeignfunctioncallsETA?(0/4)[1m7.4s]testthat(v1.0.0)281001.0mcheckingforeignfunctioncallstestthat(dev)2810059.5scheckingforeignfunctioncallsETA?(0/4)[1m7.7s]testthat(dev)2810059.9scheckingforeignfunctioncallsETA?(0/4)[1m8.1s]testthat(dev)281001.0mcheckingforeignfunctioncallsETA?(0/4)[1m8.5s]testthat(dev)281001.0mcheckingforeignfunctioncallsETA?(0/4)[1m8.9s]testthat(dev)281001.0mcheckingforeignfunctioncallsETA?(0/4)[1m9.2s]testthat(v1.0.0)281001.1mcheckingforeignfunctioncallstestthat(dev)281001.0mcheckingforeignfunctioncallsETA?(0/4)[1m9.7s]testthat(v1.0.0)281001.1mcheckingforeignfunctioncallsETA?(0/4)[1m10.2s]testthat(v1.0.0)281001.1mcheckingforeignfunctioncallsETA?(0/4)[1m10.5s]testthat(v1.0.0)281001.1mcheckingforeignfunctioncallsETA?(0/4)[1m10.8s]testthat(dev)281001.1mcheckingforeignfunctioncallsETA?(0/4)[1m11.2s]testthat(dev)281001.1mcheckingforeignfunctioncallsETA?(0/4)[1m11.6s]testthat(dev)281001.1mcheckingforeignfunctioncallsETA?(0/4)[1m11.9s]testthat(dev)281001.1mcheckingforeignfunctioncallsETA?(0/4)[1m12.4s]ETA?(0/4)[1m12.7s]testthat(v1.0.0)291001.1mcheckingRcodeforpossibleproETA?(0/4)[1m13s]testthat(v1.0.0)291001.1mcheckingRcodeforpossibleproETA?(0/4)[1m13.4s]testthat(v1.0.0)311001.1mcheckingRdmetadata...ETA?(0/4)[1m13.8s]testthat(v1.0.0)311001.1mcheckingRdmetadata...ETA?(0/4)[1m14.1s]testthat(v1.0.0)311001.1mcheckingRdmetadata...ETA?(0/4)[1m14.5s]testthat(v1.0.0)321001.1mcheckingformissingdocumentatitestthat(dev)291001.1mcheckingRcodeforpossibleproETA?(0/4)[1m14.8s]testthat(v1.0.0)321001.1mcheckingformissingdocumentatitestthat(dev)291001.1mcheckingRcodeforpossibleproETA?(0/4)[1m15.2s]testthat(v1.0.0)321001.2mcheckingformissingdocumentatitestthat(dev)301001.1mcheckingRdfiles...ETA?(0/4)[1m15.6s]testthat(v1.0.0)321001.2mcheckingformissingdocumentatitestthat(dev)311001.1mcheckingRdmetadata...ETA?(0/4)[1m16s]testthat(v1.0.0)321001.2mcheckingformissingdocumentatitestthat(dev)311001.1mcheckingRdmetadata...ETA?(0/4)[1m16.4s]testthat(v1.0.0)331001.2mcheckingforcode/documentationtestthat(dev)321001.1mcheckingformissingdocumentatiETA?(0/4)[1m16.8s]testthat(v1.0.0)331001.2mcheckingforcode/documentationtestthat(dev)321001.1mcheckingformissingdocumentatiETA?(0/4)[1m17.1s]testthat(v1.0.0)331001.2mcheckingforcode/documentationtestthat(dev)321001.2mcheckingformissingdocumentatiETA?(0/4)[1m17.4s]testthat(v1.0.0)331001.2mcheckingforcode/documentationtestthat(dev)321001.2mcheckingformissingdocumentatiETA?(0/4)[1m17.8s]testthat(dev)321001.2mcheckingformissingdocumentatiETA?(0/4)[1m18.2s]testthat(v1.0.0)341001.2mcheckingRd\usagesections...testthat(dev)321001.2mcheckingformissingdocumentatiETA?(0/4)[1m18.6s]testthat(v1.0.0)381001.2mcheckinglineendingsinMakefiltestthat(dev)331001.2mcheckingforcode/documentationETA?(0/4)[1m19s]testthat(v1.0.0)431001.2mcheckingcompiledcode...testthat(dev)331001.2mcheckingforcode/documentationETA?(0/4)[1m19.4s]testthat(v1.0.0)451001.2mcheckingfilesin‘vignettes’..testthat(dev)331001.2mcheckingforcode/documentationETA?(0/4)[1m19.8s]testthat(v1.0.0)451001.2mcheckingfilesin‘vignettes’..testthat(dev)331001.2mcheckingforcode/documentationETA?(0/4)[1m20.1s]testthat(v1.0.0)451001.2mcheckingfilesin‘vignettes’..testthat(dev)341001.2mcheckingRd\usagesections...ETA?(0/4)[1m20.4s]testthat(v1.0.0)451001.2mcheckingfilesin‘vignettes’..testthat(dev)351001.2mcheckingRdcontents...ETA?(0/4)[1m20.7s]testthat(dev)381001.2mcheckinglineendingsinMakefilETA?(0/4)[1m21.1s]testthat(v1.0.0)451001.3mcheckingfilesin‘vignettes’..testthat(dev)431001.2mcheckingcompiledcode...ETA?(0/4)[1m21.5s]testthat(v1.0.0)451001.3mcheckingfilesin‘vignettes’..testthat(dev)451001.2mcheckingfilesin‘vignettes’..ETA?(0/4)[1m21.8s]testthat(v1.0.0)451001.3mcheckingfilesin‘vignettes’..testthat(dev)451001.2mcheckingfilesin‘vignettes’..ETA?(0/4)[1m22.1s]testthat(v1.0.0)451001.3mcheckingfilesin‘vignettes’..testthat(dev)451001.2mcheckingfilesin‘vignettes’..ETA?(0/4)[1m22.5s]testthat(dev)451001.2mcheckingfilesin‘vignettes’..ETA?(0/4)[1m22.8s]ETA?(0/4)[1m23.2s]testthat(dev)451001.3mcheckingfilesin‘vignettes’..ETA?(0/4)[1m23.6s]testthat(dev)451001.3mcheckingfilesin‘vignettes’..ETA?(0/4)[1m23.9s]testthat(dev)451001.3mcheckingfilesin‘vignettes’..ETA?(0/4)[1m24.3s]testthat(v1.0.0)461001.3mcheckingexamples...testthat(dev)451001.3mcheckingfilesin‘vignettes’..ETA?(0/4)[1m24.7s]testthat(v1.0.0)471001.3mcheckingtests...ETA?(0/4)[1m25.1s]testthat(v1.0.0)471001.3mcheckingtests...ETA?(0/4)[1m25.5s]testthat(v1.0.0)471001.3mcheckingtests...ETA?(0/4)[1m25.9s]testthat(v1.0.0)471001.3mcheckingtests...ETA?(0/4)[1m26.3s]testthat(dev)471001.3mcheckingforunstateddependenciETA?(0/4)[1m26.6s]testthat(dev)471001.3mcheckingtests...ETA?(0/4)[1m27s]testthat(dev)471001.3mcheckingtests...ETA?(0/4)[1m27.5s]testthat(v1.0.0)471001.4mcheckingtests...testthat(dev)471001.3mcheckingtests...ETA?(0/4)[1m27.9s]testthat(v1.0.0)471001.4mcheckingtests...testthat(dev)471001.3mcheckingtests...ETA?(0/4)[1m28.3s]testthat(v1.0.0)471001.4mcheckingtests...ETA?(0/4)[1m28.6s]testthat(v1.0.0)471001.4mcheckingtests...ETA?(0/4)[1m29s]testthat(dev)471001.4mcheckingtests...ETA?(0/4)[1m29.4s]testthat(dev)471001.4mcheckingtests...ETA?(0/4)[1m29.8s]testthat(dev)471001.4mcheckingtests...ETA?(0/4)[1m30.1s]testthat(dev)471001.4mcheckingtests...ETA?(0/4)[1m30.4s]ETA?(0/4)[1m30.8s]ETA?(0/4)[1m31.1s]ETA?(0/4)[1m31.4s]ETA?(0/4)[1m31.8s]ETA?(0/4)[1m32.1s]ETA?(0/4)[1m32.5s]ETA?(0/4)[1m32.8s]ETA?(0/4)[1m33.1s]testthat(v1.0.0)471001.5mcheckingtests...ETA?(0/4)[1m33.5s]testthat(v1.0.0)471001.5mcheckingtests...ETA?(0/4)[1m33.9s]testthat(v1.0.0)471001.5mcheckingtests...ETA?(0/4)[1m34.3s]testthat(v1.0.0)471001.5mcheckingtests...ETA?(0/4)[1m34.7s]ETA?(0/4)[1m35s]testthat(dev)471001.5mcheckingtests...ETA?(0/4)[1m35.3s]testthat(dev)471001.5mcheckingtests...ETA?(0/4)[1m35.6s]testthat(dev)471001.5mcheckingtests...ETA?(0/4)[1m36s]testthat(dev)471001.5mcheckingtests...ETA?(0/4)[1m36.3s]ETA?(0/4)[1m36.7s]ETA?(0/4)[1m37.1s]ETA?(0/4)[1m37.5s]ETA?(0/4)[1m37.8s]ETA?(0/4)[1m38.2s]ETA?(0/4)[1m38.6s]ETA?(0/4)[1m39s]ETA?(0/4)[1m39.3s]testthat(v1.0.0)471001.6mcheckingtests...ETA?(0/4)[1m39.8s]testthat(v1.0.0)471001.6mcheckingtests...ETA?(0/4)[1m40.1s]testthat(v1.0.0)471001.6mcheckingtests...ETA?(0/4)[1m40.5s]testthat(v1.0.0)471001.6mcheckingtests...ETA?(0/4)[1m40.8s]ETA?(0/4)[1m41.2s]testthat(dev)471001.6mcheckingtests...ETA?(0/4)[1m41.5s]testthat(dev)471001.6mcheckingtests...ETA?(0/4)[1m41.8s]testthat(dev)471001.6mcheckingtests...ETA?(0/4)[1m42.2s]testthat(dev)471001.6mcheckingtests...ETA?(0/4)[1m42.5s]ETA?(0/4)[1m42.9s]ETA?(0/4)[1m43.3s]ETA?(0/4)[1m43.7s]ETA?(0/4)[1m44.1s]ETA?(0/4)[1m44.5s]ETA?(0/4)[1m44.9s]ETA?(0/4)[1m45.2s]testthat(v1.0.0)471001.7mcheckingtests...ETA?(0/4)[1m45.5s]testthat(v1.0.0)471001.7mcheckingtests...ETA?(0/4)[1m46s]testthat(v1.0.0)471001.7mcheckingtests...ETA?(0/4)[1m46.3s]testthat(v1.0.0)471001.7mcheckingtests...ETA?(0/4)[1m46.7s]ETA?(0/4)[1m47.1s]testthat(dev)471001.7mcheckingtests...ETA?(0/4)[1m47.4s]testthat(dev)471001.7mcheckingtests...ETA?(0/4)[1m47.8s]testthat(dev)471001.7mcheckingtests...ETA?(0/4)[1m48.2s]testthat(dev)471001.7mcheckingtests...ETA?(0/4)[1m48.5s]ETA?(0/4)[1m49s]ETA?(0/4)[1m49.7s]ETA?(0/4)[1m50.2s]ETA?(0/4)[1m50.7s]ETA?(0/4)[1m51.2s]testthat(v1.0.0)471001.8mcheckingtests...ETA?(0/4)[1m51.7s]testthat(v1.0.0)471001.8mcheckingtests...ETA?(0/4)[1m52.3s]testthat(v1.0.0)471001.8mcheckingtests...ETA?(0/4)[1m52.6s]testthat(v1.0.0)471001.8mcheckingtests...ETA?(0/4)[1m53.1s]testthat(dev)471001.8mcheckingtests...ETA?(0/4)[1m54s]testthat(dev)471001.8mcheckingtests...ETA?(0/4)[1m54.5s]testthat(dev)471001.8mcheckingtests...ETA?(0/4)[1m54.9s]testthat(dev)471001.8mcheckingtests...ETA?(0/4)[1m55.3s]ETA?(0/4)[1m55.8s]ETA?(0/4)[1m56.3s]ETA?(0/4)[1m57.1s]testthat(v1.0.0)471001.9mcheckingtests...ETA?(0/4)[1m58.3s]testthat(v1.0.0)471001.9mcheckingtests...ETA?(0/4)[1m58.9s]testthat(v1.0.0)471001.9mcheckingtests...testthat(dev)471001.9mcheckingtests...ETA?(0/4)[1m59.8s]testthat(v1.0.0)471001.9mcheckingtests...testthat(dev)471001.9mcheckingtests...ETA?(0/4)[2m0.3s]testthat(dev)471001.9mcheckingtests...ETA?(0/4)[2m1s]testthat(dev)471001.9mcheckingtests...ETA?(0/4)[2m1.5s]ETA?(0/4)[2m2.1s]ETA?(0/4)[2m2.6s]ETA?(0/4)[2m3s]ETA?(0/4)[2m3.6s]testthat(v1.0.0)471002.0mcheckingtests...ETA?(0/4)[2m4.5s]testthat(v1.0.0)471002.0mcheckingtests...ETA?(0/4)[2m5s]testthat(v1.0.0)471002.0mcheckingtests...testthat(dev)471002.0mcheckingtests...ETA?(0/4)[2m5.6s]testthat(v1.0.0)471002.0mcheckingtests...testthat(dev)471002.0mcheckingtests...ETA?(0/4)[2m6.3s]testthat(dev)471002.0mcheckingtests...ETA?(0/4)[2m7s]testthat(dev)471002.0mcheckingtests...ETA?(0/4)[2m7.6s]ETA?(0/4)[2m8.1s]ETA?(0/4)[2m8.5s]ETA?(0/4)[2m8.9s]ETA?(0/4)[2m9.5s]testthat(v1.0.0)471002.1mcheckingtests...ETA?(0/4)[2m10.1s]testthat(v1.0.0)471002.1mcheckingtests...ETA?(0/4)[2m10.9s]testthat(v1.0.0)471002.1mcheckingtests...testthat(dev)471002.1mcheckingtests...ETA?(0/4)[2m11.8s]testthat(v1.0.0)471002.1mcheckingtests...testthat(dev)471002.1mcheckingtests...ETA?(0/4)[2m12.3s]testthat(dev)471002.1mcheckingtests...ETA?(0/4)[2m12.6s]testthat(dev)471002.1mcheckingtests...ETA?(0/4)[2m12.9s]ETA?(0/4)[2m13.3s]ETA?(0/4)[2m14.1s]ETA?(0/4)[2m14.6s]ETA?(0/4)[2m15.1s]testthat(v1.0.0)471002.2mcheckingtests...ETA?(0/4)[2m15.9s]testthat(v1.0.0)471002.2mcheckingtests...ETA?(0/4)[2m16.4s]testthat(v1.0.0)471002.2mcheckingtests...ETA?(0/4)[2m17.3s]testthat(v1.0.0)471002.2mcheckingtests...testthat(dev)471002.2mcheckingtests...ETA?(0/4)[2m18s]testthat(dev)471002.2mcheckingtests...ETA?(0/4)[2m18.6s]testthat(dev)471002.2mcheckingtests...ETA?(0/4)[2m19.2s]testthat(dev)471002.2mcheckingtests...ETA?(0/4)[2m19.9s]ETA?(0/4)[2m20.4s]ETA?(0/4)[2m21s]ETA?(0/4)[2m21.6s]testthat(v1.0.0)471002.3mcheckingtests...ETA?(0/4)[2m22.5s]testthat(v1.0.0)471002.3mcheckingtests...ETA?(0/4)[2m23.1s]testthat(v1.0.0)471002.3mcheckingtests...testthat(dev)471002.3mcheckingtests...ETA?(0/4)[2m23.7s]testthat(v1.0.0)471002.3mcheckingtests...testthat(dev)471002.3mcheckingtests...ETA?(0/4)[2m24.2s]testthat(dev)471002.3mcheckingtests...ETA?(0/4)[2m24.7s]testthat(dev)471002.3mcheckingtests...ETA?(0/4)[2m25.4s]ETA?(0/4)[2m25.9s]ETA?(0/4)[2m26.6s]ETA?(0/4)[2m27s]ETA?(0/4)[2m27.6s]testthat(v1.0.0)471002.4mcheckingtests...ETA?(0/4)[2m28.2s]testthat(v1.0.0)471002.4mcheckingtests...ETA?(0/4)[2m28.7s]testthat(v1.0.0)471002.4mcheckingtests...testthat(dev)471002.4mcheckingtests...ETA?(0/4)[2m29.4s]testthat(v1.0.0)471002.4mcheckingtests...testthat(dev)471002.4mcheckingtests...ETA?(0/4)[2m30s]testthat(dev)471002.4mcheckingtests...ETA?(0/4)[2m30.5s]testthat(dev)471002.4mcheckingtests...ETA?(0/4)[2m31.1s]ETA?(0/4)[2m31.6s]ETA?(0/4)[2m32.1s]ETA?(0/4)[2m32.5s]ETA?(0/4)[2m32.9s]ETA?(0/4)[2m33.5s]testthat(v1.0.0)471002.5mcheckingtests...ETA?(0/4)[2m34s]testthat(v1.0.0)471002.5mcheckingtests...ETA?(0/4)[2m34.4s]testthat(v1.0.0)471002.5mcheckingtests...ETA?(0/4)[2m34.8s]testthat(v1.0.0)471002.5mcheckingtests...ETA?(0/4)[2m35.2s]testthat(dev)471002.5mcheckingtests...ETA?(0/4)[2m35.6s]testthat(dev)471002.5mcheckingtests...ETA?(0/4)[2m36s]testthat(dev)471002.5mcheckingtests...ETA?(0/4)[2m36.5s]testthat(dev)471002.5mcheckingtests...ETA?(0/4)[2m36.9s]ETA?(0/4)[2m37.4s]ETA?(0/4)[2m37.9s]ETA?(0/4)[2m38.2s]ETA?(0/4)[2m38.6s]ETA?(0/4)[2m39s]ETA?(0/4)[2m39.6s]testthat(v1.0.0)471002.6mcheckingtests...ETA?(0/4)[2m40.1s]testthat(v1.0.0)471002.6mcheckingtests...ETA?(0/4)[2m40.8s]testthat(v1.0.0)471002.6mcheckingtests...testthat(dev)471002.6mcheckingtests...ETA?(0/4)[2m41.3s]testthat(v1.0.0)471002.6mcheckingtests...testthat(dev)471002.6mcheckingtests...ETA?(0/4)[2m41.7s]testthat(dev)471002.6mcheckingtests...ETA?(0/4)[2m42.3s]testthat(dev)471002.6mcheckingtests...ETA?(0/4)[2m42.8s]ETA?(0/4)[2m43.1s]ETA?(0/4)[2m43.5s]ETA?(0/4)[2m43.8s]ETA?(0/4)[2m44.2s]ETA?(0/4)[2m44.5s]ETA?(0/4)[2m44.8s]ETA?(0/4)[2m45.1s]testthat(v1.0.0)471002.7mcheckingtests...ETA?(0/4)[2m45.5s]testthat(v1.0.0)471002.7mcheckingtests...ETA?(0/4)[2m45.9s]testthat(v1.0.0)481002.7mcheckingtests...ETA?(0/4)[2m46.2s]testthat(v1.0.0)!481002.7mETA8m(1/4)[2m46.8s]installingclisymbolsETA8m(1/4)[2m47.2s]installingclisymbolstestthat(dev)481002.7mcheckingtests...ETA8m(1/4)[2m47.6s]installingclisymbolstestthat(dev)!481002.7mETA3m(2/4)[2m48s]installingclisymbolsETA3m(2/4)[2m48.4s]installingclisymbolsETA3m(2/4)[2m48.7s]installingclisymbolsETA3m(2/4)[2m49.2s]installingclisymbolsETA3m(2/4)[2m49.6s]installingclisymbolsETA3m(2/4)[2m50s]installingclisymbolsETA3m(2/4)[2m50.3s]installingclisymbolsgoodpractice(v1.0.0)00001.1sstarting...ETA3m(2/4)[2m51.9s]goodpractice(v1.0.0)20002.5scheckingpackagenamespaceinforgoodpractice(dev)00001.1sstarting...ETA3m(2/4)[2m53.4s]goodpractice(v1.0.0)20003.0scheckingpackagenamespaceinforgoodpractice(dev)20001.7scheckingpackagenamespaceinforETA3m(2/4)[2m53.9s]goodpractice(v1.0.0)50003.5scheckingifthereisanamespacegoodpractice(dev)20002.1scheckingpackagenamespaceinforETA3m(2/4)[2m54.4s]goodpractice(v1.0.0)90003.9scheckingforsufficient/correctgoodpractice(dev)20002.6scheckingpackagenamespaceinforETA3m(2/4)[2m54.8s]goodpractice(v1.0.0)90004.4scheckingforsufficient/correctgoodpractice(dev)20003.0scheckingpackagenamespaceinforETA3m(2/4)[2m55.3s]goodpractice(v1.0.0)90005.0scheckingforsufficient/correctgoodpractice(dev)50003.7scheckingifthereisanamespaceETA3m(2/4)[2m56s]goodpractice(v1.0.0)90005.6scheckingforsufficient/correctgoodpractice(dev)90004.2scheckingforsufficient/correctETA3m(2/4)[2m56.5s]goodpractice(v1.0.0)90006.1scheckingforsufficient/correctgoodpractice(dev)90004.8scheckingforsufficient/correctETA3m(2/4)[2m57s]goodpractice(v1.0.0)90006.8scheckingforsufficient/correctgoodpractice(dev)90005.5scheckingforsufficient/correctETA3m(2/4)[2m57.8s]goodpractice(v1.0.0)90007.4scheckingforsufficient/correctgoodpractice(dev)90006.0scheckingforsufficient/correctETA3m(2/4)[2m58.2s]goodpractice(v1.0.0)90008.0scheckingforsufficient/correctgoodpractice(dev)90006.6scheckingforsufficient/correctETA3m(2/4)[2m58.8s]goodpractice(v1.0.0)90008.5scheckingforsufficient/correctgoodpractice(dev)90007.1scheckingforsufficient/correctETA3m(2/4)[2m59.3s]goodpractice(v1.0.0)90009.0scheckingforsufficient/correctgoodpractice(dev)90007.6scheckingforsufficient/correctETA3m(2/4)[2m59.8s]goodpractice(v1.0.0)90009.4scheckingforsufficient/correctgoodpractice(dev)90008.1scheckingforsufficient/correctETA3m(2/4)[3m0.3s]goodpractice(v1.0.0)900010.0scheckingforsufficient/correctgoodpractice(dev)90008.6scheckingforsufficient/correctETA3m(2/4)[3m0.9s]goodpractice(v1.0.0)900010.5scheckingforsufficient/correctgoodpractice(dev)90009.1scheckingforsufficient/correctETA3m(2/4)[3m1.3s]goodpractice(v1.0.0)900011.0scheckingforsufficient/correctgoodpractice(dev)90009.6scheckingforsufficient/correctETA3m(2/4)[3m1.9s]goodpractice(v1.0.0)1500011.6scheckingforleft-overfiles..goodpractice(dev)900010.3scheckingforsufficient/correctETA3m(2/4)[3m2.6s]goodpractice(v1.0.0)1600012.3scheckingindexinformation...goodpractice(dev)900010.9scheckingforsufficient/correctETA3m(2/4)[3m3.2s]goodpractice(v1.0.0)1600012.8scheckingindexinformation...goodpractice(dev)900011.4scheckingforsufficient/correctETA3m(2/4)[3m3.6s]goodpractice(v1.0.0)1800013.3scheckingcodefilesfornon-ASCgoodpractice(dev)900011.9scheckingforsufficient/correctETA3m(2/4)[3m4.2s]goodpractice(v1.0.0)1900013.8scheckingRfilesforsyntaxerrgoodpractice(dev)900012.4scheckingforsufficient/correctETA3m(2/4)[3m4.7s]goodpractice(v1.0.0)1900014.4scheckingRfilesforsyntaxerrgoodpractice(dev)1600013.0scheckingindexinformation...ETA3m(2/4)[3m5.3s]goodpractice(v1.0.0)2000015.0scheckingwhetherthepackagecagoodpractice(dev)1600013.6scheckingindexinformation...ETA3m(2/4)[3m5.9s]goodpractice(v1.0.0)2000015.5scheckingwhetherthepackagecagoodpractice(dev)1900014.2scheckingRfilesforsyntaxerrETA3m(2/4)[3m6.5s]goodpractice(v1.0.0)2100016.1scheckingwhetherthepackagecagoodpractice(dev)1900014.7scheckingRfilesforsyntaxerrETA3m(2/4)[3m7s]goodpractice(v1.0.0)2100016.6scheckingwhetherthepackagecagoodpractice(dev)1900015.2scheckingRfilesforsyntaxerrETA3m(2/4)[3m7.4s]goodpractice(v1.0.0)2200017.1scheckingwhetherthepackagecagoodpractice(dev)2000015.7scheckingwhetherthepackagecaETA3m(2/4)[3m8s]goodpractice(v1.0.0)2200017.6scheckingwhetherthepackagecagoodpractice(dev)2100016.3scheckingwhetherthepackagecaETA3m(2/4)[3m8.5s]goodpractice(v1.0.0)2300018.1scheckingwhetherthenamespacegoodpractice(dev)2100016.8scheckingwhetherthepackagecaETA3m(2/4)[3m9s]goodpractice(v1.0.0)2300018.6scheckingwhetherthenamespacegoodpractice(dev)2200017.2scheckingwhetherthepackagecaETA3m(2/4)[3m9.5s]goodpractice(v1.0.0)2400019.2scheckingwhetherthenamespacegoodpractice(dev)2200017.8scheckingwhetherthepackagecaETA3m(2/4)[3m10.1s]goodpractice(v1.0.0)2400019.9scheckingwhetherthenamespacegoodpractice(dev)2300018.5scheckingwhetherthenamespaceETA3m(2/4)[3m10.8s]goodpractice(v1.0.0)2500020.4scheckingloadingwithoutbeinggoodpractice(dev)2300019.0scheckingwhetherthenamespaceETA3m(2/4)[3m11.2s]goodpractice(v1.0.0)2500020.8scheckingloadingwithoutbeinggoodpractice(dev)2300019.4scheckingwhetherthenamespaceETA3m(2/4)[3m11.7s]goodpractice(v1.0.0)2500021.3scheckingloadingwithoutbeinggoodpractice(dev)2400019.9scheckingwhetherthenamespaceETA3m(2/4)[3m12.1s]goodpractice(v1.0.0)2500021.8scheckingloadingwithoutbeinggoodpractice(dev)2400020.4scheckingwhetherthenamespaceETA3m(2/4)[3m12.6s]goodpractice(v1.0.0)2600022.3scheckingdependenciesinRcodegoodpractice(dev)2500020.9scheckingloadingwithoutbeingETA3m(2/4)[3m13.1s]goodpractice(v1.0.0)2600022.7scheckingdependenciesinRcodegoodpractice(dev)2500021.3scheckingloadingwithoutbeingETA3m(2/4)[3m13.5s]goodpractice(v1.0.0)2600023.2scheckingdependenciesinRcodegoodpractice(dev)2500021.9scheckingloadingwithoutbeingETA3m(2/4)[3m14.1s]goodpractice(v1.0.0)2700023.8scheckingS3generic/methodconsgoodpractice(dev)2500022.4scheckingloadingwithoutbeingETA3m(2/4)[3m14.7s]goodpractice(v1.0.0)2700024.4scheckingS3generic/methodconsgoodpractice(dev)2600023.0scheckingdependenciesinRcodeETA3m(2/4)[3m15.2s]goodpractice(v1.0.0)2800024.9scheckingreplacementfunctionsgoodpractice(dev)2600023.5scheckingdependenciesinRcodeETA3m(2/4)[3m15.8s]goodpractice(v1.0.0)2800025.4scheckingreplacementfunctionsgoodpractice(dev)2700024.0scheckingS3generic/methodconsETA3m(2/4)[3m16.4s]goodpractice(v1.0.0)2900026.0scheckingforeignfunctioncallsgoodpractice(dev)2700024.6scheckingS3generic/methodconsETA3m(2/4)[3m16.8s]goodpractice(v1.0.0)2900026.5scheckingforeignfunctioncallsgoodpractice(dev)2800025.1scheckingreplacementfunctionsETA3m(2/4)[3m17.4s]goodpractice(v1.0.0)2900027.0scheckingforeignfunctioncallsgoodpractice(dev)2800025.6scheckingreplacementfunctionsETA3m(2/4)[3m17.8s]goodpractice(v1.0.0)2900027.4scheckingforeignfunctioncallsgoodpractice(dev)2900026.1scheckingforeignfunctioncallsETA3m(2/4)[3m18.3s]goodpractice(v1.0.0)2900028.0scheckingforeignfunctioncallsgoodpractice(dev)2900026.6scheckingforeignfunctioncallsETA3m(2/4)[3m18.8s]goodpractice(v1.0.0)2900028.5scheckingforeignfunctioncallsgoodpractice(dev)2900027.1scheckingforeignfunctioncallsETA3m(2/4)[3m19.4s]goodpractice(v1.0.0)2900029.0scheckingforeignfunctioncallsgoodpractice(dev)2900027.7scheckingforeignfunctioncallsETA3m(2/4)[3m19.9s]goodpractice(v1.0.0)2900029.5scheckingforeignfunctioncallsgoodpractice(dev)2900028.1scheckingforeignfunctioncallsETA3m(2/4)[3m20.4s]goodpractice(v1.0.0)3200030.1scheckingRdmetadata...goodpractice(dev)2900028.7scheckingforeignfunctioncallsETA3m(2/4)[3m20.9s]goodpractice(v1.0.0)3200030.5scheckingRdmetadata...goodpractice(dev)2900029.1scheckingforeignfunctioncallsETA3m(2/4)[3m21.4s]goodpractice(v1.0.0)3200031.0scheckingRdmetadata...goodpractice(dev)2900029.6scheckingforeignfunctioncallsETA3m(2/4)[3m21.9s]goodpractice(v1.0.0)3300031.5scheckingformissingdocumentatgoodpractice(dev)3000030.1scheckingRcodeforpossibleprETA3m(2/4)[3m22.4s]goodpractice(v1.0.0)3300032.0scheckingformissingdocumentatgoodpractice(dev)3200030.6scheckingRdmetadata...ETA3m(2/4)[3m22.9s]goodpractice(v1.0.0)3300032.5scheckingformissingdocumentatgoodpractice(dev)3200031.1scheckingRdmetadata...ETA3m(2/4)[3m23.3s]goodpractice(v1.0.0)3300032.9scheckingformissingdocumentatgoodpractice(dev)3300031.6scheckingformissingdocumentatETA3m(2/4)[3m23.8s]goodpractice(v1.0.0)3300033.5scheckingformissingdocumentatgoodpractice(dev)3300032.1scheckingformissingdocumentatETA3m(2/4)[3m24.3s]goodpractice(v1.0.0)3400034.0scheckingformissingdocumentatgoodpractice(dev)3300032.6scheckingformissingdocumentatETA3m(2/4)[3m24.9s]goodpractice(v1.0.0)3400034.6scheckingforcode/documentationgoodpractice(dev)3300033.3scheckingformissingdocumentatETA3m(2/4)[3m25.6s]goodpractice(v1.0.0)3400035.3scheckingforcode/documentationgoodpractice(dev)3300033.9scheckingformissingdocumentatETA3m(2/4)[3m26.2s]goodpractice(v1.0.0)3500035.8scheckingRd\usagesections...goodpractice(dev)3400034.4scheckingforcode/documentationETA3m(2/4)[3m26.7s]goodpractice(v1.0.0)3700036.3scheckingforunstateddependencgoodpractice(dev)3400034.9scheckingforcode/documentationETA3m(2/4)[3m27.2s]goodpractice(v1.0.0)3900036.8scheckingfilesin‘vignettes’.goodpractice(dev)3400035.4scheckingforcode/documentationETA3m(2/4)[3m27.7s]goodpractice(v1.0.0)3900037.4scheckingfilesin‘vignettes’.goodpractice(dev)3500036.0scheckingRd\usagesections...ETA3m(2/4)[3m28.3s]goodpractice(v1.0.0)3900038.1scheckingfilesin‘vignettes’.goodpractice(dev)3700036.7scheckingforunstateddependencETA3m(2/4)[3m29s]goodpractice(v1.0.0)3900038.7scheckingfilesin‘vignettes’.goodpractice(dev)3900037.4scheckingfilesin‘vignettes’.ETA3m(2/4)[3m29.7s]goodpractice(v1.0.0)4100039.3scheckingforunstateddependencgoodpractice(dev)3900037.9scheckingfilesin‘vignettes’.ETA4m(2/4)[3m30.2s]goodpractice(v1.0.0)4100039.8scheckingtests...goodpractice(dev)3900038.4scheckingfilesin‘vignettes’.ETA4m(2/4)[3m30.7s]goodpractice(v1.0.0)4100040.3scheckingtests...goodpractice(dev)4000038.9scheckingfilesin‘vignettes’.ETA4m(2/4)[3m31.1s]goodpractice(v1.0.0)4100040.8scheckingtests...goodpractice(dev)4100039.4scheckingtests...ETA4m(2/4)[3m31.7s]goodpractice(v1.0.0)4100041.4scheckingtests...goodpractice(dev)4100040.0scheckingtests...ETA4m(2/4)[3m32.2s]goodpractice(v1.0.0)4100041.9scheckingtests...goodpractice(dev)4100040.5scheckingtests...ETA4m(2/4)[3m32.7s]goodpractice(v1.0.0)4100042.5scheckingtests...goodpractice(dev)4100041.3scheckingtests...ETA4m(2/4)[3m33.5s]goodpractice(v1.0.0)4100043.2scheckingtests...goodpractice(dev)4100041.8scheckingtests...ETA4m(2/4)[3m34.1s]goodpractice(v1.0.0)4100043.7scheckingtests...goodpractice(dev)4100042.4scheckingtests...ETA4m(2/4)[3m34.6s]goodpractice(v1.0.0)4100044.2scheckingtests...goodpractice(dev)4100042.8scheckingtests...ETA4m(2/4)[3m35.1s]goodpractice(v1.0.0)4100044.8scheckingtests...goodpractice(dev)4100043.4scheckingtests...ETA4m(2/4)[3m35.6s]goodpractice(v1.0.0)4100045.2scheckingtests...goodpractice(dev)4100043.8scheckingtests...ETA4m(2/4)[3m36.1s]goodpractice(v1.0.0)4100045.7scheckingtests...goodpractice(dev)4100044.3scheckingtests...ETA4m(2/4)[3m36.5s]goodpractice(v1.0.0)4100046.1scheckingtests...goodpractice(dev)4100044.8scheckingtests...ETA4m(2/4)[3m37s]goodpractice(v1.0.0)4100046.6scheckingtests...goodpractice(dev)4100045.3scheckingtests...ETA4m(2/4)[3m37.5s]goodpractice(v1.0.0)4100047.2scheckingtests...goodpractice(dev)4100045.8scheckingtests...ETA4m(2/4)[3m38s]goodpractice(v1.0.0)4100047.6scheckingtests...goodpractice(dev)4100046.3scheckingtests...ETA4m(2/4)[3m38.5s]goodpractice(v1.0.0)4100048.1scheckingtests...goodpractice(dev)4100046.8scheckingtests...ETA4m(2/4)[3m39s]goodpractice(v1.0.0)4100048.6scheckingtests...goodpractice(dev)4100047.3scheckingtests...ETA4m(2/4)[3m39.5s]goodpractice(v1.0.0)4100049.2scheckingtests...goodpractice(dev)4100047.8scheckingtests...ETA4m(2/4)[3m40.1s]goodpractice(v1.0.0)4200049.7sgoodpractice(dev)4100048.3scheckingtests...ETA4m(2/4)[3m40.6s]goodpractice(v1.0.0)4200050.0sgoodpractice(dev)4200048.8sETA1m(3/4)[3m41s]goodpractice(dev)4200049.0sFinishedin3m41.5sETA?(0/4)[4.4s]installingdiffviewer,praise(dev) \ No newline at end of file +ETA?(1/NA)[30ms]SOKNWEETA?(0/4)[1.1s]installingfastmapsysyamlETA?(0/4)[1.4s]installingfastmapsysyamlzipETA?(0/4)[1.8s]installingfastmapsysyamlziprstudioapiETA?(0/4)[2.1s]installingfastmapsysyamlziprstudioapiiniETA?(0/4)[2.3s]installingfastmapsysyamlziprstudioapiiniwhiskerETA?(0/4)[2.7s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[3s]installingfastmapsysyamlziprstudioapiiniwhiskercommonmETA?(0/4)[3.3s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[3.5s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[3.8s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[3.9s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[4.1s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[4.3s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[4.5s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[4.7s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[4.9s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[5.1s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[5.4s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[5.6s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[5.7s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[6s]installingfastmapsysyamlziprstudioapiiniwhiskercommonmETA?(0/4)[6.2s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[6.4s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[6.6s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[6.7s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[6.9s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[7.2s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[7.4s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[7.6s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[7.8s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[8s]installingfastmapsysyamlziprstudioapiiniwhiskercommonmETA?(0/4)[8.2s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[8.4s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[8.6s]installingfastmapsysyamlziprstudioapiiniwhiskercommoETA?(0/4)[9.1s]installingfastmapsysziprstudioapiinicommonmarkpraiseETA?(0/4)[9.4s]installingpraisepraiseETA?(0/4)[9.8s]installingbase64encpraisepraiseETA?(0/4)[10.1s]installingbase64encrlangpraisepraiseETA?(0/4)[10.5s]installingbase64encrlangdigestpraisepraiseETA?(0/4)[10.8s]installingbase64encrlangdigestclipraisepraiseETA?(0/4)[11.2s]installingbase64encrlangdigestclirappdirspraisepraisETA?(0/4)[11.6s]installingbase64encrlangdigestclirappdirsfspraiseprETA?(0/4)[12s]installingbase64encrlangdigestclirappdirsfsR6praisepETA?(0/4)[12.6s]installingbase64encrlangdigestclirappdirsfsR6xfunpETA?(0/4)[13.3s]installingbase64encrlangdigestclirappdirsfsR6xfunpETA?(0/4)[13.9s]installingbase64encrlangdigestclirappdirsfsR6xfunpETA?(0/4)[14.4s]installingrlangdigestclirappdirsfsR6xfunpsaskpassETA?(0/4)[14.5s]installingrlangdigestclirappdirsfsR6xfunpsaskpassETA?(0/4)[15.2s]installingclirappdirsfsR6xfunpsaskpassglueRcppETA?(0/4)[15.9s]installingrappdirsfsR6xfunpsaskpassglueRcppmimeETA?(0/4)[16.5s]installingfsR6xfunpsaskpassglueRcppmimejsonliteETA?(0/4)[17.1s]installingxfunpsaskpassglueRcppmimejsonliteevaluateETA?(0/4)[17.7s]installingpsaskpassglueRcppmimejsonliteevaluatecurlETA?(0/4)[18.1s]installingglueRcppmimejsonliteevaluatecurlmagrittrETA?(0/4)[18.6s]installingglueRcppmimejsonliteevaluatecurlmagrittrwETA?(0/4)[19.5s]installingRcppmimejsonliteevaluatecurlmagrittrwithrETA?(0/4)[20.1s]installingRcppjsonliteevaluatecurlmagrittrwithrotelETA?(0/4)[20.6s]installingjsonliteevaluatecurlmagrittrwithrotelcrayoETA?(0/4)[21.2s]installingjsonliteevaluatecurlmagrittrwithrotelcrayoETA?(0/4)[21.7s]installingevaluatecurlmagrittrwithrotelcrayonlazyevaETA?(0/4)[22.3s]installingcurlmagrittrwithrotelcrayonlazyevalgitcredETA?(0/4)[22.8s]installingwithrotelcrayonlazyevalgitcredsrprojrootprETA?(0/4)[23.3s]installingwithrotelcrayonlazyevalgitcredsrprojrootprETA?(0/4)[23.8s]installingwithrotelcrayonlazyevalgitcredsrprojrootprETA?(0/4)[24.4s]installingcrayonlazyevalgitcredsrprojrootprettyunitsrETA?(0/4)[25s]installinglazyevalgitcredsrprojrootprettyunitsremotescoETA?(0/4)[25.6s]installinggitcredsrprojrootprettyunitsremotescodetoolsETA?(0/4)[26.1s]installingprettyunitsremotescodetoolsbackportsxmlparseETA?(0/4)[26.6s]installingremotescodetoolsbackportsxmlparsedatacliprxETA?(0/4)[27.1s]installingremotescodetoolsbackportsxmlparsedatacliprxETA?(0/4)[27.7s]installinghtmltoolsbackportsxmlparsedatacliprxtablesoETA?(0/4)[28.1s]installinghtmltoolscachembackportsxmlparsedatacliprxtETA?(0/4)[28.7s]installinghtmltoolscachemlifecyclexmlparsedatacliprxtETA?(0/4)[29.2s]installinghtmltoolscachemlifecyclehighrcliprxtablesoETA?(0/4)[29.7s]installinghtmltoolscachemlifecyclehighrprocessxxtableETA?(0/4)[30.5s]installinghtmltoolscachemlifecyclehighrprocessxopenssETA?(0/4)[31s]installinghtmltoolscachemlifecyclehighrprocessxopensslETA?(0/4)[31.5s]installinghtmltoolscachemlifecyclehighrprocessxopenssETA?(0/4)[32s]installinghtmltoolscachemlifecyclehighrprocessxopensslETA?(0/4)[32.5s]installinglifecyclehighrprocessxopenssllatertinytexdETA?(0/4)[33.1s]installinghighrprocessxopenssllatertinytexdescdiffobETA?(0/4)[33.6s]installingprocessxopenssllatertinytexdescdiffobjsessETA?(0/4)[34s]installingprocessxopenssllatertinytexdescdiffobjsessioETA?(0/4)[34.5s]installingprocessxopenssllatertinytexdescdiffobjsessETA?(0/4)[35.3s]installingsassopenssllatertinytexdescdiffobjsessioniETA?(0/4)[36s]installingsassmemoisetinytexdescdiffobjsessioninforexETA?(0/4)[36.5s]installingsassmemoisejquerylibtinytexdescdiffobjsessETA?(0/4)[36.7s]installingsassmemoisejquerylibtinytexdescdiffobjsessETA?(0/4)[37s]installingsassmemoisejquerylibtinytexdescdiffobjsessioETA?(0/4)[37.1s]installingsassmemoisejquerylibtinytexdescdiffobjsessETA?(0/4)[37.8s]installingsassmemoisejquerylibvctrstinytexdescsessioETA?(0/4)[38.4s]installingsassmemoisejquerylibvctrstinytexfontawesomeETA?(0/4)[38.9s]installingsassmemoisejquerylibvctrstinytexfontawesomeETA?(0/4)[39.4s]installingsassmemoisejquerylibvctrsfontawesomeknitrcETA?(0/4)[40.1s]installingsassmemoisejquerylibvctrsfontawesomeknitrcETA?(0/4)[40.7s]installingsassmemoisejquerylibvctrsfontawesomeknitrcETA?(0/4)[41.4s]installingsassjquerylibvctrsfontawesomeknitrcallrcreETA?(0/4)[42s]installingsassjquerylibvctrsfontawesomeknitrcallrcredeETA?(0/4)[42.1s]installingsassjquerylibvctrsfontawesomeknitrcallrcreETA?(0/4)[42.3s]installingsassjquerylibvctrsfontawesomeknitrcallrcreETA?(0/4)[42.5s]installingsassjquerylibvctrsfontawesomeknitrcallrcreETA?(0/4)[42.8s]installingsassjquerylibvctrsfontawesomeknitrcallrcreETA?(0/4)[42.9s]installingsassjquerylibvctrsfontawesomeknitrcallrcreETA?(0/4)[43.1s]installingsassjquerylibvctrsfontawesomeknitrcallrcreETA?(0/4)[43.3s]installingsassjquerylibvctrsfontawesomeknitrcallrcreETA?(0/4)[43.5s]installingsassjquerylibvctrsfontawesomeknitrcallrcreETA?(0/4)[44.2s]installingjquerylibfontawesomeknitrcallrcredentialsprETA?(0/4)[44.8s]installingbslibcallrcredentialspromiseshttrxopenwaldETA?(0/4)[45.2s]installingbslibcredentialshttr2promiseshttrxopenwaldETA?(0/4)[45.8s]installingbslibcredentialshttr2promiseshttrpurrrwaldETA?(0/4)[46.2s]installingbslibcredentialshttr2promiseshttrpurrrwaldETA?(0/4)[46.7s]installingbslibhttr2promisespkgbuildhttrpurrrwaldolETA?(0/4)[47.3s]installingbslibhttr2pkgbuildhttrgertpurrrwaldolintrETA?(0/4)[47.8s]installingbslibhttr2pkgbuildhttrgertpurrrwaldocycloETA?(0/4)[48.4s]installingbslibhttr2pkgbuildhttrgertpurrrhttpuvwaldETA?(0/4)[48.7s]installingbslibhttr2pkgbuildhttrgertpurrrhttpuvwaldETA?(0/4)[49.3s]installingbslibhttr2pkgbuildgertpurrrhttpuvwaldowhoETA?(0/4)[49.9s]installingbslibhttr2pkgbuildgertpurrrhttpuvwhoamicyETA?(0/4)[50.3s]installingbslibhttr2pkgbuildgertpurrrhttpuvwhoamicyETA?(0/4)[51s]installingbslibpkgbuildgertpurrrghhttpuvwhoamicyclocoETA?(0/4)[51.6s]installingrmarkdownpkgbuildgertghhttpuvwhoamicyclocoETA?(0/4)[52.1s]installingrmarkdowngertghhttpuvpkgloadwhoamicyclocomETA?(0/4)[52.5s]installingrmarkdowngertghhttpuvpkgloadwhoamircmdchecETA?(0/4)[52.9s]installingrmarkdowngertghhttpuvpkgloadwhoamircmdchecETA?(0/4)[53.1s]installingrmarkdowngertghhttpuvpkgloadwhoamircmdchecETA?(0/4)[53.4s]installingrmarkdowngertghhttpuvpkgloadwhoamircmdchecETA?(0/4)[53.6s]installingrmarkdowngertghhttpuvpkgloadwhoamircmdchecETA?(0/4)[53.8s]installingrmarkdowngertghhttpuvpkgloadwhoamircmdchecETA?(0/4)[53.9s]installingrmarkdowngertghhttpuvpkgloadwhoamircmdchecETA?(0/4)[54.3s]installingrmarkdowngertghhttpuvpkgloadrcmdcheckcovrETA?(0/4)[54.5s]installingrmarkdownghhttpuvpkgloadrcmdcheckcovrETA?(0/4)[54.6s]installingrmarkdownghhttpuvpkgloadrcmdcheckcovrETA?(0/4)[55s]installingrmarkdownghpkgloadrcmdcheckcovrshinyETA?(0/4)[55.2s]installingrmarkdownghpkgloadrcmdcheckcovrshinyETA?(0/4)[55.4s]installingrmarkdownghpkgloadrcmdcheckcovrshinyETA?(0/4)[55.8s]installingrmarkdownpkgloadrcmdcheckcovrusethisshinyETA?(0/4)[56.1s]installingrmarkdownpkgloadrcmdcheckcovrusethisshinyETA?(0/4)[56.3s]installingrmarkdownpkgloadrcmdcheckusethisshinyETA?(0/4)[56.4s]installingrmarkdownpkgloadrcmdcheckusethisshinyETA?(0/4)[56.9s]installingrmarkdownrcmdcheckusethisshinytestthatETA?(0/4)[57.1s]installingrmarkdownrcmdcheckusethisshinytestthatETA?(0/4)[57.2s]installingrmarkdownrcmdcheckusethisshinytestthatETA?(0/4)[57.7s]installinghtmlwidgetsrcmdcheckusethisshinytestthatETA?(0/4)[57.8s]installinghtmlwidgetsrcmdcheckusethisshinytestthatETA?(0/4)[58.1s]installinghtmlwidgetsrcmdcheckusethisshinytestthatETA?(0/4)[58.2s]installinghtmlwidgetsrcmdcheckusethisshinytestthatETA?(0/4)[58.6s]installinghtmlwidgetsusethisshinytestthatETA?(0/4)[58.7s]installinghtmlwidgetsusethisshinytestthatETA?(0/4)[58.9s]installinghtmlwidgetsusethisshinytestthatETA?(0/4)[59.1s]installinghtmlwidgetsusethisshinytestthatETA?(0/4)[59.3s]installinghtmlwidgetsusethisshinytestthatETA?(0/4)[59.5s]installinghtmlwidgetsusethisshinytestthatETA?(0/4)[59.7s]installinghtmlwidgetsusethisshinytestthatETA?(0/4)[59.9s]installinghtmlwidgetsusethisshinytestthatETA?(0/4)[1m0.1s]installinghtmlwidgetsshinytestthatETA?(0/4)[1m0.3s]installinghtmlwidgetsshinytestthatETA?(0/4)[1m0.5s]installinghtmlwidgetsshinytestthat══goodpractice═════════════════════════╪═══╪═════════════╪════════════════════+praisev1.0.0https://cran.r-project.org00000.1sstarting...+praisev1.0.0local0000starting...ETA?(0/4)[1m3.4s]installinghtmlwidgetsshiny+praisev1.0.0https://cran.r-project.org00002.7sstarting...+praisev1.0.0local00000.2sstarting...ETA?(0/4)[1m5.9s]installingshiny+praisev1.0.0https://cran.r-project.org20003.4scheckingpacka+praisev1.0.0local00000.9sstarting...ETA?(0/4)[1m6.6s]installingshinydiffviewer+praisev1.0.0https://cran.r-project.org20003.6scheckingpacka+praisev1.0.0local00001.1sstarting...ETA?(0/4)[1m6.8s]installingshinydiffviewer+praisev1.0.0https://cran.r-project.org20003.9scheckingpacka+praisev1.0.0local00001.3sstarting...ETA?(0/4)[1m7s]installingshinydiffviewer+praisev1.0.0https://cran.r-project.org20004.1scheckingpacka+praisev1.0.0local00001.6sstarting...ETA?(0/4)[1m7.3s]installingshinydiffviewer+praisev1.0.0https://cran.r-project.org20004.5scheckingpacka+praisev1.0.0local20002.0scheckingpackaETA?(0/4)[1m7.7s]installingshinydiffviewer+praisev1.0.0https://cran.r-project.org20004.7scheckingpacka+praisev1.0.0local20002.2scheckingpackaETA?(0/4)[1m7.9s]installingshinydiffviewer+praisev1.0.0https://cran.r-project.org50005.0scheckingifth+praisev1.0.0local20002.5scheckingpackaETA?(0/4)[1m8.2s]installingshinydiffviewer+praisev1.0.0https://cran.r-project.org50005.2scheckingifth+praisev1.0.0local50002.7scheckingifthETA?(0/4)[1m8.5s]installingshinydiffviewer+praisev1.0.0https://cran.r-project.org50005.5scheckingifth+praisev1.0.0local50003.0scheckingifthETA?(0/4)[1m8.8s]installingshinydiffviewer+praisev1.0.0https://cran.r-project.org50005.8scheckingifth+praisev1.0.0local50003.3scheckingifthETA?(0/4)[1m9.1s]installingshinydiffviewer+praisev1.0.0https://cran.r-project.org90006.2scheckingfors+praisev1.0.0local90003.7scheckingforsETA?(0/4)[1m9.4s]installingdiffviewer+praisev1.0.0https://cran.r-project.org90006.5scheckingfors+praisev1.0.0local90003.9scheckingforsETA?(0/4)[1m9.7s]installingdiffviewer+praisev1.0.0https://cran.r-project.org90006.7scheckingfors+praisev1.0.0local90004.2scheckingforsETA?(0/4)[1m9.9s]installingdiffviewer+praisev1.0.0https://cran.r-project.org90006.9scheckingfors+praisev1.0.0local90004.4scheckingforsETA?(0/4)[1m10.1s]installingdiffviewer+praisev1.0.0https://cran.r-project.org90007.2scheckingfors+praisev1.0.0local90004.7scheckingforsETA?(0/4)[1m10.4s]installingdiffviewer+praisev1.0.0https://cran.r-project.org90007.5scheckingfors+praisev1.0.0local90004.9scheckingforsETA?(0/4)[1m10.7s]installingdiffviewer+praisev1.0.0https://cran.r-project.org90007.7scheckingfors+praisev1.0.0local90005.2scheckingforsETA?(0/4)[1m10.9s]installingdiffviewer+praisev1.0.0https://cran.r-project.org90007.9scheckingfors+praisev1.0.0local90005.4scheckingfors+praisev1.0.0https://cran.r-project.org900011.1scheckingfor+praisev1.0.0local90008.6scheckingfors══testthat═════════════════════════════╪═══╪═════════════╪════════════════════ETA?(0/4)[1m14.3s]+praisev1.0.0https://cran.r-project.org900014.5scheckingfor+praisev1.0.0local900012.0scheckingfor+praisev1.0.0https://cran.r-project.org00003.5sstarting...ETA?(0/4)[1m17.7s]+praisev1.0.0https://cran.r-project.org900015.0scheckingfor+praisev1.0.0local900012.5scheckingfor+praisev1.0.0https://cran.r-project.org00004.0sstarting...+praisev1.0.0local00000.7sstarting...ETA?(0/4)[1m18.3s]+praisev1.0.0https://cran.r-project.org900015.4scheckingfor+praisev1.0.0local900012.9scheckingfor+praisev1.0.0local00001.2sstarting...ETA?(0/4)[1m18.6s]+praisev1.0.0https://cran.r-project.org900015.8scheckingfor+praisev1.0.0local900013.3scheckingfor+praisev1.0.0https://cran.r-project.org20004.9scheckingpacka+praisev1.0.0local00001.6sstarting...ETA?(0/4)[1m19s]+praisev1.0.0https://cran.r-project.org900016.2scheckingfor+praisev1.0.0local900013.6scheckingfor+praisev1.0.0https://cran.r-project.org20005.2scheckingpacka+praisev1.0.0local00001.9sstarting...ETA?(0/4)[1m19.4s]+praisev1.0.0https://cran.r-project.org900016.5scheckingfor+praisev1.0.0local900014.0scheckingfor+praisev1.0.0https://cran.r-project.org20005.6scheckingpacka+praisev1.0.0local00002.3sstarting...ETA?(0/4)[1m19.8s]+praisev1.0.0https://cran.r-project.org900017.0scheckingfor+praisev1.0.0local900014.5scheckingfor+praisev1.0.0https://cran.r-project.org20006.0scheckingpacka+praisev1.0.0local00002.7sstarting...ETA?(0/4)[1m20.3s]+praisev1.0.0https://cran.r-project.org900017.5scheckingfor+praisev1.0.0local900015.0scheckingfor+praisev1.0.0https://cran.r-project.org50006.5scheckingifth+praisev1.0.0local00003.3sstarting...ETA?(0/4)[1m20.7s]+praisev1.0.0https://cran.r-project.org900017.9scheckingfor+praisev1.0.0local900015.4scheckingfor+praisev1.0.0https://cran.r-project.org50007.0scheckingifth+praisev1.0.0local20003.7scheckingpackaETA?(0/4)[1m21.1s]+praisev1.0.0https://cran.r-project.org900018.3scheckingfor+praisev1.0.0local900015.8scheckingfor+praisev1.0.0https://cran.r-project.org50007.3scheckingifth+praisev1.0.0local20004.1scheckingpackaETA?(0/4)[1m21.5s]+praisev1.0.0https://cran.r-project.org900018.6scheckingfor+praisev1.0.0local900016.1scheckingfor+praisev1.0.0https://cran.r-project.org50007.7scheckingifth+praisev1.0.0local20004.4scheckingpackaETA?(0/4)[1m21.8s]+praisev1.0.0https://cran.r-project.org900019.0scheckingfor+praisev1.0.0local900016.5scheckingfor+praisev1.0.0https://cran.r-project.org50008.0scheckingifth+praisev1.0.0local20004.7scheckingpackaETA?(0/4)[1m22.2s]+praisev1.0.0https://cran.r-project.org900019.5scheckingfor+praisev1.0.0local900016.9scheckingfor+praisev1.0.0https://cran.r-project.org50008.5scheckingifth+praisev1.0.0local20005.2scheckingpackaETA?(0/4)[1m22.7s]+praisev1.0.0https://cran.r-project.org900019.9scheckingfor+praisev1.0.0local900017.4scheckingfor+praisev1.0.0https://cran.r-project.org50008.9scheckingifth+praisev1.0.0local20005.6scheckingpackaETA?(0/4)[1m23.1s]+praisev1.0.0https://cran.r-project.org900020.3scheckingfor+praisev1.0.0local900017.8scheckingfor+praisev1.0.0https://cran.r-project.org50009.3scheckingifth+praisev1.0.0local20006.1scheckingpackaETA?(0/4)[1m23.6s]+praisev1.0.0https://cran.r-project.org900020.8scheckingfor+praisev1.0.0local1200018.3scheckingpack+praisev1.0.0https://cran.r-project.org50009.8scheckingifth+praisev1.0.0local20006.5scheckingpackaETA?(0/4)[1m24s]+praisev1.0.0https://cran.r-project.org900021.3scheckingfor+praisev1.0.0local1500018.8scheckingfor+praisev1.0.0https://cran.r-project.org500010.3scheckingift+praisev1.0.0local20007.0scheckingpackaETA?(0/4)[1m24.5s]+praisev1.0.0https://cran.r-project.org1200021.7scheckingpack+praisev1.0.0local1500019.2scheckingfor+praisev1.0.0https://cran.r-project.org500010.8scheckingift+praisev1.0.0local20007.5scheckingpackaETA?(0/4)[1m24.9s]+praisev1.0.0https://cran.r-project.org1200022.1scheckingpack+praisev1.0.0local1500019.6scheckingfor+praisev1.0.0https://cran.r-project.org500011.2scheckingift+praisev1.0.0local20007.9scheckingpackaETA?(0/4)[1m25.3s]+praisev1.0.0https://cran.r-project.org1200022.6scheckingpack+praisev1.0.0local1500020.0scheckingfor+praisev1.0.0https://cran.r-project.org900011.6scheckingfor+praisev1.0.0local20008.3scheckingpackaETA?(0/4)[1m25.8s]+praisev1.0.0https://cran.r-project.org1200023.0scheckingpack+praisev1.0.0local1500020.5scheckingfor+praisev1.0.0https://cran.r-project.org900012.0scheckingfor+praisev1.0.0local20008.7scheckingpackaETA?(0/4)[1m26.3s]+praisev1.0.0https://cran.r-project.org1200023.5scheckingpack+praisev1.0.0local1500020.9scheckingfor+praisev1.0.0https://cran.r-project.org900012.5scheckingfor+praisev1.0.0local20009.2scheckingpackaETA?(0/4)[1m26.7s]+praisev1.0.0https://cran.r-project.org1200023.9scheckingpack+praisev1.0.0local1600021.4scheckinginde+praisev1.0.0https://cran.r-project.org900012.9scheckingfor+praisev1.0.0local20009.7scheckingpackaETA?(0/4)[1m27.1s]+praisev1.0.0https://cran.r-project.org1500024.4scheckingfor+praisev1.0.0local1600021.9scheckinginde+praisev1.0.0https://cran.r-project.org900013.4scheckingfor+praisev1.0.0local200010.1scheckingpackETA?(0/4)[1m27.6s]+praisev1.0.0https://cran.r-project.org1500024.8scheckingfor+praisev1.0.0local1600022.3scheckinginde+praisev1.0.0https://cran.r-project.org900013.8scheckingfor+praisev1.0.0local200010.5scheckingpackETA?(0/4)[1m28.1s]+praisev1.0.0https://cran.r-project.org1500025.4scheckingfor+praisev1.0.0local1600022.9scheckinginde+praisev1.0.0https://cran.r-project.org900014.4scheckingfor+praisev1.0.0local500011.1scheckingiftETA?(0/4)[1m28.6s]+praisev1.0.0https://cran.r-project.org1500025.8scheckingfor+praisev1.0.0local1600023.3scheckinginde+praisev1.0.0https://cran.r-project.org900014.8scheckingfor+praisev1.0.0local500011.6scheckingiftETA?(0/4)[1m29s]+praisev1.0.0https://cran.r-project.org1500026.2scheckingfor+praisev1.0.0local1600023.7scheckinginde+praisev1.0.0https://cran.r-project.org900015.2scheckingfor+praisev1.0.0local500011.9scheckingiftETA?(0/4)[1m29.4s]+praisev1.0.0https://cran.r-project.org1500026.6scheckingfor+praisev1.0.0local1600024.1scheckinginde+praisev1.0.0https://cran.r-project.org900015.6scheckingfor+praisev1.0.0local500012.4scheckingiftETA?(0/4)[1m29.8s]+praisev1.0.0https://cran.r-project.org1500027.0scheckingfor+praisev1.0.0local1600024.5scheckinginde+praisev1.0.0https://cran.r-project.org900016.0scheckingfor+praisev1.0.0local500012.7scheckingiftETA?(0/4)[1m30.2s]+praisev1.0.0https://cran.r-project.org1500027.4scheckingfor+praisev1.0.0local1600024.8scheckinginde+praisev1.0.0https://cran.r-project.org900016.4scheckingfor+praisev1.0.0local500013.1scheckingiftETA?(0/4)[1m30.6s]+praisev1.0.0https://cran.r-project.org1500027.8scheckingfor+praisev1.0.0local1600025.2scheckinginde+praisev1.0.0https://cran.r-project.org900016.8scheckingfor+praisev1.0.0local500013.5scheckingiftETA?(0/4)[1m31s]+praisev1.0.0https://cran.r-project.org1500028.2scheckingfor+praisev1.0.0local1600025.6scheckinginde+praisev1.0.0https://cran.r-project.org900017.2scheckingfor+praisev1.0.0local500013.9scheckingiftETA?(0/4)[1m31.4s]+praisev1.0.0https://cran.r-project.org1500028.6scheckingfor+praisev1.0.0local1600026.0scheckinginde+praisev1.0.0https://cran.r-project.org900017.6scheckingfor+praisev1.0.0local500014.3scheckingiftETA?(0/4)[1m31.7s]+praisev1.0.0https://cran.r-project.org1500029.0scheckingfor+praisev1.0.0local1600026.4scheckinginde+praisev1.0.0https://cran.r-project.org900018.0scheckingfor+praisev1.0.0local500014.7scheckingiftETA?(0/4)[1m32.2s]+praisev1.0.0https://cran.r-project.org1500029.4scheckingfor+praisev1.0.0local1600026.8scheckinginde+praisev1.0.0https://cran.r-project.org900018.4scheckingfor+praisev1.0.0local500015.1scheckingiftETA?(0/4)[1m32.5s]+praisev1.0.0https://cran.r-project.org1500029.7scheckingfor+praisev1.0.0local1600027.2scheckinginde+praisev1.0.0https://cran.r-project.org900018.8scheckingfor+praisev1.0.0local900015.5scheckingforETA?(0/4)[1m32.9s]+praisev1.0.0https://cran.r-project.org1500030.1scheckingfor+praisev1.0.0local1600027.6scheckinginde+praisev1.0.0https://cran.r-project.org900019.2scheckingfor+praisev1.0.0local900015.9scheckingforETA?(0/4)[1m33.3s]+praisev1.0.0https://cran.r-project.org1500030.5scheckingfor+praisev1.0.0local1600028.0scheckinginde+praisev1.0.0https://cran.r-project.org900019.6scheckingfor+praisev1.0.0local900016.3scheckingforETA?(0/4)[1m33.7s]+praisev1.0.0https://cran.r-project.org1500031.0scheckingfor+praisev1.0.0local1600028.5scheckinginde+praisev1.0.0https://cran.r-project.org900020.0scheckingfor+praisev1.0.0local900016.8scheckingforETA?(0/4)[1m34.3s]+praisev1.0.0https://cran.r-project.org1500031.5scheckingfor+praisev1.0.0local1600029.0scheckinginde+praisev1.0.0https://cran.r-project.org900020.6scheckingfor+praisev1.0.0local900017.3scheckingforETA?(0/4)[1m34.7s]+praisev1.0.0https://cran.r-project.org1500032.0scheckingfor+praisev1.0.0local1600029.5scheckinginde+praisev1.0.0https://cran.r-project.org900021.0scheckingfor+praisev1.0.0local900017.7scheckingforETA?(0/4)[1m35.2s]+praisev1.0.0https://cran.r-project.org1500032.5scheckingfor+praisev1.0.0local1600030.0scheckinginde+praisev1.0.0https://cran.r-project.org900021.5scheckingfor+praisev1.0.0local900018.2scheckingforETA?(0/4)[1m35.7s]+praisev1.0.0https://cran.r-project.org1500033.0scheckingfor+praisev1.0.0local1600030.5scheckinginde+praisev1.0.0https://cran.r-project.org900022.0scheckingfor+praisev1.0.0local900018.7scheckingforETA?(0/4)[1m36.2s]+praisev1.0.0https://cran.r-project.org1500033.5scheckingfor+praisev1.0.0local1600031.0scheckinginde+praisev1.0.0https://cran.r-project.org900022.5scheckingfor+praisev1.0.0local900019.2scheckingforETA?(0/4)[1m36.7s]+praisev1.0.0https://cran.r-project.org1500033.9scheckingfor+praisev1.0.0local1600031.4scheckinginde+praisev1.0.0https://cran.r-project.org900023.0scheckingfor+praisev1.0.0local900019.7scheckingforETA?(0/4)[1m37.1s]+praisev1.0.0https://cran.r-project.org1500034.3scheckingfor+praisev1.0.0local1600031.8scheckinginde+praisev1.0.0https://cran.r-project.org900023.4scheckingfor+praisev1.0.0local900020.1scheckingforETA?(0/4)[1m37.5s]+praisev1.0.0https://cran.r-project.org1600034.8scheckinginde+praisev1.0.0local1600032.3scheckinginde+praisev1.0.0https://cran.r-project.org900023.8scheckingfor+praisev1.0.0local900020.5scheckingforETA?(0/4)[1m38s]+praisev1.0.0https://cran.r-project.org1600035.3scheckinginde+praisev1.0.0local1600032.8scheckinginde+praisev1.0.0https://cran.r-project.org900024.3scheckingfor+praisev1.0.0local900021.0scheckingforETA?(0/4)[1m38.5s]+praisev1.0.0https://cran.r-project.org1600035.8scheckinginde+praisev1.0.0local1600033.3scheckinginde+praisev1.0.0https://cran.r-project.org900024.8scheckingfor+praisev1.0.0local900021.5scheckingforETA?(0/4)[1m39.2s]+praisev1.0.0https://cran.r-project.org1600036.5scheckinginde+praisev1.0.0local1600034.0scheckinginde+praisev1.0.0https://cran.r-project.org900025.5scheckingfor+praisev1.0.0local900022.2scheckingforETA?(0/4)[1m39.8s]+praisev1.0.0https://cran.r-project.org1600037.0scheckinginde+praisev1.0.0local1600034.5scheckinginde+praisev1.0.0https://cran.r-project.org900026.1scheckingfor+praisev1.0.0local900022.8scheckingforETA?(0/4)[1m40.3s]+praisev1.0.0https://cran.r-project.org1600037.5scheckinginde+praisev1.0.0local1600035.0scheckinginde+praisev1.0.0https://cran.r-project.org900026.6scheckingfor+praisev1.0.0local900023.3scheckingforETA?(0/4)[1m40.8s]+praisev1.0.0https://cran.r-project.org1700038.0scheckingpack+praisev1.0.0local1600035.5scheckinginde+praisev1.0.0https://cran.r-project.org900027.0scheckingfor+praisev1.0.0local900023.7scheckingforETA?(0/4)[1m41.2s]+praisev1.0.0https://cran.r-project.org1900038.5scheckingRfi+praisev1.0.0local1600035.9scheckinginde+praisev1.0.0https://cran.r-project.org900027.5scheckingfor+praisev1.0.0local900024.2scheckingforETA?(0/4)[1m41.7s]+praisev1.0.0https://cran.r-project.org1900038.9scheckingRfi+praisev1.0.0local1600036.4scheckinginde+praisev1.0.0https://cran.r-project.org900028.0scheckingfor+praisev1.0.0local900024.7scheckingforETA?(0/4)[1m42.1s]+praisev1.0.0https://cran.r-project.org1900039.4scheckingRfi+praisev1.0.0local1600036.9scheckinginde+praisev1.0.0https://cran.r-project.org900028.4scheckingfor+praisev1.0.0local900025.1scheckingforETA?(0/4)[1m42.6s]+praisev1.0.0https://cran.r-project.org2000039.8scheckingwhet+praisev1.0.0local1600037.3scheckinginde+praisev1.0.0https://cran.r-project.org900028.9scheckingfor+praisev1.0.0local900025.6scheckingforETA?(0/4)[1m43.1s]+praisev1.0.0https://cran.r-project.org2000040.3scheckingwhet+praisev1.0.0local1700037.8scheckingpack+praisev1.0.0https://cran.r-project.org900029.3scheckingfor+praisev1.0.0local900026.0scheckingforETA?(0/4)[1m43.5s]+praisev1.0.0https://cran.r-project.org2000040.8scheckingwhet+praisev1.0.0local1900038.4scheckingRfi+praisev1.0.0https://cran.r-project.org900029.8scheckingfor+praisev1.0.0local900026.5scheckingforETA?(0/4)[1m44.1s]+praisev1.0.0https://cran.r-project.org2000041.3scheckingwhet+praisev1.0.0local1900038.8scheckingRfi+praisev1.0.0https://cran.r-project.org900030.3scheckingfor+praisev1.0.0local900027.1scheckingforETA?(0/4)[1m44.5s]+praisev1.0.0https://cran.r-project.org2000041.7scheckingwhet+praisev1.0.0local1900039.1scheckingRfi+praisev1.0.0https://cran.r-project.org900030.7scheckingfor+praisev1.0.0local900027.4scheckingforETA?(0/4)[1m44.8s]+praisev1.0.0https://cran.r-project.org2000042.1scheckingwhet+praisev1.0.0local1900039.6scheckingRfi+praisev1.0.0https://cran.r-project.org900031.1scheckingfor+praisev1.0.0local900027.8scheckingforETA?(0/4)[1m45.3s]+praisev1.0.0https://cran.r-project.org2000042.6scheckingwhet+praisev1.0.0local1900040.0scheckingRfi+praisev1.0.0https://cran.r-project.org900031.6scheckingfor+praisev1.0.0local900028.3scheckingforETA?(0/4)[1m45.8s]+praisev1.0.0https://cran.r-project.org2100043.0scheckingwhet+praisev1.0.0local1900040.5scheckingRfi+praisev1.0.0https://cran.r-project.org900032.1scheckingfor+praisev1.0.0local900028.8scheckingforETA?(0/4)[1m46.2s]+praisev1.0.0https://cran.r-project.org2100043.4scheckingwhet+praisev1.0.0local1900040.9scheckingRfi+praisev1.0.0https://cran.r-project.org900032.5scheckingfor+praisev1.0.0local900029.2scheckingforETA?(0/4)[1m46.7s]+praisev1.0.0https://cran.r-project.org2200043.9scheckingwhet+praisev1.0.0local1900041.4scheckingRfi+praisev1.0.0https://cran.r-project.org900032.9scheckingfor+praisev1.0.0local900029.6scheckingforETA?(0/4)[1m47.1s]+praisev1.0.0https://cran.r-project.org2200044.3scheckingwhet+praisev1.0.0local1900041.8scheckingRfi+praisev1.0.0https://cran.r-project.org900033.3scheckingfor+praisev1.0.0local900030.1scheckingforETA?(0/4)[1m47.5s]+praisev1.0.0https://cran.r-project.org2200044.7scheckingwhet+praisev1.0.0local1900042.2scheckingRfi+praisev1.0.0https://cran.r-project.org900033.8scheckingfor+praisev1.0.0local900030.5scheckingforETA?(0/4)[1m48s]+praisev1.0.0https://cran.r-project.org2200045.2scheckingwhet+praisev1.0.0local2000042.7scheckingwhet+praisev1.0.0https://cran.r-project.org900034.2scheckingfor+praisev1.0.0local900030.9scheckingforETA?(0/4)[1m48.4s]+praisev1.0.0https://cran.r-project.org2200045.6scheckingwhet+praisev1.0.0local2000043.1scheckingwhet+praisev1.0.0https://cran.r-project.org900034.7scheckingfor+praisev1.0.0local900031.4scheckingforETA?(0/4)[1m48.9s]+praisev1.0.0https://cran.r-project.org2300046.1scheckingwhet+praisev1.0.0local2100043.6scheckingwhet+praisev1.0.0https://cran.r-project.org900035.1scheckingfor+praisev1.0.0local900031.8scheckingforETA?(0/4)[1m49.3s]+praisev1.0.0https://cran.r-project.org2300046.6scheckingwhet+praisev1.0.0local2100044.1scheckingwhet+praisev1.0.0https://cran.r-project.org900035.6scheckingfor+praisev1.0.0local900032.4scheckingforETA?(0/4)[1m49.8s]+praisev1.0.0https://cran.r-project.org2400047.0scheckingwhet+praisev1.0.0local2100044.5scheckingwhet+praisev1.0.0https://cran.r-project.org900036.1scheckingfor+praisev1.0.0local900032.8scheckingforETA?(0/4)[1m50.2s]+praisev1.0.0https://cran.r-project.org2400047.5scheckingwhet+praisev1.0.0local2100044.9scheckingwhet+praisev1.0.0https://cran.r-project.org900036.5scheckingfor+praisev1.0.0local900033.2scheckingforETA?(0/4)[1m50.7s]+praisev1.0.0https://cran.r-project.org2400047.9scheckingwhet+praisev1.0.0local2200045.4scheckingwhet+praisev1.0.0https://cran.r-project.org900036.9scheckingfor+praisev1.0.0local900033.6scheckingforETA?(0/4)[1m51.1s]+praisev1.0.0https://cran.r-project.org2400048.4scheckingwhet+praisev1.0.0local2200045.9scheckingwhet+praisev1.0.0https://cran.r-project.org900037.4scheckingfor+praisev1.0.0local900034.1scheckingforETA?(0/4)[1m51.6s]+praisev1.0.0https://cran.r-project.org2500048.9scheckingload+praisev1.0.0local2200046.4scheckingwhet+praisev1.0.0https://cran.r-project.org900037.9scheckingfor+praisev1.0.0local900034.6scheckingforETA?(0/4)[1m52.1s]+praisev1.0.0https://cran.r-project.org2500049.3scheckingload+praisev1.0.0local2200046.8scheckingwhet+praisev1.0.0https://cran.r-project.org900038.4scheckingfor+praisev1.0.0local900035.1scheckingforETA?(0/4)[1m52.6s]+praisev1.0.0https://cran.r-project.org2500049.8scheckingload+praisev1.0.0local2300047.3scheckingwhet+praisev1.0.0https://cran.r-project.org900038.8scheckingfor+praisev1.0.0local900035.5scheckingforETA?(0/4)[1m53s]+praisev1.0.0https://cran.r-project.org2500050.3scheckingload+praisev1.0.0local2300047.8scheckingwhet+praisev1.0.0https://cran.r-project.org900039.3scheckingfor+praisev1.0.0local900036.0scheckingforETA?(0/4)[1m53.5s]+praisev1.0.0https://cran.r-project.org2500050.8scheckingload+praisev1.0.0local2300048.2scheckingwhet+praisev1.0.0https://cran.r-project.org900039.8scheckingfor+praisev1.0.0local900036.5scheckingforETA?(0/4)[1m54s]+praisev1.0.0https://cran.r-project.org2500051.4scheckingload+praisev1.0.0local2400048.9scheckingwhet+praisev1.0.0https://cran.r-project.org900040.3scheckingfor+praisev1.0.0local900037.0scheckingforETA?(0/4)[1m54.6s]+praisev1.0.0https://cran.r-project.org2600051.9scheckingdepe+praisev1.0.0local2400049.4scheckingwhet+praisev1.0.0https://cran.r-project.org900040.9scheckingfor+praisev1.0.0local900037.6scheckingforETA?(0/4)[1m55.2s]+praisev1.0.0https://cran.r-project.org2600052.5scheckingdepe+praisev1.0.0local2500049.9scheckingload+praisev1.0.0https://cran.r-project.org900041.4scheckingfor+praisev1.0.0local900038.2scheckingforETA?(0/4)[1m55.7s]+praisev1.0.0https://cran.r-project.org2600052.9scheckingdepe+praisev1.0.0local2500050.4scheckingload+praisev1.0.0https://cran.r-project.org900041.9s(30.4s)check+praisev1.0.0local900038.7scheckingforETA?(0/4)[1m56.1s]+praisev1.0.0https://cran.r-project.org2700053.4scheckingS3g+praisev1.0.0local2500050.9scheckingload+praisev1.0.0https://cran.r-project.org900042.4s(30.9s)check+praisev1.0.0local900039.1scheckingforETA?(0/4)[1m56.7s]+praisev1.0.0https://cran.r-project.org2700054.0scheckingS3g+praisev1.0.0local2500051.5scheckingload+praisev1.0.0https://cran.r-project.org900042.9s(31.4s)check+praisev1.0.0local900039.7scheckingforETA?(0/4)[1m57.2s]+praisev1.0.0https://cran.r-project.org2700054.5scheckingS3g+praisev1.0.0local2600052.0scheckingdepe+praisev1.0.0https://cran.r-project.org900043.5s(32.0s)check+praisev1.0.0local900040.2scheckingforETA?(0/4)[1m57.7s]+praisev1.0.0https://cran.r-project.org2700055.0scheckingS3g+praisev1.0.0local2600052.4scheckingdepe+praisev1.0.0https://cran.r-project.org900044.0s(32.5s)check+praisev1.0.0local900040.7scheckingforETA?(0/4)[1m58.2s]+praisev1.0.0https://cran.r-project.org2700055.4scheckingS3g+praisev1.0.0local2700052.9scheckingS3g+praisev1.0.0https://cran.r-project.org900044.4s(32.9s)check+praisev1.0.0local900041.2scheckingforETA?(0/4)[1m58.6s]+praisev1.0.0https://cran.r-project.org2700055.9scheckingS3g+praisev1.0.0local2700053.3scheckingS3g+praisev1.0.0https://cran.r-project.org900044.9s(33.4s)check+praisev1.0.0local900041.6scheckingforETA?(0/4)[1m59.1s]+praisev1.0.0https://cran.r-project.org2800056.3scheckingrepl+praisev1.0.0local2700053.8scheckingS3g+praisev1.0.0https://cran.r-project.org900045.3s(33.8s)check+praisev1.0.0local900042.0scheckingforETA?(0/4)[1m59.5s]+praisev1.0.0https://cran.r-project.org2800056.8scheckingrepl+praisev1.0.0local2700054.3scheckingS3g+praisev1.0.0https://cran.r-project.org900045.8s(34.3s)check+praisev1.0.0local900042.5scheckingforETA?(0/4)[2m0.1s]+praisev1.0.0https://cran.r-project.org2800057.3scheckingrepl+praisev1.0.0local2800054.7scheckingrepl+praisev1.0.0https://cran.r-project.org900046.3s(34.8s)check+praisev1.0.0local900043.0scheckingforETA?(0/4)[2m0.5s]+praisev1.0.0https://cran.r-project.org2800057.7scheckingrepl+praisev1.0.0local2800055.1scheckingrepl+praisev1.0.0https://cran.r-project.org900046.7s(35.2s)check+praisev1.0.0local900043.4scheckingforETA?(0/4)[2m0.8s]+praisev1.0.0https://cran.r-project.org2900058.1scheckingfore+praisev1.0.0local2900055.6scheckingfore+praisev1.0.0https://cran.r-project.org900047.1s(35.6s)check+praisev1.0.0local900043.8scheckingforETA?(0/4)[2m1.3s]+praisev1.0.0https://cran.r-project.org2900058.6scheckingfore+praisev1.0.0local2900056.0scheckingfore+praisev1.0.0https://cran.r-project.org900047.6s(36.0s)check+praisev1.0.0local900044.3scheckingforETA?(0/4)[2m1.8s]+praisev1.0.0https://cran.r-project.org2900059.0scheckingfore+praisev1.0.0local2900056.5scheckingfore+praisev1.0.0https://cran.r-project.org900048.0s(36.5s)check+praisev1.0.0local900044.8scheckingforETA?(0/4)[2m2.3s]+praisev1.0.0https://cran.r-project.org2900059.6scheckingfore+praisev1.0.0local2900057.1scheckingfore+praisev1.0.0https://cran.r-project.org900048.5s(37.0s)check+praisev1.0.0local900045.3scheckingforETA?(0/4)[2m2.8s]+praisev1.0.0https://cran.r-project.org290001.0mcheckingforei+praisev1.0.0local2900057.6scheckingfore+praisev1.0.0https://cran.r-project.org900049.1s(37.6s)check+praisev1.0.0local900045.9s(30.5s)checkETA?(0/4)[2m3.3s]+praisev1.0.0https://cran.r-project.org290001.0mcheckingforei+praisev1.0.0local2900058.0scheckingfore+praisev1.0.0https://cran.r-project.org900049.6s(38.1s)check+praisev1.0.0local900046.3s(30.9s)checkETA?(0/4)[2m3.8s]+praisev1.0.0https://cran.r-project.org290001.0mcheckingforei+praisev1.0.0local2900058.5scheckingfore+praisev1.0.0https://cran.r-project.org900050.1s(38.5s)check+praisev1.0.0local900046.8s(31.4s)checkETA?(0/4)[2m4.3s]+praisev1.0.0https://cran.r-project.org290001.0mcheckingforei+praisev1.0.0local2900059.0scheckingfore+praisev1.0.0https://cran.r-project.org900050.5s(39.0s)check+praisev1.0.0local900047.3s(31.9s)checkETA?(0/4)[2m4.7s]+praisev1.0.0local2900059.5scheckingfore+praisev1.0.0https://cran.r-project.org900051.0s(39.5s)check+praisev1.0.0local900047.7s(32.3s)checkETA?(0/4)[2m5.2s]+praisev1.0.0local300001.0mcheckingRcod+praisev1.0.0https://cran.r-project.org900051.5s(40.0s)check+praisev1.0.0local900048.2s(32.9s)checkETA?(0/4)[2m5.8s]+praisev1.0.0https://cran.r-project.org290001.1mcheckingforei+praisev1.0.0local320001.0mcheckingRdme+praisev1.0.0https://cran.r-project.org900052.1s(40.5s)check+praisev1.0.0local900048.8s(33.4s)checkETA?(0/4)[2m6.3s]+praisev1.0.0https://cran.r-project.org290001.1mcheckingforei+praisev1.0.0local320001.0mcheckingRdme+praisev1.0.0https://cran.r-project.org900052.6s(41.1s)check+praisev1.0.0local900049.3s(33.9s)checkETA?(0/4)[2m6.8s]+praisev1.0.0https://cran.r-project.org290001.1mcheckingforei+praisev1.0.0local330001.0mcheckingform+praisev1.0.0https://cran.r-project.org900053.0s(41.5s)check+praisev1.0.0local900049.7s(34.3s)checkETA?(0/4)[2m7.2s]+praisev1.0.0https://cran.r-project.org290001.1mcheckingforei+praisev1.0.0local330001.0mcheckingform+praisev1.0.0https://cran.r-project.org900053.4s(41.9s)check+praisev1.0.0local900050.1s(34.7s)checkETA?(0/4)[2m7.5s]+praisev1.0.0local330001.0mcheckingform+praisev1.0.0https://cran.r-project.org900053.8s(42.3s)check+praisev1.0.0local900050.5s(35.1s)checkETA?(0/4)[2m7.9s]+praisev1.0.0local330001.0mcheckingform+praisev1.0.0https://cran.r-project.org900054.2s(42.6s)check+praisev1.0.0local900050.9s(35.5s)checkETA?(0/4)[2m8.3s]+praisev1.0.0local330001.1mcheckingform+praisev1.0.0https://cran.r-project.org900054.6s(43.1s)check+praisev1.0.0local900051.3s(36.0s)checkETA?(0/4)[2m8.8s]+praisev1.0.0local330001.1mcheckingform+praisev1.0.0https://cran.r-project.org900055.1s(43.6s)check+praisev1.0.0local900051.8s(36.4s)checkETA?(0/4)[2m9.2s]+praisev1.0.0local330001.1mcheckingform+praisev1.0.0https://cran.r-project.org900055.5s(44.0s)check+praisev1.0.0local900052.2s(36.8s)checkETA?(0/4)[2m9.7s]+praisev1.0.0local330001.1mcheckingform+praisev1.0.0https://cran.r-project.org900055.9s(44.4s)check+praisev1.0.0local900052.7s(37.3s)checkETA?(0/4)[2m10.1s]+praisev1.0.0https://cran.r-project.org900056.4s(44.9s)check+praisev1.0.0local900053.1s(37.7s)checkETA?(0/4)[2m10.5s]+praisev1.0.0https://cran.r-project.org900056.8s(45.2s)check+praisev1.0.0local900053.5s(38.1s)checkETA?(0/4)[2m10.9s]+praisev1.0.0https://cran.r-project.org900057.2s(45.6s)check+praisev1.0.0local900053.9s(38.5s)checkETA?(0/4)[2m11.3s]+praisev1.0.0https://cran.r-project.org900057.6s(46.1s)check+praisev1.0.0local900054.3s(38.9s)checkETA?(0/4)[2m11.8s]+praisev1.0.0https://cran.r-project.org900058.1s(46.5s)check+praisev1.0.0local900054.8s(39.4s)checkETA?(0/4)[2m12.2s]+praisev1.0.0https://cran.r-project.org290001.2mcheckingforei+praisev1.0.0https://cran.r-project.org900058.4s(46.9s)check+praisev1.0.0local900055.1s(39.7s)checkETA?(0/4)[2m12.6s]+praisev1.0.0https://cran.r-project.org290001.2mcheckingforei+praisev1.0.0https://cran.r-project.org900058.8s(47.3s)check+praisev1.0.0local900055.5s(40.1s)checkETA?(0/4)[2m13s]+praisev1.0.0https://cran.r-project.org300001.2mcheckingRcod+praisev1.0.0https://cran.r-project.org900059.3s(47.7s)check+praisev1.0.0local900056.0s(40.6s)checkETA?(0/4)[2m13.5s]+praisev1.0.0https://cran.r-project.org310001.2mcheckingRdfi+praisev1.0.0https://cran.r-project.org1200059.7scheckingpack+praisev1.0.0local900056.5s(41.1s)checkETA?(0/4)[2m14s]+praisev1.0.0https://cran.r-project.org320001.2mcheckingRdme+praisev1.0.0https://cran.r-project.org120001.0mcheckingpacka+praisev1.0.0local900057.0s(41.6s)checkETA?(0/4)[2m14.5s]+praisev1.0.0https://cran.r-project.org320001.2mcheckingRdme+praisev1.0.0local330001.2mcheckingform+praisev1.0.0https://cran.r-project.org120001.0mcheckingpacka+praisev1.0.0local900057.5s(42.1s)checkETA?(0/4)[2m15.1s]+praisev1.0.0https://cran.r-project.org320001.2mcheckingRdme+praisev1.0.0local330001.2mcheckingform+praisev1.0.0https://cran.r-project.org150001.0mcheckingforl+praisev1.0.0local900058.1s(42.7s)checkETA?(0/4)[2m15.7s]+praisev1.0.0https://cran.r-project.org330001.2mcheckingform+praisev1.0.0local330001.2mcheckingform+praisev1.0.0https://cran.r-project.org150001.0mcheckingforl+praisev1.0.0local900058.6s(43.2s)checkETA?(0/4)[2m16.1s]+praisev1.0.0https://cran.r-project.org330001.2mcheckingform+praisev1.0.0local340001.2mcheckingforc+praisev1.0.0https://cran.r-project.org160001.0mcheckingindex+praisev1.0.0local900059.0s(43.6s)checkETA?(0/4)[2m16.5s]+praisev1.0.0https://cran.r-project.org330001.2mcheckingform+praisev1.0.0local340001.2mcheckingforc+praisev1.0.0https://cran.r-project.org160001.0mcheckingindex+praisev1.0.0local900059.4s(44.1s)checkETA?(0/4)[2m16.9s]+praisev1.0.0https://cran.r-project.org330001.2mcheckingform+praisev1.0.0local340001.2mcheckingforc+praisev1.0.0https://cran.r-project.org160001.1mcheckingindex+praisev1.0.0local900059.8s(44.5s)checkETA?(0/4)[2m17.3s]+praisev1.0.0local340001.2mcheckingforc+praisev1.0.0https://cran.r-project.org160001.1mcheckingindex+praisev1.0.0local90001.0m(44.8s)checkiETA?(0/4)[2m17.7s]+praisev1.0.0https://cran.r-project.org160001.1mcheckingindex+praisev1.0.0local90001.0m(45.3s)checkiETA?(0/4)[2m18.1s]+praisev1.0.0https://cran.r-project.org330001.3mcheckingform+praisev1.0.0https://cran.r-project.org160001.1mcheckingindex+praisev1.0.0local120001.0mcheckingpackaETA?(0/4)[2m18.4s]+praisev1.0.0https://cran.r-project.org330001.3mcheckingform+praisev1.0.0local120001.0mcheckingpackaETA?(0/4)[2m18.8s]+praisev1.0.0https://cran.r-project.org330001.3mcheckingform+praisev1.0.0local120001.0mcheckingpackaETA?(0/4)[2m19.2s]+praisev1.0.0https://cran.r-project.org330001.3mcheckingform+praisev1.0.0local120001.0mcheckingpackaETA?(0/4)[2m19.6s]+praisev1.0.0https://cran.r-project.org170001.1mcheckingpackaETA?(0/4)[2m20s]+praisev1.0.0https://cran.r-project.org190001.1mcheckingRfil+praisev1.0.0local150001.1mcheckingforlETA?(0/4)[2m20.5s]+praisev1.0.0local340001.3mcheckingforc+praisev1.0.0https://cran.r-project.org190001.1mcheckingRfil+praisev1.0.0local150001.1mcheckingforlETA?(0/4)[2m20.9s]+praisev1.0.0local360001.3mcheckingRdco+praisev1.0.0https://cran.r-project.org190001.1mcheckingRfil+praisev1.0.0local150001.1mcheckingforlETA?(0/4)[2m21.4s]+praisev1.0.0local370001.3mcheckingforu+praisev1.0.0https://cran.r-project.org190001.1mcheckingRfil+praisev1.0.0local150001.1mcheckingforlETA?(0/4)[2m21.8s]+praisev1.0.0local370001.3mcheckingforu+praisev1.0.0local160001.1mcheckingindexETA?(0/4)[2m22.2s]+praisev1.0.0local390001.3mcheckingfiles+praisev1.0.0https://cran.r-project.org200001.1mcheckingwheth+praisev1.0.0local160001.1mcheckingindexETA?(0/4)[2m22.6s]+praisev1.0.0https://cran.r-project.org340001.3mcheckingforc+praisev1.0.0local390001.3mcheckingfiles+praisev1.0.0https://cran.r-project.org200001.1mcheckingwheth+praisev1.0.0local160001.1mcheckingindexETA?(0/4)[2m23s]+praisev1.0.0https://cran.r-project.org340001.3mcheckingforc+praisev1.0.0local390001.3mcheckingfiles+praisev1.0.0https://cran.r-project.org200001.2mcheckingwheth+praisev1.0.0local160001.1mcheckingindexETA?(0/4)[2m23.4s]+praisev1.0.0https://cran.r-project.org340001.3mcheckingforc+praisev1.0.0local390001.3mcheckingfiles+praisev1.0.0https://cran.r-project.org200001.2mcheckingwhethETA?(0/4)[2m23.8s]+praisev1.0.0https://cran.r-project.org340001.4mcheckingforc+praisev1.0.0https://cran.r-project.org210001.2mcheckingwhethETA?(0/4)[2m24.2s]+praisev1.0.0https://cran.r-project.org360001.4mcheckingRdco+praisev1.0.0https://cran.r-project.org210001.2mcheckingwhethETA?(0/4)[2m24.6s]+praisev1.0.0https://cran.r-project.org370001.4mcheckingforu+praisev1.0.0https://cran.r-project.org210001.2mcheckingwhethETA?(0/4)[2m25.1s]+praisev1.0.0https://cran.r-project.org370001.4mcheckingforu+praisev1.0.0local410001.3mcheckingforu+praisev1.0.0https://cran.r-project.org210001.2mcheckingwhethETA?(0/4)[2m25.5s]+praisev1.0.0https://cran.r-project.org370001.4mcheckingforu+praisev1.0.0local410001.3mcheckingforu+praisev1.0.0https://cran.r-project.org220001.2mcheckingwhethETA?(0/4)[2m25.9s]+praisev1.0.0https://cran.r-project.org370001.4mcheckingforu+praisev1.0.0local410001.3mcheckingforu+praisev1.0.0https://cran.r-project.org220001.2mcheckingwhethETA?(0/4)[2m26.3s]+praisev1.0.0local410001.3mcheckingforu+praisev1.0.0https://cran.r-project.org220001.2mcheckingwheth+praisev1.0.0local160001.2mcheckingindexETA?(0/4)[2m26.7s]+praisev1.0.0local410001.4mcheckingtests+praisev1.0.0https://cran.r-project.org220001.2mcheckingwheth+praisev1.0.0local160001.2mcheckingindexETA?(0/4)[2m27.1s]+praisev1.0.0local410001.4mcheckingtests+praisev1.0.0local160001.2mcheckingindexETA?(0/4)[2m27.5s]+praisev1.0.0https://cran.r-project.org390001.4mcheckingfiles+praisev1.0.0local410001.4mcheckingtests+praisev1.0.0https://cran.r-project.org230001.2mcheckingwheth+praisev1.0.0local160001.2mcheckingindexETA?(0/4)[2m28s]+praisev1.0.0https://cran.r-project.org390001.4mcheckingfiles+praisev1.0.0local410001.4mcheckingtests+praisev1.0.0https://cran.r-project.org230001.2mcheckingwhethETA?(0/4)[2m28.5s]+praisev1.0.0https://cran.r-project.org390001.4mcheckingfiles+praisev1.0.0https://cran.r-project.org240001.2mcheckingwhethETA?(0/4)[2m29s]+praisev1.0.0https://cran.r-project.org390001.4mcheckingfiles+praisev1.0.0https://cran.r-project.org250001.3mcheckingloadiETA?(0/4)[2m29.5s]+praisev1.0.0https://cran.r-project.org250001.3mcheckingloadiETA?(0/4)[2m29.9s]+praisev1.0.0https://cran.r-project.org390001.5mcheckingfiles+praisev1.0.0https://cran.r-project.org250001.3mcheckingloadiETA?(0/4)[2m30.2s]+praisev1.0.0https://cran.r-project.org390001.5mcheckingfiles+praisev1.0.0https://cran.r-project.org250001.3mcheckingloadiETA?(0/4)[2m30.6s]+praisev1.0.0https://cran.r-project.org390001.5mcheckingfilesETA?(0/4)[2m31s]+praisev1.0.0https://cran.r-project.org390001.5mcheckingfiles+praisev1.0.0https://cran.r-project.org260001.3mcheckingwhethETA?(0/4)[2m31.4s]+praisev1.0.0https://cran.r-project.org260001.3mcheckingwheth+praisev1.0.0local170001.2mcheckingpackaETA?(0/4)[2m31.9s]+praisev1.0.0https://cran.r-project.org260001.3mcheckingwheth+praisev1.0.0local180001.2mcheckingcodeETA?(0/4)[2m32.3s]+praisev1.0.0https://cran.r-project.org260001.3mcheckingwheth+praisev1.0.0local180001.3mcheckingcodeETA?(0/4)[2m32.7s]+praisev1.0.0local410001.5mcheckingtests+praisev1.0.0local190001.3mcheckingRfilETA?(0/4)[2m33.1s]+praisev1.0.0local410001.5mcheckingtests+praisev1.0.0local190001.3mcheckingRfilETA?(0/4)[2m33.5s]+praisev1.0.0local410001.5mcheckingtests+praisev1.0.0local190001.3mcheckingRfilETA?(0/4)[2m33.8s]+praisev1.0.0local410001.5mcheckingtests+praisev1.0.0local190001.3mcheckingRfilETA?(0/4)[2m34.3s]ETA?(0/4)[2m34.7s]+praisev1.0.0https://cran.r-project.org400001.5mcheckingexampETA?(0/4)[2m35.2s]+praisev1.0.0https://cran.r-project.org400001.5mcheckingexamp+praisev1.0.0https://cran.r-project.org260001.4mcheckingwhethETA?(0/4)[2m35.7s]+praisev1.0.0https://cran.r-project.org400001.6mcheckingexamp+praisev1.0.0https://cran.r-project.org260001.4mcheckingwhethETA?(0/4)[2m36.3s]+praisev1.0.0https://cran.r-project.org400001.6mcheckingexamp+praisev1.0.0https://cran.r-project.org260001.4mcheckingwhethETA?(0/4)[2m36.7s]+praisev1.0.0https://cran.r-project.org410001.6mcheckingforu+praisev1.0.0https://cran.r-project.org260001.4mcheckingwhethETA?(0/4)[2m37.1s]+praisev1.0.0https://cran.r-project.org410001.6mcheckingforuETA?(0/4)[2m37.6s]+praisev1.0.0https://cran.r-project.org410001.6mcheckingforuETA?(0/4)[2m38s]+praisev1.0.0https://cran.r-project.org410001.6mcheckingtests+praisev1.0.0local190001.4mcheckingRfilETA?(0/4)[2m38.5s]+praisev1.0.0https://cran.r-project.org410001.6mcheckingtests+praisev1.0.0local410001.6mcheckingtests+praisev1.0.0local190001.4mcheckingRfilETA?(0/4)[2m39.1s]+praisev1.0.0https://cran.r-project.org410001.6mcheckingtests+praisev1.0.0local410001.6mcheckingtests+praisev1.0.0https://cran.r-project.org270001.4mcheckingdepen+praisev1.0.0local190001.4mcheckingRfilETA?(0/4)[2m39.6s]+praisev1.0.0https://cran.r-project.org410001.6mcheckingtests+praisev1.0.0local410001.6mcheckingtests+praisev1.0.0https://cran.r-project.org270001.4mcheckingdepen+praisev1.0.0local200001.4mcheckingwhethETA?(0/4)[2m40.2s]+praisev1.0.0local410001.6mcheckingtests+praisev1.0.0https://cran.r-project.org270001.4mcheckingdepen+praisev1.0.0local200001.4mcheckingwhethETA?(0/4)[2m40.7s]+praisev1.0.0https://cran.r-project.org270001.4mcheckingdepen+praisev1.0.0local200001.4mcheckingwhethETA?(0/4)[2m41.2s]+praisev1.0.0https://cran.r-project.org280001.5mcheckingS3ge+praisev1.0.0local200001.4mcheckingwhethETA?(0/4)[2m41.7s]+praisev1.0.0https://cran.r-project.org280001.5mcheckingS3ge+praisev1.0.0local210001.4mcheckingwhethETA?(0/4)[2m42.2s]+praisev1.0.0https://cran.r-project.org410001.7mcheckingtests+praisev1.0.0https://cran.r-project.org280001.5mcheckingS3ge+praisev1.0.0local210001.4mcheckingwhethETA?(0/4)[2m42.7s]+praisev1.0.0https://cran.r-project.org410001.7mcheckingtests+praisev1.0.0https://cran.r-project.org280001.5mcheckingS3ge+praisev1.0.0local210001.4mcheckingwhethETA?(0/4)[2m43.1s]+praisev1.0.0https://cran.r-project.org410001.7mcheckingtests+praisev1.0.0local220001.4mcheckingwhethETA?(0/4)[2m43.7s]+praisev1.0.0https://cran.r-project.org410001.7mcheckingtests+praisev1.0.0https://cran.r-project.org290001.5mcheckingrepla+praisev1.0.0local220001.4mcheckingwhethETA?(0/4)[2m44.2s]+praisev1.0.0local410001.7mcheckingtests+praisev1.0.0https://cran.r-project.org290001.5mcheckingrepla+praisev1.0.0local220001.5mcheckingwhethETA?(0/4)[2m44.7s]+praisev1.0.0local410001.7mcheckingtests+praisev1.0.0https://cran.r-project.org290001.5mcheckingrepla+praisev1.0.0local230001.5mcheckingwhethETA?(0/4)[2m45.2s]+praisev1.0.0local420001.7mcheckingtests+praisev1.0.0https://cran.r-project.org290001.5mcheckingrepla+praisev1.0.0local240001.5mcheckingwhethETA?(0/4)[2m45.8s]+praisev1.0.0local420001.7m+praisev1.0.0local240001.5mcheckingwhethETA?(0/4)[2m46.2s]+praisev1.0.0local240001.5mcheckingwhethETA8m(1/4)[2m46.7s]+praisev1.0.0local240001.5mcheckingwhethETA8m(1/4)[2m47.1s]+praisev1.0.0https://cran.r-project.org290001.6mcheckingreplaETA8m(1/4)[2m47.5s]+praisev1.0.0https://cran.r-project.org290001.6mcheckingrepla+praisev1.0.0local250001.5mcheckingloadiETA8m(1/4)[2m47.9s]+praisev1.0.0https://cran.r-project.org410001.8mcheckingtests+praisev1.0.0https://cran.r-project.org290001.6mcheckingrepla+praisev1.0.0local250001.5mcheckingloadiETA8m(1/4)[2m48.4s]+praisev1.0.0https://cran.r-project.org410001.8mcheckingtests+praisev1.0.0https://cran.r-project.org290001.6mcheckingrepla+praisev1.0.0local250001.5mcheckingloadiETA8m(1/4)[2m48.8s]+praisev1.0.0https://cran.r-project.org410001.8mcheckingtests+praisev1.0.0local250001.5mcheckingloadiETA8m(1/4)[2m49.2s]+praisev1.0.0https://cran.r-project.org410001.8mcheckingtests+praisev1.0.0https://cran.r-project.org300001.6mcheckingforeiETA8m(1/4)[2m49.7s]+praisev1.0.0https://cran.r-project.org300001.6mcheckingforeiETA9m(1/4)[2m50s]+praisev1.0.0https://cran.r-project.org300001.6mcheckingforei+praisev1.0.0local250001.6mcheckingloadiETA9m(1/4)[2m50.5s]+praisev1.0.0https://cran.r-project.org300001.6mcheckingforei+praisev1.0.0local250001.6mcheckingloadiETA9m(1/4)[2m50.9s]+praisev1.0.0local250001.6mcheckingloadiETA9m(1/4)[2m51.3s]+praisev1.0.0local250001.6mcheckingloadiETA9m(1/4)[2m51.7s]ETA9m(1/4)[2m52.1s]ETA9m(1/4)[2m52.6s]ETA9m(1/4)[2m53s]+praisev1.0.0https://cran.r-project.org300001.7mcheckingforeiETA9m(1/4)[2m53.4s]+praisev1.0.0https://cran.r-project.org420001.8mcheckingtests+praisev1.0.0https://cran.r-project.org300001.7mcheckingforeiETA9m(1/4)[2m53.9s]+praisev1.0.0https://cran.r-project.org420001.9mcheckingtests+praisev1.0.0https://cran.r-project.org300001.7mcheckingforeiETA9m(1/4)[2m54.3s]+praisev1.0.0https://cran.r-project.org420001.9m+praisev1.0.0https://cran.r-project.org300001.7mcheckingforeiETA3m(2/4)[2m54.9s]ETA3m(2/4)[2m55.1s]ETA3m(2/4)[2m55.3s]ETA3m(2/4)[2m55.5s]ETA3m(2/4)[2m55.8s]ETA3m(2/4)[2m56s]ETA3m(2/4)[2m56.2s]+praisev1.0.0local250001.7mcheckingloadiETA3m(2/4)[2m56.4s]+praisev1.0.0local250001.7mcheckingloadiETA3m(2/4)[2m56.6s]+praisev1.0.0local250001.7mcheckingloadiETA3m(2/4)[2m56.8s]+praisev1.0.0local250001.7mcheckingloadiETA3m(2/4)[2m57s]ETA3m(2/4)[2m57.2s]ETA3m(2/4)[2m57.4s]ETA3m(2/4)[2m57.8s]ETA3m(2/4)[2m58s]ETA3m(2/4)[2m58.2s]ETA3m(2/4)[2m58.4s]ETA3m(2/4)[2m58.6s]+praisev1.0.0local260001.7mcheckingwhethETA3m(2/4)[2m59s]+praisev1.0.0https://cran.r-project.org300001.8mcheckingforei+praisev1.0.0local260001.7mcheckingwhethETA3m(2/4)[2m59.1s]+praisev1.0.0https://cran.r-project.org300001.8mcheckingforei+praisev1.0.0local260001.7mcheckingwhethETA3m(2/4)[2m59.3s]+praisev1.0.0https://cran.r-project.org300001.8mcheckingforei+praisev1.0.0local260001.7mcheckingwhethETA3m(2/4)[2m59.5s]+praisev1.0.0https://cran.r-project.org300001.8mcheckingforeiETA3m(2/4)[2m59.7s]ETA3m(2/4)[2m59.9s]ETA3m(2/4)[3m0.1s]ETA3m(2/4)[3m0.5s]+praisev1.0.0https://cran.r-project.org310001.8mcheckingRcodETA3m(2/4)[3m0.7s]+praisev1.0.0https://cran.r-project.org310001.8mcheckingRcodETA3m(2/4)[3m0.9s]+praisev1.0.0https://cran.r-project.org310001.8mcheckingRcodETA3m(2/4)[3m1.2s]+praisev1.0.0https://cran.r-project.org310001.8mcheckingRcodETA3m(2/4)[3m1.4s]+praisev1.0.0https://cran.r-project.org330001.8mcheckingRdmeETA3m(2/4)[3m1.6s]+praisev1.0.0https://cran.r-project.org330001.8mcheckingRdmeETA3m(2/4)[3m1.8s]+praisev1.0.0https://cran.r-project.org330001.8mcheckingRdmeETA3m(2/4)[3m2s]+praisev1.0.0https://cran.r-project.org330001.8mcheckingRdmeETA3m(2/4)[3m2.2s]+praisev1.0.0local260001.8mcheckingwhethETA3m(2/4)[3m2.4s]+praisev1.0.0local260001.8mcheckingwhethETA3m(2/4)[3m2.6s]+praisev1.0.0local260001.8mcheckingwhethETA3m(2/4)[3m2.8s]+praisev1.0.0local260001.8mcheckingwhethETA3m(2/4)[3m3s]ETA3m(2/4)[3m3.2s]+praisev1.0.0local270001.8mcheckingdepenETA3m(2/4)[3m3.4s]+praisev1.0.0local270001.8mcheckingdepenETA3m(2/4)[3m3.6s]+praisev1.0.0local270001.8mcheckingdepenETA3m(2/4)[3m3.8s]+praisev1.0.0local270001.8mcheckingdepenETA3m(2/4)[3m4s]ETA3m(2/4)[3m4.2s]+praisev1.0.0local280001.8mcheckingS3geETA3m(2/4)[3m4.4s]+praisev1.0.0local280001.8mcheckingS3geETA3m(2/4)[3m4.7s]+praisev1.0.0local280001.8mcheckingS3geETA3m(2/4)[3m4.9s]+praisev1.0.0https://cran.r-project.org330001.9mcheckingRdme+praisev1.0.0local280001.8mcheckingS3geETA3m(2/4)[3m5.1s]+praisev1.0.0https://cran.r-project.org340001.9mcheckingformETA3m(2/4)[3m5.4s]+praisev1.0.0https://cran.r-project.org340001.9mcheckingformETA3m(2/4)[3m5.6s]+praisev1.0.0https://cran.r-project.org340001.9mcheckingformETA3m(2/4)[3m5.9s]+praisev1.0.0https://cran.r-project.org340001.9mcheckingformETA3m(2/4)[3m6.1s]ETA3m(2/4)[3m6.4s]ETA3m(2/4)[3m6.6s]+praisev1.0.0local290001.8mcheckingreplaETA3m(2/4)[3m6.9s]+praisev1.0.0local290001.8mcheckingreplaETA3m(2/4)[3m7.1s]+praisev1.0.0local290001.8mcheckingreplaETA3m(2/4)[3m7.3s]+praisev1.0.0local290001.8mcheckingreplaETA3m(2/4)[3m7.5s]ETA3m(2/4)[3m7.8s]ETA3m(2/4)[3m8s]ETA3m(2/4)[3m8.2s]+praisev1.0.0local300001.9mcheckingforeiETA3m(2/4)[3m8.4s]+praisev1.0.0local300001.9mcheckingforeiETA3m(2/4)[3m8.7s]+praisev1.0.0local300001.9mcheckingforeiETA3m(2/4)[3m8.9s]+praisev1.0.0local300001.9mcheckingforeiETA3m(2/4)[3m9.1s]ETA3m(2/4)[3m9.3s]ETA3m(2/4)[3m9.5s]ETA3m(2/4)[3m10s]ETA3m(2/4)[3m10.2s]ETA3m(2/4)[3m10.4s]ETA3m(2/4)[3m10.7s]ETA3m(2/4)[3m10.9s]+praisev1.0.0https://cran.r-project.org340002.0mcheckingformETA3m(2/4)[3m11.1s]+praisev1.0.0https://cran.r-project.org340002.0mcheckingformETA3m(2/4)[3m11.3s]+praisev1.0.0https://cran.r-project.org340002.0mcheckingformETA3m(2/4)[3m11.5s]+praisev1.0.0https://cran.r-project.org340002.0mcheckingformETA3m(2/4)[3m11.7s]ETA3m(2/4)[3m11.9s]ETA3m(2/4)[3m12.1s]ETA3m(2/4)[3m12.4s]ETA3m(2/4)[3m12.6s]ETA3m(2/4)[3m12.8s]ETA3m(2/4)[3m13s]ETA3m(2/4)[3m13.2s]ETA3m(2/4)[3m13.4s]ETA3m(2/4)[3m13.6s]ETA3m(2/4)[3m13.8s]ETA3m(2/4)[3m14s]ETA3m(2/4)[3m14.2s]+praisev1.0.0local300002.0mcheckingforeiETA3m(2/4)[3m14.4s]+praisev1.0.0local300002.0mcheckingforeiETA3m(2/4)[3m14.7s]+praisev1.0.0local300002.0mcheckingforeiETA3m(2/4)[3m14.9s]+praisev1.0.0local300002.0mcheckingforeiETA3m(2/4)[3m15.1s]ETA3m(2/4)[3m15.3s]ETA3m(2/4)[3m15.5s]ETA3m(2/4)[3m15.7s]ETA3m(2/4)[3m15.9s]ETA3m(2/4)[3m16.2s]+praisev1.0.0https://cran.r-project.org350002.0mcheckingforcETA3m(2/4)[3m16.4s]+praisev1.0.0https://cran.r-project.org350002.0mcheckingforcETA3m(2/4)[3m16.6s]+praisev1.0.0https://cran.r-project.org350002.0mcheckingforcETA3m(2/4)[3m16.8s]+praisev1.0.0https://cran.r-project.org350002.1mcheckingforcETA3m(2/4)[3m17s]+praisev1.0.0https://cran.r-project.org350002.1mcheckingforcETA3m(2/4)[3m17.2s]+praisev1.0.0https://cran.r-project.org350002.1mcheckingforc+praisev1.0.0local310002.0mcheckingRcodETA3m(2/4)[3m17.5s]+praisev1.0.0https://cran.r-project.org350002.1mcheckingforc+praisev1.0.0local310002.0mcheckingRcodETA3m(2/4)[3m17.7s]+praisev1.0.0https://cran.r-project.org360002.1mcheckingRd\u+praisev1.0.0local310002.0mcheckingRcodETA3m(2/4)[3m18s]+praisev1.0.0https://cran.r-project.org370002.1mcheckingRdco+praisev1.0.0local310002.0mcheckingRcodETA3m(2/4)[3m18.3s]+praisev1.0.0https://cran.r-project.org370002.1mcheckingRdco+praisev1.0.0local320002.0mcheckingRdfiETA3m(2/4)[3m18.6s]+praisev1.0.0https://cran.r-project.org400002.1mcheckingline+praisev1.0.0local330002.0mcheckingRdmeETA3m(2/4)[3m18.9s]+praisev1.0.0https://cran.r-project.org440002.1mcheckinguseo+praisev1.0.0local330002.0mcheckingRdmeETA3m(2/4)[3m19.2s]+praisev1.0.0https://cran.r-project.org440002.1mcheckinguseo+praisev1.0.0local330002.0mcheckingRdmeETA3m(2/4)[3m19.5s]+praisev1.0.0https://cran.r-project.org450002.1mcheckingcompi+praisev1.0.0local340002.0mcheckingformETA3m(2/4)[3m19.7s]+praisev1.0.0https://cran.r-project.org450002.1mcheckingcompi+praisev1.0.0local340002.0mcheckingformETA3m(2/4)[3m20s]+praisev1.0.0https://cran.r-project.org450002.1mcheckingcompi+praisev1.0.0local340002.0mcheckingformETA3m(2/4)[3m20.2s]+praisev1.0.0https://cran.r-project.org450002.1mcheckingcompi+praisev1.0.0local340002.1mcheckingformETA3m(2/4)[3m20.4s]+praisev1.0.0local340002.1mcheckingformETA3m(2/4)[3m20.7s]+praisev1.0.0local340002.1mcheckingformETA3m(2/4)[3m20.9s]+praisev1.0.0local340002.1mcheckingformETA3m(2/4)[3m21.1s]+praisev1.0.0https://cran.r-project.org470002.1mcheckingfilesETA3m(2/4)[3m21.3s]+praisev1.0.0https://cran.r-project.org470002.1mcheckingfilesETA3m(2/4)[3m21.6s]+praisev1.0.0https://cran.r-project.org470002.1mcheckingfilesETA3m(2/4)[3m21.8s]+praisev1.0.0https://cran.r-project.org470002.1mcheckingfilesETA3m(2/4)[3m22s]ETA3m(2/4)[3m22.2s]ETA3m(2/4)[3m22.4s]ETA3m(2/4)[3m22.7s]+praisev1.0.0https://cran.r-project.org470002.2mcheckingfilesETA3m(2/4)[3m23s]+praisev1.0.0https://cran.r-project.org470002.2mcheckingfilesETA3m(2/4)[3m23.2s]+praisev1.0.0https://cran.r-project.org470002.2mcheckingfilesETA3m(2/4)[3m23.4s]+praisev1.0.0https://cran.r-project.org470002.2mcheckingfilesETA3m(2/4)[3m23.6s]+praisev1.0.0local350002.1mcheckingforcETA3m(2/4)[3m23.8s]+praisev1.0.0local350002.1mcheckingforcETA3m(2/4)[3m24.1s]+praisev1.0.0local350002.1mcheckingforcETA3m(2/4)[3m24.3s]+praisev1.0.0local350002.1mcheckingforcETA3m(2/4)[3m24.6s]ETA3m(2/4)[3m24.8s]ETA3m(2/4)[3m25s]ETA3m(2/4)[3m25.2s]+praisev1.0.0local360002.1mcheckingRd\uETA3m(2/4)[3m25.5s]+praisev1.0.0local360002.1mcheckingRd\uETA3m(2/4)[3m25.7s]+praisev1.0.0local370002.1mcheckingRdcoETA3m(2/4)[3m25.9s]+praisev1.0.0local370002.1mcheckingRdcoETA3m(2/4)[3m26.2s]+praisev1.0.0local400002.2mcheckinglineETA3m(2/4)[3m26.4s]+praisev1.0.0local440002.2mcheckinguseoETA3m(2/4)[3m26.7s]+praisev1.0.0local450002.2mcheckingcompiETA3m(2/4)[3m26.9s]+praisev1.0.0https://cran.r-project.org490002.2mcheckingforu+praisev1.0.0local450002.2mcheckingcompiETA3m(2/4)[3m27.2s]+praisev1.0.0https://cran.r-project.org490002.2mcheckingforu+praisev1.0.0local450002.2mcheckingcompiETA3m(2/4)[3m27.5s]+praisev1.0.0https://cran.r-project.org490002.2mcheckingforu+praisev1.0.0local470002.2mcheckingfilesETA3m(2/4)[3m27.7s]+praisev1.0.0https://cran.r-project.org490002.2mcheckingforu+praisev1.0.0local470002.2mcheckingfilesETA3m(2/4)[3m27.9s]+praisev1.0.0local470002.2mcheckingfilesETA3m(2/4)[3m28.1s]+praisev1.0.0local470002.2mcheckingfilesETA3m(2/4)[3m28.3s]ETA3m(2/4)[3m28.5s]ETA3m(2/4)[3m28.7s]ETA3m(2/4)[3m29s]+praisev1.0.0https://cran.r-project.org490002.3mcheckingforuETA3m(2/4)[3m29.2s]+praisev1.0.0https://cran.r-project.org490002.3mcheckingforuETA3m(2/4)[3m29.4s]+praisev1.0.0https://cran.r-project.org490002.3mcheckingforuETA3m(2/4)[3m29.7s]+praisev1.0.0https://cran.r-project.org490002.3mcheckingforuETA3m(2/4)[3m29.9s]ETA4m(2/4)[3m30.2s]ETA4m(2/4)[3m30.4s]+praisev1.0.0https://cran.r-project.org490002.3mcheckingtestsETA4m(2/4)[3m30.7s]+praisev1.0.0https://cran.r-project.org490002.3mcheckingtestsETA4m(2/4)[3m30.9s]+praisev1.0.0https://cran.r-project.org490002.3mcheckingtestsETA4m(2/4)[3m31.2s]+praisev1.0.0https://cran.r-project.org490002.3mcheckingtestsETA4m(2/4)[3m31.4s]ETA4m(2/4)[3m31.7s]ETA4m(2/4)[3m31.9s]ETA4m(2/4)[3m32.1s]+praisev1.0.0local470002.3mcheckingfilesETA4m(2/4)[3m32.4s]+praisev1.0.0local470002.3mcheckingfilesETA4m(2/4)[3m32.6s]+praisev1.0.0local470002.3mcheckingfilesETA4m(2/4)[3m32.8s]+praisev1.0.0local470002.3mcheckingfilesETA4m(2/4)[3m33.1s]ETA4m(2/4)[3m33.3s]ETA4m(2/4)[3m33.6s]ETA4m(2/4)[3m33.8s]ETA4m(2/4)[3m34.1s]ETA4m(2/4)[3m34.3s]ETA4m(2/4)[3m34.5s]ETA4m(2/4)[3m34.8s]+praisev1.0.0https://cran.r-project.org490002.4mcheckingtestsETA4m(2/4)[3m35s]+praisev1.0.0https://cran.r-project.org490002.4mcheckingtestsETA4m(2/4)[3m35.4s]+praisev1.0.0https://cran.r-project.org490002.4mcheckingtestsETA4m(2/4)[3m35.7s]+praisev1.0.0https://cran.r-project.org490002.4mcheckingtestsETA4m(2/4)[3m36s]ETA4m(2/4)[3m36.3s]ETA4m(2/4)[3m36.5s]ETA4m(2/4)[3m36.7s]ETA4m(2/4)[3m36.9s]ETA4m(2/4)[3m37.1s]ETA4m(2/4)[3m37.3s]ETA4m(2/4)[3m37.6s]ETA4m(2/4)[3m37.8s]ETA4m(2/4)[3m38.2s]+praisev1.0.0local470002.4mcheckingfilesETA4m(2/4)[3m38.4s]+praisev1.0.0local470002.4mcheckingfilesETA4m(2/4)[3m38.6s]+praisev1.0.0local470002.4mcheckingfilesETA4m(2/4)[3m38.8s]+praisev1.0.0local470002.4mcheckingfilesETA4m(2/4)[3m39.1s]ETA4m(2/4)[3m39.3s]ETA4m(2/4)[3m39.5s]ETA4m(2/4)[3m39.7s]ETA4m(2/4)[3m40s]ETA4m(2/4)[3m40.2s]ETA4m(2/4)[3m40.4s]ETA4m(2/4)[3m40.6s]ETA4m(2/4)[3m40.9s]+praisev1.0.0https://cran.r-project.org490002.5mcheckingtestsETA4m(2/4)[3m41.1s]+praisev1.0.0https://cran.r-project.org490002.5mcheckingtestsETA4m(2/4)[3m41.4s]+praisev1.0.0https://cran.r-project.org490002.5mcheckingtestsETA4m(2/4)[3m41.6s]+praisev1.0.0https://cran.r-project.org490002.5mcheckingtestsETA4m(2/4)[3m41.9s]ETA4m(2/4)[3m42.2s]ETA4m(2/4)[3m42.4s]ETA4m(2/4)[3m42.6s]ETA4m(2/4)[3m42.9s]ETA4m(2/4)[3m43.1s]ETA4m(2/4)[3m43.4s]ETA4m(2/4)[3m43.6s]ETA4m(2/4)[3m43.8s]ETA4m(2/4)[3m44.1s]ETA4m(2/4)[3m44.3s]+praisev1.0.0local470002.5mcheckingfilesETA4m(2/4)[3m44.5s]+praisev1.0.0local490002.5mcheckingforuETA4m(2/4)[3m44.9s]+praisev1.0.0local490002.5mcheckingforuETA4m(2/4)[3m45.1s]+praisev1.0.0local490002.5mcheckingforuETA4m(2/4)[3m45.4s]+praisev1.0.0local490002.5mcheckingforuETA4m(2/4)[3m45.7s]ETA4m(2/4)[3m46s]ETA4m(2/4)[3m46.3s]ETA4m(2/4)[3m46.6s]ETA4m(2/4)[3m46.9s]+praisev1.0.0https://cran.r-project.org490002.6mcheckingtestsETA4m(2/4)[3m47.2s]+praisev1.0.0https://cran.r-project.org490002.6mcheckingtestsETA4m(2/4)[3m47.6s]+praisev1.0.0https://cran.r-project.org490002.6mcheckingtestsETA4m(2/4)[3m47.8s]+praisev1.0.0https://cran.r-project.org490002.6mcheckingtestsETA4m(2/4)[3m48.1s]ETA4m(2/4)[3m48.4s]+praisev1.0.0local490002.5mcheckingtestsETA4m(2/4)[3m48.8s]+praisev1.0.0local490002.5mcheckingtestsETA4m(2/4)[3m49.2s]+praisev1.0.0local490002.5mcheckingtestsETA4m(2/4)[3m49.4s]+praisev1.0.0local490002.5mcheckingtestsETA4m(2/4)[3m49.7s]ETA4m(2/4)[3m50s]ETA4m(2/4)[3m50.3s]+praisev1.0.0local490002.6mcheckingtestsETA4m(2/4)[3m50.5s]+praisev1.0.0local490002.6mcheckingtestsETA4m(2/4)[3m50.9s]+praisev1.0.0local490002.6mcheckingtestsETA4m(2/4)[3m51.2s]+praisev1.0.0local490002.6mcheckingtestsETA4m(2/4)[3m51.5s]ETA4m(2/4)[3m51.8s]ETA4m(2/4)[3m52.1s]ETA4m(2/4)[3m52.3s]ETA4m(2/4)[3m52.6s]ETA4m(2/4)[3m53s]+praisev1.0.0https://cran.r-project.org490002.7mcheckingtestsETA4m(2/4)[3m53.3s]+praisev1.0.0https://cran.r-project.org490002.7mcheckingtestsETA4m(2/4)[3m53.6s]+praisev1.0.0https://cran.r-project.org490002.7mcheckingtestsETA4m(2/4)[3m53.9s]+praisev1.0.0https://cran.r-project.org490002.7mcheckingtestsETA4m(2/4)[3m54.2s]ETA4m(2/4)[3m54.5s]ETA4m(2/4)[3m54.7s]ETA4m(2/4)[3m55s]ETA4m(2/4)[3m55.3s]ETA4m(2/4)[3m55.7s]ETA4m(2/4)[3m55.9s]ETA4m(2/4)[3m56.3s]+praisev1.0.0local490002.7mcheckingtestsETA4m(2/4)[3m56.6s]+praisev1.0.0local490002.7mcheckingtestsETA4m(2/4)[3m57s]+praisev1.0.0local490002.7mcheckingtestsETA4m(2/4)[3m57.3s]+praisev1.0.0local490002.7mcheckingtestsETA4m(2/4)[3m57.6s]ETA4m(2/4)[3m57.9s]ETA4m(2/4)[3m58.3s]ETA4m(2/4)[3m58.6s]ETA4m(2/4)[3m58.9s]+praisev1.0.0https://cran.r-project.org490002.8mcheckingtestsETA4m(2/4)[3m59.4s]+praisev1.0.0https://cran.r-project.org490002.8mcheckingtestsETA4m(2/4)[3m59.7s]+praisev1.0.0https://cran.r-project.org490002.8mcheckingtestsETA4m(2/4)[4m0.1s]+praisev1.0.0https://cran.r-project.org490002.8mcheckingtestsETA4m(2/4)[4m0.4s]ETA4m(2/4)[4m0.7s]ETA4m(2/4)[4m1s]ETA4m(2/4)[4m1.3s]ETA4m(2/4)[4m1.6s]ETA4m(2/4)[4m2s]ETA4m(2/4)[4m2.3s]+praisev1.0.0local490002.8mcheckingtestsETA4m(2/4)[4m2.6s]+praisev1.0.0local490002.8mcheckingtestsETA4m(2/4)[4m2.9s]+praisev1.0.0local490002.8mcheckingtestsETA4m(2/4)[4m3.2s]+praisev1.0.0local490002.8mcheckingtestsETA4m(2/4)[4m3.5s]ETA4m(2/4)[4m3.9s]ETA4m(2/4)[4m4.2s]ETA4m(2/4)[4m4.6s]ETA4m(2/4)[4m5.2s]+praisev1.0.0https://cran.r-project.org490002.9mcheckingtestsETA4m(2/4)[4m5.7s]+praisev1.0.0https://cran.r-project.org490002.9mcheckingtestsETA4m(2/4)[4m6s]+praisev1.0.0https://cran.r-project.org490002.9mcheckingtestsETA4m(2/4)[4m6.3s]+praisev1.0.0https://cran.r-project.org490002.9mcheckingtestsETA4m(2/4)[4m6.6s]ETA4m(2/4)[4m7s]ETA4m(2/4)[4m7.2s]ETA4m(2/4)[4m7.5s]ETA4m(2/4)[4m7.8s]ETA4m(2/4)[4m8s]ETA4m(2/4)[4m8.3s]+praisev1.0.0local490002.9mcheckingtestsETA4m(2/4)[4m8.6s]+praisev1.0.0local490002.9mcheckingtestsETA4m(2/4)[4m8.9s]+praisev1.0.0local490002.9mcheckingtestsETA4m(2/4)[4m9.2s]+praisev1.0.0local490002.9mcheckingtestsETA4m(2/4)[4m9.4s]ETA4m(2/4)[4m9.7s]ETA4m(2/4)[4m10s]ETA4m(2/4)[4m10.3s]ETA4m(2/4)[4m10.6s]ETA4m(2/4)[4m11s]+praisev1.0.0https://cran.r-project.org490003.0mcheckingtestsETA4m(2/4)[4m11.3s]+praisev1.0.0https://cran.r-project.org490003.0mcheckingtestsETA4m(2/4)[4m11.5s]+praisev1.0.0https://cran.r-project.org490003.0mcheckingtestsETA4m(2/4)[4m11.8s]+praisev1.0.0https://cran.r-project.org490003.0mcheckingtestsETA4m(2/4)[4m12.1s]ETA4m(2/4)[4m12.4s]ETA4m(2/4)[4m12.6s]ETA4m(2/4)[4m12.9s]ETA4m(2/4)[4m13.2s]ETA4m(2/4)[4m13.5s]ETA4m(2/4)[4m13.8s]ETA4m(2/4)[4m14s]ETA4m(2/4)[4m14.3s]+praisev1.0.0local490003.0mcheckingtestsETA4m(2/4)[4m14.6s]+praisev1.0.0local490003.0mcheckingtestsETA4m(2/4)[4m14.9s]+praisev1.0.0local490003.0mcheckingtestsETA4m(2/4)[4m15.3s]+praisev1.0.0local490003.0mcheckingtestsETA4m(2/4)[4m15.7s]ETA4m(2/4)[4m16s]ETA4m(2/4)[4m16.5s]ETA4m(2/4)[4m17s]+praisev1.0.0https://cran.r-project.org490003.1mcheckingtestsETA4m(2/4)[4m17.4s]+praisev1.0.0https://cran.r-project.org490003.1mcheckingtestsETA4m(2/4)[4m17.8s]+praisev1.0.0https://cran.r-project.org490003.1mcheckingtestsETA4m(2/4)[4m18.3s]+praisev1.0.0https://cran.r-project.org490003.1mcheckingtestsETA4m(2/4)[4m18.7s]ETA4m(2/4)[4m19.1s]ETA4m(2/4)[4m19.6s]ETA4m(2/4)[4m19.9s]ETA4m(2/4)[4m20.3s]+praisev1.0.0local490003.1mcheckingtestsETA4m(2/4)[4m20.6s]+praisev1.0.0local490003.1mcheckingtestsETA4m(2/4)[4m21s]+praisev1.0.0local490003.1mcheckingtestsETA4m(2/4)[4m21.3s]+praisev1.0.0local490003.1mcheckingtestsETA4m(2/4)[4m21.6s]ETA4m(2/4)[4m22s]ETA4m(2/4)[4m22.5s]ETA4m(2/4)[4m22.8s]ETA4m(2/4)[4m23.1s]+praisev1.0.0https://cran.r-project.org490003.2mcheckingtestsETA4m(2/4)[4m23.4s]+praisev1.0.0https://cran.r-project.org490003.2mcheckingtestsETA4m(2/4)[4m23.7s]+praisev1.0.0https://cran.r-project.org490003.2mcheckingtestsETA4m(2/4)[4m24.1s]+praisev1.0.0https://cran.r-project.org490003.2mcheckingtestsETA4m(2/4)[4m24.5s]ETA4m(2/4)[4m24.9s]ETA4m(2/4)[4m25.5s]ETA4m(2/4)[4m25.8s]ETA4m(2/4)[4m26.2s]+praisev1.0.0local490003.2mcheckingtestsETA4m(2/4)[4m26.5s]+praisev1.0.0local490003.2mcheckingtestsETA4m(2/4)[4m26.9s]+praisev1.0.0local490003.2mcheckingtestsETA4m(2/4)[4m27.2s]+praisev1.0.0local490003.2mcheckingtestsETA4m(2/4)[4m27.6s]ETA4m(2/4)[4m27.9s]ETA4m(2/4)[4m28.4s]ETA4m(2/4)[4m28.8s]+praisev1.0.0https://cran.r-project.org490003.3mcheckingtestsETA4m(2/4)[4m29.2s]+praisev1.0.0https://cran.r-project.org490003.3mcheckingtestsETA4m(2/4)[4m29.5s]+praisev1.0.0https://cran.r-project.org490003.3mcheckingtestsETA4m(2/4)[4m29.9s]+praisev1.0.0https://cran.r-project.org490003.3mcheckingtestsETA5m(2/4)[4m30.1s]ETA5m(2/4)[4m30.5s]ETA5m(2/4)[4m30.8s]ETA5m(2/4)[4m31.1s]ETA5m(2/4)[4m31.5s]ETA5m(2/4)[4m31.8s]ETA5m(2/4)[4m32.3s]+praisev1.0.0local490003.3mcheckingtestsETA5m(2/4)[4m32.6s]+praisev1.0.0local490003.3mcheckingtestsETA5m(2/4)[4m33.1s]+praisev1.0.0local490003.3mcheckingtestsETA5m(2/4)[4m33.6s]+praisev1.0.0local490003.3mcheckingtestsETA5m(2/4)[4m34.3s]ETA5m(2/4)[4m34.7s]ETA5m(2/4)[4m35.1s]+praisev1.0.0https://cran.r-project.org490003.4mcheckingtestsETA5m(2/4)[4m35.7s]+praisev1.0.0https://cran.r-project.org490003.4mcheckingtestsETA5m(2/4)[4m36.4s]+praisev1.0.0https://cran.r-project.org490003.4mcheckingtestsETA5m(2/4)[4m36.8s]+praisev1.0.0https://cran.r-project.org490003.4mcheckingtestsETA5m(2/4)[4m37.4s]ETA5m(2/4)[4m37.8s]ETA5m(2/4)[4m38.3s]+praisev1.0.0local490003.4mcheckingtestsETA5m(2/4)[4m38.9s]+praisev1.0.0local490003.4mcheckingtestsETA5m(2/4)[4m39.3s]+praisev1.0.0local490003.4mcheckingtestsETA5m(2/4)[4m39.6s]+praisev1.0.0local490003.4mcheckingtestsETA5m(2/4)[4m40s]ETA5m(2/4)[4m40.3s]ETA5m(2/4)[4m40.7s]ETA5m(2/4)[4m41.2s]+praisev1.0.0https://cran.r-project.org490003.5mcheckingtestsETA5m(2/4)[4m41.7s]+praisev1.0.0https://cran.r-project.org490003.5mcheckingtestsETA5m(2/4)[4m42.3s]+praisev1.0.0https://cran.r-project.org490003.5mcheckingtestsETA5m(2/4)[4m42.8s]+praisev1.0.0https://cran.r-project.org490003.5mcheckingtestsETA5m(2/4)[4m43.4s]ETA5m(2/4)[4m44.1s]+praisev1.0.0local490003.5mcheckingtestsETA5m(2/4)[4m44.8s]+praisev1.0.0local490003.5mcheckingtestsETA5m(2/4)[4m45.3s]+praisev1.0.0local490003.5mcheckingtestsETA5m(2/4)[4m45.8s]+praisev1.0.0local490003.5mcheckingtestsETA5m(2/4)[4m46.5s]ETA5m(2/4)[4m46.9s]+praisev1.0.0https://cran.r-project.org490003.6mcheckingtestsETA5m(2/4)[4m47.4s]+praisev1.0.0https://cran.r-project.org490003.6mcheckingtestsETA5m(2/4)[4m47.8s]+praisev1.0.0https://cran.r-project.org490003.6mcheckingtestsETA5m(2/4)[4m48.1s]+praisev1.0.0https://cran.r-project.org490003.6mcheckingtestsETA5m(2/4)[4m48.6s]ETA5m(2/4)[4m49.1s]ETA5m(2/4)[4m49.5s]ETA5m(2/4)[4m50s]ETA5m(2/4)[4m50.5s]+praisev1.0.0local490003.6mcheckingtestsETA5m(2/4)[4m50.9s]+praisev1.0.0local490003.6mcheckingtestsETA5m(2/4)[4m51.4s]+praisev1.0.0local490003.6mcheckingtestsETA5m(2/4)[4m51.8s]+praisev1.0.0local490003.6mcheckingtestsETA5m(2/4)[4m52.1s]ETA5m(2/4)[4m52.5s]ETA5m(2/4)[4m52.9s]+praisev1.0.0https://cran.r-project.org490003.7mcheckingtestsETA5m(2/4)[4m53.2s]+praisev1.0.0https://cran.r-project.org490003.7mcheckingtestsETA5m(2/4)[4m53.6s]+praisev1.0.0https://cran.r-project.org490003.7mcheckingtestsETA5m(2/4)[4m54s]+praisev1.0.0https://cran.r-project.org490003.7mcheckingtestsETA5m(2/4)[4m54.4s]ETA5m(2/4)[4m54.8s]ETA5m(2/4)[4m55.1s]ETA5m(2/4)[4m55.6s]ETA5m(2/4)[4m55.9s]ETA5m(2/4)[4m56.3s]+praisev1.0.0local490003.7mcheckingtestsETA5m(2/4)[4m56.8s]+praisev1.0.0local490003.7mcheckingtestsETA5m(2/4)[4m57.3s]+praisev1.0.0local490003.7mcheckingtestsETA5m(2/4)[4m57.7s]+praisev1.0.0local490003.7mcheckingtestsETA5m(2/4)[4m58.1s]ETA5m(2/4)[4m58.5s]ETA5m(2/4)[4m58.9s]+praisev1.0.0https://cran.r-project.org490003.8mcheckingtestsETA5m(2/4)[4m59.4s]+praisev1.0.0https://cran.r-project.org490003.8mcheckingtestsETA5m(2/4)[4m59.7s]+praisev1.0.0https://cran.r-project.org490003.8mcheckingtestsETA5m(2/4)[5m0.1s]+praisev1.0.0https://cran.r-project.org490003.8mcheckingtestsETA5m(2/4)[5m0.5s]ETA5m(2/4)[5m1s]ETA5m(2/4)[5m1.4s]ETA5m(2/4)[5m1.9s]+praisev1.0.0local490003.8mcheckingtestsETA5m(2/4)[5m2.6s]+praisev1.0.0local490003.8mcheckingtestsETA5m(2/4)[5m3.1s]+praisev1.0.0local490003.8mcheckingtestsETA5m(2/4)[5m3.5s]+praisev1.0.0local490003.8mcheckingtestsETA5m(2/4)[5m3.9s]ETA5m(2/4)[5m4.3s]ETA5m(2/4)[5m4.7s]ETA5m(2/4)[5m5.3s]+praisev1.0.0https://cran.r-project.org490003.9mcheckingtestsETA5m(2/4)[5m5.8s]+praisev1.0.0https://cran.r-project.org490003.9mcheckingtestsETA5m(2/4)[5m6.5s]+praisev1.0.0https://cran.r-project.org490003.9mcheckingtestsETA5m(2/4)[5m7s]+praisev1.0.0https://cran.r-project.org490003.9mcheckingtestsETA5m(2/4)[5m7.6s]ETA5m(2/4)[5m7.9s]ETA5m(2/4)[5m8.3s]+praisev1.0.0local490003.9mcheckingtestsETA5m(2/4)[5m8.7s]+praisev1.0.0local490003.9mcheckingtestsETA5m(2/4)[5m9.2s]+praisev1.0.0local490003.9mcheckingtestsETA5m(2/4)[5m9.6s]+praisev1.0.0local490003.9mcheckingtestsETA5m(2/4)[5m9.9s]ETA5m(2/4)[5m10.3s]ETA5m(2/4)[5m10.6s]ETA5m(2/4)[5m11s]+praisev1.0.0https://cran.r-project.org490004.0mcheckingtestsETA5m(2/4)[5m11.4s]+praisev1.0.0https://cran.r-project.org490004.0mcheckingtestsETA5m(2/4)[5m11.8s]+praisev1.0.0https://cran.r-project.org490004.0mcheckingtestsETA5m(2/4)[5m12.1s]+praisev1.0.0https://cran.r-project.org490004.0mcheckingtestsETA5m(2/4)[5m12.5s]ETA5m(2/4)[5m12.9s]ETA5m(2/4)[5m13.2s]ETA5m(2/4)[5m13.6s]ETA5m(2/4)[5m13.9s]ETA5m(2/4)[5m14.3s]+praisev1.0.0local490004.0mcheckingtestsETA5m(2/4)[5m14.6s]+praisev1.0.0local490004.0mcheckingtestsETA5m(2/4)[5m15.1s]+praisev1.0.0local490004.0mcheckingtestsETA5m(2/4)[5m15.5s]+praisev1.0.0https://cran.r-project.org490014.0mcheckingtests+praisev1.0.0local490004.0mcheckingtestsETA5m(2/4)[5m15.8s]+praisev1.0.0https://cran.r-project.org490014.0mcheckingtestsETA5m(2/4)[5m16.1s]+praisev1.0.0https://cran.r-project.org490014.0mETA2m(3/4)[5m16.6s]ETA2m(3/4)[5m16.9s]ETA2m(3/4)[5m17.2s]ETA2m(3/4)[5m17.6s]ETA2m(3/4)[5m17.9s]ETA2m(3/4)[5m18.2s]ETA2m(3/4)[5m18.6s]ETA2m(3/4)[5m18.9s]ETA2m(3/4)[5m19.2s]ETA2m(3/4)[5m19.6s]ETA2m(3/4)[5m19.9s]ETA2m(3/4)[5m20.3s]+praisev1.0.0local490004.1mcheckingtestsETA2m(3/4)[5m20.7s]+praisev1.0.0local490004.1mcheckingtestsETA2m(3/4)[5m21s]+praisev1.0.0local490004.1mcheckingtestsETA2m(3/4)[5m21.4s]+praisev1.0.0local490004.1mcheckingtestsETA2m(3/4)[5m21.7s]ETA2m(3/4)[5m22.1s]ETA2m(3/4)[5m22.4s]ETA2m(3/4)[5m22.8s]ETA2m(3/4)[5m23.2s]ETA2m(3/4)[5m23.5s]ETA2m(3/4)[5m23.9s]ETA2m(3/4)[5m24.3s]ETA2m(3/4)[5m24.6s]ETA2m(3/4)[5m25s]ETA2m(3/4)[5m25.3s]ETA2m(3/4)[5m25.8s]ETA2m(3/4)[5m26.2s]+praisev1.0.0local490004.2mcheckingtestsETA2m(3/4)[5m26.5s]+praisev1.0.0local490004.2mcheckingtestsETA2m(3/4)[5m26.9s]+praisev1.0.0local490004.2mcheckingtestsETA2m(3/4)[5m27.2s]+praisev1.0.0local490004.2mcheckingtestsETA2m(3/4)[5m27.5s]ETA2m(3/4)[5m27.9s]ETA2m(3/4)[5m28.2s]ETA2m(3/4)[5m28.5s]ETA2m(3/4)[5m28.8s]ETA2m(3/4)[5m29.1s]+praisev1.0.0local490014.2mcheckingtestsETA2m(3/4)[5m29.5s]+praisev1.0.0local490014.2mcheckingtestsETA2m(3/4)[5m29.8s]+praisev1.0.0local490014.2mETA2m(3/4)[5m30.1s]Finishedin5m30.5sETA0s(1/4)[3ms]ETA?(0/4)[1m0.7s]installinghtmlwidgetsshinytestthatETA?(0/4)[1m11.1s]installingdiffviewerETA0s(4/4)[5m30.5s] \ No newline at end of file diff --git a/man/pkg_origin.Rd b/man/pkg_origin.Rd index 2877d6b..8ab652b 100644 --- a/man/pkg_origin.Rd +++ b/man/pkg_origin.Rd @@ -3,7 +3,6 @@ \name{pkg_origin} \alias{pkg_origin} \alias{pkg_origin_repo} -\alias{try_pkg_origin_repo} \alias{pkg_origin_is_base} \alias{pkg_origin_base} \alias{pkg_origin_unknown} @@ -16,8 +15,6 @@ pkg_origin(package, ..., .class = c()) pkg_origin_repo(package, repos, ...) -try_pkg_origin_repo(package, repos, ...) - pkg_origin_is_base(package, ...) pkg_origin_base(package, ...) diff --git a/man/start_task.Rd b/man/start_task.Rd new file mode 100644 index 0000000..15e7dd3 --- /dev/null +++ b/man/start_task.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/next_task.R +\name{start_task} +\alias{start_task} +\title{Start a new task} +\usage{ +start_task(node, g, ...) +} +\arguments{ +\item{node}{Node(s) for which libpath should be constructed based on \code{g}} + +\item{g}{\code{task_graph} object} + +\item{...}{additional params passed to downstream methods} +} +\description{ +Starts task based on the \code{task} object encapsulated in the \code{node} taken +from then \code{task_graph} \code{g}. It returns an \code{install_process} or +\code{check_process} \code{R6} object. +} diff --git a/man/task_graph_libpaths.Rd b/man/task_graph_libpaths.Rd new file mode 100644 index 0000000..aeba3f5 --- /dev/null +++ b/man/task_graph_libpaths.Rd @@ -0,0 +1,22 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/next_task.R +\name{task_graph_libpaths} +\alias{task_graph_libpaths} +\title{Libpaths from task graph} +\usage{ +task_graph_libpaths(g, node = NULL, lib.loc = .libPaths(), output = tempdir()) +} +\arguments{ +\item{g}{\code{task_graph} object} + +\item{node}{Node(s) for which libpath should be constructed based on \code{g}} + +\item{lib.loc}{Library paths, defaulting to \code{\link[=.libPaths]{.libPaths()}}.} + +\item{output}{Path to the checked output directory} +} +\description{ +Function that traverses over the task dependency task to acquire libpaths +for given nodes. It ensures that when runing a node, a libpath is +constructed which has all the required packages on it. +} From 876d116549559c3cb3bc95e53e748624330dcc30 Mon Sep 17 00:00:00 2001 From: Szymon Maksymiuk <32574056+maksymiuks@users.noreply.github.com> Date: Wed, 18 Feb 2026 12:40:27 +0100 Subject: [PATCH 42/62] Upgrade package version (#85) * Upgrade package version * Make lintr happy --- CRAN-SUBMISSION | 3 --- DESCRIPTION | 2 +- R/next_task.R | 8 ++++---- 3 files changed, 5 insertions(+), 8 deletions(-) delete mode 100644 CRAN-SUBMISSION diff --git a/CRAN-SUBMISSION b/CRAN-SUBMISSION deleted file mode 100644 index 293cc27..0000000 --- a/CRAN-SUBMISSION +++ /dev/null @@ -1,3 +0,0 @@ -Version: 0.2.0 -Date: 2024-07-26 01:49:29 UTC -SHA: 3a126658cae8fd26302a897968105629ffce9502 diff --git a/DESCRIPTION b/DESCRIPTION index 6b4ed4d..9bab253 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: checked Title: Systematically Run R CMD Checks -Version: 0.5.0.9000 +Version: 0.5.0 Authors@R: c( person( diff --git a/R/next_task.R b/R/next_task.R index ef0049b..46b28a6 100644 --- a/R/next_task.R +++ b/R/next_task.R @@ -1,9 +1,9 @@ #' Libpaths from task graph -#' +#' #' Function that traverses over the task dependency task to acquire libpaths #' for given nodes. It ensures that when runing a node, a libpath is #' constructed which has all the required packages on it. -#' +#' #' @param g `task_graph` object #' @param node Node(s) for which libpath should be constructed based on `g` #' @param output Path to the checked output directory @@ -34,11 +34,11 @@ task_graph_libpaths <- function( } #' Start a new task -#' +#' #' Starts task based on the `task` object encapsulated in the `node` taken #' from then `task_graph` `g`. It returns an `install_process` or #' `check_process` `R6` object. -#' +#' #' @inheritParams task_graph_libpaths #' @param ... additional params passed to downstream methods start_task <- function(node, g, ...) { From 1fbdbb880c5895e4c299572cb258cb482d47b073 Mon Sep 17 00:00:00 2001 From: maksymis <32574056+maksymiuks@users.noreply.github.com> Date: Wed, 18 Feb 2026 14:53:07 +0100 Subject: [PATCH 43/62] Resolve further conflicts --- tests/testthat/test-check-reverse.R | 120 +------------------ tests/testthat/test-check.R | 48 +------- tests/testthat/test-dep-graph-next-package.R | 20 +--- tests/testthat/test-deps.R | 3 +- 4 files changed, 10 insertions(+), 181 deletions(-) diff --git a/tests/testthat/test-check-reverse.R b/tests/testthat/test-check-reverse.R index b403c18..fbaa7a3 100644 --- a/tests/testthat/test-check-reverse.R +++ b/tests/testthat/test-check-reverse.R @@ -1,7 +1,3 @@ -# CRAN does not like out subprocesses tests resulting in false positive tests -# results -testthat::skip_on_cran() - create_temp_repo <- function(dir, repo_path) { contrib_url <- utils::contrib.url(repo_path, type = "source") dir.create(contrib_url, recursive = TRUE) @@ -82,10 +78,8 @@ test_that("check_rev_deps works for package with one breaking change", { ) expect_length(r[[1]][[2]]$errors$potential_issues$new, 0L) expect_length(r[[1]][[2]]$errors$potential_issues$old, 0L) - - + # rev.both.ok - expect_length(r[[1]][[1]]$notes$issues, 0L) expect_length(r[[1]][[1]]$notes$potential_issues$new, 0L) expect_length(r[[1]][[1]]$notes$potential_issues$old, 0L) @@ -100,93 +94,14 @@ test_that("check_rev_deps works for package with one breaking change", { }) test_that("check_rev_deps works for a package without a version in repos", { - # Ensure source installation to make sure test works also on mac and windows withr::with_options(list(pkgType = "source"), { -<<<<<<< HEAD expect_no_error(design <- check_rev_deps( file.path(sources_new, "pkg.suggests"), n = 2L, repos = repo, reporter = NULL )) -======= - expect_no_warning(design <- check_rev_deps( - file.path(sources_new, "pkg.suggests"), - n = 2L, repos = repo, env = c("NOT_CRAN" = "false", options::opt("check_envvars")))) - }) - - expect_identical( - design$input$package[[1]]$env, - c("NOT_CRAN" = "false", options::opt("check_envvars")) - ) - - r <- results(design) - expect_s3_class(r, "checked_results") - expect_true(is.list(r)) - expect_named(r) - expect_length(r, 1L) - expect_length(r$revdep_check_task_spec, 2L) - - # pkg.none - expect_length(r$revdep_check_task_spec$pkg.none$notes$issues, 0L) - expect_length(r$revdep_check_task_spec$pkg.none$notes$potential_issues$new, 0L) - expect_length(r$revdep_check_task_spec$pkg.none$notes$potential_issues$old, 0L) - - expect_length(r$revdep_check_task_spec$pkg.none$warnings$issues, 0L) - expect_length(r$revdep_check_task_spec$pkg.none$warnings$potential_issues$new, 0L) - expect_length(r$revdep_check_task_spec$pkg.none$warnings$potential_issues$old, 0L) - - - expect_length(r$revdep_check_task_spec$pkg.none$errors$issues, 0L) - expect_length(r$revdep_check_task_spec$pkg.none$errors$potential_issues$new, 0L) - expect_length(r$revdep_check_task_spec$pkg.none$errors$potential_issues$old, 0L) - - - # pkg.none.broken - expect_length(r$revdep_check_task_spec$pkg.none.broken$notes$issues, 0L) - expect_length(r$revdep_check_task_spec$pkg.none.broken$notes$potential_issues$new, 0L) - expect_length(r$revdep_check_task_spec$pkg.none.broken$notes$potential_issues$old, 0L) - - expect_length(r$revdep_check_task_spec$pkg.none.broken$warnings$issues, 0L) - expect_length(r$revdep_check_task_spec$pkg.none.broken$warnings$potential_issues$new, 0L) - expect_length(r$revdep_check_task_spec$pkg.none.broken$warnings$potential_issues$old, 0L) - - - expect_length(r$revdep_check_task_spec$pkg.none.broken$errors$issues, 1L) - expect_true( - grepl("Running the tests in", - r$revdep_check_task_spec$pkg.none.broken$errors$issues), - grepl("\"hello world\" is not TRUE", - r$revdep_check_task_spec$pkg.none.broken$errors$issues) - ) - expect_length(r$revdep_check_task_spec$pkg.none.broken$errors$potential_issues$new, 0L) - expect_length(r$revdep_check_task_spec$pkg.none.broken$errors$potential_issues$old, 0L) - - # Error testing - dir.create(temp_lib <- tempfile("testing_lib")) - install.packages( - file.path(sources_new, "pkg.suggests"), - lib = temp_lib, - type = "source", - repos = NULL - ) - - withr::with_options(list(pkgType = "source"), { - expect_error(design <- check_rev_deps( - file.path(sources_new, "pkg.suggests"), - lib.loc = temp_lib, - n = 2L, repos = repo, env = c("NOT_CRAN" = "false", options::opt("check_envvars"))), - "cannot provide accurate reverse dependency check results") - }) -}) - -test_that("check_dev_rev_deps works as expected", { - withr::with_options(list(pkgType = "source"), { - design <- check_dev_rev_deps( - file.path(sources_new, "pkg.ok.error"), - n = 2L, repos = repo) ->>>>>>> 3615af88add43ec6f6d21ee450e4c8433c467911 }) r <- results(design) @@ -198,7 +113,6 @@ test_that("check_dev_rev_deps works as expected", { ) expect_named(r) expect_length(r, 1L) -<<<<<<< HEAD expect_length(r[[1]], 1L) expect_s3_class(r[[1]], "rev_dep_dep_results") @@ -212,7 +126,6 @@ test_that("check_dev_rev_deps works as expected", { expect_length(r[[1]][[1]]$warnings$potential_issues$new, 0L) expect_length(r[[1]][[1]]$warnings$potential_issues$old, 0L) - expect_length(r[[1]][[1]]$errors$issues, 1L) expect_true( grepl("Running the tests in", r[[1]][[1]]$errors$issues) @@ -222,35 +135,4 @@ test_that("check_dev_rev_deps works as expected", { ) expect_length(r[[1]][[1]]$errors$potential_issues$new, 0L) expect_length(r[[1]][[1]]$errors$potential_issues$old, 0L) -======= - expect_length(r$check_task_spec, 2L) - - # rev.both.error - expect_length(r$check_task_spec$`rev.both.error (dev)`$notes$issues, 0L) - expect_length(r$check_task_spec$`rev.both.error (dev)`$warnings$issues, 1L) - expect_true( - grepl("Namespace in Imports field not imported from", - r$check_task_spec$`rev.both.error (dev)`$warnings$issues), - grepl("Missing or unexported object", - r$check_task_spec$`rev.both.error (dev)`$warnings$issues) - ) - - expect_length(r$check_task_spec$`rev.both.error (dev)`$errors$issues, 1L) - expect_true( - grepl("Running the tests in", - r$check_task_spec$`rev.both.error (dev)`$errors$issues), - grepl("is not an exported object from", - r$check_task_spec$`rev.both.error (dev)`$errors$issues) - ) - - # rev.both.ok - expect_length(r$check_task_spec$`rev.both.ok (dev)`$notes$issues, 1L) - expect_true( - grepl("Namespace in Imports field not imported from", - r$check_task_spec$`rev.both.ok (dev)`$notes$issues) - ) - - expect_length(r$check_task_spec$`rev.both.ok (dev)`$warnings$issues, 0L) - expect_length(r$check_task_spec$`rev.both.ok (dev)`$errors$issues, 0L) ->>>>>>> 3615af88add43ec6f6d21ee450e4c8433c467911 }) diff --git a/tests/testthat/test-check.R b/tests/testthat/test-check.R index 077484d..28968b5 100644 --- a/tests/testthat/test-check.R +++ b/tests/testthat/test-check.R @@ -1,24 +1,5 @@ -# CRAN does not like out subprocesses tests resulting in false positive tests -# results -testthat::skip_on_cran() - test_that("check_pkgs works as expected", { examples_path <- system.file("example_packages", package = "checked") -<<<<<<< HEAD -======= - # WIP - expect_no_error(design <- check_pkgs(c( - file.path(examples_path, "exampleGood"), - file.path(examples_path, "exampleBad") - ), n = 2L, repos = "https://cran.r-project.org/", - env = c(NOT_CRAN = "false", options::opt("check_envvars")))) - - expect_identical( - design$input$package[[1]]$env, - c(NOT_CRAN = "false", options::opt("check_envvars")) - ) -}) ->>>>>>> 3615af88add43ec6f6d21ee450e4c8433c467911 expect_no_error( plan <- check_pkgs( @@ -29,7 +10,7 @@ test_that("check_pkgs works as expected", { lib.loc = .libPaths() ) ) - + r <- results(plan) expect_s3_class(r, "checked_results") expect_true(is.list(r)) @@ -67,30 +48,3 @@ test_that("check_pkgs works as expected", { expect_length(r[[1]][[2]]$errors$potential_issues$new, 0L) expect_length(r[[1]][[2]]$errors$potential_issues$old, 0L) }) - -test_that("check design restore dialog test", { - - dir_create(output <- tempfile()) - expect_true(dir.exists(output)) - with_mocked_bindings({ - check_past_output(output, options::opt("restore"), ask = TRUE) - }, restore_menu = function(...) "1") # Yes - expect_true(dir.exists(output)) - with_mocked_bindings({ - check_past_output(output, options::opt("restore"), ask = TRUE) - }, restore_menu = function(...) "2") # No - expect_true(!dir.exists(output)) - - dir_create(output <- tempfile()) - expect_true(dir.exists(output)) - check_past_output(output, options::opt("restore"), ask = FALSE) - expect_true(!dir.exists(output)) - - dir_create(output <- tempfile()) - expect_true(dir.exists(output)) - check_past_output(output, TRUE, ask = TRUE) - expect_true(dir.exists(output)) - check_past_output(output, FALSE, ask = TRUE) - expect_true(!dir.exists(output)) - -}) diff --git a/tests/testthat/test-dep-graph-next-package.R b/tests/testthat/test-dep-graph-next-package.R index e60e139..e053d67 100644 --- a/tests/testthat/test-dep-graph-next-package.R +++ b/tests/testthat/test-dep-graph-next-package.R @@ -1,13 +1,13 @@ test_that("dep_graph_next_package finds next installable package", { # nolint start, styler: off g <- igraph::make_graph(~ - A -+ B -+ C, - A ------+ D, - A -+ E -+ D, - A -+ F -+ D + A -+ B -+ C, + A ------+ D, + A -+ E -+ D, + A -+ F -+ D ) # nolint end, styler: on - + # initialize graph characteristics to mock dep graph E(g)$type <- "Depends" V(g)$root <- V(g)$name == "A" @@ -21,22 +21,14 @@ test_that("dep_graph_next_package finds next installable package", { V(g)["D"]$status <- STATUS[["in progress"]] V(g)["C"]$status <- STATUS[["done"]] g <- task_graph_update_ready(g) -<<<<<<< HEAD ready_nodes <- V(g)[V(g)$status == STATUS$ready] expect_equal(names(ready_nodes), "B") -======= - expect_equal(names(task_graph_which_ready(g)), "B") ->>>>>>> 3615af88add43ec6f6d21ee450e4c8433c467911 # if the order is reversed, now "F" and "E" should be next V(g)$status <- STATUS[["pending"]] V(g)["D"]$status <- STATUS[["done"]] V(g)["C"]$status <- STATUS[["in progress"]] g <- task_graph_update_ready(g) -<<<<<<< HEAD ready_nodes <- V(g)[V(g)$status == STATUS$ready] expect_equal(names(ready_nodes), c("F", "E")) -======= - expect_equal(names(task_graph_which_ready(g)), c("F", "E")) ->>>>>>> 3615af88add43ec6f6d21ee450e4c8433c467911 -}) +}) \ No newline at end of file diff --git a/tests/testthat/test-deps.R b/tests/testthat/test-deps.R index bdaa058..1c689d0 100644 --- a/tests/testthat/test-deps.R +++ b/tests/testthat/test-deps.R @@ -1,7 +1,7 @@ test_that("pkg_dependencies works as expected for local package", { desc <- read.dcf(system.file("DESCRIPTION", package = "checked")) rownames(desc) <- "checked" - + local_deps <- pkg_dependencies( packages = "checked", dependencies = TRUE, @@ -10,6 +10,7 @@ test_that("pkg_dependencies works as expected for local package", { expect_snapshot(local_deps) }) + test_that("pkg_dependencies works as expected for cran package", { skip_on_cran() df <- pkg_dependencies( From 93857b52e044903b67dc60c859369921d8458239 Mon Sep 17 00:00:00 2001 From: maksymis <32574056+maksymiuks@users.noreply.github.com> Date: Wed, 18 Feb 2026 16:11:35 +0100 Subject: [PATCH 44/62] Fix tests and lintr --- .lintr | 4 +- R/cli.R | 6 +- .../revdeps/v1/pkg.none.broken/DESCRIPTION | 16 ++ .../revdeps/v1/pkg.none.broken/LICENSE | 2 + .../revdeps/v1/pkg.none.broken/NAMESPACE | 3 + .../revdeps/v1/pkg.none.broken/R/hw.R | 6 + .../v1/pkg.none.broken/man/hello_world.Rd | 11 ++ .../v1/pkg.none.broken/tests/test_hw.R | 5 + tests/testthat/test-check-reverse.R | 31 ++- tests/testthat/test-checks_df.R | 184 ------------------ tests/testthat/test-dep-graph-next-package.R | 4 +- tests/testthat/test-deps.R | 2 +- tests/testthat/test-plan.R | 26 ++- tests/testthat/test-reporters.R | 14 +- tests/testthat/test-results-utils.R | 4 +- tests/testthat/test-results.R | 26 --- 16 files changed, 99 insertions(+), 245 deletions(-) create mode 100644 tests/testthat/fixtures/revdeps/v1/pkg.none.broken/DESCRIPTION create mode 100644 tests/testthat/fixtures/revdeps/v1/pkg.none.broken/LICENSE create mode 100644 tests/testthat/fixtures/revdeps/v1/pkg.none.broken/NAMESPACE create mode 100644 tests/testthat/fixtures/revdeps/v1/pkg.none.broken/R/hw.R create mode 100644 tests/testthat/fixtures/revdeps/v1/pkg.none.broken/man/hello_world.Rd create mode 100644 tests/testthat/fixtures/revdeps/v1/pkg.none.broken/tests/test_hw.R delete mode 100644 tests/testthat/test-checks_df.R delete mode 100644 tests/testthat/test-results.R diff --git a/.lintr b/.lintr index c597280..e1a22e9 100644 --- a/.lintr +++ b/.lintr @@ -9,8 +9,6 @@ exclusions: list( "tests/testthat/testing_pkgs", "tests/testthat/fixtures", - "inst/", - # TODO: These files need major refactor, skip until then - "tests/" + "inst/" ) diff --git a/R/cli.R b/R/cli.R index 7f3b31f..ef8ee2e 100644 --- a/R/cli.R +++ b/R/cli.R @@ -1,3 +1,7 @@ +# We need to define it as variable instead of direct default parameter +# to comply with CRAN LaTeX requirements +DEFAULT_ROW_SYMBOL <- list(bar = "\u2502") + #' Internal Utilities for Command-line Output #' #' Various helper functions for consistent cli output, including theming and @@ -23,7 +27,7 @@ cli_table_row <- function( errors = "E", msg = "", style = c("row", "title", "header"), - symbols = list(bar = "\u2502") + symbols = DEFAULT_ROW_SYMBOL ) { style <- match.arg(style) diff --git a/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/DESCRIPTION b/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/DESCRIPTION new file mode 100644 index 0000000..576eb7d --- /dev/null +++ b/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/DESCRIPTION @@ -0,0 +1,16 @@ +Package: pkg.none.broken +Title: What the Package Does (One Line, Title Case) +Version: 1.0.0 +Authors@R: + person("First", "Last", , "first.last@example.com", role = c("aut", "cre"), + comment = c(ORCID = "YOUR-ORCID-ID")) +Description: What the package does (one paragraph). +License: MIT + file LICENSE +Encoding: UTF-8 +Roxygen: list(markdown = TRUE) +RoxygenNote: 7.1.2 +Suggests: pkg.suggests +NeedsCompilation: no +Packaged: 2024-11-06 13:34:08 UTC; maksymis +Author: First Last [aut, cre] (YOUR-ORCID-ID) +Maintainer: First Last diff --git a/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/LICENSE b/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/LICENSE new file mode 100644 index 0000000..482a651 --- /dev/null +++ b/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/LICENSE @@ -0,0 +1,2 @@ +YEAR: 2021 +COPYRIGHT HOLDER: pkg.none authors diff --git a/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/NAMESPACE b/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/NAMESPACE new file mode 100644 index 0000000..da44dad --- /dev/null +++ b/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/NAMESPACE @@ -0,0 +1,3 @@ +# Generated by roxygen2: do not edit by hand + +export(hello_world) diff --git a/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/R/hw.R b/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/R/hw.R new file mode 100644 index 0000000..65a0d15 --- /dev/null +++ b/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/R/hw.R @@ -0,0 +1,6 @@ +#' Hello world +#' +#' @export +hello_world <- function() { + "hello world!" +} diff --git a/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/man/hello_world.Rd b/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/man/hello_world.Rd new file mode 100644 index 0000000..5d01005 --- /dev/null +++ b/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/man/hello_world.Rd @@ -0,0 +1,11 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/hw.R +\name{hello_world} +\alias{hello_world} +\title{Hello world} +\usage{ +hello_world() +} +\description{ +Hello world +} diff --git a/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/tests/test_hw.R b/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/tests/test_hw.R new file mode 100644 index 0000000..ba7da94 --- /dev/null +++ b/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/tests/test_hw.R @@ -0,0 +1,5 @@ +if (require("pkg.suggests", quietly = TRUE)) { + library(pkg.none) + stopifnot(hello_world() == "hello world") +} + diff --git a/tests/testthat/test-check-reverse.R b/tests/testthat/test-check-reverse.R index fbaa7a3..fb960a5 100644 --- a/tests/testthat/test-check-reverse.R +++ b/tests/testthat/test-check-reverse.R @@ -78,7 +78,7 @@ test_that("check_rev_deps works for package with one breaking change", { ) expect_length(r[[1]][[2]]$errors$potential_issues$new, 0L) expect_length(r[[1]][[2]]$errors$potential_issues$old, 0L) - + # rev.both.ok expect_length(r[[1]][[1]]$notes$issues, 0L) expect_length(r[[1]][[1]]$notes$potential_issues$new, 0L) @@ -113,9 +113,10 @@ test_that("check_rev_deps works for a package without a version in repos", { ) expect_named(r) expect_length(r, 1L) - expect_length(r[[1]], 1L) - + expect_length(r[[1]], 2L) expect_s3_class(r[[1]], "rev_dep_dep_results") + + # pkg.none.broken expect_s3_class(r[[1]][[1]], "rcmdcheck_rev_dep_results") expect_length(r[[1]][[1]]$notes$issues, 0L) @@ -131,8 +132,30 @@ test_that("check_rev_deps works for a package without a version in repos", { grepl("Running the tests in", r[[1]][[1]]$errors$issues) ) expect_true( - grepl("Reverse suggested deps detected", r[[1]][[1]]$errors$issues) + grepl("there is no package called", r[[1]][[1]]$errors$issues) ) expect_length(r[[1]][[1]]$errors$potential_issues$new, 0L) expect_length(r[[1]][[1]]$errors$potential_issues$old, 0L) + + + # pkg.none + expect_s3_class(r[[1]][[2]], "rcmdcheck_rev_dep_results") + + expect_length(r[[1]][[2]]$notes$issues, 0L) + expect_length(r[[1]][[2]]$notes$potential_issues$new, 0L) + expect_length(r[[1]][[2]]$notes$potential_issues$old, 0L) + + expect_length(r[[1]][[2]]$warnings$issues, 0L) + expect_length(r[[1]][[2]]$warnings$potential_issues$new, 0L) + expect_length(r[[1]][[2]]$warnings$potential_issues$old, 0L) + + expect_length(r[[1]][[2]]$errors$issues, 1L) + expect_true( + grepl("Running the tests in", r[[1]][[2]]$errors$issues) + ) + expect_true( + grepl("Reverse suggested deps detected", r[[1]][[2]]$errors$issues) + ) + expect_length(r[[1]][[2]]$errors$potential_issues$new, 0L) + expect_length(r[[1]][[2]]$errors$potential_issues$old, 0L) }) diff --git a/tests/testthat/test-checks_df.R b/tests/testthat/test-checks_df.R deleted file mode 100644 index 3d67f7a..0000000 --- a/tests/testthat/test-checks_df.R +++ /dev/null @@ -1,184 +0,0 @@ -examples_path <- system.file("example_packages", package = "checked") -path <- c( - test_path("testing_pkgs", "DALEXtra"), - test_path("testing_pkgs", "rd2markdown"), - file.path(examples_path, "exampleGood"), - file.path(examples_path, "exampleOkay"), - file.path(examples_path, "exampleBad") -) -expected_revdeps <- tools::package_dependencies( - "DALEXtra", - db = utils::available.packages(repos = "https://cran.r-project.org/"), - reverse = TRUE, - which = "all" -)[[1]] - -test_that("rev_dep_check_tasks_df works with deafult params", { - expect_silent( - df <- rev_dep_check_tasks_df( - test_path("testing_pkgs", "DALEXtra"), - repos = "https://cran.r-project.org/" - ) - ) - expect_s3_class(df, "data.frame") - expect_true(NROW(df) >= 2*length(expected_revdeps)) - expect_named(df, c("alias", "version", "package", "custom")) - - expect_s3_class(df$package, "list_of_task_spec") - expect_equal(unique(vcapply(df$package, function(x) class(x)[[1]])), "revdep_check_task_spec") - expect_equal(unique(vcapply(df$package, function(x) class(x$package_spec)[[1]])), "package_spec") - - expect_s3_class(df$custom, "list_of_task_spec") - expect_equal(unique(vcapply(df$custom, function(x) class(x)[[1]])), "custom_install_task_spec") - expect_equal(unique(vcapply(df$custom, function(x) class(x$package_spec)[[1]])), c("package_spec_source", "package_spec")) - - expect_true(all(endsWith(df$alias[seq(1, NROW(df), by = 2)], "(dev)"))) - expect_true(all(endsWith(df$alias[seq(2, NROW(df), by = 2)], "(v2.3.0)"))) - - # Test displayes - expect_no_error(print(df)) - expect_no_error(print(df$package)) - expect_no_error(print(df$custom)) -}) - -test_that("task_df functions can specify subprocesses configuration", { - expect_silent( - df <- rev_dep_check_tasks_df( - test_path("testing_pkgs", "DALEXtra"), - repos = "https://cran.r-project.org/", - env = c("NOT_CRAN" = "false", options::opt("check_envvars")), - args = c("--some-option", "--other-option", options::opt("check_args")), - build_args = c("--yet-another-option", options::opt("check_build_args")) - ) - ) - - expect_identical( - df$package[[1]]$env, - c("NOT_CRAN" = "false", options::opt("check_envvars")) - ) - expect_identical( - df$package[[1]]$args, - c("--some-option", "--other-option", options::opt("check_args")) - ) - expect_identical( - df$package[[1]]$build_args, - c("--yet-another-option", options::opt("check_build_args")) - ) - - expect_silent( - df <- rev_dep_check_tasks_df( - test_path("testing_pkgs", "DALEXtra"), - repos = "https://cran.r-project.org/", - env = c("NOT_CRAN" = "false"), - args = c("--some-option", "--other-option"), - build_args = c("--yet-another-option") - ) - ) - - expect_identical( - df$package[[1]]$env, - c("NOT_CRAN" = "false") - ) - expect_identical( - df$package[[1]]$args, - c("--some-option", "--other-option") - ) - expect_identical( - df$package[[1]]$build_args, - "--yet-another-option" - ) - - withr::with_envvar( - c(R_CHECKED_CHECK_ARGS = "--some-option --other-option --another-option", - R_CHECKED_CHECK_BUILD_ARGS = "--yet-another-option"), { - expect_silent( - df <- source_check_tasks_df( - path, - build_args = c("--another-option", options::opt("check_build_args")) - ) - ) - } - ) - - expect_identical( - df$package[[1]]$env, - options::opt("check_envvars") - ) - expect_identical( - df$package[[1]]$args, - c("--some-option", "--other-option", "--another-option") - ) - expect_identical( - df$package[[1]]$build_args, - c("--another-option", "--yet-another-option") - ) - -}) - -test_that("rev_dep_check_tasks_df development_only = TRUE", { - expect_silent( - df <- rev_dep_check_tasks_df( - test_path("testing_pkgs", "DALEXtra"), - repos = "https://cran.r-project.org/", - versions = "dev" - ) - ) - expect_s3_class(df, "data.frame") - expect_true(NROW(df) >= length(expected_revdeps)) - expect_named(df, c("alias", "version", "package", "custom")) - - expect_s3_class(df$package, "list_of_task_spec") - expect_equal(unique(vcapply(df$package, function(x) class(x)[[1]])), "check_task_spec") - expect_equal(unique(vcapply(df$package, function(x) class(x$package_spec)[[1]])), "package_spec") - - expect_s3_class(df$custom, "list_of_task_spec") - expect_equal(unique(vcapply(df$custom, function(x) class(x)[[1]])), "custom_install_task_spec") - expect_equal(unique(vcapply(df$custom, function(x) class(x$package_spec)[[1]])), "package_spec_source") - - expect_true(all(endsWith(df$alias, "(dev)"))) - expect_true(all(!endsWith(df$alias, "(v2.3.0)"))) -}) - -test_that("source_check_tasks_df works as expected", { - expect_silent( - df <- source_check_tasks_df(path) - ) - expect_s3_class(df, "data.frame") - expect_equal(NROW(df), 5) - expect_named(df, c("alias", "version", "package", "custom")) - - expect_s3_class(df$package, "list_of_task_spec") - expect_equal(unique(vcapply(df$package, function(x) class(x)[[1]])), "check_task_spec") - expect_equal(unique(vcapply(df$package, function(x) class(x$package_spec)[[1]])), "package_spec_source") - - expect_s3_class(df$custom, "list_of_task_spec") - expect_equal(unique(vcapply(df$custom, function(x) class(x)[[1]])), "custom_install_task_spec") - expect_equal(unique(vcapply(df$custom, function(x) class(x$package_spec)[[1]])), "NULL") - - expect_true(all(endsWith(df$alias, "(source)"))) -}) - -test_that("source_check_tasks_df aliases are properly handled", { - broken_names <- c("DALEXtra_new", "rd2markdown_new", "exampleGood_new", "exampleOkay_new", "exampleBad_new") - path_broken <- path - names(path_broken) <- broken_names - - expect_silent( - df <- source_check_tasks_df(path_broken) - ) - - expect_true(all(endsWith(df$alias, "_new"))) - expect_equal(df$alias, broken_names) - - expect_silent( - df <- source_check_tasks_df(c( - file.path(examples_path, "exampleGood"), - file.path(examples_path, "exampleGood"), - file.path(examples_path, "exampleGood") - )) - ) - - expect_equal( - df$alias, c("exampleGood (source_1)", "exampleGood (source_2)", "exampleGood (source_3)") - ) -}) diff --git a/tests/testthat/test-dep-graph-next-package.R b/tests/testthat/test-dep-graph-next-package.R index e053d67..a1263b1 100644 --- a/tests/testthat/test-dep-graph-next-package.R +++ b/tests/testthat/test-dep-graph-next-package.R @@ -7,7 +7,7 @@ test_that("dep_graph_next_package finds next installable package", { A -+ F -+ D ) # nolint end, styler: on - + # initialize graph characteristics to mock dep graph E(g)$type <- "Depends" V(g)$root <- V(g)$name == "A" @@ -31,4 +31,4 @@ test_that("dep_graph_next_package finds next installable package", { g <- task_graph_update_ready(g) ready_nodes <- V(g)[V(g)$status == STATUS$ready] expect_equal(names(ready_nodes), c("F", "E")) -}) \ No newline at end of file +}) diff --git a/tests/testthat/test-deps.R b/tests/testthat/test-deps.R index 1c689d0..c755a83 100644 --- a/tests/testthat/test-deps.R +++ b/tests/testthat/test-deps.R @@ -20,4 +20,4 @@ test_that("pkg_dependencies works as expected for cran package", { ) ) expect_snapshot(df) -}) \ No newline at end of file +}) diff --git a/tests/testthat/test-plan.R b/tests/testthat/test-plan.R index 5a78db4..f7ea84f 100644 --- a/tests/testthat/test-plan.R +++ b/tests/testthat/test-plan.R @@ -19,17 +19,15 @@ test_that("rev_dep_check_tasks_df works with deafult params", { "rev_dep_check_meta_task", "check_task", "install_task" - ) %in% vcapply(V(plan)$task, function(x) - class(x)[[1]]) + ) %in% vcapply(V(plan)$task, function(x) class(x)[[1]]) ) - expect_s3_class(V(plan)$task[[1]], "rev_dep_dep_meta_task") - expect_s3_class(V(plan)$task[[1]]$origin, "pkg_origin_local") + expect_s3_class(V(plan)$task[[1]], "rev_dep_dep_meta_task") + expect_s3_class(V(plan)$task[[1]]$origin, "pkg_origin_local") expect_true(V(plan)$task[[1]]$origin$package == "DALEXtra") expect_s3_class(V(plan)$task[[1]]$origin$version, "package_version") expect_true(V(plan)$task[[1]]$origin$version == "2.3.0") - - - expect_s3_class(V(plan)$task[[3]], "check_task") + + expect_s3_class(V(plan)$task[[3]], "check_task") expect_equal( names(V(plan)$task[[3]]), c("env", "args", "build_args", "origin", "seed") @@ -41,7 +39,7 @@ test_that("rev_dep_check_tasks_df works with deafult params", { expect_true(V(plan)$task[[3]]$origin$package == "marginaleffects") expect_s3_class(V(plan)$task[[3]]$origin$version, "package_version") expect_true(V(plan)$task[[3]]$origin$version == "0.31.0") - + # Test displayes expect_no_error(expect_output(print(plan))) expect_no_error(expect_output(print(V(plan)$task[[1]]))) @@ -64,19 +62,17 @@ test_that("source_check_tasks_df works as expected", { ) expect_s3_class(plan, "task_graph") expect_true(length(plan) == 6) - + expect_all_true( c( "local_check_meta_task", "check_task" - ) %in% vcapply(V(plan)$task, function(x) - class(x)[[1]]) + ) %in% vcapply(V(plan)$task, function(x) class(x)[[1]]) ) - expect_s3_class(V(plan)$task[[1]], "local_check_meta_task") + expect_s3_class(V(plan)$task[[1]], "local_check_meta_task") expect_null(V(plan)$task[[1]]$origin) - - expect_s3_class(V(plan)$task[[2]], "check_task") + expect_s3_class(V(plan)$task[[2]], "check_task") expect_equal( names(V(plan)$task[[3]]), c("env", "args", "build_args", "origin") @@ -88,7 +84,7 @@ test_that("source_check_tasks_df works as expected", { expect_true(V(plan)$task[[3]]$origin$package == "rd2markdown") expect_s3_class(V(plan)$task[[3]]$origin$version, "package_version") expect_true(V(plan)$task[[3]]$origin$version == "0.0.8") - + # Test displayes expect_no_error(expect_output(print(plan))) expect_no_error(expect_output(print(V(plan)$task[[1]]))) diff --git a/tests/testthat/test-reporters.R b/tests/testthat/test-reporters.R index 6413c74..1737ed2 100644 --- a/tests/testthat/test-reporters.R +++ b/tests/testthat/test-reporters.R @@ -27,9 +27,9 @@ test_that("reporter_basic_tty works as expected for pkg.none", { repos = repo, restore = FALSE ) - + reporter <- reporter_basic_tty() - + expect_snapshot( run(design, reporter = reporter), # We remove the last line as it reports the time which can change @@ -45,16 +45,16 @@ test_that("reporter_basic_tty works as expected for pkg.ok.error", { file.path(sources_new, "pkg.ok.error"), repos = repo ) - + design <- checker$new( plan, n = 1L, repos = repo, restore = FALSE ) - + reporter <- reporter_basic_tty() - + expect_snapshot( run(design, reporter = reporter), # We remove the last line as it reports the time which can change @@ -70,7 +70,7 @@ test_that("reporter_ansi_tty works as expected for pkg.ok.error", { file.path(sources_new, "pkg.ok.error"), repos = repo ) - + design <- checker$new( plan, n = 1L, @@ -78,7 +78,7 @@ test_that("reporter_ansi_tty works as expected for pkg.ok.error", { restore = FALSE ) reporter <- reporter_ansi_tty() - + expect_no_error(suppressMessages( capture.output( run(design, reporter = reporter) diff --git a/tests/testthat/test-results-utils.R b/tests/testthat/test-results-utils.R index d5a6434..3cd2d49 100644 --- a/tests/testthat/test-results-utils.R +++ b/tests/testthat/test-results-utils.R @@ -1,6 +1,6 @@ test_that("results_to_df works as expected", { examples_path <- system.file("example_packages", package = "checked") - + expect_no_error( plan <- check_pkgs( file.path(examples_path, c("exampleGood", "exampleBad")), @@ -9,7 +9,7 @@ test_that("results_to_df works as expected", { reporter = NULL ) ) - + r <- results(plan) df <- results_to_df(r[[1]]) expect_equal(NROW(df), 2) diff --git a/tests/testthat/test-results.R b/tests/testthat/test-results.R deleted file mode 100644 index 1d21734..0000000 --- a/tests/testthat/test-results.R +++ /dev/null @@ -1,26 +0,0 @@ -# CRAN does not like out subprocesses tests resulting in false positive tests -# results -testthat::skip_on_cran() - -test_that("results_to_file works as expected", { - examples_path <- system.file("example_packages", package = "checked") - # WIP - expect_no_error(plan <- check_pkgs(c( - file.path(examples_path, "exampleGood"), - file.path(examples_path, "exampleBad") - ), n = 2L, repos = "https://cran.r-project.org/")) - - r <- results(plan) - r_file <- tempfile() - expect_no_error(results_to_file(r, r_file)) - expect_true(!identical(readLines(r_file), "No issues identified.")) - - expect_no_error(plan <- check_rev_deps(c( - file.path(examples_path, "exampleBad") - ), n = 2L, repos = "https://cran.r-project.org/")) - - r <- results(plan) - r_file <- tempfile() - expect_no_error(results_to_file(r, r_file)) - expect_true(identical(readLines(r_file), "No issues identified.")) -}) From 20e91115ed9342e5148893cd4d6cac3aba4b52c5 Mon Sep 17 00:00:00 2001 From: maksymis <32574056+maksymiuks@users.noreply.github.com> Date: Wed, 18 Feb 2026 16:12:03 +0100 Subject: [PATCH 45/62] Fix tests and lintr --- .../revdeps/v1/pkg.none.broken/DESCRIPTION | 16 ---------------- .../fixtures/revdeps/v1/pkg.none.broken/LICENSE | 2 -- .../revdeps/v1/pkg.none.broken/NAMESPACE | 3 --- .../fixtures/revdeps/v1/pkg.none.broken/R/hw.R | 6 ------ .../v1/pkg.none.broken/man/hello_world.Rd | 11 ----------- .../revdeps/v1/pkg.none.broken/tests/test_hw.R | 5 ----- 6 files changed, 43 deletions(-) delete mode 100644 tests/testthat/fixtures/revdeps/v1/pkg.none.broken/DESCRIPTION delete mode 100644 tests/testthat/fixtures/revdeps/v1/pkg.none.broken/LICENSE delete mode 100644 tests/testthat/fixtures/revdeps/v1/pkg.none.broken/NAMESPACE delete mode 100644 tests/testthat/fixtures/revdeps/v1/pkg.none.broken/R/hw.R delete mode 100644 tests/testthat/fixtures/revdeps/v1/pkg.none.broken/man/hello_world.Rd delete mode 100644 tests/testthat/fixtures/revdeps/v1/pkg.none.broken/tests/test_hw.R diff --git a/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/DESCRIPTION b/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/DESCRIPTION deleted file mode 100644 index 576eb7d..0000000 --- a/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/DESCRIPTION +++ /dev/null @@ -1,16 +0,0 @@ -Package: pkg.none.broken -Title: What the Package Does (One Line, Title Case) -Version: 1.0.0 -Authors@R: - person("First", "Last", , "first.last@example.com", role = c("aut", "cre"), - comment = c(ORCID = "YOUR-ORCID-ID")) -Description: What the package does (one paragraph). -License: MIT + file LICENSE -Encoding: UTF-8 -Roxygen: list(markdown = TRUE) -RoxygenNote: 7.1.2 -Suggests: pkg.suggests -NeedsCompilation: no -Packaged: 2024-11-06 13:34:08 UTC; maksymis -Author: First Last [aut, cre] (YOUR-ORCID-ID) -Maintainer: First Last diff --git a/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/LICENSE b/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/LICENSE deleted file mode 100644 index 482a651..0000000 --- a/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/LICENSE +++ /dev/null @@ -1,2 +0,0 @@ -YEAR: 2021 -COPYRIGHT HOLDER: pkg.none authors diff --git a/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/NAMESPACE b/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/NAMESPACE deleted file mode 100644 index da44dad..0000000 --- a/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/NAMESPACE +++ /dev/null @@ -1,3 +0,0 @@ -# Generated by roxygen2: do not edit by hand - -export(hello_world) diff --git a/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/R/hw.R b/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/R/hw.R deleted file mode 100644 index 65a0d15..0000000 --- a/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/R/hw.R +++ /dev/null @@ -1,6 +0,0 @@ -#' Hello world -#' -#' @export -hello_world <- function() { - "hello world!" -} diff --git a/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/man/hello_world.Rd b/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/man/hello_world.Rd deleted file mode 100644 index 5d01005..0000000 --- a/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/man/hello_world.Rd +++ /dev/null @@ -1,11 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/hw.R -\name{hello_world} -\alias{hello_world} -\title{Hello world} -\usage{ -hello_world() -} -\description{ -Hello world -} diff --git a/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/tests/test_hw.R b/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/tests/test_hw.R deleted file mode 100644 index ba7da94..0000000 --- a/tests/testthat/fixtures/revdeps/v1/pkg.none.broken/tests/test_hw.R +++ /dev/null @@ -1,5 +0,0 @@ -if (require("pkg.suggests", quietly = TRUE)) { - library(pkg.none) - stopifnot(hello_world() == "hello world") -} - From e8d26659dc43020719fd0771b3ff003efbb874de Mon Sep 17 00:00:00 2001 From: maksymis <32574056+maksymiuks@users.noreply.github.com> Date: Wed, 18 Feb 2026 16:13:04 +0100 Subject: [PATCH 46/62] Regenerate docs --- man/cli.Rd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/cli.Rd b/man/cli.Rd index 6f0762c..82c8741 100644 --- a/man/cli.Rd +++ b/man/cli.Rd @@ -14,7 +14,7 @@ cli_table_row( errors = "E", msg = "", style = c("row", "title", "header"), - symbols = list(bar = "│") + symbols = DEFAULT_ROW_SYMBOL ) cli_theme(..., .envir = parent.frame()) From e5e4cec1746ff71724a53dfb6aa00effd259dee6 Mon Sep 17 00:00:00 2001 From: maksymis <32574056+maksymiuks@users.noreply.github.com> Date: Wed, 18 Feb 2026 16:55:59 +0100 Subject: [PATCH 47/62] Fix tests --- R/utils-remotes.R | 2 +- man/as.package.remotes.Rd | 1 + tests/testthat/test-check-reverse.R | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/R/utils-remotes.R b/R/utils-remotes.R index 641376d..f66ace6 100644 --- a/R/utils-remotes.R +++ b/R/utils-remotes.R @@ -9,7 +9,7 @@ #' edits to further reduce `devtools` dependencies. #' #' @param x A package object to coerce -#' +#' @keywords internal as.package.remotes <- function(x) { if (inherits(x, "package")) { return(x) diff --git a/man/as.package.remotes.Rd b/man/as.package.remotes.Rd index c774495..094994f 100644 --- a/man/as.package.remotes.Rd +++ b/man/as.package.remotes.Rd @@ -20,3 +20,4 @@ Function required for communicating with the \code{remotes} package interface Code inspired by \code{devtools} \code{load_pkg_description} with very minor edits to further reduce \code{devtools} dependencies. } +\keyword{internal} diff --git a/tests/testthat/test-check-reverse.R b/tests/testthat/test-check-reverse.R index fb960a5..3304d93 100644 --- a/tests/testthat/test-check-reverse.R +++ b/tests/testthat/test-check-reverse.R @@ -109,7 +109,7 @@ test_that("check_rev_deps works for a package without a version in repos", { expect_true(is.list(r)) expect_length( list.dirs(file.path(design$output, "checks"), recursive = FALSE), - 2 + 4 ) expect_named(r) expect_length(r, 1L) @@ -132,7 +132,7 @@ test_that("check_rev_deps works for a package without a version in repos", { grepl("Running the tests in", r[[1]][[1]]$errors$issues) ) expect_true( - grepl("there is no package called", r[[1]][[1]]$errors$issues) + grepl("Reverse suggested deps detected", r[[1]][[1]]$errors$issues) ) expect_length(r[[1]][[1]]$errors$potential_issues$new, 0L) expect_length(r[[1]][[1]]$errors$potential_issues$old, 0L) @@ -154,7 +154,7 @@ test_that("check_rev_deps works for a package without a version in repos", { grepl("Running the tests in", r[[1]][[2]]$errors$issues) ) expect_true( - grepl("Reverse suggested deps detected", r[[1]][[2]]$errors$issues) + grepl("there is no package called", r[[1]][[2]]$errors$issues) ) expect_length(r[[1]][[2]]$errors$potential_issues$new, 0L) expect_length(r[[1]][[2]]$errors$potential_issues$old, 0L) From 856512e68be4fa0b55ab7d5caa76e33e1fa5ae18 Mon Sep 17 00:00:00 2001 From: maksymis <32574056+maksymiuks@users.noreply.github.com> Date: Wed, 18 Feb 2026 18:55:45 +0100 Subject: [PATCH 48/62] rework addressing in tests --- tests/testthat/test-check-reverse.R | 123 ++++++++++++++++------------ tests/testthat/test-check.R | 58 +++++++------ tests/testthat/test-results-utils.R | 1 + 3 files changed, 105 insertions(+), 77 deletions(-) diff --git a/tests/testthat/test-check-reverse.R b/tests/testthat/test-check-reverse.R index 3304d93..0f566ef 100644 --- a/tests/testthat/test-check-reverse.R +++ b/tests/testthat/test-check-reverse.R @@ -49,48 +49,55 @@ test_that("check_rev_deps works for package with one breaking change", { expect_named(r) expect_length(r, 1L) expect_length(r[[1]], 2L) - expect_s3_class(r[[1]], "rev_dep_dep_results") - expect_s3_class(r[[1]][[1]], "rcmdcheck_rev_dep_results") - expect_s3_class(r[[1]][[2]], "rcmdcheck_rev_dep_results") # rev.both.error - expect_length(r[[1]][[2]]$notes$issues, 0L) - expect_length(r[[1]][[2]]$notes$potential_issues$new, 0L) - expect_length(r[[1]][[2]]$notes$potential_issues$old, 0L) + both_error_i <- which(grepl("rev.both.error", names(r[[1]]), fixed = TRUE)) + expect_true(length(both_error_i) == 1) + r_both_error <- r[[1]][[both_error_i]] + expect_s3_class(r_both_error, "rcmdcheck_rev_dep_results") + + expect_length(r_both_error$notes$issues, 0L) + expect_length(r_both_error$notes$potential_issues$new, 0L) + expect_length(r_both_error$notes$potential_issues$old, 0L) - expect_length(r[[1]][[2]]$warnings$issues, 1L) + expect_length(r_both_error$warnings$issues, 1L) expect_true( grepl("Namespace in Imports field not imported from", - r[[1]][[2]]$warnings$issues), + r_both_error$warnings$issues), grepl("Missing or unexported object", - r[[1]][[2]]$warnings$issues) + r_both_error$warnings$issues) ) - expect_length(r[[1]][[2]]$warnings$potential_issues$new, 0L) - expect_length(r[[1]][[2]]$warnings$potential_issues$old, 0L) + expect_length(r_both_error$warnings$potential_issues$new, 0L) + expect_length(r_both_error$warnings$potential_issues$old, 0L) - expect_length(r[[1]][[2]]$errors$issues, 1L) + expect_length(r_both_error$errors$issues, 1L) expect_true( grepl("Running the tests in", - r[[1]][[2]]$errors$issues), + r_both_error$errors$issues), grepl("is not an exported object from", - r[[1]][[2]]$errors$issues) + r_both_error$errors$issues) ) - expect_length(r[[1]][[2]]$errors$potential_issues$new, 0L) - expect_length(r[[1]][[2]]$errors$potential_issues$old, 0L) + expect_length(r_both_error$errors$potential_issues$new, 0L) + expect_length(r_both_error$errors$potential_issues$old, 0L) # rev.both.ok - expect_length(r[[1]][[1]]$notes$issues, 0L) - expect_length(r[[1]][[1]]$notes$potential_issues$new, 0L) - expect_length(r[[1]][[1]]$notes$potential_issues$old, 0L) - - expect_length(r[[1]][[1]]$warnings$issues, 0L) - expect_length(r[[1]][[1]]$warnings$potential_issues$new, 0L) - expect_length(r[[1]][[1]]$warnings$potential_issues$old, 0L) - - expect_length(r[[1]][[1]]$errors$issues, 0L) - expect_length(r[[1]][[1]]$errors$potential_issues$new, 0L) - expect_length(r[[1]][[1]]$errors$potential_issues$old, 0L) + both_ok_i <- which(grepl("rev.both.ok", names(r[[1]]), fixed = TRUE)) + expect_true(length(both_ok_i) == 1) + r_both_ok <- r[[1]][[both_ok_i]] + expect_s3_class(r_both_ok, "rcmdcheck_rev_dep_results") + + expect_length(r_both_ok$notes$issues, 0L) + expect_length(r_both_ok$notes$potential_issues$new, 0L) + expect_length(r_both_ok$notes$potential_issues$old, 0L) + + expect_length(r_both_ok$warnings$issues, 0L) + expect_length(r_both_ok$warnings$potential_issues$new, 0L) + expect_length(r_both_ok$warnings$potential_issues$old, 0L) + + expect_length(r_both_ok$errors$issues, 0L) + expect_length(r_both_ok$errors$potential_issues$new, 0L) + expect_length(r_both_ok$errors$potential_issues$old, 0L) }) test_that("check_rev_deps works for a package without a version in repos", { @@ -117,45 +124,53 @@ test_that("check_rev_deps works for a package without a version in repos", { expect_s3_class(r[[1]], "rev_dep_dep_results") # pkg.none.broken - expect_s3_class(r[[1]][[1]], "rcmdcheck_rev_dep_results") + none_broken_i <- which(grepl("pkg.none.broken-", names(r[[1]]), fixed = TRUE)) + expect_true(length(none_broken_i) == 1) + r_none_broken <- r[[1]][[none_broken_i]] + expect_s3_class(r_none_broken, "rcmdcheck_rev_dep_results") - expect_length(r[[1]][[1]]$notes$issues, 0L) - expect_length(r[[1]][[1]]$notes$potential_issues$new, 0L) - expect_length(r[[1]][[1]]$notes$potential_issues$old, 0L) + expect_length(r_none_broken$notes$issues, 0L) + expect_length(r_none_broken$notes$potential_issues$new, 0L) + expect_length(r_none_broken$notes$potential_issues$old, 0L) - expect_length(r[[1]][[1]]$warnings$issues, 0L) - expect_length(r[[1]][[1]]$warnings$potential_issues$new, 0L) - expect_length(r[[1]][[1]]$warnings$potential_issues$old, 0L) + expect_length(r_none_broken$warnings$issues, 0L) + expect_length(r_none_broken$warnings$potential_issues$new, 0L) + expect_length(r_none_broken$warnings$potential_issues$old, 0L) - expect_length(r[[1]][[1]]$errors$issues, 1L) + expect_length(r_none_broken$errors$issues, 1L) expect_true( - grepl("Running the tests in", r[[1]][[1]]$errors$issues) + grepl("Running the tests in", r_none_broken$errors$issues) ) expect_true( - grepl("Reverse suggested deps detected", r[[1]][[1]]$errors$issues) + grepl("there is no package called", r_none_broken$errors$issues) ) - expect_length(r[[1]][[1]]$errors$potential_issues$new, 0L) - expect_length(r[[1]][[1]]$errors$potential_issues$old, 0L) + expect_length(r_none_broken$errors$potential_issues$new, 0L) + expect_length(r_none_broken$errors$potential_issues$old, 0L) # pkg.none - expect_s3_class(r[[1]][[2]], "rcmdcheck_rev_dep_results") - - expect_length(r[[1]][[2]]$notes$issues, 0L) - expect_length(r[[1]][[2]]$notes$potential_issues$new, 0L) - expect_length(r[[1]][[2]]$notes$potential_issues$old, 0L) - - expect_length(r[[1]][[2]]$warnings$issues, 0L) - expect_length(r[[1]][[2]]$warnings$potential_issues$new, 0L) - expect_length(r[[1]][[2]]$warnings$potential_issues$old, 0L) - - expect_length(r[[1]][[2]]$errors$issues, 1L) + none_i <- which(grepl("pkg.none-", names(r[[1]]))) + expect_true(length(none_i) == 1) + r_none <- r[[1]][[none_i]] + expect_s3_class(r_none, "rcmdcheck_rev_dep_results") + + expect_s3_class(r_none, "rcmdcheck_rev_dep_results") + + expect_length(r_none$notes$issues, 0L) + expect_length(r_none$notes$potential_issues$new, 0L) + expect_length(r_none$notes$potential_issues$old, 0L) + + expect_length(r_none$warnings$issues, 0L) + expect_length(r_none$warnings$potential_issues$new, 0L) + expect_length(r_none$warnings$potential_issues$old, 0L) + + expect_length(r_none$errors$issues, 1L) expect_true( - grepl("Running the tests in", r[[1]][[2]]$errors$issues) + grepl("Running the tests in", r_none$errors$issues) ) expect_true( - grepl("there is no package called", r[[1]][[2]]$errors$issues) + grepl("Reverse suggested deps detected", r_none$errors$issues) ) - expect_length(r[[1]][[2]]$errors$potential_issues$new, 0L) - expect_length(r[[1]][[2]]$errors$potential_issues$old, 0L) + expect_length(r_none$errors$potential_issues$new, 0L) + expect_length(r_none$errors$potential_issues$old, 0L) }) diff --git a/tests/testthat/test-check.R b/tests/testthat/test-check.R index 28968b5..db3830f 100644 --- a/tests/testthat/test-check.R +++ b/tests/testthat/test-check.R @@ -24,27 +24,39 @@ test_that("check_pkgs works as expected", { expect_s3_class(r[[1]], "local_check_results") - expect_length(r[[1]][[1]]$notes$issues, 1L) - expect_length(r[[1]][[1]]$notes$potential_issues$new, 0L) - expect_length(r[[1]][[1]]$notes$potential_issues$old, 0L) - - expect_length(r[[1]][[1]]$warnings$issues, 3L) - expect_length(r[[1]][[1]]$warnings$potential_issues$new, 0L) - expect_length(r[[1]][[1]]$warnings$potential_issues$old, 0L) - - expect_length(r[[1]][[1]]$errors$issues, 0L) - expect_length(r[[1]][[1]]$errors$potential_issues$new, 0L) - expect_length(r[[1]][[1]]$errors$potential_issues$old, 0L) - - expect_length(r[[1]][[2]]$notes$issues, 0L) - expect_length(r[[1]][[2]]$notes$potential_issues$new, 0L) - expect_length(r[[1]][[2]]$notes$potential_issues$old, 0L) - - expect_length(r[[1]][[2]]$warnings$issues, 0L) - expect_length(r[[1]][[2]]$warnings$potential_issues$new, 0L) - expect_length(r[[1]][[2]]$warnings$potential_issues$old, 0L) - - expect_length(r[[1]][[2]]$errors$issues, 0L) - expect_length(r[[1]][[2]]$errors$potential_issues$new, 0L) - expect_length(r[[1]][[2]]$errors$potential_issues$old, 0L) + # exampleBad + example_bad_i <- which(grepl("check-exampleBad", names(r[[1]]), fixed = TRUE)) + expect_true(length(example_bad_i) == 1) + r_example_bad <- r[[1]][[example_bad_i]] + expect_s3_class(r_example_bad, "rcmdcheck_check_results") + + expect_length(r_example_bad$notes$issues, 1L) + expect_length(r_example_bad$notes$potential_issues$new, 0L) + expect_length(r_example_bad$notes$potential_issues$old, 0L) + + expect_length(r_example_bad$warnings$issues, 3L) + expect_length(r_example_bad$warnings$potential_issues$new, 0L) + expect_length(r_example_bad$warnings$potential_issues$old, 0L) + + expect_length(r_example_bad$errors$issues, 0L) + expect_length(r_example_bad$errors$potential_issues$new, 0L) + expect_length(r_example_bad$errors$potential_issues$old, 0L) + + # exampleGood + example_good_i <- which(grepl("check-exampleGood", names(r[[1]]), fixed = TRUE)) + expect_true(length(example_good_i) == 1) + r_example_good <- r[[1]][[example_good_i]] + expect_s3_class(r_example_good, "rcmdcheck_check_results") + + expect_length(r_example_good$notes$issues, 0L) + expect_length(r_example_good$notes$potential_issues$new, 0L) + expect_length(r_example_good$notes$potential_issues$old, 0L) + + expect_length(r_example_good$warnings$issues, 0L) + expect_length(r_example_good$warnings$potential_issues$new, 0L) + expect_length(r_example_good$warnings$potential_issues$old, 0L) + + expect_length(r_example_good$errors$issues, 0L) + expect_length(r_example_good$errors$potential_issues$new, 0L) + expect_length(r_example_good$errors$potential_issues$old, 0L) }) diff --git a/tests/testthat/test-results-utils.R b/tests/testthat/test-results-utils.R index 3cd2d49..7617523 100644 --- a/tests/testthat/test-results-utils.R +++ b/tests/testthat/test-results-utils.R @@ -11,6 +11,7 @@ test_that("results_to_df works as expected", { ) r <- results(plan) + stop(r) df <- results_to_df(r[[1]]) expect_equal(NROW(df), 2) expect_equal(names(df), c("notes", "warnings", "errors")) From 93e1bd93dcb58768a3fd6f1aa85abf45ba62e9ec Mon Sep 17 00:00:00 2001 From: maksymis <32574056+maksymiuks@users.noreply.github.com> Date: Wed, 18 Feb 2026 23:29:22 +0100 Subject: [PATCH 49/62] Update deafult options --- R/options.R | 3 ++- man/options.Rd | 2 +- man/options_params.Rd | 2 +- tests/testthat/_snaps/reporters.md | 8 ++++---- tests/testthat/test-check.R | 5 +++-- tests/testthat/test-results-utils.R | 3 +-- 6 files changed, 12 insertions(+), 11 deletions(-) diff --git a/R/options.R b/R/options.R index ec80dfa..b14f62e 100644 --- a/R/options.R +++ b/R/options.R @@ -60,7 +60,8 @@ options::define_options( check_args = c( "--timings", "--ignore-vignettes", - "--no-manual" + "--no-manual", + "--as-cran" ), envvar_fn = structure( function(raw, ...) trimws(strsplit(raw, " ")[[1]]), diff --git a/man/options.Rd b/man/options.Rd index d39b1f0..978cd88 100644 --- a/man/options.Rd +++ b/man/options.Rd @@ -93,7 +93,7 @@ the R CMD check.\item{default: }{\preformatted{c(`_R_CHECK_FORCE_SUGGESTS_` = FA }} \item{check_args}{\describe{ -\code{character} vector of args passed to the R CMD check.\item{default: }{\preformatted{c("--timings", "--ignore-vignettes", "--no-manual")}} +\code{character} vector of args passed to the R CMD check.\item{default: }{\preformatted{c("--timings", "--ignore-vignettes", "--no-manual", "--as-cran")}} \item{option: }{checked.check_args} \item{envvar: }{R_CHECKED_CHECK_ARGS (space-separated R CMD check flags)} }} diff --git a/man/options_params.Rd b/man/options_params.Rd index a109c74..1342f98 100644 --- a/man/options_params.Rd +++ b/man/options_params.Rd @@ -16,7 +16,7 @@ are discovered when generating results. "never" means that no errors are thrown. If "issues" then errors are emitted only on issues, whereas "potential issues" stands for error on both issues and potential issues. (Defaults to \code{"never"}, overwritable using option 'checked.results_error_on' or environment variable 'R_CHECKED_RESULTS_ERROR_ON')} -\item{check_args}{\code{character} vector of args passed to the R CMD check. (Defaults to \code{c("--timings", "--ignore-vignettes", "--no-manual")}, overwritable using option 'checked.check_args' or environment variable 'R_CHECKED_CHECK_ARGS')} +\item{check_args}{\code{character} vector of args passed to the R CMD check. (Defaults to \code{c("--timings", "--ignore-vignettes", "--no-manual", "--as-cran")}, overwritable using option 'checked.check_args' or environment variable 'R_CHECKED_CHECK_ARGS')} \item{results_keep}{character vector indicating which packages should be included in the results. "all" means that all packages are kept. If "issues" then only packages diff --git a/tests/testthat/_snaps/reporters.md b/tests/testthat/_snaps/reporters.md index 6806e4f..3d618a1 100644 --- a/tests/testthat/_snaps/reporters.md +++ b/tests/testthat/_snaps/reporters.md @@ -17,12 +17,12 @@ [][install] pkg.ok.error started [][check] rev.both.ok started [][install] pkg.ok.error finished () - [][check] rev.both.ok finished with 1 NOTE () + [][check] rev.both.ok finished with 2 NOTES () [][check] rev.both.error started - [][check] rev.both.error finished with 1 NOTE () + [][check] rev.both.error finished with 2 NOTES () [][check] rev.both.ok started - [][check] rev.both.ok finished with 1 NOTE () + [][check] rev.both.ok finished with 2 NOTES () [][check] rev.both.error started - [][check] rev.both.error finished with 1 ERROR, 1 WARNING () + [][check] rev.both.error finished with 1 ERROR, 1 WARNING, 1 NOTE () Finished in diff --git a/tests/testthat/test-check.R b/tests/testthat/test-check.R index db3830f..cfd84fc 100644 --- a/tests/testthat/test-check.R +++ b/tests/testthat/test-check.R @@ -30,7 +30,7 @@ test_that("check_pkgs works as expected", { r_example_bad <- r[[1]][[example_bad_i]] expect_s3_class(r_example_bad, "rcmdcheck_check_results") - expect_length(r_example_bad$notes$issues, 1L) + expect_length(r_example_bad$notes$issues, 3L) expect_length(r_example_bad$notes$potential_issues$new, 0L) expect_length(r_example_bad$notes$potential_issues$old, 0L) @@ -48,7 +48,7 @@ test_that("check_pkgs works as expected", { r_example_good <- r[[1]][[example_good_i]] expect_s3_class(r_example_good, "rcmdcheck_check_results") - expect_length(r_example_good$notes$issues, 0L) + expect_length(r_example_good$notes$issues, 2L) expect_length(r_example_good$notes$potential_issues$new, 0L) expect_length(r_example_good$notes$potential_issues$old, 0L) @@ -60,3 +60,4 @@ test_that("check_pkgs works as expected", { expect_length(r_example_good$errors$potential_issues$new, 0L) expect_length(r_example_good$errors$potential_issues$old, 0L) }) + diff --git a/tests/testthat/test-results-utils.R b/tests/testthat/test-results-utils.R index 7617523..dd122e3 100644 --- a/tests/testthat/test-results-utils.R +++ b/tests/testthat/test-results-utils.R @@ -11,11 +11,10 @@ test_that("results_to_df works as expected", { ) r <- results(plan) - stop(r) df <- results_to_df(r[[1]]) expect_equal(NROW(df), 2) expect_equal(names(df), c("notes", "warnings", "errors")) - expect_equal(df$notes, c(1, 0)) + expect_equal(df$notes, c(3, 2)) expect_equal(df$warnings, c(3, 0)) expect_equal(df$errors, c(0, 0)) expect_true( From 2c357bac1bee04d0c2e97d7c0f3634bb2d865349 Mon Sep 17 00:00:00 2001 From: maksymis <32574056+maksymiuks@users.noreply.github.com> Date: Thu, 19 Feb 2026 00:52:32 +0100 Subject: [PATCH 50/62] Fix typo in tests --- tests/testthat/test-check-reverse.R | 10 ++++------ tests/testthat/test-check.R | 8 ++++---- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/tests/testthat/test-check-reverse.R b/tests/testthat/test-check-reverse.R index 0f566ef..8ecc574 100644 --- a/tests/testthat/test-check-reverse.R +++ b/tests/testthat/test-check-reverse.R @@ -73,10 +73,10 @@ test_that("check_rev_deps works for package with one breaking change", { expect_length(r_both_error$errors$issues, 1L) expect_true( - grepl("Running the tests in", - r_both_error$errors$issues), - grepl("is not an exported object from", - r_both_error$errors$issues) + grepl("Running the tests in", r_both_error$errors$issues) + ) + expect_true( + grepl("is not an exported object from", r_both_error$errors$issues) ) expect_length(r_both_error$errors$potential_issues$new, 0L) expect_length(r_both_error$errors$potential_issues$old, 0L) @@ -153,8 +153,6 @@ test_that("check_rev_deps works for a package without a version in repos", { expect_true(length(none_i) == 1) r_none <- r[[1]][[none_i]] expect_s3_class(r_none, "rcmdcheck_rev_dep_results") - - expect_s3_class(r_none, "rcmdcheck_rev_dep_results") expect_length(r_none$notes$issues, 0L) expect_length(r_none$notes$potential_issues$new, 0L) diff --git a/tests/testthat/test-check.R b/tests/testthat/test-check.R index cfd84fc..4c435bc 100644 --- a/tests/testthat/test-check.R +++ b/tests/testthat/test-check.R @@ -29,7 +29,7 @@ test_that("check_pkgs works as expected", { expect_true(length(example_bad_i) == 1) r_example_bad <- r[[1]][[example_bad_i]] expect_s3_class(r_example_bad, "rcmdcheck_check_results") - + expect_length(r_example_bad$notes$issues, 3L) expect_length(r_example_bad$notes$potential_issues$new, 0L) expect_length(r_example_bad$notes$potential_issues$old, 0L) @@ -43,11 +43,12 @@ test_that("check_pkgs works as expected", { expect_length(r_example_bad$errors$potential_issues$old, 0L) # exampleGood - example_good_i <- which(grepl("check-exampleGood", names(r[[1]]), fixed = TRUE)) + example_good_i <- + which(grepl("check-exampleGood", names(r[[1]]), fixed = TRUE)) expect_true(length(example_good_i) == 1) r_example_good <- r[[1]][[example_good_i]] expect_s3_class(r_example_good, "rcmdcheck_check_results") - + expect_length(r_example_good$notes$issues, 2L) expect_length(r_example_good$notes$potential_issues$new, 0L) expect_length(r_example_good$notes$potential_issues$old, 0L) @@ -60,4 +61,3 @@ test_that("check_pkgs works as expected", { expect_length(r_example_good$errors$potential_issues$new, 0L) expect_length(r_example_good$errors$potential_issues$old, 0L) }) - From 2eb57eb6100814cf583eb478d20e006008569ef1 Mon Sep 17 00:00:00 2001 From: maksymis <32574056+maksymiuks@users.noreply.github.com> Date: Thu, 19 Feb 2026 01:41:01 +0100 Subject: [PATCH 51/62] Fix multiple values in expect_true --- tests/testthat/test-check-reverse.R | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/testthat/test-check-reverse.R b/tests/testthat/test-check-reverse.R index 8ecc574..1082aa7 100644 --- a/tests/testthat/test-check-reverse.R +++ b/tests/testthat/test-check-reverse.R @@ -63,10 +63,13 @@ test_that("check_rev_deps works for package with one breaking change", { expect_length(r_both_error$warnings$issues, 1L) expect_true( - grepl("Namespace in Imports field not imported from", - r_both_error$warnings$issues), - grepl("Missing or unexported object", - r_both_error$warnings$issues) + grepl( + "Namespace in Imports field not imported from", + r_both_error$warnings$issues + ) + ) + expect_true( + grepl("Missing or unexported object", r_both_error$warnings$issues) ) expect_length(r_both_error$warnings$potential_issues$new, 0L) expect_length(r_both_error$warnings$potential_issues$old, 0L) From 335f4be85bcaeeec9d672acd1ab148c30bc65105 Mon Sep 17 00:00:00 2001 From: maksymis <32574056+maksymiuks@users.noreply.github.com> Date: Thu, 19 Feb 2026 15:31:58 +0100 Subject: [PATCH 52/62] Fix tests --- .github/workflows/R-CMD-check.yaml | 2 ++ tests/testthat/test-check-reverse.R | 6 ------ 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index f6fab3e..6cff329 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -29,6 +29,8 @@ jobs: env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} R_KEEP_PKG_SOURCE: yes + _R_CHECK_CRAN_INCOMING_: true + _R_CHECK_FORCE_SUGGESTS_: false NOT_CRAN: "true" steps: diff --git a/tests/testthat/test-check-reverse.R b/tests/testthat/test-check-reverse.R index 1082aa7..4a8f502 100644 --- a/tests/testthat/test-check-reverse.R +++ b/tests/testthat/test-check-reverse.R @@ -62,12 +62,6 @@ test_that("check_rev_deps works for package with one breaking change", { expect_length(r_both_error$notes$potential_issues$old, 0L) expect_length(r_both_error$warnings$issues, 1L) - expect_true( - grepl( - "Namespace in Imports field not imported from", - r_both_error$warnings$issues - ) - ) expect_true( grepl("Missing or unexported object", r_both_error$warnings$issues) ) From 72b4f824f291e292c91ae0f37eebb4969d3e9991 Mon Sep 17 00:00:00 2001 From: maksymis <32574056+maksymiuks@users.noreply.github.com> Date: Thu, 19 Feb 2026 16:12:00 +0100 Subject: [PATCH 53/62] Debug ci --- tests/testthat/test-check-reverse.R | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/testthat/test-check-reverse.R b/tests/testthat/test-check-reverse.R index 4a8f502..40464e5 100644 --- a/tests/testthat/test-check-reverse.R +++ b/tests/testthat/test-check-reverse.R @@ -65,6 +65,7 @@ test_that("check_rev_deps works for package with one breaking change", { expect_true( grepl("Missing or unexported object", r_both_error$warnings$issues) ) + stop(r_both_error$warnings) expect_length(r_both_error$warnings$potential_issues$new, 0L) expect_length(r_both_error$warnings$potential_issues$old, 0L) @@ -126,6 +127,7 @@ test_that("check_rev_deps works for a package without a version in repos", { r_none_broken <- r[[1]][[none_broken_i]] expect_s3_class(r_none_broken, "rcmdcheck_rev_dep_results") + stop(r_none_broken$notes) expect_length(r_none_broken$notes$issues, 0L) expect_length(r_none_broken$notes$potential_issues$new, 0L) expect_length(r_none_broken$notes$potential_issues$old, 0L) @@ -168,4 +170,11 @@ test_that("check_rev_deps works for a package without a version in repos", { ) expect_length(r_none$errors$potential_issues$new, 0L) expect_length(r_none$errors$potential_issues$old, 0L) + + # Plot works + expect_no_error(plot(design$graph)) + expect_no_error( + g_i <- plot(design$graph, interactive = TRUE) + ) + expect_s3_class(g_i, "visNetwork") }) From 44ffe96ff5fe142f1b5c21818b941c7da4dce109 Mon Sep 17 00:00:00 2001 From: maksymis <32574056+maksymiuks@users.noreply.github.com> Date: Thu, 19 Feb 2026 16:38:05 +0100 Subject: [PATCH 54/62] Update documentation tags --- NAMESPACE | 1 + R/lib.R | 4 ++++ R/next_task.R | 5 ++++- R/package.R | 1 + R/task.R | 3 +++ R/utils-cli.R | 4 ++++ R/utils-deps.R | 1 + R/utils-igraph.R | 2 ++ _pkgdown.yml | 6 +++++- man/check_task.Rd | 1 + man/checked-package.Rd | 1 + man/fmt.Rd | 1 + man/graph_dedup_attrs.Rd | 1 + man/install_task.Rd | 1 + man/lib.Rd | 1 + man/lib_path.Rd | 1 + man/meta_task.Rd | 7 +++++++ man/pkg_dependencies.Rd | 1 + man/start_task.Rd | 1 + man/task.Rd | 3 ++- man/task_formats.Rd | 1 + man/task_graph_libpaths.Rd | 1 + tests/testthat/test-check-reverse.R | 2 -- 23 files changed, 45 insertions(+), 5 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 426b05d..838c894 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -129,6 +129,7 @@ export(check_rev_deps) export(check_task) export(checker) export(install_task) +export(meta_task) export(new_checker) export(new_rev_dep_checker) export(pkg_origin) diff --git a/R/lib.R b/R/lib.R index 5a5c0f3..c1194e8 100644 --- a/R/lib.R +++ b/R/lib.R @@ -8,6 +8,8 @@ #' @param x A [`pkg_origin()`] object used for default dispatch. #' @param ... Additional values #' @param .class An optional subclass, used primarily for dispatch. +#' +#' @keywords specs lib_path <- function(x, ..., .class = c()) { UseMethod("lib_path") } @@ -56,6 +58,8 @@ format.lib_path <- function(x, ...) { #' @param lib.root A root directory for the isolated library. #' @param dir_hash unique identifier of the isolated library #' @param name human-readable subname of the isolated library +#' +#' @keywords internal lib <- function(x, ...) { UseMethod("lib") } diff --git a/R/next_task.R b/R/next_task.R index 46b28a6..4abc9be 100644 --- a/R/next_task.R +++ b/R/next_task.R @@ -8,7 +8,8 @@ #' @param node Node(s) for which libpath should be constructed based on `g` #' @param output Path to the checked output directory #' @inheritParams lib - +#' +#' @keywords internal task_graph_libpaths <- function( g, node = NULL, @@ -41,6 +42,8 @@ task_graph_libpaths <- function( #' #' @inheritParams task_graph_libpaths #' @param ... additional params passed to downstream methods +#' +#' @keywords internal start_task <- function(node, g, ...) { UseMethod("start_task") } diff --git a/R/package.R b/R/package.R index 6206b3b..a1307de 100644 --- a/R/package.R +++ b/R/package.R @@ -1,4 +1,5 @@ #' @importFrom igraph E V #' @importFrom memoise memoise #' @importFrom rlang hash +#' @keywords internal "_PACKAGE" diff --git a/R/task.R b/R/task.R index 4c9cd47..1a7a96b 100644 --- a/R/task.R +++ b/R/task.R @@ -23,6 +23,9 @@ task <- function(..., .subclass = NULL) { #' @param ... Objects passed to specified class functions #' @param .subclass character name of the subclass. It will be appended with #' "_meta" suffix. +#' +#' @family tasks +#' @export meta_task <- function(..., .subclass = NULL) { task(..., .subclass = c(sprintf("%s_meta", .subclass), "meta")) } diff --git a/R/utils-cli.R b/R/utils-cli.R index d8dd458..df0a45e 100644 --- a/R/utils-cli.R +++ b/R/utils-cli.R @@ -8,6 +8,8 @@ #' @param nodes graph nodes to format. #' @param task task to format. #' @param tasks currently unused. +#' +#' @keywords internal task_formats <- function( g = NULL, nodes = V(g), @@ -107,6 +109,8 @@ task_formats <- function( #' #' # Examples for unexported functions are not supported #' # fmt(task = task, "{action} {package} ({version}) from {source}") +#' +#' @keywords internal fmt <- function( ..., g, diff --git a/R/utils-deps.R b/R/utils-deps.R index 16cb37b..3122dcd 100644 --- a/R/utils-deps.R +++ b/R/utils-deps.R @@ -61,6 +61,7 @@ as_pkg_dependencies <- function(x) { #' `"all"`, `"most"`, `"hard"` or `"soft"`, `NA` or a vector of dependency #' types compatible with [`as_pkg_dependencies()`] function. #' +#' @keywords internal pkg_dependencies <- function( packages, dependencies = TRUE, diff --git a/R/utils-igraph.R b/R/utils-igraph.R index e199a4f..4a993e2 100644 --- a/R/utils-igraph.R +++ b/R/utils-igraph.R @@ -47,6 +47,8 @@ star_graph <- function(...) { #' taking the attribute from the first non-NA value observed. #' #' @param g task_graph object +#' +#' @keywords internal graph_dedup_attrs <- function(g) { # pattern appended to duplicated attributes re <- "_\\d+$" diff --git a/_pkgdown.yml b/_pkgdown.yml index d74d436..6ca5575 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -9,9 +9,13 @@ reference: contents: - run - - title: Designing Check Sets + - title: Designing and Runing Check Sets contents: - has_concept("checks") + + - title: Plan checks + contents: + - has_concept("plan") - title: Building Tasks contents: diff --git a/man/check_task.Rd b/man/check_task.Rd index 128f112..420d96c 100644 --- a/man/check_task.Rd +++ b/man/check_task.Rd @@ -36,6 +36,7 @@ Create a task to run \verb{R CMD check} \seealso{ Other tasks: \code{\link{install_task}()}, +\code{\link{meta_task}()}, \code{\link{task}()} } \concept{tasks} diff --git a/man/checked-package.Rd b/man/checked-package.Rd index 2a4a1ac..033a5c5 100644 --- a/man/checked-package.Rd +++ b/man/checked-package.Rd @@ -31,3 +31,4 @@ Other contributors: } } +\keyword{internal} diff --git a/man/fmt.Rd b/man/fmt.Rd index 70cc961..8413048 100644 --- a/man/fmt.Rd +++ b/man/fmt.Rd @@ -23,3 +23,4 @@ fmt(..., g, nodes, task = NULL, .envir = parent.frame(), ansi = TRUE) Provided a task, allows for use of a handful of shorthand symbols which will use the task as a context for formatting task fields. } +\keyword{internal} diff --git a/man/graph_dedup_attrs.Rd b/man/graph_dedup_attrs.Rd index 9518308..5c3112e 100644 --- a/man/graph_dedup_attrs.Rd +++ b/man/graph_dedup_attrs.Rd @@ -15,3 +15,4 @@ which adds duplicated attributes when attributes of the same name exist in multiple graphs. Searches for suffixes and consolidates attributes, taking the attribute from the first non-NA value observed. } +\keyword{internal} diff --git a/man/install_task.Rd b/man/install_task.Rd index 5747ab0..0663971 100644 --- a/man/install_task.Rd +++ b/man/install_task.Rd @@ -46,6 +46,7 @@ Create a task to install a package and dependencies \seealso{ Other tasks: \code{\link{check_task}()}, +\code{\link{meta_task}()}, \code{\link{task}()} } \concept{tasks} diff --git a/man/lib.Rd b/man/lib.Rd index 8797a13..f317aef 100644 --- a/man/lib.Rd +++ b/man/lib.Rd @@ -49,3 +49,4 @@ lib(x, ...) \description{ Get Library Location } +\keyword{internal} diff --git a/man/lib_path.Rd b/man/lib_path.Rd index b5975e3..672bcb7 100644 --- a/man/lib_path.Rd +++ b/man/lib_path.Rd @@ -25,3 +25,4 @@ necessary information to determine where a package should be installed. lib_path method creates default path handlers for given pkg origin while lib_path_x creates an actual object. } +\keyword{specs} diff --git a/man/meta_task.Rd b/man/meta_task.Rd index c8e34e6..0662a62 100644 --- a/man/meta_task.Rd +++ b/man/meta_task.Rd @@ -16,3 +16,10 @@ meta_task(..., .subclass = NULL) Meta tasks are tasks which are not intended to perform computation. They exist simply to provide relationships among computational tasks. } +\seealso{ +Other tasks: +\code{\link{check_task}()}, +\code{\link{install_task}()}, +\code{\link{task}()} +} +\concept{tasks} diff --git a/man/pkg_dependencies.Rd b/man/pkg_dependencies.Rd index 6ee86bb..b1404d4 100644 --- a/man/pkg_dependencies.Rd +++ b/man/pkg_dependencies.Rd @@ -33,3 +33,4 @@ Inspired by \code{tools::package_dependencies}, but with the added benefit of recording the dependency type and relationships throughout the dependency tree. } +\keyword{internal} diff --git a/man/start_task.Rd b/man/start_task.Rd index 15e7dd3..5501243 100644 --- a/man/start_task.Rd +++ b/man/start_task.Rd @@ -18,3 +18,4 @@ Starts task based on the \code{task} object encapsulated in the \code{node} take from then \code{task_graph} \code{g}. It returns an \code{install_process} or \code{check_process} \code{R6} object. } +\keyword{internal} diff --git a/man/task.Rd b/man/task.Rd index cad6a36..564921a 100644 --- a/man/task.Rd +++ b/man/task.Rd @@ -22,6 +22,7 @@ related tasks. \seealso{ Other tasks: \code{\link{check_task}()}, -\code{\link{install_task}()} +\code{\link{install_task}()}, +\code{\link{meta_task}()} } \concept{tasks} diff --git a/man/task_formats.Rd b/man/task_formats.Rd index 66ef536..b9eab99 100644 --- a/man/task_formats.Rd +++ b/man/task_formats.Rd @@ -20,3 +20,4 @@ This bit of code is intended for use with \code{\link[=fmt]{fmt()}}, and allows to layer symbol bindings on top of the environment used for string interpolation which provide syntactic sugar for common formatting components. } +\keyword{internal} diff --git a/man/task_graph_libpaths.Rd b/man/task_graph_libpaths.Rd index aeba3f5..9e8c836 100644 --- a/man/task_graph_libpaths.Rd +++ b/man/task_graph_libpaths.Rd @@ -20,3 +20,4 @@ Function that traverses over the task dependency task to acquire libpaths for given nodes. It ensures that when runing a node, a libpath is constructed which has all the required packages on it. } +\keyword{internal} diff --git a/tests/testthat/test-check-reverse.R b/tests/testthat/test-check-reverse.R index 40464e5..eabe344 100644 --- a/tests/testthat/test-check-reverse.R +++ b/tests/testthat/test-check-reverse.R @@ -65,7 +65,6 @@ test_that("check_rev_deps works for package with one breaking change", { expect_true( grepl("Missing or unexported object", r_both_error$warnings$issues) ) - stop(r_both_error$warnings) expect_length(r_both_error$warnings$potential_issues$new, 0L) expect_length(r_both_error$warnings$potential_issues$old, 0L) @@ -127,7 +126,6 @@ test_that("check_rev_deps works for a package without a version in repos", { r_none_broken <- r[[1]][[none_broken_i]] expect_s3_class(r_none_broken, "rcmdcheck_rev_dep_results") - stop(r_none_broken$notes) expect_length(r_none_broken$notes$issues, 0L) expect_length(r_none_broken$notes$potential_issues$new, 0L) expect_length(r_none_broken$notes$potential_issues$old, 0L) From d1a4c9e869baeacd7c5610819744bec157f72bba Mon Sep 17 00:00:00 2001 From: maksymis <32574056+maksymiuks@users.noreply.github.com> Date: Thu, 19 Feb 2026 17:55:12 +0100 Subject: [PATCH 55/62] Fix docs --- .github/workflows/R-CMD-check.yaml | 1 - R/lib.R | 6 +++--- R/next_task.R | 4 ++-- R/options.R | 3 ++- R/task.R | 2 +- R/utils-cli.R | 4 ++-- R/utils-igraph.R | 2 +- man/lib_path.Rd | 6 +++++- man/options.Rd | 3 ++- man/options_params.Rd | 2 +- man/pkg_origin.Rd | 4 ++++ 11 files changed, 23 insertions(+), 14 deletions(-) diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index 6cff329..feb9011 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -24,7 +24,6 @@ jobs: - {os: windows-latest, r: 'release'} - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} - {os: ubuntu-latest, r: 'release'} - - {os: ubuntu-latest, r: 'oldrel-1'} env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} diff --git a/R/lib.R b/R/lib.R index c1194e8..5cdb860 100644 --- a/R/lib.R +++ b/R/lib.R @@ -8,8 +8,8 @@ #' @param x A [`pkg_origin()`] object used for default dispatch. #' @param ... Additional values #' @param .class An optional subclass, used primarily for dispatch. -#' -#' @keywords specs +#' +#' @family specs lib_path <- function(x, ..., .class = c()) { UseMethod("lib_path") } @@ -58,7 +58,7 @@ format.lib_path <- function(x, ...) { #' @param lib.root A root directory for the isolated library. #' @param dir_hash unique identifier of the isolated library #' @param name human-readable subname of the isolated library -#' +#' #' @keywords internal lib <- function(x, ...) { UseMethod("lib") diff --git a/R/next_task.R b/R/next_task.R index 4abc9be..b832ba1 100644 --- a/R/next_task.R +++ b/R/next_task.R @@ -8,7 +8,7 @@ #' @param node Node(s) for which libpath should be constructed based on `g` #' @param output Path to the checked output directory #' @inheritParams lib -#' +#' #' @keywords internal task_graph_libpaths <- function( g, @@ -42,7 +42,7 @@ task_graph_libpaths <- function( #' #' @inheritParams task_graph_libpaths #' @param ... additional params passed to downstream methods -#' +#' #' @keywords internal start_task <- function(node, g, ...) { UseMethod("start_task") diff --git a/R/options.R b/R/options.R index b14f62e..64ea9aa 100644 --- a/R/options.R +++ b/R/options.R @@ -43,7 +43,8 @@ options::define_options( "_R_CHECK_FORCE_SUGGESTS_" = FALSE, "_R_CHECK_RD_XREFS_" = FALSE, "_R_CHECK_SYSTEM_CLOCK_" = FALSE, - "_R_CHECK_SUGGESTS_ONLY_" = TRUE + "_R_CHECK_SUGGESTS_ONLY_" = TRUE, + "_R_CHECK_CRAN_INCOMING_=" = TRUE ), "`character` vector of args passed to the R CMD build.", diff --git a/R/task.R b/R/task.R index 1a7a96b..fd32ff6 100644 --- a/R/task.R +++ b/R/task.R @@ -23,7 +23,7 @@ task <- function(..., .subclass = NULL) { #' @param ... Objects passed to specified class functions #' @param .subclass character name of the subclass. It will be appended with #' "_meta" suffix. -#' +#' #' @family tasks #' @export meta_task <- function(..., .subclass = NULL) { diff --git a/R/utils-cli.R b/R/utils-cli.R index df0a45e..4ca87c3 100644 --- a/R/utils-cli.R +++ b/R/utils-cli.R @@ -8,7 +8,7 @@ #' @param nodes graph nodes to format. #' @param task task to format. #' @param tasks currently unused. -#' +#' #' @keywords internal task_formats <- function( g = NULL, @@ -109,7 +109,7 @@ task_formats <- function( #' #' # Examples for unexported functions are not supported #' # fmt(task = task, "{action} {package} ({version}) from {source}") -#' +#' #' @keywords internal fmt <- function( ..., diff --git a/R/utils-igraph.R b/R/utils-igraph.R index 4a993e2..3b74be3 100644 --- a/R/utils-igraph.R +++ b/R/utils-igraph.R @@ -47,7 +47,7 @@ star_graph <- function(...) { #' taking the attribute from the first non-NA value observed. #' #' @param g task_graph object -#' +#' #' @keywords internal graph_dedup_attrs <- function(g) { # pattern appended to duplicated attributes diff --git a/man/lib_path.Rd b/man/lib_path.Rd index 672bcb7..0d5ddbb 100644 --- a/man/lib_path.Rd +++ b/man/lib_path.Rd @@ -25,4 +25,8 @@ necessary information to determine where a package should be installed. lib_path method creates default path handlers for given pkg origin while lib_path_x creates an actual object. } -\keyword{specs} +\seealso{ +Other specs: +\code{\link{pkg_origin}()} +} +\concept{specs} diff --git a/man/options.Rd b/man/options.Rd index 978cd88..1b2ee17 100644 --- a/man/options.Rd +++ b/man/options.Rd @@ -81,7 +81,8 @@ constrocuting a plan \code{task_grap}\item{default: }{\preformatted{TRUE}} \item{check_envvars}{\describe{ named \code{character} vector of environment variables to use during the R CMD check.\item{default: }{\preformatted{c(`_R_CHECK_FORCE_SUGGESTS_` = FALSE, `_R_CHECK_RD_XREFS_` = FALSE, - `_R_CHECK_SYSTEM_CLOCK_` = FALSE, `_R_CHECK_SUGGESTS_ONLY_` = TRUE)}} + `_R_CHECK_SYSTEM_CLOCK_` = FALSE, `_R_CHECK_SUGGESTS_ONLY_` = TRUE, + `_R_CHECK_CRAN_INCOMING_=` = TRUE)}} \item{option: }{checked.check_envvars} \item{envvar: }{R_CHECKED_CHECK_ENVVARS (evaluated if possible, raw string otherwise)} }} diff --git a/man/options_params.Rd b/man/options_params.Rd index 1342f98..f149756 100644 --- a/man/options_params.Rd +++ b/man/options_params.Rd @@ -28,7 +28,7 @@ should be scanned for packages in the \code{remotes} field and added while constrocuting a plan \code{task_grap} (Defaults to \code{TRUE}, overwritable using option 'checked.add_remotes' or environment variable 'R_CHECKED_ADD_REMOTES')} \item{check_envvars}{named \code{character} vector of environment variables to use during -the R CMD check. (Defaults to \verb{c(}\emph{R_CHECK_FORCE_SUGGESTS}\verb{= FALSE,}\emph{R_CHECK_RD_XREFS}\verb{= FALSE, ; }\emph{R_CHECK_SYSTEM_CLOCK}\verb{= FALSE,}\emph{R_CHECK_SUGGESTS_ONLY}\verb{ = TRUE)}, overwritable using option 'checked.check_envvars' or environment variable 'R_CHECKED_CHECK_ENVVARS')} +the R CMD check. (Defaults to \verb{c(}\emph{R_CHECK_FORCE_SUGGESTS}\verb{= FALSE,}\emph{R_CHECK_RD_XREFS}\verb{= FALSE, ; }\emph{R_CHECK_SYSTEM_CLOCK}\verb{= FALSE,}\emph{R_CHECK_SUGGESTS_ONLY}\verb{= TRUE, ; }\emph{R_CHECK_CRAN_INCOMING}=\verb{ = TRUE)}, overwritable using option 'checked.check_envvars' or environment variable 'R_CHECKED_CHECK_ENVVARS')} \item{tty_tick_interval}{tty refresh interval when reporting results in milliseconds (Defaults to \code{0.1}, overwritable using option 'checked.tty_tick_interval' or environment variable 'R_CHECKED_TTY_TICK_INTERVAL')} diff --git a/man/pkg_origin.Rd b/man/pkg_origin.Rd index 8ab652b..333ced9 100644 --- a/man/pkg_origin.Rd +++ b/man/pkg_origin.Rd @@ -46,4 +46,8 @@ non-standard packages.} Create package specification list which consists of all the details required to identify and acquire source of the package. } +\seealso{ +Other specs: +\code{\link{lib_path}()} +} \concept{specs} From 0a9124f2ba9ead9c930b23e3bd9789fd78d698df Mon Sep 17 00:00:00 2001 From: maksymiuks <32574056+maksymiuks@users.noreply.github.com> Date: Thu, 19 Feb 2026 20:27:39 +0100 Subject: [PATCH 56/62] fix typo in params --- DESCRIPTION | 2 +- R/options.R | 10 +++++----- man/options.Rd | 6 +++--- man/options_params.Rd | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 9bab253..c22d221 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -47,7 +47,7 @@ Imports: utils (>= 3.6.2), tools Roxygen: list(markdown = TRUE) -RoxygenNote: 7.3.2 +RoxygenNote: 7.3.3 Suggests: remotes, testthat (>= 3.0.0), diff --git a/R/options.R b/R/options.R index 64ea9aa..e5be46d 100644 --- a/R/options.R +++ b/R/options.R @@ -40,11 +40,11 @@ options::define_options( "named `character` vector of environment variables to use during the R CMD check.", check_envvars = c( - "_R_CHECK_FORCE_SUGGESTS_" = FALSE, - "_R_CHECK_RD_XREFS_" = FALSE, - "_R_CHECK_SYSTEM_CLOCK_" = FALSE, - "_R_CHECK_SUGGESTS_ONLY_" = TRUE, - "_R_CHECK_CRAN_INCOMING_=" = TRUE + "_R_CHECK_FORCE_SUGGESTS_" = "false", + "_R_CHECK_RD_XREFS_" = "false", + "_R_CHECK_SYSTEM_CLOCK_" = "false", + "_R_CHECK_SUGGESTS_ONLY_" = "true", + "_R_CHECK_CRAN_INCOMING_" = "false" ), "`character` vector of args passed to the R CMD build.", diff --git a/man/options.Rd b/man/options.Rd index 1b2ee17..c00ce40 100644 --- a/man/options.Rd +++ b/man/options.Rd @@ -80,9 +80,9 @@ constrocuting a plan \code{task_grap}\item{default: }{\preformatted{TRUE}} \item{check_envvars}{\describe{ named \code{character} vector of environment variables to use during -the R CMD check.\item{default: }{\preformatted{c(`_R_CHECK_FORCE_SUGGESTS_` = FALSE, `_R_CHECK_RD_XREFS_` = FALSE, - `_R_CHECK_SYSTEM_CLOCK_` = FALSE, `_R_CHECK_SUGGESTS_ONLY_` = TRUE, - `_R_CHECK_CRAN_INCOMING_=` = TRUE)}} +the R CMD check.\item{default: }{\preformatted{c(`_R_CHECK_FORCE_SUGGESTS_` = "false", `_R_CHECK_RD_XREFS_` = "false", + `_R_CHECK_SYSTEM_CLOCK_` = "false", `_R_CHECK_SUGGESTS_ONLY_` = "true", + `_R_CHECK_CRAN_INCOMING_` = "false")}} \item{option: }{checked.check_envvars} \item{envvar: }{R_CHECKED_CHECK_ENVVARS (evaluated if possible, raw string otherwise)} }} diff --git a/man/options_params.Rd b/man/options_params.Rd index f149756..4e68647 100644 --- a/man/options_params.Rd +++ b/man/options_params.Rd @@ -28,7 +28,7 @@ should be scanned for packages in the \code{remotes} field and added while constrocuting a plan \code{task_grap} (Defaults to \code{TRUE}, overwritable using option 'checked.add_remotes' or environment variable 'R_CHECKED_ADD_REMOTES')} \item{check_envvars}{named \code{character} vector of environment variables to use during -the R CMD check. (Defaults to \verb{c(}\emph{R_CHECK_FORCE_SUGGESTS}\verb{= FALSE,}\emph{R_CHECK_RD_XREFS}\verb{= FALSE, ; }\emph{R_CHECK_SYSTEM_CLOCK}\verb{= FALSE,}\emph{R_CHECK_SUGGESTS_ONLY}\verb{= TRUE, ; }\emph{R_CHECK_CRAN_INCOMING}=\verb{ = TRUE)}, overwritable using option 'checked.check_envvars' or environment variable 'R_CHECKED_CHECK_ENVVARS')} +the R CMD check. (Defaults to \verb{c(}\emph{R_CHECK_FORCE_SUGGESTS}\verb{= "false",}\emph{R_CHECK_RD_XREFS}\verb{= "false", ; }\emph{R_CHECK_SYSTEM_CLOCK}\verb{= "false",}\emph{R_CHECK_SUGGESTS_ONLY}\verb{= "true", ; }\emph{R_CHECK_CRAN_INCOMING}\verb{ = "false")}, overwritable using option 'checked.check_envvars' or environment variable 'R_CHECKED_CHECK_ENVVARS')} \item{tty_tick_interval}{tty refresh interval when reporting results in milliseconds (Defaults to \code{0.1}, overwritable using option 'checked.tty_tick_interval' or environment variable 'R_CHECKED_TTY_TICK_INTERVAL')} From 81e0e568e10d26188c875533aeaf872269e15222 Mon Sep 17 00:00:00 2001 From: maksymiuks <32574056+maksymiuks@users.noreply.github.com> Date: Thu, 19 Feb 2026 20:38:42 +0100 Subject: [PATCH 57/62] Meet CRAN core requirements --- tests/testthat.R | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/tests/testthat.R b/tests/testthat.R index 78ec056..973b76d 100644 --- a/tests/testthat.R +++ b/tests/testthat.R @@ -1,12 +1,6 @@ -# This file is part of the standard setup for testthat. -# It is recommended that you do not modify it. -# -# Where should you do additional test configuration? -# Learn more about the roles of various files in: -# * https://r-pkgs.org/testing-design.html#sec-tests-files-overview -# * https://testthat.r-lib.org/articles/special-files.html - library(testthat) library(checked) +# Meet CRAN multiple core usage requirement +Sys.setenv("OMP_THREAD_LIMIT" = 2) test_check("checked") From 0fe93d5e36e318c4978e21deb454690ee34d2c04 Mon Sep 17 00:00:00 2001 From: maksymis <32574056+maksymiuks@users.noreply.github.com> Date: Thu, 19 Feb 2026 23:51:29 +0100 Subject: [PATCH 58/62] Update tests --- tests/testthat/test-check.R | 4 ++-- tests/testthat/test-results-utils.R | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/testthat/test-check.R b/tests/testthat/test-check.R index 4c435bc..9ca6c7f 100644 --- a/tests/testthat/test-check.R +++ b/tests/testthat/test-check.R @@ -30,7 +30,7 @@ test_that("check_pkgs works as expected", { r_example_bad <- r[[1]][[example_bad_i]] expect_s3_class(r_example_bad, "rcmdcheck_check_results") - expect_length(r_example_bad$notes$issues, 3L) + expect_length(r_example_bad$notes$issues, 2L) expect_length(r_example_bad$notes$potential_issues$new, 0L) expect_length(r_example_bad$notes$potential_issues$old, 0L) @@ -49,7 +49,7 @@ test_that("check_pkgs works as expected", { r_example_good <- r[[1]][[example_good_i]] expect_s3_class(r_example_good, "rcmdcheck_check_results") - expect_length(r_example_good$notes$issues, 2L) + expect_length(r_example_good$notes$issues, 0L) expect_length(r_example_good$notes$potential_issues$new, 0L) expect_length(r_example_good$notes$potential_issues$old, 0L) diff --git a/tests/testthat/test-results-utils.R b/tests/testthat/test-results-utils.R index dd122e3..aaaec53 100644 --- a/tests/testthat/test-results-utils.R +++ b/tests/testthat/test-results-utils.R @@ -14,7 +14,7 @@ test_that("results_to_df works as expected", { df <- results_to_df(r[[1]]) expect_equal(NROW(df), 2) expect_equal(names(df), c("notes", "warnings", "errors")) - expect_equal(df$notes, c(3, 2)) + expect_equal(df$notes, c(2, 0)) expect_equal(df$warnings, c(3, 0)) expect_equal(df$errors, c(0, 0)) expect_true( From c263a367671cbadaee10a684da0e927be46b11fe Mon Sep 17 00:00:00 2001 From: maksymis <32574056+maksymiuks@users.noreply.github.com> Date: Fri, 20 Feb 2026 00:24:01 +0100 Subject: [PATCH 59/62] Meet cran cores requirements --- tests/testthat.R | 1 - tests/testthat/_snaps/reporters.md | 8 ++++---- tests/testthat/test-check-reverse.R | 6 +++--- tests/testthat/test-check.R | 2 +- tests/testthat/test-results-utils.R | 2 +- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/tests/testthat.R b/tests/testthat.R index 973b76d..2b27e56 100644 --- a/tests/testthat.R +++ b/tests/testthat.R @@ -2,5 +2,4 @@ library(testthat) library(checked) # Meet CRAN multiple core usage requirement -Sys.setenv("OMP_THREAD_LIMIT" = 2) test_check("checked") diff --git a/tests/testthat/_snaps/reporters.md b/tests/testthat/_snaps/reporters.md index 3d618a1..6806e4f 100644 --- a/tests/testthat/_snaps/reporters.md +++ b/tests/testthat/_snaps/reporters.md @@ -17,12 +17,12 @@ [][install] pkg.ok.error started [][check] rev.both.ok started [][install] pkg.ok.error finished () - [][check] rev.both.ok finished with 2 NOTES () + [][check] rev.both.ok finished with 1 NOTE () [][check] rev.both.error started - [][check] rev.both.error finished with 2 NOTES () + [][check] rev.both.error finished with 1 NOTE () [][check] rev.both.ok started - [][check] rev.both.ok finished with 2 NOTES () + [][check] rev.both.ok finished with 1 NOTE () [][check] rev.both.error started - [][check] rev.both.error finished with 1 ERROR, 1 WARNING, 1 NOTE () + [][check] rev.both.error finished with 1 ERROR, 1 WARNING () Finished in diff --git a/tests/testthat/test-check-reverse.R b/tests/testthat/test-check-reverse.R index eabe344..b79fdf1 100644 --- a/tests/testthat/test-check-reverse.R +++ b/tests/testthat/test-check-reverse.R @@ -19,7 +19,7 @@ test_that("check_rev_deps works for package with no revdeps", { expect_no_error( checks <- check_rev_deps( file.path(sources_new, "pkg.none"), - n = 2L, + n = 1L, repos = repo, reporter = NULL ) @@ -37,7 +37,7 @@ test_that("check_rev_deps works for package with one breaking change", { withr::with_options(list(pkgType = "source"), { design <- check_rev_deps( file.path(sources_new, "pkg.ok.error"), - n = 2L, + n = 1L, repos = repo, reporter = NULL ) @@ -102,7 +102,7 @@ test_that("check_rev_deps works for a package without a version in repos", { withr::with_options(list(pkgType = "source"), { expect_no_error(design <- check_rev_deps( file.path(sources_new, "pkg.suggests"), - n = 2L, + n = 1L, repos = repo, reporter = NULL )) diff --git a/tests/testthat/test-check.R b/tests/testthat/test-check.R index 9ca6c7f..7e3c721 100644 --- a/tests/testthat/test-check.R +++ b/tests/testthat/test-check.R @@ -4,7 +4,7 @@ test_that("check_pkgs works as expected", { expect_no_error( plan <- check_pkgs( file.path(examples_path, c("exampleGood", "exampleBad")), - n = 2L, + n = 1L, repos = "https://cran.r-project.org/", reporter = NULL, lib.loc = .libPaths() diff --git a/tests/testthat/test-results-utils.R b/tests/testthat/test-results-utils.R index aaaec53..538d3b7 100644 --- a/tests/testthat/test-results-utils.R +++ b/tests/testthat/test-results-utils.R @@ -4,7 +4,7 @@ test_that("results_to_df works as expected", { expect_no_error( plan <- check_pkgs( file.path(examples_path, c("exampleGood", "exampleBad")), - n = 2L, + n = 1L, repos = "https://cran.r-project.org/", reporter = NULL ) From 43d1918e3834fc36e6dd5394bf36b54d202340ca Mon Sep 17 00:00:00 2001 From: maksymis <32574056+maksymiuks@users.noreply.github.com> Date: Fri, 20 Feb 2026 12:18:32 +0100 Subject: [PATCH 60/62] Fix snapshot tests for r devel --- tests/testthat/_snaps/deps.md | 4 ++-- tests/testthat/test-deps.R | 8 ++++++++ tests/testthat/test-reporters.R | 8 ++++++++ tests/testthat/test-results-utils.R | 3 +++ 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/tests/testthat/_snaps/deps.md b/tests/testthat/_snaps/deps.md index 8830e13..1f4f886 100644 --- a/tests/testthat/_snaps/deps.md +++ b/tests/testthat/_snaps/deps.md @@ -100,7 +100,7 @@ 70 processx Depends R >= 3, 4, 0 71 lifecycle Depends R >= 3, 6 72 magrittr Depends R >= 3, 4, 0 - 73 Matrix Depends R >= 4, 4 + 73 Matrix Depends R >= 74 Matrix Depends methods 75 rlang Depends R >= 4, 0, 0 76 vctrs Depends R >= 4, 0, 0 @@ -165,7 +165,7 @@ 135 waldo Imports glue 136 waldo Imports methods 137 waldo Imports rlang >= 1, 1, 0 - 138 lattice Depends R >= 4, 0, 0 + 138 lattice Depends R >= 139 glue Depends R >= 3, 6 140 fs Depends R >= 3, 6 141 diffobj Depends R >= 3, 1, 0 diff --git a/tests/testthat/test-deps.R b/tests/testthat/test-deps.R index c755a83..8faa773 100644 --- a/tests/testthat/test-deps.R +++ b/tests/testthat/test-deps.R @@ -19,5 +19,13 @@ test_that("pkg_dependencies works as expected for cran package", { repos = "https://packagemanager.posit.co/cran/2026-02-01" ) ) + + ap <- available_packages() + core_pkgs <- ap[!is.na(ap[, "Priority"]), "Package"] + df[df$package %in% core_pkgs & df$name == "R", ]$version <- + list(package_version(NA_character_, strict = FALSE)) + # We need to exclude dependencies lines stating minimal R + # version required for base and recommended packages as these will fail + # for different version of R regardless of used snapshot expect_snapshot(df) }) diff --git a/tests/testthat/test-reporters.R b/tests/testthat/test-reporters.R index 1737ed2..7f46465 100644 --- a/tests/testthat/test-reporters.R +++ b/tests/testthat/test-reporters.R @@ -16,6 +16,9 @@ old <- getOption("pkgType") options(pkgType = "source") test_that("reporter_basic_tty works as expected for pkg.none", { + # Entire testing suite takes too long on CRAN, we need to trim it + skip_on_cran() + plan <- plan_rev_dep_checks( file.path(sources_new, "pkg.none"), repos = repo @@ -40,6 +43,8 @@ test_that("reporter_basic_tty works as expected for pkg.none", { }) test_that("reporter_basic_tty works as expected for pkg.ok.error", { + # Entire testing suite takes too long on CRAN, we need to trim it + skip_on_cran() plan <- plan_rev_dep_checks( file.path(sources_new, "pkg.ok.error"), @@ -66,6 +71,9 @@ test_that("reporter_basic_tty works as expected for pkg.ok.error", { }) test_that("reporter_ansi_tty works as expected for pkg.ok.error", { + # Entire testing suite takes too long on CRAN, we need to trim it + skip_on_cran() + plan <- plan_rev_dep_checks( file.path(sources_new, "pkg.ok.error"), repos = repo diff --git a/tests/testthat/test-results-utils.R b/tests/testthat/test-results-utils.R index 538d3b7..36280b0 100644 --- a/tests/testthat/test-results-utils.R +++ b/tests/testthat/test-results-utils.R @@ -1,4 +1,7 @@ test_that("results_to_df works as expected", { + # Entire testing suite takes too long on CRAN, we need to trim it + skip_on_cran() + examples_path <- system.file("example_packages", package = "checked") expect_no_error( From 85dde502794ab85482d3d7cf90af3eb16309985c Mon Sep 17 00:00:00 2001 From: maksymis <32574056+maksymiuks@users.noreply.github.com> Date: Fri, 20 Feb 2026 13:09:45 +0100 Subject: [PATCH 61/62] Fix snapshot tests for r devel --- tests/testthat/test-deps.R | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/testthat/test-deps.R b/tests/testthat/test-deps.R index 8faa773..ef46b33 100644 --- a/tests/testthat/test-deps.R +++ b/tests/testthat/test-deps.R @@ -20,7 +20,9 @@ test_that("pkg_dependencies works as expected for cran package", { ) ) - ap <- available_packages() + ap <- available_packages( + repos = "https://packagemanager.posit.co/cran/2026-02-01" + ) core_pkgs <- ap[!is.na(ap[, "Priority"]), "Package"] df[df$package %in% core_pkgs & df$name == "R", ]$version <- list(package_version(NA_character_, strict = FALSE)) From 3000f2a1dc42443d01a26ca99721328fd7e414cd Mon Sep 17 00:00:00 2001 From: maksymis <32574056+maksymiuks@users.noreply.github.com> Date: Fri, 20 Feb 2026 17:10:48 +0100 Subject: [PATCH 62/62] update job variables --- .github/workflows/R-CMD-check.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index feb9011..0df5e77 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -28,7 +28,7 @@ jobs: env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} R_KEEP_PKG_SOURCE: yes - _R_CHECK_CRAN_INCOMING_: true + _R_CHECK_CRAN_INCOMING_: false _R_CHECK_FORCE_SUGGESTS_: false NOT_CRAN: "true"