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:
+26
-28
@@ -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())
|
||||
|
||||
Reference in New Issue
Block a user