diff options
Diffstat (limited to 'nixos/maintainers/option-usages.nix')
-rw-r--r-- | nixos/maintainers/option-usages.nix | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/nixos/maintainers/option-usages.nix b/nixos/maintainers/option-usages.nix new file mode 100644 index 000000000000..7413b9e18cec --- /dev/null +++ b/nixos/maintainers/option-usages.nix @@ -0,0 +1,99 @@ +{ configuration ? import ../lib/from-env.nix "NIXOS_CONFIG" <nixos-config> + +# []: 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) + ) + ); + + + # Create a list of modules where each module contains only one failling + # options. + introspectionModules = with pkgs.lib; + let + setIntrospection = opt: rec { + name = opt.name; + path = splitString "." opt.name; + config = setAttrByPath path + (throw "Usage introspection of '${name}' by forced failure."); + }; + in + map setIntrospection (collect isOption eval.options); + + overrideConfig = thrower: + pkgs.lib.recursiveUpdateUntil (path: old: new: + path == thrower.path + ) eval.config thrower.config; + + + graph = with pkgs.lib; + map (thrower: { + option = thrower.name; + usedBy = reportNewFailures eval.options (evalFun { + extraArgs = { + config = overrideConfig 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; + }; +} |