serveronly: deduplicate code with the main evolve extension
authorPierre-Yves David <pierre-yves.david@ens-lyon.org>
Tue, 28 Feb 2017 18:21:23 +0100
changeset 1838 6942750831bb
parent 1837 c8b07459c9bb
child 2020 143c8e4dc22d
serveronly: deduplicate code with the main evolve extension Now that 'serveonly' is a sub module of evolve. We can access its content in evolve. As a result we stop duplicating code all common parts are defined in the 'serveronly' module and imported by evolve when needed.
hgext3rd/evolve/__init__.py
hgext3rd/evolve/serveronly.py
tests/test-simple4server.t
--- a/hgext3rd/evolve/__init__.py	Tue Feb 28 16:12:34 2017 +0100
+++ b/hgext3rd/evolve/__init__.py	Tue Feb 28 18:21:23 2017 +0100
@@ -123,6 +123,10 @@
 from mercurial.i18n import _
 from mercurial.node import nullid
 
+from . import serveronly
+
+obsexcmsg = serveronly.obsexcmsg
+
 cmdtable = {}
 command = cmdutil.command(cmdtable)
 
@@ -387,6 +391,8 @@
 extsetup = eh.final_extsetup
 reposetup = eh.final_reposetup
 
+eh.extsetup(serveronly.extsetup)
+
 #####################################################################
 ### Option configuration                                          ###
 #####################################################################
@@ -3307,14 +3313,6 @@
 ### Obsolescence marker exchange experimenation                   ###
 #####################################################################
 
-def obsexcmsg(ui, message, important=False):
-    verbose = ui.configbool('experimental', 'verbose-obsolescence-exchange',
-                             False)
-    if verbose:
-        message = 'OBSEXC: ' + message
-    if important or verbose:
-        ui.status(message)
-
 def obsexcprg(ui, *args, **kwargs):
     topic = 'obsmarkers exchange'
     if ui.configbool('experimental', 'verbose-obsolescence-exchange', False):
@@ -3362,65 +3360,25 @@
             obsexcmsg(repo.ui, "markers already in sync\n")
             pushop.outobsmarkers = []
 
-@eh.wrapfunction(wireproto, 'capabilities')
-def discocapabilities(orig, repo, proto):
-    """wrapper to advertise new capability"""
-    caps = orig(repo, proto)
-    if obsolete.isenabled(repo, obsolete.exchangeopt):
-        caps += ' _evoext_obshash_0'
-    return caps
-
 @eh.extsetup
 def _installobsmarkersdiscovery(ui):
-    hgweb_mod.perms['evoext_obshash'] = 'pull'
-    hgweb_mod.perms['evoext_obshash1'] = 'pull'
-    # wrap command content
-    oldcap, args = wireproto.commands['capabilities']
-    def newcap(repo, proto):
-        return discocapabilities(oldcap, repo, proto)
-    wireproto.commands['capabilities'] = (newcap, args)
-    wireproto.commands['evoext_obshash'] = (srv_obshash, 'nodes')
-    wireproto.commands['evoext_obshash1'] = (srv_obshash1, 'nodes')
-    if getattr(exchange, '_pushdiscoveryobsmarkers', None) is None:
-        ui.warn(_('evolve: your mercurial version is too old\n'
-                  'evolve: (running in degraded mode, push will '
-                  'includes all markers)\n'))
-    else:
-        olddisco = exchange.pushdiscoverymapping['obsmarker']
-        def newdisco(pushop):
-            _pushdiscoveryobsmarkers(olddisco, pushop)
-        exchange.pushdiscoverymapping['obsmarker'] = newdisco
+    olddisco = exchange.pushdiscoverymapping['obsmarker']
+    def newdisco(pushop):
+        _pushdiscoveryobsmarkers(olddisco, pushop)
+    exchange.pushdiscoverymapping['obsmarker'] = newdisco
 
 ### Set discovery START
 
 from mercurial import dagutil
 from mercurial import setdiscovery
 
