fix: tell an offline cache miss from absence

Offline, fetch_file answered None for a path the cache never
stored, the same answer as a path known to be absent, and
profile_sync reported existing files as gone. A miss now raises
NotCachedError and the profile is reported unverified.
This commit is contained in:
Abdessamad Derraz committed 2026-10-18 02:46:57 +02:00
1 parent b91449590d
commit 9802804a9a
6 files changed
+59 -9

No files matched your search

+7 -3
View File
@@ -124,9 +124,13 @@ def main() -> None:
total = 0
for name in args.emulators:
findings, agreed, unjudged = audit(
name, args.emulators_dir, args.cache_dir, args.offline
)
try:
findings, agreed, unjudged = audit(
name, args.emulators_dir, args.cache_dir, args.offline
)
except upstream.UpstreamError as exc:
print(f"{name}: unreachable, {exc}", file=sys.stderr)
continue
total += len(findings)
print(
f"{name}: {agreed} agree, {len(findings)} point elsewhere, "
+8 -1
View File
@@ -1803,7 +1803,7 @@ def build_report(
return None
try:
return upstream.fetch_file(repo, sha, wanted, cache_dir, offline)
except upstream.RateLimitError:
except (upstream.RateLimitError, upstream.NotCachedError):
raise
except upstream.UpstreamError as exc:
mute.add(key)
@@ -3677,6 +3677,13 @@ def main() -> None:
)
except upstream.RateLimitError:
raise
except upstream.NotCachedError as exc:
# Offline with a cache that never stored this file: the profile
# is unverified, not wrong. Reporting GONE sent readers after
# files that exist.
report = ProfileReport(
name=name, entries=[], counts={}, skipped=f"offline: {exc}"
)
except upstream.GoneError as exc:
# The forge is not coming back: a takedown, or a host that no
# longer resolves. Saying so once in the summary beats repeating
+14 -2
View File
@@ -80,6 +80,14 @@ class RateLimitError(UpstreamError):
"""The forge refused the request for quota reasons."""
class NotCachedError(UpstreamError):
"""An offline read of something the cache never stored.
Distinct from absence: returning None made profile_sync report a file
that exists as GONE, "absent at HEAD, no rename found".
"""
class GoneError(UpstreamError):
"""The upstream is not coming back.
@@ -317,13 +325,17 @@ def fetch_file(
cache_dir: str,
offline: bool = False,
) -> list[str] | None:
"""Lines of one path at one revision, or None when absent."""
"""Lines of one path at one revision, or None when absent.
Offline, a path the cache never stored raises NotCachedError: nothing
is known about it, which is not the same as knowing it is absent.
"""
target = cache_path(cache_dir, repo, sha, path)
if target.is_file():
text = target.read_text(encoding="utf-8")
return None if text == ABSENT else text.splitlines()
if offline:
return None
raise NotCachedError(f"{repo.slug}@{sha[:8]}:{path} is not in the offline cache")
text = _http_text(raw_url(repo, sha, path))
write_cache(target, ABSENT if text is None else text)
return None if text is None else text.splitlines()