Check for installed packages before running install.packages() [duplicate] - r

This question already has answers here:
Elegant way to check for missing packages and install them?
(33 answers)
Closed 5 years ago.
I have an R script that is shared with several users on different computers. One of its lines contains the install.packages("xtable") command.
The problem is that every time someone runs the script, R spends a great deal of time apparently reinstalling the package (it actually does take some time, since the real case has vector of several packages).
How can I make first check if the packages are installed and then only run install.packages() for the ones that are not?

try: require("xtable") or "xtable" %in% rownames(installed.packages())

If you want to do it as simply as possible:
packages <- c("ggplot2", "dplyr", "Hmisc", "lme4", "arm", "lattice", "lavaan")
install.packages(setdiff(packages, rownames(installed.packages())))
Replace the packages listed on the first line by those needed to run your code, and voilà!
Note: Edited to remove conditional wrapper thanks to Artem's comment below.

This is a function I often used to check for a package, install it otherwise and load again:
pkgTest <- function(x)
{
if (!require(x,character.only = TRUE))
{
install.packages(x,dep=TRUE)
if(!require(x,character.only = TRUE)) stop("Package not found")
}
}
Works like pkgTest("xtable"). It only works if the mirror is set though, but you could enter that in the require calls.

I suggest a more lightweight solution using system.file.
is_inst <- function(pkg) {
nzchar(system.file(package = pkg))
}
is_inst2 <- function(pkg) {
pkg %in% rownames(installed.packages())
}
library(microbenchmark)
microbenchmark(is_inst("aaa"), is_inst2("aaa"))
## Unit: microseconds
## expr min lq mean median uq max neval
## is_inst("aaa") 22.284 24.6335 42.84806 34.6815 47.566 252.568 100
## is_inst2("aaa") 1099.334 1220.5510 1778.57019 1401.5095 1829.973 17653.148 100
microbenchmark(is_inst("ggplot2"), is_inst2("ggplot2"))
## Unit: microseconds
## expr min lq mean median uq max neval
## is_inst("ggplot2") 336.845 386.660 459.243 431.710 483.474 867.637 100
## is_inst2("ggplot2") 1144.613 1276.847 1507.355 1410.054 1656.557 2747.508 100

There's also the CRAN package pacman which has the p_load function to install one or more packages (but only if necessary) and then load them.

requiredPackages = c('plyr','ggplot2','ggtern')
for(p in requiredPackages){
if(!require(p,character.only = TRUE)) install.packages(p)
library(p,character.only = TRUE)
}

# Function to check whether package is installed
is.installed <- function(mypkg){
is.element(mypkg, installed.packages()[,1])
}
# check if package "hydroGOF" is installed
if (!is.installed("hydroGOF")){
install.packages("hydroGOF")
}

I found a packages script somewhere that I always put in every script to load my libraries. It will do all your library handling (downloading, installing and loading), and only when needed.
# Install function for packages
packages<-function(x){
x<-as.character(match.call()[[2]])
if (!require(x,character.only=TRUE)){
install.packages(pkgs=x,repos="http://cran.r-project.org")
require(x,character.only=TRUE)
}
}
packages(ggplot2)
packages(reshape2)
packages(plyr)
# etc etc

I have implemented the function to install and load required R packages silently. Hope might help. Here is the code:
# Function to Install and Load R Packages
Install_And_Load <- function(Required_Packages)
{
Remaining_Packages <- Required_Packages[!(Required_Packages %in% installed.packages()[,"Package"])];
if(length(Remaining_Packages))
{
install.packages(Remaining_Packages);
}
for(package_name in Required_Packages)
{
library(package_name,character.only=TRUE,quietly=TRUE);
}
}
# Specify the list of required packages to be installed and load
Required_Packages=c("ggplot2", "Rcpp");
# Call the Function
Install_And_Load(Required_Packages);

The solution I used derived from Sacha Epskamp and Shuguang's input. Here's the function:
instalaPacotes <- function(pacote) {
if (!pacote %in% installed.packages()) install.packages(pacote)
}
It works silently, echoing nothing if package "pacote" is already installed and installing it otherwise. Don't forget to write the name of the package between quotes!

