types: improve dagOf and listOrDagOf
In particular, improve the behavior of these types if the element type is a submodule.
This commit is contained in:
parent
9f223e98b7
commit
8ad4bd6c1b
|
@ -7,16 +7,25 @@ let
|
||||||
isDagEntry = e: isAttrs e && (e ? data) && (e ? after) && (e ? before);
|
isDagEntry = e: isAttrs e && (e ? data) && (e ? after) && (e ? before);
|
||||||
|
|
||||||
dagContentType = elemType:
|
dagContentType = elemType:
|
||||||
types.submodule {
|
types.submodule ({ name, ... }: {
|
||||||
options = {
|
options = {
|
||||||
data = mkOption { type = elemType; };
|
data = mkOption { type = elemType; };
|
||||||
after = mkOption { type = with types; uniq (listOf str); };
|
after = mkOption { type = with types; uniq (listOf str); };
|
||||||
before = mkOption { type = with types; uniq (listOf str); };
|
before = mkOption { type = with types; uniq (listOf str); };
|
||||||
};
|
};
|
||||||
};
|
config = mkIf (elemType.name == "submodule") {
|
||||||
|
data._module.args.dagName = name;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
in {
|
in rec {
|
||||||
# A directed acyclic graph of some inner type.
|
# A directed acyclic graph of some inner type.
|
||||||
|
#
|
||||||
|
# Note, if the element type is a submodule then the `name` argument
|
||||||
|
# will always be set to the string "data" since it picks up the
|
||||||
|
# internal structure of the DAG values. To give access to the
|
||||||
|
# "actual" attribute name a new submodule argument is provided with
|
||||||
|
# the name `dagName`.
|
||||||
dagOf = elemType:
|
dagOf = elemType:
|
||||||
let
|
let
|
||||||
convertAllToDags = let
|
convertAllToDags = let
|
||||||
|
@ -51,34 +60,30 @@ in {
|
||||||
let padWidth = stringLength (toString (length list));
|
let padWidth = stringLength (toString (length list));
|
||||||
in fixedWidthNumber padWidth i;
|
in fixedWidthNumber padWidth i;
|
||||||
|
|
||||||
convertAllToDags = defs:
|
convertAll = defs:
|
||||||
let
|
let
|
||||||
convertAttrValue = n: v:
|
|
||||||
if isDagEntry v then v else dag.entryAnywhere v;
|
|
||||||
|
|
||||||
convertListValue = namePrefix: vs:
|
convertListValue = namePrefix: vs:
|
||||||
let
|
let
|
||||||
pad = paddedIndexStr vs;
|
pad = paddedIndexStr vs;
|
||||||
makeEntry = i: v:
|
makeEntry = i: v: nameValuePair "${namePrefix}.${pad i}" v;
|
||||||
nameValuePair "${namePrefix}.${pad i}" (dag.entryAnywhere v);
|
|
||||||
in listToAttrs (imap1 makeEntry vs);
|
in listToAttrs (imap1 makeEntry vs);
|
||||||
|
|
||||||
convertValue = i: value:
|
convertValue = i: value:
|
||||||
if isList value then
|
if isList value then
|
||||||
convertListValue "unnamed-${paddedIndexStr defs i}" value
|
convertListValue "unnamed-${paddedIndexStr defs i}" value
|
||||||
else
|
else
|
||||||
mapAttrs convertAttrValue value;
|
value;
|
||||||
in imap1 (i: def: def // { value = convertValue i def.value; }) defs;
|
in imap1 (i: def: def // { value = convertValue i def.value; }) defs;
|
||||||
|
|
||||||
attrEquivalent = types.attrsOf (dagContentType elemType);
|
dagType = dagOf elemType;
|
||||||
in mkOptionType rec {
|
in mkOptionType rec {
|
||||||
name = "dagOf";
|
name = "listOrDagOf";
|
||||||
description = "DAG of ${elemType.description}s";
|
description = "list or DAG of ${elemType.description}s";
|
||||||
check = x: isAttrs x || isList x;
|
check = x: isList x || dagType.check x;
|
||||||
merge = loc: defs: attrEquivalent.merge loc (convertAllToDags defs);
|
merge = loc: defs: dagType.merge loc (convertAll defs);
|
||||||
getSubOptions = prefix: elemType.getSubOptions (prefix ++ [ "<name>" ]);
|
getSubOptions = dagType.getSubOptions;
|
||||||
getSubModules = elemType.getSubModules;
|
getSubModules = dagType.getSubModules;
|
||||||
substSubModules = m: dagOf (elemType.substSubModules m);
|
substSubModules = m: listOrDagOf (elemType.substSubModules m);
|
||||||
functor = (defaultFunctor name) // { wrapped = elemType; };
|
functor = (defaultFunctor name) // { wrapped = elemType; };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
43
tests/lib/types/dag-submodule.nix
Normal file
43
tests/lib/types/dag-submodule.nix
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
|
||||||
|
dag = config.lib.dag;
|
||||||
|
|
||||||
|
result = let
|
||||||
|
sorted = dag.topoSort config.tested.dag;
|
||||||
|
data = map (e: "${e.name}:${e.data.name}") sorted.result;
|
||||||
|
in concatStringsSep "\n" data + "\n";
|
||||||
|
|
||||||
|
in {
|
||||||
|
options.tested.dag = mkOption {
|
||||||
|
type = hm.types.dagOf (types.submodule ({ dagName, ... }: {
|
||||||
|
options.name = mkOption { type = types.str; };
|
||||||
|
config.name = "dn-${dagName}";
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
tested.dag = {
|
||||||
|
after = { };
|
||||||
|
before = dag.entryBefore [ "after" ] { };
|
||||||
|
between = dag.entryBetween [ "after" ] [ "before" ] { };
|
||||||
|
};
|
||||||
|
|
||||||
|
home.file."result.txt".text = result;
|
||||||
|
|
||||||
|
nmt.script = ''
|
||||||
|
assertFileContent \
|
||||||
|
home-files/result.txt \
|
||||||
|
${
|
||||||
|
pkgs.writeText "result.txt" ''
|
||||||
|
before:dn-before
|
||||||
|
between:dn-between
|
||||||
|
after:dn-after
|
||||||
|
''
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
{
|
{
|
||||||
|
lib-types-dag-submodule = ./dag-submodule.nix;
|
||||||
lib-types-dag-merge = ./dag-merge.nix;
|
lib-types-dag-merge = ./dag-merge.nix;
|
||||||
lib-types-list-or-dag-merge = ./list-or-dag-merge.nix;
|
lib-types-list-or-dag-merge = ./list-or-dag-merge.nix;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue