about summary refs log tree commit diff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/licenses.nix8
-rw-r--r--lib/lists.nix82
-rw-r--r--lib/maintainers.nix8
-rw-r--r--lib/modules.nix14
-rw-r--r--lib/strings.nix19
-rw-r--r--lib/trivial.nix17
6 files changed, 132 insertions, 16 deletions
diff --git a/lib/licenses.nix b/lib/licenses.nix
index 4071fcfd70d2..3708b1eb15cf 100644
--- a/lib/licenses.nix
+++ b/lib/licenses.nix
@@ -188,7 +188,7 @@ lib.mapAttrs (n: v: v // { shortName = n; }) rec {
 
   fdl13 = spdx {
     spdxId = "GFDL-1.3";
-    fullName = "GNU Free Documentation License v1.2";
+    fullName = "GNU Free Documentation License v1.3";
   };
 
   free = {
@@ -200,6 +200,12 @@ lib.mapAttrs (n: v: v // { shortName = n; }) rec {
     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";
     fullName = "GNU General Public License v1.0 only";
diff --git a/lib/lists.nix b/lib/lists.nix
index 6712e5cc93f8..4bf732b88c9a 100644
--- a/lib/lists.nix
+++ b/lib/lists.nix
@@ -89,7 +89,7 @@ rec {
   */
   flatten = x:
     if isList x
-    then foldl' (x: y: x ++ (flatten y)) [] x
+    then concatMap (y: flatten y) x
     else [x];
 
   /* Remove elements equal to 'e' from a list.  Useful for buildInputs.
@@ -256,6 +256,86 @@ rec {
   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`).
+
+     Examples:
+
+         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.
+
+     Examples:
+
+         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
diff --git a/lib/maintainers.nix b/lib/maintainers.nix
index 7f6c823d68b9..b9fd905dd54d 100644
--- a/lib/maintainers.nix
+++ b/lib/maintainers.nix
@@ -39,6 +39,7 @@
   aristid = "Aristid Breitkreuz <aristidb@gmail.com>";
   arobyn = "Alexei Robyn <shados@shados.net>";
   artuuge = "Artur E. Ruuge <artuuge@gmail.com>";
+  ashalkhakov = "Artyom Shalkhakov <artyom.shalkhakov@gmail.com>";
   asppsa = "Alastair Pharo <asppsa@gmail.com>";
   astsmtl = "Alexander Tsamutali <astsmtl@yandex.ru>";
   aszlig = "aszlig <aszlig@redmoonstudios.org>";
@@ -99,6 +100,7 @@
   davidak = "David Kleuker <post@davidak.de>";
   davidrusu = "David Rusu <davidrusu.me@gmail.com>";
   dbohdan = "Danyil Bohdan <danyil.bohdan@gmail.com>";
+  dbrock = "Daniel Brockman <daniel@brockman.se>";
   deepfire = "Kosyrev Serge <_deepfire@feelingofgreen.ru>";
   demin-dmitriy = "Dmitriy Demin <demindf@gmail.com>";
   DerGuteMoritz = "Moritz Heidkamp <moritz@twoticketsplease.de>";
@@ -127,7 +129,7 @@
   ericbmerritt = "Eric Merritt <eric@afiniate.com>";
   ericsagnes = "Eric Sagnes <eric.sagnes@gmail.com>";
   erikryb = "Erik Rybakken <erik.rybakken@math.ntnu.no>";
-  ertes = "Ertugrul Söylemez <ertesx@gmx.de>";
+  ertes = "Ertugrul Söylemez <esz@posteo.de>";
   exi = "Reno Reckling <nixos@reckling.org>";
   exlevan = "Alexey Levan <exlevan@gmail.com>";
   expipiplus1 = "Joe Hermaszewski <nix@monoid.al>";
@@ -240,14 +242,16 @@
   mathnerd314 = "Mathnerd314 <mathnerd314.gph+hs@gmail.com>";
   matthiasbeyer = "Matthias Beyer <mail@beyermatthias.de>";
   maurer = "Matthew Maurer <matthew.r.maurer+nix@gmail.com>";
-  mbakke = "Marius Bakke <ymse@tuta.io>";
+  mbakke = "Marius Bakke <mbakke@fastmail.com>";
   matthewbauer = "Matthew Bauer <mjbauer95@gmail.com>";
   mbe = "Brandon Edens <brandonedens@gmail.com>";
   mboes = "Mathieu Boespflug <mboes@tweag.net>";
   mcmtroffaes = "Matthias C. M. Troffaes <matthias.troffaes@gmail.com>";
   meditans = "Carlo Nucera <meditans@gmail.com>";
   meisternu = "Matt Miemiec <meister@krutt.org>";
+  mic92 = "Jörg Thalheim <joerg@higgsboson.tk>";
   michaelpj = "Michael Peyton Jones <michaelpj@gmail.com>";
+  michalrus = "Michal Rus <m@michalrus.com>";
   michelk = "Michel Kuhlmann <michel@kuhlmanns.info>";
   mimadrid = "Miguel Madrid <mimadrid@ucm.es>";
   mingchuan = "Ming Chuan <ming@culpring.com>";
diff --git a/lib/modules.nix b/lib/modules.nix
index 2b0d03ef6e81..6f08a49399ab 100644
--- a/lib/modules.nix
+++ b/lib/modules.nix
@@ -507,19 +507,25 @@ rec {
   /* Return a module that causes a warning to be shown if the
      specified option is defined. For example,
 
-       mkRemovedOptionModule [ "boot" "loader" "grub" "bootDevice" ]
+       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:
+  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.";
+        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
diff --git a/lib/strings.nix b/lib/strings.nix
index daf845839343..86af4d438344 100644
--- a/lib/strings.nix
+++ b/lib/strings.nix
@@ -156,12 +156,12 @@ rec {
        hasSuffix "foo" "barfoo"
        => true
   */
-  hasSuffix = suff: str:
+  hasSuffix = suffix: content:
     let
-      lenStr = stringLength str;
-      lenSuff = stringLength suff;
-    in lenStr >= lenSuff &&
-       substring (lenStr - lenSuff) lenStr str == suff;
+      lenContent = stringLength content;
+      lenSuffix = stringLength suffix;
+    in lenContent >= lenSuffix &&
+       substring (lenContent - lenSuffix) lenContent content == suffix;
 
   /* 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,
@@ -248,7 +248,7 @@ rec {
   /* Converts an ASCII string to upper-case.
 
      Example:
-       toLower "home"
+       toUpper "home"
        => "HOME"
   */
   toUpper = replaceChars lowerChars upperChars;
@@ -372,7 +372,12 @@ rec {
        getVersion pkgs.youtube-dl
        => "2016.01.01"
   */
-  getVersion = x: (builtins.parseDrvName (x.name or x)).version;
+  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.
diff --git a/lib/trivial.nix b/lib/trivial.nix
index f85c74ab88e3..25ce35570fdf 100644
--- a/lib/trivial.nix
+++ b/lib/trivial.nix
@@ -71,7 +71,7 @@ rec {
     + (if pathExists suffixFile then fileContents suffixFile else "pre-git");
 
   # Whether we're being called by nix-shell.
-  inNixShell = builtins.getEnv "IN_NIX_SHELL" == "1";
+  inNixShell = builtins.getEnv "IN_NIX_SHELL" != "";
 
   # Return minimum/maximum of two numbers.
   min = x: y: if x < y then x else y;
@@ -98,4 +98,19 @@ rec {
   */
   importJSON = path:
     builtins.fromJSON (builtins.readFile path);
+
+  /* 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}";
 }