зеркало из
				https://github.com/iharh/notes.git
				synced 2025-10-31 21:56:08 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			205 строки
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			205 строки
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| https://nixos.org/guides/nix-pills/nix-store-paths.html
 | |
| 
 | |
| Before reading existing derivations, I'd like to talk about store paths and how they are computed.
 | |
| In particular we are interested in fixed store paths that depend on an integrity hash (e.g. a sha256), which is usually applied to source tarballs.
 | |
|     
 | |
| The way store paths are computed is a little contrived, mostly due to historical reasons.
 | |
| Our reference will be the Nix source code (Store::makeFixedOutputPath).
 | |
|     https://github.com/NixOS/nix/blob/07f992a74b64f4376d5b415d0042babc924772f3/src/libstore/store-api.cc#L197
 | |
| 
 | |
| 
 | |
| # 18.1. Source paths
 | |
| 
 | |
| Let's start simple.
 | |
| You know nix allows relative paths to be used, such that the file or directory is stored in the nix store,
 | |
| that is ./myfile gets stored into /nix/store/.......
 | |
| We want to understand how is the store path generated for such a file:
 | |
| 
 | |
| $ echo mycontent > myfile
 | |
| 
 | |
| I remind you, the simplest derivation you can write has a name, a builder and the system:
 | |
| 
 | |
| ```
 | |
| $ nix repl
 | |
| nix-repl> derivation { system = "x86_64-linux"; builder = ./myfile; name = "foo"; }
 | |
|     "derivation /nix/store/y4h73bmrc9ii5bxg6i7ck6hsf5gqv8ck-foo.drv"
 | |
| ```
 | |
| 
 | |
| Now inspect the .drv to see where is ./myfile being stored:
 | |
| 
 | |
| ```
 | |
| $ nix show-derivation /nix/store/y4h73bmrc9ii5bxg6i7ck6hsf5gqv8ck-foo.drv
 | |
| {
 | |
|     "/nix/store/y4h73bmrc9ii5bxg6i7ck6hsf5gqv8ck-foo.drv": {
 | |
|         "outputs": {
 | |
|             "out": {
 | |
|                 "path": "/nix/store/hs0yi5n5nw6micqhy8l1igkbhqdkzqa1-foo"
 | |
|             }
 | |
|         },
 | |
|         "inputSrcs": [
 | |
|             "/nix/store/xv2iccirbrvklck36f1g7vldn5v58vck-myfile"
 | |
|         ],
 | |
|         "inputDrvs": {},
 | |
|         "platform": "x86_64-linux",
 | |
|         "builder": "/nix/store/xv2iccirbrvklck36f1g7vldn5v58vck-myfile",
 | |
|         "args": [],
 | |
|         "env": {
 | |
|             "builder": "/nix/store/xv2iccirbrvklck36f1g7vldn5v58vck-myfile",
 | |
|             "name": "foo",
 | |
|             "out": "/nix/store/hs0yi5n5nw6micqhy8l1igkbhqdkzqa1-foo",
 | |
|             "system": "x86_64-linux"
 | |
|         }
 | |
|     }
 | |
| }
 | |
| ```
 | |
| 
 | |
| Great, how did nix decide to use xv2iccirbrvklck36f1g7vldn5v58vck ?
 | |
| Keep looking at the nix comments.
 | |
| 
 | |
| Note: doing "nix-store --add myfile" will store the file in the same store path.
 | |
| 
 | |
| 
 | |
| # 18.1.1. Step 1, compute the hash of the file
 | |
| 
 | |
| The comments tell us to first compute the sha256 of the NAR serialization of the file. Can be done in two ways:
 | |
| 
 | |
| ```
 | |
| $ nix-hash --type sha256 myfile
 | |
|     2bfef67de873c54551d884fdab3055d84d573e654efa79db3c0d7b98883f9ee3
 | |
| ```
 | |
| 
 | |
| Or:
 | |
| 
 | |
| ```
 | |
| $ nix-store --dump myfile|sha256sum
 | |
|     2bfef67de873c54551d884fdab3055d84d573e654efa79db3c0d7b98883f9ee3
 | |
| ```
 | |
| 
 | |
| In general, Nix understands two contents:
 | |
|     * flat for regular files,
 | |
|     * or recursive for NAR serializations which can be anything.
 | |
| 
 | |
| 
 | |
| # 18.1.2. Step 2, build the string description
 | |
| 
 | |
| Then nix uses a special string which includes the hash, the path type and the file name.
 | |
| We store this in another file:
 | |
| 
 | |
| ```
 | |
| $ echo -n "source:sha256:2bfef67de873c54551d884fdab3055d84d573e654efa79db3c0d7b98883f9ee3:/nix/store:myfile" > myfile.str
 | |
| ```
 | |
| 
 | |
| 
 | |
| # 18.1.3. Step 3, compute the final hash
 | |
| 
 | |
| Finally the comments tell us to compute the base-32 representation of the first 160 bits (truncation) of a sha256 of the above string:
 | |
| 
 | |
| ```
 | |
| $ nix-hash --type sha256 --truncate --base32 --flat myfile.str
 | |
|     xv2iccirbrvklck36f1g7vldn5v58vck
 | |
| ```
 | |
| 
 | |
| 
 | |
| # 18.2. Output paths
 | |
| 
 | |
| Output paths are usually generated for derivations.
 | |
| We use the above example because it's simple.
 | |
| Even if we didn't build the derivation, nix knows the out path hs0yi5n5nw6micqhy8l1igkbhqdkzqa1.
 | |
| This is because the out path only depends on inputs.
 | |
| 
 | |
| It's computed in a similar way to source paths, except that the .drv is hashed and the type of derivation is output:out.
 | |
| In case of multiple outputs, we may have different output:<id>.
 | |
