Nix 覆盖和覆盖模式
Nix overlays and override pattern
我无法理解 Nix 覆盖和覆盖模式。我想要做的是在没有 copy/pasting 的情况下向 gdb 的 "patches" 添加一些内容
整个推导。
来自 Nix Pills 我有点看到覆盖只是模仿 OOP,实际上它只是集合的另一个属性。但是它是如何工作的呢? Override 是从原始属性集到转换后的属性集的函数,它再次具有预定义的 override 函数?
并且由于 Nix 是一种函数式语言,您也没有可以在不同范围内隐藏的仅变量绑定。但这仍然无法解释叠加层如何实现其 "magic".
通过 ~/.config/nixpkgs 我配置了一个大致如下的测试覆盖:
self: super:
{
test1 = super.gdb // { name = "test1"; buildInputs = [ super.curl ]; };
test2 = super.gdb // { name = "test2"; buildInputs = [ super.coreutils ]; };
test3 = super.gdb.override { pythonSupport = false; };
};
我得到:
nix-repl> "${test1}"
"/nix/store/ib55xzrp60fmbf5dcswxy6v8hjjl0s34-gdb-8.3"
nix-repl> "${test2}"
"/nix/store/ib55xzrp60fmbf5dcswxy6v8hjjl0s34-gdb-8.3"
nix-repl> "${test3}"
"/nix/store/vqlrphs3a2jfw69v8kwk60vhdsadv3k5-gdb-8.3"
然后
$ nix-env -iA nixpkgs.test1
replacing old 'test1'
installing 'test1'
你能解释一下这些结果吗?我是否正确认为覆盖只能更改 "defined interface" - 这是函数的所有参数,并且由于 "patches" 不是 gdb 的参数我将无法更改它?那么最好的选择是什么?
我会写一个答案,以防其他人无意中发现这个问题。
编辑 21.8.2019:
我真正想要的在https://nixos.org/nixpkgs/manual/#sec-overrides
中有描述
overrideDerivation 和 overrideAttrs
overrideDerivation 基本上是 "derivation (drv.drvAttrs // (f drv))" 并且 overrideAttrs 在 https://github.com/NixOS/nixpkgs/blob/master/pkgs/stdenv/generic/make-derivation.nix
中被定义为 mkDerivation 的一部分
然后我的代码看起来像:
gdb = super.gdb.overrideAttrs (oldAttrs: rec {
patches = oldAttrs.patches ++ [
(super.fetchpatch {
name = "...";
url = "...";
sha256 = "...";
})
];
});
问题标题具有误导性,源于我对推导的根本误解。叠加层完全按照宣传的方式工作。而且它们可能也没有那么神奇。只是一些递归,其中 endresult 是上一步的结果 // 最后一个叠加函数的输出。
What is the purpose of nix-instantiate? What is a store-derivation?
不对的地方请指正
但基本上,当您评估 Nix 代码时,"derivation function" 会将描述性属性集(名称、系统、构建器)转换为 "actual derivation"。 "actual derivation" 又是一个属性集,但诀窍在于它由商店中的 .drv 文件支持。所以在某种意义上推导有side-effects。 drv 对构建应该如何进行以及需要哪些依赖项进行编码。该文件的哈希值还确定了人工制品的目录名称(尽管尚未构建任何东西)。因此,隐含地,nix 存储中的名称也取决于所有构建输入。
当我基于将现有推导捆绑在一起来创建类似于弗兰肯斯坦的新推导时,我所做的就是创建对同一个 .drv 文件的多个引用。就好像我正在复制一个指针,结果是两个指针指向堆上的同一个值。我能够更改一些元数据,但最终构建过程仍然相同。事实上,由于 Nix 是纯粹的,我敢打赌甚至没有办法写入文件系统(更改 .drv 文件)——除非再次使用包装派生函数的东西。
另一方面,Override 允许您创建 "new instance"。由于 "inputs pattern" Nix 中的每个包都是一个从依赖属性集到最终调用 "derivation function" 的实际代码的函数。通过覆盖,您可以再次调用该函数,这使得 "derivation function" 获得不同的参数。
我无法理解 Nix 覆盖和覆盖模式。我想要做的是在没有 copy/pasting 的情况下向 gdb 的 "patches" 添加一些内容 整个推导。
来自 Nix Pills 我有点看到覆盖只是模仿 OOP,实际上它只是集合的另一个属性。但是它是如何工作的呢? Override 是从原始属性集到转换后的属性集的函数,它再次具有预定义的 override 函数?
并且由于 Nix 是一种函数式语言,您也没有可以在不同范围内隐藏的仅变量绑定。但这仍然无法解释叠加层如何实现其 "magic".
通过 ~/.config/nixpkgs 我配置了一个大致如下的测试覆盖:
self: super:
{
test1 = super.gdb // { name = "test1"; buildInputs = [ super.curl ]; };
test2 = super.gdb // { name = "test2"; buildInputs = [ super.coreutils ]; };
test3 = super.gdb.override { pythonSupport = false; };
};
我得到:
nix-repl> "${test1}"
"/nix/store/ib55xzrp60fmbf5dcswxy6v8hjjl0s34-gdb-8.3"
nix-repl> "${test2}"
"/nix/store/ib55xzrp60fmbf5dcswxy6v8hjjl0s34-gdb-8.3"
nix-repl> "${test3}"
"/nix/store/vqlrphs3a2jfw69v8kwk60vhdsadv3k5-gdb-8.3"
然后
$ nix-env -iA nixpkgs.test1
replacing old 'test1'
installing 'test1'
你能解释一下这些结果吗?我是否正确认为覆盖只能更改 "defined interface" - 这是函数的所有参数,并且由于 "patches" 不是 gdb 的参数我将无法更改它?那么最好的选择是什么?
我会写一个答案,以防其他人无意中发现这个问题。
编辑 21.8.2019:
我真正想要的在https://nixos.org/nixpkgs/manual/#sec-overrides
中有描述overrideDerivation 和 overrideAttrs
overrideDerivation 基本上是 "derivation (drv.drvAttrs // (f drv))" 并且 overrideAttrs 在 https://github.com/NixOS/nixpkgs/blob/master/pkgs/stdenv/generic/make-derivation.nix
中被定义为 mkDerivation 的一部分然后我的代码看起来像:
gdb = super.gdb.overrideAttrs (oldAttrs: rec {
patches = oldAttrs.patches ++ [
(super.fetchpatch {
name = "...";
url = "...";
sha256 = "...";
})
];
});
问题标题具有误导性,源于我对推导的根本误解。叠加层完全按照宣传的方式工作。而且它们可能也没有那么神奇。只是一些递归,其中 endresult 是上一步的结果 // 最后一个叠加函数的输出。
What is the purpose of nix-instantiate? What is a store-derivation?
不对的地方请指正
但基本上,当您评估 Nix 代码时,"derivation function" 会将描述性属性集(名称、系统、构建器)转换为 "actual derivation"。 "actual derivation" 又是一个属性集,但诀窍在于它由商店中的 .drv 文件支持。所以在某种意义上推导有side-effects。 drv 对构建应该如何进行以及需要哪些依赖项进行编码。该文件的哈希值还确定了人工制品的目录名称(尽管尚未构建任何东西)。因此,隐含地,nix 存储中的名称也取决于所有构建输入。
当我基于将现有推导捆绑在一起来创建类似于弗兰肯斯坦的新推导时,我所做的就是创建对同一个 .drv 文件的多个引用。就好像我正在复制一个指针,结果是两个指针指向堆上的同一个值。我能够更改一些元数据,但最终构建过程仍然相同。事实上,由于 Nix 是纯粹的,我敢打赌甚至没有办法写入文件系统(更改 .drv 文件)——除非再次使用包装派生函数的东西。
另一方面,Override 允许您创建 "new instance"。由于 "inputs pattern" Nix 中的每个包都是一个从依赖属性集到最终调用 "derivation function" 的实际代码的函数。通过覆盖,您可以再次调用该函数,这使得 "derivation function" 获得不同的参数。