【问题标题】:How to unload package with all dependences that are not explicitly loaded / are not used by other explicitly loaded packages?如何卸载具有未显式加载/其他显式加载包未使用的所有依赖项的包?
【发布时间】:2019-09-21 23:23:22
【问题描述】:

我想卸载包及其所有依赖项。但我不想卸载之前使用library() 加载的包或我使用library() 加载的包的依赖项的包。我该怎么做?

【问题讨论】:

  • @M.Viking 我已经看过它但没有找到“但我不想卸载我以前用library() 加载的包或我加载的包的依赖项的包与library()。”

标签: r package


【解决方案1】:

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 中传递一个字符。 此外,正如代码 cmets 中所述, 您可以使用 remotes::package_deps(package)$package 代替 transitive_deps 助手。 我认为前者已经过滤了base 包, 但我相信每次使用时它都会在线检查。

transitive_deps 助手远非完美, 它只是试图找到直接的依赖关系 (这是remotes::local_package_deps 返回的内容) 递归地, 希望通过使用acc 来累积已经看到的包来避免一些重复。

卸载包的顺序很重要, 因为您无法卸载由另一个当前加载的包导入的包。 不幸的是,deps 中的顺序并不总是完美的, 这就是为什么循环中有一个try, 跳过有问题的包,直到所有依赖包都被卸载。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-11
    • 1970-01-01
    • 2021-11-16
    • 2018-03-05
    • 1970-01-01
    • 1970-01-01
    • 2015-06-08
    • 2016-11-08
    相关资源
    最近更新 更多