comparison mercurial/hgweb/protocol.py @ 11593:d054cc5c7737

protocol: unify unbundle on the server side
author Matt Mackall <mpm@selenic.com>
date Thu, 15 Jul 2010 11:24:42 -0500
parents 5d907fbb9703
children 67863f9d805f
comparison
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)