Skip to content

nix-store path calculation #217

Open
@ghostbuster91

Description

Hi,

First, a little bit of context. I am trying to programatically generate nix derivation using scala. It turned out that I need to calculate nix-store path in order to put the drv file into the nix-store (which is a requirement for realizing it).

Because of that I started to implement minimialistic version of hnix-store in scala, so that I can calculate the nix-store output path. I tried reading The Purely Functional Software
Deployment Model
and the code in this repository (though I don't know much haskell), however it was enough for me to get started. Then I also found https://web.archive.org/web/20221001050043/https://comono.id/posts/2020-03-20-how-nix-instantiation-works/ which was an invaluable help.

I am at the point where I can calculate nix-store path correctly for some real derivations like "/nix/store/dsn6vl7x1hbn1akgpxync19gpx2dzy8w-bootstrap-tools" or more complex /nix/store/32lr8w57frc1ij5wzc3hb9ks8vzs2ms1-libffi-3.4.4.drv.

However, for some reason I cannot calculate correctly nix-store path for "/nix/store/h8z4rypl78kwais0yim76czxjnd55dsm-python3-minimal-3.10.12"

There must be something different about this package/its inputDrvs but I fail to spot anything.

I wonder if you know any better resources about the algorithm used to calculate nix-store paths.
I will list steps that I do, in the hope that maybe someone will be able to spot a mistake:
(fixed hash derivation are left out for brevity)

  1. replace each inputDrv with its descriptor hash and sort that list lexicographical
  2. mask outputs (all outputs are set to "", environment variables that refer to outputs are also set to "")
  3. calculate hash of such modified serialized derivation
  4. concatenate the hash with metadata and hash it again: sha256("output:out:sha256:${sha256(d)}:/nix/store:${d.env("name")}")
  5. truncate to 160 bits and convert to base32 nix-variant

descriptor hashes are calculated as follows:

  1. if this is a fixed hash derivation then calculate sha256("fixed:out:${d.hashAlgo}:${d.hash}:${d.path.get}")
  2. otherwise replace each inputDrv with its descriptor hash and sort that list lexicographical
  3. calculate hash of such modified serialized derivation - sha256(derivation)

If anything I think that I might be handling multiple outputs incorrectly.
If there is a derivation A that defines several outputs:

   "outputs": {
      "dev": {
        "path": "/nix/store/8qg5ralh4c1m2pas6lbi572qykxxsxdn-libffi-3.4.4-dev"
      },
      "info": {
        "path": "/nix/store/v5j3cysbnah4m265wlm57gjmln18qq7a-libffi-3.4.4-info"
      },
      "man": {
        "path": "/nix/store/x92j3f8v85h216avky5rdi5xizx12j6h-libffi-3.4.4-man"
      },
      "out": {
        "path": "/nix/store/ksz7in14b8si5f107w3ay3ph79f67i68-libffi-3.4.4"
      }
    },

and then we depend on such derivation in B:

inputDrvs=[
    "/nix/store/32lr8w57frc1ij5wzc3hb9ks8vzs2ms1-libffi-3.4.4.drv" -> ("dev", "out"),
...
]

I don't change my logic for calculating B descriptor in terms of A and I do it the same way as if there was only a single output out both defined in B and used in A.

Thanks in advance 🙇‍♂️

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions