Skip to content

Commit

Permalink
Merge pull request #231 from b-rodrigues/rix_init_after_rix
Browse files Browse the repository at this point in the history
- rix() now runs rix_init() to ensure runtime purity
  • Loading branch information
b-rodrigues authored Jul 2, 2024
2 parents ad53dcc + 1e5a412 commit e23c9c4
Show file tree
Hide file tree
Showing 28 changed files with 1,220 additions and 501 deletions.
2 changes: 2 additions & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,5 @@ create_dev_env.R
^.*.tar.gz
^\.pre-commit-config\.yaml$
^data-raw$
.envrc
.direnv
4 changes: 2 additions & 2 deletions .github/workflows/test-fetchlocal.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ jobs:

- name: Build default.nix with 2 local packages
run: |
nix-shell ./inst/extdata/default.nix --run "Rscript -e \"library(rix);rix('4.3.1', local_pkgs = c('chronicler_0.2.1.tar.gz', 'knitr_1.43.tar.gz'), overwrite = TRUE)\""
nix-shell ./inst/extdata/default.nix --run "Rscript -e \"library(rix);rix('4.3.1', local_r_pkgs = c('chronicler_0.2.1.tar.gz', 'knitr_1.43.tar.gz'), overwrite = TRUE)\""
- name: Build default.nix
run: nix-build