Or a massively overticked example from drknexus/repsych on github, glibrary. There are almost certainly more efficient and better ways to to do this, but I programmed it a long while back and it basically works.
It works even if a repo hasn't been selected by taking the default cloud option if available. If you are on an older version of R it will roll back and pick a mirror based on country code.
It tries to load the library (this step could be made more efficient using some of the methods above)
If it fails, it will try to install it
If the install fails it will notify you which packages failed to install
That is right, packages, multiple packages can be loaded/installed in a single pass along with their dependencies (at least usually, there may be a bug here).
e.g.: glibrary(xtable,sos,data.table) but I don't think it will freak out if you call glibrary("xtable","sos","data.table") instead. Pushes/pulls/forks welcome.
Code for the function:
#' Try to load a library, if that fails, install it, then load it.
#'
#' glibrary short for (get)library.
#' The primary aim of this function is to make loading packages more transparent. Given that we know we want to load a given package, actually fetching it is a formality. glibrary skims past this formality to install the requested package.
#'
#' #export
#' #param ... comma seperated package names
#' #param lib.loc See \code{\link{require}}
#' #param quietly See \code{\link{require}}
#' #param warn.conflicts See \code{\link{require}}
#' #param pickmirror If TRUE, glibrary allows the user to select the mirror, otherwise it auto-selects on the basis of the country code
#' #param countrycode This option is ignored and the first mirror with the substring "Cloud", e.g. the RStudio cloud, is selected. If no mirrors with that substring are identified, glibrary compares this value to results from getCRANmirrors() to select a mirror in the specified country.
#' #return logical; TRUE if glibrary was a success, an error if a package failed to load
#' #note keep.source was an arguement to require that was deprecated in R 2.15
#' #note This warning \code{Warning in install.packages: InternetOpenUrl failed: 'The operation timed out'} indicates that the randomly selected repository is not available. Check your internet connection. If your internet connection is fine, set pickmirror=TRUE and manually select an operational mirror.
#' #examples
#' #glibrary(lattice,MASS) #not run to prevent needless dependency
glibrary <- function(..., lib.loc = NULL, quietly = FALSE, warn.conflicts = TRUE, pickmirror = FALSE, countrycode = "us") {
warningHandle <- function(w) {
if (grepl("there is no package called",w$message,fixed=TRUE)) {
return(FALSE) #not-loadable
} else {
return(TRUE) #loadable
}
}
character.only <- TRUE #this value is locked to TRUE so that the function passes the character value to require and not the variable name thislib
librarynames <- unlist(lapply(as.list(substitute(.(...)))[-1],as.character))
#if package already loaded, remove it from librarynames before processing further
si.res <- sessionInfo()
cur.loaded <- c(si.res$basePkgs,names(si.res$otherPkgs)) #removed names(si.res$loadedOnly) because those are loaded, but not attached, so glibrary does need to handle them.
librarynames <- librarynames[librarynames %!in% cur.loaded]
success <- vector("logical", length(librarynames))
if (length(success)==0) {return(invisible(TRUE))} #everything already loaded, end.
alreadyInstalled <- installed.packages()[,"Package"]
needToInstall <- !librarynames %in% alreadyInstalled
if (any(needToInstall)) {
if (pickmirror) {chooseCRANmirror()}
if (getOption("repos")[["CRAN"]] == "#CRAN#") {
#Select the first "Cloud" if available
m <- getCRANmirrors(all = FALSE, local.only = FALSE)
URL <- m[grepl("Cloud",m$Name),"URL"][1] #get the first repos with "cloud" in the name
if (is.na(URL)) { #if we did not find the cloud,
#Fall back and use the previous method
message("\nIn repsych:glibrary: Now randomly selecting a CRAN mirror. You may reselect your CRAN mirror with chooseCRANmirror().\n")
#if there is no repository set pick a random one by country code
getCRANmirrors.res <- getCRANmirrors()
foundone <- FALSE #have we found a CRAN mirror yet?
#is it a valid country code?
if (!countrycode %in% getCRANmirrors.res$CountryCode) {
stop("In repsych::glibrary: Invalid countrycode argument")
}
ticker <- 0
while (!foundone) {
ticker <- ticker + 1
URL <- getCRANmirrors.res$URL[sample(grep(countrycode, getCRANmirrors.res$CountryCode), 1)]
host.list <- strsplit(URL, "/")
host.clean <- unlist(lapply(host.list, FUN = function(x) {return(x[3])}))
#make sure we can actually access the package list
if (nrow(available.packages(contrib.url(URL)))!=0) {foundone <- TRUE}
if (ticker > 5) {stop("In repsych::glibrary: Unable to access valid repository. Is the internet connection working?")}
} #end while
} #end else
repos <- getOption("repos")
repos["CRAN"] <- gsub("/$", "", URL[1L])
options(repos = repos)
} #done setting CRAN mirror
#installing packages
installResults <- sapply(librarynames[needToInstall],install.packages)
#checking for successful install
needToInstall <- !librarynames %in% installed.packages()[,"Package"]
if (any(needToInstall)) {
stop(paste("In repsych::glibrary: Could not download and/or install: ",paste(librarynames[needToInstall],collapse=", "),"... glibrary stopped.",sep=""))
} # done reporting any failure to install
} #done if any needed to install
#message("In repsych::glibrary: Attempting to load requested packages...\n")
#success <- tryCatch(
success <- sapply(librarynames,require, lib.loc = lib.loc, quietly = FALSE, warn.conflicts = warn.conflicts, character.only = TRUE)
#, warning=warningHandle) #end tryCatch
if(length(success) != length(librarynames)) {stop("A package failed to return a success in glibrary.")}
if (all(success)) {
#message("In repsych::glibrary: Success!")
return(invisible(TRUE))
} else {
stop(paste("\nIn repsych::glibrary, unable to load: ", paste(librarynames[!success]),
collapse = " "))
}
stop("A problem occured in glibrary") #shouldn't get this far down, all returns should be made.
}
NULL

