Update a specific R package and its dependencies

前端 未结 2 1432
情书的邮戳
情书的邮戳 2020-12-08 09:28

I have around 4000 R packages installed in my system (a server) and most of them are outdated because they were built before R-3.0.0. Now I know

update.pack         


        
2条回答
  •  时光取名叫无心
    2020-12-08 10:15

    My answer builds on Gavin's answer... Note that the original poster, user3175783, asked for a more intelligent version of update.packages(). That function skips installing packages that are already up-to-date. But Gavin's solution installs a package and all its dependencies, whether they are up-to-date or not. I used Gavin's tip of skipping base packages (which are not actually installable), and coded up a solution which also skips up-to-date packages.

    The main function is installPackages(). This function and its helpers perform a topological-sort of the dependency tree rooted at a given set of packages. The packages in the resulting list are checked for staleness and installed one by one. Here's some example output:

    > 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 
    

    Here's the code, sorry about the length:

    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);
    }
    

提交回复
热议问题