我的回答建立在Gavin的回答之上...请注意,原帖用户3175783要求更智能化的
update.packages()
版本。该函数跳过已经更新的包的安装。但是,Gavin的解决方案会安装一个包及其所有依赖项,无论它们是否是最新的。我使用了Gavin跳过基本包的提示(它们实际上不能被安装),并编写了一个跳过最新包的方案。
主要函数是
installPackages()
。这个函数及其辅助函数对以给定一组包为根的依赖树进行拓扑排序。结果列表中的包会被检查是否过时,并逐一安装。下面是一些示例输出:
> remove.packages("tibble")
Removing package from ‘/home/frederik/.local/lib/x86_64/R/packages’
(as ‘lib’ is unspecified)
> installPackages(c("ggplot2","stringr","Rcpp"), dry_run=T)
Would have installed package digest
Would have installed package Rcpp
Would have installed package plyr
Would have installed package stringi
Would have installed package stringr
...
Would have installed package lazyeval
Would have installed package tibble
Would have installed package ggplot2
以下是代码,抱歉长度有点长:
library(tools)
fdfs = function(get.children) {
rec = function(root) {
cs = get.children(root);
out = c();
for(c in cs) {
l = rec(c);
out = c(out, setdiff(l, out));
}
c(out, root);
}
rec
}
excl_prio = c("base")
nonBaseDeps = function(packages,
ap=available.packages(),
ip=installed.packages(), recursive=T) {
stopifnot(is.character(packages));
all_deps = c();
for(p in packages) {
deps = package_dependencies(p, db = ap, recursive = recursive)[[1]];
ipdeps = match(deps,ip[,"Package"])
deps = deps[is.na(ipdeps) | !(ip[ipdeps,"Priority"] %in% excl_prio)];
apdeps = match(deps,ap[,"Package"])
notfound = is.na(apdeps)
if(any(notfound)) {
notfound=deps[notfound]
stop("Package ",p," has dependencies not in database: ",paste(notfound,collapse=" "));
}
all_deps = union(deps,all_deps);
}
all_deps
}
packageOrderedDeps = function(packages, ap=available.packages()) {
odeps = sapply(packages,
fdfs(function(p){nonBaseDeps(p,ap=ap,recursive=F)}))
odeps = unique(unlist(odeps));
stopifnot(length(setdiff(packages,odeps))==0);
seen = list();
for(d in odeps) {
ddeps = nonBaseDeps(d,ap=ap,recursive=F)
stopifnot(all(ddeps %in% seen));
seen = c(seen,d);
}
as.vector(odeps)
}
isPackageCurrent = function(p,
ap=available.packages(),
ip=installed.packages(),
verbose=T) {
if(verbose) msg = function(...) cat("## ",...)
else msg = function(...) NULL;
aprow = match(p, ap[,"Package"]);
iprow = match(p, ip[,"Package"]);
if(!is.na(iprow) && (ip[iprow,"Priority"] %in% excl_prio)) {
msg("Package ",p," is a ",ip[iprow,"Priority"]," package\n");
return(T);
}
if(is.na(aprow)) {
stop("Couldn't find package ",p," among available packages");
}
if(is.na(iprow)) {
msg("Package ",p," is not currently installed, installing\n");
F;
} else {
iv = package_version(ip[iprow,"Version"]);
av = package_version(ap[aprow,"Version"]);
if(iv < av) {
msg("Package ",p," is out of date (",
as.character(iv),"<",as.character(av),")\n");
F;
} else {
msg("Package ",p," is up to date (",
as.character(iv),")\n");
T;
}
}
}
installPackages =
function(packages,
ap=available.packages(), dry_run=F,
want_deps=T) {
stopifnot(is.character(packages));
ap=tools:::.remove_stale_dups(ap)
ip=installed.packages();
ip=tools:::.remove_stale_dups(ip)
if(want_deps) {
packages = packageOrderedDeps(packages, ap);
}
for(p in packages) {
curr = isPackageCurrent(p,ap,ip);
if(!curr) {
if(dry_run) {
cat("Would have installed package ",p,"\n");
} else {
install.packages(p,dependencies=F);
}
}
}
}
updateAttachedLibraries = function(dry_run=F) {
s=search();
s=s[grep("^package:",s)];
s=gsub("^package:","",s)
installPackages(s,dry_run=dry_run);
}
update.packages(checkBuilt=TRUE, ask=FALSE)
。 - Dirk Eddelbuettelap <- available.packages(); pkgs <- tools::package_dependencies("fields",db=ap,recursive=TRUE)
开始。然后你需要过滤掉内置和推荐的包,并安装其余的包。(这不涉及依赖图的顺序,但可能适用于你的情况。) - Ben Bolker>
,而应该使用缩进4个空格的代码/预格式化标记。 - Gavin Simpsonwhich
参数。如果我使用fields并设置which = "most"
,你将需要安装近400个软件包!对于一些更受欢迎的软件包,您可能需要安装大块的CRAN,这种情况下,您可以在周末从CRAN更新所有内容。 - Gavin Simpsonupdate.packages()
函数更好,即使它存在一些限制?您为什么认为编写新的软件包安装函数是试图“重新设计或重写R的软件包系统”?这难道不是试图改进 R 的包系统吗?我们使用的函数,如package_dependencies()
和installed.packages()
难道不是专门为此目的而提供的吗? - Metamorphic