nix-community / crate2nix

rebuild only changed crates in CI with crate2nix and nix
https://nix-community.github.io/crate2nix/
Apache License 2.0
354 stars 83 forks source link

workspace crate source hashes are different between nix 2.3 and later versions #225

Closed Fuuzetsu closed 1 year ago

Fuuzetsu commented 2 years ago

crate2nix generates things like these in Cargo.nix:

      "tsu-mini-std" = rec {
        crateName = "tsu-mini-std";
        version = "0.1.0";
        edition = "2021";
        # We can't filter paths with references in Nix 2.4
        # See https://github.com/NixOS/nix/issues/5410
        src = if (lib.versionOlder builtins.nixVersion "2.4pre20211007")
          then lib.cleanSourceWith { filter = sourceFilter;  src = ../tsu-mini-std; }
          else ../tsu-mini-std;
        dependencies = [
          {
            name = "fxhash";
            packageId = "fxhash";
          }
        ];

      };

On nix 2.3.x and presumably older, this crate ends up depending on its sources (obviously) like so:

[nix-develop]$ nix-store -q -R /nix/store/4y4rb2x1w2ypj5zz1685nhpvhkwwmfhn-rust_tsu-mini-std-0.1.0.drv | tail -n 3
/nix/store/a87gw94pj9l5z1zr4b4bd6hxrcj6y1dg-source
/nix/store/7hvhcn49lynz15s267phv4ph5g2yy7ms-rust_tsu-mini-std-0.1.0.drv
/nix/store/4y4rb2x1w2ypj5zz1685nhpvhkwwmfhn-rust_tsu-mini-std-0.1.0.drv

On modern nix (I'm using 2.9 pre), it looks like this:

[nix-develop]$ nix-store -q -R /nix/store/68cjkl39fdqf49nmym9d0h1ml44bf9r2-rust_tsu-mini-std-0.1.0.drv | tail -n 3
/nix/store/4i4av9wvdx6djid9phrwqp2vnc2r69pr-tsu-mini-std
/nix/store/giw1vm6k33vv2fc2gg7qlq0sg6wshqx9-rust_tsu-mini-std-0.1.0.drv
/nix/store/68cjkl39fdqf49nmym9d0h1ml44bf9r2-rust_tsu-mini-std-0.1.0.drv

The content of /nix/store/a87gw94pj9l5z1zr4b4bd6hxrcj6y1dg-source and /nix/store/4i4av9wvdx6djid9phrwqp2vnc2r69pr-tsu-mini-std is identical! The only thing that's different is the name which changes the hash which then changes hash of everything upstream. I guess since nix 2.4, the ../path syntax gets a proper name as path: lib.cleanSourceWith uses this name if present. I guess on nix 2.3 the name is missing so the "source" default gets used. I was unable to locate the exact commit which caused the change as there are a lot of these between 2.3.16 and 2.4 though it doesn't matter much anyway.

One very simple thing we can do to make the hashes identical again is this:

diff --git a/nix/Cargo.nix b/nix/Cargo.nix
index df38fa2af..795b88012 100644
--- a/nix/Cargo.nix
+++ b/nix/Cargo.nix
@@ -24352,7 +24352,7 @@ rec {
         # We can't filter paths with references in Nix 2.4
         # See https://github.com/NixOS/nix/issues/5410
         src = if (lib.versionOlder builtins.nixVersion "2.4pre20211007")
-          then lib.cleanSourceWith { filter = sourceFilter;  src = ../tsu-mini-std; }
+          then lib.cleanSourceWith { filter = sourceFilter;  src = ../tsu-mini-std; name = "tsu-mini-std"; }
           else ../tsu-mini-std;
         dependencies = [
           {

This makes the source be /nix/store/4i4av9wvdx6djid9phrwqp2vnc2r69pr-tsu-mini-std even on nix 2.3 and everything is happy: binary caching keeps working for people on 2.3 and 2.9 all the same.

I guess then maybe crate2nix should unconditionally (or based on command line flag) insert this attribute with the crate name? This gives consistent results across more versions which seems nice/desirable.

Fuuzetsu commented 2 years ago

Probably something like this enough, but as per #224 I don't really know how to update the tests etc...

diff --git a/crate2nix/templates/Cargo.nix.tera b/crate2nix/templates/Cargo.nix.tera
index 64f8403..73da725 100644
--- a/crate2nix/templates/Cargo.nix.tera
+++ b/crate2nix/templates/Cargo.nix.tera
@@ -125,7 +125,7 @@ rec {
         # We can't filter paths with references in Nix 2.4
         # See https://github.com/NixOS/nix/issues/5410
         src = if (lib.versionOlder builtins.nixVersion "2.4pre20211007")
-          then lib.cleanSourceWith { filter = sourceFilter;  src = {{crate.source.LocalDirectory.path | safe}}; }
+          then lib.cleanSourceWith { filter = sourceFilter;  src = {{crate.source.LocalDirectory.path | safe}}; name = {{crate.crate_name}}; }
           else {{crate.source.LocalDirectory.path | safe}};
         {%- elif crate.source.Git %}
         workspace_member = null;
Fuuzetsu commented 2 years ago

I guess we don't want crate name but the dir name of the source... whichever, should be easy

Fuuzetsu commented 1 year ago

I found even more problems with this nix 2.3 codepath: for example, it'll remove .gitignore from the workspace crates while later versions will not: this is due to current sourceFilter behaviour...

Rather than trying to keep fixing it, I'm just adding an assert in our codebase that >= 2.4 is used. So I no longer really care about this ticket either.