-def _obshash(repo, nodes, version=0):
-    if version == 0:
-        hashs = _obsrelsethashtreefm0(repo)
-    elif version ==1:
-        hashs = _obsrelsethashtreefm1(repo)
-    else:
-        assert False
-    nm = repo.changelog.nodemap
-    revs = [nm.get(n) for n in nodes]
-    return [r is None and nullid or hashs[r][1] for r in revs]
-
-def srv_obshash(repo, proto, nodes):
-    return wireproto.encodelist(_obshash(repo, wireproto.decodelist(nodes)))
-
-def srv_obshash1(repo, proto, nodes):
-    return wireproto.encodelist(_obshash(repo, wireproto.decodelist(nodes),
-                                version=1))
-
 @eh.addattr(localrepo.localpeer, 'evoext_obshash')
 def local_obshash(peer, nodes):
-    return _obshash(peer._repo, nodes)
+    return serveronly._obshash(peer._repo, nodes)
 
 @eh.addattr(localrepo.localpeer, 'evoext_obshash1')
 def local_obshash1(peer, nodes):
-    return _obshash(peer._repo, nodes, version=1)
+    return serveronly._obshash(peer._repo, nodes, version=1)
 
 @eh.addattr(wireproto.wirepeer, 'evoext_obshash')
 def peer_obshash(self, nodes):
@@ -3453,10 +3411,10 @@
     _takefullsample = setdiscovery._takefullsample
     if remote.capable('_evoext_obshash_1'):
         getremotehash = remote.evoext_obshash1
-        localhash = _obsrelsethashtreefm1(local)
+        localhash = serveronly._obsrelsethashtreefm1(local)
     else:
         getremotehash = remote.evoext_obshash
-        localhash = _obsrelsethashtreefm0(local)
+        localhash = serveronly._obsrelsethashtreefm0(local)
 
     while undecided:
 
@@ -3605,33 +3563,10 @@
     caps.add('_evoext_pushobsmarkers_0')
     return caps
 
-def _pushobsmarkers(repo, data):
-    tr = lock = None
-    try:
-        lock = repo.lock()
-        tr = repo.transaction('pushkey: obsolete markers')
-        new = repo.obsstore.mergemarkers(tr, data)
-        if new is not None:
-            obsexcmsg(repo.ui, "%i obsolescence markers added\n" % new, True)
-        tr.close()
-    finally:
-        lockmod.release(tr, lock)
-    repo.hook('evolve_pushobsmarkers')
-
 @eh.addattr(localrepo.localpeer, 'evoext_pushobsmarkers_0')
 def local_pushobsmarkers(peer, obsfile):
     data = obsfile.read()