How about trying this?
#will install the pROC library if you don't have it
if(!is.element('pROC', installed.packages()[,1]))
{install.packages('pROC')
}else {print("pROC library already installed")}

This should do it. You can make required.packages a vector if you need to check for more than one.
required.packages <- "data.table"
new.packages <- required.packages[!(required.packages %in% installed.packages()[,"Package"])]
if(length(new.packages)) install.packages(new.packages)

Reading everyone's responses, I took some hints here and there and created mine. Actually very similar to most though.
## These codes are used for installing packages
# function for installing needed packages
installpkg <- function(x){
if(x %in% rownames(installed.packages())==FALSE) {
if(x %in% rownames(available.packages())==FALSE) {
paste(x,"is not a valid package - please check again...")
} else {
install.packages(x)
}
} else {
paste(x,"package already installed...")
}
}
# install necessary packages
required_packages <- c("sqldf","car")
lapply(required_packages,installpkg)

Looked at my old function, updated it using tips above and this is what i got.
# VERSION 1.0
assign("installP", function(pckgs){
ins <- function(pckg, mc){
add <- paste(c(" ", rep("-", mc+1-nchar(pckg)), " "), collapse = "");
if( !require(pckg,character.only=TRUE) ){
reps <- c("http://lib.stat.cmu.edu/R/CRAN","http://cran.uk.R-project.org");
for (r in reps) try(utils::install.packages(pckg, repos=r), silent=TRUE);
if(!require(pckg,character.only = TRUE)){ cat("Package: ",pckg,add,"not found.\n",sep="");
}else{ cat("Package: ",pckg,add,"installed.\n",sep="");}
}else{ cat("Package: ",pckg,add,"is loaded.\n",sep=""); } }
invisible(suppressMessages(suppressWarnings(lapply(pckgs,ins, mc=max(nchar(pckgs)))))); cat("\n");
}, envir=as.environment("dg_base"))
installP(c("base","a","TFX"))
Package: base ------------------- is loaded.
Package: a ---------------------- not found.
Package: TFX -------------------- installed.

