diff options
author | Yury G. Kudryashov <urkud.urkud@gmail.com> | 2008-01-23 18:11:03 +0000 |
---|---|---|
committer | Yury G. Kudryashov <urkud.urkud@gmail.com> | 2008-01-23 18:11:03 +0000 |
commit | da57804fff1d34154fc4d13e0fa02cfc23dcfc32 (patch) | |
tree | 52b0094c02d297ab2c9280003286ab7b511c7bf1 /pkgs/lib | |
parent | 4de89f61b00307debd0aebc36658a384e320bf30 (diff) | |
download | nixlib-da57804fff1d34154fc4d13e0fa02cfc23dcfc32.tar nixlib-da57804fff1d34154fc4d13e0fa02cfc23dcfc32.tar.gz nixlib-da57804fff1d34154fc4d13e0fa02cfc23dcfc32.tar.bz2 nixlib-da57804fff1d34154fc4d13e0fa02cfc23dcfc32.tar.lz nixlib-da57804fff1d34154fc4d13e0fa02cfc23dcfc32.tar.xz nixlib-da57804fff1d34154fc4d13e0fa02cfc23dcfc32.tar.zst nixlib-da57804fff1d34154fc4d13e0fa02cfc23dcfc32.zip |
Merged with trunk again
svn path=/nixpkgs/branches/stdenv-updates/; revision=10267
Diffstat (limited to 'pkgs/lib')
-rw-r--r-- | pkgs/lib/default.nix | 290 | ||||
-rw-r--r-- | pkgs/lib/strings-with-deps.nix | 36 |
2 files changed, 317 insertions, 9 deletions
diff --git a/pkgs/lib/default.nix b/pkgs/lib/default.nix index 108d62b3d8a3..87d08ab7c1c0 100644 --- a/pkgs/lib/default.nix +++ b/pkgs/lib/default.nix @@ -3,7 +3,8 @@ let inherit (builtins) - head tail isList stringLength substring lessThan sub; + head tail isList stringLength substring lessThan sub + listToAttrs attrNames hasAttr; in @@ -15,11 +16,15 @@ rec { id = x: x; - # !!! need documentation... + # accumulates / merges all attr sets until null is fed. + # example: sumArgs id { a = 'a'; x = 'x'; } { y = 'y'; x = 'X'; } null + # result : { a = 'a'; x = 'X'; y = 'Y'; } innerSumArgs = f : x : y : (if y == null then (f x) else (innerSumArgs f (x // y))); sumArgs = f : innerSumArgs f {}; + # example a = pairMap (x : y : x + y) ["a" "b" "c" "d"]; + # result: ["ab" "cd"] innerPairMap = acc: f: l: if l == [] then acc else innerPairMap (acc ++ [(f (head l)(head (tail l)))]) @@ -55,6 +60,7 @@ rec { else [(head list) separator] ++ (intersperse separator (tail list)); + toList = x : if (__isList x) then x else [x]; concatStringsSep = separator: list: concatStrings (intersperse separator list); @@ -72,6 +78,7 @@ rec { # Return an attribute from nested attribute sets. For instance ["x" # "y"] applied to some set e returns e.x.y, if it exists. The # default value is returned otherwise. + # comment: there is also builtins.getAttr ? (is there a better name for this function?) getAttr = attrPath: default: e: let attr = head attrPath; in @@ -116,6 +123,12 @@ rec { else if pred (head list) then all pred (tail list) else false; + # much shorter implementations using map and fold (are lazy as well) + # which ones are better? + # true if all/ at least one element(s) satisfy f + # all = f : l : fold logicalAND true (map f l); + # any = f : l : fold logicalOR false (map f l); + # Return true if each element of a list is equal, false otherwise. eqLists = xs: ys: @@ -246,8 +259,6 @@ rec { checker else condConcat name (tail (tail list)) checker; - - /* Options. */ mkOption = attrs: attrs // {_type = "option";}; @@ -305,4 +316,275 @@ rec { closePropagation = list: (uniqList {inputList = (innerClosePropagation [] list);}); + # calls a function (f attr value ) for each record item. returns a list + mapRecordFlatten = f : r : map (attr: f attr (builtins.getAttr attr r) ) (attrNames r); + + # to be used with listToAttrs (_a_ttribute _v_alue) + # TODO should be renamed to nv because niksnut has renamed the attribute attr to name + nv = name : value : { inherit name value; }; + # attribute set containing one attribute + nvs = name : value : listToAttrs [ (nv name value) ]; + # adds / replaces an attribute of an attribute set + setAttr = set : name : v : set // (nvs name v); + + # iterates over a list of attributes collecting the attribute attr if it exists + catAttrs = attr : l : fold ( s : l : if (hasAttr attr s) then [(builtins.getAttr attr s)] ++ l else l) [] l; + + mergeAttrs = fold ( x : y : x // y) {}; + + # Using f = a : b = b the result is similar to // + # merge attributes with custom function handling the case that the attribute + # exists in both sets + mergeAttrsWithFunc = f : set1 : set2 : + fold (n: set : if (__hasAttr n set) + then setAttr set n (f (__getAttr n set) (__getAttr n set2)) + else set ) + set1 (__attrNames set2); + + # merging two attribute set concatenating the values of same attribute names + # eg { a = 7; } { a = [ 2 3 ]; } becomes { a = [ 7 2 3 ]; } + mergeAttrsConcatenateValues = mergeAttrsWithFunc ( a : b : (toList a) ++ (toList b) ); + + # returns atribute values as a list + flattenAttrs = set : map ( attr : builtins.getAttr attr set) (attrNames set); + mapIf = cond : f : fold ( x : l : if (cond x) then [(f x)] ++ l else l) []; + +# Marc 2nd proposal: (not everything has been tested in detail yet..) + + # usage / example + # flagConfig = { + # } // (enableDisableFeature "flagName" "configure_feature" extraAttrs;) + # + # is equal to + # flagConfig = { + # flagName = { cfgOption = "--enable-configure_feature"; } // extraAttrs; + # no_flagName = { cfgOption = "--disable-configure_feature"; }; + enableDisableFeature = flagName : configure_feature : extraAttrs : + listToAttrs [ ( nv flagName ({ cfgOption = "--enable-${configure_feature}"; } // extraAttrs ) ) + ( nv "no_${flagName}" ({ cfgOption = "--disable-${configure_feature}"; } ) )]; + + # calls chooseOptionsByFlags2 with some preprocessing + # chooseOptionsByFlags2 returns an attribute set meant to be used to create new derivaitons. + # see mkDerivationByConfiguration in all-packages.nix and the examples given below. + # You can just copy paste them into all-packages.nix to test them.. + + chooseOptionsByFlags = { flagConfig, args, optionals ? [], defaults ? [], + collectExtraPhaseActions ? [] } : + let passedOptionals = filter ( x : hasAttr x args ) optionals; # these are in optionals and in args + # we simply merge in <optional_name> = { buildInputs = <arg.<optional_name>; pass = <arg.optional_name>; } + flagConfigWithOptionals = flagConfig // ( listToAttrs + (map ( o : nv o ( { buildInputs = o; pass = nvs o (builtins.getAttr o args); } + // getAttr [o] {} flagConfig ) + ) + passedOptionals ) ); + + in chooseOptionsByFlags2 flagConfigWithOptionals collectExtraPhaseActions args + ( (getAttr ["flags"] defaults args) ++ passedOptionals); + + chooseOptionsByFlags2 = flagConfig : collectExtraPhaseActions : args : flags : + let + # helper function + collectFlags = # state : flags : + fold ( flag : s : ( + if (hasAttr flag s.result) then s # this state has already been visited + else if (! hasAttr flag flagConfig) then throw "unkown flag `${flag}' specified" + else let fDesc = (builtins.getAttr flag flagConfig); + implied = flatten ( getAttr ["implies"] [] fDesc ); + blocked = flatten ( getAttr ["blocks"] [] fDesc ); + # add this flag + s2 = s // { result = ( setAttr s.result flag (builtins.getAttr flag flagConfig) ); + blockedFlagsBy = s.blockedFlagsBy + // listToAttrs (map (b: nv b flag ) blocked); }; + # add implied flags + in collectFlags s2 implied + )); + + # chosen contains flagConfig but only having those attributes elected by flags + # (or by implies attributes of elected attributes) + options = let stateOpts = collectFlags { blockedFlagsBy = {}; result = {}; } + (flags ++ ( if (hasAttr "mandatory" flagConfig) then ["mandatory"] else [] )); + # these options have not been chosen (neither by flags nor by implies) + unsetOptions = filter ( x : (! hasAttr x stateOpts.result) && (hasAttr ("no_"+x) flagConfig)) + ( attrNames flagConfig ); + # no add the corresponding no_ attributes as well .. + state = collectFlags stateOpts (map ( x : "no_" + x ) unsetOptions); + in # check for blockings: + assert ( all id ( map ( b: if (hasAttr b state.result) + then throw "flag ${b} is blocked by flag ${__getAttr b state.blockedFlagsBy}" + else true ) + (attrNames state.blockedFlagsBy) ) ); + state.result; + flatOptions = flattenAttrs options; + + # helper functions : + collectAttrs = attr : catAttrs attr flatOptions; + optsConcatStrs = delimiter : attrs : concatStrings + ( intersperse delimiter (flatten ( collectAttrs attrs ) ) ); + + ifStringGetArg = x : if (__isAttrs x) then x # ( TODO implement __isString ?) + else nvs x (__getAttr x args); + + in assert ( all id ( mapRecordFlatten ( attr : r : if ( all id ( flatten (getAttr ["assertion"] [] r ) ) ) + then true else throw "assertion failed flag ${attr}" ) + options) ); + ( rec { + + #foldOptions = attr: f : start: fold f start (catAttrs attr flatOptions); + + # compared to flags flagsSet does also contain the implied flags.. This makes it easy to write assertions. ( assert args. + inherit options flatOptions collectAttrs optsConcatStrs; + + buildInputs = map ( attr: if (! hasAttr attr args) then throw "argument ${attr} is missing!" else (builtins.getAttr attr args) ) + (flatten (catAttrs "buildInputs" flatOptions)); + propagatedBuildInputs = map ( attr: if (! hasAttr attr args) then throw "argument ${attr} is missing!" else (builtins.getAttr attr args) ) + (flatten (catAttrs "propagatedBuildInputs" flatOptions)); + + configureFlags = optsConcatStrs " " "cfgOption"; + + #flags = listToAttrs (map ( flag: nv flag (hasAttr flag options) ) (attrNames flagConfig) ); + flags_prefixed = listToAttrs (map ( flag: nv ("flag_set_"+flag) (hasAttr flag options) ) (attrNames flagConfig) ); + + pass = mergeAttrs ( map ifStringGetArg ( flatten (collectAttrs "pass") ) ); + } # now add additional phase actions (see examples) + // listToAttrs ( map ( x : nv x (optsConcatStrs "\n" x) ) collectExtraPhaseActions ) ); } + +/* + TODO: Perhaps it's better to move this documentation / these tests into some extra packages .. + + # ########################################################################### + # configuration tutorial .. examples and tests.. + # Copy this into all-packages.nix and try + + # The following derviations will all fail.. + # But they will print the passed options so that you can get to know + # how these configurations ought to work. + # TODO: There is no nice way to pass an otpion yet. + # I could imagine something like + # flags = [ "flagA" "flagB" { flagC = 4; } ]; + + # They are named: + # simpleYes, simpleNo, + # defaultsimpleYes, defaultsimpleNo + # optionalssimpleYes, optionalssimpleNo + # bitingsimpleYes can only be ran with -iA blockingBiteMonster + # assertionsimpleNo + # of course you can use -iA and the attribute name as well to select these examples + + # dummy build input + whoGetsTheFlagFirst = gnused; + whoGetsTheFlagLast = gnumake; + + # simple example demonstrating containing one flag. + # features: + # * configure options are passed automatically + # * buildInputs are collected (they are special, see the setup script) + # * they can be passed by additional name as well using pass = { inherit (args) python } + # ( or short (value not attrs) : pass = "python" ) + # * an attribute named the same way as the flag is added indicating + # true/ false (flag has been set/ not set) + # * extra phase dependend commands can be added + # Its easy to add your own stuff using co.collectAttrs or co.optsConcatStrs + # ( perhaps this name will change?) + simpleFlagYesNoF = namePrefix : extraFlagAttrs : mkDerivationByConfiguration ( { + flagConfig = { + flag = { name = namePrefix + "simpleYes"; + cfgOption = [ "--Yes" "--you-dont-need-a-list" ]; + buildInputs = [ "whoGetsTheFlagFirst" ]; + pass = { inherit gnumake; }; + extraConfigureCmd = "echo Hello, it worked! "; + blocks = "bitingMonster"; + }; + no_flag = { name = namePrefix + "simpleNo"; + cfgOption = "--no"; + implies = ["bitingMonster"]; + }; + bitingMonster = { + extraConfigureCmd = "echo Ill bite you"; + }; + gnutar = { cfgOption="--with-gnutar"; + # buildInputs and pass will be added automatically if gnutar is added to optionals + }; + # can be used to check configure options of dependencies + # eg testFlag = { assertion = [ arg.desktop.flag_set_wmii (! arg.desktop.flag_set_gnome) (! arg.desktops.flag_set_kde ]; } + assertionFlag = { assertion = false; }; # assert is nix language keyword + + }; + + collectExtraPhaseActions = [ "extraConfigureCmd" ]; + + extraAttrs = co : { + name = ( __head (co.collectAttrs "name") ); + + unpackPhase = " + echo my name is + echo \$name + echo + echo flag given \\(should be 1 or empty string\\) ? + echo \$flag_set_flag + echo + echo my build inputs are + echo \$buildInputs + echo + echo my configuration flags are + echo \$configureFlags + echo + echo what about gnumake? Did it pass? + echo \$gnumake + echo + echo configurePhase command is + echo $\configurePhase + echo + echo gnutar passed? \\(optional test\\) + echo \$gnutar + echo + echo dying now + echo die_Hopefully_Soon + "; + configurePhase = co.extraConfigureCmd; + }; + } // extraFlagAttrs ); + + + simpleYes = simpleFlagYesNoF "" {} { + inherit whoGetsTheFlagFirst lib stdenv; + flags = ["flag"]; + }; + # note the "I'll bite you" because of the implies attribute + simpleNo = simpleFlagYesNoF "" {} { + inherit whoGetsTheFlagFirst lib stdenv; + flags = []; + }; + + # specifying defaults by adding a default attribute + + yesAgainDefault = simpleFlagYesNoF "default" { defaults = [ "flag" ];} { + inherit whoGetsTheFlagFirst lib stdenv; + }; + noAgainOverridingDefault = simpleFlagYesNoF "default" { defaults = [ "flag" ];} { + inherit whoGetsTheFlagFirst lib stdenv; + flags = []; + }; + + # requested by Michael Raskin: activate flag automatically if dependency is passed: + withGnutarOptional = simpleFlagYesNoF "optionals" { optionals = [ "gnutar" ];} { + flags = [ "flag" ]; # I only need to pass this to trigger name optionalssimpleYes + inherit whoGetsTheFlagFirst lib stdenv; + inherit gnutar; + }; + withoutGnutarOptional = simpleFlagYesNoF "optionals" { optionals = [ "gnutar" ];} { + inherit whoGetsTheFlagFirst lib stdenv; + }; + + # blocking example, this shouldn't even start building: + blockingBiteMonster = simpleFlagYesNoF "biting" {} { + inherit whoGetsTheFlagFirst lib stdenv; + flags = [ "flag" "bitingMonster" ]; + }; + + # assertion example this shouldn't even start building: + assertion = simpleFlagYesNoF "assertion" {} { + inherit whoGetsTheFlagFirst lib stdenv; + flags = [ "assertionFlag" ]; + }; +*/ diff --git a/pkgs/lib/strings-with-deps.nix b/pkgs/lib/strings-with-deps.nix index 78cded99ef71..4fb4fe150a7c 100644 --- a/pkgs/lib/strings-with-deps.nix +++ b/pkgs/lib/strings-with-deps.nix @@ -1,9 +1,24 @@ +/* +Usage: + + You define you custom builder script by adding all build steps to a list. + for example: + builder = writeScript "fsg-4.4-builder" + (textClosure [doUnpack addInputs preBuild doMake installPhase doForceShare]); + + a step is defined by noDepEntry, FullDepEntry or PackEntry. + To ensure that prerequisite are met those are added before the task itself by + textClosureDupList. Duplicated items are removed again. + + See trace/nixpkgs/trunk/pkgs/top-level/builder-defs.nix for some predefined build steps + +*/ args: with args; with lib; let inherit (builtins) - head tail isList; + head tail isList isAttrs; in rec { @@ -37,12 +52,23 @@ rec { (concatLists (map textClosureDupList arg.deps)) ++ [arg] ); - textClosureList = arg: + textClosureDupListOverridable = predefined: arg: + ( + if isList arg then + textClosureDupListOverridable predefined {text = ""; deps = arg;} + else if isAttrs arg then + (concatLists (map (textClosureDupListOverridable predefined) arg.deps)) ++ [arg] + else + textClosureDupListOverridable predefined (getAttr [arg] [] predefined) + ); + + textClosureListOverridable = predefined: arg: (map (x : x.text) - (uniqList {inputList = textClosureDupList arg;})); - textClosure = arg: concatStringsSep "\n" (textClosureList arg); + (uniqList {inputList = textClosureDupListOverridable predefined arg;})); + textClosureOverridable = predefined: arg: concatStringsSep "\n" (textClosureListOverridable predefined arg); - textClosureMap = f: arg: concatStringsSep "\n" (map f (textClosureList arg)); + textClosureMapOveridable = f: predefined: arg: + concatStringsSep "\n" (map f (textClosureListOverridable predefined arg)); noDepEntry = text : {inherit text;deps = [];}; FullDepEntry = text : deps: {inherit text deps;}; |