Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
* dev:
  Bump version to 0.2.10; Change maintainer to [email protected]
  Update NEWS and README
  Rebuild vignettes
  Added note on system requirements (#98)
  Fix type errors in checkVersions() that caused addPackages() to fail. #99
  Add missing space in error message for unknown type
  update NEWS (#72)
  add MRAN url as package option (close #72)
  update NEWS
  Fixing typo in non-CRAN vignette
  Fixing typos
  • Loading branch information
andrie committed Oct 21, 2017
2 parents 1b1d7a8 + 90e6f95 commit 0c7ca84
Show file tree
Hide file tree
Showing 46 changed files with 799 additions and 1,033 deletions.
10 changes: 6 additions & 4 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: miniCRAN
Authors@R: c(person("Microsoft Corporation", role="cph"), person("Andrie", "de
Vries", role=c("aut", "cre"), email="adevries@microsoft.com"),
Vries", role=c("aut", "cre"), email="apdevries@gmail.com"),
person("Alex", "Chubaty", role="ctb", email="[email protected]"))
License: GPL-2
Copyright: Microsoft Corporation
Expand All @@ -11,11 +11,13 @@ Description: Makes it possible to create an internally consistent
reads the dependency tree for these packages, then downloads only this
subset. The user can then install packages from this repository directly,
rather than from CRAN. This is useful in production settings, e.g. server
behind a firewall, or remote locations with slow broadband access.
Date: 2017-07-20
Version: 0.2.9
behind a firewall, or remote locations with slow (or zero) Internet access.
Date: 2017-10-20
Version: 0.2.10
URL: https://github.com/RevolutionAnalytics/miniCRAN
BugReports: https://github.com/RevolutionAnalytics/miniCRAN/issues
SystemRequirements: Imports the `curl` and `XML` packages. These have system
requirements on `libxml2-devel`, `libcurl-devel` and `openssl-devel`.
Imports:
graphics,
httr,
Expand Down
13 changes: 13 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
miniCRAN v0.2.10
================

New features:
* Added package option `minicran.mran` which sets default preferred MRAN url (#72)

Bug fixes:
* Fixed 'Error in basename(prev)' when calling `addPackage()` (#99)

Other improvements:
* Fixed typos in vignettes (@ryanatanner PR#93 and PR#94)
* Added note on system requirements of curl and XML (#98)

miniCRAN v0.2.9 (Release date: 2017-07-20)
===============

Expand Down
10 changes: 5 additions & 5 deletions R/MRAN.R
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
MRAN <- function(snapshot){
url <- "https://mran.microsoft.com"
if(missing("snapshot") || is.null(snapshot)){
url
MRAN <- function(snapshot) {
url <- getOption("minicran.mran")
if (missing("snapshot") || is.null(snapshot)) {
url
} else {
sprintf("%s/snapshot/%s", url, snapshot)
}
}
CRAN <- function()getOption("repos")[1]
CRAN <- function() getOption("repos")[1]
44 changes: 29 additions & 15 deletions R/addPackages.R
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ checkVersions <- function(pkgs = NULL, path = NULL, type = "source",
if (is.null(path)) stop("path must be specified.")
if (!file.exists(path)) stop("invalid path, ", path)

duplicatePkgs <- sapply(type, function(type) {
do_one <- function(type) {
pkgPath <- repoBinPath(path, type, Rversion)
if (is.null(pkgs)) {
files <- dir(pkgPath)
Expand All @@ -35,15 +35,17 @@ checkVersions <- function(pkgs = NULL, path = NULL, type = "source",
}
files <- unlist(files)
pkgFiles <- grep("\\.(tar\\.gz|zip|tgz)$", basename(files), value = TRUE)

# identify duplicate packages and warn the user
pkgs <- sapply(strsplit(files, "_"), "[[", 1)
dupes <- pkgs[duplicated(pkgs)]
if (length(dupes)) warning("Duplicate package(s): ", paste(dupes, collapse = ", "))
file.path(pkgPath, pkgFiles)
})
}

duplicatePkgs <- sapply(type, do_one, simplify = FALSE)
names(duplicatePkgs) <- type
return(invisible(duplicatePkgs))
duplicatePkgs
}


Expand Down Expand Up @@ -72,31 +74,41 @@ addPackage <- function(pkgs = NULL, path = NULL, repos = getOption("repos"),
writePACKAGES = TRUE, deps = TRUE, quiet = FALSE) {
if (is.null(path) || is.null(pkgs)) stop("path and pkgs must both be specified.")

lapply(type, function(t) {
do_one <- function(t) {
prev <- checkVersions(pkgs = pkgs, path = path, type = t, Rversion = Rversion)
prev <- prev[[1]]
prev.df <- getPkgVersFromFile(prev)

if (deps) pkgs <- pkgDep(pkgs, repos = repos, type = t, Rversion = Rversion)

makeRepo(pkgs = pkgs, path = path, repos = repos, type = t, Rversion = Rversion,
download = TRUE, writePACKAGES = FALSE, quiet = quiet)

if (length(prev)) {
curr <- suppressWarnings(
checkVersions(pkgs = pkgs, path = path, type = t, Rversion = Rversion)
)
curr <- curr[[1]]
curr.df <- getPkgVersFromFile(curr)


findPrevPackage <- function(x) {
grep(paste0("^", x), basename(prev))
}

dupes <- with(curr.df, package[duplicated(package)])
if (length(dupes)) {
old <- lapply(dupes, function(x) { grep(paste0("^", x), basename(prev)) } )
file.remove(prev[unlist(old)])
to_remove <- lapply(dupes, findPrevPackage)
if(length(unlist(to_remove))){
file.remove(prev[unlist(to_remove)])
}
}
}
})
}

lapply(type, do_one)

n <- if (writePACKAGES) updateRepoIndex(path = path, type = type, Rversion = Rversion)
return(invisible(n))
invisible(n)
}


Expand Down Expand Up @@ -142,11 +154,13 @@ addOldPackage <- function(pkgs = NULL, path = NULL, vers = NULL,

pkgPath <- repoBinPath(path = path, type = type, Rversion = Rversion)
if (!file.exists(pkgPath)) dir.create(pkgPath, recursive = TRUE)
sapply(oldPkgs, function(x) {

do_one <- function(x) {
result <- utils::download.file(x, destfile = file.path(pkgPath, basename(x)),
method = "auto", mode = "wb", quiet = quiet)
if (result != 0) warning("error downloading file ", x)
})
}
sapply(oldPkgs, do_one)
if (writePACKAGES) invisible(updateRepoIndex(path = path, type = type, Rversion))
}

Expand Down
22 changes: 10 additions & 12 deletions R/getCranDescription.R
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@

#' @importFrom XML readHTMLTable
oldGetCranDescription <- function(pkg, repos = getOption("repos"),
type = "source",
oldGetCranDescription <- function(pkg, repos = getOption("repos"),
type = "source",
pkgs = pkgDep(pkg, repos = repos, type = type)){
getOne <- function(package) {
repos <- repos[[1]]
if(!grepl("/$", repos)) repos <- paste0(repos, "/")
url <- gsub("https://", "http://",

url <- gsub("https://", "http://",
sprintf("%sweb/packages/%s/index.html", repos, package)
)
x <- tryCatch({
Expand Down Expand Up @@ -36,20 +36,18 @@ oldGetCranDescription <- function(pkg, repos = getOption("repos"),
#'
#' @inheritParams pkgDep
#' @inheritParams makeRepo
#'
#'
#' @export
#'
#'
#' @example /inst/examples/example_getCranDescription.R
getCranDescription <- function(pkg, repos = getOption("repos"),
type = "source",
getCranDescription <- function(pkg, repos = getOption("repos"),
type = "source",
pkgs = pkgDep(pkg, repos = repos, type = type)){
if(getRversion() >= "3.4.1"){

if (getRversion() >= "3.4.1"){
pdb <- tools::CRAN_package_db()
pdb[match(pkgs, pdb$Package), ]
} else {
oldGetCranDescription(pkg = pkg, repos = repos, type = type, pkgs = pkgs)
}
}


2 changes: 1 addition & 1 deletion R/helpers.R
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ repoPrefix <- function(type, Rversion) {
"mac.binary.el-capitan" = sprintf("bin/macosx/el-capitan/contrib/%s", Rversion),
"mac.binary.leopard" = sprintf("bin/macosx/leopard/contrib/%s", Rversion),
"mac.binary.mavericks" = sprintf("bin/macosx/mavericks/contrib/%s", Rversion),
stop("Type ", type, "not recognised.")
stop("Type ", type, " not recognised.")
)
}

Expand Down
57 changes: 31 additions & 26 deletions R/minicran-package.R
Original file line number Diff line number Diff line change
Expand Up @@ -7,53 +7,58 @@
#'
#'@description
#'
#' At the end of 2014, CRAN consisted of more than 6,000 packages. Many organisations need to maintain a private mirror of CRAN, but with only a subset of packages that are relevant to them.
#'
#' `miniCRAN` makes it possible to create an internally consistent repository consisting of selected packages from CRAN-like repositories. The user specifies a set of desired packages, and miniCRAN recursively reads the dependency tree for these packages, then downloads only this subset.
#'
#'
#' At the end of 2014, CRAN consisted of more than 6,000 packages. Many organisations need to maintain a private mirror of CRAN, but with only a subset of packages that are relevant to them.
#'
#' `miniCRAN` makes it possible to create an internally consistent repository consisting of selected packages from CRAN-like repositories. The user specifies a set of desired packages, and miniCRAN recursively reads the dependency tree for these packages, then downloads only this subset.
#'
#'
#' There are many reasons for not creating a complete mirror CRAN using `rsync`:
#'
#' * You may wish to mirror only a subset of CRAN, for security, legal compliance or any other in-house reason
#' * You may wish to restrict internal package use to a subset of public packages, to minimize package duplication, or other reasons of coding standards
#' * You may wish to make packages available from public repositories other than CRAN, e.g. BioConductor, r-forge, OmegaHat, etc.
#' * You may wish to add custom in-house packages to your repository
#'
#'
#' The ambition of `miniCRAN` is to eventually satisfy all of these considerations.
#'
#'
#' @section Making a private repo:
#'
#'
#' * [pkgAvail()]: Read from a local (or remote) CRAN-like repository and determine available packages.
#' * [pkgDep()]: Find (recursive) package dependencies.
#' * [makeRepo()] : Make a mini CRAN repository, by downloading packages (and their dependencies) and creating the appropriate file structure for a repository. This allows you to use functions like [utils::available.packages()] and [utils::install.packages()] on your local repository.
#'
#'
#' This subset will be internally consistent, i.e. the following functions will work as expected:
#' * [utils::available.packages()]
#' * [utils::install.packages()]
#'
#'
#' The main function is [makeRepo()] - this will download all the required packages, with their dependencies, into the appropriate repository file structure, and then create the repository index (PACKAGES) file.
#'
#'
#'
#'
#'
#'
#' @section Updating packages in a repo:
#'
#'
#' * [oldPackages()]: Indicates packages which have a (suitable) later version on the repositories
#' * [updatePackages()]: Offers to download and install such packages
#'
#'
#'
#'
#'
#'
#' @section Creating dependencies:
#'
#'
#' To get a recursive list of dependencies as well as a plot, use [pkgDep()] followed by [makeDepGraph()].
#'
#'
#' * [pkgDep()]: Find (recursive) package dependencies.
#' * [makeDepGraph()]: Create graph of selected package dependencies.
#' * [plot.pkgDepGraph()]: Create a visualization of the dependency graph
#'
#'
#'
#'
#'
#'
#'
#'
#' @section Package options:
#'
#' \describe{
#' \item{\code{minicran.mran}}{preferred MRAN URL. Defaults to \url{https://mran.microsoft.com}
#' for R versions 3.2.2 and greater. Versions earlier than 3.2.2 use HTTP instead of HTTPS.}
#' }
#'
#' @name miniCRAN-package
#' @aliases miniCRAN minicran
#' @docType package
Expand All @@ -69,9 +74,9 @@ NULL
# data documentation ------------------------------------------------------

#' Stored version of available.packages()
#'
#'
#' Copy of the result of [utils::available.packages()] on July 1, 2014.
#'
#'
#' @docType data
#' @keywords datasets
#' @name cranJuly2014
Expand Down
7 changes: 5 additions & 2 deletions R/updatePackages.R
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ oldPackages <- function(path = NULL, repos = getOption("repos"),
updatePackages <- function(path = NULL, repos = getOption("repos"), method, ask = TRUE,
availPkgs = pkgAvail(repos = repos, type = type, Rversion = Rversion),
oldPkgs = NULL, type = "source", Rversion = R.version, quiet = FALSE) {
lapply(type, function(t) {

do_one <- function(t){
force(ask)
simplifyRepos <- function(repos, t) {
tail <- substring(contribUrl("---", type = t, Rversion = Rversion), 4)
Expand Down Expand Up @@ -137,5 +138,7 @@ updatePackages <- function(path = NULL, repos = getOption("repos"), method, ask
addPackage(update[, "Package"], path = path, repos = repos, type = t,
quiet = quiet, deps = FALSE, Rversion = Rversion)
}
})
}

lapply(type, do_one)
}
18 changes: 18 additions & 0 deletions R/zzz.R
Original file line number Diff line number Diff line change
@@ -1,2 +1,20 @@
# globals <- new.env(parent=emptyenv(), hash=TRUE)
# globals$have_RCurl <- require("RCurl")

.onLoad <- function(libname, pkgname) {
mran.url <- if (getRversion() >= "3.2.2") {
"https://mran.microsoft.com" ## use HTTPS
} else {
"http://mran.microsoft.com" ## use HTTP
}

## set options using the approach used by devtools
opts <- options()
opts.miniCRAN <- list(
minicran.mran = mran.url
)
toset <- !(names(opts.miniCRAN) %in% names(opts))
if (any(toset)) options(opts.miniCRAN[toset])

invisible()
}
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ install.packages("miniCRAN")
library("miniCRAN")
```

### Development version

Get the latest stable development version from github:

Expand All @@ -39,6 +40,23 @@ Get the latest stable development version from github:
library(devtools)
install_github("RevolutionAnalytics/miniCRAN")
```

### System requirements

The `miniCRAN` package itself doesn't introduce any system dependencies. However, the package imports [`curl`](https://cran.r-project.org/package=curl) and `XML` packages. These have system requirements on `libxml2-devel`, `libcurl-devel` and `openssl-devel`.

On systems with the `rpm` package manager (Red Hat, CentOS) try:

```bash
yum install libcurl-devel libxml2-devel openssl-devel
```

On systems with the `aptitude` package manager (Debian, Ubuntu) try:

```bash
apt-get install libcurl4-openssl-dev libxml2-devel openssl-devel
```


## Example:

Expand Down
204 changes: 187 additions & 17 deletions inst/doc/miniCRAN-dependency-graph.html

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion inst/doc/miniCRAN-dependency-graph.rmd
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ The package `chron` neatly illustrates the different roles of Imports, Suggests

## A worked example using the package chron

The function `pkgDep()` exposes not only these dependencies, but also also all recursive dependencies. In other words, it answers the question which packages need to be installed to satsify all dependencies of dependencies.
The function `pkgDep()` exposes not only these dependencies, but also all recursive dependencies. In other words, it answers the question which packages need to be installed to satisfy all dependencies of dependencies.

This means that the algorithm is as follows:

Expand Down
214 changes: 192 additions & 22 deletions inst/doc/miniCRAN-introduction.html

Large diffs are not rendered by default.

208 changes: 189 additions & 19 deletions inst/doc/miniCRAN-non-CRAN-repos.html

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion inst/doc/miniCRAN-non-CRAN-repos.rmd
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Although the package name `miniCRAN` seems to indicate you can only use CRAN as

This vignette contains some examples of how to refer to different package repositories, including CRAN, alternative mirrors of CRAN, R-Forge as well as BioConductor.

To make simplify the code to show the salient features, we use a little helper function, `index()` that is a simple wrapper around `available.packages()`:
To simplify the code to show the salient features, we use a little helper function, `index()` that is a simple wrapper around `available.packages()`:


```{r setup}
Expand Down
Loading

0 comments on commit 0c7ca84

Please sign in to comment.