Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

doc: Fix cool URIs #667

Merged
merged 1 commit into from
Feb 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions doc/cool-uris.yaml
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
# WARNING: This file is autogenerated by: scripts/ensure-stable-doc-urls.py
# Do not edit manually.
__optional__:
- doxygen_crawl.html
- meson_options.html
annotated.html: []
classes.html: []
debugging.html: []
deprecated.html: []
dir_63ce773eee1f9b680e6e312b48cc99ca.html: []
dir_891596f32582d3133e8915e72908625f.html: []
dir_d44c64559bbebec7f509842c48db8b23.html: []
dir_e68e8157741866f444e17edd764ebbae.html: []
doxygen_crawl.html: []
error-index.html: []
files.html: []
functions.html: []
Expand All @@ -33,8 +38,9 @@ group__x11.html: []
index.html: []
keymap-text-format-v1.html:
- md_doc_keymap_format_text_v1.html
md_doc_quick_guide.html: []
modules.html: []
md_doc_2quick-guide.html:
- md_doc_quick_guide.html
meson_options.html: []
pages.html: []
rule-file-format.html:
- md_doc_rules_format.html
Expand All @@ -54,6 +60,8 @@ structxkb__keymap.html: []
structxkb__rule__names.html: []
structxkb__state.html: []
todo.html: []
topics.html:
- modules.html
user-configuration.html:
- md_doc_user_configuration.html
xkb-intro.html: []
Expand Down
111 changes: 89 additions & 22 deletions scripts/ensure-stable-doc-urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,15 @@ class ExitCode(IntFlag):
NORMAL = 0
INVALID_UPDATES = 1 << 4
MISSING_UPDATES = 1 << 5
NON_UNIQUE_DIRECTIONS = 1 << 6


THIS_SCRIPT_PATH = Path(__file__)
RELATIVE_SCRIPT_PATH = THIS_SCRIPT_PATH.relative_to(THIS_SCRIPT_PATH.parent.parent)

REDIRECTION_DELAY = 6 # in seconds. Note: at least 6s for accessibility
REDIRECTION_TITLE = "xkbcommon: Page Redirection"
OPTIONAL_ENTRY = "__optional__"

# NOTE: The redirection works with the HTML tag: <meta http-equiv="refresh">.
# See: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta#http-equiv
Expand All @@ -50,7 +53,7 @@ class ExitCode(IntFlag):
<meta http-equiv="refresh" content="${delay}; url=${canonical}">
<link href="doxygen.css" rel="stylesheet" type="text/css">
<link href="doxygen-extra.css" rel="stylesheet" type="text/css">
<title>xkbcommon: Page Redirection</title>
<title>${title}</title>
</head>
<body>
<div id="top">
Expand Down Expand Up @@ -87,6 +90,14 @@ def parse_page_update(update: str) -> Update:
return updateʹ


def is_page_redirection(path: Path):
with path.open("rt", encoding="utf-8") as fd:
for line in fd:
if REDIRECTION_TITLE in line:
return True
return False


