2012-03-02 13:38:22 +01:00
|
|
|
{ configuration ? import ../lib/from-env.nix "NIXOS_CONFIG" <nixos-config>
|
2009-09-28 20:26:07 +02:00
|
|
|
|
|
|
|
# []: 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
|
2011-09-14 20:20:50 +02:00
|
|
|
|
2009-09-28 20:26:07 +02:00
|
|
|
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
|
2009-09-29 18:42:22 +02:00
|
|
|
setIntrospection = opt: rec {
|
|
|
|
name = opt.name;
|
|
|
|
path = splitString "." opt.name;
|
|
|
|
config = setAttrByPath path
|
|
|
|
(throw "Usage introspection of '${name}' by forced failure.");
|
|
|
|
};
|
2009-09-28 20:26:07 +02:00
|
|
|
in
|
2009-09-29 18:42:22 +02:00
|
|
|
map setIntrospection (collect isOption eval.options);
|
2009-09-28 20:26:07 +02:00
|
|
|
|
2009-09-29 18:42:22 +02:00
|
|
|
overrideConfig = thrower:
|
|
|
|
pkgs.lib.recursiveUpdateUntil (path: old: new:
|
|
|
|
path == thrower.path
|
|
|
|
) eval.config thrower.config;
|
2009-09-28 20:26:07 +02:00
|
|
|
|
|
|
|
|
|
|
|
graph = with pkgs.lib;
|
|
|
|
map (thrower: {
|
2009-09-29 18:42:22 +02:00
|
|
|
option = thrower.name;
|
2009-09-28 20:26:07 +02:00
|
|
|
usedBy = reportNewFailures eval.options (evalFun {
|
|
|
|
extraArgs = {
|
2009-09-29 18:42:22 +02:00
|
|
|
config = overrideConfig thrower;
|
2009-09-28 20:26:07 +02:00
|
|
|
};
|
|
|
|
}).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;
|
|
|
|
};
|
|
|
|
}
|