-    _pushobsmarkers(peer._repo, data)
-
-def srv_pushobsmarkers(repo, proto):
-    """wireprotocol command"""
-    fp = StringIO()
-    proto.redirect()
-    proto.getfile(fp)
-    data = fp.getvalue()
-    fp.close()
-    _pushobsmarkers(repo, data)
-    return wireproto.pushres(0)
+    serveronly._pushobsmarkers(peer._repo, data)
 
 def _buildpullobsmarkersboundaries(pullop):
     """small funtion returning the argument for pull markers call
@@ -3664,29 +3599,6 @@
             kwargs['evo_obscommon'] = common
     return ret
 
-@eh.wrapfunction(exchange, '_getbundleobsmarkerpart')
-def _getbundleobsmarkerpart(orig, bundler, repo, source, **kwargs):
-    if 'evo_obscommon' not in kwargs:
-        return orig(bundler, repo, source, **kwargs)
-
-    heads = kwargs.get('heads')
-    if kwargs.get('obsmarkers', False):
-        if heads is None:
-            heads = repo.heads()
-        obscommon = kwargs.get('evo_obscommon', ())
-        assert obscommon
-        obsset = repo.unfiltered().set('::%ln - ::%ln', heads, obscommon)
-        subset = [c.node() for c in obsset]
-        markers = repo.obsstore.relevantmarkers(subset)
-        exchange.buildobsmarkerspart(bundler, markers)
-
-@eh.uisetup
-def installgetbundlepartgen(ui):
-    origfunc = exchange.getbundle2partsmapping['obsmarkers']
-    def newfunc(*args, **kwargs):
-        return _getbundleobsmarkerpart(origfunc, *args, **kwargs)
-    exchange.getbundle2partsmapping['obsmarkers'] = newfunc
-
 @eh.wrapfunction(exchange, '_pullobsolete')
 def _pullobsolete(orig, pullop):
     if not obsolete.isenabled(pullop.repo, obsolete.exchangeopt):
@@ -3728,28 +3640,6 @@
         pullop.repo.invalidatevolatilesets()
     return tr
 
-def _getobsmarkersstream(repo, heads=None, common=None):
-    revset = ''
-    args = []
-    repo = repo.unfiltered()
-    if heads is None:
-        revset = 'all()'
-    elif heads:
-        revset += "(::%ln)"
-        args.append(heads)
-    else:
-        assert False, 'pulling no heads?'
-    if common:
-        revset += ' - (::%ln)'
-        args.append(common)
-    nodes = [c.node() for c in repo.set(revset, *args)]
-    markers = repo.obsstore.relevantmarkers(nodes)
-    obsdata = StringIO()
-    for chunk in obsolete.encodemarkers(markers, True):
-        obsdata.write(chunk)
-    obsdata.seek(0)
-    return obsdata
-
 @eh.addattr(wireproto.wirepeer, 'evoext_pullobsmarkers_0')
 def client_pullobsmarkers(self, heads=None, common=None):
     self.requirecap('_evoext_pullobsmarkers_0', _('look up remote obsmarkers'))
@@ -3776,75 +3666,8 @@
 
 @eh.addattr(localrepo.localpeer, 'evoext_pullobsmarkers_0')
 def local_pullobsmarkers(self, heads=None, common=None):
-    return _getobsmarkersstream(self._repo, heads=heads, common=common)
-
-# The wireproto.streamres API changed, handling chunking and compression
-# directly. Handle either case.
-if util.safehasattr(wireproto.abstractserverproto, 'groupchunks'):
-    # We need to handle chunking and compression directly
-    def streamres(d, proto):
-        return wireproto.streamres(proto.groupchunks(d))
-else:
-    # Leave chunking and compression to streamres
-    def streamres(d, proto):
-        return wireproto.streamres(reader=d, v1compressible=True)
-
-def srv_pullobsmarkers(repo, proto, others):
-    opts = wireproto.options('', ['heads', 'common'], others)
-    for k, v in opts.iteritems():
-        if k in ('heads', 'common'):
-            opts[k] = wireproto.decodelist(v)
-    obsdata = _getobsmarkersstream(repo, **opts)
-    finaldata = StringIO()
-    obsdata = obsdata.getvalue()
-    finaldata.write('%20i' % len(obsdata))
-    finaldata.write(obsdata)
-    finaldata.seek(0)
-    return streamres(finaldata, proto)
-
-def _obsrelsethashtreefm0(repo):
-    return _obsrelsethashtree(repo, obsolete._fm0encodeonemarker)
-
-def _obsrelsethashtreefm1(repo):
-    return _obsrelsethashtree(repo, obsolete._fm1encodeonemarker)
-
-def _obsrelsethashtree(repo, encodeonemarker):
-    cache = []
-    unfi = repo.unfiltered()
-    markercache = {}
-    repo.ui.progress(_("preparing locally"), 0, total=len(unfi))
-    for i in unfi:
-        ctx = unfi[i]
-        entry = 0
-        sha = hashlib.sha1()
-        # add data from p1
-        for p in ctx.parents():
-            p = p.rev()
-            if p < 0:
-                p = nullid
-            else:
-                p = cache[p][1]
-            if p != nullid:
-                entry += 1
-                sha.update(p)
-        tmarkers = repo.obsstore.relevantmarkers([ctx.node()])
-        if tmarkers:
-            bmarkers = []
-            for m in tmarkers:
-                if not m in markercache:
-                    markercache[m] = encodeonemarker(m)
-                bmarkers.append(markercache[m])
-            bmarkers.sort()
-            for m in bmarkers:
-                entry += 1
-                sha.update(m)
-        if entry:
-            cache.append((ctx.node(), sha.digest()))
-        else:
-            cache.append((ctx.node(), nullid))
-        repo.ui.progress(_("preparing locally"), i, total=len(unfi))
-    repo.ui.progress(_("preparing locally"), None)
-    return cache
+    return serveronly._getobsmarkersstream(self._repo, heads=heads,
+                                           common=common)
 
 @command('debugobsrelsethashtree',
         [('', 'v0', None, 'hash on marker format "0"'),
@@ -3858,9 +3681,9 @@
     if v0 and v1:
         raise error.Abort('cannot only specify one format')
     elif v0:
-        treefunc = _obsrelsethashtreefm0
+        treefunc = serveronly._obsrelsethashtreefm0
     else:
-        treefunc = _obsrelsethashtreefm1
+        treefunc = serveronly._obsrelsethashtreefm1
 
     for chg, obs in treefunc(repo):
         ui.status('%s %s\n' % (node.hex(chg), node.hex(obs)))
@@ -3912,32 +3735,6 @@
     ui.write(_('Done!\n'))
 
 
-@eh.wrapfunction(wireproto, 'capabilities')
-def capabilities(orig, repo, proto):
-    """wrapper to advertise new capability"""
-    caps = orig(repo, proto)
-    if obsolete.isenabled(repo, obsolete.exchangeopt):
-        caps += ' _evoext_pushobsmarkers_0'
-        caps += ' _evoext_pullobsmarkers_0'
-        caps += ' _evoext_obshash_0'
-        caps += ' _evoext_obshash_1'
-        caps += ' _evoext_getbundle_obscommon'
-    return caps
-
-
-@eh.extsetup
-def _installwireprotocol(ui):
-    localrepo.moderncaps.add('_evoext_pullobsmarkers_0')
-    hgweb_mod.perms['evoext_pushobsmarkers_0'] = 'push'
-    hgweb_mod.perms['evoext_pullobsmarkers_0'] = 'pull'
-    wireproto.commands['evoext_pushobsmarkers_0'] = (srv_pushobsmarkers, '')
-    wireproto.commands['evoext_pullobsmarkers_0'] = (srv_pullobsmarkers, '*')
-    # wrap command content
-    oldcap, args = wireproto.commands['capabilities']
-    def newcap(repo, proto):
-        return capabilities(oldcap, repo, proto)
-    wireproto.commands['capabilities'] = (newcap, args)
-
 def _helploader(ui):
     return help.gettext(evolutionhelptext)
 
--- a/hgext3rd/evolve/serveronly.py	Tue Feb 28 16:12:34 2017 +0100
+++ b/hgext3rd/evolve/serveronly.py	Tue Feb 28 18:21:23 2017 +0100
@@ -21,12 +21,14 @@
     exchange,
     extensions,
     localrepo,
+    lock as lockmod,
     node,
     obsolete,
     util,
     wireproto
 )
 from mercurial.hgweb import hgweb_mod
+from mercurial.i18n import _
 _pack = struct.pack
 
 gboptslist = gboptsmap = None
@@ -51,29 +53,37 @@
 # End of simple4server specific content
 
 
+def obsexcmsg(ui, message, important=False):
+    verbose = ui.configbool('experimental', 'verbose-obsolescence-exchange',
+                             False)
+    if verbose:
+        message = 'OBSEXC: ' + message
+    if important or verbose:
+        ui.status(message)
 
-# from evolve extension: 1a23c7c52a43
+def _pushobsmarkers(repo, data):
+    tr = lock = None
+    try:
+        lock = repo.lock()
+        tr = repo.transaction('pushkey: obsolete markers')
+        new = repo.obsstore.mergemarkers(tr, data)
+        if new is not None:
+            obsexcmsg(repo.ui, "%i obsolescence markers added\n" % new, True)
+        tr.close()
+    finally:
+        lockmod.release(tr, lock)
+    repo.hook('evolve_pushobsmarkers')
+
 def srv_pushobsmarkers(repo, proto):
-    """That receives a stream of markers and apply then to the repo"""
+    """wireprotocol command"""
     fp = StringIO()
     proto.redirect()
     proto.getfile(fp)
     data = fp.getvalue()
     fp.close()
-    lock = repo.lock()
-    try:
-        tr = repo.transaction('pushkey: obsolete markers')
-        try:
-            repo.obsstore.mergemarkers(tr, data)
-            tr.close()
-        finally:
-            tr.release()
-    finally:
-        lock.release()
-    repo.hook('evolve_pushobsmarkers')
+    _pushobsmarkers(repo, data)
     return wireproto.pushres(0)
 
-# from evolve extension: 1a23c7c52a43
 def _getobsmarkersstream(repo, heads=None, common=None):
     """Get a binary stream for all markers relevant to `::<heads> - ::<common>`
     """
@@ -98,64 +108,6 @@
     obsdata.seek(0)
     return obsdata
 
-if not util.safehasattr(obsolete.obsstore, 'relevantmarkers'):
-    # from evolve extension: 1a23c7c52a43
-    class pruneobsstore(obsolete.obsstore):
-        """And extended obsstore class that read parent information from v1
-        format
-
-        Evolve extension adds parent information in prune marker.
-        We use it to make markers relevant to pushed changeset."""
-
-        def __init__(self, *args, **kwargs):
-            self.prunedchildren = {}
-            return super(pruneobsstore, self).__init__(*args, **kwargs)
-
-        def _load(self, markers):
-            markers = self._prunedetectingmarkers(markers)
-            return super(pruneobsstore, self)._load(markers)
-
-
-        def _prunedetectingmarkers(self, markers):
-            for m in markers:
-                if not m[1]: # no successors
-                    meta = obsolete.decodemeta(m[3])
-                    if 'p1' in meta:
-                        p1 = node.bin(meta['p1'])
-                        self.prunedchildren.setdefault(p1, set()).add(m)
-                    if 'p2' in meta:
-                        p2 = node.bin(meta['p2'])
-                        self.prunedchildren.setdefault(p2, set()).add(m)
-                yield m
-
-    # from evolve extension: 1a23c7c52a43
-    def relevantmarkers(self, nodes):
-        """return a set of all obsolescence marker relevant to a set of node.
-
-        "relevant" to a set of node mean:
-
-        - marker that use this changeset as successors
-        - prune marker of direct children on this changeset.
-        - recursive application of the two rules on precursors of these markers
-
-        It is a set so you cannot rely on order"""
-        seennodes = set(nodes)
-        seenmarkers = set()
-        pendingnodes = set(nodes)
-        precursorsmarkers = self.precursors
-        prunedchildren = self.prunedchildren
-        while pendingnodes:
-            direct = set()
-            for current in pendingnodes:
-                direct.update(precursorsmarkers.get(current, ()))
-                direct.update(prunedchildren.get(current, ()))
-            direct -= seenmarkers
-            pendingnodes = set([m[0] for m in direct])
-            seenmarkers |= direct
-            pendingnodes -= seennodes
-            seennodes |= pendingnodes
-        return seenmarkers
-
 # The wireproto.streamres API changed, handling chunking and compression
 # directly. Handle either case.
 if util.safehasattr(wireproto.abstractserverproto, 'groupchunks'):
@@ -167,7 +119,6 @@
     def streamres(d, proto):
         return wireproto.streamres(reader=d, v1compressible=True)
 
-# from evolve extension: cf35f38d6a10
 def srv_pullobsmarkers(repo, proto, others):
     """serves a binary stream of markers.
 
