mirror of
https://github.com/nix-community/home-manager.git
synced 2026-10-02 19:49:18 +00:00
Drops the URL fragment from links that address a `programs.foo` or `services.foo` page. Such a path names a module rather than an option, so the page carries no matching anchor and the fragment pointed nowhere. Option paths keep their fragment, including the single-segment options `lib`, `specialisation` and `uninstall`, whose name equals their page path. Moves the anchor handling that convert-markup.py and render-options.py had in common into a new option_links module imported by both. The derivations therefore pass the mdbook directory instead of a single script file, so the import resolves.
190 lines
5.3 KiB
Python
190 lines
5.3 KiB
Python
#!/usr/bin/env python3
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
from option_links import (
|
|
OPTION_HREF,
|
|
OPTION_LINK,
|
|
option_label,
|
|
option_page_parts,
|
|
option_target,
|
|
)
|
|
|
|
|
|
def rewrite_option_links(text: str, current_file: Path) -> str:
|
|
text = OPTION_LINK.sub(
|
|
lambda match: (
|
|
f"[{match.group('label') or option_label(match.group('anchor'))}]"
|
|
f"({option_target(match.group('anchor'), current_file)})"
|
|
),
|
|
text,
|
|
)
|
|
return OPTION_HREF.sub(
|
|
lambda match: f'href="{option_target(match.group("anchor"), current_file)}"',
|
|
text,
|
|
)
|
|
|
|
|
|
def namespace_for(option_name: str) -> str:
|
|
return option_name.split(".", 1)[0]
|
|
|
|
|
|
def option_group_for(option_name: str) -> str:
|
|
return "/".join(option_page_parts(option_name))
|
|
|
|
|
|
def render_namespace(
|
|
options: dict[str, object],
|
|
destination: Path,
|
|
manpage_urls: Path,
|
|
revision: str,
|
|
anchor_prefix: str,
|
|
current_file: Path,
|
|
) -> None:
|
|
destination.parent.mkdir(parents=True, exist_ok=True)
|
|
source = destination.with_suffix(".json")
|
|
source.write_text(json.dumps(options, sort_keys=True), encoding="utf-8")
|
|
|
|
subprocess.run(
|
|
[
|
|
"nixos-render-docs",
|
|
"options",
|
|
"commonmark",
|
|
"--manpage-urls",
|
|
str(manpage_urls),
|
|
"--revision",
|
|
revision,
|
|
"--anchor-style",
|
|
"legacy",
|
|
"--anchor-prefix",
|
|
anchor_prefix,
|
|
str(source),
|
|
str(destination),
|
|
],
|
|
check=True,
|
|
)
|
|
source.unlink()
|
|
destination.write_text(
|
|
rewrite_option_links(destination.read_text(encoding="utf-8"), current_file),
|
|
encoding="utf-8",
|
|
)
|
|
|
|
|
|
def write_doc(
|
|
name: str,
|
|
doc: dict[str, str],
|
|
manpage_urls: Path,
|
|
revision: str,
|
|
output: Path,
|
|
) -> None:
|
|
options_json = Path(doc["json"]) / "share/doc/nixos/options.json"
|
|
options = json.loads(options_json.read_text(encoding="utf-8"))
|
|
|
|
grouped: dict[str, dict[str, object]] = {}
|
|
for option_name, option in options.items():
|
|
group = option_group_for(option_name)
|
|
grouped.setdefault(group, {})[option_name] = option
|
|
|
|
doc_dir = output / "options" / doc["path"]
|
|
doc_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
groups = sorted(grouped)
|
|
namespaces = sorted({group.split("/", 1)[0] for group in groups})
|
|
nested = {
|
|
namespace: sorted(
|
|
group for group in groups if group.startswith(f"{namespace}/")
|
|
)
|
|
for namespace in namespaces
|
|
}
|
|
index = [
|
|
f"# {doc['title']}\n",
|
|
"\n",
|
|
"Generated from Home Manager option definitions.\n",
|
|
"\n",
|
|
"## Namespaces\n",
|
|
"\n",
|
|
]
|
|
for namespace in namespaces:
|
|
if nested[namespace]:
|
|
index.append(f"- [{namespace}]({namespace}/index.md)\n")
|
|
else:
|
|
index.append(f"- [{namespace}]({namespace}.md)\n")
|
|
(doc_dir / "index.md").write_text("".join(index), encoding="utf-8")
|
|
|
|
summary_dir = output / "summary"
|
|
summary_dir.mkdir(parents=True, exist_ok=True)
|
|
summary = [f" - [{doc['title']}](options/{doc['path']}/index.md)\n"]
|
|
|
|
for namespace in namespaces:
|
|
if nested[namespace]:
|
|
namespace_index = doc_dir / namespace / "index.md"
|
|
namespace_index.parent.mkdir(parents=True, exist_ok=True)
|
|
namespace_index.write_text(
|
|
"".join(
|
|
[
|
|
f"# {namespace}\n",
|
|
"\n",
|
|
"## Modules\n",
|
|
"\n",
|
|
*(
|
|
f"- [{group.split('/', 1)[1]}]({group.split('/', 1)[1]}.md)\n"
|
|
for group in nested[namespace]
|
|
),
|
|
]
|
|
),
|
|
encoding="utf-8",
|
|
)
|
|
summary.append(
|
|
f" - [{namespace}](options/{doc['path']}/{namespace}/index.md)\n"
|
|
)
|
|
for group in nested[namespace]:
|
|
module_name = group.split("/", 1)[1]
|
|
summary.append(
|
|
f" - [{module_name}](options/{doc['path']}/{namespace}/{module_name}.md)\n"
|
|
)
|
|
else:
|
|
summary.append(
|
|
f" - [{namespace}](options/{doc['path']}/{namespace}.md)\n"
|
|
)
|
|
|
|
for group in groups:
|
|
page = doc_dir / f"{group}.md"
|
|
current_file = Path("options") / doc["path"] / f"{group}.md"
|
|
render_namespace(
|
|
grouped[group],
|
|
page,
|
|
manpage_urls,
|
|
revision,
|
|
doc["prefix"],
|
|
current_file,
|
|
)
|
|
|
|
(summary_dir / f"{name}.md").write_text("".join(summary), encoding="utf-8")
|
|
|
|
|
|
def main() -> int:
|
|
if len(sys.argv) != 5:
|
|
print(
|
|
"usage: render-options.py OPTION_DOCS MANPAGE_URLS REVISION OUT",
|
|
file=sys.stderr,
|
|
)
|
|
return 1
|
|
|
|
option_docs = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8"))
|
|
manpage_urls = Path(sys.argv[2])
|
|
revision = sys.argv[3]
|
|
output = Path(sys.argv[4])
|
|
|
|
for name, doc in option_docs.items():
|
|
write_doc(name, doc, manpage_urls, revision, output)
|
|
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|