def update_registry(registry_path: Path, doc_dir: Path, updates: Sequence[str]):
"""
Update the URL registry by:
Expand All @@ -95,21 +106,35 @@ def update_registry(registry_path: Path, doc_dir: Path, updates: Sequence[str]):
"""
# Parse updates
updates_ = dict(map(parse_page_update, updates))
# Update
invalid_updates = set(updates_)
# Load previous registry
with registry_path.open("rt", encoding="utf-8") as fd:
registry = yaml.safe_load(fd) or {}
registry: dict[str, list[str]] = yaml.safe_load(fd) or {}
registryʹ = dict(
(canonical, aliases)
for canonical, aliases in registry.items()
if canonical != OPTIONAL_ENTRY
)
# Expected updates
missing_updates = set(file for file in registry if not (doc_dir / file).is_file())
# Update
invalid_updates = set(updates_)
redirections = frozenset(chain(*registry.values()))
missing_updates = set(
canonical for canonical in registryʹ if not (doc_dir / canonical).is_file()
)
# Ensure each page is unique
for d, rs in registryʹ.items():
if clashes := frozenset(rs).intersection(registry):
print(
f"[ERROR] The following redirections of “{d}”",
f"clash with canonical directions: {clashes}",
)
exit(ExitCode.NON_UNIQUE_DIRECTIONS)
redirections = frozenset(chain.from_iterable(registryʹ.values()))
for file in glob.iglob("**/*.html", root_dir=doc_dir, recursive=True):
# Skip redirection pages
if file in redirections:
continue
# Get previous entry and potential update
old = updates_.get(file)
if old:
if old := updates_.get(file):
# Update old entry
invalid_updates.remove(file)
entry = registry.get(old)
Expand Down Expand Up @@ -137,19 +162,36 @@ def update_registry(registry_path: Path, doc_dir: Path, updates: Sequence[str]):
exit_code |= ExitCode.INVALID_UPDATES
if missing_updates:
for old in missing_updates:
print(f"[ERROR] “{old}” not found and has no update.")
exit_code |= ExitCode.MISSING_UPDATES
# Handle older Doxygen versions
if old in registry.get(OPTIONAL_ENTRY, []):
print(
"[WARNING] Handling old Doxygen version:",
f"skip optional “{old}”",
)
missing_updates.remove(old)
continue
old_redirections = registry[old]
for r in old_redirections:
path = doc_dir / r
if path.is_file() and not is_page_redirection(path):
print(
"[WARNING] Handling old Doxygen version:",
f"use “{r}” instead of “{old}” for the canonical direction",
)
missing_updates.remove(old)
break
else:
print(f"[ERROR] “{old}” not found and has no update.")
if missing_updates:
exit_code |= ExitCode.MISSING_UPDATES
if exit_code:
print("[ERROR] Processing interrupted: please fix the errors above.")
exit(exit_code.value)
# Write changes
with registry_path.open("wt", encoding="utf-8") as fd:
fd.write(f"# WARNING: This file is autogenerated by: {RELATIVE_SCRIPT_PATH}\n")
fd.write("# Do not edit manually.\n")
yaml.dump(
registry,
fd,
)
yaml.dump(registry, fd)


def generate_redirections(registry_path: Path, doc_dir: Path):
Expand All @@ -159,22 +201,47 @@ def generate_redirections(registry_path: Path, doc_dir: Path):
cool = True
# Load registry
with registry_path.open("rt", encoding="utf-8") as fd:
registry = yaml.safe_load(fd) or {}
for canonical, aliases in registry.items():
registry: dict[str, list[str]] = yaml.safe_load(fd) or {}
registryʹ = dict(
(canonical, aliases)
for canonical, aliases in registry.items()
if canonical != OPTIONAL_ENTRY
)
for canonical, aliases in registryʹ.items():
# Check canonical path is up-to-date
if not (doc_dir / canonical).is_file():
cool = False
print(
f"ERROR: missing canonical documentation page “{canonical}”. "
f"Please update “{registry_path}” using {RELATIVE_SCRIPT_PATH}”."
)
# Handle older Doxygen versions
if canonical in registry.get(OPTIONAL_ENTRY, []):
print(
"[WARNING] Handling old Doxygen version:",
f"skip optional “{canonical}”",
)
continue
for r in aliases:
path = doc_dir / r
if path.is_file() and not is_page_redirection(path):
print(
"[WARNING] Handling old Doxygen version:",
f"use “{r}” instead of “{canonical}” for the canonical direction",
)
canonical = r
aliases.remove(r)
break
else:
cool = False
print(
f"ERROR: missing canonical documentation page “{canonical}”. "
f"Please update “{registry_path}” using {RELATIVE_SCRIPT_PATH}”."
)
# Add a redirection page
for alias in aliases:
path = doc_dir / alias
with path.open("wt", encoding="utf-8") as fd:
fd.write(
REDIRECTION_PAGE_TEMPLATE.substitute(
canonical=canonical, delay=REDIRECTION_DELAY
canonical=canonical,
delay=REDIRECTION_DELAY,
title=REDIRECTION_TITLE,
)
)
if not cool:
Expand Down
Loading