From ba5ccc5ca8cd620b272af5d2494dd5a9a17858bb Mon Sep 17 00:00:00 2001 From: nuest Date: Fri, 23 Mar 2018 14:37:41 +0100 Subject: [PATCH] Add predetection of packages based on automagic closes #53 and #101; also update base images to 3.4.4 --- DESCRIPTION | 5 +- R/dockerfile.R | 142 +++++++++--------- R/sessionInfo-localbuild-methods.R | 85 +++++++---- R/utility-functions.R | 26 ++-- inst/docker/Dockerfile | 2 +- inst/docker/geospatial/Dockerfile | 4 +- inst/docker/local/Dockerfile | 30 ++++ man/dockerfile.Rd | 4 +- .../package_markdown/spacetime/Dockerfile | 12 ++ .../package_markdown/spacetime/main.Rmd | 107 +++++++++++++ tests/testthat/test_package_markdown.R | 14 ++ vignettes/container.Rmd | 15 ++ 12 files changed, 319 insertions(+), 127 deletions(-) create mode 100644 inst/docker/local/Dockerfile create mode 100644 tests/testthat/package_markdown/spacetime/Dockerfile create mode 100644 tests/testthat/package_markdown/spacetime/main.Rmd diff --git a/DESCRIPTION b/DESCRIPTION index 83870e1..6a8a17e 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -17,7 +17,8 @@ Imports: sysreqs, futile.logger, devtools, - semver + semver, + automagic VignetteBuilder: knitr Description: Package R sessions, scripts, workspaces and vignettes together with all dependencies to execute them in Docker containers. This package is supported @@ -48,7 +49,7 @@ Suggests: remotes, ggplot2 RoxygenNote: 6.0.1 -Collate: +Collate: 'Class-Instruction.R' 'Class-Add.R' 'Class-All.R' diff --git a/R/dockerfile.R b/R/dockerfile.R index 6b0a6b7..cb04e67 100644 --- a/R/dockerfile.R +++ b/R/dockerfile.R @@ -44,6 +44,7 @@ #' @param add_self Whether to add the package containerit itself if loaded/attached to the session #' @param vanilla Whether to use an empty vanilla session when packaging scripts and markdown files (equivalent to \code{R --vanilla}) #' @param silent Whether or not to print information during execution +#' @param predetect Extract the required libraries based on \code{library} calls using the package \code{automagic} before running a script/document #' @param versioned_libs [EXPERIMENTAL] Whether it shall be attempted to match versions of linked external libraries #' @param versioned_packages [EXPERIMENTAL] Whether it shall be attempted to match versions of R packages #' @@ -73,6 +74,7 @@ dockerfile <- function(from = utils::sessionInfo(), add_self = FALSE, vanilla = TRUE, silent = FALSE, + predetect = TRUE, versioned_libs = FALSE, versioned_packages = FALSE) { if (silent) { @@ -162,10 +164,9 @@ dockerfile <- function(from = utils::sessionInfo(), futile.logger::flog.debug("Creating from character string '%s'", from) if (dir.exists(from)) { - futile.logger::flog.debug("'%s' is a directory") + futile.logger::flog.debug("'%s' is a directory", from) .originalFrom <- from - .dockerfile <- - dockerfileFromWorkspace( + .dockerfile <- dockerfileFromWorkspace( path = from, .dockerfile = .dockerfile, soft = soft, @@ -174,15 +175,14 @@ dockerfile <- function(from = utils::sessionInfo(), copy = copy, vanilla = vanilla, silent = silent, + predetect = predetect, versioned_libs = versioned_libs, versioned_packages = versioned_packages, - workdir = workdir - ) + workdir = workdir) } else if (file.exists(from)) { futile.logger::flog.debug("'%s' is a file", from) .originalFrom <- from - .dockerfile <- - dockerfileFromFile( + .dockerfile <- dockerfileFromFile( file = from, .dockerfile = .dockerfile, soft = soft, @@ -191,10 +191,10 @@ dockerfile <- function(from = utils::sessionInfo(), copy = copy, vanilla = vanilla, silent = silent, + predetect = predetect, versioned_libs = versioned_libs, versioned_packages = versioned_packages, - workdir = workdir - ) + workdir = workdir) } else { stop("Unsupported string for 'from' argument (not a file, not a directory): ", from) } @@ -278,23 +278,24 @@ dockerfileFromSession <- function(session, return(.dockerfile) } -dockerfileFromFile <- - function(file, - .dockerfile, - soft, - copy, - offline, - add_self, - vanilla, - silent, - versioned_libs, - versioned_packages, - workdir) { +dockerfileFromFile <- function(file, + .dockerfile, + soft, + copy, + offline, + add_self, + vanilla, + silent, + predetect, + versioned_libs, + versioned_packages, + workdir) { futile.logger::flog.debug("Creating from file") # prepare context ( = working directory) and normalize paths: context = normalizePath(getwd()) file = normalizePath(file) + futile.logger::flog.debug("Working with file %s in working directory %s", file, context) #Is the file within the context? len = stringr::str_length(context) @@ -307,23 +308,19 @@ dockerfileFromFile <- # execute script / markdowns or read Rdata file to obtain sessioninfo if (stringr::str_detect(file, ".R$")) { - futile.logger::flog.info("Executing R script file in %s locally.", rel_path) - sessionInfo <- - obtain_localSessionInfo( - file = file, - vanilla = vanilla, - slave = silent, - echo = !silent - ) + futile.logger::flog.info("Processing R script file '%s' locally.", rel_path) + sessionInfo <- obtain_localSessionInfo(file = file, + vanilla = vanilla, + slave = silent, + echo = !silent, + predetect = predetect) } else if (stringr::str_detect(file, ".Rmd$")) { - futile.logger::flog.info("Processing the given file %s locally using rmarkdown::render(...)", rel_path) - sessionInfo <- - obtain_localSessionInfo( - rmd_file = file, - vanilla = vanilla, - slave = silent, - echo = !silent - ) + futile.logger::flog.info("Processing Rmd file '%s' locally using rmarkdown::render(...)", rel_path) + sessionInfo <- obtain_localSessionInfo(rmd_file = file, + vanilla = vanilla, + slave = silent, + echo = !silent, + predetect = predetect) } else if (stringr::str_detect(file, ".Rdata$")) { sessionInfo <- getSessionInfoFromRdata(file) } else{ @@ -331,17 +328,14 @@ dockerfileFromFile <- } # append system dependencies and package installation instructions - .dockerfile <- - dockerfileFromSession( - session = sessionInfo, - .dockerfile = .dockerfile, - soft = soft, - offline = offline, - add_self = add_self, - versioned_libs = versioned_libs, - versioned_packages = versioned_packages, - workdir = workdir - ) + .dockerfile <- dockerfileFromSession(session = sessionInfo, + .dockerfile = .dockerfile, + soft = soft, + offline = offline, + add_self = add_self, + versioned_libs = versioned_libs, + versioned_packages = versioned_packages, + workdir = workdir) ## working directory must be set before. Now add copy instructions if (!is.null(copy) && !is.na(copy)) { @@ -370,8 +364,7 @@ dockerfileFromFile <- sapply(copy, function(file) { if (file.exists(file)) { rel_path <- .makeRelative(normalizePath(file), context) - rel_path_dest <- - stringr::str_replace_all(rel_path, pattern = "\\\\", replacement = "/") + rel_path_dest <- stringr::str_replace_all(rel_path, pattern = "\\\\", replacement = "/") if (dir.exists(file) && !stringr::str_detect(rel_path_dest, "/$")) rel_path_dest <- paste0(rel_dir_dest, "/") @@ -389,18 +382,18 @@ dockerfileFromFile <- return(.dockerfile) } -dockerfileFromWorkspace <- - function(path, - .dockerfile, - soft, - offline, - add_self, - copy, - vanilla, - silent, - versioned_libs, - versioned_packages, - workdir) { +dockerfileFromWorkspace <- function(path, + .dockerfile, + soft, + offline, + add_self, + copy, + vanilla, + silent, + predetect, + versioned_libs, + versioned_packages, + workdir) { futile.logger::flog.debug("Creating from workspace directory") target_file <- NULL #file to be packaged @@ -443,19 +436,18 @@ dockerfileFromWorkspace <- else futile.logger::flog.info("Found file for packaging in workspace: %s", target_file) - .df <- dockerfileFromFile( - target_file, - .dockerfile = .dockerfile, - soft = soft, - offline = offline, - copy = copy, - add_self = add_self, - vanilla = vanilla, - silent = silent, - versioned_libs = versioned_libs, - versioned_packages = versioned_packages, - workdir = workdir - ) + .df <- dockerfileFromFile(target_file, + .dockerfile = .dockerfile, + soft = soft, + offline = offline, + copy = copy, + add_self = add_self, + vanilla = vanilla, + silent = silent, + predetect = predetect, + versioned_libs = versioned_libs, + versioned_packages = versioned_packages, + workdir = workdir) return(.df) } diff --git a/R/sessionInfo-localbuild-methods.R b/R/sessionInfo-localbuild-methods.R index 10806ae..3bb6d89 100644 --- a/R/sessionInfo-localbuild-methods.R +++ b/R/sessionInfo-localbuild-methods.R @@ -99,51 +99,74 @@ create_localDockerImage <- function(x, # # This method is used for packaging R scripts (see dockerFileFromFile) # and for comparing session information (see test/testthat/test_sessioninfo_repoduce.R) -obtain_localSessionInfo <- - function(expr = c(), +obtain_localSessionInfo <- function(expr = c(), file = NULL, # an R script to be executed rmd_file = NULL, # an R Markdown file vanilla = TRUE, silent = TRUE, slave = FALSE, - echo = FALSE, #whether R scripts should be 'echoed' + echo = FALSE, # whether R scripts should be 'echoed' + predetect = TRUE, # whether to use automagic to make sure all required packages are installed local_tempfile = tempfile(pattern = "rdata-sessioninfo"), local_temp_script = tempfile(pattern = "r-script")) { - #append commands to create a local sessionInfo - if (!is.null(file) && file.exists(file)) { - expr <- append(expr, call("source", file = file, echo = echo)) + #append commands to create a local sessionInfo + required_pkgs <- c() + if (!is.null(file) && file.exists(file)) { + expr <- append(expr, call("source", file = file, echo = echo)) + + if (predetect) { + required_pkgs <- automagic::parse_packages(file) + futile.logger::flog.debug("Analysed input file %s and found required packages: %s", + file, toString(required_pkgs)) } + } + + if (!is.null(rmd_file) && file.exists(rmd_file)) { + render_call <- quote(rmarkdown::render("file")) + render_call[[2]] <- rmd_file #replace the argument "file + expr <- append(expr, render_call) - if (!is.null(rmd_file) && file.exists(rmd_file)) { - render_call <- quote(rmarkdown::render("file")) - render_call[[2]] <- rmd_file #replace the argument "file - expr <- append(expr, render_call) + if (predetect) { + required_pkgs <- automagic::parse_packages(rmd_file) + futile.logger::flog.debug("Analysed input file %s and found required packages: %s", + rmd_file, toString(required_pkgs)) } + } - expr <- append(expr, .writeSessionInfoExp(local_tempfile)) - args <- .exprToParam(expr, to_string = TRUE) - if (vanilla) - args <- append("--vanilla", args) + if (predetect && length(required_pkgs) > 0) { + installing_pkgs <- stringr::str_remove_all(required_pkgs, "\"") + installing_pkgs <- setdiff(installing_pkgs, rownames(installed.packages())) + if (length(installing_pkgs) > 0) { + futile.logger::flog.info("Missing packages installed before running file: %s", + toString(installing_pkgs)) + install.packages(pkgs = installing_pkgs) + } else { + futile.logger::flog.debug("No missing packages to install before running file") + } + } - if (slave) - args <- append("--slave", args) + expr <- append(expr, .writeSessionInfoExp(local_tempfile)) + args <- .exprToParam(expr, to_string = TRUE) + if (vanilla) + args <- append("--vanilla", args) - if (silent) - args <- append("--silent", args) + if (slave) + args <- append("--slave", args) - futile.logger::flog.info(paste( - "Creating an R session with the following arguments:\n\t R ", - paste(args, collapse = " ") - )) + if (silent) + args <- append("--silent", args) - system2("R", args) + futile.logger::flog.info(paste("Creating an R session with the following arguments:\n\t R ", + paste(args, collapse = " "))) - if (!file.exists(local_tempfile)) - stop("Failed to execute the script locally! A sessionInfo could not be determined.") + system2("R", args) - load(local_tempfile) - #clean up: - unlink(local_tempfile) - unlink(local_temp_script) - return(get("info")) - } + if (!file.exists(local_tempfile)) + stop("Failed to execute the script locally! A sessionInfo could not be determined.") + + load(local_tempfile) + #clean up: + unlink(local_tempfile) + unlink(local_temp_script) + return(get("info")) +} diff --git a/R/utility-functions.R b/R/utility-functions.R index f7ca43f..086bba3 100644 --- a/R/utility-functions.R +++ b/R/utility-functions.R @@ -190,18 +190,14 @@ getSessionInfoFromRdata <- function(file) { #' #' @return An object of class session info (Can be used as an input to the dockerfile-method) #' @export -#' -clean_session <- - function(expr = list(), - file = NULL, - vanilla = TRUE, - slave = FALSE, - echo = FALSE) { - obtain_localSessionInfo( - expr = expr, - file = file, - slave = slave, - echo = echo, - vanilla = vanilla - ) - } +clean_session <- function(expr = list(), + file = NULL, + vanilla = TRUE, + slave = FALSE, + echo = FALSE) { + obtain_localSessionInfo(expr = expr, + file = file, + slave = slave, + echo = echo, + vanilla = vanilla) +} diff --git a/inst/docker/Dockerfile b/inst/docker/Dockerfile index 247d8c6..978b587 100644 --- a/inst/docker/Dockerfile +++ b/inst/docker/Dockerfile @@ -1,4 +1,4 @@ -FROM rocker/verse:3.4.3 +FROM rocker/verse:3.4.4 RUN apt-get update \ && apt-get install -y --no-install-recommends \ diff --git a/inst/docker/geospatial/Dockerfile b/inst/docker/geospatial/Dockerfile index c8e749e..6e99a8a 100644 --- a/inst/docker/geospatial/Dockerfile +++ b/inst/docker/geospatial/Dockerfile @@ -1,11 +1,11 @@ -FROM rocker/geospatial:3.4.3 +FROM rocker/geospatial:3.4.4 LABEL maintainer="o2r project " RUN apt-get update \ && apt-get install -y --no-install-recommends \ libapparmor-dev -RUN ["install2.r", "rjson", "futile.logger", "debugme"] +RUN ["install2.r", "rjson", "futile.logger"] # use devtools instead of installGithub.r to take advantage of "Remotes" defined in DESCRIPTION file RUN ["R", "-e", "devtools::install_github('o2r-project/containerit')"] diff --git a/inst/docker/local/Dockerfile b/inst/docker/local/Dockerfile new file mode 100644 index 0000000..3b3c9b8 --- /dev/null +++ b/inst/docker/local/Dockerfile @@ -0,0 +1,30 @@ +FROM rocker/geospatial:3.4.4 +LABEL maintainer="o2r project " + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + libapparmor-dev + +RUN ["install2.r", "futile.logger"] + +RUN echo 'old <- getOption("defaultPackages");\n \ +options(defaultPackages = c(old, "containerit"));\n \ +.First <- function() {\n \ + level <- Sys.getenv(x = "CONTAINERIT_FLOG_THRESHOLD", unset = "INFO", names = NA)\n \ + library(futile.logger)\n \ + futile.logger::flog.threshold(level, name = "containerit")\n \ +}\n \ +.Last <- function() {\n \ + if(!as.logical(Sys.getenv(x = "CONTAINERIT_SILENT", unset = "FALSE", names = NA))) {\n \ + cat("\n"); print(sessionInfo());\n \ + cat("\n"); print(options()$repos);\n \ + }\n \ +}' >> /usr/local/lib/R/etc/Rprofile.site + +WORKDIR /containerit +COPY . /containerit + +# use devtools instead of installGithub.r to take advantage of "Remotes" defined in DESCRIPTION file +RUN ["R", "--vanilla", "-e", "devtools::install()"] + +CMD ["R"] diff --git a/man/dockerfile.Rd b/man/dockerfile.Rd index a0fab19..0935c9d 100644 --- a/man/dockerfile.Rd +++ b/man/dockerfile.Rd @@ -11,7 +11,7 @@ dockerfile(from = utils::sessionInfo(), utils::packageVersion("containerit"))), soft = FALSE, offline = FALSE, copy = NA, container_workdir = "/payload/", cmd = Cmd("R"), entrypoint = NULL, add_self = FALSE, vanilla = TRUE, silent = FALSE, - versioned_libs = FALSE, versioned_packages = FALSE) + predetect = TRUE, versioned_libs = FALSE, versioned_packages = FALSE) } \arguments{ \item{from}{The source of the information to construct the Dockerfile. Can be a \code{sessionInfo} object, a path to a file, or the path to a workspace). If \code{NULL} then no automatic derivation of dependencies happens.} @@ -45,6 +45,8 @@ By default, the image is determinded from the given session. Alternatively, use \item{silent}{Whether or not to print information during execution} +\item{predetect}{Extract the required libraries based on \code{library} calls using the package \code{automagic} before running a script/document} + \item{versioned_libs}{[EXPERIMENTAL] Whether it shall be attempted to match versions of linked external libraries} \item{versioned_packages}{[EXPERIMENTAL] Whether it shall be attempted to match versions of R packages} diff --git a/tests/testthat/package_markdown/spacetime/Dockerfile b/tests/testthat/package_markdown/spacetime/Dockerfile new file mode 100644 index 0000000..325c4e9 --- /dev/null +++ b/tests/testthat/package_markdown/spacetime/Dockerfile @@ -0,0 +1,12 @@ +FROM rocker/r-ver:3.4.4 +LABEL maintainer="o2r" +RUN export DEBIAN_FRONTEND=noninteractive; apt-get -y update \ + && apt-get install -y gdal-bin \ + git-core \ + libgdal-dev \ + libproj-dev \ + pandoc \ + pandoc-citeproc +RUN ["install2.r", "abind", "ade4", "adehabitatLT", "adehabitatMA", "backports", "bdsmatrix", "bitops", "boot", "caTools", "CircStats", "cshapes", "deldir", "digest", "diveMove", "DoseFinding", "evaluate", "FNN", "foreign", "Formula", "geosphere", "goftest", "gstat", "htmltools", "intervals", "KernSmooth", "knitr", "lattice", "lmtest", "magrittr", "mapdata", "maps", "maptools", "MASS", "Matrix", "MatrixModels", "maxLik", "mgcv", "miscTools", "mvtnorm", "nlme", "plm", "plyr", "polyclip", "quadprog", "quantreg", "raster", "RColorBrewer", "Rcpp", "rgdal", "rmarkdown", "rpart", "rprojroot", "sandwich", "SEL", "sp", "spacetime", "SparseM", "spatstat", "spatstat.data", "spatstat.utils", "stringi", "stringr", "tensor", "trip", "uniReg", "xts", "yaml", "zoo"] +WORKDIR /payload/ +CMD ["R"] diff --git a/tests/testthat/package_markdown/spacetime/main.Rmd b/tests/testthat/package_markdown/spacetime/main.Rmd new file mode 100644 index 0000000..582609e --- /dev/null +++ b/tests/testthat/package_markdown/spacetime/main.Rmd @@ -0,0 +1,107 @@ +--- +title: 'spacetime: Spatio-Temporal Data in R' +author: + - affiliation: University of Muenster, Institute for Geoiformatics, 52North + email: edzer.pebesma@uni-muenster.de + name: Edzer Pebesma + url: http://ifgi.uni-muenster.de/ +date: "13 November 2013" +abstract: | + This document describes classes and methods designed to deal with different types of spatio-temporal data in \proglang{R} implemented in the \proglang{R} package \pkg{spacetime}, and provides examples for analyzing them. It builds upon the classes and methods for spatial data from package \pkg{sp}, and for time series data from package \pkg{xts}. The goal is to cover a number of useful representations for spatio-temporal sensor data, and results from predicting (spatial and/or temporal interpolation or smoothing), aggregating, or subsetting them, and to represent trajectories. The goals of this paper are to explore how spatio-temporal data can be sensibly represented in classes, and to find out which analysis and visualisation methods are useful and feasible. We discuss the time series convention of representing time intervals by their starting time only. This vignette is the main reference for the \proglang{R} package \code{spacetime}; it has been published as Pebesma (2012), but is kept up-to-date with the software. +output: html_document +--- + +**This file only contains the library and file loading/saving statements of the spacetime vignette.** +This probably works on a developer system, but does not work in a plain `rocker/geospatial`-based container. + +``` +daniel@gin-nuest:~/git/o2r/containerit/tests/testthat/package_markdown/spacetime$ docker run --rm -it -v $(pwd):/erc o2rproject/containerit:geospatial + +R version 3.4.3 [[...] + +> dockerfile(from = "/erc") +INFO [2018-03-23 10:15:11] Found file for packaging in workspace: /erc/main.Rmd +INFO [2018-03-23 10:15:11] Processing the given file d locally using rmarkdown::render(...) +INFO [2018-03-23 10:15:11] Creating an R session with the following arguments: + R --silent --vanilla -e "rmarkdown::render(\"/erc/main.Rmd\")" -e "info <- sessionInfo()" -e "save(list = \"info\", file = \"/tmp/RtmpKdYYco/rdata-sessioninfo125c083b0\")" +> rmarkdown::render("/erc/main.Rmd") + + +processing file: main.Rmd + |................ | 25% + ordinary text without R code + + |................................ | 50% +label: manual_install + |................................................. | 75% + ordinary text without R code + + |.................................................................| 100% +label: libraries_and_data +Quitting from lines 27-73 (main.Rmd) +Error in library("plm") : there is no package called 'plm' +Calls: ... withCallingHandlers -> withVisible -> eval -> eval -> library + +Execution halted +Error in obtain_localSessionInfo(rmd_file = file, vanilla = vanilla, slave = silent, : + Failed to execute the script locally! A sessionInfo could not be determined. +> +``` + +```{r manual_install} +#install.packages(c("diveMove", "trip", "adehabitatLT", "plm", "cshapes")) +#if (!require("plm")) install.packages("plm", repos = "http://cloud.r-project.org") +#if (!require("diveMove")) install.packages("diveMove", repos = "http://cloud.r-project.org") +#if (!require("trip")) install.packages("trip", repos = "http://cloud.r-project.org") +#if (!require("adehabitatLT")) install.packages("adehabitatLT", repos = "http://cloud.r-project.org") +#if (!require("cshapes")) install.packages("cshapes", repos = "http://cloud.r-project.org") +``` + +```{r libraries_and_data} +library("foreign") +read.dbf(system.file("shapes/sids.dbf", package = "maptools")) + +library("plm") +data("Produc", package = "plm") +#write.csv(Produc[1:5,1:9], "producSubset.csv") +#read.csv("producSubset.csv") +#read.csv("windSubset.csv") + +library("sp") +library("spacetime") + +library("gstat") +data("wind") + +library("mapdata") + +library("rgdal") + +library("lattice") +library("RColorBrewer") + +library(xts) + +library("maptools") +fname = system.file("shapes/sids.shp", package = "maptools")[1] +nc = readShapePoly(fname, proj4string = CRS("+proj=longlat +datum=NAD27")) + +library("maps") +library("maptools") + +data("Produc") +library("RColorBrewer") + +library("maptools") + +library("lattice") +library("RColorBrewer") + +library("diveMove") +library("trip") + +library("adehabitatLT") +data("puechabonsp") + +library("cshapes") +``` diff --git a/tests/testthat/test_package_markdown.R b/tests/testthat/test_package_markdown.R index 91fca85..2e47c95 100644 --- a/tests/testthat/test_package_markdown.R +++ b/tests/testthat/test_package_markdown.R @@ -79,3 +79,17 @@ test_that("File copying can be disabled with NULL", { df_copy <- dockerfile(from = "package_markdown/units/", copy = NULL) expect_false(object = any(sapply(df_copy@instructions, function(x) { inherits(x, "Copy") })), info = "no Copy instruction") }) + +test_that("Packaging fails if dependency is missing in the base image and predetection is disabled", { + remove.packages(pkgs = c("plm")) + expect_failure(dockerfile(from = "package_markdown/spacetime/", predetect = FALSE), "Failed to execute") +}) + +test_that("Packaging works if dependency is missing in the base image and predetection is enabled", { + remove.packages(pkgs = c("plm")) + df <- dockerfile(from = "package_markdown/spacetime/", maintainer = "o2r", predetect = TRUE) + expected_file <- readLines("package_markdown/spacetime/Dockerfile") + generated_file <- unlist(stringr::str_split(toString(df),"\n")) + expect_equal(generated_file, expected_file) + expect_true(object = any(grepl("\"plm\"", x = toString(df))), info = "Packages missing in the base image are detected") +}) diff --git a/vignettes/container.Rmd b/vignettes/container.Rmd index b4a4cee..96b3092 100644 --- a/vignettes/container.Rmd +++ b/vignettes/container.Rmd @@ -75,3 +75,18 @@ docker run --rm -v /tmp/containerit:/data o2rproject/containerit R -q -e "setwd( cat /tmp/containerit/Dockerfile rm -r /tmp/containerit ``` + +## Build image + +With the following commands you can build an image from the local source code. +The following command executed in the `containerit` source directory creates an image `containerit`: + +```{bash, eval=TRUE} +docker build --file inst/docker/local/Dockerfile --tag containerit . +``` + +You can try the `predetect` feature by packaging the R Markdown file of the spacetime vignette: + +``` +docker run --rm -it -v $(pwd)/tests/testthat/package_markdown/spacetime:/erc -e CONTAINERIT_FLOG_THRESHOLD=DEBUG containerit R -e "setwd('/erc'); print(dockerfile(from = '/erc'))" +```