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) |
|