Why not just delete the line from the script? If the end-user doesn't have the smarts to install xtable as needed, you've got bigger problems :-( .
That said, check out installed.packages()
Edit: dang, Ninja'd by ONE minute!
Edit: a general suggestion: load the package sos , and you'll find it very easy to get answers to a lot of "is there a function that does XXXXX" questions.

Related

R askYesNo function: print a variable which is a list + strings

I'm a complete newbie in programming with R and stuck at what I believe is actually a very simple question. I've borrowed some code snippets and put them together and everything seems to work, just printing of the package names which has to be installed from GitHub doesn't..
How can I print a Variable which is a list together with strings in the askyesno function. I tried {},[] and doubled them, tried "" and .format as in python, nothing worked.
In the following my Code, please help :)
not_installed = my_packages[!(my_packages %in% installed.packages()[ , "Package"])]
if(length(not_installed)) install.packages(not_installed)
if(length(not_installed != installed.packages()))
still_not_installed = list(not_installed)
Ask = askYesNo("$still_not_installed + cannot be install from CRAN. \n Load from GitHub?",
default = TRUE, prompts = getOption("askYesNo"), gettext(c("Yes", "No", "Cancel")))
if(Ask == TRUE)
p_load_gh("muschellij2/aal", "taiyun/corrplot/blob/master/R/corrplot-package.R",
install = TRUE, dependencies = TRUE)
Do you think this is a proper solution to search for not installed packages and load them?
Your approach to checking for install is not ideal in itself. It will not detect if a package is missing dependencies for example. We can use require which automatically checks if the package is actually usable.
Then we can just build the message with paste.
I assume you will also paste the package into your p_load_gh function, but I don't know the syntax of that particular one.
my_packages <- c("test","test2")
for(p in my_packages)
{
tryCatch(test <- require(p,character.only=T),
warning=function(w) return())
if(!test)
{
print(paste("Package", p, "not found. Installing Package!"))
install.packages(p)
}
tryCatch(test <- require(p,character.only=T),
warning=function(w) return())
if(!test)
{
Ask = askYesNo(paste("Package", p," not installable from CRAN. \n Load from GitHub?", default = TRUE, prompts = getOption("askYesNo"), gettext(c("Yes", "No", "Cancel")))
if(Ask) p_load_gh("muschellij2/aal", "taiyun/corrplot/blob/master/R/corrplot-package.R",
install = TRUE, dependencies = TRUE)
}
}
You can build a message string with paste. toString will nicely concatenate and comma-separate a vector, and then we can paste than on to the rest of your message:
Ask = askYesNo(
msg = paste(toString(still_not_installed),
"cannot be install from CRAN. \n Load from GitHub?"),
default = TRUE,
prompts = getOption("askYesNo"),
gettext(c("Yes", "No", "Cancel"))
)
I think you've got a bigger issue. Line 1: You get the subset of my_packages that are not installed, good. Line 2: you try to install them, fine. Line 3: this is bad. != does element-wise comparison - you're testing if the first not_installed package is not equal to the first installed package (alphabetically), then comparing the second to the second, etc. And then you're testing if the resulting boolean vector has any length---which it will. Instead I would suggest updating the not_installed list, just repeat Line 1 to get the update the list of uninstalled packages. And you don't need to list() them, keep them as a character vector.
Also, we should nest the attempted if(Ask == TRUE) inside the if() of needing github packages at all.
not_installed = my_packages[!(my_packages %in% installed.packages()[ , "Package"])]
if(length(not_installed)) install.packages(not_installed)
still_not_installed = my_packages[!(my_packages %in% installed.packages()[, "Package"])]
if(length(still_not_installed)) {
Ask = askYesNo(
msg = paste(toString(still_not_installed),
"cannot be install from CRAN. \n Load from GitHub?"),
default = TRUE,
prompts = getOption("askYesNo"),
gettext(c("Yes", "No", "Cancel"))
)
if(Ask == TRUE) {
# This code could still be improved, it assumes if we get to
# this point that both packages are missing, but it might
# only be one of them...
p_load_gh(
"muschellij2/aal",
"taiyun/corrplot/blob/master/R/corrplot-package.R",
install = TRUE, dependencies = TRUE)
)
}
}

How old is an installed R package?

