summary refs log tree commit diff
path: root/pkgs/build-support/autonix/default.nix
blob: 1f71d2cbb3bb6f5444c25ff8b59d784768c5a431 (plain) (blame)
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
{ pkgs }:

let inherit (pkgs) bash coreutils findutils nix wget;
    inherit (pkgs) callPackage fetchurl runCommand stdenv substituteAll writeText;
in

/* autonix is a collection of tools to automate packaging large collections
 * of software, particularly KDE. It consists of three components:
 *   1. a script (manifest) to download and hash the packages
 *   2. a dependency scanner (autonix-deps) written in Haskell that examines
 *      the package sources and tries to guess their dependencies
 *   3. a library of Nix routines (generateCollection) to generate Nix
 *      expressions from the output of the previous steps.
 */

let inherit (stdenv) lib; in

let

  resolveDeps = scope: deps:
    let resolve = dep:
          let res = scope."${dep}" or [];
          in if lib.isList res then res else [res];
    in lib.concatMap resolve deps;

in rec {

  /* Download the packages into the Nix store, compute their hashes,
   * and generate a package manifest in ./manifest.nix.
   */
  manifest =
    let
      script =
        substituteAll
          {
            src = ./manifest.sh;
            inherit bash coreutils findutils nix wget;
          };
    in
      runCommand "autonix-manifest" {}
        ''
          cp ${script} $out
          chmod +x $out
        '';

  mkPackage = callPackage: defaultOverride: name: pkg: let drv =
    { mkDerivation, fetchurl, scope }:

    mkDerivation (defaultOverride {
      inherit (pkg) name;

      src = fetchurl pkg.src;

      buildInputs = resolveDeps scope pkg.buildInputs;
      nativeBuildInputs = resolveDeps scope pkg.nativeBuildInputs;
      propagatedBuildInputs = resolveDeps scope pkg.propagatedBuildInputs;
      propagatedNativeBuildInputs =
        resolveDeps scope pkg.propagatedNativeBuildInputs;
      propagatedUserEnvPkgs = resolveDeps scope pkg.propagatedUserEnvPkgs;

      enableParallelBuilding = true;
    });
  in callPackage drv {};

  renameDeps = renames: lib.mapAttrs (name: pkg:
    let breakCycles = lib.filter (dep: dep != name);
        rename = dep: renames."${dep}" or dep;
    in pkg // {
      buildInputs = breakCycles (map rename pkg.buildInputs);
      nativeBuildInputs = breakCycles (map rename pkg.nativeBuildInputs);
      propagatedBuildInputs = breakCycles (map rename pkg.propagatedBuildInputs);
      propagatedNativeBuildInputs =
        breakCycles (map rename pkg.propagatedNativeBuildInputs);
      propagatedUserEnvPkgs = breakCycles (map rename pkg.propagatedUserEnvPkgs);
    });

  propagateDeps = propagated: lib.mapAttrs (name: pkg:
    let isPropagated = dep: lib.elem dep propagated;
        isNotPropagated = dep: !(isPropagated dep);
    in pkg // {
      buildInputs = lib.filter isNotPropagated pkg.buildInputs;
      nativeBuildInputs = lib.filter isNotPropagated pkg.nativeBuildInputs;
      propagatedBuildInputs =
        pkg.propagatedBuildInputs
        ++ lib.filter isPropagated pkg.buildInputs;
      propagatedNativeBuildInputs =
        pkg.propagatedNativeBuildInputs
        ++ lib.filter isPropagated pkg.nativeBuildInputs;
    });

  nativeDeps = native: lib.mapAttrs (name: pkg:
    let isNative = dep: lib.elem dep native;
        isNotNative = dep: !(isNative dep);
    in pkg // {
      buildInputs = lib.filter isNotNative pkg.buildInputs;
      nativeBuildInputs =
        pkg.nativeBuildInputs
        ++ lib.filter isNative pkg.buildInputs;
      propagatedBuildInputs = lib.filter isNotNative pkg.propagatedBuildInputs;
      propagatedNativeBuildInputs =
        pkg.propagatedNativeBuildInputs
        ++ lib.filter isNative pkg.propagatedBuildInputs;
    });

  userEnvDeps = user: lib.mapAttrs (name: pkg:
    let allDeps = with pkg; lib.concatLists [
          buildInputs
          nativeBuildInputs
          propagatedBuildInputs
          propagatedNativeBuildInputs
        ];
    in assert (lib.isList allDeps); pkg // {
      propagatedUserEnvPkgs = lib.filter (dep: lib.elem dep user) allDeps;
    });

  overrideDerivation = pkg: f: pkg.override (super: super // {
    mkDerivation = drv: super.mkDerivation (drv // f drv);
  });

  extendDerivation = pkg: attrs:
    let mergeAttrBy = lib.mergeAttrBy // {
          propagatedNativeBuildInputs = a: b: a ++ b;
          NIX_CFLAGS_COMPILE = a: b: "${a} ${b}";
          cmakeFlags = a: b: a ++ b;
        };
        mergeAttrsByFunc = sets:
          let merged = lib.foldl lib.mergeAttrByFunc { inherit mergeAttrBy; } sets;
          in builtins.removeAttrs merged ["mergeAttrBy"];
    in overrideDerivation pkg (drv: mergeAttrsByFunc [ drv attrs ]);

  overrideScope = pkg: fnOrSet: pkg.override (super: super // {
    scope = if builtins.isFunction fnOrSet
              then super.scope // fnOrSet super.scope
            else super.scope // fnOrSet;
  });
}