---
title: "d1 - Installing R packages in a Nix environment"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{d1-installing-r-packages-in-a-nix-environment}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

```{r, include=FALSE}
library(rix)
```

## Introduction

You now know how to declare and build reproducible development environments
using `{rix}` and Nix. This vignette will explain how to install specific
versions of CRAN packages and how to install packages from GitHub.

## A word of caution

It is important at this stage to understand that you should not call
`install.packages()` from a running Nix environment. If you want to add
packages while analyzing data, you need to add it the `default.nix` 
expression and rebuild the environment. The same goes for installing
packages from Github; use the method described in this vignette instead 
of using something like `remotes::install_github()`.

We recommend you create a script called `create_env.R` or similar, and add the call to `rix()` there:

```
library(rix)

rix(r_ver = "4.4.0",
    r_pkgs = c("dplyr", "ggplot2"),
    system_pkgs = NULL,
    git_pkgs = NULL,
    ide = "code",
    project_path = path_default_nix,
    overwrite = TRUE,
    print = TRUE)
```

Then, add the packages you need to `r_pkgs` and run the script again. Then, build
the environment using `nix-build` again, and drop into it using `nix-shell`.
Calling `install.packages()` is a bad idea for several reasons:

- it goes against the idea of defining an environment in a declarative way. If
  you were able to add packages using `install.packages()`, your environment
  would end up in a state where the `default.nix` definition of the environment
  and the actual environment don't match anymore.
- using `install.packages()` will likely simply not work, and if it does, will
  cause issues. For example, if you call `install.packages("ggplot2")` from one
  Nix shell, it will not install `{ggplot2}` "inside" the Nix shell, but will
  install it on your user's system library of packages. This is because the Nix
  shell cannot be changed at run-time, and so, R will instead install the
  packages in the user's library. This version of `{ggplot2}`, because it is in
  that system-wide library of packages, will be available to any other Nix
  shell. If you call `install.packages("ggplot2")` again from another Nix shell,
  say 6 months later, this will replace the first version of `{ggplot2}` with
  the latest version.

Ideally, you should only manage R versions and R packages using Nix, and
uninstall any system-managed version of R and R packages. But if you do wish to keep
a system-managed version of R and R packages, `rix::rix()` also runs `rix::rix_init()`
automatically which generates an `.Rprofile` file that avoids any clashes between
your global user library and Nix-managed libraries of R packages.

## Installing old packages archived on CRAN

It is possible to install an arbitrary version of a package that has been
archived on CRAN:

```{r, eval = F}
path_default_nix <- tempdir()

rix(
  r_ver = "4.2.1",
  r_pkgs = c("dplyr@0.8.0", "janitor@1.0.0"),
  system_pkgs = NULL,
  git_pkgs = NULL,
  ide = "other",
  project_path = path_default_nix,
  overwrite = TRUE
)
```

