Skip to content
Open
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
82 changes: 18 additions & 64 deletions .github/workflows/R-CMD-check.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
on:
push:
branches:
- master
- test-ci
branches: [main, master]
pull_request:
branches:
- master
branches: [main, master]

name: R-CMD-check

Expand All @@ -19,74 +17,30 @@ jobs:
fail-fast: false
matrix:
config:
# - {os: windows-latest, r: 'release', port: '8786', url: 'http://127.0.0.1'}
# - {os: macOS-latest, r: 'release', port: '8787', url: 'localhost'}
- {os: ubuntu-18.04, r: 'release', rspm: "https://packagemanager.rstudio.com/cran/__linux__/bionic/latest", port: '8787', url: 'localhost'}
- {os: ubuntu-18.04, r: 'devel', rspm: "https://packagemanager.rstudio.com/cran/__linux__/bionic/latest", port: '8789', url: 'localhost'}
- {os: ubuntu-latest, r: 'release'}

env:
R_REMOTES_NO_ERRORS_FROM_WARNINGS: true
RSPM: ${{ matrix.config.rspm }}
PORT: ${{ matrix.config.port }}
URL: ${{ matrix.config.url }}
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
R_KEEP_PKG_SOURCE: yes

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4

# In this step, this action saves a list of existing images,
# the cache is created without them in the post run.
# It also restores the cache if it exists.
- uses: satackey/action-docker-layer-caching@v0.0.8
# Ignore the failure of a step and avoid terminating the job.
continue-on-error: true
- uses: r-lib/actions/setup-pandoc@v2

- uses: r-lib/actions/setup-r@master
- uses: r-lib/actions/setup-r@v2
with:
r-version: ${{ matrix.config.r }}
use-public-rspm: true

- uses: r-lib/actions/setup-pandoc@master

- name: Query dependencies
run: |
install.packages('remotes')
saveRDS(remotes::dev_package_deps(dependencies = TRUE), ".github/depends.Rds", version = 2)
writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version")
shell: Rscript {0}

- name: Cache R packages
if: runner.os != 'Windows'
uses: actions/cache@v1
- uses: r-lib/actions/setup-r-dependencies@v2
with:
path: ${{ env.R_LIBS_USER }}
key: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-${{ hashFiles('.github/depends.Rds') }}
restore-keys: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-

- name: Install system dependencies
if: runner.os == 'Linux'
run: |
while read -r cmd
do
eval sudo $cmd
done < <(Rscript -e 'cat(remotes::system_requirements("ubuntu", "18.04"), sep = "\n")')

- name: Install dependencies
run: |
remotes::install_deps(dependencies = TRUE)
remotes::install_cran("rcmdcheck")
remotes::install_cran("devtools")
shell: Rscript {0}

- name: Check
env:
_R_CHECK_CRAN_INCOMING_REMOTE_: false
run: |
devtools::test()
rcmdcheck::rcmdcheck(args = c("--no-manual", "--as-cran"), error_on = "warning", check_dir = "check")
shell: Rscript {0}
extra-packages: any::rcmdcheck
needs: check

- name: Upload check results
if: failure()
uses: actions/upload-artifact@main
- uses: r-lib/actions/check-r-package@v2
with:
name: ${{ runner.os }}-r${{ matrix.config.r }}-results
path: check
upload-snapshots: true
args: 'c("--no-manual", "--as-cran", "--no-vignettes")'
build_args: 'c("--no-manual", "--no-build-vignettes")'
error-on: '"error"'
8 changes: 4 additions & 4 deletions .github/workflows/pkgdown.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ jobs:
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4

- uses: r-lib/actions/setup-r@v1
- uses: r-lib/actions/setup-r@v2

- uses: r-lib/actions/setup-pandoc@v1
- uses: r-lib/actions/setup-pandoc@v2

- name: Query dependencies
run: |
Expand All @@ -26,7 +26,7 @@ jobs:
shell: Rscript {0}

- name: Cache R packages
uses: actions/cache@v2
uses: actions/cache@v4
with:
path: ${{ env.R_LIBS_USER }}
key: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-${{ hashFiles('.github/depends.Rds') }}
Expand Down
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@ VignetteBuilder:
Encoding: UTF-8
LazyData: true
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.1.1
RoxygenNote: 7.3.3
SystemRequirements: Docker
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Generated by roxygen2: do not edit by hand

