aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWojtek Kosior <koszko@koszko.org>2022-08-30 12:04:42 +0200
committerWojtek Kosior <koszko@koszko.org>2022-09-28 12:54:55 +0200
commit28b89c179b15ca1424a34aa6fe86cc045dc2b80c (patch)
tree836e090a5f0961fac9a1cf74c248bc94bcfbfd2f
parent2e243e03737b1d65a82a73c1469edba111cfb0b8 (diff)
downloadhaketilo-hydrilla-28b89c179b15ca1424a34aa6fe86cc045dc2b80c.tar.gz
haketilo-hydrilla-28b89c179b15ca1424a34aa6fe86cc045dc2b80c.zip
[server] make VersionedItemInfo data structure a common API again
-rw-r--r--src/hydrilla/item_infos.py66
-rw-r--r--src/hydrilla/server/malcontent.py99
-rw-r--r--src/hydrilla/server/serve.py4
3 files changed, 92 insertions, 77 deletions
diff --git a/src/hydrilla/item_infos.py b/src/hydrilla/item_infos.py
index 9a87b40..0e10871 100644
--- a/src/hydrilla/item_infos.py
+++ b/src/hydrilla/item_infos.py
@@ -484,3 +484,69 @@ class CategorizedItemInfo(Categorizable, t.Generic[CategorizedType, CategoryKeyT
def is_empty(self) -> bool:
"""...."""
return len(self.items) == 0
+
+
+VersionedType = t.TypeVar('VersionedType', ResourceInfo, MappingInfo)
+
+class VersionedItemInfo(
+ CategorizedItemInfo[VersionedType, versions.VerTuple],
+ t.Generic[VersionedType]
+):
+ """Stores data of multiple versions of given resource/mapping."""
+ SelfType = t.TypeVar('SelfType', bound='VersionedItemInfo[VersionedType]')
+
+ def register(self: 'SelfType', item_info: VersionedType) -> 'SelfType':
+ """
+ Make item info queryable by version. Perform sanity checks for uuid.
+ """
+ return self._update(item_info.version, lambda old_info: item_info)
+
+ def unregister(self: 'SelfType', version: versions.VerTuple) -> 'SelfType':
+ """...."""
+ return self._update(version, lambda old_info: None)
+
+ @property
+ def newest_version(self) -> versions.VerTuple:
+ """...."""
+ assert not self.is_empty()
+
+ return max(self.items.keys())
+
+ @property
+ def newest_info(self) -> VersionedType:
+ """Find and return info of the newest version of item."""
+ return self.items[self.newest_version]
+
+ def get_by_ver(self, ver: t.Sequence[int]) -> t.Optional[VersionedType]:
+ """
+ Find and return info of the specified version of the item (or None if
+ absent).
+ """
+ return self.items.get(versions.normalize(ver))
+
+ def get_all(self) -> t.Iterable[VersionedType]:
+ """Generate item info for all its versions, from oldest to newest."""
+ return [self.items[version] for version in sorted(self.items.keys())]
+
+VersionedResourceInfo = VersionedItemInfo[ResourceInfo]
+VersionedMappingInfo = VersionedItemInfo[MappingInfo]
+
+
+VersionedItemInfoMap = Map[str, VersionedItemInfo]
+VersionedResourceInfoMap = Map[str, VersionedResourceInfo]
+VersionedMappingInfoMap = Map[str, VersionedMappingInfo]
+
+def register_in_map(
+ map: Map[str, VersionedItemInfo[VersionedType]],
+ info: VersionedType
+) -> Map[str, VersionedItemInfo[VersionedType]]:
+ versioned_info = map.get(info.identifier, VersionedItemInfo())
+
+ return map.set(info.identifier, versioned_info.register(info))
+
+def all_map_infos(
+ map: Map[str, VersionedItemInfo[VersionedType]]
+) -> t.Iterator[VersionedType]:
+ for versioned_info in map.values():
+ for item_info in versioned_info.get_all():
+ yield item_info
diff --git a/src/hydrilla/server/malcontent.py b/src/hydrilla/server/malcontent.py
index af925a0..9557161 100644
--- a/src/hydrilla/server/malcontent.py
+++ b/src/hydrilla/server/malcontent.py
@@ -33,63 +33,22 @@ import typing as t
from pathlib import Path
+from immutables import Map
+
from ..translations import smart_gettext as _
from ..exceptions import HaketiloException
from .. import versions
from .. import item_infos
from .. import pattern_tree
-VersionedType = t.TypeVar(
- 'VersionedType',
- item_infos.ResourceInfo,
- item_infos.MappingInfo
-)
-
-class VersionedItemInfo(
- item_infos.CategorizedItemInfo[VersionedType, versions.VerTuple],
- t.Generic[VersionedType]
-):
- """Stores data of multiple versions of given resource/mapping."""
- SelfType = t.TypeVar('SelfType', bound='VersionedItemInfo[VersionedType]')
-
- def register(self: 'SelfType', item_info: VersionedType) -> 'SelfType':
- """
- Make item info queryable by version. Perform sanity checks for uuid.
- """
- return self._update(item_info.version, lambda old_info: item_info)
-
- def unregister(self: 'SelfType', version: versions.VerTuple) -> 'SelfType':
- """...."""
- return self._update(version, lambda old_info: None)
-
- @property
- def newest_version(self) -> versions.VerTuple:
- """...."""
- assert not self.is_empty()
-
- return max(self.items.keys())
-
- @property
- def newest_info(self) -> VersionedType:
- """Find and return info of the newest version of item."""
- return self.items[self.newest_version]
-
- def get_by_ver(self, ver: t.Sequence[int]) -> t.Optional[VersionedType]:
- """
- Find and return info of the specified version of the item (or None if
- absent).
- """
- return self.items.get(versions.normalize(ver))
-
- def get_all(self) -> t.Iterable[VersionedType]:
- """Generate item info for all its versions, from oldest to newest."""
- return [self.items[version] for version in sorted(self.items.keys())]
-
MappingTree = pattern_tree.PatternTree[item_infos.MappingInfo]
-ResourceInfos = dict[str, VersionedItemInfo[item_infos.ResourceInfo]]
-MappingInfos = dict[str, VersionedItemInfo[item_infos.MappingInfo]]
+# VersionedType = t.TypeVar(
+# 'VersionedType',
+# item_infos.ResourceInfo,
+# item_infos.MappingInfo
+# )
class Malcontent:
"""
@@ -109,8 +68,8 @@ class Malcontent:
self.werror: bool = werror
self.verify_files: bool = verify_files
- self.resource_infos: ResourceInfos = {}
- self.mapping_infos: MappingInfos = {}
+ self.resource_infos: item_infos.VersionedResourceInfoMap = Map()
+ self.mapping_infos: item_infos.VersionedMappingInfoMap = Map()
self.mapping_tree: MappingTree = MappingTree()
@@ -161,15 +120,6 @@ class Malcontent:
else:
logging.error(msg)
- @staticmethod
- def _register_info(
- infos: dict[str, VersionedItemInfo[VersionedType]],
- identifier: str,
- item_info: VersionedType
- ) -> None:
- versioned_info = infos.get(identifier, VersionedItemInfo())
- infos[identifier] = versioned_info.register(item_info)
-
def _load_item(self, type: item_infos.ItemType, ver_file: Path) \
-> None:
"""
@@ -196,16 +146,15 @@ class Malcontent:
self._check_package_files(item_info)
if isinstance(item_info, item_infos.ResourceInfo):
- self._register_info(self.resource_infos, identifier, item_info)
+ self.resource_infos = item_infos.register_in_map(
+ map = self.resource_infos,
+ info = item_info
+ )
else:
- self._register_info(self.mapping_infos, identifier, item_info)
-
- @staticmethod
- def _all_infos(infos: dict[str, VersionedItemInfo[VersionedType]]) \
- -> t.Iterator[VersionedType]:
- for versioned_info in infos.values():
- for item_info in versioned_info.get_all():
- yield item_info
+ self.mapping_infos = item_infos.register_in_map(
+ map = self.mapping_infos,
+ info = item_info
+ )
def _report_missing(self) -> None:
"""
@@ -221,7 +170,7 @@ class Malcontent:
ver=versions.version_string(info.version))
logging.error(msg)
- for resource_info in self._all_infos(self.resource_infos):
+ for resource_info in item_infos.all_map_infos(self.resource_infos):
for dep_specifier in resource_info.dependencies:
identifier = dep_specifier.identifier
if identifier not in self.resource_infos:
@@ -236,7 +185,7 @@ class Malcontent:
ver=versions.version_string(info.version))
logging.error(msg)
- for mapping_info in self._all_infos(self.mapping_infos):
+ for mapping_info in item_infos.all_map_infos(self.mapping_infos):
for resource_specifier in mapping_info.payloads.values():
identifier = resource_specifier.identifier
if identifier not in self.resource_infos:
@@ -252,8 +201,8 @@ class Malcontent:
logging.error(msg)
infos: t.Iterable[item_infos.AnyInfo] = (
- *self._all_infos(self.mapping_infos),
- *self._all_infos(self.resource_infos)
+ *item_infos.all_map_infos(self.mapping_infos),
+ *item_infos.all_map_infos(self.resource_infos)
)
for item_info in infos:
for mapping_specifier in item_info.required_mappings:
@@ -266,7 +215,7 @@ class Malcontent:
Initialize structures needed to serve queries. Called once after all
data gets loaded.
"""
- for info in self._all_infos(self.mapping_infos):
+ for info in item_infos.all_map_infos(self.mapping_infos):
for pattern in info.payloads:
try:
self.mapping_tree = \
@@ -299,7 +248,7 @@ class Malcontent:
return list(collected.values())
def get_all_resources(self) -> t.Sequence[item_infos.ResourceInfo]:
- return tuple(self._all_infos(self.resource_infos))
+ return tuple(item_infos.all_map_infos(self.resource_infos))
def get_all_mappings(self) -> t.Sequence[item_infos.MappingInfo]:
- return tuple(self._all_infos(self.mapping_infos))
+ return tuple(item_infos.all_map_infos(self.mapping_infos))
diff --git a/src/hydrilla/server/serve.py b/src/hydrilla/server/serve.py
index 823437a..dc85f85 100644
--- a/src/hydrilla/server/serve.py
+++ b/src/hydrilla/server/serve.py
@@ -124,7 +124,7 @@ def get_resource_or_mapping(item_type: str, identifier: str) \
identifier = match.group(1)
- infos: t.Mapping[str, malcontent.VersionedItemInfo]
+ infos: t.Mapping[str, item_infos.VersionedItemInfo]
if item_type == 'resource':
infos = get_malcontent().resource_infos
else:
@@ -135,7 +135,7 @@ def get_resource_or_mapping(item_type: str, identifier: str) \
if versioned_info is None:
flask.abort(404)
- info = versioned_info.newest_info()
+ info = versioned_info.newest_info
# no need for send_from_directory(); path is safe, constructed by us
info_path = f'{info.identifier}/{versions.version_string(info.version)}'