mercurial/localrepo.py
changeset 31994 b36318e6d2ef
parent 31819 95a67508fd72
child 31995 fe9c4d614600
--- a/mercurial/localrepo.py	Tue Mar 28 05:06:56 2017 +0200
+++ b/mercurial/localrepo.py	Tue Mar 28 06:38:09 2017 +0200
@@ -1001,8 +1001,54 @@
         vfsmap = {'plain': self.vfs} # root of .hg/
         # we must avoid cyclic reference between repo and transaction.
         reporef = weakref.ref(self)
-        def validate(tr):
+        # Code to track tag movement
+        #
+        # Since tags are all handled as file content, it is actually quite hard
+        # to track these movement from a code perspective. So we fallback to a
+        # tracking at the repository level. One could envision to track changes
+        # to the '.hgtags' file through changegroup apply but that fails to
+        # cope with case where transaction expose new heads without changegroup
+        # being involved (eg: phase movement).
+        #
+        # For now, We gate the feature behind a flag since this likely comes
+        # with performance impacts. The current code run more often than needed
+        # and do not use caches as much as it could.  The current focus is on
+        # the behavior of the feature so we disable it by default. The flag
+        # will be removed when we are happy with the performance impact.
+        tracktags = lambda x: None
+        # experimental config: experimental.hook-track-tags
+        shouldtracktags = self.ui.configbool('experimental', 'hook-track-tags',
+                                             False)
+        if desc != 'strip' and shouldtracktags:
+            oldheads = self.changelog.headrevs()
+            def tracktags(tr2):
+                repo = reporef()
+                oldfnodes = tagsmod.fnoderevs(repo.ui, repo, oldheads)
+                newheads = repo.changelog.headrevs()
+                newfnodes = tagsmod.fnoderevs(repo.ui, repo, newheads)
+                # notes: we compare lists here.
+                # As we do it only once buiding set would not be cheaper
+                if oldfnodes != newfnodes:
+                    tr2.hookargs['tag_moved'] = '1'
+        def validate(tr2):
             """will run pre-closing hooks"""
+            # XXX the transaction API is a bit lacking here so we take a hacky
+            # path for now
+            #
+            # We cannot add this as a "pending" hooks since the 'tr.hookargs'
+            # dict is copied before these run. In addition we needs the data
+            # available to in memory hooks too.
+            #
+            # Moreover, we also need to make sure this runs before txnclose
+            # hooks and there is no "pending" mechanism that would execute
+            # logic only if hooks are about to run.
+            #
+            # Fixing this limitation of the transaction is also needed to track
+            # other families of changes (bookmarks, phases, obsolescence).
+            #
+            # This will have to be fixed before we remove the experimental
+            # gating.
+            tracktags(tr2)
             reporef().hook('pretxnclose', throw=True,
                            txnname=desc, **pycompat.strkwargs(tr.hookargs))
         def releasefn(tr, success):