mercurial/httprepo.py
changeset 11587 a036f6bd1da3
parent 11567 34cc8b84407f
child 11588 8a1f625e971d
equal deleted inserted replaced
11586:ddaaaa23bb8f 11587:a036f6bd1da3
     6 # This software may be used and distributed according to the terms of the
     6 # This software may be used and distributed according to the terms of the
     7 # GNU General Public License version 2 or any later version.
     7 # GNU General Public License version 2 or any later version.
     8 
     8 
     9 from node import bin, hex, nullid
     9 from node import bin, hex, nullid
    10 from i18n import _
    10 from i18n import _
    11 import repo, changegroup, statichttprepo, error, url, util, pushkey
    11 import repo, changegroup, statichttprepo, error, url, util, wireproto
    12 import os, urllib, urllib2, urlparse, zlib, httplib
    12 import os, urllib, urllib2, urlparse, zlib, httplib
    13 import errno, socket
    13 import errno, socket
    14 import encoding
    14 import encoding
    15 
    15 
    16 def zgenerator(f):
    16 def zgenerator(f):
    20             yield zd.decompress(chunk)
    20             yield zd.decompress(chunk)
    21     except httplib.HTTPException:
    21     except httplib.HTTPException:
    22         raise IOError(None, _('connection ended unexpectedly'))
    22         raise IOError(None, _('connection ended unexpectedly'))
    23     yield zd.flush()
    23     yield zd.flush()
    24 
    24 
    25 class httprepository(repo.repository):
    25 class httprepository(wireproto.wirerepository):
    26     def __init__(self, ui, path):
    26     def __init__(self, ui, path):
    27         self.path = path
    27         self.path = path
    28         self.caps = None
    28         self.caps = None
    29         self.handler = None
    29         self.handler = None
    30         scheme, netloc, urlpath, query, frag = urlparse.urlsplit(path)
    30         scheme, netloc, urlpath, query, frag = urlparse.urlsplit(path)
   136             return fp.read()
   136             return fp.read()
   137         finally:
   137         finally:
   138             # if using keepalive, allow connection to be reused
   138             # if using keepalive, allow connection to be reused
   139             fp.close()
   139             fp.close()
   140 
   140 
   141     def lookup(self, key):
   141     def _call(self, cmd, **args):
   142         self.requirecap('lookup', _('look up remote revision'))
   142         return self.do_read(cmd, **args)
   143         d = self.do_cmd("lookup", key = key).read()
   143 
   144         success, data = d[:-1].split(' ', 1)
   144     def _abort(self, exception):
   145         if int(success):
   145         raise exception
   146             return bin(data)
       
   147         raise error.RepoError(data)
       
   148 
       
   149     def heads(self):
       
   150         d = self.do_read("heads")
       
   151         try:
       
   152             return map(bin, d[:-1].split(" "))
       
   153         except:
       
   154             raise error.ResponseError(_("unexpected response:"), d)
       
   155 
       
   156     def branchmap(self):
       
   157         d = self.do_read("branchmap")
       
   158         try:
       
   159             branchmap = {}
       
   160             for branchpart in d.splitlines():
       
   161                 branchheads = branchpart.split(' ')
       
   162                 branchname = urllib.unquote(branchheads[0])
       
   163                 # Earlier servers (1.3.x) send branch names in (their) local
       
   164                 # charset. The best we can do is assume it's identical to our
       
   165                 # own local charset, in case it's not utf-8.
       
   166                 try:
       
   167                     branchname.decode('utf-8')
       
   168                 except UnicodeDecodeError:
       
   169                     branchname = encoding.fromlocal(branchname)
       
   170                 branchheads = [bin(x) for x in branchheads[1:]]
       
   171                 branchmap[branchname] = branchheads
       
   172             return branchmap
       
   173         except:
       
   174             raise error.ResponseError(_("unexpected response:"), d)
       
   175 
       
   176     def branches(self, nodes):
       
   177         n = " ".join(map(hex, nodes))
       
   178         d = self.do_read("branches", nodes=n)
       
   179         try:
       
   180             br = [tuple(map(bin, b.split(" "))) for b in d.splitlines()]
       
   181             return br
       
   182         except:
       
   183             raise error.ResponseError(_("unexpected response:"), d)
       
   184 
       
   185     def between(self, pairs):
       
   186         batch = 8 # avoid giant requests
       
   187         r = []
       
   188         for i in xrange(0, len(pairs), batch):
       
   189             n = " ".join(["-".join(map(hex, p)) for p in pairs[i:i + batch]])
       
   190             d = self.do_read("between", pairs=n)
       
   191             try:
       
   192                 r += [l and map(bin, l.split(" ")) or []
       
   193                       for l in d.splitlines()]
       
   194             except:
       
   195                 raise error.ResponseError(_("unexpected response:"), d)
       
   196         return r
       
   197 
   146 
   198     def changegroup(self, nodes, kind):
   147     def changegroup(self, nodes, kind):
   199         n = " ".join(map(hex, nodes))
   148         n = " ".join(map(hex, nodes))
   200         f = self.do_cmd("changegroup", roots=n)
   149         f = self.do_cmd("changegroup", roots=n)
   201         return util.chunkbuffer(zgenerator(f))
   150         return util.chunkbuffer(zgenerator(f))
   257             os.unlink(tempname)
   206             os.unlink(tempname)
   258 
   207 
   259     def stream_out(self):
   208     def stream_out(self):
   260         return self.do_cmd('stream_out')
   209         return self.do_cmd('stream_out')
   261 
   210 
   262     def pushkey(self, namespace, key, old, new):
       
   263         if not self.capable('pushkey'):
       
   264             return False
       
   265         d = self.do_cmd("pushkey", data="", # force a POST
       
   266                         namespace=namespace, key=key, old=old, new=new).read()
       
   267         code, output = d.split('\n', 1)
       
   268         try:
       
   269             ret = bool(int(code))
       
   270         except ValueError, err:
       
   271             raise error.ResponseError(
       
   272                 _('push failed (unexpected response):'), d)
       
   273         for l in output.splitlines(True):
       
   274             self.ui.status(_('remote: '), l)
       
   275         return ret
       
   276 
       
   277     def listkeys(self, namespace):
       
   278         if not self.capable('pushkey'):
       
   279             return {}
       
   280         d = self.do_cmd("listkeys", namespace=namespace).read()
       
   281         r = {}
       
   282         for l in d.splitlines():
       
   283             k, v = l.split('\t')
       
   284             r[k.decode('string-escape')] = v.decode('string-escape')
       
   285         return r
       
   286 
       
   287 class httpsrepository(httprepository):
   211 class httpsrepository(httprepository):
   288     def __init__(self, ui, path):
   212     def __init__(self, ui, path):
   289         if not url.has_https:
   213         if not url.has_https:
   290             raise util.Abort(_('Python support for SSL and HTTPS '
   214             raise util.Abort(_('Python support for SSL and HTTPS '
   291                                'is not installed'))
   215                                'is not installed'))