Is it possible to get the year that an installed R package is released using some R code? I can get the version, but then have to look it up on the internet, when this version was released.
Background: I am working for the Swiss Federal Statistical Office and a small group is trying to get a better R environment (we are working for example with the dplyr version 0.7.4 from 2017... and it is not possible to install a newer version...).
Cheers
Renger
You can use versions package to get a timestamp of package version. The package pulls the published versions of the package from the MRAN snapshot server.
versions::installed.versions("dplyr")
# [1] "1.0.7"
versions::available.versions("dplyr")
# $dplyr
# version date available
# 1 1.0.7 2021-06-18 TRUE
# 2 1.0.6 2021-05-05 TRUE
# 3 1.0.5 2021-03-05 TRUE
# ...
Package age
So if you want to answer the specific question about the package age you can do the following:
how_old <- function(pkg, lib = .libPaths()[1], return_age = FALSE) {
pkg_ver <- versions::installed.versions(pkgs = pkg, lib = lib)
av_vers <- versions::available.versions(pkgs = pkg)
pkg_dte <- subset.data.frame(
x = as.data.frame(unname(av_vers)),
subset = version == pkg_ver,
select = date,
drop = TRUE
)
pkg_dte <- as.Date(pkg_dte)
if (return_age) {
return(epocakir::dob2age(dob = pkg_dte))
} else {
return(pkg_dte)
}
}
how_old("dplyr", return_age = TRUE)
Results
[1] "1123200s (~1.86 weeks)"
Package creation
Or if you want to find out when package was installed locally.
when_created <- function(pkg, lib = .libPaths()[1]) {
# Package will always have DESCRIPTION file so that's a safe bet
desc_file <- system.file("DESCRIPTION", package = pkg, lib.loc = lib)
info <- fs::file_info(desc_file)
info$birth_time
}
when_created("dplyr")
Results
# [1] "2021-06-25 08:47:21 BST"
As #Jonathan recommended, if the package has a citation, then you can call the year in the citation.
citation("dplyr")$year
An alternative is to get the date from a list of available versions of a package.
devtools::install_github("https://github.com/cran/versions")
library(versions)
x <- versions::available.versions(c("dplyr", "ggplot2"))
version_year <-
function(x,
package.name = "",
version = "") {
pckg <- x[[package.name]]
row <- which(pckg$version == version)
return(pckg$date[row])
}
version_year(x, "ggplot2", version = "2.0.0")
#[1] "2015-12-18"
As a last resort, you can find out when a package was created from its DESCRIPTION:
packageDescription(pkg)$Packaged
In fact, citation falls back to this very field if no other date was given (either as Date/Publication or via an explicit CITATION file).

How can I automatically add/update Depends/Imports/Suggests versions in DESCRIPTION?

