aboutsummaryrefslogtreecommitdiff
path: root/nixpkgs/lib
diff options
context:
space:
mode:
authorKatharina Fey <kookie@spacekookie.de>2019-10-05 12:43:18 +0000
committerKatharina Fey <kookie@spacekookie.de>2019-10-05 12:44:52 +0000
commitcf85056ba64caf3267d43255ef4a1243e9c8ee3b (patch)
tree3051519e9c8275b870aac43f80af875715c9d124 /nixpkgs/lib
parent1148b1d122bc03e9a3665856c9b7bb96bd4e3994 (diff)
parent2436c27541b2f52deea3a4c1691216a02152e729 (diff)
Add 'nixpkgs/' from commit '2436c27541b2f52deea3a4c1691216a02152e729'
git-subtree-dir: nixpkgs git-subtree-mainline: 1148b1d122bc03e9a3665856c9b7bb96bd4e3994 git-subtree-split: 2436c27541b2f52deea3a4c1691216a02152e729
Diffstat (limited to 'nixpkgs/lib')
-rw-r--r--nixpkgs/lib/asserts.nix44
-rw-r--r--nixpkgs/lib/attrsets.nix482
-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.nix277
-rw-r--r--nixpkgs/lib/fetchers.nix13
-rw-r--r--nixpkgs/lib/filesystem.nix45
-rw-r--r--nixpkgs/lib/fixed-points.nix104
-rw-r--r--nixpkgs/lib/generators.nix227
-rw-r--r--nixpkgs/lib/kernel.nix21
-rw-r--r--nixpkgs/lib/licenses.nix753
-rw-r--r--nixpkgs/lib/lists.nix675
-rw-r--r--nixpkgs/lib/meta.nix90
-rw-r--r--nixpkgs/lib/minver.nix2
-rw-r--r--nixpkgs/lib/modules.nix732
-rw-r--r--nixpkgs/lib/options.nix207
-rw-r--r--nixpkgs/lib/sources.nix137
-rw-r--r--nixpkgs/lib/strings-with-deps.nix79
-rw-r--r--nixpkgs/lib/strings.nix664
-rw-r--r--nixpkgs/lib/systems/default.nix134
-rw-r--r--nixpkgs/lib/systems/doubles.nix65
-rw-r--r--nixpkgs/lib/systems/examples.nix244
-rw-r--r--nixpkgs/lib/systems/inspect.nix67
-rw-r--r--nixpkgs/lib/systems/parse.nix447
-rw-r--r--nixpkgs/lib/systems/platforms.nix471
-rw-r--r--nixpkgs/lib/tests/check-eval.nix7
-rw-r--r--nixpkgs/lib/tests/misc.nix404
-rwxr-xr-xnixpkgs/lib/tests/modules.sh176
-rw-r--r--nixpkgs/lib/tests/modules/alias-with-priority-can-override.nix55
-rw-r--r--nixpkgs/lib/tests/modules/alias-with-priority.nix55
-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-either.nix5
-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/declare-oneOf.nix9
-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.nix24
-rw-r--r--nixpkgs/lib/tests/systems.nix32
-rw-r--r--nixpkgs/lib/trivial.nix298
-rw-r--r--nixpkgs/lib/types.nix490
-rw-r--r--nixpkgs/lib/versions.nix47
-rw-r--r--nixpkgs/lib/zip-int-bits.nix39
78 files changed, 8486 insertions, 0 deletions
diff --git a/nixpkgs/lib/asserts.nix b/nixpkgs/lib/asserts.nix
new file mode 100644
index 00000000000..8a5f1fb3feb
--- /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 00000000000..086c3d746fc
--- /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: values)' 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/customisation.nix b/nixpkgs/lib/customisation.nix
new file mode 100644
index 00000000000..3be36fcd719
--- /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` attribute 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: _: 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 00000000000..2879f72ed2b
--- /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 00000000000..18d2dfae1e1
--- /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.doubles;
+
+ 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 showWarnings 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 forEach 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 optionalString
+ hasInfix 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 setPrio 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
+ 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
+ fakeSha256 fakeSha512
+ nixType imap;
+ });
+in lib
diff --git a/nixpkgs/lib/deprecated.nix b/nixpkgs/lib/deprecated.nix
new file mode 100644
index 00000000000..155d6f0c361
--- /dev/null
+++ b/nixpkgs/lib/deprecated.nix
@@ -0,0 +1,277 @@
+{ 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 // {
+ function = foldArgs merger f arg;
+ args = (lib.attrByPath ["passthru" "args"] {} z) // x;
+ } ));
+ withStdOverrides = base // {
+ override = base.passthru.function;
+ };
+ in
+ withStdOverrides;
+
+
+ # 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 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" ])
+ ;
+
+ 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;
+
+ # Fake hashes. Can be used as hash placeholders, when computing hash ahead isn't trivial
+ fakeSha256 = "0000000000000000000000000000000000000000000000000000000000000000";
+ fakeSha512 = "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
+}
diff --git a/nixpkgs/lib/fetchers.nix b/nixpkgs/lib/fetchers.nix
new file mode 100644
index 00000000000..1107353b51d
--- /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 00000000000..fc35a1a72c6
--- /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 00000000000..968930526a6
--- /dev/null
+++ b/nixpkgs/lib/fixed-points.nix
@@ -0,0 +1,104 @@
+{ ... }:
+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:
+ let
+ x' = f x;
+ in
+ if x' == x
+ then x
+ else converge 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 00000000000..a71654bec6c
--- /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 x == null 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 00000000000..36ea3083828
--- /dev/null
+++ b/nixpkgs/lib/kernel.nix
@@ -0,0 +1,21 @@
+{ lib, version }:
+
+with lib;
+{
+ # Common patterns/legacy
+ whenAtLeast = ver: mkIf (versionAtLeast version ver);
+ whenOlder = ver: mkIf (versionOlder version ver);
+ # range is (inclusive, exclusive)
+ whenBetween = verLow: verHigh: mkIf (versionAtLeast version verLow && versionOlder version verHigh);
+
+
+ # Keeping these around in case we decide to change this horrible implementation :)
+ option = x:
+ x // { optional = true; };
+
+ yes = { tristate = "y"; };
+ no = { tristate = "n"; };
+ module = { tristate = "m"; };
+ freeform = x: { freeform = x; };
+
+}
diff --git a/nixpkgs/lib/licenses.nix b/nixpkgs/lib/licenses.nix
new file mode 100644
index 00000000000..986b7fa1fdd
--- /dev/null
+++ b/nixpkgs/lib/licenses.nix
@@ -0,0 +1,753 @@
+{ lib }:
+let
+
+ spdx = lic: lic // {
+ url = "http://spdx.org/licenses/${lic.spdxId}.html";
+ };
+
+in
+
+lib.mapAttrs (n: v: v // { shortName = n; }) {
+ /* 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-30 = spdx {
+ spdxId = "CC-BY-NC-3.0";
+ fullName = "Creative Commons Attribution Non Commercial 3.0 Unported";
+ 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 = spdx {
+ spdxId = "curl";
+ fullName = "curl License";
+ };
+
+ 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 Lesser General Public License v2.1 only";
+ };
+
+ lgpl21Plus = spdx {
+ spdxId = "LGPL-2.1-or-later";
+ fullName = "GNU Lesser 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";
+ };
+
+ libpng2 = spdx {
+ spdxId = "libpng-2.0"; # Used since libpng 1.6.36.
+ fullName = "PNG Reference Library version 2";
+ };
+
+ 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";
+ };
+
+ osl2 = spdx {
+ spdxId = "OSL-2.0";
+ fullName = "Open Software License 2.0";
+ };
+
+ 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;
+ };
+
+ qhull = spdx {
+ spdxId = "Qhull";
+ fullName = "Qhull License";
+ };
+
+ 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 00000000000..f9f30412770
--- /dev/null
+++ b/nixpkgs/lib/lists.nix
@@ -0,0 +1,675 @@
+# 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 map;
+
+ /* 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];
+
+ /* Apply the function to each element in the list. Same as `map`, but arguments
+ flipped.
+
+ Type: forEach :: [a] -> (a -> b) -> [b]
+
+ Example:
+ forEach [ 1 2 ] (x:
+ toString x
+ )
+ => [ "1" "2" ]
+ */
+ forEach = xs: f: map f xs;
+
+ /* “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 contrast 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;
+ in [x] ++ unique (remove x list);
+
+ /* 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 00000000000..2e83c4247dd
--- /dev/null
+++ b/nixpkgs/lib/meta.nix
@@ -0,0 +1,90 @@
+/* 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;
+
+ /* Set the nix-env priority of the package.
+ */
+ setPrio = priority: addMetaAttrs { inherit priority; };
+
+ /* Decrease the nix-env priority of the package, i.e., other
+ versions/variants of the package will be preferred.
+ */
+ lowPrio = setPrio 10;
+
+ /* 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 = setPrio (-10);
+
+ /* 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 00000000000..fee6b65a244
--- /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 00000000000..c3c903c1dfa
--- /dev/null
+++ b/nixpkgs/lib/modules.nix
@@ -0,0 +1,732 @@
+{ 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:
+ acc // (mapAttrs (n: v:
+ (acc.${n} or []) ++ f module v
+ ) 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';
+
+
+ # The value with a check that it is defined
+ valueDefined = if res.isDefined then res.mergedValue else
+ throw "The option `${showOption loc}' is used but not defined.";
+
+ # Apply the 'apply' function to the merged value. This allows options to
+ # yield a value computed from the definitions
+ value = if opt ? apply then opt.apply valueDefined else valueDefined;
+
+ 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
+ getPrio = def: if def.value._type or "" == "override" then def.value.priority else defaultPriority;
+ 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;
+
+ # The default priority for things that don't have a priority specified.
+ defaultPriority = 100;
+
+ # 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:
+ mkAliasIfDef option (wrap (mkMerge option.definitions));
+
+ # Similar to mkAliasAndWrapDefinitions but copies over the priority from the
+ # option as well.
+ #
+ # If a priority is not set, it assumes a priority of defaultPriority.
+ mkAliasAndWrapDefsWithPriority = wrap: option:
+ let
+ prio = option.highestPrio or defaultPriority;
+ defsWithPrio = map (mkOverride prio) option.definitions;
+ in mkAliasIfDef option (wrap (mkMerge defsWithPrio));
+
+ mkAliasIfDef = option:
+ mkIf (isOption option && option.isDefined);
+
+ /* 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.
+
+ This also copies over the priority from the aliased option to the
+ non-aliased option.
+ */
+ 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, withPriority ? true }:
+ { 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}'.";
+ }
+ (if withPriority
+ then mkAliasAndWrapDefsWithPriority (setAttrByPath to) fromOpt
+ else mkAliasAndWrapDefinitions (setAttrByPath to) fromOpt)
+ ];
+ };
+
+}
diff --git a/nixpkgs/lib/options.nix b/nixpkgs/lib/options.nix
new file mode 100644
index 00000000000..e5c0631a543
--- /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/lib/make-options-doc/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,
+ # Deprecated, 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:\n - ${concatStringsSep "\n - " (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 (lib.warn "Option `${name}' has no description." "This option 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 00000000000..51bcf5559e3
--- /dev/null
+++ b/nixpkgs/lib/sources.nix
@@ -0,0 +1,137 @@
+# 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 version control software files/directories
+ (baseName == ".git" || type == "directory" && (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 {
+ # filter = f;
+ # src = lib.cleanSourceWith {
+ # filter = g;
+ # src = ./.;
+ # };
+ # }
+ # # Succeeds!
+ #
+ # builtins.filterSource f (builtins.filterSource g ./.)
+ # # Fails!
+ #
+ # Parameters:
+ #
+ # src: A path or cleanSourceWith result to filter and/or rename.
+ #
+ # filter: A function (path -> type -> bool)
+ # Optional with default value: constant true (include everything)
+ # The function will be combined with the && operator such
+ # that src.filter is called lazily.
+ # For implementing a filter, see
+ # https://nixos.org/nix/manual/#builtin-filterSource
+ #
+ # name: Optional name to use as part of the store path.
+ # This defaults `src.name` or otherwise `baseNameOf src`.
+ # We recommend setting `name` whenever `src` is syntactically `./.`.
+ # Otherwise, you depend on `./.`'s name in the parent directory,
+ # which can cause inconsistent names, defeating caching.
+ #
+ cleanSourceWith = { filter ? _path: _type: true, src, name ? null }:
+ 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;
+ name' = if name != null then name else if isFiltered then src.name else baseNameOf src;
+ in {
+ inherit origSrc;
+ filter = filter';
+ outPath = builtins.path { filter = filter'; path = origSrc; name = name'; };
+ _isLibCleanSourceWith = true;
+ name = name';
+ };
+
+ # Filter sources by a list of regular expressions.
+ #
+ # E.g. `src = sourceByRegex ./my-subproject [".*\.py$" "^database.sql$"]`
+ sourceByRegex = src: regexes:
+ let
+ isFiltered = src ? _isLibCleanSourceWith;
+ origSrc = if isFiltered then src.origSrc else src;
+ in lib.cleanSourceWith {
+ filter = (path: type:
+ let relPath = lib.removePrefix (toString origSrc + "/") (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 matchRef == null
+ 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 matchRef == null
+ 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 00000000000..e3336983428
--- /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 00000000000..ae0d74c6721
--- /dev/null
+++ b/nixpkgs/lib/strings.nix
@@ -0,0 +1,664 @@
+/* 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: concatIMapStringsSep :: 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";
+
+ /* 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 00000000000..0c0cdf1f11b
--- /dev/null
+++ b/nixpkgs/lib/systems/default.nix
@@ -0,0 +1,134 @@
+{ lib }:
+ let inherit (lib.attrsets) mapAttrs; in
+
+rec {
+ doubles = import ./doubles.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
+ args = if lib.isString args' then { system = args'; }
+ else args';
+ 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;
+ # Determine whether we are compatible with the provided CPU
+ isCompatible = platform: parse.isCompatible final.parsed.cpu platform.parsed.cpu;
+ # Derived meta-data
+ libc =
+ /**/ if final.isDarwin then "libSystem"
+ else if final.isMinGW then "msvcrt"
+ else if final.isWasi then "wasilibc"
+ 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.isMsp430 then "newlib"
+ else if final.isAvr then "avrlibc"
+ else if final.isNetBSD then "nblibc"
+ # 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";
+ wasi = "Wasi";
+ }.${final.parsed.kernel.name} or null;
+
+ # uname -p
+ processor = final.parsed.cpu.name;
+
+ # uname -r
+ release = null;
+ };
+
+ kernelArch =
+ if final.isAarch32 then "arm"
+ else if final.isAarch64 then "arm64"
+ else if final.isx86_32 then "x86"
+ else if final.isx86_64 then "ia64"
+ else final.parsed.cpu.name;
+
+ qemuArch =
+ if final.isArm then "arm"
+ else if final.isx86_64 then "x86_64"
+ else if final.isx86 then "i386"
+ else {
+ powerpc = "ppc";
+ powerpcle = "ppc";
+ powerpc64 = "ppc64";
+ powerpc64le = "ppc64le";
+ }.${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 &&
+ pkgs.stdenv.hostPlatform.isCompatible final
+ then "${pkgs.runtimeShell} -c '\"$@\"' --"
+ 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 if final.isWasi
+ then "${pkgs.wasmtime}/bin/wasmtime"
+ 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 00000000000..8e02fcb5de0
--- /dev/null
+++ b/nixpkgs/lib/systems/doubles.nix
@@ -0,0 +1,65 @@
+{ 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-freebsd" "x86_64-linux"
+ "x86_64-netbsd" "x86_64-openbsd" "x86_64-solaris"
+
+ "x86_64-darwin" "i686-darwin" "aarch64-darwin" "armv7a-darwin"
+
+ "x86_64-windows" "i686-windows"
+
+ "wasm64-wasi" "wasm32-wasi"
+
+ "powerpc64le-linux"
+
+ "riscv32-linux" "riscv64-linux"
+
+ "aarch64-none" "avr-none" "arm-none" "i686-none" "x86_64-none" "powerpc-none" "msp430-none" "riscv64-none" "riscv32-none"
+ ];
+
+ allParsed = map parse.mkSystemFromString all;
+
+ filterDoubles = f: map parse.doubleFromSystem (lists.filter f allParsed);
+
+in {
+ 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;
+ riscv = filterDoubles predicates.isRiscV;
+
+ 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;
+ wasi = filterDoubles predicates.isWasi;
+ windows = filterDoubles predicates.isWindows;
+
+ embedded = filterDoubles predicates.isNone;
+
+ mesaPlatforms = ["i686-linux" "x86_64-linux" "x86_64-darwin" "armv5tel-linux" "armv6l-linux" "armv7l-linux" "armv7a-linux" "aarch64-linux" "powerpc64le-linux"];
+}
diff --git a/nixpkgs/lib/systems/examples.nix b/nixpkgs/lib/systems/examples.nix
new file mode 100644
index 00000000000..511ae197948
--- /dev/null
+++ b/nixpkgs/lib/systems/examples.nix
@@ -0,0 +1,244 @@
+# 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 = {
+ config = "armv5tel-unknown-linux-gnueabi";
+ platform = platforms.sheevaplug;
+ };
+
+ raspberryPi = {
+ config = "armv6l-unknown-linux-gnueabihf";
+ platform = platforms.raspberrypi;
+ };
+
+ armv7l-hf-multiplatform = {
+ config = "armv7l-unknown-linux-gnueabihf";
+ platform = platforms.armv7l-hf-multiplatform;
+ };
+
+ aarch64-multiplatform = {
+ config = "aarch64-unknown-linux-gnu";
+ platform = platforms.aarch64-multiplatform;
+ };
+
+ armv7a-android-prebuilt = {
+ config = "armv7a-unknown-linux-androideabi";
+ sdkVer = "24";
+ ndkVer = "18b";
+ platform = platforms.armv7a-android;
+ useAndroidPrebuilt = true;
+ };
+
+ aarch64-android-prebuilt = {
+ 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 = {
+ config = "armv5tel-unknown-linux-gnueabi";
+ platform = platforms.pogoplug4;
+ };
+
+ ben-nanonote = {
+ config = "mipsel-unknown-linux-uclibc";
+ platform = platforms.ben_nanonote;
+ };
+
+ fuloongminipc = {
+ 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";
+ };
+
+ gnu64 = { config = "x86_64-unknown-linux-gnu"; };
+ gnu32 = { config = "i686-unknown-linux-gnu"; };
+
+ musl64 = { config = "x86_64-unknown-linux-musl"; };
+ musl32 = { config = "i686-unknown-linux-musl"; };
+
+ riscv64 = riscv "64";
+ riscv32 = riscv "32";
+
+ riscv64-embedded = {
+ config = "riscv64-none-elf";
+ libc = "newlib";
+ platform = platforms.riscv-multiplatform "64";
+ };
+
+ riscv32-embedded = {
+ config = "riscv32-none-elf";
+ libc = "newlib";
+ platform = platforms.riscv-multiplatform "32";
+ };
+
+ msp430 = {
+ config = "msp430-elf";
+ libc = "newlib";
+ };
+
+ 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";
+ };
+
+ 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 = {};
+ };
+
+ # BSDs
+
+ amd64-netbsd = {
+ config = "x86_64-unknown-netbsd";
+ libc = "nblibc";
+ };
+
+ #
+ # WASM
+ #
+
+ wasi32 = {
+ config = "wasm32-unknown-wasi";
+ useLLVM = true;
+ };
+
+ # Ghcjs
+ ghcjs = {
+ config = "js-unknown-ghcjs";
+ platform = {};
+ };
+}
diff --git a/nixpkgs/lib/systems/inspect.nix b/nixpkgs/lib/systems/inspect.nix
new file mode 100644
index 00000000000..8a983b3d363
--- /dev/null
+++ b/nixpkgs/lib/systems/inspect.nix
@@ -0,0 +1,67 @@
+{ 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_32 = { cpu = { family = "x86"; bits = 32; }; };
+ isx86_64 = { cpu = { family = "x86"; bits = 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"; }; };
+ isMsp430 = { cpu = { family = "msp430"; }; };
+ isAvr = { cpu = { family = "avr"; }; };
+ isAlpha = { cpu = { family = "alpha"; }; };
+ isJavaScript = { cpu = cpuTypes.js; };
+
+ 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; };
+ isWasi = { kernel = kernels.wasi; };
+ isGhcjs = { kernel = kernels.ghcjs; };
+ isNone = { kernel = kernels.none; };
+
+ 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 00000000000..5e12df32ffd
--- /dev/null
+++ b/nixpkgs/lib/systems/parse.nix
@@ -0,0 +1,447 @@
+# 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"; arch = "armv5t"; };
+ armv6m = { bits = 32; significantByte = littleEndian; family = "arm"; version = "6"; arch = "armv6-m"; };
+ armv6l = { bits = 32; significantByte = littleEndian; family = "arm"; version = "6"; arch = "armv6"; };
+ armv7a = { bits = 32; significantByte = littleEndian; family = "arm"; version = "7"; arch = "armv7-a"; };
+ armv7r = { bits = 32; significantByte = littleEndian; family = "arm"; version = "7"; arch = "armv7-r"; };
+ armv7m = { bits = 32; significantByte = littleEndian; family = "arm"; version = "7"; arch = "armv7-m"; };
+ armv7l = { bits = 32; significantByte = littleEndian; family = "arm"; version = "7"; arch = "armv7"; };
+ armv8a = { bits = 32; significantByte = littleEndian; family = "arm"; version = "8"; arch = "armv8-a"; };
+ armv8r = { bits = 32; significantByte = littleEndian; family = "arm"; version = "8"; arch = "armv8-a"; };
+ armv8m = { bits = 32; significantByte = littleEndian; family = "arm"; version = "8"; arch = "armv8-m"; };
+ aarch64 = { bits = 64; significantByte = littleEndian; family = "arm"; version = "8"; arch = "armv8-a"; };
+ aarch64_be = { bits = 64; significantByte = bigEndian; family = "arm"; version = "8"; arch = "armv8-a"; };
+
+ i386 = { bits = 32; significantByte = littleEndian; family = "x86"; arch = "i386"; };
+ i486 = { bits = 32; significantByte = littleEndian; family = "x86"; arch = "i486"; };
+ i586 = { bits = 32; significantByte = littleEndian; family = "x86"; arch = "i586"; };
+ i686 = { bits = 32; significantByte = littleEndian; family = "x86"; arch = "i686"; };
+ x86_64 = { bits = 64; significantByte = littleEndian; family = "x86"; arch = "x86-64"; };
+
+ 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"; };
+
+ msp430 = { bits = 16; significantByte = littleEndian; family = "msp430"; };
+ avr = { bits = 8; family = "avr"; };
+
+ js = { bits = 32; significantByte = littleEndian; family = "js"; };
+ };
+
+ # Determine where two CPUs are compatible with each other. That is,
+ # can we run code built for system b on system a? For that to
+ # happen, then the set of all possible possible programs that system
+ # b accepts must be a subset of the set of all programs that system
+ # a accepts. This compatibility relation forms a category where each
+ # CPU is an object and each arrow from a to b represents
+ # compatibility. CPUs with multiple modes of Endianness are
+ # isomorphic while all CPUs are endomorphic because any program
+ # built for a CPU can run on that CPU.
+ isCompatible = a: b: with cpuTypes; lib.any lib.id [
+ # x86
+ (b == i386 && isCompatible a i486)
+ (b == i486 && isCompatible a i586)
+ (b == i586 && isCompatible a i686)
+
+ # XXX: Not true in some cases. Like in WSL mode.
+ (b == i686 && isCompatible a x86_64)
+
+ # ARMv4
+ (b == arm && isCompatible a armv5tel)
+
+ # ARMv5
+ (b == armv5tel && isCompatible a armv6l)
+
+ # ARMv6
+ (b == armv6l && isCompatible a armv6m)
+ (b == armv6m && isCompatible a armv7l)
+
+ # ARMv7
+ (b == armv7l && isCompatible a armv7a)
+ (b == armv7l && isCompatible a armv7r)
+ (b == armv7l && isCompatible a armv7m)
+ (b == armv7a && isCompatible a armv8a)
+ (b == armv7r && isCompatible a armv8a)
+ (b == armv7m && isCompatible a armv8a)
+ (b == armv7a && isCompatible a armv8r)
+ (b == armv7r && isCompatible a armv8r)
+ (b == armv7m && isCompatible a armv8r)
+ (b == armv7a && isCompatible a armv8m)
+ (b == armv7r && isCompatible a armv8m)
+ (b == armv7m && isCompatible a armv8m)
+
+ # ARMv8
+ (b == armv8r && isCompatible a armv8a)
+ (b == armv8m && isCompatible a armv8a)
+
+ # XXX: not always true! Some arm64 cpus don’t support arm32 mode.
+ (b == aarch64 && a == armv8a)
+ (b == armv8a && isCompatible a aarch64)
+
+ (b == aarch64 && a == aarch64_be)
+ (b == aarch64_be && isCompatible a aarch64)
+
+ # PowerPC
+ (b == powerpc && isCompatible a powerpc64)
+ (b == powerpcle && isCompatible a powerpc)
+ (b == powerpc && a == powerpcle)
+ (b == powerpc64le && isCompatible a powerpc64)
+ (b == powerpc64 && a == powerpc64le)
+
+ # MIPS
+ (b == mips && isCompatible a mips64)
+ (b == mips && a == mipsel)
+ (b == mipsel && isCompatible a mips)
+ (b == mips64 && a == mips64el)
+ (b == mips64el && isCompatible a mips64)
+
+ # RISCV
+ (b == riscv32 && isCompatible a riscv64)
+
+ # SPARC
+ (b == sparc && isCompatible a sparc64)
+
+ # WASM
+ (b == wasm32 && isCompatible a wasm64)
+
+ # identity
+ (b == a)
+ ];
+
+ ################################################################################
+
+ 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 = {};
+ wasm = {};
+
+ 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 = { }; };
+ wasi = { execFormat = wasm; families = { }; };
+ windows = { execFormat = pe; families = { }; };
+ ghcjs = { execFormat = unknown; 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"; }
+ # MSVC ought to be the default ABI so this case isn't needed. But then it
+ # becomes difficult to handle the gnu* variants for Aarch32 correctly for
+ # minGW. So it's easier to make gnu* the default for the MinGW, but
+ # hack-in MSVC for the non-MinGW case right here.
+ else if elemAt l 1 == "windows"
+ then { cpu = elemAt l 0; kernel = "windows"; abi = "msvc"; }
+ 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"; }
+ else if (elemAt l 2 == "wasi")
+ then { cpu = elemAt l 0; vendor = elemAt l 1; kernel = "wasi"; }
+ 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 if (elemAt l 2 == "ghcjs")
+ then { cpu = elemAt l 0; vendor = "unknown"; kernel = 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 = {
+ 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 || isWindows 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 abis.unknown;
+ };
+
+ in mkSystem parsed;
+
+ mkSystemFromString = s: mkSystemFromSkeleton (mkSkeletonFromList (lib.splitString "-" s));
+
+ doubleFromSystem = { cpu, 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 00000000000..ab3cf1d5430
--- /dev/null
+++ b/nixpkgs/lib/systems/platforms.nix
@@ -0,0 +1,471 @@
+{ 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#v7a
+ armv7a-android = {
+ name = "armeabi-v7a";
+ gcc = {
+ arch = "armv7-a";
+ 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: {
+ i486-linux = pc32;
+ i586-linux = pc32;
+ 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 00000000000..8bd7b605a39
--- /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 00000000000..d8f412d3fc4
--- /dev/null
+++ b/nixpkgs/lib/tests/misc.nix
@@ -0,0 +1,404 @@
+# 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»";
+ };
+
+}
diff --git a/nixpkgs/lib/tests/modules.sh b/nixpkgs/lib/tests/modules.sh
new file mode 100755
index 00000000000..cf344122cf4
--- /dev/null
+++ b/nixpkgs/lib/tests/modules.sh
@@ -0,0 +1,176 @@
+#!/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 either types
+# types.either
+checkConfigOutput "42" config.value ./declare-either.nix ./define-value-int-positive.nix
+checkConfigOutput "\"24\"" config.value ./declare-either.nix ./define-value-string.nix
+# types.oneOf
+checkConfigOutput "42" config.value ./declare-oneOf.nix ./define-value-int-positive.nix
+checkConfigOutput "[ ]" config.value ./declare-oneOf.nix ./define-value-list.nix
+checkConfigOutput "\"24\"" config.value ./declare-oneOf.nix ./define-value-string.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
+
+# Check mkAliasOptionModule.
+checkConfigOutput "true" config.enable ./alias-with-priority.nix
+checkConfigOutput "true" config.enableAlias ./alias-with-priority.nix
+checkConfigOutput "false" config.enable ./alias-with-priority-can-override.nix
+checkConfigOutput "false" config.enableAlias ./alias-with-priority-can-override.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/alias-with-priority-can-override.nix b/nixpkgs/lib/tests/modules/alias-with-priority-can-override.nix
new file mode 100644
index 00000000000..9a18c9d9f61
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/alias-with-priority-can-override.nix
@@ -0,0 +1,55 @@
+# This is a test to show that mkAliasOptionModule sets the priority correctly
+# for aliased options.
+#
+# This test shows that an alias with a high priority is able to override
+# a non-aliased option.
+
+{ config, lib, ... }:
+
+with lib;
+
+{
+ options = {
+ # A simple boolean option that can be enabled or disabled.
+ enable = lib.mkOption {
+ type = types.nullOr types.bool;
+ default = null;
+ example = true;
+ description = ''
+ Some descriptive text
+ '';
+ };
+
+ # mkAliasOptionModule sets warnings, so this has to be defined.
+ warnings = mkOption {
+ internal = true;
+ default = [];
+ type = types.listOf types.str;
+ example = [ "The `foo' service is deprecated and will go away soon!" ];
+ description = ''
+ This option allows modules to show warnings to users during
+ the evaluation of the system configuration.
+ '';
+ };
+ };
+
+ imports = [
+ # Create an alias for the "enable" option.
+ (mkAliasOptionModule [ "enableAlias" ] [ "enable" ])
+
+ # Disable the aliased option with a high priority so it
+ # should override the next import.
+ ( { config, lib, ... }:
+ {
+ enableAlias = lib.mkForce false;
+ }
+ )
+
+ # Enable the normal (non-aliased) option.
+ ( { config, lib, ... }:
+ {
+ enable = true;
+ }
+ )
+ ];
+}
diff --git a/nixpkgs/lib/tests/modules/alias-with-priority.nix b/nixpkgs/lib/tests/modules/alias-with-priority.nix
new file mode 100644
index 00000000000..a35a06fc697
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/alias-with-priority.nix
@@ -0,0 +1,55 @@
+# This is a test to show that mkAliasOptionModule sets the priority correctly
+# for aliased options.
+#
+# This test shows that an alias with a low priority is able to be overridden
+# with a non-aliased option.
+
+{ config, lib, ... }:
+
+with lib;
+
+{
+ options = {
+ # A simple boolean option that can be enabled or disabled.
+ enable = lib.mkOption {
+ type = types.nullOr types.bool;
+ default = null;
+ example = true;
+ description = ''
+ Some descriptive text
+ '';
+ };
+
+ # mkAliasOptionModule sets warnings, so this has to be defined.
+ warnings = mkOption {
+ internal = true;
+ default = [];
+ type = types.listOf types.str;
+ example = [ "The `foo' service is deprecated and will go away soon!" ];
+ description = ''
+ This option allows modules to show warnings to users during
+ the evaluation of the system configuration.
+ '';
+ };
+ };
+
+ imports = [
+ # Create an alias for the "enable" option.
+ (mkAliasOptionModule [ "enableAlias" ] [ "enable" ])
+
+ # Disable the aliased option, but with a default (low) priority so it
+ # should be able to be overridden by the next import.
+ ( { config, lib, ... }:
+ {
+ enableAlias = lib.mkDefault false;
+ }
+ )
+
+ # Enable the normal (non-aliased) option.
+ ( { config, lib, ... }:
+ {
+ enable = true;
+ }
+ )
+ ];
+}
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 00000000000..7a017f24e77
--- /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 00000000000..76b12ad53f0
--- /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-either.nix b/nixpkgs/lib/tests/modules/declare-either.nix
new file mode 100644
index 00000000000..5a0fa978a13
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/declare-either.nix
@@ -0,0 +1,5 @@
+{ lib, ... }: {
+ options.value = lib.mkOption {
+ type = lib.types.either lib.types.int 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 00000000000..ebee243c756
--- /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 00000000000..8b2624cc5d6
--- /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 00000000000..6e48c6ac8fe
--- /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 00000000000..05d0eff01c9
--- /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 00000000000..71dad1c9135
--- /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/declare-oneOf.nix b/nixpkgs/lib/tests/modules/declare-oneOf.nix
new file mode 100644
index 00000000000..df092a14f81
--- /dev/null
+++ b/nixpkgs/lib/tests/modules/declare-oneOf.nix
@@ -0,0 +1,9 @@
+{ lib, ... }: {
+ options.value = lib.mkOption {
+ type = lib.types.oneOf [
+ lib.types.int
+ (lib.types.listOf lib.types.int)
+ lib.types.str
+ ];
+ };
+}
diff --git a/nixpkgs/lib/tests/modules/default.nix b/nixpkgs/lib/tests/modules/default.nix
new file mode 100644
index 00000000000..5b094710419
--- /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 00000000000..e565fd215a5
--- /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 00000000000..f4990a32863
--- /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 00000000000..7da74671d14
--- /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 00000000000..7dc26010ae5
--- /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 00000000000..978caa2a8c0
--- /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 00000000000..bfd8e084b59
--- /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 00000000000..4288d74dec0
--- /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 00000000000..422bb0a600b
--- /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 00000000000..c24315e09b6
--- /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 00000000000..c1d7b198be5
--- /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 00000000000..44b2c96cd02
--- /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 00000000000..822425c71bb
--- /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 00000000000..dce0ef547b3
--- /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 00000000000..236b2840ee5
--- /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 00000000000..e9b2e631f2e
--- /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 00000000000..df5722274ee
--- /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 00000000000..bd2d068d31a
--- /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 00000000000..5a0707c975f
--- /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 00000000000..a041222987a
--- /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 00000000000..5803de17263
--- /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 00000000000..68bb9f415c3
--- /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 00000000000..4831c1cc09b
--- /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 00000000000..8e3abaf536a
--- /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 00000000000..f27e31985c9
--- /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 00000000000..e7a166965a7
--- /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 00000000000..a373ee7e550
--- /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 00000000000..0d84a7c3cb6
--- /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 00000000000..c325f4e0743
--- /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 00000000000..3e687b661c1
--- /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 00000000000..f30903c47e5
--- /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 00000000000..f8f8a8da82b
--- /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 00000000000..737d142d253
--- /dev/null
+++ b/nixpkgs/lib/tests/release.nix
@@ -0,0 +1,24 @@
+{ pkgs ? import ((import ../.).cleanSource ../..) {} }:
+
+pkgs.runCommandNoCC "nixpkgs-lib-tests" {
+ buildInputs = [ pkgs.nix (import ./check-eval.nix) ];
+ NIX_PATH="nixpkgs=${pkgs.path}";
+} ''
+ 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
+
+ touch $out
+''
diff --git a/nixpkgs/lib/tests/systems.nix b/nixpkgs/lib/tests/systems.nix
new file mode 100644
index 00000000000..5748c09b564
--- /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 ++ wasi ++ windows ++ embedded);
+
+ testarm = mseteq arm [ "armv5tel-linux" "armv6l-linux" "armv7l-linux" "arm-none" "armv7a-darwin" ];
+ testi686 = mseteq i686 [ "i686-linux" "i686-freebsd" "i686-netbsd" "i686-openbsd" "i686-cygwin" "i686-windows" "i686-none" "i686-darwin" ];
+ 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" "x86_64-none" ];
+
+ testcygwin = mseteq cygwin [ "i686-cygwin" "x86_64-cygwin" ];
+ testdarwin = mseteq darwin [ "x86_64-darwin" "i686-darwin" "aarch64-darwin" "armv7a-darwin" ];
+ testfreebsd = mseteq freebsd [ "i686-freebsd" "x86_64-freebsd" ];
+ testgnu = mseteq gnu (linux /* ++ kfreebsd ++ ... */);
+ testillumos = mseteq illumos [ "x86_64-solaris" ];
+ testlinux = mseteq linux [ "aarch64-linux" "armv5tel-linux" "armv6l-linux" "armv7l-linux" "i686-linux" "mipsel-linux" "riscv32-linux" "riscv64-linux" "x86_64-linux" "powerpc64le-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 00000000000..54c66cfce7b
--- /dev/null
+++ b/nixpkgs/lib/trivial.nix
@@ -0,0 +1,298 @@
+{ 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 a == null 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 = "Markhor";
+
+ /* 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}";
+
+ showWarnings = warnings: res: lib.fold (w: x: warn w x) res warnings;
+
+ ## 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 00000000000..5e9a28ac4f0
--- /dev/null
+++ b/nixpkgs/lib/types.nix
@@ -0,0 +1,490 @@
+# 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 {
+ name = "int";
+ description = "signed integer";
+ check = isInt;
+ merge = mergeEqualOption;
+ };
+
+ # 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 {
+ /* 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 {
+ name = "float";
+ description = "floating point number";
+ check = isFloat;
+ merge = mergeEqualOption;
+ };
+
+ str = mkOptionType {
+ name = "str";
+ description = "string";
+ check = isString;
+ merge = mergeEqualOption;
+ };
+
+ 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 = warn "types.string is deprecated because it quietly concatenates strings"
+ (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 = mergeEqualOption;
+ };
+
+ # 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: mapAttrs (n: v: { inherit (def) file; value = v; }) 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 = mergeEqualOption;
+ 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 ]; };
+ };
+
+ # Any of the types in the given list
+ oneOf = ts:
+ let
+ head' = if ts == [] then throw "types.oneOf needs to get at least one type in its argument" else head ts;
+ tail' = tail ts;
+ in foldl' either head' tail';
+
+ # 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 00000000000..2c05445b3dd
--- /dev/null
+++ b/nixpkgs/lib/versions.nix
@@ -0,0 +1,47 @@
+/* Version string functions. */
+{ lib }:
+
+let
+
+ splitVersion = builtins.splitVersion or (lib.splitString ".");
+
+in
+
+{
+
+ /* 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 00000000000..edbcdfe1e68
--- /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)