A single key function, 'Require' that wraps 'install.packages', 'remotes::install_github', 'versions::install.versions', and 'base::require' that allows for reproducible workflows. As with other functions in a reproducible workflow, this package emphasizes functions that return the same result whether it is the first or subsequent times running the function.

This is an "all in one" function that will run install.packages for CRAN packages, remotes::install_github for https://github.com/ packages and will install specific versions of each package if versions are specified either via an inequality (e.g., "Holidays (>=1.0.0)") or with a packageVersionFile. The function will then run require on all named packages that satisfy their version requirements. If packages are already installed (packages supplied), and their optional version numbers are satisfied, then the "install" component will be skipped.

Require(
  packages,
  packageVersionFile,
  libPaths,
  install_githubArgs = list(),
  install.packagesArgs = list(),
  standAlone = getOption("Require.standAlone", FALSE),
  install = getOption("Require.install", TRUE),
  require = getOption("Require.require", TRUE),
  repos = getOption("repos"),
  purge = getOption("Require.purge", FALSE),
  verbose = getOption("Require.verbose", FALSE),
  ...
)

Arguments

packages

Character vector of packages to install via install.packages, then load (i.e., with library). If it is one package, it can be unquoted (as in require). In the case of a GitHub package, it will be assumed that the name of the repository is the name of the package. If this is not the case, then pass a named character vector here, where the names are the package names that could be different than the GitHub repository name.

packageVersionFile

If provided, then this will override all install.package calls with versions::install.versions

libPaths

