RFC: Perfarce extension change of behaviour in "latest" calculation

Frank Kingswood frank at kingswood-consulting.co.uk
Tue Jun 15 07:39:10 UTC 2010


Hi!

The perfarce extension currently uses a naive algorithm to detemine the 
latest p4 revision, which is reported by "hg p4id" and (more importantly) as 
the base revision on which to apply incoming p4 changelists.

The current algorithm counts back from the highest hg revision number until 
it finds a revision with the p4 changelist number set. It then searches the 
child revisions for any that change only .hgtags, and will use the first one 
it finds. The algorithm ignores the shape of the revision graph and named 
branches.

This is not usually a problem because the p4 revision history itself is 
strictly linear. However, if there are branches in the hg tree then it may 
lead to problems. The scan for .hgtags is also problematic, there could be 
multiple child revisions. Finally, the test for .hgtags needs extending to 
cover other not-pushed-or-pulled files (everything starting with .hg in the 
hg root).

I've been running with a patch that walks the revision graph from the tip of 
the default branch back, and remembers any nodes with only changes to .hg*, 
and this works fine for me.

If you're a perfarce user, will this cause problems for you?

Frank

diff -r dbdcbe5c15bb -r c4d342f969dc perfarce.py
--- a/perfarce.py	Wed May 19 11:40:45 2010 +0100
+++ b/perfarce.py	Tue Jun 01 10:13:08 2010 +0100
@@ -192,18 +192,29 @@

      def latest(self, tags=False):
          '''Find the most recent changelist which has the p4 extra data which
-        gives the p4 changelist it was converted from'''
-        for rev in xrange(len(self.repo)-1, -1, -1):
-            ctx = self.repo[rev]
+        gives the p4 changelist it was converted from.
+        Returns the revision and p4 changelist number'''
+
+        def dothgonly(ctx):
+            'returns True if only .hg files in this context'
+            for f in ctx.files():
+                if not f.startswith('.hg'):
+                    return False
+            return True
+
+        lasthg = None
+        ctx = self.repo['default']
+        while ctx.node() != node.nullid:
              extra = ctx.extra()
              if 'p4' in extra:
-                if tags:
-                    # if there is a child with p4 tags then return the child 
revision
-                    for ctx2 in ctx.children():
-                        if ctx2.description().startswith('p4 tags\n') and 
".hgtags" in ctx2:
-                            ctx = ctx2
-                            break
-                return ctx.node(), int(extra['p4'])
+                return (tags and lasthg or ctx).node(), int(extra['p4'])
+            elif dothgonly(ctx):
+                if lasthg is None:
+                    lasthg = ctx
+            else:
+                lasthg = None
+            ctx = ctx.parents()[0]
+
          raise util.Abort(_('no p4 changelist revision found'))

-- 
------------------------------------------------------------------------
Frank A. Kingswood                      frank at kingswood-consulting.co.uk
Cambridge, United Kingdom                               +44-870-095 0000



More information about the Mercurial-devel mailing list