forked from clan/clan-core
Add package function-schema and module-schema. Add check for module jsonschema.
This commit is contained in:
parent
e08342a6f3
commit
a48df5b993
@ -46,7 +46,6 @@
|
||||
syncthing = import ./syncthing nixosTestArgs;
|
||||
wayland-proxy-virtwl = import ./wayland-proxy-virtwl nixosTestArgs;
|
||||
};
|
||||
schemaTests = pkgs.callPackages ./schemas.nix { inherit self; };
|
||||
|
||||
flakeOutputs =
|
||||
lib.mapAttrs' (
|
||||
@ -58,7 +57,7 @@
|
||||
self'.legacyPackages.homeConfigurations or { }
|
||||
);
|
||||
in
|
||||
{ inherit renderClanOptions; } // nixosTests // schemaTests // flakeOutputs;
|
||||
{ inherit renderClanOptions; } // nixosTests // flakeOutputs;
|
||||
legacyPackages = {
|
||||
nixosTests =
|
||||
let
|
||||
|
@ -1,48 +0,0 @@
|
||||
{
|
||||
self,
|
||||
runCommand,
|
||||
check-jsonschema,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
clanModules.clanCore = self.nixosModules.clanCore;
|
||||
|
||||
baseModule = {
|
||||
imports = (import (pkgs.path + "/nixos/modules/module-list.nix")) ++ [
|
||||
{
|
||||
nixpkgs.hostPlatform = "x86_64-linux";
|
||||
clanCore.clanName = "dummy";
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
optionsFromModule =
|
||||
module:
|
||||
let
|
||||
evaled = lib.evalModules {
|
||||
modules = [
|
||||
module
|
||||
baseModule
|
||||
];
|
||||
};
|
||||
in
|
||||
evaled.options.clan;
|
||||
|
||||
clanModuleSchemas = lib.mapAttrs (
|
||||
_: module: self.lib.jsonschema.parseOptions (optionsFromModule module)
|
||||
) clanModules;
|
||||
|
||||
mkTest =
|
||||
name: schema:
|
||||
runCommand "schema-${name}" { } ''
|
||||
${check-jsonschema}/bin/check-jsonschema \
|
||||
--check-metaschema ${builtins.toFile "schema-${name}" (builtins.toJSON schema)}
|
||||
touch $out
|
||||
'';
|
||||
in
|
||||
lib.mapAttrs' (name: schema: {
|
||||
name = "schema-${name}";
|
||||
value = mkTest name schema;
|
||||
}) clanModuleSchemas
|
@ -21,7 +21,6 @@
|
||||
root-password = ./root-password;
|
||||
thelounge = ./thelounge.nix;
|
||||
vm-user = ./vm-user.nix;
|
||||
waypipe = ./waypipe.nix;
|
||||
xfce = ./xfce.nix;
|
||||
xfce-vm = ./xfce-vm.nix;
|
||||
zt-tcp-relay = ./zt-tcp-relay.nix;
|
||||
|
@ -34,6 +34,10 @@
|
||||
'';
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
example = [
|
||||
"folder1"
|
||||
"folder2"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -68,7 +68,6 @@ nav:
|
||||
- reference/clanModules/syncthing.md
|
||||
- reference/clanModules/thelounge.md
|
||||
- reference/clanModules/vm-user.md
|
||||
- reference/clanModules/waypipe.md
|
||||
- reference/clanModules/xfce-vm.md
|
||||
- reference/clanModules/xfce.md
|
||||
- reference/clanModules/zt-tcp-relay.md
|
||||
|
@ -38,20 +38,7 @@ let
|
||||
) clanModules;
|
||||
|
||||
clanModulesReadmes = builtins.mapAttrs (
|
||||
module_name: _module:
|
||||
let
|
||||
readme = "${self}/clanModules/${module_name}/README.md";
|
||||
readmeContents =
|
||||
if
|
||||
builtins.trace "Trying to get Module README.md for ${module_name} from ${readme}"
|
||||
# TODO: Edge cases
|
||||
(builtins.pathExists readme)
|
||||
then
|
||||
(builtins.readFile readme)
|
||||
else
|
||||
null;
|
||||
in
|
||||
readmeContents
|
||||
module_name: _module: self.lib.modules.getDescription module_name
|
||||
) clanModules;
|
||||
|
||||
# clanCore docs
|
||||
|
@ -6,6 +6,6 @@
|
||||
}:
|
||||
{
|
||||
jsonschema = import ./jsonschema { inherit lib; };
|
||||
|
||||
modules = import ./description.nix { inherit clan-core; };
|
||||
buildClan = import ./build-clan { inherit clan-core lib nixpkgs; };
|
||||
}
|
||||
|
19
lib/description.nix
Normal file
19
lib/description.nix
Normal file
@ -0,0 +1,19 @@
|
||||
{ clan-core, ... }:
|
||||
|
||||
{
|
||||
getDescription =
|
||||
modulename:
|
||||
let
|
||||
readme = "${clan-core}/clanModules/${modulename}/README.md";
|
||||
readmeContents =
|
||||
if
|
||||
builtins.trace "Trying to get Module README.md for ${modulename} from ${readme}"
|
||||
# TODO: Edge cases
|
||||
(builtins.pathExists readme)
|
||||
then
|
||||
(builtins.readFile readme)
|
||||
else
|
||||
null;
|
||||
in
|
||||
readmeContents;
|
||||
}
|
@ -17,7 +17,10 @@ let
|
||||
location: ${lib.concatStringsSep "." option.loc}
|
||||
'';
|
||||
|
||||
isExcludedOption = option: (lib.elem (option.type.name or null) excludedTypes);
|
||||
# Exclude the option if it's type is in the excludedTypes list
|
||||
# or if the option has a defaultText attribute
|
||||
isExcludedOption =
|
||||
option: ((lib.elem (option.type.name or null) excludedTypes) || (option ? defaultText));
|
||||
|
||||
filterExcluded = lib.filter (opt: !isExcludedOption opt);
|
||||
|
||||
@ -67,6 +70,10 @@ rec {
|
||||
option:
|
||||
let
|
||||
default = lib.optionalAttrs (option ? default) { inherit (option) default; };
|
||||
example = lib.optionalAttrs (option ? example) {
|
||||
examples =
|
||||
if (builtins.typeOf option.example) == "list" then option.example else [ option.example ];
|
||||
};
|
||||
description = lib.optionalAttrs (option ? description) {
|
||||
description = option.description.text or option.description;
|
||||
};
|
||||
@ -93,7 +100,7 @@ rec {
|
||||
];
|
||||
optionsList = filterExcluded optionsList';
|
||||
in
|
||||
default // description // { anyOf = map parseOption optionsList; }
|
||||
default // example // description // { anyOf = map parseOption optionsList; }
|
||||
|
||||
# handle nested options (not a submodule)
|
||||
else if !option ? _type then
|
||||
@ -116,6 +123,7 @@ rec {
|
||||
};
|
||||
in
|
||||
default
|
||||
// example
|
||||
// description
|
||||
// {
|
||||
anyOf = [
|
||||
@ -128,63 +136,77 @@ rec {
|
||||
option.type.name == "bool"
|
||||
# return jsonschema property definition for bool
|
||||
then
|
||||
default // description // { type = "boolean"; }
|
||||
default // example // description // { type = "boolean"; }
|
||||
|
||||
# parse float
|
||||
else if
|
||||
option.type.name == "float"
|
||||
# return jsonschema property definition for float
|
||||
then
|
||||
default // description // { type = "number"; }
|
||||
default // example // description // { type = "number"; }
|
||||
|
||||
# parse int
|
||||
else if
|
||||
(option.type.name == "int" || option.type.name == "positiveInt")
|
||||
# return jsonschema property definition for int
|
||||
then
|
||||
default // description // { type = "integer"; }
|
||||
default // example // description // { type = "integer"; }
|
||||
|
||||
# TODO: Add support for intMatching in jsonschema
|
||||
# parse port type aka. "unsignedInt16"
|
||||
else if option.type.name == "unsignedInt16" then
|
||||
default // example // description // { type = "integer"; }
|
||||
|
||||
# parse string
|
||||
else if
|
||||
option.type.name == "str"
|
||||
# return jsonschema property definition for string
|
||||
then
|
||||
default // description // { type = "string"; }
|
||||
default // example // description // { type = "string"; }
|
||||
|
||||
# TODO: Add support for stringMatching in jsonschema
|
||||
# parse stringMatching
|
||||
else if lib.strings.hasPrefix "strMatching" option.type.name then
|
||||
default // example // description // { type = "string"; }
|
||||
|
||||
# TODO: Add support for separatedString in jsonschema
|
||||
else if lib.strings.hasPrefix "separatedString" option.type.name then
|
||||
default // example // description // { type = "string"; }
|
||||
|
||||
# parse string
|
||||
else if
|
||||
option.type.name == "path"
|
||||
# return jsonschema property definition for path
|
||||
then
|
||||
default // description // { type = "string"; }
|
||||
default // example // description // { type = "string"; }
|
||||
|
||||
# parse anything
|
||||
else if
|
||||
option.type.name == "anything"
|
||||
# return jsonschema property definition for anything
|
||||
then
|
||||
default // description // { type = allBasicTypes; }
|
||||
default // example // description // { type = allBasicTypes; }
|
||||
|
||||
# parse unspecified
|
||||
else if
|
||||
option.type.name == "unspecified"
|
||||
# return jsonschema property definition for unspecified
|
||||
then
|
||||
default // description // { type = allBasicTypes; }
|
||||
default // example // description // { type = allBasicTypes; }
|
||||
|
||||
# parse raw
|
||||
else if
|
||||
option.type.name == "raw"
|
||||
# return jsonschema property definition for raw
|
||||
then
|
||||
default // description // { type = allBasicTypes; }
|
||||
default // example // description // { type = allBasicTypes; }
|
||||
|
||||
# parse enum
|
||||
else if
|
||||
option.type.name == "enum"
|
||||
# return jsonschema property definition for enum
|
||||
then
|
||||
default // description // { enum = option.type.functor.payload; }
|
||||
default // example // description // { enum = option.type.functor.payload; }
|
||||
|
||||
# parse listOf submodule
|
||||
else if
|
||||
@ -192,6 +214,7 @@ rec {
|
||||
# return jsonschema property definition for listOf submodule
|
||||
then
|
||||
default
|
||||
// example
|
||||
// description
|
||||
// {
|
||||
type = "array";
|
||||
@ -211,6 +234,7 @@ rec {
|
||||
};
|
||||
in
|
||||
default
|
||||
// example
|
||||
// description
|
||||
// {
|
||||
type = "array";
|
||||
@ -222,7 +246,7 @@ rec {
|
||||
(option.type.name == "listOf") && (option.type.functor.wrapped.name == "unspecified")
|
||||
# return jsonschema property definition for list
|
||||
then
|
||||
default // description // { type = "array"; }
|
||||
default // example // description // { type = "array"; }
|
||||
|
||||
# parse attrsOf submodule
|
||||
else if
|
||||
@ -230,6 +254,7 @@ rec {
|
||||
# return jsonschema property definition for attrsOf submodule
|
||||
then
|
||||
default
|
||||
// example
|
||||
// description
|
||||
// {
|
||||
type = "object";
|
||||
@ -242,6 +267,7 @@ rec {
|
||||
# return jsonschema property definition for attrs
|
||||
then
|
||||
default
|
||||
// example
|
||||
// description
|
||||
// {
|
||||
type = "object";
|
||||
@ -262,6 +288,7 @@ rec {
|
||||
};
|
||||
in
|
||||
default
|
||||
// example
|
||||
// description
|
||||
// {
|
||||
type = "object";
|
||||
|
@ -22,8 +22,8 @@
|
||||
'';
|
||||
};
|
||||
clanDir = lib.mkOption {
|
||||
type = lib.types.either lib.types.path lib.types.str;
|
||||
default = ".";
|
||||
type = lib.types.path;
|
||||
default = ./.;
|
||||
description = ''
|
||||
the location of the flake repo, used to calculate the location of facts and secrets
|
||||
'';
|
||||
|
@ -4,6 +4,7 @@
|
||||
./clan-cli/flake-module.nix
|
||||
./clan-vm-manager/flake-module.nix
|
||||
./installer/flake-module.nix
|
||||
./schemas/flake-module.nix
|
||||
];
|
||||
|
||||
perSystem =
|
||||
|
66
pkgs/schemas/flake-module.nix
Normal file
66
pkgs/schemas/flake-module.nix
Normal file
@ -0,0 +1,66 @@
|
||||
{ self, ... }:
|
||||
{
|
||||
perSystem =
|
||||
{ pkgs, lib, ... }:
|
||||
let
|
||||
clanModules = self.clanModules;
|
||||
|
||||
# Uncomment if you only want one module to be available
|
||||
# clanModules = {
|
||||
# syncthing = self.clanModules.syncthing;
|
||||
# };
|
||||
|
||||
baseModule = {
|
||||
imports = (import (pkgs.path + "/nixos/modules/module-list.nix")) ++ [
|
||||
{
|
||||
nixpkgs.hostPlatform = "x86_64-linux";
|
||||
clanCore.clanName = "dummy";
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
optionsFromModule =
|
||||
modulename: module:
|
||||
let
|
||||
evaled = lib.evalModules {
|
||||
modules = [
|
||||
module
|
||||
baseModule
|
||||
self.nixosModules.clanCore
|
||||
];
|
||||
};
|
||||
in
|
||||
if (evaled.options.clan ? "${modulename}") then evaled.options.clan.${modulename} else { };
|
||||
|
||||
clanModuleSchemas = lib.mapAttrs (
|
||||
modulename: module: self.lib.jsonschema.parseOptions (optionsFromModule modulename module)
|
||||
) clanModules;
|
||||
|
||||
clanModuleFunctionSchemas = lib.mapAttrsFlatten (modulename: module: {
|
||||
name = modulename;
|
||||
description = self.lib.modules.getDescription modulename;
|
||||
parameters = self.lib.jsonschema.parseOptions (optionsFromModule modulename module);
|
||||
}) clanModules;
|
||||
in
|
||||
rec {
|
||||
checks = {
|
||||
module-schema = pkgs.runCommand "schema-checks" { } ''
|
||||
${pkgs.check-jsonschema}/bin/check-jsonschema \
|
||||
--check-metaschema ${packages.module-schema}
|
||||
touch $out
|
||||
'';
|
||||
};
|
||||
|
||||
packages = {
|
||||
module-schema = pkgs.runCommand "jsonschema" { } ''
|
||||
MSCHEMA=${builtins.toFile "module-schemas.json" (builtins.toJSON clanModuleSchemas)}
|
||||
cp "$MSCHEMA" $out
|
||||
'';
|
||||
|
||||
function-schema = pkgs.runCommand "function-schema" { } ''
|
||||
FSCHEMA=${builtins.toFile "function-schemas.json" (builtins.toJSON clanModuleFunctionSchemas)}
|
||||
cp "$FSCHEMA" $out
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user