Passing arguments to xlconnect functions with ellipses - r

I have a bunch of excel files in one folder, and would like to write a single function as follows:
# takes a file path and sheetname for an excel workbook, passes on additional params
getxl_sheet <- function(wb_path, sheetname, ...) {
testbook <- XLConnect::loadWorkbook(wb_path)
XLConnect::readWorksheet(testbook, sheet = sheetname, ...)
}
However, when I run the following,
set.seed(31415)
x <- rnorm(15); y <- rnorm(15)
randvals <- data.frame(x=x, y=y)
XLConnect::writeWorksheetToFile("~/temp_rands.xlsx", randvals, "Sheet1")
my_vals <- getxl_sheet("~/temp_rands.xlsx", "Sheet1", endRow=5)
my_vals returns the entire 15 by 2 dataframe, as opposed to just stopping at the fifth row (likewise if I use 'endCol=1' for example, it gives both columns). On the other hand, passing additional arguments in base R hasn't been a problem:
my_plot <- function(...) {
plot(...)
}
#my_plot(x=x, y=y, pch=16, col="blue")
works as expected. What's the problem with the function defined above to read in xlsx files? Thanks.
devtools::session_info()
Session info---------------------------------------------------------------------
setting value
version R version 3.1.1 (2014-07-10)
system x86_64, darwin13.1.0
ui RStudio (0.98.1062)
language (EN)
collate en_US.UTF-8
tz America/New_York
Packages-------------------------------------------------------------------------
package * version date source
devtools 1.6.0.9000 2014-11-26 Github (hadley/devtools#bd9c252)
rJava 0.9.6 2013-12-24 CRAN (R 3.1.0)
rstudioapi 0.1 2014-03-27 CRAN (R 3.1.0)
XLConnect * 0.2.9 2014-08-14 CRAN (R 3.1.1)
XLConnectJars * 0.2.9 2014-08-14 CRAN (R 3.1.1)

The dots mechanism needs to have a function that expects dots, and unlike plot.default, readWorksheet is not designed to handle an ellipsis: You need to build some decoding into the arguments:
getxl_sheetRCshort <- function(wb_path, sheetname, ...) {
arglist <- list(...)
testbook <- loadWorkbook(wb_path);
readWorksheet(testbook, sheet = sheetname,
endRow=arglist[['endRow']], endCol=arglist[['endCol']])
}
> my_vals <- getxl_sheet("~/temp_rands.xlsx", "Sheet1", endRow=5)
> my_vals
x y
1 1.6470129 -1.27323204
2 -1.1119872 -1.77141948
3 -1.5485456 1.40846809
4 -0.7483785 -0.09450125
You could make this even more general by doing matching on the entire formals() list from the readWorksheet function and there are worked examples in SO that illustrate this. Fortunately the parser is somehow able to ignore the fact that no value is passed to 'endCol'.

Related

Use function from a package but different versions simultaneously

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

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)

check if package name belongs to a CRAN archived package

How can one check of a package has been archived from CRAN. One can check if a package is a CRAN package like so:
"ggplot2" %in% available.packages()[,1]
## [1] TRUE
But a package like helpr shows false with the same code. How could I check if a name is archived?
"helpr" %in% available.packages()[,1]
## [1] FALSE
I could scrape the archive like this:
archs <- XML::readHTMLTable(readLines("https://cran.r-project.org/src/contrib/Archive/"),
stringsAsFactors = FALSE)
gsub("/$", "", na.omit(archs[[1]][, "Name"]))
but I assume there is a built in base way to to do this as using an archived package name will throw a warning in a CRAN check.
FWIW, rolling your own CRAN_archive_db would be something like:
download.file("https://cran.rstudio.com/src/contrib/Meta/archive.rds",
"archive.rds")
archive <- readRDS("archive.rds")
R CMD check basically calls tools:::.check_packages. The functionality you're looking for is in tools:::.check_package_CRAN_incoming, and tools:::CRAN_archive_db.
Edit (by Tyler Rinker) Using Josh's answer the following code gives me what I'm after though less well succint than #hrbrmstr's:
get_archived <- function(cran = getOption("repos")){
if (is.null(cran)) cran <- "http://cran.rstudio.com/"
con <- gzcon(url(sprintf("%s/%s", cran, "src/contrib/Meta/archive.rds"), open = "rb"))
on.exit(close(con))
x <- readRDS(con)
names(x)
}
check_archived <- function(package){
tolower(package) %in% tolower(get_archived())
}
check_archived("ggplot2")
check_archived("helpr")
check_archived("foo")
## > check_archived("ggplot2")
## [1] TRUE
## > check_archived("helpr")
## [1] TRUE
## > check_archived("foo")
## [1] FALSE
I think the somewhat-recently-released package available by the ROpenSciLabs is designed for this (and much more):
github.com/ropenscilabs/available
Its readme (as of now) lists:
Checks for validity
Checks not already available on GitHub, CRAN and Bioconductor
Searches Urban Dictionary, Wiktionary and Wikipedia for unintended meanings
Can suggest possible names based on text in the package title or description.

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

Resources