Details
Details
- Reviewers
- None
- Group Reviewers
Restricted Project - Commits
- rFBHGX4c02e81ebdae: compat: add support for hg >= b4d85bc1
Diff Detail
Diff Detail
- Repository
- rFBHGX Facebook Mercurial Extensions
- Lint
Lint Skipped - Unit
Unit Tests Skipped
( )
Restricted Project |
Lint Skipped |
Unit Tests Skipped |
Path | Packages | |||
---|---|---|---|---|
M | remotefilelog/remotefilelogserver.py (45 lines) |
Status | Author | Revision | |
---|---|---|---|
Closed | martinvonz | ||
Closed | martinvonz | ||
Closed | martinvonz |
# remotefilelogserver.py - server logic for a remotefilelog server | # remotefilelogserver.py - server logic for a remotefilelog server | ||||
# | # | ||||
# Copyright 2013 Facebook, Inc. | # Copyright 2013 Facebook, Inc. | ||||
# | # | ||||
# This software may be used and distributed according to the terms of the | # This software may be used and distributed according to the terms of the | ||||
# GNU General Public License version 2 or any later version. | # GNU General Public License version 2 or any later version. | ||||
from __future__ import absolute_import | from __future__ import absolute_import | ||||
from mercurial import wireproto, changegroup, match, util, changelog, context | from mercurial import changegroup, match, util, changelog, context | ||||
from mercurial import store, error | from mercurial import store, error | ||||
from mercurial import streamclone | from mercurial import streamclone | ||||
from mercurial.extensions import wrapfunction | from mercurial.extensions import wrapfunction | ||||
from mercurial.node import bin, hex, nullid, nullrev | from mercurial.node import bin, hex, nullid, nullrev | ||||
from mercurial.i18n import _ | from mercurial.i18n import _ | ||||
from . import ( | from . import ( | ||||
constants, | constants, | ||||
lz4wrapper, | lz4wrapper, | ||||
# hg 4.6 and later | # hg 4.6 and later | ||||
from mercurial import wireprotoserver as httpprotocol | from mercurial import wireprotoserver as httpprotocol | ||||
httpprotocol.HTTP_OK # force demandimport | httpprotocol.HTTP_OK # force demandimport | ||||
except ImportError: | except ImportError: | ||||
# hg 4.5 and earlier | # hg 4.5 and earlier | ||||
from mercurial.hgweb import protocol as httpprotocol | from mercurial.hgweb import protocol as httpprotocol | ||||
httpprotocol.decodevaluefromheaders | httpprotocol.decodevaluefromheaders | ||||
try: | |||||
from mercurial import wireprototypes | |||||
wireprototypes.streamres # force demandimport | |||||
except ImportError: | |||||
# Before b4d85bc1 (4.6) | |||||
from mercurial import wireproto as wireprototypes | |||||
try: | |||||
from mercurial import wireprotov1server | |||||
wireprotov1server.commands # force demandimport | |||||
except ImportError: | |||||
# Before b4d85bc1 (4.6) | |||||
from mercurial import wireproto as wireprotov1server | |||||
def setupserver(ui, repo): | def setupserver(ui, repo): | ||||
"""Sets up a normal Mercurial repo so it can serve files to shallow repos. | """Sets up a normal Mercurial repo so it can serve files to shallow repos. | ||||
""" | """ | ||||
onetimesetup(ui) | onetimesetup(ui) | ||||
# don't send files to shallow clients during pulls | # don't send files to shallow clients during pulls | ||||
def generatefiles(orig, self, changedfiles, linknodes, commonrevs, source): | def generatefiles(orig, self, changedfiles, linknodes, commonrevs, source): | ||||
caps = self._bundlecaps or [] | caps = self._bundlecaps or [] | ||||
"""Configures the wireprotocol for both clients and servers. | """Configures the wireprotocol for both clients and servers. | ||||
""" | """ | ||||
global onetime | global onetime | ||||
if onetime: | if onetime: | ||||
return | return | ||||
onetime = True | onetime = True | ||||
# support file content requests | # support file content requests | ||||
wireproto.commands['getflogheads'] = (getflogheads, 'path') | wireprotov1server.commands['getflogheads'] = (getflogheads, 'path') | ||||
wireproto.commands['getfiles'] = (getfiles, '') | wireprotov1server.commands['getfiles'] = (getfiles, '') | ||||
wireproto.commands['getfile'] = (getfile, 'file node') | wireprotov1server.commands['getfile'] = (getfile, 'file node') | ||||
wireproto.commands['getpackv1'] = (getpack, '*') | wireprotov1server.commands['getpackv1'] = (getpack, '*') | ||||
class streamstate(object): | class streamstate(object): | ||||
match = None | match = None | ||||
shallowremote = False | shallowremote = False | ||||
noflatmf = False | noflatmf = False | ||||
state = streamstate() | state = streamstate() | ||||
def stream_out_shallow(repo, proto, other): | def stream_out_shallow(repo, proto, other): | ||||
oldnoflatmf = state.noflatmf | oldnoflatmf = state.noflatmf | ||||
try: | try: | ||||
state.shallowremote = True | state.shallowremote = True | ||||
state.match = match.always(repo.root, '') | state.match = match.always(repo.root, '') | ||||
state.noflatmf = other.get('noflatmanifest') == 'True' | state.noflatmf = other.get('noflatmanifest') == 'True' | ||||
if includepattern or excludepattern: | if includepattern or excludepattern: | ||||
state.match = match.match(repo.root, '', None, | state.match = match.match(repo.root, '', None, | ||||
includepattern, excludepattern) | includepattern, excludepattern) | ||||
streamres = wireproto.stream(repo, proto) | streamres = wireprotov1server.stream(repo, proto) | ||||
# Force the first value to execute, so the file list is computed | # Force the first value to execute, so the file list is computed | ||||
# within the try/finally scope | # within the try/finally scope | ||||
first = next(streamres.gen) | first = next(streamres.gen) | ||||
second = next(streamres.gen) | second = next(streamres.gen) | ||||
def gen(): | def gen(): | ||||
yield first | yield first | ||||
yield second | yield second | ||||
for value in streamres.gen: | for value in streamres.gen: | ||||
yield value | yield value | ||||
return wireproto.streamres(gen()) | return wireprototypes.streamres(gen()) | ||||
finally: | finally: | ||||
state.shallowremote = oldshallow | state.shallowremote = oldshallow | ||||
state.match = oldmatch | state.match = oldmatch | ||||
state.noflatmf = oldnoflatmf | state.noflatmf = oldnoflatmf | ||||
wireproto.commands['stream_out_shallow'] = (stream_out_shallow, '*') | wireprotov1server.commands['stream_out_shallow'] = (stream_out_shallow, '*') | ||||
# don't clone filelogs to shallow clients | # don't clone filelogs to shallow clients | ||||
def _walkstreamfiles(orig, repo): | def _walkstreamfiles(orig, repo): | ||||
if state.shallowremote: | if state.shallowremote: | ||||
# if we are shallow ourselves, stream our local commits | # if we are shallow ourselves, stream our local commits | ||||
if shallowrepo.requirement in repo.requirements: | if shallowrepo.requirement in repo.requirements: | ||||
striplen = len(repo.store.path) + 1 | striplen = len(repo.store.path) + 1 | ||||
readdir = repo.store.rawvfs.readdir | readdir = repo.store.rawvfs.readdir | ||||
# We no longer use getbundle_shallow commands, but we must still | # We no longer use getbundle_shallow commands, but we must still | ||||
# support it for migration purposes | # support it for migration purposes | ||||
def getbundleshallow(repo, proto, others): | def getbundleshallow(repo, proto, others): | ||||
bundlecaps = others.get('bundlecaps', '') | bundlecaps = others.get('bundlecaps', '') | ||||
bundlecaps = set(bundlecaps.split(',')) | bundlecaps = set(bundlecaps.split(',')) | ||||
bundlecaps.add('remotefilelog') | bundlecaps.add('remotefilelog') | ||||
others['bundlecaps'] = ','.join(bundlecaps) | others['bundlecaps'] = ','.join(bundlecaps) | ||||
return wireproto.commands["getbundle"][0](repo, proto, others) | return wireprotov1server.commands["getbundle"][0](repo, proto, others) | ||||
wireproto.commands["getbundle_shallow"] = (getbundleshallow, '*') | wireprotov1server.commands["getbundle_shallow"] = (getbundleshallow, '*') | ||||
# expose remotefilelog capabilities | # expose remotefilelog capabilities | ||||
def _capabilities(orig, repo, proto): | def _capabilities(orig, repo, proto): | ||||
caps = orig(repo, proto) | caps = orig(repo, proto) | ||||
if ((shallowrepo.requirement in repo.requirements or | if ((shallowrepo.requirement in repo.requirements or | ||||
ui.configbool('remotefilelog', 'server'))): | ui.configbool('remotefilelog', 'server'))): | ||||
if isinstance(proto, _sshv1server): | if isinstance(proto, _sshv1server): | ||||
# legacy getfiles method which only works over ssh | # legacy getfiles method which only works over ssh | ||||
caps.append(shallowrepo.requirement) | caps.append(shallowrepo.requirement) | ||||
caps.append('getflogheads') | caps.append('getflogheads') | ||||
caps.append('getfile') | caps.append('getfile') | ||||
return caps | return caps | ||||
if util.safehasattr(wireproto, '_capabilities'): | if util.safehasattr(wireprotov1server, '_capabilities'): | ||||
wrapfunction(wireproto, '_capabilities', _capabilities) | wrapfunction(wireprotov1server, '_capabilities', _capabilities) | ||||
else: | else: | ||||
wrapfunction(wireproto, 'capabilities', _capabilities) | wrapfunction(wireprotov1server, 'capabilities', _capabilities) | ||||
def _adjustlinkrev(orig, self, *args, **kwargs): | def _adjustlinkrev(orig, self, *args, **kwargs): | ||||
# When generating file blobs, taking the real path is too slow on large | # When generating file blobs, taking the real path is too slow on large | ||||
# repos, so force it to just return the linkrev directly. | # repos, so force it to just return the linkrev directly. | ||||
repo = self._repo | repo = self._repo | ||||
if util.safehasattr(repo, 'forcelinkrev') and repo.forcelinkrev: | if util.safehasattr(repo, 'forcelinkrev') and repo.forcelinkrev: | ||||
return self._filelog.linkrev(self._filelog.rev(self._filenode)) | return self._filelog.linkrev(self._filelog.rev(self._filenode)) | ||||
return orig(self, *args, **kwargs) | return orig(self, *args, **kwargs) | ||||
# it would be better to only flush after processing a whole batch | # it would be better to only flush after processing a whole batch | ||||
# but currently we don't know if there are more requests coming | # but currently we don't know if there are more requests coming | ||||
try: | try: | ||||
# hg 4.6 and later | # hg 4.6 and later | ||||
proto._fout.flush() | proto._fout.flush() | ||||
except AttributeError: | except AttributeError: | ||||
# hg 4.5 and earlier | # hg 4.5 and earlier | ||||
proto.fout.flush() | proto.fout.flush() | ||||
return wireproto.streamres(streamer()) | return wireprototypes.streamres(streamer()) | ||||
def createfileblob(filectx): | def createfileblob(filectx): | ||||
""" | """ | ||||
format: | format: | ||||
v0: | v0: | ||||
str(len(rawtext)) + '\0' + rawtext + ancestortext | str(len(rawtext)) + '\0' + rawtext + ancestortext | ||||
v1: | v1: | ||||
'v1' + '\n' + metalist + '\0' + rawtext + ancestortext | 'v1' + '\n' + metalist + '\0' + rawtext + ancestortext | ||||
yield wirepack.closepart() | yield wirepack.closepart() | ||||
try: | try: | ||||
# hg 4.6 and later | # hg 4.6 and later | ||||
proto._fout.flush() | proto._fout.flush() | ||||
except AttributeError: | except AttributeError: | ||||
# hg 4.5 and earlier | # hg 4.5 and earlier | ||||
proto.fout.flush() | proto.fout.flush() | ||||
return wireproto.streamres(streamer()) | return wireprototypes.streamres(streamer()) | ||||
def _receivepackrequest(stream): | def _receivepackrequest(stream): | ||||
files = {} | files = {} | ||||
while True: | while True: | ||||
filenamelen = shallowutil.readunpack(stream, | filenamelen = shallowutil.readunpack(stream, | ||||
constants.FILENAMESTRUCT)[0] | constants.FILENAMESTRUCT)[0] | ||||
if filenamelen == 0: | if filenamelen == 0: | ||||
break | break |