• 前面我们利用函数参数,通过改变调用时传入的参数,来获取一个包的不同变种

  • 但是那仍然有些坏处,比如需要包的维护者手动调用来传参,如果包的可选项多了起来,一个包的不同变种就有十几种,每个特性都让维护者来调用形成一个新derivation 不太现实。 相反,如果能让用户拥有改变参数的能力,那么他可以很自然地根据自己的需求来传参获取derivation,而包维护者只需要为那些选项设一个默认值即可 比如 与其:

    1
    2
    
    graphviz = callPackage ./graphviz.nix { };
    graphviz = callPackage ./graphviz { gdSupport = false; };
    

    不如:

    1
    
    graphvizCore = pkgs.graphviz.override { gdSupport = false; };
    
  • 函数式让我们很容易能够做到这一点,这是其它只用一系列用串行shell函数描述打包的包管理比较难做到的

  • 基本的思路是为每个derivation的返回值(一个attr set)添加一个override的key,它的value是一个函数,该函数接收一个set类型的参数,返回一个新的derivation 而derivation最后都是调用打包函数(graphviz.nix等)形成的,那么这个override应该应该是 用已有的参数,和提供的参数(override的参数),做个 //,然后把这个合集传给打包函数,得到一个新的derivation。 另,还需要返回的derivation仍然具有override的能力(属性)

    那么可以写出类似如下的函数

    1
    2
    3
    4
    5
    6
    7
    
    {
      makeOverridable = f: origArgs:
        let 
          origRes = f origArgs;
        in 
          origRes // { override = newArgs: f (origArgs // newArgs); };
    }
    

    其中origRes是一个derivationorigRes // { override = newArgs: f (origArgs // newArgs); } 也是一个derivation

    为了让返回的derivation也具有override的能力,可以这么改:

    1
    2
    3
    4
    5
    6
    7
    8
    
    # 为了让makeOverridable能访问自身,rec是必需的
    rec {
      makeOverridable = f: origArgs:
        let 
          origRes = f origArgs;
        in 
          origRes // { override = newArgs: makeOverridable f (origArgs // newArgs); };
    }
    

    唔,精巧!

    最后只需要让我们的callPackage集成这个功能就大功告成了

    default.nix

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    let
      nixpkgs = import <nixpkgs> { };
      # pkgs defined bellow
      allPkgs = nixpkgs // pkgs;
      makeOverridable = f: origArgs:
        let 
          origRes = f origArgs;
        in 
          origRes // { override = newArgs: makeOverridable f (origArgs // newArgs); };
    
      callPackage = path: overrides:
        let f = import path;
        in makeOverridable f ((builtins.intersectAttrs (builtins.functionArgs f) allPkgs) // overrides);
      pkgs = with nixpkgs; {
        mkDerivation = import ./autotoolsv2.nix nixpkgs;
        graphviz = callPackage ./graphviz.nix { };
        graphvizCore = callPackage ./graphviz.nix { gdSupport = false; };
        hello = callPackage ./hellov4.nix { };
      };
    in pkgs