You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

99 lines
2.4 KiB

  1. { configuration ? import ../lib/from-env.nix "NIXOS_CONFIG" <nixos-config>
  2. # []: display all options
  3. # [<option names>]: display the selected options
  4. , displayOptions ? [
  5. "hardware.pcmcia.enable"
  6. "environment.systemPackages"
  7. "boot.kernelModules"
  8. "services.udev.packages"
  9. "jobs"
  10. "environment.etc"
  11. "system.activationScripts"
  12. ]
  13. }:
  14. # This file is used to generate a dot graph which contains all options and
  15. # there dependencies to track problems and their sources.
  16. let
  17. evalFun = {
  18. extraArgs ? {}
  19. }: import ../lib/eval-config.nix {
  20. modules = [ configuration ];
  21. inherit extraArgs;
  22. };
  23. eval = evalFun {};
  24. inherit (eval) pkgs;
  25. reportNewFailures = old: new: with pkgs.lib;
  26. let
  27. filterChanges =
  28. filter ({fst, snd}:
  29. !(fst.config.success -> snd.config.success)
  30. );
  31. keepNames =
  32. map ({fst, snd}:
  33. assert fst.name == snd.name; snd.name
  34. );
  35. in
  36. keepNames (
  37. filterChanges (
  38. zipLists (collect isOption old) (collect isOption new)
  39. )
  40. );
  41. # Create a list of modules where each module contains only one failling
  42. # options.
  43. introspectionModules = with pkgs.lib;
  44. let
  45. setIntrospection = opt: rec {
  46. name = opt.name;
  47. path = splitString "." opt.name;
  48. config = setAttrByPath path
  49. (throw "Usage introspection of '${name}' by forced failure.");
  50. };
  51. in
  52. map setIntrospection (collect isOption eval.options);
  53. overrideConfig = thrower:
  54. pkgs.lib.recursiveUpdateUntil (path: old: new:
  55. path == thrower.path
  56. ) eval.config thrower.config;
  57. graph = with pkgs.lib;
  58. map (thrower: {
  59. option = thrower.name;
  60. usedBy = reportNewFailures eval.options (evalFun {
  61. extraArgs = {
  62. config = overrideConfig thrower;
  63. };
  64. }).options;
  65. }) introspectionModules;
  66. graphToDot = graph: with pkgs.lib; ''
  67. digraph "Option Usages" {
  68. ${concatMapStrings ({option, usedBy}:
  69. assert __trace option true;
  70. if displayOptions == [] || elem option displayOptions then
  71. concatMapStrings (user: ''
  72. "${option}" -> "${user}"''
  73. ) usedBy
  74. else ""
  75. ) graph}
  76. }
  77. '';
  78. in
  79. pkgs.texFunctions.dot2pdf {
  80. dotGraph = pkgs.writeTextFile {
  81. name = "option_usages.dot";
  82. text = graphToDot graph;
  83. };
  84. }