mercurial/hgweb/protocol.py
changeset 11593 d054cc5c7737
parent 11585 5d907fbb9703
child 11594 67863f9d805f
equal deleted inserted replaced
11592:26e0782b8380 11593:d054cc5c7737
    30     if changegroupmod.bundlepriority:
    30     if changegroupmod.bundlepriority:
    31         caps.append('unbundle=%s' % ','.join(changegroupmod.bundlepriority))
    31         caps.append('unbundle=%s' % ','.join(changegroupmod.bundlepriority))
    32     rsp = ' '.join(caps)
    32     rsp = ' '.join(caps)
    33     req.respond(HTTP_OK, HGTYPE, length=len(rsp))
    33     req.respond(HTTP_OK, HGTYPE, length=len(rsp))
    34     yield rsp
    34     yield rsp
    35 
       
    36 def unbundle(repo, req):
       
    37 
       
    38     proto = req.env.get('wsgi.url_scheme') or 'http'
       
    39     their_heads = req.form['heads'][0].split(' ')
       
    40 
       
    41     def check_heads():
       
    42         heads = map(hex, repo.heads())
       
    43         return their_heads == [hex('force')] or their_heads == heads
       
    44 
       
    45     # fail early if possible
       
    46     if not check_heads():
       
    47         req.drain()
       
    48         raise ErrorResponse(HTTP_OK, 'unsynced changes')
       
    49 
       
    50     # do not lock repo until all changegroup data is
       
    51     # streamed. save to temporary file.
       
    52 
       
    53     fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
       
    54     fp = os.fdopen(fd, 'wb+')
       
    55     try:
       
    56         length = int(req.env['CONTENT_LENGTH'])
       
    57         for s in util.filechunkiter(req, limit=length):
       
    58             fp.write(s)
       
    59 
       
    60         try:
       
    61             lock = repo.lock()
       
    62             try:
       
    63                 if not check_heads():
       
    64                     raise ErrorResponse(HTTP_OK, 'unsynced changes')
       
    65 
       
    66                 fp.seek(0)
       
    67                 header = fp.read(6)
       
    68                 if header.startswith('HG') and not header.startswith('HG10'):
       
    69                     raise ValueError('unknown bundle version')
       
    70                 elif header not in changegroupmod.bundletypes:
       
    71                     raise ValueError('unknown bundle compression type')
       
    72                 gen = changegroupmod.unbundle(header, fp)
       
    73 
       
    74                 # send addchangegroup output to client
       
    75 
       
    76                 oldio = sys.stdout, sys.stderr
       
    77                 sys.stderr = sys.stdout = cStringIO.StringIO()
       
    78 
       
    79                 try:
       
    80                     url = 'remote:%s:%s:%s' % (
       
    81                           proto,
       
    82                           urllib.quote(req.env.get('REMOTE_HOST', '')),
       
    83                           urllib.quote(req.env.get('REMOTE_USER', '')))
       
    84                     try:
       
    85                         ret = repo.addchangegroup(gen, 'serve', url, lock=lock)
       
    86                     except util.Abort, inst:
       
    87                         sys.stdout.write("abort: %s\n" % inst)
       
    88                         ret = 0
       
    89                 finally:
       
    90                     val = sys.stdout.getvalue()
       
    91                     sys.stdout, sys.stderr = oldio
       
    92                 req.respond(HTTP_OK, HGTYPE)
       
    93                 return '%d\n%s' % (ret, val),
       
    94             finally:
       
    95                 lock.release()
       
    96         except ValueError, inst:
       
    97             raise ErrorResponse(HTTP_OK, inst)
       
    98         except (OSError, IOError), inst:
       
    99             error = getattr(inst, 'strerror', 'Unknown error')
       
   100             if not isinstance(error, str):
       
   101                 error = 'Error: %s' % str(error)
       
   102             if inst.errno == errno.ENOENT:
       
   103                 code = HTTP_NOT_FOUND
       
   104             else:
       
   105                 code = HTTP_SERVER_ERROR
       
   106             filename = getattr(inst, 'filename', '')
       
   107             # Don't send our filesystem layout to the client
       
   108             if filename and filename.startswith(repo.root):
       
   109                 filename = filename[len(repo.root)+1:]
       
   110                 text = '%s: %s' % (error, filename)
       
   111             else:
       
   112                 text = error.replace(repo.root + os.path.sep, '')
       
   113             raise ErrorResponse(code, text)
       
   114     finally:
       
   115         fp.close()
       
   116         os.unlink(tempname)