diff --git a/.gitignore b/.gitignore index ccc32c58..be393dce 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ docs inst/doc dev !dev/Makefile +!dev/extract_irods_services_yaml.R *.irods /doc/ /Meta/ diff --git a/DESCRIPTION b/DESCRIPTION index faa5ea1b..1581c7c6 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -33,7 +33,8 @@ Imports: stats, testthat (>= 3.0.0), utils, - withr + withr, + yaml Suggests: httptest2, kableExtra, diff --git a/R/docker-yaml.R b/R/docker-yaml.R new file mode 100644 index 00000000..12d70827 --- /dev/null +++ b/R/docker-yaml.R @@ -0,0 +1,26 @@ +get_docker_compose_path <- function() { + system.file("irods_demo/docker-compose.yml", package = "rirods") +} + +get_docker_yaml <- function() { + docker_compose_file <- yaml::read_yaml(get_docker_compose_path(), handlers = list( + # make sure that sequences of size one are read as list + # (defaults to vector of length one) + seq = function(x) { + x <- as.list(x) + x + } + )) +} + +is_irods_service_in_yaml <- function(services, docker_compose_file) { + docker_compose_service_names <- names(docker_compose_file[["services"]]) + irods_services_pattern <- paste0(services, collapse = "|") + grepl(irods_services_pattern, docker_compose_service_names) +} + +extract_irods_services_names <- function(services) { + docker_compose_file <- get_docker_yaml() + list(names(docker_compose_file[["services"]])[is_irods_service_in_yaml(services, docker_compose_file)]) |> + setNames(docker_compose_file[["name"]]) +} diff --git a/R/irods-demo.R b/R/irods-demo.R index a78bd4b6..ac790df4 100644 --- a/R/irods-demo.R +++ b/R/irods-demo.R @@ -68,7 +68,7 @@ use_irods_demo <- function(user = character(), pass = character(), if (length(user) != 0 && length(pass) != 0) { system2( system.file(package = "rirods", "shell_scripts", "iadmin-docker-icommand.sh"), - Map(shQuote, c(user, pass)), + append(system.file("irods_demo", package = "rirods"), Map(shQuote, c(user, pass))), stdout = FALSE, stderr = FALSE ) @@ -118,17 +118,15 @@ stop_irods_demo <- function(verbose = TRUE) { #' @examples #' is_irods_demo_running() is_irods_demo_running <- function(...) { - # first check if Docker exist + # first check if Docker exists if (!check_docker(FALSE)) { return(FALSE) } - # then check if images exist + # then check if images exists if (!check_irods_images()) { return(FALSE) } - # check for client-icommand is not required (only needed for demo itself) ref <- irods_containers_ref() - ref <- ref[ref != "irods-demo-irods-client-icommands-1"] irods_containers_state <- vapply(ref, is_irods_demo_running_, integer(1)) @@ -163,9 +161,9 @@ remove_docker_images <- function() { start_irods <- function(verbose, recreate = TRUE) { if (isTRUE(recreate)) { - cmd <- " ; docker compose up -d --force-recreate nginx-reverse-proxy irods-client-http-api irods-client-icommands" + cmd <- " ; docker compose up -d --force-recreate " } else { - cmd <- " ; docker compose up -d nginx-reverse-proxy irods-client-http-api irods-client-icommands" + cmd <- " ; docker compose up -d " } system( paste0("cd ", path_to_demo(), cmd), @@ -192,6 +190,7 @@ dry_run_irods <- function(user, pass, host, lpath, verbose, user_input = FALSE) } if (isTRUE(user_input)) { if (verbose) message("\nRecreating iRODS demo. This may take a while!\n") + stop_irods_demo() start_irods(verbose, recreate = TRUE) } else{ stop("The iRODS server could not be started!", call. = FALSE) @@ -219,6 +218,7 @@ is_http_server_running_correct <- function(user, pass, host, lpath) { is_irods_server_running_correct <- function() { system2( system.file(package = "rirods", "shell_scripts", "dry-run-irods-icommands.sh"), + system.file("irods_demo", package = "rirods"), stdout = FALSE, stderr = FALSE ) == 0 @@ -262,19 +262,16 @@ check_docker <- function(verbose = TRUE) { !(Sys.which("bash") == "" || Sys.which("docker") == "" || docker_version == "") } -irods_containers_ref <- function() { - irods_demo_yml <- system.file("irods_demo", "docker-compose.yml", package = "rirods") - irods_demo_file <- readLines(irods_demo_yml) - irods_images_ref <- grep("^\\s{4}[[:graph:]]*?:$", irods_demo_file) - irods_images <- irods_demo_file[irods_images_ref] - paste0("irods-demo-", trimws(gsub( ":$", "", irods_images)), "-1") +irods_containers_ref <- function(services = c("nginx", "http-api", "icommands", "catalog")) { + docker_compose_service_names = extract_irods_services_names(services) + paste0(names(docker_compose_service_names), "-", docker_compose_service_names[[1]], "-1") } irods_images <- c( "irods-demo-irods-catalog", + "irods-demo-irods-catalog-consumer", "irods-demo-irods-catalog-provider", "irods-demo-irods-client-icommands", - "irods-demo-irods-client-rest-cpp", "irods-demo-nginx-reverse-proxy", "irods/irods_http_api" ) diff --git a/R/zzz.R b/R/zzz.R index 0587342d..5ef93733 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -3,5 +3,5 @@ .onLoad <- function(libname, pkgname) { ns <- topenv() - ns$.irods_host <- "http://localhost:9001/irods-http-api/0.2.0" + ns$.irods_host <- "http://localhost:9001/irods-http-api/0.4.0" } diff --git a/README.Rmd b/README.Rmd index c5ed53c5..1b92482d 100644 --- a/README.Rmd +++ b/README.Rmd @@ -80,7 +80,7 @@ substitute(create_irods(x), list(x = rirods:::.irods_host)) ``` ```{r project, eval=is_irods_demo_running(), echo=FALSE} -eval(substitute(create_irods(x), list(x = rirods:::.irods_host))) +eval(substitute(create_irods(x), list(x = URLencode(rirods:::.irods_host)))) ``` ### Authentication diff --git a/README.md b/README.md index 7509ff9d..50c9b7e4 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Launch a local demonstration iRODS service (including the HTTP API): use_irods_demo("alice", "passWORD") This will result in the demonstration HTTP API running at -. +. These Docker containers are designed to easily stand up a **DEMONSTRATION** of the iRODS server. It is intended for education and @@ -49,7 +49,7 @@ To connect to the HTTP API endpoint of your choice, load `rirods`, connect with `create_irods()`, and authenticate with your iRODS credentials: - create_irods("http://localhost:9001/irods-http-api/0.2.0") + create_irods("http://localhost:9001/irods-http-api/0.4.0") ### Authentication @@ -70,7 +70,6 @@ session to an iRODS collection. For this, use the `isaveRDS()` command: # check where we are in the iRODS namespace ipwd() - #> [1] "/tempZone/home/alice" # store data in iRODS isaveRDS(foo, "foo.rds") @@ -89,12 +88,6 @@ describes the data object “foo”: # check if file is stored with associated metadata ils(metadata = TRUE) - #> - #> ========== - #> iRODS Zone - #> ========== - #> logical_path attribute value units - #> /tempZone/home/alice/foo.rds foo bar baz For more on using metadata, check out `vignette("metadata")`. @@ -105,10 +98,6 @@ current R session, she would use `ireadRDS()`: # retrieve in native R format ireadRDS("foo.rds") - #> x y - #> 1 1 x - #> 2 8 y - #> 3 9 z ### Other file formats @@ -126,13 +115,6 @@ a file type that can be accessed by other programs. For this, use the # check whether it is stored ils() - #> - #> ========== - #> iRODS Zone - #> ========== - #> logical_path - #> /tempZone/home/alice/foo.csv - #> /tempZone/home/alice/foo.rds Later on somebody else might want to download this file again and store it locally: @@ -140,20 +122,6 @@ it locally: # retrieve it again later iget("foo.csv", "foo.csv") read_csv("foo.csv") - #> Rows: 3 Columns: 2 - #> ── Column specification ──────────────────────────────────────────────────────── - #> Delimiter: "," - #> chr (1): y - #> dbl (1): x - #> - #> ℹ Use `spec()` to retrieve the full column specification for this data. - #> ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message. - #> # A tibble: 3 × 2 - #> x y - #> - #> 1 1 x - #> 2 8 y - #> 3 9 z ### Query @@ -163,15 +131,9 @@ future projects. Objects can be searched with General Queries and # look for objects in the home collection with a wildcard `%` iquery("SELECT COLL_NAME, DATA_NAME WHERE COLL_NAME LIKE '/tempZone/home/%'") - #> COLL_NAME DATA_NAME - #> 1 /tempZone/home/alice foo.csv - #> 2 /tempZone/home/alice foo.rds # or for data objects with a name that starts with "foo" iquery("SELECT COLL_NAME, DATA_NAME WHERE DATA_NAME LIKE 'foo%'") - #> COLL_NAME DATA_NAME - #> 1 /tempZone/home/alice foo.csv - #> 2 /tempZone/home/alice foo.rds For more on querying, check out `vignette("metadata")`. @@ -185,7 +147,6 @@ Finally, we can clean up Alice’s home collection: # check if objects are removed ils() - #> This collection does not contain any objects or collections. # close the server stop_irods_demo() diff --git a/dev/Makefile b/dev/Makefile index aff12173..5408bb8a 100644 --- a/dev/Makefile +++ b/dev/Makefile @@ -1,19 +1,19 @@ # prepare for CRAN by removing unneeded irods_demo bagage .ONESHELL: SHELL = /bin/bash -PATH_MODULES := ../inst/irods_demo -DOCKER_MODULES := $(addprefix $(PATH_MODULES)/,irods_client_nfsrods irods_client_zone_management_tool metalnx-db metalnx minio-data) +PATH_MODULES := ../inst/irods_demo/. +IRODS_MODULES := nginx http icommands catalog +SPACE = $(eval) $(eval) +DOCKER_MODULES = $(subst $(SPACE),\|,$(IRODS_MODULES)) +DOCKER_MODULES_REGEX = ".*\($(DOCKER_MODULES)\).*" -all: update remove clean +.PHONY: update clean + +all: update clean -# update modules update: git submodule sync --recursive git submodule update --init --force --recursive --remote -# delete unnecessary docker modules -remove: - rm -rf $(DOCKER_MODULES) -# remove lines docker-compose clean: - head -n 65 '$(PATH_MODULES)/docker-compose.yml' > temp.yml - mv temp.yml '$(PATH_MODULES)/docker-compose.yml' + $(shell find $(PATH_MODULES) -type d ! -regex $(DOCKER_MODULES_REGEX) -exec rm -rf {} +) + Rscript extract_irods_services_yaml.R $(DOCKER_MODULES) diff --git a/dev/extract_irods_services_yaml.R b/dev/extract_irods_services_yaml.R new file mode 100755 index 00000000..5f10cc33 --- /dev/null +++ b/dev/extract_irods_services_yaml.R @@ -0,0 +1,15 @@ +#!/usr/bin/env Rscript --vanilla + +args <- commandArgs(trailingOnly = TRUE) + +devtools::load_all() + +extract_irods_services <- function(services = args[1]) { + new_docker_compose_file <- docker_compose_file <- get_docker_yaml() + grep_services <- is_irods_service_in_yaml(services, docker_compose_file) + new_docker_compose_file[["services"]] <- docker_compose_file[["services"]][grep_services] + yaml::write_yaml(new_docker_compose_file, get_docker_compose_path()) + invisible(NULL) +} + +extract_irods_services() diff --git a/inst/irods_demo b/inst/irods_demo index a30e0263..5e15c903 160000 --- a/inst/irods_demo +++ b/inst/irods_demo @@ -1 +1 @@ -Subproject commit a30e0263d9c45c63ecf0ef8226af954b51ef4551 +Subproject commit 5e15c90313f3291d02a51d2118d189ca90ba16fa diff --git a/inst/shell_scripts/dry-run-irods-icommands.sh b/inst/shell_scripts/dry-run-irods-icommands.sh index cfb68ab6..77276c24 100755 --- a/inst/shell_scripts/dry-run-irods-icommands.sh +++ b/inst/shell_scripts/dry-run-irods-icommands.sh @@ -1,8 +1,7 @@ #!/bin/sh -DIR="$(dirname "$(realpath "$0")")" +DIR=$(realpath $1) cd $DIR -cd ../irods_demo docker exec irods-demo-irods-client-icommands-1 ils diff --git a/inst/shell_scripts/iadmin-docker-icommand.sh b/inst/shell_scripts/iadmin-docker-icommand.sh index 2bc1b1e9..0f46062c 100755 --- a/inst/shell_scripts/iadmin-docker-icommand.sh +++ b/inst/shell_scripts/iadmin-docker-icommand.sh @@ -1,10 +1,7 @@ #!/bin/sh -DIR="$(dirname "$(realpath "$0")")" - -cd $DIR -cd ../irods_demo +DIR=$(realpath $1) docker compose up -d irods-client-icommands -docker exec irods-demo-irods-client-icommands-1 iadmin mkuser "$1" rodsuser -docker exec irods-demo-irods-client-icommands-1 iadmin moduser "$1" password "$2" +docker exec irods-demo-irods-client-icommands-1 iadmin mkuser "$2" rodsuser +docker exec irods-demo-irods-client-icommands-1 iadmin moduser "$2" password "$3" diff --git a/renv.lock b/renv.lock index 4b0a6c50..1547654f 100644 --- a/renv.lock +++ b/renv.lock @@ -1,6 +1,6 @@ { "R": { - "Version": "4.3.3", + "Version": "4.4.1", "Repositories": [ { "Name": "CRAN", @@ -31,17 +31,17 @@ }, "brio": { "Package": "brio", - "Version": "1.1.4", + "Version": "1.1.5", "Source": "Repository", "Repository": "CRAN", "Requirements": [ "R" ], - "Hash": "68bd2b066e1fe780bbf62fc8bcc36de3" + "Hash": "c1ee497a6d999947c2c224ae46799b1a" }, "callr": { "Package": "callr", - "Version": "3.7.5", + "Version": "3.7.6", "Source": "Repository", "Repository": "CRAN", "Requirements": [ @@ -50,22 +50,22 @@ "processx", "utils" ], - "Hash": "9f0e4fae4963ba775a5e5c520838c87b" + "Hash": "d7e13f49c19103ece9e58ad2d83a7354" }, "cli": { "Package": "cli", - "Version": "3.6.2", + "Version": "3.6.3", "Source": "Repository", "Repository": "CRAN", "Requirements": [ "R", "utils" ], - "Hash": "1216ac65ac55ec0058a6f75d7ca0fd52" + "Hash": "b21916dd77a27642b447374a5d30ecf3" }, "crayon": { "Package": "crayon", - "Version": "1.5.2", + "Version": "1.5.3", "Source": "Repository", "Repository": "CRAN", "Requirements": [ @@ -73,17 +73,17 @@ "methods", "utils" ], - "Hash": "e8a1e41acf02548751f45c718d55aa6a" + "Hash": "859d96e65ef198fd43e82b9628d593ef" }, "curl": { "Package": "curl", - "Version": "5.2.1", + "Version": "5.2.2", "Source": "Repository", "Repository": "CRAN", "Requirements": [ "R" ], - "Hash": "411ca2c03b1ce5f548345d2fc2685f7a" + "Hash": "8f27335f2bcff4d6035edcc82d7d46de" }, "desc": { "Package": "desc", @@ -115,25 +115,25 @@ }, "digest": { "Package": "digest", - "Version": "0.6.34", + "Version": "0.6.37", "Source": "Repository", "Repository": "CRAN", "Requirements": [ "R", "utils" ], - "Hash": "7ede2ee9ea8d3edbf1ca84c1e333ad1a" + "Hash": "33698c4b3127fc9f506654607fb73676" }, "evaluate": { "Package": "evaluate", - "Version": "0.23", + "Version": "0.24.0", "Source": "Repository", "Repository": "CRAN", "Requirements": [ "R", "methods" ], - "Hash": "daf4a1246be12c1fa8c7705a0935c1a0" + "Hash": "a1066cbc05caee9a4bf6d90f194ff4da" }, "fansi": { "Package": "fansi", @@ -149,14 +149,14 @@ }, "fs": { "Package": "fs", - "Version": "1.6.3", + "Version": "1.6.4", "Source": "Repository", "Repository": "CRAN", "Requirements": [ "R", "methods" ], - "Hash": "47b5f30c720c23999b913a1a635cf0bb" + "Hash": "15aeb8c27f5ea5161f9f6a641fafd93a" }, "glue": { "Package": "glue", @@ -171,7 +171,7 @@ }, "httr2": { "Package": "httr2", - "Version": "1.0.0", + "Version": "1.0.3", "Source": "Repository", "Repository": "CRAN", "Requirements": [ @@ -188,7 +188,7 @@ "vctrs", "withr" ], - "Hash": "e2b30f1fc039a0bab047dd52bb20ef71" + "Hash": "10d93e97faad6b629301bb3a2fd23378" }, "jsonlite": { "Package": "jsonlite", @@ -225,13 +225,13 @@ }, "openssl": { "Package": "openssl", - "Version": "2.1.1", + "Version": "2.2.1", "Source": "Repository", - "Repository": "RSPM", + "Repository": "CRAN", "Requirements": [ "askpass" ], - "Hash": "2a0dc8c6adfb6f032e4d4af82d258ab5" + "Hash": "c62edf62de70cadf40553e10c739049d" }, "pillar": { "Package": "pillar", @@ -252,7 +252,7 @@ }, "pkgbuild": { "Package": "pkgbuild", - "Version": "1.4.3", + "Version": "1.4.4", "Source": "Repository", "Repository": "CRAN", "Requirements": [ @@ -263,7 +263,7 @@ "desc", "processx" ], - "Hash": "c0143443203205e6a2760ce553dafc24" + "Hash": "a29e8e134a460a01e0ca67a4763c595b" }, "pkgconfig": { "Package": "pkgconfig", @@ -277,24 +277,25 @@ }, "pkgload": { "Package": "pkgload", - "Version": "1.3.4", + "Version": "1.4.0", "Source": "Repository", "Repository": "CRAN", "Requirements": [ "R", "cli", - "crayon", "desc", "fs", "glue", + "lifecycle", "methods", "pkgbuild", + "processx", "rlang", "rprojroot", "utils", "withr" ], - "Hash": "876c618df5ae610be84356d5d7a5d124" + "Hash": "2ec30ffbeec83da57655b850cf2d3e0e" }, "praise": { "Package": "praise", @@ -305,7 +306,7 @@ }, "processx": { "Package": "processx", - "Version": "3.8.3", + "Version": "3.8.4", "Source": "Repository", "Repository": "CRAN", "Requirements": [ @@ -314,18 +315,18 @@ "ps", "utils" ], - "Hash": "82d48b1aec56084d9438dbf98087a7e9" + "Hash": "0c90a7d71988856bad2a2a45dd871bb9" }, "ps": { "Package": "ps", - "Version": "1.7.6", + "Version": "1.7.7", "Source": "Repository", "Repository": "CRAN", "Requirements": [ "R", "utils" ], - "Hash": "dd2b9319ee0656c8acf45c7f40c59de7" + "Hash": "878b467580097e9c383acbb16adab57a" }, "rappdirs": { "Package": "rappdirs", @@ -349,24 +350,24 @@ }, "renv": { "Package": "renv", - "Version": "1.0.5", + "Version": "1.0.7", "Source": "Repository", "Repository": "CRAN", "Requirements": [ "utils" ], - "Hash": "32c3f93e8360f667ca5863272ec8ba6a" + "Hash": "397b7b2a265bc5a7a06852524dabae20" }, "rlang": { "Package": "rlang", - "Version": "1.1.3", + "Version": "1.1.4", "Source": "Repository", "Repository": "CRAN", "Requirements": [ "R", "utils" ], - "Hash": "42548638fae05fd9a9b5f3f437fbbbe2" + "Hash": "3eec01f8b1dee337674b2e34ab1f9bc1" }, "rprojroot": { "Package": "rprojroot", @@ -387,7 +388,7 @@ }, "testthat": { "Package": "testthat", - "Version": "3.2.1", + "Version": "3.2.1.1", "Source": "Repository", "Repository": "CRAN", "Requirements": [ @@ -412,7 +413,7 @@ "waldo", "withr" ], - "Hash": "4767a686ebe986e6cb01d075b3f09729" + "Hash": "3f6e7e5e2220856ff865e4834766bf2b" }, "tibble": { "Package": "tibble", @@ -459,25 +460,24 @@ }, "waldo": { "Package": "waldo", - "Version": "0.5.2", + "Version": "0.5.3", "Source": "Repository", "Repository": "CRAN", "Requirements": [ "R", "cli", "diffobj", - "fansi", "glue", "methods", "rematch2", "rlang", "tibble" ], - "Hash": "c7d3fd6d29ab077cbac8f0e2751449e6" + "Hash": "16aa934a49658677d8041df9017329b9" }, "withr": { "Package": "withr", - "Version": "3.0.0", + "Version": "3.0.1", "Source": "Repository", "Repository": "CRAN", "Requirements": [ @@ -485,7 +485,7 @@ "grDevices", "graphics" ], - "Hash": "d31b6c62c10dcf11ec530ca6b0dd5d35" + "Hash": "07909200e8bbe90426fbfeb73e1e27aa" } } } diff --git a/renv/activate.R b/renv/activate.R index 9b2e7f18..9daa13a3 100644 --- a/renv/activate.R +++ b/renv/activate.R @@ -2,7 +2,7 @@ local({ # the requested version of renv - version <- "1.0.5" + version <- "1.0.7" attr(version, "sha") <- NULL # the project directory diff --git a/tests/testthat/test-docker-yaml.R b/tests/testthat/test-docker-yaml.R new file mode 100644 index 00000000..67048c30 --- /dev/null +++ b/tests/testthat/test-docker-yaml.R @@ -0,0 +1,19 @@ +test_that("docker compose yaml can be found and loaded", { + skip_on_os("windows") + path <- get_docker_compose_path() + expect_equal(path, + system.file("irods_demo/docker-compose.yml", package = "rirods")) + expect_vector(get_docker_yaml()) + expect_equal(any(is_irods_service_in_yaml("nginx", get_docker_yaml())), TRUE) + ref <- list(c( + "irods-catalog", + "irods-catalog-provider", + "irods-catalog-consumer", + "irods-client-icommands", + "irods-client-http-api", + "nginx-reverse-proxy" + )) |> setNames("irods-demo") + expect_equal(extract_irods_services_names(c( + "nginx", "http-api", "icommands", "catalog" + )), ref) +})