```
#> # This file was generated by the {rix} R package v0.7.1 on 2024-07-01
#> # with following call:
#> # >rix(r_ver = "79b3d4bcae8c7007c9fd51c279a8a67acfa73a2a",
#> #  > r_pkgs = c("dplyr@0.8.0",
#> #  > "janitor@1.0.0"),
#> #  > system_pkgs = NULL,
#> #  > git_pkgs = NULL,
#> #  > ide = "other",
#> #  > project_path = path_default_nix,
#> #  > overwrite = TRUE)
#> # It uses nixpkgs' revision 79b3d4bcae8c7007c9fd51c279a8a67acfa73a2a for reproducibility purposes
#> # which will install R version 4.2.1.
#> # Report any issues to https://github.com/ropensci/rix
#> let
#>  pkgs = import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/79b3d4bcae8c7007c9fd51c279a8a67acfa73a2a.tar.gz") {};
#>   
#>   git_archive_pkgs = [ 
#>     (pkgs.rPackages.buildRPackage {
#>       name = "dplyr";
#>       src = pkgs.fetchzip {
#>        url = "https://cran.r-project.org/src/contrib/Archive/dplyr/dplyr_0.8.0.tar.gz";
#>        sha256 = "sha256-f30raalLd9KoZKZSxeTN71PG6BczXRIiP6g7EZeH09U=";
#>       };
#>       propagatedBuildInputs = builtins.attrValues {
#>         inherit (pkgs.rPackages) 
#>           assertthat
#>           glue
#>           magrittr
#>           pkgconfig
#>           R6
#>           Rcpp
#>           rlang
#>           tibble
#>           tidyselect
#>           BH
#>           plogr;
#>       };
#>     })
#> 
#> 
#>     (pkgs.rPackages.buildRPackage {
#>       name = "janitor";
#>       src = pkgs.fetchzip {
#>        url = "https://cran.r-project.org/src/contrib/Archive/janitor/janitor_1.0.0.tar.gz";
#>        sha256 = "sha256-3NJomE/CNbOZ+ohuVZJWe2n1RVGUm8x8a0A0qzLmdN4=";
#>       };
#>       propagatedBuildInputs = builtins.attrValues {
#>         inherit (pkgs.rPackages) 
#>           dplyr
#>           tidyr
#>           snakecase
#>           magrittr
#>           purrr
#>           rlang;
#>       };
#>     })
#>   ];
#>    
#>   system_packages = builtins.attrValues {
#>     inherit (pkgs) 
#>       R
#>       glibcLocales
#>       nix;
#>   };
#>   
#> in
#> 
#> pkgs.mkShell {
#>   LOCALE_ARCHIVE = if pkgs.system == "x86_64-linux" then  "${pkgs.glibcLocales}/lib/locale/locale-archive" else "";
#>   LANG = "en_US.UTF-8";
#>    LC_ALL = "en_US.UTF-8";
#>    LC_TIME = "en_US.UTF-8";
#>    LC_MONETARY = "en_US.UTF-8";
#>    LC_PAPER = "en_US.UTF-8";
#>    LC_MEASUREMENT = "en_US.UTF-8";
#> 
#>   buildInputs = [ git_archive_pkgs   system_packages   ];
#>   
#> }
```


The above expression will install R version 4.2.1, and `{dplyr}` at version
0.8.0 and `{janitor}` at version 1.0.0. This can be useful, especially for
packages that have been archived, but otherwise, this feature should ideally be
used sparingly. If you want to reconstruct an environment as it was around 2019,
use the version of R that was current at that time. This will ensure that every
package that gets installed is at a version compatible with that version of R,
which might not be the case if you need to install a very old version of one
particular package.

## Installing packages from Github

It is also possible to install packages from Github:

```{r, eval = F}
path_default_nix <- tempdir()

rix(
  r_ver = "4.2.1",
  r_pkgs = c("dplyr", "janitor"),
  git_pkgs = list(
    list(
      package_name = "housing",
      repo_url = "https://github.com/rap4all/housing/",
      commit = "1c860959310b80e67c41f7bbdc3e84cef00df18e"
    ),
    list(
      package_name = "fusen",
      repo_url = "https://github.com/ThinkR-open/fusen",
      commit = "d617172447d2947efb20ad6a4463742b8a5d79dc"
    )
  ),
  ide = "other",
  project_path = path_default_nix,
  overwrite = TRUE
)
```

