fix: link a source path its cached tree holds

This commit is contained in:
Abdessamad Derraz committed 2026-10-23 10:46:08 +02:00
1 parent e3a54d2423
commit db22cc37bb
1 file changed
+50 -2
+50 -2
View File
@@ -5,9 +5,11 @@ was written against, so a permalink is pinned, never guessed."""
from __future__ import annotations from __future__ import annotations
import functools
import re import re
import urllib.parse import urllib.parse
from dataclasses import dataclass from dataclasses import dataclass
from pathlib import Path
import urllib.request import urllib.request
import upstream import upstream
@@ -150,6 +152,45 @@ def _source_permalink(repo: upstream.Repo, pin: str, path: str,
url += f"-L{end}" url += f"-L{end}"
return url return url
# The tree listings profile_sync caches. Read offline only: a page build
# never calls a forge, and a listing it does not find leaves the link as the
# profile's declarations alone decide it.
TREE_CACHE = Path(__file__).resolve().parent.parent / upstream.CACHE_DIR
@functools.lru_cache(maxsize=None)
def _tree_paths(repo: upstream.Repo, pin: str) -> frozenset[str] | None:
"""Every file of a repository at a revision, None when not cached or
truncated (a missing path would then prove nothing)."""
if not repo.api_base:
return None # a browse-only forge: no listing to read
paths, truncated = upstream.list_tree(repo, pin, str(TREE_CACHE), offline=True)
return frozenset(paths) if paths and not truncated else None
def tree_holds(repo: upstream.Repo, pin: str, path: str) -> bool | None:
"""Whether the repository holds ``path`` at ``pin``: None when its tree
is not cached. trident cites src/core/loader/ncch.cpp, a Panda3DS file,
and the page linked it into 3dsTrident, where it is a 404."""
paths = _tree_paths(repo, pin)
return None if paths is None else path in paths
def _holder(
candidates: list[tuple[upstream.Repo, str]], path: str, default: tuple | None,
) -> tuple[upstream.Repo, str] | None:
"""The pinned repository that holds ``path``, source before upstream as
profile_sync.select_views orders them. Without every tree cached, the
declarations decide (``default``). A path no cached tree holds links
nowhere: no link beats a link to a file that is not there."""
verdicts = [tree_holds(repo, pin, path) for repo, pin in candidates]
if not candidates or None in verdicts:
if default is not None and tree_holds(*default, path) is False:
return None
return default
return next((cand for cand, held in zip(candidates, verdicts) if held), None)
def _commit_url(repo: upstream.Repo, pin: str) -> str: def _commit_url(repo: upstream.Repo, pin: str) -> str:
"""Forge-specific browser URL for one commit.""" """Forge-specific browser URL for one commit."""
base = f"https://{repo.host}/{repo.owner}/{repo.name}" base = f"https://{repo.host}/{repo.owner}/{repo.name}"
@@ -272,8 +313,13 @@ def _source_ref_markdown(profile: dict, value: str | dict | None) -> str:
if current_role: if current_role:
# Only the repository the part names, or no link at all. # Only the repository the part names, or no link at all.
selected = by_role.get(current_role) selected = by_role.get(current_role)
elif len(candidates) == 1: if selected is not None and tree_holds(*selected, part.path) is False:
selected = candidates[0] selected = None
else:
selected = _holder(
candidates, part.path,
candidates[0] if len(candidates) == 1 else None,
)
tag = (f" ({role_label(profile, current_role, part.path)})" tag = (f" ({role_label(profile, current_role, part.path)})"
if current_role and _two_repositories(profile) else "") if current_role and _two_repositories(profile) else "")
@@ -330,6 +376,8 @@ def link_prose_citations(profile: dict, text: str) -> str:
continue continue
if any(lo <= path_span[0] < hi for lo, hi in guarded): if any(lo <= path_span[0] < hi for lo, hi in guarded):
continue continue
if tree_holds(repo, pin, path) is False:
continue
for index, ((lo, hi), part) in enumerate(zip(spans, parts)): for index, ((lo, hi), part) in enumerate(zip(spans, parts)):
start = path_span[0] if index == 0 else lo start = path_span[0] if index == 0 else lo
url = _source_permalink(repo, pin, part.path, part.start, part.end) url = _source_permalink(repo, pin, part.path, part.start, part.end)