aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--patchwork/parser.py45
-rw-r--r--patchwork/tests/test_parser.py8
2 files changed, 41 insertions, 12 deletions
diff --git a/patchwork/parser.py b/patchwork/parser.py
index c0084cc..45dd8db 100644
--- a/patchwork/parser.py
+++ b/patchwork/parser.py
@@ -61,6 +61,11 @@ class DuplicateMailError(Exception):
self.msgid = msgid
+class DuplicateSeriesError(Exception):
+
+ pass
+
+
def normalise_space(value):
whitespace_re = re.compile(r'\s+')
return whitespace_re.sub(' ', value).strip()
@@ -256,8 +261,10 @@ def _find_series_by_references(project, mail):
refs = [h] + refs
for ref in refs:
try:
- return SeriesReference.objects.get(
+ series = SeriesReference.objects.get(
msgid=ref[:255], project=project).series
+ # we want to return a queryset like '_find_series_by_markers'
+ return Series.objects.filter(id=series.id)
except SeriesReference.DoesNotExist:
continue
@@ -294,12 +301,9 @@ def _find_series_by_markers(project, mail, author):
start_date = date - delta
end_date = date + delta
- try:
- return Series.objects.get(
- submitter=author, project=project, version=version, total=total,
- date__range=[start_date, end_date])
- except (Series.DoesNotExist, Series.MultipleObjectsReturned):
- return
+ return Series.objects.filter(
+ submitter=author, project=project, version=version, total=total,
+ date__range=[start_date, end_date])
def find_series(project, mail, author):
@@ -1094,6 +1098,23 @@ def parse_mail(mail, list_id=None):
series = None
if n:
series = find_series(project, mail, author)
+ if len(series) > 1:
+ # if this isn't our final attempt, go again
+ if attempt != 10:
+ raise DuplicateSeriesError()
+
+ # if it is and we still haven't been able to save a
+ # series, it's time to give up and just save yet
+ # another duplicate - find the best possible match
+ for series in series.order_by('-date'):
+ if Patch.objects.filter(
+ series=series, number=x).count():
+ continue
+ break
+ else:
+ series = None
+ elif len(series) == 1:
+ series = series.first()
else:
x = n = 1
@@ -1130,8 +1151,16 @@ def parse_mail(mail, list_id=None):
except SeriesReference.DoesNotExist:
SeriesReference.objects.create(
msgid=ref, project=project, series=series)
+
+ # attempt to pull the series in again, raising an
+ # exception if we lost the race when creating a series
+ # and force us to go through this again
+ if attempt != 10 and find_series(
+ project, mail, author).count() > 1:
+ raise DuplicateSeriesError()
+
break
- except IntegrityError:
+ except (IntegrityError, DuplicateSeriesError):
# we lost the race so go again
logger.warning('Conflict while saving series. This is '
'probably because multiple patches belonging '
diff --git a/patchwork/tests/test_parser.py b/patchwork/tests/test_parser.py
index 0edbd87..4a85fd4 100644
--- a/patchwork/tests/test_parser.py
+++ b/patchwork/tests/test_parser.py
@@ -400,8 +400,8 @@ class SeriesCorrelationTest(TestCase):
email = self._create_email(msgid)
project = create_project()
- self.assertIsNone(find_series(project, email,
- get_or_create_author(email)))
+ self.assertFalse(find_series(project, email,
+ get_or_create_author(email)))
def test_first_reply(self):
msgid_a = make_msgid()
@@ -413,7 +413,7 @@ class SeriesCorrelationTest(TestCase):
series = find_series(ref.series.project, email,
get_or_create_author(email))
- self.assertEqual(series, ref.series)
+ self.assertEqual(series.first(), ref.series)
def test_nested_series(self):
"""Handle a series sent in-reply-to an existing series."""
@@ -443,7 +443,7 @@ class SeriesCorrelationTest(TestCase):
# this should link to the second series - not the first
self.assertEqual(len(msgids), 4 + 1) # old series + new cover
- self.assertEqual(series, ref_v2.series)
+ self.assertEqual(series.first(), ref_v2.series)
class SubjectEncodingTest(TestCase):