```{r parsermd-chunk-4, echo = F}
#> # This file was generated by the {rix} R package v0.7.1 on 2024-07-01
#> # with following call:
#> # >rix(r_ver = "79b3d4bcae8c7007c9fd51c279a8a67acfa73a2a",
#> #  > r_pkgs = c("dplyr",
#> #  > "janitor"),
#> #  > git_pkgs = list(list(package_name = "housing",
#> #  > repo_url = "https://github.com/rap4all/housing/",
#> #  > commit = "1c860959310b80e67c41f7bbdc3e84cef00df18e"),
#> #  > list(package_name = "fusen",
#> #  > repo_url = "https://github.com/ThinkR-open/fusen",
#> #  > commit = "d617172447d2947efb20ad6a4463742b8a5d79dc")),
#> #  > ide = "other",
#> #  > project_path = path_default_nix,
#> #  > overwrite = TRUE)
#> # It uses nixpkgs' revision 79b3d4bcae8c7007c9fd51c279a8a67acfa73a2a for reproducibility purposes
#> # which will install R version 4.2.1.
#> # Report any issues to https://github.com/ropensci/rix
#> let
#>  pkgs = import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/79b3d4bcae8c7007c9fd51c279a8a67acfa73a2a.tar.gz") {};
#>
#>   rpkgs = builtins.attrValues {
#>     inherit (pkgs.rPackages)
#>       dplyr
#>       janitor;
#>   };
#>
#>   git_archive_pkgs = [
#>     (pkgs.rPackages.buildRPackage {
#>       name = "housing";
#>       src = pkgs.fetchgit {
#>         url = "https://github.com/rap4all/housing/";
#>         rev = "1c860959310b80e67c41f7bbdc3e84cef00df18e";
#>         sha256 = "sha256-s4KGtfKQ7hL0sfDhGb4BpBpspfefBN6hf+XlslqyEn4=";
#>       };
#>       propagatedBuildInputs = builtins.attrValues {
#>         inherit (pkgs.rPackages)
#>           dplyr
#>           ggplot2
#>           janitor
#>           purrr
#>           readxl
#>           rlang
#>           rvest
#>           stringr
#>           tidyr;
#>       };
#>     })
#>
#>
#>     (pkgs.rPackages.buildRPackage {
#>       name = "fusen";
#>       src = pkgs.fetchgit {
#>         url = "https://github.com/ThinkR-open/fusen";
#>         rev = "d617172447d2947efb20ad6a4463742b8a5d79dc";
#>         sha256 = "sha256-TOHA1ymLUSgZMYIA1a2yvuv0799svaDOl3zOhNRxcmw=";
#>       };
#>       propagatedBuildInputs = builtins.attrValues {
#>         inherit (pkgs.rPackages)
#>           attachment
#>           cli
#>           desc
#>           devtools
#>           glue
#>           here
#>           magrittr
#>           parsermd
#>           roxygen2
#>           stringi
#>           tibble
#>           tidyr
#>           usethis
#>           yaml;
#>       };
#>     })
#>    ];
#>
#>   system_packages = builtins.attrValues {
#>     inherit (pkgs)
#>       R
#>       glibcLocales
#>       nix;
#>   };
#>
#> in
#>
#> pkgs.mkShell {
#>   LOCALE_ARCHIVE = if pkgs.system == "x86_64-linux" then  "${pkgs.glibcLocales}/lib/locale/locale-archive" else "";
#>   LANG = "en_US.UTF-8";
#>    LC_ALL = "en_US.UTF-8";
#>    LC_TIME = "en_US.UTF-8";
#>    LC_MONETARY = "en_US.UTF-8";
#>    LC_PAPER = "en_US.UTF-8";
#>    LC_MEASUREMENT = "en_US.UTF-8";
#>
#>   buildInputs = [ git_archive_pkgs rpkgs  system_packages   ];
#>
#> }
```


This will install two packages from Github: the `{housing}` package and more
specifically the code as it is in the `fusen` branch; however the branch name is
not required, as the commit is enough to pin the exact version of the code
needed. The `{fusen}` package is also installed, as of commit `d617172447d`.

## Installing local archives

It is also possible to install packages from a local `tar.gz` file. For this,
place the package in the same folder where the `default.nix` will be generated,
and write something like this:

```{r, eval = F}
rix(
  r_ver = "4.3.1",
  local_r_pkgs = c("chronicler_0.2.1.tar.gz", "knitr_1.43.tar.gz"),
  overwrite = TRUE
)
```

This assumes that both `chronicler_0.2.1.tar.gz` and `knitr_1.43.tar.gz` have
been downloaded beforehand. If you want to include a local package that you are
developing, make sure to first build it using `devtools::build()` to build the
`.tar.gz` archive, but if you can, consider uploading the source code to your
package on Github and installing it from Github instead.

## A complete example

This example shows how to install packages from CRAN, from the CRAN archives and
from GitHub:

```{r, eval = F}
path_default_nix <- tempdir()

rix(
  r_ver = "4.2.1",
  r_pkgs = c("dplyr", "janitor", "AER@1.2-8"),
  git_pkgs = list(
    list(
      package_name = "housing",
      repo_url = "https://github.com/rap4all/housing/",
      commit = "1c860959310b80e67c41f7bbdc3e84cef00df18e"
    ),
    list(
      package_name = "fusen",
      repo_url = "https://github.com/ThinkR-open/fusen",
      commit = "d617172447d2947efb20ad6a4463742b8a5d79dc"
    )
  ),
  ide = "other",
  project_path = path_default_nix,
  overwrite = TRUE
)
```

