Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Moresteps #124

Merged
merged 6 commits into from
Apr 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ export(resolve)
importFrom(memoise,memoise)
importFrom(pkgsearch,cran_package_history)
importFrom(remotes,system_requirements)
importFrom(utils,download.file)
3 changes: 3 additions & 0 deletions R/cache.R
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#' @importFrom utils download.file
NULL

.query_mirror_validity <- function(mirror) {
if (mirror == "https://cran.r-project.org/") {
return(TRUE)
Expand Down
17 changes: 11 additions & 6 deletions R/dockerfile.R
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
dockerfile_content
}

.generate_debian_eol_dockerfile_content <- function(r_version, lib, sysreqs_cmd, cache, debian_version = "lenny") {
.generate_debian_eol_dockerfile_content <- function(r_version, lib, sysreqs_cmd, cache, debian_version = "lenny",
post_installation_steps = NULL) {
dockerfile_content <- list(
FROM = c(paste0("FROM debian/eol:", debian_version)),
chores = c("ENV TZ UTC",
Expand All @@ -28,32 +29,36 @@
c("COPY cache/rpkgs ./cache/rpkgs", "COPY cache/rsrc ./cache/rsrc"))
dockerfile_content$FROM <- c("FROM scratch", "ADD cache/debian/rootfs.tar.xz /")
}
dockerfile_content$RUN <- append(dockerfile_content$RUN, post_installation_steps)
return(dockerfile_content)
}

.generate_rocker_dockerfile_content <- function(r_version, lib, sysreqs_cmd, cache, image) {
.generate_rocker_dockerfile_content <- function(r_version, lib, sysreqs_cmd, cache, image,
post_installation_steps = NULL) {
dockerfile_content <- list(
FROM = c(paste0("FROM rocker/", image, ":", r_version)),
chores = NULL,
COPY = c("COPY rang.R ./rang.R"),
RUN = c(paste("RUN", sysreqs_cmd)),
"CMD [\"R\"]")
CMD = c("CMD [\"R\"]"))
if (!is.na(lib)) {
dockerfile_content$RUN <- append(dockerfile_content$RUN, paste0("RUN mkdir ", lib, " && Rscript rang.R"))
} else {
dockerfile_content$RUN <- append(dockerfile_content$RUN, "Rscript rang.R")
dockerfile_content$RUN <- append(dockerfile_content$RUN, "RUN Rscript rang.R")
}
if (isTRUE(cache)) {
dockerfile_content$COPY <- append(dockerfile_content$COPY, "COPY cache ./cache")
}
if (image == "rstudio") {
dockerfile_content$RUN <- c("EXPOSE 8787", "CMD [\"/init\"]")
dockerfile_content$CMD <- c("EXPOSE 8787", "CMD [\"/init\"]")
}
dockerfile_content$RUN <- append(dockerfile_content$RUN, post_installation_steps)
return(dockerfile_content)
}

.write_dockerfile <- function(dockerfile_content, path) {
content <- c(dockerfile_content$FROM, dockerfile_content$chores,
dockerfile_content$COPY, dockerfile_content$RUN)
dockerfile_content$COPY, dockerfile_content$RUN,
dockerfile_content$CMD)
writeLines(content, path)
}
18 changes: 14 additions & 4 deletions R/installation.R
Original file line number Diff line number Diff line change
Expand Up @@ -274,12 +274,13 @@ export_renv <- function(rang, path = ".") {
#' For R version < 3.1.0, the Dockerfile is based on Debian and it compiles R from source.
#' @param output_dir character, where to put the Docker file and associated content
#' @param materials_dir character, path to the directory containing additional resources (e.g. analysis scripts) to be copied into `output_dir` and in turn into the Docker container
#' @param post_installation_steps character, additional steps to be added before the `CMD` part of the Dockerfile, see an example below
#' @param image character, which versioned Rocker image to use. Can only be "r-ver", "rstudio", "tidyverse", "verse", "geospatial"
#' This applies only to R version >= 3.1
#' @param cache logical, whether to cache the packages now. Please note that the system requirements are not cached. For query with non-CRAN packages, this option is strongly recommended. For query with local packages, this must be TRUE regardless of R version. For R version < 3.1, this must be also TRUE if there is any non-CRAN packages.
#' @param no_rocker logical, whether to skip using Rocker images even when an appropriate version is available. Please keep this as `TRUE` unless you know what you are doing
#' @param debian_version when Rocker images are not used, which EOL version of Debian to use. Can only be "lenny", "etch", "squeeze", "wheezy", "jessie", "stretch". Please keep this as default "lenny" unless you know what you are doing
#' @param skip_r17 logical, whether to skip R 1.7.x. Currently, it is not possible to compile R 1.7.x (R 1.7.0 and R 1.7.1) with the method provided by `rang`. It affects `snapshot_date` from 2003-04-16 to 2003-10-07. When `skip_r17` is TRUE and `snapshot_date` is within the aforementioned range, R 1.8.0 is used instead.
#' @param skip_r17 logical, whether to skip R 1.7.x. Currently, it is not possible to compile R 1.7.x (R 1.7.0 and R 1.7.1) with the method provided by `rang`. It affects `snapshot_date` from 2003-04-16 to 2003-10-07. When `skip_r17` is TRUE and `snapshot_date` is within the aforementioned range, R 1.8.0 is used instead
#' @param ... arguments to be passed to `dockerize`
#' @return `output_dir`, invisibly
#' @inheritParams export_rang
Expand All @@ -294,10 +295,17 @@ export_renv <- function(rang, path = ".") {
#' graph <- resolve(pkgs = c("openNLP", "LDAvis", "topicmodels", "quanteda"),
#' snapshot_date = "2020-01-16")
#' dockerize(graph, ".")
#' ## An example of using post_installation_steps to install quarto
#' install_quarto <- c("RUN apt-get install -y curl git && \\
#' curl -LO https://quarto.org/download/latest/quarto-linux-amd64.deb && \\
#' dpkg -i quarto-linux-amd64.deb && \\
#' quarto install tool tinytex")
#' dockerize(graph, ".", post_installation_steps = install_quarto)
#' }
#' }
#' @export
dockerize <- function(rang, output_dir, materials_dir = NULL, image = c("r-ver", "rstudio", "tidyverse", "verse", "geospatial"),
dockerize <- function(rang, output_dir, materials_dir = NULL, post_installation_steps = NULL,
image = c("r-ver", "rstudio", "tidyverse", "verse", "geospatial"),
rang_as_comment = TRUE, cache = FALSE, verbose = TRUE, lib = NA,
cran_mirror = "https://cran.r-project.org/", check_cran_mirror = TRUE,
bioc_mirror = "https://bioconductor.org/packages/",
Expand Down Expand Up @@ -353,7 +361,8 @@ dockerize <- function(rang, output_dir, materials_dir = NULL, image = c("r-ver",
dockerfile_content <- .generate_debian_eol_dockerfile_content(r_version = r_version,
sysreqs_cmd = sysreqs_cmd, lib = lib,
cache = cache,
debian_version = debian_version)
debian_version = debian_version,
post_installation_steps = post_installation_steps)
if (isTRUE(cache)) {
.cache_rsrc(r_version = r_version, output_dir = output_dir,
verbose = verbose)
Expand All @@ -363,7 +372,8 @@ dockerize <- function(rang, output_dir, materials_dir = NULL, image = c("r-ver",
} else {
dockerfile_content <- .generate_rocker_dockerfile_content(r_version = r_version,
sysreqs_cmd = sysreqs_cmd, lib = lib,
cache = cache, image = image)
cache = cache, image = image,
post_installation_steps = post_installation_steps)
}
if (!(is.null(materials_dir))) {
materials_subdir_in_output_dir <- file.path(output_dir, "materials")
Expand Down
11 changes: 10 additions & 1 deletion man/dockerize.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 26 additions & 1 deletion tests/testthat/test_dockerize.R
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ test_that("integration of #16 in dockerize()", {
dockerize(rang = rang_ok, output_dir = temp_dir, verbose = FALSE)
x <- readLines(file.path(temp_dir, "rang.R"))
expect_true(any(grepl("^verbose <- FALSE", x)))
Dockerfile <- readLines(file.path(temp_dir, "Dockerfile"))
expect_true(any(grepl("^RUN Rscript rang\\.R", Dockerfile)))
## lib
dockerize(rang = rang_ok, output_dir = temp_dir) ## lib = NA
x <- readLines(file.path(temp_dir, "rang.R"))
Expand All @@ -47,6 +49,13 @@ test_that("integration of #16 in dockerize()", {
expect_true(any(grepl("^lib <- \"abc\"", x)))
Dockerfile <- readLines(file.path(temp_dir, "Dockerfile"))
expect_true(any(grepl("^RUN mkdir", Dockerfile)))
expect_false(any(grepl("^RUN Rscript rang\\.R", Dockerfile)))
## #123
expect_equal(tail(Dockerfile, 1), "CMD [\"R\"]")
## post
dockerize(rang = rang_ok, output_dir = temp_dir, post_installation_steps = "RUN date")
Dockerfile <- readLines(file.path(temp_dir, "Dockerfile"))
expect_equal(Dockerfile[length(Dockerfile) -1], "RUN date")
})

test_that("integration of #18 in dockerize()", {
Expand Down Expand Up @@ -95,10 +104,15 @@ test_that("Dockerize R < 3.1 and >= 2.1", {
expect_true(file.exists(file.path(temp_dir, "compile_r.sh")))
Dockerfile <- readLines(file.path(temp_dir, "Dockerfile"))
expect_true(any(grepl("^RUN bash compile_r.sh 3.0.1", Dockerfile)))
expect_equal(tail(Dockerfile, 1), "CMD [\"R\"]")
## lib
dockerize(rang_rio, output_dir = temp_dir, lib = "abc")
Dockerfile <- readLines(file.path(temp_dir, "Dockerfile"))
expect_true(any(grepl("^RUN mkdir", Dockerfile)))
expect_equal(tail(Dockerfile, 1), "CMD [\"R\"]")
dockerize(rang_rio, output_dir = temp_dir, lib = "abc", post_installation_step = "RUN date")
Dockerfile <- readLines(file.path(temp_dir, "Dockerfile"))
expect_equal(Dockerfile[length(Dockerfile) -1], "RUN date")
})

test_that("Docker R < 1.3.1", {
Expand Down Expand Up @@ -162,7 +176,9 @@ test_that("material_dir, existing, no subdir, #23", {
dockerize(graph, output_dir = temp_dir, materials_dir = fake_material_dir)
expect_true(dir.exists(file.path(temp_dir, "materials")))
expect_equal(list.files(file.path(temp_dir, "materials")), character(0))
expect_true(any(readLines(file.path(temp_dir, "Dockerfile")) == "COPY materials/ ./materials/"))
Dockerfile <- readLines(file.path(temp_dir, "Dockerfile"))
expect_true(any(Dockerfile == "COPY materials/ ./materials/"))
expect_equal(tail(Dockerfile, 1), "CMD [\"R\"]")
## Will only test post 3.1.0 from now on
## some files in fake_material_dir
temp_dir <- .generate_temp_dir()
Expand Down Expand Up @@ -212,6 +228,15 @@ test_that("readme issue #50", {
expect_true(any(grepl(temp_dir, content)))
})

test_that("#123 rstudio", {
graph <- readRDS("../testdata/graph.RDS")
temp_dir <- .generate_temp_dir()
dockerize(graph, output_dir = temp_dir, image = "rstudio")
dockerfile <- readLines(file.path(temp_dir, "Dockerfile"))
expect_true("EXPOSE 8787" %in% dockerfile)
expect_equal(tail(dockerfile, 1), "CMD [\"/init\"]")
})

test_that("dockerize with bioc #58", {
rang_bioc <- readRDS("../testdata/rang_bioc.RDS")
temp_dir <- .generate_temp_dir()
Expand Down