Docs/modules: seperate out inventory,role specific interface
This commit is contained in:
@@ -1,4 +0,0 @@
|
|||||||
# Dont import this file
|
|
||||||
# It is only here for backwards compatibility.
|
|
||||||
# Dont author new modules with this file.
|
|
||||||
{ }
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
# TODO: only kept this file to not break documentation generation.
|
|
||||||
{ }
|
|
||||||
@@ -66,6 +66,8 @@ nav:
|
|||||||
- Reference:
|
- Reference:
|
||||||
- Overview: reference/index.md
|
- Overview: reference/index.md
|
||||||
- Clan Modules:
|
- Clan Modules:
|
||||||
|
- reference/clanModules/index.md
|
||||||
|
# This is the module overview and should stay at the top
|
||||||
- reference/clanModules/admin.md
|
- reference/clanModules/admin.md
|
||||||
- reference/clanModules/borgbackup-static.md
|
- reference/clanModules/borgbackup-static.md
|
||||||
- reference/clanModules/borgbackup.md
|
- reference/clanModules/borgbackup.md
|
||||||
@@ -78,7 +80,6 @@ nav:
|
|||||||
- reference/clanModules/golem-provider.md
|
- reference/clanModules/golem-provider.md
|
||||||
- reference/clanModules/heisenbridge.md
|
- reference/clanModules/heisenbridge.md
|
||||||
- reference/clanModules/importer.md
|
- reference/clanModules/importer.md
|
||||||
- reference/clanModules/index.md
|
|
||||||
- reference/clanModules/iwd.md
|
- reference/clanModules/iwd.md
|
||||||
- reference/clanModules/localbackup.md
|
- reference/clanModules/localbackup.md
|
||||||
- reference/clanModules/localsend.md
|
- reference/clanModules/localsend.md
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
jsonDocs = pkgs.callPackage ./get-module-docs.nix {
|
jsonDocs = pkgs.callPackage ./get-module-docs.nix {
|
||||||
inherit (self) clanModules;
|
inherit (self) clanModules;
|
||||||
evalClanModules = self.lib.evalClanModules;
|
evalClanModules = self.lib.evalClanModules;
|
||||||
|
modulesRolesOptions = self.lib.evalClanModulesWithRoles self.clanModules;
|
||||||
};
|
};
|
||||||
|
|
||||||
# Frontmatter for clanModules
|
# Frontmatter for clanModules
|
||||||
@@ -23,9 +24,11 @@
|
|||||||
in
|
in
|
||||||
docs.optionsJSON;
|
docs.optionsJSON;
|
||||||
|
|
||||||
clanModulesFileInfo = pkgs.writeText "info.json" (builtins.toJSON jsonDocs.clanModules);
|
# Options available via ` imports = [ clanModules.${moduleName} ]; ` (Direct nix import)
|
||||||
# clanModulesReadmes = pkgs.writeText "info.json" (builtins.toJSON jsonDocs.clanModulesReadmes);
|
clanModulesViaNix = pkgs.writeText "info.json" (builtins.toJSON jsonDocs.clanModulesViaNix);
|
||||||
# clanModulesMeta = pkgs.writeText "info.json" (builtins.toJSON jsonDocs.clanModulesMeta);
|
|
||||||
|
# Options available when imported via ` inventory.${moduleName}....${rolesName} `
|
||||||
|
clanModulesViaRoles = pkgs.writeText "info.json" (builtins.toJSON jsonDocs.clanModulesViaRoles);
|
||||||
|
|
||||||
# Simply evaluated options (JSON)
|
# Simply evaluated options (JSON)
|
||||||
renderOptions =
|
renderOptions =
|
||||||
@@ -69,7 +72,8 @@
|
|||||||
export CLAN_CORE_PATH=${self}
|
export CLAN_CORE_PATH=${self}
|
||||||
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_VIA_ROLES=${clanModulesViaRoles}
|
||||||
|
export CLAN_MODULES_VIA_NIX=${clanModulesViaNix}
|
||||||
# Frontmatter format for clanModules
|
# Frontmatter format for clanModules
|
||||||
export CLAN_MODULES_FRONTMATTER_DOCS=${clanModulesFrontmatter}/share/doc/nixos/options.json
|
export CLAN_MODULES_FRONTMATTER_DOCS=${clanModulesFrontmatter}/share/doc/nixos/options.json
|
||||||
|
|
||||||
@@ -83,6 +87,9 @@
|
|||||||
'';
|
'';
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
legacyPackages = {
|
||||||
|
inherit jsonDocs clanModulesViaNix clanModulesViaRoles;
|
||||||
|
};
|
||||||
devShells.docs = pkgs.callPackage ./shell.nix {
|
devShells.docs = pkgs.callPackage ./shell.nix {
|
||||||
inherit (self'.packages) docs clan-cli-docs inventory-api-docs;
|
inherit (self'.packages) docs clan-cli-docs inventory-api-docs;
|
||||||
inherit
|
inherit
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
modulesRolesOptions,
|
||||||
nixosOptionsDoc,
|
nixosOptionsDoc,
|
||||||
clanModules,
|
clanModules,
|
||||||
evalClanModules,
|
evalClanModules,
|
||||||
@@ -6,14 +7,28 @@
|
|||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
# clanModules docs
|
# clanModules docs
|
||||||
clanModules = lib.mapAttrs (
|
clanModulesViaNix = lib.mapAttrs (
|
||||||
name: module:
|
name: module:
|
||||||
(nixosOptionsDoc {
|
if builtins.pathExists (module + "/default.nix") then
|
||||||
options = ((evalClanModules [ module ]).options).clan.${name} or { };
|
(nixosOptionsDoc {
|
||||||
warningsAreErrors = true;
|
options = ((evalClanModules [ module ]).options).clan.${name} or { };
|
||||||
}).optionsJSON
|
warningsAreErrors = true;
|
||||||
|
}).optionsJSON
|
||||||
|
else
|
||||||
|
{ }
|
||||||
) clanModules;
|
) clanModules;
|
||||||
|
|
||||||
|
clanModulesViaRoles = lib.mapAttrs (
|
||||||
|
_moduleName: rolesOptions:
|
||||||
|
lib.mapAttrs (
|
||||||
|
_roleName: options:
|
||||||
|
(nixosOptionsDoc {
|
||||||
|
inherit options;
|
||||||
|
warningsAreErrors = true;
|
||||||
|
}).optionsJSON
|
||||||
|
) rolesOptions
|
||||||
|
) modulesRolesOptions;
|
||||||
|
|
||||||
clanCore =
|
clanCore =
|
||||||
(nixosOptionsDoc {
|
(nixosOptionsDoc {
|
||||||
options = ((evalClanModules [ ]).options).clan.core or { };
|
options = ((evalClanModules [ ]).options).clan.core or { };
|
||||||
|
|||||||
@@ -35,9 +35,15 @@ from clan_cli.errors import ClanError
|
|||||||
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_FRONTMATTER_DOCS = os.environ.get("CLAN_MODULES_FRONTMATTER_DOCS")
|
||||||
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")
|
||||||
|
|
||||||
|
## Clan modules ##
|
||||||
|
# Some modules can be imported via nix natively
|
||||||
|
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")
|
||||||
|
|
||||||
|
|
||||||
OUT = os.environ.get("out")
|
OUT = os.environ.get("out")
|
||||||
|
|
||||||
|
|
||||||
@@ -130,15 +136,28 @@ def render_option(
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
def print_options(options_file: str, head: str, no_options: str) -> str:
|
||||||
|
res = ""
|
||||||
|
with (Path(options_file) / "share/doc/nixos/options.json").open() as f:
|
||||||
|
options: dict[str, dict[str, Any]] = json.load(f)
|
||||||
|
|
||||||
|
res += head if len(options.items()) else no_options
|
||||||
|
for option_name, info in options.items():
|
||||||
|
res += render_option(option_name, info, 4)
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
def module_header(module_name: str, has_inventory_feature: bool = False) -> str:
|
def module_header(module_name: str, has_inventory_feature: bool = False) -> str:
|
||||||
indicator = " 🔹" if has_inventory_feature else ""
|
indicator = " 🔹" if has_inventory_feature else ""
|
||||||
return f"# {module_name}{indicator}\n\n"
|
return f"# {module_name}{indicator}\n\n"
|
||||||
|
|
||||||
|
|
||||||
def module_usage(module_name: str) -> str:
|
def module_nix_usage(module_name: str) -> str:
|
||||||
return f"""## Usage
|
return f"""## Usage via Nix
|
||||||
|
|
||||||
To use this module, import it like th:
|
**This module can be also imported directly in your nixos configuration. Although it is recommended to use the [inventory](../../reference/nix-api/inventory.md) interface if available.**
|
||||||
|
|
||||||
|
Some modules are considered 'low-level' or 'expert modules' and are not available via the inventory interface.
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
{{config, lib, inputs, ...}}: {{
|
{{config, lib, inputs, ...}}: {{
|
||||||
@@ -146,6 +165,7 @@ To use this module, import it like th:
|
|||||||
# ...
|
# ...
|
||||||
}}
|
}}
|
||||||
```
|
```
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -153,7 +173,11 @@ clan_core_descr = """`clan.core` is always included in each machine `config`.
|
|||||||
Your can customize your machines behavior with the configuration [options](#module-options) provided below.
|
Your can customize your machines behavior with the configuration [options](#module-options) provided below.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
options_head = "\n## Module Options\n"
|
options_head = """
|
||||||
|
### Module Options
|
||||||
|
|
||||||
|
The following options are available for this module.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
def produce_clan_modules_frontmatter_docs() -> None:
|
def produce_clan_modules_frontmatter_docs() -> None:
|
||||||
@@ -260,13 +284,16 @@ def render_roles(roles: list[str] | None, module_name: str) -> str:
|
|||||||
if roles:
|
if roles:
|
||||||
roles_list = "\n".join([f" - `{r}`" for r in roles])
|
roles_list = "\n".join([f" - `{r}`" for r in roles])
|
||||||
return f"""
|
return f"""
|
||||||
## Inventory Roles
|
### Roles
|
||||||
|
|
||||||
Predefined roles
|
This module can be used via predefined roles
|
||||||
|
|
||||||
{roles_list}
|
{roles_list}
|
||||||
|
|
||||||
|
Every role has its own configuration options. Which are each listed below.
|
||||||
|
|
||||||
For more information, see the [inventory guide](../../manual/inventory.md).
|
For more information, see the [inventory guide](../../manual/inventory.md).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
@@ -295,8 +322,12 @@ def render_categories(categories: list[str], frontmatter: Frontmatter) -> str:
|
|||||||
|
|
||||||
|
|
||||||
def produce_clan_modules_docs() -> None:
|
def produce_clan_modules_docs() -> None:
|
||||||
if not CLAN_MODULES:
|
if not CLAN_MODULES_VIA_NIX:
|
||||||
msg = f"Environment variables are not set correctly: $out={CLAN_MODULES}"
|
msg = f"Environment variables are not set correctly: $CLAN_MODULES_VIA_NIX={CLAN_MODULES_VIA_NIX}"
|
||||||
|
raise ClanError(msg)
|
||||||
|
|
||||||
|
if not CLAN_MODULES_VIA_ROLES:
|
||||||
|
msg = f"Environment variables are not set correctly: $CLAN_MODULES_VIA_ROLES={CLAN_MODULES_VIA_ROLES}"
|
||||||
raise ClanError(msg)
|
raise ClanError(msg)
|
||||||
|
|
||||||
if not CLAN_CORE_PATH:
|
if not CLAN_CORE_PATH:
|
||||||
@@ -307,15 +338,19 @@ def produce_clan_modules_docs() -> None:
|
|||||||
msg = f"Environment variables are not set correctly: $out={OUT}"
|
msg = f"Environment variables are not set correctly: $out={OUT}"
|
||||||
raise ClanError(msg)
|
raise ClanError(msg)
|
||||||
|
|
||||||
with Path(CLAN_MODULES).open() as f:
|
|
||||||
links: dict[str, str] = json.load(f)
|
|
||||||
|
|
||||||
modules_index = "# Modules Overview\n\n"
|
modules_index = "# Modules Overview\n\n"
|
||||||
modules_index += clan_modules_descr
|
modules_index += clan_modules_descr
|
||||||
modules_index += "## Overview\n\n"
|
modules_index += "## Overview\n\n"
|
||||||
modules_index += '<div class="grid cards" markdown>\n\n'
|
modules_index += '<div class="grid cards" markdown>\n\n'
|
||||||
|
|
||||||
|
with Path(CLAN_MODULES_VIA_ROLES).open() as f2:
|
||||||
|
role_links: dict[str, dict[str, str]] = json.load(f2)
|
||||||
|
|
||||||
|
with Path(CLAN_MODULES_VIA_NIX).open() as f:
|
||||||
|
links: dict[str, str] = json.load(f)
|
||||||
|
|
||||||
for module_name, options_file in links.items():
|
for module_name, options_file in links.items():
|
||||||
|
print(f"Rendering {module_name}")
|
||||||
readme_file = CLAN_CORE_PATH / "clanModules" / module_name / "README.md"
|
readme_file = CLAN_CORE_PATH / "clanModules" / module_name / "README.md"
|
||||||
with readme_file.open() as f:
|
with readme_file.open() as f:
|
||||||
readme = f.read()
|
readme = f.read()
|
||||||
@@ -324,38 +359,79 @@ def produce_clan_modules_docs() -> None:
|
|||||||
|
|
||||||
modules_index += build_option_card(module_name, frontmatter)
|
modules_index += build_option_card(module_name, frontmatter)
|
||||||
|
|
||||||
with (Path(options_file) / "share/doc/nixos/options.json").open() as f:
|
##### Print module documentation #####
|
||||||
options: dict[str, dict[str, Any]] = json.load(f)
|
|
||||||
print(f"Rendering options for {module_name}...")
|
|
||||||
output = module_header(module_name, "inventory" in frontmatter.features)
|
|
||||||
|
|
||||||
if frontmatter.description:
|
# 1. Header
|
||||||
output += f"**{frontmatter.description}**\n\n"
|
output = module_header(module_name, "inventory" in frontmatter.features)
|
||||||
|
|
||||||
output += "## Categories\n\n"
|
# 2. Description from README.md
|
||||||
output += render_categories(frontmatter.categories, frontmatter)
|
if frontmatter.description:
|
||||||
output += "\n---\n\n"
|
output += f"**{frontmatter.description}**\n\n"
|
||||||
|
|
||||||
output += f"{readme_content}\n"
|
# 3. Categories from README.md
|
||||||
|
output += "## Categories\n\n"
|
||||||
|
output += render_categories(frontmatter.categories, frontmatter)
|
||||||
|
output += "\n---\n\n"
|
||||||
|
|
||||||
# get_roles(str) -> list[str] | None
|
# 3. README.md content
|
||||||
roles = get_roles(CLAN_CORE_PATH / "clanModules" / module_name)
|
output += f"{readme_content}\n"
|
||||||
if roles:
|
|
||||||
output += render_roles(roles, module_name)
|
|
||||||
|
|
||||||
output += module_usage(module_name)
|
# 4. Usage
|
||||||
|
##### Print usage via Inventory #####
|
||||||
|
|
||||||
output += options_head if len(options.items()) else ""
|
# get_roles(str) -> list[str] | None
|
||||||
for option_name, info in options.items():
|
# if not isinstance(options_file, str):
|
||||||
output += render_option(option_name, info)
|
roles = get_roles(CLAN_CORE_PATH / "clanModules" / module_name)
|
||||||
|
if roles:
|
||||||
|
# Render inventory usage
|
||||||
|
output += """## Usage via Inventory\n\n"""
|
||||||
|
output += render_roles(roles, module_name)
|
||||||
|
for role in roles:
|
||||||
|
role_options_file = role_links[module_name][role]
|
||||||
|
# Abort if the options file is not found
|
||||||
|
if not isinstance(role_options_file, str):
|
||||||
|
print(
|
||||||
|
f"Error: module: {module_name} in role: {role} - options file not found, Got {role_options_file}"
|
||||||
|
)
|
||||||
|
exit(1)
|
||||||
|
|
||||||
outfile = Path(OUT) / f"clanModules/{module_name}.md"
|
no_options = f"**The `{module_name}` `{role}` doesnt offer / require any options to be set.**"
|
||||||
outfile.parent.mkdir(
|
|
||||||
parents=True,
|
heading = f"""### Options of `{role}` role
|
||||||
exist_ok=True,
|
|
||||||
|
The following options are available when using the `{role}` role.
|
||||||
|
"""
|
||||||
|
output += print_options(role_options_file, heading, no_options)
|
||||||
|
else:
|
||||||
|
# No roles means no inventory usage
|
||||||
|
output += """## Usage via Inventory
|
||||||
|
|
||||||
|
**This module cannot be used via the inventory interface.**
|
||||||
|
"""
|
||||||
|
|
||||||
|
##### Print usage via Nix / nixos #####
|
||||||
|
if not isinstance(options_file, str):
|
||||||
|
print(
|
||||||
|
f"Skipping {module_name}: Cannot be used via import clanModules.{module_name}"
|
||||||
)
|
)
|
||||||
with outfile.open("w") as of:
|
output += """## Usage via Nix
|
||||||
of.write(output)
|
|
||||||
|
**This module cannot be imported directly in your nixos configuration.**
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
else:
|
||||||
|
output += module_nix_usage(module_name)
|
||||||
|
no_options = "** This module doesnt require any options to be set.**"
|
||||||
|
output += print_options(options_file, options_head, no_options)
|
||||||
|
|
||||||
|
outfile = Path(OUT) / f"clanModules/{module_name}.md"
|
||||||
|
outfile.parent.mkdir(
|
||||||
|
parents=True,
|
||||||
|
exist_ok=True,
|
||||||
|
)
|
||||||
|
with outfile.open("w") as of:
|
||||||
|
of.write(output)
|
||||||
|
|
||||||
modules_index += "</div>"
|
modules_index += "</div>"
|
||||||
modules_index += "\n"
|
modules_index += "\n"
|
||||||
|
|||||||
Reference in New Issue
Block a user