【问题标题】:Nix Pill 14: How to make callPackage overridable?Nix Pill 14:如何使 callPackage 可覆盖?
【发布时间】:2019-12-28 12:26:40
【问题描述】:

我无法理解Nix Pill 14。作者提供makeOverridable,然后挑战用户与callPackage集成。提供makeOverridabledefault.nix,如下,其中makeOverridable在文件lib.nix中,callPackage在文件default.nix中:

# file: lib.nix

rec {
  makeOverridable = f: origArgs:
    let
      origRes = f origArgs;
    in
      origRes // { override = newArgs: makeOverridable f (origArgs // newArgs); };
}
# file: default.nix

let
  nixpkgs = import <nixpkgs> {};
  allPkgs = nixpkgs // pkgs;
  callPackage = path: overrides:
    let f = import path;
    in f ((builtins.intersectAttrs (builtins.functionArgs f) allPkgs) // overrides);
  pkgs = with nixpkgs; {
    mkDerivation = import ./autotools.nix nixpkgs;
    hello = callPackage ./hello.nix { };
    graphviz = callPackage ./graphviz.nix { };
    graphvizCore = callPackage ./graphviz.nix { gdSupport = false; };
  };
in pkgs

这是我想出的:

# file: default.nix (my implementation)

let
  nixpkgs = import <nixpkgs> {};
  allPkgs = nixpkgs // pkgs;
  callPackage = path: overrides:
    let
      f = import path;
      origRes = f ((builtins.intersectAttrs (builtins.functionArgs f) allPkgs) // overrides);
    in
      origRes // { override = newArgs: callPackage f (overrides // newArgs); };
  pkgs = with nixpkgs; {
    mkDerivation = import ./autotools.nix nixpkgs;
    hello = import ./hello.nix {};
    graphviz = import ./graphviz.nix {};
    graphvizCore = graphviz.override { gdSupport = false; };
  };
in pkgs

我认为我对这里发生的事情有一个根本的误解。您能否提供正确的实现并解释我做错了什么?

编辑:我设法让它工作,但是,它仍然不是递归的。

# file: default.nix

let
  nixpkgs = import <nixpkgs> {};
  allPkgs = nixpkgs // pkgs;
  callPackage = path: overrides:
  let
    f = import path;
    origArgs = f ((builtins.intersectAttrs (builtins.functionArgs f) allPkgs) // overrides);
    makeOverridable = { override = newArgs: (origArgs // newArgs); };
  in
    origArgs // makeOverridable;
pkgs = with nixpkgs; rec {
  mkDerivation = import ./autotools.nix nixpkgs;
  hello = callPackage ./hello.nix { };
  graphviz = callPackage ./graphviz.nix { };
  graphvizCore = graphviz.override { gdSupport = false; };
};
in pkgs

编辑 2:

# file: default.nix

let
  nixpkgs = import <nixpkgs> {};
  allPkgs = nixpkgs // pkgs;
  makeOverridable = f: origArgs:
    let origRes = f origArgs;
    in origRes // { override = newArgs: makeOverridable f (origArgs // newArgs); };
  callPackage1 = path: overrides:
    let f = import path;
    in f ((builtins.intersectAttrs (builtins.functionArgs f) allPkgs) // overrides);
  callPackage = makeOverridable callPackage1;
  pkgs = with nixpkgs; {
    mkDerivation = import ./autotools.nix nixpkgs;
    hello = callPackage ./hello.nix { };
    graphviz = callPackage ./graphviz.nix { };
    graphvizCore = graphviz.override { gdSupport = false; };
  };
in pkgs

解决方案:

# file: default.nix

let
  nixpkgs = import <nixpkgs> {};
  allPkgs = nixpkgs // pkgs;
  makeOverridable = f: origArgs:
    let origRes = f origArgs;
    in origRes // { override = newArgs: makeOverridable f (origArgs // newArgs); };
  callPackage1 = path: overrides:
    let f = import path;
    in f ((builtins.intersectAttrs (builtins.functionArgs f) allPkgs) // overrides);
  callPackage = path: makeOverridable (callPackage1 path);
  pkgs = with nixpkgs; rec {
    mkDerivation = import ./autotools.nix nixpkgs;
    hello = callPackage ./hello.nix { };
    local_graphviz = callPackage ./graphviz.nix { };
    graphvizCore = local_graphviz.override { gdSupport = false; };
    graphvizCore2 = graphvizCore.override { gdSupport = false; };
  };
in pkgs

【问题讨论】:

  • 您对makeOverridable 的定义是错误的。您链接到的文档给出了两个定义,一个递归工作,一个不递归。你也没有使用。

标签: functional-programming nix nixos


【解决方案1】:

如果 makeOverridable 是使用 Nix Pills 中的定义之一正确定义的,您可以将其视为高阶函数:它接受一个名为 f 的普通函数,并将其更改为一个新函数,其结果可以被覆盖。

假设你已经有一个名为 callPackage1 的函数,你可以像这样创建一个可覆盖的版本:

rec {
  callPackage1 = ...;
  callPackage = makeOverridable callPackage1;
}

编辑 1:

实际上,callPackage1 需要一个路径来返回 makeOverridable 所期望的函数类型(一个接受集合并返回一个我们可以添加覆盖 attribute 的对象的函数)。那么让我们试试callPackage的这个定义:

callPackage = path: makeOverridable (callPackage1 path);

【讨论】:

  • 嗨,谢谢你帮我解决这个问题。当我实现时,我得到error: syntax error, unexpected REC
  • 您介意在 gist.github.com 上或通过在上面编辑您的问题发布发生语法错误的文件吗? rec 是小写的,就像我在上面写的那样?您是否在... 中填写了适当的、语法正确的函数定义?
  • 我添加了 EDIT 2。rec 在你写的时候是小写的。我将 makeOverridable 从 lib.nix 移动到 default.nix(只是复制和粘贴),然后将 callPackage1callPackage 包含在 rec 中。
  • 您不能只在let 块的中间定义一个未命名的集合。 Nix 语言希望您在 let 块中定义命名变量。幸运的是,let 块的行为很像递归集,因此您可以删除 rec { 和匹配的 };,基本上只是将这些定义移到 let 块中。
  • 我明白了。我删除了修复该错误的 rec 包装器(见上文),但现在我得到了 error: value is a function while a set was expected
【解决方案2】:

我正在使用相同的 Nix Pills,但在 Pill 14 的读者练习中遇到了问题。我发现这里的答案很有帮助。

在我的解决方案中,makeOverridable 的参数是一个未命名的函数。

let
  nixpkgs = import <nixpkgs> {};
  allPkgs = nixpkgs // pkgs;
  lib = import ./lib.nix;

  # Function to find arguments of function defined in "path"
  callPackage = path: lib.makeOverridable (overrides:
    { result =
    let f = import path;
        in f (
          (builtins.intersectAttrs (builtins.functionArgs f) allPkgs)
          // overrides
        ); }) {};

  pkgs = with nixpkgs; rec {
    mkDerivation = import ./autotools.nix nixpkgs;
    hello = callPackage ./hello.nix;
    graphviz = callPackage ./graphviz.nix;
    graphvizCore = graphviz.override { gdSupport = false; };
  };

in pkgs

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-28
    • 2019-12-18
    • 2021-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-15
    • 2019-10-18
    相关资源
    最近更新 更多