about summary refs log tree commit diff
path: root/nixpkgs/lib
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2019-01-07 02:18:36 +0000
committerAlyssa Ross <hi@alyssa.is>2019-01-07 02:18:47 +0000
commit36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2 (patch)
treeb3faaf573407b32aa645237a4d16b82778a39a92 /nixpkgs/lib
parent4e31070265257dc67d120c27e0f75c2344fdfa9a (diff)
parentabf060725d7614bd3b9f96764262dfbc2f9c2199 (diff)
downloadnixlib-36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2.tar
nixlib-36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2.tar.gz
nixlib-36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2.tar.bz2
nixlib-36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2.tar.lz
nixlib-36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2.tar.xz
nixlib-36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2.tar.zst
nixlib-36f56d99fa0a0765c9f1de4a5f17a9b05830c3f2.zip
Add 'nixpkgs/' from commit 'abf060725d7614bd3b9f96764262dfbc2f9c2199'
git-subtree-dir: nixpkgs
git-subtree-mainline: 4e31070265257dc67d120c27e0f75c2344fdfa9a
git-subtree-split: abf060725d7614bd3b9f96764262dfbc2f9c2199
Diffstat (limited to 'nixpkgs/lib')
-rw-r--r--nixpkgs/lib/asserts.nix44
-rw-r--r--nixpkgs/lib/attrsets.nix482
-rw-r--r--nixpkgs/lib/composable-derivation.nix113
-rw-r--r--nixpkgs/lib/customisation.nix206
-rw-r--r--nixpkgs/lib/debug.nix253
-rw-r--r--nixpkgs/lib/default.nix138
-rw-r--r--nixpkgs/lib/deprecated.nix393
-rw-r--r--nixpkgs/lib/fetchers.nix13
-rw-r--r--nixpkgs/lib/filesystem.nix45
-rw-r--r--nixpkgs/lib/fixed-points.nix101
-rw-r--r--nixpkgs/lib/generators.nix227
-rw-r--r--nixpkgs/lib/kernel.nix57
-rw-r--r--nixpkgs/lib/licenses.nix732
-rw-r--r--nixpkgs/lib/lists.nix663
-rw-r--r--nixpkgs/lib/meta.nix89
-rw-r--r--nixpkgs/lib/minver.nix2
-rw-r--r--nixpkgs/lib/modules.nix715
-rw-r--r--nixpkgs/lib/options.nix207
-rw-r--r--nixpkgs/lib/sources.nix104
-rw-r--r--nixpkgs/lib/strings-with-deps.nix79
-rw-r--r--nixpkgs/lib/strings.nix684
-rw-r--r--nixpkgs/lib/systems/default.nix120
-rw-r--r--nixpkgs/lib/systems/doubles.nix51
-rw-r--r--nixpkgs/lib/systems/examples.nix215
-rw-r--r--nixpkgs/lib/systems/for-meta.nix37
-rw-r--r--nixpkgs/lib/systems/inspect.nix60
-rw-r--r--nixpkgs/lib/systems/parse.nix352
-rw-r--r--nixpkgs/lib/systems/platforms.nix480
-rw-r--r--nixpkgs/lib/tests/check-eval.nix7
-rw-r--r--nixpkgs/lib/tests/misc.nix442
-rwxr-xr-xnixpkgs/lib/tests/modules.sh161
-rw-r--r--nixpkgs/lib/tests/modules/declare-coerced-value-unsound.nix10
-rw-r--r--nixpkgs/lib/tests/modules/declare-coerced-value.nix10
-rw-r--r--nixpkgs/lib/tests/modules/declare-enable.nix14
-rw-r--r--nixpkgs/lib/tests/modules/declare-int-between-value.nix9
-rw-r--r--nixpkgs/lib/tests/modules/declare-int-positive-value.nix9
-rw-r--r--nixpkgs/lib/tests/modules/declare-int-unsigned-value.nix9
-rw-r--r--nixpkgs/lib/tests/modules/declare-loaOfSub-any-enable.nix29
-rw-r--r--nixpkgs/lib/tests/modules/default.nix8
-rw-r--r--nixpkgs/lib/tests/modules/define-_module-args-custom.nix7
-rw-r--r--nixpkgs/lib/tests/modules/define-enable-force.nix5
-rw-r--r--nixpkgs/lib/tests/modules/define-enable-with-custom-arg.nix7
-rw-r--r--nixpkgs/lib/tests/modules/define-enable.nix3
-rw-r--r--nixpkgs/lib/tests/modules/define-force-enable.nix5
-rw-r--r--nixpkgs/lib/tests/modules/define-force-loaOfSub-foo-enable.nix5
-rw-r--r--nixpkgs/lib/tests/modules/define-if-loaOfSub-foo-enable.nix5
-rw-r--r--nixpkgs/lib/tests/modules/define-loaOfSub-bar-enable.nix3
-rw-r--r--nixpkgs/lib/tests/modules/define-loaOfSub-bar.nix3
-rw-r--r--nixpkgs/lib/tests/modules/define-loaOfSub-foo-enable-force.nix5
-rw-r--r--nixpkgs/lib/tests/modules/define-loaOfSub-foo-enable-if.nix5
-rw-r--r--nixpkgs/lib/tests/modules/define-loaOfSub-foo-enable.nix3
-rw-r--r--nixpkgs/lib/tests/modules/define-loaOfSub-foo-force-enable.nix7
-rw-r--r--nixpkgs/lib/tests/modules/define-loaOfSub-foo-if-enable.nix7
-rw-r--r--nixpkgs/lib/tests/modules/define-loaOfSub-foo.nix3
-rw-r--r--nixpkgs/lib/tests/modules/define-loaOfSub-force-foo-enable.nix7
-rw-r--r--nixpkgs/lib/tests/modules/define-loaOfSub-if-foo-enable.nix7
-rw-r--r--nixpkgs/lib/tests/modules/define-module-check.nix3
-rw-r--r--nixpkgs/lib/tests/modules/define-value-int-negative.nix3
-rw-r--r--nixpkgs/lib/tests/modules/define-value-int-positive.nix3
-rw-r--r--nixpkgs/lib/tests/modules/define-value-int-zero.nix3
-rw-r--r--nixpkgs/lib/tests/modules/define-value-list.nix3
-rw-r--r--nixpkgs/lib/tests/modules/define-value-string-arbitrary.nix3
-rw-r--r--nixpkgs/lib/tests/modules/define-value-string-bigint.nix3
-rw-r--r--nixpkgs/lib/tests/modules/define-value-string.nix3
-rw-r--r--nixpkgs/lib/tests/modules/disable-declare-enable.nix5
-rw-r--r--nixpkgs/lib/tests/modules/disable-define-enable.nix5
-rw-r--r--nixpkgs/lib/tests/modules/disable-enable-modules.nix5
-rw-r--r--nixpkgs/lib/tests/modules/import-custom-arg.nix6
-rw-r--r--nixpkgs/lib/tests/modules/loaOf-with-long-list.nix19
-rw-r--r--nixpkgs/lib/tests/modules/loaOf-with-many-list-merges.nix19
-rw-r--r--nixpkgs/lib/tests/release.nix31
-rw-r--r--nixpkgs/lib/tests/systems.nix32
-rw-r--r--nixpkgs/lib/trivial.nix297
-rw-r--r--nixpkgs/lib/types.nix484
-rw-r--r--nixpkgs/lib/versions.nix47
-rw-r--r--nixpkgs/lib/zip-int-bits.nix39
76 files changed, 8470 insertions, 0 deletions
diff --git a/nixpkgs/lib/asserts.nix b/nixpkgs/lib/asserts.nix
new file mode 100644
index 000000000000..8a5f1fb3feb7
--- /dev/null
+++ b/nixpkgs/lib/asserts.nix
@@ -0,0 +1,44 @@
+{ lib }:
+
+rec {
+
+  /* Print a trace message if pred is false.
+     Intended to be used to augment asserts with helpful error messages.
+
+     Example:
+       assertMsg false "nope"
+       => false
+       stderr> trace: nope
+
+       assert (assertMsg ("foo" == "bar") "foo is not bar, silly"); ""
+       stderr> trace: foo is not bar, silly
+       stderr> assert failed at …
+
+     Type:
+       assertMsg :: Bool -> String -> Bool
+  */
+  # TODO(Profpatsch): add tests that check stderr
+  assertMsg = pred: msg:
+    if pred
+    then true
+    else builtins.trace msg false;
+
+  /* Specialized `assertMsg` for checking if val is one of the elements
+     of a list. Useful for checking enums.
+
+     Example:
+       let sslLibrary = "libressl"
+       in assertOneOf "sslLibrary" sslLibrary [ "openssl" "bearssl" ]
+       => false
+       stderr> trace: sslLibrary must be one of "openssl", "bearssl", but is: "libressl"
+
+     Type:
+       assertOneOf :: String -> ComparableVal -> List ComparableVal -> Bool
+  */
+  assertOneOf = name: val: xs: assertMsg
+    (lib.elem val xs)
+    "${name} must be one of ${
+      lib.generators.toPretty {} xs}, but is: ${
+        lib.generators.toPretty {} val}";
+
+}
diff --git a/nixpkgs/lib/attrsets.nix b/nixpkgs/lib/attrsets.nix
new file mode 100644
index 000000000000..d374d229f597
--- /dev/null
+++ b/nixpkgs/lib/attrsets.nix
@@ -0,0 +1,482 @@
+{ lib }:
+# Operations on attribute sets.
+
+let
+  inherit (builtins) head tail length;
+  inherit (lib.trivial) and;
+  inherit (lib.strings) concatStringsSep;
+  inherit (lib.lists) fold concatMap concatLists;
+in
+
+rec {
+  inherit (builtins) attrNames listToAttrs hasAttr isAttrs getAttr;
+
+
+  /* Return an attribute from nested attribute sets.
+
+     Example:
+       x = { a = { b = 3; }; }
+       attrByPath ["a" "b"] 6 x
+       => 3
+       attrByPath ["z" "z"] 6 x
+       => 6
+  */
+  attrByPath = attrPath: default: e:
+    let attr = head attrPath;
+    in
+      if attrPath == [] then e
+      else if e ? ${attr}
+      then attrByPath (tail attrPath) default e.${attr}
+      else default;
+
+  /* Return if an attribute from nested attribute set exists.
+
+     Example:
+       x = { a = { b = 3; }; }
+       hasAttrByPath ["a" "b"] x
+       => true
+       hasAttrByPath ["z" "z"] x
+       => false
+
+  */
+  hasAttrByPath = attrPath: e:
+    let attr = head attrPath;
+    in
+      if attrPath == [] then true
+      else if e ? ${attr}
+      then hasAttrByPath (tail attrPath) e.${attr}
+      else false;
+
+
+  /* Return nested attribute set in which an attribute is set.
+
+     Example:
+       setAttrByPath ["a" "b"] 3
+       => { a = { b = 3; }; }
+  */
+  setAttrByPath = attrPath: value:
+    if attrPath == [] then value
+    else listToAttrs
+      [ { name = head attrPath; value = setAttrByPath (tail attrPath) value; } ];
+
+
+  /* Like `getAttrPath' without a default value. If it doesn't find the
+     path it will throw.
+
+     Example:
+       x = { a = { b = 3; }; }
+       getAttrFromPath ["a" "b"] x
+       => 3
+       getAttrFromPath ["z" "z"] x
+       => error: cannot find attribute `z.z'
+  */
+  getAttrFromPath = attrPath: set:
+    let errorMsg = "cannot find attribute `" + concatStringsSep "." attrPath + "'";
+    in attrByPath attrPath (abort errorMsg) set;
+
+
+  /* Return the specified attributes from a set.
+
+     Example:
+       attrVals ["a" "b" "c"] as
+       => [as.a as.b as.c]
+  */
+  attrVals = nameList: set: map (x: set.${x}) nameList;
+
+
+  /* Return the values of all attributes in the given set, sorted by
+     attribute name.
+
+     Example:
+       attrValues {c = 3; a = 1; b = 2;}
+       => [1 2 3]
+  */
+  attrValues = builtins.attrValues or (attrs: attrVals (attrNames attrs) attrs);
+
+
+  /* Given a set of attribute names, return the set of the corresponding
+     attributes from the given set.
+
+     Example:
+       getAttrs [ "a" "b" ] { a = 1; b = 2; c = 3; }
+       => { a = 1; b = 2; }
+  */
+  getAttrs = names: attrs: genAttrs names (name: attrs.${name});
+
+  /* Collect each attribute named `attr' from a list of attribute
+     sets.  Sets that don't contain the named attribute are ignored.
+
+     Example:
+       catAttrs "a" [{a = 1;} {b = 0;} {a = 2;}]
+       => [1 2]
+  */
+  catAttrs = builtins.catAttrs or
+    (attr: l: concatLists (map (s: if s ? ${attr} then [s.${attr}] else []) l));
+
+
+  /* Filter an attribute set by removing all attributes for which the
+     given predicate return false.
+
+     Example:
+       filterAttrs (n: v: n == "foo") { foo = 1; bar = 2; }
+       => { foo = 1; }
+  */
+  filterAttrs = pred: set:
+    listToAttrs (concatMap (name: let v = set.${name}; in if pred name v then [(nameValuePair name v)] else []) (attrNames set));
+
+
+  /* Filter an attribute set recursively by removing all attributes for
+     which the given predicate return false.
+
+     Example:
+       filterAttrsRecursive (n: v: v != null) { foo = { bar = null; }; }
+       => { foo = {}; }
+  */
+  filterAttrsRecursive = pred: set:
+    listToAttrs (
+      concatMap (name:
+        let v = set.${name}; in
+        if pred name v then [
+          (nameValuePair name (
+            if isAttrs v then filterAttrsRecursive pred v
+            else v
+          ))
+        ] else []
+      ) (attrNames set)
+    );
+
+  /* Apply fold functions to values grouped by key.
+
+     Example:
+       foldAttrs (n: a: [n] ++ a) [] [{ a = 2; } { a = 3; }]
+       => { a = [ 2 3 ]; }
+  */
+  foldAttrs = op: nul: list_of_attrs:
+    fold (n: a:
+        fold (name: o:
+          o // { ${name} = op n.${name} (a.${name} or nul); }
+        ) a (attrNames n)
+    ) {} list_of_attrs;
+
+
+  /* Recursively collect sets that verify a given predicate named `pred'
+     from the set `attrs'.  The recursion is stopped when the predicate is
+     verified.
+
+     Type:
+       collect ::
+         (AttrSet -> Bool) -> AttrSet -> [x]
+
+     Example:
+       collect isList { a = { b = ["b"]; }; c = [1]; }
+       => [["b"] [1]]
+
+       collect (x: x ? outPath)
+          { a = { outPath = "a/"; }; b = { outPath = "b/"; }; }
+       => [{ outPath = "a/"; } { outPath = "b/"; }]
+  */
+  collect = pred: attrs:
+    if pred attrs then
+      [ attrs ]
+    else if isAttrs attrs then
+      concatMap (collect pred) (attrValues attrs)
+    else
+      [];
+
+
+  /* Utility function that creates a {name, value} pair as expected by
+     builtins.listToAttrs.
+
+     Example:
+       nameValuePair "some" 6
+       => { name = "some"; value = 6; }
+  */
+  nameValuePair = name: value: { inherit name value; };
+
+
+  /* Apply a function to each element in an attribute set.  The
+     function takes two arguments --- the attribute name and its value
+     --- and returns the new value for the attribute.  The result is a
+     new attribute set.
+
+     Example:
+       mapAttrs (name: value: name + "-" + value)
+          { x = "foo"; y = "bar"; }
+       => { x = "x-foo"; y = "y-bar"; }
+  */
+  mapAttrs = builtins.mapAttrs or
+    (f: set:
+      listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set)));
+
+
+  /* Like `mapAttrs', but allows the name of each attribute to be
+     changed in addition to the value.  The applied function should
+     return both the new name and value as a `nameValuePair'.
+
+     Example:
+       mapAttrs' (name: value: nameValuePair ("foo_" + name) ("bar-" + value))
+          { x = "a"; y = "b"; }
+       => { foo_x = "bar-a"; foo_y = "bar-b"; }
+  */
+  mapAttrs' = f: set:
+    listToAttrs (map (attr: f attr set.${attr}) (attrNames set));
+
+
+  /* Call a function for each attribute in the given set and return
+     the result in a list.
+
+     Example:
+       mapAttrsToList (name: value: name + value)
+          { x = "a"; y = "b"; }
+       => [ "xa" "yb" ]
+  */
+  mapAttrsToList = f: attrs:
+    map (name: f name attrs.${name}) (attrNames attrs);
+
+
+  /* Like `mapAttrs', except that it recursively applies itself to
+     attribute sets.  Also, the first argument of the argument
+     function is a *list* of the names of the containing attributes.
+
+     Type:
+       mapAttrsRecursive ::
+         ([String] -> a -> b) -> AttrSet -> AttrSet
+
+     Example:
+       mapAttrsRecursive (path: value: concatStringsSep "-" (path ++ [value]))
+         { n = { a = "A"; m = { b = "B"; c = "C"; }; }; d = "D"; }
+       => { n = { a = "n-a-A"; m = { b = "n-m-b-B"; c = "n-m-c-C"; }; }; d = "d-D"; }
+  */
+  mapAttrsRecursive = mapAttrsRecursiveCond (as: true);
+
+
+  /* Like `mapAttrsRecursive', but it takes an additional predicate
+     function that tells it whether to recursive into an attribute
+     set.  If it returns false, `mapAttrsRecursiveCond' does not
+     recurse, but does apply the map function.  It is returns true, it
+     does recurse, and does not apply the map function.
+
+     Type:
+       mapAttrsRecursiveCond ::
+         (AttrSet -> Bool) -> ([String] -> a -> b) -> AttrSet -> AttrSet
+
+     Example:
+       # To prevent recursing into derivations (which are attribute
+       # sets with the attribute "type" equal to "derivation"):
+       mapAttrsRecursiveCond
+         (as: !(as ? "type" && as.type == "derivation"))
+         (x: ... do something ...)
+         attrs
+  */
+  mapAttrsRecursiveCond = cond: f: set:
+    let
+      recurse = path: set:
+        let
+          g =
+            name: value:
+            if isAttrs value && cond value
+              then recurse (path ++ [name]) value
+              else f (path ++ [name]) value;
+        in mapAttrs g set;
+    in recurse [] set;
+
+
+  /* Generate an attribute set by mapping a function over a list of
+     attribute names.
+
+     Example:
+       genAttrs [ "foo" "bar" ] (name: "x_" + name)
+       => { foo = "x_foo"; bar = "x_bar"; }
+  */
+  genAttrs = names: f:
+    listToAttrs (map (n: nameValuePair n (f n)) names);
+
+
+  /* Check whether the argument is a derivation. Any set with
+     { type = "derivation"; } counts as a derivation.
+
+     Example:
+       nixpkgs = import <nixpkgs> {}
+       isDerivation nixpkgs.ruby
+       => true
+       isDerivation "foobar"
+       => false
+  */
+  isDerivation = x: isAttrs x && x ? type && x.type == "derivation";
+
+  /* Converts a store path to a fake derivation. */
+  toDerivation = path:
+    let
+      path' = builtins.storePath path;
+      res =
+        { type = "derivation";
+          name = builtins.unsafeDiscardStringContext (builtins.substring 33 (-1) (baseNameOf path'));
+          outPath = path';
+          outputs = [ "out" ];
+          out = res;
+          outputName = "out";
+        };
+    in res;
+
+
+  /* If `cond' is true, return the attribute set `as',
+     otherwise an empty attribute set.
+
+     Example:
+       optionalAttrs (true) { my = "set"; }
+       => { my = "set"; }
+       optionalAttrs (false) { my = "set"; }
+       => { }
+  */
+  optionalAttrs = cond: as: if cond then as else {};
+
+
+  /* Merge sets of attributes and use the function f to merge attributes
+     values.
+
+     Example:
+       zipAttrsWithNames ["a"] (name: vs: vs) [{a = "x";} {a = "y"; b = "z";}]
+       => { a = ["x" "y"]; }
+  */
+  zipAttrsWithNames = names: f: sets:
+    listToAttrs (map (name: {
+      inherit name;
+      value = f name (catAttrs name sets);
+    }) names);
+
+  /* Implementation note: Common names  appear multiple times in the list of
+     names, hopefully this does not affect the system because the maximal
+     laziness avoid computing twice the same expression and listToAttrs does
+     not care about duplicated attribute names.
+
+     Example:
+       zipAttrsWith (name: values: values) [{a = "x";} {a = "y"; b = "z";}]
+       => { a = ["x" "y"]; b = ["z"] }
+  */
+  zipAttrsWith = f: sets: zipAttrsWithNames (concatMap attrNames sets) f sets;
+  /* Like `zipAttrsWith' with `(name: values: value)' as the function.
+
+    Example:
+      zipAttrs [{a = "x";} {a = "y"; b = "z";}]
+      => { a = ["x" "y"]; b = ["z"] }
+  */
+  zipAttrs = zipAttrsWith (name: values: values);
+
+  /* Does the same as the update operator '//' except that attributes are
+     merged until the given predicate is verified.  The predicate should
+     accept 3 arguments which are the path to reach the attribute, a part of
+     the first attribute set and a part of the second attribute set.  When
+     the predicate is verified, the value of the first attribute set is
+     replaced by the value of the second attribute set.
+
+     Example:
+       recursiveUpdateUntil (path: l: r: path == ["foo"]) {
+         # first attribute set
+         foo.bar = 1;
+         foo.baz = 2;
+         bar = 3;
+       } {
+         #second attribute set
+         foo.bar = 1;
+         foo.quz = 2;
+         baz = 4;
+       }
+
+       returns: {
+         foo.bar = 1; # 'foo.*' from the second set
+         foo.quz = 2; #
+         bar = 3;     # 'bar' from the first set
+         baz = 4;     # 'baz' from the second set
+       }
+
+     */
+  recursiveUpdateUntil = pred: lhs: rhs:
+    let f = attrPath:
+      zipAttrsWith (n: values:
+        let here = attrPath ++ [n]; in
+        if tail values == []
+        || pred here (head (tail values)) (head values) then
+          head values
+        else
+          f here values
+      );
+    in f [] [rhs lhs];
+
+  /* A recursive variant of the update operator ‘//’.  The recursion
+     stops when one of the attribute values is not an attribute set,
+     in which case the right hand side value takes precedence over the
+     left hand side value.
+
+     Example:
+       recursiveUpdate {
+         boot.loader.grub.enable = true;
+         boot.loader.grub.device = "/dev/hda";
+       } {
+         boot.loader.grub.device = "";
+       }
+
+       returns: {
+         boot.loader.grub.enable = true;
+         boot.loader.grub.device = "";
+       }
+
+     */
+  recursiveUpdate = lhs: rhs:
+    recursiveUpdateUntil (path: lhs: rhs:
+      !(isAttrs lhs && isAttrs rhs)
+    ) lhs rhs;
+
+  /* Returns true if the pattern is contained in the set. False otherwise.
+
+     Example:
+       matchAttrs { cpu = {}; } { cpu = { bits = 64; }; }
+       => true
+   */
+  matchAttrs = pattern: attrs: assert isAttrs pattern;
+    fold and true (attrValues (zipAttrsWithNames (attrNames pattern) (n: values:
+      let pat = head values; val = head (tail values); in
+      if length values == 1 then false
+      else if isAttrs pat then isAttrs val && matchAttrs pat val
+      else pat == val
+    ) [pattern attrs]));
+
+  /* Override only the attributes that are already present in the old set
+    useful for deep-overriding.
+
+    Example:
+      overrideExisting {} { a = 1; }
+      => {}
+      overrideExisting { b = 2; } { a = 1; }
+      => { b = 2; }
+      overrideExisting { a = 3; b = 2; } { a = 1; }
+      => { a = 1; b = 2; }
+  */
+  overrideExisting = old: new:
+    mapAttrs (name: value: new.${name} or value) old;
+
+  /* Get a package output.
+     If no output is found, fallback to `.out` and then to the default.
+
+     Example:
+       getOutput "dev" pkgs.openssl
+       => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-dev"
+  */
+  getOutput = output: pkg:
+    if pkg.outputUnspecified or false
+      then pkg.${output} or pkg.out or pkg
+      else pkg;
+
+  getBin = getOutput "bin";
+  getLib = getOutput "lib";
+  getDev = getOutput "dev";
+
+  /* Pick the outputs of packages to place in buildInputs */
+  chooseDevOutputs = drvs: builtins.map getDev drvs;
+
+  /*** deprecated stuff ***/
+
+  zipWithNames = zipAttrsWithNames;
+  zip = builtins.trace
+    "lib.zip is deprecated, use lib.zipAttrsWith instead" zipAttrsWith;
+
+}
diff --git a/nixpkgs/lib/composable-derivation.nix b/nixpkgs/lib/composable-derivation.nix
new file mode 100644
index 000000000000..cb1fdc121e11
--- /dev/null
+++ b/nixpkgs/lib/composable-derivation.nix
@@ -0,0 +1,113 @@
+{lib, pkgs}:
+let inherit (lib) nvs; in
+{
+
+  # composableDerivation basically mixes these features:
+  # - fix function
+  # - mergeAttrBy
+  # - provides shortcuts for "options" such as "--enable-foo" and adding
+  #   buildInputs, see php example
+  #
+  # It predates styles which are common today, such as
+  #  * the config attr
+  #  * mkDerivation.override feature
+  #  * overrideDerivation (lib/customization.nix)
+  #
+  # Some of the most more important usage examples (which could be rewritten if it was important):
+  # * php
+  # * postgis
+  # * vim_configurable
+  #
+  # A minimal example illustrating most features would look like this:
+  # let base = composableDerivation { (fixed: let inherit (fixed.fixed) name in {
+  #    src = fetchurl {
+  #    }
+  #    buildInputs = [A];
+  #    preConfigre = "echo ${name}";
+  #    # attention, "name" attr is missing, thus you cannot instantiate "base".
+  # }
+  # in {
+  #  # These all add name attribute, thus you can instantiate those:
+  #  v1 = base.merge   ({ name = "foo-add-B"; buildInputs = [B]; });       // B gets merged into buildInputs
+  #  v2 = base.merge   ({ name = "mix-in-pre-configure-lines" preConfigre = ""; });
+  #  v3 = base.replace ({ name = "foo-no-A-only-B;" buildInputs = [B]; });
+  # }
+  #
+  # So yes, you can think about it being something like nixos modules, and
+  # you'd be merging "features" in one at a time using .merge or .replace
+  # Thanks Shea for telling me that I rethink the documentation ..
+  #
+  # issues:
+  # * its complicated to understand
+  # * some "features" such as exact merge behaviour are buried in mergeAttrBy
+  #   and defaultOverridableDelayableArgs assuming the default behaviour does
+  #   the right thing in the common case
+  # * Eelco once said using such fix style functions are slow to evaluate
+  # * Too quick & dirty. Hard to understand for others. The benefit was that
+  #   you were able to create a kernel builder like base derivation and replace
+  #   / add patches the way you want without having to declare function arguments
+  #
+  # nice features:
+  # declaring "optional features" is modular. For instance:
+  #   flags.curl = {
+  #     configureFlags = ["--with-curl=${curl.dev}" "--with-curlwrappers"];
+  #     buildInputs = [curl openssl];
+  #   };
+  #   flags.other = { .. }
+  # (Example taken from PHP)
+  #
+  # alternative styles / related features:
+  #  * Eg see function supporting building the kernel
+  #  * versionedDerivation (discussion about this is still going on - or ended)
+  #  * composedArgsAndFun
+  #  * mkDerivation.override
+  #  * overrideDerivation
+  #  * using { .., *Support ? false }: like configurable options.
+  # To find those examples use grep
+  #
+  # To sum up: It exists for historical reasons - and for most commonly used
+  # tasks the alternatives should be used
+  #
+  # If you have questions about this code ping Marc Weber.
+  composableDerivation = {
+        mkDerivation ? pkgs.stdenv.mkDerivation,
+
+        # list of functions to be applied before defaultOverridableDelayableArgs removes removeAttrs names
+        # prepareDerivationArgs handles derivation configurations
+        applyPreTidy ? [ lib.prepareDerivationArgs ],
+
+        # consider adding addtional elements by derivation.merge { removeAttrs = ["elem"]; };
+        removeAttrs ? ["cfg" "flags"]
+
+      }: (lib.defaultOverridableDelayableArgs ( a: mkDerivation a)
+         {
+           inherit applyPreTidy removeAttrs;
+         }).merge;
+
+  # some utility functions
+  # use this function to generate flag attrs for prepareDerivationArgs
+  # E nable  D isable F eature
+  edf = {name, feat ? name, enable ? {}, disable ? {} , value ? ""}:
+    nvs name {
+    set = {
+      configureFlags = ["--enable-${feat}${if value == "" then "" else "="}${value}"];
+    } // enable;
+    unset = {
+      configureFlags = ["--disable-${feat}"];
+    } // disable;
+  };
+
+  # same for --with and --without-
+  # W ith or W ithout F eature
+  wwf = {name, feat ? name, enable ? {}, disable ? {}, value ? ""}:
+    nvs name {
+    set = enable // {
+      configureFlags = ["--with-${feat}${if value == "" then "" else "="}${value}"]
+                       ++ lib.maybeAttr "configureFlags" [] enable;
+    };
+    unset = disable // {
+      configureFlags = ["--without-${feat}"]
+                       ++ lib.maybeAttr "configureFlags" [] disable;
+    };
+  };
+}
diff --git a/nixpkgs/lib/customisation.nix b/nixpkgs/lib/customisation.nix
new file mode 100644
index 000000000000..68062dd0daf0
--- /dev/null
+++ b/nixpkgs/lib/customisation.nix
@@ -0,0 +1,206 @@
+{ lib }:
+
+rec {
+
+
+  /* `overrideDerivation drv f' takes a derivation (i.e., the result
+     of a call to the builtin function `derivation') and returns a new
+     derivation in which the attributes of the original are overridden
+     according to the function `f'.  The function `f' is called with
+     the original derivation attributes.
+
+     `overrideDerivation' allows certain "ad-hoc" customisation
+     scenarios (e.g. in ~/.config/nixpkgs/config.nix).  For instance,
+     if you want to "patch" the derivation returned by a package
+     function in Nixpkgs to build another version than what the
+     function itself provides, you can do something like this:
+
+       mySed = overrideDerivation pkgs.gnused (oldAttrs: {
+         name = "sed-4.2.2-pre";
+         src = fetchurl {
+           url = ftp://alpha.gnu.org/gnu/sed/sed-4.2.2-pre.tar.bz2;
+           sha256 = "11nq06d131y4wmf3drm0yk502d2xc6n5qy82cg88rb9nqd2lj41k";
+         };
+         patches = [];
+       });
+
+     For another application, see build-support/vm, where this
+     function is used to build arbitrary derivations inside a QEMU
+     virtual machine.
+  */
+  overrideDerivation = drv: f:
+    let
+      newDrv = derivation (drv.drvAttrs // (f drv));
+    in lib.flip (extendDerivation true) newDrv (
+      { meta = drv.meta or {};
+        passthru = if drv ? passthru then drv.passthru else {};
+      }
+      //
+      (drv.passthru or {})
+      //
+      (if (drv ? crossDrv && drv ? nativeDrv)
+       then {
+         crossDrv = overrideDerivation drv.crossDrv f;
+         nativeDrv = overrideDerivation drv.nativeDrv f;
+       }
+       else { }));
+
+
+  /* `makeOverridable` takes a function from attribute set to attribute set and
+     injects `override` attibute which can be used to override arguments of
+     the function.
+
+       nix-repl> x = {a, b}: { result = a + b; }
+
+       nix-repl> y = lib.makeOverridable x { a = 1; b = 2; }
+
+       nix-repl> y
+       { override = «lambda»; overrideDerivation = «lambda»; result = 3; }
+
+       nix-repl> y.override { a = 10; }
+       { override = «lambda»; overrideDerivation = «lambda»; result = 12; }
+
+     Please refer to "Nixpkgs Contributors Guide" section
+     "<pkg>.overrideDerivation" to learn about `overrideDerivation` and caveats
+     related to its use.
+  */
+  makeOverridable = f: origArgs:
+    let
+      ff = f origArgs;
+      overrideWith = newArgs: origArgs // (if lib.isFunction newArgs then newArgs origArgs else newArgs);
+    in
+      if builtins.isAttrs ff then (ff // {
+        override = newArgs: makeOverridable f (overrideWith newArgs);
+        overrideDerivation = fdrv:
+          makeOverridable (args: overrideDerivation (f args) fdrv) origArgs;
+        ${if ff ? overrideAttrs then "overrideAttrs" else null} = fdrv:
+          makeOverridable (args: (f args).overrideAttrs fdrv) origArgs;
+      })
+      else if lib.isFunction ff then {
+        override = newArgs: makeOverridable f (overrideWith newArgs);
+        __functor = self: ff;
+        overrideDerivation = throw "overrideDerivation not yet supported for functors";
+      }
+      else ff;
+
+
+  /* Call the package function in the file `fn' with the required
+    arguments automatically.  The function is called with the
+    arguments `args', but any missing arguments are obtained from
+    `autoArgs'.  This function is intended to be partially
+    parameterised, e.g.,
+
+      callPackage = callPackageWith pkgs;
+      pkgs = {
+        libfoo = callPackage ./foo.nix { };
+        libbar = callPackage ./bar.nix { };
+      };
+
+    If the `libbar' function expects an argument named `libfoo', it is
+    automatically passed as an argument.  Overrides or missing
+    arguments can be supplied in `args', e.g.
+
+      libbar = callPackage ./bar.nix {
+        libfoo = null;
+        enableX11 = true;
+      };
+  */
+  callPackageWith = autoArgs: fn: args:
+    let
+      f = if lib.isFunction fn then fn else import fn;
+      auto = builtins.intersectAttrs (lib.functionArgs f) autoArgs;
+    in makeOverridable f (auto // args);
+
+
+  /* Like callPackage, but for a function that returns an attribute
+     set of derivations. The override function is added to the
+     individual attributes. */
+  callPackagesWith = autoArgs: fn: args:
+    let
+      f = if lib.isFunction fn then fn else import fn;
+      auto = builtins.intersectAttrs (lib.functionArgs f) autoArgs;
+      origArgs = auto // args;
+      pkgs = f origArgs;
+      mkAttrOverridable = name: pkg: makeOverridable (newArgs: (f newArgs).${name}) origArgs;
+    in lib.mapAttrs mkAttrOverridable pkgs;
+
+
+  /* Add attributes to each output of a derivation without changing
+     the derivation itself and check a given condition when evaluating. */
+  extendDerivation = condition: passthru: drv:
+    let
+      outputs = drv.outputs or [ "out" ];
+
+      commonAttrs = drv // (builtins.listToAttrs outputsList) //
+        ({ all = map (x: x.value) outputsList; }) // passthru;
+
+      outputToAttrListElement = outputName:
+        { name = outputName;
+          value = commonAttrs // {
+            inherit (drv.${outputName}) type outputName;
+            drvPath = assert condition; drv.${outputName}.drvPath;
+            outPath = assert condition; drv.${outputName}.outPath;
+          };
+        };
+
+      outputsList = map outputToAttrListElement outputs;
+    in commonAttrs // {
+      outputUnspecified = true;
+      drvPath = assert condition; drv.drvPath;
+      outPath = assert condition; drv.outPath;
+    };
+
+  /* Strip a derivation of all non-essential attributes, returning
+     only those needed by hydra-eval-jobs. Also strictly evaluate the
+     result to ensure that there are no thunks kept alive to prevent
+     garbage collection. */
+  hydraJob = drv:
+    let
+      outputs = drv.outputs or ["out"];
+
+      commonAttrs =
+        { inherit (drv) name system meta; inherit outputs; }
+        // lib.optionalAttrs (drv._hydraAggregate or false) {
+          _hydraAggregate = true;
+          constituents = map hydraJob (lib.flatten drv.constituents);
+        }
+        // (lib.listToAttrs outputsList);
+
+      makeOutput = outputName:
+        let output = drv.${outputName}; in
+        { name = outputName;
+          value = commonAttrs // {
+            outPath = output.outPath;
+            drvPath = output.drvPath;
+            type = "derivation";
+            inherit outputName;
+          };
+        };
+
+      outputsList = map makeOutput outputs;
+
+      drv' = (lib.head outputsList).value;
+    in lib.deepSeq drv' drv';
+
+  /* Make a set of packages with a common scope. All packages called
+     with the provided `callPackage' will be evaluated with the same
+     arguments. Any package in the set may depend on any other. The
+     `overrideScope'` function allows subsequent modification of the package
+     set in a consistent way, i.e. all packages in the set will be
+     called with the overridden packages. The package sets may be
+     hierarchical: the packages in the set are called with the scope
+     provided by `newScope' and the set provides a `newScope' attribute
+     which can form the parent scope for later package sets. */
+  makeScope = newScope: f:
+    let self = f self // {
+          newScope = scope: newScope (self // scope);
+          callPackage = self.newScope {};
+          overrideScope = g: lib.warn
+            "`overrideScope` (from `lib.makeScope`) is deprecated. Do `overrideScope' (self: super: { … })` instead of `overrideScope (super: self: { … })`. All other overrides have the parameters in that order, including other definitions of `overrideScope`. This was the only definition violating the pattern."
+            (makeScope newScope (lib.fixedPoints.extends (lib.flip g) f));
+          overrideScope' = g: makeScope newScope (lib.fixedPoints.extends g f);
+          packages = f;
+        };
+    in self;
+
+}
diff --git a/nixpkgs/lib/debug.nix b/nixpkgs/lib/debug.nix
new file mode 100644
index 000000000000..2879f72ed2ba
--- /dev/null
+++ b/nixpkgs/lib/debug.nix
@@ -0,0 +1,253 @@
+/* Collection of functions useful for debugging
+   broken nix expressions.
+
+   * `trace`-like functions take two values, print
+     the first to stderr and return the second.
+   * `traceVal`-like functions take one argument
+     which both printed and returned.
+   * `traceSeq`-like functions fully evaluate their
+     traced value before printing (not just to “weak
+     head normal form” like trace does by default).
+   * Functions that end in `-Fn` take an additional
+     function as their first argument, which is applied
+     to the traced value before it is printed.
+*/
+{ lib }:
+let
+  inherit (builtins) trace isAttrs isList isInt
+          head substring attrNames;
+  inherit (lib) id elem isFunction;
+in
+
+rec {
+
+  # -- TRACING --
+
+  /* Conditionally trace the supplied message, based on a predicate.
+
+     Type: traceIf :: bool -> string -> a -> a
+
+     Example:
+       traceIf true "hello" 3
+       trace: hello
+       => 3
+  */
+  traceIf =
+    # Predicate to check
+    pred:
+    # Message that should be traced
+    msg:
+    # Value to return
+    x: if pred then trace msg x else x;
+
+  /* Trace the supplied value after applying a function to it, and
+     return the original value.
+
+     Type: traceValFn :: (a -> b) -> a -> a
+
+     Example:
+       traceValFn (v: "mystring ${v}") "foo"
+       trace: mystring foo
+       => "foo"
+  */
+  traceValFn =
+    # Function to apply
+    f:
+    # Value to trace and return
+    x: trace (f x) x;
+
+  /* Trace the supplied value and return it.
+
+     Type: traceVal :: a -> a
+
+     Example:
+       traceVal 42
+       # trace: 42
+       => 42
+  */
+  traceVal = traceValFn id;
+
+  /* `builtins.trace`, but the value is `builtins.deepSeq`ed first.
+
+     Type: traceSeq :: a -> b -> b
+
+     Example:
+       trace { a.b.c = 3; } null
+       trace: { a = <CODE>; }
+       => null
+       traceSeq { a.b.c = 3; } null
+       trace: { a = { b = { c = 3; }; }; }
+       => null
+  */
+  traceSeq =
+    # The value to trace
+    x:
+    # The value to return
+    y: trace (builtins.deepSeq x x) y;
+
+  /* Like `traceSeq`, but only evaluate down to depth n.
+     This is very useful because lots of `traceSeq` usages
+     lead to an infinite recursion.
+
+     Example:
+       traceSeqN 2 { a.b.c = 3; } null
+       trace: { a = { b = {…}; }; }
+       => null
+   */
+  traceSeqN = depth: x: y: with lib;
+    let snip = v: if      isList  v then noQuotes "[…]" v
+                  else if isAttrs v then noQuotes "{…}" v
+                  else v;
+        noQuotes = str: v: { __pretty = const str; val = v; };
+        modify = n: fn: v: if (n == 0) then fn v
+                      else if isList  v then map (modify (n - 1) fn) v
+                      else if isAttrs v then mapAttrs
+                        (const (modify (n - 1) fn)) v
+                      else v;
+    in trace (generators.toPretty { allowPrettyValues = true; }
+               (modify depth snip x)) y;
+
+  /* A combination of `traceVal` and `traceSeq` that applies a
+     provided function to the value to be traced after `deepSeq`ing
+     it.
+  */
+  traceValSeqFn =
+    # Function to apply
+    f:
+    # Value to trace
+    v: traceValFn f (builtins.deepSeq v v);
+
+  /* A combination of `traceVal` and `traceSeq`. */
+  traceValSeq = traceValSeqFn id;
+
+  /* A combination of `traceVal` and `traceSeqN` that applies a
+  provided function to the value to be traced. */
+  traceValSeqNFn =
+    # Function to apply
+    f:
+    depth:
+    # Value to trace
+    v: traceSeqN depth (f v) v;
+
+  /* A combination of `traceVal` and `traceSeqN`. */
+  traceValSeqN = traceValSeqNFn id;
+
+
+  # -- TESTING --
+
+  /* Evaluate a set of tests.  A test is an attribute set `{expr,
+     expected}`, denoting an expression and its expected result.  The
+     result is a list of failed tests, each represented as `{name,
+     expected, actual}`, denoting the attribute name of the failing
+     test and its expected and actual results.
+
+     Used for regression testing of the functions in lib; see
+     tests.nix for an example. Only tests having names starting with
+     "test" are run.
+
+     Add attr { tests = ["testName"]; } to run these tests only.
+  */
+  runTests =
+    # Tests to run
+    tests: lib.concatLists (lib.attrValues (lib.mapAttrs (name: test:
+    let testsToRun = if tests ? tests then tests.tests else [];
+    in if (substring 0 4 name == "test" ||  elem name testsToRun)
+       && ((testsToRun == []) || elem name tests.tests)
+       && (test.expr != test.expected)
+
+      then [ { inherit name; expected = test.expected; result = test.expr; } ]
+      else [] ) tests));
+
+  /* Create a test assuming that list elements are `true`.
+
+     Example:
+       { testX = allTrue [ true ]; }
+  */
+  testAllTrue = expr: { inherit expr; expected = map (x: true) expr; };
+
+
+  # -- DEPRECATED --
+
+  traceShowVal = x: trace (showVal x) x;
+  traceShowValMarked = str: x: trace (str + showVal x) x;
+
+  attrNamesToStr = a:
+    trace ( "Warning: `attrNamesToStr` is deprecated "
+          + "and will be removed in the next release. "
+          + "Please use more specific concatenation "
+          + "for your uses (`lib.concat(Map)StringsSep`)." )
+    (lib.concatStringsSep "; " (map (x: "${x}=") (attrNames a)));
+
+  showVal = with lib;
+    trace ( "Warning: `showVal` is deprecated "
+          + "and will be removed in the next release, "
+          + "please use `traceSeqN`" )
+    (let
+      modify = v:
+        let pr = f: { __pretty = f; val = v; };
+        in   if isDerivation v then pr
+          (drv: "<δ:${drv.name}:${concatStringsSep ","
+                                 (attrNames drv)}>")
+        else if [] ==   v then pr (const "[]")
+        else if isList  v then pr (l: "[ ${go (head l)}, … ]")
+        else if isAttrs v then pr
+          (a: "{ ${ concatStringsSep ", " (attrNames a)} }")
+        else v;
+      go = x: generators.toPretty
+        { allowPrettyValues = true; }
+        (modify x);
+    in go);
+
+  traceXMLVal = x:
+    trace ( "Warning: `traceXMLVal` is deprecated "
+          + "and will be removed in the next release. "
+          + "Please use `traceValFn builtins.toXML`." )
+    (trace (builtins.toXML x) x);
+  traceXMLValMarked = str: x:
+    trace ( "Warning: `traceXMLValMarked` is deprecated "
+          + "and will be removed in the next release. "
+          + "Please use `traceValFn (x: str + builtins.toXML x)`." )
+    (trace (str + builtins.toXML x) x);
+
+  # trace the arguments passed to function and its result
+  # maybe rewrite these functions in a traceCallXml like style. Then one function is enough
+  traceCall  = n: f: a: let t = n2: x: traceShowValMarked "${n} ${n2}:" x; in t "result" (f (t "arg 1" a));
+  traceCall2 = n: f: a: b: let t = n2: x: traceShowValMarked "${n} ${n2}:" x; in t "result" (f (t "arg 1" a) (t "arg 2" b));
+  traceCall3 = n: f: a: b: c: let t = n2: x: traceShowValMarked "${n} ${n2}:" x; in t "result" (f (t "arg 1" a) (t "arg 2" b) (t "arg 3" c));
+
+  traceValIfNot = c: x:
+    trace ( "Warning: `traceValIfNot` is deprecated "
+          + "and will be removed in the next release. "
+          + "Please use `if/then/else` and `traceValSeq 1`.")
+    (if c x then true else traceSeq (showVal x) false);
+
+
+  addErrorContextToAttrs = attrs:
+    trace ( "Warning: `addErrorContextToAttrs` is deprecated "
+          + "and will be removed in the next release. "
+          + "Please use `builtins.addErrorContext` directly." )
+    (lib.mapAttrs (a: v: lib.addErrorContext "while evaluating ${a}" v) attrs);
+
+  # example: (traceCallXml "myfun" id 3) will output something like
+  # calling myfun arg 1: 3 result: 3
+  # this forces deep evaluation of all arguments and the result!
+  # note: if result doesn't evaluate you'll get no trace at all (FIXME)
+  #       args should be printed in any case
+  traceCallXml = a:
+    trace ( "Warning: `traceCallXml` is deprecated "
+          + "and will be removed in the next release. "
+          + "Please complain if you use the function regularly." )
+    (if !isInt a then
+      traceCallXml 1 "calling ${a}\n"
+    else
+      let nr = a;
+      in (str: expr:
+          if isFunction expr then
+            (arg:
+              traceCallXml (builtins.add 1 nr) "${str}\n arg ${builtins.toString nr} is \n ${builtins.toXML (builtins.seq arg arg)}" (expr arg)
+            )
+          else
+            let r = builtins.seq expr expr;
+            in trace "${str}\n result:\n${builtins.toXML r}" r
+      ));
+}
diff --git a/nixpkgs/lib/default.nix b/nixpkgs/lib/default.nix
new file mode 100644
index 000000000000..e4e3e7d325a4
--- /dev/null
+++ b/nixpkgs/lib/default.nix
@@ -0,0 +1,138 @@
+/* Library of low-level helper functions for nix expressions.
+ *
+ * Please implement (mostly) exhaustive unit tests
+ * for new functions in `./tests.nix'.
+ */
+let
+
+  inherit (import ./fixed-points.nix {}) makeExtensible;
+
+  lib = makeExtensible (self: let
+    callLibs = file: import file { lib = self; };
+  in with self; {
+
+    # often used, or depending on very little
+    trivial = callLibs ./trivial.nix;
+    fixedPoints = callLibs ./fixed-points.nix;
+
+    # datatypes
+    attrsets = callLibs ./attrsets.nix;
+    lists = callLibs ./lists.nix;
+    strings = callLibs ./strings.nix;
+    stringsWithDeps = callLibs ./strings-with-deps.nix;
+
+    # packaging
+    customisation = callLibs ./customisation.nix;
+    maintainers = import ../maintainers/maintainer-list.nix;
+    meta = callLibs ./meta.nix;
+    sources = callLibs ./sources.nix;
+    versions = callLibs ./versions.nix;
+
+    # module system
+    modules = callLibs ./modules.nix;
+    options = callLibs ./options.nix;
+    types = callLibs ./types.nix;
+
+    # constants
+    licenses = callLibs ./licenses.nix;
+    systems = callLibs ./systems;
+
+    # misc
+    asserts = callLibs ./asserts.nix;
+    debug = callLibs ./debug.nix;
+    generators = callLibs ./generators.nix;
+    misc = callLibs ./deprecated.nix;
+
+    # domain-specific
+    fetchers = callLibs ./fetchers.nix;
+
+    # Eval-time filesystem handling
+    filesystem = callLibs ./filesystem.nix;
+
+    # back-compat aliases
+    platforms = systems.forMeta;
+
+    inherit (builtins) add addErrorContext attrNames concatLists
+      deepSeq elem elemAt filter genericClosure genList getAttr
+      hasAttr head isAttrs isBool isInt isList isString length
+      lessThan listToAttrs pathExists readFile replaceStrings seq
+      stringLength sub substring tail;
+    inherit (trivial) id const concat or and bitAnd bitOr bitXor bitNot
+      boolToString mergeAttrs flip mapNullable inNixShell min max
+      importJSON warn info nixpkgsVersion version mod compare
+      splitByAndCompare functionArgs setFunctionArgs isFunction;
+    inherit (fixedPoints) fix fix' converge extends composeExtensions
+      makeExtensible makeExtensibleWithCustomName;
+    inherit (attrsets) attrByPath hasAttrByPath setAttrByPath
+      getAttrFromPath attrVals attrValues getAttrs catAttrs filterAttrs
+      filterAttrsRecursive foldAttrs collect nameValuePair mapAttrs
+      mapAttrs' mapAttrsToList mapAttrsRecursive mapAttrsRecursiveCond
+      genAttrs isDerivation toDerivation optionalAttrs
+      zipAttrsWithNames zipAttrsWith zipAttrs recursiveUpdateUntil
+      recursiveUpdate matchAttrs overrideExisting getOutput getBin
+      getLib getDev chooseDevOutputs zipWithNames zip;
+    inherit (lists) singleton foldr fold foldl foldl' imap0 imap1
+      concatMap flatten remove findSingle findFirst any all count
+      optional optionals toList range partition zipListsWith zipLists
+      reverseList listDfs toposort sort naturalSort compareLists take
+      drop sublist last init crossLists unique intersectLists
+      subtractLists mutuallyExclusive groupBy groupBy';
+    inherit (strings) concatStrings concatMapStrings concatImapStrings
+      intersperse concatStringsSep concatMapStringsSep
+      concatImapStringsSep makeSearchPath makeSearchPathOutput
+      makeLibraryPath makeBinPath makePerlPath makeFullPerlPath optionalString
+      hasPrefix hasSuffix stringToCharacters stringAsChars escape
+      escapeShellArg escapeShellArgs replaceChars lowerChars
+      upperChars toLower toUpper addContextFrom splitString
+      removePrefix removeSuffix versionOlder versionAtLeast getVersion
+      nameFromURL enableFeature enableFeatureAs withFeature
+      withFeatureAs fixedWidthString fixedWidthNumber isStorePath
+      toInt readPathsFromFile fileContents;
+    inherit (stringsWithDeps) textClosureList textClosureMap
+      noDepEntry fullDepEntry packEntry stringAfter;
+    inherit (customisation) overrideDerivation makeOverridable
+      callPackageWith callPackagesWith extendDerivation hydraJob
+      makeScope;
+    inherit (meta) addMetaAttrs dontDistribute setName updateName
+      appendToName mapDerivationAttrset lowPrio lowPrioSet hiPrio
+      hiPrioSet;
+    inherit (sources) pathType pathIsDirectory cleanSourceFilter
+      cleanSource sourceByRegex sourceFilesBySuffices
+      commitIdFromGitRepo cleanSourceWith pathHasContext
+      canCleanSource;
+    inherit (modules) evalModules closeModules unifyModuleSyntax
+      applyIfFunction unpackSubmodule packSubmodule mergeModules
+      mergeModules' mergeOptionDecls evalOptionValue mergeDefinitions
+      pushDownProperties dischargeProperties filterOverrides
+      sortProperties fixupOptionType mkIf mkAssert mkMerge mkOverride
+      mkOptionDefault mkDefault mkForce mkVMOverride mkStrict
+      mkFixStrictness mkOrder mkBefore mkAfter mkAliasDefinitions
+      mkAliasAndWrapDefinitions fixMergeModules mkRemovedOptionModule
+      mkRenamedOptionModule mkMergedOptionModule mkChangedOptionModule
+      mkAliasOptionModule doRename filterModules;
+    inherit (options) isOption mkEnableOption mkSinkUndeclaredOptions
+      mergeDefaultOption mergeOneOption mergeEqualOption getValues
+      getFiles optionAttrSetToDocList optionAttrSetToDocList'
+      scrubOptionValue literalExample showOption showFiles
+      unknownModule mkOption;
+    inherit (types) isType setType defaultTypeMerge defaultFunctor
+      isOptionType mkOptionType;
+    inherit (asserts)
+      assertMsg assertOneOf;
+    inherit (debug) addErrorContextToAttrs traceIf traceVal traceValFn
+      traceXMLVal traceXMLValMarked traceSeq traceSeqN traceValSeq
+      traceValSeqFn traceValSeqN traceValSeqNFn traceShowVal
+      traceShowValMarked showVal traceCall traceCall2 traceCall3
+      traceValIfNot runTests testAllTrue traceCallXml attrNamesToStr;
+    inherit (misc) maybeEnv defaultMergeArg defaultMerge foldArgs
+      defaultOverridableDelayableArgs composedArgsAndFun
+      maybeAttrNullable maybeAttr ifEnable checkFlag getValue
+      checkReqs uniqList uniqListExt condConcat lazyGenericClosure
+      innerModifySumArgs modifySumArgs innerClosePropagation
+      closePropagation mapAttrsFlatten nvs setAttr setAttrMerge
+      mergeAttrsWithFunc mergeAttrsConcatenateValues
+      mergeAttrsNoOverride mergeAttrByFunc mergeAttrsByFuncDefaults
+      mergeAttrsByFuncDefaultsClean mergeAttrBy prepareDerivationArgs
+      nixType imap overridableDelayableArgs;
+  });
+in lib
diff --git a/nixpkgs/lib/deprecated.nix b/nixpkgs/lib/deprecated.nix
new file mode 100644
index 000000000000..34cf336d1f42
--- /dev/null
+++ b/nixpkgs/lib/deprecated.nix
@@ -0,0 +1,393 @@
+{ lib }:
+let
+    inherit (builtins) head tail isList isAttrs isInt attrNames;
+
+in
+
+with lib.lists;
+with lib.attrsets;
+with lib.strings;
+
+rec {
+
+  # returns default if env var is not set
+  maybeEnv = name: default:
+    let value = builtins.getEnv name; in
+    if value == "" then default else value;
+
+  defaultMergeArg = x : y: if builtins.isAttrs y then
+    y
+  else
+    (y x);
+  defaultMerge = x: y: x // (defaultMergeArg x y);
+  foldArgs = merger: f: init: x:
+    let arg = (merger init (defaultMergeArg init x));
+        # now add the function with composed args already applied to the final attrs
+        base = (setAttrMerge "passthru" {} (f arg)
+                        ( z: z // rec {
+                            function = foldArgs merger f arg;
+                            args = (lib.attrByPath ["passthru" "args"] {} z) // x;
+                          } ));
+        withStdOverrides = base // {
+          override = base.passthru.function;
+        };
+        in
+          withStdOverrides;
+
+
+  # predecessors: proposed replacement for applyAndFun (which has a bug cause it merges twice)
+  # the naming "overridableDelayableArgs" tries to express that you can
+  # - override attr values which have been supplied earlier
+  # - use attr values before they have been supplied by accessing the fix point
+  #   name "fixed"
+  # f: the (delayed overridden) arguments are applied to this
+  #
+  # initial: initial attrs arguments and settings. see defaultOverridableDelayableArgs
+  #
+  # returns: f applied to the arguments // special attributes attrs
+  #     a) merge: merge applied args with new args. Wether an argument is overridden depends on the merge settings
+  #     b) replace: this let's you replace and remove names no matter which merge function has been set
+  #
+  # examples: see test cases "res" below;
+  overridableDelayableArgs =
+          f:        # the function applied to the arguments
+          initial:  # you pass attrs, the functions below are passing a function taking the fix argument
+    let
+        takeFixed = if lib.isFunction initial then initial else (fixed : initial); # transform initial to an expression always taking the fixed argument
+        tidy = args:
+            let # apply all functions given in "applyPreTidy" in sequence
+                applyPreTidyFun = fold ( n: a: x: n ( a x ) ) lib.id (maybeAttr "applyPreTidy" [] args);
+            in removeAttrs (applyPreTidyFun args) ( ["applyPreTidy"] ++ (maybeAttr  "removeAttrs" [] args) ); # tidy up args before applying them
+        fun = n: x:
+            let newArgs = fixed:
+                    let args = takeFixed fixed;
+                        mergeFun = args.${n};
+                    in if isAttrs x then (mergeFun args x)
+                       else assert lib.isFunction x;
+                            mergeFun args (x ( args // { inherit fixed; }));
+            in overridableDelayableArgs f newArgs;
+    in
+    (f (tidy (lib.fix takeFixed))) // {
+      merge   = fun "mergeFun";
+      replace = fun "keepFun";
+    };
+  defaultOverridableDelayableArgs = f:
+      let defaults = {
+            mergeFun = mergeAttrByFunc; # default merge function. merge strategie (concatenate lists, strings) is given by mergeAttrBy
+            keepFun = a: b: { inherit (a) removeAttrs mergeFun keepFun mergeAttrBy; } // b; # even when using replace preserve these values
+            applyPreTidy = []; # list of functions applied to args before args are tidied up (usage case : prepareDerivationArgs)
+            mergeAttrBy = mergeAttrBy // {
+              applyPreTidy = a: b: a ++ b;
+              removeAttrs = a: b: a ++ b;
+            };
+            removeAttrs = ["mergeFun" "keepFun" "mergeAttrBy" "removeAttrs" "fixed" ]; # before applying the arguments to the function make sure these names are gone
+          };
+      in (overridableDelayableArgs f defaults).merge;
+
+
+
+  # rec { # an example of how composedArgsAndFun can be used
+  #  a  = composedArgsAndFun (x: x) { a = ["2"]; meta = { d = "bar";}; };
+  #  # meta.d will be lost ! It's your task to preserve it (eg using a merge function)
+  #  b  = a.passthru.function { a = [ "3" ]; meta = { d2 = "bar2";}; };
+  #  # instead of passing/ overriding values you can use a merge function:
+  #  c  = b.passthru.function ( x: { a = x.a  ++ ["4"]; }); # consider using (maybeAttr "a" [] x)
+  # }
+  # result:
+  # {
+  #   a = { a = ["2"];     meta = { d = "bar"; }; passthru = { function = .. }; };
+  #   b = { a = ["3"];     meta = { d2 = "bar2"; }; passthru = { function = .. }; };
+  #   c = { a = ["3" "4"]; meta = { d2 = "bar2"; }; passthru = { function = .. }; };
+  #   # c2 is equal to c
+  # }
+  composedArgsAndFun = f: foldArgs defaultMerge f {};
+
+
+  # shortcut for attrByPath ["name"] default attrs
+  maybeAttrNullable = maybeAttr;
+
+  # shortcut for attrByPath ["name"] default attrs
+  maybeAttr = name: default: attrs: attrs.${name} or default;
+
+
+  # Return the second argument if the first one is true or the empty version
+  # of the second argument.
+  ifEnable = cond: val:
+    if cond then val
+    else if builtins.isList val then []
+    else if builtins.isAttrs val then {}
+    # else if builtins.isString val then ""
+    else if val == true || val == false then false
+    else null;
+
+
+  # Return true only if there is an attribute and it is true.
+  checkFlag = attrSet: name:
+        if name == "true" then true else
+        if name == "false" then false else
+        if (elem name (attrByPath ["flags"] [] attrSet)) then true else
+        attrByPath [name] false attrSet ;
+
+
+  # Input : attrSet, [ [name default] ... ], name
+  # Output : its value or default.
+  getValue = attrSet: argList: name:
+  ( attrByPath [name] (if checkFlag attrSet name then true else
+        if argList == [] then null else
+        let x = builtins.head argList; in
+                if (head x) == name then
+                        (head (tail x))
+                else (getValue attrSet
+                        (tail argList) name)) attrSet );
+
+
+  # Input : attrSet, [[name default] ...], [ [flagname reqs..] ... ]
+  # Output : are reqs satisfied? It's asserted.
+  checkReqs = attrSet: argList: condList:
+  (
+    fold lib.and true
+      (map (x: let name = (head x); in
+
+        ((checkFlag attrSet name) ->
+        (fold lib.and true
+        (map (y: let val=(getValue attrSet argList y); in
+                (val!=null) && (val!=false))
+        (tail x))))) condList));
+
+
+  # This function has O(n^2) performance.
+  uniqList = { inputList, acc ? [] }:
+    let go = xs: acc:
+             if xs == []
+             then []
+             else let x = head xs;
+                      y = if elem x acc then [] else [x];
+                  in y ++ go (tail xs) (y ++ acc);
+    in go inputList acc;
+
+  uniqListExt = { inputList,
+                  outputList ? [],
+                  getter ? (x: x),
+                  compare ? (x: y: x==y) }:
+        if inputList == [] then outputList else
+        let x = head inputList;
+            isX = y: (compare (getter y) (getter x));
+            newOutputList = outputList ++
+                (if any isX outputList then [] else [x]);
+        in uniqListExt { outputList = newOutputList;
+                         inputList = (tail inputList);
+                         inherit getter compare;
+                       };
+
+  condConcat = name: list: checker:
+        if list == [] then name else
+        if checker (head list) then
+                condConcat
+                        (name + (head (tail list)))
+                        (tail (tail list))
+                        checker
+        else condConcat
+                name (tail (tail list)) checker;
+
+  lazyGenericClosure = {startSet, operator}:
+    let
+      work = list: doneKeys: result:
+        if list == [] then
+          result
+        else
+          let x = head list; key = x.key; in
+          if elem key doneKeys then
+            work (tail list) doneKeys result
+          else
+            work (tail list ++ operator x) ([key] ++ doneKeys) ([x] ++ result);
+    in
+      work startSet [] [];
+
+  innerModifySumArgs = f: x: a: b: if b == null then (f a b) // x else
+        innerModifySumArgs f x (a // b);
+  modifySumArgs = f: x: innerModifySumArgs f x {};
+
+
+  innerClosePropagation = acc: xs:
+    if xs == []
+    then acc
+    else let y  = head xs;
+             ys = tail xs;
+         in if ! isAttrs y
+            then innerClosePropagation acc ys
+            else let acc' = [y] ++ acc;
+                 in innerClosePropagation
+                      acc'
+                      (uniqList { inputList = (maybeAttrNullable "propagatedBuildInputs" [] y)
+                                           ++ (maybeAttrNullable "propagatedNativeBuildInputs" [] y)
+                                           ++ ys;
+                                  acc = acc';
+                                }
+                      );
+
+  closePropagation = list: (uniqList {inputList = (innerClosePropagation [] list);});
+
+  # calls a function (f attr value ) for each record item. returns a list
+  mapAttrsFlatten = f: r: map (attr: f attr r.${attr}) (attrNames r);
+
+  # attribute set containing one attribute
+  nvs = name: value: listToAttrs [ (nameValuePair name value) ];
+  # adds / replaces an attribute of an attribute set
+  setAttr = set: name: v: set // (nvs name v);
+
+  # setAttrMerge (similar to mergeAttrsWithFunc but only merges the values of a particular name)
+  # setAttrMerge "a" [] { a = [2];} (x: x ++ [3]) -> { a = [2 3]; }
+  # setAttrMerge "a" [] {         } (x: x ++ [3]) -> { a = [  3]; }
+  setAttrMerge = name: default: attrs: f:
+    setAttr attrs name (f (maybeAttr name default attrs));
+
+  # 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 set ? ${n}
+                        then setAttr set n (f set.${n} set2.${n})
+                        else set )
+           (set2 // 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) );
+
+  # merges attributes using //, if a name exists in both attributes
+  # an error will be triggered unless its listed in mergeLists
+  # so you can mergeAttrsNoOverride { buildInputs = [a]; } { buildInputs = [a]; } {} to get
+  # { buildInputs = [a b]; }
+  # merging buildPhase doesn't really make sense. The cases will be rare where appending /prefixing will fit your needs?
+  # in these cases the first buildPhase will override the second one
+  # ! deprecated, use mergeAttrByFunc instead
+  mergeAttrsNoOverride = { mergeLists ? ["buildInputs" "propagatedBuildInputs"],
+                           overrideSnd ? [ "buildPhase" ]
+                         }: attrs1: attrs2:
+    fold (n: set:
+        setAttr set n ( if set ? ${n}
+            then # merge
+              if elem n mergeLists # attribute contains list, merge them by concatenating
+                then attrs2.${n} ++ attrs1.${n}
+              else if elem n overrideSnd
+                then attrs1.${n}
+              else throw "error mergeAttrsNoOverride, attribute ${n} given in both attributes - no merge func defined"
+            else attrs2.${n} # add attribute not existing in attr1
+           )) attrs1 (attrNames attrs2);
+
+
+  # example usage:
+  # mergeAttrByFunc  {
+  #   inherit mergeAttrBy; # defined below
+  #   buildInputs = [ a b ];
+  # } {
+  #  buildInputs = [ c d ];
+  # };
+  # will result in
+  # { mergeAttrsBy = [...]; buildInputs = [ a b c d ]; }
+  # is used by prepareDerivationArgs, defaultOverridableDelayableArgs and can be used when composing using
+  # foldArgs, composedArgsAndFun or applyAndFun. Example: composableDerivation in all-packages.nix
+  mergeAttrByFunc = x: y:
+    let
+          mergeAttrBy2 = { mergeAttrBy = lib.mergeAttrs; }
+                      // (maybeAttr "mergeAttrBy" {} x)
+                      // (maybeAttr "mergeAttrBy" {} y); in
+    fold lib.mergeAttrs {} [
+      x y
+      (mapAttrs ( a: v: # merge special names using given functions
+          if x ? ${a}
+             then if y ? ${a}
+               then v x.${a} y.${a} # both have attr, use merge func
+               else x.${a} # only x has attr
+             else y.${a} # only y has attr)
+          ) (removeAttrs mergeAttrBy2
+                         # don't merge attrs which are neither in x nor y
+                         (filter (a: ! x ? ${a} && ! y ? ${a})
+                                 (attrNames mergeAttrBy2))
+            )
+      )
+    ];
+  mergeAttrsByFuncDefaults = foldl mergeAttrByFunc { inherit mergeAttrBy; };
+  mergeAttrsByFuncDefaultsClean = list: removeAttrs (mergeAttrsByFuncDefaults list) ["mergeAttrBy"];
+
+  # sane defaults (same name as attr name so that inherit can be used)
+  mergeAttrBy = # { buildInputs = concatList; [...]; passthru = mergeAttr; [..]; }
+    listToAttrs (map (n: nameValuePair n lib.concat)
+      [ "nativeBuildInputs" "buildInputs" "propagatedBuildInputs" "configureFlags" "prePhases" "postAll" "patches" ])
+    // listToAttrs (map (n: nameValuePair n lib.mergeAttrs) [ "passthru" "meta" "cfg" "flags" ])
+    // listToAttrs (map (n: nameValuePair n (a: b: "${a}\n${b}") ) [ "preConfigure" "postInstall" ])
+  ;
+
+  # prepareDerivationArgs tries to make writing configurable derivations easier
+  # example:
+  #  prepareDerivationArgs {
+  #    mergeAttrBy = {
+  #       myScript = x: y: x ++ "\n" ++ y;
+  #    };
+  #    cfg = {
+  #      readlineSupport = true;
+  #    };
+  #    flags = {
+  #      readline = {
+  #        set = {
+  #           configureFlags = [ "--with-compiler=${compiler}" ];
+  #           buildInputs = [ compiler ];
+  #           pass = { inherit compiler; READLINE=1; };
+  #           assertion = compiler.dllSupport;
+  #           myScript = "foo";
+  #        };
+  #        unset = { configureFlags = ["--without-compiler"]; };
+  #      };
+  #    };
+  #    src = ...
+  #    buildPhase = '' ... '';
+  #    name = ...
+  #    myScript = "bar";
+  #  };
+  # if you don't have need for unset you can omit the surrounding set = { .. } attr
+  # all attrs except flags cfg and mergeAttrBy will be merged with the
+  # additional data from flags depending on config settings
+  # It's used in composableDerivation in all-packages.nix. It's also used
+  # heavily in the new python and libs implementation
+  #
+  # should we check for misspelled cfg options?
+  # TODO use args.mergeFun here as well?
+  prepareDerivationArgs = args:
+    let args2 = { cfg = {}; flags = {}; } // args;
+        flagName = name: "${name}Support";
+        cfgWithDefaults = (listToAttrs (map (n: nameValuePair (flagName n) false) (attrNames args2.flags)))
+                          // args2.cfg;
+        opts = attrValues (mapAttrs (a: v:
+                let v2 = if v ? set || v ? unset then v else { set = v; };
+                    n = if cfgWithDefaults.${flagName a} then "set" else "unset";
+                    attr = maybeAttr n {} v2; in
+                if (maybeAttr "assertion" true attr)
+                  then attr
+                  else throw "assertion of flag ${a} of derivation ${args.name} failed"
+               ) args2.flags );
+    in removeAttrs
+      (mergeAttrsByFuncDefaults ([args] ++ opts ++ [{ passthru = cfgWithDefaults; }]))
+      ["flags" "cfg" "mergeAttrBy" ];
+
+
+  nixType = x:
+      if isAttrs x then
+          if x ? outPath then "derivation"
+          else "attrs"
+      else if lib.isFunction x then "function"
+      else if isList x then "list"
+      else if x == true then "bool"
+      else if x == false then "bool"
+      else if x == null then "null"
+      else if isInt x then "int"
+      else "string";
+
+  /* deprecated:
+
+     For historical reasons, imap has an index starting at 1.
+
+     But for consistency with the rest of the library we want an index
+     starting at zero.
+  */
+  imap = imap1;
+}
diff --git a/nixpkgs/lib/fetchers.nix b/nixpkgs/lib/fetchers.nix
new file mode 100644
index 000000000000..1107353b51dd
--- /dev/null
+++ b/nixpkgs/lib/fetchers.nix
@@ -0,0 +1,13 @@
+# snippets that can be shared by multiple fetchers (pkgs/build-support)
+{ lib }:
+{
+
+  proxyImpureEnvVars = [
+    # We borrow these environment variables from the caller to allow
+    # easy proxy configuration.  This is impure, but a fixed-output
+    # derivation like fetchurl is allowed to do so since its result is
+    # by definition pure.
+    "http_proxy" "https_proxy" "ftp_proxy" "all_proxy" "no_proxy"
+  ];
+
+}
diff --git a/nixpkgs/lib/filesystem.nix b/nixpkgs/lib/filesystem.nix
new file mode 100644
index 000000000000..fc35a1a72c64
--- /dev/null
+++ b/nixpkgs/lib/filesystem.nix
@@ -0,0 +1,45 @@
+{ lib }:
+{ # haskellPathsInDir : Path -> Map String Path
+  # A map of all haskell packages defined in the given path,
+  # identified by having a cabal file with the same name as the
+  # directory itself.
+  haskellPathsInDir = root:
+    let # Files in the root
+        root-files = builtins.attrNames (builtins.readDir root);
+        # Files with their full paths
+        root-files-with-paths =
+          map (file:
+            { name = file; value = root + "/${file}"; }
+          ) root-files;
+        # Subdirectories of the root with a cabal file.
+        cabal-subdirs =
+          builtins.filter ({ name, value }:
+            builtins.pathExists (value + "/${name}.cabal")
+          ) root-files-with-paths;
+    in builtins.listToAttrs cabal-subdirs;
+  # locateDominatingFile :  RegExp
+  #                      -> Path
+  #                      -> Nullable { path : Path;
+  #                                    matches : [ MatchResults ];
+  #                                  }
+  # Find the first directory containing a file matching 'pattern'
+  # upward from a given 'file'.
+  # Returns 'null' if no directories contain a file matching 'pattern'.
+  locateDominatingFile = pattern: file:
+    let go = path:
+          let files = builtins.attrNames (builtins.readDir path);
+              matches = builtins.filter (match: match != null)
+                          (map (builtins.match pattern) files);
+          in
+            if builtins.length matches != 0
+              then { inherit path matches; }
+              else if path == /.
+                then null
+                else go (dirOf path);
+        parent = dirOf file;
+        isDir =
+          let base = baseNameOf file;
+              type = (builtins.readDir parent).${base} or null;
+          in file == /. || type == "directory";
+    in go (if isDir then file else parent);
+}
diff --git a/nixpkgs/lib/fixed-points.nix b/nixpkgs/lib/fixed-points.nix
new file mode 100644
index 000000000000..2f818c88de5d
--- /dev/null
+++ b/nixpkgs/lib/fixed-points.nix
@@ -0,0 +1,101 @@
+{ ... }:
+rec {
+  # Compute the fixed point of the given function `f`, which is usually an
+  # attribute set that expects its final, non-recursive representation as an
+  # argument:
+  #
+  #     f = self: { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; }
+  #
+  # Nix evaluates this recursion until all references to `self` have been
+  # resolved. At that point, the final result is returned and `f x = x` holds:
+  #
+  #     nix-repl> fix f
+  #     { bar = "bar"; foo = "foo"; foobar = "foobar"; }
+  #
+  #  Type: fix :: (a -> a) -> a
+  #
+  # See https://en.wikipedia.org/wiki/Fixed-point_combinator for further
+  # details.
+  fix = f: let x = f x; in x;
+
+  # A variant of `fix` that records the original recursive attribute set in the
+  # result. This is useful in combination with the `extends` function to
+  # implement deep overriding. See pkgs/development/haskell-modules/default.nix
+  # for a concrete example.
+  fix' = f: let x = f x // { __unfix__ = f; }; in x;
+
+  # Return the fixpoint that `f` converges to when called recursively, starting
+  # with the input `x`.
+  #
+  #     nix-repl> converge (x: x / 2) 16
+  #     0
+  converge = f: x:
+    if (f x) == x
+    then x
+    else converge f (f x);
+
+  # Modify the contents of an explicitly recursive attribute set in a way that
+  # honors `self`-references. This is accomplished with a function
+  #
+  #     g = self: super: { foo = super.foo + " + "; }
+  #
+  # that has access to the unmodified input (`super`) as well as the final
+  # non-recursive representation of the attribute set (`self`). `extends`
+  # differs from the native `//` operator insofar as that it's applied *before*
+  # references to `self` are resolved:
+  #
+  #     nix-repl> fix (extends g f)
+  #     { bar = "bar"; foo = "foo + "; foobar = "foo + bar"; }
+  #
+  # The name of the function is inspired by object-oriented inheritance, i.e.
+  # think of it as an infix operator `g extends f` that mimics the syntax from
+  # Java. It may seem counter-intuitive to have the "base class" as the second
+  # argument, but it's nice this way if several uses of `extends` are cascaded.
+  #
+  # To get a better understanding how `extends` turns a function with a fix
+  # point (the package set we start with) into a new function with a different fix
+  # point (the desired packages set) lets just see, how `extends g f`
+  # unfolds with `g` and `f` defined above:
+  #
+  # extends g f = self: let super = f self; in super // g self super;
+  #             = self: let super = { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; }; in super // g self super
+  #             = self: { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; } // g self { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; }
+  #             = self: { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; } // { foo = "foo" + " + "; }
+  #             = self: { foo = "foo + "; bar = "bar"; foobar = self.foo + self.bar; }
+  #
+  extends = f: rattrs: self: let super = rattrs self; in super // f self super;
+
+  # Compose two extending functions of the type expected by 'extends'
+  # into one where changes made in the first are available in the
+  # 'super' of the second
+  composeExtensions =
+    f: g: self: super:
+      let fApplied = f self super;
+          super' = super // fApplied;
+      in fApplied // g self super';
+
+  # Create an overridable, recursive attribute set. For example:
+  #
+  #     nix-repl> obj = makeExtensible (self: { })
+  #
+  #     nix-repl> obj
+  #     { __unfix__ = «lambda»; extend = «lambda»; }
+  #
+  #     nix-repl> obj = obj.extend (self: super: { foo = "foo"; })
+  #
+  #     nix-repl> obj
+  #     { __unfix__ = «lambda»; extend = «lambda»; foo = "foo"; }
+  #
+  #     nix-repl> obj = obj.extend (self: super: { foo = super.foo + " + "; bar = "bar"; foobar = self.foo + self.bar; })
+  #
+  #     nix-repl> obj
+  #     { __unfix__ = «lambda»; bar = "bar"; extend = «lambda»; foo = "foo + "; foobar = "foo + bar"; }
+  makeExtensible = makeExtensibleWithCustomName "extend";
+
+  # Same as `makeExtensible` but the name of the extending attribute is
+  # customized.
+  makeExtensibleWithCustomName = extenderName: rattrs:
+    fix' rattrs // {
+      ${extenderName} = f: makeExtensibleWithCustomName extenderName (extends f rattrs);
+   };
+}
diff --git a/nixpkgs/lib/generators.nix b/nixpkgs/lib/generators.nix
new file mode 100644
index 000000000000..863ba847423e
--- /dev/null
+++ b/nixpkgs/lib/generators.nix
@@ -0,0 +1,227 @@
+/* Functions that generate widespread file
+ * formats from nix data structures.
+ *
+ * They all follow a similar interface:
+ * generator { config-attrs } data
+ *
+ * `config-attrs` are “holes” in the generators
+ * with sensible default implementations that
+ * can be overwritten. The default implementations
+ * are mostly generators themselves, called with
+ * their respective default values; they can be reused.
+ *
+ * Tests can be found in ./tests.nix
+ * Documentation in the manual, #sec-generators
+ */
+{ lib }:
+with (lib).trivial;
+let
+  libStr = lib.strings;
+  libAttr = lib.attrsets;
+
+  inherit (lib) isFunction;
+in
+
+rec {
+
+  ## -- HELPER FUNCTIONS & DEFAULTS --
+
+  /* Convert a value to a sensible default string representation.
+   * The builtin `toString` function has some strange defaults,
+   * suitable for bash scripts but not much else.
+   */
+  mkValueStringDefault = {}: v: with builtins;
+    let err = t: v: abort
+          ("generators.mkValueStringDefault: " +
+           "${t} not supported: ${toPretty {} v}");
+    in   if isInt      v then toString v
+    # we default to not quoting strings
+    else if isString   v then v
+    # isString returns "1", which is not a good default
+    else if true  ==   v then "true"
+    # here it returns to "", which is even less of a good default
+    else if false ==   v then "false"
+    else if null  ==   v then "null"
+    # if you have lists you probably want to replace this
+    else if isList     v then err "lists" v
+    # same as for lists, might want to replace
+    else if isAttrs    v then err "attrsets" v
+    else if isFunction v then err "functions" v
+    else err "this value is" (toString v);
+
+
+  /* Generate a line of key k and value v, separated by
+   * character sep. If sep appears in k, it is escaped.
+   * Helper for synaxes with different separators.
+   *
+   * mkValueString specifies how values should be formatted.
+   *
+   * mkKeyValueDefault {} ":" "f:oo" "bar"
+   * > "f\:oo:bar"
+   */
+  mkKeyValueDefault = {
+    mkValueString ? mkValueStringDefault {}
+  }: sep: k: v:
+    "${libStr.escape [sep] k}${sep}${mkValueString v}";
+
+
+  ## -- FILE FORMAT GENERATORS --
+
+
+  /* Generate a key-value-style config file from an attrset.
+   *
+   * mkKeyValue is the same as in toINI.
+   */
+  toKeyValue = {
+    mkKeyValue ? mkKeyValueDefault {} "="
+  }: attrs:
+    let mkLine = k: v: mkKeyValue k v + "\n";
+    in libStr.concatStrings (libAttr.mapAttrsToList mkLine attrs);
+
+
+  /* Generate an INI-style config file from an
+   * attrset of sections to an attrset of key-value pairs.
+   *
+   * generators.toINI {} {
+   *   foo = { hi = "${pkgs.hello}"; ciao = "bar"; };
+   *   baz = { "also, integers" = 42; };
+   * }
+   *
+   *> [baz]
+   *> also, integers=42
+   *>
+   *> [foo]
+   *> ciao=bar
+   *> hi=/nix/store/y93qql1p5ggfnaqjjqhxcw0vqw95rlz0-hello-2.10
+   *
+   * The mk* configuration attributes can generically change
+   * the way sections and key-value strings are generated.
+   *
+   * For more examples see the test cases in ./tests.nix.
+   */
+  toINI = {
+    # apply transformations (e.g. escapes) to section names
+    mkSectionName ? (name: libStr.escape [ "[" "]" ] name),
+    # format a setting line from key and value
+    mkKeyValue    ? mkKeyValueDefault {} "="
+  }: attrsOfAttrs:
+    let
+        # map function to string for each key val
+        mapAttrsToStringsSep = sep: mapFn: attrs:
+          libStr.concatStringsSep sep
+            (libAttr.mapAttrsToList mapFn attrs);
+        mkSection = sectName: sectValues: ''
+          [${mkSectionName sectName}]
+        '' + toKeyValue { inherit mkKeyValue; } sectValues;
+    in
+      # map input to ini sections
+      mapAttrsToStringsSep "\n" mkSection attrsOfAttrs;
+
+
+  /* Generates JSON from an arbitrary (non-function) value.
+    * For more information see the documentation of the builtin.
+    */
+  toJSON = {}: builtins.toJSON;
+
+
+  /* YAML has been a strict superset of JSON since 1.2, so we
+    * use toJSON. Before it only had a few differences referring
+    * to implicit typing rules, so it should work with older
+    * parsers as well.
+    */
+  toYAML = {}@args: toJSON args;
+
+
+  /* Pretty print a value, akin to `builtins.trace`.
+    * Should probably be a builtin as well.
+    */
+  toPretty = {
+    /* If this option is true, attrsets like { __pretty = fn; val = …; }
+       will use fn to convert val to a pretty printed representation.
+       (This means fn is type Val -> String.) */
+    allowPrettyValues ? false
+  }@args: v: with builtins;
+    let     isPath   = v: typeOf v == "path";
+    in if   isInt      v then toString v
+    else if isFloat    v then "~${toString v}"
+    else if isString   v then ''"${libStr.escape [''"''] v}"''
+    else if true  ==   v then "true"
+    else if false ==   v then "false"
+    else if null  ==   v then "null"
+    else if isPath     v then toString v
+    else if isList     v then "[ "
+        + libStr.concatMapStringsSep " " (toPretty args) v
+      + " ]"
+    else if isAttrs    v then
+      # apply pretty values if allowed
+      if attrNames v == [ "__pretty" "val" ] && allowPrettyValues
+         then v.__pretty v.val
+      # TODO: there is probably a better representation?
+      else if v ? type && v.type == "derivation" then
+        "<δ:${v.name}>"
+        # "<δ:${concatStringsSep "," (builtins.attrNames v)}>"
+      else "{ "
+          + libStr.concatStringsSep " " (libAttr.mapAttrsToList
+              (name: value:
+                "${toPretty args name} = ${toPretty args value};") v)
+        + " }"
+    else if isFunction v then
+      let fna = lib.functionArgs v;
+          showFnas = concatStringsSep "," (libAttr.mapAttrsToList
+                       (name: hasDefVal: if hasDefVal then "(${name})" else name)
+                       fna);
+      in if fna == {}    then "<λ>"
+                         else "<λ:{${showFnas}}>"
+    else abort "generators.toPretty: should never happen (v = ${v})";
+
+  # PLIST handling
+  toPlist = {}: v: let
+    isFloat = builtins.isFloat or (x: false);
+    expr = ind: x:  with builtins;
+      if isNull x   then "" else
+      if isBool x   then bool ind x else
+      if isInt x    then int ind x else
+      if isString x then str ind x else
+      if isList x   then list ind x else
+      if isAttrs x  then attrs ind x else
+      if isFloat x  then float ind x else
+      abort "generators.toPlist: should never happen (v = ${v})";
+
+    literal = ind: x: ind + x;
+
+    bool = ind: x: literal ind  (if x then "<true/>" else "<false/>");
+    int = ind: x: literal ind "<integer>${toString x}</integer>";
+    str = ind: x: literal ind "<string>${x}</string>";
+    key = ind: x: literal ind "<key>${x}</key>";
+    float = ind: x: literal ind "<real>${toString x}</real>";
+
+    indent = ind: expr "\t${ind}";
+
+    item = ind: libStr.concatMapStringsSep "\n" (indent ind);
+
+    list = ind: x: libStr.concatStringsSep "\n" [
+      (literal ind "<array>")
+      (item ind x)
+      (literal ind "</array>")
+    ];
+
+    attrs = ind: x: libStr.concatStringsSep "\n" [
+      (literal ind "<dict>")
+      (attr ind x)
+      (literal ind "</dict>")
+    ];
+
+    attr = let attrFilter = name: value: name != "_module" && value != null;
+    in ind: x: libStr.concatStringsSep "\n" (lib.flatten (lib.mapAttrsToList
+      (name: value: lib.optional (attrFilter name value) [
+      (key "\t${ind}" name)
+      (expr "\t${ind}" value)
+    ]) x));
+
+  in ''<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+${expr "" v}
+</plist>'';
+
+}
diff --git a/nixpkgs/lib/kernel.nix b/nixpkgs/lib/kernel.nix
new file mode 100644
index 000000000000..45b33aea7b87
--- /dev/null
+++ b/nixpkgs/lib/kernel.nix
@@ -0,0 +1,57 @@
+{ lib
+# we pass the kernel version here to keep a nice syntax `whenOlder "4.13"`
+# kernelVersion, e.g., config.boot.kernelPackages.version
+, version
+, mkValuePreprocess ? null
+}:
+
+with lib;
+rec {
+  # Common patterns
+  when        = cond: opt: if cond then opt else null;
+  whenAtLeast = ver: when (versionAtLeast version ver);
+  whenOlder   = ver: when (versionOlder version ver);
+  whenBetween = verLow: verHigh: when (versionAtLeast version verLow && versionOlder version verHigh);
+
+  # Keeping these around in case we decide to change this horrible implementation :)
+  option = x: if x == null then null else "?${x}";
+  yes    = "y";
+  no     = "n";
+  module = "m";
+
+  mkValue = val:
+  let
+    isNumber = c: elem c ["0" "1" "2" "3" "4" "5" "6" "7" "8" "9"];
+  in
+    if val == "" then "\"\""
+    else if val == yes || val == module || val == no then val
+    else if all isNumber (stringToCharacters val) then val
+    else if substring 0 2 val == "0x" then val
+    else val; # FIXME: fix quoting one day
+
+
+  # generate nix intermediate kernel config file of the form
+  #
+  #       VIRTIO_MMIO m
+  #       VIRTIO_BLK y
+  #       VIRTIO_CONSOLE n
+  #       NET_9P_VIRTIO? y
+  #
+  # Use mkValuePreprocess to preprocess option values, aka mark 'modules' as
+  # 'yes' or vice-versa
+  # Borrowed from copumpkin https://github.com/NixOS/nixpkgs/pull/12158
+  # returns a string, expr should be an attribute set
+  generateNixKConf = exprs: mkValuePreprocess:
+  let
+    mkConfigLine = key: rawval:
+    let
+      val = if builtins.isFunction mkValuePreprocess then mkValuePreprocess rawval else rawval;
+    in
+      if val == null
+        then ""
+        else if hasPrefix "?" val
+          then "${key}? ${mkValue (removePrefix "?" val)}\n"
+          else "${key} ${mkValue val}\n";
+    mkConf = cfg: concatStrings (mapAttrsToList mkConfigLine cfg);
+  in mkConf exprs;
+}
diff --git a/nixpkgs/lib/licenses.nix b/nixpkgs/lib/licenses.nix
new file mode 100644
index 000000000000..fc9cb42621d4
--- /dev/null
+++ b/nixpkgs/lib/licenses.nix
@@ -0,0 +1,732 @@
+{ lib }:
+let
+
+  spdx = lic: lic // {
+    url = "http://spdx.org/licenses/${lic.spdxId}.html";
+  };
+
+in
+
+lib.mapAttrs (n: v: v // { shortName = n; }) rec {
+  /* License identifiers from spdx.org where possible.
+   * If you cannot find your license here, then look for a similar license or
+   * add it to this list. The URL mentioned above is a good source for inspiration.
+   */
+
+  abstyles = spdx {
+    spdxId = "Abstyles";
+    fullName = "Abstyles License";
+  };
+
+  afl21 = spdx {
+    spdxId = "AFL-2.1";
+    fullName = "Academic Free License v2.1";
+  };
+
+  afl3 = spdx {
+    spdxId = "AFL-3.0";
+    fullName = "Academic Free License v3.0";
+  };
+
+  agpl3 = spdx {
+    spdxId = "AGPL-3.0-only";
+    fullName = "GNU Affero General Public License v3.0 only";
+  };
+
+  agpl3Plus = spdx {
+    spdxId = "AGPL-3.0-or-later";
+    fullName = "GNU Affero General Public License v3.0 or later";
+  };
+
+  amazonsl = {
+    fullName = "Amazon Software License";
+    url = http://aws.amazon.com/asl/;
+    free = false;
+  };
+
+  amd = {
+    fullName = "AMD License Agreement";
+    url = http://developer.amd.com/amd-license-agreement/;
+    free = false;
+  };
+
+  apsl20 = spdx {
+    spdxId = "APSL-2.0";
+    fullName = "Apple Public Source License 2.0";
+  };
+
+  arphicpl = {
+    fullName = "Arphic Public License";
+    url = https://www.freedesktop.org/wiki/Arphic_Public_License/;
+  };
+
+  artistic1 = spdx {
+    spdxId = "Artistic-1.0";
+    fullName = "Artistic License 1.0";
+  };
+
+  artistic2 = spdx {
+    spdxId = "Artistic-2.0";
+    fullName = "Artistic License 2.0";
+  };
+
+  asl20 = spdx {
+    spdxId = "Apache-2.0";
+    fullName = "Apache License 2.0";
+  };
+
+  boost = spdx {
+    spdxId = "BSL-1.0";
+    fullName = "Boost Software License 1.0";
+  };
+
+  beerware = spdx {
+    spdxId = "Beerware";
+    fullName = ''Beerware License'';
+  };
+
+  bsd0 = spdx {
+    spdxId = "0BSD";
+    fullName = "BSD Zero Clause License";
+  };
+
+  bsd2 = spdx {
+    spdxId = "BSD-2-Clause";
+    fullName = ''BSD 2-clause "Simplified" License'';
+  };
+
+  bsd3 = spdx {
+    spdxId = "BSD-3-Clause";
+    fullName = ''BSD 3-clause "New" or "Revised" License'';
+  };
+
+  bsdOriginal = spdx {
+    spdxId = "BSD-4-Clause";
+    fullName = ''BSD 4-clause "Original" or "Old" License'';
+  };
+
+  bsl11 = {
+    fullName = "Business Source License 1.1";
+    url = https://mariadb.com/bsl11;
+    free = false;
+  };
+
+  clArtistic = spdx {
+    spdxId = "ClArtistic";
+    fullName = "Clarified Artistic License";
+  };
+
+  cc0 = spdx {
+    spdxId = "CC0-1.0";
+    fullName = "Creative Commons Zero v1.0 Universal";
+  };
+
+  cc-by-nc-sa-20 = spdx {
+    spdxId = "CC-BY-NC-SA-2.0";
+    fullName = "Creative Commons Attribution Non Commercial Share Alike 2.0";
+    free = false;
+  };
+
+  cc-by-nc-sa-25 = spdx {
+    spdxId = "CC-BY-NC-SA-2.5";
+    fullName = "Creative Commons Attribution Non Commercial Share Alike 2.5";
+    free = false;
+  };
+
+  cc-by-nc-sa-30 = spdx {
+    spdxId = "CC-BY-NC-SA-3.0";
+    fullName = "Creative Commons Attribution Non Commercial Share Alike 3.0";
+    free = false;
+  };
+
+  cc-by-nc-sa-40 = spdx {
+    spdxId = "CC-BY-NC-SA-4.0";
+    fullName = "Creative Commons Attribution Non Commercial Share Alike 4.0";
+    free = false;
+  };
+
+  cc-by-nc-40 = spdx {
+    spdxId = "CC-BY-NC-4.0";
+    fullName = "Creative Commons Attribution Non Commercial 4.0 International";
+    free = false;
+  };
+
+  cc-by-nd-30 = spdx {
+    spdxId = "CC-BY-ND-3.0";
+    fullName = "Creative Commons Attribution-No Derivative Works v3.00";
+    free = false;
+  };
+
+  cc-by-sa-25 = spdx {
+    spdxId = "CC-BY-SA-2.5";
+    fullName = "Creative Commons Attribution Share Alike 2.5";
+  };
+
+  cc-by-30 = spdx {
+    spdxId = "CC-BY-3.0";
+    fullName = "Creative Commons Attribution 3.0";
+  };
+
+  cc-by-sa-30 = spdx {
+    spdxId = "CC-BY-SA-3.0";
+    fullName = "Creative Commons Attribution Share Alike 3.0";
+  };
+
+  cc-by-40 = spdx {
+    spdxId = "CC-BY-4.0";
+    fullName = "Creative Commons Attribution 4.0";
+  };
+
+  cc-by-sa-40 = spdx {
+    spdxId = "CC-BY-SA-4.0";
+    fullName = "Creative Commons Attribution Share Alike 4.0";
+  };
+
+  cddl = spdx {
+    spdxId = "CDDL-1.0";
+    fullName = "Common Development and Distribution License 1.0";
+  };
+
+  cecill20 = spdx {
+    spdxId = "CECILL-2.0";
+    fullName = "CeCILL Free Software License Agreement v2.0";
+  };
+
+  cecill-b = spdx {
+    spdxId = "CECILL-B";
+    fullName  = "CeCILL-B Free Software License Agreement";
+  };
+
+  cecill-c = spdx {
+    spdxId = "CECILL-C";
+    fullName  = "CeCILL-C Free Software License Agreement";
+  };
+
+  cpal10 = spdx {
+    spdxId = "CPAL-1.0";
+    fullName = "Common Public Attribution License 1.0";
+  };
+
+  cpl10 = spdx {
+    spdxId = "CPL-1.0";
+    fullName = "Common Public License 1.0";
+  };
+
+  curl = {
+    fullName = "MIT/X11 derivate";
+    url = "https://curl.haxx.se/docs/copyright.html";
+  };
+
+  doc = spdx {
+    spdxId = "DOC";
+    fullName = "DOC License";
+  };
+
+  eapl = {
+    fullName = "EPSON AVASYS PUBLIC LICENSE";
+    url = http://avasys.jp/hp/menu000000700/hpg000000603.htm;
+    free = false;
+  };
+
+  efl10 = spdx {
+    spdxId = "EFL-1.0";
+    fullName = "Eiffel Forum License v1.0";
+  };
+
+  efl20 = spdx {
+    spdxId = "EFL-2.0";
+    fullName = "Eiffel Forum License v2.0";
+  };
+
+  elastic = {
+    fullName = "ELASTIC LICENSE";
+    url = https://github.com/elastic/elasticsearch/blob/master/licenses/ELASTIC-LICENSE.txt;
+    free = false;
+  };
+
+  epl10 = spdx {
+    spdxId = "EPL-1.0";
+    fullName = "Eclipse Public License 1.0";
+  };
+
+  epl20 = spdx {
+    spdxId = "EPL-2.0";
+    fullName = "Eclipse Public License 2.0";
+  };
+
+  epson = {
+    fullName = "Seiko Epson Corporation Software License Agreement for Linux";
+    url = https://download.ebz.epson.net/dsc/du/02/eula/global/LINUX_EN.html;
+    free = false;
+  };
+
+  eupl11 = spdx {
+    spdxId = "EUPL-1.1";
+    fullName = "European Union Public License 1.1";
+  };
+
+  fdl12 = spdx {
+    spdxId = "GFDL-1.2-only";
+    fullName = "GNU Free Documentation License v1.2 only";
+  };
+
+  fdl12Plus = spdx {
+    spdxId = "GFDL-1.2-or-later";
+    fullName = "GNU Free Documentation License v1.2 or later";
+  };
+
+  fdl13 = spdx {
+    spdxId = "GFDL-1.3-only";
+    fullName = "GNU Free Documentation License v1.3 only";
+  };
+
+  fdl13Plus = spdx {
+    spdxId = "GFDL-1.3-or-later";
+    fullName = "GNU Free Documentation License v1.3 or later";
+  };
+
+  ffsl = {
+    fullName = "Floodgap Free Software License";
+    url = http://www.floodgap.com/software/ffsl/license.html;
+    free = false;
+  };
+
+  free = {
+    fullName = "Unspecified free software license";
+  };
+
+  g4sl = {
+    fullName = "Geant4 Software License";
+    url = https://geant4.web.cern.ch/geant4/license/LICENSE.html;
+  };
+
+  geogebra = {
+    fullName = "GeoGebra Non-Commercial License Agreement";
+    url = https://www.geogebra.org/license;
+    free = false;
+  };
+
+  gpl1 = spdx {
+    spdxId = "GPL-1.0-only";
+    fullName = "GNU General Public License v1.0 only";
+  };
+
+  gpl1Plus = spdx {
+    spdxId = "GPL-1.0-or-later";
+    fullName = "GNU General Public License v1.0 or later";
+  };
+
+  gpl2 = spdx {
+    spdxId = "GPL-2.0-only";
+    fullName = "GNU General Public License v2.0 only";
+  };
+
+  gpl2Classpath = spdx {
+    spdxId = "GPL-2.0-with-classpath-exception";
+    fullName = "GNU General Public License v2.0 only (with Classpath exception)";
+  };
+
+  gpl2ClasspathPlus = {
+    fullName = "GNU General Public License v2.0 or later (with Classpath exception)";
+    url = https://fedoraproject.org/wiki/Licensing/GPL_Classpath_Exception;
+  };
+
+  gpl2Oss = {
+    fullName = "GNU General Public License version 2 only (with OSI approved licenses linking exception)";
+    url = https://www.mysql.com/about/legal/licensing/foss-exception;
+  };
+
+  gpl2Plus = spdx {
+    spdxId = "GPL-2.0-or-later";
+    fullName = "GNU General Public License v2.0 or later";
+  };
+
+  gpl3 = spdx {
+    spdxId = "GPL-3.0-only";
+    fullName = "GNU General Public License v3.0 only";
+  };
+
+  gpl3Plus = spdx {
+    spdxId = "GPL-3.0-or-later";
+    fullName = "GNU General Public License v3.0 or later";
+  };
+
+  gpl3ClasspathPlus = {
+    fullName = "GNU General Public License v3.0 or later (with Classpath exception)";
+    url = https://fedoraproject.org/wiki/Licensing/GPL_Classpath_Exception;
+  };
+
+  hpnd = spdx {
+    spdxId = "HPND";
+    fullName = "Historic Permission Notice and Disclaimer";
+  };
+
+  # Intel's license, seems free
+  iasl = {
+    fullName = "iASL";
+    url = http://www.calculate-linux.org/packages/licenses/iASL;
+  };
+
+  ijg = spdx {
+    spdxId = "IJG";
+    fullName = "Independent JPEG Group License";
+  };
+
+  imagemagick = spdx {
+    fullName = "ImageMagick License";
+    spdxId = "imagemagick";
+  };
+
+  inria-compcert = {
+    fullName  = "INRIA Non-Commercial License Agreement for the CompCert verified compiler";
+    url       = "http://compcert.inria.fr/doc/LICENSE";
+    free      = false;
+  };
+
+  inria-icesl = {
+    fullName = "INRIA Non-Commercial License Agreement for IceSL";
+    url      = "http://shapeforge.loria.fr/icesl/EULA_IceSL_binary.pdf";
+    free     = false;
+  };
+
+  ipa = spdx {
+    spdxId = "IPA";
+    fullName = "IPA Font License";
+  };
+
+  ipl10 = spdx {
+    spdxId = "IPL-1.0";
+    fullName = "IBM Public License v1.0";
+  };
+
+  isc = spdx {
+    spdxId = "ISC";
+    fullName = "ISC License";
+  };
+
+  # Proprietary binaries; free to redistribute without modification.
+  issl = {
+    fullName = "Intel Simplified Software License";
+    url = https://software.intel.com/en-us/license/intel-simplified-software-license;
+    free = false;
+  };
+
+  jasper = spdx {
+    spdxId = "JasPer-2.0";
+    fullName = "JasPer License";
+  };
+
+  lgpl2 = spdx {
+    spdxId = "LGPL-2.0-only";
+    fullName = "GNU Library General Public License v2 only";
+  };
+
+  lgpl2Plus = spdx {
+    spdxId = "LGPL-2.0-or-later";
+    fullName = "GNU Library General Public License v2 or later";
+  };
+
+  lgpl21 = spdx {
+    spdxId = "LGPL-2.1-only";
+    fullName = "GNU Library General Public License v2.1 only";
+  };
+
+  lgpl21Plus = spdx {
+    spdxId = "LGPL-2.1-or-later";
+    fullName = "GNU Library General Public License v2.1 or later";
+  };
+
+  lgpl3 = spdx {
+    spdxId = "LGPL-3.0-only";
+    fullName = "GNU Lesser General Public License v3.0 only";
+  };
+
+  lgpl3Plus = spdx {
+    spdxId = "LGPL-3.0-or-later";
+    fullName = "GNU Lesser General Public License v3.0 or later";
+  };
+
+  libpng = spdx {
+    spdxId = "Libpng";
+    fullName = "libpng License";
+  };
+
+  libtiff = spdx {
+    spdxId = "libtiff";
+    fullName = "libtiff License";
+  };
+
+  llgpl21 = {
+    fullName = "Lisp LGPL; GNU Lesser General Public License version 2.1 with Franz Inc. preamble for clarification of LGPL terms in context of Lisp";
+    url = http://opensource.franz.com/preamble.html;
+  };
+
+  lppl12 = spdx {
+    spdxId = "LPPL-1.2";
+    fullName = "LaTeX Project Public License v1.2";
+  };
+
+  lppl13c = spdx {
+    spdxId = "LPPL-1.3c";
+    fullName = "LaTeX Project Public License v1.3c";
+  };
+
+  lpl-102 = spdx {
+    spdxId = "LPL-1.02";
+    fullName = "Lucent Public License v1.02";
+  };
+
+  miros = {
+    fullName = "MirOS License";
+    url = https://opensource.org/licenses/MirOS;
+  };
+
+  # spdx.org does not (yet) differentiate between the X11 and Expat versions
+  # for details see http://en.wikipedia.org/wiki/MIT_License#Various_versions
+  mit = spdx {
+    spdxId = "MIT";
+    fullName = "MIT License";
+  };
+
+  mpl10 = spdx {
+    spdxId = "MPL-1.0";
+    fullName = "Mozilla Public License 1.0";
+  };
+
+  mpl11 = spdx {
+    spdxId = "MPL-1.1";
+    fullName = "Mozilla Public License 1.1";
+  };
+
+  mpl20 = spdx {
+    spdxId = "MPL-2.0";
+    fullName = "Mozilla Public License 2.0";
+  };
+
+  mspl = spdx {
+    spdxId = "MS-PL";
+    fullName = "Microsoft Public License";
+  };
+
+  msrla = {
+    fullName  = "Microsoft Research License Agreement";
+    url       = "http://research.microsoft.com/en-us/projects/pex/msr-la.txt";
+    free = false;
+  };
+
+  nasa13 = spdx {
+    spdxId = "NASA-1.3";
+    fullName = "NASA Open Source Agreement 1.3";
+    free = false;
+  };
+
+  ncsa = spdx {
+    spdxId = "NCSA";
+    fullName  = "University of Illinois/NCSA Open Source License";
+  };
+
+  notion_lgpl = {
+    url = "https://raw.githubusercontent.com/raboof/notion/master/LICENSE";
+    fullName = "Notion modified LGPL";
+  };
+
+  nposl3 = spdx {
+    spdxId = "NPOSL-3.0";
+    fullName = "Non-Profit Open Software License 3.0";
+  };
+
+  ocamlpro_nc = {
+    fullName = "OCamlPro Non Commercial license version 1";
+    url = "https://alt-ergo.ocamlpro.com/http/alt-ergo-2.2.0/OCamlPro-Non-Commercial-License.pdf";
+    free = false;
+  };
+
+  ofl = spdx {
+    spdxId = "OFL-1.1";
+    fullName = "SIL Open Font License 1.1";
+  };
+
+  openldap = spdx {
+    spdxId = "OLDAP-2.8";
+    fullName = "Open LDAP Public License v2.8";
+  };
+
+  openssl = spdx {
+    spdxId = "OpenSSL";
+    fullName = "OpenSSL License";
+  };
+
+  osl21 = spdx {
+    spdxId = "OSL-2.1";
+    fullName = "Open Software License 2.1";
+  };
+
+  osl3 = spdx {
+    spdxId = "OSL-3.0";
+    fullName = "Open Software License 3.0";
+  };
+
+  php301 = spdx {
+    spdxId = "PHP-3.01";
+    fullName = "PHP License v3.01";
+  };
+
+  postgresql = spdx {
+    spdxId = "PostgreSQL";
+    fullName = "PostgreSQL License";
+  };
+
+  postman = {
+    fullName = "Postman EULA";
+    url = https://www.getpostman.com/licenses/postman_base_app;
+    free = false;
+  };
+
+  psfl = spdx {
+    spdxId = "Python-2.0";
+    fullName = "Python Software Foundation License version 2";
+    #url = http://docs.python.org/license.html;
+  };
+
+  publicDomain = {
+    fullName = "Public Domain";
+  };
+
+  purdueBsd = {
+    fullName = " Purdue BSD-Style License"; # also know as lsof license
+    url = https://enterprise.dejacode.com/licenses/public/purdue-bsd;
+  };
+
+  qpl = spdx {
+    spdxId = "QPL-1.0";
+    fullName = "Q Public License 1.0";
+  };
+
+  qwt = {
+    fullName = "Qwt License, Version 1.0";
+    url = http://qwt.sourceforge.net/qwtlicense.html;
+  };
+
+  ruby = spdx {
+    spdxId = "Ruby";
+    fullName = "Ruby License";
+  };
+
+  sendmail = spdx {
+    spdxId = "Sendmail";
+    fullName = "Sendmail License";
+  };
+
+  sgi-b-20 = spdx {
+    spdxId = "SGI-B-2.0";
+    fullName = "SGI Free Software License B v2.0";
+  };
+
+  sleepycat = spdx {
+    spdxId = "Sleepycat";
+    fullName = "Sleepycat License";
+  };
+
+  smail = {
+    shortName = "smail";
+    fullName = "SMAIL General Public License";
+    url = http://metadata.ftp-master.debian.org/changelogs/main/d/debianutils/debianutils_4.8.1_copyright;
+  };
+
+  tcltk = spdx {
+    spdxId = "TCL";
+    fullName = "TCL/TK License";
+  };
+
+  ufl = {
+    fullName = "Ubuntu Font License 1.0";
+    url = http://font.ubuntu.com/ufl/ubuntu-font-licence-1.0.txt;
+  };
+
+  unfree = {
+    fullName = "Unfree";
+    free = false;
+  };
+
+  unfreeRedistributable = {
+    fullName = "Unfree redistributable";
+    free = false;
+  };
+
+  unfreeRedistributableFirmware = {
+    fullName = "Unfree redistributable firmware";
+    # Note: we currently consider these "free" for inclusion in the
+    # channel and NixOS images.
+  };
+
+  unlicense = spdx {
+    spdxId = "Unlicense";
+    fullName = "The Unlicense";
+  };
+
+  upl = {
+    fullName = "Universal Permissive License";
+    url = "https://oss.oracle.com/licenses/upl/";
+  };
+
+  vim = spdx {
+    spdxId = "Vim";
+    fullName = "Vim License";
+  };
+
+  virtualbox-puel = {
+    fullName = "Oracle VM VirtualBox Extension Pack Personal Use and Evaluation License (PUEL)";
+    url = "https://www.virtualbox.org/wiki/VirtualBox_PUEL";
+    free = false;
+  };
+
+  vsl10 = spdx {
+    spdxId = "VSL-1.0";
+    fullName = "Vovida Software License v1.0";
+  };
+
+  watcom = spdx {
+    spdxId = "Watcom-1.0";
+    fullName = "Sybase Open Watcom Public License 1.0";
+  };
+
+  w3c = spdx {
+    spdxId = "W3C";
+    fullName = "W3C Software Notice and License";
+  };
+
+  wadalab = {
+    fullName = "Wadalab Font License";
+    url = https://fedoraproject.org/wiki/Licensing:Wadalab?rd=Licensing/Wadalab;
+  };
+
+  wtfpl = spdx {
+    spdxId = "WTFPL";
+    fullName = "Do What The F*ck You Want To Public License";
+  };
+
+  wxWindows = spdx {
+    spdxId = "wxWindows";
+    fullName = "wxWindows Library Licence, Version 3.1";
+  };
+
+  xfig = {
+    fullName = "xfig";
+    url = "http://mcj.sourceforge.net/authors.html#xfig";
+  };
+
+  zlib = spdx {
+    spdxId = "Zlib";
+    fullName = "zlib License";
+  };
+
+  zpl20 = spdx {
+    spdxId = "ZPL-2.0";
+    fullName = "Zope Public License 2.0";
+  };
+
+  zpl21 = spdx {
+    spdxId = "ZPL-2.1";
+    fullName = "Zope Public License 2.1";
+  };
+}
diff --git a/nixpkgs/lib/lists.nix b/nixpkgs/lib/lists.nix
new file mode 100644
index 000000000000..be541427c247
--- /dev/null
+++ b/nixpkgs/lib/lists.nix
@@ -0,0 +1,663 @@
+# General list operations.
+
+{ lib }:
+with lib.trivial;
+let
+  inherit (lib.strings) toInt;
+in
+rec {
+
+  inherit (builtins) head tail length isList elemAt concatLists filter elem genList;
+
+  /*  Create a list consisting of a single element.  `singleton x` is
+      sometimes more convenient with respect to indentation than `[x]`
+      when x spans multiple lines.
+
+      Type: singleton :: a -> [a]
+
+      Example:
+        singleton "foo"
+        => [ "foo" ]
+  */
+  singleton = x: [x];
+
+  /* “right fold” a binary function `op` between successive elements of
+     `list` with `nul' as the starting value, i.e.,
+     `foldr op nul [x_1 x_2 ... x_n] == op x_1 (op x_2 ... (op x_n nul))`.
+
+     Type: foldr :: (a -> b -> b) -> b -> [a] -> b
+
+     Example:
+       concat = foldr (a: b: a + b) "z"
+       concat [ "a" "b" "c" ]
+       => "abcz"
+       # different types
+       strange = foldr (int: str: toString (int + 1) + str) "a"
+       strange [ 1 2 3 4 ]
+       => "2345a"
+  */
+  foldr = op: nul: list:
+    let
+      len = length list;
+      fold' = n:
+        if n == len
+        then nul
+        else op (elemAt list n) (fold' (n + 1));
+    in fold' 0;
+
+  /* `fold` is an alias of `foldr` for historic reasons */
+  # FIXME(Profpatsch): deprecate?
+  fold = foldr;
+
+
+  /* “left fold”, like `foldr`, but from the left:
+     `foldl op nul [x_1 x_2 ... x_n] == op (... (op (op nul x_1) x_2) ... x_n)`.
+
+     Type: foldl :: (b -> a -> b) -> b -> [a] -> b
+
+     Example:
+       lconcat = foldl (a: b: a + b) "z"
+       lconcat [ "a" "b" "c" ]
+       => "zabc"
+       # different types
+       lstrange = foldl (str: int: str + toString (int + 1)) ""
+       strange [ 1 2 3 4 ]
+       => "a2345"
+  */
+  foldl = op: nul: list:
+    let
+      foldl' = n:
+        if n == -1
+        then nul
+        else op (foldl' (n - 1)) (elemAt list n);
+    in foldl' (length list - 1);
+
+  /* Strict version of `foldl`.
+
+     The difference is that evaluation is forced upon access. Usually used
+     with small whole results (in contract with lazily-generated list or large
+     lists where only a part is consumed.)
+
+     Type: foldl' :: (b -> a -> b) -> b -> [a] -> b
+  */
+  foldl' = builtins.foldl' or foldl;
+
+  /* Map with index starting from 0
+
+     Type: imap0 :: (int -> a -> b) -> [a] -> [b]
+
+     Example:
+       imap0 (i: v: "${v}-${toString i}") ["a" "b"]
+       => [ "a-0" "b-1" ]
+  */
+  imap0 = f: list: genList (n: f n (elemAt list n)) (length list);
+
+  /* Map with index starting from 1
+
+     Type: imap1 :: (int -> a -> b) -> [a] -> [b]
+
+     Example:
+       imap1 (i: v: "${v}-${toString i}") ["a" "b"]
+       => [ "a-1" "b-2" ]
+  */
+  imap1 = f: list: genList (n: f (n + 1) (elemAt list n)) (length list);
+
+  /* Map and concatenate the result.
+
+     Type: concatMap :: (a -> [b]) -> [a] -> [b]
+
+     Example:
+       concatMap (x: [x] ++ ["z"]) ["a" "b"]
+       => [ "a" "z" "b" "z" ]
+  */
+  concatMap = builtins.concatMap or (f: list: concatLists (map f list));
+
+  /* Flatten the argument into a single list; that is, nested lists are
+     spliced into the top-level lists.
+
+     Example:
+       flatten [1 [2 [3] 4] 5]
+       => [1 2 3 4 5]
+       flatten 1
+       => [1]
+  */
+  flatten = x:
+    if isList x
+    then concatMap (y: flatten y) x
+    else [x];
+
+  /* Remove elements equal to 'e' from a list.  Useful for buildInputs.
+
+     Type: remove :: a -> [a] -> [a]
+
+     Example:
+       remove 3 [ 1 3 4 3 ]
+       => [ 1 4 ]
+  */
+  remove =
+    # Element to remove from the list
+    e: filter (x: x != e);
+
+  /* Find the sole element in the list matching the specified
+     predicate, returns `default` if no such element exists, or
+     `multiple` if there are multiple matching elements.
+
+     Type: findSingle :: (a -> bool) -> a -> a -> [a] -> a
+
+     Example:
+       findSingle (x: x == 3) "none" "multiple" [ 1 3 3 ]
+       => "multiple"
+       findSingle (x: x == 3) "none" "multiple" [ 1 3 ]
+       => 3
+       findSingle (x: x == 3) "none" "multiple" [ 1 9 ]
+       => "none"
+  */
+  findSingle =
+    # Predicate
+    pred:
+    # Default value to return if element was not found.
+    default:
+    # Default value to return if more than one element was found
+    multiple:
+    # Input list
+    list:
+    let found = filter pred list; len = length found;
+    in if len == 0 then default
+      else if len != 1 then multiple
+      else head found;
+
+  /* Find the first element in the list matching the specified
+     predicate or return `default` if no such element exists.
+
+     Type: findFirst :: (a -> bool) -> a -> [a] -> a
+
+     Example:
+       findFirst (x: x > 3) 7 [ 1 6 4 ]
+       => 6
+       findFirst (x: x > 9) 7 [ 1 6 4 ]
+       => 7
+  */
+  findFirst =
+    # Predicate
+    pred:
+    # Default value to return
+    default:
+    # Input list
+    list:
+    let found = filter pred list;
+    in if found == [] then default else head found;
+
+  /* Return true if function `pred` returns true for at least one
+     element of `list`.
+
+     Type: any :: (a -> bool) -> [a] -> bool
+
+     Example:
+       any isString [ 1 "a" { } ]
+       => true
+       any isString [ 1 { } ]
+       => false
+  */
+  any = builtins.any or (pred: foldr (x: y: if pred x then true else y) false);
+
+  /* Return true if function `pred` returns true for all elements of
+     `list`.
+
+     Type: all :: (a -> bool) -> [a] -> bool
+
+     Example:
+       all (x: x < 3) [ 1 2 ]
+       => true
+       all (x: x < 3) [ 1 2 3 ]
+       => false
+  */
+  all = builtins.all or (pred: foldr (x: y: if pred x then y else false) true);
+
+  /* Count how many elements of `list` match the supplied predicate
+     function.
+
+     Type: count :: (a -> bool) -> [a] -> int
+
+     Example:
+       count (x: x == 3) [ 3 2 3 4 6 ]
+       => 2
+  */
+  count =
+    # Predicate
+    pred: foldl' (c: x: if pred x then c + 1 else c) 0;
+
+  /* Return a singleton list or an empty list, depending on a boolean
+     value.  Useful when building lists with optional elements
+     (e.g. `++ optional (system == "i686-linux") flashplayer').
+
+     Type: optional :: bool -> a -> [a]
+
+     Example:
+       optional true "foo"
+       => [ "foo" ]
+       optional false "foo"
+       => [ ]
+  */
+  optional = cond: elem: if cond then [elem] else [];
+
+  /* Return a list or an empty list, depending on a boolean value.
+
+     Type: optionals :: bool -> [a] -> [a]
+
+     Example:
+       optionals true [ 2 3 ]
+       => [ 2 3 ]
+       optionals false [ 2 3 ]
+       => [ ]
+  */
+  optionals =
+    # Condition
+    cond:
+    # List to return if condition is true
+    elems: if cond then elems else [];
+
+
+  /* If argument is a list, return it; else, wrap it in a singleton
+     list.  If you're using this, you should almost certainly
+     reconsider if there isn't a more "well-typed" approach.
+
+     Example:
+       toList [ 1 2 ]
+       => [ 1 2 ]
+       toList "hi"
+       => [ "hi "]
+  */
+  toList = x: if isList x then x else [x];
+
+  /* Return a list of integers from `first' up to and including `last'.
+
+     Type: range :: int -> int -> [int]
+
+     Example:
+       range 2 4
+       => [ 2 3 4 ]
+       range 3 2
+       => [ ]
+  */
+  range =
+    # First integer in the range
+    first:
+    # Last integer in the range
+    last:
+    if first > last then
+      []
+    else
+      genList (n: first + n) (last - first + 1);
+
+  /* Splits the elements of a list in two lists, `right` and
+     `wrong`, depending on the evaluation of a predicate.
+
+     Type: (a -> bool) -> [a] -> { right :: [a], wrong :: [a] }
+
+     Example:
+       partition (x: x > 2) [ 5 1 2 3 4 ]
+       => { right = [ 5 3 4 ]; wrong = [ 1 2 ]; }
+  */
+  partition = builtins.partition or (pred:
+    foldr (h: t:
+      if pred h
+      then { right = [h] ++ t.right; wrong = t.wrong; }
+      else { right = t.right; wrong = [h] ++ t.wrong; }
+    ) { right = []; wrong = []; });
+
+  /* Splits the elements of a list into many lists, using the return value of a predicate.
+     Predicate should return a string which becomes keys of attrset `groupBy' returns.
+
+     `groupBy'` allows to customise the combining function and initial value
+
+     Example:
+       groupBy (x: boolToString (x > 2)) [ 5 1 2 3 4 ]
+       => { true = [ 5 3 4 ]; false = [ 1 2 ]; }
+       groupBy (x: x.name) [ {name = "icewm"; script = "icewm &";}
+                             {name = "xfce";  script = "xfce4-session &";}
+                             {name = "icewm"; script = "icewmbg &";}
+                             {name = "mate";  script = "gnome-session &";}
+                           ]
+       => { icewm = [ { name = "icewm"; script = "icewm &"; }
+                      { name = "icewm"; script = "icewmbg &"; } ];
+            mate  = [ { name = "mate";  script = "gnome-session &"; } ];
+            xfce  = [ { name = "xfce";  script = "xfce4-session &"; } ];
+          }
+
+       groupBy' builtins.add 0 (x: boolToString (x > 2)) [ 5 1 2 3 4 ]
+       => { true = 12; false = 3; }
+  */
+  groupBy' = op: nul: pred: lst:
+    foldl' (r: e:
+              let
+                key = pred e;
+              in
+                r // { ${key} = op (r.${key} or nul) e; }
+           ) {} lst;
+
+  groupBy = groupBy' (sum: e: sum ++ [e]) [];
+
+  /* Merges two lists of the same size together. If the sizes aren't the same
+     the merging stops at the shortest. How both lists are merged is defined
+     by the first argument.
+
+     Type: zipListsWith :: (a -> b -> c) -> [a] -> [b] -> [c]
+
+     Example:
+       zipListsWith (a: b: a + b) ["h" "l"] ["e" "o"]
+       => ["he" "lo"]
+  */
+  zipListsWith =
+    # Function to zip elements of both lists
+    f:
+    # First list
+    fst:
+    # Second list
+    snd:
+    genList
+      (n: f (elemAt fst n) (elemAt snd n)) (min (length fst) (length snd));
+
+  /* Merges two lists of the same size together. If the sizes aren't the same
+     the merging stops at the shortest.
+
+     Type: zipLists :: [a] -> [b] -> [{ fst :: a, snd :: b}]
+
+     Example:
+       zipLists [ 1 2 ] [ "a" "b" ]
+       => [ { fst = 1; snd = "a"; } { fst = 2; snd = "b"; } ]
+  */
+  zipLists = zipListsWith (fst: snd: { inherit fst snd; });
+
+  /* Reverse the order of the elements of a list.
+
+     Type: reverseList :: [a] -> [a]
+
+     Example:
+
+       reverseList [ "b" "o" "j" ]
+       => [ "j" "o" "b" ]
+  */
+  reverseList = xs:
+    let l = length xs; in genList (n: elemAt xs (l - n - 1)) l;
+
+  /* Depth-First Search (DFS) for lists `list != []`.
+
+     `before a b == true` means that `b` depends on `a` (there's an
+     edge from `b` to `a`).
+
+     Example:
+         listDfs true hasPrefix [ "/home/user" "other" "/" "/home" ]
+           == { minimal = "/";                  # minimal element
+                visited = [ "/home/user" ];     # seen elements (in reverse order)
+                rest    = [ "/home" "other" ];  # everything else
+              }
+
+         listDfs true hasPrefix [ "/home/user" "other" "/" "/home" "/" ]
+           == { cycle   = "/";                  # cycle encountered at this element
+                loops   = [ "/" ];              # and continues to these elements
+                visited = [ "/" "/home/user" ]; # elements leading to the cycle (in reverse order)
+                rest    = [ "/home" "other" ];  # everything else
+
+   */
+  listDfs = stopOnCycles: before: list:
+    let
+      dfs' = us: visited: rest:
+        let
+          c = filter (x: before x us) visited;
+          b = partition (x: before x us) rest;
+        in if stopOnCycles && (length c > 0)
+           then { cycle = us; loops = c; inherit visited rest; }
+           else if length b.right == 0
+                then # nothing is before us
+                     { minimal = us; inherit visited rest; }
+                else # grab the first one before us and continue
+                     dfs' (head b.right)
+                          ([ us ] ++ visited)
+                          (tail b.right ++ b.wrong);
+    in dfs' (head list) [] (tail list);
+
+  /* Sort a list based on a partial ordering using DFS. This
+     implementation is O(N^2), if your ordering is linear, use `sort`
+     instead.
+
+     `before a b == true` means that `b` should be after `a`
+     in the result.
+
+     Example:
+
+         toposort hasPrefix [ "/home/user" "other" "/" "/home" ]
+           == { result = [ "/" "/home" "/home/user" "other" ]; }
+
+         toposort hasPrefix [ "/home/user" "other" "/" "/home" "/" ]
+           == { cycle = [ "/home/user" "/" "/" ]; # path leading to a cycle
+                loops = [ "/" ]; }                # loops back to these elements
+
+         toposort hasPrefix [ "other" "/home/user" "/home" "/" ]
+           == { result = [ "other" "/" "/home" "/home/user" ]; }
+
+         toposort (a: b: a < b) [ 3 2 1 ] == { result = [ 1 2 3 ]; }
+
+   */
+  toposort = before: list:
+    let
+      dfsthis = listDfs true before list;
+      toporest = toposort before (dfsthis.visited ++ dfsthis.rest);
+    in
+      if length list < 2
+      then # finish
+           { result =  list; }
+      else if dfsthis ? "cycle"
+           then # there's a cycle, starting from the current vertex, return it
+                { cycle = reverseList ([ dfsthis.cycle ] ++ dfsthis.visited);
+                  inherit (dfsthis) loops; }
+           else if toporest ? "cycle"
+                then # there's a cycle somewhere else in the graph, return it
+                     toporest
+                # Slow, but short. Can be made a bit faster with an explicit stack.
+                else # there are no cycles
+                     { result = [ dfsthis.minimal ] ++ toporest.result; };
+
+  /* Sort a list based on a comparator function which compares two
+     elements and returns true if the first argument is strictly below
+     the second argument.  The returned list is sorted in an increasing
+     order.  The implementation does a quick-sort.
+
+     Example:
+       sort (a: b: a < b) [ 5 3 7 ]
+       => [ 3 5 7 ]
+  */
+  sort = builtins.sort or (
+    strictLess: list:
+    let
+      len = length list;
+      first = head list;
+      pivot' = n: acc@{ left, right }: let el = elemAt list n; next = pivot' (n + 1); in
+        if n == len
+          then acc
+        else if strictLess first el
+          then next { inherit left; right = [ el ] ++ right; }
+        else
+          next { left = [ el ] ++ left; inherit right; };
+      pivot = pivot' 1 { left = []; right = []; };
+    in
+      if len < 2 then list
+      else (sort strictLess pivot.left) ++  [ first ] ++  (sort strictLess pivot.right));
+
+  /* Compare two lists element-by-element.
+
+     Example:
+       compareLists compare [] []
+       => 0
+       compareLists compare [] [ "a" ]
+       => -1
+       compareLists compare [ "a" ] []
+       => 1
+       compareLists compare [ "a" "b" ] [ "a" "c" ]
+       => 1
+  */
+  compareLists = cmp: a: b:
+    if a == []
+    then if b == []
+         then 0
+         else -1
+    else if b == []
+         then 1
+         else let rel = cmp (head a) (head b); in
+              if rel == 0
+              then compareLists cmp (tail a) (tail b)
+              else rel;
+
+  /* Sort list using "Natural sorting".
+     Numeric portions of strings are sorted in numeric order.
+
+     Example:
+       naturalSort ["disk11" "disk8" "disk100" "disk9"]
+       => ["disk8" "disk9" "disk11" "disk100"]
+       naturalSort ["10.46.133.149" "10.5.16.62" "10.54.16.25"]
+       => ["10.5.16.62" "10.46.133.149" "10.54.16.25"]
+       naturalSort ["v0.2" "v0.15" "v0.0.9"]
+       => [ "v0.0.9" "v0.2" "v0.15" ]
+  */
+  naturalSort = lst:
+    let
+      vectorise = s: map (x: if isList x then toInt (head x) else x) (builtins.split "(0|[1-9][0-9]*)" s);
+      prepared = map (x: [ (vectorise x) x ]) lst; # remember vectorised version for O(n) regex splits
+      less = a: b: (compareLists compare (head a) (head b)) < 0;
+    in
+      map (x: elemAt x 1) (sort less prepared);
+
+  /* Return the first (at most) N elements of a list.
+
+     Type: take :: int -> [a] -> [a]
+
+     Example:
+       take 2 [ "a" "b" "c" "d" ]
+       => [ "a" "b" ]
+       take 2 [ ]
+       => [ ]
+  */
+  take =
+    # Number of elements to take
+    count: sublist 0 count;
+
+  /* Remove the first (at most) N elements of a list.
+
+     Type: drop :: int -> [a] -> [a]
+
+     Example:
+       drop 2 [ "a" "b" "c" "d" ]
+       => [ "c" "d" ]
+       drop 2 [ ]
+       => [ ]
+  */
+  drop =
+    # Number of elements to drop
+    count:
+    # Input list
+    list: sublist count (length list) list;
+
+  /* Return a list consisting of at most `count` elements of `list`,
+     starting at index `start`.
+
+     Type: sublist :: int -> int -> [a] -> [a]
+
+     Example:
+       sublist 1 3 [ "a" "b" "c" "d" "e" ]
+       => [ "b" "c" "d" ]
+       sublist 1 3 [ ]
+       => [ ]
+  */
+  sublist =
+    # Index at which to start the sublist
+    start:
+    # Number of elements to take
+    count:
+    # Input list
+    list:
+    let len = length list; in
+    genList
+      (n: elemAt list (n + start))
+      (if start >= len then 0
+       else if start + count > len then len - start
+       else count);
+
+  /* Return the last element of a list.
+
+     This function throws an error if the list is empty.
+
+     Type: last :: [a] -> a
+
+     Example:
+       last [ 1 2 3 ]
+       => 3
+  */
+  last = list:
+    assert lib.assertMsg (list != []) "lists.last: list must not be empty!";
+    elemAt list (length list - 1);
+
+  /* Return all elements but the last.
+
+     This function throws an error if the list is empty.
+
+     Type: init :: [a] -> [a]
+
+     Example:
+       init [ 1 2 3 ]
+       => [ 1 2 ]
+  */
+  init = list:
+    assert lib.assertMsg (list != []) "lists.init: list must not be empty!";
+    take (length list - 1) list;
+
+
+  /* Return the image of the cross product of some lists by a function.
+
+    Example:
+      crossLists (x:y: "${toString x}${toString y}") [[1 2] [3 4]]
+      => [ "13" "14" "23" "24" ]
+  */
+  crossLists = f: foldl (fs: args: concatMap (f: map f args) fs) [f];
+
+
+  /* Remove duplicate elements from the list. O(n^2) complexity.
+
+     Type: unique :: [a] -> [a]
+
+     Example:
+       unique [ 3 2 3 4 ]
+       => [ 3 2 4 ]
+   */
+  unique = list:
+    if list == [] then
+      []
+    else
+      let
+        x = head list;
+        xs = unique (drop 1 list);
+      in [x] ++ remove x xs;
+
+  /* Intersects list 'e' and another list. O(nm) complexity.
+
+     Example:
+       intersectLists [ 1 2 3 ] [ 6 3 2 ]
+       => [ 3 2 ]
+  */
+  intersectLists = e: filter (x: elem x e);
+
+  /* Subtracts list 'e' from another list. O(nm) complexity.
+
+     Example:
+       subtractLists [ 3 2 ] [ 1 2 3 4 5 3 ]
+       => [ 1 4 5 ]
+  */
+  subtractLists = e: filter (x: !(elem x e));
+
+  /* Test if two lists have no common element.
+     It should be slightly more efficient than (intersectLists a b == [])
+  */
+  mutuallyExclusive = a: b:
+    (builtins.length a) == 0 ||
+    (!(builtins.elem (builtins.head a) b) &&
+     mutuallyExclusive (builtins.tail a) b);
+
+}
diff --git a/nixpkgs/lib/meta.nix b/nixpkgs/lib/meta.nix
new file mode 100644
index 000000000000..199030c103af
--- /dev/null
+++ b/nixpkgs/lib/meta.nix
@@ -0,0 +1,89 @@
+/* Some functions for manipulating meta attributes, as well as the
+   name attribute. */
+
+{ lib }:
+
+rec {
+
+
+  /* Add to or override the meta attributes of the given
+     derivation.
+
+     Example:
+       addMetaAttrs {description = "Bla blah";} somePkg
+  */
+  addMetaAttrs = newAttrs: drv:
+    drv // { meta = (drv.meta or {}) // newAttrs; };
+
+
+  /* Disable Hydra builds of given derivation.
+  */
+  dontDistribute = drv: addMetaAttrs { hydraPlatforms = []; } drv;
+
+
+  /* Change the symbolic name of a package for presentation purposes
+     (i.e., so that nix-env users can tell them apart).
+  */
+  setName = name: drv: drv // {inherit name;};
+
+
+  /* Like `setName', but takes the previous name as an argument.
+
+     Example:
+       updateName (oldName: oldName + "-experimental") somePkg
+  */
+  updateName = updater: drv: drv // {name = updater (drv.name);};
+
+
+  /* Append a suffix to the name of a package (before the version
+     part). */
+  appendToName = suffix: updateName (name:
+    let x = builtins.parseDrvName name; in "${x.name}-${suffix}-${x.version}");
+
+
+  /* Apply a function to each derivation and only to derivations in an attrset
+  */
+  mapDerivationAttrset = f: set: lib.mapAttrs (name: pkg: if lib.isDerivation pkg then (f pkg) else pkg) set;
+
+
+  /* Decrease the nix-env priority of the package, i.e., other
+     versions/variants of the package will be preferred.
+  */
+  lowPrio = drv: addMetaAttrs { priority = 10; } drv;
+
+
+  /* Apply lowPrio to an attrset with derivations
+  */
+  lowPrioSet = set: mapDerivationAttrset lowPrio set;
+
+
+  /* Increase the nix-env priority of the package, i.e., this
+     version/variant of the package will be preferred.
+  */
+  hiPrio = drv: addMetaAttrs { priority = -10; } drv;
+
+
+  /* Apply hiPrio to an attrset with derivations
+  */
+  hiPrioSet = set: mapDerivationAttrset hiPrio set;
+
+
+  /* Check to see if a platform is matched by the given `meta.platforms`
+     element.
+
+     A `meta.platform` pattern is either
+
+       1. (legacy) a system string.
+
+       2. (modern) a pattern for the platform `parsed` field.
+
+     We can inject these into a patten for the whole of a structured platform,
+     and then match that.
+  */
+  platformMatch = platform: elem: let
+      pattern =
+        if builtins.isString elem
+        then { system = elem; }
+        else { parsed = elem; };
+    in lib.matchAttrs pattern platform;
+}
diff --git a/nixpkgs/lib/minver.nix b/nixpkgs/lib/minver.nix
new file mode 100644
index 000000000000..fee6b65a2447
--- /dev/null
+++ b/nixpkgs/lib/minver.nix
@@ -0,0 +1,2 @@
+# Expose the minimum required version for evaluating Nixpkgs
+"2.0"
diff --git a/nixpkgs/lib/modules.nix b/nixpkgs/lib/modules.nix
new file mode 100644
index 000000000000..5fb83a4a538c
--- /dev/null
+++ b/nixpkgs/lib/modules.nix
@@ -0,0 +1,715 @@
+{ lib }:
+
+with lib.lists;
+with lib.strings;
+with lib.trivial;
+with lib.attrsets;
+with lib.options;
+with lib.debug;
+with lib.types;
+
+rec {
+
+  /* Evaluate a set of modules.  The result is a set of two
+     attributes: ‘options’: the nested set of all option declarations,
+     and ‘config’: the nested set of all option values.
+     !!! Please think twice before adding to this argument list! The more
+     that is specified here instead of in the modules themselves the harder
+     it is to transparently move a set of modules to be a submodule of another
+     config (as the proper arguments need to be replicated at each call to
+     evalModules) and the less declarative the module set is. */
+  evalModules = { modules
+                , prefix ? []
+                , # This should only be used for special arguments that need to be evaluated
+                  # when resolving module structure (like in imports). For everything else,
+                  # there's _module.args. If specialArgs.modulesPath is defined it will be
+                  # used as the base path for disabledModules.
+                  specialArgs ? {}
+                , # This would be remove in the future, Prefer _module.args option instead.
+                  args ? {}
+                , # This would be remove in the future, Prefer _module.check option instead.
+                  check ? true
+                }:
+    let
+      # This internal module declare internal options under the `_module'
+      # attribute.  These options are fragile, as they are used by the
+      # module system to change the interpretation of modules.
+      internalModule = rec {
+        _file = ./modules.nix;
+
+        key = _file;
+
+        options = {
+          _module.args = mkOption {
+            type = types.attrsOf types.unspecified;
+            internal = true;
+            description = "Arguments passed to each module.";
+          };
+
+          _module.check = mkOption {
+            type = types.bool;
+            internal = true;
+            default = check;
+            description = "Whether to check whether all option definitions have matching declarations.";
+          };
+        };
+
+        config = {
+          _module.args = args;
+        };
+      };
+
+      closed = closeModules (modules ++ [ internalModule ]) ({ inherit config options lib; } // specialArgs);
+
+      options = mergeModules prefix (reverseList (filterModules (specialArgs.modulesPath or "") closed));
+
+      # Traverse options and extract the option values into the final
+      # config set.  At the same time, check whether all option
+      # definitions have matching declarations.
+      # !!! _module.check's value can't depend on any other config values
+      # without an infinite recursion. One way around this is to make the
+      # 'config' passed around to the modules be unconditionally unchecked,
+      # and only do the check in 'result'.
+      config = yieldConfig prefix options;
+      yieldConfig = prefix: set:
+        let res = removeAttrs (mapAttrs (n: v:
+          if isOption v then v.value
+          else yieldConfig (prefix ++ [n]) v) set) ["_definedNames"];
+        in
+        if options._module.check.value && set ? _definedNames then
+          foldl' (res: m:
+            foldl' (res: name:
+              if set ? ${name} then res else throw "The option `${showOption (prefix ++ [name])}' defined in `${m.file}' does not exist.")
+              res m.names)
+            res set._definedNames
+        else
+          res;
+      result = { inherit options config; };
+    in result;
+
+
+ # Filter disabled modules. Modules can be disabled allowing
+ # their implementation to be replaced.
+ filterModules = modulesPath: modules:
+   let
+     moduleKey = m: if isString m then toString modulesPath + "/" + m else toString m;
+     disabledKeys = map moduleKey (concatMap (m: m.disabledModules) modules);
+   in
+     filter (m: !(elem m.key disabledKeys)) modules;
+
+  /* Close a set of modules under the ‘imports’ relation. */
+  closeModules = modules: args:
+    let
+      toClosureList = file: parentKey: imap1 (n: x:
+        if isAttrs x || isFunction x then
+          let key = "${parentKey}:anon-${toString n}"; in
+          unifyModuleSyntax file key (unpackSubmodule (applyIfFunction key) x args)
+        else
+          let file = toString x; key = toString x; in
+          unifyModuleSyntax file key (applyIfFunction key (import x) args));
+    in
+      builtins.genericClosure {
+        startSet = toClosureList unknownModule "" modules;
+        operator = m: toClosureList m.file m.key m.imports;
+      };
+
+  /* Massage a module into canonical form, that is, a set consisting
+     of ‘options’, ‘config’ and ‘imports’ attributes. */
+  unifyModuleSyntax = file: key: m:
+    let metaSet = if m ? meta
+      then { meta = m.meta; }
+      else {};
+    in
+    if m ? config || m ? options then
+      let badAttrs = removeAttrs m ["_file" "key" "disabledModules" "imports" "options" "config" "meta"]; in
+      if badAttrs != {} then
+        throw "Module `${key}' has an unsupported attribute `${head (attrNames badAttrs)}'. This is caused by assignments to the top-level attributes `config' or `options'."
+      else
+        { file = m._file or file;
+          key = toString m.key or key;
+          disabledModules = m.disabledModules or [];
+          imports = m.imports or [];
+          options = m.options or {};
+          config = mkMerge [ (m.config or {}) metaSet ];
+        }
+    else
+      { file = m._file or file;
+        key = toString m.key or key;
+        disabledModules = m.disabledModules or [];
+        imports = m.require or [] ++ m.imports or [];
+        options = {};
+        config = mkMerge [ (removeAttrs m ["_file" "key" "disabledModules" "require" "imports"]) metaSet ];
+      };
+
+  applyIfFunction = key: f: args@{ config, options, lib, ... }: if isFunction f then
+    let
+      # Module arguments are resolved in a strict manner when attribute set
+      # deconstruction is used.  As the arguments are now defined with the
+      # config._module.args option, the strictness used on the attribute
+      # set argument would cause an infinite loop, if the result of the
+      # option is given as argument.
+      #
+      # To work-around the strictness issue on the deconstruction of the
+      # attributes set argument, we create a new attribute set which is
+      # constructed to satisfy the expected set of attributes.  Thus calling
+      # a module will resolve strictly the attributes used as argument but
+      # not their values.  The values are forwarding the result of the
+      # evaluation of the option.
+      requiredArgs = builtins.attrNames (lib.functionArgs f);
+      context = name: ''while evaluating the module argument `${name}' in "${key}":'';
+      extraArgs = builtins.listToAttrs (map (name: {
+        inherit name;
+        value = builtins.addErrorContext (context name)
+          (args.${name} or config._module.args.${name});
+      }) requiredArgs);
+
+      # Note: we append in the opposite order such that we can add an error
+      # context on the explicited arguments of "args" too. This update
+      # operator is used to make the "args@{ ... }: with args.lib;" notation
+      # works.
+    in f (args // extraArgs)
+  else
+    f;
+
+  /* We have to pack and unpack submodules. We cannot wrap the expected
+     result of the function as we would no longer be able to list the arguments
+     of the submodule. (see applyIfFunction) */
+  unpackSubmodule = unpack: m: args:
+    if isType "submodule" m then
+      { _file = m.file; } // (unpack m.submodule args)
+    else unpack m args;
+
+  packSubmodule = file: m:
+    { _type = "submodule"; file = file; submodule = m; };
+
+  /* Merge a list of modules.  This will recurse over the option
+     declarations in all modules, combining them into a single set.
+     At the same time, for each option declaration, it will merge the
+     corresponding option definitions in all machines, returning them
+     in the ‘value’ attribute of each option. */
+  mergeModules = prefix: modules:
+    mergeModules' prefix modules
+      (concatMap (m: map (config: { inherit (m) file; inherit config; }) (pushDownProperties m.config)) modules);
+
+  mergeModules' = prefix: options: configs:
+    let
+     /* byName is like foldAttrs, but will look for attributes to merge in the
+        specified attribute name.
+
+        byName "foo" (module: value: ["module.hidden=${module.hidden},value=${value}"])
+        [
+          {
+            hidden="baz";
+            foo={qux="bar"; gla="flop";};
+          }
+          {
+            hidden="fli";
+            foo={qux="gne"; gli="flip";};
+          }
+        ]
+        ===>
+        {
+          gla = [ "module.hidden=baz,value=flop" ];
+          gli = [ "module.hidden=fli,value=flip" ];
+          qux = [ "module.hidden=baz,value=bar" "module.hidden=fli,value=gne" ];
+        }
+      */
+      byName = attr: f: modules: foldl' (acc: module:
+        foldl' (inner: name:
+          inner // { ${name} = (acc.${name} or []) ++ (f module module.${attr}.${name}); }
+          ) acc (attrNames module.${attr})
+        ) {} modules;
+      # an attrset 'name' => list of submodules that declare ‘name’.
+      declsByName = byName "options"
+        (module: option: [{ inherit (module) file; options = option; }])
+        options;
+      # an attrset 'name' => list of submodules that define ‘name’.
+      defnsByName = byName "config" (module: value:
+        map (config: { inherit (module) file; inherit config; }) (pushDownProperties value)
+        ) configs;
+      # extract the definitions for each loc
+      defnsByName' = byName "config"
+        (module: value: [{ inherit (module) file; inherit value; }])
+        configs;
+    in
+    (flip mapAttrs declsByName (name: decls:
+      # We're descending into attribute ‘name’.
+        let
+          loc = prefix ++ [name];
+          defns = defnsByName.${name} or [];
+          defns' = defnsByName'.${name} or [];
+          nrOptions = count (m: isOption m.options) decls;
+        in
+          if nrOptions == length decls then
+            let opt = fixupOptionType loc (mergeOptionDecls loc decls);
+            in evalOptionValue loc opt defns'
+          else if nrOptions != 0 then
+            let
+              firstOption = findFirst (m: isOption m.options) "" decls;
+              firstNonOption = findFirst (m: !isOption m.options) "" decls;
+            in
+              throw "The option `${showOption loc}' in `${firstOption.file}' is a prefix of options in `${firstNonOption.file}'."
+          else
+            mergeModules' loc decls defns
+      ))
+    // { _definedNames = map (m: { inherit (m) file; names = attrNames m.config; }) configs; };
+
+  /* Merge multiple option declarations into a single declaration.  In
+     general, there should be only one declaration of each option.
+     The exception is the ‘options’ attribute, which specifies
+     sub-options.  These can be specified multiple times to allow one
+     module to add sub-options to an option declared somewhere else
+     (e.g. multiple modules define sub-options for ‘fileSystems’).
+
+     'loc' is the list of attribute names where the option is located.
+
+     'opts' is a list of modules.  Each module has an options attribute which
+     correspond to the definition of 'loc' in 'opt.file'. */
+  mergeOptionDecls = loc: opts:
+    foldl' (res: opt:
+      let t  = res.type;
+          t' = opt.options.type;
+          mergedType = t.typeMerge t'.functor;
+          typesMergeable = mergedType != null;
+          typeSet = if (bothHave "type") && typesMergeable
+                       then { type = mergedType; }
+                       else {};
+          bothHave = k: opt.options ? ${k} && res ? ${k};
+      in
+      if bothHave "default" ||
+         bothHave "example" ||
+         bothHave "description" ||
+         bothHave "apply" ||
+         (bothHave "type" && (! typesMergeable))
+      then
+        throw "The option `${showOption loc}' in `${opt.file}' is already declared in ${showFiles res.declarations}."
+      else
+        let
+          /* Add the modules of the current option to the list of modules
+             already collected.  The options attribute except either a list of
+             submodules or a submodule. For each submodule, we add the file of the
+             current option declaration as the file use for the submodule.  If the
+             submodule defines any filename, then we ignore the enclosing option file. */
+          options' = toList opt.options.options;
+          coerceOption = file: opt:
+            if isFunction opt then packSubmodule file opt
+            else packSubmodule file { options = opt; };
+          getSubModules = opt.options.type.getSubModules or null;
+          submodules =
+            if getSubModules != null then map (packSubmodule opt.file) getSubModules ++ res.options
+            else if opt.options ? options then map (coerceOption opt.file) options' ++ res.options
+            else res.options;
+        in opt.options // res //
+          { declarations = res.declarations ++ [opt.file];
+            options = submodules;
+          } // typeSet
+    ) { inherit loc; declarations = []; options = []; } opts;
+
+  /* Merge all the definitions of an option to produce the final
+     config value. */
+  evalOptionValue = loc: opt: defs:
+    let
+      # Add in the default value for this option, if any.
+      defs' =
+          (optional (opt ? default)
+            { file = head opt.declarations; value = mkOptionDefault opt.default; }) ++ defs;
+
+      # Handle properties, check types, and merge everything together.
+      res =
+        if opt.readOnly or false && length defs' > 1 then
+          throw "The option `${showOption loc}' is read-only, but it's set multiple times."
+        else
+          mergeDefinitions loc opt.type defs';
+
+      # Check whether the option is defined, and apply the ‘apply’
+      # function to the merged value.  This allows options to yield a
+      # value computed from the definitions.
+      value =
+        if !res.isDefined then
+          throw "The option `${showOption loc}' is used but not defined."
+        else if opt ? apply then
+          opt.apply res.mergedValue
+        else
+          res.mergedValue;
+
+    in opt //
+      { value = builtins.addErrorContext "while evaluating the option `${showOption loc}':" value;
+        inherit (res.defsFinal') highestPrio;
+        definitions = map (def: def.value) res.defsFinal;
+        files = map (def: def.file) res.defsFinal;
+        inherit (res) isDefined;
+      };
+
+  # Merge definitions of a value of a given type.
+  mergeDefinitions = loc: type: defs: rec {
+    defsFinal' =
+      let
+        # Process mkMerge and mkIf properties.
+        defs' = concatMap (m:
+          map (value: { inherit (m) file; inherit value; }) (dischargeProperties m.value)
+        ) defs;
+
+        # Process mkOverride properties.
+        defs'' = filterOverrides' defs';
+
+        # Sort mkOrder properties.
+        defs''' =
+          # Avoid sorting if we don't have to.
+          if any (def: def.value._type or "" == "order") defs''.values
+          then sortProperties defs''.values
+          else defs''.values;
+      in {
+        values = defs''';
+        inherit (defs'') highestPrio;
+      };
+
+    defsFinal = defsFinal'.values;
+
+    # Type-check the remaining definitions, and merge them.
+    mergedValue = foldl' (res: def:
+      if type.check def.value then res
+      else throw "The option value `${showOption loc}' in `${def.file}' is not of type `${type.description}'.")
+      (type.merge loc defsFinal) defsFinal;
+
+    isDefined = defsFinal != [];
+
+    optionalValue =
+      if isDefined then { value = mergedValue; }
+      else {};
+  };
+
+  /* Given a config set, expand mkMerge properties, and push down the
+     other properties into the children.  The result is a list of
+     config sets that do not have properties at top-level.  For
+     example,
+
+       mkMerge [ { boot = set1; } (mkIf cond { boot = set2; services = set3; }) ]
+
+     is transformed into
+
+       [ { boot = set1; } { boot = mkIf cond set2; services = mkIf cond set3; } ].
+
+     This transform is the critical step that allows mkIf conditions
+     to refer to the full configuration without creating an infinite
+     recursion.
+  */
+  pushDownProperties = cfg:
+    if cfg._type or "" == "merge" then
+      concatMap pushDownProperties cfg.contents
+    else if cfg._type or "" == "if" then
+      map (mapAttrs (n: v: mkIf cfg.condition v)) (pushDownProperties cfg.content)
+    else if cfg._type or "" == "override" then
+      map (mapAttrs (n: v: mkOverride cfg.priority v)) (pushDownProperties cfg.content)
+    else # FIXME: handle mkOrder?
+      [ cfg ];
+
+  /* Given a config value, expand mkMerge properties, and discharge
+     any mkIf conditions.  That is, this is the place where mkIf
+     conditions are actually evaluated.  The result is a list of
+     config values.  For example, ‘mkIf false x’ yields ‘[]’,
+     ‘mkIf true x’ yields ‘[x]’, and
+
+       mkMerge [ 1 (mkIf true 2) (mkIf true (mkIf false 3)) ]
+
+     yields ‘[ 1 2 ]’.
+  */
+  dischargeProperties = def:
+    if def._type or "" == "merge" then
+      concatMap dischargeProperties def.contents
+    else if def._type or "" == "if" then
+      if isBool def.condition then
+        if def.condition then
+          dischargeProperties def.content
+        else
+          [ ]
+      else
+        throw "‘mkIf’ called with a non-Boolean condition"
+    else
+      [ def ];
+
+  /* Given a list of config values, process the mkOverride properties,
+     that is, return the values that have the highest (that is,
+     numerically lowest) priority, and strip the mkOverride
+     properties.  For example,
+
+       [ { file = "/1"; value = mkOverride 10 "a"; }
+         { file = "/2"; value = mkOverride 20 "b"; }
+         { file = "/3"; value = "z"; }
+         { file = "/4"; value = mkOverride 10 "d"; }
+       ]
+
+     yields
+
+       [ { file = "/1"; value = "a"; }
+         { file = "/4"; value = "d"; }
+       ]
+
+     Note that "z" has the default priority 100.
+  */
+  filterOverrides = defs: (filterOverrides' defs).values;
+
+  filterOverrides' = defs:
+    let
+      defaultPrio = 100;
+      getPrio = def: if def.value._type or "" == "override" then def.value.priority else defaultPrio;
+      highestPrio = foldl' (prio: def: min (getPrio def) prio) 9999 defs;
+      strip = def: if def.value._type or "" == "override" then def // { value = def.value.content; } else def;
+    in {
+      values = concatMap (def: if getPrio def == highestPrio then [(strip def)] else []) defs;
+      inherit highestPrio;
+    };
+
+  /* Sort a list of properties.  The sort priority of a property is
+     1000 by default, but can be overridden by wrapping the property
+     using mkOrder. */
+  sortProperties = defs:
+    let
+      strip = def:
+        if def.value._type or "" == "order"
+        then def // { value = def.value.content; inherit (def.value) priority; }
+        else def;
+      defs' = map strip defs;
+      compare = a: b: (a.priority or 1000) < (b.priority or 1000);
+    in sort compare defs';
+
+  /* Hack for backward compatibility: convert options of type
+     optionSet to options of type submodule.  FIXME: remove
+     eventually. */
+  fixupOptionType = loc: opt:
+    let
+      options = opt.options or
+        (throw "Option `${showOption loc'}' has type optionSet but has no option attribute, in ${showFiles opt.declarations}.");
+      f = tp:
+        let optionSetIn = type: (tp.name == type) && (tp.functor.wrapped.name == "optionSet");
+        in
+        if tp.name == "option set" || tp.name == "submodule" then
+          throw "The option ${showOption loc} uses submodules without a wrapping type, in ${showFiles opt.declarations}."
+        else if optionSetIn "attrsOf" then types.attrsOf (types.submodule options)
+        else if optionSetIn "loaOf"   then types.loaOf   (types.submodule options)
+        else if optionSetIn "listOf"  then types.listOf  (types.submodule options)
+        else if optionSetIn "nullOr"  then types.nullOr  (types.submodule options)
+        else tp;
+    in
+      if opt.type.getSubModules or null == null
+      then opt // { type = f (opt.type or types.unspecified); }
+      else opt // { type = opt.type.substSubModules opt.options; options = []; };
+
+
+  /* Properties. */
+
+  mkIf = condition: content:
+    { _type = "if";
+      inherit condition content;
+    };
+
+  mkAssert = assertion: message: content:
+    mkIf
+      (if assertion then true else throw "\nFailed assertion: ${message}")
+      content;
+
+  mkMerge = contents:
+    { _type = "merge";
+      inherit contents;
+    };
+
+  mkOverride = priority: content:
+    { _type = "override";
+      inherit priority content;
+    };
+
+  mkOptionDefault = mkOverride 1500; # priority of option defaults
+  mkDefault = mkOverride 1000; # used in config sections of non-user modules to set a default
+  mkForce = mkOverride 50;
+  mkVMOverride = mkOverride 10; # used by ‘nixos-rebuild build-vm’
+
+  mkStrict = builtins.trace "`mkStrict' is obsolete; use `mkOverride 0' instead." (mkOverride 0);
+
+  mkFixStrictness = id; # obsolete, no-op
+
+  mkOrder = priority: content:
+    { _type = "order";
+      inherit priority content;
+    };
+
+  mkBefore = mkOrder 500;
+  mkAfter = mkOrder 1500;
+
+
+  # Convenient property used to transfer all definitions and their
+  # properties from one option to another. This property is useful for
+  # renaming options, and also for including properties from another module
+  # system, including sub-modules.
+  #
+  #   { config, options, ... }:
+  #
+  #   {
+  #     # 'bar' might not always be defined in the current module-set.
+  #     config.foo.enable = mkAliasDefinitions (options.bar.enable or {});
+  #
+  #     # 'barbaz' has to be defined in the current module-set.
+  #     config.foobar.paths = mkAliasDefinitions options.barbaz.paths;
+  #   }
+  #
+  # Note, this is different than taking the value of the option and using it
+  # as a definition, as the new definition will not keep the mkOverride /
+  # mkDefault properties of the previous option.
+  #
+  mkAliasDefinitions = mkAliasAndWrapDefinitions id;
+  mkAliasAndWrapDefinitions = wrap: option:
+    mkIf (isOption option && option.isDefined) (wrap (mkMerge option.definitions));
+
+
+  /* Compatibility. */
+  fixMergeModules = modules: args: evalModules { inherit modules args; check = false; };
+
+
+  /* Return a module that causes a warning to be shown if the
+     specified option is defined. For example,
+
+       mkRemovedOptionModule [ "boot" "loader" "grub" "bootDevice" ] "<replacement instructions>"
+
+     causes a warning if the user defines boot.loader.grub.bootDevice.
+
+     replacementInstructions is a string that provides instructions on
+     how to achieve the same functionality without the removed option,
+     or alternatively a reasoning why the functionality is not needed.
+     replacementInstructions SHOULD be provided!
+  */
+  mkRemovedOptionModule = optionName: replacementInstructions:
+    { options, ... }:
+    { options = setAttrByPath optionName (mkOption {
+        visible = false;
+      });
+      config.warnings =
+        let opt = getAttrFromPath optionName options; in
+        optional opt.isDefined ''
+            The option definition `${showOption optionName}' in ${showFiles opt.files} no longer has any effect; please remove it.
+            ${replacementInstructions}'';
+    };
+
+  /* Return a module that causes a warning to be shown if the
+     specified "from" option is defined; the defined value is however
+     forwarded to the "to" option. This can be used to rename options
+     while providing backward compatibility. For example,
+
+       mkRenamedOptionModule [ "boot" "copyKernels" ] [ "boot" "loader" "grub" "copyKernels" ]
+
+     forwards any definitions of boot.copyKernels to
+     boot.loader.grub.copyKernels while printing a warning.
+  */
+  mkRenamedOptionModule = from: to: doRename {
+    inherit from to;
+    visible = false;
+    warn = true;
+    use = builtins.trace "Obsolete option `${showOption from}' is used. It was renamed to `${showOption to}'.";
+  };
+
+  /* Return a module that causes a warning to be shown if any of the "from"
+     option is defined; the defined values can be used in the "mergeFn" to set
+     the "to" value.
+     This function can be used to merge multiple options into one that has a
+     different type.
+
+     "mergeFn" takes the module "config" as a parameter and must return a value
+     of "to" option type.
+
+       mkMergedOptionModule
+         [ [ "a" "b" "c" ]
+           [ "d" "e" "f" ] ]
+         [ "x" "y" "z" ]
+         (config:
+           let value = p: getAttrFromPath p config;
+           in
+           if      (value [ "a" "b" "c" ]) == true then "foo"
+           else if (value [ "d" "e" "f" ]) == true then "bar"
+           else "baz")
+
+     - options.a.b.c is a removed boolean option
+     - options.d.e.f is a removed boolean option
+     - options.x.y.z is a new str option that combines a.b.c and d.e.f
+       functionality
+
+     This show a warning if any a.b.c or d.e.f is set, and set the value of
+     x.y.z to the result of the merge function
+  */
+  mkMergedOptionModule = from: to: mergeFn:
+    { config, options, ... }:
+    {
+      options = foldl recursiveUpdate {} (map (path: setAttrByPath path (mkOption {
+        visible = false;
+        # To use the value in mergeFn without triggering errors
+        default = "_mkMergedOptionModule";
+      })) from);
+
+      config = {
+        warnings = filter (x: x != "") (map (f:
+          let val = getAttrFromPath f config;
+              opt = getAttrFromPath f options;
+          in
+          optionalString
+            (val != "_mkMergedOptionModule")
+            "The option `${showOption f}' defined in ${showFiles opt.files} has been changed to `${showOption to}' that has a different type. Please read `${showOption to}' documentation and update your configuration accordingly."
+        ) from);
+      } // setAttrByPath to (mkMerge
+             (optional
+               (any (f: (getAttrFromPath f config) != "_mkMergedOptionModule") from)
+               (mergeFn config)));
+    };
+
+  /* Single "from" version of mkMergedOptionModule.
+     Return a module that causes a warning to be shown if the "from" option is
+     defined; the defined value can be used in the "mergeFn" to set the "to"
+     value.
+     This function can be used to change an option into another that has a
+     different type.
+
+     "mergeFn" takes the module "config" as a parameter and must return a value of
+     "to" option type.
+
+       mkChangedOptionModule [ "a" "b" "c" ] [ "x" "y" "z" ]
+         (config:
+           let value = getAttrFromPath [ "a" "b" "c" ] config;
+           in
+           if   value > 100 then "high"
+           else "normal")
+
+     - options.a.b.c is a removed int option
+     - options.x.y.z is a new str option that supersedes a.b.c
+
+     This show a warning if a.b.c is set, and set the value of x.y.z to the
+     result of the change function
+  */
+  mkChangedOptionModule = from: to: changeFn:
+    mkMergedOptionModule [ from ] to changeFn;
+
+  /* Like ‘mkRenamedOptionModule’, but doesn't show a warning. */
+  mkAliasOptionModule = from: to: doRename {
+    inherit from to;
+    visible = true;
+    warn = false;
+    use = id;
+  };
+
+  doRename = { from, to, visible, warn, use }:
+    { config, options, ... }:
+    let
+      fromOpt = getAttrFromPath from options;
+      toOf = attrByPath to
+        (abort "Renaming error: option `${showOption to}' does not exist.");
+    in
+    {
+      options = setAttrByPath from (mkOption {
+        inherit visible;
+        description = "Alias of <option>${showOption to}</option>.";
+        apply = x: use (toOf config);
+      });
+      config = mkMerge [
+        {
+          warnings = optional (warn && fromOpt.isDefined)
+            "The option `${showOption from}' defined in ${showFiles fromOpt.files} has been renamed to `${showOption to}'.";
+        }
+        (mkAliasAndWrapDefinitions (setAttrByPath to) fromOpt)
+      ];
+    };
+
+}
diff --git a/nixpkgs/lib/options.nix b/nixpkgs/lib/options.nix
new file mode 100644
index 000000000000..791930eafbd0
--- /dev/null
+++ b/nixpkgs/lib/options.nix
@@ -0,0 +1,207 @@
+# Nixpkgs/NixOS option handling.
+{ lib }:
+
+with lib.trivial;
+with lib.lists;
+with lib.attrsets;
+with lib.strings;
+
+rec {
+
+  /* Returns true when the given argument is an option
+
+     Type: isOption :: a -> bool
+
+     Example:
+       isOption 1             // => false
+       isOption (mkOption {}) // => true
+  */
+  isOption = lib.isType "option";
+
+  /* Creates an Option attribute set. mkOption accepts an attribute set with the following keys:
+
+     All keys default to `null` when not given.
+
+     Example:
+       mkOption { }  // => { _type = "option"; }
+       mkOption { defaultText = "foo"; } // => { _type = "option"; defaultText = "foo"; }
+  */
+  mkOption =
+    {
+    # Default value used when no definition is given in the configuration.
+    default ? null,
+    # Textual representation of the default, for the manual.
+    defaultText ? null,
+    # Example value used in the manual.
+    example ? null,
+    # String describing the option.
+    description ? null,
+    # Related packages used in the manual (see `genRelatedPackages` in ../nixos/doc/manual/default.nix).
+    relatedPackages ? null,
+    # Option type, providing type-checking and value merging.
+    type ? null,
+    # Function that converts the option value to something else.
+    apply ? null,
+    # Whether the option is for NixOS developers only.
+    internal ? null,
+    # Whether the option shows up in the manual.
+    visible ? null,
+    # Whether the option can be set only once
+    readOnly ? null,
+    # Obsolete, used by types.optionSet.
+    options ? null
+    } @ attrs:
+    attrs // { _type = "option"; };
+
+  /* Creates an Option attribute set for a boolean value option i.e an
+     option to be toggled on or off:
+
+     Example:
+       mkEnableOption "foo"
+       => { _type = "option"; default = false; description = "Whether to enable foo."; example = true; type = { ... }; }
+  */
+  mkEnableOption =
+    # Name for the created option
+    name: mkOption {
+    default = false;
+    example = true;
+    description = "Whether to enable ${name}.";
+    type = lib.types.bool;
+  };
+
+  /* This option accepts anything, but it does not produce any result.
+
+     This is useful for sharing a module across different module sets
+     without having to implement similar features as long as the
+     values of the options are not accessed. */
+  mkSinkUndeclaredOptions = attrs: mkOption ({
+    internal = true;
+    visible = false;
+    default = false;
+    description = "Sink for option definitions.";
+    type = mkOptionType {
+      name = "sink";
+      check = x: true;
+      merge = loc: defs: false;
+    };
+    apply = x: throw "Option value is not readable because the option is not declared.";
+  } // attrs);
+
+  mergeDefaultOption = loc: defs:
+    let list = getValues defs; in
+    if length list == 1 then head list
+    else if all isFunction list then x: mergeDefaultOption loc (map (f: f x) list)
+    else if all isList list then concatLists list
+    else if all isAttrs list then foldl' lib.mergeAttrs {} list
+    else if all isBool list then foldl' lib.or false list
+    else if all isString list then lib.concatStrings list
+    else if all isInt list && all (x: x == head list) list then head list
+    else throw "Cannot merge definitions of `${showOption loc}' given in ${showFiles (getFiles defs)}.";
+
+  mergeOneOption = loc: defs:
+    if defs == [] then abort "This case should never happen."
+    else if length defs != 1 then
+      throw "The unique option `${showOption loc}' is defined multiple times, in ${showFiles (getFiles defs)}."
+    else (head defs).value;
+
+  /* "Merge" option definitions by checking that they all have the same value. */
+  mergeEqualOption = loc: defs:
+    if defs == [] then abort "This case should never happen."
+    else foldl' (val: def:
+      if def.value != val then
+        throw "The option `${showOption loc}' has conflicting definitions, in ${showFiles (getFiles defs)}."
+      else
+        val) (head defs).value defs;
+
+  /* Extracts values of all "value" keys of the given list.
+
+     Type: getValues :: [ { value :: a } ] -> [a]
+
+     Example:
+       getValues [ { value = 1; } { value = 2; } ] // => [ 1 2 ]
+       getValues [ ]                               // => [ ]
+  */
+  getValues = map (x: x.value);
+
+  /* Extracts values of all "file" keys of the given list
+
+     Type: getFiles :: [ { file :: a } ] -> [a]
+
+     Example:
+       getFiles [ { file = "file1"; } { file = "file2"; } ] // => [ "file1" "file2" ]
+       getFiles [ ]                                         // => [ ]
+  */
+  getFiles = map (x: x.file);
+
+  # Generate documentation template from the list of option declaration like
+  # the set generated with filterOptionSets.
+  optionAttrSetToDocList = optionAttrSetToDocList' [];
+
+  optionAttrSetToDocList' = prefix: options:
+    concatMap (opt:
+      let
+        docOption = rec {
+          loc = opt.loc;
+          name = showOption opt.loc;
+          description = opt.description or (throw "Option `${name}' has no description.");
+          declarations = filter (x: x != unknownModule) opt.declarations;
+          internal = opt.internal or false;
+          visible = opt.visible or true;
+          readOnly = opt.readOnly or false;
+          type = opt.type.description or null;
+        }
+        // optionalAttrs (opt ? example) { example = scrubOptionValue opt.example; }
+        // optionalAttrs (opt ? default) { default = scrubOptionValue opt.default; }
+        // optionalAttrs (opt ? defaultText) { default = opt.defaultText; }
+        // optionalAttrs (opt ? relatedPackages && opt.relatedPackages != null) { inherit (opt) relatedPackages; };
+
+        subOptions =
+          let ss = opt.type.getSubOptions opt.loc;
+          in if ss != {} then optionAttrSetToDocList' opt.loc ss else [];
+      in
+        [ docOption ] ++ subOptions) (collect isOption options);
+
+
+  /* This function recursively removes all derivation attributes from
+     `x` except for the `name` attribute.
+
+     This is to make the generation of `options.xml` much more
+     efficient: the XML representation of derivations is very large
+     (on the order of megabytes) and is not actually used by the
+     manual generator.
+  */
+  scrubOptionValue = x:
+    if isDerivation x then
+      { type = "derivation"; drvPath = x.name; outPath = x.name; name = x.name; }
+    else if isList x then map scrubOptionValue x
+    else if isAttrs x then mapAttrs (n: v: scrubOptionValue v) (removeAttrs x ["_args"])
+    else x;
+
+
+  /* For use in the `example` option attribute. It causes the given
+     text to be included verbatim in documentation. This is necessary
+     for example values that are not simple values, e.g., functions.
+  */
+  literalExample = text: { _type = "literalExample"; inherit text; };
+
+  # Helper functions.
+
+  /* Convert an option, described as a list of the option parts in to a
+     safe, human readable version.
+
+     Example:
+       (showOption ["foo" "bar" "baz"]) == "foo.bar.baz"
+       (showOption ["foo" "bar.baz" "tux"]) == "foo.\"bar.baz\".tux"
+  */
+  showOption = parts: let
+    escapeOptionPart = part:
+      let
+        escaped = lib.strings.escapeNixString part;
+      in if escaped == "\"${part}\""
+         then part
+         else escaped;
+    in (concatStringsSep ".") (map escapeOptionPart parts);
+  showFiles = files: concatStringsSep " and " (map (f: "`${f}'") files);
+  unknownModule = "<unknown-file>";
+
+}
diff --git a/nixpkgs/lib/sources.nix b/nixpkgs/lib/sources.nix
new file mode 100644
index 000000000000..1a9f3f7d1f34
--- /dev/null
+++ b/nixpkgs/lib/sources.nix
@@ -0,0 +1,104 @@
+# Functions for copying sources to the Nix store.
+{ lib }:
+
+rec {
+
+  # Returns the type of a path: regular (for file), symlink, or directory
+  pathType = p: with builtins; getAttr (baseNameOf p) (readDir (dirOf p));
+
+  # Returns true if the path exists and is a directory, false otherwise
+  pathIsDirectory = p: if builtins.pathExists p then (pathType p) == "directory" else false;
+
+  # Bring in a path as a source, filtering out all Subversion and CVS
+  # directories, as well as backup files (*~).
+  cleanSourceFilter = name: type: let baseName = baseNameOf (toString name); in ! (
+    # Filter out Subversion and CVS directories.
+    (type == "directory" && (baseName == ".git" || baseName == ".svn" || baseName == "CVS" || baseName == ".hg")) ||
+    # Filter out editor backup / swap files.
+    lib.hasSuffix "~" baseName ||
+    builtins.match "^\\.sw[a-z]$" baseName != null ||
+    builtins.match "^\\..*\\.sw[a-z]$" baseName != null ||
+
+    # Filter out generates files.
+    lib.hasSuffix ".o" baseName ||
+    lib.hasSuffix ".so" baseName ||
+    # Filter out nix-build result symlinks
+    (type == "symlink" && lib.hasPrefix "result" baseName)
+  );
+
+  # Filters a source tree removing version control files and directories using cleanSourceWith
+  #
+  # Example:
+  #          cleanSource ./.
+  cleanSource = src: cleanSourceWith { filter = cleanSourceFilter; inherit src; };
+
+  # Like `builtins.filterSource`, except it will compose with itself,
+  # allowing you to chain multiple calls together without any
+  # intermediate copies being put in the nix store.
+  #
+  #     lib.cleanSourceWith f (lib.cleanSourceWith g ./.)     # Succeeds!
+  #     builtins.filterSource f (builtins.filterSource g ./.) # Fails!
+  cleanSourceWith = { filter, src }:
+    let
+      isFiltered = src ? _isLibCleanSourceWith;
+      origSrc = if isFiltered then src.origSrc else src;
+      filter' = if isFiltered then name: type: filter name type && src.filter name type else filter;
+    in {
+      inherit origSrc;
+      filter = filter';
+      outPath = builtins.filterSource filter' origSrc;
+      _isLibCleanSourceWith = true;
+    };
+
+  # Filter sources by a list of regular expressions.
+  #
+  # E.g. `src = sourceByRegex ./my-subproject [".*\.py$" "^database.sql$"]`
+  sourceByRegex = src: regexes: cleanSourceWith {
+    filter = (path: type:
+      let relPath = lib.removePrefix (toString src + "/") (toString path);
+      in lib.any (re: builtins.match re relPath != null) regexes);
+    inherit src;
+  };
+
+  # Get all files ending with the specified suffices from the given
+  # directory or its descendants.  E.g. `sourceFilesBySuffices ./dir
+  # [".xml" ".c"]'.
+  sourceFilesBySuffices = path: exts:
+    let filter = name: type:
+      let base = baseNameOf (toString name);
+      in type == "directory" || lib.any (ext: lib.hasSuffix ext base) exts;
+    in cleanSourceWith { inherit filter; src = path; };
+
+
+  # Get the commit id of a git repo
+  # Example: commitIdFromGitRepo <nixpkgs/.git>
+  commitIdFromGitRepo =
+    let readCommitFromFile = file: path:
+      with builtins;
+        let fileName       = toString path + "/" + file;
+            packedRefsName = toString path + "/packed-refs";
+        in if lib.pathExists fileName
+           then
+             let fileContent = lib.fileContents fileName;
+                 # Sometimes git stores the commitId directly in the file but
+                 # sometimes it stores something like: «ref: refs/heads/branch-name»
+                 matchRef    = match "^ref: (.*)$" fileContent;
+             in if   isNull matchRef
+                then fileContent
+                else readCommitFromFile (lib.head matchRef) path
+           # Sometimes, the file isn't there at all and has been packed away in the
+           # packed-refs file, so we have to grep through it:
+           else if lib.pathExists packedRefsName
+           then
+             let fileContent = readFile packedRefsName;
+                 matchRef    = match (".*\n([^\n ]*) " + file + "\n.*") fileContent;
+             in if   isNull matchRef
+                then throw ("Could not find " + file + " in " + packedRefsName)
+                else lib.head matchRef
+           else throw ("Not a .git directory: " + path);
+    in readCommitFromFile "HEAD";
+
+  pathHasContext = builtins.hasContext or (lib.hasPrefix builtins.storeDir);
+
+  canCleanSource = src: src ? _isLibCleanSourceWith || !(pathHasContext (toString src));
+}
diff --git a/nixpkgs/lib/strings-with-deps.nix b/nixpkgs/lib/strings-with-deps.nix
new file mode 100644
index 000000000000..e3336983428f
--- /dev/null
+++ b/nixpkgs/lib/strings-with-deps.nix
@@ -0,0 +1,79 @@
+{ lib }:
+/*
+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
+
+  Attention:
+
+  let
+    pkgs = (import <nixpkgs>) {};
+  in let
+    inherit (pkgs.stringsWithDeps) fullDepEntry packEntry noDepEntry textClosureMap;
+    inherit (pkgs.lib) id;
+
+    nameA = noDepEntry "Text a";
+    nameB = fullDepEntry "Text b" ["nameA"];
+    nameC = fullDepEntry "Text c" ["nameA"];
+
+    stages = {
+      nameHeader = noDepEntry "#! /bin/sh \n";
+      inherit nameA nameB nameC;
+    };
+  in
+    textClosureMap id stages
+    [ "nameHeader" "nameA" "nameB" "nameC"
+      nameC # <- added twice. add a dep entry if you know that it will be added once only [1]
+      "nameB" # <- this will not be added again because the attr name (reference) is used
+    ]
+
+  # result: Str("#! /bin/sh \n\nText a\nText b\nText c\nText c",[])
+
+  [1] maybe this behaviour should be removed to keep things simple (?)
+*/
+
+with lib.lists;
+with lib.attrsets;
+with lib.strings;
+
+rec {
+
+  /* !!! The interface of this function is kind of messed up, since
+     it's way too overloaded and almost but not quite computes a
+     topological sort of the depstrings. */
+
+  textClosureList = predefined: arg:
+    let
+      f = done: todo:
+        if todo == [] then {result = []; inherit done;}
+        else
+          let entry = head todo; in
+          if isAttrs entry then
+            let x = f done entry.deps;
+                y = f x.done (tail todo);
+            in { result = x.result ++ [entry.text] ++ y.result;
+                 done = y.done;
+               }
+          else if done ? ${entry} then f done (tail todo)
+          else f (done // listToAttrs [{name = entry; value = 1;}]) ([predefined.${entry}] ++ tail todo);
+    in (f {} arg).result;
+
+  textClosureMap = f: predefined: names:
+    concatStringsSep "\n" (map f (textClosureList predefined names));
+
+  noDepEntry = text: {inherit text; deps = [];};
+  fullDepEntry = text: deps: {inherit text deps;};
+  packEntry = deps: {inherit deps; text="";};
+
+  stringAfter = deps: text: { inherit text deps; };
+
+}
diff --git a/nixpkgs/lib/strings.nix b/nixpkgs/lib/strings.nix
new file mode 100644
index 000000000000..48420a367815
--- /dev/null
+++ b/nixpkgs/lib/strings.nix
@@ -0,0 +1,684 @@
+/* String manipulation functions. */
+{ lib }:
+let
+
+inherit (builtins) length;
+
+in
+
+rec {
+
+  inherit (builtins) stringLength substring head tail isString replaceStrings;
+
+  /* Concatenate a list of strings.
+
+    Type: concatStrings :: [string] -> string
+
+     Example:
+       concatStrings ["foo" "bar"]
+       => "foobar"
+  */
+  concatStrings = builtins.concatStringsSep "";
+
+  /* Map a function over a list and concatenate the resulting strings.
+
+    Type: concatMapStrings :: (a -> string) -> [a] -> string
+
+     Example:
+       concatMapStrings (x: "a" + x) ["foo" "bar"]
+       => "afooabar"
+  */
+  concatMapStrings = f: list: concatStrings (map f list);
+
+  /* Like `concatMapStrings` except that the f functions also gets the
+     position as a parameter.
+
+     Type: concatImapStrings :: (int -> a -> string) -> [a] -> string
+
+     Example:
+       concatImapStrings (pos: x: "${toString pos}-${x}") ["foo" "bar"]
+       => "1-foo2-bar"
+  */
+  concatImapStrings = f: list: concatStrings (lib.imap1 f list);
+
+  /* Place an element between each element of a list
+
+     Type: intersperse :: a -> [a] -> [a]
+
+     Example:
+       intersperse "/" ["usr" "local" "bin"]
+       => ["usr" "/" "local" "/" "bin"].
+  */
+  intersperse =
+    # Separator to add between elements
+    separator:
+    # Input list
+    list:
+    if list == [] || length list == 1
+    then list
+    else tail (lib.concatMap (x: [separator x]) list);
+
+  /* Concatenate a list of strings with a separator between each element
+
+     Type: concatStringsSep :: string -> [string] -> string
+
+     Example:
+        concatStringsSep "/" ["usr" "local" "bin"]
+        => "usr/local/bin"
+  */
+  concatStringsSep = builtins.concatStringsSep or (separator: list:
+    concatStrings (intersperse separator list));
+
+  /* Maps a function over a list of strings and then concatenates the
+     result with the specified separator interspersed between
+     elements.
+
+     Type: concatMapStringsSep :: string -> (string -> string) -> [string] -> string
+
+     Example:
+        concatMapStringsSep "-" (x: toUpper x)  ["foo" "bar" "baz"]
+        => "FOO-BAR-BAZ"
+  */
+  concatMapStringsSep =
+    # Separator to add between elements
+    sep:
+    # Function to map over the list
+    f:
+    # List of input strings
+    list: concatStringsSep sep (map f list);
+
+  /* Same as `concatMapStringsSep`, but the mapping function
+     additionally receives the position of its argument.
+
+     Type: concatMapStringsSep :: string -> (int -> string -> string) -> [string] -> string
+
+     Example:
+       concatImapStringsSep "-" (pos: x: toString (x / pos)) [ 6 6 6 ]
+       => "6-3-2"
+  */
+  concatImapStringsSep =
+    # Separator to add between elements
+    sep:
+    # Function that receives elements and their positions
+    f:
+    # List of input strings
+    list: concatStringsSep sep (lib.imap1 f list);
+
+  /* Construct a Unix-style, colon-separated search path consisting of
+     the given `subDir` appended to each of the given paths.
+
+     Type: makeSearchPath :: string -> [string] -> string
+
+     Example:
+       makeSearchPath "bin" ["/root" "/usr" "/usr/local"]
+       => "/root/bin:/usr/bin:/usr/local/bin"
+       makeSearchPath "bin" [""]
+       => "/bin"
+  */
+  makeSearchPath =
+    # Directory name to append
+    subDir:
+    # List of base paths
+    paths:
+    concatStringsSep ":" (map (path: path + "/" + subDir) (builtins.filter (x: x != null) paths));
+
+  /* Construct a Unix-style search path by appending the given
+     `subDir` to the specified `output` of each of the packages. If no
+     output by the given name is found, fallback to `.out` and then to
+     the default.
+
+     Type: string -> string -> [package] -> string
+
+     Example:
+       makeSearchPathOutput "dev" "bin" [ pkgs.openssl pkgs.zlib ]
+       => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-dev/bin:/nix/store/wwh7mhwh269sfjkm6k5665b5kgp7jrk2-zlib-1.2.8/bin"
+  */
+  makeSearchPathOutput =
+    # Package output to use
+    output:
+    # Directory name to append
+    subDir:
+    # List of packages
+    pkgs: makeSearchPath subDir (map (lib.getOutput output) pkgs);
+
+  /* Construct a library search path (such as RPATH) containing the
+     libraries for a set of packages
+
+     Example:
+       makeLibraryPath [ "/usr" "/usr/local" ]
+       => "/usr/lib:/usr/local/lib"
+       pkgs = import <nixpkgs> { }
+       makeLibraryPath [ pkgs.openssl pkgs.zlib ]
+       => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r/lib:/nix/store/wwh7mhwh269sfjkm6k5665b5kgp7jrk2-zlib-1.2.8/lib"
+  */
+  makeLibraryPath = makeSearchPathOutput "lib" "lib";
+
+  /* Construct a binary search path (such as $PATH) containing the
+     binaries for a set of packages.
+
+     Example:
+       makeBinPath ["/root" "/usr" "/usr/local"]
+       => "/root/bin:/usr/bin:/usr/local/bin"
+  */
+  makeBinPath = makeSearchPathOutput "bin" "bin";
+
+
+  /* Construct a perl search path (such as $PERL5LIB)
+
+     Example:
+       pkgs = import <nixpkgs> { }
+       makePerlPath [ pkgs.perlPackages.libnet ]
+       => "/nix/store/n0m1fk9c960d8wlrs62sncnadygqqc6y-perl-Net-SMTP-1.25/lib/perl5/site_perl"
+  */
+  # FIXME(zimbatm): this should be moved in perl-specific code
+  makePerlPath = makeSearchPathOutput "lib" "lib/perl5/site_perl";
+
+  /* Construct a perl search path recursively including all dependencies (such as $PERL5LIB)
+
+     Example:
+       pkgs = import <nixpkgs> { }
+       makeFullPerlPath [ pkgs.perlPackages.CGI ]
+       => "/nix/store/fddivfrdc1xql02h9q500fpnqy12c74n-perl-CGI-4.38/lib/perl5/site_perl:/nix/store/8hsvdalmsxqkjg0c5ifigpf31vc4vsy2-perl-HTML-Parser-3.72/lib/perl5/site_perl:/nix/store/zhc7wh0xl8hz3y3f71nhlw1559iyvzld-perl-HTML-Tagset-3.20/lib/perl5/site_perl"
+  */
+  makeFullPerlPath = deps: makePerlPath (lib.misc.closePropagation deps);
+
+  /* Depending on the boolean `cond', return either the given string
+     or the empty string. Useful to concatenate against a bigger string.
+
+     Type: optionalString :: bool -> string -> string
+
+     Example:
+       optionalString true "some-string"
+       => "some-string"
+       optionalString false "some-string"
+       => ""
+  */
+  optionalString =
+    # Condition
+    cond:
+    # String to return if condition is true
+    string: if cond then string else "";
+
+  /* Determine whether a string has given prefix.
+
+     Type: hasPrefix :: string -> string -> bool
+
+     Example:
+       hasPrefix "foo" "foobar"
+       => true
+       hasPrefix "foo" "barfoo"
+       => false
+  */
+  hasPrefix =
+    # Prefix to check for
+    pref:
+    # Input string
+    str: substring 0 (stringLength pref) str == pref;
+
+  /* Determine whether a string has given suffix.
+
+     Type: hasSuffix :: string -> string -> bool
+
+     Example:
+       hasSuffix "foo" "foobar"
+       => false
+       hasSuffix "foo" "barfoo"
+       => true
+  */
+  hasSuffix =
+    # Suffix to check for
+    suffix:
+    # Input string
+    content:
+    let
+      lenContent = stringLength content;
+      lenSuffix = stringLength suffix;
+    in lenContent >= lenSuffix &&
+       substring (lenContent - lenSuffix) lenContent content == suffix;
+
+  /* Determine whether a string contains the given infix
+
+    Type: hasInfix :: string -> string -> bool
+
+    Example:
+      hasInfix "bc" "abcd"
+      => true
+      hasInfix "ab" "abcd"
+      => true
+      hasInfix "cd" "abcd"
+      => true
+      hasInfix "foo" "abcd"
+      => false
+  */
+  hasInfix = infix: content:
+    let
+      drop = x: substring 1 (stringLength x) x;
+    in hasPrefix infix content
+      || content != "" && hasInfix infix (drop content);
+
+  /* Convert a string to a list of characters (i.e. singleton strings).
+     This allows you to, e.g., map a function over each character.  However,
+     note that this will likely be horribly inefficient; Nix is not a
+     general purpose programming language. Complex string manipulations
+     should, if appropriate, be done in a derivation.
+     Also note that Nix treats strings as a list of bytes and thus doesn't
+     handle unicode.
+
+     Type: stringtoCharacters :: string -> [string]
+
+     Example:
+       stringToCharacters ""
+       => [ ]
+       stringToCharacters "abc"
+       => [ "a" "b" "c" ]
+       stringToCharacters "💩"
+       => [ "�" "�" "�" "�" ]
+  */
+  stringToCharacters = s:
+    map (p: substring p 1 s) (lib.range 0 (stringLength s - 1));
+
+  /* Manipulate a string character by character and replace them by
+     strings before concatenating the results.
+
+     Type: stringAsChars :: (string -> string) -> string -> string
+
+     Example:
+       stringAsChars (x: if x == "a" then "i" else x) "nax"
+       => "nix"
+  */
+  stringAsChars =
+    # Function to map over each individual character
+    f:
+    # Input string
+    s: concatStrings (
+      map f (stringToCharacters s)
+    );
+
+  /* Escape occurrence of the elements of `list` in `string` by
+     prefixing it with a backslash.
+
+     Type: escape :: [string] -> string -> string
+
+     Example:
+       escape ["(" ")"] "(foo)"
+       => "\\(foo\\)"
+  */
+  escape = list: replaceChars list (map (c: "\\${c}") list);
+
+  /* Quote string to be used safely within the Bourne shell.
+
+     Type: escapeShellArg :: string -> string
+
+     Example:
+       escapeShellArg "esc'ape\nme"
+       => "'esc'\\''ape\nme'"
+  */
+  escapeShellArg = arg: "'${replaceStrings ["'"] ["'\\''"] (toString arg)}'";
+
+  /* Quote all arguments to be safely passed to the Bourne shell.
+
+     Type: escapeShellArgs :: [string] -> string
+
+     Example:
+       escapeShellArgs ["one" "two three" "four'five"]
+       => "'one' 'two three' 'four'\\''five'"
+  */
+  escapeShellArgs = concatMapStringsSep " " escapeShellArg;
+
+  /* Turn a string into a Nix expression representing that string
+
+     Type: string -> string
+
+     Example:
+       escapeNixString "hello\${}\n"
+       => "\"hello\\\${}\\n\""
+  */
+  escapeNixString = s: escape ["$"] (builtins.toJSON s);
+
+  # Obsolete - use replaceStrings instead.
+  replaceChars = builtins.replaceStrings or (
+    del: new: s:
+    let
+      substList = lib.zipLists del new;
+      subst = c:
+        let found = lib.findFirst (sub: sub.fst == c) null substList; in
+        if found == null then
+          c
+        else
+          found.snd;
+    in
+      stringAsChars subst s);
+
+  # Case conversion utilities.
+  lowerChars = stringToCharacters "abcdefghijklmnopqrstuvwxyz";
+  upperChars = stringToCharacters "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+  /* Converts an ASCII string to lower-case.
+
+     Type: toLower :: string -> string
+
+     Example:
+       toLower "HOME"
+       => "home"
+  */
+  toLower = replaceChars upperChars lowerChars;
+
+  /* Converts an ASCII string to upper-case.
+
+     Type: toUpper :: string -> string
+
+     Example:
+       toUpper "home"
+       => "HOME"
+  */
+  toUpper = replaceChars lowerChars upperChars;
+
+  /* Appends string context from another string.  This is an implementation
+     detail of Nix.
+
+     Strings in Nix carry an invisible `context` which is a list of strings
+     representing store paths.  If the string is later used in a derivation
+     attribute, the derivation will properly populate the inputDrvs and
+     inputSrcs.
+
+     Example:
+       pkgs = import <nixpkgs> { };
+       addContextFrom pkgs.coreutils "bar"
+       => "bar"
+  */
+  addContextFrom = a: b: substring 0 0 a + b;
+
+  /* Cut a string with a separator and produces a list of strings which
+     were separated by this separator.
+
+     NOTE: this function is not performant and should never be used.
+
+     Example:
+       splitString "." "foo.bar.baz"
+       => [ "foo" "bar" "baz" ]
+       splitString "/" "/usr/local/bin"
+       => [ "" "usr" "local" "bin" ]
+  */
+  splitString = _sep: _s:
+    let
+      sep = addContextFrom _s _sep;
+      s = addContextFrom _sep _s;
+      sepLen = stringLength sep;
+      sLen = stringLength s;
+      lastSearch = sLen - sepLen;
+      startWithSep = startAt:
+        substring startAt sepLen s == sep;
+
+      recurse = index: startAt:
+        let cutUntil = i: [(substring startAt (i - startAt) s)]; in
+        if index <= lastSearch then
+          if startWithSep index then
+            let restartAt = index + sepLen; in
+            cutUntil index ++ recurse restartAt restartAt
+          else
+            recurse (index + 1) startAt
+        else
+          cutUntil sLen;
+    in
+      recurse 0 0;
+
+  /* Return a string without the specified prefix, if the prefix matches.
+
+     Type: string -> string -> string
+
+     Example:
+       removePrefix "foo." "foo.bar.baz"
+       => "bar.baz"
+       removePrefix "xxx" "foo.bar.baz"
+       => "foo.bar.baz"
+  */
+  removePrefix =
+    # Prefix to remove if it matches
+    prefix:
+    # Input string
+    str:
+    let
+      preLen = stringLength prefix;
+      sLen = stringLength str;
+    in
+      if hasPrefix prefix str then
+        substring preLen (sLen - preLen) str
+      else
+        str;
+
+  /* Return a string without the specified suffix, if the suffix matches.
+
+     Type: string -> string -> string
+
+     Example:
+       removeSuffix "front" "homefront"
+       => "home"
+       removeSuffix "xxx" "homefront"
+       => "homefront"
+  */
+  removeSuffix =
+    # Suffix to remove if it matches
+    suffix:
+    # Input string
+    str:
+    let
+      sufLen = stringLength suffix;
+      sLen = stringLength str;
+    in
+      if sufLen <= sLen && suffix == substring (sLen - sufLen) sufLen str then
+        substring 0 (sLen - sufLen) str
+      else
+        str;
+
+  /* Return true if string v1 denotes a version older than v2.
+
+     Example:
+       versionOlder "1.1" "1.2"
+       => true
+       versionOlder "1.1" "1.1"
+       => false
+  */
+  versionOlder = v1: v2: builtins.compareVersions v2 v1 == 1;
+
+  /* Return true if string v1 denotes a version equal to or newer than v2.
+
+     Example:
+       versionAtLeast "1.1" "1.0"
+       => true
+       versionAtLeast "1.1" "1.1"
+       => true
+       versionAtLeast "1.1" "1.2"
+       => false
+  */
+  versionAtLeast = v1: v2: !versionOlder v1 v2;
+
+  /* This function takes an argument that's either a derivation or a
+     derivation's "name" attribute and extracts the version part from that
+     argument.
+
+     Example:
+       getVersion "youtube-dl-2016.01.01"
+       => "2016.01.01"
+       getVersion pkgs.youtube-dl
+       => "2016.01.01"
+  */
+  getVersion = x:
+   let
+     parse = drv: (builtins.parseDrvName drv).version;
+   in if isString x
+      then parse x
+      else x.version or (parse x.name);
+
+  /* Extract name with version from URL. Ask for separator which is
+     supposed to start extension.
+
+     Example:
+       nameFromURL "https://nixos.org/releases/nix/nix-1.7/nix-1.7-x86_64-linux.tar.bz2" "-"
+       => "nix"
+       nameFromURL "https://nixos.org/releases/nix/nix-1.7/nix-1.7-x86_64-linux.tar.bz2" "_"
+       => "nix-1.7-x86"
+  */
+  nameFromURL = url: sep:
+    let
+      components = splitString "/" url;
+      filename = lib.last components;
+      name = builtins.head (splitString sep filename);
+    in assert name != filename; name;
+
+  /* Create an --{enable,disable}-<feat> string that can be passed to
+     standard GNU Autoconf scripts.
+
+     Example:
+       enableFeature true "shared"
+       => "--enable-shared"
+       enableFeature false "shared"
+       => "--disable-shared"
+  */
+  enableFeature = enable: feat: "--${if enable then "enable" else "disable"}-${feat}";
+
+  /* Create an --{enable-<feat>=<value>,disable-<feat>} string that can be passed to
+     standard GNU Autoconf scripts.
+
+     Example:
+       enableFeature true "shared" "foo"
+       => "--enable-shared=foo"
+       enableFeature false "shared" (throw "ignored")
+       => "--disable-shared"
+  */
+  enableFeatureAs = enable: feat: value: enableFeature enable feat + optionalString enable "=${value}";
+
+  /* Create an --{with,without}-<feat> string that can be passed to
+     standard GNU Autoconf scripts.
+
+     Example:
+       withFeature true "shared"
+       => "--with-shared"
+       withFeature false "shared"
+       => "--without-shared"
+  */
+  withFeature = with_: feat: "--${if with_ then "with" else "without"}-${feat}";
+
+  /* Create an --{with-<feat>=<value>,without-<feat>} string that can be passed to
+     standard GNU Autoconf scripts.
+
+     Example:
+       with_Feature true "shared" "foo"
+       => "--with-shared=foo"
+       with_Feature false "shared" (throw "ignored")
+       => "--without-shared"
+  */
+  withFeatureAs = with_: feat: value: withFeature with_ feat + optionalString with_ "=${value}";
+
+  /* Create a fixed width string with additional prefix to match
+     required width.
+
+     This function will fail if the input string is longer than the
+     requested length.
+
+     Type: fixedWidthString :: int -> string -> string
+
+     Example:
+       fixedWidthString 5 "0" (toString 15)
+       => "00015"
+  */
+  fixedWidthString = width: filler: str:
+    let
+      strw = lib.stringLength str;
+      reqWidth = width - (lib.stringLength filler);
+    in
+      assert lib.assertMsg (strw <= width)
+        "fixedWidthString: requested string length (${
+          toString width}) must not be shorter than actual length (${
+            toString strw})";
+      if strw == width then str else filler + fixedWidthString reqWidth filler str;
+
+  /* Format a number adding leading zeroes up to fixed width.
+
+     Example:
+       fixedWidthNumber 5 15
+       => "00015"
+  */
+  fixedWidthNumber = width: n: fixedWidthString width "0" (toString n);
+
+  /* Check whether a value can be coerced to a string */
+  isCoercibleToString = x:
+    builtins.elem (builtins.typeOf x) [ "path" "string" "null" "int" "float" "bool" ] ||
+    (builtins.isList x && lib.all isCoercibleToString x) ||
+    x ? outPath ||
+    x ? __toString;
+
+  /* Check whether a value is a store path.
+
+     Example:
+       isStorePath "/nix/store/d945ibfx9x185xf04b890y4f9g3cbb63-python-2.7.11/bin/python"
+       => false
+       isStorePath "/nix/store/d945ibfx9x185xf04b890y4f9g3cbb63-python-2.7.11/"
+       => true
+       isStorePath pkgs.python
+       => true
+       isStorePath [] || isStorePath 42 || isStorePath {} || …
+       => false
+  */
+  isStorePath = x:
+    if isCoercibleToString x then
+      let str = toString x; in
+      builtins.substring 0 1 str == "/"
+      && dirOf str == builtins.storeDir
+    else
+      false;
+
+  /* Parse a string string as an int.
+
+     Type: string -> int
+
+     Example:
+       toInt "1337"
+       => 1337
+       toInt "-4"
+       => -4
+       toInt "3.14"
+       => error: floating point JSON numbers are not supported
+  */
+  # Obviously, it is a bit hacky to use fromJSON this way.
+  toInt = str:
+    let may_be_int = builtins.fromJSON str; in
+    if builtins.isInt may_be_int
+    then may_be_int
+    else throw "Could not convert ${str} to int.";
+
+  /* Read a list of paths from `file`, relative to the `rootPath`.
+     Lines beginning with `#` are treated as comments and ignored.
+     Whitespace is significant.
+
+     NOTE: This function is not performant and should be avoided.
+
+     Example:
+       readPathsFromFile /prefix
+         ./pkgs/development/libraries/qt-5/5.4/qtbase/series
+       => [ "/prefix/dlopen-resolv.patch" "/prefix/tzdir.patch"
+            "/prefix/dlopen-libXcursor.patch" "/prefix/dlopen-openssl.patch"
+            "/prefix/dlopen-dbus.patch" "/prefix/xdg-config-dirs.patch"
+            "/prefix/nix-profiles-library-paths.patch"
+            "/prefix/compose-search-path.patch" ]
+  */
+  readPathsFromFile = rootPath: file:
+    let
+      lines = lib.splitString "\n" (builtins.readFile file);
+      removeComments = lib.filter (line: line != "" && !(lib.hasPrefix "#" line));
+      relativePaths = removeComments lines;
+      absolutePaths = builtins.map (path: rootPath + "/${path}") relativePaths;
+    in
+      absolutePaths;
+
+  /* Read the contents of a file removing the trailing \n
+
+     Type: fileContents :: path -> string
+
+     Example:
+       $ echo "1.0" > ./version
+
+       fileContents ./version
+       => "1.0"
+  */
+  fileContents = file: removeSuffix "\n" (builtins.readFile file);
+}
diff --git a/nixpkgs/lib/systems/default.nix b/nixpkgs/lib/systems/default.nix
new file mode 100644
index 000000000000..25df5e174069
--- /dev/null
+++ b/nixpkgs/lib/systems/default.nix
@@ -0,0 +1,120 @@
+{ lib }:
+  let inherit (lib.attrsets) mapAttrs; in
+
+rec {
+  doubles = import ./doubles.nix { inherit lib; };
+  forMeta = import ./for-meta.nix { inherit lib; };
+  parse = import ./parse.nix { inherit lib; };
+  inspect = import ./inspect.nix { inherit lib; };
+  platforms = import ./platforms.nix { inherit lib; };
+  examples = import ./examples.nix { inherit lib; };
+
+  # Elaborate a `localSystem` or `crossSystem` so that it contains everything
+  # necessary.
+  #
+  # `parsed` is inferred from args, both because there are two options with one
+  # clearly prefered, and to prevent cycles. A simpler fixed point where the RHS
+  # always just used `final.*` would fail on both counts.
+  elaborate = args: let
+    final = {
+      # Prefer to parse `config` as it is strictly more informative.
+      parsed = parse.mkSystemFromString (if args ? config then args.config else args.system);
+      # Either of these can be losslessly-extracted from `parsed` iff parsing succeeds.
+      system = parse.doubleFromSystem final.parsed;
+      config = parse.tripleFromSystem final.parsed;
+      # Just a guess, based on `system`
+      platform = platforms.selectBySystem final.system;
+      # Derived meta-data
+      libc =
+        /**/ if final.isDarwin              then "libSystem"
+        else if final.isMinGW               then "msvcrt"
+        else if final.isMusl                then "musl"
+        else if final.isUClibc              then "uclibc"
+        else if final.isAndroid             then "bionic"
+        else if final.isLinux /* default */ then "glibc"
+        else if final.isAvr                 then "avrlibc"
+        # TODO(@Ericson2314) think more about other operating systems
+        else                                     "native/impure";
+      extensions = {
+        sharedLibrary =
+          /**/ if final.isDarwin  then ".dylib"
+          else if final.isWindows then ".dll"
+          else                         ".so";
+        executable =
+          /**/ if final.isWindows then ".exe"
+          else                         "";
+      };
+      # Misc boolean options
+      useAndroidPrebuilt = false;
+      useiOSPrebuilt = false;
+
+      # Output from uname
+      uname = {
+        # uname -s
+        system = {
+          "linux" = "Linux";
+          "windows" = "Windows";
+          "darwin" = "Darwin";
+          "netbsd" = "NetBSD";
+          "freebsd" = "FreeBSD";
+          "openbsd" = "OpenBSD";
+        }.${final.parsed.kernel.name} or null;
+
+         # uname -p
+         processor = final.parsed.cpu.name;
+
+         # uname -r
+         release = null;
+      };
+
+      qemuArch =
+        if final.isArm then "arm"
+        else if final.isx86_64 then "x86_64"
+        else if final.isx86 then "i386"
+        else {
+          "powerpc" = "ppc";
+          "powerpc64" = "ppc64";
+          "powerpc64le" = "ppc64";
+          "mips64" = "mips";
+          "mipsel64" = "mipsel";
+        }.${final.parsed.cpu.name} or final.parsed.cpu.name;
+
+      emulator = pkgs: let
+        qemu-user = pkgs.qemu.override {
+          smartcardSupport = false;
+          spiceSupport = false;
+          openGLSupport = false;
+          virglSupport = false;
+          vncSupport = false;
+          gtkSupport = false;
+          sdlSupport = false;
+          pulseSupport = false;
+          smbdSupport = false;
+          seccompSupport = false;
+          hostCpuTargets = ["${final.qemuArch}-linux-user"];
+        };
+        wine-name = "wine${toString final.parsed.cpu.bits}";
+        wine = (pkgs.winePackagesFor wine-name).minimal;
+      in
+        if final.parsed.kernel.name == pkgs.stdenv.hostPlatform.parsed.kernel.name &&
+           (final.parsed.cpu.name == pkgs.stdenv.hostPlatform.parsed.cpu.name ||
+            (final.platform.isi686 && pkgs.stdenv.hostPlatform.isx86_64))
+        then pkgs.runtimeShell
+        else if final.isWindows
+        then "${wine}/bin/${wine-name}"
+        else if final.isLinux && pkgs.stdenv.hostPlatform.isLinux
+        then "${qemu-user}/bin/qemu-${final.qemuArch}"
+        else throw "Don't know how to run ${final.config} executables.";
+
+    } // mapAttrs (n: v: v final.parsed) inspect.predicates
+      // args;
+  in assert final.useAndroidPrebuilt -> final.isAndroid;
+     assert lib.foldl
+       (pass: { assertion, message }:
+         if assertion final
+         then pass
+         else throw message)
+       true
+       (final.parsed.abi.assertions or []);
+    final;
+}
diff --git a/nixpkgs/lib/systems/doubles.nix b/nixpkgs/lib/systems/doubles.nix
new file mode 100644
index 000000000000..58677c0bdd90
--- /dev/null
+++ b/nixpkgs/lib/systems/doubles.nix
@@ -0,0 +1,51 @@
+{ lib }:
+let
+  inherit (lib) lists;
+  inherit (lib.systems) parse;
+  inherit (lib.systems.inspect) predicates;
+  inherit (lib.attrsets) matchAttrs;
+
+  all = [
+    "aarch64-linux"
+    "armv5tel-linux" "armv6l-linux" "armv7l-linux"
+
+    "mipsel-linux"
+
+    "i686-cygwin" "i686-freebsd" "i686-linux" "i686-netbsd" "i686-openbsd"
+
+    "x86_64-cygwin" "x86_64-darwin" "x86_64-freebsd" "x86_64-linux"
+    "x86_64-netbsd" "x86_64-openbsd" "x86_64-solaris"
+
+    "x86_64-windows" "i686-windows"
+  ];
+
+  allParsed = map parse.mkSystemFromString all;
+
+  filterDoubles = f: map parse.doubleFromSystem (lists.filter f allParsed);
+
+in rec {
+  inherit all;
+
+  none = [];
+
+  arm     = filterDoubles predicates.isAarch32;
+  aarch64 = filterDoubles predicates.isAarch64;
+  x86     = filterDoubles predicates.isx86;
+  i686    = filterDoubles predicates.isi686;
+  x86_64  = filterDoubles predicates.isx86_64;
+  mips    = filterDoubles predicates.isMips;
+
+  cygwin  = filterDoubles predicates.isCygwin;
+  darwin  = filterDoubles predicates.isDarwin;
+  freebsd = filterDoubles predicates.isFreeBSD;
+  # Should be better, but MinGW is unclear.
+  gnu     = filterDoubles (matchAttrs { kernel = parse.kernels.linux; abi = parse.abis.gnu; }) ++ filterDoubles (matchAttrs { kernel = parse.kernels.linux; abi = parse.abis.gnueabi; }) ++ filterDoubles (matchAttrs { kernel = parse.kernels.linux; abi = parse.abis.gnueabihf; });
+  illumos = filterDoubles predicates.isSunOS;
+  linux   = filterDoubles predicates.isLinux;
+  netbsd  = filterDoubles predicates.isNetBSD;
+  openbsd = filterDoubles predicates.isOpenBSD;
+  unix    = filterDoubles predicates.isUnix;
+  windows = filterDoubles predicates.isWindows;
+
+  mesaPlatforms = ["i686-linux" "x86_64-linux" "x86_64-darwin" "armv5tel-linux" "armv6l-linux" "armv7l-linux" "aarch64-linux" "powerpc64le-linux"];
+}
diff --git a/nixpkgs/lib/systems/examples.nix b/nixpkgs/lib/systems/examples.nix
new file mode 100644
index 000000000000..ac1633a1a15f
--- /dev/null
+++ b/nixpkgs/lib/systems/examples.nix
@@ -0,0 +1,215 @@
+# These can be passed to nixpkgs as either the `localSystem` or
+# `crossSystem`. They are put here for user convenience, but also used by cross
+# tests and linux cross stdenv building, so handle with care!
+{ lib }:
+let
+  platforms = import ./platforms.nix { inherit lib; };
+
+  riscv = bits: {
+    config = "riscv${bits}-unknown-linux-gnu";
+    platform = platforms.riscv-multiplatform bits;
+  };
+in
+
+rec {
+  #
+  # Linux
+  #
+  powernv = {
+    config = "powerpc64le-unknown-linux-gnu";
+    platform = platforms.powernv;
+  };
+  musl-power = {
+    config = "powerpc64le-unknown-linux-musl";
+    platform = platforms.powernv;
+  };
+
+  sheevaplug = rec {
+    config = "armv5tel-unknown-linux-gnueabi";
+    platform = platforms.sheevaplug;
+  };
+
+  raspberryPi = rec {
+    config = "armv6l-unknown-linux-gnueabihf";
+    platform = platforms.raspberrypi;
+  };
+
+  armv7l-hf-multiplatform = rec {
+    config = "armv7l-unknown-linux-gnueabihf";
+    platform = platforms.armv7l-hf-multiplatform;
+  };
+
+  aarch64-multiplatform = rec {
+    config = "aarch64-unknown-linux-gnu";
+    platform = platforms.aarch64-multiplatform;
+  };
+
+  armv5te-android-prebuilt = rec {
+    config = "armv5tel-unknown-linux-androideabi";
+    sdkVer = "21";
+    ndkVer = "18b";
+    platform = platforms.armv5te-android;
+    useAndroidPrebuilt = true;
+  };
+
+  armv7a-android-prebuilt = rec {
+    config = "armv7a-unknown-linux-androideabi";
+    sdkVer = "24";
+    ndkVer = "18b";
+    platform = platforms.armv7a-android;
+    useAndroidPrebuilt = true;
+  };
+
+  aarch64-android-prebuilt = rec {
+    config = "aarch64-unknown-linux-android";
+    sdkVer = "24";
+    ndkVer = "18b";
+    platform = platforms.aarch64-multiplatform;
+    useAndroidPrebuilt = true;
+  };
+
+  scaleway-c1 = armv7l-hf-multiplatform // rec {
+    platform = platforms.scaleway-c1;
+    inherit (platform.gcc) fpu;
+  };
+
+  pogoplug4 = rec {
+    config = "armv5tel-unknown-linux-gnueabi";
+    platform = platforms.pogoplug4;
+  };
+
+  ben-nanonote = rec {
+    config = "mipsel-unknown-linux-uclibc";
+    platform = platforms.ben_nanonote;
+  };
+
+  fuloongminipc = rec {
+    config = "mipsel-unknown-linux-gnu";
+    platform = platforms.fuloong2f_n32;
+  };
+
+  muslpi = raspberryPi // {
+    config = "armv6l-unknown-linux-musleabihf";
+  };
+
+  aarch64-multiplatform-musl = aarch64-multiplatform // {
+    config = "aarch64-unknown-linux-musl";
+  };
+
+  musl64 = { config = "x86_64-unknown-linux-musl"; };
+  musl32  = { config = "i686-unknown-linux-musl"; };
+
+  riscv64 = riscv "64";
+  riscv32 = riscv "32";
+
+  avr = {
+    config = "avr";
+  };
+
+  arm-embedded = {
+    config = "arm-none-eabi";
+    libc = "newlib";
+  };
+  armhf-embedded = {
+    config = "arm-none-eabihf";
+    libc = "newlib";
+  };
+
+  aarch64-embedded = {
+    config = "aarch64-none-elf";
+    libc = "newlib";
+  };
+  
+  aarch64be-embedded = {
+    config = "aarch64_be-none-elf";
+    libc = "newlib";
+  };
+
+  ppc-embedded = {
+    config = "powerpc-none-eabi";
+    libc = "newlib";
+  };
+  
+  ppcle-embedded = {
+    config = "powerpcle-none-eabi";
+    libc = "newlib";
+  };
+  
+  alpha-embedded = {
+    config = "alpha-elf";
+    libc = "newlib";
+  };
+
+  i686-embedded = {
+    config = "i686-elf";
+    libc = "newlib";
+  };
+
+  x86_64-embedded = {
+    config = "x86_64-elf";
+    libc = "newlib";
+  };
+
+  #
+  # Darwin
+  #
+
+  iphone64 = {
+    config = "aarch64-apple-ios";
+    # config = "aarch64-apple-darwin14";
+    sdkVer = "10.2";
+    xcodeVer = "8.2";
+    xcodePlatform = "iPhoneOS";
+    useiOSPrebuilt = true;
+    platform = {};
+  };
+
+  iphone32 = {
+    config = "armv7a-apple-ios";
+    # config = "arm-apple-darwin10";
+    sdkVer = "10.2";
+    xcodeVer = "8.2";
+    xcodePlatform = "iPhoneOS";
+    useiOSPrebuilt = true;
+    platform = {};
+  };
+
+  iphone64-simulator = {
+    config = "x86_64-apple-ios";
+    # config = "x86_64-apple-darwin14";
+    sdkVer = "10.2";
+    xcodeVer = "8.2";
+    xcodePlatform = "iPhoneSimulator";
+    useiOSPrebuilt = true;
+    platform = {};
+  };
+
+  iphone32-simulator = {
+    config = "i686-apple-ios";
+    # config = "i386-apple-darwin11";
+    sdkVer = "10.2";
+    xcodeVer = "8.2";
+    xcodePlatform = "iPhoneSimulator";
+    useiOSPrebuilt = true;
+    platform = {};
+  };
+
+  #
+  # Windows
+  #
+
+  # 32 bit mingw-w64
+  mingw32 = {
+    config = "i686-pc-mingw32";
+    libc = "msvcrt"; # This distinguishes the mingw (non posix) toolchain
+    platform = {};
+  };
+
+  # 64 bit mingw-w64
+  mingwW64 = {
+    # That's the triplet they use in the mingw-w64 docs.
+    config = "x86_64-pc-mingw32";
+    libc = "msvcrt"; # This distinguishes the mingw (non posix) toolchain
+    platform = {};
+  };
+}
diff --git a/nixpkgs/lib/systems/for-meta.nix b/nixpkgs/lib/systems/for-meta.nix
new file mode 100644
index 000000000000..51fb6ae760d1
--- /dev/null
+++ b/nixpkgs/lib/systems/for-meta.nix
@@ -0,0 +1,37 @@
+{ lib }:
+let
+  inherit (lib.systems) parse;
+  inherit (lib.systems.inspect) patterns;
+
+  abis = lib.mapAttrs (_: abi: builtins.removeAttrs abi [ "assertions" ]) parse.abis;
+
+in rec {
+  all     = [ {} ]; # `{}` matches anything
+  none    = [];
+
+  arm     = [ patterns.isAarch32 ];
+  aarch64 = [ patterns.isAarch64 ];
+  x86     = [ patterns.isx86 ];
+  i686    = [ patterns.isi686 ];
+  x86_64  = [ patterns.isx86_64 ];
+  mips    = [ patterns.isMips ];
+  riscv   = [ patterns.isRiscV ];
+
+  cygwin  = [ patterns.isCygwin ];
+  darwin  = [ patterns.isDarwin ];
+  freebsd = [ patterns.isFreeBSD ];
+  # Should be better, but MinGW is unclear.
+  gnu     = [
+    { kernel = parse.kernels.linux; abi = abis.gnu; }
+    { kernel = parse.kernels.linux; abi = abis.gnueabi; }
+    { kernel = parse.kernels.linux; abi = abis.gnueabihf; }
+  ];
+  illumos = [ patterns.isSunOS ];
+  linux   = [ patterns.isLinux ];
+  netbsd  = [ patterns.isNetBSD ];
+  openbsd = [ patterns.isOpenBSD ];
+  unix    = patterns.isUnix; # Actually a list
+  windows = [ patterns.isWindows ];
+
+  inherit (lib.systems.doubles) mesaPlatforms;
+}
diff --git a/nixpkgs/lib/systems/inspect.nix b/nixpkgs/lib/systems/inspect.nix
new file mode 100644
index 000000000000..2fcf1afe4628
--- /dev/null
+++ b/nixpkgs/lib/systems/inspect.nix
@@ -0,0 +1,60 @@
+{ lib }:
+with import ./parse.nix { inherit lib; };
+with lib.attrsets;
+with lib.lists;
+
+let abis_ = abis; in
+let abis = lib.mapAttrs (_: abi: builtins.removeAttrs abi [ "assertions" ]) abis_; in
+
+rec {
+  patterns = rec {
+    isi686         = { cpu = cpuTypes.i686; };
+    isx86_64       = { cpu = cpuTypes.x86_64; };
+    isPowerPC      = { cpu = cpuTypes.powerpc; };
+    isPower = { cpu = { family = "power"; }; };
+    isx86          = { cpu = { family = "x86"; }; };
+    isAarch32      = { cpu = { family = "arm"; bits = 32; }; };
+    isAarch64      = { cpu = { family = "arm"; bits = 64; }; };
+    isMips         = { cpu = { family = "mips"; }; };
+    isRiscV        = { cpu = { family = "riscv"; }; };
+    isSparc        = { cpu = { family = "sparc"; }; };
+    isWasm         = { cpu = { family = "wasm"; }; };
+    isAvr          = { cpu = { family = "avr"; }; };
+
+    is32bit        = { cpu = { bits = 32; }; };
+    is64bit        = { cpu = { bits = 64; }; };
+    isBigEndian    = { cpu = { significantByte = significantBytes.bigEndian; }; };
+    isLittleEndian = { cpu = { significantByte = significantBytes.littleEndian; }; };
+
+    isBSD          = { kernel = { families = { inherit (kernelFamilies) bsd; }; }; };
+    isDarwin       = { kernel = { families = { inherit (kernelFamilies) darwin; }; }; };
+    isUnix         = [ isBSD isDarwin isLinux isSunOS isCygwin ];
+
+    isMacOS        = { kernel = kernels.macos; };
+    isiOS          = { kernel = kernels.ios; };
+    isLinux        = { kernel = kernels.linux; };
+    isSunOS        = { kernel = kernels.solaris; };
+    isFreeBSD      = { kernel = kernels.freebsd; };
+    isNetBSD       = { kernel = kernels.netbsd; };
+    isOpenBSD      = { kernel = kernels.openbsd; };
+    isWindows      = { kernel = kernels.windows; };
+    isCygwin       = { kernel = kernels.windows; abi = abis.cygnus; };
+    isMinGW        = { kernel = kernels.windows; abi = abis.gnu; };
+
+    isAndroid      = [ { abi = abis.android; } { abi = abis.androideabi; } ];
+    isMusl         = with abis; map (a: { abi = a; }) [ musl musleabi musleabihf ];
+    isUClibc       = with abis; map (a: { abi = a; }) [ uclibc uclibceabi uclibceabihf ];
+
+    isEfi          = map (family: { cpu.family = family; })
+                       [ "x86" "arm" "aarch64" ];
+
+    # Deprecated after 18.03
+    isArm = isAarch32;
+  };
+
+  matchAnyAttrs = patterns:
+    if builtins.isList patterns then attrs: any (pattern: matchAttrs pattern attrs) patterns
+    else matchAttrs patterns;
+
+  predicates = mapAttrs (_: matchAnyAttrs) patterns;
+}
diff --git a/nixpkgs/lib/systems/parse.nix b/nixpkgs/lib/systems/parse.nix
new file mode 100644
index 000000000000..7db09fc550e2
--- /dev/null
+++ b/nixpkgs/lib/systems/parse.nix
@@ -0,0 +1,352 @@
+# Define the list of system with their properties.
+#
+# See https://clang.llvm.org/docs/CrossCompilation.html and
+# http://llvm.org/docs/doxygen/html/Triple_8cpp_source.html especially
+# Triple::normalize. Parsing should essentially act as a more conservative
+# version of that last function.
+#
+# Most of the types below come in "open" and "closed" pairs. The open ones
+# specify what information we need to know about systems in general, and the
+# closed ones are sub-types representing the whitelist of systems we support in
+# practice.
+#
+# Code in the remainder of nixpkgs shouldn't rely on the closed ones in
+# e.g. exhaustive cases. Its more a sanity check to make sure nobody defines
+# systems that overlap with existing ones and won't notice something amiss.
+#
+{ lib }:
+with lib.lists;
+with lib.types;
+with lib.attrsets;
+with lib.strings;
+with (import ./inspect.nix { inherit lib; }).predicates;
+
+let
+  inherit (lib.options) mergeOneOption;
+
+  setTypes = type:
+    mapAttrs (name: value:
+      assert type.check value;
+      setType type.name ({ inherit name; } // value));
+
+in
+
+rec {
+
+  ################################################################################
+
+  types.openSignificantByte = mkOptionType {
+    name = "significant-byte";
+    description = "Endianness";
+    merge = mergeOneOption;
+  };
+
+  types.significantByte = enum (attrValues significantBytes);
+
+  significantBytes = setTypes types.openSignificantByte {
+    bigEndian = {};
+    littleEndian = {};
+  };
+
+  ################################################################################
+
+  # Reasonable power of 2
+  types.bitWidth = enum [ 8 16 32 64 128 ];
+
+  ################################################################################
+
+  types.openCpuType = mkOptionType {
+    name = "cpu-type";
+    description = "instruction set architecture name and information";
+    merge = mergeOneOption;
+    check = x: types.bitWidth.check x.bits
+      && (if 8 < x.bits
+          then types.significantByte.check x.significantByte
+          else !(x ? significantByte));
+  };
+
+  types.cpuType = enum (attrValues cpuTypes);
+
+  cpuTypes = with significantBytes; setTypes types.openCpuType {
+    arm      = { bits = 32; significantByte = littleEndian; family = "arm"; };
+    armv5tel = { bits = 32; significantByte = littleEndian; family = "arm"; version = "5"; };
+    armv6m   = { bits = 32; significantByte = littleEndian; family = "arm"; version = "6"; };
+    armv6l   = { bits = 32; significantByte = littleEndian; family = "arm"; version = "6"; };
+    armv7a   = { bits = 32; significantByte = littleEndian; family = "arm"; version = "7"; };
+    armv7r   = { bits = 32; significantByte = littleEndian; family = "arm"; version = "7"; };
+    armv7m   = { bits = 32; significantByte = littleEndian; family = "arm"; version = "7"; };
+    armv7l   = { bits = 32; significantByte = littleEndian; family = "arm"; version = "7"; };
+    armv8a   = { bits = 32; significantByte = littleEndian; family = "arm"; version = "8"; };
+    armv8r   = { bits = 32; significantByte = littleEndian; family = "arm"; version = "8"; };
+    armv8m   = { bits = 32; significantByte = littleEndian; family = "arm"; version = "8"; };
+    aarch64  = { bits = 64; significantByte = littleEndian; family = "arm"; version = "8"; };
+    aarch64_be = { bits = 64; significantByte = bigEndian; family = "arm"; version = "8"; };
+
+    i386     = { bits = 32; significantByte = littleEndian; family = "x86"; };
+    i486     = { bits = 32; significantByte = littleEndian; family = "x86"; };
+    i586     = { bits = 32; significantByte = littleEndian; family = "x86"; };
+    i686     = { bits = 32; significantByte = littleEndian; family = "x86"; };
+    x86_64   = { bits = 64; significantByte = littleEndian; family = "x86"; };
+
+    mips     = { bits = 32; significantByte = bigEndian;    family = "mips"; };
+    mipsel   = { bits = 32; significantByte = littleEndian; family = "mips"; };
+    mips64   = { bits = 64; significantByte = bigEndian;    family = "mips"; };
+    mips64el = { bits = 64; significantByte = littleEndian; family = "mips"; };
+
+    powerpc  = { bits = 32; significantByte = bigEndian;    family = "power"; };
+    powerpc64 = { bits = 64; significantByte = bigEndian; family = "power"; };
+    powerpc64le = { bits = 64; significantByte = littleEndian; family = "power"; };
+    powerpcle = { bits = 32; significantByte = littleEndian; family = "power"; };
+
+    riscv32  = { bits = 32; significantByte = littleEndian; family = "riscv"; };
+    riscv64  = { bits = 64; significantByte = littleEndian; family = "riscv"; };
+
+    sparc    = { bits = 32; significantByte = bigEndian;    family = "sparc"; };
+    sparc64  = { bits = 64; significantByte = bigEndian;    family = "sparc"; };
+
+    wasm32   = { bits = 32; significantByte = littleEndian; family = "wasm"; };
+    wasm64   = { bits = 64; significantByte = littleEndian; family = "wasm"; };
+    
+    alpha    = { bits = 64; significantByte = littleEndian; family = "alpha"; };
+
+    avr      = { bits = 8; family = "avr"; };
+  };
+
+  ################################################################################
+
+  types.openVendor = mkOptionType {
+    name = "vendor";
+    description = "vendor for the platform";
+    merge = mergeOneOption;
+  };
+
+  types.vendor = enum (attrValues vendors);
+
+  vendors = setTypes types.openVendor {
+    apple = {};
+    pc = {};
+
+    none = {};
+    unknown = {};
+  };
+
+  ################################################################################
+
+  types.openExecFormat = mkOptionType {
+    name = "exec-format";
+    description = "executable container used by the kernel";
+    merge = mergeOneOption;
+  };
+
+  types.execFormat = enum (attrValues execFormats);
+
+  execFormats = setTypes types.openExecFormat {
+    aout = {}; # a.out
+    elf = {};
+    macho = {};
+    pe = {};
+
+    unknown = {};
+  };
+
+  ################################################################################
+
+  types.openKernelFamily = mkOptionType {
+    name = "exec-format";
+    description = "executable container used by the kernel";
+    merge = mergeOneOption;
+  };
+
+  types.kernelFamily = enum (attrValues kernelFamilies);
+
+  kernelFamilies = setTypes types.openKernelFamily {
+    bsd = {};
+    darwin = {};
+  };
+
+  ################################################################################
+
+  types.openKernel = mkOptionType {
+    name = "kernel";
+    description = "kernel name and information";
+    merge = mergeOneOption;
+    check = x: types.execFormat.check x.execFormat
+        && all types.kernelFamily.check (attrValues x.families);
+  };
+
+  types.kernel = enum (attrValues kernels);
+
+  kernels = with execFormats; with kernelFamilies; setTypes types.openKernel {
+    # TODO(@Ericson2314): Don't want to mass-rebuild yet to keeping 'darwin' as
+    # the nnormalized name for macOS.
+    macos   = { execFormat = macho;   families = { inherit darwin; }; name = "darwin"; };
+    ios     = { execFormat = macho;   families = { inherit darwin; }; };
+    freebsd = { execFormat = elf;     families = { inherit bsd; }; };
+    linux   = { execFormat = elf;     families = { }; };
+    netbsd  = { execFormat = elf;     families = { inherit bsd; }; };
+    none    = { execFormat = unknown; families = { }; };
+    openbsd = { execFormat = elf;     families = { inherit bsd; }; };
+    solaris = { execFormat = elf;     families = { }; };
+    windows = { execFormat = pe;      families = { }; };
+  } // { # aliases
+    # 'darwin' is the kernel for all of them. We choose macOS by default.
+    darwin = kernels.macos;
+    watchos = kernels.ios;
+    tvos = kernels.ios;
+    win32 = kernels.windows;
+  };
+
+  ################################################################################
+
+  types.openAbi = mkOptionType {
+    name = "abi";
+    description = "binary interface for compiled code and syscalls";
+    merge = mergeOneOption;
+  };
+
+  types.abi = enum (attrValues abis);
+
+  abis = setTypes types.openAbi {
+    cygnus       = {};
+    msvc         = {};
+
+    # Note: eabi is specific to ARM and PowerPC.
+    # On PowerPC, this corresponds to PPCEABI.
+    # On ARM, this corresponds to ARMEABI.
+    eabi         = { float = "soft"; };
+    eabihf       = { float = "hard"; };
+
+    # Other architectures should use ELF in embedded situations.
+    elf          = {};
+
+    androideabi  = {};
+    android      = {
+      assertions = [
+        { assertion = platform: !platform.isAarch32;
+          message = ''
+            The "android" ABI is not for 32-bit ARM. Use "androideabi" instead.
+          '';
+        }
+      ];
+    };
+
+    gnueabi      = { float = "soft"; };
+    gnueabihf    = { float = "hard"; };
+    gnu          = {
+      assertions = [
+        { assertion = platform: !platform.isAarch32;
+          message = ''
+            The "gnu" ABI is ambiguous on 32-bit ARM. Use "gnueabi" or "gnueabihf" instead.
+          '';
+        }
+      ];
+    };
+
+    musleabi     = { float = "soft"; };
+    musleabihf   = { float = "hard"; };
+    musl         = {};
+
+    uclibceabihf = { float = "soft"; };
+    uclibceabi   = { float = "hard"; };
+    uclibc       = {};
+
+    unknown = {};
+  };
+
+  ################################################################################
+
+  types.parsedPlatform = mkOptionType {
+    name = "system";
+    description = "fully parsed representation of llvm- or nix-style platform tuple";
+    merge = mergeOneOption;
+    check = { cpu, vendor, kernel, abi }:
+           types.cpuType.check cpu
+        && types.vendor.check vendor
+        && types.kernel.check kernel
+        && types.abi.check abi;
+  };
+
+  isSystem = isType "system";
+
+  mkSystem = components:
+    assert types.parsedPlatform.check components;
+    setType "system" components;
+
+  mkSkeletonFromList = l: {
+    "1" = if elemAt l 0 == "avr"
+      then { cpu = elemAt l 0; kernel = "none"; abi = "unknown"; }
+      else throw "Target specification with 1 components is ambiguous";
+    "2" = # We only do 2-part hacks for things Nix already supports
+      if elemAt l 1 == "cygwin"
+        then { cpu = elemAt l 0;                      kernel = "windows";  abi = "cygnus";   }
+      else if (elemAt l 1) == "elf"
+      then { cpu = elemAt l 0; vendor = "unknown";    kernel = "none";     abi = elemAt l 1; }
+      else   { cpu = elemAt l 0;                      kernel = elemAt l 1;                   };
+    "3" = # Awkwards hacks, beware!
+      if elemAt l 1 == "apple"
+        then { cpu = elemAt l 0; vendor = "apple";    kernel = elemAt l 2;                   }
+      else if (elemAt l 1 == "linux") || (elemAt l 2 == "gnu")
+        then { cpu = elemAt l 0;                      kernel = elemAt l 1; abi = elemAt l 2; }
+      else if (elemAt l 2 == "mingw32") # autotools breaks on -gnu for window
+        then { cpu = elemAt l 0; vendor = elemAt l 1; kernel = "windows";  abi = "gnu"; }
+      else if hasPrefix "netbsd" (elemAt l 2)
+        then { cpu = elemAt l 0; vendor = elemAt l 1;    kernel = elemAt l 2;                }
+      else if (elem (elemAt l 2) ["eabi" "eabihf" "elf"])
+        then { cpu = elemAt l 0; vendor = "unknown"; kernel = elemAt l 1; abi = elemAt l 2; }
+      else throw "Target specification with 3 components is ambiguous";
+    "4" =    { cpu = elemAt l 0; vendor = elemAt l 1; kernel = elemAt l 2; abi = elemAt l 3; };
+  }.${toString (length l)}
+    or (throw "system string has invalid number of hyphen-separated components");
+
+  # This should revert the job done by config.guess from the gcc compiler.
+  mkSystemFromSkeleton = { cpu
+                         , # Optional, but fallback too complex for here.
+                           # Inferred below instead.
+                           vendor ? assert false; null
+                         , kernel
+                         , # Also inferred below
+                           abi    ? assert false; null
+                         } @ args: let
+    getCpu    = name: cpuTypes.${name} or (throw "Unknown CPU type: ${name}");
+    getVendor = name:  vendors.${name} or (throw "Unknown vendor: ${name}");
+    getKernel = name:  kernels.${name} or (throw "Unknown kernel: ${name}");
+    getAbi    = name:     abis.${name} or (throw "Unknown ABI: ${name}");
+
+    parsed = rec {
+      cpu = getCpu args.cpu;
+      vendor =
+        /**/ if args ? vendor    then getVendor args.vendor
+        else if isDarwin  parsed then vendors.apple
+        else if isWindows parsed then vendors.pc
+        else                     vendors.unknown;
+      kernel = if hasPrefix "darwin" args.kernel      then getKernel "darwin"
+               else if hasPrefix "netbsd" args.kernel then getKernel "netbsd"
+               else                                   getKernel args.kernel;
+      abi =
+        /**/ if args ? abi       then getAbi args.abi
+        else if isLinux   parsed then
+          if isAarch32 parsed then
+            if lib.versionAtLeast (parsed.cpu.version or "0") "6"
+            then abis.gnueabihf
+            else abis.gnueabi
+          else abis.gnu
+        else if isWindows parsed then abis.gnu
+        else                     abis.unknown;
+    };
+
+  in mkSystem parsed;
+
+  mkSystemFromString = s: mkSystemFromSkeleton (mkSkeletonFromList (lib.splitString "-" s));
+
+  doubleFromSystem = { cpu, vendor, kernel, abi, ... }:
+    /**/ if abi == abis.cygnus       then "${cpu.name}-cygwin"
+    else if kernel.families ? darwin then "${cpu.name}-darwin"
+    else "${cpu.name}-${kernel.name}";
+
+  tripleFromSystem = { cpu, vendor, kernel, abi, ... } @ sys: assert isSystem sys; let
+    optAbi = lib.optionalString (abi != abis.unknown) "-${abi.name}";
+  in "${cpu.name}-${vendor.name}-${kernel.name}${optAbi}";
+
+  ################################################################################
+
+}
diff --git a/nixpkgs/lib/systems/platforms.nix b/nixpkgs/lib/systems/platforms.nix
new file mode 100644
index 000000000000..1ed072e94645
--- /dev/null
+++ b/nixpkgs/lib/systems/platforms.nix
@@ -0,0 +1,480 @@
+{ lib }:
+rec {
+  pcBase = {
+    name = "pc";
+    kernelBaseConfig = "defconfig";
+    # Build whatever possible as a module, if not stated in the extra config.
+    kernelAutoModules = true;
+    kernelTarget = "bzImage";
+  };
+
+  pc64 = pcBase // { kernelArch = "x86_64"; };
+
+  pc32 = pcBase // { kernelArch = "i386"; };
+
+  pc32_simplekernel = pc32 // {
+    kernelAutoModules = false;
+  };
+
+  pc64_simplekernel = pc64 // {
+    kernelAutoModules = false;
+  };
+
+  powernv = {
+    name = "PowerNV";
+    kernelArch = "powerpc";
+    kernelBaseConfig = "powernv_defconfig";
+    kernelTarget = "zImage";
+    kernelInstallTarget = "install";
+    kernelFile = "vmlinux";
+    kernelAutoModules = true;
+    # avoid driver/FS trouble arising from unusual page size
+    kernelExtraConfig = ''
+      PPC_64K_PAGES n
+      PPC_4K_PAGES y
+      IPV6 y
+    '';
+  };
+
+  ##
+  ## ARM
+  ##
+
+  pogoplug4 = {
+    name = "pogoplug4";
+
+    gcc = {
+      arch = "armv5te";
+    };
+
+    kernelMajor = "2.6";
+    kernelBaseConfig = "multi_v5_defconfig";
+    kernelArch = "arm";
+    kernelAutoModules = false;
+    kernelExtraConfig =
+      ''
+        # Ubi for the mtd
+        MTD_UBI y
+        UBIFS_FS y
+        UBIFS_FS_XATTR y
+        UBIFS_FS_ADVANCED_COMPR y
+        UBIFS_FS_LZO y
+        UBIFS_FS_ZLIB y
+        UBIFS_FS_DEBUG n
+      '';
+    kernelMakeFlags = [ "LOADADDR=0x8000" ];
+    kernelTarget = "uImage";
+    # TODO reenable once manual-config's config actually builds a .dtb and this is checked to be working
+    #kernelDTB = true;
+  };
+
+  sheevaplug = {
+    name = "sheevaplug";
+    kernelMajor = "2.6";
+    kernelBaseConfig = "multi_v5_defconfig";
+    kernelArch = "arm";
+    kernelAutoModules = false;
+    kernelExtraConfig = ''
+      BLK_DEV_RAM y
+      BLK_DEV_INITRD y
+      BLK_DEV_CRYPTOLOOP m
+      BLK_DEV_DM m
+      DM_CRYPT m
+      MD y
+      REISERFS_FS m
+      BTRFS_FS m
+      XFS_FS m
+      JFS_FS m
+      EXT4_FS m
+      USB_STORAGE_CYPRESS_ATACB m
+
+      # mv cesa requires this sw fallback, for mv-sha1
+      CRYPTO_SHA1 y
+      # Fast crypto
+      CRYPTO_TWOFISH y
+      CRYPTO_TWOFISH_COMMON y
+      CRYPTO_BLOWFISH y
+      CRYPTO_BLOWFISH_COMMON y
+
+      IP_PNP y
+      IP_PNP_DHCP y
+      NFS_FS y
+      ROOT_NFS y
+      TUN m
+      NFS_V4 y
+      NFS_V4_1 y
+      NFS_FSCACHE y
+      NFSD m
+      NFSD_V2_ACL y
+      NFSD_V3 y
+      NFSD_V3_ACL y
+      NFSD_V4 y
+      NETFILTER y
+      IP_NF_IPTABLES y
+      IP_NF_FILTER y
+      IP_NF_MATCH_ADDRTYPE y
+      IP_NF_TARGET_LOG y
+      IP_NF_MANGLE y
+      IPV6 m
+      VLAN_8021Q m
+
+      CIFS y
+      CIFS_XATTR y
+      CIFS_POSIX y
+      CIFS_FSCACHE y
+      CIFS_ACL y
+
+      WATCHDOG y
+      WATCHDOG_CORE y
+      ORION_WATCHDOG m
+
+      ZRAM m
+      NETCONSOLE m
+
+      # Disable OABI to have seccomp_filter (required for systemd)
+      # https://github.com/raspberrypi/firmware/issues/651
+      OABI_COMPAT n
+
+      # Fail to build
+      DRM n
+      SCSI_ADVANSYS n
+      USB_ISP1362_HCD n
+      SND_SOC n
+      SND_ALI5451 n
+      FB_SAVAGE n
+      SCSI_NSP32 n
+      ATA_SFF n
+      SUNGEM n
+      IRDA n
+      ATM_HE n
+      SCSI_ACARD n
+      BLK_DEV_CMD640_ENHANCED n
+
+      FUSE_FS m
+
+      # systemd uses cgroups
+      CGROUPS y
+
+      # Latencytop
+      LATENCYTOP y
+
+      # Ubi for the mtd
+      MTD_UBI y
+      UBIFS_FS y
+      UBIFS_FS_XATTR y
+      UBIFS_FS_ADVANCED_COMPR y
+      UBIFS_FS_LZO y
+      UBIFS_FS_ZLIB y
+      UBIFS_FS_DEBUG n
+
+      # Kdb, for kernel troubles
+      KGDB y
+      KGDB_SERIAL_CONSOLE y
+      KGDB_KDB y
+    '';
+    kernelMakeFlags = [ "LOADADDR=0x0200000" ];
+    kernelTarget = "uImage";
+    kernelDTB = true; # Beyond 3.10
+    gcc = {
+      arch = "armv5te";
+    };
+  };
+
+  raspberrypi = {
+    name = "raspberrypi";
+    kernelMajor = "2.6";
+    kernelBaseConfig = "bcm2835_defconfig";
+    kernelDTB = true;
+    kernelArch = "arm";
+    kernelAutoModules = true;
+    kernelPreferBuiltin = true;
+    kernelExtraConfig = ''
+      # Disable OABI to have seccomp_filter (required for systemd)
+      # https://github.com/raspberrypi/firmware/issues/651
+      OABI_COMPAT n
+    '';
+    kernelTarget = "zImage";
+    gcc = {
+      arch = "armv6";
+      fpu = "vfp";
+    };
+  };
+
+  # Legacy attribute, for compatibility with existing configs only.
+  raspberrypi2 = armv7l-hf-multiplatform;
+
+  scaleway-c1 = armv7l-hf-multiplatform // {
+    gcc = {
+      cpu = "cortex-a9";
+      fpu = "vfpv3";
+    };
+  };
+
+  utilite = {
+    name = "utilite";
+    kernelMajor = "2.6";
+    kernelBaseConfig = "multi_v7_defconfig";
+    kernelArch = "arm";
+    kernelAutoModules = false;
+    kernelExtraConfig =
+      ''
+        # Ubi for the mtd
+        MTD_UBI y
+        UBIFS_FS y
+        UBIFS_FS_XATTR y
+        UBIFS_FS_ADVANCED_COMPR y
+        UBIFS_FS_LZO y
+        UBIFS_FS_ZLIB y
+        UBIFS_FS_DEBUG n
+      '';
+    kernelMakeFlags = [ "LOADADDR=0x10800000" ];
+    kernelTarget = "uImage";
+    kernelDTB = true;
+    gcc = {
+      cpu = "cortex-a9";
+      fpu = "neon";
+    };
+  };
+
+  guruplug = sheevaplug // {
+    # Define `CONFIG_MACH_GURUPLUG' (see
+    # <http://kerneltrap.org/mailarchive/git-commits-head/2010/5/19/33618>)
+    # and other GuruPlug-specific things.  Requires the `guruplug-defconfig'
+    # patch.
+
+    kernelBaseConfig = "guruplug_defconfig";
+  };
+
+  beaglebone = armv7l-hf-multiplatform // {
+    name = "beaglebone";
+    kernelBaseConfig = "bb.org_defconfig";
+    kernelAutoModules = false;
+    kernelExtraConfig = ""; # TBD kernel config
+    kernelTarget = "zImage";
+  };
+
+  # https://developer.android.com/ndk/guides/abis#armeabi
+  armv5te-android = {
+    name = "armeabi";
+    gcc = {
+      arch = "armv5te";
+      float = "soft";
+      float-abi = "soft";
+    };
+  };
+
+  # https://developer.android.com/ndk/guides/abis#v7a
+  armv7a-android =  {
+    name = "armeabi-v7a";
+    gcc = {
+      arch = "armv7-a";
+      float = "hard";
+      float-abi = "softfp";
+      fpu = "vfpv3-d16";
+    };
+  };
+
+  armv7l-hf-multiplatform = {
+    name = "armv7l-hf-multiplatform";
+    kernelMajor = "2.6"; # Using "2.6" enables 2.6 kernel syscalls in glibc.
+    kernelBaseConfig = "multi_v7_defconfig";
+    kernelArch = "arm";
+    kernelDTB = true;
+    kernelAutoModules = true;
+    kernelPreferBuiltin = true;
+    kernelTarget = "zImage";
+    kernelExtraConfig = ''
+      # Serial port for Raspberry Pi 3. Upstream forgot to add it to the ARMv7 defconfig.
+      SERIAL_8250_BCM2835AUX y
+      SERIAL_8250_EXTENDED y
+      SERIAL_8250_SHARE_IRQ y
+
+      # Fix broken sunxi-sid nvmem driver.
+      TI_CPTS y
+
+      # Hangs ODROID-XU4
+      ARM_BIG_LITTLE_CPUIDLE n
+
+      # Disable OABI to have seccomp_filter (required for systemd)
+      # https://github.com/raspberrypi/firmware/issues/651
+      OABI_COMPAT n
+    '';
+    gcc = {
+      # Some table about fpu flags:
+      # http://community.arm.com/servlet/JiveServlet/showImage/38-1981-3827/blogentry-103749-004812900+1365712953_thumb.png
+      # Cortex-A5: -mfpu=neon-fp16
+      # Cortex-A7 (rpi2): -mfpu=neon-vfpv4
+      # Cortex-A8 (beaglebone): -mfpu=neon
+      # Cortex-A9: -mfpu=neon-fp16
+      # Cortex-A15: -mfpu=neon-vfpv4
+
+      # More about FPU:
+      # https://wiki.debian.org/ArmHardFloatPort/VfpComparison
+
+      # vfpv3-d16 is what Debian uses and seems to be the best compromise: NEON is not supported in e.g. Scaleway or Tegra 2,
+      # and the above page suggests NEON is only an improvement with hand-written assembly.
+      arch = "armv7-a";
+      fpu = "vfpv3-d16";
+
+      # For Raspberry Pi the 2 the best would be:
+      #   cpu = "cortex-a7";
+      #   fpu = "neon-vfpv4";
+    };
+  };
+
+  aarch64-multiplatform = {
+    name = "aarch64-multiplatform";
+    kernelMajor = "2.6"; # Using "2.6" enables 2.6 kernel syscalls in glibc.
+    kernelBaseConfig = "defconfig";
+    kernelArch = "arm64";
+    kernelDTB = true;
+    kernelAutoModules = true;
+    kernelPreferBuiltin = true;
+    kernelExtraConfig = ''
+      # Raspberry Pi 3 stuff. Not needed for kernels >= 4.10.
+      ARCH_BCM2835 y
+      BCM2835_MBOX y
+      BCM2835_WDT y
+      RASPBERRYPI_FIRMWARE y
+      RASPBERRYPI_POWER y
+      SERIAL_8250_BCM2835AUX y
+      SERIAL_8250_EXTENDED y
+      SERIAL_8250_SHARE_IRQ y
+
+      # Cavium ThunderX stuff.
+      PCI_HOST_THUNDER_ECAM y
+
+      # Nvidia Tegra stuff.
+      PCI_TEGRA y
+
+      # The default (=y) forces us to have the XHCI firmware available in initrd,
+      # which our initrd builder can't currently do easily.
+      USB_XHCI_TEGRA m
+    '';
+    kernelTarget = "Image";
+    gcc = {
+      arch = "armv8-a";
+    };
+  };
+
+  ##
+  ## MIPS
+  ##
+
+  ben_nanonote = {
+    name = "ben_nanonote";
+    kernelMajor = "2.6";
+    kernelArch = "mips";
+    gcc = {
+      arch = "mips32";
+      float = "soft";
+    };
+  };
+
+  fuloong2f_n32 = {
+    name = "fuloong2f_n32";
+    kernelMajor = "2.6";
+    kernelBaseConfig = "lemote2f_defconfig";
+    kernelArch = "mips";
+    kernelAutoModules = false;
+    kernelExtraConfig = ''
+      MIGRATION n
+      COMPACTION n
+
+      # nixos mounts some cgroup
+      CGROUPS y
+
+      BLK_DEV_RAM y
+      BLK_DEV_INITRD y
+      BLK_DEV_CRYPTOLOOP m
+      BLK_DEV_DM m
+      DM_CRYPT m
+      MD y
+      REISERFS_FS m
+      EXT4_FS m
+      USB_STORAGE_CYPRESS_ATACB m
+
+      IP_PNP y
+      IP_PNP_DHCP y
+      IP_PNP_BOOTP y
+      NFS_FS y
+      ROOT_NFS y
+      TUN m
+      NFS_V4 y
+      NFS_V4_1 y
+      NFS_FSCACHE y
+      NFSD m
+      NFSD_V2_ACL y
+      NFSD_V3 y
+      NFSD_V3_ACL y
+      NFSD_V4 y
+
+      # Fail to build
+      DRM n
+      SCSI_ADVANSYS n
+      USB_ISP1362_HCD n
+      SND_SOC n
+      SND_ALI5451 n
+      FB_SAVAGE n
+      SCSI_NSP32 n
+      ATA_SFF n
+      SUNGEM n
+      IRDA n
+      ATM_HE n
+      SCSI_ACARD n
+      BLK_DEV_CMD640_ENHANCED n
+
+      FUSE_FS m
+
+      # Needed for udev >= 150
+      SYSFS_DEPRECATED_V2 n
+
+      VGA_CONSOLE n
+      VT_HW_CONSOLE_BINDING y
+      SERIAL_8250_CONSOLE y
+      FRAMEBUFFER_CONSOLE y
+      EXT2_FS y
+      EXT3_FS y
+      REISERFS_FS y
+      MAGIC_SYSRQ y
+
+      # The kernel doesn't boot at all, with FTRACE
+      FTRACE n
+    '';
+    kernelTarget = "vmlinux";
+    gcc = {
+      arch = "loongson2f";
+      float = "hard";
+      abi = "n32";
+    };
+  };
+
+  ##
+  ## Other
+  ##
+
+  riscv-multiplatform = bits: {
+    name = "riscv-multiplatform";
+    kernelArch = "riscv";
+    bfdEmulation = "elf${bits}lriscv";
+    kernelTarget = "vmlinux";
+    kernelAutoModules = true;
+    kernelBaseConfig = "defconfig";
+    kernelExtraConfig = ''
+      FTRACE n
+      SERIAL_OF_PLATFORM y
+    '';
+  };
+
+  selectBySystem = system: {
+      "i686-linux" = pc32;
+      "x86_64-linux" = pc64;
+      "armv5tel-linux" = sheevaplug;
+      "armv6l-linux" = raspberrypi;
+      "armv7a-linux" = armv7l-hf-multiplatform;
+      "armv7l-linux" = armv7l-hf-multiplatform;
+      "aarch64-linux" = aarch64-multiplatform;
+      "mipsel-linux" = fuloong2f_n32;
+      "powerpc64le-linux" = powernv;
+    }.${system} or pcBase;
+}
diff --git a/nixpkgs/lib/tests/check-eval.nix b/nixpkgs/lib/tests/check-eval.nix
new file mode 100644
index 000000000000..8bd7b605a39b
--- /dev/null
+++ b/nixpkgs/lib/tests/check-eval.nix
@@ -0,0 +1,7 @@
+# Throws an error if any of our lib tests fail.
+
+let tests = [ "misc" "systems" ];
+    all = builtins.concatLists (map (f: import (./. + "/${f}.nix")) tests);
+in if all == []
+     then null
+   else throw (builtins.toJSON all)
diff --git a/nixpkgs/lib/tests/misc.nix b/nixpkgs/lib/tests/misc.nix
new file mode 100644
index 000000000000..1604fbb39cbb
--- /dev/null
+++ b/nixpkgs/lib/tests/misc.nix
@@ -0,0 +1,442 @@
+# to run these tests:
+# nix-instantiate --eval --strict nixpkgs/lib/tests/misc.nix
+# if the resulting list is empty, all tests passed
+with import ../default.nix;
+
+runTests {
+
+
+# TRIVIAL
+
+  testId = {
+    expr = id 1;
+    expected = 1;
+  };
+
+  testConst = {
+    expr = const 2 3;
+    expected = 2;
+  };
+
+  /*
+  testOr = {
+    expr = or true false;
+    expected = true;
+  };
+  */
+
+  testAnd = {
+    expr = and true false;
+    expected = false;
+  };
+
+  testFix = {
+    expr = fix (x: {a = if x ? a then "a" else "b";});
+    expected = {a = "a";};
+  };
+
+  testComposeExtensions = {
+    expr = let obj = makeExtensible (self: { foo = self.bar; });
+               f = self: super: { bar = false; baz = true; };
+               g = self: super: { bar = super.baz or false; };
+               f_o_g = composeExtensions f g;
+               composed = obj.extend f_o_g;
+           in composed.foo;
+    expected = true;
+  };
+
+  testBitAnd = {
+    expr = (bitAnd 3 10);
+    expected = 2;
+  };
+
+  testBitOr = {
+    expr = (bitOr 3 10);
+    expected = 11;
+  };
+
+  testBitXor = {
+    expr = (bitXor 3 10);
+    expected = 9;
+  };
+
+# STRINGS
+
+  testConcatMapStrings = {
+    expr = concatMapStrings (x: x + ";") ["a" "b" "c"];
+    expected = "a;b;c;";
+  };
+
+  testConcatStringsSep = {
+    expr = concatStringsSep "," ["a" "b" "c"];
+    expected = "a,b,c";
+  };
+
+  testSplitStringsSimple = {
+    expr = strings.splitString "." "a.b.c.d";
+    expected = [ "a" "b" "c" "d" ];
+  };
+
+  testSplitStringsEmpty = {
+    expr = strings.splitString "." "a..b";
+    expected = [ "a" "" "b" ];
+  };
+
+  testSplitStringsOne = {
+    expr = strings.splitString ":" "a.b";
+    expected = [ "a.b" ];
+  };
+
+  testSplitStringsNone = {
+    expr = strings.splitString "." "";
+    expected = [ "" ];
+  };
+
+  testSplitStringsFirstEmpty = {
+    expr = strings.splitString "/" "/a/b/c";
+    expected = [ "" "a" "b" "c" ];
+  };
+
+  testSplitStringsLastEmpty = {
+    expr = strings.splitString ":" "2001:db8:0:0042::8a2e:370:";
+    expected = [ "2001" "db8" "0" "0042" "" "8a2e" "370" "" ];
+  };
+
+  testIsStorePath =  {
+    expr =
+      let goodPath =
+            "${builtins.storeDir}/d945ibfx9x185xf04b890y4f9g3cbb63-python-2.7.11";
+      in {
+        storePath = isStorePath goodPath;
+        storePathDerivation = isStorePath (import ../.. {}).hello;
+        storePathAppendix = isStorePath
+          "${goodPath}/bin/python";
+        nonAbsolute = isStorePath (concatStrings (tail (stringToCharacters goodPath)));
+        asPath = isStorePath (/. + goodPath);
+        otherPath = isStorePath "/something/else";
+        otherVals = {
+          attrset = isStorePath {};
+          list = isStorePath [];
+          int = isStorePath 42;
+        };
+      };
+    expected = {
+      storePath = true;
+      storePathDerivation = true;
+      storePathAppendix = false;
+      nonAbsolute = false;
+      asPath = true;
+      otherPath = false;
+      otherVals = {
+        attrset = false;
+        list = false;
+        int = false;
+      };
+    };
+  };
+
+# LISTS
+
+  testFilter = {
+    expr = filter (x: x != "a") ["a" "b" "c" "a"];
+    expected = ["b" "c"];
+  };
+
+  testFold =
+    let
+      f = op: fold: fold op 0 (range 0 100);
+      # fold with associative operator
+      assoc = f builtins.add;
+      # fold with non-associative operator
+      nonAssoc = f builtins.sub;
+    in {
+      expr = {
+        assocRight = assoc foldr;
+        # right fold with assoc operator is same as left fold
+        assocRightIsLeft = assoc foldr == assoc foldl;
+        nonAssocRight = nonAssoc foldr;
+        nonAssocLeft = nonAssoc foldl;
+        # with non-assoc operator the fold results are not the same
+        nonAssocRightIsNotLeft = nonAssoc foldl != nonAssoc foldr;
+        # fold is an alias for foldr
+        foldIsRight = nonAssoc fold == nonAssoc foldr;
+      };
+      expected = {
+        assocRight = 5050;
+        assocRightIsLeft = true;
+        nonAssocRight = 50;
+        nonAssocLeft = (-5050);
+        nonAssocRightIsNotLeft = true;
+        foldIsRight = true;
+      };
+    };
+
+  testTake = testAllTrue [
+    ([] == (take 0 [  1 2 3 ]))
+    ([1] == (take 1 [  1 2 3 ]))
+    ([ 1 2 ] == (take 2 [  1 2 3 ]))
+    ([ 1 2 3 ] == (take 3 [  1 2 3 ]))
+    ([ 1 2 3 ] == (take 4 [  1 2 3 ]))
+  ];
+
+  testFoldAttrs = {
+    expr = foldAttrs (n: a: [n] ++ a) [] [
+    { a = 2; b = 7; }
+    { a = 3;        c = 8; }
+    ];
+    expected = { a = [ 2 3 ]; b = [7]; c = [8];};
+  };
+
+  testSort = {
+    expr = sort builtins.lessThan [ 40 2 30 42 ];
+    expected = [2 30 40 42];
+  };
+
+  testToIntShouldConvertStringToInt = {
+    expr = toInt "27";
+    expected = 27;
+  };
+
+  testToIntShouldThrowErrorIfItCouldNotConvertToInt = {
+    expr = builtins.tryEval (toInt "\"foo\"");
+    expected = { success = false; value = false; };
+  };
+
+  testHasAttrByPathTrue = {
+    expr = hasAttrByPath ["a" "b"] { a = { b = "yey"; }; };
+    expected = true;
+  };
+
+  testHasAttrByPathFalse = {
+    expr = hasAttrByPath ["a" "b"] { a = { c = "yey"; }; };
+    expected = false;
+  };
+
+
+# ATTRSETS
+
+  # code from the example
+  testRecursiveUpdateUntil = {
+    expr = recursiveUpdateUntil (path: l: r: path == ["foo"]) {
+      # first attribute set
+      foo.bar = 1;
+      foo.baz = 2;
+      bar = 3;
+    } {
+      #second attribute set
+      foo.bar = 1;
+      foo.quz = 2;
+      baz = 4;
+    };
+    expected = {
+      foo.bar = 1; # 'foo.*' from the second set
+      foo.quz = 2; #
+      bar = 3;     # 'bar' from the first set
+      baz = 4;     # 'baz' from the second set
+    };
+  };
+
+  testOverrideExistingEmpty = {
+    expr = overrideExisting {} { a = 1; };
+    expected = {};
+  };
+
+  testOverrideExistingDisjoint = {
+    expr = overrideExisting { b = 2; } { a = 1; };
+    expected = { b = 2; };
+  };
+
+  testOverrideExistingOverride = {
+    expr = overrideExisting { a = 3; b = 2; } { a = 1; };
+    expected = { a = 1; b = 2; };
+  };
+
+# GENERATORS
+# these tests assume attributes are converted to lists
+# in alphabetical order
+
+  testMkKeyValueDefault = {
+    expr = generators.mkKeyValueDefault {} ":" "f:oo" "bar";
+    expected = ''f\:oo:bar'';
+  };
+
+  testMkValueString = {
+    expr = let
+      vals = {
+        int = 42;
+        string = ''fo"o'';
+        bool = true;
+        bool2 = false;
+        null = null;
+        # float = 42.23; # floats are strange
+      };
+      in mapAttrs
+        (const (generators.mkValueStringDefault {}))
+        vals;
+    expected = {
+      int = "42";
+      string = ''fo"o'';
+      bool = "true";
+      bool2 = "false";
+      null = "null";
+      # float = "42.23" true false [ "bar" ] ]'';
+    };
+  };
+
+  testToKeyValue = {
+    expr = generators.toKeyValue {} {
+      key = "value";
+      "other=key" = "baz";
+    };
+    expected = ''
+      key=value
+      other\=key=baz
+    '';
+  };
+
+  testToINIEmpty = {
+    expr = generators.toINI {} {};
+    expected = "";
+  };
+
+  testToINIEmptySection = {
+    expr = generators.toINI {} { foo = {}; bar = {}; };
+    expected = ''
+      [bar]
+
+      [foo]
+    '';
+  };
+
+  testToINIDefaultEscapes = {
+    expr = generators.toINI {} {
+      "no [ and ] allowed unescaped" = {
+        "and also no = in keys" = 42;
+      };
+    };
+    expected = ''
+      [no \[ and \] allowed unescaped]
+      and also no \= in keys=42
+    '';
+  };
+
+  testToINIDefaultFull = {
+    expr = generators.toINI {} {
+      "section 1" = {
+        attribute1 = 5;
+        x = "Me-se JarJar Binx";
+        # booleans are converted verbatim by default
+        boolean = false;
+      };
+      "foo[]" = {
+        "he\\h=he" = "this is okay";
+      };
+    };
+    expected = ''
+      [foo\[\]]
+      he\h\=he=this is okay
+
+      [section 1]
+      attribute1=5
+      boolean=false
+      x=Me-se JarJar Binx
+    '';
+  };
+
+  /* right now only invocation check */
+  testToJSONSimple =
+    let val = {
+      foobar = [ "baz" 1 2 3 ];
+    };
+    in {
+      expr = generators.toJSON {} val;
+      # trivial implementation
+      expected = builtins.toJSON val;
+  };
+
+  /* right now only invocation check */
+  testToYAMLSimple =
+    let val = {
+      list = [ { one = 1; } { two = 2; } ];
+      all = 42;
+    };
+    in {
+      expr = generators.toYAML {} val;
+      # trivial implementation
+      expected = builtins.toJSON val;
+  };
+
+  testToPretty = {
+    expr = mapAttrs (const (generators.toPretty {})) rec {
+      int = 42;
+      float = 0.1337;
+      bool = true;
+      string = ''fno"rd'';
+      path = /. + "/foo";
+      null_ = null;
+      function = x: x;
+      functionArgs = { arg ? 4, foo }: arg;
+      list = [ 3 4 function [ false ] ];
+      attrs = { foo = null; "foo bar" = "baz"; };
+      drv = derivation { name = "test"; system = builtins.currentSystem; };
+    };
+    expected = rec {
+      int = "42";
+      float = "~0.133700";
+      bool = "true";
+      string = ''"fno\"rd"'';
+      path = "/foo";
+      null_ = "null";
+      function = "<λ>";
+      functionArgs = "<λ:{(arg),foo}>";
+      list = "[ 3 4 ${function} [ false ] ]";
+      attrs = "{ \"foo\" = null; \"foo bar\" = \"baz\"; }";
+      drv = "<δ:test>";
+    };
+  };
+
+  testToPrettyAllowPrettyValues = {
+    expr = generators.toPretty { allowPrettyValues = true; }
+             { __pretty = v: "«" + v + "»"; val = "foo"; };
+    expected  = "«foo»";
+  };
+
+
+# MISC
+
+  testOverridableDelayableArgsTest = {
+    expr =
+      let res1 = defaultOverridableDelayableArgs id {};
+          res2 = defaultOverridableDelayableArgs id { a = 7; };
+          res3 = let x = defaultOverridableDelayableArgs id { a = 7; };
+                 in (x.merge) { b = 10; };
+          res4 = let x = defaultOverridableDelayableArgs id { a = 7; };
+                in (x.merge) ( x: { b = 10; });
+          res5 = let x = defaultOverridableDelayableArgs id { a = 7; };
+                in (x.merge) ( x: { a = builtins.add x.a 3; });
+          res6 = let x = defaultOverridableDelayableArgs id { a = 7; mergeAttrBy = { a = builtins.add; }; };
+                     y = x.merge {};
+                in (y.merge) { a = 10; };
+
+          resRem7 = res6.replace (a: removeAttrs a ["a"]);
+
+          # fixed tests (delayed args): (when using them add some comments, please)
+          resFixed1 =
+                let x = defaultOverridableDelayableArgs id ( x: { a = 7; c = x.fixed.b; });
+                    y = x.merge (x: { name = "name-${builtins.toString x.fixed.c}"; });
+                in (y.merge) { b = 10; };
+          strip = attrs: removeAttrs attrs ["merge" "replace"];
+      in all id
+        [ ((strip res1) == { })
+          ((strip res2) == { a = 7; })
+          ((strip res3) == { a = 7; b = 10; })
+          ((strip res4) == { a = 7; b = 10; })
+          ((strip res5) == { a = 10; })
+          ((strip res6) == { a = 17; })
+          ((strip resRem7) == {})
+          ((strip resFixed1) == { a = 7; b = 10; c =10; name = "name-10"; })
+        ];
+    expected = true;
+  };
+
+}
diff --git a/nixpkgs/lib/tests/modules.sh b/nixpkgs/lib/tests/modules.sh
new file mode 100755
index 000000000000..b83e1eb7d82d
--- /dev/null
+++ b/nixpkgs/lib/tests/modules.sh
@@ -0,0 +1,161 @@
+#!/bin/sh
+#
+# This script is used to test that the module system is working as expected.
+# By default it test the version of nixpkgs which is defined in the NIX_PATH.
+
+cd ./modules
+
+pass=0
+fail=0
+
+evalConfig() {
+    local attr=$1
+    shift;
+    local script="import ./default.nix { modules = [ $@ ];}"
+    nix-instantiate --timeout 1 -E "$script" -A "$attr" --eval-only --show-trace
+}
+
+reportFailure() {
+    local attr=$1
+    shift;
+    local script="import ./default.nix { modules = [ $@ ];}"
+    echo 2>&1 "$ nix-instantiate -E '$script' -A '$attr' --eval-only"
+    evalConfig "$attr" "$@"
+    fail=$((fail + 1))
+}
+
+checkConfigOutput() {
+    local outputContains=$1
+    shift;
+    if evalConfig "$@" 2>/dev/null | grep --silent "$outputContains" ; then
+        pass=$((pass + 1))
+        return 0;
+    else
+        echo 2>&1 "error: Expected result matching '$outputContains', while evaluating"
+        reportFailure "$@"
+        return 1
+    fi
+}
+
+checkConfigError() {
+    local errorContains=$1
+    local err=""
+    shift;
+    if err==$(evalConfig "$@" 2>&1 >/dev/null); then
+        echo 2>&1 "error: Expected error code, got exit code 0, while evaluating"
+        reportFailure "$@"
+        return 1
+    else
+        if echo "$err" | grep --silent "$errorContains" ; then
+            pass=$((pass + 1))
+            return 0;
+        else
+            echo 2>&1 "error: Expected error matching '$errorContains', while evaluating"
+            reportFailure "$@"
+            return 1
+        fi
+    fi
+}
+
+# Check boolean option.
+checkConfigOutput "false" config.enable ./declare-enable.nix
+checkConfigError 'The option .* defined in .* does not exist.' config.enable ./define-enable.nix
+
+# Check integer types.
+# unsigned
+checkConfigOutput "42" config.value ./declare-int-unsigned-value.nix ./define-value-int-positive.nix
+checkConfigError 'The option value .* in .* is not of type.*unsigned integer.*' config.value ./declare-int-unsigned-value.nix ./define-value-int-negative.nix
+# positive
+checkConfigError 'The option value .* in .* is not of type.*positive integer.*' config.value ./declare-int-positive-value.nix ./define-value-int-zero.nix
+# between
+checkConfigOutput "42" config.value ./declare-int-between-value.nix ./define-value-int-positive.nix
+checkConfigError 'The option value .* in .* is not of type.*between.*-21 and 43.*inclusive.*' config.value ./declare-int-between-value.nix ./define-value-int-negative.nix
+
+# Check mkForce without submodules.
+set -- config.enable ./declare-enable.nix ./define-enable.nix
+checkConfigOutput "true" "$@"
+checkConfigOutput "false" "$@" ./define-force-enable.nix
+checkConfigOutput "false" "$@" ./define-enable-force.nix
+
+# Check mkForce with option and submodules.
+checkConfigError 'attribute .*foo.* .* not found' config.loaOfSub.foo.enable ./declare-loaOfSub-any-enable.nix
+checkConfigOutput 'false' config.loaOfSub.foo.enable ./declare-loaOfSub-any-enable.nix ./define-loaOfSub-foo.nix
+set -- config.loaOfSub.foo.enable ./declare-loaOfSub-any-enable.nix ./define-loaOfSub-foo-enable.nix
+checkConfigOutput 'true' "$@"
+checkConfigOutput 'false' "$@" ./define-force-loaOfSub-foo-enable.nix
+checkConfigOutput 'false' "$@" ./define-loaOfSub-force-foo-enable.nix
+checkConfigOutput 'false' "$@" ./define-loaOfSub-foo-force-enable.nix
+checkConfigOutput 'false' "$@" ./define-loaOfSub-foo-enable-force.nix
+
+# Check overriding effect of mkForce on submodule definitions.
+checkConfigError 'attribute .*bar.* .* not found' config.loaOfSub.bar.enable ./declare-loaOfSub-any-enable.nix ./define-loaOfSub-foo.nix
+checkConfigOutput 'false' config.loaOfSub.bar.enable ./declare-loaOfSub-any-enable.nix ./define-loaOfSub-foo.nix ./define-loaOfSub-bar.nix
+set -- config.loaOfSub.bar.enable ./declare-loaOfSub-any-enable.nix ./define-loaOfSub-foo.nix ./define-loaOfSub-bar-enable.nix
+checkConfigOutput 'true' "$@"
+checkConfigError 'attribute .*bar.* .* not found' "$@" ./define-force-loaOfSub-foo-enable.nix
+checkConfigError 'attribute .*bar.* .* not found' "$@" ./define-loaOfSub-force-foo-enable.nix
+checkConfigOutput 'true' "$@" ./define-loaOfSub-foo-force-enable.nix
+checkConfigOutput 'true' "$@" ./define-loaOfSub-foo-enable-force.nix
+
+# Check mkIf with submodules.
+checkConfigError 'attribute .*foo.* .* not found' config.loaOfSub.foo.enable ./declare-enable.nix ./declare-loaOfSub-any-enable.nix
+set -- config.loaOfSub.foo.enable ./declare-enable.nix ./declare-loaOfSub-any-enable.nix
+checkConfigError 'attribute .*foo.* .* not found' "$@" ./define-if-loaOfSub-foo-enable.nix
+checkConfigError 'attribute .*foo.* .* not found' "$@" ./define-loaOfSub-if-foo-enable.nix
+checkConfigError 'attribute .*foo.* .* not found' "$@" ./define-loaOfSub-foo-if-enable.nix
+checkConfigOutput 'false' "$@" ./define-loaOfSub-foo-enable-if.nix
+checkConfigOutput 'true' "$@" ./define-enable.nix ./define-if-loaOfSub-foo-enable.nix
+checkConfigOutput 'true' "$@" ./define-enable.nix ./define-loaOfSub-if-foo-enable.nix
+checkConfigOutput 'true' "$@" ./define-enable.nix ./define-loaOfSub-foo-if-enable.nix
+checkConfigOutput 'true' "$@" ./define-enable.nix ./define-loaOfSub-foo-enable-if.nix
+
+# Check disabledModules with config definitions and option declarations.
+set -- config.enable ./define-enable.nix ./declare-enable.nix
+checkConfigOutput "true" "$@"
+checkConfigOutput "false" "$@" ./disable-define-enable.nix
+checkConfigError "The option .*enable.* defined in .* does not exist" "$@" ./disable-declare-enable.nix
+checkConfigError "attribute .*enable.* in selection path .*config.enable.* not found" "$@" ./disable-define-enable.nix ./disable-declare-enable.nix
+checkConfigError "attribute .*enable.* in selection path .*config.enable.* not found" "$@" ./disable-enable-modules.nix
+
+# Check _module.args.
+set -- config.enable ./declare-enable.nix ./define-enable-with-custom-arg.nix
+checkConfigError 'while evaluating the module argument .*custom.* in .*define-enable-with-custom-arg.nix.*:' "$@"
+checkConfigOutput "true" "$@" ./define-_module-args-custom.nix
+
+# Check that using _module.args on imports cause infinite recursions, with
+# the proper error context.
+set -- "$@" ./define-_module-args-custom.nix ./import-custom-arg.nix
+checkConfigError 'while evaluating the module argument .*custom.* in .*import-custom-arg.nix.*:' "$@"
+checkConfigError 'infinite recursion encountered' "$@"
+
+# Check _module.check.
+set -- config.enable ./declare-enable.nix ./define-enable.nix ./define-loaOfSub-foo.nix
+checkConfigError 'The option .* defined in .* does not exist.' "$@"
+checkConfigOutput "true" "$@" ./define-module-check.nix
+
+# Check coerced value.
+checkConfigOutput "\"42\"" config.value ./declare-coerced-value.nix
+checkConfigOutput "\"24\"" config.value ./declare-coerced-value.nix ./define-value-string.nix
+checkConfigError 'The option value .* in .* is not.*string or signed integer convertible to it' config.value ./declare-coerced-value.nix ./define-value-list.nix
+
+# Check coerced value with unsound coercion
+checkConfigOutput "12" config.value ./declare-coerced-value-unsound.nix
+checkConfigError 'The option value .* in .* is not.*8 bit signed integer.* or string convertible to it' config.value ./declare-coerced-value-unsound.nix ./define-value-string-bigint.nix
+checkConfigError 'unrecognised JSON value' config.value ./declare-coerced-value-unsound.nix ./define-value-string-arbitrary.nix
+
+# Check loaOf with long list.
+checkConfigOutput "1 2 3 4 5 6 7 8 9 10" config.result ./loaOf-with-long-list.nix
+
+# Check loaOf with many merges of lists.
+checkConfigOutput "1 2 3 4 5 6 7 8 9 10" config.result ./loaOf-with-many-list-merges.nix
+
+cat <<EOF
+====== module tests ======
+$pass Pass
+$fail Fail
+EOF
+
+if test $fail -ne 0; then
+    exit 1
+fi
+exit 0
diff --git a/nixpkgs/lib/tests/modules/declare-coerced-value-unsound.nix b/nixpkgs/lib/tests/modules/declare-coerced-value-unsound.nix
new file mode 100644
index 000000000000..7a017f24e77d
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/declare-coerced-value-unsound.nix
@@ -0,0 +1,10 @@
+{ lib, ... }:
+
+{
+  options = {
+    value = lib.mkOption {
+      default = "12";
+      type = lib.types.coercedTo lib.types.str lib.toInt lib.types.ints.s8;
+    };
+  };
+}
diff --git a/nixpkgs/lib/tests/modules/declare-coerced-value.nix b/nixpkgs/lib/tests/modules/declare-coerced-value.nix
new file mode 100644
index 000000000000..76b12ad53f00
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/declare-coerced-value.nix
@@ -0,0 +1,10 @@
+{ lib, ... }:
+
+{
+  options = {
+    value = lib.mkOption {
+      default = 42;
+      type = lib.types.coercedTo lib.types.int builtins.toString lib.types.str;
+    };
+  };
+}
diff --git a/nixpkgs/lib/tests/modules/declare-enable.nix b/nixpkgs/lib/tests/modules/declare-enable.nix
new file mode 100644
index 000000000000..ebee243c7568
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/declare-enable.nix
@@ -0,0 +1,14 @@
+{ lib, ... }:
+
+{
+  options = {
+    enable = lib.mkOption {
+      default = false;
+      example = true;
+      type = lib.types.bool;
+      description = ''
+        Some descriptive text
+      '';
+    };
+  };
+}
diff --git a/nixpkgs/lib/tests/modules/declare-int-between-value.nix b/nixpkgs/lib/tests/modules/declare-int-between-value.nix
new file mode 100644
index 000000000000..8b2624cc5d65
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/declare-int-between-value.nix
@@ -0,0 +1,9 @@
+{ lib, ... }:
+
+{
+  options = {
+    value = lib.mkOption {
+      type = lib.types.ints.between (-21) 43;
+    };
+  };
+}
diff --git a/nixpkgs/lib/tests/modules/declare-int-positive-value.nix b/nixpkgs/lib/tests/modules/declare-int-positive-value.nix
new file mode 100644
index 000000000000..6e48c6ac8feb
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/declare-int-positive-value.nix
@@ -0,0 +1,9 @@
+{ lib, ... }:
+
+{
+  options = {
+    value = lib.mkOption {
+      type = lib.types.ints.positive;
+    };
+  };
+}
diff --git a/nixpkgs/lib/tests/modules/declare-int-unsigned-value.nix b/nixpkgs/lib/tests/modules/declare-int-unsigned-value.nix
new file mode 100644
index 000000000000..05d0eff01c94
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/declare-int-unsigned-value.nix
@@ -0,0 +1,9 @@
+{ lib, ... }:
+
+{
+  options = {
+    value = lib.mkOption {
+      type = lib.types.ints.unsigned;
+    };
+  };
+}
diff --git a/nixpkgs/lib/tests/modules/declare-loaOfSub-any-enable.nix b/nixpkgs/lib/tests/modules/declare-loaOfSub-any-enable.nix
new file mode 100644
index 000000000000..71dad1c91359
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/declare-loaOfSub-any-enable.nix
@@ -0,0 +1,29 @@
+{ lib, ... }:
+
+let
+  submod = { ... }: {
+    options = {
+      enable = lib.mkOption {
+        default = false;
+        example = true;
+        type = lib.types.bool;
+        description = ''
+          Some descriptive text
+        '';
+      };
+    };
+  };
+in
+
+{
+  options = {
+    loaOfSub = lib.mkOption {
+      default = {};
+      example = {};
+      type = lib.types.loaOf (lib.types.submodule [ submod ]);
+      description = ''
+        Some descriptive text
+      '';
+    };
+  };
+}
diff --git a/nixpkgs/lib/tests/modules/default.nix b/nixpkgs/lib/tests/modules/default.nix
new file mode 100644
index 000000000000..5b0947104198
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/default.nix
@@ -0,0 +1,8 @@
+{ lib ? import ../.., modules ? [] }:
+
+{
+  inherit (lib.evalModules {
+    inherit modules;
+    specialArgs.modulesPath = ./.;
+  }) config options;
+}
diff --git a/nixpkgs/lib/tests/modules/define-_module-args-custom.nix b/nixpkgs/lib/tests/modules/define-_module-args-custom.nix
new file mode 100644
index 000000000000..e565fd215a57
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/define-_module-args-custom.nix
@@ -0,0 +1,7 @@
+{ lib, ... }:
+
+{
+  config = {
+    _module.args.custom = true;
+  };
+}
diff --git a/nixpkgs/lib/tests/modules/define-enable-force.nix b/nixpkgs/lib/tests/modules/define-enable-force.nix
new file mode 100644
index 000000000000..f4990a328631
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/define-enable-force.nix
@@ -0,0 +1,5 @@
+{ lib, ... }:
+
+{
+  enable = lib.mkForce false;
+}
diff --git a/nixpkgs/lib/tests/modules/define-enable-with-custom-arg.nix b/nixpkgs/lib/tests/modules/define-enable-with-custom-arg.nix
new file mode 100644
index 000000000000..7da74671d148
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/define-enable-with-custom-arg.nix
@@ -0,0 +1,7 @@
+{ lib, custom, ... }:
+
+{
+  config = {
+    enable = custom;
+  };
+}
diff --git a/nixpkgs/lib/tests/modules/define-enable.nix b/nixpkgs/lib/tests/modules/define-enable.nix
new file mode 100644
index 000000000000..7dc26010ae59
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/define-enable.nix
@@ -0,0 +1,3 @@
+{
+  enable = true;
+}
diff --git a/nixpkgs/lib/tests/modules/define-force-enable.nix b/nixpkgs/lib/tests/modules/define-force-enable.nix
new file mode 100644
index 000000000000..978caa2a8c07
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/define-force-enable.nix
@@ -0,0 +1,5 @@
+{ lib, ... }:
+
+lib.mkForce {
+  enable = false;
+}
diff --git a/nixpkgs/lib/tests/modules/define-force-loaOfSub-foo-enable.nix b/nixpkgs/lib/tests/modules/define-force-loaOfSub-foo-enable.nix
new file mode 100644
index 000000000000..bfd8e084b590
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/define-force-loaOfSub-foo-enable.nix
@@ -0,0 +1,5 @@
+{ lib, ... }:
+
+lib.mkForce {
+  loaOfSub.foo.enable = false;
+}
diff --git a/nixpkgs/lib/tests/modules/define-if-loaOfSub-foo-enable.nix b/nixpkgs/lib/tests/modules/define-if-loaOfSub-foo-enable.nix
new file mode 100644
index 000000000000..4288d74dec00
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/define-if-loaOfSub-foo-enable.nix
@@ -0,0 +1,5 @@
+{ config, lib, ... }:
+
+lib.mkIf config.enable {
+  loaOfSub.foo.enable = true;
+}
diff --git a/nixpkgs/lib/tests/modules/define-loaOfSub-bar-enable.nix b/nixpkgs/lib/tests/modules/define-loaOfSub-bar-enable.nix
new file mode 100644
index 000000000000..422bb0a600bf
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/define-loaOfSub-bar-enable.nix
@@ -0,0 +1,3 @@
+{
+  loaOfSub.bar.enable = true;
+}
diff --git a/nixpkgs/lib/tests/modules/define-loaOfSub-bar.nix b/nixpkgs/lib/tests/modules/define-loaOfSub-bar.nix
new file mode 100644
index 000000000000..c24315e09b6e
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/define-loaOfSub-bar.nix
@@ -0,0 +1,3 @@
+{
+  loaOfSub.bar = {};
+}
diff --git a/nixpkgs/lib/tests/modules/define-loaOfSub-foo-enable-force.nix b/nixpkgs/lib/tests/modules/define-loaOfSub-foo-enable-force.nix
new file mode 100644
index 000000000000..c1d7b198be54
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/define-loaOfSub-foo-enable-force.nix
@@ -0,0 +1,5 @@
+{ lib, ... }:
+
+{
+  loaOfSub.foo.enable = lib.mkForce false;
+}
diff --git a/nixpkgs/lib/tests/modules/define-loaOfSub-foo-enable-if.nix b/nixpkgs/lib/tests/modules/define-loaOfSub-foo-enable-if.nix
new file mode 100644
index 000000000000..44b2c96cd021
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/define-loaOfSub-foo-enable-if.nix
@@ -0,0 +1,5 @@
+{ config, lib, ... }:
+
+{
+  loaOfSub.foo.enable = lib.mkIf config.enable true;
+}
diff --git a/nixpkgs/lib/tests/modules/define-loaOfSub-foo-enable.nix b/nixpkgs/lib/tests/modules/define-loaOfSub-foo-enable.nix
new file mode 100644
index 000000000000..822425c71bb9
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/define-loaOfSub-foo-enable.nix
@@ -0,0 +1,3 @@
+{
+  loaOfSub.foo.enable = true;
+}
diff --git a/nixpkgs/lib/tests/modules/define-loaOfSub-foo-force-enable.nix b/nixpkgs/lib/tests/modules/define-loaOfSub-foo-force-enable.nix
new file mode 100644
index 000000000000..dce0ef547b31
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/define-loaOfSub-foo-force-enable.nix
@@ -0,0 +1,7 @@
+{ lib, ... }:
+
+{
+  loaOfSub.foo = lib.mkForce {
+    enable = false;
+  };
+}
diff --git a/nixpkgs/lib/tests/modules/define-loaOfSub-foo-if-enable.nix b/nixpkgs/lib/tests/modules/define-loaOfSub-foo-if-enable.nix
new file mode 100644
index 000000000000..236b2840ee51
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/define-loaOfSub-foo-if-enable.nix
@@ -0,0 +1,7 @@
+{ config, lib, ... }:
+
+{
+  loaOfSub.foo = lib.mkIf config.enable {
+    enable = true;
+  };
+}
diff --git a/nixpkgs/lib/tests/modules/define-loaOfSub-foo.nix b/nixpkgs/lib/tests/modules/define-loaOfSub-foo.nix
new file mode 100644
index 000000000000..e9b2e631f2ec
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/define-loaOfSub-foo.nix
@@ -0,0 +1,3 @@
+{
+  loaOfSub.foo = {};
+}
diff --git a/nixpkgs/lib/tests/modules/define-loaOfSub-force-foo-enable.nix b/nixpkgs/lib/tests/modules/define-loaOfSub-force-foo-enable.nix
new file mode 100644
index 000000000000..df5722274ee5
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/define-loaOfSub-force-foo-enable.nix
@@ -0,0 +1,7 @@
+{ lib, ... }:
+
+{
+  loaOfSub = lib.mkForce {
+    foo.enable = false;
+  };
+}
diff --git a/nixpkgs/lib/tests/modules/define-loaOfSub-if-foo-enable.nix b/nixpkgs/lib/tests/modules/define-loaOfSub-if-foo-enable.nix
new file mode 100644
index 000000000000..bd2d068d31a2
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/define-loaOfSub-if-foo-enable.nix
@@ -0,0 +1,7 @@
+{ config, lib, ... }:
+
+{
+  loaOfSub = lib.mkIf config.enable {
+    foo.enable = true;
+  };
+}
diff --git a/nixpkgs/lib/tests/modules/define-module-check.nix b/nixpkgs/lib/tests/modules/define-module-check.nix
new file mode 100644
index 000000000000..5a0707c975fa
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/define-module-check.nix
@@ -0,0 +1,3 @@
+{
+  _module.check = false;
+}
diff --git a/nixpkgs/lib/tests/modules/define-value-int-negative.nix b/nixpkgs/lib/tests/modules/define-value-int-negative.nix
new file mode 100644
index 000000000000..a041222987ad
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/define-value-int-negative.nix
@@ -0,0 +1,3 @@
+{
+  value = -23;
+}
diff --git a/nixpkgs/lib/tests/modules/define-value-int-positive.nix b/nixpkgs/lib/tests/modules/define-value-int-positive.nix
new file mode 100644
index 000000000000..5803de172636
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/define-value-int-positive.nix
@@ -0,0 +1,3 @@
+{
+  value = 42;
+}
diff --git a/nixpkgs/lib/tests/modules/define-value-int-zero.nix b/nixpkgs/lib/tests/modules/define-value-int-zero.nix
new file mode 100644
index 000000000000..68bb9f415c3c
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/define-value-int-zero.nix
@@ -0,0 +1,3 @@
+{
+  value = 0;
+}
diff --git a/nixpkgs/lib/tests/modules/define-value-list.nix b/nixpkgs/lib/tests/modules/define-value-list.nix
new file mode 100644
index 000000000000..4831c1cc09ba
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/define-value-list.nix
@@ -0,0 +1,3 @@
+{
+  value = [];
+}
diff --git a/nixpkgs/lib/tests/modules/define-value-string-arbitrary.nix b/nixpkgs/lib/tests/modules/define-value-string-arbitrary.nix
new file mode 100644
index 000000000000..8e3abaf536a0
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/define-value-string-arbitrary.nix
@@ -0,0 +1,3 @@
+{
+  value = "foobar";
+}
diff --git a/nixpkgs/lib/tests/modules/define-value-string-bigint.nix b/nixpkgs/lib/tests/modules/define-value-string-bigint.nix
new file mode 100644
index 000000000000..f27e31985c92
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/define-value-string-bigint.nix
@@ -0,0 +1,3 @@
+{
+  value = "1000";
+}
diff --git a/nixpkgs/lib/tests/modules/define-value-string.nix b/nixpkgs/lib/tests/modules/define-value-string.nix
new file mode 100644
index 000000000000..e7a166965a7a
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/define-value-string.nix
@@ -0,0 +1,3 @@
+{
+  value = "24";
+}
diff --git a/nixpkgs/lib/tests/modules/disable-declare-enable.nix b/nixpkgs/lib/tests/modules/disable-declare-enable.nix
new file mode 100644
index 000000000000..a373ee7e550e
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/disable-declare-enable.nix
@@ -0,0 +1,5 @@
+{ lib, ... }:
+
+{
+  disabledModules = [ ./declare-enable.nix ];
+}
diff --git a/nixpkgs/lib/tests/modules/disable-define-enable.nix b/nixpkgs/lib/tests/modules/disable-define-enable.nix
new file mode 100644
index 000000000000..0d84a7c3cb6c
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/disable-define-enable.nix
@@ -0,0 +1,5 @@
+{ lib, ... }:
+
+{
+  disabledModules = [ ./define-enable.nix ];
+}
diff --git a/nixpkgs/lib/tests/modules/disable-enable-modules.nix b/nixpkgs/lib/tests/modules/disable-enable-modules.nix
new file mode 100644
index 000000000000..c325f4e07431
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/disable-enable-modules.nix
@@ -0,0 +1,5 @@
+{ lib, ... }:
+
+{
+  disabledModules = [ "define-enable.nix" "declare-enable.nix" ];
+}
diff --git a/nixpkgs/lib/tests/modules/import-custom-arg.nix b/nixpkgs/lib/tests/modules/import-custom-arg.nix
new file mode 100644
index 000000000000..3e687b661c16
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/import-custom-arg.nix
@@ -0,0 +1,6 @@
+{ lib, custom, ... }:
+
+{
+  imports = []
+  ++ lib.optional custom ./define-enable-force.nix;
+}
diff --git a/nixpkgs/lib/tests/modules/loaOf-with-long-list.nix b/nixpkgs/lib/tests/modules/loaOf-with-long-list.nix
new file mode 100644
index 000000000000..f30903c47e50
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/loaOf-with-long-list.nix
@@ -0,0 +1,19 @@
+{ config, lib, ... }:
+
+{
+  options = {
+    loaOfInt = lib.mkOption {
+      type = lib.types.loaOf lib.types.int;
+    };
+
+    result = lib.mkOption {
+      type = lib.types.str;
+    };
+  };
+
+  config = {
+    loaOfInt = [ 1 2 3 4 5 6 7 8 9 10 ];
+
+    result = toString (lib.attrValues config.loaOfInt);
+  };
+}
diff --git a/nixpkgs/lib/tests/modules/loaOf-with-many-list-merges.nix b/nixpkgs/lib/tests/modules/loaOf-with-many-list-merges.nix
new file mode 100644
index 000000000000..f8f8a8da82bc
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/loaOf-with-many-list-merges.nix
@@ -0,0 +1,19 @@
+{ config, lib, ... }:
+
+{
+  options = {
+    loaOfInt = lib.mkOption {
+      type = lib.types.loaOf lib.types.int;
+    };
+
+    result = lib.mkOption {
+      type = lib.types.str;
+    };
+  };
+
+  config = {
+    loaOfInt = lib.mkMerge (map lib.singleton [ 1 2 3 4 5 6 7 8 9 10 ]);
+
+    result = toString (lib.attrValues config.loaOfInt);
+  };
+}
diff --git a/nixpkgs/lib/tests/release.nix b/nixpkgs/lib/tests/release.nix
new file mode 100644
index 000000000000..d9a8a0067253
--- /dev/null
+++ b/nixpkgs/lib/tests/release.nix
@@ -0,0 +1,31 @@
+{ pkgs ? import ((import ../.).cleanSource ../..) {} }:
+
+pkgs.stdenv.mkDerivation {
+  name = "nixpkgs-lib-tests";
+  buildInputs = [ pkgs.nix ];
+  NIX_PATH="nixpkgs=${pkgs.path}";
+
+  buildCommand = ''
+    datadir="${pkgs.nix}/share"
+    export TEST_ROOT=$(pwd)/test-tmp
+    export NIX_BUILD_HOOK=
+    export NIX_CONF_DIR=$TEST_ROOT/etc
+    export NIX_DB_DIR=$TEST_ROOT/db
+    export NIX_LOCALSTATE_DIR=$TEST_ROOT/var
+    export NIX_LOG_DIR=$TEST_ROOT/var/log/nix
+    export NIX_STATE_DIR=$TEST_ROOT/var/nix
+    export NIX_STORE_DIR=$TEST_ROOT/store
+    export PAGER=cat
+    cacheDir=$TEST_ROOT/binary-cache
+    nix-store --init
+
+    cd ${pkgs.path}/lib/tests
+    bash ./modules.sh
+
+    [[ "$(nix-instantiate --eval --strict misc.nix)" == "[ ]" ]]
+
+    [[ "$(nix-instantiate --eval --strict systems.nix)" == "[ ]" ]]
+
+    touch $out
+  '';
+}
diff --git a/nixpkgs/lib/tests/systems.nix b/nixpkgs/lib/tests/systems.nix
new file mode 100644
index 000000000000..5e1293658215
--- /dev/null
+++ b/nixpkgs/lib/tests/systems.nix
@@ -0,0 +1,32 @@
+# We assert that the new algorithmic way of generating these lists matches the
+# way they were hard-coded before.
+#
+# One might think "if we exhaustively test, what's the point of procedurally
+# calculating the lists anyway?". The answer is one can mindlessly update these
+# tests as new platforms become supported, and then just give the diff a quick
+# sanity check before committing :).
+let
+  lib = import ../default.nix;
+  mseteq = x: y: {
+    expr     = lib.sort lib.lessThan x;
+    expected = lib.sort lib.lessThan y;
+  };
+in with lib.systems.doubles; lib.runTests {
+  testall = mseteq all (linux ++ darwin ++ freebsd ++ openbsd ++ netbsd ++ illumos ++ windows);
+
+  testarm = mseteq arm [ "armv5tel-linux" "armv6l-linux" "armv7l-linux" ];
+  testi686 = mseteq i686 [ "i686-linux" "i686-freebsd" "i686-netbsd" "i686-openbsd" "i686-cygwin" "i686-windows" ];
+  testmips = mseteq mips [ "mipsel-linux" ];
+  testx86_64 = mseteq x86_64 [ "x86_64-linux" "x86_64-darwin" "x86_64-freebsd" "x86_64-openbsd" "x86_64-netbsd" "x86_64-cygwin" "x86_64-solaris" "x86_64-windows" ];
+
+  testcygwin = mseteq cygwin [ "i686-cygwin" "x86_64-cygwin" ];
+  testdarwin = mseteq darwin [ "x86_64-darwin" ];
+  testfreebsd = mseteq freebsd [ "i686-freebsd" "x86_64-freebsd" ];
+  testgnu = mseteq gnu (linux /* ++ kfreebsd ++ ... */);
+  testillumos = mseteq illumos [ "x86_64-solaris" ];
+  testlinux = mseteq linux [ "i686-linux" "x86_64-linux" "armv5tel-linux" "armv6l-linux" "armv7l-linux" "aarch64-linux" "mipsel-linux" ];
+  testnetbsd = mseteq netbsd [ "i686-netbsd" "x86_64-netbsd" ];
+  testopenbsd = mseteq openbsd [ "i686-openbsd" "x86_64-openbsd" ];
+  testwindows = mseteq windows [ "i686-cygwin" "x86_64-cygwin" "i686-windows" "x86_64-windows" ];
+  testunix = mseteq unix (linux ++ darwin ++ freebsd ++ openbsd ++ netbsd ++ illumos ++ cygwin);
+}
diff --git a/nixpkgs/lib/trivial.nix b/nixpkgs/lib/trivial.nix
new file mode 100644
index 000000000000..17489311236d
--- /dev/null
+++ b/nixpkgs/lib/trivial.nix
@@ -0,0 +1,297 @@
+{ lib }:
+
+rec {
+
+  ## Simple (higher order) functions
+
+  /* The identity function
+     For when you need a function that does “nothing”.
+
+     Type: id :: a -> a
+  */
+  id =
+    # The value to return
+    x: x;
+
+  /* The constant function
+
+     Ignores the second argument. If called with only one argument,
+     constructs a function that always returns a static value.
+
+     Type: const :: a -> b -> a
+     Example:
+       let f = const 5; in f 10
+       => 5
+  */
+  const =
+    # Value to return
+    x:
+    # Value to ignore
+    y: x;
+
+
+  ## Named versions corresponding to some builtin operators.
+
+  /* Concatenate two lists
+
+     Type: concat :: [a] -> [a] -> [a]
+
+     Example:
+       concat [ 1 2 ] [ 3 4 ]
+       => [ 1 2 3 4 ]
+  */
+  concat = x: y: x ++ y;
+
+  /* boolean “or” */
+  or = x: y: x || y;
+
+  /* boolean “and” */
+  and = x: y: x && y;
+
+  /* bitwise “and” */
+  bitAnd = builtins.bitAnd
+    or (import ./zip-int-bits.nix
+        (a: b: if a==1 && b==1 then 1 else 0));
+
+  /* bitwise “or” */
+  bitOr = builtins.bitOr
+    or (import ./zip-int-bits.nix
+        (a: b: if a==1 || b==1 then 1 else 0));
+
+  /* bitwise “xor” */
+  bitXor = builtins.bitXor
+    or (import ./zip-int-bits.nix
+        (a: b: if a!=b then 1 else 0));
+
+  /* bitwise “not” */
+  bitNot = builtins.sub (-1);
+
+  /* Convert a boolean to a string.
+
+     This function uses the strings "true" and "false" to represent
+     boolean values. Calling `toString` on a bool instead returns "1"
+     and "" (sic!).
+
+     Type: boolToString :: bool -> string
+  */
+  boolToString = b: if b then "true" else "false";
+
+  /* Merge two attribute sets shallowly, right side trumps left
+
+     mergeAttrs :: attrs -> attrs -> attrs
+
+     Example:
+       mergeAttrs { a = 1; b = 2; } { b = 3; c = 4; }
+       => { a = 1; b = 3; c = 4; }
+  */
+  mergeAttrs =
+    # Left attribute set
+    x:
+    # Right attribute set (higher precedence for equal keys)
+    y: x // y;
+
+  /* Flip the order of the arguments of a binary function.
+
+     Type: flip :: (a -> b -> c) -> (b -> a -> c)
+
+     Example:
+       flip concat [1] [2]
+       => [ 2 1 ]
+  */
+  flip = f: a: b: f b a;
+
+  /* Apply function if the supplied argument is non-null.
+
+     Example:
+       mapNullable (x: x+1) null
+       => null
+       mapNullable (x: x+1) 22
+       => 23
+  */
+  mapNullable =
+    # Function to call
+    f:
+    # Argument to check for null before passing it to `f`
+    a: if isNull a then a else f a;
+
+  # Pull in some builtins not included elsewhere.
+  inherit (builtins)
+    pathExists readFile isBool
+    isInt isFloat add sub lessThan
+    seq deepSeq genericClosure;
+
+
+  ## nixpks version strings
+
+  /* Returns the current full nixpkgs version number. */
+  version = release + versionSuffix;
+
+  /* Returns the current nixpkgs release number as string. */
+  release = lib.strings.fileContents ../.version;
+
+  /* Returns the current nixpkgs release code name.
+
+     On each release the first letter is bumped and a new animal is chosen
+     starting with that new letter.
+  */
+  codeName = "Koi";
+
+  /* Returns the current nixpkgs version suffix as string. */
+  versionSuffix =
+    let suffixFile = ../.version-suffix;
+    in if pathExists suffixFile
+    then lib.strings.fileContents suffixFile
+    else "pre-git";
+
+  /* Attempts to return the the current revision of nixpkgs and
+     returns the supplied default value otherwise.
+
+     Type: revisionWithDefault :: string -> string
+  */
+  revisionWithDefault =
+    # Default value to return if revision can not be determined
+    default:
+    let
+      revisionFile = "${toString ./..}/.git-revision";
+      gitRepo      = "${toString ./..}/.git";
+    in if lib.pathIsDirectory gitRepo
+       then lib.commitIdFromGitRepo gitRepo
+       else if lib.pathExists revisionFile then lib.fileContents revisionFile
+       else default;
+
+  nixpkgsVersion = builtins.trace "`lib.nixpkgsVersion` is deprecated, use `lib.version` instead!" version;
+
+  /* Determine whether the function is being called from inside a Nix
+     shell.
+
+     Type: inNixShell :: bool
+  */
+  inNixShell = builtins.getEnv "IN_NIX_SHELL" != "";
+
+
+  ## Integer operations
+
+  /* Return minimum of two numbers. */
+  min = x: y: if x < y then x else y;
+
+  /* Return maximum of two numbers. */
+  max = x: y: if x > y then x else y;
+
+  /* Integer modulus
+
+     Example:
+       mod 11 10
+       => 1
+       mod 1 10
+       => 1
+  */
+  mod = base: int: base - (int * (builtins.div base int));
+
+
+  ## Comparisons
+
+  /* C-style comparisons
+
+     a < b,  compare a b => -1
+     a == b, compare a b => 0
+     a > b,  compare a b => 1
+  */
+  compare = a: b:
+    if a < b
+    then -1
+    else if a > b
+         then 1
+         else 0;
+
+  /* Split type into two subtypes by predicate `p`, take all elements
+     of the first subtype to be less than all the elements of the
+     second subtype, compare elements of a single subtype with `yes`
+     and `no` respectively.
+
+     Type: (a -> bool) -> (a -> a -> int) -> (a -> a -> int) -> (a -> a -> int)
+
+     Example:
+       let cmp = splitByAndCompare (hasPrefix "foo") compare compare; in
+
+       cmp "a" "z" => -1
+       cmp "fooa" "fooz" => -1
+
+       cmp "f" "a" => 1
+       cmp "fooa" "a" => -1
+       # while
+       compare "fooa" "a" => 1
+  */
+  splitByAndCompare =
+    # Predicate
+    p:
+    # Comparison function if predicate holds for both values
+    yes:
+    # Comparison function if predicate holds for neither value
+    no:
+    # First value to compare
+    a:
+    # Second value to compare
+    b:
+    if p a
+    then if p b then yes a b else -1
+    else if p b then 1 else no a b;
+
+
+  /* Reads a JSON file.
+
+     Type :: path -> any
+  */
+  importJSON = path:
+    builtins.fromJSON (builtins.readFile path);
+
+
+  ## Warnings
+
+  # See https://github.com/NixOS/nix/issues/749. Eventually we'd like these
+  # to expand to Nix builtins that carry metadata so that Nix can filter out
+  # the INFO messages without parsing the message string.
+  #
+  # Usage:
+  # {
+  #   foo = lib.warn "foo is deprecated" oldFoo;
+  # }
+  #
+  # TODO: figure out a clever way to integrate location information from
+  # something like __unsafeGetAttrPos.
+
+  warn = msg: builtins.trace "WARNING: ${msg}";
+  info = msg: builtins.trace "INFO: ${msg}";
+
+
+  ## Function annotations
+
+  /* Add metadata about expected function arguments to a function.
+     The metadata should match the format given by
+     builtins.functionArgs, i.e. a set from expected argument to a bool
+     representing whether that argument has a default or not.
+     setFunctionArgs : (a → b) → Map String Bool → (a → b)
+
+     This function is necessary because you can't dynamically create a
+     function of the { a, b ? foo, ... }: format, but some facilities
+     like callPackage expect to be able to query expected arguments.
+  */
+  setFunctionArgs = f: args:
+    { # TODO: Should we add call-time "type" checking like built in?
+      __functor = self: f;
+      __functionArgs = args;
+    };
+
+  /* Extract the expected function arguments from a function.
+     This works both with nix-native { a, b ? foo, ... }: style
+     functions and functions with args set with 'setFunctionArgs'. It
+     has the same return type and semantics as builtins.functionArgs.
+     setFunctionArgs : (a → b) → Map String Bool.
+  */
+  functionArgs = f: f.__functionArgs or (builtins.functionArgs f);
+
+  /* Check whether something is a function or something
+     annotated with function args.
+  */
+  isFunction = f: builtins.isFunction f ||
+    (f ? __functor && isFunction (f.__functor f));
+}
diff --git a/nixpkgs/lib/types.nix b/nixpkgs/lib/types.nix
new file mode 100644
index 000000000000..d1ece2402ad7
--- /dev/null
+++ b/nixpkgs/lib/types.nix
@@ -0,0 +1,484 @@
+# Definitions related to run-time type checking.  Used in particular
+# to type-check NixOS configurations.
+{ lib }:
+with lib.lists;
+with lib.attrsets;
+with lib.options;
+with lib.trivial;
+with lib.strings;
+let
+
+  inherit (lib.modules) mergeDefinitions;
+  outer_types =
+rec {
+  isType = type: x: (x._type or "") == type;
+
+  setType = typeName: value: value // {
+    _type = typeName;
+  };
+
+
+  # Default type merging function
+  # takes two type functors and return the merged type
+  defaultTypeMerge = f: f':
+    let wrapped = f.wrapped.typeMerge f'.wrapped.functor;
+        payload = f.binOp f.payload f'.payload;
+    in
+    # cannot merge different types
+    if f.name != f'.name
+       then null
+    # simple types
+    else if    (f.wrapped == null && f'.wrapped == null)
+            && (f.payload == null && f'.payload == null)
+       then f.type
+    # composed types
+    else if (f.wrapped != null && f'.wrapped != null) && (wrapped != null)
+       then f.type wrapped
+    # value types
+    else if (f.payload != null && f'.payload != null) && (payload != null)
+       then f.type payload
+    else null;
+
+  # Default type functor
+  defaultFunctor = name: {
+    inherit name;
+    type    = types."${name}" or null;
+    wrapped = null;
+    payload = null;
+    binOp   = a: b: null;
+  };
+
+  isOptionType = isType "option-type";
+  mkOptionType =
+    { # Human-readable representation of the type, should be equivalent to
+      # the type function name.
+      name
+    , # Description of the type, defined recursively by embedding the wrapped type if any.
+      description ? null
+    , # Function applied to each definition that should return true if
+      # its type-correct, false otherwise.
+      check ? (x: true)
+    , # Merge a list of definitions together into a single value.
+      # This function is called with two arguments: the location of
+      # the option in the configuration as a list of strings
+      # (e.g. ["boot" "loader "grub" "enable"]), and a list of
+      # definition values and locations (e.g. [ { file = "/foo.nix";
+      # value = 1; } { file = "/bar.nix"; value = 2 } ]).
+      merge ? mergeDefaultOption
+    , # Return a flat list of sub-options.  Used to generate
+      # documentation.
+      getSubOptions ? prefix: {}
+    , # List of modules if any, or null if none.
+      getSubModules ? null
+    , # Function for building the same option type with a different list of
+      # modules.
+      substSubModules ? m: null
+    , # Function that merge type declarations.
+      # internal, takes a functor as argument and returns the merged type.
+      # returning null means the type is not mergeable
+      typeMerge ? defaultTypeMerge functor
+    , # The type functor.
+      # internal, representation of the type as an attribute set.
+      #   name: name of the type
+      #   type: type function.
+      #   wrapped: the type wrapped in case of compound types.
+      #   payload: values of the type, two payloads of the same type must be
+      #            combinable with the binOp binary operation.
+      #   binOp: binary operation that merge two payloads of the same type.
+      functor ? defaultFunctor name
+    }:
+    { _type = "option-type";
+      inherit name check merge getSubOptions getSubModules substSubModules typeMerge functor;
+      description = if description == null then name else description;
+    };
+
+
+  # When adding new types don't forget to document them in
+  # nixos/doc/manual/development/option-types.xml!
+  types = rec {
+    unspecified = mkOptionType {
+      name = "unspecified";
+    };
+
+    bool = mkOptionType {
+      name = "bool";
+      description = "boolean";
+      check = isBool;
+      merge = mergeEqualOption;
+    };
+
+    int = mkOptionType rec {
+        name = "int";
+        description = "signed integer";
+        check = isInt;
+        merge = mergeOneOption;
+      };
+
+    # Specialized subdomains of int
+    ints =
+      let
+        betweenDesc = lowest: highest:
+          "${toString lowest} and ${toString highest} (both inclusive)";
+        between = lowest: highest:
+          assert lib.assertMsg (lowest <= highest)
+            "ints.between: lowest must be smaller than highest";
+          addCheck int (x: x >= lowest && x <= highest) // {
+            name = "intBetween";
+            description = "integer between ${betweenDesc lowest highest}";
+          };
+        ign = lowest: highest: name: docStart:
+          between lowest highest // {
+            inherit name;
+            description = docStart + "; between ${betweenDesc lowest highest}";
+          };
+        unsign = bit: range: ign 0 (range - 1)
+          "unsignedInt${toString bit}" "${toString bit} bit unsigned integer";
+        sign = bit: range: ign (0 - (range / 2)) (range / 2 - 1)
+          "signedInt${toString bit}" "${toString bit} bit signed integer";
+
+      in rec {
+        /* An int with a fixed range.
+        *
+        * Example:
+        *   (ints.between 0 100).check (-1)
+        *   => false
+        *   (ints.between 0 100).check (101)
+        *   => false
+        *   (ints.between 0 0).check 0
+        *   => true
+        */
+        inherit between;
+
+        unsigned = addCheck types.int (x: x >= 0) // {
+          name = "unsignedInt";
+          description = "unsigned integer, meaning >=0";
+        };
+        positive = addCheck types.int (x: x > 0) // {
+          name = "positiveInt";
+          description = "positive integer, meaning >0";
+        };
+        u8 = unsign 8 256;
+        u16 = unsign 16 65536;
+        # the biggest int a 64-bit Nix accepts is 2^63 - 1 (9223372036854775808), for a 32-bit Nix it is 2^31 - 1 (2147483647)
+        # the smallest int a 64-bit Nix accepts is -2^63 (-9223372036854775807), for a 32-bit Nix it is -2^31 (-2147483648)
+        # u32 = unsign 32 4294967296;
+        # u64 = unsign 64 18446744073709551616;
+
+        s8 = sign 8 256;
+        s16 = sign 16 65536;
+        # s32 = sign 32 4294967296;
+      };
+
+    # Alias of u16 for a port number
+    port = ints.u16;
+
+    float = mkOptionType rec {
+        name = "float";
+        description = "floating point number";
+        check = isFloat;
+        merge = mergeOneOption;
+    };
+
+    str = mkOptionType {
+      name = "str";
+      description = "string";
+      check = isString;
+      merge = mergeOneOption;
+    };
+
+    strMatching = pattern: mkOptionType {
+      name = "strMatching ${escapeNixString pattern}";
+      description = "string matching the pattern ${pattern}";
+      check = x: str.check x && builtins.match pattern x != null;
+      inherit (str) merge;
+    };
+
+    # Merge multiple definitions by concatenating them (with the given
+    # separator between the values).
+    separatedString = sep: mkOptionType rec {
+      name = "separatedString";
+      description = if sep == ""
+        then "Concatenated string" # for types.string.
+        else "strings concatenated with ${builtins.toJSON sep}"
+      ;
+      check = isString;
+      merge = loc: defs: concatStringsSep sep (getValues defs);
+      functor = (defaultFunctor name) // {
+        payload = sep;
+        binOp = sepLhs: sepRhs:
+          if sepLhs == sepRhs then sepLhs
+          else null;
+      };
+    };
+
+    lines = separatedString "\n";
+    commas = separatedString ",";
+    envVar = separatedString ":";
+
+    # Deprecated; should not be used because it quietly concatenates
+    # strings, which is usually not what you want.
+    string = separatedString "";
+
+    attrs = mkOptionType {
+      name = "attrs";
+      description = "attribute set";
+      check = isAttrs;
+      merge = loc: foldl' (res: def: mergeAttrs res def.value) {};
+    };
+
+    # derivation is a reserved keyword.
+    package = mkOptionType {
+      name = "package";
+      check = x: isDerivation x || isStorePath x;
+      merge = loc: defs:
+        let res = mergeOneOption loc defs;
+        in if isDerivation res then res else toDerivation res;
+    };
+
+    shellPackage = package // {
+      check = x: (package.check x) && (hasAttr "shellPath" x);
+    };
+
+    path = mkOptionType {
+      name = "path";
+      # Hacky: there is no ‘isPath’ primop.
+      check = x: builtins.substring 0 1 (toString x) == "/";
+      merge = mergeOneOption;
+    };
+
+    # drop this in the future:
+    list = builtins.trace "`types.list` is deprecated; use `types.listOf` instead" types.listOf;
+
+    listOf = elemType: mkOptionType rec {
+      name = "listOf";
+      description = "list of ${elemType.description}s";
+      check = isList;
+      merge = loc: defs:
+        map (x: x.value) (filter (x: x ? value) (concatLists (imap1 (n: def:
+          if isList def.value then
+            imap1 (m: def':
+              (mergeDefinitions
+                (loc ++ ["[definition ${toString n}-entry ${toString m}]"])
+                elemType
+                [{ inherit (def) file; value = def'; }]
+              ).optionalValue
+            ) def.value
+          else
+            throw "The option value `${showOption loc}` in `${def.file}` is not a list.") defs)));
+      getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["*"]);
+      getSubModules = elemType.getSubModules;
+      substSubModules = m: listOf (elemType.substSubModules m);
+      functor = (defaultFunctor name) // { wrapped = elemType; };
+    };
+
+    nonEmptyListOf = elemType:
+      let list = addCheck (types.listOf elemType) (l: l != []);
+      in list // { description = "non-empty " + list.description; };
+
+    attrsOf = elemType: mkOptionType rec {
+      name = "attrsOf";
+      description = "attribute set of ${elemType.description}s";
+      check = isAttrs;
+      merge = loc: defs:
+        mapAttrs (n: v: v.value) (filterAttrs (n: v: v ? value) (zipAttrsWith (name: defs:
+            (mergeDefinitions (loc ++ [name]) elemType defs).optionalValue
+          )
+          # Push down position info.
+          (map (def: listToAttrs (mapAttrsToList (n: def':
+            { name = n; value = { inherit (def) file; value = def'; }; }) def.value)) defs)));
+      getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name>"]);
+      getSubModules = elemType.getSubModules;
+      substSubModules = m: attrsOf (elemType.substSubModules m);
+      functor = (defaultFunctor name) // { wrapped = elemType; };
+    };
+
+    # List or attribute set of ...
+    loaOf = elemType:
+      let
+        convertAllLists = defs:
+          let
+            padWidth = stringLength (toString (length defs));
+            unnamedPrefix = i: "unnamed-" + fixedWidthNumber padWidth i + ".";
+          in
+            imap1 (i: convertIfList (unnamedPrefix i)) defs;
+
+        convertIfList = unnamedPrefix: def:
+          if isList def.value then
+            let
+              padWidth = stringLength (toString (length def.value));
+              unnamed = i: unnamedPrefix + fixedWidthNumber padWidth i;
+            in
+              { inherit (def) file;
+                value = listToAttrs (
+                  imap1 (elemIdx: elem:
+                    { name = elem.name or (unnamed elemIdx);
+                      value = elem;
+                    }) def.value);
+              }
+          else
+            def;
+        attrOnly = attrsOf elemType;
+      in mkOptionType rec {
+        name = "loaOf";
+        description = "list or attribute set of ${elemType.description}s";
+        check = x: isList x || isAttrs x;
+        merge = loc: defs: attrOnly.merge loc (convertAllLists defs);
+        getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name?>"]);
+        getSubModules = elemType.getSubModules;
+        substSubModules = m: loaOf (elemType.substSubModules m);
+        functor = (defaultFunctor name) // { wrapped = elemType; };
+      };
+
+    # Value of given type but with no merging (i.e. `uniq list`s are not concatenated).
+    uniq = elemType: mkOptionType rec {
+      name = "uniq";
+      inherit (elemType) description check;
+      merge = mergeOneOption;
+      getSubOptions = elemType.getSubOptions;
+      getSubModules = elemType.getSubModules;
+      substSubModules = m: uniq (elemType.substSubModules m);
+      functor = (defaultFunctor name) // { wrapped = elemType; };
+    };
+
+    # Null or value of ...
+    nullOr = elemType: mkOptionType rec {
+      name = "nullOr";
+      description = "null or ${elemType.description}";
+      check = x: x == null || elemType.check x;
+      merge = loc: defs:
+        let nrNulls = count (def: def.value == null) defs; in
+        if nrNulls == length defs then null
+        else if nrNulls != 0 then
+          throw "The option `${showOption loc}` is defined both null and not null, in ${showFiles (getFiles defs)}."
+        else elemType.merge loc defs;
+      getSubOptions = elemType.getSubOptions;
+      getSubModules = elemType.getSubModules;
+      substSubModules = m: nullOr (elemType.substSubModules m);
+      functor = (defaultFunctor name) // { wrapped = elemType; };
+    };
+
+    # A submodule (like typed attribute set). See NixOS manual.
+    submodule = opts:
+      let
+        opts' = toList opts;
+        inherit (lib.modules) evalModules;
+      in
+      mkOptionType rec {
+        name = "submodule";
+        check = x: isAttrs x || isFunction x;
+        merge = loc: defs:
+          let
+            coerce = def: if isFunction def then def else { config = def; };
+            modules = opts' ++ map (def: { _file = def.file; imports = [(coerce def.value)]; }) defs;
+          in (evalModules {
+            inherit modules;
+            args.name = last loc;
+            prefix = loc;
+          }).config;
+        getSubOptions = prefix: (evalModules
+          { modules = opts'; inherit prefix;
+            # This is a work-around due to the fact that some sub-modules,
+            # such as the one included in an attribute set, expects a "args"
+            # attribute to be given to the sub-module. As the option
+            # evaluation does not have any specific attribute name, we
+            # provide a default one for the documentation.
+            #
+            # This is mandatory as some option declaration might use the
+            # "name" attribute given as argument of the submodule and use it
+            # as the default of option declarations.
+            #
+            # Using lookalike unicode single angle quotation marks because
+            # of the docbook transformation the options receive. In all uses
+            # &gt; and &lt; wouldn't be encoded correctly so the encoded values
+            # would be used, and use of `<` and `>` would break the XML document.
+            # It shouldn't cause an issue since this is cosmetic for the manual.
+            args.name = "‹name›";
+          }).options;
+        getSubModules = opts';
+        substSubModules = m: submodule m;
+        functor = (defaultFunctor name) // {
+          # Merging of submodules is done as part of mergeOptionDecls, as we have to annotate
+          # each submodule with its location.
+          payload = [];
+          binOp = lhs: rhs: [];
+        };
+      };
+
+    # A value from a set of allowed ones.
+    enum = values:
+      let
+        show = v:
+               if builtins.isString v then ''"${v}"''
+          else if builtins.isInt v then builtins.toString v
+          else ''<${builtins.typeOf v}>'';
+      in
+      mkOptionType rec {
+        name = "enum";
+        description = "one of ${concatMapStringsSep ", " show values}";
+        check = flip elem values;
+        merge = mergeOneOption;
+        functor = (defaultFunctor name) // { payload = values; binOp = a: b: unique (a ++ b); };
+      };
+
+    # Either value of type `t1` or `t2`.
+    either = t1: t2: mkOptionType rec {
+      name = "either";
+      description = "${t1.description} or ${t2.description}";
+      check = x: t1.check x || t2.check x;
+      merge = loc: defs:
+        let
+          defList = map (d: d.value) defs;
+        in
+          if   all (x: t1.check x) defList
+               then t1.merge loc defs
+          else if all (x: t2.check x) defList
+               then t2.merge loc defs
+          else mergeOneOption loc defs;
+      typeMerge = f':
+        let mt1 = t1.typeMerge (elemAt f'.wrapped 0).functor;
+            mt2 = t2.typeMerge (elemAt f'.wrapped 1).functor;
+        in
+           if (name == f'.name) && (mt1 != null) && (mt2 != null)
+           then functor.type mt1 mt2
+           else null;
+      functor = (defaultFunctor name) // { wrapped = [ t1 t2 ]; };
+    };
+
+    # Either value of type `finalType` or `coercedType`, the latter is
+    # converted to `finalType` using `coerceFunc`.
+    coercedTo = coercedType: coerceFunc: finalType:
+      assert lib.assertMsg (coercedType.getSubModules == null)
+        "coercedTo: coercedType must not have submodules (it’s a ${
+          coercedType.description})";
+      mkOptionType rec {
+        name = "coercedTo";
+        description = "${finalType.description} or ${coercedType.description} convertible to it";
+        check = x: finalType.check x || (coercedType.check x && finalType.check (coerceFunc x));
+        merge = loc: defs:
+          let
+            coerceVal = val:
+              if finalType.check val then val
+              else coerceFunc val;
+          in finalType.merge loc (map (def: def // { value = coerceVal def.value; }) defs);
+        getSubOptions = finalType.getSubOptions;
+        getSubModules = finalType.getSubModules;
+        substSubModules = m: coercedTo coercedType coerceFunc (finalType.substSubModules m);
+        typeMerge = t1: t2: null;
+        functor = (defaultFunctor name) // { wrapped = finalType; };
+      };
+
+    # Obsolete alternative to configOf.  It takes its option
+    # declarations from the ‘options’ attribute of containing option
+    # declaration.
+    optionSet = mkOptionType {
+      name = builtins.trace "types.optionSet is deprecated; use types.submodule instead" "optionSet";
+      description = "option set";
+    };
+
+    # Augment the given type with an additional type check function.
+    addCheck = elemType: check: elemType // { check = x: elemType.check x && check x; };
+
+  };
+};
+
+in outer_types // outer_types.types
diff --git a/nixpkgs/lib/versions.nix b/nixpkgs/lib/versions.nix
new file mode 100644
index 000000000000..8f7f98ff5e1e
--- /dev/null
+++ b/nixpkgs/lib/versions.nix
@@ -0,0 +1,47 @@
+/* Version string functions. */
+{ lib }:
+
+let
+
+  splitVersion = builtins.splitVersion or (lib.splitString ".");
+
+in
+
+rec {
+
+  /* Get the major version string from a string.
+
+    Example:
+      major "1.2.3"
+      => "1"
+  */
+  major = v: builtins.elemAt (splitVersion v) 0;
+
+  /* Get the minor version string from a string.
+
+    Example:
+      minor "1.2.3"
+      => "2"
+  */
+  minor = v: builtins.elemAt (splitVersion v) 1;
+
+  /* Get the patch version string from a string.
+
+    Example:
+      patch "1.2.3"
+      => "3"
+  */
+  patch = v: builtins.elemAt (splitVersion v) 2;
+
+  /* Get string of the first two parts (major and minor)
+     of a version string.
+
+     Example:
+       majorMinor "1.2.3"
+       => "1.2"
+  */
+  majorMinor = v:
+    builtins.concatStringsSep "."
+    (lib.take 2 (splitVersion v));
+
+}
diff --git a/nixpkgs/lib/zip-int-bits.nix b/nixpkgs/lib/zip-int-bits.nix
new file mode 100644
index 000000000000..edbcdfe1e682
--- /dev/null
+++ b/nixpkgs/lib/zip-int-bits.nix
@@ -0,0 +1,39 @@
+/* Helper function to implement a fallback for the bit operators
+   `bitAnd`, `bitOr` and `bitXOr` on older nix version.
+   See ./trivial.nix
+*/
+f: x: y:
+  let
+    # (intToBits 6) -> [ 0 1 1 ]
+    intToBits = x:
+      if x == 0 || x == -1 then
+        []
+      else
+        let
+          headbit  = if (x / 2) * 2 != x then 1 else 0;          # x & 1
+          tailbits = if x < 0 then ((x + 1) / 2) - 1 else x / 2; # x >> 1
+        in
+          [headbit] ++ (intToBits tailbits);
+
+    # (bitsToInt [ 0 1 1 ] 0) -> 6
+    # (bitsToInt [ 0 1 0 ] 1) -> -6
+    bitsToInt = l: signum:
+      if l == [] then
+        (if signum == 0 then 0 else -1)
+      else
+        (builtins.head l) + (2 * (bitsToInt (builtins.tail l) signum));
+
+    xsignum = if x < 0 then 1 else 0;
+    ysignum = if y < 0 then 1 else 0;
+    zipListsWith' = fst: snd:
+      if fst==[] && snd==[] then
+        []
+      else if fst==[] then
+        [(f xsignum             (builtins.head snd))] ++ (zipListsWith' []                  (builtins.tail snd))
+      else if snd==[] then
+        [(f (builtins.head fst) ysignum            )] ++ (zipListsWith' (builtins.tail fst) []                 )
+      else
+        [(f (builtins.head fst) (builtins.head snd))] ++ (zipListsWith' (builtins.tail fst) (builtins.tail snd));
+  in
+    assert (builtins.isInt x) && (builtins.isInt y);
+    bitsToInt (zipListsWith' (intToBits x) (intToBits y)) (f xsignum ysignum)