d1 - Installing R packages in a Nix environment
Source:vignettes/d1-installing-r-packages-in-a-nix-environment.Rmd
d1-installing-r-packages-in-a-nix-environment.Rmd
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 thedefault.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 callinstall.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 callinstall.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:
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:
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
)
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:
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:
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.