1 nix store paths
来看一下Nix的hash部分如何求值
先以单个文件为例
$ echo mycontent > myfile
1 2
nix-repl> derivation { system = "x86_64-linux"; builder = ./myfile; name = "foo"; } «derivation /nix/store/y4h73bmrc9ii5bxg6i7ck6hsf5gqv8ck-foo.drv»
$ nix derivation show /nix/store/y4h73bmrc9ii5bxg6i7ck6hsf5gqv8ck-foo.drv
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
{ "/nix/store/y4h73bmrc9ii5bxg6i7ck6hsf5gqv8ck-foo.drv": { "args": [], "builder": "/nix/store/xv2iccirbrvklck36f1g7vldn5v58vck-myfile", "env": { "builder": "/nix/store/xv2iccirbrvklck36f1g7vldn5v58vck-myfile", "name": "foo", "out": "/nix/store/hs0yi5n5nw6micqhy8l1igkbhqdkzqa1-foo", "system": "x86_64-linux" }, "inputDrvs": {}, "inputSrcs": [ "/nix/store/xv2iccirbrvklck36f1g7vldn5v58vck-myfile" ], "name": "foo", "outputs": { "out": { "path": "/nix/store/hs0yi5n5nw6micqhy8l1igkbhqdkzqa1-foo" } }, "system": "x86_64-linux" } }
(也可以用
nix-store --add myfile
来得到这个hash)inputDrvs
部分文件的hash部分的求值 其中/nix/store/xv2iccirbrvklck36f1g7vldn5v58vck-myfile
的hash部分是怎么求出的呢?- 计算出文件的hash
$ nix-hash --type sha256 myfile
2bfef67de873c54551d884fdab3055d84d573e654efa79db3c0d7b98883f9ee3
( 注:nix-hash
做的事比普通的sha256sum
要多一步,就是先把文件或目录打成NAR
格式,以上面为例,其等于nix-store --dump | sha256sum
而nix-hash --type sha256 --flat myfile
和sha256sum myfile
是等价的 对于Nix来说,只有两种内容格式,flat for regular files, or recursive for NAR serializations which can be anything.
)
- 计算出文件的hash
- 创建字符描述
$ echo -n "source:sha256:2bfef67de873c54551d884fdab3055d84d573e654efa79db3c0d7b98883f9ee3:/nix/store:myfile" > myfile.str
- 创建字符描述
- 计算出最后的hash
$ nix-hash --type sha256 --truncate --base32 --flat myfile.str
xv2iccirbrvklck36f1g7vldn5v58vck
- 计算出最后的hash
out path
hash部分的求值 之前我们说过,out path
在derivation实际被构建之间就已知了,而且只与输入有关 out path的hash求值与输入类似,除了类型变为了output:out
(多个输出则类型分别为output:<id>
)- 获取
.drv
文件中除了out path
部分的内容的hash
1 2
cp -f /nix/store/y4h73bmrc9ii5bxg6i7ck6hsf5gqv8ck-foo.drv myout.drv sed -i 's,/nix/store/hs0yi5n5nw6micqhy8l1igkbhqdkzqa1-foo,,g' myout.drv
( 这么做有点hack,实际上out path的求值过程中应该是有个中间文件,其内容类似如下(全在一行,没有换行):
1
Derive([("out","","","")],[],["/nix/store/xv2iccirbrvklck36f1g7vldn5v58vck-myfile"],"x86_64-linux","/nix/store/xv2iccirbrvklck36f1g7vldn5v58vck-myfile",[],[("builder","/nix/store/xv2iccirbrvklck36f1g7vldn5v58vck-myfile"),("name","foo"),("out",""),("system","x86_64-linux")])
即
out
内容为空的.drv
文件的内容 )求hash
$ sha256sum myout.drv
1bdc41b9649a0d59f270a92d69ce6b5af0bc82b46cb9d9441ebc6620665f40b5 myout.drv
- 获取
- 创建字符串描述
$ echo -n "output:out:sha256:1bdc41b9649a0d59f270a92d69ce6b5af0bc82b46cb9d9441ebc6620665f40b5:/nix/store:foo" > myout.str
- 创建字符串描述
- 对字符串描述文件求hash,得到最后的hash
$ nix-hash --type sha256 --truncate --base32 --flat myout.str
hs0yi5n5nw6micqhy8l1igkbhqdkzqa1
- 对字符串描述文件求hash,得到最后的hash
tar
包采用一种特别的求值方式,其只与文件的内容有关,而与文件名无关(fixed-output paths
),但步骤类似derivation有三个特别的和hash相关的参数:
outputHashMode
outputHash
outputHashAlgo
,分别表示该derivation的hash的模式(“flat” or “recursive”),hash值和hash的算法 (refer: outputHashMode)当指定了
outputHash
时,derivation函数会确保该derivation的out path
的hash部分的值为outputHash
的值以之前的tar文件
hello-2.12.1.tar.gz
为例$ sha256sum hello-2.12.1.tar.gz
的到hash8d99142afd92576f30b0cd7cb42a8dc6809998bc5d607d88761f512e26c7db20
$ nix-instantiate --expr 'derivation { system = "x86_64-linux"; name = "helloTar"; builder = "none"; outputHash = "8d99142afd92576f30b0cd7cb42a8dc6809998bc5d607d88761f512e26c7db20"; outputHashMode = "flat"; outputHashAlgo = "sha256"; }'
得到derivation/nix/store/gszqyzlnns85sjy1rj9jg04kil5fl39w-helloTar.drv
通过
nix derivation show /nix/store/gszqyzlnns85sjy1rj9jg04kil5fl39w-helloTar.drv
查看derivation的详细信息1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
{ "/nix/store/gszqyzlnns85sjy1rj9jg04kil5fl39w-helloTar.drv": { "args": [], "builder": "none", "env": { "builder": "none", "name": "helloTar", "out": "/nix/store/qwj2km5i1p31616kmxgkm9iinfxs7iqr-helloTar", "outputHash": "8d99142afd92576f30b0cd7cb42a8dc6809998bc5d607d88761f512e26c7db20", "outputHashAlgo": "sha256", "outputHashMode": "flat", "system": "x86_64-linux" }, "inputDrvs": {}, "inputSrcs": [], "name": "helloTar", "outputs": { "out": { "hash": "8d99142afd92576f30b0cd7cb42a8dc6809998bc5d607d88761f512e26c7db20", "hashAlgo": "sha256", "path": "/nix/store/qwj2km5i1p31616kmxgkm9iinfxs7iqr-helloTar" } }, "system": "x86_64-linux" } }
然后像以前一样,把描述性的字符放入文件,然后对其求hash
$ echo -n 'fixed:out:sha256:8d99142afd92576f30b0cd7cb42a8dc6809998bc5d607d88761f512e26c7db20:' > helloTar.str
sha256sum helloTar.str
2dd22467c73f65de429fd32c70e68444aeb55f502082f23f8d509185e0341c22 helloTar.str
比inputSrc和out path多一步,再用结果放入文件求一次hash
$ echo -n "output:out:sha256:2dd22467c73f65de429fd32c70e68444aeb55f502082f23f8d509185e0341c22:/nix/store:helloTar" > helloTar.res
$ nix-hash --type sha256 --truncate --base32 --flat helloTar.res
qwj2km5i1p31616kmxgkm9iinfxs7iqr
哈哈,这正是我们的out path
的hash部分总结 hash的计算总共有两次hash 对于输入文件(inputSrcs)来讲,其依赖于文件内容和文件名 先把用NAR的格式归档的文件本身hash 将hash即一些元数据以字符串的形式存在文件中 对该文件再次hash 对于输出文件(out path)来说,其hash只依赖输入(
.drv
文件),而与输出的内容无关 先将.drv文件(残缺"out" 部分的版本)
求NAR hash 然后把hash与"output:“等源信息以字符串形式写入文件 最后对该文件求一次 nix-hash --type sha256 --truncate --base32 --flat
得到最后的hash tar文件与out path类似,只不过其不依赖.drv
文件,而只依赖tar文件内容和derivation name等