Skip to content

Commit

Permalink
Use rlang to prompt for installing outdated and missing dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
lionel- committed Dec 16, 2021
1 parent 158d9f5 commit cb1ffc2
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 25 deletions.
4 changes: 3 additions & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ Imports:
utils,
withr (>= 2.4.3)
Suggests:
Rcpp,
bitops,
covr,
pak,
pkgbuild,
Rcpp,
remotes,
testthat (>= 3.1.0)
Remotes:
r-lib/rlang@check-pkg-inpout
Expand Down
5 changes: 5 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
* `load_all()` now calls `rlang::check_installed()` to prompt whether
to install missing packages.

Outdated and missing dependencies are installed using pak if
installed. If not, the remotes package is used if installed.
Otherwise rlang is used as a last resort but this method does not
support Remotes fields.

* User `onLoad` hooks are now run after exports have been
populated. This allows the hook to use exported functions.

Expand Down
11 changes: 1 addition & 10 deletions R/imports-env.r
Original file line number Diff line number Diff line change
Expand Up @@ -60,21 +60,12 @@ load_imports <- function(path = ".") {
return(invisible(imports))
}

deps_check_installed(imports)
deps_check_installed(path, imports)
process_imports(path)

invisible(deps)
}

abort_for_missing_packages <- function(x, pkgs) {
if (any(!x)) {
abort(
paste0("Dependency package(s) ",
paste0("'", pkgs[!x], "'", collapse = ","),
" not available."))
}
}

# Load imported objects
# The code in this function is taken and adapted from base::loadNamespace
# Setup variables were added and the for loops put in a tryCatch block
Expand Down
2 changes: 1 addition & 1 deletion R/load-depends.r
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ load_depends <- function(path = ".", quiet = FALSE) {
return(invisible())
}

deps_check_installed(depends)
deps_check_installed(path, depends)

# The `quietly` argument of `require()` does not affect attachment
# of required packages
Expand Down
25 changes: 22 additions & 3 deletions R/package-deps.r
Original file line number Diff line number Diff line change
Expand Up @@ -44,23 +44,42 @@ parse_deps <- function(string) {
deps[names != "R", ]
}

# Takes a dependency data frame generated by the `desc` package
deps_check_installed <- function(deps) {
# Takes a dependency data frame generated by the `desc` package.
deps_check_installed <- function(path, deps, call = caller_env()) {
if (!nrow(deps)) {
return()
}

pkg <- deps$package
ver <- deps$version

# Recreate `pkg (>= ver)` strings
has_version <- ver != "*"
pkg[has_version] <- sprintf(
"%s (%s)",
pkg[has_version],
ver[has_version]
)

check_installed(pkg)
# Outdated and missing dependencies are installed using pak if
# installed. If not, the remotes package is used if installed.
# Otherwise rlang is used as a last resort but this method does not
# support Remotes fields.
action <- function(pkg, ...) {
if (is_installed("pak")) {
deps <- pak::pkg_deps(path, upgrade = FALSE)
deps <- deps[deps$package %in% pkg, ]
pak::pak(deps$ref, ask = FALSE)
} else if (is_installed("remotes")) {
deps <- remotes::dev_package_deps(path)
deps <- deps[deps$package %in% pkg, ]
update(deps, upgrade = TRUE)
} else {
check_installed(pkg, action = NULL, call = call)
}
}

check_installed(pkg, action = action, call = call)
}


Expand Down
19 changes: 9 additions & 10 deletions tests/testthat/test-depend.r
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
local_load_all_quiet()

test_that("Warned about dependency versions", {
test_that("Warn about mismatched version", {
# Should give a warning about grid version
expect_warning(load_all("testImportVersion"), "Need grid >=")
expect_error(
load_all("testImportVersion"),
class = "rlib_error_package_not_found"
)
unload("testImportVersion")

# TODO: Add check for NOT giving a warning about compiler version
# Not possible with testthat?
})


test_that("Error on missing dependencies", {
# Should give a warning about missing package
expect_error(regexp = "Dependency package[(]s[)] 'missingpackage' not available",
expect_warning(regexp = "missingpackage.* not available",
load_all("testImportMissing")))
expect_error(
load_all("testImportMissing"),
class = "rlib_error_package_not_found"
)

# Loading process will be partially done; unload it
unload("testImportMissing")
Expand Down

0 comments on commit cb1ffc2

Please sign in to comment.