- name: Build default.nix with 1 local package
run: |
nix-shell ./inst/extdata/default.nix --run "Rscript -e \"library(rix);rix('4.3.1', local_pkgs = 'chronicler_0.2.1.tar.gz', overwrite = TRUE)\""
nix-shell ./inst/extdata/default.nix --run "Rscript -e \"library(rix);rix('4.3.1', local_r_pkgs = 'chronicler_0.2.1.tar.gz', overwrite = TRUE)\""
- name: Build default.nix
run: nix-build
20 changes: 12 additions & 8 deletions R/fetchers.R
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ remove_base <- function(list_imports) {
get_imports <- function(path) {
tmp_dir <- tempdir()

# Some packages have a Description file in the testthat folder
# (see jimhester/lookup) so we need to get rid of that
path <- Filter(function(x)!grepl("testthat", x), path)

# Is the path pointing to a tar.gz archive
# or directly to a DESCRIPTION file?
if (grepl("\\.tar\\.gz", path)) {
Expand Down Expand Up @@ -189,25 +193,25 @@ fetchlocal <- function(local_pkg) {
}

#' fetchlocals Installs a local R package
#' @param local_pkgs Either a list of paths to local packages, or a path to a
#' @param local_r_pkgs Either a list of paths to local packages, or a path to a
#' single package
#' @return A character. The Nix definition to build the local R packages from
#' local sources.
#' @noRd
fetchlocals <- function(local_pkgs) {
paths_exist <- file.exists(local_pkgs)
fetchlocals <- function(local_r_pkgs) {
paths_exist <- file.exists(local_r_pkgs)

if (!all(paths_exist)) {
stop(
paste0(
"local_pkgs: The following paths are incorrect:\n",
paste(local_pkgs[!paths_exist], collapse = "\n")
"local_r_pkgs: The following paths are incorrect:\n",
paste(local_r_pkgs[!paths_exist], collapse = "\n")
)
)
} else if (length(local_pkgs) == 1) {
fetchlocal(local_pkgs)
} else if (length(local_r_pkgs) == 1) {
fetchlocal(local_r_pkgs)
} else {
paste(lapply(local_pkgs, fetchlocal), collapse = "\n")
paste(lapply(local_r_pkgs, fetchlocal), collapse = "\n")
}
}

Expand Down
218 changes: 145 additions & 73 deletions R/rix.R

Large diffs are not rendered by default.

26 changes: 13 additions & 13 deletions R/rix_helpers.R
Original file line number Diff line number Diff line change
Expand Up @@ -137,21 +137,21 @@ generate_rpkgs <- function(rPackages, flag_rpkgs) {
}
}

#' generate_local_pkgs Internal function that generates the string containing the correct Nix expression for installing local packages
#' @param local_pkgs Character, list of local R packages to install.
#' @param flag_local_pkgs Character, are there any local R packages at all?
#' generate_local_r_pkgs Internal function that generates the string containing the correct Nix expression for installing local packages
#' @param local_r_pkgs Character, list of local R packages to install.
#' @param flag_local_r_pkgs Character, are there any local R packages at all?
#' @noRd
generate_local_pkgs <- function(local_pkgs, flag_local_pkgs) {
if (flag_local_pkgs == "") {
generate_local_r_pkgs <- function(local_r_pkgs, flag_local_r_pkgs) {
if (flag_local_r_pkgs == "") {
NULL
} else {
sprintf(
"
local_pkgs = [
local_r_pkgs = [
%s
];
",
fetchlocals(local_pkgs)
fetchlocals(local_r_pkgs)
)
}
}
Expand Down Expand Up @@ -272,13 +272,13 @@ generate_locale_variables <- function() {
#' @param attrib Character, set the correct wrapper for the Nix expression.
#' @param flag_git_archive Character, are there R packages from Github at all?
#' @param flag_rpkgs Character, are there any R packages at all?
#' @param flag_local_pkgs Character, are there any local R packages at all?
#' @param flag_local_r_pkgs Character, are there any local R packages at all?
#' @noRd
generate_wrapped_pkgs <- function(ide,
attrib,
flag_git_archive,
flag_rpkgs,
flag_local_pkgs) {
flag_local_r_pkgs) {
if (flag_rpkgs == "") {
return(NULL)
} else if (ide %in% names(attrib)) {
Expand All @@ -291,7 +291,7 @@ generate_wrapped_pkgs <- function(ide,
attrib[ide],
flag_git_archive,
flag_rpkgs,
flag_local_pkgs
flag_local_r_pkgs
)
} else {
NULL
Expand All @@ -303,14 +303,14 @@ generate_wrapped_pkgs <- function(ide,
#' @param flag_git_archive Character, are there R packages from Github at all?
#' @param flag_rpkgs Character, are there any R packages at all?
#' @param flag_tex_pkgs Character, are there any LaTex packages at all?
#' @param flag_local_pkgs Character, are there any wrapped packages at all?
#' @param flag_local_r_pkgs Character, are there any wrapped packages at all?
#' @param flag_wrapper Character, are there any wrapped packages at all?
#' @param shell_hook Character, the mkShell's shellHook.
#' @noRd
generate_shell <- function(flag_git_archive,
flag_rpkgs,
flag_tex_pkgs,
flag_local_pkgs,
flag_local_r_pkgs,
flag_wrapper,
shell_hook) {
sprintf(
Expand All @@ -328,7 +328,7 @@ pkgs.mkShell {
flag_git_archive,
flag_rpkgs,
flag_tex_pkgs,
flag_local_pkgs,
flag_local_r_pkgs,
flag_wrapper,
shell_hook
)
Expand Down
63 changes: 35 additions & 28 deletions R/rix_init.R
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@
#' reproducibility of Nix-R environments during runtime. Concretely, if you
#' already have a system or user library of R packages (if you have R installed
#' through the usual means for your operating system), using `rix::rix_init()`
#' will prevent Nix-R environments to load packages from the user library
#' which would cause issues.
#' 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:
#' will prevent Nix-R environments to load packages from the user library which
#' would cause issues. 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
Expand All @@ -41,9 +41,9 @@
#' 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::rix_init()` ensures
#' that Nix command line programs are accessible by adding the path of the
#' "bin" directory of the default Nix profile,
#' might not be found. The `.Rprofile` code written by `rix::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.
#'
Expand All @@ -55,28 +55,32 @@
#' packaged for macOS. We recommend calling `rix::rix_init()` prior to comparing R
#' 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 working directory path. If the folder
#' does not exist yet, it will be created.
#' `rix::rix_init()` is called automatically by `rix::rix()` when generating a
#' `default.nix` file, and when called by `rix::rix()` will only add the `.Rprofile`
#' if none exists. In case you have a custom `.Rprofile` that you wish to keep
#' using, but also want to benefit from what `rix_init()` offers, manually call
#' it and set the `rprofile_action` to `"append"`.
#'
#' @param project_path Character with the folder path to the isolated nix-R
#' project. Defaults to `"."`, which is the current working directory path. If
#' the folder does not exist yet, it will be created.
#' @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::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.
#' destined for `project_path` folder. Possible values include
#' `"create_missing"`, which only writes `.Rprofile` if it does not yet exist
#' (otherwise does nothing) - this is the action set when using `rix()` - ;
#' `"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::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.
#' @param message_type Character. Message type, defaults to `"simple"`, which
#' gives minimal but sufficient feedback. Other values are currently
#' `"quiet`, which writes `.Rprofile` without message, and
#' `"verbose"`, which displays the mechanisms implemented to achieve fully
#' controlled R project environments in Nix.
#' gives minimal but sufficient feedback. Other values are currently
#' `"quiet`, which writes `.Rprofile` without message, and `"verbose"`,
#' which displays the mechanisms implemented to achieve fully controlled R project environments in Nix.
#' @export
#' @seealso [with_nix()]
#' @return Nothing, this function only has the side-effect of writing a file
#' called ".Rprofile" to the specified path.
#' @return Nothing, this function only has the side-effect of writing a file called ".Rprofile" to the specified path.
#' @examples
#' \dontrun{
#' # create an isolated, runtime-pure R setup via Nix
Expand Down Expand Up @@ -412,6 +416,9 @@ nix_rprofile <- function() {
}

if (isTRUE(is_nix_r)) {
install.packages <- function(...){
stop("You are currently in an R session running from Nix.\nDon't install packages using install.packages(),\nadd them to the default.nix file instead.")
}
current_paths <- .libPaths()
userlib_paths <- Sys.getenv("R_LIBS_USER")
user_dir <- grep(paste(userlib_paths, collapse = "|"), current_paths, fixed = TRUE)
Expand Down
3 changes: 1 addition & 2 deletions R/with_nix.R
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,11 @@
#' can easily do so by providing Nix expressions in custom `.nix` or
#' `default.nix` files in different subfolders of the project.
#'
#' It is recommended that you use `rix_init()` to generate a custom `.Rprofile`
#' `rix_init()` is run automatically to generate a custom `.Rprofile`
#' file for the subshell in `project_dir`. The defaults in that file ensure
#' that only R packages from the Nix store, that are defined in the subshell
#' `.nix` file are loaded and system's libraries are excluded.
#'
#'
#' To do its job, `with_nix()` heavily relies on patterns that manipulate
#' language expressions (aka computing on the language) offered in base R as
#' well as the \{codetools\} package by Luke Tierney.
Expand Down
12 changes: 6 additions & 6 deletions inst/extdata/default.nix
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This file was generated by the {rix} R package v0.7.1 on 2024-06-28
# This file was generated by the {rix} R package v0.7.1 on 2024-07-02
# with following call:
# >rix(r_ver = "1e3deb3d8a86a870d925760db1a5adecc64d329d",
# >rix(r_ver = "b9014df496d5b68bf7c0145d0e9b0f529ce4f2a8",
# > r_pkgs = NULL,
# > system_pkgs = NULL,
# > git_pkgs = list(package_name = "rix",
Expand All @@ -11,20 +11,20 @@
# > project_path = "../inst/extdata",
# > overwrite = TRUE,
# > shell_hook = NULL)
# It uses nixpkgs' revision 1e3deb3d8a86a870d925760db1a5adecc64d329d for reproducibility purposes
# It uses nixpkgs' revision b9014df496d5b68bf7c0145d0e9b0f529ce4f2a8 for reproducibility purposes
# which will install R version latest.
# Report any issues to https://github.com/b-rodrigues/rix
let
pkgs = import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/1e3deb3d8a86a870d925760db1a5adecc64d329d.tar.gz") {};
pkgs = import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/b9014df496d5b68bf7c0145d0e9b0f529ce4f2a8.tar.gz") {};

git_archive_pkgs = [
(pkgs.rPackages.buildRPackage {
name = "rix";
src = pkgs.fetchgit {
url = "https://github.com/b-rodrigues/rix/";
branchName = "master";
rev = "1a9680f892024ca08d2b5af737baba0a9a042339";
sha256 = "sha256-HkNE+4VrtqEOOMxyxqz6jnSMg/1SOppdTyKif/yR0ss=";
rev = "ad53dccd9f87e56a5c9e486b11e5c8f659fcb162";
sha256 = "sha256-spwHEm6ohT5p2Ef8GNbsMjyL3FgMoAvCn7mQjZ2ruQs=";
};
propagatedBuildInputs = builtins.attrValues {
inherit (pkgs.rPackages)
Expand Down
Loading

0 comments on commit e23c9c4

Please sign in to comment.