@@ -186,20 +137,17 @@
     finaldata.seek(0)
     return streamres(finaldata, proto)
 
-
-# from evolve extension: 3249814dabd1
 def _obsrelsethashtreefm0(repo):
     return _obsrelsethashtree(repo, obsolete._fm0encodeonemarker)
 
-# from evolve extension: 3249814dabd1
 def _obsrelsethashtreefm1(repo):
     return _obsrelsethashtree(repo, obsolete._fm1encodeonemarker)
 
-# from evolve extension: 3249814dabd1
 def _obsrelsethashtree(repo, encodeonemarker):
     cache = []
     unfi = repo.unfiltered()
     markercache = {}
+    repo.ui.progress(_("preparing locally"), 0, total=len(unfi))
     for i in unfi:
         ctx = unfi[i]
         entry = 0
@@ -229,9 +177,10 @@
             cache.append((ctx.node(), sha.digest()))
         else:
             cache.append((ctx.node(), node.nullid))
+        repo.ui.progress(_("preparing locally"), i, total=len(unfi))
+    repo.ui.progress(_("preparing locally"), None)
     return cache
 
-# from evolve extension: 3249814dabd1
 def _obshash(repo, nodes, version=0):
     if version == 0:
         hashs = _obsrelsethashtreefm0(repo)
