AFAIK, вы не можете автоматически различать пакеты, которые являются Depends
зависимостями других подключенных пакетов и пакетов, которые вы загружаете с помощью library
.
РЕДАКТИРОВАТЬ: Я имеюобновил мой ответ на вопрос, связанный выше, показывая возможную альтернативу для отслеживания явного использования library
.Можно было бы использовать его для вычисления attached
в приведенном ниже коде вместо использования search
.
Вот одна возможность, которую я нашел, используя пакет remotes
:
transitive_deps <- function(package, acc = character()) {
direct_deps <- remotes::local_package_deps(system.file(package = package))
filtered_deps <- setdiff(direct_deps, acc)
if (length(filtered_deps) == 0L) {
package
}
else {
acc <- union(acc, filtered_deps)
for (dep in filtered_deps) { acc <- union(acc, transitive_deps(dep, acc)) }
union(package, acc)
}
}
unload_deep <- function(package) {
# find all transitive dependencies of the package
deps <- transitive_deps(package) # alternatively: remotes::package_deps(package)$package
# do not unload base packages
deps <- setdiff(deps, installed.packages(priority = "base")[, "Package"])
# do not unload packages explicitly attached with library()
attached <- search()
deps <- setdiff(deps, substring(attached, unlist(gregexpr(":", attached)) + 1L)) # remove "package:" prefix
# first unload provided package
tryCatch(unloadNamespace(package), error = function(...) {
package <- paste0("package:", package)
if (package %in% search()) {
# at least try to detach it if some other package imports it
detach(package, character.only = TRUE)
}
})
deps <- setdiff(deps, package)
# try to unload remaining
while (length(deps) > 0L) {
unloaded_one <- FALSE
for (dep in deps) {
flag <- try(unloadNamespace(dep), silent = TRUE)
if (!inherits(flag, "try-error")) {
unloaded_one <- TRUE
break
}
}
if (unloaded_one) {
deps <- setdiff(deps, dep)
}
else {
# could not unload any, must be used by other unrelated packages
break
}
}
# return
invisible()
}
Вам необходимо передать символ в package
.Также, как уже упоминалось в комментариях к коду, вы можете использовать remotes::package_deps(package)$package
вместо transitive_deps
помощника.Я думаю, что первый уже фильтрует base
пакеты, но я считаю, что он проверяет онлайн каждый раз, когда вы его используете.
Помощник transitive_deps
далек от совершенства, он просто пытается найти прямые зависимости (вот чтоremotes::local_package_deps
возвращает) рекурсивно, мы надеемся избежать некоторого повторения, используя acc
для накопления уже увиденных пакетов.
Порядок, в котором выгружаются пакеты, важен, поскольку вы не можете выгрузить пакет, импортированный другим в данный момент.загруженный пакет.К сожалению, порядок в deps
не всегда идеален для этого, поэтому в цикле есть try
, чтобы пропустить проблемные пакеты, пока все зависимые пакеты не будут выгружены.