Reputation: 1414
Currently, the default and latest Ruby in Nix is 2.2.2-p0. When I run nix-env -qaP ruby
it returns a list, which says that this ruby version is accessed via nixpkgs.ruby
. I expect that this Ruby link will change to stay up-to-date with the latest supported ruby version. There is no optional nixpkgs.ruby_2_2_2 for me to use to ensure my ruby version.
Looking at the .nix definition file at https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/interpreters/ruby/ruby-2.2.2.nix, however, I see that they specify the revision in that script.
So I'm wondering, is there some way for me to specify the revision of the Nix package that I want when I'm listing it in the buildInputs
of my Nix expression for creating the development environment (which will be accessed via nix-shell .
)? Or is there something else that I might do that would enable me to ensure that ruby 2.2.2-p0 is used for the installation, and not just the latest Ruby, which might change?
Current script:
let
pkgs = import <nixpkgs> {};
in with pkgs; {
rubyEnv = stdenv.mkDerivation rec {
name = "ruby-env";
version = "0.1";
src = ./.;
buildInputs = [
stdenv
ruby
bundler_HEAD
];
};
}
I didn't see this covered in the documentation at http://nixos.org/nix/manual/#chap-writing-nix-expressions
Upvotes: 3
Views: 1199
Reputation: 2091
The currently accepted answer (Aug 2023) is obsolete because nixpkgs doesn't carry point-releases for Ruby anymore, only minor versions. So if you need e.g. 3.2.0, but nixpkgs is on 3.2.2, you have to build it yourself or get an old Ruby.
mkRuby
Here's how to build 3.2.0 using nix(pkgs), using all the latest toolchains etc:
let
pkgs = (import <nixpkgs> {});
ruby_3_2_0 = pkgs.mkRuby {
version = pkgs.mkRubyVersion "3" "2" "0" "";
# Leave this empty. Nix will complain, and tell you what
# value to put here.
sha256 = "";
};
in
ruby_3_2_0
Here's how to use that to e.g. get a dev shell:
nix shell --impure --expr 'let ...'
Or using old style nix:
nix-shell -E 'let ... in pkgs.mkShell { packages = [ ruby_3_2_0 ]; }'
I guess you can install it the same way, using nix-env -i -E 'let ...'
, although I don't use nix-env locally so I can't try it.
This solution works for as long as nixpkgs carries the right information for you to build ruby locally, such as the necessary patches etc. At some point, your ruby version falls so far behind that nixpkgs won't maintain that anymore.
You can always go back to an old version of nixpkgs which has the ruby version you want.
Finding the right nixpkgs commit though can be a bit of a dark art. Ruby is a perfect example here because it's so tricky. I'll take you through some examples.
I first use the nixpkgs PR tracker to find the right version: ruby 3.2.1 in:title
. If you look closely, you can see a PR labeled "init at 3.2.1", which I'm assuming means they started tracking the 3.2.x minor at 3.2.1, not 3.2.0. Let's take that commit, as it was merged into their staging branch: a239c7d2eeaad81602f83ece87dc7bfa5593ceab
.†
Now we can do:
# _3_2, not _3_2_1
nix shell github:NixOS/nixpkgs/a239c7d2eeaad81602f83ece87dc7bfa5593ceab#ruby_3_2
ruby --version
† See the "Get latest successful Hydra build" chapter for a better strategy on choosing a commit.
I can't find any record of ruby 3.2.0 ever living in nixpkgs, so I have a feeling your only option is to build this yourself.
A different example: 2.3.0. Much older (2016), from a time nixpkgs didn't have flakes (did they even exist at all?).
I use the same GitHub PR search, this time it's an easier find: commit 3d4dff50724030376d7b7c3d4714d375f416f004
into master. But as there were no flakes at that time:
$ nix shell github:NixOS/nixpkgs/3d4dff50724030376d7b7c3d4714d375f416f004#ruby_2_3_0
error: getting status of '/nix/store/c0csr6c2lxhqhf1s148bq44fz6v5mpp7-source/flake.nix': No such file or directory
So instead I use:
$ nix shell --impure --expr 'let pkgs = (import (builtins.fetchTarball "https://github.com/NixOS/nixpkgs/archive/3d4dff50724030376d7b7c3d4714d375f416f004.tar.gz") {}); in pkgs.ruby_2_3_0'
But another problem arises:
... long error snip ...
error: Package ‘ruby-2.3.0-p0’ in ‘/nix/store/c0csr6c2lxhqhf1s148bq44fz6v5mpp7-source/pkgs/development/interpreters/ruby/default.nix:123’ is not supported on ‘aarch64-darwin’, refusing to evaluate.
a) For `nixos-rebuild` you can set
{ nixpkgs.config.allowBroken = true; }
in configuration.nix to override this.
b) For `nix-env`, `nix-build` or any other Nix command you can add
{ allowBroken = true; }
to ~/.nixpkgs/config.nix.
This is because my laptop is aarch64-darwin
(aka Apple Silicon), and that's not supported by Ruby in 2016 (makes sense). If I fire up a linux x86 virtual machine, though, and use the same line, it works.
A merge commit into nixpkgs' stable branch is probably not an ideal revision, because the big nixpkgs CI (called Hydra) doesn't build every staging version. You will end up rebuilding the entire world yourself, including compilers and everything up to ruby itself. This does work in a pinch, but it's painful. It's a lot worse than the solution at the top using mkRuby
, because that uses existing, pre-built compilers, and only needs to compile Ruby itself. Not the entire toolchain.
The better solution is to find "what was the first revision that Hydra built that contains my target revision?". As far as I know there is no clean solution to this. My best bet for now is the unofficial https://channels.nix.gsc.io, e.g. picking my desired channel nixpkgs-unstable
: "https://channels.nix.gsc.io/nixpkgs-unstable/history-v2". Unfortunately I see its last update was May 2023, and it's Aug by now, so I fear it's out of date. Still, I know my commit is from March 2023 so I can demonstrate:
git clone https://github.com/NixOS/nixpkgs && cd nixpkgs
targettime=$(git show -s --format=%ct a239c7d2eeaad81602f83ece87dc7bfa5593ceab)
curl -sSL --fail https://channels.nix.gsc.io/nixpkgs-unstable/history-v2 | \
while read rev time rest ; do
if [[ "$time" -lt "$targettime" ]]; then
continue
fi
if git merge-base --is-ancestor a239c7d2eeaad81602f83ece87dc7bfa5593ceab "$rev"; then
echo "$rev"
break
fi
done
I got 98f3b08f58ff125ef02d55cd52a83f44f245f2ea
. Plugging that into the same nix shell ..
line above gives me a result without building anything, just downloading ruby 3.2.1 from Hydra.
Upvotes: 0
Reputation: 2884
There is no optional nixpkgs.ruby_2_2_2 for me to use to ensure my ruby version.
Actually there is a ruby_2_2_2
in nixpkgs:
$ nix-env -qaP ruby
nixos.ruby_1_8 ruby-1.8.7-p374
nixos.ruby_1_9 ruby-1.9.3-p551
nixos.ruby_2_0 ruby-2.0.0-p645
nixos.ruby_2_1_0 ruby-2.1.0-p0
nixos.ruby_2_1_1 ruby-2.1.1-p0
nixos.ruby_2_1_2 ruby-2.1.2-p353
nixos.ruby_2_1_3 ruby-2.1.3-p0
nixos.ruby_2_1 ruby-2.1.6-p0
nixos.ruby_2_2_0 ruby-2.2.0-p0
nixos.ruby ruby-2.2.2-p0
nixos.bundler_HEAD ruby-2.2.2-p0-bundler-2015-01-11
By looking at the definition of ruby package in the index, you can see that the current default ruby is just an alias to ruby 2.2:
ruby = ruby_2_2;
that is in turn an alias to ruby 2.2.2:
ruby_2_2 = ruby_2_2_2;
To override the ruby package to a specific ruby version in a nix expression, overridePackages
can be used:
let
nixpkgs = import <nixpkgs> {};
pkgs = nixpkgs.overridePackages (self: super: {
ruby = nixpkgs.ruby_2_2_2;
});
in with pkgs;
{
rubyEnv = stdenv.mkDerivation rec {
name = "ruby-env";
version = "0.1";
src = ./.;
buildInputs = [
stdenv
ruby
bundler
];
};
}
Upvotes: 3