Print conflict details with the new infrastructure (bug #11181)
[stgit] / stgit / lib / transaction.py
index 7c7139c..54de127 100644 (file)
@@ -75,7 +75,7 @@ class StackTransaction(object):
       your refs and index+worktree, or fail without having done
       anything."""
     def __init__(self, stack, msg, discard_changes = False,
-                 allow_conflicts = False):
+                 allow_conflicts = False, allow_bad_head = False):
         """Create a new L{StackTransaction}.
 
         @param discard_changes: Discard any changes in index+worktree
@@ -94,11 +94,14 @@ class StackTransaction(object):
         self.__base = self.__stack.base
         self.__discard_changes = discard_changes
         self.__bad_head = None
+        self.__conflicts = None
         if isinstance(allow_conflicts, bool):
             self.__allow_conflicts = lambda trans: allow_conflicts
         else:
             self.__allow_conflicts = allow_conflicts
         self.__temp_index = self.temp_index_tree = None
+        if not allow_bad_head:
+            self.__assert_head_top_equal()
     stack = property(lambda self: self.__stack)
     patches = property(lambda self: self.__patches)
     def __set_applied(self, val):
@@ -137,13 +140,16 @@ class StackTransaction(object):
     def __set_head(self, val):
         self.__bad_head = val
     head = property(__get_head, __set_head)
-    def __checkout(self, tree, iw, allow_bad_head):
-        if not (allow_bad_head or self.__stack.head_top_equal()):
+    def __assert_head_top_equal(self):
+        if not self.__stack.head_top_equal():
             out.error(
                 'HEAD and top are not the same.',
                 'This can happen if you modify a branch with git.',
                 '"stg repair --help" explains more about what to do next.')
             self.__abort()
+    def __checkout(self, tree, iw, allow_bad_head):
+        if not allow_bad_head:
+            self.__assert_head_top_equal()
         if self.__current_tree == tree and not self.__discard_changes:
             # No tree change, but we still want to make sure that
             # there are no unresolved conflicts. Conflicts
@@ -176,7 +182,8 @@ class StackTransaction(object):
         if iw:
             self.__checkout(self.__stack.head.data.tree, iw,
                             allow_bad_head = True)
-    def run(self, iw = None, set_head = True, allow_bad_head = False):
+    def run(self, iw = None, set_head = True, allow_bad_head = False,
+            print_current_patch = True):
         """Execute the transaction. Will either succeed, or fail (with an
         exception) and do nothing."""
         self.__check_consistency()
@@ -195,7 +202,10 @@ class StackTransaction(object):
             self.__stack.set_head(new_head, self.__msg)
 
         if self.__error:
-            out.error(self.__error)
+            if self.__conflicts:
+                out.error(*([self.__error] + self.__conflicts))
+            else:
+                out.error(self.__error)
 
         # Write patches.
         def write(msg):
@@ -218,7 +228,8 @@ class StackTransaction(object):
             self.__patches = _TransPatchMap(self.__stack)
             self.__conflicting_push()
             write(self.__msg + ' (CONFLICT)')
-        _print_current_patch(old_applied, self.__applied)
+        if print_current_patch:
+            _print_current_patch(old_applied, self.__applied)
 
         if self.__error:
             return utils.STGIT_CONFLICT
@@ -254,7 +265,7 @@ class StackTransaction(object):
         self.__print_popped(popped)
         return popped1
 
-    def delete_patches(self, p):
+    def delete_patches(self, p, quiet = False):
         """Delete all patches pn for which p(pn) is true. Return the list of
         other patches that had to be popped to accomplish this. Always
         succeeds."""
@@ -273,7 +284,8 @@ class StackTransaction(object):
             if p(pn):
                 s = ['', ' (empty)'][self.patches[pn].data.is_nochange()]
                 self.patches[pn] = None
-                out.info('Deleted %s%s' % (pn, s))
+                if not quiet:
+                    out.info('Deleted %s%s' % (pn, s))
         return popped
 
     def push_patch(self, pn, iw = None):
@@ -282,7 +294,6 @@ class StackTransaction(object):
         conflicts to them."""
         orig_cd = self.patches[pn].data
         cd = orig_cd.set_committer(None)
-        s = ['', ' (empty)'][cd.is_nochange()]
         oldparent = cd.parent
         cd = cd.set_parent(self.top)
         base = oldparent.data.tree
@@ -290,6 +301,7 @@ class StackTransaction(object):
         theirs = cd.tree
         tree, self.temp_index_tree = self.temp_index.merge(
             base, ours, theirs, self.temp_index_tree)
+        s = ''
         merge_conflict = False
         if not tree:
             if iw == None:
@@ -303,9 +315,10 @@ class StackTransaction(object):
                 tree = iw.index.write_tree()
                 self.__current_tree = tree
                 s = ' (modified)'
-            except git.MergeConflictException:
+            except git.MergeConflictException, e:
                 tree = ours
                 merge_conflict = True
+                self.__conflicts = e.conflicts
                 s = ' (conflict)'
             except git.MergeException, e:
                 self.__halt(str(e))
@@ -313,9 +326,12 @@ class StackTransaction(object):
         if any(getattr(cd, a) != getattr(orig_cd, a) for a in
                ['parent', 'tree', 'author', 'message']):
             comm = self.__stack.repository.commit(cd)
+            self.head = comm
         else:
             comm = None
             s = ' (unmodified)'
+        if not merge_conflict and cd.is_nochange():
+            s = ' (empty)'
         out.info('Pushed %s%s' % (pn, s))
         def update():
             if comm:
@@ -333,7 +349,7 @@ class StackTransaction(object):
 
             # Save this update so that we can run it a little later.
             self.__conflicting_push = update
-            self.__halt('Merge conflict')
+            self.__halt("%d merge conflict(s)" % len(self.__conflicts))
         else:
             # Update immediately.
             update()