diff options
Diffstat (limited to 'src/hydrilla/proxy/state_impl/payloads.py')
-rw-r--r-- | src/hydrilla/proxy/state_impl/payloads.py | 170 |
1 files changed, 168 insertions, 2 deletions
diff --git a/src/hydrilla/proxy/state_impl/payloads.py b/src/hydrilla/proxy/state_impl/payloads.py index 2bee11f..e622e52 100644 --- a/src/hydrilla/proxy/state_impl/payloads.py +++ b/src/hydrilla/proxy/state_impl/payloads.py @@ -31,11 +31,14 @@ This module provides an interface to interact with payloads inside Haketilo. # Enable using with Python 3.7. from __future__ import annotations +import sqlite3 import dataclasses as dc import typing as t +from ... import item_infos from .. import state as st from . import base +from . import items @dc.dataclass(frozen=True, unsafe_hash=True) @@ -48,8 +51,163 @@ class ConcretePayloadRef(st.PayloadRef): except KeyError: raise st.MissingItemError() - def get_mapping(self) -> st.MappingVersionRef: - raise NotImplementedError() + def has_problems(self) -> bool: + with self.state.cursor(transaction=True) as cursor: + cursor.execute( + ''' + SELECT + iv.installed == 'F' + FROM + payloads AS p + JOIN item_versions AS iv + ON p.mapping_item_id = iv.item_version_id + WHERE + p.payload_id = ?; + ''', + (self.id,) + ) + + rows = cursor.fetchall() + + if rows == []: + raise st.MissingItemError() + + (mapping_install_failed,), = rows + if mapping_install_failed: + return True + + cursor.execute( + ''' + SELECT + COUNT(*) > 0 + FROM + payloads AS p + JOIN resolved_depended_resources AS rdd + USING (payload_id) + JOIN item_versions AS iv + ON rdd.resource_item_id = iv.item_version_id + WHERE + p.payload_id = ? AND iv.installed = 'F'; + ''', + (self.id,) + ) + + (resource_install_failed,), = cursor.fetchall() + if resource_install_failed: + return True + + return False + + def get_display_info(self) -> st.PayloadDisplayInfo: + with self.state.cursor() as cursor: + cursor.execute( + ''' + SELECT + p.pattern, + ive.item_version_id, + ive.definition, + ive.repo, + ive.repo_iteration, + ive.installed, + ive.active, + ive.is_orphan, + ive.is_local + FROM + payloads AS p + JOIN item_versions_extra AS ive + ON p.mapping_item_id = ive.item_version_id + WHERE + p.payload_id = ?; + ''', + (self.id,) + ) + + rows = cursor.fetchall() + + if rows == []: + raise st.MissingItemError() + + (pattern_str, mapping_version_id, definition, repo, repo_iteration, + installed_status, active_status, is_orphan, is_local), = rows + + has_problems = self.has_problems() + + mapping_version_ref = items.ConcreteMappingVersionRef( + id = str(mapping_version_id), + state = self.state + ) + + mapping_version_info = item_infos.MappingInfo.load( + definition, + repo, + repo_iteration + ) + + mapping_version_display_info = st.MappingVersionDisplayInfo( + ref = mapping_version_ref, + info = mapping_version_info, + installed = st.InstalledStatus(installed_status), + active = st.ActiveStatus(active_status), + is_orphan = is_orphan, + is_local = is_local + ) + + return st.PayloadDisplayInfo( + ref = self, + mapping_info = mapping_version_display_info, + pattern = pattern_str, + has_problems = has_problems + ) + + def ensure_items_installed(self) -> None: + with self.state.cursor(transaction=True) as cursor: + cursor.execute( + 'SELECT mapping_item_id FROM payloads WHERE payload_id = ?;', + (self.id,) + ) + + rows = cursor.fetchall() + + if rows == []: + raise st.MissingItemError() + + (mapping_version_id,), = rows + + cursor.execute( + ''' + UPDATE + item_versions + SET + installed = 'I' + WHERE + item_version_id = ?; + ''', + (mapping_version_id,) + ) + + cursor.execute( + ''' + WITH depended_resource_ids AS ( + SELECT + rdd.resource_item_id + FROM + payloads AS p + JOIN resolved_depended_resources AS rdd + USING (payload_id) + WHERE + payload_id = ? + ) + UPDATE + item_versions + SET + installed = 'I' + WHERE + item_version_id IN depended_resource_ids; + ''', + (self.id,) + ) + + self.state.pull_missing_files() def get_script_paths(self) \ -> t.Iterable[t.Sequence[str]]: @@ -135,3 +293,11 @@ class ConcretePayloadRef(st.PayloadRef): (data, mime_type), = result return st.FileData(type=mime_type, name=file_name, contents=data) + + +@dc.dataclass(frozen=True) +class ConcretePayloadStore(st.PayloadStore): + state: base.HaketiloStateWithFields + + def get(self, id: str) -> st.PayloadRef: + return ConcretePayloadRef(str(int(id)), self.state) |