Related
I have a multiple versions of the same package foo (all with one function bar), that I all want to use in the same script.
Following this question, I can load v1 of the package with library("foo", lib.loc = "pkgs/v1"). But this loads all of the functions from the package.
Now I want to assign foo::bar from the version v1 to bar_v1 and foo::bar from version v2 to bar_v2 to call them independently. But I do not see the option to only load one function of the library given a lib location (eg a solution would be to specify a lib.loc in the function call bar_v1 <- foo::bar).
Is this possible in R?
MWE
I have created a test package here github.com/DavZim/testPkg, which has one function foo which prints the package version (hard coded). The package has two releases, one for each version.
To get the tar.gz files of the package, you can use this
# Download Files from https://github.com/DavZim/testPkg
download.file("https://github.com/DavZim/testPkg/releases/download/v0.1.0/testPkg_0.1.0.tar.gz", "testPkg_0.1.0.tar.gz")
download.file("https://github.com/DavZim/testPkg/releases/download/v0.2.0/testPkg_0.2.0.tar.gz", "testPkg_0.2.0.tar.gz")
Then to setup the folder structure in the form of
pkgs/
0.1.0/
testPkg/
0.2.0/
testPkg/
I use
if (dir.exists("pkgs")) unlink("pkgs", recursive = TRUE)
dir.create("pkgs")
dir.create("pkgs/0.1.0")
dir.create("pkgs/0.2.0")
# install the packages locally
install.packages("testPkg_0.1.0.tar.gz", lib = "pkgs/0.1.0", repos = NULL)
install.packages("testPkg_0.2.0.tar.gz", lib = "pkgs/0.2.0", repos = NULL)
Now the question is what do I write in myscript.R?
Ideally I would have something like this
bar_v1 <- some_function(package = "testPkg", function = "foo", lib.loc = "pkgs/0.1.0")
bar_v2 <- some_function(package = "testPkg", function = "foo", lib.loc = "pkgs/0.2.0")
bar_v1() # calling testPkg::foo from lib.loc pkgs/0.1.0
#> [1] "Hello World from Version 0.1.0"
bar_v2() # calling testPkg::foo from lib.loc pkgs/0.2.0
#> [1] "Hello World from Version 0.2.0"
Non-working Try
Playing around with it, I thought something like this might work.
But it doesn't...
lb <- .libPaths()
.libPaths("pkgs/0.1.0")
v1 <- testPkg::foo
v1()
#> [1] "Hello from 0.1.0"
.libPaths("pkgs/0.2.0")
v2 <- testPkg::foo
v2()
#> [1] "Hello from 0.1.0"
.libPaths(lb)
v1()
#> [1] "Hello from 0.1.0"
v2()
#> [1] "Hello from 0.1.0" #! This should be 0.2.0!
Interestingly, if I swap around the versions to load 0.2.0 first then 0.1.0, I get this
lb <- .libPaths()
.libPaths("pkgs/0.2.0")
v1 <- testPkg::foo
v1()
#> [1] "Hello from 0.2.0"
.libPaths("pkgs/0.1.0")
v2 <- testPkg::foo
v2()
#> [1] "Hello from 0.2.0"
.libPaths(lb)
v1()
#> [1] "Hello from 0.2.0"
v2()
#> [1] "Hello from 0.2.0"
1) Successive loads Assume that we have source packages for testPkg in the current directory and they are named testPkg_0.1.0.tar.gz and testPkg_0.2.0.tar.gz. Now create pkgs, pkgs/0.1.0 and pkgs/0.2.0 directories to act as release libraries and then install those source packages into those libraries.
Now assuming each has a function foo which does not depend on other objects in the package, load each package in turn, rename foo, and detach/unload the package. Now both can be accessed under the new names.
dir.create("pkgs")
dir.create("pkgs/0.1.0")
dir.create("pkgs/0.2.0")
install.packages("testPkg_0.1.0.tar.gz", "pkgs/0.1.0", NULL)
install.packages("testPkg_0.2.0.tar.gz", "pkgs/0.2.0", NULL)
library("testPkg", lib.loc = "pkgs/0.1.0")
fooA <- foo
detach(unload = TRUE)
library("testPkg", lib.loc = "pkgs/0.2.0")
fooB <- foo
detach(unload = TRUE)
fooA
fooB
2) Change package name Another approach is to install one release normally and then for the other release download its source, change its name in the DESCRIPTION file and then install it under the new name. Then both can be used.
Assuming testPkg_0.1.0.tar.gz and testPkg_0.2.0.tar.gz source packages both have function foo and that the two tar.gz files are in current directory we can accomplish this as follows. Note that changer will both change the DESCRIPTION file to use name testPkgTest and the directory name of the source package to the same.
library(changer)
install.packages("testPkg_0.1.0.tar.gz", repos = NULL)
untar("testPkg_0.2.0.tar.gz")
changer("testPkg", "testPkgTest")
install.packages("testPkgTest", type = "source", repos = NULL)
testPkg::foo()
## [1] "Hello World from Version 0.1.0"
testPkgTest::foo()
## [1] "Hello World from Version 0.2.0"
Old
3) import Below we suggested the import package but unfortunately, as was pointed out in the comments, the code below using this package does not actually work and imports the same package twice. I have created an issue on the import github site. https://github.com/rticulate/import/issues/74
Suppose we have source packages
mypkg_0.2.4.tar.gz and mypkg_0.2.5.tar.gz
in the current directory and that each has a function myfun.
Then this will create a library for each, install them into
the respective libraries and import myfun from each. These will be located in A and B on the search path.
Note that the import package
should be installed but not loaded, i.e. no library(import)
statement should be used. You may wish to read the documentation of the import package since variations of this are possible.
# use development version of import -- the CRAN version (1.3.0) has
# a bug in the .library= argument
devtools::install_github("rticulate/import")
dir.create("mypkglib")
dir.create("mypkglib/v0.2.4")
dir.create("mypkglib/v0.2.5")
install.packages("mypkg_0.2.4.tar.gz", "mypkglib/v0.2.4", NULL)
install.packages("mypkg_0.2.5.tar.gz", "mypkglib/v0.2.5", NULL)
import::from("mypkg", .library = "mypkglib/v0.2.4", .into = "A", myfun)
import::from("mypkg", .library = "mypkglib/v0.2.5", .into = "B", myfun)
search()
ls("A")
ls("B")
get("myfun", "A")
get("myfun", "B")
Another possibility is to put them both into imports (used by default) with different names
import::from("mypkg", .library = "mypkglib/v0.2.4", myfunA = myfun)
import::from("mypkg", .library = "mypkglib/v0.2.5", myfunB = myfun)
search()
ls("imports")
myfunA
myfunB
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).
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)
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);
}
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.