| Title: | Installing and Loading R Packages for Reproducible Workflows |
|---|---|
| Description: | A single key function, 'Require' that makes rerun-tolerant versions of 'install.packages' and 'require' for CRAN packages, packages no longer on CRAN (i.e., archived), specific versions of packages, and GitHub packages. This approach is developed to create reproducible workflows that are flexible and fast enough to use while in development stages, while able to build snapshots once a stable package collection is found. 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, with subsequent times being sufficiently fast that they can be run every time without undue waiting burden on the user or developer. |
| Authors: | Eliot J B McIntire [aut, cre] (ORCID: <https://orcid.org/0000-0002-6914-8316>), Alex M Chubaty [ctb] (ORCID: <https://orcid.org/0000-0001-7146-8135>), His Majesty the King in Right of Canada, as represented by the Minister of Natural Resources Canada [cph] |
| Maintainer: | Eliot J B McIntire <[email protected]> |
| License: | GPL-3 |
| Version: | 2.0.0.9021 |
| Built: | 2026-06-04 11:04:48 UTC |
| Source: | https://github.com/PredictiveEcology/Require |
A single key function, 'Require' that makes rerun-tolerant versions of 'install.packages' and 'require' for CRAN packages, packages no longer on CRAN (i.e., archived), specific versions of packages, and GitHub packages. This approach is developed to create reproducible workflows that are flexible and fast enough to use while in development stages, while able to build snapshots once a stable package collection is found. 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, with subsequent times being sufficiently fast that they can be run every time without undue waiting burden on the user or developer.
This is an "all in one" function that will run install.packages for CRAN
and GitHub packages and will install specific versions
of each package if versions are specified either via an (in)equality
(e.g., "glue (>=1.6.2)" or "glue (==1.6.2)" for an exact version) or with a
packageVersionFile. If require = TRUE, the default, 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(INSTALL_opts = "--no-multiarch"), 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), type = getOption("pkgType"), upgrade = FALSE, returnDetails = FALSE, ... ) Install( packages, packageVersionFile, libPaths, install_githubArgs = list(), install.packagesArgs = list(INSTALL_opts = "--no-multiarch"), standAlone = getOption("Require.standAlone", FALSE), install = TRUE, repos = getOption("repos"), purge = getOption("Require.purge", FALSE), verbose = getOption("Require.verbose", FALSE), type = getOption("pkgType"), upgrade = FALSE, ... )Require( packages, packageVersionFile, libPaths, install_githubArgs = list(), install.packagesArgs = list(INSTALL_opts = "--no-multiarch"), 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), type = getOption("pkgType"), upgrade = FALSE, returnDetails = FALSE, ... ) Install( packages, packageVersionFile, libPaths, install_githubArgs = list(), install.packagesArgs = list(INSTALL_opts = "--no-multiarch"), standAlone = getOption("Require.standAlone", FALSE), install = TRUE, repos = getOption("repos"), purge = getOption("Require.purge", FALSE), verbose = getOption("Require.verbose", FALSE), type = getOption("pkgType"), upgrade = FALSE, ... )
packages |
Either a character vector of packages to install via
|
packageVersionFile |
Character string of a file name or logical. If
|
libPaths |
The library path (or libraries) where all packages should be
installed, and looked for to load (i.e., call |
install_githubArgs |
Deprecated. Values passed here are merged with
|
install.packagesArgs |
List of optional named arguments, passed to
|
standAlone |
Logical. If |
install |
Logical or "force". If |
require |
Logical or character string. If |
repos |
The remote repository (e.g., a CRAN mirror), passed to either
|
purge |
Logical. Should all caches be purged? Default is
Internally, there are calls to |
verbose |
Numeric or logical indicating how verbose should the function
be. If -1 or -2, then as little verbosity as possible. If 0 or FALSE,
then minimal outputs; if |
type |
See |
upgrade |
When |
returnDetails |
Logical. If |
... |
Passed to |
Install is the same as Require(..., require = FALSE), for convenience.
Require is intended to replace base::require, thus it returns a
logical, named vector indicating whether the named packages have been loaded.
Because Require also has the ability to install packages, a return value of
FALSE does not mean that it did not install correctly; rather, it means it
did not attach with require, which could be because it did not install
correctly, or also because e.g., require = FALSE.
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()[1], i.e., the current active R package directory. Any packages
or dependencies that are not yet installed will be installed in libPaths.
Follows remotes::install_github standard. As with
remotes::install_github, it is not possible to specify a past version of
a GitHub package unless that version is a tag or the user passes the SHA
that had that package version. Similarly, if a developer does a local
install e.g., via pkgload::install, of an active project, this package
will not be able know of the GitHub state, and thus pkgSnapshot will not
be able to recover this state as there is no SHA associated with a local
installation. Use Require (or remotes::install_github) to create a
record of the GitHub state.
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 addressed (if there
are no conflicts), allowing a call to pkgSnapshot() to take a snapshot or
"record" of the current collection of packages and versions.
When installing new packages, Require
will put all source and binary files in an R-version specific subfolder of
getOption("Require.cachePkgDir") whose default is RPackageCache(),
meaning cache packages locally in a project-independent location, and
will reuse them if needed. To turn off this feature, set
options("Require.cachePkgDir" = FALSE).
For advanced use and diagnosis, the user can set verbose = TRUE or
1 or 2 (or via options("Require.verbose")). This will attach an
attribute attr(obj, "Require") to the output of this function.
Maintainer: Eliot J B McIntire [email protected] (ORCID)
Authors:
Eliot J B McIntire [email protected] (ORCID)
Other contributors:
Alex M Chubaty [email protected] (ORCID) [contributor]
His Majesty the King in Right of Canada, as represented by the Minister of Natural Resources Canada [copyright holder]
Useful links:
Report bugs at https://github.com/PredictiveEcology/Require/issues
## Not run: opts <- Require:::.setupExample() library(Require) getCRANrepos(ind = 1) Require("utils") # analogous to require(stats), but it checks for # pkg dependencies, and installs them, if missing # unquoted version Require(c(tools, utils)) if (Require:::.runLongExamples()) { # Install in a new local library (libPaths) tempPkgFolder <- file.path(tempdir(), "Require/Packages") # use standAlone, means it will put it in libPaths, even if it already exists # in another local library (e.g., personal library) Install("crayon", libPaths = tempPkgFolder, standAlone = TRUE) # Mutual dependencies, only installs once -- e.g., cli tempPkgFolder <- file.path(tempdir(), "Require/Packages") Install(c("cli", "R6"), libPaths = tempPkgFolder, standAlone = TRUE) # Mutual dependencies, only installs once -- e.g., rlang tempPkgFolder <- file.path(tempdir(), "Require/Packages") Install(c("rlang", "ellipsis"), libPaths = tempPkgFolder, standAlone = TRUE) ##################################################################################### # Isolated projects -- Use a project folder and pass to libPaths or set .libPaths() # ##################################################################################### # GitHub packages if (requireNamespace("gitcreds", quietly = TRUE)) { # if (is(try(gitcreds::gitcreds_get(), silent = TRUE), "gitcreds")) { ProjectPackageFolder <- file.path(tempdir(), "Require/ProjectA") if (requireNamespace("curl")) { Require("PredictiveEcology/fpCompare@development", libPaths = ProjectPackageFolder, ) } # No install because it is there already Install("PredictiveEcology/fpCompare@development", libPaths = ProjectPackageFolder, ) # the latest version on GitHub ############################################################################ # Mixing and matching GitHub, CRAN, with and without version numbering ############################################################################ pkgs <- c( "remotes (<=2.4.1)", # old version "digest (>= 0.6.28)", # recent version "PredictiveEcology/fpCompare@a0260b8476b06628bba0ae73af3430cce9620ca0" # exact version ) Require::Require(pkgs, libPaths = ProjectPackageFolder) # } } Require:::.cleanup(opts) } ## End(Not run)## Not run: opts <- Require:::.setupExample() library(Require) getCRANrepos(ind = 1) Require("utils") # analogous to require(stats), but it checks for # pkg dependencies, and installs them, if missing # unquoted version Require(c(tools, utils)) if (Require:::.runLongExamples()) { # Install in a new local library (libPaths) tempPkgFolder <- file.path(tempdir(), "Require/Packages") # use standAlone, means it will put it in libPaths, even if it already exists # in another local library (e.g., personal library) Install("crayon", libPaths = tempPkgFolder, standAlone = TRUE) # Mutual dependencies, only installs once -- e.g., cli tempPkgFolder <- file.path(tempdir(), "Require/Packages") Install(c("cli", "R6"), libPaths = tempPkgFolder, standAlone = TRUE) # Mutual dependencies, only installs once -- e.g., rlang tempPkgFolder <- file.path(tempdir(), "Require/Packages") Install(c("rlang", "ellipsis"), libPaths = tempPkgFolder, standAlone = TRUE) ##################################################################################### # Isolated projects -- Use a project folder and pass to libPaths or set .libPaths() # ##################################################################################### # GitHub packages if (requireNamespace("gitcreds", quietly = TRUE)) { # if (is(try(gitcreds::gitcreds_get(), silent = TRUE), "gitcreds")) { ProjectPackageFolder <- file.path(tempdir(), "Require/ProjectA") if (requireNamespace("curl")) { Require("PredictiveEcology/fpCompare@development", libPaths = ProjectPackageFolder, ) } # No install because it is there already Install("PredictiveEcology/fpCompare@development", libPaths = ProjectPackageFolder, ) # the latest version on GitHub ############################################################################ # Mixing and matching GitHub, CRAN, with and without version numbering ############################################################################ pkgs <- c( "remotes (<=2.4.1)", # old version "digest (>= 0.6.28)", # recent version "PredictiveEcology/fpCompare@a0260b8476b06628bba0ae73af3430cce9620ca0" # exact version ) Require::Require(pkgs, libPaths = ProjectPackageFolder) # } } Require:::.cleanup(opts) } ## End(Not run)
main-master-aware download from GitHubEquivalent to utils::download.file, but taking the GITHUB_PAT environment
variable and using it to access the Github url.
.downloadFileMasterMainAuth( url, destfile, need = "HEAD", verbose = getOption("Require.verbose"), verboseLevel = 2 ).downloadFileMasterMainAuth( url, destfile, need = "HEAD", verbose = getOption("Require.verbose"), verboseLevel = 2 )
url |
a |
destfile |
a character string (or vector, see the |
need |
If specified, user can suggest which |
verbose |
Numeric or logical indicating how verbose should the function
be. If -1 or -2, then as little verbosity as possible. If 0 or FALSE,
then minimal outputs; if |
verboseLevel |
A numeric indicating what verbose threshold (level) above which this message will show. |
This is called for its side effect, namely, the same as utils::download.file, but
using a GITHUB_PAT, it if is in the environment, and trying both master and
main if the actual url specifies either master or main and it does not exist.
installed.packages
This reads the DESCRIPTION files only, so can only access fields that are
available in the DESCRIPTION file. This is different than installed.packages
which has many other fields, like "Built", "NeedsCompilation" etc. If those
fields are needed, then this function will return an empty column in the returned
character matrix.
.installed.pkgs( lib.loc = .libPaths(), which = c("Depends", "Imports", "LinkingTo"), other = NULL, purge = getOption("Require.purge", FALSE), packages = NULL, collapse = FALSE ).installed.pkgs( lib.loc = .libPaths(), which = c("Depends", "Imports", "LinkingTo"), other = NULL, purge = getOption("Require.purge", FALSE), packages = NULL, collapse = FALSE )
lib.loc |
character vector describing the location of R library trees to
search through, or |
which |
a character vector listing the types of dependencies, a subset
of |
other |
Can supply other fields; the only benefit here is that a user
can specify |
purge |
Logical. Should all caches be purged? Default is
Internally, there are calls to |
packages |
Character vector. If |
collapse |
Logical. If |
This is the mechanism by which install.packages determines which packages
should be installed from where. With this override, we can indicate arbitrary
repos, Package, File for each individual package.
availablePackagesOverride( toInstall, repos, purge, type = getOption("pkgType"), verbose = getOption("Require.verbose") )availablePackagesOverride( toInstall, repos, purge, type = getOption("pkgType"), verbose = getOption("Require.verbose") )
toInstall |
A |
repos |
The remote repository (e.g., a CRAN mirror), passed to either
|
purge |
Logical. Should all caches be purged? Default is
Internally, there are calls to |
type |
See |
verbose |
Numeric or logical indicating how verbose should the function
be. If -1 or -2, then as little verbosity as possible. If 0 or FALSE,
then minimal outputs; if |
VersionOnRepos, versionSpec and inequality columnsNeeds VersionOnRepos, versionSpec and inequality columns
availableVersionOK(pkgDT)availableVersionOK(pkgDT)
pkgDT |
A |
Removes downloaded package archives from the cache that cachePkgDir()
returns. With usePak = TRUE (the default) this delegates to
pak::cache_clean() (no packages arg) or
pak::cache_delete(package = ...) (selective). With usePak = FALSE
it walks Require's legacy bookkeeping dir and unlinks tarballs there.
cacheClearPackages( packages, ask = interactive(), Rversion = versionMajorMinor(), clearCranCache = FALSE, verbose = getOption("Require.verbose") ) clearRequirePackageCache( packages, ask = interactive(), Rversion = versionMajorMinor(), clearCranCache = FALSE, verbose = getOption("Require.verbose") )cacheClearPackages( packages, ask = interactive(), Rversion = versionMajorMinor(), clearCranCache = FALSE, verbose = getOption("Require.verbose") ) clearRequirePackageCache( packages, ask = interactive(), Rversion = versionMajorMinor(), clearCranCache = FALSE, verbose = getOption("Require.verbose") )
packages |
Either missing or a character vector of package names (currently cannot specify version number) to remove from the cache. |
ask |
Logical. If |
Rversion |
An R version (major.minor, e.g., |
clearCranCache |
Logical. If |
verbose |
Numeric or logical indicating how verbose should the function
be. If -1 or -2, then as little verbosity as possible. If 0 or FALSE,
then minimal outputs; if |
Require's own bookkeeping (SHA DB, mirrors.csv, available.packages
snapshots) is preserved by this function; use cachePurge() to clear
those as well.
clearRequirePackageCache() is a deprecated alias.
The Rversion parameter is honoured only on the legacy path – pak's
cache is not partitioned by R version the way Require's cache was, so
pak::cache_clean()/pak::cache_delete() operate on the whole cache
regardless of Rversion. The function emits a verbose note when
Rversion != versionMajorMinor() under usePak = TRUE.
A wrapper around tools::R_user_dir("Require", which = "cache") that
creates the directory, if it does not exist.
cacheDefaultDir()cacheDefaultDir()
The default cache directory
cacheDir() returns Require's own scratch directory (SHA database,
available.packages snapshots, mirrors.csv, pkgDep cache); cachePkgDir()
returns the package binary tarball cache.
cacheDir(create, verbose = getOption("Require.verbose")) cachePkgDir(create)cacheDir(create, verbose = getOption("Require.verbose")) cachePkgDir(create)
create |
A logical indicating whether the path should
be created if it does not exist. Default is |
verbose |
Numeric or logical indicating how verbose should the function
be. If -1 or -2, then as little verbosity as possible. If 0 or FALSE,
then minimal outputs; if |
A path string. When create = TRUE, the directory is created (with
a README placed in cacheDir()'s root if absent); otherwise the
function just returns what the path would be.
| Function | What it holds | Default location | Knob |
cacheDir() |
Require-internal bookkeeping (SHA DB, mirrors.csv, pkgDep cache) | tools::R_user_dir("Require", "cache") |
R_REQUIRE_CACHE |
cachePkgDir() |
Package binary tarballs | pak's cache_summary()$cachepath (pak mode) |
R_USER_CACHE_DIR (via pak) |
cachePkgDir() |
Package binary tarballs | <cacheDir>/packages/<Rver> (legacy) |
R_REQUIRE_CACHE
|
Both defaults flow from tools::R_user_dir(), so setting
R_USER_CACHE_DIR=/some/path in .Renviron redirects both caches
to sibling subdirectories of /some/path/R/ – pak's cache lands in
pkgcache/pkg/, Require's in Require/. That's the one-knob way to
set up a shared cache across machines or R versions.
cachePkgDir() changes with usePak
getOption("Require.usePak", TRUE) (default)Thin wrapper over
pak::cache_summary()$cachepath. The directory is owned by pak/pkgcache;
location is controlled by R_USER_CACHE_DIR (read at pak's subprocess
spawn time). Default: tools::R_user_dir("pkgcache", "cache")/pkg.
usePak = FALSE (legacy)Returns <cacheDir>/packages/<Rver>,
controlled by R_REQUIRE_CACHE.
Require-internal bookkeeping files always live next to the legacy path
(<cacheDir>/packages/<Rver>) regardless of usePak – pak doesn't know
about them and would treat them as stray files.
The following Require-specific knobs and helpers were folded into the pair above. Each is still functional for one release cycle and emits a deprecation warning when used.
| Deprecated | Use instead |
cacheGetOptionCachePkgDir() |
cachePkgDir() |
rpackageFolder() (internal) |
(inlined into checkLibPaths()) |
purgeCache() |
cachePurge() |
clearRequirePackageCache() |
cacheClearPackages() |
options("Require.cachePkgDir") |
R_USER_CACHE_DIR env var |
Sys.getenv("R_REQUIRE_PKG_CACHE") |
R_USER_CACHE_DIR env var
|
Require.cachePkgDir (deprecated)Deprecated. Use cachePkgDir() instead – it is now the single
getter for the package-tarball cache and wraps
pak::cache_summary()$cachepath under usePak = TRUE (the default).
This function is kept for one release cycle as a functional shim. It
still resolves a user-supplied path from options("Require.cachePkgDir")
or the R_REQUIRE_PKG_CACHE environment variable when set, but those
two knobs are themselves deprecated and ignored under usePak = TRUE.
To redirect pak's package cache to a shared location, set
R_USER_CACHE_DIR in .Renviron (pak's standard env var). See
cacheDir() for the full migration table.
Resolution order (legacy path):
If R_REQUIRE_PKG_CACHE is set, return it.
Else if options("Require.cachePkgDir") is character, return it.
Else if the option is TRUE, return cachePkgDir(FALSE).
Else if the option is FALSE, return NULL.
Otherwise, return cachePkgDir(FALSE).
cacheGetOptionCachePkgDir()cacheGetOptionCachePkgDir()
Clears Require's own bookkeeping caches: the available.packages()
snapshot, the GitHub SHA database, the DESCRIPTION cache, and the
pkgDep memoisation database. These live under cacheDir() and are
distinct from the package binary tarball cache.
cachePurge(packages = FALSE, repos = getOption("repos")) purgeCache(packages = FALSE, repos = getOption("repos"))cachePurge(packages = FALSE, repos = getOption("repos")) purgeCache(packages = FALSE, repos = getOption("repos"))
packages |
Either a character vector of packages to install via
|
repos |
The remote repository (e.g., a CRAN mirror), passed to either
|
With packages = TRUE, the package binary cache is also cleared by
calling cacheClearPackages() – which under usePak = TRUE (the
default) delegates to pak::cache_clean(), and under the legacy path
walks Require's bookkeeping dir directly.
purgeCache() is a deprecated alias.
Run for its side effect, namely, all cached objects are removed.
Creates the directories, and adds version number
checkLibPaths(libPaths, ifMissing, exact = FALSE, ...)checkLibPaths(libPaths, ifMissing, exact = FALSE, ...)
libPaths |
The library path (or libraries) where all packages should be
installed, and looked for to load (i.e., call |
ifMissing |
An alternative path if |
exact |
Logical. If |
... |
Not used, but allows other functions to pass through arguments. |
Checks the specified path to a directory for formatting consistencies, such as trailing slashes, etc.
checkPath(path, create) ## S4 method for signature 'character,logical' checkPath(path, create) ## S4 method for signature 'character,missing' checkPath(path) ## S4 method for signature 'NULL,ANY' checkPath(path) ## S4 method for signature 'missing,ANY' checkPath()checkPath(path, create) ## S4 method for signature 'character,logical' checkPath(path, create) ## S4 method for signature 'character,missing' checkPath(path) ## S4 method for signature 'NULL,ANY' checkPath(path) ## S4 method for signature 'missing,ANY' checkPath()
path |
A character string corresponding to a directory path. |
create |
A logical indicating whether the path should
be created if it does not exist. Default is |
Character string denoting the cleaned up filepath.
This will not work for paths to files.
To check for existence of files, use file.exists().
To normalize a path to a file, use normPath() or normalizePath().
## normalize file paths paths <- list("./aaa/zzz", "./aaa/zzz/", ".//aaa//zzz", ".//aaa//zzz/", ".\\\\aaa\\\\zzz", ".\\\\aaa\\\\zzz\\\\", file.path(".", "aaa", "zzz")) checked <- normPath(paths) length(unique(checked)) ## 1; all of the above are equivalent ## check to see if a path exists tmpdir <- file.path(tempdir(), "example_checkPath") dir.exists(tmpdir) ## FALSE tryCatch(checkPath(tmpdir, create = FALSE), error = function(e) FALSE) ## FALSE checkPath(tmpdir, create = TRUE) dir.exists(tmpdir) ## TRUE unlink(tmpdir, recursive = TRUE) # clean up## normalize file paths paths <- list("./aaa/zzz", "./aaa/zzz/", ".//aaa//zzz", ".//aaa//zzz/", ".\\\\aaa\\\\zzz", ".\\\\aaa\\\\zzz\\\\", file.path(".", "aaa", "zzz")) checked <- normPath(paths) length(unique(checked)) ## 1; all of the above are equivalent ## check to see if a path exists tmpdir <- file.path(tempdir(), "example_checkPath") dir.exists(tmpdir) ## FALSE tryCatch(checkPath(tmpdir, create = FALSE), error = function(e) FALSE) ## FALSE checkPath(tmpdir, create = TRUE) dir.exists(tmpdir) ## TRUE unlink(tmpdir, recursive = TRUE) # clean up
Alternative to utils::compareVersion that is vectorized on version,
versionSpec and/or inequality. This will also return an NA element
in the returned vector if one of the arguments has NA for that element.
compareVersion2(version, versionSpec, inequality)compareVersion2(version, versionSpec, inequality)
version |
One or more package versions. Can be |
versionSpec |
One or more versions to compare to.
Can be |
inequality |
The inequality to use, i.e., |
a logical vector of the length of the longest of the 3 arguments.
Only checks for deprecated libPath argument (singular)
dealWithMissingLibPaths( libPaths, standAlone = getOption("Require.standAlone", FALSE), ... )dealWithMissingLibPaths( libPaths, standAlone = getOption("Require.standAlone", FALSE), ... )
libPaths |
The library path (or libraries) where all packages should be
installed, and looked for to load (i.e., call |
standAlone |
Logical. If |
... |
Checks for the incorrect argument |
A series of helpers to access and deal with GitHub packages
DESCRIPTIONFileVersionV(file, purge = getOption("Require.purge", FALSE)) DESCRIPTIONFileOtherV(file, other = "RemoteSha") dlGitHubDESCRIPTION( pkg, purge = getOption("Require.purge", FALSE), verbose = getOption("Require.verbose") )DESCRIPTIONFileVersionV(file, purge = getOption("Require.purge", FALSE)) DESCRIPTIONFileOtherV(file, other = "RemoteSha") dlGitHubDESCRIPTION( pkg, purge = getOption("Require.purge", FALSE), verbose = getOption("Require.verbose") )
file |
A file path to a |
purge |
Logical. Should all caches be purged? Default is
Internally, there are calls to |
other |
Any other keyword in a |
pkg |
A character string with a GitHub package specification (c.f. remotes) |
verbose |
Numeric or logical indicating how verbose should the function
be. If -1 or -2, then as little verbosity as possible. If 0 or FALSE,
then minimal outputs; if |
dlGitHubDESCRIPTION retrieves the DESCRIPTION file from GitHub.com
This uses pkgDepTopoSort internally so that the package
dependency tree is determined, and then packages are unloaded
in the reverse order. Some packages don't unload successfully for
a variety of reasons. Several known packages that have this problem
are identified internally and not unloaded. Currently, these are
glue, rlang, ps, ellipsis, and, processx.
detachAll( pkgs, dontTry = NULL, doSort = TRUE, verbose = getOption("Require.verbose") )detachAll( pkgs, dontTry = NULL, doSort = TRUE, verbose = getOption("Require.verbose") )
pkgs |
A character vector of packages to detach. Will be topologically sorted
unless |
dontTry |
A character vector of packages to not try. This can be used by a user if they find a package fails in attempts to unload it, e.g., "ps" |
doSort |
If |
verbose |
Numeric or logical indicating how verbose should the function
be. If -1 or -2, then as little verbosity as possible. If 0 or FALSE,
then minimal outputs; if |
A numeric named vector, with names of the packages that were attempted.
2 means the package was successfully unloaded, 1 it was
tried, but failed, 3 it was not loaded, so was not unloaded.
These are wrappers around available.packages and also get the archived versions available on CRAN.
dlArchiveVersionsAvailable( package, repos = getOption("repos"), verbose = getOption("Require.verbose") ) available.packagesCached( repos, purge, verbose = getOption("Require.verbose"), returnDataTable = TRUE, type )dlArchiveVersionsAvailable( package, repos = getOption("repos"), verbose = getOption("Require.verbose") ) available.packagesCached( repos, purge, verbose = getOption("Require.verbose"), returnDataTable = TRUE, type )
package |
A single package name (without version or github specifications) |
repos |
The remote repository (e.g., a CRAN mirror), passed to either
|
verbose |
Numeric or logical indicating how verbose should the function
be. If -1 or -2, then as little verbosity as possible. If 0 or FALSE,
then minimal outputs; if |
purge |
Logical. Should all caches be purged? Default is
Internally, there are calls to |
returnDataTable |
Logical. If |
type |
See |
dlArchiveVersionsAvailable searches CRAN Archives for available versions.
It has been borrowed from a sub-set of the code in a non-exported function:
remotes:::download_version_url
Deals with missing libPaths arg, and takes first
doLibPaths(libPaths, standAlone = FALSE)doLibPaths(libPaths, standAlone = FALSE)
libPaths |
The library path (or libraries) where all packages should be
installed, and looked for to load (i.e., call |
standAlone |
Logical. If |
1st level –> create the .pkgEnv object in Require
envPkgCreate(parentEnv = asNamespace("Require"))envPkgCreate(parentEnv = asNamespace("Require"))
parentEnv |
The parent environment in which to make the new environment.
Defaults to |
3rd level for deps #############################################
envPkgDepDepsCreate()envPkgDepDepsCreate()
3rd level for DESCRIPTIONFile
envPkgDepDESCFileCreate()envPkgDepDESCFileCreate()
Cleans a character vector of non-package name related information (e.g., version)
extractPkgName(pkgs, filenames) extractVersionNumber(pkgs, filenames) extractInequality(pkgs) extractPkgGitHub(pkgs)extractPkgName(pkgs, filenames) extractVersionNumber(pkgs, filenames) extractInequality(pkgs) extractPkgGitHub(pkgs)
pkgs |
A character string vector of packages with or without GitHub path or versions |
filenames |
Can be supplied instead of |
Just the package names without extraneous info.
extractPkgName("Require (>=0.0.1)") extractVersionNumber(c( "Require (<=0.0.1)", "PredictiveEcology/Require@development (<=0.0.4)" )) extractInequality("Require (<=0.0.1)") extractPkgGitHub("PredictiveEcology/Require")extractPkgName("Require (>=0.0.1)") extractVersionNumber(c( "Require (<=0.0.1)", "PredictiveEcology/Require@development (<=0.0.4)" )) extractInequality("Require (<=0.0.1)") extractPkgGitHub("PredictiveEcology/Require")
packages argument may have up to 4 pieces of information for GitHub
packages: name, repository, branch, version. For CRAN-alikes, it will only
be 2 pieces: name, version. There can also be an inequality or equality, if
there is a version.The packages argument may have up to 4 pieces of information for GitHub
packages: name, repository, branch, version. For CRAN-alikes, it will only
be 2 pieces: name, version. There can also be an inequality or equality, if
there is a version.
getDeps( pkgDT, which, recursive, type = type, repos, libPaths, verbose, parentChain = "" )getDeps( pkgDT, which, recursive, type = type, repos, libPaths, verbose, parentChain = "" )
pkgDT |
A |
which |
a character vector listing the types of dependencies, a subset
of |
recursive |
Logical. Should dependencies of dependencies be searched,
recursively. NOTE: Dependencies of suggests will not be recursive. Default
|
type |
See |
repos |
is used for |
libPaths |
A path to search for installed packages. Defaults to
|
verbose |
Numeric or logical indicating how verbose should the function
be. If -1 or -2, then as little verbosity as possible. If 0 or FALSE,
then minimal outputs; if |
parentChain |
A character string representing the chain of parent
packages that required this package, e.g., |
If version is not supplied, it will take the local, installed version, if it
exists. Otherwise, it is assumed that the HEAD is desired.
The function will find it in the ap or on github.com. For github packages,
this is obviously a slow step, which can be accelerated if user supplies a sha
or a version e.g., getDeps("PredictiveEcology/LandR@development (==1.0.2)")
A (named) vector of SaveNames, which is a concatenation of the 2 or 4 elements
above, plus the which and the recursive.
Simple test for internet availability.
internetExists(verbose = getOption("Require.verbose"), force = FALSE)internetExists(verbose = getOption("Require.verbose"), force = FALSE)
verbose |
Numeric or logical indicating how verbose should the function
be. If -1 or -2, then as little verbosity as possible. If 0 or FALSE,
then minimal outputs; if |
force |
If |
Logical. TRUE if internet is available, FALSE if not.
This is a simple version of purrr::transpose, only for lists with 2 levels.
invertList(l)invertList(l)
l |
A list with 2 levels. If some levels are absent, they will be |
A list with 2 levels deep, inverted from l
# create a 2-deep, 2 levels in first, 3 levels in second a <- list(a = list(d = 1, e = 2:3, f = 4:6), b = list(d = 5, e = 55)) invertList(a) # creates 2-deep, now 3 levels outer --> 2 levels inner# create a 2-deep, 2 levels in first, 3 levels in second a <- list(a = list(d = 1, e = 2:3, f = 4:6), b = list(d = 5, e = 55)) invertList(a) # creates 2-deep, now 3 levels outer --> 2 levels inner
Package column to available.packages
Will join available.packages() with pkgDT, if pkgDT does not already have
a column named Depends, which would be an indicator that this had already
happened.
joinToAvailablePackages(pkgDT, repos, type, which, verbose)joinToAvailablePackages(pkgDT, repos, type, which, verbose)
pkgDT |
A |
repos |
is used for |
type |
See |
which |
a character vector listing the types of dependencies, a subset
of |
verbose |
Numeric or logical indicating how verbose should the function
be. If -1 or -2, then as little verbosity as possible. If 0 or FALSE,
then minimal outputs; if |
The returned data.table will have most of the columns from
available.packages appended to the pkgDT, including Depends, Imports,
Suggests. It will change the column name that is normally
returned from available.packages as Version to VersionOnRepos.
First try to create a hardlink to the file. If that fails, try a symbolic link (symlink) before falling back to copying the file. "File" here can mean a file or a directory.
linkOrCopy(from, to, allowSymlink = FALSE) fileRenameOrMove(from, to)linkOrCopy(from, to, allowSymlink = FALSE) fileRenameOrMove(from, to)
from, to
|
character vectors, containing file names or paths. |
allowSymlink |
Logical. If |
This will also convert a git repo with nothing after the @ to @HEAD
masterMainToHead(gitRepo)masterMainToHead(gitRepo)
gitRepo |
A git repository of the form account/repo with optional @branch or @sha or @tag |
The git repository with @HEAD if it had @master, @main or no @.
Sends to message, but in a structured way so that a data.frame-like can
be cleanly sent to messaging.
This will only show a message if the value of verbose is greater than the
verboseLevel. This is mostly useful for developers of code who want to give
users of their code easy access to how verbose their code will be. A developer
of a function will place this messageVerbose internally, setting the verboseLevel
according to how advanced they may want the message to be. 1 is a reasonable
default for standard use, 0 would be for "a very important message for all users",
2 or above would be increasing levels of details for e.g., advanced use.
If a user sets to -1 with this numeric approach, they can avoid all messaging.
messageDF(df, round, verbose = getOption("Require.verbose"), verboseLevel = 1) messageVerbose(..., verbose = getOption("Require.verbose"), verboseLevel = 1) messageVerboseCounter( pre = "", post = "", verbose = getOption("Require.verbose"), verboseLevel = 1, counter = 1, total = 1, minCounter = 1 )messageDF(df, round, verbose = getOption("Require.verbose"), verboseLevel = 1) messageVerbose(..., verbose = getOption("Require.verbose"), verboseLevel = 1) messageVerboseCounter( pre = "", post = "", verbose = getOption("Require.verbose"), verboseLevel = 1, counter = 1, total = 1, minCounter = 1 )
df |
A data.frame, data.table, matrix |
round |
An optional numeric to pass to |
verbose |
Numeric or logical indicating how verbose should the function
be. If -1 or -2, then as little verbosity as possible. If 0 or FALSE,
then minimal outputs; if |
verboseLevel |
A numeric indicating what verbose threshold (level) above which this message will show. |
... |
Passed to |
pre |
A single text string to paste before the counter |
post |
A single text string to paste after the counter |
counter |
An integer indicating which iteration is being done |
total |
An integer indicating the total number to be done. |
minCounter |
An integer indicating the minimum (i.e,. starting value) |
Used for side effects, namely messaging that can be turned on or off with different
numeric values of verboseLevel. A user sets the verboseLevel for a particular
message.
modifyList for multiple listsThis calls utils::modifyList iteratively using
base::Reduce, so it can handle >2 lists.
The subsequent list elements that share a name will override
previous list elements with that same name.
It also will handle the case where any list is a NULL. Note:
default keep.null = TRUE, which is different than modifyList
modifyList2(..., keep.null = FALSE) modifyList3(..., keep.null = TRUE)modifyList2(..., keep.null = FALSE) modifyList3(..., keep.null = TRUE)
... |
One or more named lists. |
keep.null |
If |
More or less a convenience around
Reduce(modifyList, list(...)), with some checks, and the addition of
keep.null = TRUE by default.
modifyList3 retains the original behaviour of modifyList2 (prior to
Oct 2022); however, it cannot retain NULL values in lists.
modifyList2(list(a = 1), list(a = 2, b = 2)) modifyList2(list(a = 1), NULL, list(a = 2, b = 2)) modifyList2( list(a = 1), list(x = NULL), list(a = 2, b = 2), list(a = 3, c = list(1:10)) )modifyList2(list(a = 1), list(a = 2, b = 2)) modifyList2(list(a = 1), NULL, list(a = 2, b = 2)) modifyList2( list(a = 1), list(x = NULL), list(a = 2, b = 2), list(a = 3, c = list(1:10)) )
Checks the specified filepath for formatting consistencies:
use slash instead of backslash;
do tilde etc. expansion;
remove trailing slash.
normPath(path) ## S4 method for signature 'character' normPath(path) ## S4 method for signature 'list' normPath(path) ## S4 method for signature 'NULL' normPath(path) ## S4 method for signature 'missing' normPath() ## S4 method for signature 'logical' normPath(path)normPath(path) ## S4 method for signature 'character' normPath(path) ## S4 method for signature 'list' normPath(path) ## S4 method for signature 'NULL' normPath(path) ## S4 method for signature 'missing' normPath() ## S4 method for signature 'logical' normPath(path)
path |
A character vector of filepaths. |
Character vector of cleaned up filepaths.
## normalize file paths paths <- list("./aaa/zzz", "./aaa/zzz/", ".//aaa//zzz", ".//aaa//zzz/", ".\\\\aaa\\\\zzz", ".\\\\aaa\\\\zzz\\\\", file.path(".", "aaa", "zzz")) checked <- normPath(paths) length(unique(checked)) ## 1; all of the above are equivalent ## check to see if a path exists tmpdir <- file.path(tempdir(), "example_checkPath") dir.exists(tmpdir) ## FALSE tryCatch(checkPath(tmpdir, create = FALSE), error = function(e) FALSE) ## FALSE checkPath(tmpdir, create = TRUE) dir.exists(tmpdir) ## TRUE unlink(tmpdir, recursive = TRUE) # clean up## normalize file paths paths <- list("./aaa/zzz", "./aaa/zzz/", ".//aaa//zzz", ".//aaa//zzz/", ".\\\\aaa\\\\zzz", ".\\\\aaa\\\\zzz\\\\", file.path(".", "aaa", "zzz")) checked <- normPath(paths) length(unique(checked)) ## 1; all of the above are equivalent ## check to see if a path exists tmpdir <- file.path(tempdir(), "example_checkPath") dir.exists(tmpdir) ## FALSE tryCatch(checkPath(tmpdir, create = FALSE), error = function(e) FALSE) ## FALSE checkPath(tmpdir, create = TRUE) dir.exists(tmpdir) ## TRUE unlink(tmpdir, recursive = TRUE) # clean up
This will pad floating point numbers, right or left. For integers, either class
integer or functionally integer (e.g., 1.0), it will not pad right of the decimal.
For more specific control or to get exact padding right and left of decimal,
try the stringi package. It will also not do any rounding. See examples.
paddedFloatToChar(x, padL = ceiling(log10(x + 1)), padR = 3, pad = "0")paddedFloatToChar(x, padL = ceiling(log10(x + 1)), padR = 3, pad = "0")
x |
numeric. Number to be converted to character with padding |
padL |
numeric. Desired number of digits on left side of decimal.
If not enough, |
padR |
numeric. Desired number of digits on right side of decimal.
If not enough, |
pad |
character to use as padding ( |
Character string representing the filename.
Eliot McIntire and Alex Chubaty
paddedFloatToChar(1.25) paddedFloatToChar(1.25, padL = 3, padR = 5) paddedFloatToChar(1.25, padL = 3, padR = 1) # no rounding, so keeps 2 right of decimalpaddedFloatToChar(1.25) paddedFloatToChar(1.25, padL = 3, padR = 5) paddedFloatToChar(1.25, padL = 3, padR = 1) # no rounding, so keeps 2 right of decimal
This converts a specification like PredictiveEcology/Require@development
into separate columns, "Account", "Repo", "Branch", "GitSubFolder" (if there is one)
parseGitHub(pkgDT, verbose = getOption("Require.verbose"))parseGitHub(pkgDT, verbose = getOption("Require.verbose"))
pkgDT |
A pkgDT data.table. |
verbose |
Numeric or logical indicating how verbose should the function
be. If -1 or -2, then as little verbosity as possible. If 0 or FALSE,
then minimal outputs; if |
parseGitHub turns the single character string representation into 3 or 4:
Account, Repo, Branch, SubFolder.
parseGitHub returns a data.table with added columns.
This is primarily for package developers. It allows the testing of what the recursive dependencies would be if a package was removed from the immediate dependencies.
pkgDepIfDepRemoved( pkg = character(), depsRemoved = character(), verbose = getOption() )pkgDepIfDepRemoved( pkg = character(), depsRemoved = character(), verbose = getOption() )
pkg |
A package name to be testing the dependencies |
depsRemoved |
A vector of package names who are to be "removed" from the
|
verbose |
Numeric or logical indicating how verbose should the function
be. If -1 or -2, then as little verbosity as possible. If 0 or FALSE,
then minimal outputs; if |
A list with 3 named lists Direct, Recursive and IfRemoved.
Direct will show the top level direct dependencies, either Remaining or
Removed. Recursive will show the full recursive dependencies, either
Remaining or Removed. IfRemoved returns all package dependencies that
are removed for each top level dependency. If a top level dependency is not
listed in this final list, then it means that it is also a recursive
dependency elsewhere, so its removal has no effect.
## Not run: if (Require:::.runLongExamples()) { opts <- Require:::.setupExample() pkgDepIfDepRemoved("reproducible", "data.table") Require:::.cleanup(opts) } ## End(Not run)## Not run: if (Require:::.runLongExamples()) { opts <- Require:::.setupExample() pkgDepIfDepRemoved("reproducible", "data.table") Require:::.cleanup(opts) } ## End(Not run)
This is a wrapper around tools::dependsOnPkgs,
but with the added option of topoSort, which
will sort them such that the packages at the top will have
the least number of dependencies that are in packages.
This is essentially a topological sort, but it is done
heuristically. This can be used to e.g., detach or
unloadNamespace packages in order so that they each
of their dependencies are detached or unloaded first.
pkgDep2 is a convenience wrapper of pkgDep that "goes one level in",
i.e., the first order dependencies, and runs the pkgDep on those.
This will first look in local filesystem (in .libPaths()) and will use a
local package to find its dependencies. If the package does not exist
locally, including whether it is the correct version, then it will look in
(currently) CRAN and its archives (if the current CRAN version is not the
desired version to check). It will also look on GitHub if the package
description is of the form of a GitHub package with format
account/repo@branch or account/repo@commit. For this, it will attempt to
get package dependencies from the GitHub ‘DESCRIPTION’ file. This is
intended to replace tools::package_dependencies or pkgDep in the
miniCRAN package, but with modifications to allow multiple sources to
be searched in the same function call.
pkgDepTopoSort( packages, deps, reverse = FALSE, topoSort = TRUE, libPaths, useAllInSearch = FALSE, returnFull = TRUE, recursive = TRUE, purge = getOption("Require.purge", FALSE), which = c("Depends", "Imports", "LinkingTo"), type = getOption("pkgType"), verbose = getOption("Require.verbose"), ... ) pkgDep2(...) pkgDep( packages, libPaths, which = c("Depends", "Imports", "LinkingTo"), recursive = TRUE, depends, imports, suggests, linkingTo, repos = getOption("repos"), keepVersionNumber = TRUE, includeBase = FALSE, includeSelf = TRUE, sort = TRUE, simplify = TRUE, purge = getOption("Require.purge", FALSE), verbose = getOption("Require.verbose"), type = getOption("pkgType"), Additional_repositories = FALSE, ... )pkgDepTopoSort( packages, deps, reverse = FALSE, topoSort = TRUE, libPaths, useAllInSearch = FALSE, returnFull = TRUE, recursive = TRUE, purge = getOption("Require.purge", FALSE), which = c("Depends", "Imports", "LinkingTo"), type = getOption("pkgType"), verbose = getOption("Require.verbose"), ... ) pkgDep2(...) pkgDep( packages, libPaths, which = c("Depends", "Imports", "LinkingTo"), recursive = TRUE, depends, imports, suggests, linkingTo, repos = getOption("repos"), keepVersionNumber = TRUE, includeBase = FALSE, includeSelf = TRUE, sort = TRUE, simplify = TRUE, purge = getOption("Require.purge", FALSE), verbose = getOption("Require.verbose"), type = getOption("pkgType"), Additional_repositories = FALSE, ... )
packages |
Either a character vector of packages to install via
|
deps |
An optional named list of (reverse) dependencies.
If not supplied, then |
reverse |
Logical. If |
topoSort |
Logical. If |
libPaths |
A path to search for installed packages. Defaults to
|
useAllInSearch |
Logical. If |
returnFull |
Logical. Primarily useful when |
recursive |
Logical. Should dependencies of dependencies be searched,
recursively. NOTE: Dependencies of suggests will not be recursive. Default
|
purge |
Logical. Should all caches be purged? Default is
Internally, there are calls to |
which |
a character vector listing the types of dependencies, a subset
of |
type |
See |
verbose |
Numeric or logical indicating how verbose should the function
be. If -1 or -2, then as little verbosity as possible. If 0 or FALSE,
then minimal outputs; if |
... |
Currently only |
depends |
Logical. Include packages listed in "Depends". Default |
imports |
Logical. Include packages listed in "Imports". Default |
suggests |
Logical. Include packages listed in "Suggests". Default
|
linkingTo |
Logical. Include packages listed in "LinkingTo". Default
|
repos |
The remote repository (e.g., a CRAN mirror), passed to either
|
keepVersionNumber |
Logical. If |
includeBase |
Logical. Should R base packages be included, specifically,
those in |
includeSelf |
Logical. If |
sort |
Logical. If |
simplify |
Logical or numeric. If |
Additional_repositories |
Logical. If |
A possibly ordered, named (with packages as names) list where list elements are either full reverse depends.
tools::package_dependencies and pkgDep will differ under the
following circumstances:
GitHub packages are not detected
using tools::package_dependencies;
tools::package_dependencies
does not detect the dependencies of base packages among themselves, e.g.,
methods depends on stats and graphics.
## Not run: if (Require:::.runLongExamples()) { opts <- Require:::.setupExample() pkgDepTopoSort(c("Require", "data.table"), reverse = TRUE) Require:::.cleanup(opts) } ## End(Not run) ## Not run: if (Require:::.runLongExamples()) { opts <- Require:::.setupExample() pkgDep2("reproducible") # much bigger one pkgDep2("tidyverse") Require:::.cleanup(opts) } ## End(Not run) ## Not run: if (Require:::.runLongExamples()) { opts <- Require:::.setupExample() pkgDep("tidyverse", recursive = TRUE) # GitHub, local, and CRAN packages pkgDep(c("PredictiveEcology/reproducible", "Require", "plyr")) Require:::.cleanup(opts) } ## End(Not run)## Not run: if (Require:::.runLongExamples()) { opts <- Require:::.setupExample() pkgDepTopoSort(c("Require", "data.table"), reverse = TRUE) Require:::.cleanup(opts) } ## End(Not run) ## Not run: if (Require:::.runLongExamples()) { opts <- Require:::.setupExample() pkgDep2("reproducible") # much bigger one pkgDep2("tidyverse") Require:::.cleanup(opts) } ## End(Not run) ## Not run: if (Require:::.runLongExamples()) { opts <- Require:::.setupExample() pkgDep("tidyverse", recursive = TRUE) # GitHub, local, and CRAN packages pkgDep(c("PredictiveEcology/reproducible", "Require", "plyr")) Require:::.cleanup(opts) } ## End(Not run)
This can be used later by Require to install or re-install the correct versions. See examples.
pkgSnapshot( packageVersionFile = getOption("Require.packageVersionFile"), libPaths = .libPaths(), standAlone = FALSE, purge = getOption("Require.purge", FALSE), exact = TRUE, includeBase = FALSE, verbose = getOption("Require.verbose") ) pkgSnapshot2( packageVersionFile = getOption("Require.packageVersionFile"), libPaths, standAlone = FALSE, purge = getOption("Require.purge", FALSE), exact = TRUE, includeBase = FALSE, verbose = getOption("Require.verbose") )pkgSnapshot( packageVersionFile = getOption("Require.packageVersionFile"), libPaths = .libPaths(), standAlone = FALSE, purge = getOption("Require.purge", FALSE), exact = TRUE, includeBase = FALSE, verbose = getOption("Require.verbose") ) pkgSnapshot2( packageVersionFile = getOption("Require.packageVersionFile"), libPaths, standAlone = FALSE, purge = getOption("Require.purge", FALSE), exact = TRUE, includeBase = FALSE, verbose = getOption("Require.verbose") )
packageVersionFile |
A filename to save the packages and their currently
installed version numbers. Defaults to |
libPaths |
The path to the local library where packages are installed.
Defaults to the |
standAlone |
Logical. If |
purge |
Logical. Should all caches be purged? Default is
Internally, there are calls to |
exact |
Logical. If |
includeBase |
Logical. Should R base packages be included, specifically,
those in |
verbose |
Numeric or logical indicating how verbose should the function
be. If -1 or -2, then as little verbosity as possible. If 0 or FALSE,
then minimal outputs; if |
A file is written with the package names and versions of all packages within libPaths.
This can later be passed to Require.
pkgSnapshot2 returns a vector of package names and versions, with no file output. See
examples.
Will both write a file, and (invisibly) return a vector of packages with the
version numbers. This vector can be used directly in Require, though it should likely
be used with require = FALSE to prevent attaching all the packages.
Pass the snapshot file to Require() via packageVersionFile = "snapshot.txt".
By default this routes through a multi-stage installer (gated by
options(Require.snapshotInstaller = "install.packages")) that:
Skips already-installed-at-target-version refs.
Cache pre-filter via pkgcache::pkg_cache_list(). Source tarballs feed
pak::pkg_install(local::...); binaries are reserved for step (4). Rotten
cache rows (missing fullpath, gzip-corrupt, DESCRIPTION mismatch) are
auto-evicted via pkgcache::pkg_cache_delete_files() so future runs
don't keep tripping on them.
Parallel libcurl-multi download for refs not in cache, chunked at 50
URLs per call (macOS file-descriptor limit). Walks priority URLs: row's
Repository -> PPM -> CRAN -> CRAN/Archive. Up to 4 retries with
exponential backoff (Require.snapshotDownloadAttempts).
Hybrid binary-first install via install.packages(type = "binary")
for any ref that has a cache binary matching this R session
(R.version$platform, <major>.<minor>). Skips compilation, reduces
pak's parallel-build workload. Disable via
options(Require.snapshotInstallerHybrid = FALSE).
pak::pkg_install(local::...) for the rest with dependencies = NA,
upgrade = FALSE. Refs already-installed-at-target-version are excluded
upfront so pak doesn't reinstall-to-self.
install.packages(repos = file://...) fallback if pak refuses (its
solver is strict; install.packages is best-effort and tolerates
per-package compile failures).
Bump-and-retry: for any ref still missing, walks newer-than-pin
versions from CRAN/PPM/Archive ascending and tries each until one
installs (capped at 20 candidates). Disable via
options(Require.snapshotInstallerBumpOnFail = FALSE) for strict
reproducibility (no drift, fail loudly).
Diagnostic report classifying each gap with a concrete fix: line.
Built binaries from this run are added back to pkgcache via
cacheBuiltBinaries() (registered on on.exit), so a subsequent run hits
step (4) instead of recompiling.
A ref's DESCRIPTION declares Imports: X (>= V) but the snapshot
pins X at a version that doesn't satisfy it. pak's strict solver
refuses to install. The installer runs a coherence pre-check before
handing off to pak and prints any unsatisfied constraint with a fix
suggestion (e.g., servr 0.30 requires xfun (>= 0.42); snapshot pins xfun = 0.40 -> bump xfun).
R pseudo-packagepkgSnapshot() writes a row recording the running R version
(e.g., R,4.4,...). The installer skips this row alongside base
packages.
Source builds need the host's system libs to match what the package
expects. The installer's classifyCompileFailure() recognises
missing-header errors (jpeglib.h, gdal.h, geos_c.h, glpk.h,
ft2build.h, sodium.h, ...) and prints the corresponding
brew install ... (or apt) suggestion. R 4.5's removal of
Calloc/Free, GDAL >= 3.10's const OGRSpatialReference* ABI
change, and Rcpp's class_::constructor<> template-arity limit are
each pattern-matched and reported with a "bump <pkg>" suggestion.
~/.R/Makevars
R's default compile flags only search /opt/R/arm64/include. To pick
up Homebrew headers (libjpeg, glpk, freetype, etc.), add to
~/.R/Makevars:
CPPFLAGS += -I/opt/homebrew/include
LDFLAGS += -L/opt/homebrew/lib
pkgcache indexpkgcache shares state across R versions and architectures. Cache
rows tagged with platform/rversion that don't match this session
are filtered out (e.g., R-4.5 binaries when running R-4.4); validation
also catches index rows whose file content disagrees with the index
(a known historical bug-class). Both kinds get auto-evicted, so
pak::cache_clean() is rarely needed.
local:: is source-onlyConfirmed empirically that pak's pkg_install("local::<file>")
rejects binary tarballs (.tgz / .zip content) with
"Platform mismatch" – even when the binary is for the current
platform. The hybrid stage installs binaries via
install.packages(type = "binary") BEFORE pak runs, so pak only
sees source refs.
install.packages continues past per-package compile failures;
pak::pkg_install does not. The fallback to install.packages and
the bump-and-retry stage together provide a best-effort completion
guarantee even when individual refs are environment-fragile.
Require.snapshotInstaller"install.packages" to use the
pipeline above; "pak" for the legacy direct-pak path.
Require.snapshotInstallerUsePPMTRUE (default) to prepend a PPM
binary repo. PPM serves Mac binaries by content-negotiating the
R/<version> User-Agent.
Require.snapshotInstallerHybridTRUE (default) – pre-install
cache binaries via install.packages(type = "binary") before pak.
Require.snapshotInstallerBumpOnFailTRUE (default) – walk newer versions for refs that fail at the pin. FALSE for strict reproducibility.
Require.snapshotInstallerKnownFailscharacter vector of pkg names to skip in bump-retry (e.g. environment-dependent refs whose newer versions also won't help).
Require.snapshotInstallerPakSilentFALSE (default) – pak's resolver output reaches the user.
Require.snapshotDownloadAttemptsRetry count for libcurl-multi downloads. Default 4.
Require.snapshotDownloadChunkURLs per download.file() call.
Default 50 (stays under macOS's ~256 file-descriptor ulimit).
## Not run: if (Require:::.runLongExamples()) { opts <- Require:::.setupExample() # install one archived version so that below does something interesting libForThisEx <- tempdir2("Example") Require("crayon (==1.5.1)", libPaths = libForThisEx, require = FALSE) # Normal use -- using the libForThisEx for example; # normally libPaths would be omitted to get all # packages in user or project library tf <- tempfile() # writes to getOption("Require.packageVersionFile") # within project; also returns a vector # of packages with version pkgs <- pkgSnapshot( packageVersionFile = tf, libPaths = libForThisEx, standAlone = TRUE # only this library ) # Now move this file to another computer e.g. by committing in git, # emailing, googledrive # on next computer/project Require(packageVersionFile = tf, libPaths = libForThisEx) # Using pkgSnapshot2 to get the vector of packages and versions pkgs <- pkgSnapshot2( libPaths = libForThisEx, standAlone = TRUE ) Install(pkgs) # will install packages from previous line Require:::.cleanup(opts) unlink(getOption("Require.packageVersionFile")) } ## End(Not run)## Not run: if (Require:::.runLongExamples()) { opts <- Require:::.setupExample() # install one archived version so that below does something interesting libForThisEx <- tempdir2("Example") Require("crayon (==1.5.1)", libPaths = libForThisEx, require = FALSE) # Normal use -- using the libForThisEx for example; # normally libPaths would be omitted to get all # packages in user or project library tf <- tempfile() # writes to getOption("Require.packageVersionFile") # within project; also returns a vector # of packages with version pkgs <- pkgSnapshot( packageVersionFile = tf, libPaths = libForThisEx, standAlone = TRUE # only this library ) # Now move this file to another computer e.g. by committing in git, # emailing, googledrive # on next computer/project Require(packageVersionFile = tf, libPaths = libForThisEx) # Using pkgSnapshot2 to get the vector of packages and versions pkgs <- pkgSnapshot2( libPaths = libForThisEx, standAlone = TRUE ) Install(pkgs) # will install packages from previous line Require:::.cleanup(opts) unlink(getOption("Require.packageVersionFile")) } ## End(Not run)
Require optionsThese provide top-level, powerful settings for a comprehensive reproducible workflow. See Details below.
RequireOptions() getRequireOptions()RequireOptions() getRequireOptions()
RequireOptions()prints the default values of package options set at startup, which may have been changed (e.g., by the user) during the current session.
getRequireOptions()prints the current values of package options.
Below are options that can be set with options("Require.xxx" = newValue),
where xxx is one of the values below, and newValue is a new value to give
the option. Sometimes these options can be placed in the user's .Rprofile
file so they persist between sessions.
The following options are likely of interest to most users:
install Default: TRUE. This is the default argument to Require,
but does not affect Install. If this is FALSE, then no installations
will be attempted, and missing packages will result in an error.
RPackageCache Default: cacheGetOptionCachePkgDir(), which must be
either a path or a logical. To turn off package caching, set this to FALSE.
This can be set using an environment variable e.g.,
Sys.setenv(R_REQUIRE_PKG_CACHE = "somePath"), or
Sys.setenv(R_REQUIRE_PKG_CACHE = "TRUE"); if that is not set, then an
either a path or logical option (options(Require.cachePkgDir = "somePath")
or options(Require.cachePkgDir = TRUE)).
If TRUE, the default folder location cachePkgDir() will be used.
If this is TRUE or a path is provided, then binary and source packages will be cached here.
Subsequent downloads of same package will use local copy.
Default is to have packages not be cached locally so each install of the same version will
be from the original source, e.g., CRAN, GitHub.
otherPkgsDefault: A character vector of packages that are
generally more successful if installed from Source on Unix-alikes. Since
there are repositories that offer binary packages builds for Linux (e.g.,
RStudio Package Manager), the vector of package names indicated here will
default to a standard CRAN repository, forcing a source install. See also
spatialPkgs option, which does the same for spatial packages.
purgeDefault: FALSE. If set to (almost) all internal caches used
by Require will be deleted and rebuilt. This should not generally be
necessary as it will automatically be deleted after (by default) 1 hour (set
via R_AVAILABLE_PACKAGES_CACHE_CONTROL_MAX_AGE environment variable in seconds).
downloadTimeoutDefault: 300L (seconds). Used as the floor for
options("timeout") during GitHub source-archive downloads in the legacy
(non-pak) install path. R's stock 60-second timeout is too short for
slow connections fetching multi-MB zips. Has no effect under
Require.usePak = TRUE, which delegates downloads to pak's own libcurl
client.
spatialPkgs Default: A character vector of packages that are
generally more successful if installed from Source on Unix-alikes. Since
there are repositories that offer binary packages builds for Linux (e.g.,
Posit Package Manager), the vector of package names indicated here will
default to a standard CRAN repository, forcing a source install.
See also otherPkgs option, which does the same for non-spatial packages.
useCranCache Default: FALSE. A user can optionally use the locally
cached packages that are available due to a user's use of the crancache package.
verbose Default: 1. See ?Require.
.basePkgs
Recursive function to remove .basePkgs
rmBase(includeBase = formals(pkgDep)[["includeBase"]], deps)rmBase(includeBase = formals(pkgDep)[["includeBase"]], deps)
includeBase |
Logical. If |
deps |
Either a list of dependencies, a data.table of dependencies with
a column |
Reference table of R versions and their release dates (2018 and later).
rversionsrversions
Update this as needed using rversions::r_versions():
# install.packages("rversions")
v = rversions::r_versions()
keep = which(as.Date(v$date, format = "
as.Date("2018-01-01", format = "
dput(v[keep, c("version", "date")])
setdiff, but takes into account namesThis will identify the elements in l1 that are not in l2. If
missingFill is provided, then elements that are in l2, but not in l1
will be returned, assigning missingFill to their values. This might be
NULL or "", i.e., some sort of empty value. This function will work on
named lists, named vectors and likely on other named classes.
setdiffNamed(l1, l2, missingFill)setdiffNamed(l1, l2, missingFill)
l1 |
A named list or named vector |
l2 |
A named list or named vector (must be same class as |
missingFill |
A value, such as |
There are 3 types of differences that might occur with named
elements: 1. a new named element, 2. an removed named element, and 3. a
modified named element. This function captures all of these. In the case of
unnamed elements, e.g., setdiff, the first two are not seen as differences,
if the values are not different.
A vector or list of the elements in l1 that are not in l2, and
optionally the elements of l2 that are not in l1, with values set to
missingFill
.libPaths
This will set the .libPaths() by either adding a new path to it if
standAlone = FALSE, or will concatenate c(libPath, tail(.libPaths(), 1))
if standAlone = TRUE. Currently, the default is to make this new
.libPaths() "sticky", meaning it becomes associated with the current
directory even through a restart of R. It does this by adding and/updating
the ‘.Rprofile’ file in the current directory. If this current directory
is a project, then the project will have the new .libPaths() associated
with it, even through an R restart.
setLibPaths( libPaths, standAlone = TRUE, updateRprofile = getOption("Require.updateRprofile", FALSE), exact = FALSE, verbose = getOption("Require.verbose") )setLibPaths( libPaths, standAlone = TRUE, updateRprofile = getOption("Require.updateRprofile", FALSE), exact = FALSE, verbose = getOption("Require.verbose") )
libPaths |
A new path to append to, or replace all existing user
components of |
standAlone |
Logical. If |
updateRprofile |
Logical or Character string. If |
exact |
Logical. This function will automatically append the R version
number to the |
verbose |
Numeric or logical indicating how verbose should the function
be. If -1 or -2, then as little verbosity as possible. If 0 or FALSE,
then minimal outputs; if |
This details of this code were modified from https://github.com/milesmcbain. A different, likely non-approved by CRAN approach that also works is here: https://stackoverflow.com/a/36873741/3890027.
The main point of this function is to set .libPaths(), which will
be changed as a side effect of this function. As when setting options,
this will return the previous state of .libPaths() allowing the user to
reset easily.
## Not run: if (Require:::.runLongExamples()) { opts <- Require:::.setupExample() origDir <- setwd(tempdir()) td <- tempdir() setLibPaths(td) # set a new R package library locally setLibPaths() # reset it to original setwd(origDir) # Using standAlone = FALSE means that newly installed packages # will be installed # in the new package library, but loading packages can come # from any of the ones listed in .libPaths() # will have 2 or more paths otherLib <- file.path(td, "newProjectLib") setLibPaths(otherLib, standAlone = FALSE) # Can restart R, and changes will stay # remove the custom .libPaths() setLibPaths() # reset to previous; remove from .Rprofile # because libPath arg is empty Require:::.cleanup(opts) unlink(otherLib, recursive = TRUE) } ## End(Not run)## Not run: if (Require:::.runLongExamples()) { opts <- Require:::.setupExample() origDir <- setwd(tempdir()) td <- tempdir() setLibPaths(td) # set a new R package library locally setLibPaths() # reset it to original setwd(origDir) # Using standAlone = FALSE means that newly installed packages # will be installed # in the new package library, but loading packages can come # from any of the ones listed in .libPaths() # will have 2 or more paths otherLib <- file.path(td, "newProjectLib") setLibPaths(otherLib, standAlone = FALSE) # Can restart R, and changes will stay # remove the custom .libPaths() setLibPaths() # reset to previous; remove from .Rprofile # because libPath arg is empty Require:::.cleanup(opts) unlink(otherLib, recursive = TRUE) } ## End(Not run)
Enable use of binary package builds for Linux from the RStudio Package
Manager repo. This will set the repos option, affecting the current R
session. It will put this binaryLinux in the first position. If the
getOption("repos") is NULL, it will put backupCRAN in second position.
setLinuxBinaryRepo( binaryLinux = urlForArchivedPkgs, backupCRAN = srcPackageURLOnCRAN )setLinuxBinaryRepo( binaryLinux = urlForArchivedPkgs, backupCRAN = srcPackageURLOnCRAN )
binaryLinux |
A CRAN repository serving binary Linux packages. |
backupCRAN |
If there is no CRAN repository set |
setup and setupOff are currently deprecated.
These may be re-created in a future version.
In its place, a user can simply put .libPaths(libs, include.site = FALSE)
in their .Rprofile file, where libs is the directory where the packages
should be installed and should be a folder with the R version number, e.g.,
derived by using checkLibPaths(libs).
setup( newLibPaths, RPackageFolders, RPackageCache = cacheGetOptionCachePkgDir(), standAlone = getOption("Require.standAlone", TRUE), verbose = getOption("Require.verbose") ) setupOff(removePackages = FALSE, verbose = getOption("Require.verbose"))setup( newLibPaths, RPackageFolders, RPackageCache = cacheGetOptionCachePkgDir(), standAlone = getOption("Require.standAlone", TRUE), verbose = getOption("Require.verbose") ) setupOff(removePackages = FALSE, verbose = getOption("Require.verbose"))
newLibPaths |
Same as |
RPackageFolders |
One or more folders where R packages are installed to and loaded from. In the case of more than one folder provided, installation will only happen in the first one. |
RPackageCache |
See |
standAlone |
Logical. If |
verbose |
Numeric or logical indicating how verbose should the function
be. If -1 or -2, then as little verbosity as possible. If 0 or FALSE,
then minimal outputs; if |
removePackages |
Deprecated. Please remove packages manually from |
The list of R packages that Require installs from source on Linux, even if
the getOptions("repos") is a binary repository. This list can be updated by
the user by modifying the options Require.spatialPkgs or
Require.otherPkgs. Default "force source only packages" are visible with
RequireOptions().
sourcePkgs(additional = NULL, spatialPkgs = NULL, otherPkgs = NULL)sourcePkgs(additional = NULL, spatialPkgs = NULL, otherPkgs = NULL)
additional |
Any other packages to be added to the other 2 argument vectors |
spatialPkgs |
A character vector of package names that focus on spatial analyses. |
otherPkgs |
A character vector of package names that often require system specific compilation. |
A sorted concatenation of the 3 input parameters.
split for a data.table that keeps integrity of a column of lists of data.table objectsdata.table::split does 2 bad things:
reorders if using f
destroys the integrity of a column that is a list of data.tables, when using by
So, to keep order, need by, but to keep integrity, need f. This function
splitKeepOrderAndDTIntegrity(pkgDT, splitOn)splitKeepOrderAndDTIntegrity(pkgDT, splitOn)
pkgDT |
A |
splitOn |
Character vector passed to |
A list of data.table objects of length(unique(splitOn)).
This uses sys package so that messaging can be controlled. This also provides
the option to parallelize by spawning multiple background process to allow
parallel e.g., downloads. Noting that if libcurl is installed (and detected
using capabilities("libcurl")), then no explicit parallelism will be allowed,
instead method = "libcurl" will be passed enabling parallel downloads.
sysInstallAndDownload( args, splitOn = "pkgs", doLine = "outfiles <- do.call(download.packages, args)", returnOutfile = FALSE, doLineVectorized = TRUE, tmpdir, libPaths, verbose )sysInstallAndDownload( args, splitOn = "pkgs", doLine = "outfiles <- do.call(download.packages, args)", returnOutfile = FALSE, doLineVectorized = TRUE, tmpdir, libPaths, verbose )
args |
A list with all arguments for a do.call to either |
splitOn |
A character vector of the names in |
doLine |
A character string with the |
returnOutfile |
A logical. If |
doLineVectorized |
A logical. If |
tmpdir |
A single path where all downloads will be put |
libPaths |
The library path (or libraries) where all packages should be
installed, and looked for to load (i.e., call |
verbose |
Numeric or logical indicating how verbose should the function
be. If -1 or -2, then as little verbosity as possible. If 0 or FALSE,
then minimal outputs; if |
Mostly for side effects, namely installed packages or downloaded packages or
files. However, in the case of returnOutfile = TRUE, then a list of
filenames will be returned with any outputs from the doLine.
Create a temporary subdirectory in .RequireTempPath(), or a
temporary file in that temporary subdirectory.
tempdir2( sub = "", tempdir = getOption("Require.tempPath", .RequireTempPath()), create = TRUE )tempdir2( sub = "", tempdir = getOption("Require.tempPath", .RequireTempPath()), create = TRUE )
sub |
Character string, length 1. Can be a result of
|
tempdir |
Optional character string where the
temporary dir should be placed. Defaults to |
create |
Logical. Should the directory be created. Default |
Make a temporary subfile in a temporary (sub-)directory
tempfile2( sub = "", tempdir = getOption("Require.tempPath", .RequireTempPath()), ... )tempfile2( sub = "", tempdir = getOption("Require.tempPath", .RequireTempPath()), ... )
sub |
Character string, length 1. Can be a result of
|
tempdir |
Optional character string where the
temporary dir should be placed. Defaults to |
... |
passed to |
The resulting string(s) will have only name (including github.com repository if it exists).
trimVersionNumber(pkgs)trimVersionNumber(pkgs)
pkgs |
A character string vector of packages with or without GitHub path or versions |
trimVersionNumber("PredictiveEcology/Require (<=0.0.1)")trimVersionNumber("PredictiveEcology/Require (<=0.0.1)")
Similar to update.packages, but works for archived, non-archived,
and Github packages.
updatePackages( libPaths = .libPaths()[1], purge = FALSE, verbose = getOption("Require.verbose") )updatePackages( libPaths = .libPaths()[1], purge = FALSE, verbose = getOption("Require.verbose") )
libPaths |
The library to update; defaults to |
purge |
Logical. Should the assessment of |
verbose |
Numeric or logical indicating how verbose should the function
be. If -1 or -2, then as little verbosity as possible. If 0 or FALSE,
then minimal outputs; if |
Run for its side effect, namely, updating installed packages to their latest possible state, whether they are on CRAN currently, archived, or on GitHub.