| 
 | |
| At the time nix computes the out path, the .drv contains an empty string for each out path.
 | |
| So what we do is getting our .drv and replacing the out path with an empty string:
 | |
| 
 | |
| ```
 | |
| $ cp -f /nix/store/y4h73bmrc9ii5bxg6i7ck6hsf5gqv8ck-foo.drv myout.drv
 | |
| $ sed -i 's,/nix/store/hs0yi5n5nw6micqhy8l1igkbhqdkzqa1-foo,,g' myout.drv
 | |
| ```
 | |
| 
 | |
| The myout.drv is the .drv state in which nix is when computing the out path for our derivation:
 | |
| 
 | |
| ```
 | |
| $ sha256sum myout.drv
 | |
|     1bdc41b9649a0d59f270a92d69ce6b5af0bc82b46cb9d9441ebc6620665f40b5  myout.drv
 | |
| $ echo -n "output:out:sha256:1bdc41b9649a0d59f270a92d69ce6b5af0bc82b46cb9d9441ebc6620665f40b5:/nix/store:foo" > myout.str
 | |
| $ nix-hash --type sha256 --truncate --base32 --flat myout.str
 | |
|     hs0yi5n5nw6micqhy8l1igkbhqdkzqa1
 | |
| ```
 | |
| 
 | |
| Then nix puts that out path in the .drv, and that's it.
 | |
| 
 | |
| In case the .drv has input derivations, that is it references other .drv,
 | |
| then such .drv paths are replaced by this same algorithm which returns a hash.
 | |
| 
 | |
| In other words, you get a final .drv where every other .drv path is replaced by its hash.
 | |
| 
 | |
| 
 | |
| # 18.3. Fixed-output paths
 | |
| 
 | |
| Finally, the other most used kind of path is when we know beforehand an integrity hash of a file.
 | |
| This is usual for tarballs.
 | |
| 
 | |
| A derivation can take three special attributes: outputHashMode, outputHash and outputHashAlgo which are well documented in the nix manual.
 | |
|     https://nixos.org/manual/nix/stable/#sec-advanced-attributes
 | |
| 
 | |
| The builder must create the out path and make sure its hash is the same as the one declared with outputHash.
 | |
| 
 | |
| Let's say our builder should create a file whose contents is mycontent:
 | |
| 
 | |
| ```
 | |
| $ echo mycontent > myfile
 | |
| $ sha256sum myfile
 | |
|     f3f3c4763037e059b4d834eaf68595bbc02ba19f6d2a500dce06d124e2cd99bb  myfile
 | |
| nix-repl> derivation { name = "bar"; system = "x86_64-linux"; builder = "none"; outputHashMode = "flat"; outputHashAlgo = "sha256"; outputHash = "f3f3c4763037e059b4d834eaf68595bbc02ba19f6d2a500dce06d124e2cd99bb"; }
 | |
|     "derivation /nix/store/ymsf5zcqr9wlkkqdjwhqllgwa97rff5i-bar.drv"
 | |
| ```
 | |
| 
 | |
| Inspect the .drv and see that it also stored the fact that it's a fixed-output derivation with sha256 algorithm, compared to the previous examples:
 | |
| 
 | |
| ```
 | |
| $ nix show-derivation /nix/store/ymsf5zcqr9wlkkqdjwhqllgwa97rff5i-bar.drv
 | |
| {
 | |
|     "/nix/store/ymsf5zcqr9wlkkqdjwhqllgwa97rff5i-bar.drv": {
 | |
|         "outputs": {
 | |
|             "out": {
 | |
|                 "path": "/nix/store/a00d5f71k0vp5a6klkls0mvr1f7sx6ch-bar",
 | |
|                 "hashAlgo": "sha256",
 | |
|                 "hash": "f3f3c4763037e059b4d834eaf68595bbc02ba19f6d2a500dce06d124e2cd99bb"
 | |
|             }
 | |
|         },
 | |
|         [...]
 | |
|     }
 | |
| }
 | |
| ```
 | |
| 
 | |
| It doesn't matter which input derivations are being used, the final out path must only depend on the declared hash.
 | |
| 
 | |
| What nix does is to create an intermediate string representation of the fixed-output content:
 | |
| 
 | |
| ```
 | |
| $ echo -n "fixed:out:sha256:f3f3c4763037e059b4d834eaf68595bbc02ba19f6d2a500dce06d124e2cd99bb:" > mycontent.str
 | |
| $ sha256sum mycontent.str 
 | |
|     423e6fdef56d53251c5939359c375bf21ea07aaa8d89ca5798fb374dbcfd7639  myfile.str
 | |
| ```
 | |
| 
 | |
| Then proceed as it was a normal derivation output path:
 | |
| 
 | |
| ```
 | |
| $ echo -n "output:out:sha256:423e6fdef56d53251c5939359c375bf21ea07aaa8d89ca5798fb374dbcfd7639:/nix/store:bar" > myfile.str
 | |
| $ nix-hash --type sha256 --truncate --base32 --flat myfile.str
 | |
|     a00d5f71k0vp5a6klkls0mvr1f7sx6ch
 | |
| ```
 | |
| 
 | |
| Hence, the store path only depends on the declared fixed-output hash.
 | |
| 
 | |
| 18.4. Conclusion
 | |
| 
 | |
| There are other types of store paths, but you get the idea.
 | |
| Nix first hashes the contents, then creates a string description, and the final store path is the hash of this string.
 | |
| 
 | |
| Also we've introduced some fundamentals, in particular the fact that Nix knows beforehand the out path of a derivation since it only depends on the inputs.
 | |
| We've also introduced fixed-output derivations which are especially used by the nixpkgs repository for downloading and verifying source tarballs. 
 | |
| 
 | 
