[PATCH 1 of 2 RFC V2] largefiles: changed overridelog to work with graphlog

Lucas Moscovicz lmoscovicz at fb.com
Wed Mar 5 18:10:49 CST 2014


# HG changeset patch
# User Lucas Moscovicz <lmoscovicz at fb.com>
# Date 1394063709 28800
#      Wed Mar 05 15:55:09 2014 -0800
# Node ID 2367ddb8b07acef2ea7f72936c0ba46f47908205
# Parent  ef75710021e1c1dd2ef192c21b274313698186d4
largefiles: changed overridelog to work with graphlog

Log for largefiles was failing for graphlog since it was overriding match
instead of matchandpats.

Tests for graphlog to be added in future patches.

diff --git a/hgext/largefiles/overrides.py b/hgext/largefiles/overrides.py
--- a/hgext/largefiles/overrides.py
+++ b/hgext/largefiles/overrides.py
@@ -8,7 +8,7 @@
 
 '''Overridden Mercurial commands and functions for the largefiles extension'''
 
-import os
+import os, re, glob
 import copy
 
 from mercurial import hg, commands, util, cmdutil, scmutil, match as match_, \
@@ -47,6 +47,15 @@
     scmutil.match = f
     return oldmatch
 
+def installmatchandpatsfn(f):
+    oldmatchandpats = scmutil.matchandpats
+    setattr(f, 'oldmatchandpats', oldmatchandpats)
+    scmutil.matchandpats = f
+    return oldmatchandpats
+
+def installfilelogfn(f):
+    revset.symbols['filelog'] = f
+
 def restorematchfn():
     '''restores scmutil.match to what it was before installnormalfilesmatchfn
     was called.  no-op if scmutil.match is its original function.
@@ -55,6 +64,20 @@
     restore matchfn to reverse'''
     scmutil.match = getattr(scmutil.match, 'oldmatch', scmutil.match)
 
+def restorematchandpatsfn():
+    '''restores scmutil.matchandpats to what it was before
+    installnormalfilesmatchandpatsfn was called.  no-op if scmutil.matchandpats
+    is its original function.
+
+    Note that n calls to installnormalfilesmatchandpatsfn will require n calls
+    to restore matchfn to reverse'''
+    scmutil.matchandpats = getattr(scmutil.matchandpats, 'oldmatchandpats',
+            scmutil.matchandpats)
+
+def restorefilelogfn():
+    '''restores revset.filelog to what it was before.'''
+    revset.symbols['filelog'] = revset.filelog
+
 def addlargefiles(ui, repo, *pats, **opts):
     large = opts.pop('large', None)
     lfsize = lfutil.getminsize(
@@ -241,15 +264,15 @@
         repo._repo.lfstatus = False
 
 def overridelog(orig, ui, repo, *pats, **opts):
-    def overridematch(ctx, pats=[], opts={}, globbed=False,
+    def overridematchandpats(ctx, pats=[], opts={}, globbed=False,
             default='relpath'):
         """Matcher that merges root directory with .hglf, suitable for log.
         It is still possible to match .hglf directly.
         For any listed files run log on the standin too.
         matchfn tries both the given filename and with .hglf stripped.
         """
-        match = oldmatch(ctx, pats, opts, globbed, default)
-        m = copy.copy(match)
+        matchandpats = oldmatchandpats(ctx, pats, opts, globbed, default)
+        m, p = copy.copy(matchandpats)
         for i in range(0, len(m._files)):
             standin = lfutil.standin(m._files[i])
             if standin in repo[ctx.node()]:
@@ -264,14 +287,81 @@
             r = origmatchfn(f)
             return r
         m.matchfn = lfmatchfn
-        return m
-    oldmatch = installmatchfn(overridematch)
+
+        def expandpats(pats):
+            ret = []
+            for p in pats:
+                kind, name = match_._patsplit(p, None)
+                if kind is None:
+                    try:
+                        globbed = glob.glob(name)
+                    except re.error:
+                        globbed = [name]
+                    if globbed:
+                        ret.extend(globbed)
+                        for g in globbed:
+                            if not lfutil.isstandin(g):
+                                ret.append(lfutil.standin(g))
+                        continue
+                ret.append(p)
+            return ret
+
+        if pats == ("",):
+            pats = []
+        else:
+            pats = expandpats(pats or [])
+
+        for f in m.files():
+            if f not in pats:
+                pats.append(f)
+                if not lfutil.isstandin(f):
+                    slf = lfutil.standin(f)
+                else:
+                    slf = lfutil.splitstandin(f)
+                if not slf in pats:
+                    pats.append(slf)
+        return m, pats
+
+    def overridefilelog(repo, subset, x):
+        """``filelog(pattern)``
+        Changesets connected to the specified filelog.
+
+        For performance reasons, ``filelog()`` does not show every changeset
+        that affects the requested file(s). See :hg:`help log` for details. For
+        a slower, more accurate result, use ``file()``.
+
+        The pattern without explicit kind like ``glob:`` is expected to be
+        relative to the current directory and match against a file exactly
+        for efficiency.
+        """
+
+        # i18n: "filelog" is a keyword
+        pat = revset.getstring(x, _("filelog requires a pattern"))
+        s = set()
+
+        if not match_.patkind(pat):
+            fl = repo.file(pat)
+            for fr in fl:
+                s.add(fl.linkrev(fr))
+        else:
+            m = match_.match(repo.root, repo.getcwd(), [pat], ctx=repo[None])
+            for f in repo[None]:
+                if m(f):
+                    fl = repo.file(f)
+                    for fr in fl:
+                        s.add(fl.linkrev(fr))
+
+        return subset.filter(lambda r: r in s)
+
+    oldmatchandpats = installmatchandpatsfn(overridematchandpats)
+    installfilelogfn(overridefilelog)
     try:
         repo.lfstatus = True
         return orig(ui, repo, *pats, **opts)
     finally:
         repo.lfstatus = False
-        restorematchfn()
+        restorematchandpatsfn()
+        restorefilelogfn()
 
 def overrideverify(orig, ui, repo, *pats, **opts):
     large = opts.pop('large', False)
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -428,7 +428,7 @@
         '''Return a list of revisions matching the given revset'''
         expr = revset.formatspec(expr, *args)
         m = revset.match(None, expr)
-        return revset.baseset([r for r in m(self, revset.baseset(self))])
+        return m(self, revset.spanset(self))
 
     def set(self, expr, *args):
         '''


More information about the Mercurial-devel mailing list