J'ai environ 4000 packages R installés sur mon système (un serveur) et la plupart d'entre eux sont obsolètes car ils ont été construits avant R-3.0.0. Maintenant je sais
update.packages(checkBuilt=TRUE, ask=FALSE)
mettrait à jour tous mes packages mais c'est trop lent. Le fait est que les utilisateurs n'utilisent pas la plupart des packages et de temps en temps ils me demandent de mettre à jour un package (par exemple des champs) qu'ils utiliseraient. Maintenant, si je cours
install.packages("fields")
il ne ferait que mettre à jour les champs du package mais pas les cartes du package même si les champs dépendent des cartes. Ainsi, lorsque j'essaie de charger les champs du package:
library("fields")
Je reçois un message d'erreur
Error: package ‘maps’ was built before R 3.0.0: please re-install it
Existe-t-il un moyen de mettre à niveau les champs afin qu'il mette également à jour automatiquement les champs des packages en fonction?
Comme Ben l'a indiqué dans son commentaire, vous devez obtenir les dépendances pour fields
, puis filtrer les packages avec la priorité "Base"
Ou "Recommended"
, Puis transmettre cette liste de packages à install.packages()
pour gérer l'installation. Quelque chose comme:
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
}
Cela donne:
R> instPkgPlusDeps("fields")
Loading required package: tools
[1] "fields" "spam" "maps"
qui correspond à
> packageDescription("fields", fields = "Depends")
[1] "R (>= 2.13), methods, spam, maps"
Vous obtenez des avertissements de la ligne sapply()
si une dépendance dans deps
n'est pas réellement installée. Je pense que ceux-ci sont inoffensifs car la valeur retournée dans ce cas est NA
et nous l'utilisons pour indiquer les packages que nous voulons installer. Je doute que cela vous affectera si vous avez installé 4000 packages.
La valeur par défaut est not pour installer les packages mais simplement renvoyer la liste des dépendances. J'ai pensé que c'était le plus sûr car vous ne réalisez peut-être pas la chaîne de dépendances impliquée et finissez par installer des centaines de packages par accident. Entrez install = TRUE
Si vous êtes heureux d'installer les packages indiqués.
Notez que je restreins les types de dépendances recherchés - choses ballon si vous utilisez which = "most"
- champs a plus de 300 de ces dépendances une fois que vous résolvez récursivement ces dépendances (qui incluent Suggests:
également). which = "all"
Recherchera tout, y compris Enhances:
Qui sera à nouveau une plus grande liste de packages. Voir ?tools::package_dependencies
Pour les entrées valides pour l'argument which
.
Ma réponse s'appuie sur la réponse de Gavin ... Notez que l'affiche originale, user3175783, demandait une version plus intelligente de update.packages()
. Cette fonction ignore l'installation de packages déjà à jour. Mais la solution de Gavin installe un package et toutes ses dépendances, qu'elles soient à jour ou non. J'ai utilisé l'astuce de Gavin pour ignorer les packages de base (qui ne sont pas réellement installables) et j'ai codé une solution qui ignore également les packages à jour.
La fonction principale est installPackages()
. Cette fonction et ses assistants effectuent une sorte de topologie de l'arborescence de dépendances enracinée dans un ensemble donné de packages. La validité des packages de la liste résultante est vérifiée et installée une par une. Voici quelques exemples de sortie:
> 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
Voici le code, désolé pour la longueur:
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);
}