Merge pull request 'Feat(clanLib): init types {uniqueDeferredSerializableModule}' (#3737) from hsjobeki/clan-core:fix-2 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3737
This commit is contained in:
@@ -3,12 +3,13 @@
|
|||||||
## Add any logic to ./module.nix
|
## Add any logic to ./module.nix
|
||||||
{
|
{
|
||||||
lib,
|
lib,
|
||||||
|
clanLib,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
flakePartsModule = {
|
flakePartsModule = {
|
||||||
imports = [
|
imports = [
|
||||||
./interface.nix
|
(lib.modules.importApply ./interface.nix { inherit clanLib; })
|
||||||
./module.nix
|
./module.nix
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
{ pkgs, lib }:
|
{
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
clanLib,
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
eval = lib.evalModules {
|
eval = lib.evalModules {
|
||||||
class = "nixos";
|
class = "nixos";
|
||||||
modules = [
|
modules = [
|
||||||
./interface.nix
|
(lib.modules.importApply ./interface.nix { inherit clanLib; })
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
evalDocs = pkgs.nixosOptionsDoc {
|
evalDocs = pkgs.nixosOptionsDoc {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ in
|
|||||||
let
|
let
|
||||||
jsonDocs = import ./eval-docs.nix {
|
jsonDocs = import ./eval-docs.nix {
|
||||||
inherit pkgs lib;
|
inherit pkgs lib;
|
||||||
|
inherit (self) clanLib;
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ module:
|
|||||||
;
|
;
|
||||||
};
|
};
|
||||||
modules = [
|
modules = [
|
||||||
./interface.nix
|
(lib.modules.importApply ./interface.nix { inherit (clan-core) clanLib; })
|
||||||
module
|
module
|
||||||
{
|
{
|
||||||
inherit specialArgs;
|
inherit specialArgs;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
{ clanLib }:
|
||||||
{
|
{
|
||||||
lib,
|
lib,
|
||||||
self,
|
self,
|
||||||
@@ -94,7 +95,11 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
inventory = lib.mkOption {
|
inventory = lib.mkOption {
|
||||||
type = types.submodule { imports = [ ../inventory/build-inventory/interface.nix ]; };
|
type = types.submodule {
|
||||||
|
imports = [
|
||||||
|
(lib.modules.importApply ../inventory/build-inventory/interface.nix { inherit clanLib; })
|
||||||
|
];
|
||||||
|
};
|
||||||
description = ''
|
description = ''
|
||||||
The `Inventory` submodule.
|
The `Inventory` submodule.
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ lib.fix (clanLib: {
|
|||||||
inventory = clanLib.callLib ./inventory { };
|
inventory = clanLib.callLib ./inventory { };
|
||||||
modules = clanLib.callLib ./inventory/frontmatter { };
|
modules = clanLib.callLib ./inventory/frontmatter { };
|
||||||
test = clanLib.callLib ./test { };
|
test = clanLib.callLib ./test { };
|
||||||
|
# Custom types
|
||||||
|
types = clanLib.callLib ./types { };
|
||||||
|
|
||||||
# Plain imports.
|
# Plain imports.
|
||||||
introspection = import ./introspection { inherit lib; };
|
introspection = import ./introspection { inherit lib; };
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ rec {
|
|||||||
./introspection/flake-module.nix
|
./introspection/flake-module.nix
|
||||||
./inventory/flake-module.nix
|
./inventory/flake-module.nix
|
||||||
./jsonschema/flake-module.nix
|
./jsonschema/flake-module.nix
|
||||||
|
./types/flake-module.nix
|
||||||
];
|
];
|
||||||
flake.clanLib = import ./default.nix {
|
flake.clanLib = import ./default.nix {
|
||||||
inherit lib inputs self;
|
inherit lib inputs self;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
{ clanLib }:
|
||||||
{
|
{
|
||||||
lib,
|
lib,
|
||||||
config,
|
config,
|
||||||
@@ -390,9 +391,7 @@ in
|
|||||||
types.submodule {
|
types.submodule {
|
||||||
options.settings = lib.mkOption {
|
options.settings = lib.mkOption {
|
||||||
default = { };
|
default = { };
|
||||||
# Dont transform the value with `types.deferredModule` here. We need to keep it json serializable
|
type = clanLib.types.uniqueDeferredSerializableModule;
|
||||||
# TODO: We need a custom serializer for deferredModule
|
|
||||||
type = types.deferredModule;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -404,7 +403,7 @@ in
|
|||||||
};
|
};
|
||||||
settings = lib.mkOption {
|
settings = lib.mkOption {
|
||||||
default = { };
|
default = { };
|
||||||
type = types.deferredModule;
|
type = clanLib.types.uniqueDeferredSerializableModule;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ in
|
|||||||
{
|
{
|
||||||
inherit (services) evalClanService mapInstances resolveModule;
|
inherit (services) evalClanService mapInstances resolveModule;
|
||||||
inherit (import ./build-inventory { inherit lib clanLib; }) buildInventory;
|
inherit (import ./build-inventory { inherit lib clanLib; }) buildInventory;
|
||||||
interface = ./build-inventory/interface.nix;
|
interface = lib.modules.importApply ./build-inventory/interface.nix { inherit clanLib; };
|
||||||
# Returns the list of machine names
|
# Returns the list of machine names
|
||||||
# { ... } -> [ string ]
|
# { ... } -> [ string ]
|
||||||
resolveTags =
|
resolveTags =
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ let
|
|||||||
|
|
||||||
frontMatterSchema = jsonLib.parseOptions self.clanLib.modules.frontmatterOptions { };
|
frontMatterSchema = jsonLib.parseOptions self.clanLib.modules.frontmatterOptions { };
|
||||||
|
|
||||||
inventorySchema = jsonLib.parseModule (import ../build-inventory/interface.nix);
|
inventorySchema = jsonLib.parseModule (
|
||||||
|
import ../build-inventory/interface.nix { inherit (self) clanLib; }
|
||||||
|
);
|
||||||
|
|
||||||
renderSchema = pkgs.writers.writePython3Bin "render-schema" {
|
renderSchema = pkgs.writers.writePython3Bin "render-schema" {
|
||||||
flakeIgnore = [
|
flakeIgnore = [
|
||||||
|
|||||||
40
lib/types/default.nix
Normal file
40
lib/types/default.nix
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
{ lib, ... }:
|
||||||
|
{
|
||||||
|
uniqueDeferredSerializableModule = lib.fix (
|
||||||
|
self:
|
||||||
|
|
||||||
|
let
|
||||||
|
checkDef =
|
||||||
|
_loc: def:
|
||||||
|
if def.value ? imports then
|
||||||
|
throw "uniqueDeferredSerializableModule doesn't allow nested imports"
|
||||||
|
else
|
||||||
|
def;
|
||||||
|
in
|
||||||
|
# Essentially the "raw" type, but with a custom name and check
|
||||||
|
lib.mkOptionType {
|
||||||
|
name = "deferredModule";
|
||||||
|
description = "deferred custom module. Must be JSON serializable.";
|
||||||
|
descriptionClass = "noun";
|
||||||
|
# Unfortunately, tryEval doesn't catch JSON errors
|
||||||
|
check = value: lib.seq (builtins.toJSON value) (lib.isAttrs value);
|
||||||
|
merge = lib.options.mergeUniqueOption {
|
||||||
|
message = "------";
|
||||||
|
merge = loc: defs: {
|
||||||
|
imports = map (
|
||||||
|
def:
|
||||||
|
lib.seq (checkDef loc def) lib.setDefaultModuleLocation
|
||||||
|
"${def.file}, via option ${lib.showOption loc}"
|
||||||
|
def.value
|
||||||
|
) defs;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
functor = {
|
||||||
|
inherit (self) name;
|
||||||
|
type = self;
|
||||||
|
# Non mergable type
|
||||||
|
binOp = _a: _b: null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
25
lib/types/flake-module.nix
Normal file
25
lib/types/flake-module.nix
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
{ self, inputs, ... }:
|
||||||
|
{
|
||||||
|
perSystem =
|
||||||
|
{ ... }:
|
||||||
|
let
|
||||||
|
# Module that contains the tests
|
||||||
|
# This module adds:
|
||||||
|
# - legacyPackages.<system>.eval-tests-hello-world
|
||||||
|
# - checks.<system>.eval-tests-hello-world
|
||||||
|
test-types-module = (
|
||||||
|
self.clanLib.test.flakeModules.makeEvalChecks {
|
||||||
|
module = throw "";
|
||||||
|
inherit self inputs;
|
||||||
|
testName = "types";
|
||||||
|
tests = ./tests.nix;
|
||||||
|
# Optional arguments passed to the test
|
||||||
|
testArgs = { };
|
||||||
|
}
|
||||||
|
);
|
||||||
|
in
|
||||||
|
{
|
||||||
|
imports = [ test-types-module ];
|
||||||
|
legacyPackages.xxx = { };
|
||||||
|
};
|
||||||
|
}
|
||||||
92
lib/types/tests.nix
Normal file
92
lib/types/tests.nix
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
{ lib, clanLib, ... }:
|
||||||
|
let
|
||||||
|
evalSettingsModule =
|
||||||
|
m:
|
||||||
|
lib.evalModules {
|
||||||
|
modules = [
|
||||||
|
{
|
||||||
|
options.foo = lib.mkOption {
|
||||||
|
type = clanLib.types.uniqueDeferredSerializableModule;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
m
|
||||||
|
];
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
test_simple =
|
||||||
|
let
|
||||||
|
eval = evalSettingsModule {
|
||||||
|
foo = { };
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
inherit eval;
|
||||||
|
expr = eval.config.foo;
|
||||||
|
expected = {
|
||||||
|
# Foo has imports
|
||||||
|
# This can only ever be one module due to the type of foo
|
||||||
|
imports = [
|
||||||
|
{
|
||||||
|
# This is the result of 'setDefaultModuleLocation'
|
||||||
|
# Which also returns exactly one module
|
||||||
|
_file = "<unknown-file>, via option foo";
|
||||||
|
imports = [
|
||||||
|
{ }
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
test_no_nested_imports =
|
||||||
|
let
|
||||||
|
eval = evalSettingsModule {
|
||||||
|
foo = {
|
||||||
|
imports = [ ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
inherit eval;
|
||||||
|
expr = eval.config.foo;
|
||||||
|
expectedError = {
|
||||||
|
type = "ThrownError";
|
||||||
|
message = "*nested imports";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
test_no_function_modules =
|
||||||
|
let
|
||||||
|
eval = evalSettingsModule {
|
||||||
|
foo =
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
inherit eval;
|
||||||
|
expr = eval.config.foo;
|
||||||
|
expectedError = {
|
||||||
|
type = "TypeError";
|
||||||
|
message = "cannot convert a function to JSON";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
test_non_attrs_module =
|
||||||
|
let
|
||||||
|
eval = evalSettingsModule {
|
||||||
|
foo = "foo.nix";
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
inherit eval;
|
||||||
|
expr = eval.config.foo;
|
||||||
|
expectedError = {
|
||||||
|
type = "ThrownError";
|
||||||
|
message = ".*foo.* is not of type";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user