mirror of
https://github.com/NixOS/nixpkgs.git
synced 2025-06-11 04:05:40 +03:00
lib/types: init {types.attrsWith}
This commit is contained in:
parent
9ca7693cdc
commit
c4a9529071
3 changed files with 106 additions and 31 deletions
|
@ -575,6 +575,9 @@ checkConfigOutput '^38|27$' options.submoduleLine38.declarationPositions.1.line
|
||||||
# nested options work
|
# nested options work
|
||||||
checkConfigOutput '^34$' options.nested.nestedLine34.declarationPositions.0.line ./declaration-positions.nix
|
checkConfigOutput '^34$' options.nested.nestedLine34.declarationPositions.0.line ./declaration-positions.nix
|
||||||
|
|
||||||
|
# AttrsWith tests
|
||||||
|
checkConfigOutput '^11$' config.result ./lazy-attrsWith.nix
|
||||||
|
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
====== module tests ======
|
====== module tests ======
|
||||||
$pass Pass
|
$pass Pass
|
||||||
|
|
45
lib/tests/modules/lazy-attrsWith.nix
Normal file
45
lib/tests/modules/lazy-attrsWith.nix
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
# Check that AttrsWith { lazy = true; } is lazy
|
||||||
|
{ lib, ... }:
|
||||||
|
let
|
||||||
|
inherit (lib) types mkOption;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
# Module A
|
||||||
|
(
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
options.mergedLazy = mkOption {
|
||||||
|
# Same as lazyAttrsOf
|
||||||
|
type = types.attrsWith {
|
||||||
|
lazy = true;
|
||||||
|
elemType = types.int;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
# Module B
|
||||||
|
(
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
options.mergedLazy = lib.mkOption {
|
||||||
|
# Same as lazyAttrsOf
|
||||||
|
type = types.attrsWith {
|
||||||
|
lazy = true;
|
||||||
|
elemType = types.int;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
# Result
|
||||||
|
(
|
||||||
|
{ config, ... }:
|
||||||
|
{
|
||||||
|
# Can only evaluate if lazy
|
||||||
|
config.mergedLazy.bar = config.mergedLazy.baz + 1;
|
||||||
|
config.mergedLazy.baz = 10;
|
||||||
|
options.result = mkOption { default = config.mergedLazy.bar; };
|
||||||
|
}
|
||||||
|
)
|
||||||
|
];
|
||||||
|
}
|
|
@ -582,48 +582,75 @@ rec {
|
||||||
substSubModules = m: nonEmptyListOf (elemType.substSubModules m);
|
substSubModules = m: nonEmptyListOf (elemType.substSubModules m);
|
||||||
};
|
};
|
||||||
|
|
||||||
attrsOf = elemType: mkOptionType rec {
|
attrsOf = elemType: attrsWith { inherit elemType; };
|
||||||
name = "attrsOf";
|
|
||||||
description = "attribute set of ${optionDescriptionPhrase (class: class == "noun" || class == "composite") elemType}";
|
|
||||||
descriptionClass = "composite";
|
|
||||||
check = isAttrs;
|
|
||||||
merge = loc: defs:
|
|
||||||
mapAttrs (n: v: v.value) (filterAttrs (n: v: v ? value) (zipAttrsWith (name: defs:
|
|
||||||
(mergeDefinitions (loc ++ [name]) elemType defs).optionalValue
|
|
||||||
)
|
|
||||||
# Push down position info.
|
|
||||||
(map (def: mapAttrs (n: v: { inherit (def) file; value = v; }) def.value) defs)));
|
|
||||||
emptyValue = { value = {}; };
|
|
||||||
getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name>"]);
|
|
||||||
getSubModules = elemType.getSubModules;
|
|
||||||
substSubModules = m: attrsOf (elemType.substSubModules m);
|
|
||||||
functor = (defaultFunctor name) // { wrapped = elemType; };
|
|
||||||
nestedTypes.elemType = elemType;
|
|
||||||
};
|
|
||||||
|
|
||||||
# A version of attrsOf that's lazy in its values at the expense of
|
# A version of attrsOf that's lazy in its values at the expense of
|
||||||
# conditional definitions not working properly. E.g. defining a value with
|
# conditional definitions not working properly. E.g. defining a value with
|
||||||
# `foo.attr = mkIf false 10`, then `foo ? attr == true`, whereas with
|
# `foo.attr = mkIf false 10`, then `foo ? attr == true`, whereas with
|
||||||
# attrsOf it would correctly be `false`. Accessing `foo.attr` would throw an
|
# attrsOf it would correctly be `false`. Accessing `foo.attr` would throw an
|
||||||
# error that it's not defined. Use only if conditional definitions don't make sense.
|
# error that it's not defined. Use only if conditional definitions don't make sense.
|
||||||
lazyAttrsOf = elemType: mkOptionType rec {
|
lazyAttrsOf = elemType: attrsWith { inherit elemType; lazy = true; };
|
||||||
name = "lazyAttrsOf";
|
|
||||||
description = "lazy attribute set of ${optionDescriptionPhrase (class: class == "noun" || class == "composite") elemType}";
|
# base type for lazyAttrsOf and attrsOf
|
||||||
|
attrsWith = {
|
||||||
|
elemType,
|
||||||
|
lazy ? false,
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
typeName = if lazy then "lazyAttrsOf" else "attrsOf";
|
||||||
|
# Push down position info.
|
||||||
|
pushPositions = map (def: mapAttrs (n: v: { inherit (def) file; value = v; }) def.value);
|
||||||
|
in
|
||||||
|
mkOptionType {
|
||||||
|
name = typeName;
|
||||||
|
description = (if lazy then "lazy attribute set" else "attribute set") + " of ${optionDescriptionPhrase (class: class == "noun" || class == "composite") elemType}";
|
||||||
descriptionClass = "composite";
|
descriptionClass = "composite";
|
||||||
check = isAttrs;
|
check = isAttrs;
|
||||||
merge = loc: defs:
|
merge = if lazy then (
|
||||||
zipAttrsWith (name: defs:
|
# Lazy merge Function
|
||||||
let merged = mergeDefinitions (loc ++ [name]) elemType defs;
|
loc: defs:
|
||||||
# mergedValue will trigger an appropriate error when accessed
|
zipAttrsWith (name: defs:
|
||||||
in merged.optionalValue.value or elemType.emptyValue.value or merged.mergedValue
|
let merged = mergeDefinitions (loc ++ [name]) elemType defs;
|
||||||
)
|
# mergedValue will trigger an appropriate error when accessed
|
||||||
# Push down position info.
|
in merged.optionalValue.value or elemType.emptyValue.value or merged.mergedValue
|
||||||
(map (def: mapAttrs (n: v: { inherit (def) file; value = v; }) def.value) defs);
|
)
|
||||||
|
# Push down position info.
|
||||||
|
(pushPositions defs)
|
||||||
|
) else (
|
||||||
|
# Non-lazy merge Function
|
||||||
|
loc: defs:
|
||||||
|
mapAttrs (n: v: v.value) (filterAttrs (n: v: v ? value) (zipAttrsWith (name: defs:
|
||||||
|
(mergeDefinitions (loc ++ [name]) elemType (defs)).optionalValue
|
||||||
|
)
|
||||||
|
# Push down position info.
|
||||||
|
(pushPositions defs)))
|
||||||
|
);
|
||||||
emptyValue = { value = {}; };
|
emptyValue = { value = {}; };
|
||||||
getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name>"]);
|
getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name>"]);
|
||||||
getSubModules = elemType.getSubModules;
|
getSubModules = elemType.getSubModules;
|
||||||
substSubModules = m: lazyAttrsOf (elemType.substSubModules m);
|
substSubModules = m: attrsWith { elemType = elemType.substSubModules m; inherit lazy; };
|
||||||
functor = (defaultFunctor name) // { wrapped = elemType; };
|
functor = defaultFunctor "attrsWith" // {
|
||||||
|
wrapped = elemType;
|
||||||
|
payload = {
|
||||||
|
# Important!: Add new function attributes here in case of future changes
|
||||||
|
inherit elemType lazy;
|
||||||
|
};
|
||||||
|
binOp = lhs: rhs:
|
||||||
|
let
|
||||||
|
elemType = lhs.elemType.typeMerge rhs.elemType.functor;
|
||||||
|
lazy =
|
||||||
|
if lhs.lazy == rhs.lazy then
|
||||||
|
lhs.lazy
|
||||||
|
else
|
||||||
|
null;
|
||||||
|
in
|
||||||
|
if elemType == null || lazy == null then
|
||||||
|
null
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inherit elemType lazy;
|
||||||
|
};
|
||||||
|
};
|
||||||
nestedTypes.elemType = elemType;
|
nestedTypes.elemType = elemType;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue