aboutsummaryrefslogtreecommitdiffstats
path: root/pkgs/populate/lib/default.nix
blob: e9155c54d16f14ffe3574f61c6dc5af0e731ad4b (plain)
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
# populate's Nix library: the types of sources, which describe how to write
# them in Nix, and evalSource, which turns sources written so into the
# sources populate reads as JSON.  lib is nixpkgs' lib.
{ lib ? import <nixpkgs/lib> }:

let
  # nixpkgs' lib, with what the types use besides.
  lib' = lib // {
    test = re: x: lib.isString x && lib.match re x != null;
    types = lib.types // types;
  };

  types =
    import ./types/posix.nix { lib = lib'; } //
    import ./types/populate.nix { lib = lib'; };

in rec {

  inherit types;

  # The sources, a list of attribute sets of sources by name, or one, with
  # shorthands expanded and defaults filled in, and without settings that
  # are null, as populate reads them, e.g. with builtins.toJSON.
  evalSource = let
    eval = source: lib.evalModules {
      modules = lib.singleton {
        _file = toString ./.;
        imports = map (source: { inherit source; }) (lib.toList source);
        options.source = lib.mkOption {
          default = {};
          type = lib.types.attrsOf types.source;
        };
      };
    };
    sanitize = x: lib.getAttr (lib.typeOf x) {
      bool = x;
      list = map sanitize x;
      set = lib.mapAttrs
              (lib.const sanitize)
              (lib.filterAttrs
                (name: value: name != "_module" && value != null) x);
      string = x;
    };
  in
    source: sanitize (eval source).config.source;

  # Inputs a source draws from other sources, as list of attribute sets like
  # { path = [ "stockholm" "nixpkgs" ]; source = "nixpkgs"; }.
  flakeFollows = source: let
    flatten = prefix: inputs: lib.concatLists (lib.mapAttrsToList
      (name: input:
        lib.optional (input.follows or null != null) {
          path = prefix ++ [ name ];
          source = input.follows;
        } ++
        flatten (prefix ++ [ name ]) (input.inputs or {}))
      inputs);
  in
    flatten [] (source.${source.type}.inputs or {});

  # Tells whether a source's inputs get drawn from other sources by a
  # generated flake in .populate/flakes, instead of by rewriting the lock
  # file of the flake in the source.  Symlink sources point at other
  # sources, whose lock files stay as they are.
  hasGeneratedFlake = source:
    flakeFollows source != [] &&
    (source.type == "symlink" || !(source.${source.type}.rewriteLock or true));

  # Tells whether a flake or flake-input source gets delivered as a copy,
  # which gets patched, gets its lock file rewritten, or is materialized.
  derivesFlake = source: let
    source' = source.${source.type};
  in
    lib.elem source.type [ "flake" "flake-input" ] &&
    (source'.materialize or false || source'.patches or [] != [] ||
     (source'.rewriteLock or true && flakeFollows source != []));

}