I like to keep my R packages up to date, and in developing my own package, I want to stick to #Hadley's advice:
Generally, it’s always better to specify the version and to be conservative about which version to require. Unless you know otherwise, always require a version greater than or equal to the version you’re currently using.
So, I'll need some of those here in DESCRIPTION:
Imports:
knitr (>= 1.13),
rmarkdown (>= 1.0)
Is there an existing tool to programmatically update the versions of dependencies based on the packages I currently have installed?
I know this is a small thing and I can do this manually, but I just know this is the kind of thing that is easily forgotten.
Using the locally installed version of a package as a minimum dependency also seems to make sense because I tested / build with those dependencies.
Is there a reason why I shouldn't do this?
Another option is with the usethis package, although this actually immediately overwrites the description file, so not sure if this is always desired
# use overwrite = TRUE to update dependencies with version numbers
usethis::use_latest_dependencies(overwrite = TRUE, source = "CRAN")
This shld do what you ask (well, you still need to cut/paste the output into DESCRIPTION :-)
#' Add curent version string to package dependencies
#'
#' Will \code{cat} out a cut/paste-able set of fields for a
#' \code{DESCRIPTION} file with minimum required versions for
#' each package based upon currently available package vesions
#' in CRAN.
#'
#' #param pkg package description, can be path or package name
#' #param fields fields to get & report dependencies for
#' #note R and the R version is NOT added to \code{Depends}
#' #examples
#' add_pkg_versions("qmethod")
#' add_pkg_versions("MASS")
#' \dontrun { # assumes you're in a pkg devel dir
#' add_pkg_versions()
#' }
add_pkg_versions <- function(pkg=".",
fields=c("Depends", "Imports", "LinkingTo", "Suggests")) {
require(purrr)
walk(c("dplyr", "tools", "stringi", "devtools"), require, character.only=TRUE)
stopifnot(is_scalar_character(pkg), pkg != "")
fields <- match.arg(fields, c("Depends", "Imports", "LinkingTo", "Suggests"),
several.ok=TRUE)
avail <- as_data_frame(available.packages())
if (pkg == ".") {
pkg_deps <- unclass(as_data_frame(read.dcf(file.path(package_file(), "DESCRIPTION"))))
pkg <- pkg_deps$Package
map(fields, ~stri_split_lines(pkg_deps[[.]])) %>%
map(function(x) {
if (length(x) > 0) {
unlist(x) %>%
stri_replace_all_regex(" \\(.*$|,", "") %>%
discard(`%in%`, c("", "R"))
} else { x }
}) -> pkg_deps
names(pkg_deps) <- fields
} else {
pkg_deps <- map(fields, ~flatten_chr((package_dependencies(pkg, which=.))))
names(pkg_deps) <- fields
}
pkg_deps <- discard(pkg_deps, function(x) {length(x)==0})
map(pkg_deps, function(x) {
non_base <- filter(avail, Package %in% x)
base <- setdiff(x, non_base$Package)
non_base %>%
mutate(pv=sprintf("%s (>= %s)", Package, Version)) %>%
select(pv) %>%
flatten_chr() -> pkg_plus_version
sort(c(pkg_plus_version, base))
}) -> pkg_deps
cat("Package: ", pkg, "\n", sep="")
walk(names(pkg_deps), function(x) {
cat(x, ":\n", sep="")
sprintf(" %s", pkg_deps[[x]]) %>%
paste0(collapse=",\n") %>%
cat()
cat("\n")
})
}
One of your packages:
add_pkg_versions("qmethod")
Package: qmethod
Imports:
digest (>= 0.6.10),
GPArotation (>= 2014.11-1),
knitr (>= 1.13),
methods,
psych (>= 1.6.6),
tools,
xtable (>= 1.8-2)
Just to show edge cases are handled:
add_pkg_versions("MASS")
Package: MASS
Depends:
graphics,
grDevices,
stats,
utils
Imports:
methods
Suggests:
lattice (>= 0.20-33),
nlme (>= 3.1-128),
nnet (>= 7.3-12),
survival (>= 2.39-5)

Update a specific R package and its dependencies

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.packages(checkBuilt=TRUE, ask=FALSE)
would update all my packages but that's too slow. The thing is the users do not use most of the packages and now and then they ask me to update a package (say fields) they'd use. Now if I run
install.packages("fields")
it would only update the package fields but not the package maps even if fields depends on maps. Thus when I try to load the package fields:
library("fields")
I get an error message
Error: package ‘maps’ was built before R 3.0.0: please re-install it
Is there a way to upgrade fields so that it would also automatically update the packages fields depends on?
As Ben indicated in his comment, you need to get the dependencies for fields, then filter out the packages with Priority "Base" or "Recommended", and then pass that list of package to install.packages() to deal with the installation. Something like:
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
}
This gives:
R> instPkgPlusDeps("fields")
Loading required package: tools
[1] "fields" "spam" "maps"
which matches with
> packageDescription("fields", fields = "Depends")
[1] "R (>= 2.13), methods, spam, maps"
You get warnings from the sapply() line if a dependency in deps is not actually installed. I think these are harmless as the returned value in that case is NA and we use that to indicate packages we want to install. I doubt it will affect you if you have 4000 packages installed.
The default is not to install packages but just return the list of dependencies. I figured this was safest as you may not realise the chain of dependencies implied and end up installing hundreds of packages accidentally. Pass in install = TRUE if you are happy to install the packages indicated.
Note that I restrict the types of dependencies searched for - things balloon if you use which = "most" - fields has over 300 such dependencies once you recursively resolve those dependences (which include Suggests: fields too). which = "all" will look for everything, including Enhances: which will be a bigger list of packages again. See ?tools::package_dependencies for valid inputs for the which argument.
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);
}

Problems installing R packages

