packrat/0000755000176200001440000000000013372757542011716 5ustar liggesuserspackrat/inst/0000755000176200001440000000000013352207316012656 5ustar liggesuserspackrat/inst/resources/0000755000176200001440000000000013352207316014670 5ustar liggesuserspackrat/inst/resources/init-rprofile.R0000644000176200001440000000016313372655512017605 0ustar liggesusers#### -- Packrat Autoloader (version 0.5.0) -- #### source("packrat/init.R") #### -- End Packrat Autoloader -- #### packrat/inst/resources/mac_r_userlib.sh0000644000176200001440000000555113352207316020040 0ustar liggesusers#!/bin/bash set -e # R system library to user library migration script for Mac OS X # # Date: January 14, 2014 # Author: Joe Cheng # # From https://cran.r-project.org/bin/macosx/RMacOSX-FAQ.html: # The official CRAN binaries come pre-packaged in such a way that # administrator have sufficient privileges to update R and install # packages system-wide. # # This means that any install.packages() call, or using Install Package # from RStudio, causes packages to be installed in the system library # (e.g. /Library/Frameworks/R.framework/Versions/3.0/Resources/library). # The system library contains base and recommended packages as well. # # We believe it's more hygienic to keep base/recommended packages # separate from user-installed packages, and this separation is # necessary for the Packrat[0] dependency management system to provide # isolation benefits. # # This script creates a personal library directory, and migrates any # non-base, non-recommended packages from the system library into # it. It then sets the permissions on the system library to only be # writable by root. This will ensure that future install.packages calls # will not add more packages to the system library. # # [0] https://rstudio.github.io/packrat/ # The system-wide library RLIBDIR=`R --vanilla --slave -e "cat(tail(.libPaths(), 1))"` # The user library (which might not exist yet) RLIBSUSER=`R --vanilla --slave -e "cat(path.expand(head(Sys.getenv('R_LIBS_USER'), 1)))"` # The list of non-base, non-recommended packages in the system-wide library PKGS=`R --vanilla --slave -e "cat(with(as.data.frame(installed.packages(tail(.libPaths(), 1))), paste(Package[is.na(Priority)])))"` if [ "$RLIBDIR" == "" ]; then echo "ERROR: Couldn't detect system library directory, aborting" >&2 exit 1 fi if [ "$RLIBSUSER" == "" ]; then echo "ERROR: Couldn't detect R_LIBS_USER directory, aborting" >&2 exit 1 fi echo "Saving backup of $RLIBDIR to ./SystemLibBackup.tar.gz" if [ -f ./SystemLibBackup.tar.gz ]; then echo "SystemLibBackup.tar.gz exists. Press Enter to overwrite, or Ctrl-C to abort:" >&2 read -s < /dev/tty echo "Backing up..." fi tar -czPf SystemLibBackup.tar.gz "$RLIBDIR" #tar -czf SystemLibBackup.tar.gz -C "$RLIBDIR" $(ls $RLIBDIR) echo "Backup successful." echo "Migrating user-installed packages to $RLIBSUSER" echo "Press Enter to continue, or Ctrl-C to abort" read -s < /dev/tty mkdir -p "$RLIBSUSER" for pkg in $PKGS; do echo "Moving $pkg" if [ -d "$RLIBSUSER/$pkg" ]; then echo "ERROR: The directory $RLIBSUSER/$pkg already exists, aborting" >&2 echo "Please delete the package $pkg from either $RLIBDIR or $RLIBSUSER." exit 3 fi # Do a copy to get default permissions cp -R "$RLIBDIR/$pkg" "$RLIBSUSER" sudo rm -rf "$RLIBDIR/$pkg" done echo echo "Making $RLIBDIR writable only by root (chmod 755)" sudo chmod -R 755 "$RLIBDIR" echo echo Success! packrat/inst/resources/init.R0000644000176200001440000002032613372655512015770 0ustar liggesuserslocal({ ## Helper function to get the path to the library directory for a ## given packrat project. getPackratLibDir <- function(projDir = NULL) { path <- file.path("packrat", "lib", R.version$platform, getRversion()) if (!is.null(projDir)) { ## Strip trailing slashes if necessary projDir <- sub("/+$", "", projDir) ## Only prepend path if different from current working dir if (!identical(normalizePath(projDir), normalizePath(getwd()))) path <- file.path(projDir, path) } path } ## Ensure that we set the packrat library directory relative to the ## project directory. Normally, this should be the working directory, ## but we also use '.rs.getProjectDirectory()' if necessary (e.g. we're ## rebuilding a project while within a separate directory) libDir <- if (exists(".rs.getProjectDirectory")) getPackratLibDir(.rs.getProjectDirectory()) else getPackratLibDir() ## Unload packrat in case it's loaded -- this ensures packrat _must_ be ## loaded from the private library. Note that `requireNamespace` will ## succeed if the package is already loaded, regardless of lib.loc! if ("packrat" %in% loadedNamespaces()) try(unloadNamespace("packrat"), silent = TRUE) if (suppressWarnings(requireNamespace("packrat", quietly = TRUE, lib.loc = libDir))) { # Check 'print.banner.on.startup' -- when NA and RStudio, don't print print.banner <- packrat::get_opts("print.banner.on.startup") if (print.banner == "auto" && is.na(Sys.getenv("RSTUDIO", unset = NA))) { print.banner <- TRUE } else { print.banner <- FALSE } return(packrat::on(print.banner = print.banner)) } ## Escape hatch to allow RStudio to handle bootstrapping. This ## enables RStudio to provide print output when automagically ## restoring a project from a bundle on load. if (!is.na(Sys.getenv("RSTUDIO", unset = NA)) && is.na(Sys.getenv("RSTUDIO_PACKRAT_BOOTSTRAP", unset = NA))) { Sys.setenv("RSTUDIO_PACKRAT_BOOTSTRAP" = "1") setHook("rstudio.sessionInit", function(...) { # Ensure that, on sourcing 'packrat/init.R', we are # within the project root directory if (exists(".rs.getProjectDirectory")) { owd <- getwd() setwd(.rs.getProjectDirectory()) on.exit(setwd(owd), add = TRUE) } source("packrat/init.R") }) return(invisible(NULL)) } ## Bootstrapping -- only performed in interactive contexts, ## or when explicitly asked for on the command line if (interactive() || "--bootstrap-packrat" %in% commandArgs(TRUE)) { needsRestore <- "--bootstrap-packrat" %in% commandArgs(TRUE) message("Packrat is not installed in the local library -- ", "attempting to bootstrap an installation...") ## We need utils for the following to succeed -- there are calls to functions ## in 'restore' that are contained within utils. utils gets loaded at the ## end of start-up anyhow, so this should be fine library("utils", character.only = TRUE) ## Install packrat into local project library packratSrcPath <- list.files(full.names = TRUE, file.path("packrat", "src", "packrat") ) ## No packrat tarballs available locally -- try some other means of installation if (!length(packratSrcPath)) { message("> No source tarball of packrat available locally") ## There are no packrat sources available -- try using a version of ## packrat installed in the user library to bootstrap if (requireNamespace("packrat", quietly = TRUE) && packageVersion("packrat") >= "0.2.0.99") { message("> Using user-library packrat (", packageVersion("packrat"), ") to bootstrap this project") } ## Couldn't find a user-local packrat -- try finding and using devtools ## to install else if (requireNamespace("devtools", quietly = TRUE)) { message("> Attempting to use devtools::install_github to install ", "a temporary version of packrat") library(stats) ## for setNames devtools::install_github("rstudio/packrat") } ## Try downloading packrat from CRAN if available else if ("packrat" %in% rownames(available.packages())) { message("> Installing packrat from CRAN") install.packages("packrat") } ## Fail -- couldn't find an appropriate means of installing packrat else { stop("Could not automatically bootstrap packrat -- try running ", "\"'install.packages('devtools'); devtools::install_github('rstudio/packrat')\"", "and restarting R to bootstrap packrat.") } # Restore the project, unload the temporary packrat, and load the private packrat if (needsRestore) packrat::restore(prompt = FALSE, restart = TRUE) ## This code path only reached if we didn't restart earlier unloadNamespace("packrat") requireNamespace("packrat", lib.loc = libDir, quietly = TRUE) return(packrat::on()) } ## Multiple packrat tarballs available locally -- try to choose one ## TODO: read lock file and infer most appropriate from there; low priority because ## after bootstrapping packrat a restore should do the right thing if (length(packratSrcPath) > 1) { warning("Multiple versions of packrat available in the source directory;", "using packrat source:\n- ", shQuote(packratSrcPath)) packratSrcPath <- packratSrcPath[[1]] } lib <- file.path("packrat", "lib", R.version$platform, getRversion()) if (!file.exists(lib)) { dir.create(lib, recursive = TRUE) } message("> Installing packrat into project private library:") message("- ", shQuote(lib)) surround <- function(x, with) { if (!length(x)) return(character()) paste0(with, x, with) } ## Invoke install.packages() in clean R session peq <- function(x, y) paste(x, y, sep = " = ") installArgs <- c( peq("pkgs", surround(packratSrcPath, with = "'")), peq("lib", surround(lib, with = "'")), peq("repos", "NULL"), peq("type", surround("source", with = "'")) ) fmt <- "utils::install.packages(%s)" installCmd <- sprintf(fmt, paste(installArgs, collapse = ", ")) ## Write script to file (avoid issues with command line quoting ## on R 3.4.3) installFile <- tempfile("packrat-bootstrap", fileext = ".R") writeLines(installCmd, con = installFile) on.exit(unlink(installFile), add = TRUE) fullCmd <- paste( surround(file.path(R.home("bin"), "R"), with = "\""), "--vanilla", "--slave", "-f", surround(installFile, with = "\"") ) system(fullCmd) ## Tag the installed packrat so we know it's managed by packrat ## TODO: should this be taking information from the lockfile? this is a bit awkward ## because we're taking an un-annotated packrat source tarball and simply assuming it's now ## an 'installed from source' version ## -- InstallAgent -- ## installAgent <- "InstallAgent: packrat 0.5.0" ## -- InstallSource -- ## installSource <- "InstallSource: source" packratDescPath <- file.path(lib, "packrat", "DESCRIPTION") DESCRIPTION <- readLines(packratDescPath) DESCRIPTION <- c(DESCRIPTION, installAgent, installSource) cat(DESCRIPTION, file = packratDescPath, sep = "\n") # Otherwise, continue on as normal message("> Attaching packrat") library("packrat", character.only = TRUE, lib.loc = lib) message("> Restoring library") if (needsRestore) packrat::restore(prompt = FALSE, restart = FALSE) # If the environment allows us to restart, do so with a call to restore restart <- getOption("restart") if (!is.null(restart)) { message("> Packrat bootstrap successfully completed. ", "Restarting R and entering packrat mode...") return(restart()) } # Callers (source-erers) can define this hidden variable to make sure we don't enter packrat mode # Primarily useful for testing if (!exists(".__DONT_ENTER_PACKRAT_MODE__.") && interactive()) { message("> Packrat bootstrap successfully completed. Entering packrat mode...") packrat::on() } Sys.unsetenv("RSTUDIO_PACKRAT_BOOTSTRAP") } }) packrat/inst/rstudio/0000755000176200001440000000000013352207316014347 5ustar liggesuserspackrat/inst/rstudio/rstudio-protocol0000644000176200001440000000001313352207316017614 0ustar liggesusersVersion: 1 packrat/tests/0000755000176200001440000000000013352207316013043 5ustar liggesuserspackrat/tests/test-cranlike-repositories.R0000644000176200001440000000352113352207316020461 0ustar liggesuserslibrary(packrat) (function() { # Disable R_TESTS within this scope (we don't want the R # subprocess to attempt to call startup.Rs) R_TESTS <- Sys.getenv("R_TESTS", unset = NA) if (!is.na(R_TESTS)) { Sys.unsetenv("R_TESTS") on.exit(Sys.setenv(R_TESTS = R_TESTS), add = TRUE) } dir <- tempdir() owd <- setwd(dir) on.exit(setwd(owd), add = TRUE) # Save repos repos <- getOption("repos") on.exit(options(repos = repos), add = TRUE) # Create the local repo localCRAN <- file.path(dir, "sushi") packrat::repos_create(localCRAN) on.exit(unlink(localCRAN, recursive = TRUE), add = TRUE) # Use only the 'sushi' repository options(repos = getOption("repos")["sushi"]) # Create an example package. env <- new.env(parent = emptyenv()) env$sashimi <- function() {} suppressMessages( utils::package.skeleton("sashimi", path = dir, environment = env) ) on.exit(unlink(file.path(dir, "sashimi"), recursive = TRUE), add = TRUE) # tidy up the broken package unlink(file.path(dir, "sashimi/man"), recursive = TRUE) # Try uploading the package from the directory itself (requires building) message("\nBuilding sashimi:\n") packrat::repos_upload(file.path(dir, "sashimi"), "sushi") # Try building and uploading a tarball system(paste("R --vanilla CMD build", file.path(dir, "sashimi"))) tarball <- list.files(dir, pattern = "\\.tar\\.gz$")[[1]] packrat::repos_upload(file.path(dir, tarball), "sushi") # Try installing the package as normal tempLib <- file.path(dir, "library") if (!file.exists(tempLib)) { dir.create(tempLib) on.exit(unlink(tempLib, recursive = TRUE), add = TRUE) } install.packages("sashimi", lib = tempLib, type = "source") # avoid bogus warning from R CMD check eval(call("library", "sashimi", lib.loc = tempLib)) detach("package:sashimi", unload = TRUE) })() packrat/tests/testthat/0000755000176200001440000000000013372655524014715 5ustar liggesuserspackrat/tests/testthat/test-aaa.R0000644000176200001440000000017313352207316016526 0ustar liggesuserscontext("Initialization") test_that("we can re-initialize the test repository", { skip_on_cran() rebuildTestRepo() }) packrat/tests/testthat/test-packrat.R0000644000176200001440000002460713352207316017441 0ustar liggesusers# Packrat tests # # To run these tests, set the working directory to packrat/tests and run # test_check("packrat") # # Also run by R CMD CHECK. library(testthat) # Set up test context. context("packrat") withTestContext({ test_that("init creates project structure and installs dependencies", { skip_on_cran() projRoot <- cloneTestProject("sated") init(enter = FALSE, projRoot, options = list(local.repos = "packages")) lib <- libDir(projRoot) expect_true(file.exists(lockFilePath(projRoot))) expect_true(file.exists(srcDir(projRoot))) expect_true(file.exists(libDir(projRoot))) expect_true(file.exists(file.path(lib, "breakfast"))) expect_true(file.exists(file.path(lib, "bread"))) expect_true(file.exists(file.path(lib, "oatmeal"))) expect_true(file.exists(file.path(lib, "packrat"))) expect_true(file.exists(file.path(lib, "toast"))) }) test_that("init does not install dependencies when infer.dependencies is false", { skip_on_cran() projRoot <- cloneTestProject("sated") init(enter = FALSE, projRoot, options = list(local.repos = "packages"), infer.dependencies=FALSE) lib <- libDir(projRoot) expect_true(file.exists(lockFilePath(projRoot))) expect_true(file.exists(srcDir(projRoot))) expect_true(file.exists(libDir(projRoot))) expect_false(file.exists(file.path(lib, "breakfast"))) expect_false(file.exists(file.path(lib, "bread"))) expect_false(file.exists(file.path(lib, "oatmeal"))) expect_true(file.exists(file.path(lib, "packrat"))) expect_false(file.exists(file.path(lib, "toast"))) }) test_that("restore ignores dirty packages", { skip_on_cran() projRoot <- cloneTestProject("carbs") lib <- libDir(projRoot) init(projRoot, options = list(local.repos = "packages"), enter = FALSE) expect_true(file.exists(file.path(lib, "bread"))) installTestPkg("oatmeal", "1.0.0", lib) expect_true(file.exists(file.path(lib, "oatmeal"))) restore(projRoot, prompt = FALSE, restart = FALSE) expect_true(file.exists(file.path(lib, "oatmeal"))) }) test_that("restore installs missing packages", { skip_on_cran() projRoot <- cloneTestProject("carbs") lib <- libDir(projRoot) init(enter = FALSE, projRoot, options = list(local.repos = "packages")) expect_true(file.exists(file.path(lib, "bread"))) # Remove a used package and restore remove.packages("bread", lib = lib) expect_false(file.exists(file.path(lib, "bread"))) restore(projRoot, prompt = FALSE, restart = FALSE) expect_true(file.exists(file.path(lib, "bread"))) }) test_that("snapshot captures new dependencies", { skip_on_cran() projRoot <- cloneTestProject("healthy") lib <- libDir(projRoot) init(enter = FALSE, projRoot, options = list(local.repos = "packages")) # Simulate the addition of a dependency expect_false(file.exists(file.path(lib, "bread"))) expect_false(file.exists(file.path(lib, "toast"))) installTestPkg("bread", "1.0.0", lib) addTestDependency(projRoot, "toast") # toast depends on bread expect_true(file.exists(file.path(lib, "bread"))) # Snapshot the new state and make sure we picked up both toast and its # dependency, bread pkgs <- pkgNames(lockInfo(projRoot)) expect_false("bread" %in% pkgs) expect_false("toast" %in% pkgs) snapshot(projRoot) pkgs <- pkgNames(lockInfo(projRoot)) expect_true("bread" %in% pkgs) expect_true("toast" %in% pkgs) }) test_that("snapshot captures new installed dependecies but not inferred dependencies when infer.dependencies is FALSE", { skip_on_cran() projRoot <- cloneTestProject("healthy") lib <- libDir(projRoot) init(enter = FALSE, projRoot, options = list(local.repos = "packages")) # Simulate the addition of a dependency expect_false(file.exists(file.path(lib, "bread"))) expect_false(file.exists(file.path(lib, "toast"))) installTestPkg("bread", "1.0.0", lib) addTestDependency(projRoot, "toast") # toast depends on bread expect_true(file.exists(file.path(lib, "bread"))) # Snapshot the new state and make sure we picked up both toast and its # dependency, bread pkgs <- pkgNames(lockInfo(projRoot)) expect_false("bread" %in% pkgs) expect_false("toast" %in% pkgs) snapshot(projRoot, infer.dependencies = FALSE) pkgs <- pkgNames(lockInfo(projRoot)) expect_true("bread" %in% pkgs) expect_false("toast" %in% pkgs) }) test_that("dependencies in library directories are ignored", { skip_on_cran() makeLibrariesProject() projRoot <- cloneTestProject("libraries") lib <- libDir(projRoot) init(enter = FALSE, projRoot, options = list(local.repos = "packages")) # This test project has a file called library.R that depends on bread, and # three .R files inside library/, library.old/, and library.new/ that # depend on oatmeal. expect_true(file.exists(file.path(lib, "bread"))) expect_false(file.exists(file.path(lib, "oatmeal"))) }) test_that("dependencies in \"ignored.directories\" are ignored", { skip_on_cran() projRoot <- cloneTestProject("partlyignored") lib <- libDir(projRoot) init(enter = FALSE, projRoot, options = list(ignored.directories="ignoreme")) # This test project has a file called notignored.R that depends on bread, and # another file called ignoreme/ignorethis.R that depends on toast. expect_true(file.exists(file.path(lib, "bread"))) expect_false(file.exists(file.path(lib, "toast"))) }) test_that("clean removes libraries and sources", { skip_on_cran() projRoot <- cloneTestProject("smallbreakfast") lib <- libDir(projRoot) src <- srcDir(projRoot) init(enter = FALSE, projRoot, options = list(local.repos = "packages")) expect_true(file.exists(file.path(lib, "bread"))) expect_true(file.exists(file.path(lib, "oatmeal"))) expect_true(file.exists(file.path(src, "bread"))) expect_true(file.exists(file.path(src, "oatmeal"))) # Remove the dependency on oatmeal and clean removeTestDependencyFile(projRoot, "oatmeal.R") clean("oatmeal", project = projRoot) # bread should still be present, but we should have removed the orphaned # package oatmeal expect_true(file.exists(file.path(lib, "bread"))) expect_false(file.exists(file.path(lib, "oatmeal"))) expect_true(file.exists(file.path(src, "bread"))) expect_false(file.exists(file.path(src, "oatmeal"))) }) test_that("init works with multiple repos", { skip_on_cran() repos <- getOption("repos") pkgType <- getOption("pkgType") on.exit({ options("repos" = repos) options("pkgType" = pkgType) }, add = TRUE) options(repos = c(CRAN = getOption("repos"), custom = getOption("repos"))) projRoot <- cloneTestProject("empty") init(enter = FALSE, projRoot, options = list(local.repos = "packages")) }) test_that("fileDependencies.R picks up '::', ':::' dependencies", { file <- tempfile() cat("library('baz')\nlibrary('bat')\nstringr::foo(1)\nKmisc::enumerate(2)\nfunction() {{plyr::bar(plyr::baz(1, 2))}}\n", file = file) on.exit(unlink(file)) deps <- fileDependencies.R(file) expect_identical( intersect(deps, c("baz", "bat", "stringr", "Kmisc", "plyr")), union(deps, c("baz", "bat", "stringr", "Kmisc", "plyr")) ) }) test_that("init, disable handle projects that have been initted / disabled sensibly", { skip_on_cran() skip_on_os("windows") projRoot <- cloneTestProject("sated") packrat::init(enter = FALSE, projRoot, options = list(local.repos = "packages")) list.files(projRoot, all.files = TRUE, recursive = TRUE) expect_true(file.exists(file.path(projRoot, ".Rprofile"))) packrat::disable(projRoot, restart = FALSE) expect_false(file.exists(file.path(projRoot, ".Rprofile"))) unlink(projRoot, recursive = TRUE) projRoot <- cloneTestProject("sated") text <- "## Some comments\n## That should be preserved\n" cat(text, file = file.path(projRoot, ".Rprofile")) packrat::init(enter = FALSE, projRoot, options = list(local.repos = "packages")) list.files(projRoot, all.files = TRUE, recursive = TRUE) expect_true(file.exists(file.path(projRoot, ".Rprofile"))) content <- readLines(file.path(projRoot, ".Rprofile")) expect_true(grepl(text, paste(content, collapse = "\n"))) packrat::disable(projRoot, restart = FALSE) path <- file.path(projRoot, ".Rprofile") expect_true(file.exists(path)) if (file.exists(path)) { content <- readChar(path, file.info(path)$size, TRUE) expect_true(grepl(text, paste(content, collapse = "\n"))) } unlink(projRoot, recursive = TRUE) ## Empty .Rprofile projRoot <- cloneTestProject("sated") file.create(file.path(projRoot, ".Rprofile")) packrat::init(enter = FALSE, projRoot, options = list(local.repos = "packages")) expect_true(file.exists(file.path(projRoot, ".Rprofile"))) content <- readLines(file.path(projRoot, ".Rprofile")) packrat::disable(projRoot, restart = FALSE) expect_false(file.exists(file.path(projRoot, ".Rprofile"))) }) test_that("status does not fail", { skip_on_cran() projRoot <- cloneTestProject("sated") init(enter = FALSE, projRoot, options = list(local.repos = "packages")) status(projRoot) unlink(file.path(projRoot, "packrat/lib/x86_64-apple-darwin13.3.0/3.2.0/bread"), recursive = TRUE) status(projRoot) unlink(file.path(projRoot, "packrat/lib/x86_64-apple-darwin13.3.0/3.2.0/breakfast"), recursive = TRUE) status(projRoot) # Try removing an item from the lockfile lf <- readLines(lockFilePath(projRoot)) blanks <- which(lf == "") breakfastStart <- grep("Package:\\s*breakfast", lf) breakfastEnd <- sort(blanks[blanks > breakfastStart])[1] lf <- lf[-c(breakfastStart:breakfastEnd)] cat(lf, file = lockFilePath(projRoot), sep = "\n") status(projRoot) }) test_that("hash does not fail if LinkingTo packages are not available", { skip_on_cran() expect_warning(hash("packages/egg/DESCRIPTION")) }) test_that("snapshot succeeds with an empty DESCRIPTION", { skip_on_cran() projRoot <- cloneTestProject("emptydesc") .snapshotImpl(projRoot, implicit.packrat.dependency = FALSE, snapshot.sources = FALSE) }) }) packrat/tests/testthat/test-utils.R0000644000176200001440000000351313352207316017145 0ustar liggesuserscontext("utils") emit <- function(x) cat(x, sep = "\n") test_that("dir_copy copies directories", { # Work in temporary directory owd <- getwd() on.exit(setwd(owd)) setwd(tempdir()) # Create a directory and try to copy it dir.create("foo") file.create("foo/foo1.R") file.create("foo/foo2.R") file.create("foo/foo3.R") file.create("foo/.dotFile") dir_copy("foo", "bar", overwrite = TRUE) expect_identical( list.files("foo"), list.files("bar") ) expect_error(dir_copy("foo", "bar")) }) test_that("defer evaluates in appropriate environment", { foo <- function() { emit("+ foo") defer(emit("> foo"), environment()) defer(emit("> foo.parent"), parent.frame(1)) defer(emit("> foo.parent.parent"), parent.frame(2)) emit("- foo") } bar <- function() { emit("+ bar") foo() emit("- bar") } baz <- function() { emit("+ baz") bar() emit("- baz") } output <- capture.output(baz()) expected <- c( "+ baz", "+ bar", "+ foo", "- foo", "> foo", "- bar", "> foo.parent", "- baz", "> foo.parent.parent" ) expect_identical(output, expected) }) test_that("defer captures arguments properly", { foo <- function(x) { defer(emit(x), envir = parent.frame()) } bar <- function(y) { emit("+ bar") foo(y) emit("- bar") } output <- capture.output(bar("> foo")) expected <- c("+ bar", "- bar", "> foo") expect_identical(output, expected) }) test_that("defer works with arbitrary expressions", { foo <- function(x) { defer({ x + 1 emit("> foo") }, envir = parent.frame()) } bar <- function() { emit("+ bar") foo(1) emit("- bar") } output <- capture.output(bar()) expected <- c("+ bar", "- bar", "> foo") expect_identical(output, expected) }) packrat/tests/testthat/projects/0000755000176200001440000000000013372654033016540 5ustar liggesuserspackrat/tests/testthat/projects/empty/0000755000176200001440000000000013352207316017672 5ustar liggesuserspackrat/tests/testthat/projects/empty/empty.R0000644000176200001440000000000013352207316021141 0ustar liggesuserspackrat/tests/testthat/projects/emptydesc/0000755000176200001440000000000013352207316020531 5ustar liggesuserspackrat/tests/testthat/projects/emptydesc/app.R0000644000176200001440000000001613352207316021431 0ustar liggesusers# empty app.R packrat/tests/testthat/projects/emptydesc/DESCRIPTION0000644000176200001440000000000013352207316022225 0ustar liggesuserspackrat/tests/testthat/projects/carbs/0000755000176200001440000000000013352207316017626 5ustar liggesuserspackrat/tests/testthat/projects/carbs/flour.R0000644000176200001440000000002013352207316021070 0ustar liggesuserslibrary(bread) packrat/tests/testthat/projects/smallbreakfast/0000755000176200001440000000000013352207316021527 5ustar liggesuserspackrat/tests/testthat/projects/smallbreakfast/oatmeal.R0000644000176200001440000000002213352207316023266 0ustar liggesuserslibrary(oatmeal) packrat/tests/testthat/projects/smallbreakfast/bread.R0000644000176200001440000000002013352207316022717 0ustar liggesuserslibrary(bread) packrat/tests/testthat/projects/sated/0000755000176200001440000000000013352207316017634 5ustar liggesuserspackrat/tests/testthat/projects/sated/sated.R0000644000176200001440000000002413352207316021053 0ustar liggesuserslibrary(breakfast) packrat/tests/testthat/projects/healthy/0000755000176200001440000000000013352207316020172 5ustar liggesuserspackrat/tests/testthat/projects/healthy/healthy.R0000644000176200001440000000002213352207316021745 0ustar liggesuserslibrary(oatmeal) packrat/tests/testthat/projects/libraries/0000755000176200001440000000000013372654033020514 5ustar liggesuserspackrat/tests/testthat/projects/libraries/packrat/0000755000176200001440000000000013372655524022147 5ustar liggesuserspackrat/tests/testthat/projects/libraries/packrat/library.new/0000755000176200001440000000000013372654033024375 5ustar liggesuserspackrat/tests/testthat/projects/libraries/packrat/library.new/lib-new.R0000644000176200001440000000002113372654033026046 0ustar liggesuserslibrary(oatmeal) packrat/tests/testthat/projects/libraries/packrat/lib/0000755000176200001440000000000013372654033022707 5ustar liggesuserspackrat/tests/testthat/projects/libraries/packrat/lib/lib-current.R0000644000176200001440000000002113372654033025251 0ustar liggesuserslibrary(oatmeal) packrat/tests/testthat/projects/libraries/library.R0000644000176200001440000000001713372654033022301 0ustar liggesuserslibrary(bread) packrat/tests/testthat/projects/partlyignored/0000755000176200001440000000000013352207316021417 5ustar liggesuserspackrat/tests/testthat/projects/partlyignored/ignoreme/0000755000176200001440000000000013352207316023224 5ustar liggesuserspackrat/tests/testthat/projects/partlyignored/ignoreme/ignorethis.R0000644000176200001440000000001713352207316025520 0ustar liggesuserslibrary(toast) packrat/tests/testthat/projects/partlyignored/notignored.R0000644000176200001440000000001713352207316023710 0ustar liggesuserslibrary(bread) packrat/tests/testthat/test-shiny.R0000644000176200001440000000141513352207316017136 0ustar liggesuserscontext("Shiny") test_that("projects which use shiny implicitly are detected", { skip_on_cran() # Try checking to see if packrat believes all example shiny apps # are, in fact, shiny apps options(repos = c(CRAN = "https://cran.rstudio.org")) if ("shiny" %in% rownames(installed.packages())) { examplesPath <- system.file("examples", package = "shiny") apps <- list.files(examplesPath, full.names = TRUE) for (app in apps) { expect_true("shiny" %in% packrat:::appDependencies(app)) } } # Check that 'shiny' is listed as a dependency for an # R Markdown document with 'runtime: shiny' interactiveDocPath <- file.path("resources", "interactive-doc-example.Rmd") expect_true("shiny" %in% packrat:::fileDependencies(interactiveDocPath)) }) packrat/tests/testthat/test-with_extlib.R0000644000176200001440000000153413372654577020351 0ustar liggesuserscontext("extlib without packages") test_that("with_extlib successfully works with no packages provided", { skip_on_cran() ## Make sure packrat mode is off if (packrat:::isPackratModeOn()) packrat::off() orig_libs <- packrat:::getLibPaths() .libPaths(c(file.path(getwd(), "packages"), orig_libs)) on.exit(.libPaths(orig_libs), add = TRUE) expect_identical(packageVersion("bread"), package_version("1.0.0")) # don't use packrat::on so we can avoid the initialization step packrat:::setPackratModeOn(auto.snapshot = FALSE, clean.search.path = FALSE) # Wildcard the quotes around 'bread'; newer versions of R emit "smart" quotes. expect_error(packageVersion("bread"), "package .bread. not found", perl = TRUE) expect_identical(packrat::with_extlib(expr = packageVersion("bread")), package_version("1.0.0")) packrat::off() }) packrat/tests/testthat/test-packrat-mode.R0000644000176200001440000000075513352207316020361 0ustar liggesuserscontext("packrat mode") test_that("packrat_mode successfully sets the library paths when turned on and off", { with_dir(tempdir(), { ## Make sure packrat mode is off if (packrat:::isPackratModeOn()) packrat::off() orig_libs <- getLibPaths() # don't use packrat::on so we can avoid the initialization step packrat:::setPackratModeOn(auto.snapshot = FALSE, clean.search.path = FALSE) packrat::off() expect_identical(orig_libs, getLibPaths()) }) }) packrat/tests/testthat/test-cache.R0000644000176200001440000000764313352207316017060 0ustar liggesuserscontext("Cache") # https://github.com/rstudio/packrat/issues/345 test_that("package installation when configured with a a cache uses the cache", { skip_on_cran() skip_on_os("windows") scopeTestContext() projRoot <- cloneTestProject("healthy") libRoot <- file.path(projRoot, "packrat", "lib") srcRoot <- file.path(projRoot, "packrat", "src") theCache <- tempfile("packrat-cache-") ensureDirectory(theCache) Sys.setenv(R_PACKRAT_CACHE_DIR = theCache) on.exit(Sys.unsetenv("R_PACKRAT_CACHE_DIR"), add = TRUE) init(projRoot, options = list(local.repos = "packages"), enter = FALSE) rv <- R.Version() packageDir <- file.path(libDir(projRoot), "oatmeal") expect_true(file.exists(packageDir), packageDir) expect_false(is.symlink(packageDir), packageDir) set_opts(project = projRoot, use.cache = TRUE) on.exit(set_opts(use.cache = FALSE, project = projRoot), add = TRUE) options(packrat.verbose.cache = TRUE) on.exit(options(packrat.verbose.cache = FALSE), add = TRUE) # Initial restore. Populates the cache and creates a symlink into it. unlink(libRoot, recursive = TRUE) unlink(srcRoot, recursive = TRUE) restore(projRoot, overwrite.dirty = TRUE, prompt = FALSE, restart = FALSE) expect_true(file.exists(packageDir), packageDir) expect_true(is.symlink(packageDir), packageDir) # Subsequent restore. Uses the cache. unlink(libRoot, recursive = TRUE) unlink(srcRoot, recursive = TRUE) restore(projRoot, overwrite.dirty = TRUE, prompt = FALSE, restart = FALSE) # Daisy-chain a test where we attempt to recover when # a cache entry is corrupt. This test models some real-life # situations we've seen where a cache's package entries seem # to lose all files except for an empty DESCRIPTION. pkgDir <- file.path(libDir(projRoot), "oatmeal") cacheEntry <- system(paste("readlink", pkgDir), intern = TRUE) unlink(cacheEntry, recursive = TRUE) ensureDirectory(cacheEntry) file.create(file.path(cacheEntry, "DESCRIPTION")) unlink(libRoot, recursive = TRUE) unlink(srcRoot, recursive = TRUE) restore(projRoot, overwrite.dirty = TRUE, prompt = FALSE, restart = FALSE) expect_true(file.exists(packageDir), packageDir) expect_true(is.symlink(packageDir), packageDir) }) test_that("packrat uses the untrusted cache when instructed", { skip_on_cran() skip_on_os("windows") scopeTestContext() # pretend that we're RStudio Connect Sys.setenv(RSTUDIO_CONNECT = 1) on.exit(Sys.unsetenv("RSTUDIO_CONNECT"), add = TRUE) projRoot <- cloneTestProject("healthy") libRoot <- file.path(projRoot, "packrat", "lib") srcRoot <- file.path(projRoot, "packrat", "src") theCache <- tempfile("packrat-cache-") ensureDirectory(theCache) Sys.setenv(R_PACKRAT_CACHE_DIR = theCache) on.exit(Sys.unsetenv("R_PACKRAT_CACHE_DIR"), add = TRUE) init(projRoot, options = list(local.repos = "packages"), enter = FALSE) rv <- R.Version() packageDir <- file.path(libDir(projRoot), "oatmeal") expect_true(file.exists(packageDir), packageDir) expect_false(is.symlink(packageDir), packageDir) set_opts(project = projRoot, use.cache = TRUE) on.exit(set_opts(use.cache = FALSE, project = projRoot), add = TRUE) options(packrat.verbose.cache = TRUE) on.exit(options(packrat.verbose.cache = FALSE), add = TRUE) # Initial restore. Populates the cache and creates a symlink into it. unlink(libRoot, recursive = TRUE) restore(projRoot, overwrite.dirty = TRUE, prompt = FALSE, restart = FALSE) expect_true(file.exists(packageDir), packageDir) expect_true(is.symlink(packageDir), packageDir) # Subsequent restore. Uses the cache. unlink(libRoot, recursive = TRUE) restore(projRoot, overwrite.dirty = TRUE, prompt = FALSE, restart = FALSE) expect_true(file.exists(packageDir), packageDir) expect_true(is.symlink(packageDir), packageDir) }) packrat/tests/testthat/test-git.R0000644000176200001440000000072213352207316016567 0ustar liggesuserscontext("git") test_that("isGitProject identifies projects as sub-directories of git-managed folders as git projects", { skip_on_cran() dir <- file.path(tempdir(), "test-packrat-git") subdir <- file.path(dir, "subdir") dir.create(subdir, recursive = TRUE) dir.create(file.path(dir, ".git")) expect_true(isGitProject(dir)) expect_true(isGitProject(subdir)) expect_false(isGitProject(tempdir())) unlink(dir, recursive = TRUE) }) packrat/tests/testthat/test-hash.R0000644000176200001440000000135013352207316016725 0ustar liggesuserscontext("hash") test_that("we can hash packages containing multiple packages in LinkingTo", { skip_on_cran() path <- system.file("DESCRIPTION", package = "Rclusterpp") if (file.exists(path)) { hash(path) } }) test_that("hash function is available and has expected arguments", { skip_on_cran() # This test is a canary that you may be breaking compatibility with Connect, # which expects this non-exported function to be present. That's not to say # the function signature can't be changed, only that the relevant call in # Connect's packrat_restore.R should be studied to avoid any breakage. expect_identical( formals(hash), pairlist(path = quote(expr =), descLookup = as.name("installedDescLookup")) ) }) packrat/tests/testthat/test-local-repositories.R0000644000176200001440000000151713352207316021626 0ustar liggesuserscontext("Local Repositories") withTestContext({ test_that("init fails when package not found in any repo", { projRoot <- cloneTestProject("sated") repos <- getOption("repos") options(repos = c(CRAN = paste0("file:///", normalizePath("repo-empty")))) ## we expect a warning signalling that the package 'breakfast' is not found ## in a repo or locally expect_error(suppressWarnings(init(enter = FALSE, projRoot))) options(repos = repos) }) test_that("install_local fails if no repository has been defined", { expect_error(install_local("foo")) }) test_that("packrat::get_opts can read / write atrocious paths", { path <- list.files(pattern = "^Ugly") with_dir(tempdir(), { opts$local.repos(path) readPath <- opts$local.repos() expect_identical(path, readPath) }) }) }) packrat/tests/testthat/test-github.R0000644000176200001440000000076313352207316017273 0ustar liggesuserscontext("GitHub") test_that("we can use devtools:::download to retrieve GitHub archives", { skip("run manually for now") if (!canUseGitHubDownloader()) skip("requires devtools") url <- "https://api.github.com/repos/rstudio/packrat/tarball/cd0f9a4dae7ea0c79966b6784b44d7e4e4edadad" destination <- tempfile("packrat-test-gh-", fileext = ".tar.gz") result <- githubDownload(url, destination) expect_true(result == 0) expect_true(file.exists(destination)) unlink(destination) }) packrat/tests/testthat/resources/0000755000176200001440000000000013372654061016722 5ustar liggesuserspackrat/tests/testthat/resources/params-example.Rmd0000644000176200001440000000030213352207316022270 0ustar liggesusers--- title: "Rmd with parameters" params: whack: !r stringr::word("the quick brown fox jumped over the lazy dog", 2) --- This is an example document using parameters. ```{r} params$whack ``` packrat/tests/testthat/resources/evaluate-deps.Rmd0000644000176200001440000000021113352207316022112 0ustar liggesusers--- title: Hello, world! --- ```{r} library(abc) library(def) ``` ```{r eval=FALSE} x + {}} ``` ```{r} library(ghi) library(jkl) ``` packrat/tests/testthat/resources/interactive-doc-example.Rmd0000644000176200001440000000403713352207316024076 0ustar liggesusers--- title: "Untitled" runtime: shiny output: html_document --- This R Markdown document is made interactive using Shiny. Unlike the more traditional workflow of creating static reports, you can now create documents that allow your readers to change the assumptions underlying your analysis and see the results immediately. To learn more, see [Interactive Documents](https://rmarkdown.rstudio.com/authoring_shiny.html). ## Inputs and Outputs You can embed Shiny inputs and outputs in your document. Outputs are automatically updated whenever inputs change. This demonstrates how a standard R plot can be made interactive by wrapping it in the Shiny `renderPlot` function. The `selectInput` and `sliderInput` functions create the input widgets used to drive the plot. ```{r, echo=FALSE} inputPanel( selectInput("n_breaks", label = "Number of bins:", choices = c(10, 20, 35, 50), selected = 20), sliderInput("bw_adjust", label = "Bandwidth adjustment:", min = 0.2, max = 2, value = 1, step = 0.2) ) renderPlot({ hist(faithful$eruptions, probability = TRUE, breaks = as.numeric(input$n_breaks), xlab = "Duration (minutes)", main = "Geyser eruption duration") dens <- density(faithful$eruptions, adjust = input$bw_adjust) lines(dens, col = "blue") }) ``` ## Embedded Application It's also possible to embed an entire Shiny application within an R Markdown document using the `shinyAppDir` function. This example embeds a Shiny application located in another directory: ```{r, echo=FALSE} shinyAppDir( system.file("examples/06_tabsets", package="shiny"), options=list( width="100%", height=550 ) ) ``` Note the use of the `height` parameter to determine how much vertical space the embedded application should occupy. You can also use the `shinyApp` function to define an application inline rather then in an external directory. In all of R code chunks above the `echo = FALSE` attribute is used. This is to prevent the R code within the chunk from rendering in the document alongside the Shiny components. packrat/tests/testthat/resources/knitr-minimal.Rnw0000644000176200001440000000330713352207316022163 0ustar liggesusers%% LyX 2.0.3 created this file. For more info, see https://www.lyx.org/. %% Do not edit unless you really know what you are doing. \documentclass{article} \usepackage[sc]{mathpazo} \usepackage[T1]{fontenc} \usepackage{geometry} \geometry{verbose,tmargin=2.5cm,bmargin=2.5cm,lmargin=2.5cm,rmargin=2.5cm} \setcounter{secnumdepth}{2} \setcounter{tocdepth}{2} \usepackage{url} \usepackage[unicode=true,pdfusetitle, bookmarks=true,bookmarksnumbered=true,bookmarksopen=true,bookmarksopenlevel=2, breaklinks=false,pdfborder={0 0 1},backref=false,colorlinks=false] {hyperref} \hypersetup{ pdfstartview={XYZ null null 1}} \begin{document} <>= library(knitr) # set global chunk options opts_chunk$set(fig.path='figure/minimal-', fig.align='center', fig.show='hold') options(replace.assign=TRUE,width=90) @ \title{A Minimal Demo of knitr} \author{Yihui Xie} \maketitle You can test if \textbf{knitr} works with this minimal demo. OK, let's get started with some boring random numbers: <>= set.seed(1121) (x=rnorm(20)) mean(x);var(x) @ The first element of \texttt{x} is \Sexpr{x[1]}. Boring boxplots and histograms recorded by the PDF device: <>= ## two plots side by side (option fig.show='hold') par(mar=c(4,4,.1,.1),cex.lab=.95,cex.axis=.9,mgp=c(2,.7,0),tcl=-.3,las=1) boxplot(x) hist(x,main='') @ Do the above chunks work? You should be able to compile the \TeX{} document and get a PDF file like this one: \url{https://bitbucket.org/stat/knitr/downloads/knitr-minimal.pdf}. The Rnw source of this document is at \url{https://github.com/yihui/knitr/blob/master/inst/examples/knitr-minimal.Rnw}. \end{document} packrat/tests/testthat/resources/test-sweave.Rnw0000644000176200001440000000021113352207316021646 0ustar liggesusers\documentclass{article} \begin{document} \SweaveOpts{concordance=TRUE} <<>>= library(digest) library(Rcpp) @ <<>>= @ \end{document} packrat/tests/testthat/resources/emoji.Rmd0000644000176200001440000000013513352207316020463 0ustar liggesusers--- title: "missing package reference" output: html_document --- `r emo::ji("see_no_evil")` packrat/tests/testthat/resources/alternate-engines.Rmd0000644000176200001440000000031013352207316022760 0ustar liggesusers--- title: "Untitled" output: html_document --- ```{bash} echo "Shell we play a game?" ``` ```{r} library(testthat) print("This code relies on testthat.") ``` ```{bash} echo "I shell return." ``` packrat/tests/testthat/resources/no-chunks.Rmd0000644000176200001440000000023613352207316021267 0ustar liggesusers--- title: "No Chunks" output: html_document --- This R Markdown document does not have any chunks in it. It might as well be an ordinary Markdown document. packrat/tests/testthat/test-bitbucket.R0000644000176200001440000000103513352207316017756 0ustar liggesuserscontext("Bitbucket") test_that("we can use devtools:::download to retrieve Bitbucket archives", { skip("run manually for now") if (!canUseBitbucketDownloader()) skip("requires devtools") url <- "https://bitbucket.org/mariamedp/packrat-test-pkg/get/5a6b90280c5fec133efb88aec95014d4f9aef80f.tar.gz" destination <- tempfile("packrat-test-bitbucket-", fileext = ".tar.gz") result <- bitbucketDownload(url, destination) expect_true(result == 0) expect_true(file.exists(destination)) unlink(destination) }) packrat/tests/testthat/lockfiles/0000755000176200001440000000000013352207316016656 5ustar liggesuserspackrat/tests/testthat/lockfiles/lockfile-multipleRepos.txt0000644000176200001440000000065613352207316024060 0ustar liggesusersPackratFormat: 1.3 PackratVersion: 0.2.0.108 RVersion: 3.2.0 Repos: CRAN=https://cran.rstudio.org, BioCsoft=https://bioconductor.org/packages/3.0/bioc, BioCann=https://bioconductor.org/packages/3.0/data/annotation, BioCexp=https://bioconductor.org/packages/3.0/data/experiment, BioCextra=https://bioconductor.org/packages/3.0/extra Package: packrat Source: source Version: 0.2.0.108 SourcePath: /Users/kevin/git/packrat packrat/tests/testthat/test-downloader.R0000644000176200001440000000300613352207316020140 0ustar liggesuserscontext("Downloader") getAvailableDownloadMethods <- function() { if (is.windows()) { methods <- "internal" if (getRversion() >= "3.2") methods <- c(methods, "wininet") return(methods) } has <- function(program) { nzchar(Sys.which(program)[[1]]) } methods <- "internal" if (has("wget")) methods <- c(methods, "wget") if (has("curl")) methods <- c(methods, "curl") if (canUseLibCurlDownloadMethod()) methods <- c(methods, "libcurl") methods } test_that("404s are errors", { skip_on_cran() URL <- "https://cran.rstudio.com/no/such/file/here.txt" methods <- getAvailableDownloadMethods() destfile <- tempfile() on.exit(try(unlink(file), silent = TRUE), add = TRUE) for (method in methods) { expect_error( downloadFile(URL, destfile = destfile, method = method, quiet = TRUE), info = sprintf("(method = '%s')", method) ) } }) test_that("The same content is returned regardless of download method", { skip_on_cran() URL <- "https://cran.rstudio.org/src/base/AUTHORS" methods <- getAvailableDownloadMethods() methods <- setdiff(methods, "internal") contents <- lapply(methods, function(method) { path <- tempfile() on.exit(try(unlink(path), silent = TRUE), add = TRUE) downloadFile(URL, destfile = path, method = method, quiet = TRUE) readChar(path, file.info(path)$size, TRUE) }) expect_true( length(Reduce(unique, contents)) == 1, info = "various download methods retrieve exact same content" ) }) packrat/tests/testthat/packages/0000755000176200001440000000000013372653776016502 5ustar liggesuserspackrat/tests/testthat/packages/bread/0000755000176200001440000000000013352207316017536 5ustar liggesuserspackrat/tests/testthat/packages/bread/DESCRIPTION0000644000176200001440000000035713352207316021251 0ustar liggesusersPackage: bread Type: Package Version: 1.0.0 Repository: CRAN License: GPL Description: Packrat test package Title: Packrat test package Author: Anonymous Person Maintainer: Anonymous Person packrat/tests/testthat/packages/toast/0000755000176200001440000000000013352207316017613 5ustar liggesuserspackrat/tests/testthat/packages/toast/DESCRIPTION0000644000176200001440000000037713352207316021330 0ustar liggesusersPackage: toast Depends: bread Type: Package Version: 1.0.0 Repository: CRAN License: GPL Description: Packrat test package Title: Packrat test package Author: Anonymous Person Maintainer: Anonymous Person packrat/tests/testthat/packages/packrat/0000755000176200001440000000000013372653776020127 5ustar liggesuserspackrat/tests/testthat/packages/packrat/DESCRIPTION0000644000176200001440000000121413372653776021633 0ustar liggesusersPackage: packrat Type: Package Title: A Dependency Management System for Projects and their R Package Dependencies Version: 0.4.9-15 Author: Kevin Ushey, Jonathan McPherson, Joe Cheng, Aron Atkins, JJ Allaire Maintainer: Kevin Ushey Description: Manage the R packages your project depends on in an isolated, portable, and reproducible way. License: GPL-2 Depends: R (>= 3.0.0) Imports: tools, utils Suggests: testthat (>= 0.7), devtools, httr, knitr, rmarkdown URL: https://github.com/rstudio/packrat/ BugReports: https://github.com/rstudio/packrat/issues RoxygenNote: 6.1.0 Repository: CRAN packrat/tests/testthat/packages/breakfast/0000755000176200001440000000000013352207316020423 5ustar liggesuserspackrat/tests/testthat/packages/breakfast/DESCRIPTION0000644000176200001440000000041413352207316022130 0ustar liggesusersPackage: breakfast Type: Package Version: 1.0.0 Depends: oatmeal, toast Repository: CRAN License: GPL Description: Packrat test package Title: Packrat test package Author: Anonymous Person Maintainer: Anonymous Person packrat/tests/testthat/packages/oatmeal/0000755000176200001440000000000013352207316020103 5ustar liggesuserspackrat/tests/testthat/packages/oatmeal/DESCRIPTION0000644000176200001440000000036213352207316021612 0ustar liggesusersPackage: oatmeal Type: Package Version: 1.0.0 Repository: CRAN License: GPL Description: Packrat test package Title: Packrat test package Author: Anonymous Person Maintainer: Anonymous Person packrat/tests/testthat/packages/egg/0000755000176200001440000000000013352207316017223 5ustar liggesuserspackrat/tests/testthat/packages/egg/DESCRIPTION0000644000176200001440000000037613352207316020737 0ustar liggesusersPackage: bread Type: Package Version: 1.0.0 Repository: CRAN License: GPL Description: Packrat test package Title: Packrat test package Author: Anonymous Person Maintainer: Anonymous Person LinkingTo: yolk packrat/tests/testthat/test-dependencies.R0000644000176200001440000000324613352207316020436 0ustar liggesuserscontext("Dependencies") test_that("dependencies are properly resolved in expressions", { skip_on_cran() expr <- quote({ library(tools) library("utils") requireNamespace(quietly = TRUE, package = "knitr") # Don't trip up on 'library(x, character.only = TRUE)' for (x in 1:10) library(x, character.only = TRUE) "stats"::rnorm(1) setRefClass("foo", "bar") }) dependencies <- expressionDependencies(expr) expect_true(setequal( c("tools", "utils", "stats", "knitr", "methods"), dependencies )) }) test_that("dependencies are discovered in R Markdown documents using alternate engines", { skip_on_cran() altEngineRmd <- file.path("resources", "alternate-engines.Rmd") expect_true("testthat" %in% packrat:::fileDependencies(altEngineRmd)) }) test_that("dependencies are discovered in R Markdown documents with R chunks", { skip_on_cran() ordinaryRmd <- file.path("resources", "params-example.Rmd") expect_true("rmarkdown" %in% packrat:::fileDependencies(ordinaryRmd)) }) test_that("dependencies are discovered in R Markdown documents with no chunks", { skip_on_cran() chunklessRmd <- file.path("resources", "no-chunks.Rmd") expect_true("rmarkdown" %in% packrat:::fileDependencies(chunklessRmd)) }) test_that("dependencies are discovered in inline R code", { skip_on_cran() # ensure that we've restored 'inline_exec' properly at the end inline_exec <- yoink("knitr", "inline_exec") on.exit( expect_identical(inline_exec, yoink("knitr", "inline_exec")), add = TRUE ) # run the regular test emojiRmd <- file.path("resources", "emoji.Rmd") expect_true("emo" %in% packrat:::fileDependencies(emojiRmd)) }) packrat/tests/testthat/repo/0000755000176200001440000000000013372757542015665 5ustar liggesuserspackrat/tests/testthat/repo/src/0000755000176200001440000000000013372653776016460 5ustar liggesuserspackrat/tests/testthat/repo/src/contrib/0000755000176200001440000000000013372653776020120 5ustar liggesuserspackrat/tests/testthat/repo/src/contrib/bread/0000755000176200001440000000000013372653776021175 5ustar liggesuserspackrat/tests/testthat/repo/src/contrib/bread/bread_1.0.0.tar.gz0000644000176200001440000000040313372653776024112 0ustar liggesusers‹í’QKÃ0ÇûœO‘OPÓvm ˆX6‘Áœ¥–½gÝm†i®$W¡ßÞ´_DAÐéCîr¹ÿåOÈÖ‚Ú],næÕ²¬—÷ëàçžl6£ÌÒ1Šøm?¤2ˆ’$c!“( DK!.~ÁË:GÊz+GxÑæ‹>߶ߟÃÐy)UsTÈùvø¬î[ŸŸŠlÖi49B VA‹NÚ>çóªX³•nÀ8/¸-Wl®±º¥Q0L°Š8#ÞžÆÕšžà“³¢£G´9/ šþ;ÇK9~ù^¹¶ŽºÆíáŠÝ)mÈ/øŽˆýõsOLLLü^)¬eLpackrat/tests/testthat/repo/src/contrib/toast/0000755000176200001440000000000013372653776021252 5ustar liggesuserspackrat/tests/testthat/repo/src/contrib/toast/toast_1.0.0.tar.gz0000644000176200001440000000041313372653776024245 0ustar liggesusers‹í’ÑJÃ0†{§ÈÔ´Ý"–mÈ`ÎR‹÷±=›a3 ɩз7­ÃQt»éáœÿüù A#=^-W‹j]Öë‡mô÷°@>›•çó±²ôc?q%Y6OSƳ$X’ò<(û‡,_èxÓùuT¥Êx‰9ÞŠ9ºÄª’Z5]i|_vâÔ¦²PvõAÚ–áÚ’øïÌÍò”3…$LûPKò¡À~Û‹œ–V‰b<ÉÚK• vÜÒ›åõPtMqaKë۷0ò|Ï¿‹cCu:!c ×oÍŠTáĶÊXÙù˜Mnµù¾7½êBS|ü)1'²uÐê‡iÒRó¤Å}¼ ›˜Ò…ƒA¦(¯š NÍœîÇ@¼¯²;m¯œ«xà±ùVg¨×†¸ö‰x¾hXœ"cëfq´ÿú-\pÁüOøHºa packrat/tests/testthat/repo/src/contrib/PACKAGES.gz0000644000176200001440000000063413372653776021643 0ustar liggesusers‹’Kk1…÷ó+´lÀ4zËl(´˜¶d%]‡yÈÌÈ)ý÷ÛqíÇíJoïÜsWà[¨qI܈Šg§& KR•´¤ÅSãq˜æÓ/«§â냜¶ý|¼ Œ !MpL0ÇóÚ*AZÙâb˜>§~Ót÷¿ ©XA^UæÅ™jaÊï•pƒC˜–$AîºÉiwí"‘cÔ( ©¶ÎF£]àPHÉc>þ‹è@ð–êB-†¶êŸiI~§®½L"PЊjê¹SŽKœÖˆ‘Ù¹Pž^#Áº>cxõý_‰xT ¯m¥‹XŒŽ9…‚ËkªG“òfžŒp–-Eio+y å;ùtGøŽè¦xì7iÌónN©›d››n*~lë§ýö<ä5äýZê› øòzyó¸ íÐ솱‡± é×ðÆæ-ûk4VLíê]”–m8•„š‹.X°Õ5£G['£‡Žú¨ñMp9es¨œRDf(Æ7žJp ã úì…Ë?wpackrat/tests/testthat/repo/src/contrib/PACKAGES.rds0000644000176200001440000000114013372653776022004 0ustar liggesusersý7zXZi"Þ6!t/å£à}!],|ùŸø¦ð¡“>KÛcÞí@·¾‰5ÌçÁhð”ϯÿº0KJ¦ 2¤žº.ü†¸4Y`‚ÓÙ<Ї‡Ò’üV¹K> ñµÍåáÖK»”1¾º!‡!‹òÄ–JÒ,1¸’NÛSwùåÑþ«Î*¥•ȶmìç¼4JsÅûž° è QýÅá¼Ð¡‘_ÿŒuï<åysCO*g×ÕåÞ8‡â¥º›2Ù^è(ø9žúŸ‡Õo>>Šu³ÿ¥-@ ]ä0{‚øC‡€]´åt¾eYž¢Déœ(š-Iº-U¬5°k¢>ba#’õ®Lú!uÖÖvnÞ0]xœ?¶Ã3¶kº·H½€EyµNÓ3Öô¶šðOpV-VÈ„ÎÑÂé #´y½Aʺ®8`ý‰x#d6²ßÛt¯ÍƢ˸øY£x>õ’„ñߨ]œTwæv)Ÿp3Ü‘˜–tˆ(ëž+ÐáÔ¢}@†RÃFêbÇ—óé½Â°/Åùësİ˻²I±ãz1´ï€{Ñé ™ú2K—‰¡ ˆDS˜W' ñiCQÌF_I­|¶Ùe.R¹â±€Hë^d€Î”?¹þ P¨³d>0 ‹YZpackrat/tests/testthat/repo/src/contrib/PACKAGES0000644000176200001440000000156713372653776021232 0ustar liggesusersPackage: bread Version: 1.0.0 License: GPL MD5sum: 1dcbd204458db242b342c78405a68019 NeedsCompilation: no Path: bread Package: breakfast Version: 1.0.0 Depends: oatmeal, toast License: GPL MD5sum: b2086a4a5079b9f87bd37ae4553b22cf NeedsCompilation: no Path: breakfast Package: bread Version: 1.0.0 LinkingTo: yolk License: GPL MD5sum: a4d0a76070c3b6b356db77eef2942bc0 NeedsCompilation: no Path: egg Package: oatmeal Version: 1.0.0 License: GPL MD5sum: c2a0782daddc791662fca2ffb2b6e435 NeedsCompilation: no Path: oatmeal Package: packrat Version: 0.4.9-15 Depends: R (>= 3.0.0) Imports: tools, utils Suggests: testthat (>= 0.7), devtools, httr, knitr, rmarkdown License: GPL-2 MD5sum: f12642bcfbf5928783057a46d0a42d91 NeedsCompilation: no Path: packrat Package: toast Version: 1.0.0 Depends: bread License: GPL MD5sum: ace77e300ee298c4e520f89a38c05caa NeedsCompilation: no Path: toast packrat/tests/testthat/repo/src/contrib/breakfast/0000755000176200001440000000000013372653776022062 5ustar liggesuserspackrat/tests/testthat/repo/src/contrib/breakfast/breakfast_1.0.0.tar.gz0000644000176200001440000000042413372653776025667 0ustar liggesusers‹í’oKÃ0Æû:Ÿ"@júwPD,›È`ÎR‹ï³î:C·$$W¡ßÞ´N_© Œú¦?Çåî¹{ ÙàmÃ-^¯îŸ—庨ÖO[ï²0GÇc\¤ÉYø‘ÄAìQ”„![DAê± JÒÔ£ìÂ>¾¥³È³Ò›¿ô¹¶¦™Âд¼nù2ºûü¤êµËÏòÆ %3øÌgdäÞfTq<?^QTƒ¨­¬@eúŒ.Ë|K6¢iÝ ‡bãT¶6Bã8h˜l8R‹TŸ×TðC-ïðU™ŒæRÉþ¤:K gJIzóusg,v{¡|e·ä‘ ‰îÀ_D„ü÷[ÌÌÌÌLÉ;«ù¡±packrat/tests/testthat/repo/src/contrib/oatmeal/0000755000176200001440000000000013372653776021542 5ustar liggesuserspackrat/tests/testthat/repo/src/contrib/oatmeal/oatmeal_1.0.0.tar.gz0000644000176200001440000000040313372653776025024 0ustar liggesusers‹í’QKÃ0ÇûœO‘OPÓdí ˆX6‘Áœ¥–½‡z›a[®$W¡ßÞ¬>© ŒéCŽ»ÜÿîOj:€ÞßÌ^fÕ¢¬Ï«èÒˆ@6™ qš¥Cò”Q™Œ¥R)ÅT%Y$%Sqqq'_ÐyÒ.XÙÁ»±?ô…¶Í憮K©›ÞBÎñôXÝ·!;—Ùœ7hsžÄ"¬‚½!t}ÎgU±bKÓ€õAðX.Ù|ãLKƒà8Áiâžx{WÚÃ7wEGoèr^X´ý;Ï˰-¿ý¬Ü;OÝ«ÁÝöŽ=ic)øˆ±¿~ñ‘‘‘‘ÿÁœÑ¿ªpackrat/tests/testthat/repo/src/contrib/egg/0000755000176200001440000000000013372653776020662 5ustar liggesuserspackrat/tests/testthat/repo/src/contrib/egg/egg_1.0.0.tar.gz0000644000176200001440000000041313372653776023265 0ustar liggesusers‹íQKÃ0ÇûœO‘OPÓfm!ˆX6‘A¥–½ÇîVCg®$©ÐooV‡‚‚Û^úƒãr—û_þÚöfõð²¬Öe½~Þç€yÒÅbÊYšL™Å_õž¥AÄyÇ,ãQ°(æYPv7?¬“Æ[éàCé?æüØ~ C—¥”M'[ôՀܑzìýùÔ$[0V¡4 YÈH=ZåÐŒ‚.«|C Õ€¶^ðXd¶1ªw“à¸ÁHGXGûÓºZ¹ür—î  ¹F=¾ã`iéGMo¿;÷ƺa§0DÓÞ‘'©´óÿJwJ·5 :â¡#×þý™™™™ëñ ³j‰wpackrat/tests/testthat/test-bundle.R0000644000176200001440000000203113352207316017250 0ustar liggesuserscontext("Bundle") test_that("Bundle works when using R's internal tar", { skip_on_cran() skip_on_travis() scopeTestContext() # force packrat to use the internal R tar TAR <- Sys.getenv("TAR") Sys.unsetenv("TAR") on.exit(Sys.setenv(TAR = TAR), add = TRUE) # bundle with the regular bundle and verify bundle_test(packrat::bundle, function() { expect_identical( grep("lib*", list.files("packrat"), value = TRUE, invert = TRUE), list.files("untarred/packrat-test-bundle/packrat/") ) }) }) test_that("Bundle works when omitting CRAN packages", { skip_on_cran() skip_on_travis() scopeTestContext() checker <- function() { # we shouldn't see any CRAN packages in the unbundled sources srcDir <- "untarred/packrat-test-bundle/packrat/src" srcFiles <- list.files(srcDir, pattern = "tar.gz$", recursive = TRUE) cat(paste(srcFiles, collapse = "\n")) expect_true(length(srcFiles) == 0, "src dir should be empty") } bundle_test(packrat:::bundle, checker, omit.cran.src = TRUE) }) packrat/tests/testthat/test-ignores.R0000644000176200001440000000514713352207316017460 0ustar liggesuserscontext("ignores") test_that("updateRBuildIgnore adds the packrat directory to ignore", { path <- file.path(tempdir(), ".Rbuildignore") unlink(path) updateRBuildIgnore(project = tempdir()) content <- readLines(path) expect_identical(content, c("^packrat/", "^\\.Rprofile$")) unlink(path) }) test_that("updateRBuildIgnore preserves content in ignore file", { path <- file.path(tempdir(), ".Rbuildignore") unlink(path) cat(c("foo", "bar", "baz"), file = path, sep = "\n") updateRBuildIgnore(project = tempdir()) content <- readLines(path) expect_identical(content, c("foo", "bar", "baz", "^packrat/", "^\\.Rprofile$")) unlink(path) }) test_that("updateGitIgnore works", { options <- list( vcs.ignore.lib = TRUE, vcs.ignore.src = FALSE ) dir <- file.path(tempdir(), "packrat-test") .gitignore <- file.path(dir, ".gitignore") dir.create(dir) updateGitIgnore(project = dir, options = options) content <- readLines(.gitignore) expect_identical(content, "packrat/lib*/") ## idempotency updateGitIgnore(project = dir, options = options) content <- readLines(.gitignore) expect_identical(content, "packrat/lib*/") ## preserve content of a .gitignore unlink(.gitignore) cat(c("foo", "bar", "baz"), file = .gitignore, sep = "\n") updateGitIgnore(project = dir, options = options) content <- readLines(.gitignore) expect_true(all(c("foo", "bar", "baz", "packrat/lib*/") %in% content)) ## change options options$vcs.ignore.src <- TRUE updateGitIgnore(project = dir, options = options) content <- readLines(.gitignore) expect_true(all(c("foo", "bar", "baz", "packrat/lib*/", "packrat/src/") %in% content)) ## remove all options options[] <- FALSE updateGitIgnore(project = dir, options = options) content <- readLines(.gitignore) expect_true(all(c("foo", "bar", "baz") %in% content)) expect_false("packrat/lib*/" %in% content) expect_false("packrat/src/" %in% content) ## when all options FALSE and .gitignore does not already ## exist, .gitignore is not created. unlink(.gitignore) updateGitIgnore(project = dir, options = options) expect_false(file.exists(.gitignore)) unlink(dir, recursive = TRUE) }) test_that("updateIgnoreFile preserves old structure of file", { contents <- c( "# This is a comment.", "ignore/path", "", "# This is a comment.", "ignore/path" ) file <- tempfile() on.exit(unlink(file)) cat(contents, file = file, sep = "\n") updateIgnoreFile(project = tempdir(), file = basename(file), add = c("packrat/lib*/")) updated <- readLines(file) expect_identical(updated, c(contents, "packrat/lib*/")) }) packrat/tests/testthat/Ugly, but legal, path for a project (long)/0000755000176200001440000000000013352207316024150 5ustar liggesuserspackrat/tests/testthat/Ugly, but legal, path for a project (long)/bread/0000755000176200001440000000000013352207316025225 5ustar liggesuserspackrat/tests/testthat/Ugly, but legal, path for a project (long)/bread/DESCRIPTION0000644000176200001440000000035713352207316026740 0ustar liggesusersPackage: bread Type: Package Version: 1.0.0 Repository: CRAN License: GPL Description: Packrat test package Title: Packrat test package Author: Anonymous Person Maintainer: Anonymous Person packrat/tests/testthat/Ugly, but legal, path for a project (long)/toast/0000755000176200001440000000000013352207316025302 5ustar liggesuserspackrat/tests/testthat/Ugly, but legal, path for a project (long)/toast/DESCRIPTION0000644000176200001440000000037713352207316027017 0ustar liggesusersPackage: toast Depends: bread Type: Package Version: 1.0.0 Repository: CRAN License: GPL Description: Packrat test package Title: Packrat test package Author: Anonymous Person Maintainer: Anonymous Person packrat/tests/testthat/Ugly, but legal, path for a project (long)/packrat/0000755000176200001440000000000013352207316025575 5ustar liggesuserspackrat/tests/testthat/Ugly, but legal, path for a project (long)/packrat/DESCRIPTION0000644000176200001440000000036213352207316027304 0ustar liggesusersPackage: packrat Type: Package Version: 0.0.0 Repository: CRAN License: GPL Description: Packrat test package Title: Packrat test package Author: Anonymous Person Maintainer: Anonymous Person packrat/tests/testthat/Ugly, but legal, path for a project (long)/breakfast/0000755000176200001440000000000013352207316026112 5ustar liggesuserspackrat/tests/testthat/Ugly, but legal, path for a project (long)/breakfast/DESCRIPTION0000644000176200001440000000041413352207316027617 0ustar liggesusersPackage: breakfast Type: Package Version: 1.0.0 Depends: oatmeal, toast Repository: CRAN License: GPL Description: Packrat test package Title: Packrat test package Author: Anonymous Person Maintainer: Anonymous Person packrat/tests/testthat/Ugly, but legal, path for a project (long)/oatmeal/0000755000176200001440000000000013352207316025572 5ustar liggesuserspackrat/tests/testthat/Ugly, but legal, path for a project (long)/oatmeal/DESCRIPTION0000644000176200001440000000036213352207316027301 0ustar liggesusersPackage: oatmeal Type: Package Version: 1.0.0 Repository: CRAN License: GPL Description: Packrat test package Title: Packrat test package Author: Anonymous Person Maintainer: Anonymous Person packrat/tests/testthat/other-packages/0000755000176200001440000000000013352207316017600 5ustar liggesuserspackrat/tests/testthat/other-packages/packrat/0000755000176200001440000000000013352207316021225 5ustar liggesuserspackrat/tests/testthat/other-packages/packrat/DESCRIPTION0000644000176200001440000000036213352207316022734 0ustar liggesusersPackage: packrat Type: Package Version: 0.0.0 Repository: CRAN License: GPL Description: Packrat test package Title: Packrat test package Author: Anonymous Person Maintainer: Anonymous Person packrat/tests/testthat/test-rmarkdown.R0000644000176200001440000000161213352207316020007 0ustar liggesuserscontext("R Markdown") test_that("Rmd documents with parameters are analyzed", { skip_on_cran() # we need to skip this test if we don't have an up-to-date version of knitr available if (packageVersion("knitr") < "1.11") skip("requires knitr 1.11 or greater") parameterDocPath <- file.path("resources", "params-example.Rmd") deps <- packrat:::fileDependencies(parameterDocPath) expect_true("rmarkdown" %in% deps, "all Rmd docs have an rmarkdown dependency") expect_true("shiny" %in% deps, "Rmd docs with parameters have a shiny dependency for the customization app") expect_true("stringr" %in% deps, "dependencies in parameter expressions are extracted") }) test_that("We can discover dependencies with an evaluate hook", { skip_on_cran() path <- "resources/evaluate-deps.Rmd" deps <- fileDependencies.Rmd.evaluate(path) expect_equal(deps, c("abc", "def", "ghi", "jkl")) }) packrat/tests/testthat/repo-empty/0000755000176200001440000000000013352207316017004 5ustar liggesuserspackrat/tests/testthat/repo-empty/src/0000755000176200001440000000000013352207316017573 5ustar liggesuserspackrat/tests/testthat/repo-empty/src/contrib/0000755000176200001440000000000013352207316021233 5ustar liggesuserspackrat/tests/testthat/repo-empty/src/contrib/PACKAGES0000644000176200001440000000000013352207316022322 0ustar liggesuserspackrat/tests/testthat/test-lockfile.R0000644000176200001440000000166513352207316017603 0ustar liggesuserscontext("lockfile") test_that("Topo sort works", { # Good graph <- list( 'A' = c('B', 'C'), 'B' = c(), 'C' = c('B'), 'D' = c() ) expect_true(verifyTopoSort(graph, topoSort(graph))) # Bad: Circular graph bad.graph <- list( 'A' = c('B'), 'B' = c('C'), 'C' = c('A') ) expect_error(topoSort(bad.graph)) # Bad: Dependency that has no row bad.graph.2 <- list( 'A' = c('D') ) expect_error(topoSort(bad.graph.2)) }) test_that("Repository is properly split by readLockFile", { lf <- readLockFile("lockfiles/lockfile-multipleRepos.txt") expect_equal( lf$repos, c(CRAN = "https://cran.rstudio.org", BioCsoft = "https://bioconductor.org/packages/3.0/bioc", BioCann = "https://bioconductor.org/packages/3.0/data/annotation", BioCexp = "https://bioconductor.org/packages/3.0/data/experiment", BioCextra = "https://bioconductor.org/packages/3.0/extra" ) ) }) packrat/tests/test-all.R0000644000176200001440000000007113352207316014711 0ustar liggesuserslibrary(testthat) library(packrat) test_check("packrat") packrat/NAMESPACE0000644000176200001440000000146413372654401013130 0ustar liggesusers# Generated by roxygen2: do not edit by hand export(.snapshotImpl) export(bundle) export(bundles_dir) export(clean) export(disable) export(extlib) export(get_lockfile_metadata) export(get_opts) export(init) export(install) export(install_local) export(lib_dir) export(off) export(on) export(opts) export(packify) export(packrat_lib) export(packrat_mode) export(project_dir) export(repos_add) export(repos_add_local) export(repos_create) export(repos_list) export(repos_remove) export(repos_set) export(repos_set_local) export(repos_upload) export(restore) export(search_path) export(set_lockfile_metadata) export(set_opts) export(snapshot) export(src_dir) export(status) export(unbundle) export(unused_packages) export(user_lib) export(with_extlib) import(utils) importFrom(tools,md5sum) importFrom(tools,pkgVignettes) packrat/R/0000755000176200001440000000000013370077201012100 5ustar liggesuserspackrat/R/rstudio-protocol.R0000644000176200001440000000143513352207316015560 0ustar liggesusers# This package contains methods invoked by the RStudio IDE. If a breaking change # is made to the signature or behavior of these methods, bump this version to # prevent older versions of RStudio from attempting integration. # # Note that: # - RStudio uses the version number of the package to determine if the package # meets the minimum version requirement for integration (is the package too # old?), and this protocol number to determine the maximum version requirement # (is it too new?). # - Backwards compatibility is presumed: that is, if RStudio has protocol 3 and # the package has protocol 2, it is accepted. The package version number, not # the protocol version number, is used to determine whether the package is too # old to be compatible. .RStudio_protocol_version = 1 packrat/R/cranlike-repositories.R0000644000176200001440000002413313352207316016545 0ustar liggesusers#' Create a Local, CRAN-like Repository #' #' Generate a local CRAN-like repository which can be #' used to store and distribute \R packages. #' #' @param path Path to a local CRAN-like repository. #' @param name The name to assign to the repository. Defaults to the #' directory name in which the reopsitory is created. #' @param add Add this new repository to the current set of repositories? #' #' @export repos_create <- function(path, name = basename(path), add = TRUE) { if (file.exists(path)) stop("Path '", path, "' is not empty; cannot create ", "repository at this location", call. = FALSE) if (name %in% names(getOption("repos"))) stop("A repository named '", name, "' is already registered!") dir.create(path, recursive = TRUE) root <- normalize.path(path) # helper function for writing PACKAGES, PACKAGES.gz into a directory # (as tools::write_PACKAGES does nothing if the directory is empty) write_packages <- function(dir) { file.create(file.path(dir, "PACKAGES")) conn <- gzfile(file.path(dir, "PACKAGES.gz"), "wt") write.dcf(data.frame(), conn) close(conn) } ## Create the 'contrib' dirs # Create the 'src' dir and write PACKAGES srcContribDir <- file.path(root, "src", "contrib") dir.create(srcContribDir, recursive = TRUE) write_packages(srcContribDir) # Create the 'bin' dirs and write PACKAGES binContribDirs <- binContribDirs(root) lapply(binContribDirs, function(dirs) { lapply(dirs, function(dir) { dir.create(dir, recursive = TRUE) type <- if (grepl("/bin/windows/", dir)) "win.binary" else if (grepl("/bin/macosx/", dir)) "mac.binary" else "source" write_packages(dir) }) }) message("Local CRAN repository '", name, "' created at: ", "\n- ", shQuote(normalize.path(path))) URI <- paste(filePrefix(), root, sep = "") names(URI) <- name if (add) options(repos = c(getOption("repos"), URI)) URI } binContribDirs <- function(root, rVersions = NULL) { # Add a number of empty R-version folders by default, just # so that these versions of R don't fail when attempting to query # the PACKAGES file in the binary directory if (is.null(rVersions)) rVersions <- c("2.15", "2.16", "3.0", "3.1", "3.2", "3.3", "3.4", "3.5") list( win.binary = file.path(root, "bin/windows/contrib", rVersions), mac.binary = file.path(root, "bin/macosx/contrib", rVersions), mac.binary.mavericks = file.path(root, "bin/macosx/mavericks/contrib", rVersions), mac.binary.leopard = file.path(root, "bin/macosx/leopard/contrib", rVersions) ) } #' Upload a Package to a Local CRAN-like Repository #' #' @param package Path to a package tarball. The tarball should be #' created by \code{R CMD build}; alternatively, it can be the path #' to a folder containing the source code for a package (which #' will then be built with \code{R CMD build}) and then uploaded #' to the local repository. #' @param to The name of the CRAN-like repository. It (currently) must #' be a local (on-disk) CRAN repository. #' @param ... Optional arguments passed to \code{R CMD build}. #' @export repos_upload <- function(package, to, ...) { # validation if (!file.exists(package)) stop("no package named '", package, "'", call. = FALSE) if (is.directory(package) && !file.exists(file.path(package, "DESCRIPTION"))) stop("directory '", package, "' exists but contains no DESCRIPTION file", call. = FALSE) if (!(is.directory(package)) && !(grepl("\\.tar\\.gz$", package))) stop("file '", package, "' exists but is not appropriately named; ", "uploadable package tarballs are generated by `R CMD build`", call. = FALSE) if (!is.string(to)) stop("'to' should be a length-one character vector, naming ", "a repository available in 'getOption(\"repos\")'", call. = FALSE) repos <- getOption("repos") isNameOfRepo <- to %in% names(repos) isRepo <- to %in% repos if (!(isNameOfRepo || isRepo)) stop("no repository '", to, "' available; ", "try adding a repository with 'packrat::repos_create()'", call. = FALSE) if (isNameOfRepo) { repoName <- to repoPath <- repos[[repoName]] } else { repoName <- names(repos)[which(repos == to)] repoPath <- to } if (!grepl(reFilePrefix(), repoPath)) stop("packages can only be uploaded to local CRAN-like repositories with ", "this version of packrat", call. = FALSE) # perform upload if (is.directory(package)) uploadPackageSourceDir(package, repoName, repoPath, ...) else uploadPackageTarball(package, repoName, repoPath) } uploadPackageSourceDir <- function(package, repoName, repoPath, ...) { # create temporary directory for package randomString <- paste(sample(c(0:9, letters, LETTERS), 16, TRUE), collapse = "") dir <- file.path(tempdir(), paste(basename(package), randomString, sep = "-")) on.exit(unlink(dir, recursive = TRUE)) success <- dir_copy(package, dir, pattern = "^[^\\.]") if (!all(success)) stop("failed to copy package files to temporary directory") # Annotate the DESCRIPTION with the name of the repository we're # going to be uploading to descPath <- file.path(dir, "DESCRIPTION") setRepositoryField(descPath, repoName) path <- build(dir, ...) if (!file.exists(path)) stop("failed to build source package") contribUrl <- sub(reFilePrefix(), "", file.path(repoPath, "src", "contrib")) success <- file.copy( path, contribUrl ) if (!success) stop("failed to copy built package to CRAN repo '", repoName, "'") tools::write_PACKAGES(contribUrl, type = "source") message("Package '", basename(path), "' successfully uploaded.") file.path(contribUrl, basename(path)) } uploadPackageTarball <- function(package, repoName, repoPath, ...) { # Annotate the package DESCRIPTION with the repository tmpTarballPath <- file.path(tempdir(), "packrat-tarball-upload") untar(package, exdir = tmpTarballPath, tar = "internal") pkgName <- sub("_.*", "", basename(package)) untarredPath <- file.path(tmpTarballPath, pkgName) setRepositoryField( file.path(untarredPath, "DESCRIPTION"), repoName ) owd <- getwd() setwd(tmpTarballPath) on.exit(setwd(owd), add = TRUE) success <- tar( basename(package), files = pkgName, compression = "gzip", tar = "internal" ) if (success != 0) stop("Failed to re-tar package tarball") path <- normalize.path(basename(package)) contribUrl <- sub(reFilePrefix(), "", file.path(repoPath, "src", "contrib")) if (!file.copy(path, contribUrl, overwrite = TRUE)) stop("failed to upload package '", basename(package), "' to '", contribUrl, "'") tools::write_PACKAGES(contribUrl, type = "source") message("Package '", basename(path), "' successfully uploaded.") file.path(contribUrl, basename(path)) } addRepos <- function(repos, overwrite = FALSE, local = FALSE) { dots <- repos dotNames <- names(dots) if (!length(dotNames) || any(!nzchar(dotNames))) stop("all arguments should be named") # For local (on-disk) repositories, ensure that the paths # supplied do exist if (local) { missing <- unlist(lapply(dots, function(x) { !file.exists(x) })) if (any(missing)) stop("The following paths do not exist: \n- ", paste(shQuote(dots[missing]), collapse = "\n- ")) } oldRepos <- getOption("repos") if (!overwrite) { conflicts <- intersect(names(dots), names(oldRepos)) if (length(conflicts)) { quoted <- paste(shQuote(conflicts), " (", oldRepos[conflicts], ")", sep = "") stop("The following repositories have already been set.\n", "Use 'overwrite = TRUE' to override these repository paths.\n- ", paste(quoted, collapse = "\n- ")) } } URIs <- if (local) { paths <- normalizePath(unlist(dots), winslash = "/", mustWork = TRUE) paste(filePrefix(), paths, sep = "") } else { unlist(dots) } newRepos <- URIs names(newRepos) <- names(dots) repos <- c(oldRepos, newRepos) repos <- repos[!duplicated(repos)] options(repos = repos) invisible(repos) } #' Add a Repository #' #' Add a repository to the set of currently available repositories. This is #' effectively an easier-to-use wrapper over interacting with the #' \code{"repos"} option, which is otherwise set with \code{options(repos = ...)}. #' #' \code{repos_add_local} is used for adding file-based repositories; that is, #' CRAN repositories that live locally on disk and not on the internet / local network. #' #' @param ... Named arguments of the form \code{ = }. #' @param overwrite Boolean; overwrite if a repository with the given name #' already exists? #' #' @rdname repository-management #' @name repository-management #' #' @export repos_add <- function(..., overwrite = FALSE) { addRepos(list(...), overwrite = overwrite, local = FALSE) } #' @rdname repository-management #' @name repository-management #' @export repos_add_local <- function(..., overwrite = FALSE) { addRepos(list(...), overwrite = overwrite, local = TRUE) } #' @rdname repository-management #' @name repository-management #' @export repos_set <- function(...) { addRepos(list(...), overwrite = TRUE, local = FALSE) } #' @rdname repository-management #' @name repository-management #' @export repos_set_local <- function(...) { addRepos(list(...), overwrite = TRUE, local = TRUE) } #' @param names The names of repositories (as exist in e.g. #' \code{names(getOption("repos"))}). #' @rdname repository-management #' @name repository-management #' @export repos_remove <- function(names) { oldRepos <- getOption("repos") repos <- oldRepos[setdiff(names(oldRepos), names)] options(repos = repos) invisible(repos) } #' @rdname repository-management #' @name repository-management #' @export repos_list <- function() getOption("repos") setRepositoryField <- function(descPath, repoName) { contents <- readLines(descPath) repoIdx <- grep("^Repository:", contents) repoLine <- paste("Repository:", repoName) if (length(repoIdx)) contents[[repoIdx]] <- repoLine else contents <- c(contents, repoLine) cat(contents, file = descPath, sep = "\n") } packrat/R/r-hooks.R0000644000176200001440000000110513352207316013604 0ustar liggesusers# Call an action hook (indicating whether the action is running or not) callHook <- function(project, action, running) { project <- normalizePath(project, winslash = '/') for (fun in getHooksList("packrat.onAction")) { if (is.character(fun)) fun <- get(fun) try(fun(project, action, running)) } } # The value for getHook can be a single function or a list of functions, # This function ensures that the result can always be processed as a list getHooksList <- function(name) { hooks <- getHook(name) if (!is.list(hooks)) hooks <- list(hooks) hooks } packrat/R/disable.R0000644000176200001440000000236613352207316013637 0ustar liggesusers#' Disable the use of Packrat in a Project #' #' Disable packrat within a project, reverting to the use of standard user #' package libraries. #' #' @param project The directory in which packrat will be disabled (defaults to #' the current working directory) #' @param restart If \code{TRUE}, restart the R session after disabling packrat. #' #' @note Disabling packrat for a project removes the packrat initialization code #' from the .Rprofile file, resulting in the use of standard user package #' libraries. Note that the \code{packrat} directory is not deleted, but remains #' unused. #' #' To re-enable the use of packrat for a project you can call the #' \code{\link{init}} function. #' #' The \code{restart} parameter will only result in a restart of R when the R #' environment packrat is running within makes available a restart function via #' \code{getOption("restart")}. #' #' @export disable <- function(project = NULL, restart = TRUE) { # get the project project <- getProjectDir(project) # remove packrat from the .Rprofile editRprofileAutoloader(project, "remove") # turn packrat mode off if (isPackratModeOn()) off(project) # restart if requested if (restart) attemptRestart(restore.packrat.mode = FALSE) invisible() } packrat/R/utils.R0000644000176200001440000004311513352207316013371 0ustar liggesuserssilent <- function(expr) { suppressWarnings(suppressMessages( capture.output(result <- eval(expr, envir = parent.frame())) )) result } forceUnload <- function(pkg) { if (!startswith(pkg, "package:")) pkg <- paste("package", pkg, sep = ":") # force detach from search path if (pkg %in% search()) detach(pkg, character.only = TRUE, unload = TRUE, force = TRUE) # unload DLL if there is one pkgName <- gsub("package:", "", pkg, fixed = TRUE) pkgDLL <- getLoadedDLLs()[[pkgName]] if (!is.null(pkgDLL)) { suppressWarnings({ pkgDir <- system.file(package = pkgName) if (nzchar(pkgDir)) try(library.dynam.unload(pkgName, pkgDir), silent = TRUE) }) } # unload the namespace if it's still loaded if (pkgName %in% loadedNamespaces()) { unloadNamespace(pkgName) } } list_files <- function(path = ".", pattern = NULL, all.files = FALSE, full.names = FALSE, recursive = FALSE, ignore.case = FALSE, include.dirs = FALSE, no.. = TRUE) { files <- list.files(path = path, pattern = pattern, all.files = all.files, full.names = full.names, recursive = recursive, ignore.case = ignore.case, include.dirs = include.dirs, no.. = no..) dirs <- list.dirs(path = path, full.names = full.names, recursive = recursive) setdiff(files, dirs) } # wrapper around read.dcf to workaround LC_CTYPE bug # (see: http://r.789695.n4.nabble.com/Bug-in-read-dcf-all-TRUE-td4690578.html) readDcf <- function(...) { loc <- Sys.getlocale('LC_CTYPE') on.exit(Sys.setlocale('LC_CTYPE', loc)) read.dcf(...) } is_dir <- function(file) { isTRUE(file.info(file)$isdir) ## isTRUE guards against NA (ie, missing file) } # Copy a directory at file location 'from' to location 'to' -- this is kludgey, # but file.copy does not handle copying of directories cleanly dir_copy <- function(from, to, overwrite = FALSE, all.files = TRUE, pattern = NULL, ignore.case = TRUE) { owd <- getwd() on.exit(setwd(owd), add = TRUE) # Make sure we're doing sane things if (!is_dir(from)) stop("'", from, "' is not a directory.") if (file.exists(to)) { if (overwrite) { unlink(to, recursive = TRUE) } else { stop(paste( sep = "", if (is_dir(to)) "Directory" else "File", " already exists at path '", to, "'." )) } } success <- dir.create(to, recursive = TRUE) if (!success) stop("Couldn't create directory '", to, "'.") # Get relative file paths files.relative <- list.files(from, all.files = all.files, full.names = FALSE, recursive = TRUE, no.. = TRUE) # Apply the pattern to the files if (!is.null(pattern)) { files.relative <- Reduce(intersect, lapply(pattern, function(p) { grep( pattern = p, x = files.relative, ignore.case = ignore.case, perl = TRUE, value = TRUE ) })) } # Get paths from and to files.from <- file.path(from, files.relative) files.to <- file.path(to, files.relative) # Create the directory structure dirnames <- unique(dirname(files.to)) sapply(dirnames, function(x) dir.create(x, recursive = TRUE, showWarnings = FALSE)) # Copy the files res <- file.copy(files.from, files.to) if (!all(res)) { # The copy failed; we should clean up after ourselves and return an error unlink(to, recursive = TRUE) stop("Could not copy all files from directory '", from, "' to directory '", to, "'.") } setNames(res, files.relative) } wrap <- function(x, width = 78, ...) { paste(strwrap(x = paste(x, collapse = " "), width = width, ...), collapse = "\n") } pkgDescriptionDependencies <- function(file) { fields <- c("Depends", "Imports", "Suggests", "LinkingTo") if (!file.exists(file)) stop("no file '", file, "'") DESCRIPTION <- readDcf(file) # ignore empty description if (nrow(DESCRIPTION) < 1) return(list()) requirements <- DESCRIPTION[1, fields[fields %in% colnames(DESCRIPTION)]] ## Remove whitespace requirements <- gsub("[[:space:]]*", "", requirements) ## Parse packages + their version parsed <- vector("list", length(requirements)) for (i in seq_along(requirements)) { x <- requirements[[i]] splat <- unlist(strsplit(x, ",", fixed = TRUE)) res <- lapply(splat, function(y) { if (grepl("(", y, fixed = TRUE)) { list( Package = gsub("\\(.*", "", y), Version = gsub(".*\\((.*?)\\)", "\\1", y, perl = TRUE), Field = names(requirements)[i] ) } else { list( Package = y, Version = NA, Field = names(requirements)[i] ) } }) parsed[[i]] <- list( Package = sapply(res, "[[", "Package"), Version = sapply(res, "[[", "Version"), Field = sapply(res, "[[", "Field") ) } result <- do.call(rbind, lapply(parsed, function(x) { as.data.frame(x, stringsAsFactors = FALSE) })) ## Don't include 'base' packages ip <- installed.packages() basePkgs <- ip[Vectorize(isTRUE)(ip[, "Priority"] == "base"), "Package"] result <- result[!(result$Package %in% basePkgs), ] ## Don't include R result <- result[!result$Package == "R", ] result } # does str1 start with str2? startswith <- function(str1, str2) { if (!length(str2) == 1) stop("expecting a length 1 string for 'str2'") sapply(str1, function(x) { identical( substr(x, 1, min(nchar(x), nchar(str2))), str2 ) }) } # does str1 end with str2? endswith <- function(str1, str2) { if (!length(str2) == 1) stop("expecting a length 1 string for 'str2'") n2 <- nchar(str2) sapply(str1, function(x) { nx <- nchar(x) identical( substr(x, nx - n2 + 1, nx), str2 ) }) } stopIfNoLockfile <- function(project) { path <- lockFilePath(project) if (!file.exists(path)) { stop("This project does not have a lockfile. (Have you called 'packrat::snapshot()' yet?)", call. = FALSE) } invisible(TRUE) } stopIfNotPackified <- function(project) { if (!checkPackified(project, quiet = TRUE)) { if (identical(project, getwd())) { stop("This project has not yet been packified.\nRun 'packrat::init()' to init packrat.", call. = FALSE) } else { stop("The project at '", project, "' has not yet been packified.\nRun 'packrat::init('", project, "') to init packrat.", call. = FALSE) } } } # Expected to be used with .Rbuildignore, .Rinstignore # .gitignore + SVN ignore have their own (similar) logical, but # need to handle options specially updateIgnoreFile <- function(project = NULL, file, add = NULL, remove = NULL) { project <- getProjectDir(project) # if no ignore file exists, populate it path <- file.path(project, file) if (!file.exists(path)) { if (length(add) > 0) cat(add, file = path, sep = "\n") return(invisible()) } # read ignore file and track changes oldContent <- readLines(path) newContent <- oldContent # add items to end of ignore file (avoid duplication of entries) if (length(add)) newContent <- c(newContent, setdiff(add, newContent)) # remove items from ignore file if (length(remove)) newContent <- newContent[!(newContent %in% remove)] # only mutate ignore file if contents have indeed changed if (!identical(oldContent, newContent)) cat(newContent, file = path, sep = "\n") return(invisible()) } updateRBuildIgnore <- function(project = NULL) { add <- c( "^packrat/", "^\\.Rprofile$" ) updateIgnoreFile(project = project, file = ".Rbuildignore", add = add) } updateGitIgnore <- function(project = NULL, options) { git.options <- options[grepl("^vcs", names(options))] names(git.options) <- swap( names(git.options), c( "vcs.ignore.lib" = paste0(relLibraryRootDir(), "*/"), "vcs.ignore.src" = paste0(relSrcDir(), "/") ) ) add <- names(git.options)[sapply(git.options, isTRUE)] remove <- names(git.options)[sapply(git.options, isFALSE)] updateIgnoreFile(project = project, file = ".gitignore", add = add, remove = remove) } # A packrat project is managed by git if any one of its parent directories # contains a '.git' folder. isGitProject <- function(project) { path <- project while (dirname(path) != path) { .git <- file.path(path, ".git") if (file.exists(.git) && is_dir(.git)) return(TRUE) path <- dirname(path) } return(FALSE) } isSvnProject <- function(project) { .svn <- file.path(project, ".svn") file.exists(.svn) && is_dir(.svn) } getSvnIgnore <- function(svn, dir) { owd <- getwd() on.exit(setwd(owd)) setwd(dir) result <- system(paste(svn, "propget", "svn:ignore"), intern = TRUE) result[result != ""] } setSvnIgnore <- function(svn, dir, ignores) { owd <- getwd() on.exit(setwd(owd)) setwd(dir) ignores <- paste(ignores, collapse = "\n") system(paste(svn, "propset", "svn:ignore", shQuote(ignores), "."), intern = TRUE) } updateSvnIgnore <- function(project, options) { svn.options <- options[grepl("^vcs", names(options))] names(svn.options) <- swap( names(svn.options), c( "vcs.ignore.lib" = relLibraryRootDir(), "vcs.ignore.src" = relSrcDir() ) ) add <- names(svn.options)[sapply(svn.options, isTRUE)] remove <- names(svn.options)[sapply(svn.options, isFALSE)] ## We need to explicitly exclude library.new, library.old add <- unique(c(add, relNewLibraryDir(), relOldLibraryDir() )) add <- c(add, "packrat/lib-R") svn <- Sys.which("svn") if (svn == "") { stop("Could not locate an 'svn' executable on your PATH") } ignores <- getSvnIgnore(svn, project) ignores <- union(ignores, add) ignores <- setdiff(ignores, remove) setSvnIgnore(svn, project, ignores) } ## Wrappers over setLibPaths that do some better error reporting setLibPaths <- function(paths) { for (path in paths) { if (!file.exists(path)) { stop("No directory exists at path '", path, "'") } } .libPaths(paths) } normalize_paths <- function(paths, winslash = "/", mustWork = FALSE) { paths[paths == ""] <- getwd() unlist(lapply(paths, function(path) { normalizePath(path, winslash = "/", mustWork = FALSE) })) } getLibPaths <- function() { normalize_paths(.libPaths()) } getUserLibPaths <- function() { allPaths <- getLibPaths() sysPaths <- normalize_paths(c(.Library, .Library.site)) setdiff(allPaths, sysPaths) } ## Get the default library paths (those that would be used upon ## starting a new R session) getDefaultLibPaths <- function() { getenv("R_PACKRAT_DEFAULT_LIBPATHS") } getInstalledPkgInfo <- function(packages, installed.packages, ...) { ip <- installed.packages missingFromLib <- packages[!(packages %in% rownames(ip))] if (length(missingFromLib)) { warning("The following packages are not installed in the current library:\n- ", paste(missingFromLib, sep = ", ")) } packages <- setdiff(packages, missingFromLib) getPkgInfo(packages, ip) } getPkgInfo <- function(packages, installed.packages) { records <- installed.packages[packages, , drop = FALSE] ## Convert from matrix to list records <- apply(records, 1, as.list) ## Parse the package dependency fields -- we split up the depends, imports, etc. for (i in seq_along(records)) { for (field in c("Depends", "Imports", "LinkingTo", "Suggests", "Enhances")) { item <- records[[i]][[field]] if (is.na(item)) next item <- gsub("[[:space:]]*(.*?)[[:space:]]*", "\\1", item, perl = TRUE) item <- unlist(strsplit(item, ",[[:space:]]*", perl = TRUE)) ## Remove version info item <- gsub("\\(.*", "", item) records[[i]][[field]] <- item } } records } `%||%` <- function(x, y) { if (is.null(x)) y else x } `%nin%` <- function(x, y) { !(x %in% y) } isFALSE <- function(x) identical(x, FALSE) swap <- function(vec, from, to = NULL) { if (is.null(to)) { to <- unname(unlist(from)) from <- names(from) } tmp <- to[match(vec, from)] tmp[is.na(tmp)] <- vec[is.na(tmp)] return(tmp) } attemptRestart <- function(..., restore.packrat.mode = TRUE) { restart <- getOption("restart") if (!is.null(restart)) { # set packrat mode environment variable here so that # the host environment knows to return to packrat # mode after the restart (affects how .libPaths are # handled during the restart) if (restore.packrat.mode) { setPackratModeEnvironmentVar() } restart(...) TRUE } else { FALSE } } loadedNamespacePaths <- function() { loadedNamespaceNames <- loadedNamespaces() paths <- unlist(lapply(loadedNamespaceNames, function(nm) { if (nm == "base") return(NA) ns <- asNamespace(nm) if (!exists(".__NAMESPACE__.", envir = ns)) return(NA) getNamespaceInfo(ns, "path") })) result <- data.frame( namespace = loadedNamespaceNames, dir = dirname(paths), path = paths ) result <- result[order(result$dir), ] rownames(result) <- NULL result } # Work around namespace:stats potentially not being loaded setNames <- function(object = nm, nm) { names(object) <- nm object } # Drop null values in a list dropNull <- function(x) { Filter(Negate(is.null), x) } surround <- function(x, with = "'") { if (!length(x)) return(character()) paste0(with, as.character(x), with) } write_dcf <- function(x, file = "", append = FALSE, indent = 4, width = 72, keep.white = NULL, ...) { write.dcf(x = x, file = file, append = append, indent = indent, width = width, keep.white = keep.white, ...) } symlink <- function(from, to) { # attempt to generating the symlink if (is.windows()) Sys.junction(from, to) else file.symlink(from, to) # check to see if the file was properly generated file.exists(to) } with_dir <- function(dir, expr) { owd <- getwd() setwd(dir) on.exit(setwd(owd)) eval(expr, envir = parent.frame()) } set_collate <- function(locale) { cur <- Sys.getlocale(category = "LC_COLLATE") Sys.setlocale(category = "LC_COLLATE", locale = locale) cur } with_collate <- function(locale, code) { old <- set_collate(locale) on.exit(set_collate(old)) force(code) } sort_c <- function(x) with_collate("C", sort(x)) is.string <- function(x) { is.character(x) && length(x) == 1 } is.directory <- function(x) { file.exists(x) && isTRUE(file.info(x)[["isdir"]]) # guard against NA } getBinaryPkgType <- function() { .Platform$pkgType } normalize.path <- function(path) { normalizePath(path, winslash = "/", mustWork = TRUE) } filePrefix <- function() { if (is.windows()) "file:///" else "file://" } reFilePrefix <- function() { paste("^", filePrefix(), sep = "") } isProgramOnPath <- function(program) { nzchar(Sys.which(program)[[1]]) } isPathToSameFile <- function(lhs, rhs) { if (!(is.string(lhs) && is.string(rhs))) return(FALSE) lhsNorm <- normalizePath(lhs, winslash = "/", mustWork = FALSE) rhsNorm <- normalizePath(rhs, winslash = "/", mustWork = FALSE) lhsNorm == rhsNorm } isTestingPackrat <- function() { !is.na(Sys.getenv("R_PACKRAT_TESTING", unset = NA)) } defer <- function(expr, envir = parent.frame()) { # Create a call that must be evaluated in the parent frame (as # that's where functions and symbols need to be resolved) call <- substitute( evalq(expr, envir = envir), list(expr = substitute(expr), envir = parent.frame()) ) # Use 'do.call' with 'on.exit' to attach the evaluation to # the exit handlrs of the selected frame do.call(base::on.exit, list(substitute(call), add = TRUE), envir = envir) } isUsingExternalTar <- function() { TAR <- Sys.getenv("TAR") if (!nzchar(TAR)) return(FALSE) if (!nzchar(Sys.which(TAR))) return(FALSE) if (identical(TAR, "internal")) return(FALSE) TRUE } join <- function(..., sep = "", collapse = NULL) { paste(..., sep = sep, collapse = collapse) } # sneakily get a function yoink <- function(package, symbol) { eval(call(":::", package, symbol)) } enumerate <- function(list, fn) { keys <- names(list) values <- list sapply(seq_along(keys), function(i) { fn(keys[[i]], values[[i]]) }) } packageVersionInstalled <- function(...) { enumerate(list(...), function(package, version) { result <- try(packageVersion(package), silent = TRUE) !inherits(result, "try-error") && result >= version }) } packratOption <- function(envName, optionName, defaultValue) { envValue <- Sys.getenv(envName, unset = NA) if (!is.na(envValue)) return(envValue) optionValue <- getOption(optionName) if (!is.null(optionValue)) return(optionValue) defaultValue } packratOptionBoolean <- function(envName, optionName, defaultValue) { option <- packratOption(envName, optionName, defaultValue) if (is.character(option)) { option <- if (!nzchar(option)) FALSE else if (tolower(option) %in% c("t", "true", "y", "yes")) TRUE else if (tolower(option) %in% c("f", "false", "n", "no")) FALSE else as.logical(eval(parse(text = option))) } as.logical(option) } ensureDirectory <- function(path) { info <- file.info(path) if (identical(info$isdir, TRUE)) return(path) else if (identical(info$isdir, FALSE)) stop("path '", path, "' exists but is not a directory") else if (!dir.create(path, recursive = TRUE)) stop("failed to create directory at path '", path, "'") path } quietly <- function(expr) { withCallingHandlers( tryCatch(expr = expr, error = identity), warning = function(w) invokeRestart("muffleWarning"), message = function(m) invokeRestart("muffleMessage") ) } onError <- function(default, expr) { tryCatch(expr, error = function(e) default) } packrat/R/clean-search-path.R0000644000176200001440000000203413352207316015503 0ustar liggesusers## Clean up the search path -- unload all packages in the user library ## Primarily used when entering packrat mode cleanSearchPath <- function(verbose = TRUE, lib.loc = getUserLibPaths()) { searchPath <- search_path() ## Don't remove anything in a packrat private library toCheck <- grep("packrat", searchPath$lib.dir, invert = TRUE) if (!length(toCheck)) return(NULL) searchPath <- searchPath[toCheck, ] searchPath$path <- paste("package", searchPath$package, sep = ":") ip <- utils::installed.packages(lib.loc = lib.loc) searchPath <- searchPath[searchPath$package %in% rownames(ip), ] ## Don't unload base, recommended packages userPkgs <- searchPath$package[is.na(ip[searchPath$package, "Priority"])] searchPathToUnload <- searchPath[searchPath$package %in% userPkgs, ] if (verbose && nrow(searchPathToUnload)) { message("Unloading packages in user library:\n- ", paste(searchPathToUnload$package, collapse = ", ")) } for (path in searchPathToUnload$path) { forceUnload(path) } searchPathToUnload } packrat/R/restore-routines.R0000644000176200001440000001215313352207316015560 0ustar liggesusersisTrustedPackage <- function(package) { untrusted <- getOption("packrat.untrusted.packages", default = character()) !package %in% untrusted } isCorruptPackageCacheEntry <- function(path) { # if we don't have a cache entry, it's not corrupt if (!file.exists(path)) return(FALSE) # check for missing DESCRIPTION file desc <- file.path(path, "DESCRIPTION") if (!file.exists(desc)) { fmt <- "Cache entry for package '%s' appears to be corrupt: no DESCRIPTION file" warning(sprintf(fmt, basename(path))) return(TRUE) } # check for empty DESCRIPTION file info <- file.info(desc) if (info$size == 0) { fmt <- "Cache entry for package '%s' appears to be corrupt: DESCRIPTION file is empty" warning(sprintf(fmt, basename(path))) return(TRUE) } # TODO: other smoke tests? # okay, everything looks good return(FALSE) } hashTarball <- function(path) { # TODO: unpack, recursively hash, and combine? for now # we just hash the tarball as-is tools::md5sum(files = normalizePath(path, mustWork = TRUE)) } restoreWithCopyFromCache <- function(project, pkgRecord, cacheCopyStatus) { # don't copy from cache if disabled for this project if (!isUsingCache(project)) return(FALSE) # don't try to use cache if we don't have a hash if (!length(pkgRecord$hash)) return(FALSE) # don't try to cache uncacheable packages (ie, packages that # need to be reinstalled each time for whatever reason) if (!isCacheable(pkgRecord$name)) return(FALSE) # ensure that the cache package path exists source <- cacheLibDir(pkgRecord$name, pkgRecord$hash, pkgRecord$name) if (!file_test("-d", source)) return(FALSE) # sanity check for cache corruption -- we've seen some cases where # a cache entry exists, but it's just an empty folder if (isCorruptPackageCacheEntry(source)) return(FALSE) # attempt to form a symlink to the packrat library # (remove stale file if one exists) lib <- libDir(project) target <- file.path(lib, pkgRecord$name) # if we already have a directory at the target location, back it up # and attempt to restore it if something goes wrong and we fail to # copy from the cache if (file.exists(target)) { temp <- tempfile(tmpdir = lib) file.rename(target, temp) on.exit({ if (file.exists(target)) unlink(temp, recursive = !is.symlink(temp)) else file.rename(temp, target) }, add = TRUE) } # attempt the symlink suppressWarnings(symlink(source, target)) success <- file.exists(target) if (success) { cacheCopyStatus$type <- "symlinked cache" return(TRUE) } # symlinking failed; attempt a copy from the cache to the target directory success <- all(dir_copy( cacheLibDir(pkgRecord$name, pkgRecord$hash), file.path(libDir(project), pkgRecord$name) )) if (success) { cacheCopyStatus$type <- "copied cache" return(TRUE) } # failed to copy or symlink from cache; report warning and return false warning("failed to symlink or copy package '", pkgRecord$name, "' from cache") return(FALSE) } restoreWithCopyFromUntrustedCache <- function(project, pkgRecord, cacheCopyStatus) { # don't copy from cache if disabled for this project if (!isUsingCache(project)) return(FALSE) # don't try to cache uncacheable packages (ie, packages that # need to be reinstalled each time for whatever reason) if (!isCacheable(pkgRecord$name)) return(FALSE) # attempt to find source tarball associated with passed-in # package record tarballName <- pkgSrcFilename(pkgRecord) tarballPath <- file.path(srcDir(project), pkgRecord$name, tarballName) if (!file.exists(tarballPath)) return(FALSE) # attempt to hash tarball hash <- hashTarball(tarballPath) if (!is.character(hash)) return(FALSE) # attempt to discover cached package in untrusted cache source <- untrustedCacheLibDir(pkgRecord$name, hash, pkgRecord$name) if (!file.exists(source)) return(FALSE) # attempt to form a symlink to the packrat library # (remove stale file if one exists) lib <- libDir(project) target <- file.path(lib, pkgRecord$name) if (file.exists(target)) { temp <- tempfile(tmpdir = lib) file.rename(target, temp) on.exit({ if (file.exists(target)) unlink(temp, recursive = !is.symlink(temp)) else file.rename(temp, target) }, add = TRUE) } suppressWarnings(symlink(source, target)) success <- file.exists(target) if (success) { cacheCopyStatus$type <- "symlinked user cache" return(TRUE) } # symlinking failed; attempt a copy from the cache to the target directory success <- all(dir_copy( cacheLibDir(pkgRecord$name, pkgRecord$hash), file.path(libDir(project), pkgRecord$name) )) if (success) { cacheCopyStatus$type <- "copied user cache" return(TRUE) } # failed to copy or symlink from cache; report warning and return false warning("failed to symlink or copy package '", pkgRecord$name, "' from user cache") return(FALSE) } packrat/R/install.R0000644000176200001440000005012713352207316013700 0ustar liggesusers#' Install a local development package. #' #' Uses \code{R CMD INSTALL} to install the package. Will also try to install #' dependencies of the package from CRAN, if they're not already installed. #' #' By default, installation takes place using the current package directory. #' If you have compiled code, this means that artefacts of compilation will be #' created in the \code{src/} directory. If you want to avoid this, you can #' use \code{local = FALSE} to first build a package bundle and then install #' it from a temporary directory. This is slower, but keeps the source #' directory pristine. #' #' If the package is loaded, it will be reloaded after installation. #' #' @param pkg package description, can be path or package name. #' @param reload if \code{TRUE} (the default), will automatically reload the #' package after installing. #' @param quick if \code{TRUE} skips docs, multiple-architectures, #' demos, and vignettes, to make installation as fast as possible. #' @param local if \code{FALSE} \code{\link{build}}s the package first: #' this ensures that the installation is completely clean, and prevents any #' binary artefacts (like \file{.o}, \code{.so}) from appearing in your local #' package directory, but is considerably slower, because every compile has #' to start from scratch. #' @param args An optional character vector of additional command line #' arguments to be passed to \code{R CMD install}. This defaults to the #' value of the option \code{"devtools.install.args"}. #' @param quiet if \code{TRUE} suppresses output from this function. #' @param dependencies \code{logical} indicating to also install uninstalled #' packages which this \code{pkg} depends on/links to/suggests. See #' argument \code{dependencies} of \code{\link{install.packages}}. #' @param build_vignettes if \code{TRUE}, will build vignettes. Normally it is #' \code{build} that's responsible for creating vignettes; this argument makes #' sure vignettes are built even if a build never happens (i.e. because #' \code{local = TRUE}. #' @param keep_source If \code{TRUE} will keep the srcrefs from an installed #' package. This is useful for debugging (especially inside of RStudio). #' It defaults to the option \code{"keep.source.pkgs"}. #' @export #' @importFrom tools pkgVignettes install <- function(pkg = ".", reload = TRUE, quick = FALSE, local = TRUE, args = getOption("devtools.install.args"), quiet = FALSE, dependencies = NA, build_vignettes = !quick, keep_source = getOption("keep.source.pkgs")) { pkg <- as.package(pkg) if (!quiet) message("Installing ", pkg$package) # Build the package. Only build locally if it doesn't have vignettes has_vignettes <- length(pkgVignettes(dir = pkg$path)$doc > 0) if (local && !(has_vignettes && build_vignettes)) { built_path <- pkg$path } else { built_path <- build(pkg, tempdir(), vignettes = build_vignettes, quiet = quiet) on.exit(unlink(built_path)) } opts <- c( paste("--library=", shQuote(getLibPaths()[1]), sep = ""), if (keep_source) "--with-keep.source", "--install-tests" ) if (quick) { opts <- c(opts, "--no-docs", "--no-multiarch", "--no-demo") } opts <- paste(paste(opts, collapse = " "), paste(args, collapse = " ")) R(paste("CMD INSTALL ", shQuote(built_path), " ", opts, sep = ""), quiet = quiet) if (reload) reload(pkg$package, quiet = quiet) invisible(TRUE) } build <- function(pkg = ".", path = NULL, binary = FALSE, vignettes = TRUE, args = NULL, quiet = FALSE) { pkg <- as.package(pkg) if (is.null(path)) { path <- dirname(pkg$path) } if (getRversion() < "3.1.0") { noBuildVignettes <- "--no-vignettes" } else { noBuildVignettes <- "--no-build-vignettes" } if (binary) { args <- c("--build", args) cmd <- paste0("CMD INSTALL ", shQuote(pkg$path), " ", paste0(args, collapse = " ")) ext <- if (.Platform$OS.type == "windows") "zip" else "tgz" } else { args <- c(args, "--no-manual", "--no-resave-data") if (!vignettes) { args <- c(args, noBuildVignettes) } else if (!nzchar(Sys.which("pdflatex"))) { message("pdflatex not found. Not building PDF vignettes.") args <- c(args, noBuildVignettes) } cmd <- paste0("CMD build ", shQuote(pkg$path), " ", paste0(args, collapse = " ")) ext <- "tar.gz" } with_libpaths(c(tempdir(), getLibPaths()), R(cmd, path, quiet = quiet)) targz <- paste0(pkg$package, "_", pkg$version, ".", ext) file.path(path, targz) } R.path <- function() file.path(R.home("bin"), "R") R <- function(options, path = tempdir(), env_vars = NULL, ...) { options <- paste("--vanilla", options) r_path <- file.path(R.home("bin"), "R") # If rtools has been detected, add it to the path only when running R... if (!is.null(get_rtools_path())) { old <- add_path(get_rtools_path(), 0) on.exit(set_path(old)) } in_dir(path, system_check(r_path, options, c(r_env_vars(), env_vars), ...)) } r_env_vars <- function() { c("LC_ALL" = "C", "R_LIBS" = paste(getLibPaths(), collapse = .Platform$path.sep), "CYGWIN" = "nodosfilewarning", # When R CMD check runs tests, it sets R_TESTS. When the tests # themeselves run R CMD xxxx, as is the case with the tests in # devtools, having R_TESTS set causes errors because it confuses # the R subprocesses. Unsetting it here avoids those problems. "R_TESTS" = "", "NOT_CRAN" = "true", "TAR" = auto_tar()) } auto_tar <- function() { tar <- Sys.getenv("TAR", unset = NA) if (!is.na(tar)) return(tar) windows <- .Platform$OS.type == "windows" no_rtools <- is.null(get_rtools_path()) if (windows && no_rtools) "internal" else "" } with_something <- function(set) { function(new, code) { old <- set(new) on.exit(set(old)) force(code) } } in_dir <- with_something(setwd) set_libpaths <- function(paths) { old <- getLibPaths() setLibPaths(paths) invisible(old) } with_libpaths <- with_something(set_libpaths) with_envvar <- function(new, code, action = "replace") { old <- set_envvar(new, action) on.exit(set_envvar(old, "replace")) force(code) } install_local_path <- function(path, subdir = NULL, ...) { invisible(lapply(path, install_local_path_single, subdir = subdir, ...)) } install_local_path_single <- function(path, subdir = NULL, before_install = NULL, ..., quiet = FALSE) { stopifnot(file.exists(path)) if (!quiet) { message("Installing package from '", path, "'") } if (!file.info(path)$isdir) { bundle <- path path <- decompress(path) on.exit(unlink(path), add = TRUE) } else { bundle <- NULL } pkg_path <- if (is.null(subdir)) path else file.path(path, subdir) # Check it's an R package if (!file.exists(file.path(pkg_path, "DESCRIPTION"))) { stop("Does not appear to be an R package (no DESCRIPTION)", call. = FALSE) } # Check configure is executable if present config_path <- file.path(pkg_path, "configure") if (file.exists(config_path)) { Sys.chmod(config_path, "777") } # Call before_install for bundles (if provided) if (!is.null(bundle) && !is.null(before_install)) before_install(bundle, pkg_path) # Finally, run install with_build_tools({ install(pkg_path, quiet = quiet, ...) }) } with_build_tools <- function(code) { check <- getOption("buildtools.check", NULL) if (!is.null(check)) { if (check("Installing R packages from source")) { with <- getOption("buildtools.with", NULL) if (!is.null(with)) with(code) else force(code) } } else { force(code) } } decompress <- function(src, target = tempdir()) { tryCatch( decompressImpl(src, target), error = function(e) { fmt <- paste( "Failed to extract archive:", "- '%s' => '%s'", "Reason: %s", sep = "\n" ) msg <- sprintf(fmt, src, target, e$message) message(msg, sep = "\n") } ) } decompressImpl <- function(src, target = tempdir()) { stopifnot(file.exists(src)) # force internal tar (otherwise bad things can happen on Windows if # unexpected versions of tar.exe are on the PATH) TAR <- Sys.getenv("TAR") Sys.setenv(TAR = "internal") on.exit(Sys.setenv(TAR = TAR), add = TRUE) if (grepl("\\.zip$", src)) { unzip(src, exdir = target, unzip = getOption("unzip")) outdir <- getrootdir(as.vector(unzip(src, list = TRUE)$Name)) } else if (grepl("\\.tar$", src)) { untar(src, exdir = target) outdir <- getrootdir(untar(src, list = TRUE)) } else if (grepl("\\.(tar\\.gz|tgz)$", src)) { untar(src, exdir = target, compressed = "gzip") outdir <- getrootdir(untar(src, compressed = "gzip", list = TRUE)) } else if (grepl("\\.(tar\\.bz2|tbz)$", src)) { untar(src, exdir = target, compressed = "bzip2") outdir <- getrootdir(untar(src, compressed = "bzip2", list = TRUE)) } else { ext <- gsub("^[^.]*\\.", "", src) stop("Don't know how to decompress files with extension ", ext, call. = FALSE) } file.path(target, outdir) } getdir <- function(path) sub("/[^/]*$", "", path) getrootdir <- function(file_list) { getdir(file_list[which.min(nchar(gsub("[^/]", "", file_list)))]) } as.package <- function(x = NULL) { if (is.package(x)) return(x) x <- check_dir(x) load_pkg_description(x) } check_dir <- function(x) { if (is.null(x)) { stop("Path is null", call. = FALSE) } # Normalise path and strip trailing slashes x <- gsub("\\\\", "/", x, fixed = TRUE) x <- sub("/*$", "", x) if (!file.exists(x)) { stop("Can't find directory ", x, call. = FALSE) } if (!file.info(x)$isdir) { stop(x, " is not a directory", call. = FALSE) } x } load_pkg_description <- function(path) { path <- normalizePath(path) path_desc <- file.path(path, "DESCRIPTION") if (!file.exists(path_desc)) { stop("No description at ", path_desc, call. = FALSE) } desc <- as.list(readDcf(path_desc)[1, ]) names(desc) <- tolower(names(desc)) desc$path <- path structure(desc, class = "package") } is.package <- function(x) inherits(x, "package") if (!exists("set_rtools_path")) { set_rtools_path <- NULL get_rtools_path <- NULL local({ rtools_paths <- NULL set_rtools_path <<- function(rtools) { stopifnot(is.rtools(rtools)) path <- file.path(rtools$path, version_info[[rtools$version]]$path) rtools_paths <<- path } get_rtools_path <<- function() { rtools_paths } }) } find_rtools <- function(debug = FALSE) { # Non-windows users don't need rtools if (.Platform$OS.type != "windows") return(TRUE) # First try the path from_path <- scan_path_for_rtools(debug) if (is_compatible(from_path)) { set_rtools_path(from_path) return(TRUE) } if (!is.null(from_path)) { # Installed if (is.null(from_path$version)) { # but not from rtools if (debug) "gcc and ls on path, assuming set up is correct\n" return(TRUE) } else { # Installed, but not compatible message("WARNING: Rtools ", from_path$version, " found on the path", " at ", from_path$path, " is not compatible with R ", getRversion(), ".\n\n", "Please download and install ", rtools_needed(), " from ", rtools_url, ", remove the incompatible version from your PATH, then run find_rtools().") return(invisible(FALSE)) } } # Not on path, so try registry registry_candidates <- scan_registry_for_rtools(debug) if (length(registry_candidates) == 0) { # Not on path or in registry, so not installled message("WARNING: Rtools is required to build R packages, but is not ", "currently installed.\n\n", "Please download and install ", rtools_needed(), " from ", rtools_url, " and then run find_rtools().") return(invisible(FALSE)) } from_registry <- Find(is_compatible, registry_candidates, right = TRUE) if (is.null(from_registry)) { # In registry, but not compatible. versions <- vapply(registry_candidates, function(x) x$version, character(1)) message("WARNING: Rtools is required to build R packages, but no version ", "of Rtools compatible with R ", getRversion(), " was found. ", "(Only the following incompatible version(s) of Rtools were found:", paste(versions, collapse = ","), ")\n\n", "Please download and install ", rtools_needed(), " from ", rtools_url, " and then run find_rtools().") return(invisible(FALSE)) } installed_ver <- installed_version(from_registry$path, debug = debug) if (is.null(installed_ver)) { # Previously installed version now deleted message("WARNING: Rtools is required to build R packages, but the ", "version of Rtools previously installed in ", from_registry$path, " has been deleted.\n\n", "Please download and install ", rtools_needed(), " from ", rtools_url, " and then run find_rtools().") return(invisible(FALSE)) } if (installed_ver != from_registry$version) { # Installed version doesn't match registry version message("WARNING: Rtools is required to build R packages, but no version ", "of Rtools compatible with R ", getRversion(), " was found. ", "Rtools ", from_registry$version, " was previously installed in ", from_registry$path, " but now that directory contains Rtools ", installed_ver, ".\n\n", "Please download and install ", rtools_needed(), " from ", rtools_url, " and then run find_rtools().") return(invisible(FALSE)) } # Otherwise it must be ok :) set_rtools_path(from_registry) TRUE } scan_path_for_rtools <- function(debug = FALSE) { if (debug) cat("Scanning path...\n") # First look for ls and gcc ls_path <- Sys.which("ls") if (ls_path == "") return(NULL) if (debug) cat("ls :", ls_path, "\n") gcc_path <- Sys.which("gcc") if (gcc_path == "") return(NULL) if (debug) cat("gcc:", gcc_path, "\n") # We have a candidate installPath install_path <- dirname(dirname(ls_path)) install_path2 <- dirname(dirname(dirname(gcc_path))) if (install_path2 != install_path) return(NULL) version <- installed_version(install_path, debug = debug) if (debug) cat("Version:", version, "\n") rtools(install_path, version) } scan_registry_for_rtools <- function(debug = FALSE) { if (debug) cat("Scanning registry...\n") keys <- NULL try(keys <- utils::readRegistry("SOFTWARE\\R-core\\Rtools", hive = "HLM", view = "32-bit", maxdepth = 2), silent = TRUE) if (is.null(keys)) return(NULL) rts <- vector("list", length(keys)) for (i in seq_along(keys)) { version <- names(keys)[[i]] key <- keys[[version]] if (!is.list(key) || is.null(key$InstallPath)) next; install_path <- normalizePath(key$InstallPath, mustWork = FALSE, winslash = "/") if (debug) cat("Found", install_path, "for", version, "\n") rts[[i]] <- rtools(install_path, version) } Filter(Negate(is.null), rts) } installed_version <- function(path, debug) { if (!file.exists(file.path(path, "Rtools.txt"))) return(NULL) # Find the version path version_path <- file.path(path, "VERSION.txt") if (debug) { cat("VERSION.txt\n") cat(readLines(version_path), "\n") } if (!file.exists(version_path)) return(NULL) # Rtools is in the path -- now crack the VERSION file contents <- NULL try(contents <- readLines(version_path), silent = TRUE) if (is.null(contents)) return(NULL) # Extract the version contents <- gsub("^\\s+|\\s+$", "", contents) version_re <- "Rtools version (\\d\\.\\d+)\\.[0-9.]+$" if (!grepl(version_re, contents)) return(NULL) m <- regexec(version_re, contents) regmatches(contents, m)[[1]][2] } is_compatible <- function(rtools) { if (is.null(rtools)) return(FALSE) if (is.null(rtools$version)) return(FALSE) stopifnot(is.rtools(rtools)) info <- version_info[[rtools$version]] if (is.null(info)) return(FALSE) r_version <- getRversion() r_version >= info$version_min && r_version <= info$version_max } rtools <- function(path, version) { structure(list(version = version, path = path), class = "rtools") } is.rtools <- function(x) inherits(x, "rtools") rtools_url <- "https://cran.r-project.org/bin/windows/Rtools/" version_info <- list( "2.11" = list( version_min = "2.10.0", version_max = "2.11.1", path = c("bin", "perl/bin", "MinGW/bin") ), "2.12" = list( version_min = "2.12.0", version_max = "2.12.2", path = c("bin", "perl/bin", "MinGW/bin", "MinGW64/bin") ), "2.13" = list( version_min = "2.13.0", version_max = "2.13.2", path = c("bin", "MinGW/bin", "MinGW64/bin") ), "2.14" = list( version_min = "2.13.0", version_max = "2.14.2", path = c("bin", "MinGW/bin", "MinGW64/bin") ), "2.15" = list( version_min = "2.14.2", version_max = "2.15.1", path = c("bin", "gcc-4.6.3/bin") ), "2.16" = list( version_min = "2.15.2", version_max = "3.0.0", path = c("bin", "gcc-4.6.3/bin") ), "3.0" = list( version_min = "2.15.2", version_max = "3.0.99", path = c("bin", "gcc-4.6.3/bin") ), "3.1" = list( version_min = "3.0.0", version_max = "3.1.99", path = c("bin", "gcc-4.6.3/bin") ) ) rtools_needed <- function() { r_version <- getRversion() for (i in rev(seq_along(version_info))) { version <- names(version_info)[i] info <- version_info[[i]] ok <- r_version >= info$version_min && r_version <= info$version_max if (ok) return(paste("Rtools", version)) } "the appropriate version of Rtools" } system_check <- function(cmd, args = character(), env = character(), quiet = FALSE, ...) { full <- paste(shQuote(cmd), paste(args, collapse = ", ")) if (!quiet) { message(wrap_command(full)) message() } # Use system2 instead of system as we can then handle redirection # on Windows result <- suppressWarnings(with_envvar( env, if (quiet) { system2(cmd, args, stdout = TRUE, stderr = TRUE) } else { system2(cmd, args) } )) status <- attr(result, "status") if (!is.null(status) && status != 0) { stopMsg <- paste0( "Command failed (", status, ")", "\n\nFailed to run system command:\n\n", "\t", full ) if (length(result)) { stopMsg <- paste0( stopMsg, "\n\nThe command failed with output:\n", paste(result, collapse = "\n") ) } # issue #186 if (nchar(stopMsg) > getOption("warning.length")) { print(stopMsg, file = stderr()) } stop(stopMsg, call. = FALSE) } invisible(TRUE) } wrap_command <- function(x) { lines <- strwrap(x, getOption("width") - 2, exdent = 2) continue <- c(rep(" \\", length(lines) - 1), "") paste(lines, continue, collapse = "\n") } set_envvar <- function(envs, action = "replace") { stopifnot(is.named(envs)) stopifnot(is.character(action), length(action) == 1) action <- match.arg(action, c("replace", "prefix", "suffix")) old <- Sys.getenv(names(envs), names = TRUE, unset = NA) set <- !is.na(envs) both_set <- set & !is.na(old) if (any(both_set)) { if (action == "prefix") { envs[both_set] <- paste(envs[both_set], old[both_set]) } else if (action == "suffix") { envs[both_set] <- paste(old[both_set], envs[both_set]) } } if (any(set)) do.call("Sys.setenv", as.list(envs[set])) if (any(!set)) Sys.unsetenv(names(envs)[!set]) invisible(old) } is.named <- function(x) { !is.null(names(x)) && all(names(x) != "") } "%||%" <- function(a, b) if (!is.null(a)) a else b get_path <- function() { strsplit(Sys.getenv("PATH"), .Platform$path.sep)[[1]] } set_path <- function(path) { path <- normalizePath(path, mustWork = FALSE) old <- get_path() path <- paste(path, collapse = .Platform$path.sep) Sys.setenv(PATH = path) invisible(old) } add_path <- function(path, after = Inf) { set_path(append(get_path(), path, after)) } reload <- function(pkg = ".", quiet = FALSE) { if (paste0("package:", pkg) %in% search()) { if (!quiet) message("Reloading installed package: \", pkg, \"") forceUnload(pkg) library(pkg, character.only = TRUE, quietly = TRUE) } } packrat/R/get-package-actions.R0000644000176200001440000000662513352207316016044 0ustar liggesusers# returns a list of actions that would be performed if the given action were # performed on the given project getActions <- function(verb, project) { project <- getProjectDir(project) if (verb == "restore") actionFunc <- restore else if (verb == "snapshot") actionFunc <- snapshot else if (verb == "clean") actionFunc <- clean else stop("Unknown action '", verb, "'") suppressMessages(actionFunc(project = project, dry.run = TRUE)) } getActionMessages <- function(verb, project) { records <- getActions(verb, project) suppressMessages(packageActionMessages(verb, records)) } packageActionMessages <- function(verb, records) { if (!length(records$actions)) { message("No ", verb, " actions to perform!") return(invisible(NULL)) } pkgNames <- names(records$actions) ip <- installed.packages() installedPkgInfo <- suppressWarnings(getInstalledPkgInfo(pkgNames, ip)) # pkgRecords # |__ . # | |__ name # | |__ source # | |__ version # | |__ source_path # | \__ depends # \__ . # |__ name # |__ source # |__ version # |__ source_path # \__ depends # actions # repos # project # targetLib parens <- function(x) { paste("(", x, ")", sep = "", collapse = ", ") } n <- length(records$actions) msgs <- data.frame( package = names(records$actions), action = unname(records$actions), packrat.version = character(n), library.version = character(n), message = character(n), stringsAsFactors = FALSE ) for (i in seq_along(records$actions)) { action <- records$actions[[i]] package <- names(records$actions)[[i]] record <- records$pkgRecords[sapply(records$pkgRecords, function(x) { x$name == package })] packrat.version <- if (length(record) == 1) record[[1]]$version else NA library.version <- installedPkgInfo[[package]][["Version"]] %||% NA if (verb == "snapshot") { msgs$message[[i]] <- switch(action, add = paste("Add", shQuote(package), parens(library.version), "to Packrat"), remove = paste("Remove", shQuote(package), parens(packrat.version), "from Packrat"), upgrade = paste("Replace", shQuote(package), parens(paste(packrat.version, "->", library.version)), "in Packrat"), downgrade = paste("Replace", shQuote(package), parens(paste(packrat.version, "->", library.version)), "in Packrat"), crossgrade = paste("Crossgrade", shQuote(package), parens(paste(packrat.version, "->", library.version)), "in Packrat"), stop("Unrecognized action") ) } else { msgs$message[[i]] <- switch(action, add = paste("Install", shQuote(package), parens(packrat.version)), remove = paste("Uninstall", shQuote(package), parens(packrat.version)), upgrade = paste("Upgrade", shQuote(package), parens(paste(library.version, "->", packrat.version))), downgrade = paste("Downgrade", shQuote(package), parens(paste(library.version, "->", packrat.version))), crossgrade = paste("Crossgrade", shQuote(package), parens(paste(library.version, "->", packrat.version))), stop("Unrecognized action") ) } msgs$packrat.version[[i]] <- packrat.version msgs$library.version[[i]] <- library.version } msgs } packrat/R/bundle.R0000644000176200001440000001553013352207316013502 0ustar liggesusers#' Bundle a Packrat Project #' #' Bundle a packrat project, for easy sharing. #' #' The project is bundled as a gzipped tarball (\code{.tar.gz}), which can #' be unbundled either with \code{packrat::\link{unbundle}} (which #' restores the project as well), \R's own \code{utils::\link{untar}}, or #' through most system \code{tar} implementations. #' #' @param project The project directory. Defaults to the currently activate #' project. By default, the current project active under \code{packratMode} #' is checked. #' @param file The path to write the bundle. By default, we write #' the bundle to \code{packrat/bundles/-.tar.gz}, with #' \code{} as returned by \code{Sys.date()}. #' @param include.src Include the packrat sources? #' @param include.lib Include the packrat private library? #' @param include.bundles Include other packrat bundle tarballs #' (as in \code{packrat/bundles/})? #' @param include.vcs.history Include version control history (ie, \code{.git/} #' or \code{.svn/} folders)? #' @param overwrite Boolean; overwrite the file at \code{file} if it already exists? #' @param omit.cran.src Boolean; when \code{TRUE}, packages whose sources can #' be retrieved from CRAN are excluded from the bundle. #' @param ... Optional arguments passed to \code{\link{tar}}. #' @export #' @return The path (invisibly) to the bundled project. bundle <- function(project = NULL, file = NULL, include.src = TRUE, include.lib = FALSE, include.bundles = TRUE, include.vcs.history = FALSE, overwrite = FALSE, omit.cran.src = FALSE, ...) { project <- getProjectDir(project) stopIfNotPackified(project) # Make sure we're in the project dir so relative paths are properly set owd <- getwd() on.exit(setwd(owd), add = TRUE) setwd(project) # If file is NULL, write to a local file with the current date if (is.null(file)) { tarName <- paste(basename(project), Sys.Date(), sep = "-") tarName <- paste(tarName, ".tar.gz", sep = "") bundlesDir <- bundlesDir(project) if (!file.exists(bundlesDir)) { dir.create(bundlesDir, recursive = TRUE) } file <- file.path(bundlesDir(project), tarName) } file <- file.path( normalizePath(dirname(file), mustWork = FALSE), basename(file) ) if (file.exists(file) && !overwrite) { stop("A file already exists at file location '", file, "'.") } # Regex negation patterns that we use to selectively leave some items out pattern <- c( "^(?!\\.Rproj\\.user)", "^(?!\\.Rhistory)", if (!include.src) "^(?!packrat/src/)", if (!include.lib) "^(?!packrat/lib.*)", if (!include.bundles) "^(?!packrat/bundles/)", if (!include.vcs.history) "^(?!\\.(git|svn))" ) ## Make sure the base folder name is inheritted from the project name ## ## The internal version of 'tar' used by R on Windows fails if one tries to include ## a file in a sub-directory, without actually including that subdirectory. ## To work around this, we are forced to copy the files we want to tar to ## a temporary directory, and then tar that. bundlePath <- file.path(tempdir(), "packrat-bundles") from <- getwd() to <- file.path(bundlePath, basename(project)) dir_copy( from = from, to = to, pattern = pattern, overwrite = TRUE ) ## Clean up after ourselves on.exit(unlink(to, recursive = TRUE), add = TRUE) ## Remove any CRAN packages if 'omit.cran.src' was specified. if (omit.cran.src) { lockfile <- readLockFilePackages(lockFilePath(project)) pkgs <- vapply(lockfile, `[[`, FUN.VALUE = character(1), "name", USE.NAMES = FALSE) isCRAN <- vapply(lockfile, FUN.VALUE = logical(1), function(x) { x[["source"]] == "CRAN" }) cranPkgs <- pkgs[isCRAN] srcPkgs <- list.files( srcDir(project = to), full.names = TRUE, recursive = TRUE ) for (srcPkg in srcPkgs) { isPathToCranPkg <- any(unlist(lapply(cranPkgs, function(cranPkg) { grepl(cranPkg, basename(srcPkg)) }))) if (isPathToCranPkg) { unlink(srcPkg) } } } ## Now bundle up that copied directory, from the tempdir path setwd(bundlePath) result <- tar( tarfile = file, files = basename(project), compression = "gzip", tar = "internal", ... ) if (result != 0) { stop("Failed to bundle the packrat project.") } message("The packrat project has been bundled at:\n- \"", file, "\"") invisible(file) } extractProjectNameFromBundlePath <- function(bundlePath) { bundleBasename <- basename(bundlePath) reDate <- "^(.*?)-\\d{4}-\\d{2}-\\d{2}\\.tar\\.gz$" if (grepl(reDate, bundleBasename, perl = TRUE)) gsub(reDate, "\\1", bundleBasename, perl = TRUE) } ##' Unbundle a Packrat Project ##' ##' Unbundle a previously \code{\link{bundle}}d project. ##' ##' @param bundle Path to the bundled file. ##' @param where The directory where we will unbundle the project. ##' @param ... Optional arguments passed to \code{\link{tar}}. ##' @param restore Boolean; should we \code{\link{restore}} the library ##' after \code{unbundle}-ing the project? ##' @export unbundle <- function(bundle, where, ..., restore = TRUE) { bundle <- normalizePath(bundle, winslash = "/", mustWork = TRUE) if (!file.exists(where) && is_dir(where)) { dir.create(where, recursive = TRUE) } where <- normalizePath(where, winslash = "/", mustWork = TRUE) ## Get the list of files in the output directory -- we diff against it ## to figure out what the top-level directory name is owd <- getwd() on.exit(setwd(owd), add = TRUE) setwd(where) # Ensure that the directory we'll be creating doesn't already exist. # It's possible that people will have renamed the bundles, so make # this a no-op on error. projectName <- extractProjectNameFromBundlePath(bundle) if (!is.null(projectName) && file.exists(file.path(where, projectName))) stop("Path '", file.path(where, projectName), "' already exists!") whereFiles <- list.files() message("- Untarring '", basename(bundle), "' in directory '", where, "'...") untar(bundle, exdir = where, tar = "internal", ...) dirName <- normalizePath(setdiff(list.files(), whereFiles), winslash = "/", mustWork = TRUE) if (restore) { if (length(dirName) != 1) { stop("Couldn't infer top-level directory name; cannot perform automatic restore") } setwd(dirName) ## Ensure the (empty) library directory is present before restoring dir.create(libDir(getwd()), recursive = TRUE, showWarnings = FALSE) message("- Restoring project library...") restore(project = getwd(), restart = FALSE) message("Done! The project has been unbundled and restored at:\n- \"", dirName, "\"") } else { message("Done! The packrat project has been unbundled at:\n- \"", dirName, "\"") } invisible(dirName) } packrat/R/install-local.R0000644000176200001440000000451613352207316014771 0ustar liggesusersfindPackageDirectoriesAndTarballs <- function(dir) { dirs <- list.dirs(dir, recursive = FALSE) hasDesc <- unlist(lapply(dirs, function(dir) { file.exists(file.path(dir, "DESCRIPTION")) })) dirs[hasDesc] } ##' Install a Package from a Local Repository ##' ##' This function can be used to install a package from a local 'repository'; i.e., ##' a directory containing package tarballs and sources. ##' ##' @param pkgs A character vector of package names. ##' @param lib The library in which the package should be installed. ##' @param repos The local repositories to search for the package names specified. ##' @param ... Optional arguments passed to \code{\link[packrat]{install}}. ##' @export install_local <- function(pkgs, ..., lib = .libPaths()[1], repos = get_opts("local.repos")) { for (pkg in pkgs) { install_local_single(pkg, lib = lib, repos = repos, ...) } } findLocalRepoForPkg <- function(pkg, repos = get_opts("local.repos"), fatal = TRUE) { if (!length(repos) || identical(repos, "")) return(character()) # Search through the local repositories for a suitable package hasPackage <- unlist(lapply(repos, function(repo) { file.exists(file.path(repo, pkg)) })) names(hasPackage) <- repos numFound <- sum(hasPackage) if (numFound == 0) { if (fatal) { stop("No package '", pkg, "' found in local repositories specified") } else { return(NULL) } } if (numFound > 1) warning("Package '", pkg, "' found in multiple local repositories:\n- ", paste(shQuote(file.path(repos[hasPackage], pkg)), collapse = ", ")) repos[hasPackage][1] } install_local_single <- function(pkg, lib = .libPaths()[1], repos = get_opts("local.repos"), fatal = TRUE, ...) { if (!length(repos) || identical(repos, "")) stop("No local repositories have been defined. ", "Use 'packrat::set_opts(local.repos = ...)' to add local repositories.", call. = FALSE) repoToUse <- findLocalRepoForPkg(pkg, repos, fatal = fatal) path <- file.path(repoToUse, pkg) with_libpaths(lib, install_local_path(path = path, ...)) } packrat/R/available-updates.R0000644000176200001440000001264713352207316015622 0ustar liggesusersenumerate <- function(x, f, ...) { result <- vector("list", length(x)) for (i in seq_along(x)) { result[[i]] <- f(x[[i]], ...) } names(result) <- names(x) result } githubUpdates <- function(lib.loc = .libPaths()) { do.call(rbind, enumerate(lib.loc, function(lib) { pkgs <- list.files(lib, full.names = TRUE) DESCRIPTIONS <- enumerate(pkgs, function(pkg) { path <- file.path(pkg, "DESCRIPTION") if (!file.exists(path)) return(NULL) readDcf(path) }) names(DESCRIPTIONS) <- pkgs DESCRIPTIONS <- Filter(function(x) any(grepl("^Github", colnames(x))), DESCRIPTIONS) if (!length(DESCRIPTIONS)) return(NULL) if (!requireNamespace("httr")) stop("Need package 'httr' to check for GitHub updates") do.call(rbind, enumerate(DESCRIPTIONS, function(x) { url <- file.path("https://api.github.com", "repos", x[, "GithubUsername"], x[, "GithubRepo"], "branches") response <- httr::GET(url) status <- response$status if (response$status == 403) { warning("rejected by server", call. = FALSE) sha1 <- NA } else if (!response$status == 200) { warning("failed to get tracking information for GitHub package '", x[, "Package"], "'; did its associated repository move?", call. = FALSE) sha1 <- NA } else { content <- httr::content(response, "parsed") ## Find the index of the response with the appropriate name index <- which(sapply(content, `[[`, "name") == x[, "GithubRef"]) if (!length(index)) { warning("no reference '", x[, "GithubRef"], "' found associated with this repository; was the branch deleted?", call. = FALSE) sha1 <- NA } else { sha1 <- content[[index]]$commit$sha } } data.frame( stringsAsFactors = FALSE, Package = unname(x[, "Package"]), LibPath = lib, Installed = unname(x[, "GithubSHA1"]), Built = gsub(";.*", "", x[, "Built"]), ReposVer = sha1, Repository = file.path("https://github.com", x[, "GithubUsername"], x[, "GithubRepo"], "tree", x[, "GithubRef"]) ) # Gross dependency-free version # dest <- tempfile() # status <- download(url, destfile = dest, quiet = TRUE) # content <- readLines(dest) # sha1_scraped <- grep("Copy SHA", content, fixed = TRUE, value = TRUE) # sha1 <- gsub("^(.*?)data-clipboard-text=\"(.*?)\"(.*?)$", "\\2", sha1_scraped, perl = TRUE) })) })) } bitbucketUpdates <- function(lib.loc = .libPaths()) { do.call(rbind, enumerate(lib.loc, function(lib) { pkgs <- list.files(lib, full.names = TRUE) DESCRIPTIONS <- enumerate(pkgs, function(pkg) { path <- file.path(pkg, "DESCRIPTION") if (!file.exists(path)) return(NULL) readDcf(path) }) names(DESCRIPTIONS) <- pkgs DESCRIPTIONS <- Filter(function(x) "RemoteType" %in% colnames(x) && x[,"RemoteType"] == "bitbucket", DESCRIPTIONS) if (!length(DESCRIPTIONS)) return(NULL) if (!requireNamespace("httr")) stop("Need package 'httr' to check for Bitbucket updates") do.call(rbind, enumerate(DESCRIPTIONS, function(x) { url <- file.path("https://api.bitbucket.org", "2.0", "repositories", x[, "RemoteUsername"], x[, "RemoteRepo"], "refs", "branches") response <- httr::GET(url) status <- response$status if (response$status == 403) { warning("rejected by server", call. = FALSE) sha <- NA } else if (!response$status == 200) { warning("failed to get tracking information for Bitbucket package '", x[, "Package"], "'; did its associated repository move?", call. = FALSE) sha <- NA } else { content <- httr::content(response, "parsed") ## Find the index of the response with the appropriate name index <- which(sapply(content$values, `[[`, "name") == x[, "RemoteRef"]) if (!length(index)) { warning("no reference '", x[, "RemoteRef"], "' found associated with this repository; was the branch deleted?", call. = FALSE) sha <- NA } else { sha <- content$values[[index]]$target$hash } } data.frame( stringsAsFactors = FALSE, Package = unname(x[, "Package"]), LibPath = lib, Installed = unname(x[, "RemoteSha"]), Built = gsub(";.*", "", x[, "Built"]), ReposVer = sha, Repository = file.path("https://bitbucket.org", x[, "RemoteUsername"], x[, "RemoteRepo"], "src", x[, "RemoteRef"]) ) })) })) } available_updates <- function() { cranUpdates <- as.data.frame(old.packages(), stringsAsFactors = FALSE) githubUpdates <- githubUpdates() bitbucketUpdates <- bitbucketUpdates() list( CRAN = cranUpdates, GitHub = githubUpdates, Bitbucket = bitbucketUpdates ) } packrat/R/github.R0000644000176200001440000000137213352207316013512 0ustar liggesusersisGitHubURL <- function(url) { is.string(url) && grepl("^http(?:s)?://(?:www|api).github.com", url, perl = TRUE) } canUseGitHubDownloader <- function() { all(packageVersionInstalled(devtools = "1.9.1", httr = "1.0.0")) } githubDownload <- function(url, destfile, ...) { onError(1, { github_pat <- yoink("devtools", "github_pat") authenticate <- yoink("httr", "authenticate") GET <- yoink("httr", "GET") content <- yoink("httr", "content") token <- github_pat(quiet = TRUE) auth <- if (!is.null(token)) authenticate(token, "x-oauth-basic", "basic") else list() request <- GET(url, auth) writeBin(content(request, "raw"), destfile) if (file.exists(destfile)) 0 else 1 }) } packrat/R/external.R0000644000176200001440000000725713372654757014103 0ustar liggesusers##' Managing External Libraries ##' ##' These functions provide a mechanism for (temporarily) using packages outside ##' of the packrat private library. The packages are searched within the 'default' ##' libraries; that is, the libraries that would be available upon launching a new ##' \R session. ##' ##' @param packages An optional set of package names (as a character ##' vector) to load for the duration of evaluation of \code{expr}. ##' Whether \code{packages} is provided or \code{NULL} (the ##' default), \code{expr} is evaluated in an environment where the ##' external library path is in place, not the local (packrat) ##' library path. ##' @param expr An \R expression. ##' @param envir An environment in which the expression is evaluated. ##' @name packrat-external ##' @rdname packrat-external ##' @examples \dontrun{ ##' with_extlib("lattice", xyplot(1 ~ 1)) ##' with_extlib(expr = packageVersion("lattice")) ##' # since devtools requires roxygen2 >= 5.0.0 for this step, this ##' # should fail unless roxygen2 is available in the packrat lib.loc ##' with_extlib("devtools", load_all("path/to/project")) ##' # this method will work given roxygen2 is installed in the ##' # non-packrat lib.loc with devtools ##' with_extlib(expr = devtools::load_all("path/to/project")) ##' } ##' @export with_extlib <- function(packages = NULL, expr, envir = parent.frame()) { # need to force this promise now otherwise it will get evaluated # in the wrong context later on force(envir) if (!is.null(packages) && !is.character(packages)) { stop("'packages' should be a character vector of libraries", call. = FALSE) } call <- match.call() local({ tryCatch({ ## Record the search path, then load the libraries oldSearch <- search() libPaths <- .packrat_mutables$get("origLibPaths") oldLibPaths <- .libPaths() if (!length(libPaths)) libPaths <- getDefaultLibPaths() .libPaths(libPaths) for (package in packages) { library(package, character.only = TRUE, warn.conflicts = FALSE) } ## Evaluate the call error <- try(res <- eval(call$expr, envir = envir), silent = TRUE) ## Now, propagate the error / result if (exists("res", envir = environment(), inherits = FALSE)) { res } else { stop(attr(error, "condition")$message, call. = FALSE) } }, finally = { newSearch <- search() for (path in setdiff(newSearch, oldSearch)) { try(forceUnload(path)) } .libPaths(oldLibPaths) }) }) } ##' @name packrat-external ##' @rdname packrat-external ##' @export extlib <- function(packages) { # place user library at front of library paths (we want to # include both the user library and the packrat library just # so that external packaegs can still load and depend on # packages only installed within the private library as well) oldLibPaths <- .libPaths() newLibPaths <- c(getDefaultLibPaths(), .libPaths()) .libPaths(newLibPaths) on.exit(.libPaths(oldLibPaths), add = TRUE) for (package in packages) library(package, character.only = TRUE) } loadExternalPackages <- function() { pkgs <- get_opts("external.packages") if (length(pkgs)) { pkgs <- pkgs[ !is.null(pkgs) & !is.na(pkgs) & nchar(pkgs) ] failures <- dropNull(lapply(pkgs, function(pkg) { tryCatch( expr = extlib(pkg), error = function(e) { pkg } ) })) if (length(failures)) { failures <- as.character(unlist(failures)) message("Warning: failed to load the following external packages:\n- ", paste(shQuote(failures), collapse = ", ")) } return(length(failures) > 0) } return(TRUE) } packrat/R/testthat-helpers.R0000644000176200001440000001345713352207316015537 0ustar liggesusers# Clone a test project into a temporary directory for manipulation; returns the # path to the test project cloneTestProject <- function(projectName) { root <- file.path("projects", projectName) target <- tempdir() if (file.exists(file.path(target, projectName))) { unlink(file.path(target, projectName), recursive = TRUE) } file.copy(root, target, recursive = TRUE) return(file.path(target, projectName)) } # "Rebuilds" the test repo from its package "sources" (just DESCRIPTION files). rebuildTestRepo <- function(testroot = getwd()) { # Try to guess where the DESCRIPTION file lives (for R CMD check # and for interactive testing) candidates <- c( "DESCRIPTION", "../../DESCRIPTION", "../../00_pkg_src/packrat/DESCRIPTION", "../../packrat/DESCRIPTION" ) for (candidate in candidates) { if (file.exists(candidate)) { DESCRIPTION <- normalizePath(candidate, winslash = "/") break } } owd <- getwd() on.exit(setwd(owd)) # Move to the folder housing our dummy packages. source <- file.path(testroot, "packages") setwd(source) # Create a dummy folder for the current version of Packrat. dir.create("packrat", showWarnings = FALSE) file.copy(DESCRIPTION, "packrat/DESCRIPTION", overwrite = TRUE) # Force Packrat tests to believe the currently installed / tested # version of Packrat is on CRAN. cat("Repository: CRAN", file = "packrat/DESCRIPTION", sep = "\n", append = TRUE) # Copy in the dummy folders. target <- file.path(testroot, "repo", "src", "contrib") unlink(target, recursive = TRUE) dir.create(target, recursive = TRUE) pkgs <- list.files(source) for (pkg in pkgs) { descfile <- as.data.frame(read.dcf(file.path(source, pkg, "DESCRIPTION"))) tarball <- paste(pkg, "_", as.character(descfile$Version), ".tar.gz", sep = "") tar(tarball, pkg, compression = "gzip", tar = "internal") dir.create(file.path(target, pkg)) file.rename(file.path(source, tarball), file.path(target, pkg, tarball)) } tools::write_PACKAGES(target, subdirs = TRUE) } # Installs a test package from source. Necessary because install.packages # fails under R CMD CHECK. installTestPkg <- function(pkg, ver, lib) { pkgSrc <- file.path("repo", "src", "contrib", pkg, paste(pkg, "_", ver, ".tar.gz", sep = "")) install_local_path(path = pkgSrc, reload = FALSE, args = paste("-l", lib), dependencies = FALSE, quick = TRUE, quiet = TRUE) } # Adds a dependency on a package to a test project addTestDependency <- function(projRoot, pkg) { write(paste("library(", pkg, ")", sep = ""), file = file.path(projRoot, "deps.R"), append = TRUE) } # Removes a dependency from a test project (by deleting a file... fancy!) removeTestDependencyFile <- function(projRoot, file) { unlink(file.path(projRoot, file)) } verifyTopoSort <- function(graph, sorted) { if (length(graph) != length(sorted)) return(FALSE) if (length(sorted) < 2) return(TRUE) if (!identical(unique(sorted), sorted)) return(FALSE) if (any(is.na(sorted)) || any(is.na(names(graph)))) return(FALSE) for (i in seq_along(sorted)) { deps <- graph[[sorted[[i]]]] if (length(setdiff(deps, head(sorted, i - 1))) > 0) { return(FALSE) } } return(TRUE) } # Make the 'libraries' 'project' -- this is used to test whether files within the # packrat controlled libraries are ignored makeLibrariesProject <- function() { if (basename(getwd()) != "testthat") { warning("This function is only used to build a sample 'libraries' project in the testthat dir") return(NULL) } project <- file.path("projects", "libraries") unlink(project, recursive = TRUE) dir.create(project) cat("library(bread)", file = file.path(project, "library.R"), sep = "\n") ## Create the potential packrat libraries that might exist dir.create(newLibraryDir(project), recursive = TRUE) dir.create(oldLibraryDir(project), recursive = TRUE) dir.create(libraryRootDir(project), recursive = TRUE) # Some files within depending on oatmeal cat("library(oatmeal)", file = file.path(libraryRootDir(project), "lib-current.R"), sep = "\n") cat("library(oatmeal)", file = file.path(oldLibraryDir(project), "lib-old.R"), sep = "\n") cat("library(oatmeal)", file = file.path(newLibraryDir(project), "lib-new.R"), sep = "\n") project } # Sets up repositories etc. for a test context, and restores them when done. beginTestContext <- function() { fields <- c("repos", "pkgType", "warn") options <- setNames(lapply(fields, getOption), fields) Sys.setenv(R_PACKRAT_TESTING = "yes") Sys.setenv(R_PACKRAT_LIBPATHS = paste(.libPaths(), collapse = .Platform$path.sep)) CRAN <- paste(filePrefix(), normalizePath("repo", winslash = "/"), sep = "") options(repos = c(CRAN = CRAN), pkgType = "source", warn = 0) assign("test.options", options, envir = .packrat) } endTestContext <- function() { Sys.unsetenv("R_PACKRAT_TESTING") Sys.unsetenv("R_PACKRAT_LIBPATHS") options <- get("test.options", envir = .packrat) do.call(base::options, options) } withTestContext <- function(expr) { beginTestContext() force(expr) endTestContext() } scopeTestContext <- function() { beginTestContext() defer(endTestContext(), parent.frame()) } bundle_test <- function(bundler, checker, ...) { # set and restore directory owd <- setwd(tempdir()) on.exit(setwd(owd), add = TRUE) # create temporary directory dir <- file.path(tempdir(), "packrat-test-bundle") dir.create(dir) on.exit(unlink(dir, recursive = TRUE), add = TRUE) # enter, bundle and untar setwd("packrat-test-bundle") suppressWarnings(packrat::init(enter = FALSE)) bundler(file = "test-bundle.tar.gz", ...) utils::untar("test-bundle.tar.gz", exdir = "untarred", tar = "internal") # run checker checker() } packrat/R/env.R0000644000176200001440000000126113352207316013015 0ustar liggesusers# Tools for storing state in environment variables. getenv <- function(x) { strsplit(Sys.getenv(x, unset = ""), .Platform$path.sep, fixed = TRUE)[[1]] } setenv <- function(...) { dots <- list(...) # validate argument length n <- length(dots) if (n %% 2 != 0) stop("expected even number of arguments to 'setenv'") # extract keys, values from '...' indices <- seq(1, length(dots), by = 2) keys <- dots[indices] vals <- dots[indices + 1] # construct call to Sys.setenv names(vals) <- keys vals <- lapply(vals, function(val) { paste(val, collapse = .Platform$path.sep) }) do.call(Sys.setenv, vals) } unsetenv <- function(name) { Sys.unsetenv(name) } packrat/R/pkg.R0000644000176200001440000004524213353453167013025 0ustar liggesusers# Package dependency: # list( # name = 'ggplot2', # source = 'CRAN', # version = '0.9.3.1', # or: '>= 3.0', 'github:hadley/ggplot2/fix/axis', '' # ) # Package record: # list( # name = 'ggplot2', # source = 'github', # version = '0.9.3.1', # gh_repo = 'ggplot2', # gh_username = 'hadley', # gh_ref = 'master', # gh_sha1 = '66b81e9307793029f6083fc6108592786a564b09' # # Optional: # , gh_subdir = 'pkg' # ) # Checks whether a package was installed from source and is # within the packrat ecosystem hasSourcePathInDescription <- function(pkgNames, lib.loc) { pkgNames[unlist(lapply(pkgNames, function(pkg) { # Get the package location in the library path loc <- find.package(pkg, lib.loc, quiet = TRUE) # If there was no package, FALSE if (!length(loc)) return(FALSE) # If there's no DESCRIPTION (not sure how this could happen), warn + FALSE if (!file.exists(file.path(loc, "DESCRIPTION"))) { warning("Package '", pkg, "' was found at library location '", loc, "' but has no DESCRIPTION") return(FALSE) } # Read the DESCRIPTION and look for Packrat fields dcf <- readDcf(file.path(loc, "DESCRIPTION")) "InstallSourcePath" %in% colnames(dcf) }))] } # Returns package records for a package that was installed from source by # packrat (and is within the packrat ecosystem) getPackageRecordsInstalledFromSource <- function(pkgs, lib.loc) { lapply(pkgs, function(pkg) { loc <- find.package(pkg, lib.loc) dcf <- as.data.frame(readDcf(file.path(loc, "DESCRIPTION")), stringsAsFactors = FALSE) deps <- combineDcfFields(dcf, c("Depends", "Imports", "LinkingTo")) deps <- deps[deps != "R"] record <- structure(list( name = pkg, source = 'source', version = dcf$Version, source_path = dcf$InstallSourcePath, hash = hash(file.path(loc, "DESCRIPTION")) ), class = c('packageRecord', 'source')) }) } # Get package records for those manually specified with source.packages getPackageRecordsLocalRepos <- function(pkgNames, repos, fatal = TRUE) { lapply(pkgNames, function(pkgName) { getPackageRecordsLocalReposImpl(pkgName, repos, fatal = fatal) }) } getPackageRecordsLocalReposImpl <- function(pkg, repos, fatal = TRUE) { repoToUse <- findLocalRepoForPkg(pkg, repos, fatal = fatal) if (!length(repoToUse)) return(NULL) path <- file.path(repoToUse, pkg) dcf <- as.data.frame(readDcf(file.path(path, "DESCRIPTION")), stringsAsFactors = FALSE) deps <- combineDcfFields(dcf, c("Depends", "Imports", "LinkingTo")) deps <- deps[deps != "R"] structure(list( name = pkg, source = 'source', version = dcf$Version, source_path = file.path(repoToUse, pkg), hash = hash(file.path(repoToUse, pkg, "DESCRIPTION")) ), class = c('packageRecord', 'source')) } getPackageRecordsExternalSource <- function(pkgNames, available, lib.loc, missing.package, fallback.ok = FALSE) { lapply(pkgNames, function(pkgName) { # The actual package record that will be populated by below logic. result <- list() # First, attempt to discover the actual installation for this package. pkgDescFile <- system.file("DESCRIPTION", package = pkgName, lib.loc = lib.loc) if (file.exists(pkgDescFile)) { # If the package is currently installed, then we can return a package # record constructed from the DESCRIPTION file. df <- as.data.frame(readDcf(pkgDescFile)) result <- suppressWarnings(inferPackageRecord(df)) # Normalize NULL source vs. 'unknown' source. if (is.null(result$source)) result$source <- "unknown" # If we don't know the package source, but the user has opted in # to CRAN fallback, then warn the user and update the inferred source. if (fallback.ok && result$source == "unknown") { fmt <- paste( "Package '%s %s' was installed from sources;", "Packrat will assume this package is available from", "a CRAN-like repository during future restores" ) warning(sprintf(fmt, pkgName, result$version)) result$source <- "CRAN" } } else if (fallback.ok && pkgName %in% rownames(available)) { # The package is not currently installed, but is available on CRAN. # Snapshot the latest available version for this package from CRAN. warning("Failed to infer source for package '", pkgName, "'; using ", "latest available version on CRAN instead") # Construct the package record by hand -- generate the minimal # bits of the DESCRIPTION file, and infer the package record # from that. pkg <- available[pkgName,] df <- data.frame( Package = pkg[["Package"]], Version = pkg[["Version"]], Repository = "CRAN" ) result <- suppressWarnings(inferPackageRecord(df)) } else { # We were unable to determine an appropriate package record # for this package; invoke the 'missing.package' callback. return(missing.package(pkgName, lib.loc)) } # Update the hash when available. if (nzchar(pkgDescFile)) result$hash <- hash(pkgDescFile) result }) } getPackageRecordsLockfile <- function(pkgNames, project) { if (file.exists(lockFilePath(project))) { result <- readLockFile(lockFilePath(project))$packages result[unlist(lapply(result, function(x) { x$name %in% pkgNames }))] } else { list() } } error_not_installed <- function(package, lib.loc) { stop( 'The package "', package, '" is not installed in ', ifelse(is.null(lib.loc), 'the current libpath', lib.loc) ) } # Returns a package records for the given packages getPackageRecords <- function(pkgNames, project = NULL, available = NULL, recursive = TRUE, lib.loc = NULL, missing.package = error_not_installed, check.lockfile = FALSE, fallback.ok = FALSE) { project <- getProjectDir(project) local.repos <- get_opts("local.repos", project = project) # screen out empty package names that might have snuck in pkgNames <- setdiff(pkgNames, "") if (check.lockfile) { lockfilePkgRecords <- getPackageRecordsLockfile(pkgNames, project = project) pkgNames <- setdiff(pkgNames, sapply(lockfilePkgRecords, "[[", "name")) } else { lockfilePkgRecords <- list() } # First, get the package records for packages installed from source pkgsInstalledFromSource <- hasSourcePathInDescription(pkgNames, lib.loc = lib.loc) srcPkgRecords <- getPackageRecordsInstalledFromSource(pkgsInstalledFromSource, lib.loc = lib.loc) pkgNames <- setdiff(pkgNames, pkgsInstalledFromSource) # Next, get the package records for packages that are now presumedly from # an external source externalPkgRecords <- suppressWarnings( getPackageRecordsExternalSource(pkgNames, available = available, lib.loc = lib.loc, missing.package = function(...) NULL) ) # Drop unknowns externalPkgRecords <- externalPkgRecords[unlist(lapply(externalPkgRecords, function(x) { x$source != "unknown" }))] pkgNames <- setdiff(pkgNames, sapply(externalPkgRecords, "[[", "name")) # Finally, get the package records for packages manually specified in source.packages manualSrcPkgRecords <- getPackageRecordsLocalRepos(pkgNames, local.repos, fatal = !fallback.ok) pkgNames <- setdiff(pkgNames, sapply(manualSrcPkgRecords, "[[", "name")) # If there's leftovers (for example, packages installed from source that cannot be located # in any of the local repositories), but it's a package we can find on CRAN, fallback to it if (length(pkgNames) && fallback.ok) { fallbackPkgRecords <- getPackageRecordsExternalSource(pkgNames, available = available, lib.loc = lib.loc, missing.package = function(...) NULL, fallback.ok = fallback.ok) ## TODO: Message or warning when this happens? } else { fallbackPkgRecords <- list() } pkgNames <- setdiff(pkgNames, sapply(fallbackPkgRecords, "[[", "name")) # If there's anything leftover, fail if (length(pkgNames)) stop("Unable to retrieve package records for the following packages:\n- ", paste(shQuote(pkgNames), collapse = ", "), call. = FALSE) # Collect the records together allRecords <- c( lockfilePkgRecords, srcPkgRecords, manualSrcPkgRecords, externalPkgRecords, fallbackPkgRecords ) # Remove any null records allRecords <- dropNull(allRecords) # Now get recursive package dependencies if necessary if (recursive) { allRecords <- lapply(allRecords, function(record) { deps <- getPackageDependencies(pkgs = record$name, lib.loc = lib.loc, available.packages = available) if (!is.null(deps)) { record$depends <- getPackageRecords( deps, project = project, available, TRUE, lib.loc = lib.loc, missing.package = missing.package, check.lockfile = check.lockfile, fallback.ok = fallback.ok ) } record }) } allRecords } # Reads a description file and attempts to infer where the package came from. # Currently works only for packages installed from CRAN or from GitHub/Bitbucket using # devtools 1.4 or later. inferPackageRecord <- function(df) { name <- as.character(df$Package) ver <- as.character(df$Version) if (!is.null(df$GithubRepo)) { # It's GitHub! return(structure(c(list( name = name, source = 'github', version = ver, gh_repo = as.character(df$GithubRepo), gh_username = as.character(df$GithubUsername), gh_ref = as.character(df$GithubRef), gh_sha1 = as.character(df$GithubSHA1)), c(gh_subdir = as.character(df$GithubSubdir)), c(remote_host = as.character(df$RemoteHost)), c(remote_repo = as.character(df$RemoteRepo)), c(remote_username = as.character(df$RemoteUsername)), c(remote_ref = as.character(df$RemoteRef)), c(remote_sha = as.character(df$RemoteSha)) ), class = c('packageRecord', 'github'))) } else if (!is.null(df$RemoteType) && df$RemoteType == "bitbucket") { # It's Bitbucket! return(structure(c(list( name = name, source = 'bitbucket', version = ver, remote_repo = as.character(df$RemoteRepo), remote_username = as.character(df$RemoteUsername), remote_ref = as.character(df$RemoteRef), remote_sha = as.character(df$RemoteSha)), c(remote_host = as.character(df$RemoteHost)), c(remote_subdir = as.character(df$RemoteSubdir)) ), class = c('packageRecord', 'bitbucket'))) } else if (identical(as.character(df$Priority), 'base')) { # It's a base package! return(NULL) } else if (!is.null(df$biocViews)) { # It's Bioconductor! return(structure(list( name = name, source = 'Bioconductor', version = ver ), class = c('packageRecord', 'Bioconductor'))) } else if (!is.null(df$Repository) && identical(as.character(df$Repository), 'CRAN')) { # It's CRAN! return(structure(list( name = name, source = 'CRAN', version = ver ), class = c('packageRecord', 'CRAN'))) } else if (!is.null(df$Repository)) { # It's a package from a custom CRAN-like repo! return(structure(list( name = name, source = as.character(df$Repository), version = ver ), class = c("packageRecord", "CustomCRANLikeRepository"))) } else if (identical(as.character(df$InstallSource), "source")) { # It's a local source package! return(structure(list( name = name, source = 'source', version = ver ), class = c('packageRecord', 'source'))) } else if ((identical(name, "manipulate") || identical(name, "rstudio")) && identical(as.character(df$Author), "RStudio")) { # The 'manipulate' and 'rstudio' packages are auto-installed by RStudio # into the package library; ignore them so they won't appear orphaned. return(NULL) } else { # Don't warn if this is an R package being managed by packrat. # NOTE: Not all projects with DESCRIPTION files are R packages! pkgName <- NULL if (isPackratModeOn()) { projectPath <- .packrat_mutables$get("project") if (!is.null(projectPath) && isRPackage(projectPath)) { pkgName <- tryCatch( unname(readDcf(file.path(projectPath, "DESCRIPTION"))[, "Package"]), error = function(e) NULL ) } } if (!identical(pkgName, name)) { warning("Couldn't figure out the origin of package ", name) } return(structure(list( name = name, source = 'unknown', version = ver ), class = 'packageRecord')) } } # Given a list of source package paths, parses the DESCRIPTION for each and # returns a data frame containing each (with row names given by package names) getSourcePackageInfo <- function(source.packages) { info <- lapply(source.packages, getSourcePackageInfoImpl) result <- do.call(rbind, info) row.names(result) <- result$name result } getSourcePackageInfoImpl <- function(path) { ## For tarballs, we unzip them to a temporary directory and then read from there tempdir <- file.path(tempdir(), "packrat", path) if (endswith(path, "tar.gz")) { untar(path, exdir = tempdir, tar = "internal") folderName <- list.files(tempdir, full.names = TRUE)[[1]] } else { folderName <- path } descPath <- file.path(folderName, "DESCRIPTION") if (!file.exists(descPath)) { stop("Cannot treat ", path, " as a source package directory; ", descPath, " is missing.") } desc <- as.data.frame(readDcf(descPath)) data.frame( name = as.character(desc$Package), version = as.character(desc$Version), path = normalizePath(path, winslash = '/'), stringsAsFactors = FALSE ) } pick <- function(property, package, defaultValue = NA) { func <- function(packageRecord) { if (is.null(packageRecord)) return(defaultValue) else return(packageRecord[[property]]) } if (!missing(package)) { return(func(package)) } else { return(func) } } # If called without a second argument, returns a curried function. If called # with a second argument then it returns the package without the indicated # properties. strip <- function(properties, package) { func <- function(packageRecord) { packageRecord[!names(packageRecord) %in% properties] } if (!missing(package)) { return(func(package)) } else { return(func) } } # Returns a character vector of package names. Depends are ignored. pkgNames <- function(packageRecords) { if (length(packageRecords) == 0) return(character(0)) sapply(packageRecords, pick("name")) } # Filters out all record properties except name and version. Dependencies are # dropped. pkgNamesAndVersions <- function(packageRecords) { if (length(packageRecords) == 0) return(character(0)) lapply(packageRecords, function(pkg) { pkg[names(pkg) %in% c('name', 'version')] }) } # Recursively filters out all record properties except name, version, and # depends. pkgNamesVersDeps <- function(packageRecords) { if (length(packageRecords) == 0) return(character(0)) lapply(packageRecords, function(pkg) { pkg <- pkg[names(pkg) %in% c('name', 'version', 'depends')] pkg$depends <- pkgNamesVersDeps(pkg$depends) return(pkg) }) } # Searches package records recursively looking for packages searchPackages <- function(packages, packageNames) { lapply(packageNames, function(pkgName) { for (pkg in packages) { if (pkg$name == pkgName) return(pkg) if (!is.null(pkg$depends)) { found <- searchPackages(pkg$depends, pkgName)[[1]] if (!is.null(found)) return(found) } } return(NULL) }) } # Returns a linear list of package records, sorted by name, with all dependency # information removed (or, optionally, reduced to names) flattenPackageRecords <- function(packageRecords, depInfo = FALSE, sourcePath = FALSE) { visited <- new.env(parent = emptyenv()) visit <- function(pkgRecs) { for (rec in pkgRecs) { if (isTRUE(depInfo)) { rec$requires <- pkgNames(rec$depends) if (length(rec$requires) == 0) rec$requires <- NA_character_ else if (length(rec$requires) > 1) rec$requires <- paste(rec$requires, collapse = ', ') } visit(rec$depends) rec$depends <- NULL if (!isTRUE(sourcePath)) rec$source_path <- NULL visited[[rec$name]] <- rec } } visit(packageRecords) lapply(sort_c(ls(visited)), function(name) { visited[[name]] }) } # States: NA (unchanged), remove, add, upgrade, downgrade, crossgrade # (crossgrade means name and version was the same but something else was # different, i.e. different source or GitHub SHA1 hash or something) diff <- function(packageRecordsA, packageRecordsB) { removed <- pkgNameDiff(packageRecordsA, packageRecordsB) removed <- structure(rep.int('remove', length(removed)), names = removed) added <- pkgNameDiff(packageRecordsB, packageRecordsA) added <- structure(rep.int('add', length(added)), names = added) both <- pkgNameIntersect(packageRecordsA, packageRecordsB) both <- structure( sapply(both, function(pkgName) { pkgA <- searchPackages(packageRecordsA, pkgName)[[1]] pkgB <- searchPackages(packageRecordsB, pkgName)[[1]] if (identical(strip(c('depends', 'source_path', 'hash'), pkgA), strip(c('depends', 'source_path', 'hash'), pkgB))) return(NA) verComp <- compareVersion(pkgA$version, pkgB$version) if (verComp < 0) return('upgrade') else if (verComp > 0) return('downgrade') else return('crossgrade') }), names = both ) return(c(removed, added, both)) } pkgNameIntersect <- function(packageRecordsA, packageRecordsB) { a <- pkgNames(flattenPackageRecords(packageRecordsA)) b <- pkgNames(flattenPackageRecords(packageRecordsB)) intersect(a, b) } pkgNameDiff <- function(packageRecordsA, packageRecordsB) { a <- pkgNames(flattenPackageRecords(packageRecordsA)) b <- pkgNames(flattenPackageRecords(packageRecordsB)) setdiff(a, b) } packrat/R/augment-rprofile.R0000644000176200001440000000302213352207316015502 0ustar liggesusers## Augment the .Rprofile for a project -- if it doesn't exist, just copy ## from packrat; if it does, check it and add if necessary augmentRprofile <- function(project = NULL) { project <- getProjectDir(project) path <- file.path(project, ".Rprofile") if (!file.exists(path)) { file.copy( instInitRprofileFilePath(), path ) } else { editRprofileAutoloader(project, "update") } } # edit the .Rprofile for this project editRprofileAutoloader <- function(project, action = c("update", "remove")) { # resolve action argument action <- match.arg(action) # if the .Rprofile doesn't exist, create it if (!file.exists(file.path(project, ".Rprofile"))) file.create(file.path(project, ".Rprofile")) ## Read the .Rprofile in and see if it's been packified path <- file.path(project, ".Rprofile") .Rprofile <- readLines(path) packifyStart <- grep("#### -- Packrat Autoloader", .Rprofile, fixed = TRUE) packifyEnd <- grep("#### -- End Packrat Autoloader -- ####", .Rprofile, fixed = TRUE) if (length(packifyStart) && length(packifyEnd)) .Rprofile <- .Rprofile[-c(packifyStart:packifyEnd)] ## Append init.R to the .Rprofile if needed if (identical(action, "update")) .Rprofile <- c(.Rprofile, readLines(instInitRprofileFilePath())) ## if the .Rprofile is now empty, delete it if (identical(gsub("[[:space:]]", "", unique(.Rprofile)), "") || !length(.Rprofile)) file.remove(file.path(project, ".Rprofile")) else cat(.Rprofile, file = path, sep = "\n") invisible() } packrat/R/bitbucket.R0000644000176200001440000000346513352207316014211 0ustar liggesusersisBitbucketURL <- function(url) { is.string(url) && grepl("^http(?:s)?://(?:www|api).bitbucket.(org|com)", url, perl = TRUE) } canUseBitbucketDownloader <- function() { all(packageVersionInstalled(devtools = "1.9.1", httr = "1.0.0")) } bitbucketDownload <- function(url, destfile, ...) { onError(1, { bitbucket_user <- bitbucket_user bitbucket_pwd <- bitbucket_pwd authenticate <- yoink("httr", "authenticate") GET <- yoink("httr", "GET") content <- yoink("httr", "content") user <- bitbucket_user(quiet=TRUE) pwd <- bitbucket_pwd(quiet=TRUE) auth <- if (!is.null(user) & !is.null(pwd)) { authenticate(user, pwd, type="basic") } else { list() } request <- GET(url, auth) if(request$status == 401) { warning("Failed to download package from Bitbucket: not authorized. ", "Did you set BITBUCKET_USERNAME and BITBUCKET_PASSWORD env vars?", call. = FALSE) return(1) } writeBin(content(request, "raw"), destfile) if (file.exists(destfile)) 0 else 1 }) } #' Retrieve Bitbucket user. #' #' A bitbucket user #' Looks in env var \code{BITBUCKET_USERNAME} #' #' @keywords internal #' bitbucket_user <- function(quiet = FALSE) { user <- Sys.getenv("BITBUCKET_USERNAME") if (nzchar(user)) { if (!quiet) { message("Using Bitbucket username from envvar BITBUCKET_USERNAME") } return(user) } return(NULL) } #' Retrieve Bitbucket password #' #' A bitbucket password #' Looks in env var \code{BITBUCKET_PASSWORD} #' #' @keywords internal #' bitbucket_pwd <- function(quiet = FALSE) { pwd <- Sys.getenv("BITBUCKET_PASSWORD") if (nzchar(pwd)) { if (!quiet) { message("Using Bitbucket password from envvar BITBUCKET_PASSWORD") } return(pwd) } return(NULL) } packrat/R/search-path.R0000644000176200001440000000265513352207316014434 0ustar liggesusers##' Get Packages on the Search Path ##' ##' Retrieve the packages on the search path, as well as the ##' associated library location. ##' ##' @export search_path <- function() { ## NOTE: We cannot use searchpaths() here because it follows symlinks -- ## for consistency, we want to use the symlink, not the actual path ## Start by getting everything on the search path + the library location pkgs <- data.frame( package = search(), stringsAsFactors = FALSE ) ## Filter to only actual packages pkgs <- pkgs[ grep("^package:", pkgs$package), , drop = FALSE] ## Clean up the package name by removing the initial 'package:' pkgs$package <- sub("^package:", "", pkgs$package) ## Get the library locations ## NOTE: find.package is special-cased when the first argument is ## of length 1 -- we rely on that behaviour here ## normalizePath used on Windows because .Library can be stored as a ## truncated path ## ...but only do it on Windows, because normalizePath will resolve symlinks, ## which we want to avoid here pkgs$lib.loc <- unlist(lapply(pkgs$package, find.package)) if (is.windows()) { pkgs$lib.loc <- normalizePath(pkgs$lib.loc, winslash = "/") } ## Get just the directory containing the library, not the library path itself pkgs$lib.dir <- dirname(pkgs$lib.loc) ## Arrange by lib.dir pkgs <- pkgs[ order(pkgs$lib.dir), ] ## Unset the rownames rownames(pkgs) <- NULL pkgs } packrat/R/dependencies.R0000644000176200001440000004425513370077201014663 0ustar liggesusers#' Detect Application Dependencies #' #' Recursively detect all package dependencies for an application. This function #' parses all \R files in the application directory to determine what packages #' the application depends directly. #' #' Only direct dependencies are detected (i.e. no recursion is done to find the #' dependencies of the dependencies). #' #' @param project Directory containing application. Defaults to current working #' directory. #' @param implicit.packrat.dependency Include \code{packrat} as an implicit #' dependency of this project, if not otherwise discovered? This should be #' \code{FALSE} only if you can guarantee that \code{packrat} will be available #' via other means when attempting to load this project. #' #' @details Dependencies are determined by parsing application source code and #' looking for calls to \code{library}, \code{require}, \code{::}, and #' \code{:::}. #' #' @return Returns a list of the names of the packages on which R code in the #' application depends. #' #' @examples #' #' \dontrun{ #' #' # dependencies for the app in the current working dir #' appDependencies() #' #' # dependencies for an app in another directory #' appDependencies("~/projects/shiny/app1") #' #' } #' @keywords internal appDependencies <- function(project = NULL, available.packages = NULL, fields = opts$snapshot.fields(), implicit.packrat.dependency = TRUE) { if (is.null(available.packages)) available.packages <- availablePackages() project <- getProjectDir(project) ## We want to search both local and global library paths for DESCRIPTION files ## in the recursive dependency lookup; hence we take a large (ordered) union ## of library paths. The ordering ensures that we search the private library first, ## and fall back to the local / global library (necessary for `packrat::init`) libPaths <- c( libDir(project), .libPaths(), .packrat_mutables$origLibPaths ) ## For R packages, we only use the DESCRIPTION file if (isRPackage(project)) { ## Make sure we get records recursively from the packages in DESCRIPTION parentDeps <- pkgDescriptionDependencies(file.path(project, "DESCRIPTION"))$Package # Strip out any dependencies the user has requested we do not track. parentDeps <- setdiff(parentDeps, packrat::opts$ignored.packages()) ## For downstream dependencies, we don't grab their Suggests: ## Presumedly, we can build child dependencies without vignettes, and hence ## do not need suggests -- for the package itself, we should make sure ## we grab suggests, however childDeps <- recursivePackageDependencies(parentDeps, libPaths, available.packages, fields) } else { parentDeps <- setdiff(unique(c(dirDependencies(project))), "packrat") parentDeps <- setdiff(parentDeps, packrat::opts$ignored.packages()) childDeps <- recursivePackageDependencies(parentDeps, libPaths, available.packages, fields) } result <- unique(c(parentDeps, childDeps)) # should packrat be included as automatic dependency? if (implicit.packrat.dependency) { result <- unique(c(result, "packrat")) } # If this project is implicitly a shiny application, then # add that in as the previously run expression dependency lookup # won't have found it. if (!("shiny" %in% result) && isShinyApp(project)) result <- c(result, "shiny") if (is.null(result)) return(character()) sorted <- sort_c(result) # some users have seen empty package names discovered here # although we don't know the underlying cause, we should # just filter these out as we know they can't be valid setdiff(sorted, "") } # detect all package dependencies for a directory of files dirDependencies <- function(dir) { dir <- normalizePath(dir, winslash = '/') # first get the packages referred to in source code pattern <- "[.](?:r|rmd|rnw|rpres)$" pkgs <- character() R_files <- list.files(dir, pattern = pattern, ignore.case = TRUE, recursive = TRUE ) ## Avoid anything within the packrat directory itself -- all inference ## should be done on user code packratDirRegex <- "(?:^|/)packrat" R_files <- grep(packratDirRegex, R_files, invert = TRUE, value = TRUE) ## Avoid anything on the list of ignored directories ignoredDir <- get_opts("ignored.directories") if (length(ignoredDir) > 0) { # Make sure all the directories end with a slash... ignoredDir <- ifelse( substr(ignoredDir, nchar(ignoredDir), nchar(ignoredDir)) != "/", paste0(ignoredDir, "/"), ignoredDir ) # Make a regex to match any of them. ignoredDirRegex <- paste0( "(?:^", paste0( ignoredDir, collapse=")|(?:^" ), ")" ) R_files <- grep(ignoredDirRegex, R_files, invert = TRUE, value = TRUE) } if (!identical(getOption("packrat.dependency.discovery.disabled"), TRUE)) { sapply(R_files, function(file) { filePath <- file.path(dir, file) pkgs <<- append(pkgs, fileDependencies(file.path(dir, file))) }) } ## Exclude recommended packages if there is no package installed locally ## this places an implicit dependency on the system-installed version of a package dropSystemPackages(pkgs) } # detect all package dependencies for a source file (parses the file and then # recursively examines all expressions in the file) # ad-hoc dispatch based on the file extension fileDependencies <- function(file) { file <- normalizePath(file, winslash = "/", mustWork = TRUE) fileext <- tolower(gsub(".*\\.", "", file)) switch(fileext, r = fileDependencies.R(file), rmd = fileDependencies.Rmd(file), rnw = fileDependencies.Rnw(file), rpres = fileDependencies.Rpres(file), stop("Unrecognized file type '", file, "'") ) } hasYamlFrontMatter <- function(content) { lines <- grep("^(---|\\.\\.\\.)\\s*$", content, perl = TRUE) 1 %in% lines && length(lines) >= 2 && grepl("^---\\s*$", content[1], perl = TRUE) } yamlDeps <- function(yaml) { c( "shiny"[any(grepl("runtime:[[:space:]]*shiny", yaml, perl = TRUE))], "rticles"[any(grepl("rticles::", yaml, perl = TRUE))] ) } stripAltEngines <- function(file, encoding) { contents <- readLines(file, encoding = encoding) # generate a list of all the headers engineHeaders <- which(grepl("^## --.*engine=", contents)) allHeaders <- c(which(grepl("^## --", contents)), length(contents)) # calculate the end of each alternate engine code block (the beginning of the # very next code block) engineEnds <- vapply(engineHeaders, function(x) { allHeaders[min(which(allHeaders > x))] - 1 }, 0) # exclude the alternate engine code block lines regions <- rep.int(TRUE, length(contents)) for (h in seq_along(engineHeaders)) { regions[engineHeaders[[h]]:engineEnds[[h]]] <- FALSE } writeLines(contents[regions], file) } fileDependencies.Rmd <- function(file) { deps <- "rmarkdown" # try using an evaluate-based approach for dependencies if (knitrHasEvaluateHook()) { # attempt to load rmarkdown isRmarkdownLoaded <- "rmarkdown" %in% loadedNamespaces() if (requireNamespace("rmarkdown", quietly = TRUE)) { # unload rmarkdown after we're done with it if it # wasn't already loaded if (!isRmarkdownLoaded) { on.exit( try(unloadNamespace("rmarkdown"), silent = TRUE), add = TRUE ) } # render with a custom evaluate hook to discover dependencies deps <- c(deps, fileDependencies.Rmd.evaluate(file)) } } # we don't know this file's encoding, so presume the default encoding encoding <- getOption("encoding") format <- NULL # check whether the default output format references a package if (requireNamespace("rmarkdown", quietly = TRUE)) { tryCatch({ format <- rmarkdown::default_output_format(file) }, error = function(e) { # if we can't parse the YAML header with the default encoding, try UTF-8 encoding <<- "UTF-8" format <<- rmarkdown::default_output_format(file, encoding) }) components <- strsplit(format$name, "::")[[1]] if (length(components) == 2) { deps <- c(deps, components[[1]]) } } # We need to check for and parse YAML frontmatter if necessary yamlDeps <- NULL content <- readLines(file, encoding = encoding, warn = FALSE) if (hasYamlFrontMatter(content)) { # Extract the YAML frontmatter. tripleDashesDots <- grep("^(---|\\.\\.\\.)\\s*$", content, perl = TRUE) start <- tripleDashesDots[[1]] end <- tripleDashesDots[[2]] yaml <- paste(content[(start + 1):(end - 1)], collapse = "\n") # Populate 'deps'. yamlDeps <- yamlDeps(yaml) deps <- c(deps, yamlDeps) # Extract additional dependencies from YAML parameters. if (requireNamespace("knitr", quietly = TRUE) && packageVersion("knitr") >= "1.10.18") { # attempt to extract knitr params from yaml knitParams <- tryCatch( knitr::knit_params_yaml(yaml, evaluate = FALSE), error = function(e) { warning(e) NULL } ) if (length(knitParams)) { deps <- c(deps, "shiny") for (param in knitParams) { if (!is.null(param$expr)) { parsed <- quietly(parse(text = param$expr)) if (!inherits(parsed, "error")) deps <- c(deps, expressionDependencies(parsed)) } } } } } # Escape hatch for empty .Rmd files if (!length(content) || identical(unique(gsub("[[:space:]]", "", content, perl = TRUE)), "")) { return(deps) } ## Unload knitr if needed only for the duration of this function call ## This prevents errors with e.g. `packrat::restore` performed after ## a `fileDependencies.Rmd` call on Windows, where having knitr loaded ## would prevent an installation of knitr to succeed knitrIsLoaded <- "knitr" %in% loadedNamespaces() on.exit({ if (!knitrIsLoaded && "knitr" %in% loadedNamespaces()) { try(unloadNamespace("knitr"), silent = TRUE) } }, add = TRUE) if (requireNamespace("knitr", quietly = TRUE)) { tempfile <- tempfile() on.exit(unlink(tempfile)) tryCatch(silent( knitr::knit(file, output = tempfile, tangle = TRUE, encoding = encoding) ), error = function(e) { message("Unable to tangle file '", file, "'; cannot parse dependencies") character() }) if (file.exists(tempfile)) { stripAltEngines(tempfile, encoding) c(deps, fileDependencies.R(tempfile)) } else { deps } } else { warning("knitr is required to parse dependencies but is not available") deps } } fileDependencies.knitr <- function(...) { fileDependencies.Rmd(...) } fileDependencies.Rpres <- function(...) { fileDependencies.Rmd(...) } fileDependencies.Rnw <- function(file) { tempfile <- tempfile() on.exit(unlink(tempfile)) tryCatch(silent({ utils::Stangle(file, output = tempfile) fileDependencies.R(tempfile) }), error = function(e) { fileDependencies.knitr(file) }) } fileDependencies.R <- function(file) { if (!file.exists(file)) { warning("No file at path '", file, "'.") return(character()) } # build a list of package dependencies to return pkgs <- character() # parse file and examine expressions -- first attempt to # parse in system encoding, then try again with UTF-8 exprs <- quietly(parse(file, n = -1L)) if (inherits(exprs, "error")) exprs <- quietly(parse(file, n = -1L, encoding = "UTF-8")) # report parse errors to the user if (inherits(exprs, "error")) { warning(paste("Failed to parse", file, "; dependencies in this file will", "not be discovered.")) exprs <- NULL } # extract expression dependencies for (i in seq_along(exprs)) pkgs <- append(pkgs, expressionDependencies(exprs[[i]])) # return packages setdiff(unique(pkgs), "") } anyOf <- function(object, ...) { predicates <- list(...) for (predicate in predicates) if (predicate(object)) return(TRUE) FALSE } allOf <- function(object, ...) { predicates <- list(...) for (predicate in predicates) if (!predicate(object)) return(FALSE) TRUE } recursiveWalk <- function(`_node`, fn, ...) { fn(`_node`, ...) if (is.call(`_node`)) { for (i in seq_along(`_node`)) { recursiveWalk(`_node`[[i]], fn, ...) } } } # Fills 'env' as a side effect identifyPackagesUsed <- function(call, env) { if (!is.call(call)) return() fn <- call[[1]] if (!anyOf(fn, is.character, is.symbol)) return() fnString <- as.character(fn) # Check for '::', ':::' if (fnString %in% c("::", ":::")) { if (anyOf(call[[2]], is.character, is.symbol)) { pkg <- as.character(call[[2]]) env[[pkg]] <- TRUE return() } } # Check for S4-related function calls (implying a dependency on methods) if (fnString %in% c("setClass", "setMethod", "setRefClass", "setGeneric", "setGroupGeneric")) { env[["methods"]] <- TRUE return() } # Check for packge loaders pkgLoaders <- c("library", "require", "loadNamespace", "requireNamespace") if (!fnString %in% pkgLoaders) return() # Try matching the call. loader <- tryCatch( get(fnString, envir = asNamespace("base")), error = function(e) NULL ) if (!is.function(loader)) return() matched <- match.call(loader, call) if (!"package" %in% names(matched)) return() # Protect against 'character.only = TRUE' + symbols. # This defends us against a construct like: # # for (x in pkgs) # library(x, character.only = TRUE) # if ("character.only" %in% names(matched)) { if (is.symbol(matched[["package"]])) { return() } } if (anyOf(matched[["package"]], is.symbol, is.character)) { pkg <- as.character(matched[["package"]]) env[[pkg]] <- TRUE return() } } expressionDependencies <- function(e) { if (is.expression(e)) { return(unlist(lapply(e, function(call) { expressionDependencies(call) }))) } else if (is.call(e)) { env <- new.env(parent = emptyenv()) recursiveWalk(e, identifyPackagesUsed, env) return(ls(env, all.names = TRUE)) } else character() } # Read a DESCRIPTION file into a data.frame readDESCRIPTION <- function(path) { if (!file.exists(path)) stop("No DESCRIPTION file at path '", path, "'") tryCatch( readDcf(file = path, all = TRUE), error = function(e) { return(data.frame()) } ) } isRPackage <- function(project) { descriptionPath <- file.path(project, "DESCRIPTION") if (!file.exists(descriptionPath)) return(FALSE) DESCRIPTION <- readDESCRIPTION(descriptionPath) # If 'Type' is in the DESCRIPTION, ensure it's equal to 'Package'. if ("Type" %in% names(DESCRIPTION)) return(identical(DESCRIPTION$Type, "Package")) # Some packages will have a DESCRIPTION file without the 'Type' field. # Check that these still declare themselves with the 'Package' field. if ("Package" %in% names(DESCRIPTION)) return(TRUE) # DESCRIPTION for a non-R package (e.g. Shiny application?) FALSE } # Infer whether a project is (implicitly) a Shiny application, # in the absence of explicit `library()` statements. isShinyApp <- function(project) { # Check for a DESCRIPTION file with 'Type: Shiny' descriptionPath <- file.path(project, "DESCRIPTION") if (file.exists(descriptionPath)) { DESCRIPTION <- readDESCRIPTION(descriptionPath) if (length(DESCRIPTION$Type) && tolower(DESCRIPTION$Type) == "shiny") return(TRUE) } # Check for a server.r with a 'shinyServer' call serverPath <- file.path(project, "server.R") if (file.exists(file.path(project, "server.R"))) { contents <- paste(readLines(serverPath), collapse = "\n") if (grepl("shinyServer\\s*\\(", contents, perl = TRUE)) return(TRUE) } # Check for a single-file application with 'app.R' appPath <- file.path(project, "app.R") if (file.exists(appPath)) { contents <- paste(readLines(appPath), collapse = "\n") if (grepl("shinyApp\\s*\\(", contents, perl = TRUE)) return(TRUE) } return(FALSE) } knitrHasEvaluateHook <- function() { isKnitrLoaded <- "knitr" %in% loadedNamespaces() if (!requireNamespace("knitr", quietly = TRUE)) return(FALSE) if (!isKnitrLoaded) { on.exit( try(unloadNamespace("knitr"), silent = TRUE), add = TRUE ) } hooks <- knitr::knit_hooks$get() "evaluate" %in% names(hooks) } fileDependencies.Rmd.evaluate <- function(file) { # discovered packages (to be updated by evaluate hook) deps <- list() # save old hook and install our custom hook evaluate_hook <- knitr::knit_hooks$get("evaluate") on.exit(knitr::knit_hooks$set(evaluate = evaluate_hook), add = TRUE) knitr::knit_hooks$set(evaluate = function(code, ...) { try(silent = TRUE, { parsed <- parse(text = code, encoding = "UTF-8") deps <<- c(deps, expressionDependencies(parsed)) }) }) # rudely override knitr's 'inline_exec' function so # that we can detect dependencies within inline chunks knitr <- asNamespace("knitr") if (exists("inline_exec", envir = knitr)) { inline_exec <- yoink("knitr", "inline_exec") do.call("unlockBinding", list("inline_exec", knitr)) assign("inline_exec", function(block, ...) { # do our own special stuff try(silent = TRUE, { code <- paste(block$code, collapse = "\n") parsed <- parse(text = code, encoding = "UTF-8") deps <<- c(deps, expressionDependencies(parsed)) }) # return block input without evaluating anything block$input }, envir = knitr) on.exit({ assign("inline_exec", inline_exec, envir = knitr) do.call("lockBinding", list("inline_exec", knitr)) }, add = TRUE) } # attempt to render document with our custom hook active outfile <- tempfile() tryCatch( rmarkdown::render(file, output_file = outfile, quiet = TRUE), error = identity ) unlink(outfile) unique(unlist(deps, recursive = TRUE)) } packrat/R/descfile.R0000644000176200001440000000127213352207316014005 0ustar liggesusers # ensure that a file ends with a single newline normalizeDcf <- function(path) { n <- file.info(path)$size contents <- readChar(path, n, TRUE) replaced <- gsub("\n*$", "", contents) if (!identical(contents, replaced)) cat(replaced, file = path, sep = "\n") path } appendToDcf <- function(path, records) { normalizeDcf(path) write_dcf(records, path, append = TRUE) } # Combines one or more comma-delimited fields from a data frame read from a # DCF. combineDcfFields <- function(dcfFrame, fields) { unique(unlist(lapply(fields, function(field) { gsub("\\s.*", "", unlist( strsplit( gsub("^\\s*", "", as.character(dcfFrame[[field]])), "\\s*,\\s*"))) }))) } packrat/R/available-packages.R0000644000176200001440000000351413352207316015724 0ustar liggesusersdefaultRepositoryDbFields <- function() { c( "Package", "Version", "Priority", "Depends", "Imports", "LinkingTo", "Suggests", "Enhances", "License", "License_is_FOSS", "License_restricts_use", "OS_type", "Archs", "MD5sum", "NeedsCompilation" ) } availablePackagesSkeleton <- function() { tools <- asNamespace("tools") defaults <- tryCatch( tools$.get_standard_repository_db_fields(type = "source"), error = identity ) if (inherits(defaults, "error")) defaults <- defaultRepositoryDbFields() fields <- c(defaults, "File", "Repository") data <- array( character(), dim = c(0L, length(fields)), dimnames = list(NULL, fields) ) data } availablePackagesBinary <- function(repos = getOption("repos")) { availablePackages(repos = repos, type = .Platform$pkgType) } availablePackagesSource <- function(repos = getOption("repos")) { availablePackages(repos = repos, type = "source") } hasBinaryRepositories <- function() { !identical(.Platform$pkgType, "source") } availablePackages <- function(repos = getOption("repos"), type = getOption("pkgType")) { # check cache for entry key <- paste(deparse(repos), deparse(type), sep = " ", collapse = " ") if (!is.null(.packrat$repos[[key]])) return(.packrat$repos[[key]]) # catch errors related to e.g. missing PACKAGES file (could happen for # source-only repositories, if we tried to query a binary repository) # # NOTE: older versions of R don't support the 'repos' argument to # available.packages result <- tryCatch( available.packages( contriburl = utils::contrib.url(repos, type), type = type ), error = function(e) { availablePackagesSkeleton() } ) # cache and return .packrat$repos[[key]] <- result result } packrat/R/update.R0000644000176200001440000000370213352207316013511 0ustar liggesusersupdateInit <- function() { # Update init.R (the file sourced from within the .Rprofile) init.R <- readLines(file.path("inst", "resources", "init.R")) packrat.version <- read.dcf("DESCRIPTION")[1, "Version"] ## Sync the packrat path, messages source("R/aaa-globals.R") installAgentLine <- grep("## -- InstallAgent -- ##", init.R) init.R[installAgentLine + 1] <- paste(" installAgent <-", shQuote(paste("InstallAgent:", "packrat", packrat.version), type = "cmd")) installSourceLine <- grep("## -- InstallSource -- ##", init.R) init.R[installSourceLine + 1] <- paste(" installSource <-", shQuote(paste("InstallSource:", "source"), type = "cmd")) cat(init.R, file = file.path("inst", "resources", "init.R"), sep = "\n") # Update the .Rprofile that is written out to a project directory .Rprofile <- readLines(file.path("inst", "resources", "init-rprofile.R")) version <- read.dcf("DESCRIPTION")[, "Version"] .Rprofile[1] <- paste0("#### -- Packrat Autoloader (version ", version, ") -- ####") cat(.Rprofile, file = file.path("inst", "resources", "init-rprofile.R"), sep = "\n") } # This function is used to update project settings, typically called after # a call to packrat::set_opts updateSettings <- function(project = NULL, options = NULL) { project <- getProjectDir(project) if (is.null(options)) { options <- get_opts(project = project) } # Make sure the packrat directory is ignored if we're in a package if (file.exists(file.path(project, "DESCRIPTION"))) { updateRBuildIgnore(project) } if (isGitProject(project)) { updateGitIgnore(project, options) } if (isSvnProject(project)) { updateSvnIgnore(project, options) } # Set the repositories if (file.exists(lockFilePath(project))) { lockFile <- readLockFile(file = lockFilePath(project)) options('repos' = lockFile$repos) } # Update the external packages library symlinkExternalPackages(project = project) invisible(TRUE) } packrat/R/hooks.R0000644000176200001440000001113613352207316013352 0ustar liggesusers# Hooks for library modifying functions that can be used to auto.snapshot # and also maintain library state consistency when within packrat mode snapshotHook <- function(expr, value, ok, visible) { tryCatch( expr = { snapshotHookImpl() }, # Cases where an automatic snapshot can fail: # # 1. A library is deleted, e.g. with remove.packages. # TODO: How should we handle an automatic snapshot fail? error = function(e) { project <- .packrat_mutables$get("project") if (is.null(project)) { file = "" ## to stdout } else { file = file.path(project, "packrat", "packrat.log") } if (inherits(e, "simpleError")) { msg <- e$message } else { msg <- e } if (identical(file, "")) message(paste("Error on automatic snapshot:", msg)) else cat(msg, file = file, append = TRUE) } ) } ## Make a call that copies the local available.packages() cache makeCopyAvailablePackagesCacheCmd <- function(contrib.url, dir) { makeName <- function(contrib.url) { vapply(contrib.url, function(x) { paste0("repos_", URLencode(x, TRUE), ".rds") }, character(1), USE.NAMES = FALSE) } name <- makeName(contrib.url) fromCmd <- paste0("file.path(", paste(sep = ", ", surround(dir, with = "'"), surround(name, with = "'") ), ")" ) toCmd <- paste0("file.path(tempdir(), '", name, "')") paste0("file.copy(", fromCmd, ", ", toCmd, ")") } ## Builds a call that can be executed asynchronously -- returned as a character ## vector that can be pasted with e.g. paste(call, collapse = "; ") buildSnapshotHookCall <- function(project, debug = FALSE) { project <- getProjectDir() packratDir <- getPackratDir(project) snapshotLockPath <- file.path(packratDir, "snapshot.lock") ## utility paster peq <- function(x, y) paste(x, y, sep = " = ") snapshotArgs <- paste(sep = ", ", peq("project", surround(project, with = "'")), peq("auto.snapshot", "TRUE"), peq("verbose", "FALSE") ) repos <- gsub("\"", "'", paste(deparse(getOption('repos'), width.cutoff = 500), collapse = ' ')) setwdCmd <- paste0("setwd(", surround(project, with = "'"), ")") reposCmd <- paste0("options('repos' = ", repos, ")") copyAvailablePackagesCacheCmd <- makeCopyAvailablePackagesCacheCmd( contrib.url(getOption('repos')), tempdir() ) setLibsCmd <- paste0(".libPaths(c(", paste(surround(getUserLibPaths(), with = "'"), collapse = ", "), "))") if (debug) { snapshotCmd <- paste0("packrat:::snapshotImpl(", snapshotArgs, ")") } else { snapshotCmd <- paste0("try(suppressMessages(packrat:::snapshotImpl(", snapshotArgs, ")), silent = TRUE)") } cleanupCmd <- paste0("if (file.exists(", surround(snapshotLockPath, with = "'"), ")) file.remove(", surround(snapshotLockPath, with = "'"), ")") removeTmpdirCmd <- paste0("unlink(tempdir(), recursive = TRUE)") c( setwdCmd, reposCmd, copyAvailablePackagesCacheCmd, setLibsCmd, snapshotCmd, cleanupCmd, removeTmpdirCmd, "invisible()" ) } snapshotHookImpl <- function(debug = FALSE) { if (!isPackratModeOn()) return(invisible(TRUE)) if (!debug && !isTRUE(get_opts("auto.snapshot"))) return(invisible(TRUE)) project <- getProjectDir() packratDir <- getPackratDir(project) ## A snapshot lock file that we should check to ensure we don't try to ## snapshot multiple times snapshotLockPath <- file.path(packratDir, "snapshot.lock") ## This file needs to be checked, and deleted, by the async process if (file.exists(snapshotLockPath)) { ## we assume another process is currently performing an async snapshot if (debug) cat("Automatic snapshot already in process; exiting\n") return(TRUE) } fullCmd <- paste(buildSnapshotHookCall(project, debug = debug), collapse = "; ") file.create(snapshotLockPath, recursive = TRUE) r_path <- file.path(R.home("bin"), "R") args <- paste("--vanilla", "--slave", "-e", surround(fullCmd, with = "\"")) if (debug) { cat("Performing an automatic snapshot:\n\n") cat(paste(surround(r_path, with = "\""), args), "\n") result <- system2(r_path, args, stdout = TRUE, stderr = TRUE) cat("Captured result:\n") print(result) } else { result <- system2(r_path, args, stdout = FALSE, stderr = FALSE, wait = FALSE) } invisible(TRUE) } packrat/R/package-namespace-helpers.R0000644000176200001440000000116513352207316017215 0ustar liggesusersloaded_user_pkgs <- function() { loaded <- loadedNamespaces() ip <- installed.packages() basePkgs <- rownames(ip)[!is.na(ip[, "Priority"])] loaded[!(loaded %in% basePkgs)] } ns_imports <- function(packages) { setNames(lapply(packages, ns_imports_single), packages) } ns_imports_single <- function(package) { ns <- asNamespace(package) names(getNamespaceImports(ns)) } is_imported <- function(package) { imports <- ns_imports(loadedNamespaces()) any(sapply(imports, function(x) package %in% x)) } unloadable <- function(packages) { result <- sapply(packages, Negate(is_imported)) names(result)[result] } packrat/R/restore.R0000644000176200001440000010160213352207316013710 0ustar liggesusers# Given a package record, indicate the name we expect its source archive to have. pkgSrcFilename <- function(pkgRecord) { if (identical(pkgRecord$source, "github")) paste(pkgRecord$gh_sha1, ".tar.gz", sep = "") else if (identical(pkgRecord$source, "bitbucket")) paste(pkgRecord$remote_sha, ".tar.gz", sep = "") else paste(pkgRecord$name, "_", pkgRecord$version, ".tar.gz", sep = "") } # Given a package record and a set of known repositories, indicate whether the # package exists on a CRAN-like repository. isFromCranlikeRepo <- function(pkgRecord, repos) { # for package records inferred from a DESCRIPTION file, we know # whether a package came from a CRAN-like repository if (inherits(pkgRecord, "CustomCRANLikeRepository")) return(TRUE) # TODO: this shouldn't happen, but if it does we'll assume the package # can be obtained from CRAN source <- pkgRecord$source if (!length(source)) return(TRUE) # for records that do declare a source, ensure it's not 'source', 'github' or 'bitbucket'. # in previous releases of packrat, we attempted to match the repository name # with one of the existing repositories; however, this caused issues in # certain environments (the names declared repositories in the lockfile, and # the the names of the active repositories in the R session, may not match) !tolower(source) %in% c("source", "github", "bitbucket") } # Given a package record and a database of packages, check to see if # the package version is current. NB: Assumes package is present in db. versionMatchesDb <- function(pkgRecord, db) { versionMatch <- identical(pkgRecord$version, db[pkgRecord$name,"Version"]) # For GitHub and Bitbucket, we also need to check that the SHA1 is identical # (the source may be updated even if the version hasn't been bumped) if (versionMatch && identical(pkgRecord$source, "github")) { pkgDescFile <- system.file('DESCRIPTION', package = pkgRecord$name) installedPkgRecord <- inferPackageRecord(as.data.frame(readDcf(pkgDescFile))) versionMatch <- identical(pkgRecord$gh_sha1, installedPkgRecord$gh_sha1) } else if (versionMatch && identical(pkgRecord$source, "bitbucket")) { pkgDescFile <- system.file('DESCRIPTION', package = pkgRecord$name) installedPkgRecord <- inferPackageRecord(as.data.frame(readDcf(pkgDescFile))) versionMatch <- identical(pkgRecord$remote_sha, installedPkgRecord$remote_sha) } versionMatch } # Given a package record, fetch the sources for the package and place them in # the source directory root given by sourceDir. getSourceForPkgRecord <- function(pkgRecord, sourceDir, availablePkgs, repos, quiet = FALSE) { # Skip packages for which we can't find sources if (is.null(pkgRecord$source) || is.na(pkgRecord$source)) { if (!quiet) { warning("Couldn't determine source for ", pkgRecord$name, " (", pkgRecord$version, ")") } return(NULL) } # If we don't know where this package's source resides, give up if (identical(pkgRecord$source, "unknown") && !quiet) { stop("No sources available for package ", pkgRecord$name, ". Packrat can ", "find sources for packages on CRAN-like repositories and packages ", "installed using devtools::install_github or devtools::install_bitbucket. TODO: local repo") } # Create the directory in which to place this package's sources pkgSrcDir <- file.path(sourceDir, pkgRecord$name) if (!file.exists(pkgSrcDir)) dir.create(pkgSrcDir, recursive = TRUE) # If the file we want to download already exists, skip it pkgSrcFile <- pkgSrcFilename(pkgRecord) if (file.exists(file.path(pkgSrcDir, pkgSrcFile))) return(NULL) if (!quiet) { message("Fetching sources for ", pkgRecord$name, " (", pkgRecord$version, ") ... ", appendLF = FALSE) } type <- pkgRecord$source # If this is a local source path, compress the local sources rather than # trying to download from an external source if (identical(pkgRecord$source, "source")) { local({ if (file.exists(file.path(pkgRecord$source_path, "DESCRIPTION"))) { ## If the path supplied is the directory of a source package, ## build it build( pkg = pkgRecord$source_path, path = file.path(pkgSrcDir), binary = FALSE, vignettes = FALSE, quiet = TRUE ) } else if (endswith(pkgRecord$source_path, ".tar.gz")) { ## We assume it's a package already generated by R CMD build -- just ## copy the tarball over file.copy(pkgRecord$source_path, file.path(pkgSrcDir, basename(pkgRecord$source_path))) } else { # R's tar command preserves paths relative to the current directory in # the archive, so temporarily set the working directory there while # we create the tarball wd <- getwd() on.exit(setwd(wd), add = TRUE) setwd(file.path(pkgRecord$source_path, "..")) tar(file.path(pkgSrcDir, pkgSrcFile), files = pkgRecord$name, compression = "gzip", tar = "internal") } }) type <- "local" } else if (isFromCranlikeRepo(pkgRecord, repos)) { # Attempt to detect if this is the current version of a package # on a CRAN-like repository currentVersion <- if (pkgRecord$name %in% rownames(availablePkgs)) availablePkgs[pkgRecord$name, "Version"] else NA # Is the reported package version from 'available.packages()' # newer than that reported from CRAN? If so, we may be attempting # to install a package version not compatible with this version of # R. if (!is.na(currentVersion) && is.character(pkgRecord$version)) { compared <- utils::compareVersion(currentVersion, pkgRecord$version) if (compared == -1) { fmt <- paste( "Package version '%s' is newer than the latest version reported", "by CRAN ('%s') -- packrat may be unable to retrieve package sources." ) msg <- sprintf(fmt, pkgRecord$version, currentVersion) warning(msg) } } # Is the source for this version of the package on CRAN and/or a # Bioconductor repo? if (identical(pkgRecord$version, currentVersion)) { # Get the source package # NOTE: we cannot use 'availablePkgs' as it might have been used to # generate an available package listing for _binary_ packages, # rather than source packages. Leave it NULL and let R do the # right thing fileLoc <- downloadPackagesWithRetries(pkgRecord$name, destdir = pkgSrcDir, repos = repos, type = "source") if (!nrow(fileLoc)) { stop("Failed to download current version of ", pkgRecord$name, "(", pkgRecord$version, ")") } # If the file wasn't saved to the destination directory (which can happen # if the repo is local--see documentation in download.packages), copy it # there now if (!identical(fileLoc[1,2], file.path(pkgSrcDir, pkgSrcFile))) { file.copy(fileLoc[1,2], pkgSrcDir) } type <- paste(type, "current") } else { # The version requested is not the version on CRAN; it may be an # older version. Look for the older version in the CRAN archive for # each named repository. foundVersion <- FALSE for (repo in repos) { tryCatch({ archiveUrl <- file.path(repo, "src/contrib/Archive", pkgRecord$name, pkgSrcFile) if (!downloadWithRetries(archiveUrl, destfile = file.path(pkgSrcDir, pkgSrcFile), mode = "wb", quiet = TRUE)) { stop("Failed to download package from URL:\n- ", shQuote(archiveUrl)) } foundVersion <- TRUE type <- paste(type, "archived") break }, error = function(e) { # Ignore error and try the next repository }) } if (!foundVersion) { message("FAILED") stopMsg <- sprintf("Failed to retrieve package sources for %s %s from CRAN (internet connectivity issue?)", pkgRecord$name, pkgRecord$version) if (!is.na(currentVersion)) stopMsg <- paste(stopMsg, sprintf("[%s is current]", currentVersion)) stop(stopMsg) } } } else if (identical(pkgRecord$source, "github")) { # Prefer using https if possible. Note that 'wininet' # can fail if attempting to download from an 'http' # URL that redirects to an 'https' URL. # https://github.com/rstudio/packrat/issues/269 method <- tryCatch( secureDownloadMethod(), error = function(e) "internal" ) if (is.null(pkgRecord$remote_host) || !nzchar(pkgRecord$remote_host)) { # Guard against packages installed with older versions of devtools # (it's possible the associated package record will not contain a # 'remote_host' entry) protocol <- if (identical(method, "internal")) "http" else "https" fmt <- "%s://api.github.com/repos/%s/%s/tarball/%s" archiveUrl <- sprintf(fmt, protocol, pkgRecord$gh_username, pkgRecord$gh_repo, pkgRecord$gh_sha1) } else { # Prefer using the 'remote_host' entry as it allows for successfuly # installation of packages available on private GitHub repositories # (which will not use api.github.com) fmt <- "%s/repos/%s/%s/tarball/%s" archiveUrl <- sprintf(fmt, pkgRecord$remote_host, pkgRecord$remote_username, pkgRecord$remote_repo, pkgRecord$remote_sha) } srczip <- tempfile(fileext = '.tar.gz') on.exit({ if (file.exists(srczip)) unlink(srczip, recursive = TRUE) }, add = TRUE) if (canUseGitHubDownloader()) { status <- githubDownload(archiveUrl, srczip) if (status) { message("FAILED") stop("Failed to download package from URL:\n- ", shQuote(archiveUrl)) } } else { success <- downloadWithRetries(archiveUrl, destfile = srczip, quiet = TRUE, mode = "wb") if (!success) { message("FAILED") stop("Failed to download package from URL:\n- ", shQuote(archiveUrl)) } } local({ scratchDir <- tempfile() on.exit({ if (file.exists(scratchDir)) unlink(scratchDir, recursive = TRUE) }) # untar can emit noisy warnings (e.g. "skipping pax global extended # headers"); hide those suppressWarnings(untar(srczip, exdir = scratchDir, tar = "internal")) # Find the base directory basedir <- if (length(dir(scratchDir)) == 1) file.path(scratchDir, dir(scratchDir)) else scratchDir if (!is.null(pkgRecord$gh_subdir)) basedir <- file.path(basedir, pkgRecord$gh_subdir) if (!file.exists(file.path(basedir, 'DESCRIPTION'))) { stop('No DESCRIPTION file was found in the archive for ', pkgRecord$name) } ghinfo <- as.data.frame(c(list( GithubRepo = pkgRecord$gh_repo, GithubUsername = pkgRecord$gh_username, GithubRef = pkgRecord$gh_ref, GithubSHA1 = pkgRecord$gh_sha1)), c(GithubSubdir = pkgRecord$gh_subdir) ) appendToDcf(file.path(basedir, 'DESCRIPTION'), ghinfo) file.create(file.path(pkgSrcDir, pkgSrcFile)) dest <- normalizePath(file.path(pkgSrcDir, pkgSrcFile), winslash = '/') # R's internal tar (which we use here for cross-platform consistency) # emits warnings when there are > 100 characters in the path, due to the # resulting incompatibility with older implementations of tar. This isn't # relevant for our purposes, so suppress the warning. in_dir(dirname(basedir), suppressWarnings(tar(tarfile = dest, files = basename(basedir), compression = 'gzip', tar = 'internal')) ) }) type <- "GitHub" } else if (identical(pkgRecord$source, "bitbucket")) { # Prefer using https if possible. Note that 'wininet' # can fail if attempting to download from an 'http' # URL that redirects to an 'https' URL. # https://github.com/rstudio/packrat/issues/269 method <- tryCatch( secureDownloadMethod(), error = function(e) "internal" ) if (is.null(pkgRecord$remote_host) || !nzchar(pkgRecord$remote_host)) { protocol <- if (identical(method, "internal")) "http" else "https" pkgRecord$remote_host <- paste0(protocol, "://bitbucket.org") } fmt <- "%s/%s/%s/get/%s.tar.gz" archiveUrl <- sprintf(fmt, pkgRecord$remote_host, pkgRecord$remote_username, pkgRecord$remote_repo, pkgRecord$remote_sha) srczip <- tempfile(fileext = '.tar.gz') on.exit({ if (file.exists(srczip)) unlink(srczip, recursive = TRUE) }, add = TRUE) if (canUseBitbucketDownloader()) { status <- bitbucketDownload(archiveUrl, srczip) if (status) { message("FAILED") stop("Failed to download package from URL:\n- ", shQuote(archiveUrl)) } } else { success <- downloadWithRetries(archiveUrl, destfile = srczip, quiet = TRUE, mode = "wb") if (!success) { message("FAILED") stop("Failed to download package from URL:\n- ", shQuote(archiveUrl)) } } local({ scratchDir <- tempfile() on.exit({ if (file.exists(scratchDir)) unlink(scratchDir, recursive = TRUE) }) # untar can emit noisy warnings (e.g. "skipping pax global extended # headers"); hide those suppressWarnings(untar(srczip, exdir = scratchDir, tar = "internal")) # Find the base directory basedir <- if (length(dir(scratchDir)) == 1) file.path(scratchDir, dir(scratchDir)) else scratchDir if (!is.null(pkgRecord$remote_subdir)) basedir <- file.path(basedir, pkgRecord$remote_subdir) if (!file.exists(file.path(basedir, 'DESCRIPTION'))) { stop('No DESCRIPTION file was found in the archive for ', pkgRecord$name) } remote_info <- as.data.frame(c(list( RemoteRepo = pkgRecord$remote_repo, RemoteUsername = pkgRecord$remote_username, RemoteRef = pkgRecord$remote_ref, RemoteSha = pkgRecord$remote_sha)), c(RemoteSubdir = pkgRecord$remote_subdir) ) appendToDcf(file.path(basedir, 'DESCRIPTION'), remote_info) file.create(file.path(pkgSrcDir, pkgSrcFile)) dest <- normalizePath(file.path(pkgSrcDir, pkgSrcFile), winslash = '/') # R's internal tar (which we use here for cross-platform consistency) # emits warnings when there are > 100 characters in the path, due to the # resulting incompatibility with older implementations of tar. This isn't # relevant for our purposes, so suppress the warning. in_dir(dirname(basedir), suppressWarnings(tar(tarfile = dest, files = basename(basedir), compression = 'gzip', tar = 'internal')) ) }) type <- "Bitbucket" } if (!quiet) { if (file.exists(file.path(pkgSrcDir, pkgSrcFile))) { message("OK (", type, ")") } else { message("FAILED") stop("Could not find sources for ", pkgRecord$name, " (", pkgRecord$version, ").") } } } snapshotSources <- function(project, repos, pkgRecords) { # Don't snapshot packages included in external.packages external.packages <- opts$external.packages() pkgRecords <- Filter(function(x) !(x$name %in% external.packages), pkgRecords) # Get a list of source packages available on the repositories availablePkgs <- availablePackagesSource(repos = repos) # Find the source directory (create it if necessary) sourceDir <- srcDir(project) if (!file.exists(sourceDir)) dir.create(sourceDir, recursive = TRUE) # Get the sources for each package results <- lapply(pkgRecords, function(pkgRecord) { try(getSourceForPkgRecord(pkgRecord, sourceDir, availablePkgs, repos), silent = TRUE) }) errors <- results[sapply(results, function(x) inherits(x, "try-error"))] if (length(errors) > 0) stop("Errors occurred when fetching source files:\n", errors) invisible(NULL) } annotatePkgDesc <- function(pkgRecord, project, lib = libDir(project)) { descFile <- file.path(lib, pkgRecord$name, 'DESCRIPTION') # Get the records to write records <- list( InstallAgent = paste('packrat', packageVersion('packrat')), InstallSource = pkgRecord$source, InstallSourcePath = pkgRecord$source_path, Hash = hash(descFile) ) # Read in the DCF file content <- as.data.frame(readDcf(descFile)) stopifnot(nrow(content) == 1) # Replace the records for (i in seq_along(records)) { name <- names(records)[i] content[name] <- records[name] } # Write it out write_dcf(content, descFile) } # Annotate a set of packages by name. annotatePkgs <- function(pkgNames, project, lib = libDir(project)) { records <- searchPackages(lockInfo(project), pkgNames) lapply(records, function(record) { annotatePkgDesc(record, project, lib) }) } # Takes a vector of package names, and returns a logical vector that indicates # whether the package was not installed by packrat. installedByPackrat <- function(pkgNames, lib.loc, default=NA) { # Can't use installed.packages(fields='InstallAgent') here because it uses # Meta/package.rds, not the DESCRIPTION file, and we only record this info in # the DESCRIPTION file. return(as.logical(sapply(pkgNames, function(pkg) { descFile <- file.path(lib.loc, pkg, 'DESCRIPTION') if (!file.exists(descFile)) return(default) ia <- as.character(as.data.frame(readDcf(descFile))$InstallAgent) if (length(ia) == 0) return(FALSE) return(grepl('^packrat\\b', ia)[1]) }))) } # Removes one or more packages from the app's private library and cached # sources. removePkgs <- function(project, pkgNames, lib.loc = libDir(project)) { unlink(file.path(srcDir(project), pkgNames), recursive = TRUE) remove.packages(pkgNames, lib.loc) pkgNames } # Installs a single package from its record. Returns the method used to install # the package (built source, downloaded binary, etc.) installPkg <- function(pkgRecord, project, repos, lib = libDir(project)) { pkgSrc <- NULL type <- "built source" needsInstall <- TRUE # If we're trying to install a package that overwrites a symlink, e.g. for a # cached package, we need to move that symlink out of the way (otherwise # `install.packages()` or `R CMD INSTALL` will fail with surprising errors, # like: # # Error: 'zoo' is not a valid package name # # To avoid this, we explicitly move the symlink out of the way, and later # restore it if, for some reason, package installation failed. pkgInstallPath <- file.path(lib, pkgRecord$name) # NOTE: a symlink that points to a path that doesn't exist # will return FALSE when queried by `file.exists()`! if (file.exists(pkgInstallPath) || is.symlink(pkgInstallPath)) { temp <- tempfile(tmpdir = lib) file.rename(pkgInstallPath, temp) on.exit({ if (file.exists(pkgInstallPath)) unlink(temp, recursive = !is.symlink(temp)) else file.rename(temp, pkgInstallPath) }, add = TRUE) } # Try restoring the package from the global cache. cacheCopyStatus <- new.env(parent = emptyenv()) copiedFromCache <- restoreWithCopyFromCache(project, pkgRecord, cacheCopyStatus) if (copiedFromCache) { type <- cacheCopyStatus$type needsInstall <- FALSE } # Try restoring the package from the 'unsafe' cache, if applicable. copiedFromUntrustedCache <- restoreWithCopyFromUntrustedCache(project, pkgRecord, cacheCopyStatus) if (copiedFromUntrustedCache) { type <- cacheCopyStatus$type needsInstall <- FALSE } # if we still need to attempt an installation at this point, # remove a prior installation / file from library (if necessary). # we move the old directory out of the way temporarily, and then # delete if if all went well, or restore it if installation failed # for some reason if (needsInstall && file.exists(pkgInstallPath)) { pkgRenamePath <- tempfile(tmpdir = lib) file.rename(pkgInstallPath, pkgRenamePath) on.exit({ if (file.exists(pkgInstallPath)) unlink(pkgRenamePath, recursive = !is.symlink(pkgRenamePath)) else file.rename(pkgRenamePath, pkgInstallPath) }, add = TRUE) } # Try downloading a binary (when appropriate). if (!(copiedFromCache || copiedFromUntrustedCache) && hasBinaryRepositories() && isFromCranlikeRepo(pkgRecord, repos) && pkgRecord$name %in% rownames(availablePackagesBinary(repos = repos)) && versionMatchesDb(pkgRecord, availablePackagesBinary(repos = repos))) { tempdir <- tempdir() tryCatch({ # install.packages emits both messages and standard output; redirect these # streams to keep our own output clean. # on windows, we need to detach the package before installation detachPackageForInstallationIfNecessary(pkgRecord$name) suppressMessages( capture.output( utils::install.packages(pkgRecord$name, lib = lib, repos = repos, type = .Platform$pkgType, available = availablePackagesBinary(repos = repos), quiet = TRUE, dependencies = FALSE, verbose = FALSE) ) ) type <- "downloaded binary" needsInstall <- FALSE }, error = function(e) { # Do nothing here, we'll try local sources if we fail to download from # the repo }) } if (is.null(pkgSrc)) { # When installing from github/bitbucket or an older version, use the cached source # tarball or zip created in snapshotSources pkgSrc <- file.path(srcDir(project), pkgRecord$name, pkgSrcFilename(pkgRecord)) } if (needsInstall) { if (!file.exists(pkgSrc)) { # If the source file is missing, try to download it. (Could happen in the # case where the packrat lockfile is present but cached sources are # missing.) getSourceForPkgRecord(pkgRecord, srcDir(project), availablePackagesSource(repos = repos), repos, quiet = TRUE) if (!file.exists(pkgSrc)) { stop("Failed to install ", pkgRecord$name, " (", pkgRecord$version, ")", ": sources missing at ", pkgSrc) } } local({ # devtools does not install to any libraries other than the default, so # if the library we wish to install to is not the default, set as the # default while we do this operation. if (!isPathToSameFile(getLibPaths()[1], lib)) { oldLibPaths <- getLibPaths() on.exit(setLibPaths(oldLibPaths), add = TRUE) # Make sure the library actually exists, otherwise setLibPaths will silently # fail if (!file.exists(lib)) dir.create(lib, recursive = TRUE) setLibPaths(lib) } # on windows, we need to detach the package before installation detachPackageForInstallationIfNecessary(pkgRecord$name) quiet <- isTRUE(packrat::opts$quiet.package.installation()) install_local_path(path = pkgSrc, reload = FALSE, dependencies = FALSE, quick = TRUE, quiet = quiet) }) } # Annotate DESCRIPTION file so we know we installed it annotatePkgDesc(pkgRecord, project, lib) # copy package into cache if enabled if (isUsingCache(project)) { pkgPath <- file.path(lib, pkgRecord$name) # copy into global cache if this is a trusted package if (isTrustedPackage(pkgRecord$name)) { descPath <- file.path(pkgPath, "DESCRIPTION") if (!file.exists(descPath)) { warning("cannot cache package: no DESCRIPTION file at path '", descPath, "'") } else { hash <- hash(descPath) moveInstalledPackageToCache( packagePath = pkgPath, hash = hash, cacheDir = cacheLibDir() ) } } else { pkgPath <- file.path(lib, pkgRecord$name) tarballName <- pkgSrcFilename(pkgRecord) tarballPath <- file.path(srcDir(project), pkgRecord$name, tarballName) if (!file.exists(tarballPath)) { warning("cannot cache untrusted package: source tarball not available") } else { hash <- hashTarball(tarballPath) moveInstalledPackageToCache( packagePath = pkgPath, hash = hash, cacheDir = untrustedCacheLibDir() ) } } } return(type) } playActions <- function(pkgRecords, actions, repos, project, lib) { installedPkgs <- installed.packages(priority = c("NA", "recommended")) targetPkgs <- searchPackages(pkgRecords, names(actions)) for (i in seq_along(actions)) { action <- as.character(actions[i]) pkgRecord <- targetPkgs[i][[1]] if (is.null(pkgRecord) && !identical(action, "remove")) { warning("Can't ", action, " ", names(actions[i]), ": missing from lockfile") next } if (action %in% c("upgrade", "downgrade", "crossgrade")) { # Changing package type or version: Remove the old one now (we'll write # a new one in a moment) message("Replacing ", pkgRecord$name, " (", action, " ", installedPkgs[pkgRecord$name,"Version"], " to ", pkgRecord$version, ") ... ", appendLF = FALSE) removePkgs(project, pkgRecord$name, lib) } else if (identical(action, "add")) { # Insert newline to show progress on consoles that buffer to newlines. message("Installing ", pkgRecord$name, " (", pkgRecord$version, ") ... ", appendLF = TRUE) } else if (identical(action, "remove")) { if (is.null(pkgRecord)) { message("Removing ", names(actions[i]), " ... ", appendLF = FALSE) removePkgs(project, names(actions[i]), lib) } else { message("Removing ", pkgRecord$name, "( ", pkgRecord$version, ") ... ", appendLF = FALSE) removePkgs(project, pkgRecord$name, lib) } message("OK") next } type <- installPkg(pkgRecord, project, repos, lib) message("\tOK (", type, ")") } invisible() } restoreImpl <- function(project, repos, pkgRecords, lib, pkgsToIgnore = character(), prompt = interactive(), dry.run = FALSE, restart = TRUE) { # optionally overlay the 'src' directory from a custom location overlaySourcePackages(srcDir(project)) discoverUntrustedPackages(srcDir(project)) # We also ignore restores for packages specified in external.packages pkgsToIgnore <- c( pkgsToIgnore, packrat::opts$external.packages(), packrat::opts$ignored.packages() ) installedPkgs <- rownames(installed.packages(lib.loc = lib)) installedPkgs <- setdiff(installedPkgs, c("manipulate", "rstudio")) installedPkgRecords <- getPackageRecords( installedPkgs, project = project, recursive = FALSE, lib.loc = lib ) actions <- diff(installedPkgRecords, pkgRecords) actions[names(actions) %in% pkgsToIgnore] <- NA restartNeeded <- FALSE mustConfirm <- any(c('downgrade', 'remove', 'crossgrade') %in% actions) if (all(is.na(actions))) { message("Already up to date.") return(invisible()) } # Since we print actions as we do them, there's no need to do a summary # print first unless we need the user to confirm. if (prompt && mustConfirm && !dry.run) { summarizeDiffs(actions, installedPkgRecords, pkgRecords, 'Adding these packages to your library:', 'Removing these packages from your library:', 'Upgrading these packages in your library:', 'Downgrading these packages in your library:', 'Modifying these packages in your library:') answer <- readline('Do you want to continue? [Y/n]: ') answer <- gsub('^\\s*(.*?)\\s*$', '\\1', answer) if (nzchar(answer) && tolower(answer) != 'y') { return(invisible()) } } # The actions are sorted alphabetically; resort them in the order given by # pkgRecords (previously sorted topologically). Remove actions are special, # since they don't exist in the lockfile-generated list; extract them and # combine afterwards. removeActions <- actions[actions == "remove"] actions <- c(removeActions, unlist(lapply(pkgRecords, function(p) { actions[p$name] }))) # If any of the packages to be mutated are loaded, and the library we're # installing to is the default library, make a copy of the library and perform # the changes on the copy. actions <- actions[!is.na(actions)] # Assign targetLib based on whether the namespace of a package within the # packrat directory is loaded -- packages that don't exist can just # return "" -- this will fail the equality checks later loadedNamespaces <- loadedNamespaces() packageLoadPaths <- sapply(names(actions), function(x) { if (x %in% loadedNamespaces) getNamespaceInfo(x, "path") else "" }) loadedFromPrivateLibrary <- names(actions)[ packageLoadPaths == libDir(project) ] if (length(loadedFromPrivateLibrary)) { newLibrary <- newLibraryDir(project) dir_copy(libraryRootDir(project), newLibrary) restartNeeded <- TRUE targetLib <- file.path(newLibrary, R.version$platform, getRversion()) } else { targetLib <- lib } # Play the list, if there's anything to play if (!dry.run) { playActions(pkgRecords, actions, repos, project, targetLib) if (restartNeeded) { if (!restart || !attemptRestart()) message("You must restart R to finish applying these changes.") } } else { list(pkgRecords = pkgRecords, actions = actions, repos = repos, project = project, targetLib = targetLib) } } detachPackageForInstallationIfNecessary <- function(pkg) { # no need to detach if not actually attached searchPathName <- paste("package", pkg, sep = ":") if (!searchPathName %in% search()) return(FALSE) # get the library the package was actually loaded from location <- which(search() == searchPathName) pkgPath <- attr(as.environment(location), "path") if (!is.character(pkgPath)) return(FALSE) # got the package path; detach and reload on exit of parent. # when running tests, we want to reload packrat from the same # directory it was run from rather than the private library, as # we install a dummy version of packrat that doesn't actually export # the functions we need libPaths <- if (pkg == "packrat" && isTestingPackrat()) { strsplit(Sys.getenv("R_PACKRAT_LIBPATHS"), .Platform$path.sep, fixed = TRUE)[[1]] } else { dirname(pkgPath) } detach(searchPathName, character.only = TRUE) # re-load the package when the calling function returns defer(library(pkg, lib.loc = libPaths, character.only = TRUE), parent.frame()) TRUE } discoverUntrustedPackages <- function(srcDir) { if (is.na(Sys.getenv("RSTUDIO_CONNECT", unset = NA))) return() # set the 'packrat.untrusted.packages' option if # it has not yet been specified if (is.null(getOption("packrat.untrusted.packages"))) options("packrat.untrusted.packages" = list.files(srcDir)) } overlaySourcePackages <- function(srcDir, overlayDir = NULL) { if (is.null(overlayDir)) overlayDir <- Sys.getenv("R_PACKRAT_SRC_OVERLAY") if (!is.character(overlayDir) || !is.directory(overlayDir)) return() overlayDir <- normalizePath(overlayDir, winslash = "/", mustWork = TRUE) sources <- list.files( overlayDir, recursive = TRUE, full.names = FALSE, no.. = TRUE, include.dirs = FALSE, pattern = "\\.tar\\.gz$" ) lapply(sources, function(source) { target <- file.path(srcDir, source) source <- file.path(overlayDir, source) # skip if this tarball already exists in the target directory if (file.exists(target)) return(NULL) # attempt to symlink source to target dir.create(dirname(target), recursive = TRUE, showWarnings = FALSE) if (!is.directory(dirname(target))) stop("failed to create directory '", dirname(target), "'") # generate symlink symlink(source, target) # report success file.exists(target) }) } packrat/R/status.R0000644000176200001440000002477313352207316013565 0ustar liggesusers#' Show differences between the last snapshot and the library #' #' Shows the differences between the project's packrat dependencies, its private #' package library, and its R scripts. #' #' These differences are created when you use the normal R package management #' commands like \code{\link{install.packages}}, \code{\link{update.packages}}, #' and \code{\link{remove.packages}}. To bring these differences into packrat, you #' can use \code{\link{snapshot}}. #' #' Differences can also arise if one of your collaborators adds or removes #' packages from the packrat dependencies. In this case, you simply need to tell #' packrat to update your private package library using \code{\link{restore}}. #' #' @param project The directory that contains the R project. #' @param lib.loc The library to examine. Defaults to the private library #' associated with the project directory. #' @param quiet Print detailed information about the packrat status to the console? #' #' @return Either \code{NULL} if a \code{packrat} project has not yet been #' initialized, or a (invisibly) a \code{data.frame} with components: #' \item{package}{The package name,} #' \item{packrat.version}{The package version used in the last snapshot,} #' \item{packrat.source}{The location from which the package was obtained,} #' \item{library.version}{The package version available in the local library,} #' \item{currently.used}{Whether the package is used in any of the R code in the current project.} #' #' @export status <- function(project = NULL, lib.loc = libDir(project), quiet = FALSE) { project <- getProjectDir(project) stopIfNoLockfile(project) projectDefault <- identical(project, '.') project <- normalizePath(project, winslash = '/', mustWork = TRUE) ### Step 1: Collect packages from three sources: packrat.lock, code inspection ### (using lib.loc and getLibPaths() to find packages/dependencies), and by ### enumerating the packages in lib.loc. ## Packages from the lockfile (with their version) packratPackages <- lockInfo(project, fatal = FALSE) if (length(packratPackages) == 0) { initArg <- if (projectDefault) '' else deparse(project) cat('This directory does not appear to be using packrat.\n', 'Call packrat::init(', initArg, ') to initialize packrat.', sep = '') return(invisible()) } # Get the names, alongside the versions, of packages recorded in the lockfile packratNames <- getPackageElement(packratPackages, "name") packratVersions <- getPackageElement(packratPackages, "version") packratSources <- getPackageElement(packratPackages, "source") ## Packages in the library (with their version) installedPkgFolders <- list.files(lib.loc, full.names = TRUE) installedPkgRecords <- lapply(installedPkgFolders, function(path) { descPath <- file.path(path, "DESCRIPTION") if (!file.exists(descPath)) { warning("No DESCRIPTION file for installed package '", basename(path), "'") return(NULL) } DESCRIPTION <- readDcf(descPath, all = TRUE) list( name = DESCRIPTION$Package, source = DESCRIPTION$InstallSource, version = DESCRIPTION$Version ) }) installedPkgNames <- unlist(lapply(installedPkgRecords, `[[`, "name")) names(installedPkgNames) <- installedPkgNames installedPkgVersions <- unlist(lapply(installedPkgRecords, `[[`, "version")) names(installedPkgVersions) <- installedPkgNames # Manually construct package records suitable for later reporting # Packages inferred from the code # Don't stop execution if package missing from library; just propagate later # as information to user # # NOTE: We avoid explicitly calling `available.packages()`, just in case we haven't # yet cached the set of available packages. However, to infer broken dependency chains # it is in general necessary to have the set of `available.packages()` to fill in # broken links. availablePkgs <- if (hasCachedAvailablePackages()) availablePackages() else availablePackagesSkeleton() inferredPkgNames <- appDependencies( project, available.packages = availablePkgs ) # Suppress warnings on 'Suggests', since they may be from non-CRAN repos (e.g. OmegaHat) suggestedPkgNames <- suppressWarnings( appDependencies(project, available.packages = availablePkgs, fields = "Suggests") ) # All packages mentioned in one of the three above allPkgNames <- sort_c(unique(c( packratNames, installedPkgNames, inferredPkgNames ))) # Match the above with the set of all package names .match <- function(what, from = allPkgNames) { if (is.null(what)) NA else what[from] } packrat.version <- .match(packratVersions) packrat.source <- .match(packratSources) library.version <- .match(installedPkgVersions) currently.used <- allPkgNames %in% c(inferredPkgNames, suggestedPkgNames) # Generate a table that holds the current overall state external.packages <- opts$external.packages() statusTbl <- data.frame(stringsAsFactors = FALSE, row.names = 1:length(allPkgNames), package = allPkgNames, packrat.version = packrat.version, packrat.source = packrat.source, library.version = library.version, currently.used = currently.used, external.package = allPkgNames %in% external.packages ) # Only give information on packages not included in external.packages statusTbl <- statusTbl[!statusTbl$external.package, ] # Fill the state, according to the different kinds of mismatches there might # be between packrat.version, library.version, currently.used if (!quiet) { # Packages that are only tracked within packrat, but are no longer present # in the local library nor found in the user's code onlyPackrat <- with(statusTbl, !is.na(packrat.version) & is.na(library.version) & !currently.used ) if (any(onlyPackrat)) { prettyPrint( searchPackages(packratPackages, statusTbl$package[onlyPackrat]), header = c("The following packages are tracked by packrat, but are no longer ", "available in the local library nor present in your code:"), footer = c("You can call packrat::snapshot() to remove these packages from the lockfile, ", "or if you intend to use these packages, use packrat::restore() to restore them ", "to your private library.") ) } # Packages that are used in the code, but are not mentioned in either packrat # or the library whichUntrackedPackages <- with(statusTbl, currently.used & is.na(packrat.version) & is.na(library.version) ) pkgNamesUntracked <- statusTbl$package[whichUntrackedPackages] if (length(pkgNamesUntracked)) { prettyPrintNames( pkgNamesUntracked, c("The following packages are referenced in your code, but are not present\n", "in your library nor in packrat:\n"), c("\nYou will need to install these packages manually, then use\n", "packrat::snapshot() to record these packages in packrat.") ) } # Packages that are in the library, currently used, but not tracked by packrat whichMissingFromPackrat <- with(statusTbl, currently.used & is.na(packrat.version) & (!is.na(library.version)) ) missingFromPackrat <- statusTbl$package[whichMissingFromPackrat] if (length(missingFromPackrat)) { prettyPrintPair( searchPackages(installedPkgRecords, missingFromPackrat), searchPackages(packratPackages, missingFromPackrat), "The following packages have been updated in your library, but have not been recorded in packrat:", "Use packrat::snapshot() to record these packages in packrat.", "library", "packrat" ) } # Packages that are tracked by packrat, currently used, but out of sync in the library whichOutOfSync <- with(statusTbl, currently.used & !is.na(packrat.version) & !is.na(library.version) & packrat.version != library.version) pkgNamesOutOfSync <- statusTbl$package[whichOutOfSync] if (length(pkgNamesOutOfSync)) { prettyPrintPair( searchPackages(packratPackages, pkgNamesOutOfSync), searchPackages(installedPkgRecords, pkgNamesOutOfSync), "The following packages are out of sync between packrat and your current library:", c("Use packrat::snapshot() to set packrat to use the current library, or use\n", "packrat::restore() to reset the library to the last snapshot."), "packrat", "library" ) } # Packages which have been deleted from the library, but are still tracked by packrat, # and still in use whichDeletedButStillTracked <- with(statusTbl, currently.used & !is.na(packrat.version) & is.na(library.version)) deletedButStillTracked <- statusTbl$package[whichDeletedButStillTracked] if (length(deletedButStillTracked)) { prettyPrintPair( searchPackages(packratPackages, deletedButStillTracked), searchPackages(installedPkgRecords, deletedButStillTracked), "The following packages are used in your code, tracked by packrat, but no longer present in your library:", c("Use packrat::restore() to restore these libraries.") ) } # If everything is in order, let the user know if (!(any(onlyPackrat) || length(missingFromPackrat) || length(pkgNamesUntracked) || length(pkgNamesOutOfSync) || length(deletedButStillTracked) || length(missingFromPackrat))) { message("Up to date.") } } invisible(statusTbl) } getPackageElement <- function(package, element) { setNames( unlist(lapply(package, "[[", element)), unlist(lapply(package, "[[", "name")) ) } hasCachedAvailablePackages <- function() { contrib.url <- contrib.url(getOption('repos')) tempFiles <- list.files(tempdir()) repoNames <- paste("repos_", URLencode(contrib.url, TRUE), ".rds", sep = "") all(repoNames %in% tempFiles) } packrat/R/downloader.R0000644000176200001440000002235213352207316014367 0ustar liggesusers# Download a file, using http, https, or ftp # # This is a wrapper for \code{\link{download.file}} and takes all the same # arguments. The only difference is that, if the protocol is https, it changes # some settings to make it work. How exactly the settings are changed # differs among platforms. # # This function also should follow http redirects on all platforms, which is # something that does not happen by default when \code{curl} is used, as on # Mac OS X. # # With Windows, it calls \code{setInternet2}, which tells R to use the # \code{internet2.dll}. Then it downloads the file by calling # \code{\link{download.file}} using the \code{"internal"} method. # # On other platforms, it will try to use \code{wget}, then \code{curl}, and # then \code{lynx} to download the file. Typically, Linux platforms will have # \code{wget} installed, and Mac OS X will have \code{curl}. # # Note that for many (perhaps most) types of files, you will want to use # \code{mode="wb"} so that the file is downloaded in binary mode. # # @param url The URL to download. # @param ... Other arguments that are passed to \code{\link{download.file}}. # # @seealso \code{\link{download.file}} for more information on the arguments # that can be used with this function. # # @examples # \dontrun{ # # Download the downloader source, in binary mode # download("https://github.com/wch/downloader/zipball/master", # "downloader.zip", mode = "wb") # } # download <- function(url, destfile, method = inferAppropriateDownloadMethod(url), ...) { # download to temporary file, then attempt to move to required location tempfile <- tempfile(tmpdir = dirname(destfile)) on.exit(unlink(tempfile)) # call downloadImpl -- returns '0' on success status <- downloadImpl(url, destfile = tempfile, method = method, ...) if (status) return(status) # attempt to rename the downloaded file, and return 0 on success success <- file.rename(tempfile, destfile) if (success) 0 else 1 } downloadImpl <- function(url, method, ...) { # If this is a path to a GitHub URL, attempt to download with authentication, # so that private GitHub repositories can be handled. if (isGitHubURL(url) && canUseGitHubDownloader()) { result <- try(githubDownload(url, ...), silent = TRUE) if (!inherits(result, "try-error")) return(result) } # If this is a path to a Bitbucket URL, attempt to download. if (isBitbucketURL(url) && canUseBitbucketDownloader()) { result <- try(bitbucketDownload(url, ...), silent = TRUE) if (!inherits(result, "try-error")) return(result) } # When on Windows using an 'internal' method, we need to call # 'setInternet2' to set some appropriate state. if (is.windows() && method == "internal") { # If we directly use setInternet2, R CMD CHECK gives a Note on Mac/Linux seti2 <- `::`(utils, 'setInternet2') # Check whether we are already using internet2 for internal usingInternet2 <- seti2(NA) # If not then temporarily set it if (!usingInternet2) { # Store initial settings, and restore on exit on.exit(suppressWarnings(seti2(usingInternet2)), add = TRUE) # Needed for https. Will get warning if setInternet2(FALSE) already run # and internet routines are used. But the warnings don't seem to matter. suppressWarnings(seti2(TRUE)) } } downloadFile(url, method, ...) } downloadFile <- function(url, method = inferAppropriateDownloadMethod(url), extra = "", ...) { # If the download method we're using matches the current option for # 'download.file.method', then propagate 'extra' options. if (!nzchar(extra) && identical(getOption("download.file.method"), method)) extra <- getOption("download.file.extra", default = "") # ensure 'extra' is a string extra <- paste(extra, collapse = " ") # pass extra arguments for 'curl' downloader if (method == "curl") { # use '-L' to follow redirects if (!grepl("\\b-L\\b", extra)) extra <- paste(extra, "-L") # switch off the curl globbing parser if (!grepl("\\b-g\\b", extra)) extra <- paste(extra, "-g") # use '-f' to ensure we fail on server errors if (!grepl("\\b-f\\b", extra)) extra <- paste(extra, "-f") # make curl quiet -- avoid polluting console with e.g. # curl: (22) The requested URL returned error: 404 Not Found if (!grepl("\\b-s\\b", extra)) extra <- paste(extra, "-s") # lower connection timeout connect.timeout <- getOption("packrat.connect.timeout") if (!is.null(connect.timeout) && !grepl("\\b--connect-timeout\\b", extra)) extra <- paste(extra, "--connect-timeout", connect.timeout) # redirect stderr to stdout, for nicer output in RStudio if (!grepl("\\b--stderr -\\b", extra)) extra <- paste(extra, "--stderr -") } # catch warnings in the call caughtWarning <- NULL result <- withCallingHandlers( download.file(url = url, method = method, extra = extra, ...), warning = function(w) { caughtWarning <<- w invokeRestart("muffleWarning") } ) # If we're using 'wget' or 'curl', upgrade the warning to an error. if (method %in% c("curl", "wget") && length(caughtWarning)) { msg <- sprintf("Failed to download '%s' ('%s' had status code '%s')", url, method, result) stop(msg) } return(result) } # TODO: we cannot use libcurl until R no longer sends HEAD requests when # attempting to download files canUseLibCurlDownloadMethod <- function() { FALSE } # Attempt download.packages multiple times. # # Assumes we are downloading a single package. downloadPackagesWithRetries <- function(name, destdir, repos, type, maxTries = 5L) { maxTries <- as.integer(maxTries) stopifnot(maxTries > 0L) stopifnot(length(name) > 0L) fileLoc <- matrix(character(), 0L, 2L) for (i in 1:maxTries) { fileLoc <- download.packages(name, destdir = destdir, repos = repos, type = type, quiet = TRUE) if (nrow(fileLoc)) { break } } fileLoc } # Download from a URL with a certain number of retries -- returns TRUE # if the download succeeded, and FALSE otherwise downloadWithRetries <- function(url, ..., maxTries = 5L) { maxTries <- as.integer(maxTries) stopifnot(maxTries > 0L) success <- FALSE for (i in 1:maxTries) { # NOTE: Windows seems to return a warning that the status code was 200 # even on a successful download... tryCatch( expr = { result <- suppressWarnings(download(url, ...)) if (result %in% c(0, 200)) success <- TRUE else Sys.sleep(1) }, error = function(e) { Sys.sleep(1) } ) if (success) break } success } inferAppropriateDownloadMethod <- function(url) { ## If the user wants to explicitly use their own download method, ## they can set 'packrat.download.method' and we'll honor that. packrat.download.method <- getOption("packrat.download.method") if (is.function(packrat.download.method)) return(packrat.download.method(url)) # If the user has already opted into using a certain download method, # don't stomp on that. download.file.method <- getOption("download.file.method") if (!is.null(download.file.method)) return(download.file.method) # Prefer using external programs (they can better handle redirects # than R's internal downloader, or so it seems) isSecureWebProtocol <- grepl("^(?:ht|f)tps://", url, perl = TRUE) if (is.linux() || is.mac() || isSecureWebProtocol) return(secureDownloadMethod()) # Use "wininet" as default for R >= 3.2 if (is.windows() && getRversion() >= "3.2") return("wininet") # default return("internal") } # Attempt to determine a secure download method for the current # platform/configuration. Returns NULL if no such method can # be ascertained. secureDownloadMethod <- function() { # Check whether we are running R 3.2 and whether we have libcurl isR32 <- getRversion() >= "3.2" if (is.windows()) { # For windows we prefer binding directly to wininet if we can (since # that doesn't rely on the value of setInternet2). If it's R <= 3.1 # then we can use "internal" for https so long as internet2 is enabled # (we don't use libcurl on Windows because it doesn't check certs). if (isR32) return("wininet") # Otherwise, make a call to 'setInternet2' and use the 'internal' method # if that call succeeds. seti2 <- `::`(utils, 'setInternet2') if (suppressWarnings(seti2(NA))) return("internal") } # For Darwin and Linux we use libcurl if we can and then fall back # to curl or wget as appropriate. We prefer libcurl because it honors # the same proxy configuration that "internal" does so it less likely # to break downloads for users behind proxy servers. if (canUseLibCurlDownloadMethod()) return("libcurl") # Otherwise, fall back to 'wget' or 'curl' (preferring 'wget') candidates <- c("curl", "wget") for (candidate in candidates) if (isProgramOnPath(candidate)) return(candidate) stop("Failed to discover a secure download method.") } packrat/R/git-prune.R0000644000176200001440000000446113352207316014144 0ustar liggesusersgit_files <- function(project = NULL) { project <- getProjectDir(project) owd <- getwd() setwd(project) on.exit(setwd(owd)) objects <- system("git rev-list --all --objects", intern = TRUE) splat <- strsplit(objects, " ", fixed = TRUE) sort(unique(unlist(sapply(splat, function(x) { if (length(x) == 2) x[[2]] else NULL })))) } git_prune <- function(project = NULL, prune.lib = TRUE, prune.src = FALSE) { # See: http://stevelorek.com/how-to-shrink-a-git-repository.html for notes project <- getProjectDir(project) owd <- getwd() setwd(project) on.exit(setwd(owd)) if (!isGitProject(project)) stop("Not a git project (no .git/ directory found)", call. = FALSE) localBranches <- system("git branch", intern = TRUE) localBranches <- gsub("^[[:blank:]]*", "", localBranches) allBranches <- system("git branch -a | grep remotes | grep -v HEAD | grep -v master", intern = TRUE) allBranches <- gsub("^[[:blank:]]*", "", allBranches) needsClone <- allBranches[!(gsub(".*/", "", allBranches) %in% localBranches)] if (length(needsClone)) { message("Deep-cloning Git repository...") for (branch in needsClone) system(paste("git branch --track", gsub(".*/", "", branch), branch), ignore.stdout = TRUE, ignore.stderr = TRUE) message("Done!") } allFiles <- git_files() toRemove <- character() if (prune.lib) toRemove <- c(toRemove, grep("^packrat/lib*/", allFiles, value = TRUE)) if (prune.src) toRemove <- c(toRemove, grep("^packrat/src/", allFiles, value = TRUE)) n <- length(toRemove) if (!n) { message("Nothing to prune. Exiting...") return(invisible(character())) } for (i in seq_along(toRemove)) { file <- toRemove[[i]] message("Removing file ", i, " of ", n, "...") cmd <- paste("git filter-branch --tag-name-filter cat --index-filter", "'git rm -r --cached --ignore-unmatch", file, "' --prune-empty -f -- --all") system(cmd, ignore.stdout = TRUE, ignore.stderr = TRUE) } unlink(file.path(project, ".git", "refs", "original"), recursive = TRUE) system("git reflog expire --expire=now --all") system("git gc --prune=now") system("git gc --aggressive --prune=now") message("Done!") return(invisible(toRemove)) } packrat/R/library-support.R0000644000176200001440000001324713352207316015412 0ustar liggesusers## System packages == installed packages with a non-NA priority ## Returns TRUE/FALSE, indicating whether the symlinking was successful symlinkSystemPackages <- function(project = NULL) { project <- getProjectDir(project) # skip symlinking if requested by user if (!packrat::opts$symlink.system.packages()) return(FALSE) # Get the path to the base R library installation sysLibPath <- normalizePath(R.home("library"), winslash = "/", mustWork = TRUE) ## Get the system packages sysPkgs <- utils::installed.packages(sysLibPath) sysPkgsBase <- sysPkgs[!is.na(sysPkgs[, "Priority"]), ] sysPkgNames <- rownames(sysPkgsBase) ## Make a directory where we can symlink these libraries libRdir <- libRdir(project = project) if (!file.exists(libRdir)) if (!dir.create(libRdir, recursive = TRUE)) return(FALSE) ## Generate symlinks for each package for (pkg in sysPkgNames) { source <- file.path(sysLibPath, pkg) target <- file.path(libRdir, pkg) if (!ensurePackageSymlink(source, target)) return(FALSE) } TRUE } isPathToSamePackage <- function(source, target) { # When not on Windows, we can just check that the normalized # paths resolve to the same location. if (!is.windows()) return(normalizePath(source) == normalizePath(target)) # On Windows, junction points are not resolved by 'normalizePath()', # so we need an alternate strategy for determining if the junction # point is up to date. We ensure that the 'DESCRIPTION' files at # both locations are equivalent. lhsPath <- file.path(source, "DESCRIPTION") rhsPath <- file.path(target, "DESCRIPTION") # If either of these files do not exist, bail if (!(file.exists(lhsPath) && file.exists(rhsPath))) return(FALSE) lhsContents <- readChar(lhsPath, file.info(lhsPath)$size, TRUE) rhsContents <- readChar(rhsPath, file.info(rhsPath)$size, TRUE) identical(lhsContents, rhsContents) } # Clean up recursive symlinks erroneously generated by # older versions of packrat. This code can probably be # removed in a future release of packrat. cleanRecursivePackageSymlinks <- function(source) { target <- file.path(source, basename(source)) if (file.exists(target)) { sourceFiles <- list.files(source) targetFiles <- list.files(target) if (identical(sourceFiles, targetFiles)) unlink(target) } } ensurePackageSymlink <- function(source, target) { cleanRecursivePackageSymlinks(source) # If we have a symlink already active in the # target location, check that it points to the # library corresponding to the current running # R session. if (file.exists(target)) { if (isPathToSamePackage(source, target)) return(TRUE) # Remove the old symlink target (swallowing errors) tryCatch( unlink(target, recursive = !is.symlink(target)), error = identity ) # Check if the file still exists and warn if so if (file.exists(target)) { # request information on the existing file info <- paste(capture.output(print(file.info(target))), collapse = "\n") msg <- c( sprintf("Packrat failed to remove a pre-existing file at '%s'.", target), "Please report this issue at 'https://github.com/rstudio/packrat/issues'.", "File info:", info ) warning(paste(msg, collapse = "\n")) } } # If, for some reason, the target directory # still exists, bail as otherwise symlinking # will not work as desired. if (file.exists(target)) stop("Target '", target, "' already exists and is not a symlink") # Perform the symlink. symlink(source, target) # Success if the file now exists file.exists(file.path(target, "DESCRIPTION")) } symlinkExternalPackages <- function(project = NULL) { external.packages <- opts$external.packages() if (!length(external.packages)) return(invisible(NULL)) project <- getProjectDir(project) if (!file.exists(libExtDir(project))) if (!dir.create(libExtDir(project), recursive = TRUE)) stop("Failed to create 'lib-ext' packrat directory") # Get the default (non-packrat) library paths lib.loc <- getDefaultLibPaths() pkgDeps <- recursivePackageDependencies( external.packages, lib.loc = lib.loc, available.packages = NULL ) allPkgs <- union(external.packages, pkgDeps) # Get the locations of these packages within the supplied lib.loc loc <- lapply(allPkgs, function(x) { find.package(x, lib.loc = lib.loc, quiet = TRUE) }) names(loc) <- allPkgs # Warn about missing packages notFound <- loc[sapply(loc, function(x) { !length(x) })] if (length(notFound)) { warning("The following external packages could not be located:\n- ", paste(shQuote(names(notFound)), collapse = ", ")) } # Symlink the packages that were found loc <- loc[sapply(loc, function(x) length(x) > 0)] results <- lapply(loc, function(x) { source <- x target <- file.path(libExtDir(project), basename(x)) ensurePackageSymlink(source, target) }) failedSymlinks <- results[sapply(results, Negate(isTRUE))] if (length(failedSymlinks)) { warning("The following external packages could not be linked into ", "the packrat private library:\n- ", paste(shQuote(names(failedSymlinks)), collapse = ", ")) } } is.symlink <- function(path) { ## Strip trailing '/' path <- gsub("/*$", "", path) ## Sys.readlink returns NA for error, "" for 'not a symlink', and for symlink ## return false for first two cases, true for second result <- Sys.readlink(path) if (is.na(result)) FALSE else nzchar(result) } useSymlinkedSystemLibrary <- function(project = NULL) { project <- getProjectDir(project) replaceLibrary(".Library", libRdir(project = project)) } packrat/R/lockfile.R0000644000176200001440000002140313352207316014015 0ustar liggesusers# Given a list of named lists, return a list of all the names used collectFieldNames <- function(lists) { allFieldNames <- character(0) for (lst in lists) allFieldNames <- union(allFieldNames, unique(names(lst))) return(allFieldNames) } # Create a single-row data frame with the given column names and all NA values naRow <- function(fieldNames) { structure( do.call(data.frame, as.list(rep.int(NA, length(fieldNames)))), names = fieldNames ) } # Like rbind.data.frame but tolerates heterogeneous columns, filling in any # missing values with NA rbind2 <- function(df1, df2) { allNames <- union(names(df1), names(df2)) missing1 <- setdiff(allNames, names(df1)) missing2 <- setdiff(allNames, names(df2)) return(rbind( cbind(df1, naRow(missing1), row.names = NULL), cbind(naRow(missing2), df2, row.names = NULL) )) } writeLockFile <- function(file, lockinfo) { rver <- as.character(getRversion()) # Construct Repos as a key-value pair to write into the lock file repos <- activeRepos(dirname(file)) # Windows automatically transforms \n to \r\n on write through write.dcf separator <- ",\n" reposString <- paste(names(repos), unname(repos), sep = "=", collapse = separator) # The first record contains metadata about the project and lockfile preamble <- data.frame( PackratFormat = .packrat$packratFormat, PackratVersion = as.character(packageVersion("packrat")), RVersion = rver, Repos = reposString ) stopifnot(nrow(preamble) == 1) # Remaining records are about the packages if (length(lockinfo)) { packages <- flattenPackageRecords(lockinfo, depInfo = TRUE, sourcePath = TRUE) fieldNames <- collectFieldNames(packages) packageInfo <- lapply(fieldNames, function(fieldName) { values <- data.frame(vapply(packages, function(pkg) { if (length(pkg[[fieldName]])) pkg[[fieldName]] else NA_character_ }, character(1), USE.NAMES = FALSE)) names(values) <- fieldName return(values) }) packageInfoDf <- do.call(data.frame, packageInfo) df <- rbind2(preamble, packageInfoDf) } else { df <- as.data.frame(preamble, stringsAsFactors = FALSE) } names(df) <- translate(names(df), r_aliases) write_dcf(df, file) invisible() } readLockFile <- function(file) { df <- as.data.frame(readDcf(file), stringsAsFactors = FALSE) df <- cleanupWhitespace(df) # Used 'GitHub' instead of 'Github' for a brief period -- translate those names(df) <- gsub("^GitHub", "Github", names(df)) # Translate the names according to the aliases we maintain names(df) <- translate(names(df), aliases) # Split the repos repos <- gsub("[\r\n]", " ", df[1, 'Repos']) repos <- strsplit(unlist(strsplit(repos, "\\s*,\\s*", perl = TRUE)), "=", fixed = TRUE) # Support older-style lockfiles containing unnamed repositories repoLens <- vapply(repos, length, numeric(1)) if (all(repoLens == 1)) { # Support for old (unnamed) repositories if (length(repoLens) > 1) { # We warn if there were multiple repositories (if there was only one, we # can safely assume it was CRAN) warning("Old-style repository format detected; bumped to new version\n", "Please re-set the repositories with options(repos = ...)\n", "and call packrat::snapshot() to update the lock file.") } repos <- c(CRAN = repos[[1]]) } else if (all(repoLens == 2)) { repos <- setNames( sapply(repos, "[[", 2), sapply(repos, "[[", 1) ) } packages <- if (nrow(df) > 1) deserializePackages(utils::tail(df, -1)) else list() list( packrat_format = df[1, 'PackratFormat'], packrat_version = df[1, 'PackratVersion'], r_version = df[1, 'RVersion'], repos = repos, packages = packages ) } # Remove leading and trailing whitespace from character vectors # in the dataframe, and return the modified dataframe cleanupWhitespace <- function(df) { for (i in seq_along(df)) { if (is.character(df[[i]])) df[[i]] <- sub('^\\s*(.*?)\\s*$', '\\1', df[[i]]) } return(df) } # @param graph Named list where the names are the packages and the values # are the names of the packages that they depend on. Packages with no # dependencies should have character(0) or NULL. # @return Sorted character vector of package names topoSort <- function(graph) { packageNames <- names(graph) # Key: dependency, Value: dependent # Use this to answer: What things depend on this key? dependents <- new.env(parent = emptyenv(), size = as.integer(length(packageNames) * 1.3)) # Key: dependent, Value: Number of dependencies # Use this to answer: How many things does this key depend on? dependencyCount <- new.env(parent = emptyenv(), size = as.integer(length(packageNames) * 1.3)) for (packageName in packageNames) dependencyCount[[packageName]] <- 0 # Initialize dependents and dependencyCount for (pkgName in packageNames) { for (r in graph[[pkgName]]) { dependents[[r]] <- c(dependents[[r]], pkgName) dependencyCount[[pkgName]] <- dependencyCount[[pkgName]] + 1 } } if (length(setdiff(ls(dependents), packageNames)) > 0) stop("Corrupted lockfile: missing dependencies") # TODO: better message # Do topo sort sortedNames <- character(0) leaves <- packageNames[vapply(packageNames, function(pkgName) { identical(dependencyCount[[pkgName]], 0) }, logical(1))] while (length(leaves) > 0) { leaf <- leaves[[1]] leaves <- utils::tail(leaves, -1) sortedNames <- c(sortedNames, leaf) # See who depends on the leaf for (dependent in dependents[[leaf]]) { # Decrease the dependency count for this dependent dependencyCount[[dependent]] <- dependencyCount[[dependent]] - 1 # Is this dependent now a leaf? if (identical(dependencyCount[[dependent]], 0)) { leaves <- c(leaves, dependent) do.call(rm, list(dependent, envir = dependencyCount)) } } if (exists(leaf, where = dependents)) do.call(rm, list(leaf, envir = dependents)) } if (!setequal(sortedNames, packageNames)) stop("Corrupt lockfile: circular package dependencies detected") sortedNames } deserializePackages <- function(df) { packageNames <- df[, 'name'] ## Begin validation # Test for package records without names if (any(is.na(packageNames))) stop("Invalid lockfile format: missing package name detected") dupNames <- packageNames[duplicated(packageNames)] if (length(dupNames) > 0) { stop("The following package(s) appear in the lockfile more than once: ", paste(dupNames, collapse = ", ")) } # TODO: Test that package names are valid (what are the rules?) ## End validation graph <- lapply(seq.int(nrow(df)), function(i) { req <- df[i, 'requires'] if (is.null(req) || is.na(req)) return(character(0)) reqs <- unique(strsplit(req, '\\s*,\\s*')[[1]]) if (identical(reqs, '')) return(character(0)) return(reqs) }) names(graph) <- packageNames # Validate graph undeclaredDeps <- setdiff(unique(unlist(graph)), packageNames) if (length(undeclaredDeps) > 0) { stop("The following dependencies are missing lockfile entries: ", paste(undeclaredDeps, collapse = ", ")) } topoSorted <- topoSort(graph) # It's now safe to drop the requires info since it's encoded in the graph df <- df[, names(df) != 'requires', drop = FALSE] sortedPackages <- lapply(topoSorted, function(pkgName) { pkg <- as.list(df[df$name == pkgName,]) pkg <- pkg[!is.na(pkg)] return(pkg) }) names(sortedPackages) <- topoSorted for (i in seq_along(sortedPackages)) { pkg <- sortedPackages[[i]] pkg$depends <- lapply(graph[[pkg$name]], function(depName) { sortedPackages[[depName]] }) sortedPackages[[i]] <- pkg } names(sortedPackages) <- NULL return(sortedPackages) } translate <- function(x, dict) { vapply(x, function(val) { if (!(val %in% names(dict))) val else as.vector(dict[[val]]) }, character(1)) } # Translates persistent names with in-memory names (i.e. the names are what the # fields are called in the lockfile, and the values are what the fields are # called after they've been deserialized into package records). # # NB: This list must be maintained if additional fields are added to package # records! aliases <- c( Package = "name", Source = "source", Version = "version", Requires = "requires", GithubRepo = "gh_repo", GithubUsername = "gh_username", GithubRef = "gh_ref", GithubSha1 = "gh_sha1", GithubSubdir = "gh_subdir", RemoteHost = "remote_host", RemoteRepo = "remote_repo", RemoteUsername = "remote_username", RemoteRef = "remote_ref", RemoteSha = "remote_sha", RemoteSubdir = "remote_subdir", SourcePath = "source_path", Hash = "hash" ) r_aliases <- structure(names(aliases), names = aliases) packrat/R/options.R0000644000176200001440000002736713352207316013737 0ustar liggesusers## When adding new options, be sure to update the VALID_OPTIONS list ## (define your own custom validators by assigning a function) ## and update the default_opts() function + documentation in 'get_opts()' below VALID_OPTIONS <- list( auto.snapshot = function(x) x %in% c(TRUE, FALSE), use.cache = list(TRUE, FALSE), print.banner.on.startup = list(TRUE, FALSE, "auto"), vcs.ignore.lib = list(TRUE, FALSE), vcs.ignore.src = list(TRUE, FALSE), external.packages = function(x) { is.null(x) || is.character(x) }, local.repos = function(x) { is.null(x) || is.character(x) }, load.external.packages.on.startup = list(TRUE, FALSE), ignored.packages = function(x) { is.null(x) || is.character(x) }, ignored.directories = function(x) { is.null(x) || is.character(x) }, quiet.package.installation = list(TRUE, FALSE), snapshot.recommended.packages = list(TRUE, FALSE), snapshot.fields = function(x) { is.null(x) || is.character(x) }, symlink.system.packages = list(TRUE, FALSE) ) default_opts <- function() { list( auto.snapshot = FALSE, use.cache = FALSE, print.banner.on.startup = "auto", vcs.ignore.lib = TRUE, vcs.ignore.src = FALSE, external.packages = Sys.getenv("R_PACKRAT_EXTERNAL_PACKAGES", unset = ""), local.repos = NULL, load.external.packages.on.startup = TRUE, ignored.packages = NULL, ignored.directories = c("data", "inst"), quiet.package.installation = TRUE, snapshot.recommended.packages = FALSE, snapshot.fields = c("Imports", "Depends", "LinkingTo"), symlink.system.packages = TRUE ) } initOptions <- function(project = NULL, options = default_opts()) { project <- getProjectDir(project) opts <- c(project = project, options) do.call(set_opts, opts) } ##' Get/set packrat project options ##' ##' Get and set options for the current packrat-managed project. ##' ##' @section Valid Options: ##' ##' \itemize{ ##' \item \code{auto.snapshot}: Perform automatic, asynchronous snapshots when running interactively? ##' (logical; defaults to \code{FALSE}) ##' \item \code{use.cache}: ##' Install packages into a global cache, which is then shared across projects? The ##' directory to use is read through \code{Sys.getenv("R_PACKRAT_CACHE_DIR")}. ##' Windows support is currently experimental. ##' (logical; defaults to \code{FALSE}) ##' \item \code{print.banner.on.startup}: ##' Print the banner on startup? Can be one of \code{TRUE} (always print), ##' \code{FALSE} (never print), and \code{'auto'} (do the right thing) ##' (defaults to \code{"auto"}) ##' \item \code{vcs.ignore.lib}: ##' If TRUE, version control configuration is modified to ignore packrat private libraries. ##' (logical; defaults to \code{TRUE}) ##' \item \code{vcs.ignore.src}: ##' If TRUE, version control configuration is modified to ignore packrat private sources. ##' (logical; defaults to \code{FALSE}) ##' \item \code{external.packages}: ##' Packages which should be loaded from the user library. This can be useful for ##' very large packages which you don't want duplicated across multiple projects, ##' e.g. BioConductor annotation packages, or for package development scenarios ##' wherein you want to use e.g. \code{devtools} and \code{roxygen2} for package ##' development, but do not want your package to depend on these packages. ##' (character; defaults to \code{Sys.getenv("R_PACKRAT_EXTERNAL_PACKAGES")}) ##' \item \code{local.repos}: ##' Ad-hoc local 'repositories'; i.e., directories containing package sources within ##' sub-directories. ##' (character; empty by default) ##' \item \code{load.external.packages.on.startup}: ##' Load any packages specified within \code{external.packages} on startup? ##' (logical; defaults to \code{TRUE}) ##' \item \code{ignored.packages}: ##' Prevent packrat from tracking certain packages. Dependencies of these packages ##' will also not be tracked (unless these packages are encountered as dependencies ##' in a separate context from the ignored package). ##' (character; empty by default) ##' \item \code{ignored.directories}: ##' Prevent packrat from looking for dependencies inside certain directories of your ##' workspace. For example, if you have set your "local.repos" to be inside your local ##' workspace so that you can track custom packages as git submodules. ##' Each item should be the relative path to a directory in the workspace, e.g. "data", ##' "lib/gitsubmodule". Note that packrat already ignores any "invisible" files and ##' directories, such as those whose names start with a "." character. ##' (character; empty by default) ##' \item \code{quiet.package.installation}: ##' Emit output during package installation? ##' (logical; defaults to \code{TRUE}) ##' \item \code{snapshot.recommended.packages}: ##' Should 'recommended' packages discovered in the system library be ##' snapshotted? See the \code{Priority} field of \code{available.packages()} ##' for more information -- 'recommended' packages are those normally bundled ##' with CRAN releases of R on OS X and Windows, but new releases are also ##' available on the CRAN server. ##' (logical; defaults to \code{FALSE}) ##' \item \code{snapshot.fields}: ##' What fields of a package's DESCRIPTION file should be used when discovering ##' dependencies? ##' (character, defaults to \code{c("Imports", "Depends", "LinkingTo")}) ##' \item \code{symlink.system.packages}: ##' Symlink base \R packages into a private \code{packrat/lib-R} directory? ##' This is done to further encapsulate the project from user packages that ##' have been installed into the \R system library. ##' (boolean, defaults to \code{TRUE}) ##' } ##' ##' @param options A character vector of valid option names. ##' @param simplify Boolean; \code{unlist} the returned options? Useful for when retrieving ##' a single option. ##' @param project The project directory. When in packrat mode, defaults to the current project; ##' otherwise, defaults to the current working directory. ##' @param persist Boolean; persist these options for future sessions? ##' @param ... Entries of the form \code{key = value}, used for setting packrat project options. ##' @rdname packrat-options ##' @name packrat-options ##' @export ##' @examples \dontrun{ ##' ## use 'devtools' and 'knitr' from the user library ##' packrat::set_opts(external.packages = c("devtools", "knitr")) ##' ##' ## set local repository ##' packrat::set_opts(local.repos = c("~/projects/R")) ##' ##' ## get the set of 'external packages' ##' packrat::opts$external.packages() ##' ##' ## set the external packages ##' packrat::opts$external.packages(c("devtools", "knitr")) ##' } get_opts <- function(options = NULL, simplify = TRUE, project = NULL) { project <- getProjectDir(project) cachedOptions <- get("options", envir = .packrat) if (is.null(cachedOptions)) { opts <- read_opts(project = project) assign("options", opts, envir = .packrat) } else { opts <- get("options", envir = .packrat) } if (is.null(options)) { opts } else { result <- opts[names(opts) %in% options] if (simplify) unlist(unname(result)) else result } } make_setter <- function(name) { force(name) function(x, persist = TRUE) { if (missing(x)) return(get_opts(name)) else setOptions(setNames(list(x), name), persist = persist) } } ##' @rdname packrat-options ##' @name packrat-options ##' @export set_opts <- function(..., project = NULL, persist = TRUE) { setOptions(list(...), project = project, persist = persist) } setOptions <- function(options, project = NULL, persist = TRUE) { project <- getProjectDir(project) optsPath <- packratOptionsFilePath(project) if (persist && !file.exists(optsPath)) { dir.create(dirname(optsPath), recursive = TRUE, showWarnings = FALSE) file.create(optsPath) } options <- validateOptions(options) keys <- names(options) values <- options opts <- read_opts(project = project) for (i in seq_along(keys)) { if (is.null(values[[i]])) opts[keys[[i]]] <- list(NULL) else opts[[keys[[i]]]] <- values[[i]] } write_opts(opts, project = project, persist = persist) if (persist) updateSettings(project) invisible(opts) } ##' @rdname packrat-options ##' @format NULL ##' @export opts <- setNames(lapply(names(VALID_OPTIONS), function(x) { make_setter(x) }), names(VALID_OPTIONS)) validateOptions <- function(opts) { for (i in seq_along(opts)) { key <- names(opts)[[i]] value <- opts[[i]] if (!(key %in% names(VALID_OPTIONS))) { stop("'", key, "' is not a valid packrat option", call. = FALSE) } opt <- VALID_OPTIONS[[key]] if (is.list(opt)) { if (!(value %in% opt)) { stop("'", value, "' is not a valid setting for packrat option '", key, "'", call. = FALSE) } } else if (is.function(opt)) { if (!opt(value)) { stop("'", value, "' is not a valid setting for packrat option '", key, "'", call. = FALSE) } } } opts } ## Read an options file with fields unparsed readOptsFile <- function(path) { content <- readLines(path) namesRegex <- "^[[:alnum:]\\_\\.]*:" namesIndices <- grep(namesRegex, content, perl = TRUE) if (!length(namesIndices)) return(list()) contentIndices <- mapply(seq, namesIndices, c(namesIndices[-1] - 1, length(content)), SIMPLIFY = FALSE) if (!length(contentIndices)) return(list()) result <- lapply(contentIndices, function(x) { if (length(x) == 1) { result <- sub(".*:\\s*", "", content[[x]], perl = TRUE) } else { first <- sub(".*:\\s*", "", content[[x[1]]]) if (first == "") first <- NULL rest <- gsub("^\\s*", "", content[x[2:length(x)]], perl = TRUE) result <- c(first, rest) } result[result != ""] }) names(result) <- unlist(lapply(strsplit(content[namesIndices], ":", fixed = TRUE), `[[`, 1)) result } ## Read and parse an options file. Returns the default set ## of options if no options available. read_opts <- function(project = NULL) { project <- getProjectDir(project) path <- packratOptionsFilePath(project) if (!file.exists(path)) return(default_opts()) opts <- readOptsFile(path) if (!length(opts)) return(default_opts()) opts[] <- lapply(opts, function(x) { if (identical(x, "TRUE")) { return(TRUE) } else if (identical(x, "FALSE")) { return(FALSE) } else if (identical(x, "NA")) { return(NA) } else { x } }) opts } write_opts <- function(options, project = NULL, persist = TRUE) { project <- getProjectDir(project) if (!is.list(options)) stop("Expecting options as an R list of values") # Fill options that are left out defaultOpts <- default_opts() missingOptionNames <- setdiff(names(defaultOpts), names(options)) for (optionName in missingOptionNames) { opt <- defaultOpts[[optionName]] if (is.null(opt)) { options[optionName] <- list(NULL) } else { options[[optionName]] <- opt } } # Preserve order options <- options[names(VALID_OPTIONS)] labels <- names(options) if ("external.packages" %in% names(options)) { oep <- as.character(options$external.packages) options$external.packages <- as.character(unlist(strsplit(oep, "\\s*,\\s*", perl = TRUE))) } # Update the in-memory options cache assign("options", options, envir = .packrat) # Write options to disk if (!persist) return(invisible(TRUE)) sep <- ifelse( unlist(lapply(options, length)) > 1, ":\n", ": " ) options[] <- lapply(options, function(x) { if (length(x) == 0) "" else if (length(x) == 1) as.character(x) else paste(" ", x, sep = "", collapse = "\n") }) output <- character(length(labels)) for (i in seq_along(labels)) { output[[i]] <- paste(labels[[i]], options[[i]], sep = sep[[i]]) } cat(output, file = packratOptionsFilePath(project), sep = "\n") } packrat/R/cache.R0000644000176200001440000002327013361406540013274 0ustar liggesusers# Used in case we need to special-case packages what packages are cached isCacheable <- function(package) { TRUE } isUsingCache <- function(project) { isTRUE(get_opts("use.cache", project = project)) } installedDescLookup <- function(pkgName) { system.file("DESCRIPTION", package = pkgName) } # We assume 'path' is the path to a DESCRIPTION file, or a data frame (the # data frame data must have stringsAsFactors = FALSE). # # descLookup is a function that takes a single argument pkgName and must # return one of: 1) a file path to DESCRIPTION file, 2) a data frame (with # stringsAsFactors = FALSE) of the DESCRIPTION dcf data, or 3) NULL if # the DESCRIPTION is not available. By default, installedDescLookup is # used, which looks in the active lib paths for the desired DESCRIPTION # files. # #' @importFrom tools md5sum hash <- function(path, descLookup = installedDescLookup) { if (!file.exists(path)) stop("No DESCRIPTION file at path '", path, "'!") if (is.data.frame(path)) { DESCRIPTION <- path } else { DESCRIPTION <- as.data.frame(readDcf(path), stringsAsFactors = FALSE) } pkgName <- DESCRIPTION[["Package"]] # Remote SHA backwards compatible with cache v2: use 'GithubSHA1' if exists, otherwise all 'Remote' fields remote_fields <- if ("GithubSHA1" %in% names(DESCRIPTION)) { "GithubSHA1" } else if (is.null(DESCRIPTION[["RemoteType"]]) || DESCRIPTION[["RemoteType"]] == "cran") { # Packages installed with install.packages or locally without remotes c() } else { # Mirror the order used by devtools when augmenting the DESCRIPTION. c("RemoteType", "RemoteHost", "RemoteRepo", "RemoteUsername", "RemoteRef", "RemoteSha", "RemoteSubdir") } # Mirror the order of DESCRIPTION fields produced by `package.skeleton` and # `devtools::create_description`. fields <- c("Package", "Version", "Depends", "Imports", "Suggests", "LinkingTo", remote_fields) # TODO: Do we want the 'Built' field used for hashing? The main problem with using that is # it essentially makes packages installed from source un-recoverable, since they will get # built transiently and installed (and so that field could never be replicated). # Create a "sub" data frame with a consistently ordered set of columns. # # This ensures that package hashing is not sensitive to DESCRIPTION field # order. common <- intersect(fields, names(DESCRIPTION)) sub <- DESCRIPTION[common] # Handle LinkingTo specially -- we need to discover what version of packages in LinkingTo # were actually linked against in order to properly disambiguate e.g. httpuv 1.0 linked # against Rcpp 0.11.2 and httpuv 1.0 linked against Rcpp 0.11.2.1 # TODO: It would really be best if, on installation, we recorded what version of LinkingTo # packages were actually linked to, in case that package is not available in the library # (or, even worse, is actually a different version!) linkingToField <- unlist(strsplit(as.character(sub[["LinkingTo"]]), "\\s*,\\s*")) linkingToPkgs <- gsub("\\s*\\(.*", "", linkingToField) linkingToPkgs <- gsub("^\\s*(.*?)\\s*$", "\\1", linkingToPkgs, perl = TRUE) linkingToHashes <- lapply(linkingToPkgs, function(x) { linkingToDesc <- descLookup(x) # If we return NULL if (is.null(linkingToDesc)) return(NULL) else if (is.character(linkingToDesc) && !file.exists(linkingToDesc)) return(NULL) else hash(linkingToDesc, descLookup = descLookup) }) missingLinkingToPkgs <- linkingToPkgs[vapply(linkingToHashes, is.null, logical(1))] if (length(missingLinkingToPkgs)) { warning("The following packages specified in the LinkingTo field for package '", pkgName, "' are unavailable:\n- ", paste(shQuote(missingLinkingToPkgs), collapse = ", "), "\nThese packages are required to be installed when attempting to hash this package for caching.", call. = FALSE) } linkingToHashes <- if (length(linkingToHashes)) paste( collapse = "", sort_c(unlist(dropNull(linkingToHashes))) ) # Normalize for hashing and add in the linkingTo hashes as well ready <- normalizeForHash(sub) ready <- paste(ready, linkingToHashes) tempfile <- tempfile() cat(ready, file = tempfile) result <- md5sum(tempfile) unlink(tempfile) if (is.na(result)) stop("Failed to hash file!") unname(result) } normalizeForHash <- function(item) { gsub("[[:space:]]", "", paste(unlist(item), collapse = "")) } isVerboseCache <- function() { return(isTRUE(getOption("packrat.verbose.cache"))) } # helper function to remove the package from its original location and # create a symlink to the cached version. symlinkPackageToCache <- function(packagePath, cachedPackagePath) { packageName <- basename(packagePath) backupPackagePath <- tempfile(tmpdir = dirname(packagePath)) if (!file.rename(packagePath, backupPackagePath)) { stop("failed to back up package directory '", packagePath, "'; cannot safely link to cache.") } on.exit(unlink(backupPackagePath, recursive = TRUE), add = TRUE) if (!symlink(cachedPackagePath, packagePath)) { # symlink failed; attempt to restore the backup back to its original name. if (!file.rename(backupPackagePath, packagePath)) { stop("failed to restore package from '", backupPackagePath, "' to ", "'", packagePath, "' after symlink to ", "'", cachedPackagePath, "' failed; package may be lost") } stop("failed to create a symlink from '", packagePath, "' to '", cachedPackagePath, "'") } if (isVerboseCache()) { message("Using cached ", packageName, ".") } return(cachedPackagePath) } # Given a path to an installed package (outside the packrat cache), move that # package into the cache and replace the original directory with a symbolic # link into the package cache. # # If the package already exists inside the cache, overwrite=TRUE causes # replacement of the cached content while overwrite=FALSE with fatal=FALSE # uses the cached package. Using overwrite=TRUE with fatal=TRUE will err. moveInstalledPackageToCache <- function(packagePath, hash, overwrite = TRUE, fatal = FALSE, cacheDir = cacheLibDir()) { ensureDirectory(cacheDir) packageName <- basename(packagePath) cachedPackagePath <- file.path(cacheDir, packageName, hash, packageName) backupPackagePath <- tempfile(tmpdir = dirname(cachedPackagePath)) # check for existence of package in cache if (file.exists(cachedPackagePath)) { if (fatal && !overwrite) { stop("cached package already exists at path '", cachedPackagePath, "'") } if (!fatal) { return(symlinkPackageToCache(packagePath, cachedPackagePath)) } } # back up a pre-existing cached package (restore on failure) if (file.exists(cachedPackagePath)) { if (!file.rename(cachedPackagePath, backupPackagePath)) { stop("failed to back up package '", packageName, "'; cannot safely copy to cache") } on.exit(unlink(backupPackagePath, recursive = TRUE), add = TRUE) } if (isVerboseCache()) { message("Caching ", packageName, ".") } # attempt to rename to cache if (suppressWarnings(file.rename(packagePath, cachedPackagePath))) { return(symlinkPackageToCache(packagePath, cachedPackagePath)) } # rename failed; copy to temporary destination in same directory # and then attempt to rename from there tempPath <- tempfile(tmpdir = dirname(cachedPackagePath)) on.exit(unlink(tempPath, recursive = TRUE), add = TRUE) if (all(dir_copy(packagePath, tempPath))) { # check to see if the cached package path exists now; if it does, # assume that this was generated by another R process that successfully # populated the cache if (file.exists(cachedPackagePath)) { return(symlinkPackageToCache(packagePath, cachedPackagePath)) } # attempt to rename to target path if (suppressWarnings(file.rename(tempPath, cachedPackagePath))) { return(symlinkPackageToCache(packagePath, cachedPackagePath)) } } # failed to insert package into cache -- clean up and return error if (!file.rename(backupPackagePath, cachedPackagePath)) { stop("failed to restore package '", packageName, "' in cache; package may be lost from cache") } # return failure stop("failed to copy package '", packageName, "' to cache") } # Pull out cached package information from the DESCRIPTION cachedPackages <- function(cacheDir = cacheLibDir(), fields = NULL) { pkgCachePaths <- list.files(cacheDir, full.names = TRUE) pkgPaths <- setNames(lapply(pkgCachePaths, function(x) { list.files(x, full.names = TRUE) }), basename(pkgCachePaths)) lapply(seq_along(pkgPaths), function(i) { pkgName <- names(pkgPaths)[[i]] hashedPaths <- pkgPaths[[i]] result <- setNames(lapply(hashedPaths, function(path) { as.list(readDcf(file.path(path, pkgName, "DESCRIPTION"), all = TRUE)) }), pkgName) if (!is.null(fields)) { lapply(result, `[`, fields) } else { result } }) } listCachedPackages <- cachedPackages clearPackageCache <- function(cacheDir = cacheLibDir(), ask = TRUE) { if (ask) { message("The packrat cache directory was resolved to:\n- ", shQuote(cacheDir)) msg <- "Are you sure you want to clear the packrat cache? [Y/n]: " response <- readline(msg) if (tolower(substring(response, 1, 1)) != "y") { message("Operation aborted.") return(invisible(NULL)) } } unlink(cacheDir, recursive = TRUE) } deletePackagesFromCache <- function(packages, cacheDir = cacheLibDir()) { paths <- file.path(cacheDir, packages) lapply(paths, function(path) { unlink(path, recursive = TRUE) }) } packrat/R/platform.R0000644000176200001440000000027713352207316014057 0ustar liggesusersis.windows <- function() { Sys.info()["sysname"] == "Windows" } is.mac <- function() { Sys.info()["sysname"] == "Darwin" } is.linux <- function() { Sys.info()["sysname"] == "Linux" } packrat/R/packrat.R0000644000176200001440000005211413352207316013655 0ustar liggesusers#' Packrat: Reproducible dependency management #' #' Packrat is a tool for managing the \R packages your project depends on in #' an isolated, portable, and reproducible way. #' #' Use packrat to make your \R projects more: #' #' \itemize{ #' \item \strong{Isolated}: Installing a new or updated package for one project #' won't break your other projects, and vice versa. That's because packrat gives #' each project its own private package library. #' \item \strong{Portable}: Easily transport your projects from one computer to #' another, even across different platforms. Packrat makes it easy to install the #' packages your project depends on. #' \item \strong{Reproducible}: Packrat records the exact package versions you #' depend on, and ensures those exact versions are the ones that get installed #' wherever you go.} #' #' Use \code{\link{init}} to create a new packrat project, #' \code{\link{snapshot}} to record changes to your project's library, and #' \code{\link{restore}} to recreate your library the way it was the last time you #' (or anyone!) took a snapshot. #' #' Using these simple functions and sharing packrat's files lets you collaborate #' in a shared, consistent environment with others as your project grows and #' changes, and provides an easy way to share your results when you're done. #' #' @section Anatomy of a packrat project: #' #' A packrat project contains a few extra files and directories. The #' \code{\link{init}} function creates these files for you, if they don't #' already exist. #' #' \describe{ #' \item{\code{packrat/lib/}}{Private package library for this project.} #' \item{\code{packrat/src/}}{Source packages of all the dependencies that #'packrat has been made aware of.} #' #' \item{\code{packrat/packrat.lock}}{Lists the precise package versions that were used #' to satisfy dependencies, including dependencies of dependencies. (This file #' should never be edited by hand!)} #' #' \item{\code{.Rprofile}}{Directs \R to use the private package #' library (when it is started from the project directory).} #' } #' #' @section Using packrat with version control: #' #' Packrat is designed to work hand in hand with Git, Subversion, or any other #' version control system. Be sure to check in the \code{.Rprofile}, #' \code{packrat.lock} files, and everything under #' \code{packrat/src/}. You can tell your VCS to ignore \code{packrat/lib/} (or #' feel free to check it in if you don't mind taking up some extra space in your #' repository). #' #' @examples #' \dontrun{ #' # Create a new packrat project from an existing directory of \R code #' init() #' #' # Install a package and take a snapshot of the new state of the library #' install.packages("TTR") #' snapshot() #' #' # Accidentally remove a package and restore to add it back #' remove.packages("TTR") #' restore() #' } #' #' @docType package #' @name packrat #' @import utils #' @author RStudio, Inc. NULL #' Initialize Packrat on a new or existing \R project #' #' Given a project directory, makes a new packrat project in the directory. #' #' \code{init} works as follows: #' #' \enumerate{ #' #' \item Application dependencies are computed by examining the \R code #' throughout the project for \code{library} and \code{require} calls. You can #' opt out of this behavior by setting \code{infer.dependencies} to #' \code{FALSE}. #' #' \item A snapshot is taken of the version of each package currently used by #' the project as described in \code{\link{snapshot}}, and each package's #' sources are downloaded. #' #' \item A private library is created in the directory. #' #' \item The snapshot is applied to the directory as described in #' \code{\link{restore}}. } When \code{init} is finished, all the packages #' on which the project depends are installed in a new, private library located #' inside the project directory. #' #' \strong{You must restart your \R session in the given project directory after #' running \code{init} in order for the changes to take effect!} #' #' When \R is started in the directory, it will use the new, private library. #' Calls to \code{\link{require}} and \code{\link{library}} will load packages #' from the private library (except for 'base' or 'recommended' \R packages, #' which are found in the system library), and functions such as \code{\link{install.packages}} #' will modify that private library. You can sync this private library with #' packrat using \code{\link{snapshot}} and \code{\link{restore}}. #' #' @param project The directory that contains the \R project. #' @param options An \R \code{list} of options, as specified in #' \code{\link{packrat-options}}. #' @param enter Boolean, enter packrat mode for this project after finishing a init? #' @param restart If \code{TRUE}, restart the R session after init. #' @param infer.dependencies If \code{TRUE}, infer package dependencies by #' examining the \R code. #' #' @note #' #' The \code{restart} parameter will only result in a restart of R when the #' R environment packrat is running within makes available a restart function #' via \code{getOption("restart")}. #' #' @seealso \link{packrat} for a description of the files created by #' \code{init}. #' @examples \dontrun{ #' #' ## initialize a project using a local repository of packages #' packrat::init(options = list(local.repos = "~/projects/R")) #' #' } #' @export init <- function(project = '.', options = NULL, enter = TRUE, restart = enter, infer.dependencies = TRUE) { ## Get the initial directory structure, so we can rewind if necessary project <- normalizePath(project, winslash = '/', mustWork = TRUE) message("Initializing packrat project in directory:\n- ", surround(prettyDir(project), "\"")) ## A set of files that packrat might generate as part of init -- we ## enumerate them here to assist with later cleanup prFiles <- c( file.path(project, ".gitignore"), file.path(project, ".Rprofile"), file.path(project, "packrat"), file.path(project, "packrat", "lib"), file.path(project, "packrat", "lib-R"), file.path(project, "packrat", "src"), file.path(project, "packrat", "packrat.lock"), file.path(project, "packrat", "packrat.opts") ) priorStructure <- setNames( file.exists(prFiles), prFiles ) withCallingHandlers( initImpl(project, options, enter, restart, infer.dependencies), error = function(e) { # Undo any changes to the directory that did not exist previously for (i in seq_along(priorStructure)) { file <- names(priorStructure)[[i]] fileExistedBefore <- priorStructure[[i]] fileExistsNow <- file.exists(file) if (!fileExistedBefore && fileExistsNow) { unlink(file, recursive = TRUE) } } } ) } initImpl <- function(project = getwd(), options = NULL, enter = TRUE, restart = enter, infer.dependencies = TRUE) { opts <- get_opts(project = project) if (is.null(opts)) opts <- default_opts() # Read custom Packrat options and apply them customDefaultOptions <- getOption("packrat.default.project.options") if (!is.null(customDefaultOptions)) { # Validate the options (will stop on failure) validateOptions(customDefaultOptions) # Set the options for (i in seq_along(customDefaultOptions)) { name <- names(customDefaultOptions)[[i]] opts[[name]] <- customDefaultOptions[[name]] } } # NOTE: Explicitly set options should override default options set by # the user if (!is.null(options)) { for (i in seq_along(options)) { name <- names(options)[[i]] opts[[name]] <- options[[name]] } } # Force packrat mode off if (isPackratModeOn()) off() # We always re-packify so that the current version of packrat present can # insert the appropriate auto-loaders packify(project = project, quiet = TRUE) # Make sure the .Rprofile is up to date augmentRprofile(project) options <- initOptions(project, opts) ## writes out packrat.opts and returns generated list # If we don't yet have a lockfile, take a snapshot and then build the Packrat library. if (!file.exists(lockFilePath(project = project))) { snapshotImpl(project, lib.loc = NULL, ignore.stale = TRUE, fallback.ok = TRUE, infer.dependencies = infer.dependencies) restore(project, overwrite.dirty = TRUE, restart = FALSE) } # Copy init.R so a user can 'start from zero' with a project file.copy( instInitFilePath(), file.path(project, "packrat", "init.R") ) # Update project settings -- this also involves updating the .gitignore, # etc updateSettings(project, options) ## Symlink system libraries always symlinkSystemPackages(project = project) message("Initialization complete!") if (enter) { setwd(project) # Restart R if the environment is capable of it (otherwise enter packrat mode) if (!restart || !attemptRestart()) on(project = project, clean.search.path = TRUE) } invisible() } #' Apply the most recent snapshot to the library #' #' Applies the most recent snapshot to the project's private library. #' #' \code{restore} works by adding, removing, and changing packages so that the #' set of installed packages and their versions matches the snapshot exactly. #' #' There are three common use cases for \code{restore}: #' \itemize{ #' \item \strong{Hydrate}: Use \code{restore} after copying a project to a new #' machine to populate the library on that machine. #' #' \item \strong{Sync}: Use \code{restore} to apply library changes made by a #' collaborator to your own library. (In general, you want to run \code{restore} #' whenever you pick up a change to \code{packrat.lock}) #' #' \item \strong{Rollback}: Use \code{restore} to undo accidental changes made #' to the library since the last snapshot. #' } #' #' \code{restore} cannot make changes to packages that are currently loaded. If #' changes are necessary to currently loaded packages, you will need to restart #' \R to apply the changes (\code{restore} will let you know when this is #' necessary). It is recommended that you do this as soon as possible, because #' any library changes made between running \code{restore} and restarting \R will #' be lost. #' #' @note #' \code{restore} can be destructive; it will remove packages that were not in #' the snapshot, and it will replace newer packages with older versions if #' that's what the snapshot indicates. \code{restore} will warn you before #' attempting to remove or downgrade a package (if \code{prompt} is #' \code{TRUE}), but will always perform upgrades and new installations without #' prompting. #' #' \code{restore} works only on the private package library created by packrat; #' if you have other libraries on your path, they will be unaffected. #' #' The \code{restart} parameter will only result in a restart of R when the #' R environment packrat is running within makes available a restart function #' via \code{getOption("restart")}. #' #' @param project The project directory. When in packrat mode, if this is \code{NULL}, #' then the directory associated with the current packrat project is used. Otherwise, #' the project directory specified is used. #' @param overwrite.dirty A dirty package is one that has been changed since the #' last snapshot or restore. Packrat will leave these alone by default. If you #' want to guarantee that \code{restore} will put you in the exact state #' represented by the snapshot being applied, use \code{overwrite.dirty = TRUE}. #' @param prompt \code{TRUE} to prompt before performing potentially destructive #' changes (package removals or downgrades); \code{FALSE} to perform these #' operations without confirmation. #' @param dry.run If \code{TRUE}, compute the changes to your packrat state that #' would be made if a restore was performed, without actually executing them. #' @param restart If \code{TRUE}, restart the R session after restoring. #' #' @seealso #' \code{\link{snapshot}}, the command that creates the snapshots applied with #' \code{restore}. #' #' \code{\link{status}} to view the differences between the most recent snapshot #' and the library. #' #' @export restore <- function(project = NULL, overwrite.dirty = FALSE, prompt = interactive(), dry.run = FALSE, restart = !dry.run) { project <- getProjectDir(project) stopIfNoLockfile(project) if (!dry.run) { callHook(project, "restore", TRUE) on.exit(callHook(project, "restore", FALSE), add = TRUE) } # Ensure the .libPaths() is set for the duration of this restore. # Because it's possible for a user to attempt to restore a particular # project while _not_ within packrat mode, we do not want the new # .libPaths() to be persistent -- so we unset them at the conclusion # of the restore. This is done to ensure downstream calls to e.g. # `system.file()` are successful. libDir <- libDir(project) if (!file.exists(libDir(project))) dir.create(libDir(project), recursive = TRUE) oldLibPaths <- .libPaths() .libPaths(c(libDir(project), oldLibPaths)) on.exit(.libPaths(oldLibPaths), add = TRUE) # RTools cp.exe (invoked during installation) can warn on Windows since we # use paths of the format c:/foo/bar and it prefers /cygwin/c/foo/bar. # Unfortunately, R's implementation of tar treats this warning output as # though it were part of the list of files in the archive. cygwin <- Sys.getenv("CYGWIN", unset = NA) if (Sys.info()["sysname"] == "Windows" && length(grep("nodosfilewarning", cygwin)) == 0) { Sys.setenv("CYGWIN" = paste(cygwin, "nodosfilewarning")) on.exit(Sys.setenv("CYGWIN" = cygwin), add = TRUE) } # Validate the version of R used when restoring this project, and # warn if the versions don't match. packages <- lockInfo(project) r_version <- lockInfo(project, 'r_version') if (!identical(as.character(getRversion()), r_version)) { warning('The most recent snapshot was generated using R version ', r_version) } # See if any of the packages that are currently in the library are dirty. # Dirty packages that are represented in the snapshot will be either ignored # (with a message) or overwritten, depending on the value of the # overwrite.dirty flag. Dirty packages that are not represented in the snapshot # (like git untracked) will be silently ignored in all cases. libPkgNames <- rownames(installed.packages(libDir, noCache = TRUE)) dirty <- !installedByPackrat(libPkgNames, libDir, TRUE) dirtyPackageNames <- libPkgNames[dirty] if (!isTRUE(overwrite.dirty)) { prettyPrint( packages[pkgNames(packages) %in% dirtyPackageNames], 'The following packages were not installed by packrat and will be ignored:', 'If you would like to overwrite them, call restore again with\noverwrite.dirty = TRUE.' ) # Keep all dirty packages pkgsToIgnore <- dirtyPackageNames } else { # Even if overwrite.dirty is TRUE, we still want to keep packages that are # dirty and NOT represented in the list of packages to install (this is akin # to "untracked" files in git). pkgsToIgnore <- dirtyPackageNames[!dirtyPackageNames %in% pkgNames(packages)] } # Configure repos globally to avoid explicitly passing the repos list to all # downstream function calls. repos <- lockInfo(project, 'repos') externalRepos <- getOption('repos') options(repos = repos) on.exit({ options(repos = externalRepos) }, add = TRUE) # Install each package from CRAN or github/bitbucket, from binaries when available and # then from sources. restoreImpl(project, repos, packages, libDir, pkgsToIgnore = pkgsToIgnore, prompt = prompt, dry.run = dry.run, restart = restart) } #' Remove Packages from the Library #' #' Remove packages from the given library. #' #' @param packages A set of package names to remove from the project. When #' \code{NULL}, \code{\link{unused_packages}} is used to find packages #' unused in the project. #' @param project The project directory. Defaults to current working #' directory. #' @param lib.loc The library to clean. Defaults to the private package library #' associated with the project directory. #' @param dry.run Perform a dry run, returning records on which packages would #' have been moved by the current clean action. #' @param force Force package removal, even if they are still in use within the project? #' #' @examples \dontrun{ #' #' # Get unused package records #' unused_packages() #' #' # Clean all unused packages #' clean() #' #' # Clean specific packages #' clean("foo") #' #' } #' @export clean <- function(packages = NULL, project = NULL, lib.loc = libDir(project), dry.run = FALSE, force = FALSE) { project <- getProjectDir(project) callHook(project, "clean", TRUE) on.exit(callHook(project, "clean", FALSE), add = TRUE) cleanableRecords <- unused_packages(project = project, lib.loc = lib.loc) cleanable <- sapply(cleanableRecords, "[[", "name") if (is.null(packages)) { packages <- cleanable } pkgsUnsafeToRemove <- setdiff(packages, cleanable) if (length(pkgsUnsafeToRemove) && !force && !dry.run) { stop("The following packages are in use in your project and are unsafe to remove:\n- ", paste(shQuote(pkgsUnsafeToRemove), collapse = ", "), "\nUse clean(..., force = TRUE) to force removal") } if (dry.run) { if (identical(packages, cleanable)) { pkgRecords <- cleanableRecords } else { pkgRecords <- getPackageRecords(packages, project = project, available = NULL, recursive = FALSE, lib.loc = lib.loc) } actions <- rep("remove", length(packages)) names(actions) <- packages invisible(list(pkgRecords = pkgRecords, actions = actions)) } else { result <- removePkgs(project = project, pkgNames = packages, lib.loc = lib.loc) if (length(result)) { message("The following packages have been removed:\n- ", paste(shQuote(result), collapse = ", ")) } else { message("The packrat private library is already clean.") } invisible(result) } } ##' Find Unused Packages in a Project ##' ##' Unused packages are those still contained within your project library, but ##' are unused in your project. ##' ##' @param project The project directory. ##' @param lib.loc The library to check. ##' @export unused_packages <- function(project = NULL, lib.loc = libDir(project)) { project <- getProjectDir(project) packagesInUse <- appDependencies(project) installedPkgNames <- row.names(installed.packages( lib.loc = lib.loc, priority = c('NA', 'recommended'), noCache = TRUE )) orphans <- setdiff(installedPkgNames, packagesInUse) ## Exclude 'manipulate', 'rstudio' orphans <- setdiff(orphans, c("manipulate", "rstudio")) orphanRecs <- getPackageRecords(orphans, project = project, available = NULL, recursive = FALSE, lib.loc = lib.loc) orphanRecs } #' Automatically Enter Packrat Mode on Startup #' #' Install/augment the \code{.Rprofile} in a project, so that all \R sessions #' started in this directory enter \code{packrat mode}, and use the local #' project library. #' #' It is not normally necessary to call \code{packify} directly; these files are #' normally installed by \code{\link{init}}. \code{packify} can be used to #' restore the files if they are missing (for instance, if they were not added to #' source control, or were accidentally removed). #' #' You'll need to restart \R in the specified directory after running #' \code{packify} in order to start using the private package library. #' #' @param project The directory in which to install the \code{.Rprofile} file. #' @param quiet Be chatty? #' @export packify <- function(project = NULL, quiet = FALSE) { project <- getProjectDir(project) packratDir <- getPackratDir(project) if (!file.exists(packratDir)) { dir.create(packratDir) } libraryRootDir <- libraryRootDir(project) if (!file.exists(libraryRootDir)) { dir.create(libraryRootDir) } srcDir <- srcDir(project) if (!file.exists(srcDir)) { dir.create(srcDir) } ## Copy over the packrat autoloader augmentRprofile(project = project) ## Copy in packrat/init.R file.copy( instInitFilePath(), file.path(project, "packrat", "init.R"), overwrite = TRUE ) invisible() } lockInfo <- function(project, property='packages', fatal=TRUE) { project <- getProjectDir(project) # Get and parse the lockfile lockFilePath <- lockFilePath(project) if (!file.exists(lockFilePath)) { if (fatal) { stop(paste(lockFilePath, " is missing. Run packrat::init('", project, "') to generate it.", sep = "")) } else { return(list()) } } readLockFile(lockFilePath)[[property]] } packrat/R/lockfile-metadata.R0000644000176200001440000000734213352207316015601 0ustar liggesusers#' Get / Set packrat lockfile metadata #' #' Get and set metadata in the current packrat-managed project lockfile \code{packrat.lock} #' #' Project's \code{packrat.lock} contains some metadata before packages #' dependencies informations. The project's lockfile is created and updated #' programmatically by \code{\link{snapshot}}. However it could be necessary sometimes to #' modify manually some of those values. For example, it could be useful to set another repository #' CRAN url when deploying to a offline environnement. #' #' @section available metadata : #' #' \itemize{ #' \item \code{r_version}: R version the project depends on #' \item \code{repos}: Name of repos and their url recorded packages can be #' retrieve from. Only url is recommended to change if need. Name of repos is #' used in package records and must be identical #' } #' #' @param repos A named character vector of the form \code{c( = "")}. #' @param r_version A length-one character vector with suitable numeric version #' string. See \code{\link[base]{package_version}}. #' @param project The project directory. When in packrat mode, defaults to the current project; #' otherwise, defaults to the current working directory. #' @export #' @rdname lockfile-metadata #' @name lockfile-metadata #' @examples \dontrun{ #' # changes repos url #' repos <- old_repos <- get_lockfile_metadata("repos") #' repos #' repos["CRAN"] <- "https://cran.r-project.org/" #' set_lockfile_metadata(repos = repos) #' get_lockfile_metadata("repos") #' # setting back old state #' # set_lockfile_metadata(repos = old_repos) #' #' # changes R version #' rver <- old_rver <- get_lockfile_metadata("r_version") #' rver #' rver <- "3.4.1" #' set_lockfile_metadata(r_version = rver) #' get_lockfile_metadata("r_version") #' # Setting back old state #' # set_lockfile_metadata(r_version = old_rver) #' } set_lockfile_metadata <- function(repos = NULL, r_version = NULL, project = NULL) { project <- getProjectDir(project) lf_filepath <- lockFilePath(project) if (!file.exists(lf_filepath)) { stop(paste(lockFilePath, " is missing. Run packrat::init('", project, "') to generate it.", sep = "")) } lf <- as.data.frame(readDcf(lf_filepath), stringsAsFactors = FALSE) # update repos if (!is.null(repos)) { # Windows automatically transforms \n to \r\n on write through write.dcf separator <- ",\n" reposString <- paste(names(repos), unname(repos), sep = "=", collapse = separator) lf[1, "Repos"] <- reposString } # update rversion if (!is.null(r_version)) { if (length(r_version) > 1) { stop("RVersion metadata must contains one element only", call. = FALSE) } lf[1, "RVersion"] <- as.character(package_version(r_version)) } # write back the lockfile write_dcf(lf, lf_filepath) invisible() } #' @param metadata The lockfile field name(s) to draw from. #' @param simplify Boolean; if \code{TRUE} the returned metadata will be un-listed. #' #' @rdname lockfile-metadata #' @name lockfile-metadata #' @export get_lockfile_metadata <- function(metadata = NULL, simplify = TRUE, project = NULL) { project <- getProjectDir(project) # Get and parse the lockfile lockFilePath <- lockFilePath(project) if (!file.exists(lockFilePath)) { stop(paste(lockFilePath, " is missing. Run packrat::init('", project, "') to generate it.", sep = "")) } lf_metadata <- readLockFile(lockFilePath)[names(available_metadata)] if (is.null(metadata)) { lf_metadata } else { result <- lf_metadata[names(lf_metadata) %in% metadata] if (simplify) unlist(unname(result)) else result } } # lockfile metadata available for modification and r_aliases available_metadata <- c( r_version = "RVersion", repos = "Repos" ) packrat/R/paths.R0000644000176200001440000001647113352207316013355 0ustar liggesusers#' Paths to Packrat Resources #' #' These functions provide a mechanism for retrieving the paths to #' Packrat resource directories. Each of these directories can be #' overridden by setting either an environment variable, or an \R #' option. #' #' @section Project Directory: #' #' \code{project_dir()} is special -- the \code{R_PACKRAT_PROJECT_DIR} #' environment variable is set and unset by \code{\link{on}} and #' \code{\link{off}}, respectively, and generally should not be #' overridden by the user. #' #' @section Directory Resolution: #' #' The following table shows the order in which resource directories #' are discovered (from left to right). The first non-empty result is #' used. #' #' \tabular{llll}{ #' \strong{API} \tab \strong{Environment Variable} \tab \strong{R Option} \tab \strong{Default Value} \cr #' \code{project_dir()} \tab \code{R_PACKRAT_PROJECT_DIR} \tab \code{packrat.project.dir} \tab \code{getwd()} \cr #' \code{src_dir()} \tab \code{R_PACKRAT_SRC_DIR} \tab \code{packrat.src.dir} \tab \code{"packrat/src"} \cr #' \code{lib_dir()} \tab \code{R_PACKRAT_LIB_DIR} \tab \code{packrat.lib.dir} \tab \code{"packrat/lib"} \cr #' \code{bundles_dir()} \tab \code{R_PACKRAT_BUNDLES_DIR} \tab \code{packrat.bundles.dir} \tab \code{"packrat/bundles"} \cr #' \emph{(none)} \tab \code{R_PACKRAT_LIB_R_DIR} \tab \code{packrat.lib-r.dir} \tab \code{"packrat/lib-R"} \cr #' \emph{(none)} \tab \code{R_PACKRAT_LIB_EXT_DIR} \tab \code{packrat.lib-ext.dir} \tab \code{"packrat/lib-ext"} \cr #' } #' #' @param project The project directory. #' @rdname packrat-resources #' @name packrat-resources NULL #' @rdname packrat-resources #' @export project_dir <- function(project = NULL) { getProjectDir(project = project) } #' @rdname packrat-resources #' @export src_dir <- function(project = NULL) { srcDir(project = project) } #' @rdname packrat-resources #' @export lib_dir <- function(project = NULL) { libDir(project = project) } #' @rdname packrat-resources #' @export bundles_dir <- function(project = NULL) { bundlesDir(project = project) } # Internal Implementations ---- getProjectDir <- function(project = NULL) { if (!is.null(project) && length(project) > 0) return(normalizePath(project, winslash = "/", mustWork = TRUE)) packratOption( "R_PACKRAT_PROJECT_DIR", "packrat.project.dir", if (length(getwd()) > 0) normalizePath(getwd(), winslash = "/", mustWork = TRUE) else "" ) } getPackratDir <- function(project = NULL) { project <- getProjectDir(project) file.path(project, "packrat") } platformRelDir <- function() { file.path(R.version$platform, getRversion()) } libDir <- function(project = NULL) { packratOption( "R_PACKRAT_LIB_DIR", "packrat.lib.dir", file.path(libraryRootDir(project), platformRelDir()) ) } libRdir <- function(project = NULL) { packratOption( "R_PACKRAT_LIB_R_DIR", "packrat.lib-r.dir", file.path(getPackratDir(project), "lib-R", platformRelDir()) ) } libExtDir <- function(project = NULL) { packratOption( "R_PACKRAT_LIB_EXT_DIR", "packrat.lib-ext.dir", file.path(getPackratDir(project), "lib-ext", platformRelDir()) ) } srcDir <- function(project = NULL) { packratOption( "R_PACKRAT_SRC_DIR", "packrat.src.dir", file.path(getPackratDir(project), "src") ) } bundlesDir <- function(project = NULL) { packratOption( "R_PACKRAT_BUNDLES_DIR", "packrat.bundles.dir", file.path(getPackratDir(project), "bundles") ) } relLibDir <- function() { file.path("packrat", relativeLibDir("lib")) } ## The root library directory for a project, e.g. //lib libraryRootDir <- function(project = NULL) { project <- getProjectDir(project) file.path(project, "packrat/lib") } relLibraryRootDir <- function() { "packrat/lib" } relativeLibDir <- function(libraryRoot) { file.path(libraryRoot, R.version$platform, getRversion()) } # Temporary library directory when modifying an in-use library newLibraryDir <- function(project = NULL) { file.path(getPackratDir(project), "library.new") } relNewLibraryDir <- function() { file.path("packrat", "library.new") } oldLibraryDir <- function(project = NULL) { file.path(getPackratDir(project), "library.old") } relOldLibraryDir <- function() { "packrat/library.old" } relSrcDir <- function() { "packrat/src" } lockFilePath <- function(project = NULL) { file.path(getPackratDir(project), "packrat.lock") } snapshotLockFilePath <- function(project = NULL) { file.path(getPackratDir(project), "snapshot.lock") } ## Use a file instead of env. variables as it"s better handled across ## multiple R sessions packratModeFilePath <- function(project = NULL) { packratDir <- getPackratDir(project) file.path(packratDir, "packrat.mode") } instInitFilePath <- function() { file.path(system.file(package = "packrat"), "resources/init.R") } instInitRprofileFilePath <- function() { file.path(system.file(package = "packrat"), "resources/init-rprofile.R") } instMacRUserlibFilePath <- function() { file.path(system.file(package = "packrat"), "resources/mac_r_userlib.sh") } packratOptionsFilePath <- function(project = NULL) { file.path(getPackratDir(project), "packrat.opts") } startsWithBytes <- function(x, y) { Encoding(x) <- Encoding(y) <- "bytes" return(substring(x, 1, nchar(y, type = "bytes")) == y) } prettyDir <- function(project = NULL, ...) { project <- getProjectDir(project) homeDir <- path.expand("~/") if (startsWithBytes(project, homeDir)) project <- gsub(homeDir, "~/", project, fixed = TRUE) file.path(project, ...) } prettyProjectDir <- function(project = NULL) { prettyDir(project = project) } prettyLibDir <- function(project = NULL) { prettyDir(project = project, "packrat/lib") } #' @rdname packrat-external #' @name packrat-external #' @export user_lib <- function() { libraries <- unlist(strsplit(Sys.getenv("R_LIBS_USER"), .Platform$path.sep, fixed = TRUE)) normalizePath(libraries, winslash = "/", mustWork = FALSE) } userLib <- user_lib #' @rdname packrat-external #' @name packrat-external #' @export packrat_lib <- function() { project <- getProjectDir() libDir(project) } ## A location where "global" packrat data is stored, e.g. the library cache appDataDir <- function() { packratOption( "R_PACKRAT_CACHE_DIR", "packrat.cache.dir", defaultAppDataDir() ) } defaultAppDataDir <- function() { # borrowed and modified from shinyapps # get the home directory from the operating system (in case # the user has redefined the meaning of ~) but fault back # to ~ if there is no HOME variable defined homeDir <- Sys.getenv("HOME", unset = "~") # determine application config dir (platform specific) if (is.windows()) appDataDirBase <- Sys.getenv("APPDATA") else if (is.mac()) appDataDirBase <- file.path(homeDir, "Library/Application Support") else appDataDirBase <- Sys.getenv("XDG_CONFIG_HOME", file.path(homeDir, ".config")) # normalize path appDataDir <- normalizePath(file.path(appDataDirBase, "packrat"), mustWork = FALSE) # return it appDataDir } packratCacheVersion <- function() { "v2" } cacheLibDir <- function(...) { file.path(appDataDir(), packratCacheVersion(), "library", ...) } untrustedCacheLibDir <- function(...) { file.path(appDataDir(), packratCacheVersion(), "library-client", ...) } packrat/R/recursive-package-dependencies.R0000644000176200001440000001236413352207316020257 0ustar liggesusersgetPackageDependencies <- function(pkgs, lib.loc, available.packages = availablePackages(), fields = c("Depends", "Imports", "LinkingTo")) { if (isPackratModeOn()) { lockPkgs <- readLockFilePackages(file = lockFilePath()) } deps <- unlist(lapply(pkgs, function(pkg) { # Read the package DESCRIPTION file pkgDescFile <- system.file('DESCRIPTION', package = pkg, lib.loc = lib.loc) # Get any packages available in local repositories localReposPkgPaths <- as.character(unlist(lapply(opts$local.repos(), function(x) { fullPaths <- list.files(x, full.names = TRUE) fullPaths[file.exists(file.path(fullPaths, "DESCRIPTION"))] }))) localReposPkgs <- basename(localReposPkgPaths) if (file.exists(pkgDescFile)) { # try to read dependency information from the locally installed package # if it's available (dependency information in available.packages may not # be accurate if there's a locally installed version with a different # dependency list) theseDeps <- combineDcfFields(as.data.frame(readDcf(pkgDescFile)), fields) } else if (isPackratModeOn() && pkg %in% names(lockPkgs)) { # if packrat mode is on, we'll also try reading dependencies from the lock file theseDeps <- lockPkgs[[pkg]]$requires } else if (pkg %in% row.names(available.packages)) { # no locally installed version but we can check dependencies in the # package database theseDeps <- as.list( available.packages[pkg, fields]) } else if (pkg %in% localReposPkgs) { # use the version in the local repository allIdx <- which(localReposPkgs == pkg) path <- localReposPkgPaths[allIdx[1]] if (length(allIdx) > 1) { warning("Package '", pkg, "' found in multiple local repositories; ", "inferring dependencies from package at path:\n- ", shQuote(path)) } theseDeps <- combineDcfFields(as.data.frame(readDcf(path)), fields) } else { warning("Package '", pkg, "' not available in repository or locally") return(NULL) } ## Split fields, remove white space splitDeps <- lapply(theseDeps, function(x) { if (is.na(x)) return(NULL) splat <- unlist(strsplit(x, ",[[:space:]]*")) ## Remove versioning information as this function only returns package names splat <- gsub("\\(.*", "", splat, perl = TRUE) gsub("[[:space:]].*", "", splat, perl = TRUE) }) unlist(splitDeps, use.names = FALSE) })) deps <- dropSystemPackages(deps) if (is.null(deps)) NULL else sort_c(unique(deps)) } discoverBaseRecommendedPackages <- function() { # First, attempt to ask 'tools' what the standard package # names are. Since this function is unexported we are # careful on how we query + use it. tools <- asNamespace("tools") pkgs <- tryCatch(tools$.get_standard_package_names(), error = identity) ok <- is.list(pkgs) && all(c("base", "recommended") %in% names(pkgs)) && length(pkgs$base) && length(pkgs$recommended) if (ok) return(pkgs) # Otherwise, fall back to installed.packages(). ip <- utils::installed.packages() list( base = rownames(ip)[ip[, "Priority"] %in% "base"], recommended = rownames(ip)[ip[, "Priority"] %in% "recommended"] ) } excludeBasePackages <- function(packages) { pkgs <- discoverBaseRecommendedPackages() setdiff(packages, c("R", pkgs$base)) } excludeRecommendedPackages <- function(packages) { # NOTE: becase utils::installed.packages() can fail in some # scenarios, e.g. when libraries live on networked drives, # we fall back to a simple listing of files in the associated # library paths installedPkgsSystemLib <- list.files(.Library) installedPkgsLocalLib <- list.files(.libPaths()[1]) ## Exclude recommended packages if there is no package installed locally ## this places an implicit dependency on the system-installed version of a package pkgs <- discoverBaseRecommendedPackages() rcmd <- pkgs$recommended recommendedPkgsInSystemLib <- intersect(installedPkgsSystemLib, rcmd) recommendedPkgsInLocalLib <- intersect(installedPkgsLocalLib, rcmd) toExclude <- setdiff(recommendedPkgsInSystemLib, recommendedPkgsInLocalLib) setdiff(packages, toExclude) } dropSystemPackages <- function(packages) { # always exclude base packages packages <- excludeBasePackages(packages) # exclude recommended packages if desired by user if (!isTRUE(packrat::opts$snapshot.recommended.packages())) packages <- excludeRecommendedPackages(packages) packages } recursivePackageDependencies <- function(pkgs, lib.loc, available.packages = availablePackages(), fields = c("Depends", "Imports", "LinkingTo")) { if (!length(pkgs)) return(NULL) deps <- getPackageDependencies(pkgs, lib.loc, available.packages, fields) depsToCheck <- setdiff(deps, pkgs) while (length(depsToCheck)) { newDeps <- getPackageDependencies(depsToCheck, lib.loc, available.packages, fields) depsToCheck <- setdiff(newDeps, deps) deps <- sort_c(unique(c(deps, newDeps))) } if (is.null(deps)) NULL else sort_c(unique(deps)) } packrat/R/packrat-mode.R0000644000176200001440000003033213352207316014575 0ustar liggesusersisPackratModeOn <- function(project = NULL) { !is.na(Sys.getenv("R_PACKRAT_MODE", unset = NA)) } setPackratModeEnvironmentVar <- function() { Sys.setenv("R_PACKRAT_MODE" = "1") } ensurePkgTypeNotBoth <- function() { oldPkgType <- getOption("pkgType") if (identical(oldPkgType, "both")) options(pkgType = .Platform$pkgType) oldPkgType } beforePackratModeOn <- function(project) { # Ensure that we leave packrat mode before transfering # to a new project. if (isPackratModeOn()) off(print.banner = FALSE) project <- getProjectDir(project) ## Check and see if we need to generate default options if (!file.exists(packratOptionsFilePath(project = project))) initOptions(project = project) # Ensure that 'pkgType' is not set to 'both', since its defaults are # confusing and set up in such a way that packrat just breaks. oldPkgType <- ensurePkgTypeNotBoth() # If someone is going from packrat mode on in project A, to packrat mode on # in project B, then we only want to update the 'project' in the state -- # we should just carry forward the other state variables if (!isPackratModeOn(project = project)) { state <- list( origLibPaths = getLibPaths(), .Library = .Library, .Library.site = .Library.site, project = project, oldPkgType = oldPkgType ) } else { state <- .packrat_mutables$get() state$project <- project } state } afterPackratModeOn <- function(project, auto.snapshot, clean.search.path, state, print.banner) { project <- getProjectDir(project) libRoot <- libraryRootDir(project) localLib <- libDir(project) dir.create(libRoot, recursive = TRUE, showWarnings = FALSE) # Override auto.snapshot if running under RStudio, as it has its own packrat # file handlers if (!is.na(Sys.getenv("RSTUDIO", unset = NA))) { auto.snapshot <- FALSE } # If snapshot.lock exists, assume it's an orphan of an earlier, crashed # R process -- remove it if (file.exists(snapshotLockFilePath(project))) { unlink(snapshotLockFilePath(project)) } # If there's a new library (created to make changes to packages loaded in the # last R session), remove the old library and replace it with the new one. newLibRoot <- newLibraryDir(project) if (file.exists(newLibRoot)) { message("Applying Packrat library updates ... ", appendLF = FALSE) succeeded <- FALSE if (file.rename(libRoot, oldLibraryDir(project))) { if (file.rename(newLibRoot, libRoot)) { succeeded <- TRUE } else { # Moved the old library out of the way but couldn't move the new # in its place; move the old library back file.rename(oldLibraryDir(project), libRoot) } } if (succeeded) { message("OK") } else { message("FAILED") cat("Packrat was not able to make changes to its local library at\n", localLib, ". Check this directory's permissions and run\n", "packrat::restore() to try again.\n", sep = "") } } # If the new library temporary folder exists, remove it now so we don't # attempt to reapply the same failed changes newLibDir <- newLibraryDir(project) if (file.exists(newLibDir)) { unlink(newLibDir, recursive = TRUE) } oldLibDir <- oldLibraryDir(project) if (file.exists(oldLibDir)) { unlink(oldLibDir, recursive = TRUE) } # If the library directory doesn't exist, create it if (!file.exists(localLib)) { dir.create(localLib, recursive = TRUE) } # Clean the search path up -- unload libraries that may have been loaded before if (clean.search.path) { unloadedSearchPath <- cleanSearchPath(lib.loc = getUserLibPaths()) } # Hide the site libraries hideSiteLibraries() ## Symlink system libraries if possible; otherwise don't touch .Library if (symlinkSystemPackages(project = project)) { useSymlinkedSystemLibrary(project = project) } # Refresh the contents of 'lib-ext' if necessary symlinkExternalPackages(project = project) # Set the library if (!file.exists(libExtDir(project))) dir.create(libExtDir(project), recursive = TRUE) setLibPaths(c(localLib, libExtDir(project))) # Load any packages specified in external.packages if (isTRUE(opts$load.external.packages.on.startup())) { lapply(opts$external.packages(), function(x) { library(x, character.only = TRUE, quietly = TRUE) }) } # If we unloaded packrat, reload the packrat namespace (don't need to attach) # and then reassign the mutables # TODO: reframe this logic since, if mutables change from version to version, # this could be problematic if (clean.search.path && "packrat" %in% unloadedSearchPath$package) { try(unloadNamespace("packrat")) if (!requireNamespace("packrat", lib.loc = localLib, quietly = TRUE)) { # We are forced to initialize the project to install packrat locally .__DONT_ENTER_PACKRAT_MODE__. <- TRUE source(file.path(project, "packrat", "init.R"), local = TRUE) if (!requireNamespace("packrat", quietly = TRUE)) { stop("FATAL: could not install a local version of packrat") } } } # Give the user some visual indication that they're starting a packrat project if (interactive() && print.banner) { msg <- paste("Packrat mode on. Using library in directory:\n- \"", prettyLibDir(project), "\"", sep = "") message(msg) } # Insert hooks to library modifying functions to auto.snapshot on change if (interactive() && isTRUE(auto.snapshot)) { if (file.exists(getPackratDir(project))) { addTaskCallback(snapshotHook, name = "packrat.snapshotHook") } else { warning("this project has not been packified; cannot activate automatic snapshotting") } } # Finally, update state in the current packrat package made available # Because we may have reloaded packrat, we make sure that we update the state # for whichever packrat we now have as a loaded namespace (which may not be # the version of packrat executing this function call!) mutables <- get(".packrat_mutables", envir = asNamespace("packrat")) mutables$set(state) # Record the active project. Sys.setenv(R_PACKRAT_PROJECT_DIR = project) # Set the repositories repos <- lockInfo(project = project, property = "repos", fatal = FALSE) if (length(repos)) { options(repos = repos) } # Set a secure download method if any of the repos URLs use https and # a secure download method has not already been set if (any(grepl("^(?:ht|f)tps", repos))) { downloadMethod <- getOption("download.file.method") if (is.null(downloadMethod) || identical(downloadMethod, "internal")) { method <- secureDownloadMethod() if (is.null(method)) { secureRepos <- grep("^https", repos, value = TRUE) pasted <- paste("-", shQuote(secureRepos), collapse = "\n") warning("The following repositories require a secure download method, but ", "no such method could be selected:\n", pasted) } options(download.file.method = method) } } # Update settings updateSettings(project = project) invisible(getLibPaths()) } setPackratModeOn <- function(project = NULL, auto.snapshot = get_opts("auto.snapshot"), clean.search.path = TRUE, print.banner = TRUE) { state <- beforePackratModeOn(project = project) setPackratModeEnvironmentVar() afterPackratModeOn(project = project, auto.snapshot = auto.snapshot, clean.search.path = clean.search.path, state = state, print.banner = print.banner) } setPackratModeOff <- function(project = NULL, print.banner = TRUE) { # Restore .Library.site if (isPackratModeOn()) { restoreSiteLibraries() restoreLibrary(".Library") } Sys.unsetenv("R_PACKRAT_MODE") # Disable hooks that were turned on before removeTaskCallback("packrat.snapshotHook") # Reset the library paths libPaths <- .packrat_mutables$get("origLibPaths") if (is.null(libPaths)) libPaths <- getDefaultLibPaths() if (length(libPaths)) setLibPaths(libPaths) # Reset 'pkgType' oldPkgType <- .packrat_mutables$get("oldPkgType") if (!is.null(oldPkgType)) options(pkgType = oldPkgType) # Turn off packrat mode if (interactive() && print.banner) { msg <- paste(collapse = "\n", c("Packrat mode off. Resetting library paths to:", paste("- \"", getLibPaths(), "\"", sep = "") ) ) message(msg) } # Default back to the current working directory for packrat function calls .packrat_mutables$set(project = NULL) Sys.unsetenv("R_PACKRAT_PROJECT_DIR") invisible(getLibPaths()) } checkPackified <- function(project = NULL, quiet = FALSE) { project <- getProjectDir(project) # Check for a lockfile. lockPath <- lockFilePath(project) if (!file.exists(lockPath)) { if (!quiet) message("The packrat lock file does not exist.") return(FALSE) } # Check for the Packrat autoloader. profile <- file.path(project, ".Rprofile") if (!file.exists(profile)) return(FALSE) contents <- readLines(profile) if (!any(grepl("#### -- Packrat Autoloader", contents))) return(FALSE) TRUE } ##' Packrat Mode ##' ##' Use these functions to switch \code{packrat} mode on and off. When within ##' \code{packrat} mode, the \R session will use the private library generated ##' for the current project. ##' ##' @param on Turn packrat mode on (\code{TRUE}) or off (\code{FALSE}). If omitted, packrat mode ##' will be toggled. ##' @param project The directory in which packrat mode is launched -- this is ##' where local libraries will be used and updated. ##' @param auto.snapshot Perform automatic, asynchronous snapshots? ##' @param clean.search.path Detach and unload any packages loaded from non-system ##' libraries before entering packrat mode? ##' @param print.banner Print the packrat banner when entering / exiting packrat mode? ##' The packrat banner informs you of the new packrat mode state, as well as the library ##' path in use. ##' @name packrat-mode ##' @rdname packrat-mode ##' @export packrat_mode <- function(on = NULL, project = NULL, auto.snapshot = get_opts("auto.snapshot"), clean.search.path = TRUE) { project <- getProjectDir(project) if (is.null(on)) { togglePackratMode(project = project, auto.snapshot = auto.snapshot, clean.search.path = clean.search.path) } else if (identical(on, TRUE)) { setPackratModeOn(project = project, auto.snapshot = auto.snapshot, clean.search.path = clean.search.path) } else if (identical(on, FALSE)) { setPackratModeOff(project = project) } else { stop("'on' must be one of TRUE, FALSE or NULL, was '", on, "'") } } ##' @rdname packrat-mode ##' @name packrat-mode ##' @export on <- function(project = NULL, auto.snapshot = get_opts("auto.snapshot"), clean.search.path = TRUE, print.banner = TRUE) { project <- getProjectDir(project) # If there is no lockfile already, perform an init if (!file.exists(lockFilePath(project = project))) return(init(project = project)) setPackratModeOn(project = project, auto.snapshot = auto.snapshot, clean.search.path = clean.search.path, print.banner = print.banner) } ##' @rdname packrat-mode ##' @name packrat-mode ##' @export off <- function(project = NULL, print.banner = TRUE) { project <- getProjectDir(project) setPackratModeOff(project = project, print.banner = print.banner) } togglePackratMode <- function(project, auto.snapshot, clean.search.path) { if (isPackratModeOn(project = project)) { setPackratModeOff(project) } else { setPackratModeOn(project = project, auto.snapshot = auto.snapshot, clean.search.path) } } setPackratPrompt <- function() { oldPromptLeftTrimmed <- gsub("^ *", "", getOption("prompt")) options(prompt = paste("pr", oldPromptLeftTrimmed, sep = "")) } packrat/R/aaa-globals.R0000644000176200001440000000234013352207316014367 0ustar liggesusers.packrat <- new.env(parent = emptyenv()) .packrat$repos <- new.env(parent = emptyenv()) .packrat$packratFormat <- "1.4" .packrat$options <- NULL ## Mutable values that might be modified by the user (code borrowed from knitr) # merge elements of y into x with the same names merge_list = function(x, y) { x[names(y)] = y x } new_defaults = function(value = list()) { defaults = value get = function(name, default = FALSE, drop = TRUE) { if (default) defaults = value # this is only a local version if (missing(name)) defaults else { if (drop && length(name) == 1) defaults[[name]] else { setNames(defaults[name], name) } } } set = function(...) { dots = list(...) if (length(dots) == 0) return() if (is.null(names(dots)) && length(dots) == 1 && is.list(dots[[1]])) if (length(dots <- dots[[1]]) == 0) return() defaults <<- merge(dots) invisible(NULL) } merge = function(values) merge_list(defaults, values) restore = function(target = value) defaults <<- target list(get = get, set = set, merge = merge, restore = restore) } ## These should be set on entering, exiting packrat mode .packrat_mutables <- new_defaults(list( origLibPaths = NULL, project = NULL )) packrat/R/pretty-print.R0000644000176200001440000000620513352207316014711 0ustar liggesusers## Pretty printers, primarily used for status output prettyPrint <- function(packages, header, footer = NULL) { if (length(packages) > 0) { cat('\n') if (!is.null(header)) { cat(paste(header, collapse = '')) cat('\n') } print.simple.list(lapply(packages, function(pkg) { result <- ifelse(is.na(pkg$version), '', pkg$version) result <- paste(" ", result) names(result) <- paste(" ", pkg$name) result })) if (!is.null(footer)) { cat('\n') cat(paste(footer, collapse = '')) } cat('\n') } } summarizeDiffs <- function(diffs, pkgsA, pkgsB, addMessage, removeMessage, upgradeMessage, downgradeMessage, crossgradeMessage) { prettyPrint( searchPackages(pkgsB, names(diffs)[!is.na(diffs) & diffs == 'add']), addMessage ) prettyPrint( searchPackages(pkgsA, names(diffs)[!is.na(diffs) & diffs == 'remove']), removeMessage ) prettyPrintPair( searchPackages(pkgsA, names(diffs)[!is.na(diffs) & diffs == 'upgrade']), searchPackages(pkgsB, names(diffs)[!is.na(diffs) & diffs == 'upgrade']), upgradeMessage ) prettyPrintPair( searchPackages(pkgsA, names(diffs)[!is.na(diffs) & diffs == 'downgrade']), searchPackages(pkgsB, names(diffs)[!is.na(diffs) & diffs == 'downgrade']), downgradeMessage ) prettyPrintPair( searchPackages(pkgsA, names(diffs)[!is.na(diffs) & diffs == 'crossgrade']), searchPackages(pkgsB, names(diffs)[!is.na(diffs) & diffs == 'crossgrade']), crossgradeMessage ) } prettyPrintPair <- function(packagesFrom, packagesTo, header, footer = NULL, fromLabel = 'from', toLabel = 'to') { if (length(packagesFrom) != length(packagesTo)) { stop('Invalid arguments--package record lengths mismatch') } if (length(packagesFrom) > 0) { if (any(sapply(packagesFrom, is.null) & sapply(packagesTo, is.null))) { stop('Invalid arguments--NULL packages') } for (i in seq_along(packagesFrom)) { if (!is.null(packagesFrom[[i]]) && !is.null(packagesTo[[i]])) { if (!identical(packagesFrom[[i]]$name , packagesTo[[i]]$name)) { stop('Invalid arguments--package names did not match') } } } cat('\n') if (!is.null(header)) { cat(paste(header, collapse = '')) cat('\n') } pickVersion <- pick("version", defaultValue = "NA") df <- data.frame(paste(" ", sapply(packagesFrom, pickVersion)), paste(" ", sapply(packagesTo, pickVersion))) names(df) <- c(paste(" ", fromLabel), paste(" ", toLabel)) row.names(df) <- paste(" ", pkgNames(packagesFrom)) print(df) if (!is.null(footer)) { cat('\n') cat(paste(footer, collapse = '')) } cat('\n') } } prettyPrintNames <- function(packageNames, header, footer = NULL) { if (length(packageNames) > 0) { cat('\n') if (!is.null(header)) { cat(paste(header, collapse = '')) cat('\n') } cat(paste(" ", packageNames, sep = '', collapse = '\n')) cat('\n') if (!is.null(footer)) { cat(paste(footer, collapse = '')) } cat('\n') } } packrat/R/hide-site-libraries.R0000644000176200001440000000173613352207316016061 0ustar liggesusersreplaceLibrary <- function(lib, value) { ## Need to clobber in package:base, namespace:base envs <- c( as.environment("package:base"), .BaseNamespaceEnv ) for (env in envs) { do.call("unlockBinding", list(lib, env)) assign(lib, value, envir = env) do.call("lockBinding", list(lib, env)) } } hideLibrary <- function(lib) { replaceLibrary(lib, character()) } restoreLibrary <- function(lib) { cachedLib <- if (lib == ".Library") getenv("R_PACKRAT_SYSTEM_LIBRARY") else if (lib == ".Library.site") getenv("R_PACKRAT_SITE_LIBRARY") if (is.null(cachedLib)) { warning("packrat did not properly save the library state; cannot restore") return(invisible(NULL)) } replaceLibrary(lib, cachedLib) } ## Remove the site-library libraries from unix-alikes hideSiteLibraries <- function() { hideLibrary(".Library.site") } ## Restore the site-library libraries restoreSiteLibraries <- function() { restoreLibrary(".Library.site") } packrat/R/read-lock-file.R0000644000176200001440000000124213352207316015002 0ustar liggesusers# Read only package entries in the lock file, and do not expand package dependencies # Useful when a package + its requirements is of interest, and expansion of # sub-dependencies is unnecessary readLockFilePackages <- function(file) { # Drop the first row as it contains lockfile-specific info lock <- readDcf(file)[-1, , drop = FALSE] result <- apply(lock, 1, function(x) { x <- as.list(x) list( name = x$Package, source = x$Source, version = x$Version, requires = as.character(unlist(strsplit(as.character(x$Requires), ",[[:space:]]*", perl = TRUE))), hash = x$Hash ) }) names(result) <- lock[, "Package"] result } packrat/R/zzz.R0000644000176200001440000000050613352207316013063 0ustar liggesusers.onLoad <- function(libname, pkgname) { mappings <- list( "R_PACKRAT_DEFAULT_LIBPATHS" = .libPaths(), "R_PACKRAT_SYSTEM_LIBRARY" = .Library, "R_PACKRAT_SITE_LIBRARY" = .Library.site ) enumerate(mappings, function(key, val) { if (is.na(Sys.getenv(key, unset = NA))) setenv(key, val) }) } packrat/R/snapshot.R0000644000176200001440000003431613370077201014071 0ustar liggesusers#' Capture and store the packages and versions in use #' #' Finds the packages in use in the project, and stores a list #' of those packages, their sources, and their current versions in packrat. #' #' @param project The project directory. Defaults to current working #' directory. #' @param available A database of available packages. #' @param lib.loc The library to snapshot. Defaults to the private library #' associated with the given directory. #' @param ignore.stale Stale packages are packages that are different from the #' last snapshot, but were installed by packrat. Typically, packages become #' stale when a new snapshot is available, but you haven't applied it yet with #' \code{\link{restore}}. By default, packrat will prevent you from taking a #' snapshot when you have stale packages to prevent you from losing changes #' from the unapplied snapshot. If your intent is to overwrite the last #' snapshot without applying it, use \code{ignore.stale = TRUE} to skip this #' check. #' @param dry.run Computes the changes to your packrat state that would be made #' if a snapshot were performed, and prints them to the console. #' @param prompt \code{TRUE} to prompt before performing snapshotting package #' changes that might be unintended; \code{FALSE} to perform these operations #' without confirmation. Potentially unintended changes include snapshotting #' packages at an older version than the last snapshot, or missing despite #' being present in the last snapshot. #' @param snapshot.sources Boolean; should package sources be downloaded during #' snapshot? #' @param infer.dependencies If \code{TRUE}, infer package dependencies by #' examining \R code used within the project. This included the \R code #' contained within \code{.R} files, as well as other multi-mode documents #' (e.g. \code{.Rmd}). #' #' @note \code{snapshot} modifies the project's \code{packrat.lock} file, and #' the sources stored in the project's \code{packrat/src} directory. If you #' are working with a version control system, your collaborators can sync the #' changes to these files and then use \code{\link{restore}} to apply your #' snapshot. #' #' @seealso #' \code{\link{restore}} to apply a snapshot. #' \code{\link{status}} to view the differences between the most recent snapshot #' and the library. #' @examples #' \dontrun{ #' # Take a snapshot of the current project #' snapshot() #' #' # See what changes would be included in a snapshot #' snapshot(dry.run = TRUE) #' #' } #' @export snapshot <- function(project = NULL, available = NULL, lib.loc = libDir(project), ignore.stale = FALSE, dry.run = FALSE, prompt = interactive(), snapshot.sources = TRUE, infer.dependencies = TRUE) { if (is.null(available)) { available <- if (dry.run) availablePackagesSkeleton() else availablePackages() } project <- getProjectDir(project) if (file.exists(snapshotLockFilePath(project))) { stop("An automatic snapshot is currently in progress -- cannot proceed") } if (!dry.run) { callHook(project, "snapshot", TRUE) on.exit(callHook(project, "snapshot", FALSE), add = TRUE) } snapshotResult <- snapshotImpl(project, available, lib.loc, dry.run, ignore.stale = ignore.stale, prompt = prompt && !dry.run, snapshot.sources = snapshot.sources, infer.dependencies = infer.dependencies) if (dry.run) return(invisible(snapshotResult)) } #' Internal Snapshot Implementation #' #' This is the internal implementation for \code{\link{snapshot}}. Most users #' should prefer calling \code{\link{snapshot}}. #' #' @inheritParams snapshot #' @param auto.snapshot Internal use -- should be set to \code{TRUE} when this #' is an automatic snapshot. #' @param verbose Print output to the console while \code{snapshot}-ing? #' @param fallback.ok Fall back to the latest CRAN version of a package if the #' locally installed version is unavailable? #' @param snapshot.sources Download the tarball associated with a particular #' package? #' @param implicit.packrat.dependency Include \code{packrat} as an implicit #' dependency of this project, if not otherwise discovered? This should be #' \code{FALSE} only if you can guarantee that \code{packrat} will be available #' via other means when attempting to load this project. #' @param infer.dependencies If \code{TRUE}, infer package dependencies by #' examining the \R code. #' @keywords internal #' @rdname snapshotImpl #' @export .snapshotImpl <- function(project, available = NULL, lib.loc = libDir(project), dry.run = FALSE, ignore.stale = FALSE, prompt = interactive(), auto.snapshot = FALSE, verbose = TRUE, fallback.ok = FALSE, snapshot.sources = TRUE, implicit.packrat.dependency = TRUE, infer.dependencies = TRUE) { if (is.null(available)) { available <- if (dry.run) availablePackagesSkeleton() else availablePackages() } # ensure packrat directory available packratDir <- getPackratDir(project) if (!file.exists(packratDir)) dir.create(packratDir, recursive = TRUE) # When snapshotting, we take the union of: # # 1. Inferred dependencies (packages that appear to be in use in your code), and # 2. The current state of your private library. # # When packages are inferred from the code, the version taken is the most # current available in the current set of repositories. ## If we are using packrat alongside an R package, then we should ## ignore the package itself ignore <- NULL if (isRPackage(project = project)) { desc <- readDcf(file.path(project, "DESCRIPTION")) if ("Package" %in% colnames(desc)) { # R packages are not guaranteed to have a "Package" field (see isRPackge) ignore <- unname(desc[, "Package"]) } } ## respect project ignores ignore <- c(ignore, packrat::opts$ignored.packages()) ## rstudio, manipulate needs ignoring ignore <- c(ignore, c("manipulate", "rstudio")) libPkgs <- setdiff(list.files(libDir(project)), ignore) if (infer.dependencies) { inferredPkgs <- sort_c(appDependencies(project, available.packages = available, implicit.packrat.dependency = implicit.packrat.dependency)) } else { # packrat is always a dependency inferredPkgs <- 'packrat' } inferredPkgsNotInLib <- setdiff(inferredPkgs, libPkgs) # Packages currently available in the library should have package records # available, so we don't overload the missing.package argument of # getPackageRecords and let it fail if something goes wrong libPkgRecords <- getPackageRecords(libPkgs, project = project, available = available, lib.loc = lib.loc, recursive = TRUE) # For inferred packages (ie. packages within the code), we try to construct # records first from the lockfile, and then from other sources if possible # (CRAN, GitHub, Bitbucket, source repository) inferredPkgRecords <- getPackageRecords(inferredPkgsNotInLib, project = project, available = available, check.lockfile = TRUE, fallback.ok = fallback.ok) allRecords <- c( libPkgRecords, inferredPkgRecords ) allRecordsFlat <- c( flattenPackageRecords(libPkgRecords, depInfo = TRUE, sourcePath = TRUE), flattenPackageRecords(inferredPkgRecords, depInfo = TRUE, sourcePath = TRUE) ) # Compare the new records we wish to write against the current lockfile # (last snapshot) lockPackages <- lockInfo(project, fatal = FALSE) diffs <- diff(lockPackages, allRecords) # Don't remove packages that are specified as part of external.packages # This means 'external.packages' is 'sticky', in that we only remove a package # from the lockfile that's an external package if it's also removed from that field ## TODO: Think about 'downgrade', 'crossgrade', 'upgrade' -- but presumedly this ## shouldn't happen for external.packages within the context of a packrat project diffs <- diffs[!(names(diffs) %in% opts$external.packages())] mustConfirm <- any(c('downgrade', 'remove', 'crossgrade') %in% diffs) if (!ignore.stale) { # If any packages are installed, different from what's in the lockfile, and # were installed by packrat, that means they are stale. stale <- names(diffs)[!is.na(diffs) & installedByPackrat(names(diffs), lib.loc, FALSE)] if (length(stale) > 0 && verbose) { prettyPrint( getPackageRecords(stale, project = project, NULL, recursive = FALSE, lib.loc = lib.loc), 'The following packages are stale:', c('These packages must be updated by calling packrat::restore() before\n', 'snapshotting. If you are sure you want the installed versions of these\n', 'packages to be snapshotted, call packrat::snapshot() again with\n', 'ignore.stale=TRUE.') ) message('--\nSnapshot operation was cancelled, no changes were made.') return(invisible()) } } if (verbose) { summarizeDiffs(diffs, lockPackages, allRecords, 'Adding these packages to packrat:', 'Removing these packages from packrat:', 'Upgrading these packages already present in packrat:', 'Downgrading these packages already present in packrat:', 'Modifying these packages already present in packrat:') } ## For use by automatic snapshotting -- only perform the automatic snapshot ## if it's a 'safe' action; ie, escape early if we would have prompted if (mustConfirm && isTRUE(auto.snapshot)) return(invisible()) ## Short-circuit if we know that there is nothing to be updated. if (file.exists(lockFilePath(project)) && all(is.na(diffs))) { # Check to see if the current repositories + the snapshotted # repositories are in sync. lockfile <- readLockFile(lockFilePath(project)) lockfileRepos <- lockfile$repos reposInSync <- identical(sort_c(getOption("repos")), sort_c(lockfileRepos)) # Check to see whether all of the installed packages are currently # tracked by packrat. if (!reposInSync) { allTracked <- is.null(lib.loc) || all(installedByPackrat(pkgNames(allRecordsFlat), lib.loc, FALSE)) if (allTracked) { # Ensure a packrat lockfile is available if (!file.exists(lockFilePath(project))) writeLockFile(lockFilePath(project), allRecords) else if (verbose) message("Already up to date.") return() } } } if (prompt && mustConfirm) { answer <- readline('Do you want to continue? [Y/n]: ') answer <- gsub('^\\s*(.*?)\\s*$', '\\1', answer) if (nzchar(answer) && tolower(answer) != 'y') { return(invisible()) } } if (!dry.run) { # allow user to configure snapshot.sources through env / R option if (missing(snapshot.sources)) { snapshot.sources <- packratOptionBoolean( "R_PACKRAT_SNAPSHOT_SOURCES", "packrat.snapshot.sources", snapshot.sources ) } if (snapshot.sources) snapshotSources(project, activeRepos(project), allRecordsFlat) writeLockFile( lockFilePath(project), allRecords ) for (record in allRecordsFlat) { name <- record$name path <- file.path(libDir(project), name, "DESCRIPTION") if (file.exists(path)) { annotatePkgDesc(record, project, libDir(project)) } } if (verbose) { message('Snapshot written to ', shQuote(normalizePath(lockFilePath(project), winslash = '/')) ) } } return(invisible(list(pkgRecords = lockPackages, actions = diffs[!is.na(diffs)], pkgsSnapshot = allRecords))) } # NOTE: `.snapshotImpl` is exported as an 'internal' function that may be # used by other packages, but we keep an (unexported) version of `snapshotImpl` # around for compatibility with older Packrat versions. snapshotImpl <- .snapshotImpl getBiocRepos <- function() { BiocManager <- tryCatch(asNamespace("BiocManager"), error = identity) if (!inherits(BiocManager, "error")) return(BiocManager$repositories()) BiocInstaller <- tryCatch(asNamespace("BiocInstaller"), error = identity) if (!inherits(BiocInstaller, "error")) return(BiocInstaller$biocinstallRepos()) msg <- paste( "Neither BiocManager nor BiocInstaller are installed;", "cannot discover Bioconductor repositories" ) warning(msg) character() } # Returns a vector of all active repos, including CRAN (with a fallback to the # RStudio CRAN mirror if none is specified) and Bioconductor if installed. activeRepos <- function(project) { project <- getProjectDir(project) repos <- getOption("repos") repos[repos == "@CRAN@"] <- "https://cran.rstudio.com/" # Check for installation of BiocManager or BiocInstaller in the private # library. If either exists, then conclude this is a Bioconductor Packrat # project and add the Bioconductor repositories to the lockfile. location <- find.package("BiocManager", lib.loc = libDir(project), quiet = TRUE) if (!length(location)) location <- find.package("BiocInstaller", lib.loc = libDir(project), quiet = TRUE) if (length(location) == 1 && file.exists(location)) { biocRepos <- getBiocRepos() biocRepoNames <- names(biocRepos) oldRepos <- repos[!(names(repos) %in% biocRepoNames)] repos <- c(oldRepos, biocRepos) } return(repos) } packrat/README.md0000644000176200001440000001137413352207316013166 0ustar liggesusers[![Build Status](https://travis-ci.org/rstudio/packrat.svg?branch=master)](https://travis-ci.org/rstudio/packrat) [![Coverage Status](https://codecov.io/github/rstudio/packrat/coverage.svg?branch=master)](https://codecov.io/github/rstudio/packrat?branch=master) # packrat Packrat is a dependency management system for R. Use packrat to make your R projects more: * **Isolated:** Installing a new or updated package for one project won't break your other projects, and vice versa. That's because packrat gives each project its own private package library. * **Portable:** Easily transport your projects from one computer to another, even across different platforms. Packrat makes it easy to install the packages your project depends on. * **Reproducible:** Packrat records the exact package versions you depend on, and ensures those exact versions are the ones that get installed wherever you go. See the [project page](https://rstudio.github.io/packrat/) for more information, or join the discussion at [packrat-discuss](https://groups.google.com/forum/#!forum/packrat-discuss). Read the [release notes](https://github.com/rstudio/packrat/blob/master/NEWS.md) to learn what's new in Packrat. # Quick-start Guide Start by installing Packrat: install.packages("packrat") Then, start a new R session at the base directory of your project and type: packrat::init() This will install Packrat, set up a private library to be used for this project, and then place you in `packrat mode`. While in packrat mode, calls to functions like `install.packages` and `remove.packages` will modify the private project library, rather than the user library. When you want to manage the state of your private library, you can use the Packrat functions: - `packrat::snapshot()`: Save the current state of your library. - `packrat::restore()`: Restore the library state saved in the most recent snapshot. - `packrat::clean()`: Remove unused packages from your library. Share a Packrat project with `bundle` and `unbundle`: - `packrat::bundle()`: Bundle a packrat project, for easy sharing. - `packrat::unbundle()`: Unbundle a packrat project, generating a project directory with libraries restored from the most recent snapshot. Navigate projects and set/get options with: - `packrat::on()`, `packrat::off()`: Toggle packrat mode on and off, for navigating between projects within a single R session. - `packrat::get_opts`, `packrat::set_opts`: Get/set project-specific settings. Manage ad-hoc local repositories (note that these are a separate entity from CRAN-like repositories): - `packrat::set_opts(local.repos = ...)` can be used to specify *local repositories*; that is, directories containing (unzipped) package sources. - `packrat::install_local()` installs packages available in a local repository. For example, suppose I have the (unzipped) package sources for [`digest`](https://cran.r-project.org/package=digest) located within the folder`~/git/R/digest/`. To install this package, you can use: packrat::set_opts(local.repos = "~/git/R") packrat::install_local("digest") There are also utility functions for using and managing packages in the external / user library, and can be useful for leveraging packages in the user library that you might not want as project-specific dependencies, e.g. `devtools`, `knitr`, `roxygen2`: - `packrat::extlib()`: Load an external package. - `packrat::with_extlib()`: With an external package, evaluate an expression. The external package is loaded only for the duration of the evaluated expression, but note that there may be other side effects associated with the package's `.onLoad`, `.onAttach` and `.onUnload` calls that we may not be able to fully control. # Workflows Packrat supports a set of common analytic workflows: 1. `As-you-go`: use `packrat::init()` to initialize packrat with your project, and use it to manage your project library while you develop your analysis. As you install and remove packages, you can use `packrat::snapshot()` and `packrat::restore()` to maintain the R packages in your project. For collaboration, you can either use your favourite version control system, or use `packrat::bundle()` to generate a bundled version of your project that collaborators can use with `packrat::unbundle()`. 2. `When-you're-done`: take an existing or complete analysis (preferably collected within one directory), and call `packrat::init()` to immediately obtain R package sources for all packages used in your project, and snapshot that state so it can hence be preserved across time. # Setting up your own custom, CRAN-like repositories Please view the [set-up guide](https://rstudio.github.io/packrat/custom-repos.html) here for a simple walkthrough in how you might set up your own, local, custom CRAN repository. packrat/MD50000644000176200001440000002160613372757542012233 0ustar liggesusers465df9c8cd1cee9005bcf9abb1f6be9c *DESCRIPTION 68b2e6e1a0576545e864883209a52387 *NAMESPACE dd616c304a953db9df331c0a85a8e7d1 *R/aaa-globals.R a23fadcc779613acf3f15d52b947042f *R/augment-rprofile.R ffa6b4d6cf51b5ae1147227f5f1f3a78 *R/available-packages.R ef37a7a3e5a8f13e9462cd4690ce1c8a *R/available-updates.R 1ce94bf2a4d37cfd7a17de926a51aad5 *R/bitbucket.R f6f52137b7c39225623803301d0417fa *R/bundle.R d336114aba42b358e802bef41056de5b *R/cache.R c0e44e191edb46914c749f353a416c7f *R/clean-search-path.R 5db15d019506efb5c968c2ccf9d93d1a *R/cranlike-repositories.R b6565219e13213d48052901f9c66b620 *R/dependencies.R 27762c2116c568fb50b7321eb76536db *R/descfile.R 2b0cb2ecb88b7141136b2bd4e446a9c0 *R/disable.R 55c65d970109bdb6ac279c7996a9df5f *R/downloader.R eaa7717cfb33209298a25622d1b73a17 *R/env.R fcc2c581b4702d4a20eabbf8cd4a8e9d *R/external.R e0a6ec8f8623be9149fcbc2b61273389 *R/get-package-actions.R 1ffd684e1a8766dc92f24bede5fb7e00 *R/git-prune.R 70f6efd9c77ca144200f9d25e4741139 *R/github.R 1e3018c58ddc9215225e75210a389576 *R/hide-site-libraries.R 78a4df19e5ff0c384c133903884ede8b *R/hooks.R 85300d20a31dd42fa69c8799a9064029 *R/install-local.R 363be32cfb1e94cea14b8dc6692539d2 *R/install.R 97316acb3d209938dbbe5f142b348d41 *R/library-support.R 2d5482d1112731e1745149f7a47baa5a *R/lockfile-metadata.R 792b64b29456973f43f757c885756983 *R/lockfile.R 05772e053725fd0a86bccc40a79c9727 *R/options.R 58dc366ab58c4ba5a38f45cbfd562eb6 *R/package-namespace-helpers.R 6990b095b970a4ba986c1e5e5086fdea *R/packrat-mode.R fb80dd72f5733fdf2f21d0e73fcf335b *R/packrat.R 7c937477d8e4e53a21b78b3979b3a896 *R/paths.R 4886e917ff71f8f2048927748ada5440 *R/pkg.R 83dd22ef3be6e0945b00c682e4b808c2 *R/platform.R b6a42ea9d706583a34cd66f2c4fe2364 *R/pretty-print.R 569c4c36f965955d8cf887cf72ee3f02 *R/r-hooks.R e095eab068811896ebb349e87be70c69 *R/read-lock-file.R dcc91f78d149197c550075f8ae072617 *R/recursive-package-dependencies.R b59b3e74c781a83ec42ec33222fcfe6c *R/restore-routines.R 069877d76352f3667c93d4e912fb88a6 *R/restore.R 46a5754c8267d46f2115b51e95ac9ca2 *R/rstudio-protocol.R b4480fe138b665d373e5f6a343067dd1 *R/search-path.R 3eef335bd3333427d01a8ceb40c2b292 *R/snapshot.R 86a62379e9666c0ae53f0e0db7f2db1a *R/status.R 4963822b25733014acf6b564130b8525 *R/testthat-helpers.R 4d6b0ff3b7561d856b73da02ec4aa4c2 *R/update.R 57fa410632676f1fbaee37b10a69aba6 *R/utils.R dd3bc7a79be9662213ea6ecaa97c0f07 *R/zzz.R ac93e3d3068e7956017f1d0ae8a843e6 *README.md c69dc905859e83d8e6be0e81ee3cb14b *inst/resources/init-rprofile.R 1e7ff1993e1aadc026f797eefc8bf1d7 *inst/resources/init.R 5c6e028fe159e8f028d8da1048921bc3 *inst/resources/mac_r_userlib.sh 4affbb9d61d533e48a8274cdd712a9f8 *inst/rstudio/rstudio-protocol d8319bffdd090c55645e73de37c86b61 *man/appDependencies.Rd f9b4686fd9afbd59694193629f97bcdc *man/bitbucket_pwd.Rd c11828cc00825029d75dd21181f8fdb6 *man/bitbucket_user.Rd 96ba18ce3f5e2ed460fedb8a276c9178 *man/bundle.Rd 7566a4f2ba0eb30d9a358f418c3a6045 *man/clean.Rd b3bb5e41145b740603e9a2e382a93452 *man/disable.Rd 4374370b54dfb2731caa6d616cd7a4a2 *man/init.Rd 079856f2210dee4ebac66b6b89c6cee7 *man/install.Rd 359c0ba1eee38b7711f2789338e248a7 *man/install_local.Rd a0e794c4c9bc3b72d77f4c7cd757e954 *man/lockfile-metadata.Rd 0a383c23aa218d981d7082661ac07b03 *man/packify.Rd 367f519bd6e20366712c941ff06bbfff *man/packrat-external.Rd e4d392a7ba899a1aa1a03cc5542bdeaa *man/packrat-mode.Rd af4fb4c6ba6865fe1ba199981ebec9c3 *man/packrat-options.Rd ac1af16d07693ac8810b9f3a01acc798 *man/packrat-resources.Rd 3396b4bb046b03969f78e9765bfc725e *man/packrat.Rd 2e66e2efaa88cca98c652e0f85f42604 *man/repos_create.Rd dde2bfc7f1e42cb6e2b226322ad873c1 *man/repos_upload.Rd 3cab83905f116f616128526b22f53fd4 *man/repository-management.Rd e586dbeff4202bedff62854670a565cf *man/restore.Rd 26348871a8c365ded5e93e49b82f618e *man/search_path.Rd 5d219869cfca99375580d942156d292f *man/snapshot.Rd cccf1a4c0f1707c5cc80458d8feca364 *man/snapshotImpl.Rd 18373728b831be9718657ec861d79e77 *man/status.Rd 89b4d83ead74999562c00b4934898469 *man/unbundle.Rd 019623679295771926ef42d5abb3cd7b *man/unused_packages.Rd 175c1f87f53e45c3ba25e442f420ccd9 *tests/test-all.R c17f992a4258009d61b5dcf83cf58a81 *tests/test-cranlike-repositories.R ed5a74b6ccd53686fc405ec5fe0287b3 *tests/testthat/Ugly, but legal, path for a project (long)/bread/DESCRIPTION b81d577ce3cac1b01b26748ed6d4bea6 *tests/testthat/Ugly, but legal, path for a project (long)/breakfast/DESCRIPTION 700e054b6e32a80c8dcab5dcaa4e60d5 *tests/testthat/Ugly, but legal, path for a project (long)/oatmeal/DESCRIPTION 6c70d47d06818418de8a62ba55e89326 *tests/testthat/Ugly, but legal, path for a project (long)/packrat/DESCRIPTION 5b5c76f4e4849a8a7ba8ee493a125dc4 *tests/testthat/Ugly, but legal, path for a project (long)/toast/DESCRIPTION bbf95919533904a68997563891f47f52 *tests/testthat/lockfiles/lockfile-multipleRepos.txt 6c70d47d06818418de8a62ba55e89326 *tests/testthat/other-packages/packrat/DESCRIPTION ed5a74b6ccd53686fc405ec5fe0287b3 *tests/testthat/packages/bread/DESCRIPTION b81d577ce3cac1b01b26748ed6d4bea6 *tests/testthat/packages/breakfast/DESCRIPTION 5977869b48003e32552044e6d002b701 *tests/testthat/packages/egg/DESCRIPTION 700e054b6e32a80c8dcab5dcaa4e60d5 *tests/testthat/packages/oatmeal/DESCRIPTION 67fb303fb64bca0aefae728064af97da *tests/testthat/packages/packrat/DESCRIPTION 5b5c76f4e4849a8a7ba8ee493a125dc4 *tests/testthat/packages/toast/DESCRIPTION 3965e9ae499c25646e7d6f69bae61e95 *tests/testthat/projects/carbs/flour.R d41d8cd98f00b204e9800998ecf8427e *tests/testthat/projects/empty/empty.R d41d8cd98f00b204e9800998ecf8427e *tests/testthat/projects/emptydesc/DESCRIPTION d0359a4763af18f7142a27b6dde27634 *tests/testthat/projects/emptydesc/app.R 62df9ea384d35fe898da5942b7764ff5 *tests/testthat/projects/healthy/healthy.R 54687329e3d77d76ba92891fedf18882 *tests/testthat/projects/libraries/library.R 4e218e18476706dc8f388b373150ca24 *tests/testthat/projects/libraries/packrat/lib/lib-current.R 4e218e18476706dc8f388b373150ca24 *tests/testthat/projects/libraries/packrat/library.new/lib-new.R bf6fed44bb0513e754e46b10e4ab2e2e *tests/testthat/projects/partlyignored/ignoreme/ignorethis.R 54687329e3d77d76ba92891fedf18882 *tests/testthat/projects/partlyignored/notignored.R 1edbab3be3f017f0178c6202923cb7eb *tests/testthat/projects/sated/sated.R 3965e9ae499c25646e7d6f69bae61e95 *tests/testthat/projects/smallbreakfast/bread.R 62df9ea384d35fe898da5942b7764ff5 *tests/testthat/projects/smallbreakfast/oatmeal.R d41d8cd98f00b204e9800998ecf8427e *tests/testthat/repo-empty/src/contrib/PACKAGES 14a8982c56f8cb54279d9f183b652c94 *tests/testthat/repo/src/contrib/PACKAGES ee08368bebb2436b46be338f85803879 *tests/testthat/repo/src/contrib/PACKAGES.gz ff5f3447c5cbc9d77ccb134fbcd566a0 *tests/testthat/repo/src/contrib/PACKAGES.rds 1dcbd204458db242b342c78405a68019 *tests/testthat/repo/src/contrib/bread/bread_1.0.0.tar.gz b2086a4a5079b9f87bd37ae4553b22cf *tests/testthat/repo/src/contrib/breakfast/breakfast_1.0.0.tar.gz a4d0a76070c3b6b356db77eef2942bc0 *tests/testthat/repo/src/contrib/egg/egg_1.0.0.tar.gz c2a0782daddc791662fca2ffb2b6e435 *tests/testthat/repo/src/contrib/oatmeal/oatmeal_1.0.0.tar.gz f12642bcfbf5928783057a46d0a42d91 *tests/testthat/repo/src/contrib/packrat/packrat_0.4.9-15.tar.gz ace77e300ee298c4e520f89a38c05caa *tests/testthat/repo/src/contrib/toast/toast_1.0.0.tar.gz 91b0d51341b3862c9bf966acf387f0a3 *tests/testthat/resources/alternate-engines.Rmd 6312ea33543606514a199b4a22210424 *tests/testthat/resources/emoji.Rmd 9f35e681fa91648d33cd15e0b081e543 *tests/testthat/resources/evaluate-deps.Rmd e45f4420641b1eb71099a1e2784d326d *tests/testthat/resources/interactive-doc-example.Rmd efdbd22adbc79ed002cc9364e3fb978d *tests/testthat/resources/knitr-minimal.Rnw 85db3ae6db66a38f3f26d5f7df247852 *tests/testthat/resources/no-chunks.Rmd 37320ba34f8645d6322f0a3c026d612a *tests/testthat/resources/params-example.Rmd 2b8c25c9f1730941e4183fcaabc4d5ab *tests/testthat/resources/test-sweave.Rnw 25278d6507e8d0ae24ae4d264a10a0a0 *tests/testthat/test-aaa.R d1754e24d1d4d68c2401aad52df0593c *tests/testthat/test-bitbucket.R 174c55c8d93a8fcbddab2dc7a08d5dcc *tests/testthat/test-bundle.R ec72d1988fcd2aa6ab6caa7e106dfb42 *tests/testthat/test-cache.R fea4b392dea4393afc7c87384486d978 *tests/testthat/test-dependencies.R 949875a4fa8a2acec7039fca7626a7b1 *tests/testthat/test-downloader.R da1c39a812422fdcf6413e921ce21cd0 *tests/testthat/test-git.R 0b5b7e402c59de34614ae351c9aa77fd *tests/testthat/test-github.R 28fbd8b6b041c8d1fccf6d327b663b9b *tests/testthat/test-hash.R 6ee065b9c8e6da6a54de79160d8ce4e5 *tests/testthat/test-ignores.R 350f99ad7812e98635a9aa374c36a59b *tests/testthat/test-local-repositories.R b277e75321c2050218025337f29a4bb9 *tests/testthat/test-lockfile.R ebcf0f8c64056b268ad99788e128006c *tests/testthat/test-packrat-mode.R 9242a11f5c19bc1e4cb1e4322c24f42e *tests/testthat/test-packrat.R 52276297bbff802526c5e43458c49422 *tests/testthat/test-rmarkdown.R 263b660a6ed1b5f79b683f7a31f71eee *tests/testthat/test-shiny.R 21beb1a38f1759120710d0c13131ad69 *tests/testthat/test-utils.R b017d9164f411ce011bdcdfcf3bc25be *tests/testthat/test-with_extlib.R packrat/DESCRIPTION0000644000176200001440000000134513372757542013427 0ustar liggesusersPackage: packrat Type: Package Title: A Dependency Management System for Projects and their R Package Dependencies Version: 0.5.0 Author: Kevin Ushey, Jonathan McPherson, Joe Cheng, Aron Atkins, JJ Allaire Maintainer: Kevin Ushey Description: Manage the R packages your project depends on in an isolated, portable, and reproducible way. License: GPL-2 Depends: R (>= 3.0.0) Imports: tools, utils Suggests: testthat (>= 0.7), devtools, httr, knitr, rmarkdown URL: https://github.com/rstudio/packrat/ BugReports: https://github.com/rstudio/packrat/issues RoxygenNote: 6.1.1 Encoding: UTF-8 NeedsCompilation: no Packaged: 2018-11-13 23:16:36 UTC; kevin Repository: CRAN Date/Publication: 2018-11-14 08:40:02 UTC packrat/man/0000755000176200001440000000000013370077201012452 5ustar liggesuserspackrat/man/packrat-resources.Rd0000644000176200001440000000356013352207316016404 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/paths.R \name{packrat-resources} \alias{packrat-resources} \alias{project_dir} \alias{src_dir} \alias{lib_dir} \alias{bundles_dir} \title{Paths to Packrat Resources} \usage{ project_dir(project = NULL) src_dir(project = NULL) lib_dir(project = NULL) bundles_dir(project = NULL) } \arguments{ \item{project}{The project directory.} } \description{ These functions provide a mechanism for retrieving the paths to Packrat resource directories. Each of these directories can be overridden by setting either an environment variable, or an \R option. } \section{Project Directory}{ \code{project_dir()} is special -- the \code{R_PACKRAT_PROJECT_DIR} environment variable is set and unset by \code{\link{on}} and \code{\link{off}}, respectively, and generally should not be overridden by the user. } \section{Directory Resolution}{ The following table shows the order in which resource directories are discovered (from left to right). The first non-empty result is used. \tabular{llll}{ \strong{API} \tab \strong{Environment Variable} \tab \strong{R Option} \tab \strong{Default Value} \cr \code{project_dir()} \tab \code{R_PACKRAT_PROJECT_DIR} \tab \code{packrat.project.dir} \tab \code{getwd()} \cr \code{src_dir()} \tab \code{R_PACKRAT_SRC_DIR} \tab \code{packrat.src.dir} \tab \code{"packrat/src"} \cr \code{lib_dir()} \tab \code{R_PACKRAT_LIB_DIR} \tab \code{packrat.lib.dir} \tab \code{"packrat/lib"} \cr \code{bundles_dir()} \tab \code{R_PACKRAT_BUNDLES_DIR} \tab \code{packrat.bundles.dir} \tab \code{"packrat/bundles"} \cr \emph{(none)} \tab \code{R_PACKRAT_LIB_R_DIR} \tab \code{packrat.lib-r.dir} \tab \code{"packrat/lib-R"} \cr \emph{(none)} \tab \code{R_PACKRAT_LIB_EXT_DIR} \tab \code{packrat.lib-ext.dir} \tab \code{"packrat/lib-ext"} \cr } } packrat/man/packify.Rd0000644000176200001440000000165413352207316014377 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/packrat.R \name{packify} \alias{packify} \title{Automatically Enter Packrat Mode on Startup} \usage{ packify(project = NULL, quiet = FALSE) } \arguments{ \item{project}{The directory in which to install the \code{.Rprofile} file.} \item{quiet}{Be chatty?} } \description{ Install/augment the \code{.Rprofile} in a project, so that all \R sessions started in this directory enter \code{packrat mode}, and use the local project library. } \details{ It is not normally necessary to call \code{packify} directly; these files are normally installed by \code{\link{init}}. \code{packify} can be used to restore the files if they are missing (for instance, if they were not added to source control, or were accidentally removed). You'll need to restart \R in the specified directory after running \code{packify} in order to start using the private package library. } packrat/man/init.Rd0000644000176200001440000000476613352207316013723 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/packrat.R \name{init} \alias{init} \title{Initialize Packrat on a new or existing \R project} \usage{ init(project = ".", options = NULL, enter = TRUE, restart = enter, infer.dependencies = TRUE) } \arguments{ \item{project}{The directory that contains the \R project.} \item{options}{An \R \code{list} of options, as specified in \code{\link{packrat-options}}.} \item{enter}{Boolean, enter packrat mode for this project after finishing a init?} \item{restart}{If \code{TRUE}, restart the R session after init.} \item{infer.dependencies}{If \code{TRUE}, infer package dependencies by examining the \R code.} } \description{ Given a project directory, makes a new packrat project in the directory. } \details{ \code{init} works as follows: \enumerate{ \item Application dependencies are computed by examining the \R code throughout the project for \code{library} and \code{require} calls. You can opt out of this behavior by setting \code{infer.dependencies} to \code{FALSE}. \item A snapshot is taken of the version of each package currently used by the project as described in \code{\link{snapshot}}, and each package's sources are downloaded. \item A private library is created in the directory. \item The snapshot is applied to the directory as described in \code{\link{restore}}. } When \code{init} is finished, all the packages on which the project depends are installed in a new, private library located inside the project directory. \strong{You must restart your \R session in the given project directory after running \code{init} in order for the changes to take effect!} When \R is started in the directory, it will use the new, private library. Calls to \code{\link{require}} and \code{\link{library}} will load packages from the private library (except for 'base' or 'recommended' \R packages, which are found in the system library), and functions such as \code{\link{install.packages}} will modify that private library. You can sync this private library with packrat using \code{\link{snapshot}} and \code{\link{restore}}. } \note{ The \code{restart} parameter will only result in a restart of R when the R environment packrat is running within makes available a restart function via \code{getOption("restart")}. } \examples{ \dontrun{ ## initialize a project using a local repository of packages packrat::init(options = list(local.repos = "~/projects/R")) } } \seealso{ \link{packrat} for a description of the files created by \code{init}. } packrat/man/status.Rd0000644000176200001440000000316213352207316014270 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/status.R \name{status} \alias{status} \title{Show differences between the last snapshot and the library} \usage{ status(project = NULL, lib.loc = libDir(project), quiet = FALSE) } \arguments{ \item{project}{The directory that contains the R project.} \item{lib.loc}{The library to examine. Defaults to the private library associated with the project directory.} \item{quiet}{Print detailed information about the packrat status to the console?} } \value{ Either \code{NULL} if a \code{packrat} project has not yet been initialized, or a (invisibly) a \code{data.frame} with components: \item{package}{The package name,} \item{packrat.version}{The package version used in the last snapshot,} \item{packrat.source}{The location from which the package was obtained,} \item{library.version}{The package version available in the local library,} \item{currently.used}{Whether the package is used in any of the R code in the current project.} } \description{ Shows the differences between the project's packrat dependencies, its private package library, and its R scripts. } \details{ These differences are created when you use the normal R package management commands like \code{\link{install.packages}}, \code{\link{update.packages}}, and \code{\link{remove.packages}}. To bring these differences into packrat, you can use \code{\link{snapshot}}. Differences can also arise if one of your collaborators adds or removes packages from the packrat dependencies. In this case, you simply need to tell packrat to update your private package library using \code{\link{restore}}. } packrat/man/install.Rd0000644000176200001440000000476513352207316014425 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/install.R \name{install} \alias{install} \title{Install a local development package.} \usage{ install(pkg = ".", reload = TRUE, quick = FALSE, local = TRUE, args = getOption("devtools.install.args"), quiet = FALSE, dependencies = NA, build_vignettes = !quick, keep_source = getOption("keep.source.pkgs")) } \arguments{ \item{pkg}{package description, can be path or package name.} \item{reload}{if \code{TRUE} (the default), will automatically reload the package after installing.} \item{quick}{if \code{TRUE} skips docs, multiple-architectures, demos, and vignettes, to make installation as fast as possible.} \item{local}{if \code{FALSE} \code{\link{build}}s the package first: this ensures that the installation is completely clean, and prevents any binary artefacts (like \file{.o}, \code{.so}) from appearing in your local package directory, but is considerably slower, because every compile has to start from scratch.} \item{args}{An optional character vector of additional command line arguments to be passed to \code{R CMD install}. This defaults to the value of the option \code{"devtools.install.args"}.} \item{quiet}{if \code{TRUE} suppresses output from this function.} \item{dependencies}{\code{logical} indicating to also install uninstalled packages which this \code{pkg} depends on/links to/suggests. See argument \code{dependencies} of \code{\link{install.packages}}.} \item{build_vignettes}{if \code{TRUE}, will build vignettes. Normally it is \code{build} that's responsible for creating vignettes; this argument makes sure vignettes are built even if a build never happens (i.e. because \code{local = TRUE}.} \item{keep_source}{If \code{TRUE} will keep the srcrefs from an installed package. This is useful for debugging (especially inside of RStudio). It defaults to the option \code{"keep.source.pkgs"}.} } \description{ Uses \code{R CMD INSTALL} to install the package. Will also try to install dependencies of the package from CRAN, if they're not already installed. } \details{ By default, installation takes place using the current package directory. If you have compiled code, this means that artefacts of compilation will be created in the \code{src/} directory. If you want to avoid this, you can use \code{local = FALSE} to first build a package bundle and then install it from a temporary directory. This is slower, but keeps the source directory pristine. If the package is loaded, it will be reloaded after installation. } packrat/man/packrat.Rd0000644000176200001440000000551213352207316014373 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/packrat.R \docType{package} \name{packrat} \alias{packrat} \alias{packrat-package} \title{Packrat: Reproducible dependency management} \description{ Packrat is a tool for managing the \R packages your project depends on in an isolated, portable, and reproducible way. } \details{ Use packrat to make your \R projects more: \itemize{ \item \strong{Isolated}: Installing a new or updated package for one project won't break your other projects, and vice versa. That's because packrat gives each project its own private package library. \item \strong{Portable}: Easily transport your projects from one computer to another, even across different platforms. Packrat makes it easy to install the packages your project depends on. \item \strong{Reproducible}: Packrat records the exact package versions you depend on, and ensures those exact versions are the ones that get installed wherever you go.} Use \code{\link{init}} to create a new packrat project, \code{\link{snapshot}} to record changes to your project's library, and \code{\link{restore}} to recreate your library the way it was the last time you (or anyone!) took a snapshot. Using these simple functions and sharing packrat's files lets you collaborate in a shared, consistent environment with others as your project grows and changes, and provides an easy way to share your results when you're done. } \section{Anatomy of a packrat project}{ A packrat project contains a few extra files and directories. The \code{\link{init}} function creates these files for you, if they don't already exist. \describe{ \item{\code{packrat/lib/}}{Private package library for this project.} \item{\code{packrat/src/}}{Source packages of all the dependencies that packrat has been made aware of.} \item{\code{packrat/packrat.lock}}{Lists the precise package versions that were used to satisfy dependencies, including dependencies of dependencies. (This file should never be edited by hand!)} \item{\code{.Rprofile}}{Directs \R to use the private package library (when it is started from the project directory).} } } \section{Using packrat with version control}{ Packrat is designed to work hand in hand with Git, Subversion, or any other version control system. Be sure to check in the \code{.Rprofile}, \code{packrat.lock} files, and everything under \code{packrat/src/}. You can tell your VCS to ignore \code{packrat/lib/} (or feel free to check it in if you don't mind taking up some extra space in your repository). } \examples{ \dontrun{ # Create a new packrat project from an existing directory of \\R code init() # Install a package and take a snapshot of the new state of the library install.packages("TTR") snapshot() # Accidentally remove a package and restore to add it back remove.packages("TTR") restore() } } \author{ RStudio, Inc. } packrat/man/bitbucket_user.Rd0000644000176200001440000000045713352207316015763 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/bitbucket.R \name{bitbucket_user} \alias{bitbucket_user} \title{Retrieve Bitbucket user.} \usage{ bitbucket_user(quiet = FALSE) } \description{ A bitbucket user Looks in env var \code{BITBUCKET_USERNAME} } \keyword{internal} packrat/man/clean.Rd0000644000176200001440000000204313352207316014024 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/packrat.R \name{clean} \alias{clean} \title{Remove Packages from the Library} \usage{ clean(packages = NULL, project = NULL, lib.loc = libDir(project), dry.run = FALSE, force = FALSE) } \arguments{ \item{packages}{A set of package names to remove from the project. When \code{NULL}, \code{\link{unused_packages}} is used to find packages unused in the project.} \item{project}{The project directory. Defaults to current working directory.} \item{lib.loc}{The library to clean. Defaults to the private package library associated with the project directory.} \item{dry.run}{Perform a dry run, returning records on which packages would have been moved by the current clean action.} \item{force}{Force package removal, even if they are still in use within the project?} } \description{ Remove packages from the given library. } \examples{ \dontrun{ # Get unused package records unused_packages() # Clean all unused packages clean() # Clean specific packages clean("foo") } } packrat/man/repos_create.Rd0000644000176200001440000000115213352207316015415 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/cranlike-repositories.R \name{repos_create} \alias{repos_create} \title{Create a Local, CRAN-like Repository} \usage{ repos_create(path, name = basename(path), add = TRUE) } \arguments{ \item{path}{Path to a local CRAN-like repository.} \item{name}{The name to assign to the repository. Defaults to the directory name in which the reopsitory is created.} \item{add}{Add this new repository to the current set of repositories?} } \description{ Generate a local CRAN-like repository which can be used to store and distribute \R packages. } packrat/man/bitbucket_pwd.Rd0000644000176200001440000000046313352207316015574 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/bitbucket.R \name{bitbucket_pwd} \alias{bitbucket_pwd} \title{Retrieve Bitbucket password} \usage{ bitbucket_pwd(quiet = FALSE) } \description{ A bitbucket password Looks in env var \code{BITBUCKET_PASSWORD} } \keyword{internal} packrat/man/snapshotImpl.Rd0000644000176200001440000000511513352207316015426 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/snapshot.R \name{.snapshotImpl} \alias{.snapshotImpl} \title{Internal Snapshot Implementation} \usage{ .snapshotImpl(project, available = NULL, lib.loc = libDir(project), dry.run = FALSE, ignore.stale = FALSE, prompt = interactive(), auto.snapshot = FALSE, verbose = TRUE, fallback.ok = FALSE, snapshot.sources = TRUE, implicit.packrat.dependency = TRUE, infer.dependencies = TRUE) } \arguments{ \item{project}{The project directory. Defaults to current working directory.} \item{available}{A database of available packages.} \item{lib.loc}{The library to snapshot. Defaults to the private library associated with the given directory.} \item{dry.run}{Computes the changes to your packrat state that would be made if a snapshot were performed, and prints them to the console.} \item{ignore.stale}{Stale packages are packages that are different from the last snapshot, but were installed by packrat. Typically, packages become stale when a new snapshot is available, but you haven't applied it yet with \code{\link{restore}}. By default, packrat will prevent you from taking a snapshot when you have stale packages to prevent you from losing changes from the unapplied snapshot. If your intent is to overwrite the last snapshot without applying it, use \code{ignore.stale = TRUE} to skip this check.} \item{prompt}{\code{TRUE} to prompt before performing snapshotting package changes that might be unintended; \code{FALSE} to perform these operations without confirmation. Potentially unintended changes include snapshotting packages at an older version than the last snapshot, or missing despite being present in the last snapshot.} \item{auto.snapshot}{Internal use -- should be set to \code{TRUE} when this is an automatic snapshot.} \item{verbose}{Print output to the console while \code{snapshot}-ing?} \item{fallback.ok}{Fall back to the latest CRAN version of a package if the locally installed version is unavailable?} \item{snapshot.sources}{Download the tarball associated with a particular package?} \item{implicit.packrat.dependency}{Include \code{packrat} as an implicit dependency of this project, if not otherwise discovered? This should be \code{FALSE} only if you can guarantee that \code{packrat} will be available via other means when attempting to load this project.} \item{infer.dependencies}{If \code{TRUE}, infer package dependencies by examining the \R code.} } \description{ This is the internal implementation for \code{\link{snapshot}}. Most users should prefer calling \code{\link{snapshot}}. } \keyword{internal} packrat/man/packrat-mode.Rd0000644000176200001440000000240313352207316015311 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/packrat-mode.R \name{packrat-mode} \alias{packrat-mode} \alias{packrat_mode} \alias{on} \alias{off} \title{Packrat Mode} \usage{ packrat_mode(on = NULL, project = NULL, auto.snapshot = get_opts("auto.snapshot"), clean.search.path = TRUE) on(project = NULL, auto.snapshot = get_opts("auto.snapshot"), clean.search.path = TRUE, print.banner = TRUE) off(project = NULL, print.banner = TRUE) } \arguments{ \item{on}{Turn packrat mode on (\code{TRUE}) or off (\code{FALSE}). If omitted, packrat mode will be toggled.} \item{project}{The directory in which packrat mode is launched -- this is where local libraries will be used and updated.} \item{auto.snapshot}{Perform automatic, asynchronous snapshots?} \item{clean.search.path}{Detach and unload any packages loaded from non-system libraries before entering packrat mode?} \item{print.banner}{Print the packrat banner when entering / exiting packrat mode? The packrat banner informs you of the new packrat mode state, as well as the library path in use.} } \description{ Use these functions to switch \code{packrat} mode on and off. When within \code{packrat} mode, the \R session will use the private library generated for the current project. } packrat/man/unused_packages.Rd0000644000176200001440000000071113352207316016103 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/packrat.R \name{unused_packages} \alias{unused_packages} \title{Find Unused Packages in a Project} \usage{ unused_packages(project = NULL, lib.loc = libDir(project)) } \arguments{ \item{project}{The project directory.} \item{lib.loc}{The library to check.} } \description{ Unused packages are those still contained within your project library, but are unused in your project. } packrat/man/snapshot.Rd0000644000176200001440000000524113352207316014604 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/snapshot.R \name{snapshot} \alias{snapshot} \title{Capture and store the packages and versions in use} \usage{ snapshot(project = NULL, available = NULL, lib.loc = libDir(project), ignore.stale = FALSE, dry.run = FALSE, prompt = interactive(), snapshot.sources = TRUE, infer.dependencies = TRUE) } \arguments{ \item{project}{The project directory. Defaults to current working directory.} \item{available}{A database of available packages.} \item{lib.loc}{The library to snapshot. Defaults to the private library associated with the given directory.} \item{ignore.stale}{Stale packages are packages that are different from the last snapshot, but were installed by packrat. Typically, packages become stale when a new snapshot is available, but you haven't applied it yet with \code{\link{restore}}. By default, packrat will prevent you from taking a snapshot when you have stale packages to prevent you from losing changes from the unapplied snapshot. If your intent is to overwrite the last snapshot without applying it, use \code{ignore.stale = TRUE} to skip this check.} \item{dry.run}{Computes the changes to your packrat state that would be made if a snapshot were performed, and prints them to the console.} \item{prompt}{\code{TRUE} to prompt before performing snapshotting package changes that might be unintended; \code{FALSE} to perform these operations without confirmation. Potentially unintended changes include snapshotting packages at an older version than the last snapshot, or missing despite being present in the last snapshot.} \item{snapshot.sources}{Boolean; should package sources be downloaded during snapshot?} \item{infer.dependencies}{If \code{TRUE}, infer package dependencies by examining \R code used within the project. This included the \R code contained within \code{.R} files, as well as other multi-mode documents (e.g. \code{.Rmd}).} } \description{ Finds the packages in use in the project, and stores a list of those packages, their sources, and their current versions in packrat. } \note{ \code{snapshot} modifies the project's \code{packrat.lock} file, and the sources stored in the project's \code{packrat/src} directory. If you are working with a version control system, your collaborators can sync the changes to these files and then use \code{\link{restore}} to apply your snapshot. } \examples{ \dontrun{ # Take a snapshot of the current project snapshot() # See what changes would be included in a snapshot snapshot(dry.run = TRUE) } } \seealso{ \code{\link{restore}} to apply a snapshot. \code{\link{status}} to view the differences between the most recent snapshot and the library. } packrat/man/repository-management.Rd0000644000176200001440000000217113352207316017275 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/cranlike-repositories.R \name{repository-management} \alias{repository-management} \alias{repos_add} \alias{repos_add_local} \alias{repos_set} \alias{repos_set_local} \alias{repos_remove} \alias{repos_list} \title{Add a Repository} \usage{ repos_add(..., overwrite = FALSE) repos_add_local(..., overwrite = FALSE) repos_set(...) repos_set_local(...) repos_remove(names) repos_list() } \arguments{ \item{...}{Named arguments of the form \code{ = }.} \item{overwrite}{Boolean; overwrite if a repository with the given name already exists?} \item{names}{The names of repositories (as exist in e.g. \code{names(getOption("repos"))}).} } \description{ Add a repository to the set of currently available repositories. This is effectively an easier-to-use wrapper over interacting with the \code{"repos"} option, which is otherwise set with \code{options(repos = ...)}. } \details{ \code{repos_add_local} is used for adding file-based repositories; that is, CRAN repositories that live locally on disk and not on the internet / local network. } packrat/man/repos_upload.Rd0000644000176200001440000000137713352207316015447 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/cranlike-repositories.R \name{repos_upload} \alias{repos_upload} \title{Upload a Package to a Local CRAN-like Repository} \usage{ repos_upload(package, to, ...) } \arguments{ \item{package}{Path to a package tarball. The tarball should be created by \code{R CMD build}; alternatively, it can be the path to a folder containing the source code for a package (which will then be built with \code{R CMD build}) and then uploaded to the local repository.} \item{to}{The name of the CRAN-like repository. It (currently) must be a local (on-disk) CRAN repository.} \item{...}{Optional arguments passed to \code{R CMD build}.} } \description{ Upload a Package to a Local CRAN-like Repository } packrat/man/packrat-options.Rd0000644000176200001440000001146313352207316016066 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/options.R \docType{data} \name{packrat-options} \alias{packrat-options} \alias{get_opts} \alias{set_opts} \alias{opts} \title{Get/set packrat project options} \usage{ get_opts(options = NULL, simplify = TRUE, project = NULL) set_opts(..., project = NULL, persist = TRUE) opts } \arguments{ \item{options}{A character vector of valid option names.} \item{simplify}{Boolean; \code{unlist} the returned options? Useful for when retrieving a single option.} \item{project}{The project directory. When in packrat mode, defaults to the current project; otherwise, defaults to the current working directory.} \item{...}{Entries of the form \code{key = value}, used for setting packrat project options.} \item{persist}{Boolean; persist these options for future sessions?} } \description{ Get and set options for the current packrat-managed project. } \section{Valid Options}{ \itemize{ \item \code{auto.snapshot}: Perform automatic, asynchronous snapshots when running interactively? (logical; defaults to \code{FALSE}) \item \code{use.cache}: Install packages into a global cache, which is then shared across projects? The directory to use is read through \code{Sys.getenv("R_PACKRAT_CACHE_DIR")}. Windows support is currently experimental. (logical; defaults to \code{FALSE}) \item \code{print.banner.on.startup}: Print the banner on startup? Can be one of \code{TRUE} (always print), \code{FALSE} (never print), and \code{'auto'} (do the right thing) (defaults to \code{"auto"}) \item \code{vcs.ignore.lib}: If TRUE, version control configuration is modified to ignore packrat private libraries. (logical; defaults to \code{TRUE}) \item \code{vcs.ignore.src}: If TRUE, version control configuration is modified to ignore packrat private sources. (logical; defaults to \code{FALSE}) \item \code{external.packages}: Packages which should be loaded from the user library. This can be useful for very large packages which you don't want duplicated across multiple projects, e.g. BioConductor annotation packages, or for package development scenarios wherein you want to use e.g. \code{devtools} and \code{roxygen2} for package development, but do not want your package to depend on these packages. (character; defaults to \code{Sys.getenv("R_PACKRAT_EXTERNAL_PACKAGES")}) \item \code{local.repos}: Ad-hoc local 'repositories'; i.e., directories containing package sources within sub-directories. (character; empty by default) \item \code{load.external.packages.on.startup}: Load any packages specified within \code{external.packages} on startup? (logical; defaults to \code{TRUE}) \item \code{ignored.packages}: Prevent packrat from tracking certain packages. Dependencies of these packages will also not be tracked (unless these packages are encountered as dependencies in a separate context from the ignored package). (character; empty by default) \item \code{ignored.directories}: Prevent packrat from looking for dependencies inside certain directories of your workspace. For example, if you have set your "local.repos" to be inside your local workspace so that you can track custom packages as git submodules. Each item should be the relative path to a directory in the workspace, e.g. "data", "lib/gitsubmodule". Note that packrat already ignores any "invisible" files and directories, such as those whose names start with a "." character. (character; empty by default) \item \code{quiet.package.installation}: Emit output during package installation? (logical; defaults to \code{TRUE}) \item \code{snapshot.recommended.packages}: Should 'recommended' packages discovered in the system library be snapshotted? See the \code{Priority} field of \code{available.packages()} for more information -- 'recommended' packages are those normally bundled with CRAN releases of R on OS X and Windows, but new releases are also available on the CRAN server. (logical; defaults to \code{FALSE}) \item \code{snapshot.fields}: What fields of a package's DESCRIPTION file should be used when discovering dependencies? (character, defaults to \code{c("Imports", "Depends", "LinkingTo")}) \item \code{symlink.system.packages}: Symlink base \R packages into a private \code{packrat/lib-R} directory? This is done to further encapsulate the project from user packages that have been installed into the \R system library. (boolean, defaults to \code{TRUE}) } } \examples{ \dontrun{ ## use 'devtools' and 'knitr' from the user library packrat::set_opts(external.packages = c("devtools", "knitr")) ## set local repository packrat::set_opts(local.repos = c("~/projects/R")) ## get the set of 'external packages' packrat::opts$external.packages() ## set the external packages packrat::opts$external.packages(c("devtools", "knitr")) } } \keyword{datasets} packrat/man/bundle.Rd0000644000176200001440000000317513352207316014222 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/bundle.R \name{bundle} \alias{bundle} \title{Bundle a Packrat Project} \usage{ bundle(project = NULL, file = NULL, include.src = TRUE, include.lib = FALSE, include.bundles = TRUE, include.vcs.history = FALSE, overwrite = FALSE, omit.cran.src = FALSE, ...) } \arguments{ \item{project}{The project directory. Defaults to the currently activate project. By default, the current project active under \code{packratMode} is checked.} \item{file}{The path to write the bundle. By default, we write the bundle to \code{packrat/bundles/-.tar.gz}, with \code{} as returned by \code{Sys.date()}.} \item{include.src}{Include the packrat sources?} \item{include.lib}{Include the packrat private library?} \item{include.bundles}{Include other packrat bundle tarballs (as in \code{packrat/bundles/})?} \item{include.vcs.history}{Include version control history (ie, \code{.git/} or \code{.svn/} folders)?} \item{overwrite}{Boolean; overwrite the file at \code{file} if it already exists?} \item{omit.cran.src}{Boolean; when \code{TRUE}, packages whose sources can be retrieved from CRAN are excluded from the bundle.} \item{...}{Optional arguments passed to \code{\link{tar}}.} } \value{ The path (invisibly) to the bundled project. } \description{ Bundle a packrat project, for easy sharing. } \details{ The project is bundled as a gzipped tarball (\code{.tar.gz}), which can be unbundled either with \code{packrat::\link{unbundle}} (which restores the project as well), \R's own \code{utils::\link{untar}}, or through most system \code{tar} implementations. } packrat/man/appDependencies.Rd0000644000176200001440000000272113352207316016034 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/dependencies.R \name{appDependencies} \alias{appDependencies} \title{Detect Application Dependencies} \usage{ appDependencies(project = NULL, available.packages = NULL, fields = opts$snapshot.fields(), implicit.packrat.dependency = TRUE) } \arguments{ \item{project}{Directory containing application. Defaults to current working directory.} \item{implicit.packrat.dependency}{Include \code{packrat} as an implicit dependency of this project, if not otherwise discovered? This should be \code{FALSE} only if you can guarantee that \code{packrat} will be available via other means when attempting to load this project.} } \value{ Returns a list of the names of the packages on which R code in the application depends. } \description{ Recursively detect all package dependencies for an application. This function parses all \R files in the application directory to determine what packages the application depends directly. } \details{ Only direct dependencies are detected (i.e. no recursion is done to find the dependencies of the dependencies). Dependencies are determined by parsing application source code and looking for calls to \code{library}, \code{require}, \code{::}, and \code{:::}. } \examples{ \dontrun{ # dependencies for the app in the current working dir appDependencies() # dependencies for an app in another directory appDependencies("~/projects/shiny/app1") } } \keyword{internal} packrat/man/disable.Rd0000644000176200001440000000201713352207316014346 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/disable.R \name{disable} \alias{disable} \title{Disable the use of Packrat in a Project} \usage{ disable(project = NULL, restart = TRUE) } \arguments{ \item{project}{The directory in which packrat will be disabled (defaults to the current working directory)} \item{restart}{If \code{TRUE}, restart the R session after disabling packrat.} } \description{ Disable packrat within a project, reverting to the use of standard user package libraries. } \note{ Disabling packrat for a project removes the packrat initialization code from the .Rprofile file, resulting in the use of standard user package libraries. Note that the \code{packrat} directory is not deleted, but remains unused. To re-enable the use of packrat for a project you can call the \code{\link{init}} function. The \code{restart} parameter will only result in a restart of R when the R environment packrat is running within makes available a restart function via \code{getOption("restart")}. } packrat/man/packrat-external.Rd0000644000176200001440000000275213352207316016216 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/external.R, R/paths.R \name{packrat-external} \alias{packrat-external} \alias{with_extlib} \alias{extlib} \alias{user_lib} \alias{packrat_lib} \title{Managing External Libraries} \usage{ with_extlib(packages = NULL, expr, envir = parent.frame()) extlib(packages) user_lib() packrat_lib() } \arguments{ \item{packages}{An optional set of package names (as a character vector) to load for the duration of evaluation of \code{expr}. Whether \code{packages} is provided or \code{NULL} (the default), \code{expr} is evaluated in an environment where the external library path is in place, not the local (packrat) library path.} \item{expr}{An \R expression.} \item{envir}{An environment in which the expression is evaluated.} } \description{ These functions provide a mechanism for (temporarily) using packages outside of the packrat private library. The packages are searched within the 'default' libraries; that is, the libraries that would be available upon launching a new \R session. } \examples{ \dontrun{ with_extlib("lattice", xyplot(1 ~ 1)) with_extlib(expr = packageVersion("lattice")) # since devtools requires roxygen2 >= 5.0.0 for this step, this # should fail unless roxygen2 is available in the packrat lib.loc with_extlib("devtools", load_all("path/to/project")) # this method will work given roxygen2 is installed in the # non-packrat lib.loc with devtools with_extlib(expr = devtools::load_all("path/to/project")) } } packrat/man/restore.Rd0000644000176200001440000000634113352207316014432 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/packrat.R \name{restore} \alias{restore} \title{Apply the most recent snapshot to the library} \usage{ restore(project = NULL, overwrite.dirty = FALSE, prompt = interactive(), dry.run = FALSE, restart = !dry.run) } \arguments{ \item{project}{The project directory. When in packrat mode, if this is \code{NULL}, then the directory associated with the current packrat project is used. Otherwise, the project directory specified is used.} \item{overwrite.dirty}{A dirty package is one that has been changed since the last snapshot or restore. Packrat will leave these alone by default. If you want to guarantee that \code{restore} will put you in the exact state represented by the snapshot being applied, use \code{overwrite.dirty = TRUE}.} \item{prompt}{\code{TRUE} to prompt before performing potentially destructive changes (package removals or downgrades); \code{FALSE} to perform these operations without confirmation.} \item{dry.run}{If \code{TRUE}, compute the changes to your packrat state that would be made if a restore was performed, without actually executing them.} \item{restart}{If \code{TRUE}, restart the R session after restoring.} } \description{ Applies the most recent snapshot to the project's private library. } \details{ \code{restore} works by adding, removing, and changing packages so that the set of installed packages and their versions matches the snapshot exactly. There are three common use cases for \code{restore}: \itemize{ \item \strong{Hydrate}: Use \code{restore} after copying a project to a new machine to populate the library on that machine. \item \strong{Sync}: Use \code{restore} to apply library changes made by a collaborator to your own library. (In general, you want to run \code{restore} whenever you pick up a change to \code{packrat.lock}) \item \strong{Rollback}: Use \code{restore} to undo accidental changes made to the library since the last snapshot. } \code{restore} cannot make changes to packages that are currently loaded. If changes are necessary to currently loaded packages, you will need to restart \R to apply the changes (\code{restore} will let you know when this is necessary). It is recommended that you do this as soon as possible, because any library changes made between running \code{restore} and restarting \R will be lost. } \note{ \code{restore} can be destructive; it will remove packages that were not in the snapshot, and it will replace newer packages with older versions if that's what the snapshot indicates. \code{restore} will warn you before attempting to remove or downgrade a package (if \code{prompt} is \code{TRUE}), but will always perform upgrades and new installations without prompting. \code{restore} works only on the private package library created by packrat; if you have other libraries on your path, they will be unaffected. The \code{restart} parameter will only result in a restart of R when the R environment packrat is running within makes available a restart function via \code{getOption("restart")}. } \seealso{ \code{\link{snapshot}}, the command that creates the snapshots applied with \code{restore}. \code{\link{status}} to view the differences between the most recent snapshot and the library. } packrat/man/lockfile-metadata.Rd0000644000176200001440000000431613352207316016315 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/lockfile-metadata.R \name{lockfile-metadata} \alias{lockfile-metadata} \alias{set_lockfile_metadata} \alias{get_lockfile_metadata} \title{Get / Set packrat lockfile metadata} \usage{ set_lockfile_metadata(repos = NULL, r_version = NULL, project = NULL) get_lockfile_metadata(metadata = NULL, simplify = TRUE, project = NULL) } \arguments{ \item{repos}{A named character vector of the form \code{c( = "")}.} \item{r_version}{A length-one character vector with suitable numeric version string. See \code{\link[base]{package_version}}.} \item{project}{The project directory. When in packrat mode, defaults to the current project; otherwise, defaults to the current working directory.} \item{metadata}{The lockfile field name(s) to draw from.} \item{simplify}{Boolean; if \code{TRUE} the returned metadata will be un-listed.} } \description{ Get and set metadata in the current packrat-managed project lockfile \code{packrat.lock} } \details{ Project's \code{packrat.lock} contains some metadata before packages dependencies informations. The project's lockfile is created and updated programmatically by \code{\link{snapshot}}. However it could be necessary sometimes to modify manually some of those values. For example, it could be useful to set another repository CRAN url when deploying to a offline environnement. } \section{available metadata }{ \itemize{ \item \code{r_version}: R version the project depends on \item \code{repos}: Name of repos and their url recorded packages can be retrieve from. Only url is recommended to change if need. Name of repos is used in package records and must be identical } } \examples{ \dontrun{ # changes repos url repos <- old_repos <- get_lockfile_metadata("repos") repos repos["CRAN"] <- "https://cran.r-project.org/" set_lockfile_metadata(repos = repos) get_lockfile_metadata("repos") # setting back old state # set_lockfile_metadata(repos = old_repos) # changes R version rver <- old_rver <- get_lockfile_metadata("r_version") rver rver <- "3.4.1" set_lockfile_metadata(r_version = rver) get_lockfile_metadata("r_version") # Setting back old state # set_lockfile_metadata(r_version = old_rver) } } packrat/man/install_local.Rd0000644000176200001440000000131213352207316015560 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/install-local.R \name{install_local} \alias{install_local} \title{Install a Package from a Local Repository} \usage{ install_local(pkgs, ..., lib = .libPaths()[1], repos = get_opts("local.repos")) } \arguments{ \item{pkgs}{A character vector of package names.} \item{...}{Optional arguments passed to \code{\link[packrat]{install}}.} \item{lib}{The library in which the package should be installed.} \item{repos}{The local repositories to search for the package names specified.} } \description{ This function can be used to install a package from a local 'repository'; i.e., a directory containing package tarballs and sources. } packrat/man/unbundle.Rd0000644000176200001440000000107113352207316014556 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/bundle.R \name{unbundle} \alias{unbundle} \title{Unbundle a Packrat Project} \usage{ unbundle(bundle, where, ..., restore = TRUE) } \arguments{ \item{bundle}{Path to the bundled file.} \item{where}{The directory where we will unbundle the project.} \item{...}{Optional arguments passed to \code{\link{tar}}.} \item{restore}{Boolean; should we \code{\link{restore}} the library after \code{unbundle}-ing the project?} } \description{ Unbundle a previously \code{\link{bundle}}d project. } packrat/man/search_path.Rd0000644000176200001440000000045113352207316015224 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/search-path.R \name{search_path} \alias{search_path} \title{Get Packages on the Search Path} \usage{ search_path() } \description{ Retrieve the packages on the search path, as well as the associated library location. }