feat: add portable submodule type #11
|
@ -916,6 +916,117 @@ lib: {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
## Create a type from a submodule which can be used in multiple parts of the configuration.
|
||||||
|
##
|
||||||
|
## @type { module :: Module, name? :: String, description? :: String } -> Attrs
|
||||||
|
portable =
|
||||||
|
{ name ? "PortableSubmodule"
|
||||||
|
, description ? "portable submodule"
|
||||||
|
, module
|
||||||
|
,
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
normalize =
|
||||||
|
value:
|
||||||
|
if builtins.isFunction value || builtins.isList value then
|
||||||
|
value
|
||||||
|
else if value ? __modules__ then
|
||||||
|
value.__modules__
|
||||||
|
else
|
||||||
|
{ config = value; };
|
||||||
|
|
||||||
|
initial = lib.types.create {
|
||||||
|
name = "PortableSubmoduleInitial";
|
||||||
|
description = "initial portable submodule value";
|
||||||
|
check = value: builtins.isFunction value || builtins.isAttrs value || builtins.isList value;
|
||||||
|
merge =
|
||||||
|
location: definitions:
|
||||||
|
let
|
||||||
|
normalized = builtins.map (definition: lib.lists.from.any (normalize definition.value)) definitions;
|
||||||
|
in
|
||||||
|
builtins.concatLists normalized;
|
||||||
|
};
|
||||||
|
|
||||||
|
base = { config }: {
|
||||||
|
options = {
|
||||||
|
__modules__ = lib.options.create {
|
||||||
|
description = "User specified modules to be evaluated.";
|
||||||
|
type = lib.types.list.of (initial // { merge = lib.options.merge.one; });
|
||||||
|
internal = true;
|
||||||
|
default.value = [ ];
|
||||||
|
};
|
||||||
|
|
||||||
|
extend = lib.options.create {
|
||||||
|
description = "Extend the submodule configuration.";
|
||||||
|
type = lib.types.function lib.types.raw;
|
||||||
|
internal = true;
|
||||||
|
writable = false;
|
||||||
|
default.value = module:
|
||||||
|
let
|
||||||
|
normalized =
|
||||||
|
if builtins.isList module then module
|
||||||
|
else if builtins.isFunction module || module ? config then
|
||||||
|
[ module ]
|
||||||
|
else [{ config = module; }];
|
||||||
|
|
||||||
|
modules = config.__modules__ ++ normalized;
|
||||||
|
|
||||||
|
result = lib.modules.run {
|
||||||
|
modules = [
|
||||||
|
module
|
||||||
|
base
|
||||||
|
{ config.__modules__ = modules; }
|
||||||
|
] ++ modules;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
result.config;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
transform = location: value:
|
||||||
|
let
|
||||||
|
modules = lib.lists.from.any (normalize value);
|
||||||
|
|
||||||
|
result = lib.modules.run {
|
||||||
|
prefix = location;
|
||||||
|
modules = [
|
||||||
|
module
|
||||||
|
base
|
||||||
|
{ config.__modules__ = modules; }
|
||||||
|
] ++ modules;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
result.config;
|
||||||
|
|
||||||
|
final = lib.types.raw // {
|
||||||
|
merge = location: definitions:
|
||||||
|
let
|
||||||
|
modules = lib.lists.flatten (
|
||||||
|
builtins.map (definition: normalize definition.value) definitions
|
||||||
|
);
|
||||||
|
|
||||||
|
result = lib.modules.run {
|
||||||
|
prefix = location;
|
||||||
|
modules = [
|
||||||
|
module
|
||||||
|
base
|
||||||
|
{ config.__modules__ = modules; }
|
||||||
|
] ++ modules;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
result.config;
|
||||||
|
};
|
||||||
|
|
||||||
|
type = lib.types.coerceWithLocation initial transform final;
|
||||||
|
in
|
||||||
|
type // {
|
||||||
|
inherit name description;
|
||||||
|
children = type.children // {
|
||||||
|
inherit module base;
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
deferred = {
|
deferred = {
|
||||||
|
|
|
@ -1,4 +1,51 @@
|
||||||
let
|
let
|
||||||
lib = import ./../default.nix;
|
lib = import ./../default.nix;
|
||||||
in
|
in
|
||||||
{ }
|
{
|
||||||
|
"PortableSubmodule" = {
|
||||||
|
"is portable" =
|
||||||
|
let
|
||||||
|
submodule = { config }: {
|
||||||
|
options = {
|
||||||
|
primitive = lib.options.create {
|
||||||
|
type = lib.types.string;
|
||||||
|
default.value = "<default>";
|
||||||
|
};
|
||||||
|
|
||||||
|
computed = lib.options.create {
|
||||||
|
type = lib.types.string;
|
||||||
|
default.value = "computed: ${config.primitive}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
option = lib.options.create {
|
||||||
|
default.value = { };
|
||||||
|
type = lib.types.submodules.portable {
|
||||||
|
module = submodule;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
moduleA = {
|
||||||
|
options.a = option;
|
||||||
|
};
|
||||||
|
moduleB = { config }: {
|
||||||
|
options.b = option;
|
||||||
|
|
||||||
|
config.b = config.a;
|
||||||
|
};
|
||||||
|
moduleC = {
|
||||||
|
config.b.primitive = "custom";
|
||||||
|
};
|
||||||
|
|
||||||
|
result = lib.modules.run {
|
||||||
|
modules = [
|
||||||
|
moduleA
|
||||||
|
moduleB
|
||||||
|
moduleC
|
||||||
|
];
|
||||||
|
};
|
||||||
|
in
|
||||||
|
result.config.b.computed == "computed: custom";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue