From 503e546b2b0c9dba505a4e7940f257d41ad95f67 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Thu, 25 Aug 2022 12:43:29 +0200 Subject: [proxy] properly flag failed package installations in sqlite db --- .../state_impl/_operations/pull_missing_files.py | 9 +++--- src/hydrilla/proxy/state_impl/base.py | 37 ++++++++++++++++++++++ src/hydrilla/proxy/tables.sql | 4 +-- src/hydrilla/proxy/web_ui/packages.py | 5 +++ src/hydrilla/proxy/web_ui/repos.py | 4 +-- .../packages/show_single_version.html.jinja | 5 +++ .../web_ui/templates/repos/show_single.html.jinja | 5 +++ 7 files changed, 59 insertions(+), 10 deletions(-) diff --git a/src/hydrilla/proxy/state_impl/_operations/pull_missing_files.py b/src/hydrilla/proxy/state_impl/_operations/pull_missing_files.py index 04a2910..f1e0414 100644 --- a/src/hydrilla/proxy/state_impl/_operations/pull_missing_files.py +++ b/src/hydrilla/proxy/state_impl/_operations/pull_missing_files.py @@ -81,17 +81,16 @@ def pull_missing_files( try: url = urljoin(repo_url, f'file/sha256/{sha256}') response = requests.get(url) - except: - raise state.RepoCommunicationError() - if not response.ok: + assert response.ok + + file_bytes = response.content + except: raise state.FileMissingError( repo_id = str(repo_id), sha256 = sha256 ) - file_bytes = response.content - computed_sha256 = hashlib.sha256(file_bytes).digest().hex() if computed_sha256 != sha256: raise state.FileIntegrityError( diff --git a/src/hydrilla/proxy/state_impl/base.py b/src/hydrilla/proxy/state_impl/base.py index 25fd4c5..a889e71 100644 --- a/src/hydrilla/proxy/state_impl/base.py +++ b/src/hydrilla/proxy/state_impl/base.py @@ -78,6 +78,34 @@ class PolicyTree(pattern_tree.PatternTree[policies.PolicyFactory]): return policy_tree +def mark_failed_file_installs( + cursor: sqlite3.Cursor, + file_sha256: str, + repo_id: int +) -> None: + cursor.execute( + ''' + WITH failed_items AS ( + SELECT DISTINCT + item_version_id + FROM + files AS f + JOIN file_uses AS fu USING (file_id) + JOIN item_versions_extra AS ive USING (item_version_id) + WHERE + f.sha256 = ? AND f.data IS NULL AND ive.repo_id = ? + ) + UPDATE + item_versions + SET + installed = 'F' + WHERE + item_version_id IN failed_items; + ''', + (file_sha256, repo_id) + ) + + PayloadsData = t.Mapping[st.PayloadRef, st.PayloadData] # mypy needs to be corrected: @@ -123,6 +151,15 @@ class HaketiloStateWithFields(st.HaketiloState): if start_transaction: self.current_cursor.execute('ROLLBACK TRANSACTION;') raise + except st.FileInstallationError as ex: + if start_transaction: + assert self.current_cursor is not None + mark_failed_file_installs( + cursor = self.current_cursor, + file_sha256 = ex.sha256, + repo_id = int(ex.repo_id) + ) + raise finally: self.current_cursor = None diff --git a/src/hydrilla/proxy/tables.sql b/src/hydrilla/proxy/tables.sql index 54fe3ee..2483c96 100644 --- a/src/hydrilla/proxy/tables.sql +++ b/src/hydrilla/proxy/tables.sql @@ -245,8 +245,8 @@ SELECT iv.repo_iteration_id, iv.definition, iv.active, - r.name AS repo, - ri.iteration AS repo_iteration, + r.repo_id, r.name AS repo, + ri.repo_iteration_id, ri.iteration AS repo_iteration, COALESCE(r.active_iteration_id, -1) != ri.repo_iteration_id AND r.repo_id != 1 AS is_orphan, r.repo_id = 1 AS is_local diff --git a/src/hydrilla/proxy/web_ui/packages.py b/src/hydrilla/proxy/web_ui/packages.py index 5172a07..1edddc0 100644 --- a/src/hydrilla/proxy/web_ui/packages.py +++ b/src/hydrilla/proxy/web_ui/packages.py @@ -179,6 +179,11 @@ def alter_package_version(mapping_version_id: str) -> werkzeug.Response: return flask.redirect(flask.url_for('.packages')) else: raise ValueError() + except st.FileInstallationError: + return show_package_version( + mapping_version_id, + {'file_installation_error': True} + ) except st.ImpossibleSituation: return show_package_version( mapping_version_id, diff --git a/src/hydrilla/proxy/web_ui/repos.py b/src/hydrilla/proxy/web_ui/repos.py index 5aa5a21..c31a0a4 100644 --- a/src/hydrilla/proxy/web_ui/repos.py +++ b/src/hydrilla/proxy/web_ui/repos.py @@ -130,9 +130,7 @@ def alter_repo(repo_id: str) -> werkzeug.Response: except st.RepoCommunicationError: return show_repo(repo_id, {'repo_communication_error': True}) except st.FileInstallationError: - # We'll add the ability to present more meaningful errors later. For now - # let's treat file errors the same as repo communication errors. - return show_repo(repo_id, {'repo_communication_error': True}) + return show_repo(repo_id, {'file_installation_error': True}) except st.RepoApiVersionUnsupported: return show_repo(repo_id, {'repo_api_version_unsupported': True}) except st.MissingItemError: diff --git a/src/hydrilla/proxy/web_ui/templates/packages/show_single_version.html.jinja b/src/hydrilla/proxy/web_ui/templates/packages/show_single_version.html.jinja index aa01272..4d4f1d5 100644 --- a/src/hydrilla/proxy/web_ui/templates/packages/show_single_version.html.jinja +++ b/src/hydrilla/proxy/web_ui/templates/packages/show_single_version.html.jinja @@ -22,6 +22,11 @@ in a proprietary work, I am not going to enforce this in court. {% extends "packages/show_single.html.jinja" %} {% block title %} {{ _('web_ui.packages.single_version.title') }} {% endblock %} {% block main_info %} + {% if file_installation_error is defined %} + + {% endif %} {% if uninstall_disallowed is defined %}