summary refs log tree commit diff
path: root/maintainers/option-usages.nix
diff options
context:
space:
mode:
authorNicolas Pierron <nicolas.b.pierron@gmail.com>2009-09-28 18:26:07 +0000
committerNicolas Pierron <nicolas.b.pierron@gmail.com>2009-09-28 18:26:07 +0000
commitbd41c01bfe45bdc20f85632b5ee35879ddd4584f (patch)
tree0dd540b19b4536315aa492d15482bf112ea272d1 /maintainers/option-usages.nix
parent373445c410fedf111d8239a652d9672885da8f80 (diff)
downloadnixpkgs-bd41c01bfe45bdc20f85632b5ee35879ddd4584f.tar
nixpkgs-bd41c01bfe45bdc20f85632b5ee35879ddd4584f.tar.gz
nixpkgs-bd41c01bfe45bdc20f85632b5ee35879ddd4584f.tar.bz2
nixpkgs-bd41c01bfe45bdc20f85632b5ee35879ddd4584f.tar.lz
nixpkgs-bd41c01bfe45bdc20f85632b5ee35879ddd4584f.tar.xz
nixpkgs-bd41c01bfe45bdc20f85632b5ee35879ddd4584f.tar.zst
nixpkgs-bd41c01bfe45bdc20f85632b5ee35879ddd4584f.zip
Add a nix expression which generate a graph inside a pdf to display option
usages.

svn path=/nixos/trunk/; revision=17483
Diffstat (limited to 'maintainers/option-usages.nix')
-rw-r--r--maintainers/option-usages.nix131
1 files changed, 131 insertions, 0 deletions
diff --git a/maintainers/option-usages.nix b/maintainers/option-usages.nix
new file mode 100644
index 00000000000..6ddc6e9db60
--- /dev/null
+++ b/maintainers/option-usages.nix
@@ -0,0 +1,131 @@
+{ configuration ? import ../lib/from-env.nix "NIXOS_CONFIG" /etc/nixos/configuration.nix
+
+# []: display all options
+# [<option names>]: display the selected options
+, displayOptions ? [
+    "hardware.pcmcia.enable"
+    "environment.systemPackages"
+    "boot.kernelModules"
+    "services.udev.packages"
+    "jobs"
+    "environment.etc"
+    "system.activationScripts"
+  ]
+}:
+
+# This file is used to generate a dot graph which contains all options and
+# there dependencies to track problems and their sources.
+
+let
+  
+  evalFun = {
+    extraArgs ? {}
+  }: import ../lib/eval-config.nix {
+       modules = [ configuration ];
+       inherit extraArgs;
+     };
+
+  eval = evalFun {};
+  inherit (eval) pkgs;
+
+  reportNewFailures = old: new: with pkgs.lib;
+    let
+      filterChanges =
+        filter ({fst, snd}:
+          !(fst.config.success -> snd.config.success)
+        );
+
+      keepNames =
+        map ({fst, snd}:
+          assert fst.name == snd.name; snd.name
+        );
+     in
+       keepNames (
+         filterChanges (
+           zipLists (collect isOption old) (collect isOption new)
+         )
+       );
+
+
+  mkProtect = name: value: { _type = "protect"; inherit name value; };
+  isProtected = attr: (pkgs.lib.typeOf attr) == "protect";
+
+  getName = set: with pkgs.lib;
+    if isProtected set then
+      set.name
+    else
+      getName (head (attrValues set));
+
+  rmProtect = set: with pkgs.lib;
+    if isProtected set then
+      set.value
+    else
+      mapAttrs (n: rmProtect) set;
+
+  # Create a list of modules where each module contains only one failling
+  # options.
+  introspectionModules = with pkgs.lib;
+    let
+      genericFun = f: set:
+        fold (name: rest:
+          (map (v:
+            listToAttrs [(nameValuePair name v)]
+          ) (f (getAttr name set)))
+          ++ rest
+        ) [] (attrNames set);
+
+      addIntrospection = opt: mkProtect opt.name (
+        throw "Usage introspection of '${opt.name}' by forced failure."
+      );
+
+      f = v:
+        if isOption v then
+          [(addIntrospection v)]
+        else
+          genericFun f v;
+    in
+      genericFun f eval.options;
+
+  overrideConfig = override: with pkgs.lib;
+    let f = configs:
+      zip (n: v:
+        if tail v == [] || isProtected (head v) then
+          head v
+        else
+          f v
+      ) configs;
+    in
+      f [ override eval.config ];
+
+
+  graph = with pkgs.lib;
+    map (thrower: {
+      option = getName thrower;
+      usedBy = reportNewFailures eval.options (evalFun {
+        extraArgs = {
+          config = overrideConfig (rmProtect thrower);
+        };
+      }).options;
+    }) introspectionModules;
+
+  graphToDot = graph: with pkgs.lib; ''
+    digraph "Option Usages" {
+      ${concatMapStrings ({option, usedBy}:
+          assert __trace option true;
+          if displayOptions == [] || elem option displayOptions then
+            concatMapStrings (user: ''
+              "${option}" -> "${user}"''
+            ) usedBy
+          else ""
+        ) graph}
+    }
+  '';
+
+in
+
+pkgs.texFunctions.dot2pdf {
+  dotGraph = pkgs.writeTextFile {
+    name = "option_usages.dot";
+    text = graphToDot graph;
+  };
+}