feat(docs): MkDocs Material site + auto-generated hardware overview
Bootstraps an MkDocs Material documentation site (rendered to
docs.makerfloss.eu by the Forgejo Actions runner). The first feature
is an auto-generated hardware overview built from per-host YAML
frontmatter blocks under docs/hardware/.
- mkdocs.yml, requirements.txt: MkDocs Material 9.5 + pyyaml
- Makefile: docs-index | docs-build | docs-serve | docs-check
- scripts/gen_overview.py: stdlib + pyyaml generator, deterministic and
offline. Reads scripts/overview_config.yml — category-driven so
services/vms can plug in later without touching the script.
- scripts/overview_config.yml: hardware schema and index layout
- docs/hardware/{makerfloss,fisi,tembo}.md: 3 sample entries
- docs/hardware/index.md: GENERATED, committed (CI fails on drift)
- docs/index.md: site landing page
- .forgejo/workflows/docs.yml: drift-check + mkdocs build --strict +
rsync site/ to /srv/docs-makerfloss/html on push to main
- .gitignore: site/, .venv, __pycache__
Schema:
- hostname, kind, status (required; kind/status are enums)
- model, location, cpu, cpu_cores, cpu_threads, ram_gb, storage_gb,
storage_type (enum), storage_notes, nic_gbps (all optional)
- Filename stem MUST equal hostname (enforced by generator)
- Extra optional fields are accepted silently and live on the per-page
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 21:10:58 +02:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
"""Generate a category overview Markdown file from per-item YAML frontmatter.
|
|
|
|
|
|
|
|
|
|
Reads `scripts/overview_config.yml`, picks the block named by `--category`,
|
|
|
|
|
walks `source_dir/*.md` (excluding `output_file`), validates each file's
|
|
|
|
|
frontmatter, and writes a grouped+sorted table to `output_file`.
|
|
|
|
|
|
|
|
|
|
Exits non-zero on any schema violation. Deterministic, offline, stdlib + PyYAML.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
import argparse
|
|
|
|
|
import re
|
|
|
|
|
import sys
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
|
|
import yaml
|
|
|
|
|
|
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parent.parent
|
|
|
|
|
CONFIG_PATH = REPO_ROOT / "scripts" / "overview_config.yml"
|
|
|
|
|
|
|
|
|
|
FRONTMATTER_RE = re.compile(r"^---\s*\n(.*?)\n---\s*\n", re.DOTALL)
|
|
|
|
|
|
2026-06-30 21:31:48 +02:00
|
|
|
# Shown at the bottom of every error report so a newcomer knows where to look.
|
|
|
|
|
GUIDE_URL = "https://docs.makerfloss.eu/guides/editing-hardware-docs/"
|
|
|
|
|
|
feat(docs): MkDocs Material site + auto-generated hardware overview
Bootstraps an MkDocs Material documentation site (rendered to
docs.makerfloss.eu by the Forgejo Actions runner). The first feature
is an auto-generated hardware overview built from per-host YAML
frontmatter blocks under docs/hardware/.
- mkdocs.yml, requirements.txt: MkDocs Material 9.5 + pyyaml
- Makefile: docs-index | docs-build | docs-serve | docs-check
- scripts/gen_overview.py: stdlib + pyyaml generator, deterministic and
offline. Reads scripts/overview_config.yml — category-driven so
services/vms can plug in later without touching the script.
- scripts/overview_config.yml: hardware schema and index layout
- docs/hardware/{makerfloss,fisi,tembo}.md: 3 sample entries
- docs/hardware/index.md: GENERATED, committed (CI fails on drift)
- docs/index.md: site landing page
- .forgejo/workflows/docs.yml: drift-check + mkdocs build --strict +
rsync site/ to /srv/docs-makerfloss/html on push to main
- .gitignore: site/, .venv, __pycache__
Schema:
- hostname, kind, status (required; kind/status are enums)
- model, location, cpu, cpu_cores, cpu_threads, ram_gb, storage_gb,
storage_type (enum), storage_notes, nic_gbps (all optional)
- Filename stem MUST equal hostname (enforced by generator)
- Extra optional fields are accepted silently and live on the per-page
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 21:10:58 +02:00
|
|
|
|
|
|
|
|
class SchemaError(Exception):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
2026-06-30 21:31:48 +02:00
|
|
|
def _allowed_hint(field: str, enums: dict) -> str:
|
|
|
|
|
allowed = enums.get(field)
|
|
|
|
|
return f" Allowed values: {', '.join(map(str, allowed))}." if allowed else ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _example_value(field: str, enums: dict) -> str:
|
|
|
|
|
allowed = enums.get(field)
|
|
|
|
|
return str(allowed[0]) if allowed else "..."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def report_errors(errors: list[str], category: str) -> None:
|
|
|
|
|
"""Print a collected list of problems with orientation for newcomers."""
|
|
|
|
|
print(
|
|
|
|
|
f"\ngen_overview: found {len(errors)} problem(s) in the {category} docs:",
|
|
|
|
|
file=sys.stderr,
|
|
|
|
|
)
|
|
|
|
|
for err in errors:
|
|
|
|
|
print(f" ✗ {err}", file=sys.stderr)
|
|
|
|
|
print(
|
|
|
|
|
"\nFix the field(s) named above, then run 'make docs-index' again.\n"
|
|
|
|
|
f"Guide: {GUIDE_URL}",
|
|
|
|
|
file=sys.stderr,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
feat(docs): MkDocs Material site + auto-generated hardware overview
Bootstraps an MkDocs Material documentation site (rendered to
docs.makerfloss.eu by the Forgejo Actions runner). The first feature
is an auto-generated hardware overview built from per-host YAML
frontmatter blocks under docs/hardware/.
- mkdocs.yml, requirements.txt: MkDocs Material 9.5 + pyyaml
- Makefile: docs-index | docs-build | docs-serve | docs-check
- scripts/gen_overview.py: stdlib + pyyaml generator, deterministic and
offline. Reads scripts/overview_config.yml — category-driven so
services/vms can plug in later without touching the script.
- scripts/overview_config.yml: hardware schema and index layout
- docs/hardware/{makerfloss,fisi,tembo}.md: 3 sample entries
- docs/hardware/index.md: GENERATED, committed (CI fails on drift)
- docs/index.md: site landing page
- .forgejo/workflows/docs.yml: drift-check + mkdocs build --strict +
rsync site/ to /srv/docs-makerfloss/html on push to main
- .gitignore: site/, .venv, __pycache__
Schema:
- hostname, kind, status (required; kind/status are enums)
- model, location, cpu, cpu_cores, cpu_threads, ram_gb, storage_gb,
storage_type (enum), storage_notes, nic_gbps (all optional)
- Filename stem MUST equal hostname (enforced by generator)
- Extra optional fields are accepted silently and live on the per-page
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 21:10:58 +02:00
|
|
|
def parse_frontmatter(path: Path) -> dict | None:
|
|
|
|
|
text = path.read_text(encoding="utf-8")
|
|
|
|
|
m = FRONTMATTER_RE.match(text)
|
|
|
|
|
if not m:
|
|
|
|
|
return None
|
|
|
|
|
try:
|
|
|
|
|
data = yaml.safe_load(m.group(1))
|
|
|
|
|
except yaml.YAMLError as e:
|
|
|
|
|
raise SchemaError(f"{path}: invalid YAML frontmatter: {e}") from e
|
|
|
|
|
if not isinstance(data, dict):
|
|
|
|
|
raise SchemaError(f"{path}: frontmatter is not a mapping")
|
|
|
|
|
return data
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def validate(path: Path, fm: dict, cfg: dict) -> None:
|
2026-06-30 21:31:48 +02:00
|
|
|
enums = cfg.get("enums", {})
|
|
|
|
|
name = path.name
|
feat(docs): MkDocs Material site + auto-generated hardware overview
Bootstraps an MkDocs Material documentation site (rendered to
docs.makerfloss.eu by the Forgejo Actions runner). The first feature
is an auto-generated hardware overview built from per-host YAML
frontmatter blocks under docs/hardware/.
- mkdocs.yml, requirements.txt: MkDocs Material 9.5 + pyyaml
- Makefile: docs-index | docs-build | docs-serve | docs-check
- scripts/gen_overview.py: stdlib + pyyaml generator, deterministic and
offline. Reads scripts/overview_config.yml — category-driven so
services/vms can plug in later without touching the script.
- scripts/overview_config.yml: hardware schema and index layout
- docs/hardware/{makerfloss,fisi,tembo}.md: 3 sample entries
- docs/hardware/index.md: GENERATED, committed (CI fails on drift)
- docs/index.md: site landing page
- .forgejo/workflows/docs.yml: drift-check + mkdocs build --strict +
rsync site/ to /srv/docs-makerfloss/html on push to main
- .gitignore: site/, .venv, __pycache__
Schema:
- hostname, kind, status (required; kind/status are enums)
- model, location, cpu, cpu_cores, cpu_threads, ram_gb, storage_gb,
storage_type (enum), storage_notes, nic_gbps (all optional)
- Filename stem MUST equal hostname (enforced by generator)
- Extra optional fields are accepted silently and live on the per-page
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 21:10:58 +02:00
|
|
|
for field in cfg["required_fields"]:
|
|
|
|
|
if field not in fm:
|
2026-06-30 21:31:48 +02:00
|
|
|
raise SchemaError(
|
|
|
|
|
f"{name}: missing required field '{field}'. Add a line like "
|
|
|
|
|
f"'{field}: {_example_value(field, enums)}' to the frontmatter."
|
|
|
|
|
f"{_allowed_hint(field, enums)}"
|
|
|
|
|
)
|
|
|
|
|
for field, allowed in enums.items():
|
feat(docs): MkDocs Material site + auto-generated hardware overview
Bootstraps an MkDocs Material documentation site (rendered to
docs.makerfloss.eu by the Forgejo Actions runner). The first feature
is an auto-generated hardware overview built from per-host YAML
frontmatter blocks under docs/hardware/.
- mkdocs.yml, requirements.txt: MkDocs Material 9.5 + pyyaml
- Makefile: docs-index | docs-build | docs-serve | docs-check
- scripts/gen_overview.py: stdlib + pyyaml generator, deterministic and
offline. Reads scripts/overview_config.yml — category-driven so
services/vms can plug in later without touching the script.
- scripts/overview_config.yml: hardware schema and index layout
- docs/hardware/{makerfloss,fisi,tembo}.md: 3 sample entries
- docs/hardware/index.md: GENERATED, committed (CI fails on drift)
- docs/index.md: site landing page
- .forgejo/workflows/docs.yml: drift-check + mkdocs build --strict +
rsync site/ to /srv/docs-makerfloss/html on push to main
- .gitignore: site/, .venv, __pycache__
Schema:
- hostname, kind, status (required; kind/status are enums)
- model, location, cpu, cpu_cores, cpu_threads, ram_gb, storage_gb,
storage_type (enum), storage_notes, nic_gbps (all optional)
- Filename stem MUST equal hostname (enforced by generator)
- Extra optional fields are accepted silently and live on the per-page
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 21:10:58 +02:00
|
|
|
if field in fm and fm[field] not in allowed:
|
|
|
|
|
raise SchemaError(
|
2026-06-30 21:31:48 +02:00
|
|
|
f"{name}: {field} {fm[field]!r} is not allowed. "
|
|
|
|
|
f"Use one of: {', '.join(map(str, allowed))}."
|
feat(docs): MkDocs Material site + auto-generated hardware overview
Bootstraps an MkDocs Material documentation site (rendered to
docs.makerfloss.eu by the Forgejo Actions runner). The first feature
is an auto-generated hardware overview built from per-host YAML
frontmatter blocks under docs/hardware/.
- mkdocs.yml, requirements.txt: MkDocs Material 9.5 + pyyaml
- Makefile: docs-index | docs-build | docs-serve | docs-check
- scripts/gen_overview.py: stdlib + pyyaml generator, deterministic and
offline. Reads scripts/overview_config.yml — category-driven so
services/vms can plug in later without touching the script.
- scripts/overview_config.yml: hardware schema and index layout
- docs/hardware/{makerfloss,fisi,tembo}.md: 3 sample entries
- docs/hardware/index.md: GENERATED, committed (CI fails on drift)
- docs/index.md: site landing page
- .forgejo/workflows/docs.yml: drift-check + mkdocs build --strict +
rsync site/ to /srv/docs-makerfloss/html on push to main
- .gitignore: site/, .venv, __pycache__
Schema:
- hostname, kind, status (required; kind/status are enums)
- model, location, cpu, cpu_cores, cpu_threads, ram_gb, storage_gb,
storage_type (enum), storage_notes, nic_gbps (all optional)
- Filename stem MUST equal hostname (enforced by generator)
- Extra optional fields are accepted silently and live on the per-page
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 21:10:58 +02:00
|
|
|
)
|
feat(docs): add services category alongside hardware
Mirror the auto-indexed per-host pattern for a new docs/services/
category, seeded with the six things currently deployed on or around
makerfloss.eu: docs, slides, forgejo, gandi-dns, marp, mermaid.
Generator/hook generalisation:
- scripts/gen_overview.py: replace the hardcoded `hostname` check
with a configurable `key_field` (default: hostname). Add a generic
`key-link` column kind (replaces the old `hostname-link`) and a
`url-link` kind that renders the value as a clickable link.
- scripts/overview_config.yml: declare hardware's key_field, then add
a `services` block (key_field=name, its own kind/status enums,
grouped by kind for the index table).
- scripts/mkdocs_hooks.py: route by `page.file.src_uri` so each
hardware/* page gets a "Specs" table and each services/* page gets
a "Service" table; both share the helpers in gen_overview.
Wiring:
- Makefile: docs-index and docs-check now regenerate and drift-check
both indices.
- .forgejo/workflows/docs.yml: same on the CI runner.
- mkdocs.yml: add Services to nav.
- README.md, CLAUDE.md: list services/ in the repo-layout block.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 17:48:15 +02:00
|
|
|
key_field = cfg.get("key_field", "hostname")
|
|
|
|
|
if key_field not in fm:
|
|
|
|
|
raise SchemaError(
|
2026-06-30 21:31:48 +02:00
|
|
|
f"{name}: missing the '{key_field}' field (the device's id). It must "
|
|
|
|
|
f"match the filename, e.g. '{key_field}: {path.stem}'."
|
feat(docs): add services category alongside hardware
Mirror the auto-indexed per-host pattern for a new docs/services/
category, seeded with the six things currently deployed on or around
makerfloss.eu: docs, slides, forgejo, gandi-dns, marp, mermaid.
Generator/hook generalisation:
- scripts/gen_overview.py: replace the hardcoded `hostname` check
with a configurable `key_field` (default: hostname). Add a generic
`key-link` column kind (replaces the old `hostname-link`) and a
`url-link` kind that renders the value as a clickable link.
- scripts/overview_config.yml: declare hardware's key_field, then add
a `services` block (key_field=name, its own kind/status enums,
grouped by kind for the index table).
- scripts/mkdocs_hooks.py: route by `page.file.src_uri` so each
hardware/* page gets a "Specs" table and each services/* page gets
a "Service" table; both share the helpers in gen_overview.
Wiring:
- Makefile: docs-index and docs-check now regenerate and drift-check
both indices.
- .forgejo/workflows/docs.yml: same on the CI runner.
- mkdocs.yml: add Services to nav.
- README.md, CLAUDE.md: list services/ in the repo-layout block.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 17:48:15 +02:00
|
|
|
)
|
feat(docs): MkDocs Material site + auto-generated hardware overview
Bootstraps an MkDocs Material documentation site (rendered to
docs.makerfloss.eu by the Forgejo Actions runner). The first feature
is an auto-generated hardware overview built from per-host YAML
frontmatter blocks under docs/hardware/.
- mkdocs.yml, requirements.txt: MkDocs Material 9.5 + pyyaml
- Makefile: docs-index | docs-build | docs-serve | docs-check
- scripts/gen_overview.py: stdlib + pyyaml generator, deterministic and
offline. Reads scripts/overview_config.yml — category-driven so
services/vms can plug in later without touching the script.
- scripts/overview_config.yml: hardware schema and index layout
- docs/hardware/{makerfloss,fisi,tembo}.md: 3 sample entries
- docs/hardware/index.md: GENERATED, committed (CI fails on drift)
- docs/index.md: site landing page
- .forgejo/workflows/docs.yml: drift-check + mkdocs build --strict +
rsync site/ to /srv/docs-makerfloss/html on push to main
- .gitignore: site/, .venv, __pycache__
Schema:
- hostname, kind, status (required; kind/status are enums)
- model, location, cpu, cpu_cores, cpu_threads, ram_gb, storage_gb,
storage_type (enum), storage_notes, nic_gbps (all optional)
- Filename stem MUST equal hostname (enforced by generator)
- Extra optional fields are accepted silently and live on the per-page
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 21:10:58 +02:00
|
|
|
stem = path.stem
|
feat(docs): add services category alongside hardware
Mirror the auto-indexed per-host pattern for a new docs/services/
category, seeded with the six things currently deployed on or around
makerfloss.eu: docs, slides, forgejo, gandi-dns, marp, mermaid.
Generator/hook generalisation:
- scripts/gen_overview.py: replace the hardcoded `hostname` check
with a configurable `key_field` (default: hostname). Add a generic
`key-link` column kind (replaces the old `hostname-link`) and a
`url-link` kind that renders the value as a clickable link.
- scripts/overview_config.yml: declare hardware's key_field, then add
a `services` block (key_field=name, its own kind/status enums,
grouped by kind for the index table).
- scripts/mkdocs_hooks.py: route by `page.file.src_uri` so each
hardware/* page gets a "Specs" table and each services/* page gets
a "Service" table; both share the helpers in gen_overview.
Wiring:
- Makefile: docs-index and docs-check now regenerate and drift-check
both indices.
- .forgejo/workflows/docs.yml: same on the CI runner.
- mkdocs.yml: add Services to nav.
- README.md, CLAUDE.md: list services/ in the repo-layout block.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 17:48:15 +02:00
|
|
|
value = fm[key_field]
|
|
|
|
|
if stem != value:
|
feat(docs): MkDocs Material site + auto-generated hardware overview
Bootstraps an MkDocs Material documentation site (rendered to
docs.makerfloss.eu by the Forgejo Actions runner). The first feature
is an auto-generated hardware overview built from per-host YAML
frontmatter blocks under docs/hardware/.
- mkdocs.yml, requirements.txt: MkDocs Material 9.5 + pyyaml
- Makefile: docs-index | docs-build | docs-serve | docs-check
- scripts/gen_overview.py: stdlib + pyyaml generator, deterministic and
offline. Reads scripts/overview_config.yml — category-driven so
services/vms can plug in later without touching the script.
- scripts/overview_config.yml: hardware schema and index layout
- docs/hardware/{makerfloss,fisi,tembo}.md: 3 sample entries
- docs/hardware/index.md: GENERATED, committed (CI fails on drift)
- docs/index.md: site landing page
- .forgejo/workflows/docs.yml: drift-check + mkdocs build --strict +
rsync site/ to /srv/docs-makerfloss/html on push to main
- .gitignore: site/, .venv, __pycache__
Schema:
- hostname, kind, status (required; kind/status are enums)
- model, location, cpu, cpu_cores, cpu_threads, ram_gb, storage_gb,
storage_type (enum), storage_notes, nic_gbps (all optional)
- Filename stem MUST equal hostname (enforced by generator)
- Extra optional fields are accepted silently and live on the per-page
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 21:10:58 +02:00
|
|
|
raise SchemaError(
|
2026-06-30 21:31:48 +02:00
|
|
|
f"{name}: '{key_field}: {value}' does not match the filename '{name}'. "
|
|
|
|
|
f"Rename the file to '{value}.md', or set {key_field} to '{stem}'."
|
feat(docs): MkDocs Material site + auto-generated hardware overview
Bootstraps an MkDocs Material documentation site (rendered to
docs.makerfloss.eu by the Forgejo Actions runner). The first feature
is an auto-generated hardware overview built from per-host YAML
frontmatter blocks under docs/hardware/.
- mkdocs.yml, requirements.txt: MkDocs Material 9.5 + pyyaml
- Makefile: docs-index | docs-build | docs-serve | docs-check
- scripts/gen_overview.py: stdlib + pyyaml generator, deterministic and
offline. Reads scripts/overview_config.yml — category-driven so
services/vms can plug in later without touching the script.
- scripts/overview_config.yml: hardware schema and index layout
- docs/hardware/{makerfloss,fisi,tembo}.md: 3 sample entries
- docs/hardware/index.md: GENERATED, committed (CI fails on drift)
- docs/index.md: site landing page
- .forgejo/workflows/docs.yml: drift-check + mkdocs build --strict +
rsync site/ to /srv/docs-makerfloss/html on push to main
- .gitignore: site/, .venv, __pycache__
Schema:
- hostname, kind, status (required; kind/status are enums)
- model, location, cpu, cpu_cores, cpu_threads, ram_gb, storage_gb,
storage_type (enum), storage_notes, nic_gbps (all optional)
- Filename stem MUST equal hostname (enforced by generator)
- Extra optional fields are accepted silently and live on the per-page
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 21:10:58 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def fmt_cpu(fm: dict) -> str:
|
2026-05-27 10:31:46 +02:00
|
|
|
model = fm.get("cpu") or ""
|
feat(docs): MkDocs Material site + auto-generated hardware overview
Bootstraps an MkDocs Material documentation site (rendered to
docs.makerfloss.eu by the Forgejo Actions runner). The first feature
is an auto-generated hardware overview built from per-host YAML
frontmatter blocks under docs/hardware/.
- mkdocs.yml, requirements.txt: MkDocs Material 9.5 + pyyaml
- Makefile: docs-index | docs-build | docs-serve | docs-check
- scripts/gen_overview.py: stdlib + pyyaml generator, deterministic and
offline. Reads scripts/overview_config.yml — category-driven so
services/vms can plug in later without touching the script.
- scripts/overview_config.yml: hardware schema and index layout
- docs/hardware/{makerfloss,fisi,tembo}.md: 3 sample entries
- docs/hardware/index.md: GENERATED, committed (CI fails on drift)
- docs/index.md: site landing page
- .forgejo/workflows/docs.yml: drift-check + mkdocs build --strict +
rsync site/ to /srv/docs-makerfloss/html on push to main
- .gitignore: site/, .venv, __pycache__
Schema:
- hostname, kind, status (required; kind/status are enums)
- model, location, cpu, cpu_cores, cpu_threads, ram_gb, storage_gb,
storage_type (enum), storage_notes, nic_gbps (all optional)
- Filename stem MUST equal hostname (enforced by generator)
- Extra optional fields are accepted silently and live on the per-page
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 21:10:58 +02:00
|
|
|
cores = fm.get("cpu_cores")
|
|
|
|
|
threads = fm.get("cpu_threads")
|
|
|
|
|
suffix = ""
|
2026-05-27 10:31:46 +02:00
|
|
|
if isinstance(cores, int) and isinstance(threads, int) and threads != cores:
|
feat(docs): MkDocs Material site + auto-generated hardware overview
Bootstraps an MkDocs Material documentation site (rendered to
docs.makerfloss.eu by the Forgejo Actions runner). The first feature
is an auto-generated hardware overview built from per-host YAML
frontmatter blocks under docs/hardware/.
- mkdocs.yml, requirements.txt: MkDocs Material 9.5 + pyyaml
- Makefile: docs-index | docs-build | docs-serve | docs-check
- scripts/gen_overview.py: stdlib + pyyaml generator, deterministic and
offline. Reads scripts/overview_config.yml — category-driven so
services/vms can plug in later without touching the script.
- scripts/overview_config.yml: hardware schema and index layout
- docs/hardware/{makerfloss,fisi,tembo}.md: 3 sample entries
- docs/hardware/index.md: GENERATED, committed (CI fails on drift)
- docs/index.md: site landing page
- .forgejo/workflows/docs.yml: drift-check + mkdocs build --strict +
rsync site/ to /srv/docs-makerfloss/html on push to main
- .gitignore: site/, .venv, __pycache__
Schema:
- hostname, kind, status (required; kind/status are enums)
- model, location, cpu, cpu_cores, cpu_threads, ram_gb, storage_gb,
storage_type (enum), storage_notes, nic_gbps (all optional)
- Filename stem MUST equal hostname (enforced by generator)
- Extra optional fields are accepted silently and live on the per-page
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 21:10:58 +02:00
|
|
|
suffix = f" · {cores}c/{threads}t"
|
2026-05-27 10:31:46 +02:00
|
|
|
elif isinstance(cores, int):
|
feat(docs): MkDocs Material site + auto-generated hardware overview
Bootstraps an MkDocs Material documentation site (rendered to
docs.makerfloss.eu by the Forgejo Actions runner). The first feature
is an auto-generated hardware overview built from per-host YAML
frontmatter blocks under docs/hardware/.
- mkdocs.yml, requirements.txt: MkDocs Material 9.5 + pyyaml
- Makefile: docs-index | docs-build | docs-serve | docs-check
- scripts/gen_overview.py: stdlib + pyyaml generator, deterministic and
offline. Reads scripts/overview_config.yml — category-driven so
services/vms can plug in later without touching the script.
- scripts/overview_config.yml: hardware schema and index layout
- docs/hardware/{makerfloss,fisi,tembo}.md: 3 sample entries
- docs/hardware/index.md: GENERATED, committed (CI fails on drift)
- docs/index.md: site landing page
- .forgejo/workflows/docs.yml: drift-check + mkdocs build --strict +
rsync site/ to /srv/docs-makerfloss/html on push to main
- .gitignore: site/, .venv, __pycache__
Schema:
- hostname, kind, status (required; kind/status are enums)
- model, location, cpu, cpu_cores, cpu_threads, ram_gb, storage_gb,
storage_type (enum), storage_notes, nic_gbps (all optional)
- Filename stem MUST equal hostname (enforced by generator)
- Extra optional fields are accepted silently and live on the per-page
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 21:10:58 +02:00
|
|
|
suffix = f" · {cores}c"
|
2026-05-27 10:31:46 +02:00
|
|
|
return (str(model) + suffix).strip()
|
feat(docs): MkDocs Material site + auto-generated hardware overview
Bootstraps an MkDocs Material documentation site (rendered to
docs.makerfloss.eu by the Forgejo Actions runner). The first feature
is an auto-generated hardware overview built from per-host YAML
frontmatter blocks under docs/hardware/.
- mkdocs.yml, requirements.txt: MkDocs Material 9.5 + pyyaml
- Makefile: docs-index | docs-build | docs-serve | docs-check
- scripts/gen_overview.py: stdlib + pyyaml generator, deterministic and
offline. Reads scripts/overview_config.yml — category-driven so
services/vms can plug in later without touching the script.
- scripts/overview_config.yml: hardware schema and index layout
- docs/hardware/{makerfloss,fisi,tembo}.md: 3 sample entries
- docs/hardware/index.md: GENERATED, committed (CI fails on drift)
- docs/index.md: site landing page
- .forgejo/workflows/docs.yml: drift-check + mkdocs build --strict +
rsync site/ to /srv/docs-makerfloss/html on push to main
- .gitignore: site/, .venv, __pycache__
Schema:
- hostname, kind, status (required; kind/status are enums)
- model, location, cpu, cpu_cores, cpu_threads, ram_gb, storage_gb,
storage_type (enum), storage_notes, nic_gbps (all optional)
- Filename stem MUST equal hostname (enforced by generator)
- Extra optional fields are accepted silently and live on the per-page
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 21:10:58 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def fmt_ram(fm: dict) -> str:
|
|
|
|
|
n = fm.get("ram_gb")
|
2026-05-27 10:31:46 +02:00
|
|
|
if isinstance(n, int):
|
|
|
|
|
return f"{n} GB"
|
|
|
|
|
if isinstance(n, str) and n:
|
|
|
|
|
return n
|
|
|
|
|
return ""
|
feat(docs): MkDocs Material site + auto-generated hardware overview
Bootstraps an MkDocs Material documentation site (rendered to
docs.makerfloss.eu by the Forgejo Actions runner). The first feature
is an auto-generated hardware overview built from per-host YAML
frontmatter blocks under docs/hardware/.
- mkdocs.yml, requirements.txt: MkDocs Material 9.5 + pyyaml
- Makefile: docs-index | docs-build | docs-serve | docs-check
- scripts/gen_overview.py: stdlib + pyyaml generator, deterministic and
offline. Reads scripts/overview_config.yml — category-driven so
services/vms can plug in later without touching the script.
- scripts/overview_config.yml: hardware schema and index layout
- docs/hardware/{makerfloss,fisi,tembo}.md: 3 sample entries
- docs/hardware/index.md: GENERATED, committed (CI fails on drift)
- docs/index.md: site landing page
- .forgejo/workflows/docs.yml: drift-check + mkdocs build --strict +
rsync site/ to /srv/docs-makerfloss/html on push to main
- .gitignore: site/, .venv, __pycache__
Schema:
- hostname, kind, status (required; kind/status are enums)
- model, location, cpu, cpu_cores, cpu_threads, ram_gb, storage_gb,
storage_type (enum), storage_notes, nic_gbps (all optional)
- Filename stem MUST equal hostname (enforced by generator)
- Extra optional fields are accepted silently and live on the per-page
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 21:10:58 +02:00
|
|
|
|
|
|
|
|
|
2026-05-18 15:14:46 +02:00
|
|
|
def _fmt_size_gb(n: int) -> str:
|
|
|
|
|
if n >= 1000 and n % 1000 == 0:
|
|
|
|
|
return f"{n // 1000} TB"
|
|
|
|
|
if n >= 1000:
|
|
|
|
|
return f"{n / 1000:.1f} TB"
|
|
|
|
|
return f"{n} GB"
|
|
|
|
|
|
|
|
|
|
|
feat(docs): MkDocs Material site + auto-generated hardware overview
Bootstraps an MkDocs Material documentation site (rendered to
docs.makerfloss.eu by the Forgejo Actions runner). The first feature
is an auto-generated hardware overview built from per-host YAML
frontmatter blocks under docs/hardware/.
- mkdocs.yml, requirements.txt: MkDocs Material 9.5 + pyyaml
- Makefile: docs-index | docs-build | docs-serve | docs-check
- scripts/gen_overview.py: stdlib + pyyaml generator, deterministic and
offline. Reads scripts/overview_config.yml — category-driven so
services/vms can plug in later without touching the script.
- scripts/overview_config.yml: hardware schema and index layout
- docs/hardware/{makerfloss,fisi,tembo}.md: 3 sample entries
- docs/hardware/index.md: GENERATED, committed (CI fails on drift)
- docs/index.md: site landing page
- .forgejo/workflows/docs.yml: drift-check + mkdocs build --strict +
rsync site/ to /srv/docs-makerfloss/html on push to main
- .gitignore: site/, .venv, __pycache__
Schema:
- hostname, kind, status (required; kind/status are enums)
- model, location, cpu, cpu_cores, cpu_threads, ram_gb, storage_gb,
storage_type (enum), storage_notes, nic_gbps (all optional)
- Filename stem MUST equal hostname (enforced by generator)
- Extra optional fields are accepted silently and live on the per-page
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 21:10:58 +02:00
|
|
|
def fmt_storage(fm: dict) -> str:
|
2026-05-18 15:14:46 +02:00
|
|
|
drives = fm.get("storage")
|
|
|
|
|
if isinstance(drives, list) and drives:
|
|
|
|
|
parts = []
|
|
|
|
|
for d in drives:
|
|
|
|
|
gb = d.get("gb")
|
|
|
|
|
t = (d.get("type") or "").upper()
|
|
|
|
|
if isinstance(gb, int):
|
|
|
|
|
parts.append(f"{_fmt_size_gb(gb)} {t}".strip())
|
|
|
|
|
elif t:
|
|
|
|
|
parts.append(t)
|
|
|
|
|
return " + ".join(parts)
|
2026-05-27 10:31:46 +02:00
|
|
|
if isinstance(drives, str) and drives:
|
|
|
|
|
return drives
|
2026-05-18 15:14:46 +02:00
|
|
|
|
feat(docs): MkDocs Material site + auto-generated hardware overview
Bootstraps an MkDocs Material documentation site (rendered to
docs.makerfloss.eu by the Forgejo Actions runner). The first feature
is an auto-generated hardware overview built from per-host YAML
frontmatter blocks under docs/hardware/.
- mkdocs.yml, requirements.txt: MkDocs Material 9.5 + pyyaml
- Makefile: docs-index | docs-build | docs-serve | docs-check
- scripts/gen_overview.py: stdlib + pyyaml generator, deterministic and
offline. Reads scripts/overview_config.yml — category-driven so
services/vms can plug in later without touching the script.
- scripts/overview_config.yml: hardware schema and index layout
- docs/hardware/{makerfloss,fisi,tembo}.md: 3 sample entries
- docs/hardware/index.md: GENERATED, committed (CI fails on drift)
- docs/index.md: site landing page
- .forgejo/workflows/docs.yml: drift-check + mkdocs build --strict +
rsync site/ to /srv/docs-makerfloss/html on push to main
- .gitignore: site/, .venv, __pycache__
Schema:
- hostname, kind, status (required; kind/status are enums)
- model, location, cpu, cpu_cores, cpu_threads, ram_gb, storage_gb,
storage_type (enum), storage_notes, nic_gbps (all optional)
- Filename stem MUST equal hostname (enforced by generator)
- Extra optional fields are accepted silently and live on the per-page
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 21:10:58 +02:00
|
|
|
n = fm.get("storage_gb")
|
|
|
|
|
t = fm.get("storage_type", "").upper() if fm.get("storage_type") else ""
|
|
|
|
|
if not isinstance(n, int):
|
|
|
|
|
return t # type alone if no capacity
|
2026-05-18 15:14:46 +02:00
|
|
|
return f"{_fmt_size_gb(n)} {t}".strip()
|
feat(docs): MkDocs Material site + auto-generated hardware overview
Bootstraps an MkDocs Material documentation site (rendered to
docs.makerfloss.eu by the Forgejo Actions runner). The first feature
is an auto-generated hardware overview built from per-host YAML
frontmatter blocks under docs/hardware/.
- mkdocs.yml, requirements.txt: MkDocs Material 9.5 + pyyaml
- Makefile: docs-index | docs-build | docs-serve | docs-check
- scripts/gen_overview.py: stdlib + pyyaml generator, deterministic and
offline. Reads scripts/overview_config.yml — category-driven so
services/vms can plug in later without touching the script.
- scripts/overview_config.yml: hardware schema and index layout
- docs/hardware/{makerfloss,fisi,tembo}.md: 3 sample entries
- docs/hardware/index.md: GENERATED, committed (CI fails on drift)
- docs/index.md: site landing page
- .forgejo/workflows/docs.yml: drift-check + mkdocs build --strict +
rsync site/ to /srv/docs-makerfloss/html on push to main
- .gitignore: site/, .venv, __pycache__
Schema:
- hostname, kind, status (required; kind/status are enums)
- model, location, cpu, cpu_cores, cpu_threads, ram_gb, storage_gb,
storage_type (enum), storage_notes, nic_gbps (all optional)
- Filename stem MUST equal hostname (enforced by generator)
- Extra optional fields are accepted silently and live on the per-page
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 21:10:58 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def fmt_nic(fm: dict) -> str:
|
|
|
|
|
g = fm.get("nic_gbps")
|
2026-05-27 10:31:46 +02:00
|
|
|
if g is None or g == "":
|
feat(docs): MkDocs Material site + auto-generated hardware overview
Bootstraps an MkDocs Material documentation site (rendered to
docs.makerfloss.eu by the Forgejo Actions runner). The first feature
is an auto-generated hardware overview built from per-host YAML
frontmatter blocks under docs/hardware/.
- mkdocs.yml, requirements.txt: MkDocs Material 9.5 + pyyaml
- Makefile: docs-index | docs-build | docs-serve | docs-check
- scripts/gen_overview.py: stdlib + pyyaml generator, deterministic and
offline. Reads scripts/overview_config.yml — category-driven so
services/vms can plug in later without touching the script.
- scripts/overview_config.yml: hardware schema and index layout
- docs/hardware/{makerfloss,fisi,tembo}.md: 3 sample entries
- docs/hardware/index.md: GENERATED, committed (CI fails on drift)
- docs/index.md: site landing page
- .forgejo/workflows/docs.yml: drift-check + mkdocs build --strict +
rsync site/ to /srv/docs-makerfloss/html on push to main
- .gitignore: site/, .venv, __pycache__
Schema:
- hostname, kind, status (required; kind/status are enums)
- model, location, cpu, cpu_cores, cpu_threads, ram_gb, storage_gb,
storage_type (enum), storage_notes, nic_gbps (all optional)
- Filename stem MUST equal hostname (enforced by generator)
- Extra optional fields are accepted silently and live on the per-page
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 21:10:58 +02:00
|
|
|
return ""
|
2026-05-27 10:31:46 +02:00
|
|
|
if isinstance(g, str):
|
|
|
|
|
return g
|
2026-05-18 15:14:46 +02:00
|
|
|
|
|
|
|
|
def one(v: float | int) -> str:
|
|
|
|
|
if isinstance(v, float) and not v.is_integer():
|
|
|
|
|
return f"{v}"
|
|
|
|
|
return f"{int(v)}"
|
|
|
|
|
|
|
|
|
|
if isinstance(g, list):
|
|
|
|
|
if not g:
|
|
|
|
|
return ""
|
|
|
|
|
return "/".join(one(v) for v in g) + " GbE"
|
|
|
|
|
return f"{one(g)} GbE"
|
feat(docs): MkDocs Material site + auto-generated hardware overview
Bootstraps an MkDocs Material documentation site (rendered to
docs.makerfloss.eu by the Forgejo Actions runner). The first feature
is an auto-generated hardware overview built from per-host YAML
frontmatter blocks under docs/hardware/.
- mkdocs.yml, requirements.txt: MkDocs Material 9.5 + pyyaml
- Makefile: docs-index | docs-build | docs-serve | docs-check
- scripts/gen_overview.py: stdlib + pyyaml generator, deterministic and
offline. Reads scripts/overview_config.yml — category-driven so
services/vms can plug in later without touching the script.
- scripts/overview_config.yml: hardware schema and index layout
- docs/hardware/{makerfloss,fisi,tembo}.md: 3 sample entries
- docs/hardware/index.md: GENERATED, committed (CI fails on drift)
- docs/index.md: site landing page
- .forgejo/workflows/docs.yml: drift-check + mkdocs build --strict +
rsync site/ to /srv/docs-makerfloss/html on push to main
- .gitignore: site/, .venv, __pycache__
Schema:
- hostname, kind, status (required; kind/status are enums)
- model, location, cpu, cpu_cores, cpu_threads, ram_gb, storage_gb,
storage_type (enum), storage_notes, nic_gbps (all optional)
- Filename stem MUST equal hostname (enforced by generator)
- Extra optional fields are accepted silently and live on the per-page
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 21:10:58 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def cell(fm: dict, col: dict) -> str:
|
|
|
|
|
kind = col.get("kind")
|
feat(docs): add services category alongside hardware
Mirror the auto-indexed per-host pattern for a new docs/services/
category, seeded with the six things currently deployed on or around
makerfloss.eu: docs, slides, forgejo, gandi-dns, marp, mermaid.
Generator/hook generalisation:
- scripts/gen_overview.py: replace the hardcoded `hostname` check
with a configurable `key_field` (default: hostname). Add a generic
`key-link` column kind (replaces the old `hostname-link`) and a
`url-link` kind that renders the value as a clickable link.
- scripts/overview_config.yml: declare hardware's key_field, then add
a `services` block (key_field=name, its own kind/status enums,
grouped by kind for the index table).
- scripts/mkdocs_hooks.py: route by `page.file.src_uri` so each
hardware/* page gets a "Specs" table and each services/* page gets
a "Service" table; both share the helpers in gen_overview.
Wiring:
- Makefile: docs-index and docs-check now regenerate and drift-check
both indices.
- .forgejo/workflows/docs.yml: same on the CI runner.
- mkdocs.yml: add Services to nav.
- README.md, CLAUDE.md: list services/ in the repo-layout block.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 17:48:15 +02:00
|
|
|
if kind == "key-link":
|
|
|
|
|
v = fm[col["field"]]
|
|
|
|
|
return f"[{v}]({v}.md)"
|
|
|
|
|
if kind == "url-link":
|
|
|
|
|
u = fm.get(col["field"], "")
|
|
|
|
|
if not u:
|
|
|
|
|
return ""
|
|
|
|
|
label = u.removeprefix("https://").removeprefix("http://")
|
|
|
|
|
return f"[{label}]({u})"
|
feat(docs): MkDocs Material site + auto-generated hardware overview
Bootstraps an MkDocs Material documentation site (rendered to
docs.makerfloss.eu by the Forgejo Actions runner). The first feature
is an auto-generated hardware overview built from per-host YAML
frontmatter blocks under docs/hardware/.
- mkdocs.yml, requirements.txt: MkDocs Material 9.5 + pyyaml
- Makefile: docs-index | docs-build | docs-serve | docs-check
- scripts/gen_overview.py: stdlib + pyyaml generator, deterministic and
offline. Reads scripts/overview_config.yml — category-driven so
services/vms can plug in later without touching the script.
- scripts/overview_config.yml: hardware schema and index layout
- docs/hardware/{makerfloss,fisi,tembo}.md: 3 sample entries
- docs/hardware/index.md: GENERATED, committed (CI fails on drift)
- docs/index.md: site landing page
- .forgejo/workflows/docs.yml: drift-check + mkdocs build --strict +
rsync site/ to /srv/docs-makerfloss/html on push to main
- .gitignore: site/, .venv, __pycache__
Schema:
- hostname, kind, status (required; kind/status are enums)
- model, location, cpu, cpu_cores, cpu_threads, ram_gb, storage_gb,
storage_type (enum), storage_notes, nic_gbps (all optional)
- Filename stem MUST equal hostname (enforced by generator)
- Extra optional fields are accepted silently and live on the per-page
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 21:10:58 +02:00
|
|
|
if kind == "cpu":
|
|
|
|
|
return fmt_cpu(fm)
|
|
|
|
|
if kind == "ram":
|
|
|
|
|
return fmt_ram(fm)
|
|
|
|
|
if kind == "storage":
|
|
|
|
|
return fmt_storage(fm)
|
|
|
|
|
if kind == "nic":
|
|
|
|
|
return fmt_nic(fm)
|
|
|
|
|
value = fm.get(col["field"], "")
|
|
|
|
|
return "" if value is None else str(value)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def render(cfg: dict, items: list[dict]) -> str:
|
|
|
|
|
columns = cfg["columns"]
|
|
|
|
|
group_by = cfg.get("group_by")
|
|
|
|
|
sort_by = cfg.get("sort_by", "hostname")
|
|
|
|
|
group_titles = cfg.get("group_titles", {})
|
|
|
|
|
|
|
|
|
|
if group_by:
|
|
|
|
|
groups: dict[str, list[dict]] = {}
|
|
|
|
|
for fm in items:
|
|
|
|
|
groups.setdefault(fm.get(group_by, ""), []).append(fm)
|
|
|
|
|
ordered = sorted(groups.items())
|
|
|
|
|
else:
|
|
|
|
|
ordered = [("", items)]
|
|
|
|
|
|
|
|
|
|
lines: list[str] = []
|
|
|
|
|
lines.append(f"# {cfg['title']}")
|
|
|
|
|
lines.append("")
|
|
|
|
|
lines.append(
|
|
|
|
|
f"_Auto-generated from `{cfg['source_dir']}/*.md` — do not edit by hand. "
|
|
|
|
|
f"Run `make docs-index` after changing a file._"
|
|
|
|
|
)
|
|
|
|
|
lines.append("")
|
|
|
|
|
|
|
|
|
|
for group_key, rows in ordered:
|
|
|
|
|
rows.sort(key=lambda r: r.get(sort_by, ""))
|
|
|
|
|
if group_by:
|
|
|
|
|
title = group_titles.get(group_key, group_key.title() + "s")
|
|
|
|
|
lines.append(f"## {title}")
|
|
|
|
|
lines.append("")
|
|
|
|
|
header = "| " + " | ".join(c["header"] for c in columns) + " |"
|
|
|
|
|
sep = "|" + "|".join("---" for _ in columns) + "|"
|
|
|
|
|
lines.append(header)
|
|
|
|
|
lines.append(sep)
|
|
|
|
|
for fm in rows:
|
|
|
|
|
lines.append("| " + " | ".join(cell(fm, c) for c in columns) + " |")
|
|
|
|
|
lines.append("")
|
|
|
|
|
|
|
|
|
|
return "\n".join(lines).rstrip() + "\n"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main() -> int:
|
|
|
|
|
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
|
|
|
|
parser.add_argument("--category", required=True, help="Category key from overview_config.yml")
|
|
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
|
|
|
|
config_all = yaml.safe_load(CONFIG_PATH.read_text(encoding="utf-8"))
|
|
|
|
|
if args.category not in config_all:
|
|
|
|
|
print(f"ERROR: category {args.category!r} not in {CONFIG_PATH}", file=sys.stderr)
|
|
|
|
|
return 2
|
|
|
|
|
cfg = config_all[args.category]
|
|
|
|
|
|
|
|
|
|
source_dir = REPO_ROOT / cfg["source_dir"]
|
|
|
|
|
output_file = REPO_ROOT / cfg["output_file"]
|
|
|
|
|
output_abs = output_file.resolve()
|
|
|
|
|
|
|
|
|
|
items: list[dict] = []
|
|
|
|
|
errors: list[str] = []
|
|
|
|
|
for path in sorted(source_dir.glob("*.md")):
|
|
|
|
|
if path.resolve() == output_abs:
|
|
|
|
|
continue
|
|
|
|
|
try:
|
|
|
|
|
fm = parse_frontmatter(path)
|
|
|
|
|
except SchemaError as e:
|
|
|
|
|
errors.append(str(e))
|
|
|
|
|
continue
|
|
|
|
|
if fm is None:
|
2026-06-30 21:31:48 +02:00
|
|
|
print(
|
|
|
|
|
f"WARNING: {path.name}: no '---' frontmatter block — skipping "
|
|
|
|
|
f"(it will not appear in the {args.category} index).",
|
|
|
|
|
file=sys.stderr,
|
|
|
|
|
)
|
feat(docs): MkDocs Material site + auto-generated hardware overview
Bootstraps an MkDocs Material documentation site (rendered to
docs.makerfloss.eu by the Forgejo Actions runner). The first feature
is an auto-generated hardware overview built from per-host YAML
frontmatter blocks under docs/hardware/.
- mkdocs.yml, requirements.txt: MkDocs Material 9.5 + pyyaml
- Makefile: docs-index | docs-build | docs-serve | docs-check
- scripts/gen_overview.py: stdlib + pyyaml generator, deterministic and
offline. Reads scripts/overview_config.yml — category-driven so
services/vms can plug in later without touching the script.
- scripts/overview_config.yml: hardware schema and index layout
- docs/hardware/{makerfloss,fisi,tembo}.md: 3 sample entries
- docs/hardware/index.md: GENERATED, committed (CI fails on drift)
- docs/index.md: site landing page
- .forgejo/workflows/docs.yml: drift-check + mkdocs build --strict +
rsync site/ to /srv/docs-makerfloss/html on push to main
- .gitignore: site/, .venv, __pycache__
Schema:
- hostname, kind, status (required; kind/status are enums)
- model, location, cpu, cpu_cores, cpu_threads, ram_gb, storage_gb,
storage_type (enum), storage_notes, nic_gbps (all optional)
- Filename stem MUST equal hostname (enforced by generator)
- Extra optional fields are accepted silently and live on the per-page
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 21:10:58 +02:00
|
|
|
continue
|
|
|
|
|
try:
|
|
|
|
|
validate(path, fm, cfg)
|
|
|
|
|
except SchemaError as e:
|
|
|
|
|
errors.append(str(e))
|
|
|
|
|
continue
|
|
|
|
|
items.append(fm)
|
|
|
|
|
|
|
|
|
|
if errors:
|
2026-06-30 21:31:48 +02:00
|
|
|
report_errors(errors, args.category)
|
feat(docs): MkDocs Material site + auto-generated hardware overview
Bootstraps an MkDocs Material documentation site (rendered to
docs.makerfloss.eu by the Forgejo Actions runner). The first feature
is an auto-generated hardware overview built from per-host YAML
frontmatter blocks under docs/hardware/.
- mkdocs.yml, requirements.txt: MkDocs Material 9.5 + pyyaml
- Makefile: docs-index | docs-build | docs-serve | docs-check
- scripts/gen_overview.py: stdlib + pyyaml generator, deterministic and
offline. Reads scripts/overview_config.yml — category-driven so
services/vms can plug in later without touching the script.
- scripts/overview_config.yml: hardware schema and index layout
- docs/hardware/{makerfloss,fisi,tembo}.md: 3 sample entries
- docs/hardware/index.md: GENERATED, committed (CI fails on drift)
- docs/index.md: site landing page
- .forgejo/workflows/docs.yml: drift-check + mkdocs build --strict +
rsync site/ to /srv/docs-makerfloss/html on push to main
- .gitignore: site/, .venv, __pycache__
Schema:
- hostname, kind, status (required; kind/status are enums)
- model, location, cpu, cpu_cores, cpu_threads, ram_gb, storage_gb,
storage_type (enum), storage_notes, nic_gbps (all optional)
- Filename stem MUST equal hostname (enforced by generator)
- Extra optional fields are accepted silently and live on the per-page
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 21:10:58 +02:00
|
|
|
return 1
|
|
|
|
|
|
|
|
|
|
output_file.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
tmp = output_file.with_suffix(output_file.suffix + ".tmp")
|
|
|
|
|
tmp.write_text(render(cfg, items), encoding="utf-8")
|
|
|
|
|
tmp.replace(output_file)
|
|
|
|
|
print(f"Wrote {output_file.relative_to(REPO_ROOT)} ({len(items)} item(s))")
|
|
|
|
|
return 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
sys.exit(main())
|