@@ -241,18 +190,15 @@
         assert False
     nm = repo.changelog.nodemap
     revs = [nm.get(n) for n in nodes]
-    return [r is None and node.nullid or hashs[r][1] for r in revs]
+    return [r is None and nullid or hashs[r][1] for r in revs]
 
-# from evolve extension: 3249814dabd1
 def srv_obshash(repo, proto, nodes):
     return wireproto.encodelist(_obshash(repo, wireproto.decodelist(nodes)))
 
-# from evolve extension: 3249814dabd1
 def srv_obshash1(repo, proto, nodes):
     return wireproto.encodelist(_obshash(repo, wireproto.decodelist(nodes),
                                 version=1))
 
-# from evolve extension: 3249814dabd1
 def capabilities(orig, repo, proto):
     """wrapper to advertise new capability"""
     caps = orig(repo, proto)
@@ -270,29 +216,23 @@
         return orig(bundler, repo, source, **kwargs)
 
     heads = kwargs.get('heads')
-    if 'evo_obscommon' not in kwargs:
-        return orig(bundler, repo, source, **kwargs)
-
     if kwargs.get('obsmarkers', False):
         if heads is None:
             heads = repo.heads()
         obscommon = kwargs.get('evo_obscommon', ())
-        obsset = repo.set('::%ln - ::%ln', heads, obscommon)
+        assert obscommon
+        obsset = repo.unfiltered().set('::%ln - ::%ln', heads, obscommon)
         subset = [c.node() for c in obsset]
         markers = repo.obsstore.relevantmarkers(subset)
         exchange.buildobsmarkerspart(bundler, markers)
 