export(build_volume_arg)
export(launch_proj_docker)
export(stop_proj_docker)
export(update_renv_help)
Expand Down
53 changes: 46 additions & 7 deletions R/launch-stop-docker.R
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
#' @param url Localhost url. Default to "http://127.0.0.1". "localhost" can be a good alternative.
#' @param password String. Default to NULL. If not NULL, `password` will be used as a password to open RStudio server.
#' Useful in case you're using `{devindocker}` on a remote server.
#' @param mount_mode Optional bind-mount consistency mode passed to every `-v`
#' flag in the `docker run` command. Recommended values on macOS are
#' `"delegated"` (best for high-I/O volumes such as the renv cache and the
#' RStudio config directory) or `"cached"`. Defaults to `NULL` (no mode
#' suffix), which matches the behaviour before this option was introduced.
#'
#' @importFrom utils browseURL
#'
Expand Down Expand Up @@ -78,7 +83,8 @@ launch_proj_docker <- function(path = ".",
volumes,
open_url = TRUE,
url = "http://127.0.0.1",
password = NULL
password = NULL,
mount_mode = NULL
# vbox = FALSE
) {
# @param vbox Logical. If Docker run on windows in a virtual box, paths need to be changed
Expand All @@ -97,7 +103,7 @@ launch_proj_docker <- function(path = ".",
volumes[,"local"] <- normalizePath(as.character(volumes[,"local"]))

add_volumes <- paste(
apply(volumes, 1, function(x) paste0(" -v '", x["local"], ":", x["docker"], "'")),
apply(volumes, 1, function(x) build_volume_arg(x["local"], x["docker"], mode = mount_mode)),
collapse = ""
)
} else {
Expand Down Expand Up @@ -220,15 +226,15 @@ launch_proj_docker <- function(path = ".",
# {renv}
# _Global renv cache
ifelse(!is.null(renv_cache), paste0(" -e RENV_PATHS_CACHE=", RENV_PATHS_CACHE_CONTAINER), ""),
ifelse(!is.null(renv_cache), paste0(" -v ", RENV_PATHS_CACHE_HOST, ":", RENV_PATHS_CACHE_CONTAINER), ""),
ifelse(!is.null(renv_cache), build_volume_arg(RENV_PATHS_CACHE_HOST, RENV_PATHS_CACHE_CONTAINER, mode = mount_mode), ""),
# _Project renv library
ifelse(isTRUE(renv_out), paste0(" -e RENV_PATHS_LIBRARY_ROOT=", RENV_PATHS_LIBRARY_ROOT_CONTAINER), ""),
ifelse(isTRUE(renv_out), paste0(" -v ", RENV_PATHS_LIBRARY_ROOT_HOST, ":", RENV_PATHS_LIBRARY_ROOT_CONTAINER), ""),
ifelse(isTRUE(renv_out), build_volume_arg(RENV_PATHS_LIBRARY_ROOT_HOST, RENV_PATHS_LIBRARY_ROOT_CONTAINER, mode = mount_mode), ""),

# Rstudio server
" -v '", path, ":/home/rstudio/", projectname, "'",
" -v '", normalizePath(file.path(path, "rstudio_dotconfig"), mustWork = TRUE), ":/home/rstudio/.config'", #/rstudio
" -v '", normalizePath(file.path(path, "rstudio_dotrstudio"), mustWork = TRUE), ":/home/rstudio/.rstudio'",
build_volume_arg(path, paste0("/home/rstudio/", projectname), mode = mount_mode),
build_volume_arg(normalizePath(file.path(path, "rstudio_dotconfig"), mustWork = TRUE), "/home/rstudio/.config", mode = mount_mode),
build_volume_arg(normalizePath(file.path(path, "rstudio_dotrstudio"), mustWork = TRUE), "/home/rstudio/.rstudio", mode = mount_mode),

# Addtional volumes
ifelse(!is.null(add_volumes), add_volumes, ""),
Expand Down Expand Up @@ -297,3 +303,36 @@ clean_project_name <- function(x) {
clean_dir_name <- function(x) {
gsub(" ", "\\", x)
}

#' Render a docker `-v` volume argument, optionally with a mount mode
#'
#' On macOS, high-I/O bind mounts (e.g. the renv cache or RStudio's config
#' directory) benefit from the `delegated` or `cached` consistency mode to
#' reduce FS latency. This helper is used by [launch_proj_docker()] to build
#' every `-v` flag.
#'
#' @param local host path to mount.
#' @param container container mount point.
#' @param mode one of `NULL` / `NA` (no mode suffix), `"delegated"`,
#' `"cached"` or `"consistent"`. See
#' <https://docs.docker.com/engine/storage/bind-mounts/> for details.
#'
#' @return a single string like `" -v '/host:/container[:mode]'"`, including
#' a leading space so the result can be concatenated into the `docker run`
#' command as-is.
#' @export
build_volume_arg <- function(local, container, mode = NULL) {
if (!is.null(mode) && !is.na(mode)) {
allowed <- c("delegated", "cached", "consistent")
if (!mode %in% allowed) {
stop(
"`mode` must be one of: ", paste(allowed, collapse = ", "),
" (got '", mode, "')",
call. = FALSE
)
}
sprintf(" -v '%s:%s:%s'", local, container, mode)
} else {
sprintf(" -v '%s:%s'", local, container)
}
}
28 changes: 28 additions & 0 deletions man/build_volume_arg.Rd

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

10 changes: 9 additions & 1 deletion man/devindocker-package.Rd

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

9 changes: 8 additions & 1 deletion man/launch_proj_docker.Rd

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

39 changes: 39 additions & 0 deletions tests/testthat/test-build_volume_arg.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
testthat::context("build_volume_arg (#9)")

test_that("build_volume_arg renders a plain -v pair", {
testthat::expect_equal(
build_volume_arg("/host/path", "/container/path"),
" -v '/host/path:/container/path'"
)
})

test_that("build_volume_arg appends :delegated when requested (#9)", {
testthat::expect_equal(
build_volume_arg("/host", "/container", mode = "delegated"),
" -v '/host:/container:delegated'"
)
})

test_that("build_volume_arg accepts :cached and :consistent", {
testthat::expect_equal(
build_volume_arg("/a", "/b", mode = "cached"),
" -v '/a:/b:cached'"
)
testthat::expect_equal(
build_volume_arg("/a", "/b", mode = "consistent"),
" -v '/a:/b:consistent'"
)
})

test_that("build_volume_arg rejects unknown modes", {
testthat::expect_error(
build_volume_arg("/a", "/b", mode = "bogus"),
"mode"
)
})

test_that("NULL / NA mode is equivalent to omitting the mode", {
plain <- build_volume_arg("/a", "/b")
testthat::expect_equal(build_volume_arg("/a", "/b", mode = NULL), plain)
testthat::expect_equal(build_volume_arg("/a", "/b", mode = NA), plain)
})
Loading