aboutsummaryrefslogtreecommitdiff
path: root/src/hydrilla/proxy/state_impl
diff options
context:
space:
mode:
authorWojtek Kosior <koszko@koszko.org>2022-08-29 13:05:35 +0200
committerWojtek Kosior <koszko@koszko.org>2022-09-28 12:54:54 +0200
commit7fc6312d6df526b8eb49288aecf88d04668e7c45 (patch)
treebc9bda05270991892383839379c101515a440576 /src/hydrilla/proxy/state_impl
parent367ea85057368047a50ae98a3510e0113eadd744 (diff)
downloadhaketilo-hydrilla-7fc6312d6df526b8eb49288aecf88d04668e7c45.tar.gz
haketilo-hydrilla-7fc6312d6df526b8eb49288aecf88d04668e7c45.zip
[proxy] make it possible to also view and install/uninstall libraries (resources) through the web UI
Diffstat (limited to 'src/hydrilla/proxy/state_impl')
-rw-r--r--src/hydrilla/proxy/state_impl/concrete_state.py24
-rw-r--r--src/hydrilla/proxy/state_impl/items.py (renamed from src/hydrilla/proxy/state_impl/mappings.py)265
2 files changed, 208 insertions, 81 deletions
diff --git a/src/hydrilla/proxy/state_impl/concrete_state.py b/src/hydrilla/proxy/state_impl/concrete_state.py
index f180ec6..6bc6404 100644
--- a/src/hydrilla/proxy/state_impl/concrete_state.py
+++ b/src/hydrilla/proxy/state_impl/concrete_state.py
@@ -47,7 +47,7 @@ from .. import state as st
from .. import policies
from .. import simple_dependency_satisfying as sds
from . import base
-from . import mappings
+from . import items
from . import repos
from . import payloads
from . import _operations
@@ -61,15 +61,6 @@ class ConcreteRepoIterationRef(st.RepoIterationRef):
pass
-@dc.dataclass(frozen=True, unsafe_hash=True)
-class ConcreteResourceRef(st.ResourceRef):
- pass
-
-
-@dc.dataclass(frozen=True, unsafe_hash=True)
-class ConcreteResourceVersionRef(st.ResourceVersionRef):
- pass
-
@dc.dataclass
class ConcreteHaketiloState(base.HaketiloStateWithFields):
def __post_init__(self) -> None:
@@ -243,17 +234,16 @@ class ConcreteHaketiloState(base.HaketiloStateWithFields):
return ConcreteRepoIterationRef(repo_iteration_id)
def mapping_store(self) -> st.MappingStore:
- return mappings.ConcreteMappingStore(self)
+ return items.ConcreteMappingStore(self)
def mapping_version_store(self) -> st.MappingVersionStore:
- return mappings.ConcreteMappingVersionStore(self)
+ return items.ConcreteMappingVersionStore(self)
- def get_resource(self, resource_id: str) -> st.ResourceRef:
- return ConcreteResourceRef(resource_id)
+ def resource_store(self) -> st.ResourceStore:
+ return items.ConcreteResourceStore(self)
- def get_resource_version(self, resource_version_id: str) \
- -> st.ResourceVersionRef:
- return ConcreteResourceVersionRef(resource_version_id)
+ def resource_version_store(self) -> st.ResourceVersionStore:
+ return items.ConcreteResourceVersionStore(self)
def get_payload(self, payload_id: str) -> st.PayloadRef:
raise NotImplementedError()
diff --git a/src/hydrilla/proxy/state_impl/mappings.py b/src/hydrilla/proxy/state_impl/items.py
index eb8b4d2..b538dc5 100644
--- a/src/hydrilla/proxy/state_impl/mappings.py
+++ b/src/hydrilla/proxy/state_impl/items.py
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-3.0-or-later
-# Haketilo proxy data and configuration (MappingRef and MappingStore subtypes).
+# Haketilo proxy data and configuration (ResourceStore and MappingStore
+# implementations).
#
# This file is part of Hydrilla&Haketilo.
#
@@ -25,7 +26,8 @@
# in a proprietary program, I am not going to enforce this in court.
"""
-This module provides an interface to interact with mappings inside Haketilo.
+This module provides an interface to interact with mappings, and resources
+inside Haketilo.
"""
# Enable using with Python 3.7.
@@ -39,6 +41,74 @@ from ... import item_infos
from .. import state as st
from . import base
+def _set_installed_status(cursor: sqlite3.Cursor, id: str, new_status: str) \
+ -> None:
+ cursor.execute(
+ 'UPDATE item_versions SET installed = ? WHERE item_version_id = ?;',
+ (new_status, id)
+ )
+
+def _get_statuses(cursor: sqlite3.Cursor, id: str) -> t.Tuple[str, str]:
+ cursor.execute(
+ '''
+ SELECT
+ installed, active
+ FROM
+ item_versions
+ WHERE
+ item_version_id = ?;
+ ''',
+ (id,)
+ )
+
+ rows = cursor.fetchall()
+
+ if rows == []:
+ raise st.MissingItemError()
+
+ (installed_status, active_status), = rows
+
+ return installed_status, active_status
+
+VersionRefVar = t.TypeVar(
+ 'VersionRefVar',
+ 'ConcreteResourceVersionRef',
+ 'ConcreteMappingVersionRef'
+)
+
+def _install_version(ref: VersionRefVar) -> None:
+ with ref.state.cursor(transaction=True) as cursor:
+ installed_status, _ = _get_statuses(cursor, ref.id)
+
+ if installed_status == 'I':
+ return
+
+ _set_installed_status(cursor, ref.id, 'I')
+
+ ref.state.pull_missing_files()
+
+def _uninstall_version(ref: VersionRefVar) -> t.Optional[VersionRefVar]:
+ with ref.state.cursor(transaction=True) as cursor:
+ installed_status, active_status = _get_statuses(cursor, ref.id)
+
+ if installed_status == 'N':
+ return ref
+
+ _set_installed_status(cursor, ref.id, 'N')
+
+ ref.state.prune_orphans()
+
+ if active_status == 'R':
+ ref.state.recompute_dependencies()
+
+ cursor.execute(
+ 'SELECT COUNT(*) FROM item_versions WHERE item_version_id = ?;',
+ (ref.id,)
+ )
+
+ (version_still_present,), = cursor.fetchall()
+ return ref if version_still_present else None
+
@dc.dataclass(frozen=True, unsafe_hash=True)
class ConcreteMappingRef(st.MappingRef):
@@ -60,8 +130,8 @@ class ConcreteMappingRef(st.MappingRef):
ive.is_local,
ms.enabled
FROM
- item_versions_extra AS ive
- JOIN mapping_statuses AS ms USING (item_id)
+ item_versions_extra AS ive
+ JOIN mapping_statuses AS ms USING (item_id)
WHERE
ive.item_id = ?;
''',
@@ -111,6 +181,9 @@ class ConcreteMappingStore(st.MappingStore):
with self.state.cursor() as cursor:
cursor.execute(
'''
+ WITH available_item_ids AS (
+ SELECT DISTINCT item_id FROM item_versions
+ )
SELECT
i.item_id,
i.identifier,
@@ -128,8 +201,9 @@ class ConcreteMappingStore(st.MappingStore):
JOIN mapping_statuses AS ms
USING (item_id)
LEFT JOIN item_versions_extra AS ive
- ON ms.active_version_id = ive.item_version_id AND
- ive.active IN ('R', 'A');
+ ON ms.active_version_id = ive.item_version_id
+ WHERE
+ i.item_id IN available_item_ids;
'''
)
@@ -181,79 +255,142 @@ class ConcreteMappingStore(st.MappingStore):
@dc.dataclass(frozen=True, unsafe_hash=True)
class ConcreteMappingVersionRef(st.MappingVersionRef):
- state: base.HaketiloStateWithFields = dc.field(hash=False, compare=False)
+ state: base.HaketiloStateWithFields
- def _set_installed_status(self, cursor: sqlite3.Cursor, new_status: str) \
- -> None:
- cursor.execute(
- '''
- UPDATE
- item_versions
- SET
- installed = ?
- WHERE
- item_version_id = ?;
- ''',
- (new_status, self.id,)
- )
+ def install(self) -> None:
+ return _install_version(self)
- def _get_statuses(self, cursor: sqlite3.Cursor) -> t.Tuple[str, str]:
- cursor.execute(
- '''
- SELECT
- installed, active
- FROM
- item_versions
- WHERE
- item_version_id = ?;
- ''',
- (self.id,)
- )
+ def uninstall(self) -> t.Optional['ConcreteMappingVersionRef']:
+ return _uninstall_version(self)
- rows = cursor.fetchall()
+ def get_all_version_display_infos(self) \
+ -> t.Sequence[st.MappingVersionDisplayInfo]:
+ with self.state.cursor() as cursor:
+ cursor.execute(
+ '''
+ SELECT
+ item_id
+ FROM
+ item_versions
+ WHERE
+ item_version_id = ?;
+ ''',
+ (self.id,)
+ )
- if rows == []:
- raise st.MissingItemError()
+ rows = cursor.fetchall()
+ if rows == []:
+ raise st.MissingItemError()
- (installed_status, active_status), = rows
+ (mapping_id,), = rows
- return installed_status, active_status
+ mapping_ref = ConcreteMappingRef(str(mapping_id), self.state)
- def install(self) -> None:
- with self.state.cursor(transaction=True) as cursor:
- installed_status, _ = self._get_statuses(cursor)
+ return mapping_ref.get_version_display_infos()
+
+
+@dc.dataclass(frozen=True)
+class ConcreteMappingVersionStore(st.MappingVersionStore):
+ state: base.HaketiloStateWithFields
+
+ def get(self, id: str) -> st.MappingVersionRef:
+ return ConcreteMappingVersionRef(str(int(id)), self.state)
+
+
+@dc.dataclass(frozen=True, unsafe_hash=True)
+class ConcreteResourceRef(st.ResourceRef):
+ state: base.HaketiloStateWithFields = dc.field(hash=False, compare=False)
- if installed_status == 'I':
- return
+ def get_version_display_infos(self) \
+ -> t.Sequence[st.ResourceVersionDisplayInfo]:
+ with self.state.cursor() as cursor:
+ cursor.execute(
+ '''
+ SELECT
+ ive.item_version_id,
+ ive.definition,
+ ive.repo,
+ ive.repo_iteration,
+ ive.installed,
+ ive.active,
+ ive.is_orphan,
+ ive.is_local
+ FROM
+ item_versions_extra AS ive
+ JOIN items AS i USING (item_id)
+ WHERE
+ i.type = 'R' AND ive.item_id = ?;
+ ''',
+ (self.id,)
+ )
- self._set_installed_status(cursor, 'I')
+ rows = cursor.fetchall()
- self.state.pull_missing_files()
+ if rows == []:
+ raise st.MissingItemError()
- def uninstall(self) -> None:
- with self.state.cursor(transaction=True) as cursor:
- installed_status, active_status = self._get_statuses(cursor)
+ result = []
- if installed_status == 'N':
- return
+ for (item_version_id, definition, repo, repo_iteration,
+ installed_status, active_status, is_orphan, is_local) in rows:
+ ref = ConcreteResourceVersionRef(str(item_version_id), self.state)
- self._set_installed_status(cursor, 'N')
+ item_info = item_infos.ResourceInfo.load(
+ definition,
+ repo,
+ repo_iteration
+ )
- self.state.prune_orphans()
+ display_info = st.ResourceVersionDisplayInfo(
+ ref = ref,
+ info = item_info,
+ installed = st.InstalledStatus(installed_status),
+ active = st.ActiveStatus(active_status),
+ is_orphan = is_orphan,
+ is_local = is_local
+ )
+ result.append(display_info)
+
+ return sorted(result, key=(lambda di: di.info))
+
+
+@dc.dataclass(frozen=True)
+class ConcreteResourceStore(st.ResourceStore):
+ state: base.HaketiloStateWithFields
- if active_status == 'R':
- self.state.recompute_dependencies()
+ def get(self, id: str) -> st.ResourceRef:
+ return ConcreteResourceRef(str(int(id)), self.state)
+ def get_display_infos(self) -> t.Sequence[st.ResourceDisplayInfo]:
+ with self.state.cursor() as cursor:
cursor.execute(
- 'SELECT COUNT(*) FROM item_versions WHERE item_version_id = ?;',
- (self.id,)
+ "SELECT item_id, identifier FROM items WHERE type = 'R';"
)
- (version_still_present,), = cursor.fetchall()
- return self if version_still_present else None
+ rows = cursor.fetchall()
+
+ result = []
+
+ for item_id, identifier in rows:
+ ref = ConcreteResourceRef(str(item_id), self.state)
+
+ result.append(st.ResourceDisplayInfo(ref, identifier))
+
+ return sorted(result, key=(lambda di: di.identifier))
+
+
+@dc.dataclass(frozen=True, unsafe_hash=True)
+class ConcreteResourceVersionRef(st.ResourceVersionRef):
+ state: base.HaketiloStateWithFields
+
+ def install(self) -> None:
+ return _install_version(self)
+
+ def uninstall(self) -> t.Optional['ConcreteResourceVersionRef']:
+ return _uninstall_version(self)
def get_all_version_display_infos(self) \
- -> t.Sequence[st.MappingVersionDisplayInfo]:
+ -> t.Sequence[st.ResourceVersionDisplayInfo]:
with self.state.cursor() as cursor:
cursor.execute(
'''
@@ -271,16 +408,16 @@ class ConcreteMappingVersionRef(st.MappingVersionRef):
if rows == []:
raise st.MissingItemError()
- (mapping_id,), = rows
+ (resource_id,), = rows
- mapping_ref = ConcreteMappingRef(str(mapping_id), self.state)
+ resource_ref = ConcreteResourceRef(str(resource_id), self.state)
- return mapping_ref.get_version_display_infos()
+ return resource_ref.get_version_display_infos()
@dc.dataclass(frozen=True)
-class ConcreteMappingVersionStore(st.MappingVersionStore):
+class ConcreteResourceVersionStore(st.ResourceVersionStore):
state: base.HaketiloStateWithFields
- def get(self, id: str) -> st.MappingVersionRef:
- return ConcreteMappingVersionRef(str(int(id)), self.state)
+ def get(self, id: str) -> st.ResourceVersionRef:
+ return ConcreteResourceVersionRef(str(int(id)), self.state)