##// END OF EJS Templates
Teach import to understand git diff extensions....
Teach import to understand git diff extensions. Vanilla patch chokes on git patches that include files that are copied or renamed, then modified. So this code detects that case and rewrites the patch if necessary.

File last commit:

r2859:345bac2b default
r2860:b3d1145e default
Show More
httprepo.py
351 lines | 12.4 KiB | text/x-python | PythonLexer
mpm@selenic.com
Break apart hg.py...
r1089 # httprepo.py - HTTP repository proxy classes for mercurial
#
# Copyright 2005 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
from node import *
from remoterepo import *
Benoit Boissinot
i18n first part: make '_' available for files who need it
r1400 from i18n import gettext as _
Bryan O'Sullivan
Fix lots of exception-related problems....
r1251 from demandload import *
Thomas Arendsen Hein
Catch HTTPException when reading from remote http repository....
r2015 demandload(globals(), "hg os urllib urllib2 urlparse zlib util httplib")
Vadim Gelfer
http client: better work with authorization errors, broken sockets.
r2467 demandload(globals(), "errno keepalive tempfile socket")
mpm@selenic.com
Break apart hg.py...
r1089
Vadim Gelfer
httprepo: make "http://user:pass@host/" urls work
r2447 class passwordmgr(urllib2.HTTPPasswordMgrWithDefaultRealm):
Vadim Gelfer
prompt user for http authentication info...
r2281 def __init__(self, ui):
Vadim Gelfer
httprepo: make "http://user:pass@host/" urls work
r2447 urllib2.HTTPPasswordMgrWithDefaultRealm.__init__(self)
Vadim Gelfer
prompt user for http authentication info...
r2281 self.ui = ui
def find_user_password(self, realm, authuri):
Vadim Gelfer
httprepo: make "http://user:pass@host/" urls work
r2447 authinfo = urllib2.HTTPPasswordMgrWithDefaultRealm.find_user_password(
Vadim Gelfer
prompt user for http authentication info...
r2281 self, realm, authuri)
Alexis S. L. Carvalho
Allow http://user@example.com URLs (i.e. without passwords)
r2556 user, passwd = authinfo
if user and passwd:
return (user, passwd)
Vadim Gelfer
prompt user for http authentication info...
r2281
Vadim Gelfer
httprepo: fix small bug in authentication.
r2446 if not self.ui.interactive:
Vadim Gelfer
http: fix many problems with url parsing and auth. added proxy test....
r2337 raise util.Abort(_('http authorization required'))
Vadim Gelfer
prompt user for http authentication info...
r2281 self.ui.write(_("http authorization required\n"))
self.ui.status(_("realm: %s\n") % realm)
Alexis S. L. Carvalho
Allow http://user@example.com URLs (i.e. without passwords)
r2556 if user:
self.ui.status(_("user: %s\n") % user)
else:
user = self.ui.prompt(_("user:"), default=None)
if not passwd:
passwd = self.ui.getpass()
Vadim Gelfer
prompt user for http authentication info...
r2281
self.add_password(realm, authuri, user, passwd)
return (user, passwd)
Vadim Gelfer
http: fix many problems with url parsing and auth. added proxy test....
r2337 def netlocsplit(netloc):
'''split [user[:passwd]@]host[:port] into 4-tuple.'''
a = netloc.find('@')
if a == -1:
user, passwd = None, None
else:
userpass, netloc = netloc[:a], netloc[a+1:]
c = userpass.find(':')
if c == -1:
user, passwd = urllib.unquote(userpass), None
else:
user = urllib.unquote(userpass[:c])
passwd = urllib.unquote(userpass[c+1:])
c = netloc.find(':')
if c == -1:
host, port = netloc, None
else:
host, port = netloc[:c], netloc[c+1:]
return host, port, user, passwd
def netlocunsplit(host, port, user=None, passwd=None):
'''turn host, port, user, passwd into [user[:passwd]@]host[:port].'''
if port:
hostport = host + ':' + port
else:
hostport = host
if user:
if passwd:
userpass = urllib.quote(user) + ':' + urllib.quote(passwd)
else:
userpass = urllib.quote(user)
return userpass + '@' + hostport
return hostport
Vadim Gelfer
push over http: client support....
r2465 class httpconnection(keepalive.HTTPConnection):
# must be able to send big bundle as stream.
def send(self, data):
if isinstance(data, str):
keepalive.HTTPConnection.send(self, data)
else:
# if auth required, some data sent twice, so rewind here
data.seek(0)
for chunk in util.filechunkiter(data):
keepalive.HTTPConnection.send(self, chunk)
Alexis S. L. Carvalho
HTTPS: fix python2.3, persistent connections, don't explode if SSL is not available...
r2569 class basehttphandler(keepalive.HTTPHandler):
Vadim Gelfer
push over http: client support....
r2465 def http_open(self, req):
return self.do_open(httpconnection, req)
Alexis S. L. Carvalho
HTTPS: fix python2.3, persistent connections, don't explode if SSL is not available...
r2569 has_https = hasattr(urllib2, 'HTTPSHandler')
if has_https:
class httpsconnection(httplib.HTTPSConnection):
response_class = keepalive.HTTPResponse
# must be able to send big bundle as stream.
Alexis S. L. Carvalho
Fix push over https....
r2557
Alexis S. L. Carvalho
HTTPS: fix python2.3, persistent connections, don't explode if SSL is not available...
r2569 def send(self, data):
if isinstance(data, str):
httplib.HTTPSConnection.send(self, data)
else:
# if auth required, some data sent twice, so rewind here
data.seek(0)
for chunk in util.filechunkiter(data):
httplib.HTTPSConnection.send(self, chunk)
Alexis S. L. Carvalho
Fix push over https....
r2557
Alexis S. L. Carvalho
HTTPS: fix python2.3, persistent connections, don't explode if SSL is not available...
r2569 class httphandler(basehttphandler, urllib2.HTTPSHandler):
def https_open(self, req):
return self.do_open(httpsconnection, req)
else:
class httphandler(basehttphandler):
pass
Alexis S. L. Carvalho
Fix push over https....
r2557
mpm@selenic.com
Break apart hg.py...
r1089 class httprepository(remoterepository):
def __init__(self, ui, path):
Vadim Gelfer
hooks: add url to changegroup, incoming, prechangegroup, pretxnchangegroup hooks...
r2673 self.path = path
Vadim Gelfer
http: query server for capabilities
r2442 self.caps = None
Vadim Gelfer
http: fix many problems with url parsing and auth. added proxy test....
r2337 scheme, netloc, urlpath, query, frag = urlparse.urlsplit(path)
if query or frag:
raise util.Abort(_('unsupported URL component: "%s"') %
(query or frag))
if not urlpath: urlpath = '/'
host, port, user, passwd = netlocsplit(netloc)
# urllib cannot handle URLs with embedded user or passwd
Vadim Gelfer
hooks: add url to changegroup, incoming, prechangegroup, pretxnchangegroup hooks...
r2673 self._url = urlparse.urlunsplit((scheme, netlocunsplit(host, port),
urlpath, '', ''))
mpm@selenic.com
Break apart hg.py...
r1089 self.ui = ui
Vadim Gelfer
http: fix many problems with url parsing and auth. added proxy test....
r2337
proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy')
proxyauthinfo = None
Vadim Gelfer
push over http: client support....
r2465 handler = httphandler()
Vadim Gelfer
http: fix many problems with url parsing and auth. added proxy test....
r2337
if proxyurl:
# proxy can be proper url or host[:port]
if not (proxyurl.startswith('http:') or
proxyurl.startswith('https:')):
proxyurl = 'http://' + proxyurl + '/'
snpqf = urlparse.urlsplit(proxyurl)
proxyscheme, proxynetloc, proxypath, proxyquery, proxyfrag = snpqf
hpup = netlocsplit(proxynetloc)
proxyhost, proxyport, proxyuser, proxypasswd = hpup
if not proxyuser:
proxyuser = ui.config("http_proxy", "user")
proxypasswd = ui.config("http_proxy", "passwd")
mpm@selenic.com
Break apart hg.py...
r1089
Vadim Gelfer
http: fix many problems with url parsing and auth. added proxy test....
r2337 # see if we should use a proxy for this url
no_list = [ "localhost", "127.0.0.1" ]
Thomas Arendsen Hein
Make "[web] allow_push, deny_push" and "[http_proxy] no" use ui.configlist.
r2501 no_list.extend([p.lower() for
p in ui.configlist("http_proxy", "no")])
Vadim Gelfer
http: fix many problems with url parsing and auth. added proxy test....
r2337 no_list.extend([p.strip().lower() for
p in os.getenv("no_proxy", '').split(',')
if p.strip()])
# "http_proxy.always" config is for running tests on localhost
if (not ui.configbool("http_proxy", "always") and
host.lower() in no_list):
ui.debug(_('disabling proxy for %s\n') % host)
else:
proxyurl = urlparse.urlunsplit((
proxyscheme, netlocunsplit(proxyhost, proxyport,
proxyuser, proxypasswd or ''),
proxypath, proxyquery, proxyfrag))
handler = urllib2.ProxyHandler({scheme: proxyurl})
ui.debug(_('proxying through %s\n') % proxyurl)
mpm@selenic.com
Break apart hg.py...
r1089
Vadim Gelfer
http: fix many problems with url parsing and auth. added proxy test....
r2337 # urllib2 takes proxy values from the environment and those
# will take precedence if found, so drop them
mpm@selenic.com
Break apart hg.py...
r1089 for env in ["HTTP_PROXY", "http_proxy", "no_proxy"]:
try:
if os.environ.has_key(env):
del os.environ[env]
except OSError:
pass
Vadim Gelfer
http: fix many problems with url parsing and auth. added proxy test....
r2337 passmgr = passwordmgr(ui)
if user:
Alexis S. L. Carvalho
Allow http://user@example.com URLs (i.e. without passwords)
r2556 ui.debug(_('http auth: user %s, password %s\n') %
(user, passwd and '*' * len(passwd) or 'not set'))
Vadim Gelfer
http: fix many problems with url parsing and auth. added proxy test....
r2337 passmgr.add_password(None, host, user, passwd or '')
mpm@selenic.com
Break apart hg.py...
r1089
Vadim Gelfer
http: fix many problems with url parsing and auth. added proxy test....
r2337 opener = urllib2.build_opener(
handler,
urllib2.HTTPBasicAuthHandler(passmgr),
urllib2.HTTPDigestAuthHandler(passmgr))
Vadim Gelfer
prompt user for http authentication info...
r2281
Matt Mackall
Set the user agent for httprepo communication
r1359 # 1.0 here is the _protocol_ version
opener.addheaders = [('User-agent', 'mercurial/proto-1.0')]
mpm@selenic.com
Break apart hg.py...
r1089 urllib2.install_opener(opener)
Vadim Gelfer
hooks: add url to changegroup, incoming, prechangegroup, pretxnchangegroup hooks...
r2673 def url(self):
return self.path
Vadim Gelfer
http: query server for capabilities
r2442 # look up capabilities only when needed
def get_caps(self):
if self.caps is None:
try:
self.caps = self.do_read('capabilities').split()
except hg.RepoError:
self.caps = ()
Vadim Gelfer
push over http: client support....
r2465 self.ui.debug(_('capabilities: %s\n') %
(' '.join(self.caps or ['none'])))
Vadim Gelfer
http: query server for capabilities
r2442 return self.caps
capabilities = property(get_caps)
Vadim Gelfer
make push over http print good error message.
r1870 def lock(self):
raise util.Abort(_('operation not supported over http'))
mpm@selenic.com
Break apart hg.py...
r1089 def do_cmd(self, cmd, **args):
Vadim Gelfer
push over http: client support....
r2465 data = args.pop('data', None)
headers = args.pop('headers', {})
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 self.ui.debug(_("sending %s command\n") % cmd)
mpm@selenic.com
Break apart hg.py...
r1089 q = {"cmd": cmd}
q.update(args)
qs = urllib.urlencode(q)
Vadim Gelfer
hooks: add url to changegroup, incoming, prechangegroup, pretxnchangegroup hooks...
r2673 cu = "%s?%s" % (self._url, qs)
Thomas Arendsen Hein
Catch urllib's HTTPException and give a meaningful error message to the user....
r2294 try:
Vadim Gelfer
push over http: client support....
r2465 resp = urllib2.urlopen(urllib2.Request(cu, data, headers))
Vadim Gelfer
http client: better work with authorization errors, broken sockets.
r2467 except urllib2.HTTPError, inst:
if inst.code == 401:
raise util.Abort(_('authorization failed'))
raise
Thomas Arendsen Hein
Catch urllib's HTTPException and give a meaningful error message to the user....
r2294 except httplib.HTTPException, inst:
Vadim Gelfer
http: print better error if exception happens.
r2336 self.ui.debug(_('http error while sending %s command\n') % cmd)
self.ui.print_exc()
raise IOError(None, inst)
Vadim Gelfer
http client: support persistent connections....
r2435 try:
proto = resp.getheader('content-type')
except AttributeError:
proto = resp.headers['content-type']
mpm@selenic.com
Break apart hg.py...
r1089
# accept old "text/plain" and "application/hg-changegroup" for now
if not proto.startswith('application/mercurial') and \
not proto.startswith('text/plain') and \
not proto.startswith('application/hg-changegroup'):
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 raise hg.RepoError(_("'%s' does not appear to be an hg repository") %
Vadim Gelfer
hooks: add url to changegroup, incoming, prechangegroup, pretxnchangegroup hooks...
r2673 self._url)
mpm@selenic.com
Break apart hg.py...
r1089
if proto.startswith('application/mercurial'):
version = proto[22:]
if float(version) > 0.1:
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 raise hg.RepoError(_("'%s' uses newer protocol %s") %
Vadim Gelfer
hooks: add url to changegroup, incoming, prechangegroup, pretxnchangegroup hooks...
r2673 (self._url, version))
mpm@selenic.com
Break apart hg.py...
r1089
return resp
Vadim Gelfer
http client: support persistent connections....
r2435 def do_read(self, cmd, **args):
fp = self.do_cmd(cmd, **args)
try:
return fp.read()
finally:
# if using keepalive, allow connection to be reused
fp.close()
mpm@selenic.com
Break apart hg.py...
r1089 def heads(self):
Vadim Gelfer
http client: support persistent connections....
r2435 d = self.do_read("heads")
mpm@selenic.com
Break apart hg.py...
r1089 try:
return map(bin, d[:-1].split(" "))
except:
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 self.ui.warn(_("unexpected response:\n") + d[:400] + "\n...\n")
mpm@selenic.com
Break apart hg.py...
r1089 raise
def branches(self, nodes):
n = " ".join(map(hex, nodes))
Vadim Gelfer
http client: support persistent connections....
r2435 d = self.do_read("branches", nodes=n)
mpm@selenic.com
Break apart hg.py...
r1089 try:
br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
return br
except:
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 self.ui.warn(_("unexpected response:\n") + d[:400] + "\n...\n")
mpm@selenic.com
Break apart hg.py...
r1089 raise
def between(self, pairs):
n = "\n".join(["-".join(map(hex, p)) for p in pairs])
Vadim Gelfer
http client: support persistent connections....
r2435 d = self.do_read("between", pairs=n)
mpm@selenic.com
Break apart hg.py...
r1089 try:
p = [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ]
return p
except:
Benoit Boissinot
i18n part2: use '_' for all strings who are part of the user interface
r1402 self.ui.warn(_("unexpected response:\n") + d[:400] + "\n...\n")
mpm@selenic.com
Break apart hg.py...
r1089 raise
Vadim Gelfer
add preoutgoing and outgoing hooks....
r1736 def changegroup(self, nodes, kind):
mpm@selenic.com
Break apart hg.py...
r1089 n = " ".join(map(hex, nodes))
f = self.do_cmd("changegroup", roots=n)
bytes = 0
Eric Hopper
Fix same performance bug as c3654cfaa77 but for httprepo.py instead.
r1376 def zgenerator(f):
zd = zlib.decompressobj()
Thomas Arendsen Hein
Catch HTTPException when reading from remote http repository....
r2015 try:
for chnk in f:
yield zd.decompress(chnk)
except httplib.HTTPException, inst:
raise IOError(None, _('connection ended unexpectedly'))
Eric Hopper
Fix same performance bug as c3654cfaa77 but for httprepo.py instead.
r1376 yield zd.flush()
mpm@selenic.com
Break apart hg.py...
r1089
Eric Hopper
Fix same performance bug as c3654cfaa77 but for httprepo.py instead.
r1376 return util.chunkbuffer(zgenerator(util.filechunkiter(f)))
mpm@selenic.com
Break apart hg.py...
r1089
Vadim Gelfer
extend network protocol to stop clients from locking servers...
r2439 def unbundle(self, cg, heads, source):
Vadim Gelfer
push over http: client support....
r2465 # have to stream bundle to a temp file because we do not have
# http 1.1 chunked transfer.
fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
fp = os.fdopen(fd, 'wb+')
try:
for chunk in util.filechunkiter(cg):
fp.write(chunk)
length = fp.tell()
try:
Vadim Gelfer
http client: better work with authorization errors, broken sockets.
r2467 rfp = self.do_cmd(
'unbundle', data=fp,
headers={'content-length': length,
'content-type': 'application/octet-stream'},
heads=' '.join(map(hex, heads)))
try:
ret = int(rfp.readline())
self.ui.write(rfp.read())
return ret
finally:
rfp.close()
except socket.error, err:
if err[0] in (errno.ECONNRESET, errno.EPIPE):
raise util.Abort(_('push failed: %s'), err[1])
raise util.Abort(err[1])
Vadim Gelfer
push over http: client support....
r2465 finally:
fp.close()
os.unlink(tempname)
Vadim Gelfer
extend network protocol to stop clients from locking servers...
r2439
Vadim Gelfer
add support for streaming clone....
r2612 def stream_out(self):
return self.do_cmd('stream_out')
mpm@selenic.com
Break apart hg.py...
r1089 class httpsrepository(httprepository):
Alexis S. L. Carvalho
HTTPS: fix python2.3, persistent connections, don't explode if SSL is not available...
r2569 def __init__(self, ui, path):
if not has_https:
raise util.Abort(_('Python support for SSL and HTTPS '
'is not installed'))
httprepository.__init__(self, ui, path)
Vadim Gelfer
clean up hg.py: move repo constructor code into each repo module
r2740
def instance(ui, path, create):
if create:
raise util.Abort(_('cannot create new http repository'))
if path.startswith('hg:'):
ui.warn(_("hg:// syntax is deprecated, please use http:// instead\n"))
path = 'http:' + path[3:]
if path.startswith('https:'):
return httpsrepository(ui, path)
return httprepository(ui, path)