Fix Windows MAX_PATH failures for percent-encoded wiki filenames.

Cap encoded slug length and use \\?\ long-path writes (0.3.6).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
mihailkudravcev
2026-07-24 10:55:31 +03:00
parent d91c454099
commit dc8be1bd1a
6 changed files with 106 additions and 49 deletions
+26 -28
View File
@@ -10,8 +10,9 @@ from export1c_help.discover import HelpPage
_INVALID = re.compile(r'[\\/:*?"<>|#\[\]]+')
_SPACES = re.compile(r"\s+")
# Keep slug short so percent-encoded form fits in 255-byte FS names
_MAX_SLUG_BYTES = 72
# Encoded «Slug.md» must leave room under Windows MAX_PATH (~260) for deep
# project roots (e.g. D:\SynologyDrive\projects_syn\…\out\).
_MAX_ENCODED_FILENAME = 100
def sanitize_title(title: str) -> str:
@@ -21,39 +22,34 @@ def sanitize_title(title: str) -> str:
return title or "untitled"
def _truncate_utf8(s: str, max_bytes: int) -> str:
raw = s.encode("utf-8")
if len(raw) <= max_bytes:
return s
raw = raw[:max_bytes]
while raw:
try:
return raw.decode("utf-8").rstrip("- ")
except UnicodeDecodeError:
raw = raw[:-1]
return "page"
def _short_hash(s: str) -> str:
return hashlib.sha1(s.encode("utf-8")).hexdigest()[:8]
def _encoded_filename(slug: str) -> str:
return quote(slug, safe="-_.") + ".md"
def wiki_filename(title: str, *, meta_key: str | None = None) -> str:
"""
Gitea wiki stores non-ASCII page names as percent-encoded «Slug.md».
Slug = title with spaces → «-», truncated so encoded length ≤ 255.
Encoded length is capped so typical Windows project paths still fit
under MAX_PATH; when truncated, a short hash of meta_key (or title)
is appended for stability.
"""
slug = sanitize_title(title).replace(" ", "-")
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
encoded = _encoded_filename(slug)
if len(encoded) <= _MAX_ENCODED_FILENAME:
return encoded
suffix = "-" + _short_hash(meta_key or title)
# ASCII suffix: encoded length == visible length
budget = _MAX_ENCODED_FILENAME - len(suffix) - 3 # ".md"
while slug and len(quote(slug, safe="-_.")) > budget:
slug = slug[:-1]
slug = slug.rstrip("-") or "page"
return quote(slug, safe="-_.") + suffix + ".md"
def decode_wiki_filename(name: str) -> str:
@@ -90,11 +86,13 @@ def assign_titles(
fname = wiki_filename(title, meta_key=p.meta_key)
if fname.casefold() in used_file:
slug = _truncate_utf8(sanitize_title(title).replace(" ", "-"), 50)
fname = quote(f"{slug}-{_short_hash(p.meta_key)}", safe="-_.") + ".md"
fname = wiki_filename(
f"{title}-{_short_hash(p.meta_key)}",
meta_key=p.meta_key,
)
guard = 0
while fname.casefold() in used_file:
fname = quote(f"page-{_short_hash(p.meta_key + str(guard))}", safe="-_.") + ".md"
fname = _encoded_filename(f"page-{_short_hash(p.meta_key + str(guard))}")
guard += 1
used_title.add(title.casefold())