Skip to content

Commit c835a4b

Browse files
committed
Adds 60 second disk cache for unauthenticated indexes.
Fixes #72
1 parent e3b6475 commit c835a4b

File tree

3 files changed

+36
-3
lines changed

3 files changed

+36
-3
lines changed

src/manage/install_command.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ def _find_one(cmd, source, tag, *, installed=None, by_id=False):
390390
else:
391391
LOGGER.verbose("Searching for default Python version")
392392

393-
downloader = IndexDownloader(source, Index, {}, DOWNLOAD_CACHE)
393+
downloader = IndexDownloader(source, Index, {}, DOWNLOAD_CACHE, None if cmd.force else cmd.download_dir)
394394
install = select_package(downloader, tag, cmd.default_platform, by_id=by_id)
395395

396396
if by_id:

src/manage/list_command.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ def execute(cmd):
277277
from .urlutils import IndexDownloader
278278
try:
279279
installs = _get_installs_from_index(
280-
IndexDownloader(cmd.source, Index),
280+
IndexDownloader(cmd.source, Index, disk_cache=cmd.download_dir),
281281
tags,
282282
)
283283
except OSError as ex:

src/manage/urlutils.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -625,20 +625,46 @@ def is_valid_url(url):
625625

626626

627627
class IndexDownloader:
628-
def __init__(self, source, index_cls, auth=None, cache=None):
628+
def __init__(self, source, index_cls, auth=None, cache=None, disk_cache=None):
629629
self.index_cls = index_cls
630630
self._url = source.rstrip("/")
631631
if not self._url.casefold().endswith(".json".casefold()):
632632
self._url += "/index.json"
633633
self._auth = auth if auth is not None else {}
634634
self._cache = cache if cache is not None else {}
635+
self._disk_cache = Path(disk_cache) if disk_cache is not None else None
635636
self._urlopen = urlopen
637+
self._used_auth = False
638+
639+
def _use_disk_cache(self, url, data=None):
640+
if not self._disk_cache:
641+
return None
642+
try:
643+
if extract_url_auth(url):
644+
return None
645+
except OSError:
646+
return None
647+
from hashlib import sha256
648+
from time import time
649+
path = self._disk_cache / (sha256(url.encode("utf-8", "unicodeescape")).hexdigest() + ".cache")
650+
if data:
651+
path.parent.mkdir(parents=True, exist_ok=True)
652+
path.write_bytes(data)
653+
return
654+
try:
655+
if time() - path.lstat().st_mtime < 60:
656+
return path.read_bytes()
657+
path.unlink()
658+
return None
659+
except OSError:
660+
return None
636661

637662
def __iter__(self):
638663
return self
639664

640665
def on_auth(self, url):
641666
# TODO: Try looking for parent paths from URL
667+
self._used_auth = True
642668
try:
643669
return self._auth[url]
644670
except LookupError:
@@ -658,14 +684,21 @@ def __next__(self):
658684
except LookupError:
659685
data = None
660686

687+
data = self._use_disk_cache(url)
688+
if data:
689+
LOGGER.debug("Fetched from disk cache")
690+
661691
if not data:
662692
try:
693+
self._used_auth = False
663694
data = self._cache[url] = self._urlopen(
664695
url,
665696
"GET",
666697
{"Accepts": "application/json"},
667698
on_auth_request=self.on_auth,
668699
)
700+
if not self._used_auth:
701+
self._use_disk_cache(url, data)
669702
except FileNotFoundError: # includes 404
670703
LOGGER.error("Unable to find runtimes index at %s", sanitise_url(url))
671704
raise

0 commit comments

Comments
 (0)