hgext/obsolete.py
changeset 282 05ab164c6593
parent 279 0d87b1fbf32b
child 285 691cb55358b0
--- a/hgext/obsolete.py	Tue Jun 19 17:05:39 2012 +0200
+++ b/hgext/obsolete.py	Tue Jun 19 18:05:23 2012 +0200
@@ -225,17 +225,23 @@
     rebaseset = repo.revs('%ld - extinct()', rebaseset)
     return orig(repo, dest, rebaseset, *ags, **kws)
 
+def defineparents(orig, repo, rev, target, state, *args, **kwargs):
+    rebasestate = getattr(repo, '_rebasestate', None)
+    if rebasestate is not None:
+        repo._rebasestate = dict(state)
+        repo._rebasetarget = target
+    return orig(repo, rev, target, state, *args, **kwargs)
 
-def concludenode(orig, repo, rev, *args, **kwargs):
+def concludenode(orig, repo, rev, p1, *args, **kwargs):
     """wrapper for rebase 's concludenode that set obsolete relation"""
-    newrev = orig(repo, rev, *args, **kwargs)
-    oldnode = repo[rev].node()
-    if newrev is not None:
-        newnode = repo[newrev].node()
-    else:
-        # Revision was emptied and removed, there is no successor.
-        newnode = nullid
-    repo.addobsolete(newnode, oldnode)
+    newrev = orig(repo, rev, p1, *args, **kwargs)
+    rebasestate = getattr(repo, '_rebasestate', None)
+    if rebasestate is not None:
+        if newrev is not None:
+            nrev = repo[newrev].rev()
+        else:
+            nrev = p1
+        repo._rebasestate[rev] = nrev
     return newrev
 
 def cmdrebase(orig, ui, repo, *args, **kwargs):
@@ -244,8 +250,45 @@
                            'extension'), hint=_("see 'hg help obsolete'"))
     kwargs = dict(kwargs)
     kwargs['keep'] = True
-    return orig(ui, repo, *args, **kwargs)
 
+    # We want to mark rebased revision as obsolete and set their
+    # replacements if any. Doing it in concludenode() prevents
+    # aborting the rebase, and is not called with all relevant
+    # revisions in --collapse case. Instead, we try to track the
+    # rebase state structure by sampling/updating it in
+    # defineparents() and concludenode(). The obsolete markers are
+    # added from this state after a successful call.
+    repo._rebasestate = {}
+    repo._rebasetarget = None
+    maxrev = len(repo) - 1
+    try:
+        res = orig(ui, repo, *args, **kwargs)
+        if not res and not kwargs.get('abort') and repo._rebasetarget:
+            # We have to tell rewritten revisions from removed
+            # ones. When collapsing, removed revisions are considered
+            # to be collapsed onto the final one, while in the normal
+            # case their are marked obsolete without successor.
+            emptynode = nullid
+            if kwargs.get('collapse'):
+                emptynode = repo[max(repo._rebasestate.values())].node()
+            # Rebased revisions are assumed to be descendants of
+            # targetrev. If a source revision is mapped to targetrev
+            # or to another rebased revision, it must have been
+            # removed.
+            targetrev = repo[repo._rebasetarget].rev()
+            newrevs = set([targetrev])
+            for rev, newrev in sorted(repo._rebasestate.items()):
+                oldnode = repo[rev].node()
+                if newrev not in newrevs and newrev >= 0:
+                    newnode = repo[newrev].node()
+                    newrevs.add(newrev)
+                else:
+                    newnode = emptynode
+                repo.addobsolete(newnode, oldnode)
+        return res
+    finally:
+        delattr(repo, '_rebasestate')
+        delattr(repo, '_rebasetarget')
 
 
 def extsetup(ui):
@@ -262,6 +305,7 @@
         rebase = extensions.find('rebase')
         if rebase:
             extensions.wrapfunction(rebase, 'buildstate', buildstate)
+            extensions.wrapfunction(rebase, 'defineparents', defineparents)
             extensions.wrapfunction(rebase, 'concludenode', concludenode)
             extensions.wrapcommand(rebase.cmdtable, "rebase", cmdrebase)
     except KeyError: