Как выгрузить пакет со всеми зависимостями, которые явно не загружены / не используются другими явно загруженными пакетами? - PullRequest
3 голосов
/ 22 сентября 2019

Я хочу выгрузить пакет и все его зависимости.Но я не хочу выгружать пакеты, которые я ранее загружал с library() или пакеты, которые являются зависимостями пакетов, которые я загружал с library().Как я могу это сделать?

1 Ответ

0 голосов
/ 22 сентября 2019

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, чтобы пропустить проблемные пакеты, пока все зависимые пакеты не будут выгружены.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...