The library path (or libraries) where all packages should be installed, and looked for to load (i.e., call library). This can be used to create isolated, stand alone package installations, if used with standAlone = TRUE. Currently, the path supplied here will be prepended to .libPaths() (temporarily during this call) to Require if standAlone = FALSE or will set (temporarily) .libPaths() to c(libPaths, tail(libPaths(), 1) to keep base packages.

install_githubArgs

List of optional named arguments, passed to install_github.

install.packagesArgs

List of optional named arguments, passed to install.packages.

standAlone

Logical. If TRUE, all packages will be installed to and loaded from the libPaths only. If FALSE, then libPath will be prepended to .libPaths() during the Require call, resulting in shared packages, i.e., it will include the user's default package folder(s). This can be create dramatically faster installs if the user has a substantial number of the packages already in their personal library. Default FALSE to minimize package installing.

install

Logical or "force". If FALSE, this will not try to install anything. If "force", then it will force installation of requested packages, mimicking a call to e.g., install.packages. If TRUE, the default, then this function will try to install any missing packages or dependencies.

require

Logical. If TRUE, the default, then the function will attempt to call require on all requested packages, possibly after they are installed.

repos

The remote repository (e.g., a CRAN mirror), passed to either install.packages, install_github or installVersions.

purge

Logical. Internally, there are calls to available.packages

verbose

Numeric. If 1 (less) or 2 (more), there will be a data.table with many details attached to the output

...

Passed to all of install_github, install.packages, and remotes::install_version, i.e., the function will error if all of these functions can not use the ... argument. Good candidates are e.g., type or dependencies. This can be used with install_githubArgs or install.packageArgs which give individual options for those 2 internal function calls.

Details

standAlone will either put the Required packages and their dependencies all within the libPaths (if TRUE) or if FALSE will only install packages and their dependencies that are otherwise not installed in .libPaths(), i.e., the personal or base library paths. Any packages or dependencies that are not yet installed will be installed in libPaths. Importantly, a small hidden file (named ._packageVersionsAuto.txt) will be saved in libPaths that will store the information about the packages and their dependencies, even if the version used is located in .libPaths(), i.e., not the libPaths provided. This hidden file will be used if a user runs pkgSnapshot, enabling a new user to rebuild the entire dependency chain, without having to install all packages in an isolated directory (as does packrat). This will save potentially a lot of time and disk space, and yet maintain reproducibility. NOTE: since there is only one hidden file in a libPaths, any call to pkgSnapshot will make a snapshot of the most recent call to Require.

To build a snapshot of the desired packages and their versions, first run Require with all packages, then pkgSnapshot. If a libPaths is used, it must be used in both functions.

This function works best if all required packages are called within one Require call, as all dependencies can be identified together, and all package versions will be saved automatically (with standAlone = TRUE or standAlone = FALSE), allowing a call to pkgSnapshot when a more permanent record of versions can be made.

Note

For advanced use and diagnosis, the user can set verbose = TRUE or 1 or 2 (or via options("Require.verbose")). This will attache an attribute attr(obj, "Require") to the output of this function.

See also

Examples

if (FALSE) { # simple usage, like conditional install.packages then library library(Require) Require("stats") # analogous to require(stats), but it checks for # pkg dependencies, and installs them, if missing tempPkgFolder <- file.path(tempdir(), "Packages") # use standAlone, means it will put it in libPaths, even if it already exists # in another local library (e.g., personal library) Require("crayon", libPaths = tempPkgFolder, standAlone = TRUE) # make a package version snapshot of installed packages packageVersionFile <- "_.packageVersionTest.txt" (pkgSnapshot(libPath = tempPkgFolder, packageVersionFile, standAlone = TRUE)) # Restart R -- to remove the old temp folder (it disappears with restarting R) library(Require) tempPkgFolder <- file.path(tempdir(), "Packages") packageVersionFile <- "_.packageVersionTest.txt" # Reinstall and reload the exact version from previous Require(packageVersionFile = packageVersionFile, libPaths = tempPkgFolder, standAlone = TRUE) # Create mismatching versions -- desired version is older than current installed # This will try to install the older version, overwriting the newer version desiredVersion <- data.frame(instPkgs="crayon", instVers = "1.3.2", stringsAsFactors = FALSE) write.table(file = packageVersionFile, desiredVersion, row.names = FALSE) newTempPkgFolder <- file.path(tempdir(), "Packages2") # Note this will install the 1.3.2 version (older that current on CRAN), but # because crayon is still loaded in memory, it will return TRUE, using the current version # of crayon. To start using the older 1.3.2, need to unload or restart R Require("crayon", packageVersionFile = packageVersionFile, libPaths = newTempPkgFolder, standAlone = TRUE) # restart R again to get access to older version # run again, this time, correct "older" version installs in place of newer one library(Require) packageVersionFile <- "_.packageVersionTest.txt" newTempPkgFolder <- file.path(tempdir(), "Packages3") Require("crayon", packageVersionFile = packageVersionFile, libPaths = newTempPkgFolder, standAlone = TRUE) # Mutual dependencies, only installs once -- e.g., httr tempPkgFolder <- file.path(tempdir(), "Packages") Require(c("cranlogs", "covr"), libPaths = tempPkgFolder, standAlone = TRUE) ########################################################################################## # Isolated projects -- Just use a project folder and pass to libPaths or set .libPaths() # ########################################################################################## # GitHub packages -- restart R because crayon is needed library(Require) ProjectPackageFolder <- file.path(tempdir(), "ProjectA") # THIS ONE IS LARGE -- > 100 dependencies -- use standAlone = FALSE to # reuse already installed packages --> this won't allow as much control # of package versioning Require("PredictiveEcology/SpaDES@development", libPaths = ProjectPackageFolder, standAlone = FALSE) # To keep totally isolated: use standAlone = TRUE # --> setting .libPaths() directly means standAlone is not necessary; it will only # use .libPaths() library(Require) ProjectPackageFolder <- file.path("~", "ProjectA") setLibPaths(ProjectPackageFolder) Require("PredictiveEcology/SpaDES@development") ############################################################################ # Mixing and matching GitHub, CRAN, with and without version numbering ############################################################################ # Restart R -- when installing/loading packages, start fresh pkgs <- c("Holidays (<=1.0.4)", "TimeWarp (<= 1.0.3)", "glmm (<=1.3.0)", "achubaty/amc@development", "PredictiveEcology/LandR@development (>=0.0.1)", "PredictiveEcology/LandR@development (>=0.0.2)", "ianmseddy/LandR.CS (<=0.0.1)") Require::Require(pkgs) ############################################################################ # Using libPaths -- This will only be used inside this function; # To change .libPaths() for the whole session use a manually call to # setLibPaths(newPath) first ############################################################################ Require::Require("SpaDES", libPaths = "~/TempLib2", standAlone = FALSE) ############################################################################ # Persistent separate packages ############################################################################ setLibPaths("~/TempLib2", standAlone = TRUE) Require::Require("SpaDES") # not necessary to specifify standAlone here because .libPaths are set }