Add clanServices to docs

Renders the documentation for clanServices. Options for the modules are
extracted and rendered the same way as for the existing clanModules.

Additionally tweaks the typography for the documentation of options
slightly
This commit is contained in:
pinpox
2025-05-15 22:20:01 +02:00
parent a40d2d82b8
commit da3c1ceea3
5 changed files with 143 additions and 18 deletions

View File

@@ -3,6 +3,19 @@
{
_class = "clan.service";
manifest.name = "clan-core/hello-word";
manifest.description = "This is a test";
roles.test = {
interface =
{ lib, ... }:
{
options.foo = lib.mkOption {
type = lib.types.str;
# default = "";
description = "Some option";
};
};
};
roles.peer = {
interface =
@@ -10,6 +23,8 @@
{
options.foo = lib.mkOption {
type = lib.types.str;
# default = "";
description = "Some option";
};
};
};

View File

@@ -85,6 +85,10 @@ nav:
- 02-clan-api: decisions/02-clan-api.md
- 03-adr-numbering-process: decisions/03-adr-numbering-process.md
- Template: decisions/_template.md
- Clan Services:
- reference/clanServices/admin.md
- reference/clanServices/hello-world.md
- reference/clanServices/wifi.md
- Clan Modules:
- Overview:
- reference/clanModules/index.md

View File

@@ -36,6 +36,9 @@
# Options available when imported via ` inventory.${moduleName}....${rolesName} `
clanModulesViaRoles = pkgs.writeText "info.json" (builtins.toJSON jsonDocs.clanModulesViaRoles);
# clan service options
clanModulesViaService = pkgs.writeText "info.json" (builtins.toJSON jsonDocs.clanModulesViaService);
# Simply evaluated options (JSON)
renderOptions =
pkgs.runCommand "render-options"
@@ -85,6 +88,7 @@
export CLAN_CORE_DOCS=${jsonDocs.clanCore}/share/doc/nixos/options.json
# A file that contains the links to all clanModule docs
export CLAN_MODULES_VIA_ROLES=${clanModulesViaRoles}
export CLAN_MODULES_VIA_SERVICE=${clanModulesViaService}
export CLAN_MODULES_VIA_NIX=${clanModulesViaNix}
# Frontmatter format for clanModules
export CLAN_MODULES_FRONTMATTER_DOCS=${clanModulesFrontmatter}/share/doc/nixos/options.json
@@ -100,7 +104,12 @@
in
{
legacyPackages = {
inherit jsonDocs clanModulesViaNix clanModulesViaRoles;
inherit
jsonDocs
clanModulesViaNix
clanModulesViaRoles
clanModulesViaService
;
};
devShells.docs = pkgs.callPackage ./shell.nix {
inherit (self'.packages) docs clan-cli-docs inventory-api-docs;

View File

@@ -36,6 +36,33 @@
) rolesOptions
) modulesRolesOptions;
# Test with:
# nix build .\#legacyPackages.x86_64-linux.clanModulesViaService
clanModulesViaService = lib.mapAttrs (
_moduleName: moduleValue:
let
evaluatedService = clan-core.clanLib.inventory.evalClanService {
modules = [ moduleValue ];
prefix = [ ];
};
in
{
roles = lib.mapAttrs (
_roleName: role:
(nixosOptionsDoc {
transformOptions =
opt: if lib.strings.hasPrefix "_" opt.name then opt // { visible = false; } else opt;
options = (lib.evalModules { modules = [ role.interface ]; }).options;
warningsAreErrors = true;
}).optionsJSON
) evaluatedService.config.roles;
manifest = evaluatedService.config.manifest;
}
) clan-core.clan.modules;
clanCore =
(nixosOptionsDoc {
options =

View File

@@ -30,7 +30,12 @@ from pathlib import Path
from typing import Any
from clan_cli.errors import ClanError
from clan_lib.api.modules import Frontmatter, extract_frontmatter, get_roles
from clan_lib.api.modules import (
CategoryInfo,
Frontmatter,
extract_frontmatter,
get_roles,
)
# Get environment variables
CLAN_CORE_PATH = Path(os.environ["CLAN_CORE_PATH"])
@@ -44,6 +49,7 @@ CLAN_MODULES_VIA_NIX = os.environ.get("CLAN_MODULES_VIA_NIX")
# Some modules can be imported via inventory
CLAN_MODULES_VIA_ROLES = os.environ.get("CLAN_MODULES_VIA_ROLES")
CLAN_MODULES_VIA_SERVICE = os.environ.get("CLAN_MODULES_VIA_SERVICE")
OUT = os.environ.get("out")
@@ -58,7 +64,8 @@ def replace_store_path(text: str) -> tuple[str, str]:
res = "https://git.clan.lol/clan/clan-core/src/branch/main/" + str(
Path(*Path(text).parts[4:])
)
name = Path(res).name
# name = Path(res).name
name = str(Path(*Path(text).parts[4:]))
return (res, name)
@@ -149,8 +156,12 @@ def render_option(
decls = option.get("declarations", [])
if decls:
source_path, name = replace_store_path(decls[0])
name = name.split(",")[0]
source_path = source_path.split(",")[0]
res += f"""
:simple-git: [{name}]({source_path})
:simple-git: Declared in: [{name}]({source_path})
"""
res += "\n\n"
@@ -221,7 +232,8 @@ def produce_clan_modules_frontmatter_docs() -> None:
# header
output = """# Frontmatter
Every clan module has a `frontmatter` section within its readme. It provides machine readable metadata about the module.
Every clan module has a `frontmatter` section within its readme. It provides
machine readable metadata about the module.
!!! example
@@ -246,7 +258,8 @@ Every clan module has a `frontmatter` section within its readme. It provides mac
output += """## Overview
This provides an overview of the available attributes of the `frontmatter` within the `README.md` of a clan module.
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():
@@ -331,7 +344,7 @@ def produce_clan_core_docs() -> None:
def render_roles(roles: list[str] | None, module_name: str) -> str:
if roles:
roles_list = "\n".join([f" - `{r}`" for r in roles])
roles_list = "\n".join([f"- `{r}`" for r in roles])
return (
f"""
### Roles
@@ -341,7 +354,7 @@ This module can be used via predefined roles
{roles_list}
"""
"""
Every role has its own configuration options. Which are each listed below.
Every role has its own configuration options, which are each listed below.
For more information, see the [inventory guide](../../manual/inventory.md).
@@ -350,8 +363,10 @@ For more information, see the [inventory guide](../../manual/inventory.md).
`clan.admin.allowedkeys`
This means there are two equivalent ways to set the `allowedkeys` option. Either via a nixos module or via the inventory interface.
**But it is recommended to keep together `imports` and `config` to preserve locality of the module configuration.**
This means there are two equivalent ways to set the `allowedkeys` option.
Either via a nixos module or via the inventory interface.
**But it is recommended to keep together `imports` and `config` to preserve
locality of the module configuration.**
=== "Inventory"
@@ -383,7 +398,11 @@ For more information, see the [inventory guide](../../manual/inventory.md).
return ""
clan_modules_descr = """Clan modules are [NixOS modules](https://wiki.nixos.org/wiki/NixOS_modules) which have been enhanced with additional features provided by Clan, with certain option types restricted to enable configuration through a graphical interface.
clan_modules_descr = """
Clan modules are [NixOS modules](https://wiki.nixos.org/wiki/NixOS_modules)
which have been enhanced with additional features provided by Clan, with
certain option types restricted to enable configuration through a graphical
interface.
!!! note "🔹"
Modules with this indicator support the [inventory](../../manual/inventory.md) feature.
@@ -391,12 +410,12 @@ clan_modules_descr = """Clan modules are [NixOS modules](https://wiki.nixos.org/
"""
def render_categories(categories: list[str], frontmatter: Frontmatter) -> str:
cat_info = frontmatter.categories_info
def render_categories(
categories: list[str], categories_info: dict[str, CategoryInfo]
) -> str:
res = """<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px;">"""
for cat in categories:
color = cat_info[cat]["color"]
# description = cat_info[cat]["description"]
color = categories_info[cat]["color"]
res += f"""
<div style="background-color: {color}; color: white; padding: 10px; border-radius: 20px; text-align: center;">
{cat}
@@ -406,6 +425,56 @@ def render_categories(categories: list[str], frontmatter: Frontmatter) -> str:
return res
def produce_clan_service_docs() -> None:
if not CLAN_MODULES_VIA_SERVICE:
msg = f"Environment variables are not set correctly: $CLAN_MODULES_VIA_SERVICE={CLAN_MODULES_VIA_SERVICE}"
raise ClanError(msg)
if not CLAN_CORE_PATH:
msg = f"Environment variables are not set correctly: $CLAN_CORE_PATH={CLAN_CORE_PATH}"
raise ClanError(msg)
if not OUT:
msg = f"Environment variables are not set correctly: $out={OUT}"
raise ClanError(msg)
with Path(CLAN_MODULES_VIA_SERVICE).open() as f3:
service_links: dict[str, dict[str, dict[str, Any]]] = json.load(f3)
for module_name, module_info in service_links.items():
output = f"# {module_name}\n\n"
# output += f"`clan.modules.{module_name}`\n"
output += f"*{module_info['manifest']['description']}*\n"
fm = Frontmatter("")
# output += "## Categories\n\n"
output += render_categories(
module_info["manifest"]["categories"], fm.categories_info
)
output += "\n---\n\n## Roles\n"
output += f"The {module_name} module has the following roles:\n\n"
for role_name, _ in module_info["roles"].items():
output += f"- {role_name}\n"
for role_name, role_filename in module_info["roles"].items():
output += print_options(
role_filename,
f"## Options for the `{role_name}` role",
"This role has no configuration",
replace_prefix=f"clan.{module_name}",
)
outfile = Path(OUT) / f"clanServices/{module_name}.md"
outfile.parent.mkdir(
parents=True,
exist_ok=True,
)
with outfile.open("w") as of:
of.write(output)
def produce_clan_modules_docs() -> None:
if not CLAN_MODULES_VIA_NIX:
msg = f"Environment variables are not set correctly: $CLAN_MODULES_VIA_NIX={CLAN_MODULES_VIA_NIX}"
@@ -456,11 +525,11 @@ def produce_clan_modules_docs() -> None:
# 2. Description from README.md
if frontmatter.description:
output += f"**{frontmatter.description}**\n\n"
output += f"*{frontmatter.description}*\n\n"
# 3. Categories from README.md
output += "## Categories\n\n"
output += render_categories(frontmatter.categories, frontmatter)
output += render_categories(frontmatter.categories, frontmatter.categories_info)
output += "\n---\n\n"
# 3. README.md content
@@ -785,7 +854,7 @@ def options_docs_from_tree(
root: Option, init_level: int = 1, prefix: list[str] | None = None
) -> str:
"""
Render the options from the tree structure.
eender the options from the tree structure.
Args:
root (Option): The root option node.
@@ -829,5 +898,6 @@ if __name__ == "__main__": #
produce_inventory_docs()
produce_clan_modules_docs()
produce_clan_service_docs()
produce_clan_modules_frontmatter_docs()