Docs/frontmatter: init automatic reference for frontmatter
This commit is contained in:
@@ -104,6 +104,7 @@ nav:
|
|||||||
- reference/clanModules/zerotier-static-peers.md
|
- reference/clanModules/zerotier-static-peers.md
|
||||||
- reference/clanModules/zerotier.md
|
- reference/clanModules/zerotier.md
|
||||||
- reference/clanModules/zt-tcp-relay.md
|
- reference/clanModules/zt-tcp-relay.md
|
||||||
|
- reference/clanModules/frontmatter/index.md
|
||||||
- CLI:
|
- CLI:
|
||||||
- reference/cli/index.md
|
- reference/cli/index.md
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,13 @@
|
|||||||
evalClanModules = self.lib.evalClanModules;
|
evalClanModules = self.lib.evalClanModules;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Frontmatter for clanModules
|
||||||
|
clanModulesFrontmatter =
|
||||||
|
let
|
||||||
|
docs = pkgs.nixosOptionsDoc { options = self.lib.modules.frontmatterOptions; };
|
||||||
|
in
|
||||||
|
docs.optionsJSON;
|
||||||
|
|
||||||
clanModulesFileInfo = pkgs.writeText "info.json" (builtins.toJSON jsonDocs.clanModules);
|
clanModulesFileInfo = pkgs.writeText "info.json" (builtins.toJSON jsonDocs.clanModules);
|
||||||
# clanModulesReadmes = pkgs.writeText "info.json" (builtins.toJSON jsonDocs.clanModulesReadmes);
|
# clanModulesReadmes = pkgs.writeText "info.json" (builtins.toJSON jsonDocs.clanModulesReadmes);
|
||||||
# clanModulesMeta = pkgs.writeText "info.json" (builtins.toJSON jsonDocs.clanModulesMeta);
|
# clanModulesMeta = pkgs.writeText "info.json" (builtins.toJSON jsonDocs.clanModulesMeta);
|
||||||
@@ -56,8 +63,6 @@
|
|||||||
buildInputs = [
|
buildInputs = [
|
||||||
pkgs.python3
|
pkgs.python3
|
||||||
self'.packages.clan-cli
|
self'.packages.clan-cli
|
||||||
# TODO: see postFixup clan-cli/default.nix:L188
|
|
||||||
self'.packages.clan-cli.propagatedBuildInputs
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
''
|
''
|
||||||
@@ -65,6 +70,8 @@
|
|||||||
export CLAN_CORE_DOCS=${jsonDocs.clanCore}/share/doc/nixos/options.json
|
export CLAN_CORE_DOCS=${jsonDocs.clanCore}/share/doc/nixos/options.json
|
||||||
# A file that contains the links to all clanModule docs
|
# A file that contains the links to all clanModule docs
|
||||||
export CLAN_MODULES=${clanModulesFileInfo}
|
export CLAN_MODULES=${clanModulesFileInfo}
|
||||||
|
# Frontmatter format for clanModules
|
||||||
|
export CLAN_MODULES_FRONTMATTER_DOCS=${clanModulesFrontmatter}/share/doc/nixos/options.json
|
||||||
|
|
||||||
# buildClan options
|
# buildClan options
|
||||||
export BUILD_CLAN_PATH=${buildClanOptions}/share/doc/nixos/options.json
|
export BUILD_CLAN_PATH=${buildClanOptions}/share/doc/nixos/options.json
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ from clan_cli.errors import ClanError
|
|||||||
# Get environment variables
|
# Get environment variables
|
||||||
CLAN_CORE_PATH = Path(os.environ["CLAN_CORE_PATH"])
|
CLAN_CORE_PATH = Path(os.environ["CLAN_CORE_PATH"])
|
||||||
CLAN_CORE_DOCS = Path(os.environ["CLAN_CORE_DOCS"])
|
CLAN_CORE_DOCS = Path(os.environ["CLAN_CORE_DOCS"])
|
||||||
|
CLAN_MODULES_FRONTMATTER_DOCS = os.environ.get("CLAN_MODULES_FRONTMATTER_DOCS")
|
||||||
CLAN_MODULES = os.environ.get("CLAN_MODULES")
|
CLAN_MODULES = os.environ.get("CLAN_MODULES")
|
||||||
BUILD_CLAN_PATH = os.environ.get("BUILD_CLAN_PATH")
|
BUILD_CLAN_PATH = os.environ.get("BUILD_CLAN_PATH")
|
||||||
|
|
||||||
@@ -155,6 +156,63 @@ Your can customize your machines behavior with the configuration [options](#modu
|
|||||||
options_head = "\n## Module Options\n"
|
options_head = "\n## Module Options\n"
|
||||||
|
|
||||||
|
|
||||||
|
def produce_clan_modules_frontmatter_docs() -> None:
|
||||||
|
if not CLAN_MODULES_FRONTMATTER_DOCS:
|
||||||
|
msg = f"Environment variables are not set correctly: $CLAN_CORE_DOCS={CLAN_CORE_DOCS}"
|
||||||
|
raise ClanError(msg)
|
||||||
|
|
||||||
|
if not OUT:
|
||||||
|
msg = f"Environment variables are not set correctly: $out={OUT}"
|
||||||
|
raise ClanError(msg)
|
||||||
|
|
||||||
|
with Path(CLAN_MODULES_FRONTMATTER_DOCS).open() as f:
|
||||||
|
options: dict[str, dict[str, Any]] = json.load(f)
|
||||||
|
|
||||||
|
# header
|
||||||
|
output = """# Frontmatter
|
||||||
|
|
||||||
|
Every clan module has a `frontmatter` section within its readme. It provides machine readable metadata about the module.
|
||||||
|
|
||||||
|
!!! example
|
||||||
|
|
||||||
|
The used format is `TOML`
|
||||||
|
|
||||||
|
The content is separated by `---` and the frontmatter must be placed at the very top of the `README.md` file.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
---
|
||||||
|
description = "A description of the module"
|
||||||
|
categories = ["category1", "category2"]
|
||||||
|
|
||||||
|
[constraints]
|
||||||
|
roles.client.max = 10
|
||||||
|
roles.server.min = 1
|
||||||
|
---
|
||||||
|
# Readme content
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
output += """"## Overview
|
||||||
|
|
||||||
|
This provides an overview of the available attributes of the `frontmatter` within the `README.md` of a clan module.
|
||||||
|
|
||||||
|
"""
|
||||||
|
for option_name, info in options.items():
|
||||||
|
if option_name == "_module.args":
|
||||||
|
continue
|
||||||
|
output += render_option(option_name, info)
|
||||||
|
|
||||||
|
outfile = Path(OUT) / "clanModules/frontmatter/index.md"
|
||||||
|
outfile.parent.mkdir(
|
||||||
|
parents=True,
|
||||||
|
exist_ok=True,
|
||||||
|
)
|
||||||
|
with outfile.open("w") as of:
|
||||||
|
of.write(output)
|
||||||
|
|
||||||
|
|
||||||
def produce_clan_core_docs() -> None:
|
def produce_clan_core_docs() -> None:
|
||||||
if not CLAN_CORE_DOCS:
|
if not CLAN_CORE_DOCS:
|
||||||
msg = f"Environment variables are not set correctly: $CLAN_CORE_DOCS={CLAN_CORE_DOCS}"
|
msg = f"Environment variables are not set correctly: $CLAN_CORE_DOCS={CLAN_CORE_DOCS}"
|
||||||
@@ -259,12 +317,10 @@ def produce_clan_modules_docs() -> None:
|
|||||||
|
|
||||||
for module_name, options_file in links.items():
|
for module_name, options_file in links.items():
|
||||||
readme_file = CLAN_CORE_PATH / "clanModules" / module_name / "README.md"
|
readme_file = CLAN_CORE_PATH / "clanModules" / module_name / "README.md"
|
||||||
print(module_name, readme_file)
|
|
||||||
with readme_file.open() as f:
|
with readme_file.open() as f:
|
||||||
readme = f.read()
|
readme = f.read()
|
||||||
frontmatter: Frontmatter
|
frontmatter: Frontmatter
|
||||||
frontmatter, readme_content = extract_frontmatter(readme, str(readme_file))
|
frontmatter, readme_content = extract_frontmatter(readme, str(readme_file))
|
||||||
print(frontmatter, readme_content)
|
|
||||||
|
|
||||||
modules_index += build_option_card(module_name, frontmatter)
|
modules_index += build_option_card(module_name, frontmatter)
|
||||||
|
|
||||||
@@ -386,7 +442,6 @@ Each attribute is documented below
|
|||||||
"""
|
"""
|
||||||
with Path(BUILD_CLAN_PATH).open() as f:
|
with Path(BUILD_CLAN_PATH).open() as f:
|
||||||
options: dict[str, dict[str, Any]] = json.load(f)
|
options: dict[str, dict[str, Any]] = json.load(f)
|
||||||
# print(options)
|
|
||||||
for option_name, info in options.items():
|
for option_name, info in options.items():
|
||||||
# Skip underscore options
|
# Skip underscore options
|
||||||
if option_name.startswith("_"):
|
if option_name.startswith("_"):
|
||||||
@@ -479,3 +534,5 @@ if __name__ == "__main__": #
|
|||||||
|
|
||||||
produce_clan_core_docs()
|
produce_clan_core_docs()
|
||||||
produce_clan_modules_docs()
|
produce_clan_modules_docs()
|
||||||
|
|
||||||
|
produce_clan_modules_frontmatter_docs()
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ description = "Module A"
|
|||||||
This is the example module that does xyz.
|
This is the example module that does xyz.
|
||||||
```
|
```
|
||||||
|
|
||||||
See the [frontmatter reference](#frontmatter-reference) for all supported attributes.
|
See the [Full Frontmatter reference](../reference/clanModules/frontmatter/index.md) further details and all supported attributes.
|
||||||
|
|
||||||
## Roles
|
## Roles
|
||||||
|
|
||||||
@@ -149,60 +149,3 @@ Assuming that there is a common code path or a common interface between `server`
|
|||||||
imports = [ ../common.nix ];
|
imports = [ ../common.nix ];
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Frontmatter Reference
|
|
||||||
|
|
||||||
`description` (**Required** `String`)
|
|
||||||
: Short description of the module
|
|
||||||
|
|
||||||
`categories` (Optional `[ String ]`)
|
|
||||||
: default `[ "Uncategorized" ]`
|
|
||||||
|
|
||||||
Categories are used for Grouping and searching.
|
|
||||||
|
|
||||||
While initial oriented on [freedesktop](https://specifications.freedesktop.org/menu-spec/latest/category-registry.html) the following categories are allowed
|
|
||||||
|
|
||||||
- AudioVideo
|
|
||||||
- Audio
|
|
||||||
- Video
|
|
||||||
- Development
|
|
||||||
- Education
|
|
||||||
- Game
|
|
||||||
- Graphics
|
|
||||||
- Social
|
|
||||||
- Network
|
|
||||||
- Office
|
|
||||||
- Science
|
|
||||||
- System
|
|
||||||
- Settings
|
|
||||||
- Utility
|
|
||||||
- Uncategorized
|
|
||||||
|
|
||||||
`features` (Optional `[ String ]`)
|
|
||||||
: default `[]`
|
|
||||||
|
|
||||||
Clans Features that the module implements support for.
|
|
||||||
|
|
||||||
Available feature flags are:
|
|
||||||
|
|
||||||
- `inventory`
|
|
||||||
|
|
||||||
!!! warning "Important"
|
|
||||||
Every ClanModule, that specifies `features = [ "inventory" ]` MUST have at least one role.
|
|
||||||
Many modules use `roles/default.nix` which registers the role `default`.
|
|
||||||
|
|
||||||
If you are a clan module author and your module has only one role where you cannot determine the name, then we would like you to follow the convention.
|
|
||||||
|
|
||||||
|
|
||||||
`constraints.roles.<roleName>.<constraintType>` (Optional `int`) (Experimental)
|
|
||||||
: Contraints for the module
|
|
||||||
|
|
||||||
The following example requires exactly one `server`
|
|
||||||
and supports up to `7` clients
|
|
||||||
|
|
||||||
```md
|
|
||||||
---
|
|
||||||
constraints.roles.server.eq = 1
|
|
||||||
constraints.roles.client.max = 7
|
|
||||||
---
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ in
|
|||||||
options.roles = lib.mapAttrs (
|
options.roles = lib.mapAttrs (
|
||||||
_name: _:
|
_name: _:
|
||||||
mkOption {
|
mkOption {
|
||||||
|
description = ''
|
||||||
|
Sub-attributes of `${_name}` are constraints for the role.
|
||||||
|
'';
|
||||||
default = { };
|
default = { };
|
||||||
type = types.submoduleWith {
|
type = types.submoduleWith {
|
||||||
modules = [
|
modules = [
|
||||||
@@ -26,10 +29,16 @@ in
|
|||||||
max = mkOption {
|
max = mkOption {
|
||||||
type = types.nullOr types.int;
|
type = types.nullOr types.int;
|
||||||
default = null;
|
default = null;
|
||||||
|
description = ''
|
||||||
|
Maximum number of instances of this role that can be assigned to a module of this type.
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
min = mkOption {
|
min = mkOption {
|
||||||
type = types.int;
|
type = types.int;
|
||||||
default = 0;
|
default = 0;
|
||||||
|
description = ''
|
||||||
|
Minimum number of instances of this role that must at least be assigned to a module of this type.
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,7 @@ let
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
frontmatterDocsOptions =
|
frontmatterOptions =
|
||||||
lib.optionAttrSetToDocList
|
|
||||||
(lib.evalModules {
|
(lib.evalModules {
|
||||||
specialArgs = {
|
specialArgs = {
|
||||||
moduleName = "{moduleName}";
|
moduleName = "{moduleName}";
|
||||||
@@ -91,7 +90,7 @@ in
|
|||||||
{
|
{
|
||||||
inherit
|
inherit
|
||||||
evalFrontmatter
|
evalFrontmatter
|
||||||
frontmatterDocsOptions
|
frontmatterOptions
|
||||||
|
|
||||||
getFrontmatter
|
getFrontmatter
|
||||||
getReadme
|
getReadme
|
||||||
|
|||||||
@@ -11,11 +11,16 @@ in
|
|||||||
description = mkOption {
|
description = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
description = ''
|
description = ''
|
||||||
|
A Short description of the module.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
categories = mkOption {
|
categories = mkOption {
|
||||||
default = [ "Uncategorized" ];
|
default = [ "Uncategorized" ];
|
||||||
|
description = ''
|
||||||
|
Categories are used for Grouping and searching.
|
||||||
|
|
||||||
|
While initial oriented on [freedesktop](https://specifications.freedesktop.org/menu-spec/latest/category-registry.html) the following categories are allowed
|
||||||
|
'';
|
||||||
type = types.listOf (
|
type = types.listOf (
|
||||||
types.enum [
|
types.enum [
|
||||||
"AudioVideo"
|
"AudioVideo"
|
||||||
@@ -38,6 +43,15 @@ in
|
|||||||
};
|
};
|
||||||
features = mkOption {
|
features = mkOption {
|
||||||
default = [ ];
|
default = [ ];
|
||||||
|
description = ''
|
||||||
|
Clans Features that the module implements support for.
|
||||||
|
|
||||||
|
!!! warning "Important"
|
||||||
|
Every ClanModule, that specifies `features = [ "inventory" ]` MUST have at least one role.
|
||||||
|
Many modules use `roles/default.nix` which registers the role `default`.
|
||||||
|
|
||||||
|
If you are a clan module author and your module has only one role where you cannot determine the name, then we would like you to follow the convention.
|
||||||
|
'';
|
||||||
type = types.listOf (
|
type = types.listOf (
|
||||||
types.enum [
|
types.enum [
|
||||||
"inventory"
|
"inventory"
|
||||||
@@ -47,6 +61,19 @@ in
|
|||||||
|
|
||||||
constraints = mkOption {
|
constraints = mkOption {
|
||||||
default = { };
|
default = { };
|
||||||
|
description = ''
|
||||||
|
Contraints for the module
|
||||||
|
|
||||||
|
The following example requires exactly one `server`
|
||||||
|
and supports up to `7` clients
|
||||||
|
|
||||||
|
```md
|
||||||
|
---
|
||||||
|
constraints.roles.server.eq = 1
|
||||||
|
constraints.roles.client.max = 7
|
||||||
|
---
|
||||||
|
```
|
||||||
|
'';
|
||||||
type = types.submoduleWith {
|
type = types.submoduleWith {
|
||||||
inherit specialArgs;
|
inherit specialArgs;
|
||||||
modules = [
|
modules = [
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ let
|
|||||||
header = { };
|
header = { };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
frontMatterSchema = jsonLib.parseOptions self.lib.modules.frontmatterOptions { };
|
||||||
|
|
||||||
inventorySchema = jsonLib.parseModule (import ../build-inventory/interface.nix);
|
inventorySchema = jsonLib.parseModule (import ../build-inventory/interface.nix);
|
||||||
|
|
||||||
renderSchema = pkgs.writers.writePython3Bin "render-schema" {
|
renderSchema = pkgs.writers.writePython3Bin "render-schema" {
|
||||||
@@ -48,6 +50,7 @@ let
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
inherit
|
inherit
|
||||||
|
frontMatterSchema
|
||||||
inventorySchema
|
inventorySchema
|
||||||
modulesSchema
|
modulesSchema
|
||||||
renderSchema
|
renderSchema
|
||||||
|
|||||||
Reference in New Issue
Block a user