1#' Install a local development package.
2#'
3#' Uses `R CMD INSTALL` to install the package. Will also try to install
4#' dependencies of the package from CRAN, if they're not already installed.
5#'
6#' If `quick = TRUE`, installation takes place using the current package
7#' directory. If you have compiled code, this means that artefacts of
8#' compilation will be created in the `src/` directory. If you want to avoid
9#' this, you can use `build = TRUE` to first build a package bundle and then
10#' install it from a temporary directory. This is slower, but keeps the source
11#' directory pristine.
12#'
13#' If the package is loaded, it will be reloaded after installation. This is
14#' not always completely possible, see [reload()] for caveats.
15#'
16#' To install a package in a non-default library, use [withr::with_libpaths()].
17#'
18#' @template devtools
19#' @inheritParams remotes::install_local
20#' @param reload if `TRUE` (the default), will automatically reload the
21#'   package after installing.
22#' @param quick if `TRUE` skips docs, multiple-architectures,
23#'   demos, and vignettes, to make installation as fast as possible.
24#' @param build if `TRUE` [pkgbuild::build()]s the package first:
25#'   this ensures that the installation is completely clean, and prevents any
26#'   binary artefacts (like \file{.o}, `.so`) from appearing in your local
27#'   package directory, but is considerably slower, because every compile has
28#'   to start from scratch.
29#' @param args An optional character vector of additional command line
30#'   arguments to be passed to `R CMD INSTALL`. This defaults to the
31#'   value of the option `"devtools.install.args"`.
32#' @param build_vignettes if `TRUE`, will build vignettes. Normally it is
33#'   `build` that's responsible for creating vignettes; this argument makes
34#'   sure vignettes are built even if a build never happens (i.e. because
35#'   `build = FALSE`).
36#' @param keep_source If `TRUE` will keep the srcrefs from an installed
37#'   package. This is useful for debugging (especially inside of RStudio).
38#'   It defaults to the option `"keep.source.pkgs"`.
39#' @param ... additional arguments passed to [remotes::install_deps()]
40#'   when installing dependencies.
41#' @family package installation
42#' @seealso [update_packages()] to update installed packages from the
43#' source location and [with_debug()] to install packages with
44#' debugging flags set.
45#' @export
46install <-
47  function(pkg = ".", reload = TRUE, quick = FALSE, build = !quick,
48             args = getOption("devtools.install.args"), quiet = FALSE,
49             dependencies = NA, upgrade = "default",
50             build_vignettes = FALSE,
51             keep_source = getOption("keep.source.pkgs"),
52             force = FALSE,
53             ...) {
54    pkg <- as.package(pkg)
55
56    # Forcing all of the promises for the current namespace now will avoid lazy-load
57    # errors when the new package is installed overtop the old one.
58    # https://stat.ethz.ch/pipermail/r-devel/2015-December/072150.html
59    if (reload && is_loaded(pkg)) {
60      eapply(pkgload::ns_env(pkg$package), force, all.names = TRUE)
61    }
62
63    if (isTRUE(build_vignettes)) {
64      # we likely need all Suggested dependencies if building vignettes
65      dependencies <- TRUE
66      build_opts <- c("--no-resave-data", "--no-manual")
67    } else {
68      build_opts <- c("--no-resave-data", "--no-manual", "--no-build-vignettes")
69    }
70
71    opts <- c(
72      if (keep_source) "--with-keep.source",
73      "--install-tests"
74    )
75    if (quick) {
76      opts <- c(opts, "--no-docs", "--no-multiarch", "--no-demo")
77    }
78    opts <- c(opts, args)
79
80    check_dots_used(action = getOption("devtools.ellipsis_action", rlang::warn))
81
82    remotes::install_deps(pkg$path,
83      build = build, build_opts = build_opts,
84      INSTALL_opts = opts, dependencies = dependencies, quiet = quiet,
85      force = force, upgrade = upgrade, ...
86    )
87
88    if (build) {
89      install_path <- pkgbuild::build(pkg$path, dest_path = tempdir(), args = build_opts, quiet = quiet)
90      on.exit(file_delete(install_path), add = TRUE)
91    } else {
92      install_path <- pkg$path
93    }
94
95    was_loaded <- is_loaded(pkg)
96    was_attached <- is_attached(pkg)
97
98    if (reload && was_loaded) {
99      pkgload::unload(pkg$package)
100    }
101
102    pkgbuild::with_build_tools(required = FALSE,
103      callr::rcmd("INSTALL", c(install_path, opts), echo = !quiet, show = !quiet, spinner = FALSE, stderr = "2>&1", fail_on_status = TRUE)
104    )
105
106    if (reload && was_loaded) {
107      if (was_attached) {
108        require(pkg$package, quietly = TRUE, character.only = TRUE)
109      } else {
110        requireNamespace(pkg$package, quietly = TRUE)
111      }
112    }
113
114    invisible(TRUE)
115  }
116
117#' Install package dependencies if needed.
118#'
119#' `install_deps()` will install the
120#' user dependencies needed to run the package, `install_dev_deps()` will also
121#' install the development dependencies needed to test and build the package.
122#' @inheritParams install
123#' @inherit remotes::install_deps
124#' @export
125install_deps <- function(pkg = ".",
126                         dependencies = NA,
127                         repos = getOption("repos"),
128                         type = getOption("pkgType"),
129                         upgrade = c("default", "ask", "always", "never"),
130                         quiet = FALSE,
131                         build = TRUE,
132                         build_opts = c("--no-resave-data", "--no-manual", " --no-build-vignettes"),
133                         ...) {
134  pkg <- as.package(pkg)
135
136  check_dots_used(action = getOption("devtools.ellipsis_action", rlang::warn))
137
138  remotes::install_deps(
139    pkg$path,
140    dependencies = dependencies,
141    repos = repos,
142    type = type,
143    upgrade = upgrade,
144    quiet = quiet,
145    build = build,
146    build_opts = build_opts,
147    ...
148  )
149}
150
151#' @rdname install_deps
152#' @export
153install_dev_deps <- function(pkg = ".",
154                             dependencies = TRUE,
155                             repos = getOption("repos"),
156                             type = getOption("pkgType"),
157                             upgrade = c("default", "ask", "always", "never"),
158                             quiet = FALSE,
159                             build = TRUE,
160                             build_opts = c("--no-resave-data", "--no-manual", " --no-build-vignettes"),
161                             ...) {
162  remotes::update_packages("roxygen2")
163
164  pkg <- as.package(pkg)
165
166  check_dots_used(action = getOption("devtools.ellipsis_action", rlang::warn))
167
168  remotes::install_deps(
169    pkg$path,
170    dependencies = dependencies,
171    repos = repos,
172    type = type,
173    upgrade = upgrade,
174    quiet = quiet,
175    build = build,
176    build_opts = build_opts,
177    ...
178  )
179}
180