refactor: let cached branch tips expire

This commit is contained in:
Abdessamad Derraz committed 2026-09-03 22:29:48 +02:00
1 parent b362d81910
commit 59d3b0683a
2 files changed
+74 -8

No files matched your search

+29 -8
View File
@@ -258,13 +258,32 @@ def fetch_file(
return None if text is None else text.splitlines()
def _api(url: str, cache_dir: str, offline: bool) -> object | None:
"""Cached API call. The cache stores absence as well as payloads."""
# How long an answer about a moving reference stays trusted. A branch tip, a
# tag list or a release list changes under the profile: libretro/hatari grew
# a new main branch after its tip was first cached, and every comparison
# then ran against the old branch. Content addressed by a sha or a date
# never changes and is cached for good.
MOVING_TTL = 6 * 3600
def _api(
url: str, cache_dir: str, offline: bool, max_age: float | None = None
) -> object | None:
"""Cached API call. The cache stores absence as well as payloads.
``max_age`` bounds the trust in a cached answer, in seconds; a stale
answer is refreshed unless the run is offline, when it still serves.
"""
key = hashlib.sha256(url.encode()).hexdigest()
target = Path(cache_dir) / "_api" / f"{key}.json"
if target.is_file():
raw = target.read_text(encoding="utf-8")
return None if raw == ABSENT else json.loads(raw)
fresh = (
max_age is None
or time.time() - target.stat().st_mtime <= max_age
)
if fresh or offline:
raw = target.read_text(encoding="utf-8")
return None if raw == ABSENT else json.loads(raw)
if offline:
return None
payload = _http_json(url)
@@ -312,7 +331,9 @@ def resolve_head(
default branch, so the code a profile documents can be absent from the
tip the forge serves by default.
"""
return _first_sha(_api(_commits_url(repo, None, branch), cache_dir, offline))
return _first_sha(
_api(_commits_url(repo, None, branch), cache_dir, offline, MOVING_TTL)
)
def resolve_commit_at(
@@ -334,7 +355,7 @@ def _tags_url(repo: Repo) -> str:
def list_tags(repo: Repo, cache_dir: str, offline: bool = False) -> list[str]:
"""Tag names, newest first as the forge orders them."""
payload = _api(_tags_url(repo), cache_dir, offline)
payload = _api(_tags_url(repo), cache_dir, offline, MOVING_TTL)
if not isinstance(payload, list):
return []
return [t["name"] for t in payload if isinstance(t, dict) and t.get("name")]
@@ -344,7 +365,7 @@ def resolve_tag_commit(
repo: Repo, tag: str, cache_dir: str, offline: bool = False
) -> str | None:
"""Commit a tag points at."""
payload = _api(_tags_url(repo), cache_dir, offline)
payload = _api(_tags_url(repo), cache_dir, offline, MOVING_TTL)
if not isinstance(payload, list):
return None
for entry in payload:
@@ -399,7 +420,7 @@ def latest_release(
repo: Repo, cache_dir: str, offline: bool = False
) -> Release | None:
"""Most recent release the forge exposes."""
payload = _api(_releases_url(repo), cache_dir, offline)
payload = _api(_releases_url(repo), cache_dir, offline, MOVING_TTL)
if isinstance(payload, list):
payload = payload[0] if payload else None
if not isinstance(payload, dict):
+45
View File
@@ -365,6 +365,51 @@ class TestRevisions(unittest.TestCase):
upstream.resolve_commit_at(self.repo, "2026-03-29", self.dir)
self.assertEqual(len(self.calls), 1)
def test_a_branch_tip_is_refreshed_once_stale(self):
import os as _os
import hashlib as _hashlib
self.responses["/commits"] = [{"sha": "old"}]
self.assertEqual(upstream.resolve_head(self.repo, self.dir), "old")
url = upstream._commits_url(self.repo, None, None)
cached = (
Path(self.dir) / "_api"
/ f"{_hashlib.sha256(url.encode()).hexdigest()}.json"
)
stale = _os.path.getmtime(cached) - upstream.MOVING_TTL - 1
_os.utime(cached, (stale, stale))
self.responses["/commits"] = [{"sha": "new"}]
self.assertEqual(upstream.resolve_head(self.repo, self.dir), "new")
self.assertEqual(len(self.calls), 2)
def test_a_stale_tip_still_serves_offline(self):
import os as _os
import hashlib as _hashlib
self.responses["/commits"] = [{"sha": "old"}]
upstream.resolve_head(self.repo, self.dir)
url = upstream._commits_url(self.repo, None, None)
cached = (
Path(self.dir) / "_api"
/ f"{_hashlib.sha256(url.encode()).hexdigest()}.json"
)
stale = _os.path.getmtime(cached) - upstream.MOVING_TTL - 1
_os.utime(cached, (stale, stale))
self.assertEqual(upstream.resolve_head(self.repo, self.dir, offline=True), "old")
self.assertEqual(len(self.calls), 1)
def test_a_dated_lookup_is_cached_for_good(self):
import os as _os
import hashlib as _hashlib
self.responses["/commits"] = [{"sha": "abc"}]
upstream.resolve_commit_at(self.repo, "2026-03-29", self.dir)
url = upstream._commits_url(self.repo, "2026-03-29", None)
cached = (
Path(self.dir) / "_api"
/ f"{_hashlib.sha256(url.encode()).hexdigest()}.json"
)
_os.utime(cached, (0, 0))
upstream.resolve_commit_at(self.repo, "2026-03-29", self.dir)
self.assertEqual(len(self.calls), 1)
def test_offline_without_cache_returns_none(self):
self.assertIsNone(upstream.resolve_head(self.repo, self.dir, offline=True))
self.assertEqual(self.calls, [])