lib.types.attrTag: Take options instead of types

This commit is contained in:
Robert Hensing 2024-01-29 07:56:35 +01:00
parent 5b49672af4
commit 42d3b54f0d
2 changed files with 55 additions and 21 deletions

View File

@ -8,37 +8,55 @@ in
intStrings = mkOption {
type = types.attrsOf
(types.attrTag {
left = types.int;
right = types.str;
left = mkOption {
type = types.int;
};
right = mkOption {
type = types.str;
};
});
};
nested = mkOption {
type = types.attrTag {
left = types.int;
right = types.attrTag {
left = types.int;
right = types.str;
left = mkOption {
type = types.int;
};
right = mkOption {
type = types.attrTag {
left = mkOption {
type = types.int;
};
right = mkOption {
type = types.str;
};
};
};
};
};
merged = mkOption {
type = types.attrsOf (
types.attrTag {
yay = types.int;
yay = mkOption {
type = types.int;
};
}
);
};
submodules = mkOption {
type = types.attrsOf (
types.attrTag {
foo = types.submodule {
options = {
bar = mkOption {
type = types.int;
foo = mkOption {
type = types.submodule {
options = {
bar = mkOption {
type = types.int;
};
};
};
};
qux = types.str;
qux = mkOption {
type = types.str;
};
}
);
};
@ -50,7 +68,9 @@ in
options.merged = mkOption {
type = types.attrsOf (
types.attrTag {
nay = types.bool;
nay = mkOption {
type = types.bool;
};
}
);
};
@ -76,8 +96,7 @@ in
assert config.merged.positive.yay == 100;
# assert lib.foldl' (a: b: builtins.trace b a) true (lib.attrNames config.docs);
assert config.docs."submodules.<name>.foo.bar".type == "signed integer";
# It's not an option, so we can't render it as such. Something would be nice though.
assert ! (config.docs?"submodules.<name>.qux");
assert config.docs."submodules.<name>.qux".type == "string";
true;
};
}

View File

@ -65,6 +65,11 @@ let
fixupOptionType
mergeOptionDecls
;
inAttrPosSuffix = v: name:
let pos = builtins.unsafeGetAttrPos name v; in
if pos == null then "" else " at ${pos.file}:${toString pos.line}:${toString pos.column}";
outer_types =
rec {
__attrsFailEvaluation = true;
@ -616,8 +621,16 @@ rec {
attrTag = tags: attrTagWith { inherit tags; };
attrTagWith = { tags }:
attrTagWith = args@{ tags }:
let
tags =
mapAttrs
(n: opt:
builtins.addErrorContext "while checking that attrTag tag ${lib.strings.escapeNixIdentifier n} is an option with a type${inAttrPosSuffix args.tags n}" (
assert opt._type == "option";
opt
))
args.tags;
choicesStr = concatMapStringsSep ", " lib.strings.escapeNixIdentifier (attrNames tags);
in
mkOptionType {
@ -625,10 +638,12 @@ rec {
description = "attribute-tagged union of ${choicesStr}";
getSubOptions = prefix:
mapAttrs
(tagName: tagType:
tagType.getSubOptions (prefix ++ [ tagName ]))
(tagName: tagOption: {
"${lib.showOption prefix}" =
tagOption // { loc = prefix ++ [ tagName ]; };
})
tags;
substSubModules = m: attrTagWith { tags = mapAttrs (n: v: v.substSubModules m) tags; };
substSubModules = m: attrTagWith { tags = mapAttrs (n: opt: opt // { type = (opt.type or types.unspecified).substSubModules m; }) tags; };
check = v: isAttrs v && length (attrNames v) == 1 && tags?${head (attrNames v)};
merge = loc: defs:
let
@ -644,11 +659,11 @@ rec {
if tags?${choice}
then
{ ${choice} =
(mergeDefinitions
(lib.modules.evalOptionValue
(loc ++ [choice])
tags.${choice}
checkedValueDefs
).mergedValue;
).value;
}
else throw "The option `${showOption loc}` is defined as ${lib.strings.escapeNixIdentifier choice}, but ${lib.strings.escapeNixIdentifier choice} is not among the valid choices (${choicesStr}). Value ${choice} was defined in ${showFiles (getFiles defs)}.";
nestedTypes = tags;