diff --git a/spkrepo/models.py b/spkrepo/models.py index 6394480..c94dc53 100644 --- a/spkrepo/models.py +++ b/spkrepo/models.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +import hashlib import io import os import shutil @@ -360,6 +361,24 @@ def save(self, stream): ) as f: f.write(stream.read()) + def calculate_md5(self): + if not self.path: + raise ValueError("Path cannot be empty.") + + file_path = os.path.join(current_app.config["DATA_PATH"], self.path) + + if not os.path.exists(file_path): + raise FileNotFoundError(f"File not found at path: {file_path}") + + if self.md5 is None: + with io.open(file_path, "rb") as f: + md5_hash = hashlib.md5() + for chunk in iter(lambda: f.read(4096), b""): + md5_hash.update(chunk) + return md5_hash.hexdigest() + + return self.md5 + def _after_insert(self): assert os.path.exists(os.path.join(current_app.config["DATA_PATH"], self.path)) diff --git a/spkrepo/tests/common.py b/spkrepo/tests/common.py index cb43261..1682b9b 100644 --- a/spkrepo/tests/common.py +++ b/spkrepo/tests/common.py @@ -281,8 +281,7 @@ def create_spk(self, create, extracted, **kwargs): with create_spk(self) as spk_stream: self.save(spk_stream) if self.md5 is None: - spk_stream.seek(0) - self.md5 = hashlib.md5(spk_stream.read()).hexdigest() + self.md5 = self.calculate_md5() spk_stream.close() @classmethod diff --git a/spkrepo/utils.py b/spkrepo/utils.py index c5d4043..aa0b0ab 100644 --- a/spkrepo/utils.py +++ b/spkrepo/utils.py @@ -345,6 +345,18 @@ def unsign(self): self.stream.truncate() self.stream.seek(0) + def calculate_md5(self): + md5_hash = hashlib.md5() + + # Ensure the stream position is at the beginning + self.stream.seek(0) + + # Update MD5 hash directly from the stream + for chunk in iter(lambda: self.stream.read(4096), b""): + md5_hash.update(chunk) + + return md5_hash.hexdigest() + def _generate_signature(self, stream, timestamp_url, gnupghome): # pragma: no cover # generate the signature gpg = gnupg.GPG(gnupghome=gnupghome) diff --git a/spkrepo/views/admin.py b/spkrepo/views/admin.py index 943ecff..0b096de 100644 --- a/spkrepo/views/admin.py +++ b/spkrepo/views/admin.py @@ -428,8 +428,11 @@ def action_sign(self, ids): current_app.config["GNUPG_TIMESTAMP_URL"], current_app.config["GNUPG_PATH"], ) + build.md5 = spk.calculate_md5() + self.session.commit() success.append(filename) except Exception: + self.session.rollback() failed.append(filename) if failed: if len(failed) == 1: @@ -479,8 +482,11 @@ def action_unsign(self, ids): continue try: spk.unsign() + build.md5 = spk.calculate_md5() + self.session.commit() success.append(filename) except Exception: + self.session.rollback() failed.append(filename) if failed: if len(failed) == 1: @@ -683,8 +689,11 @@ def action_sign(self, ids): current_app.config["GNUPG_TIMESTAMP_URL"], current_app.config["GNUPG_PATH"], ) + build.md5 = spk.calculate_md5() + self.session.commit() success.append(filename) except Exception: + self.session.rollback() failed.append(filename) if failed: if len(failed) == 1: @@ -733,8 +742,11 @@ def action_unsign(self, ids): continue try: spk.unsign() + build.md5 = spk.calculate_md5() + self.session.commit() success.append(filename) except Exception: + self.session.rollback() failed.append(filename) if failed: if len(failed) == 1: diff --git a/spkrepo/views/api.py b/spkrepo/views/api.py index 9580bfd..593a73f 100644 --- a/spkrepo/views/api.py +++ b/spkrepo/views/api.py @@ -278,6 +278,8 @@ def post(self): for size, icon in build.version.icons.items(): icon.save(spk.icons[size]) build.save(spk.stream) + # generate md5 hash + build.md5 = build.calculate_md5() except Exception as e: # pragma: no cover if create_package: shutil.rmtree(os.path.join(data_path, package.name), ignore_errors=True)