nixos/tests/forgejo: fix after git v2.47 bump
[NixPkgs.git] / lib / deprecated / misc.nix
blob34d1c01ce811adcce02cb9499d0025b591b68840
1 { lib }:
3 let
4   inherit (lib)
5     and
6     any
7     attrByPath
8     attrNames
9     compare
10     concat
11     concatMap
12     elem
13     filter
14     foldl
15     foldr
16     genericClosure
17     head
18     imap1
19     init
20     isAttrs
21     isFunction
22     isInt
23     isList
24     lists
25     listToAttrs
26     mapAttrs
27     mergeAttrs
28     meta
29     nameValuePair
30     tail
31     toList
32     warn
33     ;
35   inherit (lib.attrsets) removeAttrs mapAttrsToList;
37   # returns default if env var is not set
38   maybeEnv = name: default:
39     let value = builtins.getEnv name; in
40     if value == "" then default else value;
42   defaultMergeArg = x : y: if builtins.isAttrs y then
43     y
44   else
45     (y x);
46   defaultMerge = x: y: x // (defaultMergeArg x y);
47   foldArgs = merger: f: init: x:
48     let arg = (merger init (defaultMergeArg init x));
49         # now add the function with composed args already applied to the final attrs
50         base = (setAttrMerge "passthru" {} (f arg)
51                         ( z: z // {
52                             function = foldArgs merger f arg;
53                             args = (attrByPath ["passthru" "args"] {} z) // x;
54                           } ));
55         withStdOverrides = base // {
56           override = base.passthru.function;
57         };
58         in
59           withStdOverrides;
62   # shortcut for attrByPath ["name"] default attrs
63   maybeAttrNullable = maybeAttr;
65   # shortcut for attrByPath ["name"] default attrs
66   maybeAttr = name: default: attrs: attrs.${name} or default;
69   # Return the second argument if the first one is true or the empty version
70   # of the second argument.
71   ifEnable = cond: val:
72     if cond then val
73     else if builtins.isList val then []
74     else if builtins.isAttrs val then {}
75     # else if builtins.isString val then ""
76     else if val == true || val == false then false
77     else null;
80   # Return true only if there is an attribute and it is true.
81   checkFlag = attrSet: name:
82         if name == "true" then true else
83         if name == "false" then false else
84         if (elem name (attrByPath ["flags"] [] attrSet)) then true else
85         attrByPath [name] false attrSet ;
88   # Input : attrSet, [ [name default] ... ], name
89   # Output : its value or default.
90   getValue = attrSet: argList: name:
91   ( attrByPath [name] (if checkFlag attrSet name then true else
92         if argList == [] then null else
93         let x = builtins.head argList; in
94                 if (head x) == name then
95                         (head (tail x))
96                 else (getValue attrSet
97                         (tail argList) name)) attrSet );
100   # Input : attrSet, [[name default] ...], [ [flagname reqs..] ... ]
101   # Output : are reqs satisfied? It's asserted.
102   checkReqs = attrSet: argList: condList:
103   (
104     foldr and true
105       (map (x: let name = (head x); in
107         ((checkFlag attrSet name) ->
108         (foldr and true
109         (map (y: let val=(getValue attrSet argList y); in
110                 (val!=null) && (val!=false))
111         (tail x))))) condList));
114   # This function has O(n^2) performance.
115   uniqList = { inputList, acc ? [] }:
116     let go = xs: acc:
117              if xs == []
118              then []
119              else let x = head xs;
120                       y = if elem x acc then [] else [x];
121                   in y ++ go (tail xs) (y ++ acc);
122     in go inputList acc;
124   uniqListExt = { inputList,
125                   outputList ? [],
126                   getter ? (x: x),
127                   compare ? (x: y: x==y) }:
128         if inputList == [] then outputList else
129         let x = head inputList;
130             isX = y: (compare (getter y) (getter x));
131             newOutputList = outputList ++
132                 (if any isX outputList then [] else [x]);
133         in uniqListExt { outputList = newOutputList;
134                          inputList = (tail inputList);
135                          inherit getter compare;
136                        };
138   condConcat = name: list: checker:
139         if list == [] then name else
140         if checker (head list) then
141                 condConcat
142                         (name + (head (tail list)))
143                         (tail (tail list))
144                         checker
145         else condConcat
146                 name (tail (tail list)) checker;
148   lazyGenericClosure = {startSet, operator}:
149     let
150       work = list: doneKeys: result:
151         if list == [] then
152           result
153         else
154           let x = head list; key = x.key; in
155           if elem key doneKeys then
156             work (tail list) doneKeys result
157           else
158             work (tail list ++ operator x) ([key] ++ doneKeys) ([x] ++ result);
159     in
160       work startSet [] [];
162   innerModifySumArgs = f: x: a: b: if b == null then (f a b) // x else
163         innerModifySumArgs f x (a // b);
164   modifySumArgs = f: x: innerModifySumArgs f x {};
167   innerClosePropagation = acc: xs:
168     if xs == []
169     then acc
170     else let y  = head xs;
171              ys = tail xs;
172          in if ! isAttrs y
173             then innerClosePropagation acc ys
174             else let acc' = [y] ++ acc;
175                  in innerClosePropagation
176                       acc'
177                       (uniqList { inputList = (maybeAttrNullable "propagatedBuildInputs" [] y)
178                                            ++ (maybeAttrNullable "propagatedNativeBuildInputs" [] y)
179                                            ++ ys;
180                                   acc = acc';
181                                 }
182                       );
184   closePropagationSlow = list: (uniqList {inputList = (innerClosePropagation [] list);});
186   # This is an optimisation of closePropagation which avoids the O(n^2) behavior
187   # Using a list of derivations, it generates the full closure of the propagatedXXXBuildInputs
188   # The ordering / sorting / comparison is done based on the `outPath`
189   # attribute of each derivation.
190   # On some benchmarks, it performs up to 15 times faster than closePropagation.
191   # See https://github.com/NixOS/nixpkgs/pull/194391 for details.
192   closePropagationFast = list:
193     builtins.map (x: x.val) (builtins.genericClosure {
194       startSet = builtins.map (x: {
195         key = x.outPath;
196         val = x;
197       }) (builtins.filter (x: x != null) list);
198       operator = item:
199         if !builtins.isAttrs item.val then
200           [ ]
201         else
202           builtins.concatMap (x:
203             if x != null then [{
204               key = x.outPath;
205               val = x;
206             }] else
207               [ ]) ((item.val.propagatedBuildInputs or [ ])
208                 ++ (item.val.propagatedNativeBuildInputs or [ ]));
209     });
211   closePropagation = if builtins ? genericClosure
212     then closePropagationFast
213     else closePropagationSlow;
215   # calls a function (f attr value ) for each record item. returns a list
216   mapAttrsFlatten = warn "lib.misc.mapAttrsFlatten is deprecated, please use lib.attrsets.mapAttrsToList instead." mapAttrsToList;
218   # attribute set containing one attribute
219   nvs = name: value: listToAttrs [ (nameValuePair name value) ];
220   # adds / replaces an attribute of an attribute set
221   setAttr = set: name: v: set // (nvs name v);
223   # setAttrMerge (similar to mergeAttrsWithFunc but only merges the values of a particular name)
224   # setAttrMerge "a" [] { a = [2];} (x: x ++ [3]) -> { a = [2 3]; }
225   # setAttrMerge "a" [] {         } (x: x ++ [3]) -> { a = [  3]; }
226   setAttrMerge = name: default: attrs: f:
227     setAttr attrs name (f (maybeAttr name default attrs));
229   # Using f = a: b = b the result is similar to //
230   # merge attributes with custom function handling the case that the attribute
231   # exists in both sets
232   mergeAttrsWithFunc = f: set1: set2:
233     foldr (n: set: if set ? ${n}
234                         then setAttr set n (f set.${n} set2.${n})
235                         else set )
236            (set2 // set1) (attrNames set2);
238   # merging two attribute set concatenating the values of same attribute names
239   # eg { a = 7; } {  a = [ 2 3 ]; } becomes { a = [ 7 2 3 ]; }
240   mergeAttrsConcatenateValues = mergeAttrsWithFunc ( a: b: (toList a) ++ (toList b) );
242   # merges attributes using //, if a name exists in both attributes
243   # an error will be triggered unless its listed in mergeLists
244   # so you can mergeAttrsNoOverride { buildInputs = [a]; } { buildInputs = [a]; } {} to get
245   # { buildInputs = [a b]; }
246   # merging buildPhase doesn't really make sense. The cases will be rare where appending /prefixing will fit your needs?
247   # in these cases the first buildPhase will override the second one
248   # ! deprecated, use mergeAttrByFunc instead
249   mergeAttrsNoOverride = { mergeLists ? ["buildInputs" "propagatedBuildInputs"],
250                            overrideSnd ? [ "buildPhase" ]
251                          }: attrs1: attrs2:
252     foldr (n: set:
253         setAttr set n ( if set ? ${n}
254             then # merge
255               if elem n mergeLists # attribute contains list, merge them by concatenating
256                 then attrs2.${n} ++ attrs1.${n}
257               else if elem n overrideSnd
258                 then attrs1.${n}
259               else throw "error mergeAttrsNoOverride, attribute ${n} given in both attributes - no merge func defined"
260             else attrs2.${n} # add attribute not existing in attr1
261            )) attrs1 (attrNames attrs2);
264   # example usage:
265   # mergeAttrByFunc  {
266   #   inherit mergeAttrBy; # defined below
267   #   buildInputs = [ a b ];
268   # } {
269   #  buildInputs = [ c d ];
270   # };
271   # will result in
272   # { mergeAttrsBy = [...]; buildInputs = [ a b c d ]; }
273   # is used by defaultOverridableDelayableArgs and can be used when composing using
274   # foldArgs, composedArgsAndFun or applyAndFun. Example: composableDerivation in all-packages.nix
275   mergeAttrByFunc = x: y:
276     let
277           mergeAttrBy2 = { mergeAttrBy = mergeAttrs; }
278                       // (maybeAttr "mergeAttrBy" {} x)
279                       // (maybeAttr "mergeAttrBy" {} y); in
280     foldr mergeAttrs {} [
281       x y
282       (mapAttrs ( a: v: # merge special names using given functions
283           if x ? ${a}
284              then if y ? ${a}
285                then v x.${a} y.${a} # both have attr, use merge func
286                else x.${a} # only x has attr
287              else y.${a} # only y has attr)
288           ) (removeAttrs mergeAttrBy2
289                          # don't merge attrs which are neither in x nor y
290                          (filter (a: ! x ? ${a} && ! y ? ${a})
291                                  (attrNames mergeAttrBy2))
292             )
293       )
294     ];
295   mergeAttrsByFuncDefaults = foldl mergeAttrByFunc { inherit mergeAttrBy; };
296   mergeAttrsByFuncDefaultsClean = list: removeAttrs (mergeAttrsByFuncDefaults list) ["mergeAttrBy"];
298   # sane defaults (same name as attr name so that inherit can be used)
299   mergeAttrBy = # { buildInputs = concatList; [...]; passthru = mergeAttr; [..]; }
300     listToAttrs (map (n: nameValuePair n concat)
301       [ "nativeBuildInputs" "buildInputs" "propagatedBuildInputs" "configureFlags" "prePhases" "postAll" "patches" ])
302     // listToAttrs (map (n: nameValuePair n mergeAttrs) [ "passthru" "meta" "cfg" "flags" ])
303     // listToAttrs (map (n: nameValuePair n (a: b: "${a}\n${b}") ) [ "preConfigure" "postInstall" ])
304   ;
306   nixType = x:
307       if isAttrs x then
308           if x ? outPath then "derivation"
309           else "attrs"
310       else if isFunction x then "function"
311       else if isList x then "list"
312       else if x == true then "bool"
313       else if x == false then "bool"
314       else if x == null then "null"
315       else if isInt x then "int"
316       else "string";
318   /**
319     # Deprecated
321     For historical reasons, imap has an index starting at 1.
323     But for consistency with the rest of the library we want an index
324     starting at zero.
325   */
326   imap = imap1;
328   # Fake hashes. Can be used as hash placeholders, when computing hash ahead isn't trivial
329   fakeHash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
330   fakeSha256 = "0000000000000000000000000000000000000000000000000000000000000000";
331   fakeSha512 = "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
335 # Everything in this attrset is the public interface of the file.
337   inherit
338     checkFlag
339     checkReqs
340     closePropagation
341     closePropagationFast
342     closePropagationSlow
343     condConcat
344     defaultMerge
345     defaultMergeArg
346     fakeHash
347     fakeSha256
348     fakeSha512
349     foldArgs
350     getValue
351     ifEnable
352     imap
353     innerClosePropagation
354     innerModifySumArgs
355     lazyGenericClosure
356     mapAttrsFlatten
357     maybeAttr
358     maybeAttrNullable
359     maybeEnv
360     mergeAttrBy
361     mergeAttrByFunc
362     mergeAttrsByFuncDefaults
363     mergeAttrsByFuncDefaultsClean
364     mergeAttrsConcatenateValues
365     mergeAttrsNoOverride
366     mergeAttrsWithFunc
367     modifySumArgs
368     nixType
369     nvs
370     setAttr
371     setAttrMerge
372     uniqList
373     uniqListExt
374     ;