summaryrefslogtreecommitdiff
path: root/sys/lib/python/mercurial/httprepo.py
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@localhost>2011-05-03 11:25:13 +0000
committercinap_lenrek <cinap_lenrek@localhost>2011-05-03 11:25:13 +0000
commit458120dd40db6b4df55a4e96b650e16798ef06a0 (patch)
tree8f82685be24fef97e715c6f5ca4c68d34d5074ee /sys/lib/python/mercurial/httprepo.py
parent3a742c699f6806c1145aea5149bf15de15a0afd7 (diff)
add hg and python
Diffstat (limited to 'sys/lib/python/mercurial/httprepo.py')
-rw-r--r--sys/lib/python/mercurial/httprepo.py258
1 files changed, 258 insertions, 0 deletions
diff --git a/sys/lib/python/mercurial/httprepo.py b/sys/lib/python/mercurial/httprepo.py
new file mode 100644
index 000000000..a766bf07a
--- /dev/null
+++ b/sys/lib/python/mercurial/httprepo.py
@@ -0,0 +1,258 @@
+# httprepo.py - HTTP repository proxy classes for mercurial
+#
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
+# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2, incorporated herein by reference.
+
+from node import bin, hex, nullid
+from i18n import _
+import repo, changegroup, statichttprepo, error, url, util
+import os, urllib, urllib2, urlparse, zlib, httplib
+import errno, socket
+
+def zgenerator(f):
+ zd = zlib.decompressobj()
+ try:
+ for chunk in util.filechunkiter(f):
+ yield zd.decompress(chunk)
+ except httplib.HTTPException:
+ raise IOError(None, _('connection ended unexpectedly'))
+ yield zd.flush()
+
+class httprepository(repo.repository):
+ def __init__(self, ui, path):
+ self.path = path
+ self.caps = None
+ self.handler = None
+ scheme, netloc, urlpath, query, frag = urlparse.urlsplit(path)
+ if query or frag:
+ raise util.Abort(_('unsupported URL component: "%s"') %
+ (query or frag))
+
+ # urllib cannot handle URLs with embedded user or passwd
+ self._url, authinfo = url.getauthinfo(path)
+
+ self.ui = ui
+ self.ui.debug(_('using %s\n') % self._url)
+
+ self.urlopener = url.opener(ui, authinfo)
+
+ def __del__(self):
+ for h in self.urlopener.handlers:
+ h.close()
+ if hasattr(h, "close_all"):
+ h.close_all()
+
+ def url(self):
+ return self.path
+
+ # look up capabilities only when needed
+
+ def get_caps(self):
+ if self.caps is None:
+ try:
+ self.caps = set(self.do_read('capabilities').split())
+ except error.RepoError:
+ self.caps = set()
+ self.ui.debug(_('capabilities: %s\n') %
+ (' '.join(self.caps or ['none'])))
+ return self.caps
+
+ capabilities = property(get_caps)
+
+ def lock(self):
+ raise util.Abort(_('operation not supported over http'))
+
+ def do_cmd(self, cmd, **args):
+ data = args.pop('data', None)
+ headers = args.pop('headers', {})
+ self.ui.debug(_("sending %s command\n") % cmd)
+ q = {"cmd": cmd}
+ q.update(args)
+ qs = '?%s' % urllib.urlencode(q)
+ cu = "%s%s" % (self._url, qs)
+ try:
+ if data:
+ self.ui.debug(_("sending %s bytes\n") % len(data))
+ resp = self.urlopener.open(urllib2.Request(cu, data, headers))
+ except urllib2.HTTPError, inst:
+ if inst.code == 401:
+ raise util.Abort(_('authorization failed'))
+ raise
+ except httplib.HTTPException, inst:
+ self.ui.debug(_('http error while sending %s command\n') % cmd)
+ self.ui.traceback()
+ raise IOError(None, inst)
+ except IndexError:
+ # this only happens with Python 2.3, later versions raise URLError
+ raise util.Abort(_('http error, possibly caused by proxy setting'))
+ # record the url we got redirected to
+ resp_url = resp.geturl()
+ if resp_url.endswith(qs):
+ resp_url = resp_url[:-len(qs)]
+ if self._url != resp_url:
+ self.ui.status(_('real URL is %s\n') % resp_url)
+ self._url = resp_url
+ try:
+ proto = resp.getheader('content-type')
+ except AttributeError:
+ proto = resp.headers['content-type']
+
+ safeurl = url.hidepassword(self._url)
+ # accept old "text/plain" and "application/hg-changegroup" for now
+ if not (proto.startswith('application/mercurial-') or
+ proto.startswith('text/plain') or
+ proto.startswith('application/hg-changegroup')):
+ self.ui.debug(_("requested URL: '%s'\n") % url.hidepassword(cu))
+ raise error.RepoError(_("'%s' does not appear to be an hg repository")
+ % safeurl)
+
+ if proto.startswith('application/mercurial-'):
+ try:
+ version = proto.split('-', 1)[1]
+ version_info = tuple([int(n) for n in version.split('.')])
+ except ValueError:
+ raise error.RepoError(_("'%s' sent a broken Content-Type "
+ "header (%s)") % (safeurl, proto))
+ if version_info > (0, 1):
+ raise error.RepoError(_("'%s' uses newer protocol %s") %
+ (safeurl, version))
+
+ return resp
+
+ 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()
+
+ def lookup(self, key):
+ self.requirecap('lookup', _('look up remote revision'))
+ d = self.do_cmd("lookup", key = key).read()
+ success, data = d[:-1].split(' ', 1)
+ if int(success):
+ return bin(data)
+ raise error.RepoError(data)
+
+ def heads(self):
+ d = self.do_read("heads")
+ try:
+ return map(bin, d[:-1].split(" "))
+ except:
+ raise error.ResponseError(_("unexpected response:"), d)
+
+ def branchmap(self):
+ d = self.do_read("branchmap")
+ try:
+ branchmap = {}
+ for branchpart in d.splitlines():
+ branchheads = branchpart.split(' ')
+ branchname = urllib.unquote(branchheads[0])
+ branchheads = [bin(x) for x in branchheads[1:]]
+ branchmap[branchname] = branchheads
+ return branchmap
+ except:
+ raise error.ResponseError(_("unexpected response:"), d)
+
+ def branches(self, nodes):
+ n = " ".join(map(hex, nodes))
+ d = self.do_read("branches", nodes=n)
+ try:
+ br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
+ return br
+ except:
+ raise error.ResponseError(_("unexpected response:"), d)
+
+ def between(self, pairs):
+ batch = 8 # avoid giant requests
+ r = []
+ for i in xrange(0, len(pairs), batch):
+ n = " ".join(["-".join(map(hex, p)) for p in pairs[i:i + batch]])
+ d = self.do_read("between", pairs=n)
+ try:
+ r += [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ]
+ except:
+ raise error.ResponseError(_("unexpected response:"), d)
+ return r
+
+ def changegroup(self, nodes, kind):
+ n = " ".join(map(hex, nodes))
+ f = self.do_cmd("changegroup", roots=n)
+ return util.chunkbuffer(zgenerator(f))
+
+ def changegroupsubset(self, bases, heads, source):
+ self.requirecap('changegroupsubset', _('look up remote changes'))
+ baselst = " ".join([hex(n) for n in bases])
+ headlst = " ".join([hex(n) for n in heads])
+ f = self.do_cmd("changegroupsubset", bases=baselst, heads=headlst)
+ return util.chunkbuffer(zgenerator(f))
+
+ def unbundle(self, cg, heads, source):
+ # have to stream bundle to a temp file because we do not have
+ # http 1.1 chunked transfer.
+
+ type = ""
+ types = self.capable('unbundle')
+ # servers older than d1b16a746db6 will send 'unbundle' as a
+ # boolean capability
+ try:
+ types = types.split(',')
+ except AttributeError:
+ types = [""]
+ if types:
+ for x in types:
+ if x in changegroup.bundletypes:
+ type = x
+ break
+
+ tempname = changegroup.writebundle(cg, None, type)
+ fp = url.httpsendfile(tempname, "rb")
+ try:
+ try:
+ resp = self.do_read(
+ 'unbundle', data=fp,
+ headers={'Content-Type': 'application/octet-stream'},
+ heads=' '.join(map(hex, heads)))
+ resp_code, output = resp.split('\n', 1)
+ try:
+ ret = int(resp_code)
+ except ValueError, err:
+ raise error.ResponseError(
+ _('push failed (unexpected response):'), resp)
+ self.ui.write(output)
+ return ret
+ 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])
+ finally:
+ fp.close()
+ os.unlink(tempname)
+
+ def stream_out(self):
+ return self.do_cmd('stream_out')
+
+class httpsrepository(httprepository):
+ def __init__(self, ui, path):
+ if not url.has_https:
+ raise util.Abort(_('Python support for SSL and HTTPS '
+ 'is not installed'))
+ httprepository.__init__(self, ui, path)
+
+def instance(ui, path, create):
+ if create:
+ raise util.Abort(_('cannot create new http repository'))
+ try:
+ if path.startswith('https:'):
+ inst = httpsrepository(ui, path)
+ else:
+ inst = httprepository(ui, path)
+ inst.between([(nullid, nullid)])
+ return inst
+ except error.RepoError:
+ ui.note('(falling back to static-http)\n')
+ return statichttprepo.instance(ui, "static-" + path, create)