Mercurial > public > mercurial-scm > hg
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) |