##// END OF EJS Templates
commandserver: move "listen" responsibility from service to handler...
commandserver: move "listen" responsibility from service to handler This enables chg to replace a server socket in an atomic way: 1. bind to a temp address 2. listen 3. rename Currently 3 happens before 2 so a client may see the socket file but fails to connect to it.

File last commit:

r30466:2add671b default
r32232:c8b9943c default
Show More
proto.py
189 lines | 7.0 KiB | text/x-python | PythonLexer
various
hgext: add largefiles extension...
r15168 # Copyright 2011 Fog Creek Software
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
liscju
py3: make largefiles/proto.py use absolute_import
r29312 from __future__ import absolute_import
various
hgext: add largefiles extension...
r15168
import os
Mads Kiilerich
largefiles: make the protocol hack for replacing heads with lheads more precise...
r19917 import re
various
hgext: add largefiles extension...
r15168
from mercurial.i18n import _
liscju
py3: make largefiles/proto.py use absolute_import
r29312 from mercurial import (
error,
httppeer,
util,
wireproto,
)
from . import (
lfutil,
)
timeless
pycompat: switch to util.urlreq/util.urlerr for py3 compat
r28883 urlerr = util.urlerr
urlreq = util.urlreq
Greg Ward
largefiles: cosmetics, whitespace, code style...
r15255 LARGEFILES_REQUIRED_MSG = ('\nThis repository uses the largefiles extension.'
'\n\nPlease enable it in your Mercurial config '
'file.\n')
various
hgext: add largefiles extension...
r15168
Bryan O'Sullivan
largefiles: quiet (and document) undefined name errors (issue3886)...
r18922 # these will all be replaced by largefiles.uisetup
capabilitiesorig = None
ssholdcallstream = None
httpoldcallstream = None
various
hgext: add largefiles extension...
r15168 def putlfile(repo, proto, sha):
Mads Kiilerich
largefiles: add some docstrings
r28576 '''Server command for putting a largefile into a repository's local store
and into the user cache.'''
various
hgext: add largefiles extension...
r15168 proto.redirect()
Hao Lian
largefiles: replace tempfile.NamedTemporaryFile with tempfile.mkstemp...
r15391
hlian
largefiles: in putlfile, ensure tempfile's directory exists prior to creation...
r16594 path = lfutil.storepath(repo, sha)
util.makedirs(os.path.dirname(path))
tmpfp = util.atomictempfile(path, createmode=repo.store.createmode)
various
hgext: add largefiles extension...
r15168 try:
Matt Mackall
largefiles: use try/except/finally
r25079 proto.getfile(tmpfp)
tmpfp._fp.seek(0)
if sha != lfutil.hexsha1(tmpfp._fp):
raise IOError(0, _('largefile contents do not match hash'))
tmpfp.close()
lfutil.linktousercache(repo, sha)
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except IOError as e:
Matt Mackall
largefiles: use try/except/finally
r25079 repo.ui.warn(_('largefiles: failed to put %s into store: %s\n') %
(sha, e.strerror))
return wireproto.pushres(1)
various
hgext: add largefiles extension...
r15168 finally:
Martin Geisler
largefiles: respect store.createmode and avoid extra file copy...
r16155 tmpfp.discard()
various
hgext: add largefiles extension...
r15168
return wireproto.pushres(0)
def getlfile(repo, proto, sha):
Mads Kiilerich
largefiles: add some docstrings
r28576 '''Server command for retrieving a largefile from the repository-local
cache or user cache.'''
various
hgext: add largefiles extension...
r15168 filename = lfutil.findfile(repo, sha)
if not filename:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_('requested largefile %s not present in cache')
% sha)
various
hgext: add largefiles extension...
r15168 f = open(filename, 'rb')
length = os.fstat(f.fileno())[6]
Greg Ward
largefiles: improve comments, internal docstrings...
r15252
# Since we can't set an HTTP content-length header here, and
# Mercurial core provides no way to give the length of a streamres
# (and reading the entire file into RAM would be ill-advised), we
# just send the length on the first line of the response, like the
# ssh proto does for string responses.
various
hgext: add largefiles extension...
r15168 def generator():
yield '%d\n' % length
Mads Kiilerich
largefiles: use filechunkiter for iterating largefile when serving getlfile...
r19009 for chunk in util.filechunkiter(f):
various
hgext: add largefiles extension...
r15168 yield chunk
Gregory Szorc
wireproto: perform chunking and compression at protocol layer (API)...
r30466 return wireproto.streamres(gen=generator())
various
hgext: add largefiles extension...
r15168
def statlfile(repo, proto, sha):
Mads Kiilerich
largefiles: add some docstrings
r28576 '''Server command for checking if a largefile is present - returns '2\n' if
the largefile is missing, '0\n' if it seems to be in good condition.
Mads Kiilerich
largefiles: don't verify largefile hashes on servers when processing statlfile...
r18488
The value 1 is reserved for mismatched checksum, but that is too expensive
to be verified on every stat and must be caught be running 'hg verify'
server side.'''
various
hgext: add largefiles extension...
r15168 filename = lfutil.findfile(repo, sha)
if not filename:
return '2\n'
Mads Kiilerich
largefiles: don't verify largefile hashes on servers when processing statlfile...
r18488 return '0\n'
various
hgext: add largefiles extension...
r15168
def wirereposetup(ui, repo):
class lfileswirerepository(repo.__class__):
def putlfile(self, sha, fd):
# unfortunately, httprepository._callpush tries to convert its
# input file-like into a bundle before sending it, so we can't use
# it ...
Peter Arrenbrecht
peer: introduce real peer classes...
r17192 if issubclass(self.__class__, httppeer.httppeer):
Mads Kiilerich
largefiles: don't mute and obfuscate http errors when putlfile fails...
r26825 res = self._call('putlfile', data=fd, sha=sha,
headers={'content-type':'application/mercurial-0.1'})
various
hgext: add largefiles extension...
r15168 try:
Kevin Gessner
largefiles: display remote errors from putlfile (issue3123) (issue3149)
r15778 d, output = res.split('\n', 1)
for l in output.splitlines(True):
Mads Kiilerich
largefiles: don't add extra \n when displaying remote messages in putlfile
r19949 self.ui.warn(_('remote: '), l) # assume l ends with \n
Kevin Gessner
largefiles: display remote errors from putlfile (issue3123) (issue3149)
r15778 return int(d)
Mads Kiilerich
largefiles: don't mute and obfuscate http errors when putlfile fails...
r26825 except ValueError:
Mads Kiilerich
largefiles: fix 'unexpected response' warning newlines...
r19947 self.ui.warn(_('unexpected putlfile response: %r\n') % res)
various
hgext: add largefiles extension...
r15168 return 1
# ... but we can't use sshrepository._call because the data=
# argument won't get sent, and _callpush does exactly what we want
# in this case: send the data straight through
else:
try:
ret, output = self._callpush("putlfile", fd, sha=sha)
if ret == "":
raise error.ResponseError(_('putlfile failed:'),
output)
return int(ret)
except IOError:
return 1
except ValueError:
raise error.ResponseError(
_('putlfile failed (unexpected response):'), ret)
def getlfile(self, sha):
Mads Kiilerich
largefiles: move protocol conversion into getlfile and make it an iterable...
r19004 """returns an iterable with the chunks of the file with sha sha"""
various
hgext: add largefiles extension...
r15168 stream = self._callstream("getlfile", sha=sha)
length = stream.readline()
try:
length = int(length)
except ValueError:
Matt Mackall
largefiles: fix over-long lines
r15170 self._abort(error.ResponseError(_("unexpected response:"),
length))
Mads Kiilerich
largefiles: move protocol conversion into getlfile and make it an iterable...
r19004
Mads Kiilerich
largefiles: drop limitreader, use filechunkiter limit...
r19005 # SSH streams will block if reading more than length
Mads Kiilerich
util: increase filechunkiter size to 128k...
r30181 for chunk in util.filechunkiter(stream, limit=length):
Mads Kiilerich
largefiles: move protocol conversion into getlfile and make it an iterable...
r19004 yield chunk
Mads Kiilerich
largefiles: getlfile must hit end of HTTP chunked streams to reuse connections...
r19006 # HTTP streams must hit the end to process the last empty
# chunk of Chunked-Encoding so the connection can be reused.
if issubclass(self.__class__, httppeer.httppeer):
chunk = stream.read(1)
if chunk:
self._abort(error.ResponseError(_("unexpected response:"),
chunk))
various
hgext: add largefiles extension...
r15168
Mads Kiilerich
largefiles: import whole modules instead of importing parts of them...
r21084 @wireproto.batchable
various
hgext: add largefiles extension...
r15168 def statlfile(self, sha):
Mads Kiilerich
largefiles: import whole modules instead of importing parts of them...
r21084 f = wireproto.future()
Na'Tosha Bard
largefiles: batch statlfile requests when pushing a largefiles repo (issue3386)...
r17127 result = {'sha': sha}
yield result, f
various
hgext: add largefiles extension...
r15168 try:
Na'Tosha Bard
largefiles: batch statlfile requests when pushing a largefiles repo (issue3386)...
r17127 yield int(f.value)
timeless
pycompat: switch to util.urlreq/util.urlerr for py3 compat
r28883 except (ValueError, urlerr.httperror):
Greg Ward
largefiles: improve comments, internal docstrings...
r15252 # If the server returns anything but an integer followed by a
various
hgext: add largefiles extension...
r15168 # newline, newline, it's not speaking our language; if we get
# an HTTP error, we can't be sure the largefile is present;
Greg Ward
largefiles: improve comments, internal docstrings...
r15252 # either way, consider it missing.
Na'Tosha Bard
largefiles: batch statlfile requests when pushing a largefiles repo (issue3386)...
r17127 yield 2
various
hgext: add largefiles extension...
r15168
repo.__class__ = lfileswirerepository
# advertise the largefiles=serve capability
def capabilities(repo, proto):
Mads Kiilerich
largefiles: add some docstrings
r28576 '''Wrap server command to announce largefile server capability'''
Na'Tosha Bard
largefiles: remove use of underscores that breaks coding convention
r16247 return capabilitiesorig(repo, proto) + ' largefiles=serve'
various
hgext: add largefiles extension...
r15168
def heads(repo, proto):
Mads Kiilerich
largefiles: add some docstrings
r28576 '''Wrap server command - largefile capable clients will know to call
lheads instead'''
various
hgext: add largefiles extension...
r15168 if lfutil.islfilesrepo(repo):
Na'Tosha Bard
largefiles: remove pre-1.9 code from extension first bundled with 1.9
r15224 return wireproto.ooberror(LARGEFILES_REQUIRED_MSG)
various
hgext: add largefiles extension...
r15168 return wireproto.heads(repo, proto)
Na'Tosha Bard
largefiles: remove use of underscores that breaks coding convention
r16247 def sshrepocallstream(self, cmd, **args):
various
hgext: add largefiles extension...
r15168 if cmd == 'heads' and self.capable('largefiles'):
cmd = 'lheads'
if cmd == 'batch' and self.capable('largefiles'):
args['cmds'] = args['cmds'].replace('heads ', 'lheads ')
Na'Tosha Bard
largefiles: remove use of underscores that breaks coding convention
r16247 return ssholdcallstream(self, cmd, **args)
various
hgext: add largefiles extension...
r15168
Mads Kiilerich
largefiles: make the protocol hack for replacing heads with lheads more precise...
r19917 headsre = re.compile(r'(^|;)heads\b')
Na'Tosha Bard
largefiles: remove use of underscores that breaks coding convention
r16247 def httprepocallstream(self, cmd, **args):
various
hgext: add largefiles extension...
r15168 if cmd == 'heads' and self.capable('largefiles'):
cmd = 'lheads'
if cmd == 'batch' and self.capable('largefiles'):
Mads Kiilerich
largefiles: make the protocol hack for replacing heads with lheads more precise...
r19917 args['cmds'] = headsre.sub('lheads', args['cmds'])
Na'Tosha Bard
largefiles: remove use of underscores that breaks coding convention
r16247 return httpoldcallstream(self, cmd, **args)