mirror of
https://github.com/ilyakooo0/nixpkgs.git
synced 2024-12-25 04:12:44 +03:00
Update option-usages.nix expression to work with newer version of the module system.
This commit is contained in:
parent
2c9c135ee2
commit
c47e89623b
@ -55,7 +55,7 @@ rec {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
closed = closeModules (modules ++ [ internalModule ]) (specialArgs // { inherit config options; lib = import ./.; });
|
closed = closeModules (modules ++ [ internalModule ]) ({ inherit config options; lib = import ./.; } // specialArgs);
|
||||||
|
|
||||||
# Note: the list of modules is reversed to maintain backward
|
# Note: the list of modules is reversed to maintain backward
|
||||||
# compatibility with the old module system. Not sure if this is
|
# compatibility with the old module system. Not sure if this is
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
baseModules ? import ../modules/module-list.nix
|
baseModules ? import ../modules/module-list.nix
|
||||||
, # !!! See comment about args in lib/modules.nix
|
, # !!! See comment about args in lib/modules.nix
|
||||||
extraArgs ? {}
|
extraArgs ? {}
|
||||||
|
, # !!! See comment about args in lib/modules.nix
|
||||||
|
specialArgs ? {}
|
||||||
, modules
|
, modules
|
||||||
, # !!! See comment about check in lib/modules.nix
|
, # !!! See comment about check in lib/modules.nix
|
||||||
check ? true
|
check ? true
|
||||||
@ -47,7 +49,7 @@ in rec {
|
|||||||
inherit prefix check;
|
inherit prefix check;
|
||||||
modules = modules ++ extraModules ++ baseModules ++ [ pkgsModule ];
|
modules = modules ++ extraModules ++ baseModules ++ [ pkgsModule ];
|
||||||
args = extraArgs;
|
args = extraArgs;
|
||||||
specialArgs = { modulesPath = ../modules; };
|
specialArgs = { modulesPath = ../modules; } // specialArgs;
|
||||||
}) config options;
|
}) config options;
|
||||||
|
|
||||||
# These are the extra arguments passed to every module. In
|
# These are the extra arguments passed to every module. In
|
||||||
|
@ -1,59 +1,125 @@
|
|||||||
{ configuration ? import ../lib/from-env.nix "NIXOS_CONFIG" <nixos-config>
|
{ configuration ? import ../lib/from-env.nix "NIXOS_CONFIG" <nixos-config>
|
||||||
|
|
||||||
# []: display all options
|
# provide an option name, as a string literal.
|
||||||
# [<option names>]: display the selected options
|
, testOption ? null
|
||||||
, displayOptions ? [
|
|
||||||
"hardware.pcmcia.enable"
|
# provide a list of option names, as string literals.
|
||||||
"environment.systemPackages"
|
, testOptions ? [ ]
|
||||||
"boot.kernelModules"
|
|
||||||
"services.udev.packages"
|
|
||||||
"jobs"
|
|
||||||
"environment.etc"
|
|
||||||
"system.activationScripts"
|
|
||||||
]
|
|
||||||
}:
|
}:
|
||||||
|
|
||||||
# This file is used to generate a dot graph which contains all options and
|
# This file is made to be used as follow:
|
||||||
# there dependencies to track problems and their sources.
|
#
|
||||||
|
# $ nix-instantiate ./option-usage.nix --argstr testOption service.xserver.enable -A txtContent --eval
|
||||||
|
#
|
||||||
|
# or
|
||||||
|
#
|
||||||
|
# $ nix-build ./option-usage.nix --argstr testOption service.xserver.enable -A txt -o service.xserver.enable._txt
|
||||||
|
#
|
||||||
|
# otther target exists such as, `dotContent`, `dot`, and `pdf`. If you are
|
||||||
|
# looking for the option usage of multiple options, you can provide a list
|
||||||
|
# as argument.
|
||||||
|
#
|
||||||
|
# $ nix-build ./option-usage.nix --arg testOptions \
|
||||||
|
# '["boot.loader.gummiboot.enable" "boot.loader.gummiboot.timeout"]' \
|
||||||
|
# -A txt -o gummiboot.list
|
||||||
|
#
|
||||||
|
# Note, this script is slow as it has to evaluate all options of the system
|
||||||
|
# once per queried option.
|
||||||
|
#
|
||||||
|
# This nix expression works by doing a first evaluation, which evaluates the
|
||||||
|
# result of every option.
|
||||||
|
#
|
||||||
|
# Then, for each queried option, we evaluate the NixOS modules a second
|
||||||
|
# time, except that we replace the `config` argument of all the modules with
|
||||||
|
# the result of the original evaluation, except for the tested option which
|
||||||
|
# value is replaced by a `throw` statement which is caught by the `tryEval`
|
||||||
|
# evaluation of each option value.
|
||||||
|
#
|
||||||
|
# We then compare the result of the evluation of the original module, with
|
||||||
|
# the result of the second evaluation, and consider that the new failures are
|
||||||
|
# caused by our mutation of the `config` argument.
|
||||||
|
#
|
||||||
|
# Doing so returns all option results which are directly using the
|
||||||
|
# tested option result.
|
||||||
|
|
||||||
|
with import ../../lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
evalFun = {
|
evalFun = {
|
||||||
extraArgs ? {}
|
specialArgs ? {}
|
||||||
}: import ../lib/eval-config.nix {
|
}: import ../lib/eval-config.nix {
|
||||||
modules = [ configuration ];
|
modules = [ configuration ];
|
||||||
inherit extraArgs;
|
inherit specialArgs;
|
||||||
};
|
};
|
||||||
|
|
||||||
eval = evalFun {};
|
eval = evalFun {};
|
||||||
inherit (eval) pkgs;
|
inherit (eval) pkgs;
|
||||||
|
|
||||||
reportNewFailures = old: new: with pkgs.lib;
|
excludedTestOptions = [
|
||||||
|
# We cannot evluate _module.args, as it is used during the computation
|
||||||
|
# of the modules list.
|
||||||
|
"_module.args"
|
||||||
|
|
||||||
|
# For some reasons which we yet have to investigate, some options cannot
|
||||||
|
# be replaced by a throw without cuasing a non-catchable failure.
|
||||||
|
"networking.bonds"
|
||||||
|
"networking.bridges"
|
||||||
|
"networking.interfaces"
|
||||||
|
"networking.macvlans"
|
||||||
|
"networking.sits"
|
||||||
|
"networking.vlans"
|
||||||
|
"services.openssh.startWhenNeeded"
|
||||||
|
];
|
||||||
|
|
||||||
|
# for some reasons which we yet have to investigate, some options are
|
||||||
|
# time-consuming to compute, thus we filter them out at the moment.
|
||||||
|
excludedOptions = [
|
||||||
|
"boot.systemd.services"
|
||||||
|
"systemd.services"
|
||||||
|
"environment.gnome3.packageSet"
|
||||||
|
"kde.extraPackages"
|
||||||
|
];
|
||||||
|
excludeOptions = list:
|
||||||
|
filter (opt: !(elem (showOption opt.loc) excludedOptions)) list;
|
||||||
|
|
||||||
|
|
||||||
|
reportNewFailures = old: new:
|
||||||
let
|
let
|
||||||
filterChanges =
|
filterChanges =
|
||||||
filter ({fst, snd}:
|
filter ({fst, snd}:
|
||||||
!(fst.config.success -> snd.config.success)
|
!(fst.success -> snd.success)
|
||||||
);
|
);
|
||||||
|
|
||||||
keepNames =
|
keepNames =
|
||||||
map ({fst, snd}:
|
map ({fst, snd}:
|
||||||
assert fst.name == snd.name; snd.name
|
/* assert fst.name == snd.name; */ snd.name
|
||||||
);
|
);
|
||||||
|
|
||||||
|
# Use tryEval (strict ...) to know if there is any failure while
|
||||||
|
# evaluating the option value.
|
||||||
|
#
|
||||||
|
# Note, the `strict` function is not strict enough, but using toXML
|
||||||
|
# builtins multiply by 4 the memory usage and the time used to compute
|
||||||
|
# each options.
|
||||||
|
tryCollectOptions = moduleResult:
|
||||||
|
flip map (excludeOptions (collect isOption moduleResult)) (opt:
|
||||||
|
{ name = showOption opt.loc; } // builtins.tryEval (strict opt.value));
|
||||||
in
|
in
|
||||||
keepNames (
|
keepNames (
|
||||||
filterChanges (
|
filterChanges (
|
||||||
zipLists (collect isOption old) (collect isOption new)
|
zipLists (tryCollectOptions old) (tryCollectOptions new)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
# Create a list of modules where each module contains only one failling
|
# Create a list of modules where each module contains only one failling
|
||||||
# options.
|
# options.
|
||||||
introspectionModules = with pkgs.lib;
|
introspectionModules =
|
||||||
let
|
let
|
||||||
setIntrospection = opt: rec {
|
setIntrospection = opt: rec {
|
||||||
name = opt.name;
|
name = showOption opt.loc;
|
||||||
path = splitString "." opt.name;
|
path = opt.loc;
|
||||||
config = setAttrByPath path
|
config = setAttrByPath path
|
||||||
(throw "Usage introspection of '${name}' by forced failure.");
|
(throw "Usage introspection of '${name}' by forced failure.");
|
||||||
};
|
};
|
||||||
@ -61,39 +127,67 @@ let
|
|||||||
map setIntrospection (collect isOption eval.options);
|
map setIntrospection (collect isOption eval.options);
|
||||||
|
|
||||||
overrideConfig = thrower:
|
overrideConfig = thrower:
|
||||||
pkgs.lib.recursiveUpdateUntil (path: old: new:
|
recursiveUpdateUntil (path: old: new:
|
||||||
path == thrower.path
|
path == thrower.path
|
||||||
) eval.config thrower.config;
|
) eval.config thrower.config;
|
||||||
|
|
||||||
|
|
||||||
graph = with pkgs.lib;
|
graph =
|
||||||
map (thrower: {
|
map (thrower: {
|
||||||
option = thrower.name;
|
option = thrower.name;
|
||||||
usedBy = reportNewFailures eval.options (evalFun {
|
usedBy = assert __trace "Investigate ${thrower.name}" true;
|
||||||
extraArgs = {
|
reportNewFailures eval.options (evalFun {
|
||||||
config = overrideConfig thrower;
|
specialArgs = {
|
||||||
};
|
config = overrideConfig thrower;
|
||||||
}).options;
|
};
|
||||||
|
}).options;
|
||||||
}) introspectionModules;
|
}) introspectionModules;
|
||||||
|
|
||||||
graphToDot = graph: with pkgs.lib; ''
|
displayOptionsGraph =
|
||||||
|
let
|
||||||
|
checkList =
|
||||||
|
if !(isNull testOption) then [ testOption ]
|
||||||
|
else testOptions;
|
||||||
|
checkAll = checkList == [];
|
||||||
|
in
|
||||||
|
flip filter graph ({option, usedBy}:
|
||||||
|
(checkAll || elem option checkList)
|
||||||
|
&& !(elem option excludedTestOptions)
|
||||||
|
);
|
||||||
|
|
||||||
|
graphToDot = graph: ''
|
||||||
digraph "Option Usages" {
|
digraph "Option Usages" {
|
||||||
${concatMapStrings ({option, usedBy}:
|
${concatMapStrings ({option, usedBy}:
|
||||||
assert __trace option true;
|
concatMapStrings (user: ''
|
||||||
if displayOptions == [] || elem option displayOptions then
|
"${option}" -> "${user}"''
|
||||||
concatMapStrings (user: ''
|
) usedBy
|
||||||
"${option}" -> "${user}"''
|
) displayOptionsGraph}
|
||||||
) usedBy
|
|
||||||
else ""
|
|
||||||
) graph}
|
|
||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
graphToText = graph:
|
||||||
|
concatMapStrings ({option, usedBy}:
|
||||||
|
concatMapStrings (user: ''
|
||||||
|
${user}
|
||||||
|
'') usedBy
|
||||||
|
) displayOptionsGraph;
|
||||||
|
|
||||||
in
|
in
|
||||||
|
|
||||||
pkgs.texFunctions.dot2pdf {
|
rec {
|
||||||
dotGraph = pkgs.writeTextFile {
|
dotContent = graphToDot graph;
|
||||||
|
dot = pkgs.writeTextFile {
|
||||||
name = "option_usages.dot";
|
name = "option_usages.dot";
|
||||||
text = graphToDot graph;
|
text = dotContent;
|
||||||
|
};
|
||||||
|
|
||||||
|
pdf = pkgs.texFunctions.dot2pdf {
|
||||||
|
dotGraph = dot;
|
||||||
|
};
|
||||||
|
|
||||||
|
txtContent = graphToText graph;
|
||||||
|
txt = pkgs.writeTextFile {
|
||||||
|
name = "option_usages.txt";
|
||||||
|
text = txtContent;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user