[PATCH lists.sr.ht] Remove unidiff in favor of pygit2
Export this patch
Closes https://todo.sr.ht/~sircmpwn/lists.sr.ht/101
---
listssrht/blueprints/patches.py | 12 ++++--------
listssrht/filters.py | 24 ++++++++++--------------
listssrht/process.py | 9 ++++-----
listssrht/types/email.py | 20 ++++++++++++--------
setup.py | 1 -
5 files changed, 30 insertions(+), 36 deletions(-)
diff --git a/listssrht/blueprints/patches.py b/listssrht/blueprints/patches.py
index 1de8ada..d37050d 100644
--- a/listssrht/blueprints/patches.py
+++ b/listssrht/blueprints/patches.py
@@ -84,14 +84,10 @@ def gen_cover_letter(patches):
insertions = deletions = 0
for email in patches:
cover += f" {email.patch_subject}\n"
- patch = email.patch()
- nfiles += (len(patch.added_files)
- + len(patch.modified_files)
- + len(patch.removed_files))
- insertions += sum(f.added for
- f in patch.added_files + patch.modified_files)
- deletions += sum(f.removed
- for f in patch.removed_files + patch.modified_files)
+ stats = email.patch().stats
+ nfiles += stats.files_changed
+ insertions += stats.insertions
+ deletions += stats.deletions
cover += f"\n {nfiles} files changed, {insertions} insertions(+), {deletions} deletions(-)\n"
return cover
diff --git a/listssrht/filters.py b/listssrht/filters.py
index d604c5a..63e3f18 100644
--- a/listssrht/filters.py
+++ b/listssrht/filters.py
@@ -21,18 +21,15 @@ def _format_patch(msg, limit=None):
text = Markup("")
is_diff = False
- def get_path(f):
- # [2:] to remove a/ or b/
- return f.target_file[2:].strip()
-
# Predict the starting lines of each file name
patch = msg.patch()
+ old_files = {delta.old_file.path for delta in patch.deltas}
+ new_files = {delta.new_file.path for delta in patch.deltas}
file_lines = {
- f" {get_path(f)} ": f
- for f in patch.added_files + patch.modified_files + patch.removed_files
+ f" {p} ": p for p in old_files | new_files
}
-
line_no = 0
+
for line in msg.body.replace("\r", "").split("\n"):
line_no += 1
if line_no == limit:
@@ -48,8 +45,7 @@ def _format_patch(msg, limit=None):
if f != None:
f = file_lines[f]
text += Markup(" <a href='#{}'>{}</a>".format(
- escape(msg.message_id) + "+" + escape(get_path(f)),
- escape(get_path(f))))
+ escape(msg.message_id) + "+" + escape(f), escape(f)))
try:
stat = line[line.rindex(" ") + 1:]
line = line[:line.rindex(" ") + 1]
@@ -71,7 +67,7 @@ def _format_patch(msg, limit=None):
stat = escape(stat)
except ValueError:
stat = Markup("")
- text += escape(line[len(get_path(f)) + 1:])
+ text += escape(line[len(f) + 1:])
text += escape(stat)
text += Markup("\n")
else:
@@ -143,9 +139,9 @@ def format_body(msg, limit=None):
text += Markup(urlize(escape(line), rel="noopener nofollow")) + "\n"
return text.rstrip()
-def diffstat(patch):
- p = patch.patch()
+def diffstat(patch_email):
+ stats = patch_email.patch().stats
return type("diffstat", tuple(), {
- "added": sum(f.added for f in p.added_files + p.modified_files),
- "removed": sum(f.removed for f in p.removed_files + p.modified_files),
+ "added": stats.insertions,
+ "removed": stats.deletions,
})
diff --git a/listssrht/process.py b/listssrht/process.py
index 13e0a2d..eb1eedd 100644
--- a/listssrht/process.py
+++ b/listssrht/process.py
@@ -168,11 +168,10 @@ def _archive(dest, envelope):
# TODO: should we consider multiple text parts?
mail.body = part.get_payload(decode=True).decode(charset)
break
- try:
- patch = pygit2.Diff.parse_diff(mail.body.replace("\r\n", "\n"))
- mail.is_patch = len(patch) > 0
- except:
- mail.is_patch = False
+
+ # force lazy parse of patch (if it exists) after msg body is set
+ mail.patch()
+
mail.is_request_pull = False # TODO: Detect git request-pull
reply_to = envelope["In-Reply-To"]
diff --git a/listssrht/types/email.py b/listssrht/types/email.py
index c4d7ff1..2f75120 100644
--- a/listssrht/types/email.py
+++ b/listssrht/types/email.py
@@ -1,9 +1,8 @@
import email
import io
+import pygit2
import sqlalchemy as sa
-from email import policy
from srht.database import Base
-from unidiff import PatchSet
class Email(Base):
__tablename__ = 'email'
@@ -100,11 +99,16 @@ class Email(Base):
self._parsed._email = self
return self._parsed
+ # libgit2 Diff object parsed from message body (if it exists)
def patch(self):
- if not self.is_patch:
- return None
- if hasattr(self, "_patch"):
+ if not hasattr(self, "_patch"):
+ try:
+ self._patch = pygit2.Diff.parse_diff(self.body.replace("\r\n", "\n"))
+ self.is_patch = len(self._patch) > 0
+ except:
+ self.is_patch = False
+
+ if self.is_patch:
return self._patch
- with io.StringIO(self.body) as f:
- self._patch = PatchSet(f)
- return self._patch
+
+ return None
diff --git a/setup.py b/setup.py
index 9ac7ce2..0ddbb6c 100755
--- a/setup.py
+++ b/setup.py
@@ -57,7 +57,6 @@ setup(
'flask-login',
'aiosmtpd',
'asyncpg',
- 'unidiff',
],
license = 'AGPL-3.0',
package_data={
--
2.23.0