2014-01-09 85 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