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).
Hi I've written the following code:
################# Loadin Require Libraries #################
required.packages <- c('caret','readxl')
for (pkg in required.packages){
if(!require(pkg, character.only = T)){
install.packages(pkg,
character.only = T,
dependencies = T)
library(pkg, character.only = T)
}else{
library(pkg, character.only = T)
}
}
The code shall be ran on a computer of a peer, so to take care of might missing libraries I thought I iterate threw a string list, to check if the package is installed if yes -> load if no -> install and load then. However when a package is not available R still puts out a warning message:
Warning message:
In library(package, lib.loc = lib.loc, character.only = TRUE,
logical.return = TRUE, : es gibt kein Paket namens ‘readxl’
My question: is there a better way to check / install a bunch of libraries in R? Should I care about the warning? If it is not important is there a way to surpress this warning getting printed?
Edit: Final solution Thanks to the correct answer provided by #akrun:
################# Loadin Require Libraries #################
lib <- .libPaths()[1]
required.packages <- c('caret','readxl')
i1 <- !(required.packages %in% row.names(installed.packages()))
if(any(i1)) {
install.packages(required.packages[i1], dependencies = TRUE, lib = lib)
}
lapply(required.packages, require, character.only = TRUE)
Update 2021 - Pacman
I found the pacman - package really helpful for exactly this purpose, especially the p_load function. It checks if the package is installed and otherwise tries to install the missing package.
This function is a wrapper for library and require. It checks to see
if a package is installed, if not it attempts to install the package
from CRAN and/or any other repository in the pacman repository list.
So nowadays I start all my scripts that need to be 'portable' with the following lines:
require(pacman)
# Load / Install Required Packages
p_load(dplyr, tidyr, gridExtra, psych)
In this case to load / install dplyr, tidyr, gridExtra & psych
Also nice in this package (if you want to clean up the environment) p_unload
# Unload All packages
p_unload()
Here is one option
Pkgs <- c('caret','readxl')
lib <- .libPaths()[1]
i1 <- !(Pkgs %in% row.names(installed.packages()))
if(any(i1)) {
install.packages(Pkgs[i1], dependencies = TRUE, lib = lib)
}
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)
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.
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.