aboutsummaryrefslogtreecommitdiff
path: root/repos/base.py
diff options
context:
space:
mode:
Diffstat (limited to 'repos/base.py')
-rw-r--r--repos/base.py55
1 files changed, 48 insertions, 7 deletions
diff --git a/repos/base.py b/repos/base.py
index 66ecf2d..220a30f 100644
--- a/repos/base.py
+++ b/repos/base.py
@@ -1,26 +1,66 @@
-from dataclasses import dataclass
+from dataclasses import dataclass, asdict as dataclass_asdict
import datetime
+from functools import total_ordering
import gzip
import json
import os
from pathlib import Path
import re
-from typing import Callable, Mapping
+from typing import Any, Callable, Mapping
import requests
+import semver
+
+__all__ = [
+ 'Repository',
+ 'Version',
+]
HTTP_DATE = '%a, %d %b %Y %H:%M:%S GMT'
-SLUGIFY = re.compile('\W+')
+SLUGIFY = re.compile(r'\W+')
def slug(text: str) -> str:
return SLUGIFY.sub('-', text.lower()).strip('-')
+@total_ordering
+@dataclass()
+class Version:
+ original: str
+ clean: str
+
+ def __str__(self) -> str:
+ return self.original
+
+ def __lt__(self, other: Any):
+ if not isinstance(other, Version):
+ return NotImplemented
+ if semver.VersionInfo.isvalid(self.clean) and semver.VersionInfo.isvalid(other.clean):
+ return semver.compare(self.clean, other.clean) < 0
+ return self.original < other.original
+
+class JSONEncoder(json.JSONEncoder):
+ def default(self, o: Any) -> Any:
+ if isinstance(o, Version):
+ return dataclass_asdict(o)
+ return super().default(o)
+
+class JSONDecoder(json.JSONDecoder):
+ @staticmethod
+ def object_hook(o: dict) -> Any:
+ if o.keys() == {'original', 'clean'}:
+ return Version(**o)
+ return o
+
+ def __init__(self):
+ super().__init__(object_hook=self.object_hook)
+
+
@dataclass()
class Repository:
family: str
repo: str
index_url: str
- parse: Callable[[Path], Mapping[str, str]]
+ parse: Callable[[Path], Mapping[str, Version]]
def _full_name(self):
return f'{self.family} {self.repo}'
@@ -31,7 +71,7 @@ class Repository:
def _cache_file(self, name: str) -> Path:
return self._cache_dir() / name
- def get_versions(self) -> Mapping[str, str]:
+ def get_versions(self) -> Mapping[str, Version]:
self._cache_dir().mkdir(parents=True, exist_ok=True)
downloaded_file = self._cache_file('downloaded')
if downloaded_file.exists():
@@ -57,10 +97,11 @@ class Repository:
set_mtime = datetime.datetime.strptime(set_mtime, HTTP_DATE)
os.utime(downloaded_file, (datetime.datetime.now().timestamp(), set_mtime.timestamp()))
+ if response.status_code != requests.codes.not_modified or not parsed_file.exists():
parsed_data = self.parse(downloaded_file)
with gzip.open(parsed_file, 'wt') as f:
- json.dump(parsed_data, f)
+ json.dump(parsed_data, f, cls=JSONEncoder)
return parsed_data
else:
with gzip.open(parsed_file, 'rt') as f:
- return json.load(f)
+ return json.load(f, cls=JSONDecoder)