Fix Gitea wiki filenames: use percent-encoded Cyrillic slugs.

Unicode names caused HTTP 500 in the wiki UI; match Gitea storage format.
This commit is contained in:
mihailkudravcev
2026-07-23 14:58:58 +03:00
parent aec0407b87
commit 92fd17689c
2 changed files with 21 additions and 22 deletions
+1 -1
View File
@@ -45,7 +45,7 @@ python3 export_1c_help.py --version
|------|------------| |------|------------|
| `Home.md` | оглавление по типам метаданных | | `Home.md` | оглавление по типам метаданных |
| `_Sidebar.md` | боковая навигация (объекты без форм) | | `_Sidebar.md` | боковая навигация (объекты без форм) |
| `«Заголовок».md` / `%D0%….md` | страницы справки (кириллица percent-encoded, как в Gitea) | | `«Заголовок».md` / `%D0%….md` | страницы справки (кириллица в git — **percent-encoded**, как хранит Gitea) |
| `manifest.json` | карта `meta_key` → title / filename | | `manifest.json` | карта `meta_key` → title / filename |
| Параметр | Описание | | Параметр | Описание |
+20 -21
View File
@@ -10,7 +10,8 @@ from export1c_help.discover import HelpPage
_INVALID = re.compile(r'[\\/:*?"<>|#\[\]]+') _INVALID = re.compile(r'[\\/:*?"<>|#\[\]]+')
_SPACES = re.compile(r"\s+") _SPACES = re.compile(r"\s+")
_MAX_NAME_BYTES = 180 # Keep slug short so percent-encoded form fits in 255-byte FS names
_MAX_SLUG_BYTES = 72
def sanitize_title(title: str) -> str: def sanitize_title(title: str) -> str:
@@ -38,17 +39,21 @@ def _short_hash(s: str) -> str:
def wiki_filename(title: str, *, meta_key: str | None = None) -> str: def wiki_filename(title: str, *, meta_key: str | None = None) -> str:
"""Unicode wiki slug (spaces → «-»).""" """
slug = sanitize_title(title).replace(" ", "-") Gitea wiki stores non-ASCII page names as percent-encoded «Slug.md».
# reserve room for optional -xxxxxxxx suffix
slug = _truncate_utf8(slug, _MAX_NAME_BYTES)
return f"{slug}.md"
Slug = title with spaces → «-», truncated so encoded length ≤ 255.
def wiki_filename_gitea_legacy(title: str) -> str: """
slug = sanitize_title(title).replace(" ", "-") slug = sanitize_title(title).replace(" ", "-")
slug = _truncate_utf8(slug, 80) slug = _truncate_utf8(slug, _MAX_SLUG_BYTES)
return quote(slug, safe="-_.") + ".md" if meta_key:
# stable disambiguator when truncated
pass
encoded = quote(slug, safe="-_.") + ".md"
if len(encoded) > 255 and meta_key:
slug = _truncate_utf8(slug, 50) + "-" + _short_hash(meta_key)
encoded = quote(slug, safe="-_.") + ".md"
return encoded
def decode_wiki_filename(name: str) -> str: def decode_wiki_filename(name: str) -> str:
@@ -60,11 +65,7 @@ def assign_titles(
pages: list[HelpPage], pages: list[HelpPage],
h1_by_meta: dict[str, str | None], h1_by_meta: dict[str, str | None],
) -> tuple[dict[str, str], dict[str, str]]: ) -> tuple[dict[str, str], dict[str, str]]:
""" """Returns (meta_key → title, meta_key → filename)."""
Returns (meta_key → title, meta_key → filename).
Filenames are unique even after UTF-8 truncation.
"""
used_title: set[str] = set() used_title: set[str] = set()
used_file: set[str] = set() used_file: set[str] = set()
titles: dict[str, str] = {} titles: dict[str, str] = {}
@@ -87,15 +88,13 @@ def assign_titles(
title = sanitize_title(p.meta_key) title = sanitize_title(p.meta_key)
break break
fname = wiki_filename(title) fname = wiki_filename(title, meta_key=p.meta_key)
if fname.casefold() in used_file: if fname.casefold() in used_file:
stem = fname[:-3] slug = _truncate_utf8(sanitize_title(title).replace(" ", "-"), 50)
stem = _truncate_utf8(stem, _MAX_NAME_BYTES - 9) fname = quote(f"{slug}-{_short_hash(p.meta_key)}", safe="-_.") + ".md"
fname = f"{stem}-{_short_hash(p.meta_key)}.md"
# last-resort unique
guard = 0 guard = 0
while fname.casefold() in used_file: while fname.casefold() in used_file:
fname = f"page-{_short_hash(p.meta_key + str(guard))}.md" fname = quote(f"page-{_short_hash(p.meta_key + str(guard))}", safe="-_.") + ".md"
guard += 1 guard += 1
used_title.add(title.casefold()) used_title.add(title.casefold())