Hi,
I’d appreciate some help with building an R package locally and using a flake in order to lock the versions of the other packages it depends on.
I have the source code of the R package and describe it in myown.nix
as follows
{ pkgs }:
let
depR = with pkgs.rPackages; [
data_table # all other packages on which my package depends
];
in
pkgs.rPackages.buildRPackage {
name = "myown";
src = ./.;
propagatedBuildInputs = depR;
}
I create a development shell with this package as follows. default.nix
:
let
pkgs = import <nixpkgs> {};
myown = import ./path-to/myown.nix { inherit pkgs; };
depProduction = with pkgs; [
glibcLocales # locales are required by R
R # request R with packages as specifed below
];
in
pkgs.mkShell rec {
nativeBuildInputs = depProduction ++ (with pkgs.rPackages; [
myown
]);
}
Whenever I nix-shell
, nix seems to verify some hash on the sources of myown
and, if they have changed, recompile the package. The development shell works.
Now I want to fix the versions of the dependencies of myown
(data_table
in the above example) and the current state of myown
and check that package into the nix store in order to use this specific version until I decide to upgrade.
From what I understand, I should now turn the R package into a derivation, build it with a flake, and then create the development shell in such a way that it uses exactly the version produced by that flake.
I’d be grateful if someone could point me to a working example where this is done.
What if you just used a pinned version of nixpkgs
? Does that accomplish what you’re trying to do?
let
pkgs = import <nixpkgs> {};
pinned = import (fetchTarball "https://github.com/NixOS/nixpkgs/tarball/nixos-24.05") {};
myown = import ./package.nix { pkgs = pinned; };
depProduction = [
pkgs.R # request R with packages as specifed below
];
in
pkgs.mkShell {
nativeBuildInputs = depProduction ++ [ myown ];
}
Thanks - this is an efficient solution.
In order to be on the safe side, I pinned everything to a specific commit of nixpkgs:
pkgs = import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/e8c38b73aeb218e27163376a2d617e61a2ad9b59.tar.gz") {};
Do I understand this correctly that now all versions of all packages are pinned, i.e. I will miss out on all security relevant bug fixes, too? If so, this is what I want - it affects R and its CRAN packages in this case.
I’m not sure I exactly understand what the end goal is, but this might help:
let
pkgs = import <nixpkgs> {};
pinned = import (fetchTarball "https://github.com/NixOS/nixpkgs/tarball/nixos-23.05") {};
myown = import ./package.nix { pkgs = pinned; };
depProduction = [
pkgs.R
pkgs.rPackages.devtools
];
in
pkgs.mkShell {
nativeBuildInputs = depProduction ++ [ myown pkgs.rPackages.data_table ];
}
This nix-shell with a package.nix file that also has data.table as an input will give you the following:
> .libPaths()[grepl("data.table", .libPaths())]
[1] "/nix/store/pidjv5xf8biyi0f6r7fygahgx4bzqzlw-r-data.table-1.14.8/library"
[2] "/nix/store/rczlw3v714iywx5jhfy0q8chavfh9bgq-r-data.table-1.15.4/library"
> packageVersion("data.table")
[1] ‘1.14.8’
You’ll get 2 paths for data.table
but R will only use one of them. In this case the one in package.nix takes precedent. IF you swap pinned
and pkgs
, you’ll get data.table version 1.15.4 instead and an older version of R in the final shell. So nix-shell maintains some kind of order here that you could use to your advantage.
In either case, you can also just use the lib.loc
option to load the right version.
library(data.table, lib.loc="/nix/store/rczlw3v714iywx5jhfy0q8chavfh9bgq-r-data.table-1.15.4/library")
Not really a great solution on its own, but you could always write a function that looks in .libPaths and loads a specific version.
Yes, pinning the nixpkgs version will pin R and R packages to that point in time. I wouldn’t expect it to change at all except in the rare case that something is backported.