diff hgext/lfs/wrapper.py @ 41048:84d61fdcefa5

lfs: convert to using exthelper to wrap functions I'm not 100% sure that upgraderequirements() can be double annotated safely, but it seems OK based on printing the address of the function being wrapped. One thing I've noticed is that @eh.reposetup doesn't do the usual check to ensure that it's a local repo. Should that be baked into @eh.reposetup() somehow, possibly with a non-default option to skip the check? It seems like a gaping hole if every function that gets registered needs to add this check.
author Matt Harbison <matt_harbison@yahoo.com>
date Tue, 27 Nov 2018 22:10:07 -0500
parents 4a81d82474e9
children c9e1104e6272
line wrap: on
line diff
--- a/hgext/lfs/wrapper.py	Fri Nov 30 21:39:55 2018 -0500
+++ b/hgext/lfs/wrapper.py	Tue Nov 27 22:10:07 2018 -0500
@@ -13,10 +13,21 @@
 from mercurial.node import bin, hex, nullid, short
 
 from mercurial import (
+    bundle2,
+    changegroup,
+    cmdutil,
+    context,
     error,
+    exchange,
+    exthelper,
+    localrepo,
     repository,
     revlog,
+    scmutil,
+    upgrade,
     util,
+    vfs as vfsmod,
+    wireprotov1server,
 )
 
 from mercurial.utils import (
@@ -31,17 +42,22 @@
     pointer,
 )
 
+eh = exthelper.exthelper()
+
+@eh.wrapfunction(localrepo, 'makefilestorage')
 def localrepomakefilestorage(orig, requirements, features, **kwargs):
     if b'lfs' in requirements:
         features.add(repository.REPO_FEATURE_LFS)
 
     return orig(requirements=requirements, features=features, **kwargs)
 
+@eh.wrapfunction(changegroup, 'allsupportedversions')
 def allsupportedversions(orig, ui):
     versions = orig(ui)
     versions.add('03')
     return versions
 
+@eh.wrapfunction(wireprotov1server, '_capabilities')
 def _capabilities(orig, repo, proto):
     '''Wrap server command to announce lfs server capability'''
     caps = orig(repo, proto)
@@ -130,6 +146,7 @@
     flags = rlog._revlog.flags(rev)
     return bool(flags & revlog.REVIDX_EXTSTORED)
 
+# Wrapping may also be applied by remotefilelog
 def filelogaddrevision(orig, self, text, transaction, link, p1, p2,
                        cachedelta=None, node=None,
                        flags=revlog.REVIDX_DEFAULT_FLAGS, **kwds):
@@ -149,6 +166,7 @@
     return orig(self, text, transaction, link, p1, p2, cachedelta=cachedelta,
                 node=node, flags=flags, **kwds)
 
+# Wrapping may also be applied by remotefilelog
 def filelogrenamed(orig, self, node):
     if _islfs(self, node):
         rawtext = self._revlog.revision(node, raw=True)
@@ -161,6 +179,7 @@
             return False
     return orig(self, node)
 
+# Wrapping may also be applied by remotefilelog
 def filelogsize(orig, self, rev):
     if _islfs(self, rev=rev):
         # fast path: use lfs metadata to answer size
@@ -169,6 +188,7 @@
         return int(metadata['size'])
     return orig(self, rev)
 
+@eh.wrapfunction(context.basefilectx, 'cmp')
 def filectxcmp(orig, self, fctx):
     """returns True if text is different than fctx"""
     # some fctx (ex. hg-git) is not based on basefilectx and do not have islfs
@@ -179,6 +199,7 @@
         return p1.oid() != p2.oid()
     return orig(self, fctx)
 
+@eh.wrapfunction(context.basefilectx, 'isbinary')
 def filectxisbinary(orig, self):
     if self.islfs():
         # fast path: use lfs metadata to answer isbinary
@@ -187,13 +208,16 @@
         return bool(int(metadata.get('x-is-binary', 1)))
     return orig(self)
 
+@eh.addattr(context.basefilectx, 'islfs')
 def filectxislfs(self):
     return _islfs(self.filelog(), self.filenode())
 
+@eh.wrapfunction(cmdutil, '_updatecatformatter')
 def _updatecatformatter(orig, fm, ctx, matcher, path, decode):
     orig(fm, ctx, matcher, path, decode)
     fm.data(rawdata=ctx[path].rawdata())
 
+@eh.wrapfunction(scmutil, 'wrapconvertsink')
 def convertsink(orig, sink):
     sink = orig(sink)
     if sink.repotype == 'hg':
@@ -219,6 +243,9 @@
 
     return sink
 
+# bundlerepo uses "vfsmod.readonlyvfs(othervfs)", we need to make sure lfs
+# options and blob stores are passed from othervfs to the new readonlyvfs.
+@eh.wrapfunction(vfsmod.readonlyvfs, '__init__')
 def vfsinit(orig, self, othervfs):
     orig(self, othervfs)
     # copy lfs related options
@@ -290,6 +317,7 @@
     """
     return uploadblobsfromrevs(pushop.repo, pushop.outgoing.missing)
 
+@eh.wrapfunction(exchange, 'push')
 def push(orig, repo, remote, *args, **kwargs):
     """bail on push if the extension isn't enabled on remote when needed, and
     update the remote store based on the destination path."""
@@ -316,6 +344,8 @@
     else:
         return orig(repo, remote, *args, **kwargs)
 
+# when writing a bundle via "hg bundle" command, upload related LFS blobs
+@eh.wrapfunction(bundle2, 'writenewbundle')
 def writenewbundle(orig, ui, repo, source, filename, bundletype, outgoing,
                    *args, **kwargs):
     """upload LFS blobs added by outgoing revisions on 'hg bundle'"""
@@ -393,6 +423,7 @@
     remoteblob = repo.svfs.lfsremoteblobstore
     remoteblob.writebatch(pointers, repo.svfs.lfslocalblobstore)
 
+@eh.wrapfunction(upgrade, '_finishdatamigration')
 def upgradefinishdatamigration(orig, ui, srcrepo, dstrepo, requirements):
     orig(ui, srcrepo, dstrepo, requirements)
 
@@ -407,6 +438,8 @@
                 ui.write(_('copying lfs blob %s\n') % oid)
                 lfutil.link(srclfsvfs.join(oid), dstlfsvfs.join(oid))
 
+@eh.wrapfunction(upgrade, 'preservedrequirements')
+@eh.wrapfunction(upgrade, 'supporteddestrequirements')
 def upgraderequirements(orig, repo):
     reqs = orig(repo)
     if 'lfs' in repo.requirements: