FAQ/Pinning Nixpkgs: Difference between revisions

imported>Profpatsch
Move the unstable service section down, since it is less relevant to most people than general nixpkgs pinning
Sandro (talk | contribs)
Drop pre nix 2.0, warn about negatives of pinning
 
(10 intermediate revisions by 7 users not shown)
Line 1: Line 1:
{{FAQ/breadcrumb}}
It is possible (and indeed, fairly easy) to pin a specific version of
It is possible (and indeed, fairly easy) to pin a specific version of
Nixpkgs. This can be used to upgrade individual applications
Nixpkgs. This can be used to upgrade individual applications
Line 4: Line 5:
not impacted by other systems' requirements.
not impacted by other systems' requirements.


== Nix 2.0 onwards ==
Another reason why one would want to pin nixpkgs is to get older versions of a specific software. [https://lazamar.co.uk/nix-versions/ This site] can show you all the versions a package went through, and what nixpkgs revision to use to get your specific version.
 
Note: You can <code>sudo nix-channel --remove nixpkgs</code>, but you still need a nix-channel for nixos
 
Be aware that this also pins all dependencies of the application which often causes issues for GUI applications and also brings in back outdated and potentially vulnerable dependencies.
 
<pre>
sudo nix-channel --list
nixos https://nixos.org/channels/nixos-21.05
</pre>


Nix 2.0 introduces new builtins, <code>fetchTarball</code> and <code>fetchGit</code>, which make it possible to fetch a specific version of nixpkgs without depending on an existing one:
Nix 2.0 introduces new builtins, <code>fetchTarball</code> and <code>fetchGit</code>, which make it possible to fetch a specific version of nixpkgs without depending on an existing one:
Line 19: Line 29:
</syntaxhighlight>
</syntaxhighlight>


Or, to use git for fetching<!-- (this has the advantage of being somewhat faster for updates, but is slower for the initial fetch) [not true anymore, the repository sharing mechanism has been disabled (https://github.com/NixOS/nix/pull/2358)]-->:
Or, to use git for fetching:


<syntaxhighlight lang="nix">
<syntaxhighlight lang="nix">
Line 41: Line 51:
while evaluating anonymous function at /nix/store/b93cq865x6qxpn4dw9ivrk3yjcsm8r97-nixos-19.09/pkgs/stdenv/generic/make-derivation.nix:142:17, called from undefined position:
while evaluating anonymous function at /nix/store/b93cq865x6qxpn4dw9ivrk3yjcsm8r97-nixos-19.09/pkgs/stdenv/generic/make-derivation.nix:142:17, called from undefined position:
program 'git' failed with exit code 128
program 'git' failed with exit code 128
</syntaxhighlight>
== Before 2.0 ==
The following code uses the host's Nixpkgs as a
springboard to fetch and import a specific, pinned version of Nixpkgs.
This is safe because the specific code we're using from the variable
host Nixpkgs is using a very stable API, and will be thrown away as
soon as we are done importing the pinned version of Nixpkgs.
Where before you would use <code>pkgs = import <nixpkgs> {}</code>
(which uses the host's Nixpkgs version) you can pin to an exact
version of Nixpkgs by instead using:
<syntaxhighlight lang="nix">
pkgs = let
  hostPkgs = import <nixpkgs> {};
  pinnedPkgs = hostPkgs.fetchFromGitHub {
    owner = "NixOS";
    repo = "nixpkgs";
    # nixos-unstable as of 2017-11-13T08:53:10-00:00
    rev = "ac355040656de04f59406ba2380a96f4124ebdad";
    sha256 = "0frhc7mnx88sird6ipp6578k5badibsl0jfa22ab9w6qrb88j825";
  };
in import pinnedPkgs {}
</syntaxhighlight>
This can also be instead used to pull nixpkgs from an internal fork of
Nixpkgs, with your own changes on top. Note, however, as it stands
Nix 1.11 has difficulties fetching repositories which require
authentication, this is to be fixed in Nix 1.12.
The package <code>nix-prefetch-git</code> can be used to automatically
calculate the current version and hash of a branch, and output the
information to a file:
<syntaxhighlight>
$ nix-shell -p nix-prefetch-git
[nix-shell:~]$ nix-prefetch-git https://github.com/nixos/nixpkgs.git refs/heads/nixos-unstable > nixpkgs-version.json
...
[nix-shell:~]$ cat nixpkgs-version.json
{
  "url": "https://github.com/nixos/nixpkgs.git",
  "rev": "f607771d0f5e4fa905afff1c772febd9f3103e1a",
  "date": "2018-01-09T11:18:25-05:00",
  "sha256": "1icphqpdcl8akqhfij2pxkfr7wfn86z5sr3jdjh88p9vv1550dx7",
  "fetchSubmodules": true
}
</syntaxhighlight>
This file can then be used to specify the version of Nixpkgs:
<syntaxhighlight lang="nix">
pkgs = let
  hostPkgs = import <nixpkgs> {};
  pinnedVersion = hostPkgs.lib.importJSON ./nixpkgs-version.json;
  pinnedPkgs = hostPkgs.fetchFromGitHub {
    owner = "NixOS";
    repo = "nixpkgs";
    inherit (pinnedVersion) rev sha256;
  };
in import pinnedPkgs {};
</syntaxhighlight>
Finally, this can be taken a step further, and you can apply extra
patches to the pinned version of Nixpkgs, for perhaps PRs that are not
yet merged, or private internal changes that you need. If you take
this route, probably best to move the following in to its own file
that you then import.
<syntaxhighlight lang="nix">
pkgs = let
  hostPkgs = import <nixpkgs> {};
  pinnedVersion = hostPkgs.lib.importJSON ./nixpkgs-version.json;
  pinnedPkgs = hostPkgs.fetchFromGitHub {
    owner = "NixOS";
    repo = "nixpkgs";
    inherit (pinnedVersion) rev sha256;
  };
  patches = [
    ./patches/0001-my-nixpkgs-change.patch
  ];
  patchedPkgs = hostPkgs.runCommand "nixpkgs-${pinnedVersion.rev}"
    {
      inherit pinnedPkgs;
      inherit patches;
    }
    ''
      cp -r $pinnedPkgs $out
      chmod -R +w $out
      for p in $patches; do
        echo "Applying patch $p";
        patch -d $out -p1 < "$p";
      done
    '';
in import patchedPkgs {};
</syntaxhighlight>
</syntaxhighlight>


Line 148: Line 56:
How to upgrade a single package and service to an unstable version
How to upgrade a single package and service to an unstable version


There is probably a better way, especially once flakes comes around. Some packages, let you specify which <code>package</code> to run as an option for instance.  Most don't in my experience. This is how you do it for one that doesn't.
There is probably a better way, especially once flakes come around. Some packages let you specify which <code>package</code> to run as an option but most don't. The following is a generic way that also works for those which don't.


add to configuration.nix a set allowing unstable packages.
add to configuration.nix a set allowing unstable packages.
Line 174: Line 82:


<syntaxhighlight lang="nix">
<syntaxhighlight lang="nix">
  environment.systemPackages = with pkgs; [
environment.systemPackages = with pkgs; [
        unstable.bind
  unstable.bind
        unstable.dnsutils
  unstable.dnsutils
        vim
  vim
  ];
];
</syntaxhighlight>
</syntaxhighlight>


Line 186: Line 94:


<syntaxhighlight lang="nix">
<syntaxhighlight lang="nix">
services.bind.enable = true;
services.bind.enable = true;
...
...
</syntaxhighlight>
</syntaxhighlight>


Line 195: Line 103:


<syntaxhighlight lang="nix">
<syntaxhighlight lang="nix">
  users.users.named =
users.users.named = {
      { uid = config.ids.uids.bind;
  uid = config.ids.uids.bind;
        description = "BIND daemon user";
  description = "BIND daemon user";
      };
};
  systemd.services.mybind = {
systemd.services.mybind = {
        description = "BIND Domain Name Server";
  description = "BIND Domain Name Server";
        unitConfig.Documentation = "man:named(8)";
  unitConfig.Documentation = "man:named(8)";
        after = [ "network.target" ];
  after = [ "network.target" ];
        wantedBy = [ "multi-user.target" ];
  wantedBy = [ "multi-user.target" ];
        preStart = ''
  preStart = ''
        mkdir -m 0755 -p /etc/bind
    mkdir -m 0755 -p /etc/bind
        if ! [ -f "/etc/bind/rndc.key" ]; then
    if ! [ -f "/etc/bind/rndc.key" ]; then
          ${pkgs.unstable.bind.out}/sbin/rndc-confgen -c /etc/bind/rndc.key -u named -a -A hmac-sha256 2>/dev/null
      ${pkgs.unstable.bind.out}/sbin/rndc-confgen -c /etc/bind/rndc.key -u named -a -A hmac-sha256 2>/dev/null
        fi
    fi
        ${pkgs.coreutils}/bin/mkdir -p /run/named
    ${pkgs.coreutils}/bin/mkdir -p /run/named
        chown named /run/named
    chown named /run/named
      '';
  '';
        serviceConfig = {
  serviceConfig = {
        ExecStart = "${pkgs.unstable.bind.out}/sbin/named -u named -4 -c /etc/bind/named.conf -f";
    ExecStart = "${pkgs.unstable.bind.out}/sbin/named -u named -4 -c /etc/bind/named.conf -f";
        ExecReload = "${pkgs.unstable.bind.out}/sbin/rndc -k '/etc/bind/rndc.key' reload";
    ExecReload = "${pkgs.unstable.bind.out}/sbin/rndc -k '/etc/bind/rndc.key' reload";
        ExecStop   = "${pkgs.unstable.bind.out}/sbin/rndc -k '/etc/bind/rndc.key' stop";
    ExecStop = "${pkgs.unstable.bind.out}/sbin/rndc -k '/etc/bind/rndc.key' stop";
      };
  };
 
};
};
</syntaxhighlight>
</syntaxhighlight>
Line 223: Line 130:
where all the stuff just comes from the bind services definition(which you can get from the source link on the nixos options page.)
where all the stuff just comes from the bind services definition(which you can get from the source link on the nixos options page.)
Just replace named variables, and replace <code>${pkgs.bind.out</code> with <code>${pkgs.unstable.bind.out}</code>
Just replace named variables, and replace <code>${pkgs.bind.out</code> with <code>${pkgs.unstable.bind.out}</code>
== See also ==
* [https://nix.dev/reference/pinning-nixpkgs Pinning Nixpkgs]
* [https://nix.dev/tutorials/first-steps/towards-reproducibility-pinning-nixpkgs Towards Reproducibility: Pinning Nixpkgs]
* [https://nix.dev/guides/recipes/dependency-management.html Dependency Management]