I'm setting up a new laptop running Gentoo and wish to install R (as I do on all of my computers!).
However, I've hit a bit of a problem when it comes to installing packages.
I first tried to:
> install.packages(c("ggplot2", "plyr", "reshape2"))
And it duly downloaded all of the packages and its dependencies. However they didn't install reporting.
Error in library(data.table) : there is no package called ‘data.table’
Calls: .First -> library
Execution halted
Error in library(data.table) : there is no package called ‘data.table’
Calls: .First -> library
Execution halted
Error in library(data.table) : there is no package called ‘data.table’
Calls: .First -> library
Execution halted
Error in library(data.table) : there is no package called ‘data.table’
Calls: .First -> library
Execution halted
Error in library(data.table) : there is no package called ‘data.table’
Calls: .First -> library
Execution halted
Error in library(data.table) : there is no package called ‘data.table’
Calls: .First -> library
Execution halted
Error in library(data.table) : there is no package called ‘data.table’
Calls: .First -> library
Execution halted
Error in library(data.table) : there is no package called ‘data.table’
Calls: .First -> library
Not a problem I'll just install the data.table package, unfortunately...
> install.packages("data.table")
trying URL 'http://cran.uk.r-project.org/src/contrib/data.table_1.8.2.tar.gz'
Content type 'application/x-gzip' length 818198 bytes (799 Kb)
opened URL
==================================================
downloaded 799 Kb
Error in library(data.table) : there is no package called ‘data.table’
Calls: .First -> library
Execution halted
The downloaded source packages are in
‘/tmp/RtmpbQtALj/downloaded_packages’
Updating HTML index of packages in '.Library'
Making packages.html ... done
Warning message:
In install.packages("data.table") :
installation of package ‘data.table’ had non-zero exit status
And there is no indication of why installation failed at all, so I've no idea how to go about solving this? A traceback() isn't available either.
GCC is installed and configured as the output of gcc-config shows (and the fact that I can install other software from source no problem).
# gcc-config -l
[1] x86_64-pc-linux-gnu-4.6.3 *
Stumped as to how to go about solving this one. Any thoughts or ideas on how to get more information out of install.packages() welcome.
EDIT : contents of .First as requested....
> .First
function ()
{
library(data.table)
library(foreign)
library(ggplot2)
library(Hmisc)
library(lattice)
library(plyr)
library(rms)
library(xtable)
cat("\nWelcome at", date(), "\n")
}
EDIT 2 : No Rprofile.site but there is /usr/lib64/R/library/base/R/Rprofile which has....
# cat /usr/lib64/R/library/base/R/Rprofile
### This is the system Rprofile file. It is always run on startup.
### Additional commands can be placed in site or user Rprofile files
### (see ?Rprofile).
### Notice that it is a bad idea to use this file as a template for
### personal startup files, since things will be executed twice and in
### the wrong environment (user profiles are run in .GlobalEnv).
.GlobalEnv <- globalenv()
attach(NULL, name = "Autoloads")
.AutoloadEnv <- as.environment(2)
assign(".Autoloaded", NULL, envir = .AutoloadEnv)
T <- TRUE
F <- FALSE
R.version <- structure(R.Version(), class = "simple.list")
version <- R.version # for S compatibility
## for backwards compatibility only
R.version.string <- R.version$version.string
## NOTA BENE: options() for non-base package functionality are in places like
## --------- ../utils/R/zzz.R
options(keep.source = interactive())
options(warn = 0)
# options(repos = c(CRAN="#CRAN#"))
# options(BIOC = "http://www.bioconductor.org")
options(timeout = 60)
options(encoding = "native.enc")
options(show.error.messages = TRUE)
## keep in sync with PrintDefaults() in ../../main/print.c :
options(scipen = 0)
options(max.print = 99999)# max. #{entries} in internal printMatrix()
options(add.smooth = TRUE)# currently only used in 'plot.lm'
options(stringsAsFactors = TRUE)
if(!interactive() && is.null(getOption("showErrorCalls")))
options(showErrorCalls = TRUE)
local({dp <- Sys.getenv("R_DEFAULT_PACKAGES")
if(identical(dp, "")) # marginally faster to do methods last
dp <- c("datasets", "utils", "grDevices", "graphics",
"stats", "methods")
else if(identical(dp, "NULL")) dp <- character(0)
else dp <- strsplit(dp, ",")[[1]]
dp <- sub("[[:blank:]]*([[:alnum:]]+)", "\\1", dp) # strip whitespace
options(defaultPackages = dp)
})
## Expand R_LIBS_* environment variables.
Sys.setenv(R_LIBS_SITE =
.expand_R_libs_env_var(Sys.getenv("R_LIBS_SITE")))
Sys.setenv(R_LIBS_USER =
.expand_R_libs_env_var(Sys.getenv("R_LIBS_USER")))
.First.sys <- function()
{
for(pkg in getOption("defaultPackages")) {
res <- require(pkg, quietly = TRUE, warn.conflicts = FALSE,
character.only = TRUE)
if(!res)
warning(gettextf('package %s in options("defaultPackages") was not found', sQuote(pkg)),
call.=FALSE, domain = NA)
}
}
.OptRequireMethods <- function()
{
if("methods" %in% getOption("defaultPackages")) {
res <- require("methods", quietly = TRUE, warn.conflicts = FALSE,
character.only = TRUE)
if(!res)
warning('package "methods" in options("defaultPackages") was not found', call.=FALSE)
}
}
if(nzchar(Sys.getenv("R_BATCH"))) {
.Last.sys <- function()
{
cat("> proc.time()\n")
print(proc.time())
}
## avoid passing on to spawned R processes
## A system has been reported without Sys.unsetenv, so try this
try(Sys.setenv(R_BATCH=""))
}
###-*- R -*- Unix Specific ----
.Library <- file.path(R.home(), "library")
.Library.site <- Sys.getenv("R_LIBS_SITE")
.Library.site <- if(!nchar(.Library.site)) file.path(R.home(), "site-library") else unlist(strsplit(.Library.site, ":"))
.Library.site <- .Library.site[file.exists(.Library.site)]
invisible(.libPaths(c(unlist(strsplit(Sys.getenv("R_LIBS"), ":")),
unlist(strsplit(Sys.getenv("R_LIBS_USER"), ":")
))))
local({
## we distinguish between R_PAPERSIZE as set by the user and by configure
papersize <- Sys.getenv("R_PAPERSIZE_USER")
if(!nchar(papersize)) {
lcpaper <- Sys.getlocale("LC_PAPER") # might be null: OK as nchar is 0
papersize <- if(nchar(lcpaper))
if(length(grep("(_US|_CA)", lcpaper))) "letter" else "a4"
else Sys.getenv("R_PAPERSIZE")
}
options(papersize = papersize,
printcmd = Sys.getenv("R_PRINTCMD"),
dvipscmd = Sys.getenv("DVIPS", "dvips"),
texi2dvi = Sys.getenv("R_TEXI2DVICMD"),
browser = Sys.getenv("R_BROWSER"),
pager = file.path(R.home(), "bin", "pager"),
pdfviewer = Sys.getenv("R_PDFVIEWER"),
useFancyQuotes = TRUE)
})
## non standard settings for the R.app GUI of the Mac OS X port
if(.Platform$GUI == "AQUA") {
## this is set to let RAqua use both X11 device and X11/TclTk
if (Sys.getenv("DISPLAY") == "")
Sys.setenv("DISPLAY" = ":0")
## this is to allow gfortran compiler to work
Sys.setenv("PATH" = paste(Sys.getenv("PATH"),":/usr/local/bin",sep = ""))
}## end "Aqua"
local({
tests_startup <- Sys.getenv("R_TESTS")
if(nzchar(tests_startup)) source(tests_startup)
})
Looks like data.table is not installed for the user that is running the install.packages command. I think wrapping that .First function in if (interactive()) { } would be a good idea in general. Otherwise, you need to install data.table and any other packages that load at startup since install.packages runs the .Rprofile file when starting
WARNING: You're using a non-UTF8 locale, therefore only ASCII characters will work.
Please read R for Mac OS X FAQ (see Help) section 9 and adjust your system preferences accordingly.
[History restored from /Users/carlosaburto/.Rapp.history]
defaults write org.R-project.R force.LANG en_US.UTF-8
Error: unexpected symbol in "defaults write"
starting httpd help server ... done

Resources