```
#> # This file was generated by the {rix} R package v0.7.1 on 2024-07-01
#> # with following call:
#> # >rix(r_ver = "79b3d4bcae8c7007c9fd51c279a8a67acfa73a2a",
#> #  > r_pkgs = c("dplyr",
#> #  > "janitor",
#> #  > "AER@1.2-8"),
#> #  > git_pkgs = list(list(package_name = "housing",
#> #  > repo_url = "https://github.com/rap4all/housing/",
#> #  > commit = "1c860959310b80e67c41f7bbdc3e84cef00df18e"),
#> #  > list(package_name = "fusen",
#> #  > repo_url = "https://github.com/ThinkR-open/fusen",
#> #  > commit = "d617172447d2947efb20ad6a4463742b8a5d79dc")),
#> #  > ide = "other",
#> #  > project_path = path_default_nix,
#> #  > overwrite = TRUE)
#> # It uses nixpkgs' revision 79b3d4bcae8c7007c9fd51c279a8a67acfa73a2a for reproducibility purposes
#> # which will install R version 4.2.1.
#> # Report any issues to https://github.com/ropensci/rix
#> let
#>  pkgs = import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/79b3d4bcae8c7007c9fd51c279a8a67acfa73a2a.tar.gz") {};
#>  
#>   rpkgs = builtins.attrValues {
#>     inherit (pkgs.rPackages) 
#>       dplyr
#>       janitor;
#>   };
#>  
#>   git_archive_pkgs = [
#>     (pkgs.rPackages.buildRPackage {
#>       name = "housing";
#>       src = pkgs.fetchgit {
#>         url = "https://github.com/rap4all/housing/";
#>         rev = "1c860959310b80e67c41f7bbdc3e84cef00df18e";
#>         sha256 = "sha256-s4KGtfKQ7hL0sfDhGb4BpBpspfefBN6hf+XlslqyEn4=";
#>       };
#>       propagatedBuildInputs = builtins.attrValues {
#>         inherit (pkgs.rPackages) 
#>           dplyr
#>           ggplot2
#>           janitor
#>           purrr
#>           readxl
#>           rlang
#>           rvest
#>           stringr
#>           tidyr;
#>       };
#>     })
#> 
#> 
#>     (pkgs.rPackages.buildRPackage {
#>       name = "fusen";
#>       src = pkgs.fetchgit {
#>         url = "https://github.com/ThinkR-open/fusen";
#>         rev = "d617172447d2947efb20ad6a4463742b8a5d79dc";
#>         sha256 = "sha256-TOHA1ymLUSgZMYIA1a2yvuv0799svaDOl3zOhNRxcmw=";
#>       };
#>       propagatedBuildInputs = builtins.attrValues {
#>         inherit (pkgs.rPackages) 
#>           attachment
#>           cli
#>           desc
#>           devtools
#>           glue
#>           here
#>           magrittr
#>           parsermd
#>           roxygen2
#>           stringi
#>           tibble
#>           tidyr
#>           usethis
#>           yaml;
#>       };
#>     })
#>  
#>     (pkgs.rPackages.buildRPackage {
#>       name = "AER";
#>       src = pkgs.fetchzip {
#>        url = "https://cran.r-project.org/src/contrib/Archive/AER/AER_1.2-8.tar.gz";
#>        sha256 = "sha256-OqxXcnUX/2C6wfD5fuNayc8OU+mstI3tt4eBVGQZ2S0=";
#>       };
#>       propagatedBuildInputs = builtins.attrValues {
#>         inherit (pkgs.rPackages) 
#>           car
#>           lmtest
#>           sandwich
#>           survival
#>           zoo
#>           Formula;
#>       };
#>     })
#>   ];
#>    
#>   system_packages = builtins.attrValues {
#>     inherit (pkgs) 
#>       R
#>       glibcLocales
#>       nix;
#>   };
#>   
#> in
#> 
#> pkgs.mkShell {
#>   LOCALE_ARCHIVE = if pkgs.system == "x86_64-linux" then  "${pkgs.glibcLocales}/lib/locale/locale-archive" else "";
#>   LANG = "en_US.UTF-8";
#>    LC_ALL = "en_US.UTF-8";
#>    LC_TIME = "en_US.UTF-8";
#>    LC_MONETARY = "en_US.UTF-8";
#>    LC_PAPER = "en_US.UTF-8";
#>    LC_MEASUREMENT = "en_US.UTF-8";
#>
#>   buildInputs = [ git_archive_pkgs rpkgs  system_packages   ];
#>
#> }
```


The next vignette,
`vignette("d2-installing-system-tools-and-texlive-packages-in-a-nix-environment")`,
explains how you can install tools such as text editors, git, Quarto, TexLive
packages, and any other tool available through `nixpkgs` for your development
environments.

