如何卸载所有未显式加载的依赖项/其他显式加载的包未使用的依赖项?

时间:2019-09-21 23:23:22

标签: r package

我想卸载软件包及其所有依存关系。但是我不想卸载以前用library()装载的软件包或与用library()装载的软件包相关的软件包。我该怎么办?

1 个答案:

答案 0 :(得分:0)

AFAIK,you can't automatically differentiate between packages that are Depends dependencies of other attached packages and the ones you load with 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的原因, 跳过有问题的程序包,直到所有相关程序包都已卸载。