| Title: | R Source Packages Manager |
|---|---|
| Description: | Manage a collection/library of R source packages. Discover, document, load, test source packages. Enable to use those packages as if they were actually installed. Quickly reload only what is needed on source code change. Run tests and checks in parallel. |
| Authors: | Karl Forner [aut, cre, cph] |
| Maintainer: | Karl Forner <[email protected]> |
| License: | GPL (>= 3) |
| Version: | 0.2.1 |
| Built: | 2026-05-20 09:51:20 UTC |
| Source: | https://github.com/kforner/srcpkgs |
Manage a collection/library of R source packages. Discover, document, load, test source packages. Enable to use those packages as if they were actually installed. Quickly reload only what is needed on source code change. Run tests and checks in parallel.
srcpkgs main objective is to ease development on any project
that uses a collection of R source packages (a library).
It is able to figure out which dependencies are source packages, and is able
to quickly detect changes in any of the used source packages.
Maintainer: Karl Forner [email protected] [copyright holder]
Useful links:
N.B: the hidden files and directories are ignored.
In general, this function is not used directly, instead you should use get_srcpkgs()
find_srcpkgs( root = get_project_root(), srcpkgs_paths = find_srcpkgs_paths(root, prune = prune), prune = TRUE )find_srcpkgs( root = get_project_root(), srcpkgs_paths = find_srcpkgs_paths(root, prune = prune), prune = TRUE )
root |
directory from where to search for source packages |
srcpkgs_paths |
paths to the source packages folders |
prune |
whether to report packages contained inside another package (e.g. in tests/) |
a "srcpkgs" object (or NULL if none found), a named list of "srcpkg" objects, that essentially are devtools "package" objects. The list is named after the package names.
pkg <- setup_and_get_dummy_srcpkg() pkgs <- find_srcpkgs(dirname(pkg$path)) print(pkgs)pkg <- setup_and_get_dummy_srcpkg() pkgs <- find_srcpkgs(dirname(pkg$path)) print(pkgs)
The first call to this function will trigger the initialization of the package ((cf reset()).
Since it is used by mostly all user-facing load-related functions, this enables a runtime initialization,
as opposed to a load-time initialization. So for example
you may load srcpkgs, then change the current directory to your project.
Then the first load will setup the settings.
get_srcpkgs(filter = NULL)get_srcpkgs(filter = NULL)
filter |
a pattern to filter the source packages |
For optimization, the paths to discovered source packages are cached (cf reset() and settings().
This function will reparse the DESCRIPTION for any change.
If you add or delete a source package, you must reset the source package paths using reset()
This function is useful for troubleshooting, to understand what are the source packages discovered
and managed by srcpkgs
the source packages as a "scrpkgs" object, cf find_srcpkgs(), or NULL if none
# setup a srcpkg. We need reset because it is not discoverable from the current directory pkg <- setup_and_get_dummy_srcpkg() reset(dirname(pkg$path)) print(get_srcpkgs())# setup a srcpkg. We need reset because it is not discoverable from the current directory pkg <- setup_and_get_dummy_srcpkg() reset(dirname(pkg$path)) print(get_srcpkgs())
hacks library() and loadNamespace() using the base R tracer function trace().
library(pkg) will basically call pkg_load(pkg) if the source package pkg
is managed by srcpkgs
hack_r_loaders()hack_r_loaders()
N.B: usually you do not need to call that function explicitly. The function is reentrant.
no return value, called for side-effects
At package startup (actually .OnAttach()), hack_r_loaders() will be automatically called to hack
the R loaders, UNLESS this is inhibited via the option srcpkgs.inhibit_r_loaders_hack or the
environment variable SRCPKGS.INHIBIT_R_LOADERS_HACK. You may set any value like TRUE, "TRUE", 1 or "1".
## Not run: # hack library hack_r_loaders() # unhack unhack_r_loaders() # prevent automatic hacking when srcpkgs is loaded options(srcpkgs.inhibit_r_loaders_hack=TRUE) # or Sys.setenv(SRCPKGS.INHIBIT_R_LOADERS_HACK="1") library(srcpkgs) ## End(Not run)## Not run: # hack library hack_r_loaders() # unhack unhack_r_loaders() # prevent automatic hacking when srcpkgs is loaded options(srcpkgs.inhibit_r_loaders_hack=TRUE) # or Sys.setenv(SRCPKGS.INHIBIT_R_LOADERS_HACK="1") library(srcpkgs) ## End(Not run)
This function will check a source package.
pkg_check( pkgid, src_pkgs = get_srcpkgs(), lib = ".check", roxygen = TRUE, quiet = FALSE, error_on = "error", check_system_clock = FALSE, ... )pkg_check( pkgid, src_pkgs = get_srcpkgs(), lib = ".check", roxygen = TRUE, quiet = FALSE, error_on = "error", check_system_clock = FALSE, ... )
pkgid |
a package name, path or package object |
src_pkgs |
a collection of source packages as a |
lib |
directory where to install and find installed pkgs |
roxygen |
whether to roxygenize |
quiet |
whether to be quiet/silent |
error_on |
passed to |
check_system_clock |
if FALSE, disable the |
... |
passed to |
the results as a pkg_test object, or NULL if no tests found
lists the packages that are attached, i.e. present in the R search() path
pkg_list_attached()pkg_list_attached()
the names of attached package name as a character vector
print(sort(pkg_list_attached()))print(sort(pkg_list_attached()))
N.B: the defaults are different from devtools::load_all(): the helpers are not loaded, only
the functions tagged as exported are actually exported. The intended goal is to make it as similar
to the behaviour of the R loaders.
pkg_load( pkgid, src_pkgs = get_srcpkgs(), attach = TRUE, suggests = FALSE, roxygen = TRUE, helpers = FALSE, export_all = FALSE, quiet = FALSE, dry_run = FALSE, ... )pkg_load( pkgid, src_pkgs = get_srcpkgs(), attach = TRUE, suggests = FALSE, roxygen = TRUE, helpers = FALSE, export_all = FALSE, quiet = FALSE, dry_run = FALSE, ... )
pkgid |
a package name, path or package object |
src_pkgs |
a collection of source packages as a |
attach |
Whether to attach a package environment to the search
path. If |
suggests |
whether to load suggested packages. if TRUE, the suggested are processed like imports |
roxygen |
whether to automatically roxygenise packages (if needed) |
helpers |
if |
export_all |
If |
quiet |
whether to be quiet/silent |
dry_run |
whether not to actually execute any action having side-effects |
... |
Arguments passed on to
|
This the workhorse function of the package, called by library() and loadNamespace()
when hacked (cf hack_r_loaders().
This function will check that all dependent packages are up-to-date, and document and reload them as needed.
To be able to properly load a package, its dependent source packages must be loaded in proper order. i.e. if A–>B–>C, the load order must be C, B, A
the load plan as a data frame, or NULL if there is nothing to do.
root <- tempfile() pkg <- setup_and_get_dummy_srcpkg(root) reset(root) # load and attach a package pkg_load(pkg) # just load, do not attach it (~ loadNamespace()) pkg_unload(pkg) pkg_load(pkg, attach = FALSE) # do some changes, to a source package or any of its depencies or dependents pkg_unload(pkg) plan <- pkg_load(pkg, dry_run = TRUE) # then you can inspect the plan actionsroot <- tempfile() pkg <- setup_and_get_dummy_srcpkg(root) reset(root) # load and attach a package pkg_load(pkg) # just load, do not attach it (~ loadNamespace()) pkg_unload(pkg) pkg_load(pkg, attach = FALSE) # do some changes, to a source package or any of its depencies or dependents pkg_unload(pkg) plan <- pkg_load(pkg, dry_run = TRUE) # then you can inspect the plan actions
if the package has not changed (based on the md5sum file), does nothing
otherwise roxygenise the package using roxygen2::roxygenise
and update and save the new md5sum file
pkg_roxygenise(pkg_path, force = FALSE, quiet = FALSE, ...)pkg_roxygenise(pkg_path, force = FALSE, quiet = FALSE, ...)
pkg_path |
the package path, as a character |
force |
if force(d), do not use the md5-based system to detect package changes |
quiet |
whether to be quiet/silent |
... |
passed to |
N.B: has the side-effect of loading the package
if the roxygenation has been performed
pkg <- setup_and_get_dummy_srcpkg() pkg_roxygenise(pkg$path)pkg <- setup_and_get_dummy_srcpkg() pkg_roxygenise(pkg$path)
This function will test a source package using testthat,
making sure the package and its source package dependencies are up-to-date and loaded
pkg_test( pkgid, filter = NULL, src_pkgs = get_srcpkgs(), export_all = TRUE, quiet = TRUE, ... )pkg_test( pkgid, filter = NULL, src_pkgs = get_srcpkgs(), export_all = TRUE, quiet = TRUE, ... )
pkgid |
a package name, path or package object |
filter |
filter in the tests to run. cf |
src_pkgs |
a collection of source packages as a |
export_all |
passed to |
quiet |
whether to be quiet/silent |
... |
passed to |
the results as a pkg_test object, which is an empty listL if no tests were found
root <- tempfile() pkg <- setup_and_get_dummy_srcpkg(root) reset(root) res <- pkg_test(pkg) print(res)root <- tempfile() pkg <- setup_and_get_dummy_srcpkg(root) reset(root) res <- pkg_test(pkg) print(res)
To be able to unload properly a package, all the packages that depend even indirectly on it should be unloaded first.
pkg_unload( pkg_or_name, src_pkgs = get_srcpkgs(), dry_run = FALSE, loaded = loadedNamespaces(), quiet = FALSE )pkg_unload( pkg_or_name, src_pkgs = get_srcpkgs(), dry_run = FALSE, loaded = loadedNamespaces(), quiet = FALSE )
pkg_or_name |
a package name or object ("package" or "srcpkg") |
src_pkgs |
a collection of source packages as a |
dry_run |
whether not to actually execute any action having side-effects |
loaded |
the loaded packages, useful for testing. |
quiet |
whether to be quiet/silent |
N.B: this function also works for non source packages.
a data frame of the unloaded package names, and whether they were attached, invisibly or NULL if the package is not loaded
root <- tempfile() pkg <- setup_and_get_dummy_srcpkg(root) reset(root) pkg_load(pkg) pkg_unload(pkg)root <- tempfile() pkg <- setup_and_get_dummy_srcpkg(root) reset(root) pkg_load(pkg) pkg_unload(pkg)
checks a list of source packages
pkgs_check( pkgids = names(filter_srcpkgs(src_pkgs, filter)), src_pkgs = get_srcpkgs(), filter = NULL, lib = ".check", quiet = FALSE, fail_on_error = FALSE, ... )pkgs_check( pkgids = names(filter_srcpkgs(src_pkgs, filter)), src_pkgs = get_srcpkgs(), filter = NULL, lib = ".check", quiet = FALSE, fail_on_error = FALSE, ... )
pkgids |
a list of package ids (names, paths or object), or a srcpkgs object. Also accept a singleton package object |
src_pkgs |
a collection of source packages as a |
filter |
filter out the packages to check using this pattern |
lib |
directory where to install and find installed pkgs |
quiet |
whether to be quiet/silent |
fail_on_error |
whether to die if there is at least an error or warning in the checks |
... |
passed to |
the results as a pkgs_test object
computes the dependencies of some (source) packages
pkgs_deps( pkgids, src_pkgs = get_srcpkgs(), source = TRUE, installed = TRUE, imports = TRUE, depends = TRUE, suggests = TRUE, reverse = FALSE )pkgs_deps( pkgids, src_pkgs = get_srcpkgs(), source = TRUE, installed = TRUE, imports = TRUE, depends = TRUE, suggests = TRUE, reverse = FALSE )
pkgids |
a list of package ids (names, paths or object), or a srcpkgs object. Also accept a singleton package object |
src_pkgs |
a collection of source packages as a |
source |
whether to report source packages |
installed |
whether to report installed (non-source) packages |
imports |
whether to only consider |
depends |
whether to only consider |
suggests |
whether to only consider |
reverse |
whether to compute reverse dependencies instead |
the dependencies, as a character vector, topologically sorted
pkg <- setup_and_get_dummy_srcpkg() deps_src <- pkgs_deps(pkg, installed = FALSE) deps_inst <- pkgs_deps(pkg, source = FALSE) print(get_srcpkgs()) deps_rev <- pkgs_deps(pkg, reverse = TRUE, suggests = FALSE)pkg <- setup_and_get_dummy_srcpkg() deps_src <- pkgs_deps(pkg, installed = FALSE) deps_inst <- pkgs_deps(pkg, source = FALSE) print(get_srcpkgs()) deps_rev <- pkgs_deps(pkg, reverse = TRUE, suggests = FALSE)
A source package can not be installed if its dependencies are not.
Will not reinstall packages if they are up-to-date
will roxygenise packages if needed
pkgs_install( pkgids, lib, src_pkgs = get_srcpkgs(), only_deps = FALSE, quiet = TRUE, ... )pkgs_install( pkgids, lib, src_pkgs = get_srcpkgs(), only_deps = FALSE, quiet = TRUE, ... )
pkgids |
a list of package ids (names, paths or object), or a srcpkgs object. Also accept a singleton package object |
lib |
directory where to install and find installed pkgs |
src_pkgs |
a collection of source packages as a |
only_deps |
whether not to include |
quiet |
whether to be quiet/silent |
... |
passed to |
the names of the packages actually installed
tests a list of source packages
pkgs_test( pkgids = names(filter_srcpkgs(src_pkgs, filter)), src_pkgs = get_srcpkgs(), filter = NULL, quiet = TRUE, ... )pkgs_test( pkgids = names(filter_srcpkgs(src_pkgs, filter)), src_pkgs = get_srcpkgs(), filter = NULL, quiet = TRUE, ... )
pkgids |
a list of package ids (names, paths or object), or a srcpkgs object. Also accept a singleton package object |
src_pkgs |
a collection of source packages as a |
filter |
filter out the packages to test using this pattern |
quiet |
whether to be quiet/silent |
... |
passed to |
the results as a pkgs_test object
## create a dummy collection of srcpkgs by replicating the dummy srcpkg pkg <- setup_and_get_dummy_srcpkg() pkgs <- srcpkgs(list(pkg, pkg)) res <- pkgs_test(pkgs, error_on = "never") print(res)## create a dummy collection of srcpkgs by replicating the dummy srcpkg pkg <- setup_and_get_dummy_srcpkg() pkgs <- srcpkgs(list(pkg, pkg)) res <- pkgs_test(pkgs, error_on = "never") print(res)
srcpkgs settingsWith this function, you can reset or set precisely the settings.
reset(root = find_project_root(), srcpkgs_paths = find_srcpkgs_paths(root))reset(root = find_project_root(), srcpkgs_paths = find_srcpkgs_paths(root))
root |
directory from where to search for source packages |
srcpkgs_paths |
paths to the source packages folders |
the settings (cf settings()) invisibly
# reset to appropriate defaults based on your current directory old <- reset() # explictly set the project root reset(root = tempdir()) # explictly set the source package paths (very unlikely) reset(srcpkgs_paths = c('pkgs/mypkg1', 'pkgs/mypkg2')) # restore previous settings reset(root = old$root, srcpkgs_paths = old$srcpkgs_paths)# reset to appropriate defaults based on your current directory old <- reset() # explictly set the project root reset(root = tempdir()) # explictly set the source package paths (very unlikely) reset(srcpkgs_paths = c('pkgs/mypkg1', 'pkgs/mypkg2')) # restore previous settings reset(root = old$root, srcpkgs_paths = old$srcpkgs_paths)
srcpkgs
informs about the settings currently used by srcpkgs
settings()settings()
a named list of:
initialized: whether the settings are initialized (as triggered by get_srcpkgs())
root: the project root
srcpkgs_paths: the paths of the source packages to manage
hack_r_loaders_installed: whether the R loaders are hacked
hack_r_loaders_enabled: whether the R loaded hack is in action (internal use)
print(settings())print(settings())
Intended for testing and to write examples
setup_and_get_dummy_srcpkg(dest = tempfile())setup_and_get_dummy_srcpkg(dest = tempfile())
dest |
where to install the dummy srcpkg |
the package as a srcpkg object
pkg <- setup_and_get_dummy_srcpkg() print(pkg)pkg <- setup_and_get_dummy_srcpkg() print(pkg)
creates a new "srcpkgs" object
srcpkgs(pkgs = lapply(paths, devtools::as.package), paths = NULL)srcpkgs(pkgs = lapply(paths, devtools::as.package), paths = NULL)
pkgs |
an existing srcpkgs object (no op), or a list of source package-like objects |
paths |
a list of source package paths as a character vector or list |
a srcpkgs object (a list named after the package names)
# build dummy source packages pkg1 <- setup_and_get_dummy_srcpkg() pkg2 <- pkg1 pkg2$package <- "dummy.srcpkg2" print(srcpkgs(list(pkg1, pkg2))) print(srcpkgs(paths = pkg1$path))# build dummy source packages pkg1 <- setup_and_get_dummy_srcpkg() pkg2 <- pkg1 pkg2$package <- "dummy.srcpkg2" print(srcpkgs(list(pkg1, pkg2))) print(srcpkgs(paths = pkg1$path))
The function is reentrant.
unhack_r_loaders()unhack_r_loaders()
no return value, called for side-effects
## Not run: unhack_r_loaders() ## End(Not run)## Not run: unhack_r_loaders() ## End(Not run)