# HG changeset patch # User Matt Harbison # Date 1543374607 18000 # Node ID 84d61fdcefa54c2b3cb3305c3f452548e4e1c549 # Parent 555215e2b05149b65976f8e74c8968bbce43bbf6 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. diff -r 555215e2b051 -r 84d61fdcefa5 hgext/lfs/__init__.py --- a/hgext/lfs/__init__.py Fri Nov 30 21:39:55 2018 -0500 +++ b/hgext/lfs/__init__.py Tue Nov 27 22:10:07 2018 -0500 @@ -129,14 +129,11 @@ from mercurial.i18n import _ from mercurial import ( - bundle2, - changegroup, - cmdutil, config, - context, error, exchange, extensions, + exthelper, filelog, filesetlang, localrepo, @@ -148,11 +145,7 @@ revlog, scmutil, templateutil, - upgrade, util, - vfs as vfsmod, - wireprotoserver, - wireprotov1server, ) from . import ( @@ -167,42 +160,45 @@ # leave the attribute unspecified. testedwith = 'ships-with-hg-core' -configtable = {} -configitem = registrar.configitem(configtable) +eh = exthelper.exthelper() +eh.merge(wrapper.eh) +eh.merge(wireprotolfsserver.eh) -configitem('experimental', 'lfs.serve', +cmdtable = eh.cmdtable +configtable = eh.configtable +extsetup = eh.finalextsetup +uisetup = eh.finaluisetup +reposetup = eh.finalreposetup + +eh.configitem('experimental', 'lfs.serve', default=True, ) -configitem('experimental', 'lfs.user-agent', +eh.configitem('experimental', 'lfs.user-agent', default=None, ) -configitem('experimental', 'lfs.disableusercache', +eh.configitem('experimental', 'lfs.disableusercache', default=False, ) -configitem('experimental', 'lfs.worker-enable', +eh.configitem('experimental', 'lfs.worker-enable', default=False, ) -configitem('lfs', 'url', +eh.configitem('lfs', 'url', default=None, ) -configitem('lfs', 'usercache', +eh.configitem('lfs', 'usercache', default=None, ) # Deprecated -configitem('lfs', 'threshold', +eh.configitem('lfs', 'threshold', default=None, ) -configitem('lfs', 'track', +eh.configitem('lfs', 'track', default='none()', ) -configitem('lfs', 'retry', +eh.configitem('lfs', 'retry', default=5, ) - -cmdtable = {} -command = registrar.command(cmdtable) - templatekeyword = registrar.templatekeyword() filesetpredicate = registrar.filesetpredicate() @@ -216,10 +212,12 @@ # don't die on seeing a repo with the lfs requirement supported |= {'lfs'} -def uisetup(ui): +@eh.uisetup +def _uisetup(ui): localrepo.featuresetupfuncs.add(featuresetup) -def reposetup(ui, repo): +@eh.reposetup +def _reposetup(ui, repo): # Nothing to do with a remote repo if not repo.local(): return @@ -305,6 +303,7 @@ return _match +# Called by remotefilelog def wrapfilelog(filelog): wrapfunction = extensions.wrapfunction @@ -312,6 +311,7 @@ wrapfunction(filelog, 'renamed', wrapper.filelogrenamed) wrapfunction(filelog, 'size', wrapper.filelogsize) +@eh.wrapfunction(localrepo, 'resolverevlogstorevfsoptions') def _resolverevlogstorevfsoptions(orig, ui, requirements, features): opts = orig(ui, requirements, features) for name, module in extensions.extensions(ui): @@ -326,40 +326,10 @@ return opts -def extsetup(ui): +@eh.extsetup +def _extsetup(ui): wrapfilelog(filelog.filelog) - wrapfunction = extensions.wrapfunction - - wrapfunction(localrepo, 'makefilestorage', wrapper.localrepomakefilestorage) - wrapfunction(localrepo, 'resolverevlogstorevfsoptions', - _resolverevlogstorevfsoptions) - - wrapfunction(cmdutil, '_updatecatformatter', wrapper._updatecatformatter) - wrapfunction(scmutil, 'wrapconvertsink', wrapper.convertsink) - - wrapfunction(upgrade, '_finishdatamigration', - wrapper.upgradefinishdatamigration) - - wrapfunction(upgrade, 'preservedrequirements', - wrapper.upgraderequirements) - - wrapfunction(upgrade, 'supporteddestrequirements', - wrapper.upgraderequirements) - - wrapfunction(changegroup, - 'allsupportedversions', - wrapper.allsupportedversions) - - wrapfunction(exchange, 'push', wrapper.push) - wrapfunction(wireprotov1server, '_capabilities', wrapper._capabilities) - wrapfunction(wireprotoserver, 'handlewsgirequest', - wireprotolfsserver.handlewsgirequest) - - wrapfunction(context.basefilectx, 'cmp', wrapper.filectxcmp) - wrapfunction(context.basefilectx, 'isbinary', wrapper.filectxisbinary) - context.basefilectx.islfs = wrapper.filectxislfs - scmutil.fileprefetchhooks.add('lfs', wrapper._prefetchfiles) # Make bundle choose changegroup3 instead of changegroup2. This affects @@ -367,13 +337,6 @@ # "packed1". Using "packed1" with lfs will likely cause trouble. exchange._bundlespeccontentopts["v2"]["cg.version"] = "03" - # bundlerepo uses "vfsmod.readonlyvfs(othervfs)", we need to make sure lfs - # options and blob stores are passed from othervfs to the new readonlyvfs. - wrapfunction(vfsmod.readonlyvfs, '__init__', wrapper.vfsinit) - - # when writing a bundle via "hg bundle" command, upload related LFS blobs - wrapfunction(bundle2, 'writenewbundle', wrapper.writenewbundle) - @filesetpredicate('lfs()') def lfsfileset(mctx, x): """File that uses LFS storage.""" @@ -409,8 +372,8 @@ f = templateutil._showcompatlist(context, mapping, 'lfs_file', files) return templateutil.hybrid(f, files, makemap, pycompat.identity) -@command('debuglfsupload', - [('r', 'rev', [], _('upload large files introduced by REV'))]) +@eh.command('debuglfsupload', + [('r', 'rev', [], _('upload large files introduced by REV'))]) def debuglfsupload(ui, repo, **opts): """upload lfs blobs added by the working copy parent or given revisions""" revs = opts.get(r'rev', []) diff -r 555215e2b051 -r 84d61fdcefa5 hgext/lfs/wireprotolfsserver.py --- a/hgext/lfs/wireprotolfsserver.py Fri Nov 30 21:39:55 2018 -0500 +++ b/hgext/lfs/wireprotolfsserver.py Tue Nov 27 22:10:07 2018 -0500 @@ -17,8 +17,10 @@ ) from mercurial import ( + exthelper, pycompat, util, + wireprotoserver, ) from . import blobstore @@ -31,6 +33,9 @@ HTTP_NOT_ACCEPTABLE = hgwebcommon.HTTP_NOT_ACCEPTABLE HTTP_UNSUPPORTED_MEDIA_TYPE = hgwebcommon.HTTP_UNSUPPORTED_MEDIA_TYPE +eh = exthelper.exthelper() + +@eh.wrapfunction(wireprotoserver, 'handlewsgirequest') def handlewsgirequest(orig, rctx, req, res, checkperm): """Wrap wireprotoserver.handlewsgirequest() to possibly process an LFS request if it is left unprocessed by the wrapped method. diff -r 555215e2b051 -r 84d61fdcefa5 hgext/lfs/wrapper.py --- 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: