[patch] auto merge code refactoring



Hi,

I am sending a patch that reorganises the code of the auto merge classes a bit. It extracts a new class called AutoMergeDiffer and reduces the role of Merger class to file merging only. This change should make the code easier to use and enhance in the future and allows to avoid confusing stuff like creating a second instance of Merger to avoid highlighting issues (see https://bugzilla.gnome.org/show_bug.cgi?id=578613). The next step will be to add support for merging all non-conflicting changes between 2 files in 3-way diff. Some redundant code in AutoMergeDiffer is also replaced with a call to Differ._auto_merge.
The patch is attached to the above-mentioned ticket in Bugzilla too.

Cheers,
Piotr
From 1df785d2029fa7c782bd1d66e220d587e2031154 Mon Sep 17 00:00:00 2001
From: Piotr Piastucki <leech miranda gmail com>
Date: Fri, 12 Mar 2010 11:53:23 +0100
Subject: [PATCH] Refactor auto-merge classes

A new class called AutoMergeDiffer is extracted from Merger class to separate the functionality.
AutomMergeDiffer is supposed to be a drop-in replacement for Differ while Merger class handles file merging only.
This change also prepares ground for adding 2 file merge support to Merger.
Moreover, some redundant code is removed from AutoMergeDiffer and replaced with a proper call to Differ._auto_merge
---
 meld/filemerge.py |    6 ++--
 meld/merge.py     |   65 ++++++++++++++++++++++++++---------------------------
 2 files changed, 35 insertions(+), 36 deletions(-)

diff --git a/meld/filemerge.py b/meld/filemerge.py
index 87349dc..80b06ec 100644
--- a/meld/filemerge.py
+++ b/meld/filemerge.py
@@ -26,7 +26,7 @@ class FileMerge(filediff.FileDiff):
 
     def __init__(self, prefs, num_panes):
         filediff.FileDiff.__init__(self, prefs, num_panes)
-        self.linediffer = merge.Merger()
+        self.linediffer = merge.AutoMergeDiffer()
         self.hidden_textbuffer = gtk.TextBuffer()
 
     def _connect_buffer_handlers(self):
@@ -71,11 +71,11 @@ class FileMerge(filediff.FileDiff):
         filteredpanetext = [self._filter_text(p) for p in panetext]
         filteredlines = map(lambda x: x.split("\n"), filteredpanetext)
         merger = merge.Merger()
-        step = merger.set_sequences_iter(filteredlines)
+        step = merger.initialize(filteredlines, lines)
         while step.next() == None:
             yield 1
         yield _("[%s] Merging files") % self.label_text
-        for panetext[1] in merger.merge_file(filteredlines, lines):
+        for panetext[1] in merger.merge_3_files():
             yield 1
         self.linediffer.unresolved = merger.unresolved
         self.textbuffer[1].insert(self.textbuffer[1].get_end_iter(), panetext[1])
diff --git a/meld/merge.py b/meld/merge.py
index 5f0e926..a38ff2d 100644
--- a/meld/merge.py
+++ b/meld/merge.py
@@ -19,7 +19,7 @@ import matchers
 #from _patiencediff_py import PatienceSequenceMatcher_py as PatienceSequenceMatcher
 
 
-class Merger(diffutil.Differ):
+class AutoMergeDiffer(diffutil.Differ):
 
     _matcher = matchers.MyersSequenceMatcher
    # _matcher = PatienceSequenceMatcher
@@ -30,23 +30,10 @@ class Merger(diffutil.Differ):
         self.unresolved = []
 
     def _auto_merge(self, using, texts):
-        l0, h0, l1, h1, l2, h2 = self._merge_blocks(using)
-
-        if h0 - l0 == h2 - l2 and texts[0][l0:h0] == texts[2][l2:h2]:
-            # handle simple conflicts here (exact match)
-            if l1 != h1 and l0 == h0:
-                tag = "delete"
-            elif l1 != h1:
-                tag = "replace"
-            else:
-                tag = "insert"
-            out0 = (tag, l1, h1, l0, h0)
-            out1 = (tag, l1, h1, l2, h2)
-        else:
-            # here we will try to resolve more complex conflicts automatically... if possible
-            out0 = ('conflict', l1, h1, l0, h0)
-            out1 = ('conflict', l1, h1, l2, h2)
-            if self.auto_merge:
+        for out0, out1 in diffutil.Differ._auto_merge(self, using, texts):
+            if self.auto_merge and out0[0] == 'conflict':
+                # here we will try to resolve more complex conflicts automatically here... if possible
+                l0, h0, l1, h1, l2, h2 = out0[3], out0[4], out0[1], out0[2], out1[3], out1[4]
                 len0 = h0 - l0
                 len1 = h1 - l1
                 len2 = h2 - l2
@@ -145,7 +132,7 @@ class Merger(diffutil.Differ):
                             out1 = ('conflict', i1, seq1[2], seq1[3], seq1[4])
                             yield out0, out1
                         return
-        yield out0, out1
+            yield out0, out1
 
     def change_sequence(self, sequence, startidx, sizechange, texts):
         if sequence == 1:
@@ -173,6 +160,21 @@ class Merger(diffutil.Differ):
     def get_unresolved_count(self):
         return len(self.unresolved)
 
+class Merger(diffutil.Differ):
+
+    def __init__(self, ):
+        self.differ = AutoMergeDiffer()
+        self.differ.auto_merge = True
+        self.differ.unresolved = []
+        self.texts = []
+
+    def initialize(self, sequences, texts):
+        step = self.differ.set_sequences_iter(sequences)
+        while step.next() == None:
+            yield None
+        self.texts = texts
+        yield 1
+
     def _apply_change(self, text, change, mergedtext):
         LO, HI = 1, 2
         if change[0] == 'insert':
@@ -186,15 +188,13 @@ class Merger(diffutil.Differ):
         else:
             return change[HI] - change[LO]
 
-    def merge_file(self, filteredtexts, texts):
+    def merge_3_way(self):
         LO, HI = 1, 2
-        self.auto_merge = True
-        self.unresolved = unresolved = []
-        diffs = self.diffs
+        self.unresolved = []
         lastline = 0
         mergedline = 0
         mergedtext = []
-        for change in self._merge_diffs(diffs[0], diffs[1], filteredtexts):
+        for change in self.differ.all_changes():
             yield None
             low_mark = lastline
             if change[0] != None:
@@ -203,32 +203,31 @@ class Merger(diffutil.Differ):
                 if change[1][LO] > low_mark:
                     low_mark = change[1][LO]
             for i in range(lastline, low_mark, 1):
-                mergedtext.append(texts[1][i])
+                mergedtext.append(self.texts[1][i])
             mergedline += low_mark - lastline
             lastline = low_mark
             if change[0] != None and change[1] != None and change[0][0] == 'conflict':
                 high_mark = max(change[0][HI], change[1][HI])
                 if low_mark < high_mark:
                     for i in range(low_mark, high_mark):
-                        mergedtext.append("(??)" + texts[1][i])
-                        unresolved.append(mergedline)
+                        mergedtext.append("(??)" + self.texts[1][i])
+                        self.unresolved.append(mergedline)
                         mergedline += 1
                 else:
                     #conflictsize = min(1, max(change[0][HI + 2] - change[0][LO + 2], change[1][HI + 2] - change[1][LO + 2]))
                     #for i in range(conflictsize):
                     mergedtext.append("(??)")
-                    unresolved.append(mergedline)
+                    self.unresolved.append(mergedline)
                     mergedline += 1
                 lastline = high_mark
             elif change[0] != None:
-                lastline += self._apply_change(texts[0], change[0], mergedtext)
+                lastline += self._apply_change(self.texts[0], change[0], mergedtext)
                 mergedline += change[0][HI + 2] - change[0][LO + 2]
             else:
-                lastline += self._apply_change(texts[2], change[1], mergedtext)
+                lastline += self._apply_change(self.texts[2], change[1], mergedtext)
                 mergedline += change[1][HI + 2] - change[1][LO + 2]
-        baselen = len(texts[1])
+        baselen = len(self.texts[1])
         for i in range(lastline, baselen, 1):
-            mergedtext.append(texts[1][i])
+            mergedtext.append(self.texts[1][i])
 
-        self.auto_merge = False
         yield "\n".join(mergedtext)
-- 
1.6.3.3



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]