Showing 2 of 2 files from the diff.

@@ -0,0 +1,126 @@
Loading
1 +
2 +
#' Unload packages
3 +
#'
4 +
#' It will unload `packages` and their loaded reverse dependencies
5 +
#' (imports, really).
6 +
#'
7 +
#' It will not unload
8 +
#' * base packages
9 +
#' * pak
10 +
#' * packages that are not loaded, obviously.
11 +
#'
12 +
#' This function is similar to `pkgload::unload()`, but it is specialized
13 +
#' to pak, in that
14 +
#' * it does not deal with packages loaded by pkgload.
15 +
#' * it will not unload base packages and pak itself.
16 +
#' * it will also unload the loaded reverse dependencies of the unloaded
17 +
#'   packages, in the right order.
18 +
#' * It never forces an unload. (It does not need to, since reverse
19 +
#'   dependencies are unloaded first.)
20 +
#'
21 +
#' @param packages [character] The packages to unload.
22 +
#' @return The unloaded packages, unvisibly.
23 +
#'
24 +
#' @noRd
25 +
26 +
unload <- function(packages) {
27 +
28 +
  badbase <- intersect(base_packages(), packages)
29 +
  if (length(badbase) > 0) {
30 +
    packages <- setdiff(packages, badbase)
31 +
    warning("Will not unload base packages: ", paste(badbase, collapse = ", "))
32 +
  }
33 +
34 +
  if ("pak" %in% packages) {
35 +
    packages <- setdiff(packages, "pak")
36 +
    warning("Will not unload pak")
37 +
  }
38 +
39 +
  badloaded <- setdiff(packages, loadedNamespaces())
40 +
  if (length(badloaded) > 0) {
41 +
    packages <- setdiff(packages, badloaded)
42 +
    warning(
43 +
      "Will not unload packages that are load not loaded: ",
44 +
      paste(badloaded, collapse = ", ")
45 +
    )
46 +
  }
47 +
48 +
  # This will also include reverse dependencies
49 +
  packages <- unload_order_topo(packages)
50 +
51 +
  # Always run garbage collector to force any deleted external pointers to
52 +
  # finalise
53 +
  gc()
54 +
55 +
  for (pkg in packages) {
56 +
    unloadNamespace(pkg)
57 +
    unload_dll(pkg)
58 +
  }
59 +
60 +
  invisible(packages)
61 +
}
62 +
63 +
#' Query additional packages that need to be unloaded
64 +
#'
65 +
#' @param packages [character] Packages that we want to unload.
66 +
#' @return [character] All packages that need to be unloaded, because
67 +
#' they (recursively) depend on `packages`.
68 +
#'
69 +
#' @noRd
70 +
71 +
needs_unload <- function(packages) {
72 +
  packages <- setdiff(packages, c(base_packages(), "pak"))
73 +
  packages <- intersect(packages, loadedNamespaces())
74 +
  unload_order_topo(packages)
75 +
}
76 +
77 +
package_imports <- function(package, base = FALSE) {
78 +
  imp <- unique(names(getNamespaceInfo(package, "imports")))
79 +
  if (!base) imp <- imp[! imp %in% base_packages()]
80 +
  # pkgload has some unnamed components somehow?
81 +
  imp[imp != ""]
82 +
}
83 +
84 +
unload_order_topo <- function(packages) {
85 +
  all <- setdiff(loadedNamespaces(), base_packages())
86 +
  imp <- lapply_with_names(all, package_imports)
87 +
  imp_by <- lapply_with_names(all, function(p) {
88 +
    all[vlapply(imp, `%in%`, x = p)]
89 +
  })
90 +
91 +
  revs <- packages
92 +
  while (length(more <- setdiff(unlist(imp_by[revs]), revs)) > 0) {
93 +
    revs <- c(revs, more)
94 +
  }
95 +
  imp_by <- lapply(imp_by, intersect, revs)[revs]
96 +
97 +
  topo <- character()
98 +
  while (length(topo) < length(revs)) {
99 +
    new <- names(imp_by)[viapply(imp_by, length) == 0]
100 +
    if (length(new) == 0) stop("Loop in package imports???")
101 +
    topo <- c(topo, new)
102 +
    imp_by <- lapply(imp_by, setdiff, new)[setdiff(names(imp_by), new)]
103 +
  }
104 +
105 +
  topo
106 +
}
107 +
108 +
unload_dll <- function(package) {
109 +
  pkglibs <- loaded_dlls(package)
110 +
111 +
  for (lib in pkglibs) {
112 +
    dyn.unload(lib[["path"]])
113 +
  }
114 +
115 +
  # Remove the unloaded dlls from .dynLibs()
116 +
  libs <- .dynLibs()
117 +
  .dynLibs(libs[!(libs %in% pkglibs)])
118 +
119 +
  invisible()
120 +
}
121 +
122 +
loaded_dlls <- function(package) {
123 +
  libs <- .dynLibs()
124 +
  matchidx <- vapply(libs, "[[", character(1), "name") == package
125 +
  libs[matchidx]
126 +
}

@@ -254,3 +254,7 @@
Loading
254 254
  bad <- normalizePath(libs) == lib
255 255
  pkgs[bad]
256 256
}
257 +
258 +
lapply_with_names <- function(X, FUN, ...) {
259 +
  structure(lapply(X, FUN, ...), names = X)
260 +
}
Files Coverage
R 32.72%
Project Totals (17 files) 32.72%
1
comment: false
2

3
coverage:
4
  status:
5
    project:
6
      default:
7
        target: auto
8
        threshold: 1%
9
        informational: true
10
    patch:
11
      default:
12
        target: auto
13
        threshold: 1%
14
        informational: true
Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading