安装R包时,需要自动重新安装依赖项。

4

utils::install.packages 似乎可以很好地安装缺失的依赖项。但是,如果有某个依赖项已经安装了,但由于某种原因不是正确版本(例如,在尝试安装 DiagrammeR 时,Error: package ‘igraph’ was installed by an R version with different internals; it needs to be reinstalled for use with this R version),原始的 install.packages 调用会停在那里。然后我必须手动重新安装每个有问题的依赖项。如何自动化这个过程?

我在 Linux 上运行 R 3.6.1。


这在某种程度上是你的“思维错误”:你与install.packages()的“隐含契约”是它可以假定你的_已安装的包是最新的_。你应该运行update.packages(),它会处理这部分内容。通过保持与_CRAN版本的已安装包_同步,您几乎可以确保要安装的软件包将与它们一起正常工作。(由于缺少系统库或其他install.packages()无法控制的工具,安装仍可能失败。) - Dirk Eddelbuettel
1
@DirkEddelbuettel 看起来 update.packages(就是您所指的吗?)会升级每个已安装的软件包,这应该足够了,但有些过头。 - Kodiologist
这并不是过度的。这就是系统的设计和工作方式。我在我的机器上基本每天都运行update.packages(),它只会更新一小部分包(使用Ncpus选项并行更新)。我认为你陷入了一个心理障碍,想要既有完全稳定性又没有变化,同时又能完美地安装任何其他包。但这不是CRAN给你的服务保证,所以你必须做些其他的事情:这是一个方块求圆的问题。你的情况可能有所不同。 - Dirk Eddelbuettel
1
@DirkEddelbuettel 完全不是,我只想要执行安装或更新所需的更改,而且不多不少。 - Kodiologist
我听懂了你的意思。我已经尝试解释三次,你的假设对这个任务是无效的,所以你遇到困难并不令我感到惊讶。请退一步,思考如果你没有其他(处于部分过时状态)包的安装,install.packages()会对你的新包做些什么。它们将全部都是CRAN上的最新版本。 - Dirk Eddelbuettel
2个回答

2

install.packages()中似乎没有强制执行此操作的方法。 相反,您可以使用pak :: pkg_install()。从pak :: pkg_install()的“upgrade”参数:

upgrade 
Whether to upgrade already installed packages to the latest available version. If this is 
FALSE, then only packages that need updates to satisfy version requirements, will be 
updated. If it is TRUE, all specified or dependent packages will be updated to the latest 
available version.

编辑:仔细阅读您的问题后,听起来您可能正在使用3.6版本的3.5包库。如果是这种情况,我建议在升级版本时使用R包installr。它可以自动重新安装您之前版本中所有的软件包。

编辑2:下面的代码将显示哪些是基于旧版本构建的。对于这些软件包,我建议运行install.packages(built_on_earlier_version, force = TRUE)

installed_packages <- as.data.frame(installed.packages())

installed_packages[as.package_version(installed_packages$Built) < as.package_version("3.6.0"),]

这个函数听起来像是无条件地升级所有依赖项,无论它们是否需要升级以使原始软件包可用,这有点过度了,但总比什么都不好。 - Kodiologist
@Kodiologist 这并不完全正确。如果 upgrade=FALSE,它只会在必要时更新软件包依赖项,以满足另一个软件包对该依赖项的版本要求。我相信这正是你所要求的。 - smingerson
不幸的是,看起来 pak::pkg_install 在检查依赖项是否良好时(至少在 upgrade = FALSE 的情况下)所做的一切就是检查已安装依赖项的版本;它没有检查依赖项是否实际可加载。因此,pak::pkg_install("DiagrammeR") 似乎可以工作,但是然后 library(DiagrammeR) 会产生 Error: package or namespace load failed for ‘DiagrammeR’: package ‘rgexf’ was installed by an R version with different internals; it needs to be reinstalled for use with this R version,就像 install.packages("DiagrammeR") 一样。 - Kodiologist
请查看我回答的编辑。我认为这个问题是由于使用了来自不同版本的R的包库,即3.6而不是3.5。 - smingerson
built_on_earlier_version 不仅限于所讨论的依赖关系,但如果您可以递归列出这些依赖关系,那么就可以将依赖关系与 built_on_earlier_version 进行交集设置,然后安装结果的 install.packages,我认为这样做就可以了。 - Kodiologist
显示剩余2条评论

2

这种方法很粗糙(尤其是它会多次愉快地重新下载一个软件包),但这是目前为止我想到的最好的办法:

install.rec = function(pkg, repos = 'http://archive.linux.duke.edu/cran')
# Install a package and reinstall any dependencies that need
# to be reinstalled, recursively.
   {while (T)
       {message("INSTALLING: ", pkg)
        out = paste0(collapse = " ",
            system2("Rscript", stdout = T, stderr = T, sprintf(
                "--no-init-file -e \"install.packages('%s', repos='%s')\"",
                pkg, repos)))
        p = regmatches(out, regexec(text = out, perl = T,
            "package ‘(\\S+)’ was installed (?:before R|by an R version)"))[[1]]
        if (length(p))
           {p = p[2]
            message("START RECURSING: ", pkg, " - ", p)
            install.rec(p, repos)
            message("END RECURSING: ", pkg, " - ", p)}
        else
            break}
   message("DONE WITH: ", pkg)}

install.packages不会引发条件,也不会返回错误,也不会以可捕获的方式产生其输出,因此我们必须使用系统调用来查看错误消息。这个想法来自于这里


如果你在意的话,你可以只使用基本的R语言就能做得更好。installed.packages()可以告诉你你已经安装了哪些包,available.packages()则可以告诉你有哪些包可供使用(并足以反映你的安装程序的“整体滞后性”)。再加上神奇的tools::CRAN_package_db()来获取依赖信息,然后你就可以遍历你的图形了。 - Dirk Eddelbuettel
@DirkEddelbuettel,install.packages 停止安装的检查条件是“由不同内部 R 版本安装”,这个条件只要求当前 R 的主版本号和次版本号与安装包时的版本号匹配吗? - Kodiologist
我不知道这个问题的答案。它可能是包内部的问题,或者在尝试加载时出现了 try/catch 错误。我不知道作为包作者我该如何发出信号。无论如何,我并不想伤害你的感情,但我认为你正在重新发明已有的轮子......你可以在 r-devel 上提问。 - Dirk Eddelbuettel
"我认为你正在重新发明已经存在的轮子" — 我知道,这是令人沮丧的部分。但我想现在这样也足够好了。 - Kodiologist
@DirkEddelbuettel 是的,我已经使用自定义安装的Python而不是系统Python,因此可以说我应该为R做同样的事情。 - Kodiologist
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接