at 22.05-pre 11 kB view raw
1{ lib }: 2let 3 inherit (builtins) head tail isList isAttrs isInt attrNames; 4 5in 6 7with lib.lists; 8with lib.attrsets; 9with lib.strings; 10 11rec { 12 13 # returns default if env var is not set 14 maybeEnv = name: default: 15 let value = builtins.getEnv name; in 16 if value == "" then default else value; 17 18 defaultMergeArg = x : y: if builtins.isAttrs y then 19 y 20 else 21 (y x); 22 defaultMerge = x: y: x // (defaultMergeArg x y); 23 foldArgs = merger: f: init: x: 24 let arg = (merger init (defaultMergeArg init x)); 25 # now add the function with composed args already applied to the final attrs 26 base = (setAttrMerge "passthru" {} (f arg) 27 ( z: z // { 28 function = foldArgs merger f arg; 29 args = (lib.attrByPath ["passthru" "args"] {} z) // x; 30 } )); 31 withStdOverrides = base // { 32 override = base.passthru.function; 33 }; 34 in 35 withStdOverrides; 36 37 38 # shortcut for attrByPath ["name"] default attrs 39 maybeAttrNullable = maybeAttr; 40 41 # shortcut for attrByPath ["name"] default attrs 42 maybeAttr = name: default: attrs: attrs.${name} or default; 43 44 45 # Return the second argument if the first one is true or the empty version 46 # of the second argument. 47 ifEnable = cond: val: 48 if cond then val 49 else if builtins.isList val then [] 50 else if builtins.isAttrs val then {} 51 # else if builtins.isString val then "" 52 else if val == true || val == false then false 53 else null; 54 55 56 # Return true only if there is an attribute and it is true. 57 checkFlag = attrSet: name: 58 if name == "true" then true else 59 if name == "false" then false else 60 if (elem name (attrByPath ["flags"] [] attrSet)) then true else 61 attrByPath [name] false attrSet ; 62 63 64 # Input : attrSet, [ [name default] ... ], name 65 # Output : its value or default. 66 getValue = attrSet: argList: name: 67 ( attrByPath [name] (if checkFlag attrSet name then true else 68 if argList == [] then null else 69 let x = builtins.head argList; in 70 if (head x) == name then 71 (head (tail x)) 72 else (getValue attrSet 73 (tail argList) name)) attrSet ); 74 75 76 # Input : attrSet, [[name default] ...], [ [flagname reqs..] ... ] 77 # Output : are reqs satisfied? It's asserted. 78 checkReqs = attrSet: argList: condList: 79 ( 80 foldr lib.and true 81 (map (x: let name = (head x); in 82 83 ((checkFlag attrSet name) -> 84 (foldr lib.and true 85 (map (y: let val=(getValue attrSet argList y); in 86 (val!=null) && (val!=false)) 87 (tail x))))) condList)); 88 89 90 # This function has O(n^2) performance. 91 uniqList = { inputList, acc ? [] }: 92 let go = xs: acc: 93 if xs == [] 94 then [] 95 else let x = head xs; 96 y = if elem x acc then [] else [x]; 97 in y ++ go (tail xs) (y ++ acc); 98 in go inputList acc; 99 100 uniqListExt = { inputList, 101 outputList ? [], 102 getter ? (x: x), 103 compare ? (x: y: x==y) }: 104 if inputList == [] then outputList else 105 let x = head inputList; 106 isX = y: (compare (getter y) (getter x)); 107 newOutputList = outputList ++ 108 (if any isX outputList then [] else [x]); 109 in uniqListExt { outputList = newOutputList; 110 inputList = (tail inputList); 111 inherit getter compare; 112 }; 113 114 condConcat = name: list: checker: 115 if list == [] then name else 116 if checker (head list) then 117 condConcat 118 (name + (head (tail list))) 119 (tail (tail list)) 120 checker 121 else condConcat 122 name (tail (tail list)) checker; 123 124 lazyGenericClosure = {startSet, operator}: 125 let 126 work = list: doneKeys: result: 127 if list == [] then 128 result 129 else 130 let x = head list; key = x.key; in 131 if elem key doneKeys then 132 work (tail list) doneKeys result 133 else 134 work (tail list ++ operator x) ([key] ++ doneKeys) ([x] ++ result); 135 in 136 work startSet [] []; 137 138 innerModifySumArgs = f: x: a: b: if b == null then (f a b) // x else 139 innerModifySumArgs f x (a // b); 140 modifySumArgs = f: x: innerModifySumArgs f x {}; 141 142 143 innerClosePropagation = acc: xs: 144 if xs == [] 145 then acc 146 else let y = head xs; 147 ys = tail xs; 148 in if ! isAttrs y 149 then innerClosePropagation acc ys 150 else let acc' = [y] ++ acc; 151 in innerClosePropagation 152 acc' 153 (uniqList { inputList = (maybeAttrNullable "propagatedBuildInputs" [] y) 154 ++ (maybeAttrNullable "propagatedNativeBuildInputs" [] y) 155 ++ ys; 156 acc = acc'; 157 } 158 ); 159 160 closePropagation = list: (uniqList {inputList = (innerClosePropagation [] list);}); 161 162 # calls a function (f attr value ) for each record item. returns a list 163 mapAttrsFlatten = f: r: map (attr: f attr r.${attr}) (attrNames r); 164 165 # attribute set containing one attribute 166 nvs = name: value: listToAttrs [ (nameValuePair name value) ]; 167 # adds / replaces an attribute of an attribute set 168 setAttr = set: name: v: set // (nvs name v); 169 170 # setAttrMerge (similar to mergeAttrsWithFunc but only merges the values of a particular name) 171 # setAttrMerge "a" [] { a = [2];} (x: x ++ [3]) -> { a = [2 3]; } 172 # setAttrMerge "a" [] { } (x: x ++ [3]) -> { a = [ 3]; } 173 setAttrMerge = name: default: attrs: f: 174 setAttr attrs name (f (maybeAttr name default attrs)); 175 176 # Using f = a: b = b the result is similar to // 177 # merge attributes with custom function handling the case that the attribute 178 # exists in both sets 179 mergeAttrsWithFunc = f: set1: set2: 180 foldr (n: set: if set ? ${n} 181 then setAttr set n (f set.${n} set2.${n}) 182 else set ) 183 (set2 // set1) (attrNames set2); 184 185 # merging two attribute set concatenating the values of same attribute names 186 # eg { a = 7; } { a = [ 2 3 ]; } becomes { a = [ 7 2 3 ]; } 187 mergeAttrsConcatenateValues = mergeAttrsWithFunc ( a: b: (toList a) ++ (toList b) ); 188 189 # merges attributes using //, if a name exists in both attributes 190 # an error will be triggered unless its listed in mergeLists 191 # so you can mergeAttrsNoOverride { buildInputs = [a]; } { buildInputs = [a]; } {} to get 192 # { buildInputs = [a b]; } 193 # merging buildPhase doesn't really make sense. The cases will be rare where appending /prefixing will fit your needs? 194 # in these cases the first buildPhase will override the second one 195 # ! deprecated, use mergeAttrByFunc instead 196 mergeAttrsNoOverride = { mergeLists ? ["buildInputs" "propagatedBuildInputs"], 197 overrideSnd ? [ "buildPhase" ] 198 }: attrs1: attrs2: 199 foldr (n: set: 200 setAttr set n ( if set ? ${n} 201 then # merge 202 if elem n mergeLists # attribute contains list, merge them by concatenating 203 then attrs2.${n} ++ attrs1.${n} 204 else if elem n overrideSnd 205 then attrs1.${n} 206 else throw "error mergeAttrsNoOverride, attribute ${n} given in both attributes - no merge func defined" 207 else attrs2.${n} # add attribute not existing in attr1 208 )) attrs1 (attrNames attrs2); 209 210 211 # example usage: 212 # mergeAttrByFunc { 213 # inherit mergeAttrBy; # defined below 214 # buildInputs = [ a b ]; 215 # } { 216 # buildInputs = [ c d ]; 217 # }; 218 # will result in 219 # { mergeAttrsBy = [...]; buildInputs = [ a b c d ]; } 220 # is used by defaultOverridableDelayableArgs and can be used when composing using 221 # foldArgs, composedArgsAndFun or applyAndFun. Example: composableDerivation in all-packages.nix 222 mergeAttrByFunc = x: y: 223 let 224 mergeAttrBy2 = { mergeAttrBy = lib.mergeAttrs; } 225 // (maybeAttr "mergeAttrBy" {} x) 226 // (maybeAttr "mergeAttrBy" {} y); in 227 foldr lib.mergeAttrs {} [ 228 x y 229 (mapAttrs ( a: v: # merge special names using given functions 230 if x ? ${a} 231 then if y ? ${a} 232 then v x.${a} y.${a} # both have attr, use merge func 233 else x.${a} # only x has attr 234 else y.${a} # only y has attr) 235 ) (removeAttrs mergeAttrBy2 236 # don't merge attrs which are neither in x nor y 237 (filter (a: ! x ? ${a} && ! y ? ${a}) 238 (attrNames mergeAttrBy2)) 239 ) 240 ) 241 ]; 242 mergeAttrsByFuncDefaults = foldl mergeAttrByFunc { inherit mergeAttrBy; }; 243 mergeAttrsByFuncDefaultsClean = list: removeAttrs (mergeAttrsByFuncDefaults list) ["mergeAttrBy"]; 244 245 # sane defaults (same name as attr name so that inherit can be used) 246 mergeAttrBy = # { buildInputs = concatList; [...]; passthru = mergeAttr; [..]; } 247 listToAttrs (map (n: nameValuePair n lib.concat) 248 [ "nativeBuildInputs" "buildInputs" "propagatedBuildInputs" "configureFlags" "prePhases" "postAll" "patches" ]) 249 // listToAttrs (map (n: nameValuePair n lib.mergeAttrs) [ "passthru" "meta" "cfg" "flags" ]) 250 // listToAttrs (map (n: nameValuePair n (a: b: "${a}\n${b}") ) [ "preConfigure" "postInstall" ]) 251 ; 252 253 nixType = x: 254 if isAttrs x then 255 if x ? outPath then "derivation" 256 else "attrs" 257 else if lib.isFunction x then "function" 258 else if isList x then "list" 259 else if x == true then "bool" 260 else if x == false then "bool" 261 else if x == null then "null" 262 else if isInt x then "int" 263 else "string"; 264 265 /* deprecated: 266 267 For historical reasons, imap has an index starting at 1. 268 269 But for consistency with the rest of the library we want an index 270 starting at zero. 271 */ 272 imap = imap1; 273 274 # Fake hashes. Can be used as hash placeholders, when computing hash ahead isn't trivial 275 fakeHash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; 276 fakeSha256 = "0000000000000000000000000000000000000000000000000000000000000000"; 277 fakeSha512 = "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; 278}