doc/stdenv/platform-notes: fix typo
[NixPkgs.git] / lib / strings-with-deps.nix
blob900827fe0e4b45e719b48836659afb6fb71cf8c2
1 { lib }:
2 /*
3 Usage:
5   You define you custom builder script by adding all build steps to a list.
6   for example:
7        builder = writeScript "fsg-4.4-builder"
8                (textClosure [doUnpack addInputs preBuild doMake installPhase doForceShare]);
10   a step is defined by noDepEntry, fullDepEntry or packEntry.
11   To ensure that prerequisite are met those are added before the task itself by
12   textClosureDupList. Duplicated items are removed again.
14   See trace/nixpkgs/trunk/pkgs/top-level/builder-defs.nix for some predefined build steps
16   Attention:
18   let
19     pkgs = (import <nixpkgs>) {};
20   in let
21     inherit (pkgs.stringsWithDeps) fullDepEntry packEntry noDepEntry textClosureMap;
22     inherit (pkgs.lib) id;
24     nameA = noDepEntry "Text a";
25     nameB = fullDepEntry "Text b" ["nameA"];
26     nameC = fullDepEntry "Text c" ["nameA"];
28     stages = {
29       nameHeader = noDepEntry "#! /bin/sh \n";
30       inherit nameA nameB nameC;
31     };
32   in
33     textClosureMap id stages
34     [ "nameHeader" "nameA" "nameB" "nameC"
35       nameC # <- added twice. add a dep entry if you know that it will be added once only [1]
36       "nameB" # <- this will not be added again because the attr name (reference) is used
37     ]
39   # result: Str("#! /bin/sh \n\nText a\nText b\nText c\nText c",[])
41   [1] maybe this behaviour should be removed to keep things simple (?)
44 let
45   inherit (lib)
46     concatStringsSep
47     head
48     isAttrs
49     listToAttrs
50     tail
51     ;
53 rec {
55   /**
56     Topologically sort a collection of dependent strings.
57     Only the values to keys listed in `arg` and their dependencies will be included in the result.
59     ::: {.note}
60     This function doesn't formally fulfill the definition of topological sorting, but it's good enough for our purposes in Nixpkgs.
61     :::
63     # Inputs
65     `predefined` (attribute set)
67     : strings with annotated dependencies (strings or attribute set)
68       A value can be a simple string if it has no dependencies.
69       Otherwise, is can be an attribute set with the following attributes:
70       - `deps` (list of strings)
71       - `text` (Any
73     `arg` (list of strings)
75     : Keys for which the values in the dependency closure will be included in the result
77     # Type
79     ```
80     textClosureList :: { ${phase} :: { deps :: [String]; text :: String; } | String; } -> [String] -> [String]
81     ```
83     # Examples
84     :::{.example}
85     ## `lib.stringsWithDeps.textClosureList` usage example
87     ```nix
88     textClosureList {
89       a = {
90         deps = [ "b" "c" "e" ];
91         text = "a: depends on b, c and e";
92       };
93       b = {
94         deps = [ ];
95         text = "b: no dependencies";
96       };
97       c = {
98         deps = [ "b" ];
99         text = "c: depends on b";
100       };
101       d = {
102         deps = [ "c" ];
103         text = "d: not being depended on by anything in `arg`";
104       };
105       e = {
106         deps = [ "c" ];
107         text = "e: depends on c, depended on by a, not in `arg`";
108       };
109     } [
110       "a"
111       "b"
112       "c"
113     ]
114     => [
115       "b: no dependencies"
116       "c: depends on b"
117       "e: depends on c, depended on by a, not in `arg`"
118       "a: depends on b, c and e"
119     ]
120     ```
121     :::
123     Common real world usages are:
124     - Ordering the dependent phases of `system.activationScripts`
125     - Ordering the dependent phases of `system.userActivationScripts`
127     For further examples see: [NixOS activation script](https://nixos.org/manual/nixos/stable/#sec-activation-script)
129   */
130   textClosureList = predefined: arg:
131     let
132       f = done: todo:
133         if todo == [] then {result = []; inherit done;}
134         else
135           let entry = head todo; in
136           if isAttrs entry then
137             let x = f done entry.deps;
138                 y = f x.done (tail todo);
139             in { result = x.result ++ [entry.text] ++ y.result;
140                  done = y.done;
141                }
142           else if done ? ${entry} then f done (tail todo)
143           else f (done // listToAttrs [{name = entry; value = 1;}]) ([predefined.${entry}] ++ tail todo);
144     in (f {} arg).result;
146   textClosureMap = f: predefined: names:
147     concatStringsSep "\n" (map f (textClosureList predefined names));
149   noDepEntry = text: {inherit text; deps = [];};
150   fullDepEntry = text: deps: {inherit text deps;};
151   packEntry = deps: {inherit deps; text="";};
153   stringAfter = deps: text: { inherit text deps; };