2014-01-09 69 views
20

我的系统(服务器)中安装了大约4000个R包,其中大部分过时,因为它们是在R-3.0.0之前构建的。现在我知道更新一个特定的R包及其依赖关系

update.packages(checkBuilt=TRUE, ask=FALSE) 

会更新我所有的软件包,但这太慢了。事情是用户不使用大部分软件包,现在他们要求我更新他们使用的软件包(比如字段)。现在,如果我运行

install.packages("fields") 

它只会更新包字段,而不是包映射,即使字段取决于映射。因此,当我尝试加载封装字段:

library("fields") 

我得到一个错误信息

Error: package ‘maps’ was built before R 3.0.0: please re-install it 

是否有升级领域,以便它也将自动更新域依赖的程序包的方法吗?

+2

而是试图重新设计或重新编写的r包系统,你_really truly_将被关闭,以便更好地咬住子弹并运行'update.packages(checkBuilt = TRUE,ask = FALSE)'。 –

+2

我会从'ap < - available.packages(); pkgs < - tools :: package_dependencies(“fields”,db = ap,recursive = TRUE)''。然后,您需要过滤掉内置的和推荐的软件包,并安装其余的软件包。 (这不涉及依赖图的*顺序*,但它可能适用于您的情况。) –

+0

请*不要*撤销我对使用*正确*降价代码所做的编辑!您正在使用blockquote markdown'>',并且您应该使用以4个空格缩进的代码/预缩减。 –

回答

8

如本。在他的评论中指出的,你需要得到的依赖关系fields,然后筛选出具有优先级"Base""Recommended"包,然后通过包装的该列表install.packages()处理安装。喜欢的东西:

instPkgPlusDeps <- function(pkg, install = FALSE, 
          which = c("Depends", "Imports", "LinkingTo"), 
          inc.pkg = TRUE) { 
    stopifnot(require("tools")) ## load tools 
    ap <- available.packages() ## takes a minute on first use 
    ## get dependencies for pkg recursively through all dependencies 
    deps <- package_dependencies(pkg, db = ap, which = which, recursive = TRUE) 
    ## the next line can generate warnings; I think these are harmless 
    ## returns the Priority field. `NA` indicates not Base or Recommended 
    pri <- sapply(deps[[1]], packageDescription, fields = "Priority") 
    ## filter out Base & Recommended pkgs - we want the `NA` entries 
    deps <- deps[[1]][is.na(pri)] 
    ## install pkg too? 
    if (inc.pkg) { 
    deps = c(pkg, deps) 
    } 
    ## are we installing? 
    if (install) { 
    install.packages(deps) 
    } 
    deps ## return dependencies 
} 

这给:

R> instPkgPlusDeps("fields") 
Loading required package: tools 
[1] "fields" "spam" "maps" 

> packageDescription("fields", fields = "Depends") 
[1] "R (>= 2.13), methods, spam, maps" 

您从sapply()线如果deps依赖没有实际安装得到警告匹配。我认为这些都是无害的,因为在这种情况下返回的值是NA,我们用它来表示我们想要安装的软件包。如果你安装了4000个软件包,我怀疑它会影响你。

默认值是而不是来安装软件包,但只是返回依赖关系列表。我认为这是最安全的,因为您可能没有意识到隐含的依赖关系链,并最终意外安装了数百个软件包。如果您愿意安装所示的包装,请通过install = TRUE

注意,我限制类型的依赖搜索到的 - 事情气球,如果你使用which = "most" - 领域有超过300个这样的依赖性,一旦你递归地解决这些依赖关系(包括Suggests:领域也是如此)。 which = "all"会寻找一切,包括Enhances:这将再次成为一个更大的软件包列表。有关which参数的有效输入,请参见?tools::package_dependencies

+0

这工作!谢谢加文。顺便说一句,我编辑命令'install.packages(deps)'到'install.packages(c(pkg,deps))'。 – user3175783

+0

我想,考虑到我给这个函数的名字,那么应该做出改变。我会让其他两位用户拒绝。我会看到我也能做些什么,他们不应该这样做。 –

1

我的答案建立在加文的答案上......请注意,原始海报user3175783要求更智能的版本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) 
## Package digest is out of date (0.6.9 < 0.6.10) 
Would have installed package digest 
## Package gtable is up to date (0.2.0) 
## Package MASS is up to date (7.3.45) 
## Package Rcpp is out of date (0.12.5 < 0.12.8) 
Would have installed package Rcpp 
## Package plyr is out of date (1.8.3 < 1.8.4) 
Would have installed package plyr 
## Package stringi is out of date (1.0.1 < 1.1.2) 
Would have installed package stringi 
## Package magrittr is up to date (1.5) 
## Package stringr is out of date (1.0.0 < 1.1.0) 
Would have installed package stringr 
... 
## Package lazyeval is out of date (0.1.10 < 0.2.0) 
Would have installed package lazyeval 
## Package tibble is not currently installed, installing 
Would have installed package tibble 
## Package ggplot2 is out of date (2.1.0 < 2.2.0) 
Would have installed package ggplot2 

下面的代码,大约长度遗憾:

library(tools) 

# Helper: a "functional" interface depth-first-search 
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 
} 

# Entries in the package "Priority" field which indicate the 
# package can't be upgraded. Not sure why we would exclude 
# recommended packages, since they can be upgraded... 
#excl_prio = c("base","recommended") 
excl_prio = c("base") 

# Find the non-"base" dependencies of a package. 
nonBaseDeps = function(packages, 
    ap=available.packages(), 
    ip=installed.packages(), recursive=T) { 

    stopifnot(is.character(packages)); 
    all_deps = c(); 
    for(p in packages) { 
    # Get package dependencies. Note we are ignoring version 
    # information 
    deps = package_dependencies(p, db = ap, recursive = recursive)[[1]]; 
    ipdeps = match(deps,ip[,"Package"]) 
    # We want dependencies which are either not installed, or not part 
    # of Base (e.g. not installed with R) 
    deps = deps[is.na(ipdeps) | !(ip[ipdeps,"Priority"] %in% excl_prio)]; 
    # Now check that these are in the "available.packages()" database 
    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 
} 

# Return a topologically-sorted list of dependencies for a given list 
# of packages. The output vector contains the "packages" argument, and 
# recursive dependencies, with each dependency occurring before any 
# package depending on it. 
packageOrderedDeps = function(packages, ap=available.packages()) { 

    # get ordered dependencies 
    odeps = sapply(packages, 
    fdfs(function(p){nonBaseDeps(p,ap=ap,recursive=F)})) 
    # "unique" preserves the order of its input 
    odeps = unique(unlist(odeps)); 

    # sanity checks 
    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) 
} 

# Checks if a package is up-to-date. 
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; 
     } 
    } 
} 

# Like install.packages, but skips packages which are already 
# up-to-date. Specify dry_run=T to just see what would be done. 
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); 
     } 
    } 
    } 
} 

# Convenience function to make sure all the libraries we have loaded 
# in the current R session are up-to-date (and to update them if they 
# are not) 
updateAttachedLibraries = function(dry_run=F) { 
    s=search(); 
    s=s[grep("^package:",s)]; 
    s=gsub("^package:","",s) 
    installPackages(s,dry_run=dry_run); 
} 
+0

如果你冷静下来,请在评论之前或之后发表评论,所以我知道该怎么修复... – Metamorphic