Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Imports:
lifecycle (>= 1.0.4),
memoise (>= 2.0.1),
miniUI (>= 0.1.2),
pak,
pkgbuild (>= 1.4.8),
pkgdown (>= 2.1.3),
pkgload (>= 1.4.1),
Expand Down
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* `build_manual()` reports more details on failure (#2586).
* New `check_mac_devel()` function to check a package using the macOS builder at https://mac.r-project.org/macbuilder/submit.html (@nfrerebeau, #2507)
* `is_loading()` is now re-exported from pkgload (#2556).
* `install()` now uses `pak::local_install()` instead of `remotes::install_deps()`. This gives a lot of improved behaviours, particularly around upgrading dependencies that you already have installed (#2486).
* `load_all()` now errors if called recursively, i.e. if you accidentally include a `load_all()` call in one of your R source files (#2617).
* `show_news()` now looks for NEWS files in the same locations as `utils::news()`: `inst/NEWS.Rd`, `NEWS.md`, `NEWS`, and `inst/NEWS` (@arcresu, #2499).

Expand Down
2 changes: 1 addition & 1 deletion R/build-site.R
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ build_site <- function(path = ".", quiet = TRUE, ...) {
check_dots_used(action = getOption("devtools.ellipsis_action", rlang::warn))

withr::with_temp_libpaths(action = "prefix", code = {
install(pkg = pkg$path, upgrade = "never", reload = FALSE, quiet = quiet)
install(pkg = pkg$path, upgrade = FALSE, reload = FALSE, quiet = quiet)
if (isTRUE(quiet)) {
withr::with_output_sink(
file_temp(),
Expand Down
213 changes: 108 additions & 105 deletions R/install.R
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
#' Install a local development package.
#' Install a local development package
#'
#' Uses `R CMD INSTALL` to install the package. Will also try to install
#' dependencies of the package from CRAN, if they're not already installed.
#'
#' If `quick = TRUE`, installation takes place using the current package
#' directory. If you have compiled code, this means that artefacts of
#' compilation will be created in the `src/` directory. If you want to avoid
#' this, you can use `build = TRUE` to first build a package bundle and then
#' install it from a temporary directory. This is slower, but keeps the source
#' directory pristine.
#'
#' If the package is loaded, it will be reloaded after installation. This is
#' not always completely possible, see [reload()] for caveats.
#' @description
#' Uses `R CMD INSTALL` to install the package, after installing needed
#' dependencies with [pak::local_install_deps()].
#'
#' To install a package in a non-default library, use [withr::with_libpaths()].
#'
#' @template devtools
#' @inheritParams remotes::install_local
#' @param reload if `TRUE` (the default), will automatically reload the
#' package after installing.
#' @param reload if `TRUE` (the default), will automatically attempt reload the
#' package after installing. Reloading is always completely possible so see
#' [pkgload::unregister()] for caveats.
#' @param quick if `TRUE` skips docs, multiple-architectures,
#' demos, and vignettes, to make installation as fast as possible.
#' If `quick = TRUE`, installation takes place using the current package
#' directory. If you have compiled code, this means that artefacts of
#' compilation will be created in the `src/` directory. If you want to avoid
#' this, you can use `build = TRUE` to first build a package bundle and then
#' install it from a temporary directory. This is slower, but keeps the source
#' directory pristine.
#' @param build if `TRUE` [pkgbuild::build()]s the package first:
#' this ensures that the installation is completely clean, and prevents any
#' binary artefacts (like \file{.o}, `.so`) from appearing in your local
Expand All @@ -43,118 +40,124 @@
#' @param keep_source If `TRUE` will keep the srcrefs from an installed
#' package. This is useful for debugging (especially inside of RStudio).
#' It defaults to the option `"keep.source.pkgs"`.
#' @param ... additional arguments passed to [remotes::install_deps()]
#' when installing dependencies.
#' @param quiet If `TRUE`, suppress output.
#' @param force `r lifecycle::badge("deprecated")` No longer used.
#' @family package installation
#' @seealso [update_packages()] to update installed packages from the
#' source location and [with_debug()] to install packages with
#' debugging flags set.
#' @inheritParams pak::local_install_deps
#' @seealso [with_debug()] to install packages with debugging flags set.
#' @export
install <-
function(
pkg = ".",
reload = TRUE,
quick = FALSE,
build = !quick,
args = getOption("devtools.install.args"),
quiet = FALSE,
dependencies = NA,
upgrade = "default",
build_vignettes = FALSE,
keep_source = getOption("keep.source.pkgs"),
force = FALSE,
...
) {
pkg <- as.package(pkg)

# Forcing all of the promises for the current namespace now will avoid lazy-load
# errors when the new package is installed overtop the old one.
# https://stat.ethz.ch/pipermail/r-devel/2015-December/072150.html
if (reload && is_loaded(pkg)) {
eapply(pkgload::ns_env(pkg$package), force, all.names = TRUE)
}
install <- function(
pkg = ".",
reload = TRUE,
quick = FALSE,
build = !quick,
args = getOption("devtools.install.args"),
quiet = FALSE,
dependencies = NA,
upgrade = FALSE,
build_vignettes = FALSE,
keep_source = getOption("keep.source.pkgs"),
force = deprecated()
) {
if (!is.logical(upgrade) || length(upgrade) != 1) {
cli::cli_abort("{.arg upgrade} must be a single TRUE, FALSE, or NA")
}
if (lifecycle::is_present(force)) {
lifecycle::deprecate_warn("2.5.0", "intall(force)")
}

pkg <- as.package(pkg)

# Forcing all of the promises for the current namespace now will avoid lazy-load
# errors when the new package is installed overtop the old one.
# https://stat.ethz.ch/pipermail/r-devel/2015-December/072150.html
if (reload && is_loaded(pkg)) {
eapply(pkgload::ns_env(pkg$package), base::force, all.names = TRUE)
}

if (isTRUE(build_vignettes)) {
# we likely need all Suggested dependencies if building vignettes
dependencies <- TRUE
build_opts <- c("--no-resave-data", "--no-manual")
# Install dependencies
local({
if (quiet) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hack around lack of quiet argument or option for pak.

withr::local_output_sink(withr::local_tempfile())
withr::local_message_sink(withr::local_tempfile())
} else {
build_opts <- c("--no-resave-data", "--no-manual", "--no-build-vignettes")
cli::cat_rule("Installing dependencies", col = "cyan")
}

opts <- c(
if (keep_source) "--with-keep.source",
"--install-tests"
pak::local_install_deps(
pkg$path,
upgrade = upgrade,
dependencies = dependencies || isTRUE(build_vignettes)
)
if (quick) {
opts <- c(opts, "--no-docs", "--no-multiarch", "--no-demo")
}
opts <- c(opts, args)
})

check_dots_used(action = getOption("devtools.ellipsis_action", rlang::warn))
if (isTRUE(build_vignettes)) {
build_opts <- c("--no-resave-data", "--no-manual")
} else {
build_opts <- c("--no-resave-data", "--no-manual", "--no-build-vignettes")
}
opts <- c(
if (keep_source) "--with-keep.source",
"--install-tests"
)
if (quick) {
opts <- c(opts, "--no-docs", "--no-multiarch", "--no-demo")
}
opts <- c(opts, args)

remotes::install_deps(
if (build) {
install_path <- pkgbuild::build(
pkg$path,
build = build,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit hard to see in the diff, but we're no longer passing any build or install options when we install the dependencies. I think this is likely to be fine, since you'd generally except these to coming from CRAN and not built locally.

build_opts = build_opts,
INSTALL_opts = opts,
dependencies = dependencies,
quiet = quiet,
force = force,
upgrade = upgrade,
...
dest_path = tempdir(),
args = build_opts,
quiet = quiet
)
on.exit(file_delete(install_path), add = TRUE)
} else {
install_path <- pkg$path
}

if (build) {
install_path <- pkgbuild::build(
pkg$path,
dest_path = tempdir(),
args = build_opts,
quiet = quiet
)
on.exit(file_delete(install_path), add = TRUE)
} else {
install_path <- pkg$path
}

was_loaded <- is_loaded(pkg)
was_attached <- is_attached(pkg)
was_loaded <- is_loaded(pkg)
was_attached <- is_attached(pkg)

if (reload && was_loaded) {
pkgload::unregister(pkg$package)
}
if (reload && was_loaded) {
pkgload::unregister(pkg$package)
}

pkgbuild::with_build_tools(
required = FALSE,
callr::rcmd(
"INSTALL",
c(install_path, opts),
echo = !quiet,
show = !quiet,
spinner = FALSE,
stderr = "2>&1",
fail_on_status = TRUE
)
if (!quiet) {
cli::cat_rule(paste0("R CMD INSTALL"), col = "cyan")
}
pkgbuild::with_build_tools(
required = FALSE,
callr::rcmd(
"INSTALL",
c(install_path, opts),
echo = !quiet,
show = !quiet,
spinner = FALSE,
stderr = "2>&1",
fail_on_status = TRUE
)
)

if (reload && was_loaded) {
if (was_attached) {
require(pkg$package, quietly = TRUE, character.only = TRUE)
} else {
requireNamespace(pkg$package, quietly = TRUE)
}
if (reload && was_loaded) {
if (was_attached) {
require(pkg$package, quietly = TRUE, character.only = TRUE)
} else {
requireNamespace(pkg$package, quietly = TRUE)
}

invisible(TRUE)
}

invisible(TRUE)
}

#' Install package dependencies if needed.
#'
#' `install_deps()` will install the
#' user dependencies needed to run the package, `install_dev_deps()` will also
#' install the development dependencies needed to test and build the package.
#' @inheritParams install
#' @inherit remotes::install_deps
#' @inheritParams install
#' @param ... Additional arguments passed to [remotes::install_deps()].
#' @export
install_deps <- function(
pkg = ".",
Expand Down Expand Up @@ -221,5 +224,5 @@ local_install <- function(pkg = ".", quiet = TRUE, env = parent.frame()) {

cli::cli_inform(c(i = "Installing {.pkg {pkg$package}} in temporary library"))
withr::local_temp_libpaths(.local_envir = env)
install(pkg, upgrade = "never", reload = FALSE, quick = TRUE, quiet = quiet)
install(pkg, upgrade = FALSE, reload = FALSE, quick = TRUE, quiet = quiet)
}
Loading