##// END OF EJS Templates
gitweb: provide links to branches, tags and bookmarks by name...
gitweb: provide links to branches, tags and bookmarks by name This is adapted from cd842821db2c, that was added to paper for 3.5 release. It adds another way to refer to branches, tags and bookmarks in urls: by name. It's still possible to navigate to a specific changeset hash, but now you can get more descriptive urls straight from /summary page, for example. branchentry template (and so the whole branches table on /summary and /branches) lost the column that had a plain changeset hash, because tags and bookmarks don't have this column and also because there is already a way to address branch by its changeset hash (changeset link just next to it). Maybe we can instead bring this column with a plain changeset hash to tags and bookmarks, but this, more terse, new look feels fine.

File last commit:

r25993:0851678b default
r26390:0f0cda81 default
Show More
wireproto.py
812 lines | 26.8 KiB | text/x-python | PythonLexer
Matt Mackall
protocol: introduce wireproto.py...
r11581 # wireproto.py - generic wire protocol support functions
#
# Copyright 2005-2010 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
Gregory Szorc
wireproto: use absolute_import
r25993 from __future__ import absolute_import
import os
import sys
import tempfile
import urllib
Matt Mackall
protocol: introduce wireproto.py...
r11581
Gregory Szorc
wireproto: use absolute_import
r25993 from .i18n import _
from .node import (
bin,
hex,
)
from . import (
bundle2,
changegroup as changegroupmod,
encoding,
error,
exchange,
peer,
pushkey as pushkeymod,
util,
)
Pierre-Yves David
wireproto: introduce an abstractserverproto class...
r20903
class abstractserverproto(object):
"""abstract class that summarizes the protocol API
Used as reference and documentation.
"""
def getargs(self, args):
"""return the value for arguments in <args>
returns a list of values (same order as <args>)"""
raise NotImplementedError()
def getfile(self, fp):
"""write the whole content of a file into a file like object
The file is in the form::
(<chunk-size>\n<chunk>)+0\n
chunk size is the ascii version of the int.
"""
raise NotImplementedError()
def redirect(self):
"""may setup interception for stdout and stderr
See also the `restore` method."""
raise NotImplementedError()
# If the `redirect` function does install interception, the `restore`
# function MUST be defined. If interception is not used, this function
# MUST NOT be defined.
#
# left commented here on purpose
#
#def restore(self):
# """reinstall previous stdout and stderr and return intercepted stdout
# """
# raise NotImplementedError()
def groupchunks(self, cg):
"""return 4096 chunks from a changegroup object
Some protocols may have compressed the contents."""
raise NotImplementedError()
Augie Fackler
batching: migrate basic noop batching into peer.peer...
r25912 class remotebatch(peer.batcher):
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 '''batches the queued calls; uses as few roundtrips as possible'''
def __init__(self, remote):
Brodie Rao
cleanup: eradicate long lines
r16683 '''remote must support _submitbatch(encbatch) and
_submitone(op, encargs)'''
Augie Fackler
batching: migrate basic noop batching into peer.peer...
r25912 peer.batcher.__init__(self)
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 self.remote = remote
def submit(self):
req, rsp = [], []
for name, args, opts, resref in self.calls:
mtd = getattr(self.remote, name)
Augie Fackler
wireproto: use safehasattr or getattr instead of hasattr
r14970 batchablefn = getattr(mtd, 'batchable', None)
if batchablefn is not None:
batchable = batchablefn(mtd.im_self, *args, **opts)
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 encargsorres, encresref = batchable.next()
if encresref:
req.append((name, encargsorres,))
rsp.append((batchable, encresref, resref,))
else:
resref.set(encargsorres)
else:
if req:
self._submitreq(req, rsp)
req, rsp = [], []
resref.set(mtd(*args, **opts))
if req:
self._submitreq(req, rsp)
def _submitreq(self, req, rsp):
encresults = self.remote._submitbatch(req)
for encres, r in zip(encresults, rsp):
batchable, encresref, resref = r
encresref.set(encres)
resref.set(batchable.next())
Augie Fackler
batching: migrate basic noop batching into peer.peer...
r25912 # Forward a couple of names from peer to make wireproto interactions
# slightly more sensible.
batchable = peer.batchable
future = peer.future
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621
Benoit Boissinot
wireproto: refactor list of nodeid encoding / decoding
r11597 # list of nodes encoding / decoding
def decodelist(l, sep=' '):
Peter Arrenbrecht
wireproto: fix decodelist to properly return empty list...
r13722 if l:
return map(bin, l.split(sep))
return []
Benoit Boissinot
wireproto: refactor list of nodeid encoding / decoding
r11597
def encodelist(l, sep=' '):
Pierre-Yves David
discovery: run discovery on filtered repository...
r23848 try:
return sep.join(map(hex, l))
except TypeError:
raise
Benoit Boissinot
wireproto: refactor list of nodeid encoding / decoding
r11597
Peter Arrenbrecht
wireproto: add batching support to wirerepository...
r14622 # batched call argument encoding
def escapearg(plain):
return (plain
Augie Fackler
wireproto: correctly escape batched args and responses (issue4739)...
r25708 .replace(':', ':c')
.replace(',', ':o')
.replace(';', ':s')
.replace('=', ':e'))
Peter Arrenbrecht
wireproto: add batching support to wirerepository...
r14622
def unescapearg(escaped):
return (escaped
Augie Fackler
wireproto: correctly escape batched args and responses (issue4739)...
r25708 .replace(':e', '=')
.replace(':s', ';')
.replace(':o', ',')
.replace(':c', ':'))
Peter Arrenbrecht
wireproto: add batching support to wirerepository...
r14622
Pierre-Yves David
getbundle: declare type of parameters...
r21646 # mapping of options accepted by getbundle and their types
#
# Meant to be extended by extensions. It is extensions responsibility to ensure
# such options are properly processed in exchange.getbundle.
#
# supported types are:
#
# :nodes: list of binary nodes
# :csv: list of comma-separated values
Pierre-Yves David
wireprotocol: distinguish list and set in getbundle argument...
r25403 # :scsv: list of comma-separated values return as set
Pierre-Yves David
getbundle: declare type of parameters...
r21646 # :plain: string with no transformation needed.
gboptsmap = {'heads': 'nodes',
'common': 'nodes',
Pierre-Yves David
getbundle: add `obsmarkers` argument to getbundle...
r22353 'obsmarkers': 'boolean',
Pierre-Yves David
wireprotocol: distinguish list and set in getbundle argument...
r25403 'bundlecaps': 'scsv',
Pierre-Yves David
getbundle: add a ``cg`` boolean argument to control changegroup inclusion...
r21989 'listkeys': 'csv',
'cg': 'boolean'}
Pierre-Yves David
getbundle: declare type of parameters...
r21646
Matt Mackall
protocol: move basic ssh client commands to wirerepository
r11586 # client side
Peter Arrenbrecht
peer: introduce real peer classes...
r17192 class wirepeer(peer.peerrepository):
Peter Arrenbrecht
wireproto: add batching support to wirerepository...
r14622
def batch(self):
Augie Fackler
wireproto: make wirepeer look-before-you-leap on batching...
r25913 if self.capable('batch'):
return remotebatch(self)
else:
return peer.localbatch(self)
Peter Arrenbrecht
wireproto: add batching support to wirerepository...
r14622 def _submitbatch(self, req):
cmds = []
for op, argsdict in req:
Augie Fackler
wireproto: correctly escape batched args and responses (issue4739)...
r25708 args = ','.join('%s=%s' % (escapearg(k), escapearg(v))
for k, v in argsdict.iteritems())
Peter Arrenbrecht
wireproto: add batching support to wirerepository...
r14622 cmds.append('%s %s' % (op, args))
rsp = self._call("batch", cmds=';'.join(cmds))
Augie Fackler
wireproto: correctly escape batched args and responses (issue4739)...
r25708 return [unescapearg(r) for r in rsp.split(';')]
Peter Arrenbrecht
wireproto: add batching support to wirerepository...
r14622 def _submitone(self, op, args):
return self._call(op, **args)
Peter Arrenbrecht
wireproto: make a number of commands batchable...
r14623 @batchable
Matt Mackall
protocol: move basic ssh client commands to wirerepository
r11586 def lookup(self, key):
self.requirecap('lookup', _('look up remote revision'))
Peter Arrenbrecht
wireproto: make a number of commands batchable...
r14623 f = future()
Augie Fackler
wireproto: remove todict() and use {} literals instead
r20671 yield {'key': encoding.fromlocal(key)}, f
Peter Arrenbrecht
wireproto: make a number of commands batchable...
r14623 d = f.value
Matt Mackall
protocol: move basic ssh client commands to wirerepository
r11586 success, data = d[:-1].split(" ", 1)
if int(success):
Peter Arrenbrecht
wireproto: make a number of commands batchable...
r14623 yield bin(data)
Matt Mackall
protocol: move basic ssh client commands to wirerepository
r11586 self._abort(error.RepoError(data))
Peter Arrenbrecht
wireproto: make a number of commands batchable...
r14623 @batchable
Matt Mackall
protocol: move basic ssh client commands to wirerepository
r11586 def heads(self):
Peter Arrenbrecht
wireproto: make a number of commands batchable...
r14623 f = future()
yield {}, f
d = f.value
Matt Mackall
protocol: move basic ssh client commands to wirerepository
r11586 try:
Peter Arrenbrecht
wireproto: make a number of commands batchable...
r14623 yield decodelist(d[:-1])
Matt Mackall
wireproto: avoid naked excepts
r13726 except ValueError:
Benoit Boissinot
fix undefined variables, spotted by pylint
r11879 self._abort(error.ResponseError(_("unexpected response:"), d))
Matt Mackall
protocol: move basic ssh client commands to wirerepository
r11586
Peter Arrenbrecht
wireproto: make a number of commands batchable...
r14623 @batchable
Peter Arrenbrecht
wireproto: add known([id]) function...
r13723 def known(self, nodes):
Peter Arrenbrecht
wireproto: make a number of commands batchable...
r14623 f = future()
Augie Fackler
wireproto: remove todict() and use {} literals instead
r20671 yield {'nodes': encodelist(nodes)}, f
Peter Arrenbrecht
wireproto: make a number of commands batchable...
r14623 d = f.value
Peter Arrenbrecht
wireproto: add known([id]) function...
r13723 try:
Mads Kiilerich
cleanup: fix some list comprehension redefinitions of existing vars...
r22201 yield [bool(int(b)) for b in d]
Matt Mackall
wireproto: avoid naked excepts
r13726 except ValueError:
Peter Arrenbrecht
wireproto: add known([id]) function...
r13723 self._abort(error.ResponseError(_("unexpected response:"), d))
Peter Arrenbrecht
wireproto: make a number of commands batchable...
r14623 @batchable
Matt Mackall
protocol: move basic ssh client commands to wirerepository
r11586 def branchmap(self):
Peter Arrenbrecht
wireproto: make a number of commands batchable...
r14623 f = future()
yield {}, f
d = f.value
Matt Mackall
protocol: move basic ssh client commands to wirerepository
r11586 try:
branchmap = {}
for branchpart in d.splitlines():
Benoit Boissinot
wireproto: refactor list of nodeid encoding / decoding
r11597 branchname, branchheads = branchpart.split(' ', 1)
Matt Mackall
branch: operate on branch names in local string space where possible...
r13047 branchname = encoding.tolocal(urllib.unquote(branchname))
Benoit Boissinot
wireproto: refactor list of nodeid encoding / decoding
r11597 branchheads = decodelist(branchheads)
Matt Mackall
protocol: move basic ssh client commands to wirerepository
r11586 branchmap[branchname] = branchheads
Peter Arrenbrecht
wireproto: make a number of commands batchable...
r14623 yield branchmap
Matt Mackall
protocol: move basic ssh client commands to wirerepository
r11586 except TypeError:
self._abort(error.ResponseError(_("unexpected response:"), d))
def branches(self, nodes):
Benoit Boissinot
wireproto: refactor list of nodeid encoding / decoding
r11597 n = encodelist(nodes)
Matt Mackall
protocol: move basic ssh client commands to wirerepository
r11586 d = self._call("branches", nodes=n)
try:
Benoit Boissinot
wireproto: refactor list of nodeid encoding / decoding
r11597 br = [tuple(decodelist(b)) for b in d.splitlines()]
Matt Mackall
protocol: move basic ssh client commands to wirerepository
r11586 return br
Matt Mackall
wireproto: avoid naked excepts
r13726 except ValueError:
Matt Mackall
protocol: move basic ssh client commands to wirerepository
r11586 self._abort(error.ResponseError(_("unexpected response:"), d))
def between(self, pairs):
Matt Mackall
protocol: unify basic http client requests
r11587 batch = 8 # avoid giant requests
r = []
for i in xrange(0, len(pairs), batch):
Benoit Boissinot
wireproto: refactor list of nodeid encoding / decoding
r11597 n = " ".join([encodelist(p, '-') for p in pairs[i:i + batch]])
Matt Mackall
protocol: unify basic http client requests
r11587 d = self._call("between", pairs=n)
try:
Benoit Boissinot
wireproto: refactor list of nodeid encoding / decoding
r11597 r.extend(l and decodelist(l) or [] for l in d.splitlines())
Matt Mackall
wireproto: avoid naked excepts
r13726 except ValueError:
Matt Mackall
protocol: unify basic http client requests
r11587 self._abort(error.ResponseError(_("unexpected response:"), d))
return r
Matt Mackall
protocol: move basic ssh client commands to wirerepository
r11586
Peter Arrenbrecht
wireproto: make a number of commands batchable...
r14623 @batchable
Matt Mackall
protocol: move basic ssh client commands to wirerepository
r11586 def pushkey(self, namespace, key, old, new):
if not self.capable('pushkey'):
Peter Arrenbrecht
wireproto: make a number of commands batchable...
r14623 yield False, None
f = future()
Pierre-Yves David
pushkey: add more verbose debug output regarding pushkey...
r17293 self.ui.debug('preparing pushkey for "%s:%s"\n' % (namespace, key))
Augie Fackler
wireproto: remove todict() and use {} literals instead
r20671 yield {'namespace': encoding.fromlocal(namespace),
'key': encoding.fromlocal(key),
'old': encoding.fromlocal(old),
'new': encoding.fromlocal(new)}, f
Peter Arrenbrecht
wireproto: make a number of commands batchable...
r14623 d = f.value
Pierre-Yves David
wireproto: handle other server output in pushkey...
r15652 d, output = d.split('\n', 1)
David Soria Parra
wireproto: catch possible cast error in pushkey...
r13450 try:
d = bool(int(d))
except ValueError:
raise error.ResponseError(
_('push failed (unexpected response):'), d)
Pierre-Yves David
wireproto: handle other server output in pushkey...
r15652 for l in output.splitlines(True):
self.ui.status(_('remote: '), l)
Peter Arrenbrecht
wireproto: make a number of commands batchable...
r14623 yield d
Matt Mackall
protocol: move basic ssh client commands to wirerepository
r11586
Peter Arrenbrecht
wireproto: make a number of commands batchable...
r14623 @batchable
Matt Mackall
protocol: move basic ssh client commands to wirerepository
r11586 def listkeys(self, namespace):
if not self.capable('pushkey'):
Peter Arrenbrecht
wireproto: make a number of commands batchable...
r14623 yield {}, None
f = future()
Pierre-Yves David
pushkey: add more verbose debug output regarding pushkey...
r17293 self.ui.debug('preparing listkeys for "%s"\n' % namespace)
Augie Fackler
wireproto: remove todict() and use {} literals instead
r20671 yield {'namespace': encoding.fromlocal(namespace)}, f
Peter Arrenbrecht
wireproto: make a number of commands batchable...
r14623 d = f.value
Pierre-Yves David
listkey: display the size of the listkey payload in a debug message...
r25339 self.ui.debug('received listkey for "%s": %i bytes\n'
% (namespace, len(d)))
Pierre-Yves David
wireproto: use pushkey.decodekey
r21653 yield pushkeymod.decodekeys(d)
Matt Mackall
protocol: move basic ssh client commands to wirerepository
r11586
Matt Mackall
protocol: unify stream_out client code
r11588 def stream_out(self):
return self._callstream('stream_out')
Matt Mackall
protocol: unify client changegroup methods
r11591 def changegroup(self, nodes, kind):
Benoit Boissinot
wireproto: refactor list of nodeid encoding / decoding
r11597 n = encodelist(nodes)
Pierre-Yves David
wireproto: drop the _decompress method in favor a new call type...
r20905 f = self._callcompressable("changegroup", roots=n)
Sune Foldager
changegroup: rename bundle-related functions and classes...
r22390 return changegroupmod.cg1unpacker(f, 'UN')
Matt Mackall
protocol: unify client changegroup methods
r11591
def changegroupsubset(self, bases, heads, kind):
self.requirecap('changegroupsubset', _('look up remote changes'))
Benoit Boissinot
wireproto: refactor list of nodeid encoding / decoding
r11597 bases = encodelist(bases)
heads = encodelist(heads)
Pierre-Yves David
wireproto: drop the _decompress method in favor a new call type...
r20905 f = self._callcompressable("changegroupsubset",
bases=bases, heads=heads)
Sune Foldager
changegroup: rename bundle-related functions and classes...
r22390 return changegroupmod.cg1unpacker(f, 'UN')
Matt Mackall
protocol: unify client changegroup methods
r11591
Pierre-Yves David
getbundle: declare type of parameters...
r21646 def getbundle(self, source, **kwargs):
Peter Arrenbrecht
wireproto: add getbundle() function...
r13741 self.requirecap('getbundle', _('look up remote changes'))
opts = {}
Pierre-Yves David
getbundle: sort bundlecaps before exchanging then over the wire...
r25128 bundlecaps = kwargs.get('bundlecaps')
if bundlecaps is not None:
kwargs['bundlecaps'] = sorted(bundlecaps)
else:
bundlecaps = () # kwargs could have it to None
Pierre-Yves David
getbundle: declare type of parameters...
r21646 for key, value in kwargs.iteritems():
if value is None:
continue
keytype = gboptsmap.get(key)
if keytype is None:
assert False, 'unexpected'
elif keytype == 'nodes':
value = encodelist(value)
Pierre-Yves David
wireprotocol: distinguish list and set in getbundle argument...
r25403 elif keytype in ('csv', 'scsv'):
Pierre-Yves David
getbundle: declare type of parameters...
r21646 value = ','.join(value)
Pierre-Yves David
wireproto: add a ``boolean`` type for getbundle parameters...
r21988 elif keytype == 'boolean':
Pierre-Yves David
wireprotocol: fix 'boolean' handling...
r22351 value = '%i' % bool(value)
Pierre-Yves David
getbundle: declare type of parameters...
r21646 elif keytype != 'plain':
raise KeyError('unknown getbundle option type %s'
% keytype)
opts[key] = value
Pierre-Yves David
wireproto: drop the _decompress method in favor a new call type...
r20905 f = self._callcompressable("getbundle", **opts)
Augie Fackler
cleanup: use __builtins__.any instead of util.any...
r25149 if any((cap.startswith('HG2') for cap in bundlecaps)):
Pierre-Yves David
unbundle20: retrieve unbundler instances through a factory function...
r24641 return bundle2.getunbundler(self.ui, f)
Pierre-Yves David
bundle2: allow bundle2 for pulling over the wire...
r21069 else:
Sune Foldager
changegroup: rename bundle-related functions and classes...
r22390 return changegroupmod.cg1unpacker(f, 'UN')
Peter Arrenbrecht
wireproto: add getbundle() function...
r13741
Matt Mackall
protocol: unify client unbundle support...
r11592 def unbundle(self, cg, heads, source):
'''Send cg (a readable file-like object representing the
changegroup to push, typically a chunkbuffer object) to the
Pierre-Yves David
bundle2: support for push over the wire...
r21075 remote server as a bundle.
When pushing a bundle10 stream, return an integer indicating the
result of the push (see localrepository.addchangegroup()).
When pushing a bundle20 stream, return a bundle20 stream.'''
Matt Mackall
protocol: unify client unbundle support...
r11592
Martin Geisler
wireproto: do not hash when heads == ['force']...
r14419 if heads != ['force'] and self.capable('unbundlehash'):
Shuhei Takahashi
wireproto: allow unbundle with hashed heads parameter (issue2126)...
r13942 heads = encodelist(['hashed',
util.sha1(''.join(sorted(heads))).digest()])
else:
heads = encodelist(heads)
Pierre-Yves David
bundle2: support for push over the wire...
r21075 if util.safehasattr(cg, 'deltaheader'):
# this a bundle10, do the old style call sequence
ret, output = self._callpush("unbundle", cg, heads=heads)
if ret == "":
raise error.ResponseError(
_('push failed:'), output)
try:
ret = int(ret)
except ValueError:
raise error.ResponseError(
_('push failed (unexpected response):'), ret)
Matt Mackall
protocol: unify client unbundle support...
r11592
Pierre-Yves David
bundle2: support for push over the wire...
r21075 for l in output.splitlines(True):
self.ui.status(_('remote: '), l)
else:
# bundle2 push. Send a stream, fetch a stream.
stream = self._calltwowaystream('unbundle', cg, heads=heads)
Pierre-Yves David
unbundle20: retrieve unbundler instances through a factory function...
r24641 ret = bundle2.getunbundler(self.ui, stream)
Matt Mackall
protocol: unify client unbundle support...
r11592 return ret
Peter Arrenbrecht
wireproto: add test for new optional arg missing on server...
r14048 def debugwireargs(self, one, two, three=None, four=None, five=None):
Peter Arrenbrecht
debug: add debugwireargs to test argument passing over the wire...
r13720 # don't pass optional arguments left at their default value
opts = {}
if three is not None:
opts['three'] = three
if four is not None:
opts['four'] = four
return self._call('debugwireargs', one=one, two=two, **opts)
Pierre-Yves David
wireproto: document protocol specific function of wirepeer...
r20904 def _call(self, cmd, **args):
"""execute <cmd> on the server
The command is expected to return a simple string.
returns the server reply as a string."""
raise NotImplementedError()
def _callstream(self, cmd, **args):
"""execute <cmd> on the server
The command is expected to return a stream.
returns the server reply as a file like object."""
raise NotImplementedError()
Pierre-Yves David
wireproto: drop the _decompress method in favor a new call type...
r20905 def _callcompressable(self, cmd, **args):
"""execute <cmd> on the server
The command is expected to return a stream.
Mads Kiilerich
spelling: fixes from spell checker
r21024 The stream may have been compressed in some implementations. This
Pierre-Yves David
wireproto: drop the _decompress method in favor a new call type...
r20905 function takes care of the decompression. This is the only difference
with _callstream.
returns the server reply as a file like object.
"""
raise NotImplementedError()
Pierre-Yves David
wireproto: document protocol specific function of wirepeer...
r20904 def _callpush(self, cmd, fp, **args):
"""execute a <cmd> on server
The command is expected to be related to a push. Push has a special
return method.
returns the server reply as a (ret, output) tuple. ret is either
empty (error) or a stringified int.
"""
raise NotImplementedError()
Pierre-Yves David
wireproto: add a _calltwowaystream method on wirepeer...
r21072 def _calltwowaystream(self, cmd, fp, **args):
"""execute <cmd> on server
The command will send a stream to the server and get a stream in reply.
"""
raise NotImplementedError()
Pierre-Yves David
wireproto: document protocol specific function of wirepeer...
r20904 def _abort(self, exception):
"""clearly abort the wire protocol connection and raise the exception
"""
raise NotImplementedError()
Matt Mackall
protocol: move basic ssh client commands to wirerepository
r11586 # server side
Pierre-Yves David
wireproto: document possible return type...
r20902 # wire protocol command can either return a string or one of these classes.
Dirkjan Ochtman
protocol: wrap non-string protocol responses in classes
r11625 class streamres(object):
Pierre-Yves David
wireproto: document possible return type...
r20902 """wireproto reply: binary stream
The call was successful and the result is a stream.
Iterate on the `self.gen` attribute to retrieve chunks.
"""
Dirkjan Ochtman
protocol: wrap non-string protocol responses in classes
r11625 def __init__(self, gen):
self.gen = gen
class pushres(object):
Pierre-Yves David
wireproto: document possible return type...
r20902 """wireproto reply: success with simple integer return
The call was successful and returned an integer contained in `self.res`.
"""
Dirkjan Ochtman
protocol: wrap non-string protocol responses in classes
r11625 def __init__(self, res):
self.res = res
Benoit Boissinot
wireproto: introduce pusherr() to deal with "unsynced changes" error...
r12703 class pusherr(object):
Pierre-Yves David
wireproto: document possible return type...
r20902 """wireproto reply: failure
The call failed. The `self.res` attribute contains the error message.
"""
Benoit Boissinot
wireproto: introduce pusherr() to deal with "unsynced changes" error...
r12703 def __init__(self, res):
self.res = res
Andrew Pritchard
wireproto: add out-of-band error class to allow remote repo to report errors...
r15017 class ooberror(object):
Pierre-Yves David
wireproto: document possible return type...
r20902 """wireproto reply: failure of a batch of operation
Something failed during a batch call. The error message is stored in
`self.message`.
"""
Andrew Pritchard
wireproto: add out-of-band error class to allow remote repo to report errors...
r15017 def __init__(self, message):
self.message = message
Matt Mackall
protocol: introduce wireproto.py...
r11581 def dispatch(repo, proto, command):
Kevin Bullock
filtering: rename filters to their antonyms...
r18382 repo = repo.filtered("served")
Matt Mackall
protocol: introduce wireproto.py...
r11581 func, spec = commands[command]
args = proto.getargs(spec)
Dirkjan Ochtman
protocol: wrap non-string protocol responses in classes
r11625 return func(repo, proto, *args)
Matt Mackall
protocol: introduce wireproto.py...
r11581
Peter Arrenbrecht
wireproto: fix handling of '*' args for HTTP and SSH
r13721 def options(cmd, keys, others):
opts = {}
for k in keys:
if k in others:
opts[k] = others[k]
del others[k]
if others:
Pierre-Yves David
wireproto: rephrase the error message for unknown getbundle parameters...
r21728 sys.stderr.write("warning: %s ignored unexpected arguments %s\n"
Peter Arrenbrecht
wireproto: fix handling of '*' args for HTTP and SSH
r13721 % (cmd, ",".join(others)))
return opts
Pierre-Yves David
wireproto: add decorator for wire protocol command...
r20906 # list of commands
commands = {}
def wireprotocommand(name, args=''):
Mads Kiilerich
spelling: fixes from spell checker
r21024 """decorator for wire protocol command"""
Pierre-Yves David
wireproto: add decorator for wire protocol command...
r20906 def register(func):
commands[name] = (func, args)
return func
return register
Pierre-Yves David
wireproto: use decorator for the batch command
r20907 @wireprotocommand('batch', 'cmds *')
Peter Arrenbrecht
wireproto: add batching support to wirerepository...
r14622 def batch(repo, proto, cmds, others):
Kevin Bullock
filtering: rename filters to their antonyms...
r18382 repo = repo.filtered("served")
Peter Arrenbrecht
wireproto: add batching support to wirerepository...
r14622 res = []
for pair in cmds.split(';'):
op, args = pair.split(' ', 1)
vals = {}
for a in args.split(','):
if a:
n, v = a.split('=')
vals[n] = unescapearg(v)
func, spec = commands[op]
if spec:
keys = spec.split()
data = {}
for k in keys:
if k == '*':
star = {}
for key in vals.keys():
if key not in keys:
star[key] = vals[key]
data['*'] = star
else:
data[k] = vals[k]
result = func(repo, proto, *[data[k] for k in keys])
else:
result = func(repo, proto)
Andrew Pritchard
wireproto: add out-of-band error class to allow remote repo to report errors...
r15017 if isinstance(result, ooberror):
return result
Peter Arrenbrecht
wireproto: add batching support to wirerepository...
r14622 res.append(escapearg(result))
return ';'.join(res)
Pierre-Yves David
wireproto: use decorator for the between command
r20908 @wireprotocommand('between', 'pairs')
Matt Mackall
protocol: add proto to method prototypes
r11583 def between(repo, proto, pairs):
Benoit Boissinot
wireproto: refactor list of nodeid encoding / decoding
r11597 pairs = [decodelist(p, '-') for p in pairs.split(" ")]
Matt Mackall
protocol: introduce wireproto.py...
r11581 r = []
for b in repo.between(pairs):
Benoit Boissinot
wireproto: refactor list of nodeid encoding / decoding
r11597 r.append(encodelist(b) + "\n")
Matt Mackall
protocol: introduce wireproto.py...
r11581 return "".join(r)
Pierre-Yves David
wireproto: use decorator for the branchmap command
r20909 @wireprotocommand('branchmap')
Matt Mackall
protocol: add proto to method prototypes
r11583 def branchmap(repo, proto):
Pierre-Yves David
clfilter: drop extra filtering in wireprotocol...
r18281 branchmap = repo.branchmap()
Matt Mackall
protocol: introduce wireproto.py...
r11581 heads = []
for branch, nodes in branchmap.iteritems():
Matt Mackall
branch: operate on branch names in local string space where possible...
r13047 branchname = urllib.quote(encoding.fromlocal(branch))
Benoit Boissinot
wireproto: refactor list of nodeid encoding / decoding
r11597 branchnodes = encodelist(nodes)
heads.append('%s %s' % (branchname, branchnodes))
Matt Mackall
protocol: introduce wireproto.py...
r11581 return '\n'.join(heads)
Pierre-Yves David
wireproto: use decorator for the branches command
r20910 @wireprotocommand('branches', 'nodes')
Matt Mackall
protocol: add proto to method prototypes
r11583 def branches(repo, proto, nodes):
Benoit Boissinot
wireproto: refactor list of nodeid encoding / decoding
r11597 nodes = decodelist(nodes)
Matt Mackall
protocol: introduce wireproto.py...
r11581 r = []
for b in repo.branches(nodes):
Benoit Boissinot
wireproto: refactor list of nodeid encoding / decoding
r11597 r.append(encodelist(b) + "\n")
Matt Mackall
protocol: introduce wireproto.py...
r11581 return "".join(r)
Pierre-Yves David
wireproto: extract capabilities list in outside the wireproto function...
r20774
wireprotocaps = ['lookup', 'changegroupsubset', 'branchmap', 'pushkey',
'known', 'getbundle', 'unbundlehash', 'batch']
Pierre-Yves David
wireproto: move wireproto capabilities computation in a subfunction...
r20775
def _capabilities(repo, proto):
"""return a list of capabilities for a repo
This function exists to allow extensions to easily wrap capabilities
computation
- returns a lists: easy to alter
- change done here will be propagated to both `capabilities` and `hello`
Mads Kiilerich
spelling: fixes from spell checker
r21024 command without any other action needed.
Pierre-Yves David
wireproto: move wireproto capabilities computation in a subfunction...
r20775 """
Pierre-Yves David
wireproto: extract capabilities list in outside the wireproto function...
r20774 # copy to prevent modification of the global list
caps = list(wireprotocaps)
Dirkjan Ochtman
protocol: move the streamclone implementation into wireproto
r11627 if _allowstream(repo.ui):
Benoit Allard
protocol: Add the stream-preferred capability...
r16361 if repo.ui.configbool('server', 'preferuncompressed', False):
caps.append('stream-preferred')
Sune Foldager
clone: only use stream when we understand the revlog format...
r12296 requiredformats = repo.requirements & repo.supportedformats
# if our local revlogs are just revlogv1, add 'stream' cap
if not requiredformats - set(('revlogv1',)):
caps.append('stream')
# otherwise, add 'streamreqs' detailing our local revlog format
else:
caps.append('streamreqs=%s' % ','.join(requiredformats))
Pierre-Yves David
bundle2: advertise bundle2 by default...
r24696 if repo.ui.configbool('experimental', 'bundle2-advertise', True):
Pierre-Yves David
bundle2: introduce a `getrepocaps` to retrieve the bundle2 caps of a repo...
r22342 capsblob = bundle2.encodecaps(bundle2.getrepocaps(repo))
Pierre-Yves David
bundle2: rename format, parts and config to final names...
r24686 caps.append('bundle2=' + urllib.quote(capsblob))
Matt Mackall
protocol: unify server-side capabilities functions
r11594 caps.append('unbundle=%s' % ','.join(changegroupmod.bundlepriority))
Mike Edgar
wireproto: add config knob for http header length limit...
r25691 caps.append(
'httpheader=%d' % repo.ui.configint('server', 'maxhttpheaderlen', 1024))
Pierre-Yves David
wireproto: move wireproto capabilities computation in a subfunction...
r20775 return caps
Mads Kiilerich
spelling: fixes from spell checker
r21024 # If you are writing an extension and consider wrapping this function. Wrap
Pierre-Yves David
wireproto: move wireproto capabilities computation in a subfunction...
r20775 # `_capabilities` instead.
Pierre-Yves David
wireproto: use decorator for the capabilities command
r20911 @wireprotocommand('capabilities')
Pierre-Yves David
wireproto: move wireproto capabilities computation in a subfunction...
r20775 def capabilities(repo, proto):
return ' '.join(_capabilities(repo, proto))
Matt Mackall
protocol: unify server-side capabilities functions
r11594
Pierre-Yves David
wireproto: use decorator for the changegroup command
r20912 @wireprotocommand('changegroup', 'roots')
Matt Mackall
protocol: unify changegroup commands...
r11584 def changegroup(repo, proto, roots):
Benoit Boissinot
wireproto: refactor list of nodeid encoding / decoding
r11597 nodes = decodelist(roots)
Pierre-Yves David
localrepo: move the changegroup method in changegroup module...
r20931 cg = changegroupmod.changegroup(repo, nodes, 'serve')
Dirkjan Ochtman
protocol: wrap non-string protocol responses in classes
r11625 return streamres(proto.groupchunks(cg))
Matt Mackall
protocol: unify changegroup commands...
r11584
Pierre-Yves David
wireproto: use decorator for the changegroupsubset command
r20913 @wireprotocommand('changegroupsubset', 'bases heads')
Matt Mackall
protocol: unify changegroup commands...
r11584 def changegroupsubset(repo, proto, bases, heads):
Benoit Boissinot
wireproto: refactor list of nodeid encoding / decoding
r11597 bases = decodelist(bases)
heads = decodelist(heads)
Pierre-Yves David
localrepo: move the changegroupsubset method in changegroup module...
r20927 cg = changegroupmod.changegroupsubset(repo, bases, heads, 'serve')
Dirkjan Ochtman
protocol: wrap non-string protocol responses in classes
r11625 return streamres(proto.groupchunks(cg))
Matt Mackall
protocol: unify changegroup commands...
r11584
Pierre-Yves David
wireproto: use decorator for the debugwireargs command
r20914 @wireprotocommand('debugwireargs', 'one two *')
Peter Arrenbrecht
wireproto: fix handling of '*' args for HTTP and SSH
r13721 def debugwireargs(repo, proto, one, two, others):
# only accept optional args from the known set
opts = options('debugwireargs', ['three', 'four'], others)
return repo.debugwireargs(one, two, **opts)
Peter Arrenbrecht
debug: add debugwireargs to test argument passing over the wire...
r13720
Pierre-Yves David
wireproto: expose the list of getbundle arguments to extensions...
r21615 # List of options accepted by getbundle.
#
# Meant to be extended by extensions. It is the extension's responsibility to
# ensure such options are properly processed in exchange.getbundle.
gboptslist = ['heads', 'common', 'bundlecaps']
Pierre-Yves David
wireproto: use decorator for the getbundle command
r20915 @wireprotocommand('getbundle', '*')
Peter Arrenbrecht
wireproto: add getbundle() function...
r13741 def getbundle(repo, proto, others):
Pierre-Yves David
getbundle: declare type of parameters...
r21646 opts = options('getbundle', gboptsmap.keys(), others)
Peter Arrenbrecht
wireproto: add getbundle() function...
r13741 for k, v in opts.iteritems():
Pierre-Yves David
getbundle: declare type of parameters...
r21646 keytype = gboptsmap[k]
if keytype == 'nodes':
Benoit Boissinot
bundle-ng: add bundlecaps argument to getbundle() command
r19201 opts[k] = decodelist(v)
Pierre-Yves David
getbundle: declare type of parameters...
r21646 elif keytype == 'csv':
Pierre-Yves David
wireprotocol: distinguish list and set in getbundle argument...
r25403 opts[k] = list(v.split(','))
elif keytype == 'scsv':
Benoit Boissinot
bundle-ng: add bundlecaps argument to getbundle() command
r19201 opts[k] = set(v.split(','))
Pierre-Yves David
wireproto: add a ``boolean`` type for getbundle parameters...
r21988 elif keytype == 'boolean':
Pierre-Yves David
wireprotocol: fix 'boolean' handling...
r22351 opts[k] = bool(v)
Pierre-Yves David
getbundle: declare type of parameters...
r21646 elif keytype != 'plain':
raise KeyError('unknown getbundle option type %s'
% keytype)
Pierre-Yves David
bundle2: allow bundle2 for pulling over the wire...
r21069 cg = exchange.getbundle(repo, 'serve', **opts)
Peter Arrenbrecht
wireproto: add getbundle() function...
r13741 return streamres(proto.groupchunks(cg))
Pierre-Yves David
wireproto: use decorator for the heads command
r20916 @wireprotocommand('heads')
Matt Mackall
protocol: add proto to method prototypes
r11583 def heads(repo, proto):
Pierre-Yves David
clfilter: drop extra filtering in wireprotocol...
r18281 h = repo.heads()
Benoit Boissinot
wireproto: refactor list of nodeid encoding / decoding
r11597 return encodelist(h) + "\n"
Matt Mackall
protocol: introduce wireproto.py...
r11581
Pierre-Yves David
wireproto: use decorator for the hello command
r20917 @wireprotocommand('hello')
Matt Mackall
protocol: unify server-side capabilities functions
r11594 def hello(repo, proto):
'''the hello command returns a set of lines describing various
interesting things about the server, in an RFC822-like format.
Currently the only one defined is "capabilities", which
consists of a line in the form:
capabilities: space separated list of tokens
'''
return "capabilities: %s\n" % (capabilities(repo, proto))
Pierre-Yves David
wireproto: use decorator for the listkeys command
r20919 @wireprotocommand('listkeys', 'namespace')
Matt Mackall
protocol: add proto to method prototypes
r11583 def listkeys(repo, proto, namespace):
Andreas Freimuth
wireproto: do not call pushkey module directly (issue3041)...
r15217 d = repo.listkeys(encoding.tolocal(namespace)).items()
Pierre-Yves David
wireproto: use pushkey.encodekey
r21651 return pushkeymod.encodekeys(d)
Matt Mackall
protocol: introduce wireproto.py...
r11581
Pierre-Yves David
wireproto: use decorator for the lookup command
r20920 @wireprotocommand('lookup', 'key')
Matt Mackall
protocol: add proto to method prototypes
r11583 def lookup(repo, proto, key):
Matt Mackall
protocol: introduce wireproto.py...
r11581 try:
Matt Mackall
wireproto: refuse to lookup secret csets
r15925 k = encoding.tolocal(key)
c = repo[k]
r = c.hex()
Matt Mackall
protocol: introduce wireproto.py...
r11581 success = 1
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except Exception as inst:
Matt Mackall
protocol: introduce wireproto.py...
r11581 r = str(inst)
success = 0
return "%s %s\n" % (success, r)
Pierre-Yves David
wireproto: use decorator for the known command
r20918 @wireprotocommand('known', 'nodes *')
Peter Arrenbrecht
wireproto: enable optional args for known() for future extensibility...
r14436 def known(repo, proto, nodes, others):
Peter Arrenbrecht
wireproto: add known([id]) function...
r13723 return ''.join(b and "1" or "0" for b in repo.known(decodelist(nodes)))
Pierre-Yves David
wireproto: use decorator for the pushkey command
r20921 @wireprotocommand('pushkey', 'namespace key old new')
Matt Mackall
protocol: add proto to method prototypes
r11583 def pushkey(repo, proto, namespace, key, old, new):
Matt Mackall
pushkey: use UTF-8
r13050 # compatibility with pre-1.8 clients which were accidentally
# sending raw binary nodes rather than utf-8-encoded hex
if len(new) == 20 and new.encode('string-escape') != new:
# looks like it could be a binary node
try:
Alexander Solovyov
remove unused imports and variables
r14064 new.decode('utf-8')
Matt Mackall
pushkey: use UTF-8
r13050 new = encoding.tolocal(new) # but cleanly decodes as UTF-8
except UnicodeDecodeError:
pass # binary, leave unmodified
else:
new = encoding.tolocal(new) # normal path
Wagner Bruna
wireproto: fix pushkey hook failure and output on remote http repo...
r17793 if util.safehasattr(proto, 'restore'):
proto.redirect()
try:
r = repo.pushkey(encoding.tolocal(namespace), encoding.tolocal(key),
encoding.tolocal(old), new) or False
except util.Abort:
r = False
output = proto.restore()
return '%s\n%s' % (int(r), output)
Andreas Freimuth
wireproto: do not call pushkey module directly (issue3041)...
r15217 r = repo.pushkey(encoding.tolocal(namespace), encoding.tolocal(key),
encoding.tolocal(old), new)
Matt Mackall
protocol: introduce wireproto.py...
r11581 return '%s\n' % int(r)
Dirkjan Ochtman
protocol: move the streamclone implementation into wireproto
r11627 def _allowstream(ui):
return ui.configbool('server', 'uncompressed', True, untrusted=True)
Pierre-Yves David
wireproto: use decorator for the stream command
r20922 @wireprotocommand('stream_out')
Matt Mackall
protocol: unify stream_out command
r11585 def stream(repo, proto):
Dirkjan Ochtman
protocol: move the streamclone implementation into wireproto
r11627 '''If the server supports streaming clone, it advertises the "stream"
capability with a value representing the version and flags of the repo
it is serving. Client checks to see if it understands the format.
'''
if not _allowstream(repo.ui):
return '1\n'
Gregory Szorc
exchange: move code for generating a streaming clone into exchange...
r25235 def getstream(it):
yield '0\n'
for chunk in it:
yield chunk
Bryan O'Sullivan
wireproto: don't audit local paths during stream_out...
r17556
Gregory Szorc
exchange: move code for generating a streaming clone into exchange...
r25235 try:
# LockError may be raised before the first result is yielded. Don't
# emit output until we're sure we got the lock successfully.
it = exchange.generatestreamclone(repo)
return streamres(getstream(it))
except error.LockError:
return '2\n'
Matt Mackall
protocol: unify stream_out command
r11585
Pierre-Yves David
wireproto: use decorator for the ubundle command
r20923 @wireprotocommand('unbundle', 'heads')
Matt Mackall
protocol: unify unbundle on the server side
r11593 def unbundle(repo, proto, heads):
Benoit Boissinot
wireproto: refactor list of nodeid encoding / decoding
r11597 their_heads = decodelist(heads)
Matt Mackall
protocol: unify unbundle on the server side
r11593
Pierre-Yves David
unbundle: extract checkheads in its own function...
r20967 try:
proto.redirect()
Matt Mackall
protocol: unify unbundle on the server side
r11593
Pierre-Yves David
unbundle: extract checkheads in its own function...
r20967 exchange.check_heads(repo, their_heads, 'preparing changes')
Benoit Boissinot
wireproto: redirect the output earlier
r12702
Pierre-Yves David
unbundle: extract checkheads in its own function...
r20967 # write bundle data to temporary file because it can be big
fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
fp = os.fdopen(fd, 'wb+')
r = 0
Matt Mackall
protocol: unify unbundle on the server side
r11593 try:
Pierre-Yves David
unbundle: extract checkheads in its own function...
r20967 proto.getfile(fp)
Pierre-Yves David
unbundle: extract the core logic in another function...
r20968 fp.seek(0)
Pierre-Yves David
bundle2: add a ui argument to readbundle...
r21064 gen = exchange.readbundle(repo.ui, fp, None)
Pierre-Yves David
unbundle: extract the core logic in another function...
r20968 r = exchange.unbundle(repo, gen, their_heads, 'serve',
proto._client())
Pierre-Yves David
bundle2: support for push over the wire...
r21075 if util.safehasattr(r, 'addpart'):
Mads Kiilerich
spelling: fixes from proofreading of spell checker issues
r23139 # The return looks streamable, we are in the bundle2 case and
Pierre-Yves David
bundle2: support for push over the wire...
r21075 # should return a stream.
return streamres(r.getchunks())
Pierre-Yves David
unbundle: extract checkheads in its own function...
r20967 return pushres(r)
Matt Mackall
protocol: unify unbundle on the server side
r11593 finally:
Pierre-Yves David
unbundle: extract checkheads in its own function...
r20967 fp.close()
os.unlink(tempname)
Pierre-Yves David
bundle2: refactor error bundle creation for the wireprotocol...
r24796
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except (error.BundleValueError, util.Abort, error.PushRaced) as exc:
Pierre-Yves David
bundle2: refactor error bundle creation for the wireprotocol...
r24796 # handle non-bundle2 case first
if not getattr(exc, 'duringunbundle2', False):
try:
raise
except util.Abort:
# The old code we moved used sys.stderr directly.
# We did not change it to minimise code change.
# This need to be moved to something proper.
# Feel free to do it.
sys.stderr.write("abort: %s\n" % exc)
return pushres(0)
except error.PushRaced:
return pusherr(str(exc))
bundler = bundle2.bundle20(repo.ui)
Pierre-Yves David
bundle2-wireproto: properly propagate the server output on error (issue4594)...
r24797 for out in getattr(exc, '_bundle2salvagedoutput', ()):
bundler.addpart(out)
Pierre-Yves David
bundle2: refactor error bundle creation for the wireprotocol...
r24796 try:
Pierre-Yves David
bundle2: convey PushkeyFailed error over the wire...
r25493 try:
raise
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except error.PushkeyFailed as exc:
Pierre-Yves David
bundle2: convey PushkeyFailed error over the wire...
r25493 # check client caps
remotecaps = getattr(exc, '_replycaps', None)
if (remotecaps is not None
and 'pushkey' not in remotecaps.get('error', ())):
# no support remote side, fallback to Abort handler.
raise
part = bundler.newpart('error:pushkey')
part.addparam('in-reply-to', exc.partid)
if exc.namespace is not None:
part.addparam('namespace', exc.namespace, mandatory=False)
if exc.key is not None:
part.addparam('key', exc.key, mandatory=False)
if exc.new is not None:
part.addparam('new', exc.new, mandatory=False)
if exc.old is not None:
part.addparam('old', exc.old, mandatory=False)
if exc.ret is not None:
part.addparam('ret', exc.ret, mandatory=False)
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except error.BundleValueError as exc:
Pierre-Yves David
bundle2: rename format, parts and config to final names...
r24686 errpart = bundler.newpart('error:unsupportedcontent')
Pierre-Yves David
bundle2: support None parttype in BundleValueError...
r21627 if exc.parttype is not None:
errpart.addparam('parttype', exc.parttype)
Pierre-Yves David
bundle2: support transmission of params error over the wire...
r21622 if exc.params:
errpart.addparam('params', '\0'.join(exc.params))
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except util.Abort as exc:
Pierre-Yves David
bundle2: refactor error bundle creation for the wireprotocol...
r24796 manargs = [('message', str(exc))]
Pierre-Yves David
bundle2: gracefully handle abort during unbundle...
r21177 advargs = []
Pierre-Yves David
bundle2: refactor error bundle creation for the wireprotocol...
r24796 if exc.hint is not None:
advargs.append(('hint', exc.hint))
Pierre-Yves David
bundle2: rename format, parts and config to final names...
r24686 bundler.addpart(bundle2.bundlepart('error:abort',
Pierre-Yves David
bundle2: gracefully handle abort during unbundle...
r21177 manargs, advargs))
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except error.PushRaced as exc:
Pierre-Yves David
bundle2: rename format, parts and config to final names...
r24686 bundler.newpart('error:pushraced', [('message', str(exc))])
Pierre-Yves David
bundle2: refactor error bundle creation for the wireprotocol...
r24796 return streamres(bundler.getchunks())