From 92fd17689c9e288b3ec30db5088d31e296c83a32 Mon Sep 17 00:00:00 2001 From: mihailkudravcev Date: Thu, 23 Jul 2026 14:58:58 +0300 Subject: [PATCH] Fix Gitea wiki filenames: use percent-encoded Cyrillic slugs. Unicode names caused HTTP 500 in the wiki UI; match Gitea storage format. --- README.md | 2 +- export1c_help/naming.py | 41 ++++++++++++++++++++--------------------- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 54df93f..7b890bf 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ python3 export_1c_help.py --version |------|------------| | `Home.md` | оглавление по типам метаданных | | `_Sidebar.md` | боковая навигация (объекты без форм) | -| `«Заголовок».md` / `%D0%….md` | страницы справки (кириллица — percent-encoded, как в Gitea) | +| `«Заголовок».md` / `%D0%….md` | страницы справки (кириллица в git — **percent-encoded**, как хранит Gitea) | | `manifest.json` | карта `meta_key` → title / filename | | Параметр | Описание | diff --git a/export1c_help/naming.py b/export1c_help/naming.py index 20d684d..aff835e 100644 --- a/export1c_help/naming.py +++ b/export1c_help/naming.py @@ -10,7 +10,8 @@ from export1c_help.discover import HelpPage _INVALID = re.compile(r'[\\/:*?"<>|#\[\]]+') _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: @@ -38,17 +39,21 @@ def _short_hash(s: str) -> str: def wiki_filename(title: str, *, meta_key: str | None = None) -> str: - """Unicode wiki slug (spaces → «-»).""" - slug = sanitize_title(title).replace(" ", "-") - # reserve room for optional -xxxxxxxx suffix - slug = _truncate_utf8(slug, _MAX_NAME_BYTES) - return f"{slug}.md" + """ + Gitea wiki stores non-ASCII page names as percent-encoded «Slug.md». - -def wiki_filename_gitea_legacy(title: str) -> str: + Slug = title with spaces → «-», truncated so encoded length ≤ 255. + """ slug = sanitize_title(title).replace(" ", "-") - slug = _truncate_utf8(slug, 80) - return quote(slug, safe="-_.") + ".md" + slug = _truncate_utf8(slug, _MAX_SLUG_BYTES) + 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: @@ -60,11 +65,7 @@ def assign_titles( pages: list[HelpPage], h1_by_meta: dict[str, str | None], ) -> tuple[dict[str, str], dict[str, str]]: - """ - Returns (meta_key → title, meta_key → filename). - - Filenames are unique even after UTF-8 truncation. - """ + """Returns (meta_key → title, meta_key → filename).""" used_title: set[str] = set() used_file: set[str] = set() titles: dict[str, str] = {} @@ -87,15 +88,13 @@ def assign_titles( title = sanitize_title(p.meta_key) break - fname = wiki_filename(title) + fname = wiki_filename(title, meta_key=p.meta_key) if fname.casefold() in used_file: - stem = fname[:-3] - stem = _truncate_utf8(stem, _MAX_NAME_BYTES - 9) - fname = f"{stem}-{_short_hash(p.meta_key)}.md" - # last-resort unique + slug = _truncate_utf8(sanitize_title(title).replace(" ", "-"), 50) + fname = quote(f"{slug}-{_short_hash(p.meta_key)}", safe="-_.") + ".md" guard = 0 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 used_title.add(title.casefold())