Refactor select with new maybe selector

This is a great refactor of the select functionality in the flake class.
This now uses the same parser as the nix code, but runs it in python for
nice stacktraces.

Also we now have a maybe selector which can be used by prepending the
selector with a ?

Tests have been expanded to make sure the code is more stable and easier
to understand
This commit is contained in:
lassulus
2025-04-19 15:20:13 -07:00
committed by Michael Hoang
parent f11ccac1b6
commit d93e58218d
9 changed files with 691 additions and 395 deletions

View File

@@ -30,6 +30,6 @@ lib.fix (clanLib: {
# Plain imports.
values = import ./introspection { inherit lib; };
jsonschema = import ./jsonschema { inherit lib; };
select = import select/default.nix;
select = self.inputs.nix-select.lib;
facts = import ./facts.nix { inherit lib; };
})

View File

@@ -11,7 +11,6 @@ rec {
./introspection/flake-module.nix
./inventory/flake-module.nix
./jsonschema/flake-module.nix
./select/flake-module.nix
];
flake.clanLib = import ./default.nix {
inherit lib inputs self;

View File

@@ -1,68 +0,0 @@
let
recursiveSelect =
selectorIndex: selectorList: target:
let
selector = builtins.elemAt selectorList selectorIndex;
in
# selector is empty, we are done
if selectorIndex + 1 > builtins.length selectorList then
target
else if builtins.isList target then
# support bla.* for lists and recurse into all elements
if selector == "*" then
builtins.map (v: recursiveSelect (selectorIndex + 1) selectorList v) target
# support bla.3 for lists and recurse into the 4th element
else if (builtins.match "[[:digit:]]*" selector) == [ ] then
recursiveSelect (selectorIndex + 1) selectorList (
builtins.elemAt target (builtins.fromJSON selector)
)
else
throw "only * or a number is allowed in list selector"
else if builtins.isAttrs target then
# handle the case bla.x.*.z where x is an attrset and we recurse into all elements
if selector == "*" then
builtins.mapAttrs (_: v: recursiveSelect (selectorIndex + 1) selectorList v) target
# support bla.{x,y,z}.world where we get world from each of x, y and z
else if (builtins.match ''^\{([^}]*)}$'' selector) != null then
let
attrsAsList = (
builtins.filter (x: !builtins.isList x) (
builtins.split "," (builtins.head (builtins.match ''^\{([^}]*)}$'' selector))
)
);
dummyAttrSet = builtins.listToAttrs (
map (x: {
name = x;
value = null;
}) attrsAsList
);
filteredAttrs = builtins.intersectAttrs dummyAttrSet target;
in
builtins.mapAttrs (_: v: recursiveSelect (selectorIndex + 1) selectorList v) filteredAttrs
else
recursiveSelect (selectorIndex + 1) selectorList (builtins.getAttr selector target)
else
throw "Expected a list or an attrset";
parseSelector =
selector:
let
splitByQuote = x: builtins.filter (x: !builtins.isList x) (builtins.split ''"'' x);
splitByDot =
x:
builtins.filter (x: x != "") (
map (builtins.replaceStrings [ "." ] [ "" ]) (
builtins.filter (x: !builtins.isList x) (builtins.split ''\.'' x)
)
);
handleQuoted =
x: if x == [ ] then [ ] else [ (builtins.head x) ] ++ handleUnquoted (builtins.tail x);
handleUnquoted =
x: if x == [ ] then [ ] else splitByDot (builtins.head x) ++ handleQuoted (builtins.tail x);
in
handleUnquoted (splitByQuote selector);
in
selector: target: recursiveSelect 0 (parseSelector selector) target

View File

@@ -1,45 +0,0 @@
{ self, inputs, ... }:
let
inputOverrides = builtins.concatStringsSep " " (
builtins.map (input: " --override-input ${input} ${inputs.${input}}") (builtins.attrNames inputs)
);
in
{
perSystem =
{
pkgs,
lib,
system,
...
}:
{
# Run: nix-unit --extra-experimental-features flakes --flake .#legacyPackages.x86_64-linux.evalTests
legacyPackages.evalTests-select = import ./tests.nix {
inherit lib;
inherit (self) clanLib;
};
checks = {
lib-select-eval = pkgs.runCommand "tests" { nativeBuildInputs = [ pkgs.nix-unit ]; } ''
export HOME="$(realpath .)"
export NIX_ABORT_ON_WARN=1
nix-unit --eval-store "$HOME" \
--extra-experimental-features flakes \
--show-trace \
${inputOverrides} \
--flake ${
self.filter {
include = [
"flakeModules"
"lib"
"clanModules/flake-module.nix"
"clanModules/borgbackup"
];
}
}#legacyPackages.${system}.evalTests-select
touch $out
'';
};
};
}

View File

@@ -1,10 +0,0 @@
{ clanLib, ... }:
let
inherit (clanLib) select;
in
{
test_simple_1 = {
expr = select "a" { a = 1; };
expected = 1;
};
}