Verified Commit f1467f29 authored by Sebastian Endres's avatar Sebastian Endres
Browse files

Enhance image metadata, add compliant flag

parent 0c9c4a14
......@@ -14,7 +14,7 @@ from typing import Literal, Optional, TypedDict, Union, cast
from dateutil.parser import parse as parse_date
from utils import UrlOrPath
from .utils import UrlOrPath
DETAILS_RE = re.compile(r"(?P<avg>\d+) \(± (?P<var>\d+)\) (?P<unit>\w+)")
......@@ -55,13 +55,14 @@ class RawMeasurement(TypedDict):
details: str
class RawImageInfo(TypedDict):
"""A info about an image."""
class RawImageMetadata(TypedDict):
"""Metadata about an image."""
image: str
id: str
versions: list[str]
created: Optional[str]
compliant: Optional[bool]
class RawResult(TypedDict):
......@@ -73,7 +74,7 @@ class RawResult(TypedDict):
servers: list[str]
clients: list[str]
urls: dict[str, str]
versions: Optional[dict[str, RawImageInfo]]
images: Optional[dict[str, RawImageMetadata]]
tests: dict[str, Union[RawTestDescr, RawMeasurementDescr]]
quic_draft: int
quic_version: str
......@@ -97,9 +98,27 @@ class Implementation:
url: str
role: ImplementationRole
image: Optional[str] = None
image_id: Optional[str] = None
versions: Optional[list[str]] = None
created: Optional[datetime] = None
image_versions: Optional[list[str]] = None
image_created: Optional[datetime] = None
compliant: Optional[bool] = None
def img_metadata_json(self) -> Optional[RawImageMetadata]:
if not self.image or not self.image_id:
return None
return {
"image": self.image,
"id": self.image_id,
"versions": self.image_versions or [],
"created": (
self.image_created.strftime("%Y-%m-%d %H:%M")
if self.image_created
else None
),
"compliant": self.compliant,
}
@dataclass(frozen=True)
......@@ -374,13 +393,13 @@ class Result:
def log_dir(self, value: UrlOrPath):
self.raw_data["log_dir"] = str(value)
def get_image_info(
def get_image_metadata(
self, impl: Union[str, Implementation]
) -> Union[RawImageInfo, dict]:
versions = self.raw_data.get("versions", {}) or {}
) -> Union[RawImageMetadata, dict]:
images = self.raw_data.get("images", {}) or {}
impl_name = impl if isinstance(impl, str) else impl.name
return versions.get(impl_name, {})
return images.get(impl_name, {})
def _update_implementations(
self, value: list[Implementation], role: ImplementationRole
......@@ -388,7 +407,7 @@ class Result:
assert role != ImplementationRole.BOTH
for impl in value:
img_info = self.get_image_info(impl.name)
img_info = self.get_image_metadata(impl.name)
if impl.name not in self.raw_data["urls"]:
self.raw_data["urls"][impl.name] = impl.url
......@@ -429,18 +448,18 @@ class Result:
)
for name in lookup:
versions = self.raw_data.get("versions") or {}
img_info = versions.get(name, {})
created_raw: Optional[str] = img_info.get("created")
img_metadata = self.get_image_metadata(name)
created_raw: Optional[str] = img_metadata.get("created")
created = parse_date(created_raw) if created_raw else None
ret.append(
Implementation(
name=name,
url=self.raw_data["urls"][name],
role=ImplementationRole.BOTH if name in lookup_other else role,
image_id=img_info.get("id"),
versions=img_info.get("versions"),
created=created,
image_id=img_metadata.get("id"),
image_versions=img_metadata.get("versions"),
image_created=created,
compliant=img_metadata.get("compliant"),
)
)
......@@ -467,10 +486,13 @@ class Result:
self._update_implementations(value, role=ImplementationRole.CLIENT)
@property
def implementations(self) -> frozenset[Implementation]:
"""Return a list of involved implementations."""
def implementations(self) -> dict[str, Implementation]:
"""Return a mapping of involved implementations."""
return frozenset(self.servers) | frozenset(self.clients)
return {
**{impl.name: impl for impl in self.servers},
**{impl.name: impl for impl in self.clients},
}
@property
def tests(self) -> dict[str, Union[TestDescription, MeasurmentDescription]]:
......@@ -841,10 +863,41 @@ class Result:
[test.to_raw() for test in meass_merged[server][client].values()]
)
urls = {
**{impl.name: impl.url for impl in self.implementations},
**{impl.name: impl.url for impl in other.implementations},
}
urls = dict[str, str]()
images = dict[str, RawImageMetadata]()
for name, impl in self.implementations.items():
own_img_metadata = impl.img_metadata_json()
common_img_metadata: Optional[RawImageMetadata] = None
if name in other.implementations.keys():
other_impl = other.implementations[name]
assert impl.url == other_impl.url
other_img_metadata = other_impl.img_metadata_json()
if own_img_metadata and other_img_metadata:
assert own_img_metadata == other_img_metadata
common_img_metadata = own_img_metadata
elif own_img_metadata and not other_img_metadata:
common_img_metadata = own_img_metadata
elif not own_img_metadata and other_img_metadata:
common_img_metadata = other_img_metadata
else:
common_img_metadata = own_img_metadata
urls[name] = impl.url
if common_img_metadata:
images[name] = common_img_metadata
for name, impl in other.implementations.items():
if name not in self.implementations.keys():
urls[name] = impl.url
img_metadata = impl.img_metadata_json()
if img_metadata:
images[name] = img_metadata
test_descriptions: dict[str, Union[RawTestDescr, RawMeasurementDescr]] = {
**{abbr: test.to_raw() for abbr, test in self.tests.items()},
**{abbr: test.to_raw() for abbr, test in other.tests.items()},
......@@ -857,6 +910,7 @@ class Result:
"servers": servers_merged,
"clients": clients_merged,
"urls": urls,
"images": images,
"tests": test_descriptions,
"quic_draft": self.quic_draft,
"quic_version": hex(other.quic_version),
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment