From c1bef089806ec6a053a0f4b3d6f8053795d749e5 Mon Sep 17 00:00:00 2001 From: Philipp Baumann Date: Sun, 7 Jan 2024 21:50:16 +0100 Subject: [PATCH 01/16] Boilerplating `rix::init()` --- R/find_rev.R | 91 ++++++++++++++++++++++++++++++++++++++++++ dev/build_envs.Rmd | 99 +++++++++++++++++++++++++++++++++++++++++++++- man/init.Rd | 29 ++++++++++++++ 3 files changed, 218 insertions(+), 1 deletion(-) create mode 100644 man/init.Rd diff --git a/R/find_rev.R b/R/find_rev.R index c794fdee..56d9fdbb 100644 --- a/R/find_rev.R +++ b/R/find_rev.R @@ -724,6 +724,97 @@ nix_build_exit_msg <- function(x) { return(err_msg) } +#' Inititate and maintain an isolated, project-specific R setup via Nix +#' +#' Bootstraps an isolated project folder and adds sensible defaults to +#' achieve reproducibiltiy and isolated software dependencies with highest +#' run-time purity. +#' +#' This general bootstrap helper does a couple of configurations that ensure +#' that the project runs as isolated and pure as possible by default. +#' Since a host RStudio session not launched via nix does not inherit +#' environmental variables from `.zshrc` (on macOS), we need to add the path of +#' the nixpkgs store to the `PATH` variable. +#' +#' @param project_path Character with folder path to the isolated nix-R project. +#' Defaults to `"."`, which is the current path in the working directory. +#' If the folder does not exist yet, it will be created. +#' @param message_type Character. Message type, defaults to `"simple"`, which +#' gives mimimal but sufficient feedback. Other values are currently +#' `"verbose"`, which gives more detailed diagnostics. +#' @export +init <- function(project_path = ".", + message_type = c("simple", "verbose")) { + message_type <- match.arg(message_type) + cat("\n### Initiating isolated, project-specific R setup via Nix ###\n\n") + if (!dir.exists(project_path)) { + dir.create(path = project_path, recursive = TRUE) + project_path <- normalizePath(path = project_path) + cat("==> Created isolated nix-R project folder:\n", project_path, "\n") + } else { + project_path <- normalizePath(path = project_path) + cat("==> Using existing isolated nix-R project folder:\n", project_path, + "\n") + } + # check if RStudio session is running. + is_nixr <- is_nix_rsession() + is_rstudio <- is_rstudio_session() + if (!is_nixr && is_rstudio) { + PATH <- set_nix_path() + cat( + paste0("\n==> Added `.Rprofile` entry for new R sessions in:\n", + project_path), + "\n* Adding the location of the Nix store to `PATH`", + "environmental variable for new R sessions", + "\n\n==> Also adjusting the same path via `Sys.setenv()`, so that system", + "commands can invoke key Nix commands like `nix-build` in this RStudio", + "session on the host operating system.\n" + ) + cat("\n* Current `PATH` variable available in R session is:\n\n") + cat(PATH) + } +} + +#' @noRd +is_nix_rsession <- function() { + is_nixr <- nzchar(Sys.getenv("NIX_STORE")) + if (is_nixr) { + cat("==> R session running via Nix (nixpkgs)") + return(TRUE) + } else { + cat("\n==> R session running via host operating system or docker") + return(FALSE) + } +} + +#' @noRd +is_rstudio_session <- function() { + is_rstudio <- Sys.getenv("RSTUDIO") == "1" + if (is_rstudio) { + cat("\n==> R session running from RStudio\n") + return(TRUE) + } else { + cat("* R session not running from RStudio") + return(FALSE) + } +} + +#' @noRd +set_nix_path <- function() { + old_path <- Sys.getenv("PATH") + nix_path <- "/nix/var/nix/profiles/default/bin" + has_nix_path <- any(grepl(nix_path, old_path)) + if (!has_nix_path) { + Sys.setenv( + PATH = paste(old_path, "/nix/var/nix/profiles/default/bin", sep = ":") + ) + } + return(Sys.getenv("PATH")) +} + + + + #' Evaluate function in R or shell command via `nix-shell` environment #' diff --git a/dev/build_envs.Rmd b/dev/build_envs.Rmd index f5e8c3ce..2fc3bb34 100644 --- a/dev/build_envs.Rmd +++ b/dev/build_envs.Rmd @@ -819,7 +819,104 @@ nix_build_exit_msg <- function(x) { } ``` -This function can evaluate an shell or R expression in Nix. +This function bootstraps and maintains an isolated, project-specific R setup +via Nix + +```{r, function-init} +#' Inititate and maintain an isolated, project-specific R setup via Nix +#' +#' Bootstraps an isolated project folder and adds sensible defaults to +#' achieve reproducibiltiy and isolated software dependencies with highest +#' run-time purity. +#' +#' This general bootstrap helper does a couple of configurations that ensure +#' that the project runs as isolated and pure as possible by default. +#' Since a host RStudio session not launched via nix does not inherit +#' environmental variables from `.zshrc` (on macOS), we need to add the path of +#' the nixpkgs store to the `PATH` variable. +#' +#' @param project_path Character with folder path to the isolated nix-R project. +#' Defaults to `"."`, which is the current path in the working directory. +#' If the folder does not exist yet, it will be created. +#' @param message_type Character. Message type, defaults to `"simple"`, which +#' gives mimimal but sufficient feedback. Other values are currently +#' `"verbose"`, which gives more detailed diagnostics. +#' @export +init <- function(project_path = ".", + message_type = c("simple", "verbose")) { + message_type <- match.arg(message_type) + cat("\n### Initiating isolated, project-specific R setup via Nix ###\n\n") + if (!dir.exists(project_path)) { + dir.create(path = project_path, recursive = TRUE) + project_path <- normalizePath(path = project_path) + cat("==> Created isolated nix-R project folder:\n", project_path, "\n") + } else { + project_path <- normalizePath(path = project_path) + cat("==> Using existing isolated nix-R project folder:\n", project_path, + "\n") + } + # check if RStudio session is running. + is_nixr <- is_nix_rsession() + is_rstudio <- is_rstudio_session() + if (!is_nixr && is_rstudio) { + PATH <- set_nix_path() + cat( + paste0("\n==> Added `.Rprofile` entry for new R sessions in:\n", + project_path), + "\n* Adding the location of the Nix store to `PATH`", + "environmental variable for new R sessions", + "\n\n==> Also adjusting the same path via `Sys.setenv()`, so that system", + "commands can invoke key Nix commands like `nix-build` in this RStudio", + "session on the host operating system.\n" + ) + cat("\n* Current `PATH` variable available in R session is:\n\n") + cat(PATH) + } +} + +#' @noRd +is_nix_rsession <- function() { + is_nixr <- nzchar(Sys.getenv("NIX_STORE")) + if (is_nixr) { + cat("==> R session running via Nix (nixpkgs)") + return(TRUE) + } else { + cat("\n==> R session running via host operating system or docker") + return(FALSE) + } +} + +#' @noRd +is_rstudio_session <- function() { + is_rstudio <- Sys.getenv("RSTUDIO") == "1" + if (is_rstudio) { + cat("\n==> R session running from RStudio\n") + return(TRUE) + } else { + cat("* R session not running from RStudio") + return(FALSE) + } +} + +#' @noRd +set_nix_path <- function() { + old_path <- Sys.getenv("PATH") + nix_path <- "/nix/var/nix/profiles/default/bin" + has_nix_path <- any(grepl(nix_path, old_path)) + if (!has_nix_path) { + Sys.setenv( + PATH = paste(old_path, "/nix/var/nix/profiles/default/bin", sep = ":") + ) + } + return(Sys.getenv("PATH")) +} + + + +``` + +This function can evaluate an shell or R expression in Nix via `nix-shell` +environment. ```{r, function-with-nix} diff --git a/man/init.Rd b/man/init.Rd new file mode 100644 index 00000000..6887acce --- /dev/null +++ b/man/init.Rd @@ -0,0 +1,29 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/find_rev.R +\name{init} +\alias{init} +\title{Inititate and maintain an isolated, project-specific R setup via Nix} +\usage{ +init(project_path = ".", message_type = c("simple", "verbose")) +} +\arguments{ +\item{project_path}{Character with folder path to the isolated nix-R project. +Defaults to \code{"."}, which is the current path in the working directory. +If the folder does not exist yet, it will be created.} + +\item{message_type}{Character. Message type, defaults to \code{"simple"}, which +gives mimimal but sufficient feedback. Other values are currently +\code{"verbose"}, which gives more detailed diagnostics.} +} +\description{ +Bootstraps an isolated project folder and adds sensible defaults to +achieve reproducibiltiy and isolated software dependencies with highest +run-time purity. +} +\details{ +This general bootstrap helper does a couple of configurations that ensure +that the project runs as isolated and pure as possible by default. +Since a host RStudio session not launched via nix does not inherit +environmental variables from \code{.zshrc} (on macOS), we need to add the path of +the nixpkgs store to the \code{PATH} variable. +} From 29e287099cf65201c848f4096f9232caa147c8ae Mon Sep 17 00:00:00 2001 From: Philipp Baumann Date: Sun, 7 Jan 2024 21:50:16 +0100 Subject: [PATCH 02/16] Boilerplating `rix::init()` --- NAMESPACE | 1 + 1 file changed, 1 insertion(+) diff --git a/NAMESPACE b/NAMESPACE index 5b0c8543..488b74c9 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,6 +1,7 @@ # Generated by roxygen2: do not edit by hand export(available_r) +export(init) export(nix_build) export(rix) export(tar_nix_ga) From 6907317f009b2f74d6f8b5e290c155e6d9c33a04 Mon Sep 17 00:00:00 2001 From: Philipp Baumann Date: Sun, 7 Jan 2024 22:03:29 +0100 Subject: [PATCH 03/16] `with_nix()`: failsave removal of `R_LIBS_USER` in purity fix --- R/find_rev.R | 4 ++-- dev/build_envs.Rmd | 4 ++-- man/init.Rd | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/R/find_rev.R b/R/find_rev.R index 56d9fdbb..90645681 100644 --- a/R/find_rev.R +++ b/R/find_rev.R @@ -724,7 +724,7 @@ nix_build_exit_msg <- function(x) { return(err_msg) } -#' Inititate and maintain an isolated, project-specific R setup via Nix +#' Inititate and maintain an isolated, project-specific and pure R setup via Nix #' #' Bootstraps an isolated project folder and adds sensible defaults to #' achieve reproducibiltiy and isolated software dependencies with highest @@ -1334,7 +1334,7 @@ quote_rnix <- function(expr, cat("\n", Sys.getenv("NIX_PATH")) # fix library paths for nix R on macOS and linux; avoid permission issue current_paths <- .libPaths() - userlib_paths <- c("/Users/", "/home/") + userlib_paths <- Sys.getenv("R_LIBS_USER") user_dir <- grep(paste(userlib_paths, collapse = "|"), current_paths) new_paths <- current_paths[-user_dir] .libPaths(new_paths) diff --git a/dev/build_envs.Rmd b/dev/build_envs.Rmd index 2fc3bb34..86350914 100644 --- a/dev/build_envs.Rmd +++ b/dev/build_envs.Rmd @@ -823,7 +823,7 @@ This function bootstraps and maintains an isolated, project-specific R setup via Nix ```{r, function-init} -#' Inititate and maintain an isolated, project-specific R setup via Nix +#' Inititate and maintain an isolated, project-specific and pure R setup via Nix #' #' Bootstraps an isolated project folder and adds sensible defaults to #' achieve reproducibiltiy and isolated software dependencies with highest @@ -1438,7 +1438,7 @@ quote_rnix <- function(expr, cat("\n", Sys.getenv("NIX_PATH")) # fix library paths for nix R on macOS and linux; avoid permission issue current_paths <- .libPaths() - userlib_paths <- c("/Users/", "/home/") + userlib_paths <- Sys.getenv("R_LIBS_USER") user_dir <- grep(paste(userlib_paths, collapse = "|"), current_paths) new_paths <- current_paths[-user_dir] .libPaths(new_paths) diff --git a/man/init.Rd b/man/init.Rd index 6887acce..6b8eaa2d 100644 --- a/man/init.Rd +++ b/man/init.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/find_rev.R \name{init} \alias{init} -\title{Inititate and maintain an isolated, project-specific R setup via Nix} +\title{Inititate and maintain an isolated, project-specific and pure R setup via Nix} \usage{ init(project_path = ".", message_type = c("simple", "verbose")) } From ea1c1f8dd70ad0b4a46a8e5311a5b107409d8468 Mon Sep 17 00:00:00 2001 From: Philipp Baumann Date: Sun, 7 Jan 2024 22:14:08 +0100 Subject: [PATCH 04/16] minor docs --- R/find_rev.R | 4 ++-- dev/build_envs.Rmd | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/R/find_rev.R b/R/find_rev.R index 90645681..2596949d 100644 --- a/R/find_rev.R +++ b/R/find_rev.R @@ -753,7 +753,7 @@ init <- function(project_path = ".", cat("==> Created isolated nix-R project folder:\n", project_path, "\n") } else { project_path <- normalizePath(path = project_path) - cat("==> Using existing isolated nix-R project folder:\n", project_path, + cat("==> Existing isolated nix-R project folder:\n", project_path, "\n") } # check if RStudio session is running. @@ -765,7 +765,7 @@ init <- function(project_path = ".", paste0("\n==> Added `.Rprofile` entry for new R sessions in:\n", project_path), "\n* Adding the location of the Nix store to `PATH`", - "environmental variable for new R sessions", + "environmental variable for new R sessions on host/docker Rstudio", "\n\n==> Also adjusting the same path via `Sys.setenv()`, so that system", "commands can invoke key Nix commands like `nix-build` in this RStudio", "session on the host operating system.\n" diff --git a/dev/build_envs.Rmd b/dev/build_envs.Rmd index 86350914..45b2e90b 100644 --- a/dev/build_envs.Rmd +++ b/dev/build_envs.Rmd @@ -845,14 +845,14 @@ via Nix init <- function(project_path = ".", message_type = c("simple", "verbose")) { message_type <- match.arg(message_type) - cat("\n### Initiating isolated, project-specific R setup via Nix ###\n\n") + cat("\n### Bootstrapping isolated, project-specific R setup via Nix ###\n\n") if (!dir.exists(project_path)) { dir.create(path = project_path, recursive = TRUE) project_path <- normalizePath(path = project_path) cat("==> Created isolated nix-R project folder:\n", project_path, "\n") } else { project_path <- normalizePath(path = project_path) - cat("==> Using existing isolated nix-R project folder:\n", project_path, + cat("==> Existing isolated nix-R project folder:\n", project_path, "\n") } # check if RStudio session is running. @@ -864,7 +864,7 @@ init <- function(project_path = ".", paste0("\n==> Added `.Rprofile` entry for new R sessions in:\n", project_path), "\n* Adding the location of the Nix store to `PATH`", - "environmental variable for new R sessions", + "environmental variable for new R sessions on host/docker Rstudio", "\n\n==> Also adjusting the same path via `Sys.setenv()`, so that system", "commands can invoke key Nix commands like `nix-build` in this RStudio", "session on the host operating system.\n" From beb617e5f0660e07a11c5ccc3cd77e9f7592b6bf Mon Sep 17 00:00:00 2001 From: Philipp Baumann Date: Sun, 7 Jan 2024 23:34:54 +0100 Subject: [PATCH 05/16] generate `.Rprofile`, produces pure run-time libraries for nix-R --- also tweak nix store PATH on non-nix RStudio --- R/find_rev.R | 45 +++++++++++++++++++++++++++++++++++++++++++-- dev/build_envs.Rmd | 43 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 85 insertions(+), 3 deletions(-) diff --git a/R/find_rev.R b/R/find_rev.R index 2596949d..ee6fb7a6 100644 --- a/R/find_rev.R +++ b/R/find_rev.R @@ -746,7 +746,7 @@ nix_build_exit_msg <- function(x) { init <- function(project_path = ".", message_type = c("simple", "verbose")) { message_type <- match.arg(message_type) - cat("\n### Initiating isolated, project-specific R setup via Nix ###\n\n") + cat("\n### Bootstrapping isolated, project-specific R setup via Nix ###\n\n") if (!dir.exists(project_path)) { dir.create(path = project_path, recursive = TRUE) project_path <- normalizePath(path = project_path) @@ -759,6 +759,14 @@ init <- function(project_path = ".", # check if RStudio session is running. is_nixr <- is_nix_rsession() is_rstudio <- is_rstudio_session() + + # create project-local `.Rprofile` with pure settings + # first create the call, deparse it, and write it to .Rprofile + rprofile_quoted <- nix_rprofile() + rprofile_deparsed <- deparse_chr1(expr = rprofile_quoted, collapse = "\n") + rprofile_file <- file.path(project_path, ".Rprofile") + writeLines(text = rprofile_deparsed, file(rprofile_file)) + if (!is_nixr && is_rstudio) { PATH <- set_nix_path() cat( @@ -773,6 +781,7 @@ init <- function(project_path = ".", cat("\n* Current `PATH` variable available in R session is:\n\n") cat(PATH) } + on.exit(close(file(rprofile_file))) } #' @noRd @@ -812,7 +821,39 @@ set_nix_path <- function() { return(Sys.getenv("PATH")) } - +#' @noRd +nix_rprofile <- function() { + quote( { + is_rstudio <- Sys.getenv("RSTUDIO") == "1" + is_nixr <- nzchar(Sys.getenv("NIX_STORE")) + if (!is_nixr && is_rstudio) { + # Currently, RStudio does not propagate environmental variables defined in + # `$HOME/.zshrc`, `$HOME/.bashrc` and alike. This is workaround to + # make the path of the nix store and hence basic nix commands available + # in an RStudio session + old_path <- Sys.getenv("PATH") + nix_path <- "/nix/var/nix/profiles/default/bin" + has_nix_path <- any(grepl(nix_path, old_path)) + if (!has_nix_path) { + Sys.setenv( + PATH = paste( + old_path, "/nix/var/nix/profiles/default/bin", sep = ":" + ) + ) + } + } + + if (is_nixr) { + current_paths <- .libPaths() + userlib_paths <- Sys.getenv("R_LIBS_USER") + user_dir <- grep(paste(userlib_paths, collapse = "|"), current_paths) + new_paths <- current_paths[-user_dir] + # sets new library path without user library, making nix-R pure at + # run-time + .libPaths(new_paths) + } + } ) +} diff --git a/dev/build_envs.Rmd b/dev/build_envs.Rmd index 45b2e90b..e0d12366 100644 --- a/dev/build_envs.Rmd +++ b/dev/build_envs.Rmd @@ -858,6 +858,14 @@ init <- function(project_path = ".", # check if RStudio session is running. is_nixr <- is_nix_rsession() is_rstudio <- is_rstudio_session() + + # create project-local `.Rprofile` with pure settings + # first create the call, deparse it, and write it to .Rprofile + rprofile_quoted <- nix_rprofile() + rprofile_deparsed <- deparse_chr1(expr = rprofile_quoted, collapse = "\n") + rprofile_file <- file.path(project_path, ".Rprofile") + writeLines(text = rprofile_deparsed, file(rprofile_file)) + if (!is_nixr && is_rstudio) { PATH <- set_nix_path() cat( @@ -872,6 +880,7 @@ init <- function(project_path = ".", cat("\n* Current `PATH` variable available in R session is:\n\n") cat(PATH) } + on.exit(close(file(rprofile_file))) } #' @noRd @@ -911,7 +920,39 @@ set_nix_path <- function() { return(Sys.getenv("PATH")) } - +#' @noRd +nix_rprofile <- function() { + quote( { + is_rstudio <- Sys.getenv("RSTUDIO") == "1" + is_nixr <- nzchar(Sys.getenv("NIX_STORE")) + if (!is_nixr && is_rstudio) { + # Currently, RStudio does not propagate environmental variables defined in + # `$HOME/.zshrc`, `$HOME/.bashrc` and alike. This is workaround to + # make the path of the nix store and hence basic nix commands available + # in an RStudio session + old_path <- Sys.getenv("PATH") + nix_path <- "/nix/var/nix/profiles/default/bin" + has_nix_path <- any(grepl(nix_path, old_path)) + if (!has_nix_path) { + Sys.setenv( + PATH = paste( + old_path, "/nix/var/nix/profiles/default/bin", sep = ":" + ) + ) + } + } + + if (is_nixr) { + current_paths <- .libPaths() + userlib_paths <- Sys.getenv("R_LIBS_USER") + user_dir <- grep(paste(userlib_paths, collapse = "|"), current_paths) + new_paths <- current_paths[-user_dir] + # sets new library path without user library, making nix-R pure at + # run-time + .libPaths(new_paths) + } + } ) +} ``` From d069ce3896cff75c59c8ec3f4e9a01b648c1e7ef Mon Sep 17 00:00:00 2001 From: Philipp Baumann Date: Mon, 8 Jan 2024 00:01:21 +0100 Subject: [PATCH 06/16] minimal print change --- R/find_rev.R | 4 ++-- dev/build_envs.Rmd | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/R/find_rev.R b/R/find_rev.R index ee6fb7a6..8efa45c3 100644 --- a/R/find_rev.R +++ b/R/find_rev.R @@ -788,10 +788,10 @@ init <- function(project_path = ".", is_nix_rsession <- function() { is_nixr <- nzchar(Sys.getenv("NIX_STORE")) if (is_nixr) { - cat("==> R session running via Nix (nixpkgs)") + cat("==> R session running via Nix (nixpkgs)\n") return(TRUE) } else { - cat("\n==> R session running via host operating system or docker") + cat("\n==> R session running via host operating system or docker\n") return(FALSE) } } diff --git a/dev/build_envs.Rmd b/dev/build_envs.Rmd index e0d12366..bac59f68 100644 --- a/dev/build_envs.Rmd +++ b/dev/build_envs.Rmd @@ -887,10 +887,10 @@ init <- function(project_path = ".", is_nix_rsession <- function() { is_nixr <- nzchar(Sys.getenv("NIX_STORE")) if (is_nixr) { - cat("==> R session running via Nix (nixpkgs)") + cat("==> R session running via Nix (nixpkgs)\n") return(TRUE) } else { - cat("\n==> R session running via host operating system or docker") + cat("\n==> R session running via host operating system or docker\n") return(FALSE) } } From 91a3448de9effbbe184c2d75cd1d5dc50aefcded Mon Sep 17 00:00:00 2001 From: Philipp Baumann Date: Mon, 8 Jan 2024 22:34:38 +0100 Subject: [PATCH 07/16] add type checking --- R/find_rev.R | 7 ++++++- dev/build_envs.Rmd | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/R/find_rev.R b/R/find_rev.R index 8efa45c3..842f07b4 100644 --- a/R/find_rev.R +++ b/R/find_rev.R @@ -745,7 +745,12 @@ nix_build_exit_msg <- function(x) { #' @export init <- function(project_path = ".", message_type = c("simple", "verbose")) { - message_type <- match.arg(message_type) + stopifnot( + "`project_path` needs to be character of length 1" = + is.character(project_path) && length(project_path) == 1L, + "`message_type` needs to be character" = is.character(project_path) + ) + message_type <- match.arg(message_type, choices = c("simple", "verbose")) cat("\n### Bootstrapping isolated, project-specific R setup via Nix ###\n\n") if (!dir.exists(project_path)) { dir.create(path = project_path, recursive = TRUE) diff --git a/dev/build_envs.Rmd b/dev/build_envs.Rmd index bac59f68..a2cbb85e 100644 --- a/dev/build_envs.Rmd +++ b/dev/build_envs.Rmd @@ -844,7 +844,12 @@ via Nix #' @export init <- function(project_path = ".", message_type = c("simple", "verbose")) { - message_type <- match.arg(message_type) + stopifnot( + "`project_path` needs to be character of length 1" = + is.character(project_path) && length(project_path) == 1L, + "`message_type` needs to be character" = is.character(project_path) + ) + message_type <- match.arg(message_type, choices = c("simple", "verbose")) cat("\n### Bootstrapping isolated, project-specific R setup via Nix ###\n\n") if (!dir.exists(project_path)) { dir.create(path = project_path, recursive = TRUE) From e2d7059ebeab20eded40d0dd3bee312d272d4e93 Mon Sep 17 00:00:00 2001 From: Philipp Baumann Date: Mon, 8 Jan 2024 23:28:59 +0100 Subject: [PATCH 08/16] add comments to `.Rprofile` generated by `init()` --- R/find_rev.R | 16 +++++++++++++++- dev/build_envs.Rmd | 16 +++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/R/find_rev.R b/R/find_rev.R index 842f07b4..e6d88704 100644 --- a/R/find_rev.R +++ b/R/find_rev.R @@ -770,7 +770,21 @@ init <- function(project_path = ".", rprofile_quoted <- nix_rprofile() rprofile_deparsed <- deparse_chr1(expr = rprofile_quoted, collapse = "\n") rprofile_file <- file.path(project_path, ".Rprofile") - writeLines(text = rprofile_deparsed, file(rprofile_file)) + writeLines( + text = c( +"### File generated by `rix::init()` ### +# 1. Currently, system RStudio does not propagate environmental variables +# defined in `$HOME/.zshrc`, `$HOME/.bashrc` and alike. This is workaround to +# make the path of the nix store and hence basic nix commands available +# in an RStudio session +# 2. For nix-R session, remove `R_LIBS_USER`, system's R user library.`. +# This guarantees no user libraries from the system are loaded and only +# R packages in the nix store are used. This makes nix-R behave as pure at +# run-time.", + rprofile_deparsed + ), + con = file(rprofile_file) + ) if (!is_nixr && is_rstudio) { PATH <- set_nix_path() diff --git a/dev/build_envs.Rmd b/dev/build_envs.Rmd index a2cbb85e..7b4b9afa 100644 --- a/dev/build_envs.Rmd +++ b/dev/build_envs.Rmd @@ -869,7 +869,21 @@ init <- function(project_path = ".", rprofile_quoted <- nix_rprofile() rprofile_deparsed <- deparse_chr1(expr = rprofile_quoted, collapse = "\n") rprofile_file <- file.path(project_path, ".Rprofile") - writeLines(text = rprofile_deparsed, file(rprofile_file)) + writeLines( + text = c( +"### File generated by `rix::init()` ### +# 1. Currently, system RStudio does not propagate environmental variables +# defined in `$HOME/.zshrc`, `$HOME/.bashrc` and alike. This is workaround to +# make the path of the nix store and hence basic nix commands available +# in an RStudio session +# 2. For nix-R session, remove `R_LIBS_USER`, system's R user library.`. +# This guarantees no user libraries from the system are loaded and only +# R packages in the nix store are used. This makes nix-R behave as pure at +# run-time.", + rprofile_deparsed + ), + con = file(rprofile_file) + ) if (!is_nixr && is_rstudio) { PATH <- set_nix_path() From 9c00de85c209f705d39d779f0ab1c0ced3a7dfe3 Mon Sep 17 00:00:00 2001 From: Philipp Baumann Date: Sat, 13 Jan 2024 15:20:44 +0100 Subject: [PATCH 09/16] Finetune the documentation of `rix::init()` --- R/find_rev.R | 98 ++++++++++++++++++++++++++++++++++++---------- dev/build_envs.Rmd | 98 ++++++++++++++++++++++++++++++++++++---------- man/init.Rd | 89 ++++++++++++++++++++++++++++++++++------- 3 files changed, 230 insertions(+), 55 deletions(-) diff --git a/R/find_rev.R b/R/find_rev.R index e6d88704..720eaea9 100644 --- a/R/find_rev.R +++ b/R/find_rev.R @@ -724,33 +724,90 @@ nix_build_exit_msg <- function(x) { return(err_msg) } -#' Inititate and maintain an isolated, project-specific and pure R setup via Nix +#' Initiate and maintain an isolated, project-specific, and runtime-pure R +#' setup via Nix. #' -#' Bootstraps an isolated project folder and adds sensible defaults to -#' achieve reproducibiltiy and isolated software dependencies with highest -#' run-time purity. -#' -#' This general bootstrap helper does a couple of configurations that ensure -#' that the project runs as isolated and pure as possible by default. -#' Since a host RStudio session not launched via nix does not inherit -#' environmental variables from `.zshrc` (on macOS), we need to add the path of -#' the nixpkgs store to the `PATH` variable. +#' Creates an isolated project folder for a Nix-R configuration. `rix::init()` +#' also adds, appends, or updates with or without backup a custom `.Rprofile` +#' file with code that initializes a startup R environment without system's user +#' libraries within a Nix software environment. Instead, it restricts search +#' paths to load R packages exclusively from the Nix store. Additionally, it +#' makes Nix utilities like `nix-shell` available to run system commands from +#' the system's RStudio R session, for both Linux and macOS. +#' +#' **Enhancement of computational reproducibility for Nix-R environments:** +#' +#' The primary goal of `rix::init()` is to enhance the computational +#' reproducibility of Nix-R environments during runtime. Notably, no restart is +#' required as environmental variables are set in the current session, in +#' addition to writing an `.Rprofile` file. This is particularly useful to make +#' [rix::with_nix()] evaluate custom R functions from any "Nix-to-Nix" or +#' "System-to-Nix" R setups. It introduces two side-effects that +#' take effect both in a current or later R session setup: +#' +#' 1. **Adjusting `R_LIBS_USER` path:** +#' By default, the first path of `R_LIBS_USER` points to the user library +#' outside the Nix store (see also [base::.libPaths()]). This creates +#' friction and potential impurity as R packages from the system's R user +#' library are loaded. While this feature can be useful for interactively +#' testing an R package in a Nix environment before adding it to a `.nix` +#' configuration, it can have undesired effects if not managed carefully. +#' A major drawback is that all R packages in the `R_LIBS_USER` location need +#' to be cleaned to avoid loading packages outside the Nix configuration. +#' Issues, especially on macOS, may arise due to segmentation faults or +#' incompatible linked system libraries. These problems can also occur +#' if one of the (reverse) dependencies of an R package is loaded along the +#' process. +#' +#' 2. **Make Nix commands available when running system commands from RStudio:** +#' In a host RStudio session not launched via Nix (`nix-shell`), the +#' environmental variables from `~/.zshrc` or `~/.bashrc` may not be +#' inherited. Consequently, Nix command line interfaces like `nix-shell` +#' might not be found. The `.Rprofile` code written by `rix::init()` ensures +#' that Nix command line programs are accessible by adding the path of the +#' "bin" directory of the default Nix profile, +#' `"/nix/var/nix/profiles/default/bin"`, to the `PATH` variable in an +#' RStudio R session. +#' +#' These side effects are particularly recommended when working in flexible R +#' environments, especially for users who want to maintain both the system's +#' native R setup and utilize Nix expressions for reproducible development +#' environments. This init configuration is considered pivotal to enhance the +#' adoption of Nix in the R community, particularly until RStudio in Nixpkgs is +#' packaged for macOS. We recommend calling `rix::init()` prior to comparing R +#' code ran between two software environments with `rix::with_nix()`. #' -#' @param project_path Character with folder path to the isolated nix-R project. -#' Defaults to `"."`, which is the current path in the working directory. -#' If the folder does not exist yet, it will be created. -#' @param message_type Character. Message type, defaults to `"simple"`, which -#' gives mimimal but sufficient feedback. Other values are currently -#' `"verbose"`, which gives more detailed diagnostics. +#' @param project_path Character with the folder path to the isolated nix-R project. +#' Defaults to `"."`, which is the current path in the working directory. If the folder +#' does not exist yet, it will be created. +#' @param message_type Character. Message type, defaults to `"simple"`, which +#' gives minimal but sufficient feedback. Other values are currently +#' `"verbose"`, which provides more detailed diagnostics. +#' @param rprofile_action Character. Action to take with `.Rprofile` file +#' destined for `project_path` folder. Possible values include +#' `"create_missing"`, which only writes `.Rprofile` if it +#' does not yet exist (otherwise does nothing); `"create_backup"`, which copies +#' the existing `.Rprofile` to a new backup file, generating names with +#' POSIXct-derived strings that include the time zone information. A new +#' `.Rprofile` file will be written with default code from `rix::init()`; +#' `"overwrite"` overwrites the `.Rprofile` file if it does exist; `"append"` +#' appends the existing file with code that is tailored to an isolated Nix-R +#' project setup. +#' #' @export +#' @seealso [with_nix()] init <- function(project_path = ".", - message_type = c("simple", "verbose")) { + message_type = c("simple", "verbose"), + rprofile_action = c("create_missing", "create_backup", + "overwrite", "append")) { + message_type <- match.arg(message_type, choices = c("simple", "verbose")) + rprofile_action <- match.arg(rprofile_action, + choices = c("create_backup", "create_missing", "overwrite", "append")) stopifnot( "`project_path` needs to be character of length 1" = - is.character(project_path) && length(project_path) == 1L, - "`message_type` needs to be character" = is.character(project_path) + is.character(project_path) && length(project_path) == 1L ) - message_type <- match.arg(message_type, choices = c("simple", "verbose")) + cat("\n### Bootstrapping isolated, project-specific R setup via Nix ###\n\n") if (!dir.exists(project_path)) { dir.create(path = project_path, recursive = TRUE) @@ -770,6 +827,7 @@ init <- function(project_path = ".", rprofile_quoted <- nix_rprofile() rprofile_deparsed <- deparse_chr1(expr = rprofile_quoted, collapse = "\n") rprofile_file <- file.path(project_path, ".Rprofile") + writeLines( text = c( "### File generated by `rix::init()` ### diff --git a/dev/build_envs.Rmd b/dev/build_envs.Rmd index 7b4b9afa..61d578c0 100644 --- a/dev/build_envs.Rmd +++ b/dev/build_envs.Rmd @@ -823,33 +823,90 @@ This function bootstraps and maintains an isolated, project-specific R setup via Nix ```{r, function-init} -#' Inititate and maintain an isolated, project-specific and pure R setup via Nix +#' Initiate and maintain an isolated, project-specific, and runtime-pure R +#' setup via Nix. #' -#' Bootstraps an isolated project folder and adds sensible defaults to -#' achieve reproducibiltiy and isolated software dependencies with highest -#' run-time purity. -#' -#' This general bootstrap helper does a couple of configurations that ensure -#' that the project runs as isolated and pure as possible by default. -#' Since a host RStudio session not launched via nix does not inherit -#' environmental variables from `.zshrc` (on macOS), we need to add the path of -#' the nixpkgs store to the `PATH` variable. +#' Creates an isolated project folder for a Nix-R configuration. `rix::init()` +#' also adds, appends, or updates with or without backup a custom `.Rprofile` +#' file with code that initializes a startup R environment without system's user +#' libraries within a Nix software environment. Instead, it restricts search +#' paths to load R packages exclusively from the Nix store. Additionally, it +#' makes Nix utilities like `nix-shell` available to run system commands from +#' the system's RStudio R session, for both Linux and macOS. +#' +#' **Enhancement of computational reproducibility for Nix-R environments:** +#' +#' The primary goal of `rix::init()` is to enhance the computational +#' reproducibility of Nix-R environments during runtime. Notably, no restart is +#' required as environmental variables are set in the current session, in +#' addition to writing an `.Rprofile` file. This is particularly useful to make +#' [rix::with_nix()] evaluate custom R functions from any "Nix-to-Nix" or +#' "System-to-Nix" R setups. It introduces two side-effects that +#' take effect both in a current or later R session setup: +#' +#' 1. **Adjusting `R_LIBS_USER` path:** +#' By default, the first path of `R_LIBS_USER` points to the user library +#' outside the Nix store (see also [base::.libPaths()]). This creates +#' friction and potential impurity as R packages from the system's R user +#' library are loaded. While this feature can be useful for interactively +#' testing an R package in a Nix environment before adding it to a `.nix` +#' configuration, it can have undesired effects if not managed carefully. +#' A major drawback is that all R packages in the `R_LIBS_USER` location need +#' to be cleaned to avoid loading packages outside the Nix configuration. +#' Issues, especially on macOS, may arise due to segmentation faults or +#' incompatible linked system libraries. These problems can also occur +#' if one of the (reverse) dependencies of an R package is loaded along the +#' process. +#' +#' 2. **Make Nix commands available when running system commands from RStudio:** +#' In a host RStudio session not launched via Nix (`nix-shell`), the +#' environmental variables from `~/.zshrc` or `~/.bashrc` may not be +#' inherited. Consequently, Nix command line interfaces like `nix-shell` +#' might not be found. The `.Rprofile` code written by `rix::init()` ensures +#' that Nix command line programs are accessible by adding the path of the +#' "bin" directory of the default Nix profile, +#' `"/nix/var/nix/profiles/default/bin"`, to the `PATH` variable in an +#' RStudio R session. +#' +#' These side effects are particularly recommended when working in flexible R +#' environments, especially for users who want to maintain both the system's +#' native R setup and utilize Nix expressions for reproducible development +#' environments. This init configuration is considered pivotal to enhance the +#' adoption of Nix in the R community, particularly until RStudio in Nixpkgs is +#' packaged for macOS. We recommend calling `rix::init()` prior to comparing R +#' code ran between two software environments with `rix::with_nix()`. #' -#' @param project_path Character with folder path to the isolated nix-R project. -#' Defaults to `"."`, which is the current path in the working directory. -#' If the folder does not exist yet, it will be created. -#' @param message_type Character. Message type, defaults to `"simple"`, which -#' gives mimimal but sufficient feedback. Other values are currently -#' `"verbose"`, which gives more detailed diagnostics. +#' @param project_path Character with the folder path to the isolated nix-R project. +#' Defaults to `"."`, which is the current path in the working directory. If the folder +#' does not exist yet, it will be created. +#' @param message_type Character. Message type, defaults to `"simple"`, which +#' gives minimal but sufficient feedback. Other values are currently +#' `"verbose"`, which provides more detailed diagnostics. +#' @param rprofile_action Character. Action to take with `.Rprofile` file +#' destined for `project_path` folder. Possible values include +#' `"create_missing"`, which only writes `.Rprofile` if it +#' does not yet exist (otherwise does nothing); `"create_backup"`, which copies +#' the existing `.Rprofile` to a new backup file, generating names with +#' POSIXct-derived strings that include the time zone information. A new +#' `.Rprofile` file will be written with default code from `rix::init()`; +#' `"overwrite"` overwrites the `.Rprofile` file if it does exist; `"append"` +#' appends the existing file with code that is tailored to an isolated Nix-R +#' project setup. +#' #' @export +#' @seealso [with_nix()] init <- function(project_path = ".", - message_type = c("simple", "verbose")) { + message_type = c("simple", "verbose"), + rprofile_action = c("create_missing", "create_backup", + "overwrite", "append")) { + message_type <- match.arg(message_type, choices = c("simple", "verbose")) + rprofile_action <- match.arg(rprofile_action, + choices = c("create_backup", "create_missing", "overwrite", "append")) stopifnot( "`project_path` needs to be character of length 1" = - is.character(project_path) && length(project_path) == 1L, - "`message_type` needs to be character" = is.character(project_path) + is.character(project_path) && length(project_path) == 1L ) - message_type <- match.arg(message_type, choices = c("simple", "verbose")) + cat("\n### Bootstrapping isolated, project-specific R setup via Nix ###\n\n") if (!dir.exists(project_path)) { dir.create(path = project_path, recursive = TRUE) @@ -869,6 +926,7 @@ init <- function(project_path = ".", rprofile_quoted <- nix_rprofile() rprofile_deparsed <- deparse_chr1(expr = rprofile_quoted, collapse = "\n") rprofile_file <- file.path(project_path, ".Rprofile") + writeLines( text = c( "### File generated by `rix::init()` ### diff --git a/man/init.Rd b/man/init.Rd index 6b8eaa2d..d6166a7a 100644 --- a/man/init.Rd +++ b/man/init.Rd @@ -2,28 +2,87 @@ % Please edit documentation in R/find_rev.R \name{init} \alias{init} -\title{Inititate and maintain an isolated, project-specific and pure R setup via Nix} +\title{Initiate and maintain an isolated, project-specific, and runtime-pure R +setup via Nix.} \usage{ -init(project_path = ".", message_type = c("simple", "verbose")) +init( + project_path = ".", + message_type = c("simple", "verbose"), + rprofile_action = c("create_missing", "create_backup", "overwrite", "append") +) } \arguments{ -\item{project_path}{Character with folder path to the isolated nix-R project. -Defaults to \code{"."}, which is the current path in the working directory. -If the folder does not exist yet, it will be created.} +\item{project_path}{Character with the folder path to the isolated nix-R project. +Defaults to \code{"."}, which is the current path in the working directory. If the folder +does not exist yet, it will be created.} \item{message_type}{Character. Message type, defaults to \code{"simple"}, which -gives mimimal but sufficient feedback. Other values are currently -\code{"verbose"}, which gives more detailed diagnostics.} +gives minimal but sufficient feedback. Other values are currently +\code{"verbose"}, which provides more detailed diagnostics.} + +\item{rprofile_action}{Character. Action to take with \code{.Rprofile} file +destined for \code{project_path} folder. Possible values include +\code{"create_missing"}, which only writes \code{.Rprofile} if it +does not yet exist (otherwise does nothing); \code{"create_backup"}, which copies +the existing \code{.Rprofile} to a new backup file, generating names with +POSIXct-derived strings that include the time zone information. A new +\code{.Rprofile} file will be written with default code from \code{rix::init()}; +\code{"overwrite"} overwrites the \code{.Rprofile} file if it does exist; \code{"append"} +appends the existing file with code that is tailored to an isolated Nix-R +project setup.} } \description{ -Bootstraps an isolated project folder and adds sensible defaults to -achieve reproducibiltiy and isolated software dependencies with highest -run-time purity. +Creates an isolated project folder for a Nix-R configuration. \code{rix::init()} +also adds, appends, or updates with or without backup a custom \code{.Rprofile} +file with code that initializes a startup R environment without system's user +libraries within a Nix software environment. Instead, it restricts search +paths to load R packages exclusively from the Nix store. Additionally, it +makes Nix utilities like \code{nix-shell} available to run system commands from +the system's RStudio R session, for both Linux and macOS. } \details{ -This general bootstrap helper does a couple of configurations that ensure -that the project runs as isolated and pure as possible by default. -Since a host RStudio session not launched via nix does not inherit -environmental variables from \code{.zshrc} (on macOS), we need to add the path of -the nixpkgs store to the \code{PATH} variable. +\strong{Enhancement of computational reproducibility for Nix-R environments:} + +The primary goal of \code{rix::init()} is to enhance the computational +reproducibility of Nix-R environments during runtime. Notably, no restart is +required as environmental variables are set in the current session, in +addition to writing an \code{.Rprofile} file. This is particularly useful to make +\code{\link[=with_nix]{with_nix()}} evaluate custom R functions from any "Nix-to-Nix" or +"System-to-Nix" R setups. It introduces two side-effects that +take effect both in a current or later R session setup: +\enumerate{ +\item \strong{Adjusting \code{R_LIBS_USER} path:} +By default, the first path of \code{R_LIBS_USER} points to the user library +outside the Nix store (see also \code{\link[base:libPaths]{base::.libPaths()}}). This creates +friction and potential impurity as R packages from the system's R user +library are loaded. While this feature can be useful for interactively +testing an R package in a Nix environment before adding it to a \code{.nix} +configuration, it can have undesired effects if not managed carefully. +A major drawback is that all R packages in the \code{R_LIBS_USER} location need +to be cleaned to avoid loading packages outside the Nix configuration. +Issues, especially on macOS, may arise due to segmentation faults or +incompatible linked system libraries. These problems can also occur +if one of the (reverse) dependencies of an R package is loaded along the +process. +\item \strong{Make Nix commands available when running system commands from RStudio:} +In a host RStudio session not launched via Nix (\code{nix-shell}), the +environmental variables from \verb{~/.zshrc} or \verb{~/.bashrc} may not be +inherited. Consequently, Nix command line interfaces like \code{nix-shell} +might not be found. The \code{.Rprofile} code written by \code{rix::init()} ensures +that Nix command line programs are accessible by adding the path of the +"bin" directory of the default Nix profile, +\code{"/nix/var/nix/profiles/default/bin"}, to the \code{PATH} variable in an +RStudio R session. +} + +These side effects are particularly recommended when working in flexible R +environments, especially for users who want to maintain both the system's +native R setup and utilize Nix expressions for reproducible development +environments. This init configuration is considered pivotal to enhance the +adoption of Nix in the R community, particularly until RStudio in Nixpkgs is +packaged for macOS. We recommend calling \code{rix::init()} prior to comparing R +code ran between two software environments with \code{rix::with_nix()}. +} +\seealso{ +\code{\link[=with_nix]{with_nix()}} } From 410b5a5fff5924080a396ca5bcc2667f87937b94 Mon Sep 17 00:00:00 2001 From: Philipp Baumann Date: Sat, 13 Jan 2024 15:29:25 +0100 Subject: [PATCH 10/16] important args first --- R/find_rev.R | 13 ++++++------- dev/build_envs.Rmd | 13 ++++++------- man/init.Rd | 14 +++++++------- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/R/find_rev.R b/R/find_rev.R index 720eaea9..b4dbd27b 100644 --- a/R/find_rev.R +++ b/R/find_rev.R @@ -778,11 +778,8 @@ nix_build_exit_msg <- function(x) { #' code ran between two software environments with `rix::with_nix()`. #' #' @param project_path Character with the folder path to the isolated nix-R project. -#' Defaults to `"."`, which is the current path in the working directory. If the folder +#' Defaults to `"."`, which is the current working directory path. If the folder #' does not exist yet, it will be created. -#' @param message_type Character. Message type, defaults to `"simple"`, which -#' gives minimal but sufficient feedback. Other values are currently -#' `"verbose"`, which provides more detailed diagnostics. #' @param rprofile_action Character. Action to take with `.Rprofile` file #' destined for `project_path` folder. Possible values include #' `"create_missing"`, which only writes `.Rprofile` if it @@ -793,13 +790,15 @@ nix_build_exit_msg <- function(x) { #' `"overwrite"` overwrites the `.Rprofile` file if it does exist; `"append"` #' appends the existing file with code that is tailored to an isolated Nix-R #' project setup. -#' +#' @param message_type Character. Message type, defaults to `"simple"`, which +#' gives minimal but sufficient feedback. Other values are currently +#' `"verbose"`, which provides more detailed diagnostics. #' @export #' @seealso [with_nix()] init <- function(project_path = ".", - message_type = c("simple", "verbose"), rprofile_action = c("create_missing", "create_backup", - "overwrite", "append")) { + "overwrite", "append"), + message_type = c("simple", "verbose")) { message_type <- match.arg(message_type, choices = c("simple", "verbose")) rprofile_action <- match.arg(rprofile_action, choices = c("create_backup", "create_missing", "overwrite", "append")) diff --git a/dev/build_envs.Rmd b/dev/build_envs.Rmd index 61d578c0..7926a164 100644 --- a/dev/build_envs.Rmd +++ b/dev/build_envs.Rmd @@ -877,11 +877,8 @@ via Nix #' code ran between two software environments with `rix::with_nix()`. #' #' @param project_path Character with the folder path to the isolated nix-R project. -#' Defaults to `"."`, which is the current path in the working directory. If the folder +#' Defaults to `"."`, which is the current working directory path. If the folder #' does not exist yet, it will be created. -#' @param message_type Character. Message type, defaults to `"simple"`, which -#' gives minimal but sufficient feedback. Other values are currently -#' `"verbose"`, which provides more detailed diagnostics. #' @param rprofile_action Character. Action to take with `.Rprofile` file #' destined for `project_path` folder. Possible values include #' `"create_missing"`, which only writes `.Rprofile` if it @@ -892,13 +889,15 @@ via Nix #' `"overwrite"` overwrites the `.Rprofile` file if it does exist; `"append"` #' appends the existing file with code that is tailored to an isolated Nix-R #' project setup. -#' +#' @param message_type Character. Message type, defaults to `"simple"`, which +#' gives minimal but sufficient feedback. Other values are currently +#' `"verbose"`, which provides more detailed diagnostics. #' @export #' @seealso [with_nix()] init <- function(project_path = ".", - message_type = c("simple", "verbose"), rprofile_action = c("create_missing", "create_backup", - "overwrite", "append")) { + "overwrite", "append"), + message_type = c("simple", "verbose")) { message_type <- match.arg(message_type, choices = c("simple", "verbose")) rprofile_action <- match.arg(rprofile_action, choices = c("create_backup", "create_missing", "overwrite", "append")) diff --git a/man/init.Rd b/man/init.Rd index d6166a7a..dd2be96b 100644 --- a/man/init.Rd +++ b/man/init.Rd @@ -7,19 +7,15 @@ setup via Nix.} \usage{ init( project_path = ".", - message_type = c("simple", "verbose"), - rprofile_action = c("create_missing", "create_backup", "overwrite", "append") + rprofile_action = c("create_missing", "create_backup", "overwrite", "append"), + message_type = c("simple", "verbose") ) } \arguments{ \item{project_path}{Character with the folder path to the isolated nix-R project. -Defaults to \code{"."}, which is the current path in the working directory. If the folder +Defaults to \code{"."}, which is the current working directory path. If the folder does not exist yet, it will be created.} -\item{message_type}{Character. Message type, defaults to \code{"simple"}, which -gives minimal but sufficient feedback. Other values are currently -\code{"verbose"}, which provides more detailed diagnostics.} - \item{rprofile_action}{Character. Action to take with \code{.Rprofile} file destined for \code{project_path} folder. Possible values include \code{"create_missing"}, which only writes \code{.Rprofile} if it @@ -30,6 +26,10 @@ POSIXct-derived strings that include the time zone information. A new \code{"overwrite"} overwrites the \code{.Rprofile} file if it does exist; \code{"append"} appends the existing file with code that is tailored to an isolated Nix-R project setup.} + +\item{message_type}{Character. Message type, defaults to \code{"simple"}, which +gives minimal but sufficient feedback. Other values are currently +\code{"verbose"}, which provides more detailed diagnostics.} } \description{ Creates an isolated project folder for a Nix-R configuration. \code{rix::init()} From 2bb887c16f83920ffcdaa9d3731d3d99109eced9 Mon Sep 17 00:00:00 2001 From: Philipp Baumann Date: Sat, 13 Jan 2024 23:10:27 +0100 Subject: [PATCH 11/16] implement `"create_missing` and `"create_backup"` options of `rprofile_action` --- R/find_rev.R | 128 ++++++++++++++++++++++++++++++++++----------- dev/build_envs.Rmd | 128 ++++++++++++++++++++++++++++++++++----------- 2 files changed, 196 insertions(+), 60 deletions(-) diff --git a/R/find_rev.R b/R/find_rev.R index b4dbd27b..24a4c2bb 100644 --- a/R/find_rev.R +++ b/R/find_rev.R @@ -801,13 +801,14 @@ init <- function(project_path = ".", message_type = c("simple", "verbose")) { message_type <- match.arg(message_type, choices = c("simple", "verbose")) rprofile_action <- match.arg(rprofile_action, - choices = c("create_backup", "create_missing", "overwrite", "append")) + choices = c("create_missing", "create_backup", "overwrite", "append")) stopifnot( "`project_path` needs to be character of length 1" = is.character(project_path) && length(project_path) == 1L ) - cat("\n### Bootstrapping isolated, project-specific R setup via Nix ###\n\n") + cat("\n### Bootstrapping isolated, project-specific, and runtime-pure", + "R setup via Nix ###\n\n") if (!dir.exists(project_path)) { dir.create(path = project_path, recursive = TRUE) project_path <- normalizePath(path = project_path) @@ -817,9 +818,6 @@ init <- function(project_path = ".", cat("==> Existing isolated nix-R project folder:\n", project_path, "\n") } - # check if RStudio session is running. - is_nixr <- is_nix_rsession() - is_rstudio <- is_rstudio_session() # create project-local `.Rprofile` with pure settings # first create the call, deparse it, and write it to .Rprofile @@ -827,37 +825,107 @@ init <- function(project_path = ".", rprofile_deparsed <- deparse_chr1(expr = rprofile_quoted, collapse = "\n") rprofile_file <- file.path(project_path, ".Rprofile") - writeLines( - text = c( + rprofile_text <- get_rprofile_text(rprofile_deparsed) + write_rprofile <- function(rprofile_text, rprofile_file) { + writeLines( + text = rprofile_text, + con = file(rprofile_file) + ) + } + + is_nixr <- is_nix_rsession() + is_rstudio <- is_rstudio_session() + + rprofile_exists <- file.exists(rprofile_file) + timestamp <- format(Sys.time(), "%Y-%m-%dT%H:%M:%S%z") + rprofile_backup <- paste0(rprofile_file, "_backup_", timestamp) + + switch(rprofile_action, + create_missing = { + if (rprofile_exists) { + cat( + "\n* Keep existing `.Rprofile`. in `project_path`:\n", + paste0(project_path, "/"), "\n" + ) + if (message_type == "verbose") { + cat("\n* Current lines of local `.Rprofile` are:\n\n") + cat(readLines(con = file(rprofile_file)), sep = "\n") + } + } else { + write_rprofile(rprofile_text, rprofile_file) + message_rprofile(action_string = "Added", project_path = project_path) + } + set_message_session_PATH(message_type = message_type) + }, + create_backup = { + if (rprofile_exists) { + if (message_type == "verbose") { + cat("\n* Current lines of local `.Rprofile` are\n:") + cat(readLines(con = file(rprofile_file)), sep = "\n") + } + file.copy(from = rprofile_file, to = rprofile_backup) + cat( + "\n==> Backed up existing `.Rprofile` in file:\n", rprofile_backup, + "\n" + ) + write_rprofile(rprofile_text, rprofile_file) + message_rprofile( + action_string = "Overwrote", + project_path = project_path + ) + set_message_session_PATH(message_type = message_type) + } + } + ) + + on.exit(close(file(rprofile_file))) +} + +#' @noRd +get_rprofile_text <- function(rprofile_deparsed) { + c( "### File generated by `rix::init()` ### -# 1. Currently, system RStudio does not propagate environmental variables +# 1. Currently, system RStudio does not inherit environmental variables # defined in `$HOME/.zshrc`, `$HOME/.bashrc` and alike. This is workaround to # make the path of the nix store and hence basic nix commands available # in an RStudio session # 2. For nix-R session, remove `R_LIBS_USER`, system's R user library.`. # This guarantees no user libraries from the system are loaded and only -# R packages in the nix store are used. This makes nix-R behave as pure at -# run-time.", - rprofile_deparsed - ), - con = file(rprofile_file) +# R packages in the Nix store are used. This makes Nix-R behave in pure manner +# at run-time.", + rprofile_deparsed ) - - if (!is_nixr && is_rstudio) { - PATH <- set_nix_path() - cat( - paste0("\n==> Added `.Rprofile` entry for new R sessions in:\n", - project_path), - "\n* Adding the location of the Nix store to `PATH`", - "environmental variable for new R sessions on host/docker Rstudio", - "\n\n==> Also adjusting the same path via `Sys.setenv()`, so that system", - "commands can invoke key Nix commands like `nix-build` in this RStudio", - "session on the host operating system.\n" - ) - cat("\n* Current `PATH` variable available in R session is:\n\n") - cat(PATH) +} + + +#' @noRd +message_rprofile <- function(action_string = "Added", + project_path = ".") { + msg <- paste0( + "\n==> ", action_string, + " `.Rprofile` file and code lines for new R sessions launched from:\n", + project_path, + "\n\n* Added the location of the Nix store to `PATH` ", + "environmental variable for new R sessions on host/docker RStudio:\n", + "/nix/var/nix/profiles/default/bin" + ) + cat(msg) +} + +#' @noRd +set_message_session_PATH <- function(message_type = c("simple", "verbose")) { + match.arg(message_type, choices = c("simple", "verbose")) + if (message_type == "verbose") { + cat("\n\n* Current `PATH` variable set in R session is:\n\n") + cat(Sys.getenv("PATH")) + } + cat("\n\n==> Also adjusting `PATH` via `Sys.setenv()`, so that", + "system commands can invoke key Nix commands like `nix-build` in this", + "RStudio session on the host operating system.") + PATH <- set_nix_path() + if (message_type == "verbose") { + cat("\n\n* Updated `PATH` variable is:\n\n", PATH) } - on.exit(close(file(rprofile_file))) } #' @noRd @@ -894,7 +962,7 @@ set_nix_path <- function() { PATH = paste(old_path, "/nix/var/nix/profiles/default/bin", sep = ":") ) } - return(Sys.getenv("PATH")) + invisible(Sys.getenv("PATH")) } #' @noRd @@ -913,7 +981,7 @@ nix_rprofile <- function() { if (!has_nix_path) { Sys.setenv( PATH = paste( - old_path, "/nix/var/nix/profiles/default/bin", sep = ":" + old_path, nix_path, sep = ":" ) ) } diff --git a/dev/build_envs.Rmd b/dev/build_envs.Rmd index 7926a164..bba6d986 100644 --- a/dev/build_envs.Rmd +++ b/dev/build_envs.Rmd @@ -900,13 +900,14 @@ init <- function(project_path = ".", message_type = c("simple", "verbose")) { message_type <- match.arg(message_type, choices = c("simple", "verbose")) rprofile_action <- match.arg(rprofile_action, - choices = c("create_backup", "create_missing", "overwrite", "append")) + choices = c("create_missing", "create_backup", "overwrite", "append")) stopifnot( "`project_path` needs to be character of length 1" = is.character(project_path) && length(project_path) == 1L ) - cat("\n### Bootstrapping isolated, project-specific R setup via Nix ###\n\n") + cat("\n### Bootstrapping isolated, project-specific, and runtime-pure", + "R setup via Nix ###\n\n") if (!dir.exists(project_path)) { dir.create(path = project_path, recursive = TRUE) project_path <- normalizePath(path = project_path) @@ -916,9 +917,6 @@ init <- function(project_path = ".", cat("==> Existing isolated nix-R project folder:\n", project_path, "\n") } - # check if RStudio session is running. - is_nixr <- is_nix_rsession() - is_rstudio <- is_rstudio_session() # create project-local `.Rprofile` with pure settings # first create the call, deparse it, and write it to .Rprofile @@ -926,37 +924,107 @@ init <- function(project_path = ".", rprofile_deparsed <- deparse_chr1(expr = rprofile_quoted, collapse = "\n") rprofile_file <- file.path(project_path, ".Rprofile") - writeLines( - text = c( + rprofile_text <- get_rprofile_text(rprofile_deparsed) + write_rprofile <- function(rprofile_text, rprofile_file) { + writeLines( + text = rprofile_text, + con = file(rprofile_file) + ) + } + + is_nixr <- is_nix_rsession() + is_rstudio <- is_rstudio_session() + + rprofile_exists <- file.exists(rprofile_file) + timestamp <- format(Sys.time(), "%Y-%m-%dT%H:%M:%S%z") + rprofile_backup <- paste0(rprofile_file, "_backup_", timestamp) + + switch(rprofile_action, + create_missing = { + if (rprofile_exists) { + cat( + "\n* Keep existing `.Rprofile`. in `project_path`:\n", + paste0(project_path, "/"), "\n" + ) + if (message_type == "verbose") { + cat("\n* Current lines of local `.Rprofile` are:\n\n") + cat(readLines(con = file(rprofile_file)), sep = "\n") + } + } else { + write_rprofile(rprofile_text, rprofile_file) + message_rprofile(action_string = "Added", project_path = project_path) + } + set_message_session_PATH(message_type = message_type) + }, + create_backup = { + if (rprofile_exists) { + if (message_type == "verbose") { + cat("\n* Current lines of local `.Rprofile` are\n:") + cat(readLines(con = file(rprofile_file)), sep = "\n") + } + file.copy(from = rprofile_file, to = rprofile_backup) + cat( + "\n==> Backed up existing `.Rprofile` in file:\n", rprofile_backup, + "\n" + ) + write_rprofile(rprofile_text, rprofile_file) + message_rprofile( + action_string = "Overwrote", + project_path = project_path + ) + set_message_session_PATH(message_type = message_type) + } + } + ) + + on.exit(close(file(rprofile_file))) +} + +#' @noRd +get_rprofile_text <- function(rprofile_deparsed) { + c( "### File generated by `rix::init()` ### -# 1. Currently, system RStudio does not propagate environmental variables +# 1. Currently, system RStudio does not inherit environmental variables # defined in `$HOME/.zshrc`, `$HOME/.bashrc` and alike. This is workaround to # make the path of the nix store and hence basic nix commands available # in an RStudio session # 2. For nix-R session, remove `R_LIBS_USER`, system's R user library.`. # This guarantees no user libraries from the system are loaded and only -# R packages in the nix store are used. This makes nix-R behave as pure at -# run-time.", - rprofile_deparsed - ), - con = file(rprofile_file) +# R packages in the Nix store are used. This makes Nix-R behave in pure manner +# at run-time.", + rprofile_deparsed ) - - if (!is_nixr && is_rstudio) { - PATH <- set_nix_path() - cat( - paste0("\n==> Added `.Rprofile` entry for new R sessions in:\n", - project_path), - "\n* Adding the location of the Nix store to `PATH`", - "environmental variable for new R sessions on host/docker Rstudio", - "\n\n==> Also adjusting the same path via `Sys.setenv()`, so that system", - "commands can invoke key Nix commands like `nix-build` in this RStudio", - "session on the host operating system.\n" - ) - cat("\n* Current `PATH` variable available in R session is:\n\n") - cat(PATH) +} + + +#' @noRd +message_rprofile <- function(action_string = "Added", + project_path = ".") { + msg <- paste0( + "\n==> ", action_string, + " `.Rprofile` file and code lines for new R sessions launched from:\n", + project_path, + "\n\n* Added the location of the Nix store to `PATH` ", + "environmental variable for new R sessions on host/docker RStudio:\n", + "/nix/var/nix/profiles/default/bin" + ) + cat(msg) +} + +#' @noRd +set_message_session_PATH <- function(message_type = c("simple", "verbose")) { + match.arg(message_type, choices = c("simple", "verbose")) + if (message_type == "verbose") { + cat("\n\n* Current `PATH` variable set in R session is:\n\n") + cat(Sys.getenv("PATH")) + } + cat("\n\n==> Also adjusting `PATH` via `Sys.setenv()`, so that", + "system commands can invoke key Nix commands like `nix-build` in this", + "RStudio session on the host operating system.") + PATH <- set_nix_path() + if (message_type == "verbose") { + cat("\n\n* Updated `PATH` variable is:\n\n", PATH) } - on.exit(close(file(rprofile_file))) } #' @noRd @@ -993,7 +1061,7 @@ set_nix_path <- function() { PATH = paste(old_path, "/nix/var/nix/profiles/default/bin", sep = ":") ) } - return(Sys.getenv("PATH")) + invisible(Sys.getenv("PATH")) } #' @noRd @@ -1012,7 +1080,7 @@ nix_rprofile <- function() { if (!has_nix_path) { Sys.setenv( PATH = paste( - old_path, "/nix/var/nix/profiles/default/bin", sep = ":" + old_path, nix_path, sep = ":" ) ) } From 941001a912cd9ba92b3f3a586b522b23bc2d028e Mon Sep 17 00:00:00 2001 From: Philipp Baumann Date: Sun, 14 Jan 2024 01:50:06 +0100 Subject: [PATCH 12/16] update ignores --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 04a9e1ed..ed20de9e 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,5 @@ docs result /doc/ /Meta/ -_test_with_nix.R \ No newline at end of file +_test_with_nix.R + From d0e0af999d9f920ead4b2e9de8aa91c775cf711e Mon Sep 17 00:00:00 2001 From: Philipp Baumann Date: Sun, 14 Jan 2024 09:50:36 +0100 Subject: [PATCH 13/16] `isTRUE`/`isFALSE` in `if` cond for `NA` safety --- R/find_rev.R | 18 +++++++++--------- dev/build_envs.Rmd | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/R/find_rev.R b/R/find_rev.R index 24a4c2bb..17c029e9 100644 --- a/R/find_rev.R +++ b/R/find_rev.R @@ -809,7 +809,7 @@ init <- function(project_path = ".", cat("\n### Bootstrapping isolated, project-specific, and runtime-pure", "R setup via Nix ###\n\n") - if (!dir.exists(project_path)) { + if (isFALSE(dir.exists(project_path))) { dir.create(path = project_path, recursive = TRUE) project_path <- normalizePath(path = project_path) cat("==> Created isolated nix-R project folder:\n", project_path, "\n") @@ -842,7 +842,7 @@ init <- function(project_path = ".", switch(rprofile_action, create_missing = { - if (rprofile_exists) { + if (isTRUE(rprofile_exists)) { cat( "\n* Keep existing `.Rprofile`. in `project_path`:\n", paste0(project_path, "/"), "\n" @@ -858,7 +858,7 @@ init <- function(project_path = ".", set_message_session_PATH(message_type = message_type) }, create_backup = { - if (rprofile_exists) { + if (isTRUE(rprofile_exists)) { if (message_type == "verbose") { cat("\n* Current lines of local `.Rprofile` are\n:") cat(readLines(con = file(rprofile_file)), sep = "\n") @@ -931,7 +931,7 @@ set_message_session_PATH <- function(message_type = c("simple", "verbose")) { #' @noRd is_nix_rsession <- function() { is_nixr <- nzchar(Sys.getenv("NIX_STORE")) - if (is_nixr) { + if (isTRUE(is_nixr)) { cat("==> R session running via Nix (nixpkgs)\n") return(TRUE) } else { @@ -943,7 +943,7 @@ is_nix_rsession <- function() { #' @noRd is_rstudio_session <- function() { is_rstudio <- Sys.getenv("RSTUDIO") == "1" - if (is_rstudio) { + if (isTRUE(is_rstudio)) { cat("\n==> R session running from RStudio\n") return(TRUE) } else { @@ -957,7 +957,7 @@ set_nix_path <- function() { old_path <- Sys.getenv("PATH") nix_path <- "/nix/var/nix/profiles/default/bin" has_nix_path <- any(grepl(nix_path, old_path)) - if (!has_nix_path) { + if (isFALSE(has_nix_path)) { Sys.setenv( PATH = paste(old_path, "/nix/var/nix/profiles/default/bin", sep = ":") ) @@ -970,7 +970,7 @@ nix_rprofile <- function() { quote( { is_rstudio <- Sys.getenv("RSTUDIO") == "1" is_nixr <- nzchar(Sys.getenv("NIX_STORE")) - if (!is_nixr && is_rstudio) { + if (isFALSE(is_nixr) && isTRUE(is_rstudio)) { # Currently, RStudio does not propagate environmental variables defined in # `$HOME/.zshrc`, `$HOME/.bashrc` and alike. This is workaround to # make the path of the nix store and hence basic nix commands available @@ -978,7 +978,7 @@ nix_rprofile <- function() { old_path <- Sys.getenv("PATH") nix_path <- "/nix/var/nix/profiles/default/bin" has_nix_path <- any(grepl(nix_path, old_path)) - if (!has_nix_path) { + if (isFALSE(has_nix_path)) { Sys.setenv( PATH = paste( old_path, nix_path, sep = ":" @@ -987,7 +987,7 @@ nix_rprofile <- function() { } } - if (is_nixr) { + if (isTRUE(is_nixr)) { current_paths <- .libPaths() userlib_paths <- Sys.getenv("R_LIBS_USER") user_dir <- grep(paste(userlib_paths, collapse = "|"), current_paths) diff --git a/dev/build_envs.Rmd b/dev/build_envs.Rmd index bba6d986..10cf3f2f 100644 --- a/dev/build_envs.Rmd +++ b/dev/build_envs.Rmd @@ -908,7 +908,7 @@ init <- function(project_path = ".", cat("\n### Bootstrapping isolated, project-specific, and runtime-pure", "R setup via Nix ###\n\n") - if (!dir.exists(project_path)) { + if (isFALSE(dir.exists(project_path))) { dir.create(path = project_path, recursive = TRUE) project_path <- normalizePath(path = project_path) cat("==> Created isolated nix-R project folder:\n", project_path, "\n") @@ -941,7 +941,7 @@ init <- function(project_path = ".", switch(rprofile_action, create_missing = { - if (rprofile_exists) { + if (isTRUE(rprofile_exists)) { cat( "\n* Keep existing `.Rprofile`. in `project_path`:\n", paste0(project_path, "/"), "\n" @@ -957,7 +957,7 @@ init <- function(project_path = ".", set_message_session_PATH(message_type = message_type) }, create_backup = { - if (rprofile_exists) { + if (isTRUE(rprofile_exists)) { if (message_type == "verbose") { cat("\n* Current lines of local `.Rprofile` are\n:") cat(readLines(con = file(rprofile_file)), sep = "\n") @@ -1030,7 +1030,7 @@ set_message_session_PATH <- function(message_type = c("simple", "verbose")) { #' @noRd is_nix_rsession <- function() { is_nixr <- nzchar(Sys.getenv("NIX_STORE")) - if (is_nixr) { + if (isTRUE(is_nixr)) { cat("==> R session running via Nix (nixpkgs)\n") return(TRUE) } else { @@ -1042,7 +1042,7 @@ is_nix_rsession <- function() { #' @noRd is_rstudio_session <- function() { is_rstudio <- Sys.getenv("RSTUDIO") == "1" - if (is_rstudio) { + if (isTRUE(is_rstudio)) { cat("\n==> R session running from RStudio\n") return(TRUE) } else { @@ -1056,7 +1056,7 @@ set_nix_path <- function() { old_path <- Sys.getenv("PATH") nix_path <- "/nix/var/nix/profiles/default/bin" has_nix_path <- any(grepl(nix_path, old_path)) - if (!has_nix_path) { + if (isFALSE(has_nix_path)) { Sys.setenv( PATH = paste(old_path, "/nix/var/nix/profiles/default/bin", sep = ":") ) @@ -1069,7 +1069,7 @@ nix_rprofile <- function() { quote( { is_rstudio <- Sys.getenv("RSTUDIO") == "1" is_nixr <- nzchar(Sys.getenv("NIX_STORE")) - if (!is_nixr && is_rstudio) { + if (isFALSE(is_nixr) && isTRUE(is_rstudio)) { # Currently, RStudio does not propagate environmental variables defined in # `$HOME/.zshrc`, `$HOME/.bashrc` and alike. This is workaround to # make the path of the nix store and hence basic nix commands available @@ -1077,7 +1077,7 @@ nix_rprofile <- function() { old_path <- Sys.getenv("PATH") nix_path <- "/nix/var/nix/profiles/default/bin" has_nix_path <- any(grepl(nix_path, old_path)) - if (!has_nix_path) { + if (isFALSE(has_nix_path)) { Sys.setenv( PATH = paste( old_path, nix_path, sep = ":" @@ -1086,7 +1086,7 @@ nix_rprofile <- function() { } } - if (is_nixr) { + if (isTRUE(is_nixr)) { current_paths <- .libPaths() userlib_paths <- Sys.getenv("R_LIBS_USER") user_dir <- grep(paste(userlib_paths, collapse = "|"), current_paths) From e3c30a01edd444945461a6f4f3aaa4c4536e2d25 Mon Sep 17 00:00:00 2001 From: Philipp Baumann Date: Mon, 15 Jan 2024 21:04:20 +0100 Subject: [PATCH 14/16] remove tempory init variables --- R/find_rev.R | 5 +++++ dev/build_envs.Rmd | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/R/find_rev.R b/R/find_rev.R index 17c029e9..63d04634 100644 --- a/R/find_rev.R +++ b/R/find_rev.R @@ -975,6 +975,7 @@ nix_rprofile <- function() { # `$HOME/.zshrc`, `$HOME/.bashrc` and alike. This is workaround to # make the path of the nix store and hence basic nix commands available # in an RStudio session + cat("{rix} detected RStudio R session") old_path <- Sys.getenv("PATH") nix_path <- "/nix/var/nix/profiles/default/bin" has_nix_path <- any(grepl(nix_path, old_path)) @@ -985,6 +986,7 @@ nix_rprofile <- function() { ) ) } + rm(old_path, nix_path) } if (isTRUE(is_nixr)) { @@ -995,7 +997,10 @@ nix_rprofile <- function() { # sets new library path without user library, making nix-R pure at # run-time .libPaths(new_paths) + rm(current_paths, userlib_paths, user_dir, new_paths) } + + rm(is_rstudio, is_nixr) } ) } diff --git a/dev/build_envs.Rmd b/dev/build_envs.Rmd index 10cf3f2f..4ff298d4 100644 --- a/dev/build_envs.Rmd +++ b/dev/build_envs.Rmd @@ -1074,6 +1074,7 @@ nix_rprofile <- function() { # `$HOME/.zshrc`, `$HOME/.bashrc` and alike. This is workaround to # make the path of the nix store and hence basic nix commands available # in an RStudio session + cat("{rix} detected RStudio R session") old_path <- Sys.getenv("PATH") nix_path <- "/nix/var/nix/profiles/default/bin" has_nix_path <- any(grepl(nix_path, old_path)) @@ -1084,6 +1085,7 @@ nix_rprofile <- function() { ) ) } + rm(old_path, nix_path) } if (isTRUE(is_nixr)) { @@ -1094,7 +1096,10 @@ nix_rprofile <- function() { # sets new library path without user library, making nix-R pure at # run-time .libPaths(new_paths) + rm(current_paths, userlib_paths, user_dir, new_paths) } + + rm(is_rstudio, is_nixr) } ) } From dfa17705a69997353b6a33af9525cce89eddf878 Mon Sep 17 00:00:00 2001 From: Philipp Baumann Date: Mon, 15 Jan 2024 21:48:14 +0100 Subject: [PATCH 15/16] implement `overwrite` action --- R/find_rev.R | 16 ++++++++++++++++ dev/build_envs.Rmd | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/R/find_rev.R b/R/find_rev.R index 63d04634..bac0da6f 100644 --- a/R/find_rev.R +++ b/R/find_rev.R @@ -875,6 +875,22 @@ init <- function(project_path = ".", ) set_message_session_PATH(message_type = message_type) } + }, + overwrite = { + write_rprofile(rprofile_text, rprofile_file) + if (isTRUE(rprofile_exists)) { + message_rprofile( + action_string = "Overwrote", project_path = project_path + ) + } else { + message_rprofile( + action_string = "Added", project_path = project_path + ) + } + if (message_type == "verbose") { + cat("\n* Current lines of local `.Rprofile` are:\n\n") + cat(readLines(con = file(rprofile_file)), sep = "\n") + } } ) diff --git a/dev/build_envs.Rmd b/dev/build_envs.Rmd index 4ff298d4..fa5a810b 100644 --- a/dev/build_envs.Rmd +++ b/dev/build_envs.Rmd @@ -974,6 +974,22 @@ init <- function(project_path = ".", ) set_message_session_PATH(message_type = message_type) } + }, + overwrite = { + write_rprofile(rprofile_text, rprofile_file) + if (isTRUE(rprofile_exists)) { + message_rprofile( + action_string = "Overwrote", project_path = project_path + ) + } else { + message_rprofile( + action_string = "Added", project_path = project_path + ) + } + if (message_type == "verbose") { + cat("\n* Current lines of local `.Rprofile` are:\n\n") + cat(readLines(con = file(rprofile_file)), sep = "\n") + } } ) From ed0b628902c640877f9e98e539ffbcd0f25e8a3c Mon Sep 17 00:00:00 2001 From: Philipp Baumann Date: Tue, 16 Jan 2024 20:15:46 +0100 Subject: [PATCH 16/16] Implement `"append"` option --- R/find_rev.R | 28 +++++++++++++++------------- dev/build_envs.Rmd | 28 +++++++++++++++------------- 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/R/find_rev.R b/R/find_rev.R index 658f17e4..e60ed523 100644 --- a/R/find_rev.R +++ b/R/find_rev.R @@ -844,10 +844,6 @@ init <- function(project_path = ".", "\n* Keep existing `.Rprofile`. in `project_path`:\n", paste0(project_path, "/"), "\n" ) - if (message_type == "verbose") { - cat("\n* Current lines of local `.Rprofile` are:\n\n") - cat(readLines(con = file(rprofile_file)), sep = "\n") - } } else { write_rprofile(rprofile_text, rprofile_file) message_rprofile(action_string = "Added", project_path = project_path) @@ -856,10 +852,6 @@ init <- function(project_path = ".", }, create_backup = { if (isTRUE(rprofile_exists)) { - if (message_type == "verbose") { - cat("\n* Current lines of local `.Rprofile` are\n:") - cat(readLines(con = file(rprofile_file)), sep = "\n") - } file.copy(from = rprofile_file, to = rprofile_backup) cat( "\n==> Backed up existing `.Rprofile` in file:\n", rprofile_backup, @@ -870,6 +862,10 @@ init <- function(project_path = ".", action_string = "Overwrote", project_path = project_path ) + if (message_type == "verbose") { + cat("\n* Current lines of local `.Rprofile` are\n:") + cat(readLines(con = file(rprofile_file)), sep = "\n") + } set_message_session_PATH(message_type = message_type) } }, @@ -884,12 +880,19 @@ init <- function(project_path = ".", action_string = "Added", project_path = project_path ) } - if (message_type == "verbose") { - cat("\n* Current lines of local `.Rprofile` are:\n\n") - cat(readLines(con = file(rprofile_file)), sep = "\n") - } + }, + append = { + cat(paste0(rprofile_text, "\n"), file = rprofile_file, append = TRUE) + message_rprofile( + action_string = "Appended", project_path = project_path + ) } ) + + if (message_type == "verbose") { + cat("\n* Current lines of local `.Rprofile` are:\n\n") + cat(readLines(con = file(rprofile_file)), sep = "\n") + } on.exit(close(file(rprofile_file))) } @@ -910,7 +913,6 @@ get_rprofile_text <- function(rprofile_deparsed) { ) } - #' @noRd message_rprofile <- function(action_string = "Added", project_path = ".") { diff --git a/dev/build_envs.Rmd b/dev/build_envs.Rmd index fda724b4..61950173 100644 --- a/dev/build_envs.Rmd +++ b/dev/build_envs.Rmd @@ -943,10 +943,6 @@ init <- function(project_path = ".", "\n* Keep existing `.Rprofile`. in `project_path`:\n", paste0(project_path, "/"), "\n" ) - if (message_type == "verbose") { - cat("\n* Current lines of local `.Rprofile` are:\n\n") - cat(readLines(con = file(rprofile_file)), sep = "\n") - } } else { write_rprofile(rprofile_text, rprofile_file) message_rprofile(action_string = "Added", project_path = project_path) @@ -955,10 +951,6 @@ init <- function(project_path = ".", }, create_backup = { if (isTRUE(rprofile_exists)) { - if (message_type == "verbose") { - cat("\n* Current lines of local `.Rprofile` are\n:") - cat(readLines(con = file(rprofile_file)), sep = "\n") - } file.copy(from = rprofile_file, to = rprofile_backup) cat( "\n==> Backed up existing `.Rprofile` in file:\n", rprofile_backup, @@ -969,6 +961,10 @@ init <- function(project_path = ".", action_string = "Overwrote", project_path = project_path ) + if (message_type == "verbose") { + cat("\n* Current lines of local `.Rprofile` are\n:") + cat(readLines(con = file(rprofile_file)), sep = "\n") + } set_message_session_PATH(message_type = message_type) } }, @@ -983,12 +979,19 @@ init <- function(project_path = ".", action_string = "Added", project_path = project_path ) } - if (message_type == "verbose") { - cat("\n* Current lines of local `.Rprofile` are:\n\n") - cat(readLines(con = file(rprofile_file)), sep = "\n") - } + }, + append = { + cat(paste0(rprofile_text, "\n"), file = rprofile_file, append = TRUE) + message_rprofile( + action_string = "Appended", project_path = project_path + ) } ) + + if (message_type == "verbose") { + cat("\n* Current lines of local `.Rprofile` are:\n\n") + cat(readLines(con = file(rprofile_file)), sep = "\n") + } on.exit(close(file(rprofile_file))) } @@ -1009,7 +1012,6 @@ get_rprofile_text <- function(rprofile_deparsed) { ) } - #' @noRd message_rprofile <- function(action_string = "Added", project_path = ".") {