| Title: | Manifest-Based Dependency Conflict Detection for Sandboxed and Desktop R Sessions |
|---|---|
| Description: | Lightweight, offline-first checking of R package dependencies against the currently installed environment, without requiring a full project lockfile. Verifies a declared manifest of package versions, including version constraints declared by transitive dependencies, reports session-level snapshot differences (including stale versions still loaded in a running session), detects packages shadowed by another library, and offers single-package version rollback. Designed for hosted notebooks (e.g. Kaggle, Colab, Binder) where 'renv'-style lockfile ownership is impractical, and equally usable on a normal desktop. |
| Authors: | Samruddhi Amol Shah [aut, cre], Kartik Patel [aut], Amrit Pal [ctb] |
| Maintainer: | Samruddhi Amol Shah <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.2.0 |
| Built: | 2026-10-07 09:18:22 UTC |
| Source: | https://github.com/sunraycodes/depguard |
Verifies that the packages declared in a manifest are installed at the
required versions, and (by default) walks their transitive dependency
tree to catch real conflicts: for every package in the tree, each
Imports/Depends/LinkingTo constraint such as cli (>= 3.4.0) is
compared against the version actually installed. This is the situation
that bites in practice, e.g. a newer package was installed but a
dependency was left at an older version.
dep_check( manifest = NULL, path = default_manifest_path(), recursive = TRUE, check_cran = FALSE, stop_on_problem = FALSE ) ## S3 method for class 'depguard_check' print(x, all = FALSE, ...)dep_check( manifest = NULL, path = default_manifest_path(), recursive = TRUE, check_cran = FALSE, stop_on_problem = FALSE ) ## S3 method for class 'depguard_check' print(x, all = FALSE, ...)
manifest |
A named character vector as returned by |
path |
File path to the manifest, used only if |
recursive |
Logical; if |
check_cran |
Logical; if |
stop_on_problem |
Logical; if |
x |
A |
all |
Logical; show every row rather than only problem rows. |
... |
Passed on to the data frame print method. |
Everything is computed from locally installed package metadata, so it
works with no internet connection. The network is only used if
check_cran = TRUE.
The status column is one of:
"ok": requirement satisfied;
"mismatch": installed, but the version does not satisfy the requirement;
"missing": not installed;
"restart": the version on disk is fine, but the older version still
loaded in this R session is not. Restart R to pick up the new one.
Invisibly, a data frame (class depguard_check) with columns
package, required, installed, status, depth
("direct"/"transitive"), required_by, loaded (version loaded in
this session, or "-") and reason. Printing it shows only the
problem rows; use print(x, all = TRUE) to see everything.
dep_check(manifest = c(cli = "1.0.0", utils = ""), recursive = FALSE)dep_check(manifest = c(cli = "1.0.0", utils = ""), recursive = FALSE)
Compares package versions now against a snapshot taken earlier with
dep_snapshot(). Changes are detected on disk, so an upgrade is caught
even though R keeps running the old version in memory until restart.
dep_diff(snapshot = NULL)dep_diff(snapshot = NULL)
snapshot |
A |
Risk levels:
"high": the package is loaded in this session and it changed on disk
(or the loaded version no longer matches disk). Code already run used
one version; code run after a restart will use another.
"low": the package changed but is not loaded.
"none": nothing changed.
Invisibly, a data frame with one row per package and columns
package, before, after, change ("upgraded", "downgraded",
"added", "removed", "none"), changed, currently_loaded,
loaded_version, session_stale (loaded version differs from disk) and
risk.
Detects whether R is running in a hosted notebook (Kaggle, Colab, Binder),
RStudio, or a plain desktop/server session, and reports which package
libraries exist and which are writable. depguard uses this to tailor
its advice (for example, how to restart the session after an install).
dep_env(check_online = FALSE) ## S3 method for class 'depguard_env' print(x, ...)dep_env(check_online = FALSE) ## S3 method for class 'depguard_env' print(x, ...)
check_online |
Logical; if |
x |
A |
... |
Ignored. |
Detection looks at environment variables only and makes no network calls
unless check_online = TRUE. Set options(depguard.platform = "kaggle")
(or "colab", "binder", "rstudio", "desktop") to override it.
An object of class depguard_env, a list with elements
platform, os, r_version, interactive, libs, writable_libs,
work_dir and online (NA unless check_online = TRUE).
dep_env()dep_env()
Reinstalls one package at a specific version, e.g. to undo a version that
was silently pulled in as a side effect of another install. This performs
a single-package rollback only: it does not resolve cascading
conflicts that the rollback might introduce with other packages. For full
dependency resolution, use renv::restore() or pak's solver instead.
dep_fix( package, version, method = c("auto", "pak", "remotes", "archive"), lib = NULL, dry_run = FALSE )dep_fix( package, version, method = c("auto", "pak", "remotes", "archive"), lib = NULL, dry_run = FALSE )
package |
Name of the package to roll back. |
version |
Target version string, e.g. |
method |
Which backend to use: |
lib |
Library to install into. Defaults to the first writable
library on |
dry_run |
Logical; if |
Three backends are supported. With method = "auto" the first one
available is used: pak, then remotes (both in Suggests), then
"archive", which needs nothing beyond base R: it downloads the source
tarball from the CRAN archive and installs it. (Installing from source
needs Rtools on Windows, and the Xcode command line tools on macOS if the
package contains compiled code; Kaggle/Colab-style Linux images normally
have what is needed.)
With method = "auto", if the chosen backend fails (for example because
the internet is flaky), dep_fix() falls back to the archive backend
before giving up. Set options(depguard.cran_mirror = "<url>") to use a
different CRAN mirror for the remotes and archive backends (pak
uses its own repository settings).
After installing, the version on disk is verified. If the package is loaded in the current session, R keeps running the old version until it is restarted, and you are told so.
Invisibly, TRUE on success; with dry_run = TRUE, a list
describing the plan.
## Not run: dep_fix("stringr", "1.5.0") dep_fix("stringr", "1.5.0", dry_run = TRUE) ## End(Not run)## Not run: dep_fix("stringr", "1.5.0") dep_fix("stringr", "1.5.0", dry_run = TRUE) ## End(Not run)
Convenience entry point intended to be run at the top of a notebook or
script. It reports the environment (hosted notebook or desktop, writable
libraries), warns about packages shadowed by another library, and then
either checks the environment against your manifest (see
dep_manifest()) or, if there is none, captures a baseline snapshot you
can compare against later with dep_diff().
dep_healthcheck( path = default_manifest_path(), check_cran = FALSE, libraries = TRUE )dep_healthcheck( path = default_manifest_path(), check_cran = FALSE, libraries = TRUE )
path |
File path to the manifest, used only if |
check_cran |
Logical; if |
libraries |
Logical; also run |
Invisibly, either the result of dep_check() (if a manifest
exists) or a depguard_snapshot object (if not).
dep_healthcheck()dep_healthcheck()
R searches library paths in order and loads the first copy it finds.
On hosted notebooks (a system library plus a user library) and on
desktops with several libraries, an old copy can shadow the newer one you
just installed, so packageVersion() and the version you think you
installed disagree. This is one of the commonest causes of "I upgraded it
but nothing changed".
dep_libraries()dep_libraries()
Invisibly, a data frame with one row per shadowed copy and columns
package, active_library, active_version, shadowed_library,
shadowed_version and differs (whether the versions are different).
It has zero rows when nothing is shadowed.
dep_libraries()dep_libraries()
Records the packages and versions your project needs, so that
dep_check() can later verify the live environment satisfies them. This
is a lightweight alternative to a full renv lockfile, intended for
sandboxed or ephemeral notebook sessions and for quick desktop projects
where you don't want to manage a lockfile.
dep_manifest(..., path = default_manifest_path())dep_manifest(..., path = default_manifest_path())
... |
Named arguments of the form |
path |
File path to store the manifest. Defaults to
|
Each requirement can be:
a bare version such as "1.1.4": at least that version;
a version with an operator: ">= 1.1.4", "> 1.1", "== 1.1.4"
(exactly), "< 2.0", "<= 2.0" or "!= 1.2";
NA or "": any version, as long as it is installed.
Use "==" when an upgrade would also be a conflict (see
dep_manifest_freeze() to pin whatever you have now).
The file format follows the extension of path. .rds (the default)
stores an R object. Any other extension (for example depguard.txt)
writes a human-readable text file, one package (op version) per line,
which is convenient to edit and to commit to version control.
Invisibly, the manifest as a named character vector.
tmp <- tempfile(fileext = ".rds") dep_manifest(dplyr = "1.1.4", ggplot2 = ">= 3.5.0", path = tmp) unlink(tmp) # Human-readable text format txt <- tempfile(fileext = ".txt") dep_manifest(cli = "== 3.6.2", path = txt) readLines(txt) unlink(txt)tmp <- tempfile(fileext = ".rds") dep_manifest(dplyr = "1.1.4", ggplot2 = ">= 3.5.0", path = tmp) unlink(tmp) # Human-readable text format txt <- tempfile(fileext = ".txt") dep_manifest(cli = "== 3.6.2", path = txt) readLines(txt) unlink(txt)
Writes a manifest from the versions currently installed, so a later
dep_check() (for example at the top of a re-run notebook, or after
installing something new) tells you if any of them moved.
dep_manifest_freeze( packages = NULL, exact = TRUE, path = default_manifest_path() )dep_manifest_freeze( packages = NULL, exact = TRUE, path = default_manifest_path() )
packages |
Character vector of packages to pin. Defaults to the
packages attached in this session (the ones you called |
exact |
If |
path |
File path to store the manifest. Defaults to
|
Invisibly, the manifest as a named character vector.
tmp <- tempfile(fileext = ".txt") dep_manifest_freeze("cli", path = tmp) readLines(tmp) unlink(tmp)tmp <- tempfile(fileext = ".txt") dep_manifest_freeze("cli", path = tmp) readLines(tmp) unlink(tmp)
Read an existing dependency manifest
dep_manifest_read(path = default_manifest_path())dep_manifest_read(path = default_manifest_path())
path |
File path to the manifest ( |
A named character vector of package requirements, or NULL
(invisibly) with a message if no manifest is found.
Records, for every installed package, the version on disk (what a fresh R
session would load) and the version currently loaded in this session. A
later call to dep_diff() compares against the snapshot to reveal what an
install silently changed.
dep_snapshot(scope = c("all", "loaded"), path = NULL) ## S3 method for class 'depguard_snapshot' print(x, ...)dep_snapshot(scope = c("all", "loaded"), path = NULL) ## S3 method for class 'depguard_snapshot' print(x, ...)
scope |
|
path |
Optional file path ( |
x |
A |
... |
Ignored. |
The most recent snapshot is remembered for the rest of the session, so
dep_diff() can be called without arguments. In hosted notebooks the
session usually has to be restarted after an install; pass path to save
the snapshot to disk so it survives the restart, then call
dep_diff("path/to/snapshot.rds").
An object of class depguard_snapshot, suitable for passing to
dep_diff(). Its packages element is a data frame with columns
package, disk_version, library and loaded_version.
snap <- dep_snapshot() dep_diff(snap)snap <- dep_snapshot() dep_diff(snap)