-# from evolve extension: 10867a8e27c6
-# heavily modified
 def extsetup(ui):
     localrepo.moderncaps.add('_evoext_b2x_obsmarkers_0')
     gboptsmap['evo_obscommon'] = 'nodes'
-    if not util.safehasattr(obsolete.obsstore, 'relevantmarkers'):
-        obsolete.obsstore = pruneobsstore
-        obsolete.obsstore.relevantmarkers = relevantmarkers
     hgweb_mod.perms['evoext_pushobsmarkers_0'] = 'push'
     hgweb_mod.perms['evoext_pullobsmarkers_0'] = 'pull'
     hgweb_mod.perms['evoext_obshash'] = 'pull'
+    hgweb_mod.perms['evoext_obshash1'] = 'pull'
     wireproto.commands['evoext_pushobsmarkers_0'] = (srv_pushobsmarkers, '')
     wireproto.commands['evoext_pullobsmarkers_0'] = (srv_pullobsmarkers, '*')
     # wrap module content
--- a/tests/test-simple4server.t	Tue Feb 28 16:12:34 2017 +0100
+++ b/tests/test-simple4server.t	Tue Feb 28 18:21:23 2017 +0100
@@ -99,6 +99,7 @@
   remote: adding file changes
   remote: added 1 changesets with 1 changes to 1 files (+1 heads)
   pushing 2 obsolescence markers (* bytes) (glob)
+  remote: 2 obsolescence markers added
   $ cat ../errors.log
   $ hg push
   pushing to http://localhost:$HGPORT/