changeset 35266:496154e41968

bundle2: support a 'records' mode for the 'bookmarks' part In this mode, the bookmarks changes are record in the 'bundleoperation' records instead of inflicted to the repository. This is necessary to use the part when pulling.
author Boris Feld <boris.feld@octobus.net>
date Tue, 17 Oct 2017 15:26:16 +0200
parents 1f30cbac34b6
children cb4dcd7fabe7
files mercurial/bundle2.py
diffstat 1 files changed, 43 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/bundle2.py	Tue Oct 17 15:39:34 2017 +0200
+++ b/mercurial/bundle2.py	Tue Oct 17 15:26:16 2017 +0200
@@ -1982,40 +1982,55 @@
 def handlebookmark(op, inpart):
     """transmit bookmark information
 
-    The part contains binary encoded bookmark information. The bookmark
-    information is applied as is to the unbundling repository. Make sure a
-    'check:bookmarks' part is issued earlier to check for race condition in
-    such update.
+    The part contains binary encoded bookmark information.
+
+    The exact behavior of this part can be controlled by the 'bookmarks' mode
+    on the bundle operation.
 
-    This behavior is suitable for pushing. Semantic adjustment will be needed
-    for pull.
+    When mode is 'apply' (the default) the bookmark information is applied as
+    is to the unbundling repository. Make sure a 'check:bookmarks' part is
+    issued earlier to check for push races in such update. This behavior is
+    suitable for pushing.
+
+    When mode is 'records', the information is recorded into the 'bookmarks'
+    records of the bundle operation. This behavior is suitable for pulling.
     """
     changes = bookmarks.binarydecode(inpart)
 
-    tr = op.gettransaction()
-    bookstore = op.repo._bookmarks
+    pushkeycompat = op.repo.ui.configbool('server', 'bookmarks-pushkey-compat')
+    bookmarksmode = op.modes.get('bookmarks', 'apply')
 
-    pushkeycompat = op.repo.ui.configbool('server', 'bookmarks-pushkey-compat')
-    if pushkeycompat:
-        allhooks = []
+    if bookmarksmode == 'apply':
+        tr = op.gettransaction()
+        bookstore = op.repo._bookmarks
+        if pushkeycompat:
+            allhooks = []
+            for book, node in changes:
+                hookargs = tr.hookargs.copy()
+                hookargs['pushkeycompat'] = '1'
+                hookargs['namespace'] = 'bookmark'
+                hookargs['key'] = book
+                hookargs['old'] = nodemod.hex(bookstore.get(book, ''))
+                hookargs['new'] = nodemod.hex(node if node is not None else '')
+                allhooks.append(hookargs)
+
+            for hookargs in allhooks:
+                op.repo.hook('prepushkey', throw=True, **hookargs)
+
+        bookstore.applychanges(op.repo, op.gettransaction(), changes)
+
+        if pushkeycompat:
+            def runhook():
+                for hookargs in allhooks:
+                    op.repo.hook('prepushkey', **hookargs)
+            op.repo._afterlock(runhook)
+
+    elif bookmarksmode == 'records':
         for book, node in changes:
-            hookargs = tr.hookargs.copy()
-            hookargs['pushkeycompat'] = '1'
-            hookargs['namespace'] = 'bookmark'
-            hookargs['key'] = book
-            hookargs['old'] = nodemod.hex(bookstore.get(book, ''))
-            hookargs['new'] = nodemod.hex(node if node is not None else '')
-            allhooks.append(hookargs)
-        for hookargs in allhooks:
-            op.repo.hook('prepushkey', throw=True, **hookargs)
-
-    bookstore.applychanges(op.repo, tr, changes)
-
-    if pushkeycompat:
-        def runhook():
-            for hookargs in allhooks:
-                op.repo.hook('prepushkey', **hookargs)
-        op.repo._afterlock(runhook)
+            record = {'bookmark': book, 'node': node}
+            op.records.add('bookmarks', record)
+    else:
+        raise error.ProgrammingError('unkown bookmark mode: %s' % bookmarksmode)
 
 @parthandler('phase-heads')
 def handlephases(op, inpart):