chore(lib/treewide): cleanup directory struture of lib. See lib/readme.md for details
This commit is contained in:
93
lib/introspection/default.nix
Normal file
93
lib/introspection/default.nix
Normal file
@@ -0,0 +1,93 @@
|
||||
{
|
||||
lib ? import <nixpkgs/lib>,
|
||||
}:
|
||||
let
|
||||
filterOptions = lib.filterAttrs (
|
||||
name: _:
|
||||
!builtins.elem name [
|
||||
"_module"
|
||||
"_freeformOptions"
|
||||
]
|
||||
);
|
||||
|
||||
getPrios =
|
||||
{
|
||||
options,
|
||||
}:
|
||||
let
|
||||
filteredOptions = filterOptions options;
|
||||
in
|
||||
lib.mapAttrs (
|
||||
_: opt:
|
||||
let
|
||||
prio = {
|
||||
__prio = opt.highestPrio;
|
||||
};
|
||||
filteredSubOptions = filterOptions (opt.type.getSubOptions opt.loc);
|
||||
|
||||
zipDefs = builtins.zipAttrsWith (_: vs: vs);
|
||||
|
||||
prioPerValue =
|
||||
{ type, defs }:
|
||||
lib.mapAttrs (
|
||||
attrName: prioSet:
|
||||
let
|
||||
# Evaluate the submodule
|
||||
options = filteredSubOptions;
|
||||
modules = (
|
||||
[
|
||||
{
|
||||
inherit options;
|
||||
_file = "<artifical submodule>";
|
||||
}
|
||||
]
|
||||
++ map (config: { inherit config; }) defs.${attrName}
|
||||
);
|
||||
submoduleEval = lib.evalModules {
|
||||
inherit modules;
|
||||
};
|
||||
in
|
||||
(lib.optionalAttrs (prioSet ? highestPrio) {
|
||||
__prio = prioSet.highestPrio;
|
||||
})
|
||||
// (
|
||||
if type.nestedTypes.elemType.name == "submodule" then
|
||||
getPrios { options = submoduleEval.options; }
|
||||
else
|
||||
# Nested attrsOf
|
||||
(lib.optionalAttrs (type.nestedTypes.elemType.name == "attrsOf") (
|
||||
prioPerValue {
|
||||
type = type.nestedTypes.elemType;
|
||||
defs = zipDefs defs.${attrName};
|
||||
} prioSet.value
|
||||
))
|
||||
)
|
||||
);
|
||||
|
||||
submodulePrios =
|
||||
let
|
||||
modules = (opt.definitions ++ opt.type.getSubModules);
|
||||
submoduleEval = lib.evalModules {
|
||||
inherit modules;
|
||||
};
|
||||
in
|
||||
getPrios { options = filterOptions submoduleEval.options; };
|
||||
|
||||
in
|
||||
if opt ? type && opt.type.name == "submodule" then
|
||||
(prio) // submodulePrios
|
||||
else if opt ? type && opt.type.name == "attrsOf" then
|
||||
prio
|
||||
// (prioPerValue {
|
||||
type = opt.type;
|
||||
defs = zipDefs opt.definitions;
|
||||
} (lib.modules.mergeAttrDefinitionsWithPrio opt))
|
||||
else if opt ? type && opt._type == "option" then
|
||||
prio
|
||||
else
|
||||
getPrios { options = opt; }
|
||||
) filteredOptions;
|
||||
in
|
||||
{
|
||||
inherit getPrios;
|
||||
}
|
||||
40
lib/introspection/flake-module.nix
Normal file
40
lib/introspection/flake-module.nix
Normal file
@@ -0,0 +1,40 @@
|
||||
{ self, inputs, ... }:
|
||||
let
|
||||
inputOverrides = builtins.concatStringsSep " " (
|
||||
builtins.map (input: " --override-input ${input} ${inputs.${input}}") (builtins.attrNames inputs)
|
||||
);
|
||||
in
|
||||
{
|
||||
perSystem =
|
||||
{
|
||||
pkgs,
|
||||
system,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
tests = import ./test.nix { inherit lib; };
|
||||
in
|
||||
{
|
||||
legacyPackages.evalTests-values = tests;
|
||||
checks = {
|
||||
lib-values-eval = pkgs.runCommand "tests" { nativeBuildInputs = [ pkgs.nix-unit ]; } ''
|
||||
export HOME="$(realpath .)"
|
||||
|
||||
nix-unit --eval-store "$HOME" \
|
||||
--extra-experimental-features flakes \
|
||||
${inputOverrides} \
|
||||
--flake ${
|
||||
self.filter {
|
||||
include = [
|
||||
"flakeModules"
|
||||
"lib"
|
||||
];
|
||||
}
|
||||
}#legacyPackages.${system}.evalTests-values
|
||||
|
||||
touch $out
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
297
lib/introspection/test.nix
Normal file
297
lib/introspection/test.nix
Normal file
@@ -0,0 +1,297 @@
|
||||
# tests for the nixos options to jsonschema converter
|
||||
# run these tests via `nix-unit ./test.nix`
|
||||
{
|
||||
lib ? (import <nixpkgs> { }).lib,
|
||||
slib ? (import ./. { inherit lib; }),
|
||||
}:
|
||||
let
|
||||
eval =
|
||||
modules:
|
||||
let
|
||||
evaledConfig = lib.evalModules {
|
||||
inherit modules;
|
||||
};
|
||||
in
|
||||
evaledConfig;
|
||||
in
|
||||
{
|
||||
test_default = {
|
||||
expr = slib.getPrios {
|
||||
options =
|
||||
(eval [
|
||||
{
|
||||
options.foo.bar = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
description = "Test Description";
|
||||
default = true;
|
||||
};
|
||||
}
|
||||
]).options;
|
||||
};
|
||||
expected = {
|
||||
foo.bar = {
|
||||
__prio = 1500;
|
||||
};
|
||||
};
|
||||
};
|
||||
test_no_default = {
|
||||
expr = slib.getPrios {
|
||||
options =
|
||||
(eval [
|
||||
{
|
||||
options.foo.bar = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
};
|
||||
}
|
||||
]).options;
|
||||
};
|
||||
expected = {
|
||||
foo.bar = {
|
||||
__prio = 9999;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
test_submodule = {
|
||||
expr = slib.getPrios {
|
||||
options =
|
||||
(eval [
|
||||
{
|
||||
options.foo = lib.mkOption {
|
||||
type = lib.types.submodule {
|
||||
options = {
|
||||
bar = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
]).options;
|
||||
};
|
||||
expected = {
|
||||
foo = {
|
||||
# Prio of the submodule itself
|
||||
__prio = 9999;
|
||||
|
||||
# Prio of the bar option within the submodule
|
||||
bar.__prio = 9999;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
test_submodule_with_merging =
|
||||
let
|
||||
evaluated = (
|
||||
eval [
|
||||
{
|
||||
options.foo = lib.mkOption {
|
||||
type = lib.types.submodule {
|
||||
options = {
|
||||
normal = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
};
|
||||
default = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
};
|
||||
optionDefault = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
};
|
||||
unset = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
{
|
||||
foo.default = lib.mkDefault true;
|
||||
}
|
||||
{
|
||||
foo.normal = false;
|
||||
}
|
||||
]
|
||||
);
|
||||
in
|
||||
{
|
||||
inherit evaluated;
|
||||
expr = slib.getPrios {
|
||||
options = evaluated.options;
|
||||
};
|
||||
expected = {
|
||||
foo = {
|
||||
__prio = 100;
|
||||
normal.__prio = 100; # Set via other module
|
||||
default.__prio = 1000;
|
||||
optionDefault.__prio = 1500;
|
||||
unset.__prio = 9999;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
test_submoduleWith =
|
||||
let
|
||||
evaluated = (
|
||||
eval [
|
||||
{
|
||||
options.foo = lib.mkOption {
|
||||
type = lib.types.submoduleWith {
|
||||
modules = [
|
||||
{
|
||||
options.bar = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
{
|
||||
foo.bar = false;
|
||||
}
|
||||
]
|
||||
);
|
||||
in
|
||||
{
|
||||
inherit evaluated;
|
||||
expr = slib.getPrios {
|
||||
options = evaluated.options;
|
||||
};
|
||||
expected = {
|
||||
foo = {
|
||||
__prio = 100;
|
||||
bar.__prio = 100; # Set via other module
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# TODO(@hsjobeki): Cover this edge case
|
||||
# test_freeform =
|
||||
# let
|
||||
# evaluated = (
|
||||
# eval [
|
||||
# {
|
||||
# freeformType = with lib.types; attrsOf (int);
|
||||
# options = {
|
||||
# foo = lib.mkOption {
|
||||
# type = lib.types.int;
|
||||
# default = 0;
|
||||
# };
|
||||
# };
|
||||
# }
|
||||
# {
|
||||
# bar = lib.mkForce 123;
|
||||
# baz = 1;
|
||||
# }
|
||||
# {
|
||||
# bar = 10;
|
||||
# }
|
||||
# ]
|
||||
# );
|
||||
# in
|
||||
# {
|
||||
# inherit evaluated;
|
||||
# expr = slib.getPrios {
|
||||
# options = evaluated.options;
|
||||
# };
|
||||
# expected = {
|
||||
# };
|
||||
# };
|
||||
|
||||
test_attrsOf_submodule =
|
||||
let
|
||||
evaluated = eval [
|
||||
{
|
||||
options.foo = lib.mkOption {
|
||||
type = lib.types.attrsOf (
|
||||
lib.types.submodule {
|
||||
options = {
|
||||
bar = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default = 0;
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
config.foo = {
|
||||
"nested" = {
|
||||
"bar" = 2; # <- 100 prio ?
|
||||
};
|
||||
"other" = {
|
||||
"bar" = lib.mkForce 2; # <- 50 prio ?
|
||||
};
|
||||
};
|
||||
}
|
||||
];
|
||||
in
|
||||
{
|
||||
expr = slib.getPrios { options = evaluated.options; };
|
||||
expected = {
|
||||
foo.__prio = 100;
|
||||
|
||||
foo.nested.__prio = 100;
|
||||
foo.other.__prio = 100;
|
||||
|
||||
foo.nested.bar.__prio = 100;
|
||||
foo.other.bar.__prio = 50;
|
||||
};
|
||||
};
|
||||
test_attrsOf_attrsOf_submodule =
|
||||
let
|
||||
evaluated = eval [
|
||||
{
|
||||
options.foo = lib.mkOption {
|
||||
type = lib.types.attrsOf (
|
||||
lib.types.attrsOf (
|
||||
lib.types.submodule {
|
||||
options = {
|
||||
bar = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default = 0;
|
||||
};
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
};
|
||||
config.foo = {
|
||||
a.b = {
|
||||
bar = 1;
|
||||
};
|
||||
a.c = {
|
||||
bar = 1;
|
||||
};
|
||||
x.y = {
|
||||
bar = 1;
|
||||
};
|
||||
x.z = {
|
||||
bar = 1;
|
||||
};
|
||||
};
|
||||
}
|
||||
];
|
||||
in
|
||||
{
|
||||
inherit evaluated;
|
||||
expr = slib.getPrios { options = evaluated.options; };
|
||||
expected = {
|
||||
foo.__prio = 100;
|
||||
|
||||
# Sub A
|
||||
foo.a.__prio = 100;
|
||||
# a.b doesnt have a prio
|
||||
# a.c doesnt have a prio
|
||||
foo.a.b.bar.__prio = 100;
|
||||
foo.a.c.bar.__prio = 100;
|
||||
|
||||
# Sub X
|
||||
foo.x.__prio = 100;
|
||||
# x.y doesnt have a prio
|
||||
# x.z doesnt have a prio
|
||||
foo.x.y.bar.__prio = 100;
|
||||
foo.x.z.bar.__prio = 100;
|
||||
};
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user