##// END OF EJS Templates
hgweb: use a single-element tuple to return from protocol.unbundle()...
Dirkjan Ochtman -
r6788:88a1bcc5 default
parent child Browse files
Show More
@@ -1,198 +1,196
1 #
1 #
2 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
2 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 import cStringIO, zlib, tempfile, errno, os, sys
8 import cStringIO, zlib, tempfile, errno, os, sys
9 from mercurial import util, streamclone
9 from mercurial import util, streamclone
10 from mercurial.node import bin, hex
10 from mercurial.node import bin, hex
11 from mercurial import changegroup as changegroupmod
11 from mercurial import changegroup as changegroupmod
12 from common import HTTP_OK, HTTP_NOT_FOUND, HTTP_SERVER_ERROR
12 from common import HTTP_OK, HTTP_NOT_FOUND, HTTP_SERVER_ERROR
13
13
14 # __all__ is populated with the allowed commands. Be sure to add to it if
14 # __all__ is populated with the allowed commands. Be sure to add to it if
15 # you're adding a new command, or the new command won't work.
15 # you're adding a new command, or the new command won't work.
16
16
17 __all__ = [
17 __all__ = [
18 'lookup', 'heads', 'branches', 'between', 'changegroup',
18 'lookup', 'heads', 'branches', 'between', 'changegroup',
19 'changegroupsubset', 'capabilities', 'unbundle', 'stream_out',
19 'changegroupsubset', 'capabilities', 'unbundle', 'stream_out',
20 ]
20 ]
21
21
22 HGTYPE = 'application/mercurial-0.1'
22 HGTYPE = 'application/mercurial-0.1'
23
23
24 def lookup(repo, req):
24 def lookup(repo, req):
25 try:
25 try:
26 r = hex(repo.lookup(req.form['key'][0]))
26 r = hex(repo.lookup(req.form['key'][0]))
27 success = 1
27 success = 1
28 except Exception,inst:
28 except Exception,inst:
29 r = str(inst)
29 r = str(inst)
30 success = 0
30 success = 0
31 resp = "%s %s\n" % (success, r)
31 resp = "%s %s\n" % (success, r)
32 req.respond(HTTP_OK, HGTYPE, length=len(resp))
32 req.respond(HTTP_OK, HGTYPE, length=len(resp))
33 yield resp
33 yield resp
34
34
35 def heads(repo, req):
35 def heads(repo, req):
36 resp = " ".join(map(hex, repo.heads())) + "\n"
36 resp = " ".join(map(hex, repo.heads())) + "\n"
37 req.respond(HTTP_OK, HGTYPE, length=len(resp))
37 req.respond(HTTP_OK, HGTYPE, length=len(resp))
38 yield resp
38 yield resp
39
39
40 def branches(repo, req):
40 def branches(repo, req):
41 nodes = []
41 nodes = []
42 if 'nodes' in req.form:
42 if 'nodes' in req.form:
43 nodes = map(bin, req.form['nodes'][0].split(" "))
43 nodes = map(bin, req.form['nodes'][0].split(" "))
44 resp = cStringIO.StringIO()
44 resp = cStringIO.StringIO()
45 for b in repo.branches(nodes):
45 for b in repo.branches(nodes):
46 resp.write(" ".join(map(hex, b)) + "\n")
46 resp.write(" ".join(map(hex, b)) + "\n")
47 resp = resp.getvalue()
47 resp = resp.getvalue()
48 req.respond(HTTP_OK, HGTYPE, length=len(resp))
48 req.respond(HTTP_OK, HGTYPE, length=len(resp))
49 yield resp
49 yield resp
50
50
51 def between(repo, req):
51 def between(repo, req):
52 if 'pairs' in req.form:
52 if 'pairs' in req.form:
53 pairs = [map(bin, p.split("-"))
53 pairs = [map(bin, p.split("-"))
54 for p in req.form['pairs'][0].split(" ")]
54 for p in req.form['pairs'][0].split(" ")]
55 resp = cStringIO.StringIO()
55 resp = cStringIO.StringIO()
56 for b in repo.between(pairs):
56 for b in repo.between(pairs):
57 resp.write(" ".join(map(hex, b)) + "\n")
57 resp.write(" ".join(map(hex, b)) + "\n")
58 resp = resp.getvalue()
58 resp = resp.getvalue()
59 req.respond(HTTP_OK, HGTYPE, length=len(resp))
59 req.respond(HTTP_OK, HGTYPE, length=len(resp))
60 yield resp
60 yield resp
61
61
62 def changegroup(repo, req):
62 def changegroup(repo, req):
63 req.respond(HTTP_OK, HGTYPE)
63 req.respond(HTTP_OK, HGTYPE)
64 nodes = []
64 nodes = []
65
65
66 if 'roots' in req.form:
66 if 'roots' in req.form:
67 nodes = map(bin, req.form['roots'][0].split(" "))
67 nodes = map(bin, req.form['roots'][0].split(" "))
68
68
69 z = zlib.compressobj()
69 z = zlib.compressobj()
70 f = repo.changegroup(nodes, 'serve')
70 f = repo.changegroup(nodes, 'serve')
71 while 1:
71 while 1:
72 chunk = f.read(4096)
72 chunk = f.read(4096)
73 if not chunk:
73 if not chunk:
74 break
74 break
75 yield z.compress(chunk)
75 yield z.compress(chunk)
76
76
77 yield z.flush()
77 yield z.flush()
78
78
79 def changegroupsubset(repo, req):
79 def changegroupsubset(repo, req):
80 req.respond(HTTP_OK, HGTYPE)
80 req.respond(HTTP_OK, HGTYPE)
81 bases = []
81 bases = []
82 heads = []
82 heads = []
83
83
84 if 'bases' in req.form:
84 if 'bases' in req.form:
85 bases = [bin(x) for x in req.form['bases'][0].split(' ')]
85 bases = [bin(x) for x in req.form['bases'][0].split(' ')]
86 if 'heads' in req.form:
86 if 'heads' in req.form:
87 heads = [bin(x) for x in req.form['heads'][0].split(' ')]
87 heads = [bin(x) for x in req.form['heads'][0].split(' ')]
88
88
89 z = zlib.compressobj()
89 z = zlib.compressobj()
90 f = repo.changegroupsubset(bases, heads, 'serve')
90 f = repo.changegroupsubset(bases, heads, 'serve')
91 while 1:
91 while 1:
92 chunk = f.read(4096)
92 chunk = f.read(4096)
93 if not chunk:
93 if not chunk:
94 break
94 break
95 yield z.compress(chunk)
95 yield z.compress(chunk)
96
96
97 yield z.flush()
97 yield z.flush()
98
98
99 def capabilities(repo, req):
99 def capabilities(repo, req):
100 caps = ['lookup', 'changegroupsubset']
100 caps = ['lookup', 'changegroupsubset']
101 if repo.ui.configbool('server', 'uncompressed', untrusted=True):
101 if repo.ui.configbool('server', 'uncompressed', untrusted=True):
102 caps.append('stream=%d' % repo.changelog.version)
102 caps.append('stream=%d' % repo.changelog.version)
103 if changegroupmod.bundlepriority:
103 if changegroupmod.bundlepriority:
104 caps.append('unbundle=%s' % ','.join(changegroupmod.bundlepriority))
104 caps.append('unbundle=%s' % ','.join(changegroupmod.bundlepriority))
105 rsp = ' '.join(caps)
105 rsp = ' '.join(caps)
106 req.respond(HTTP_OK, HGTYPE, length=len(rsp))
106 req.respond(HTTP_OK, HGTYPE, length=len(rsp))
107 yield rsp
107 yield rsp
108
108
109 def unbundle(repo, req):
109 def unbundle(repo, req):
110
110
111 errorfmt = '0\n%s\n'
111 errorfmt = '0\n%s\n'
112 proto = req.env.get('wsgi.url_scheme') or 'http'
112 proto = req.env.get('wsgi.url_scheme') or 'http'
113 their_heads = req.form['heads'][0].split(' ')
113 their_heads = req.form['heads'][0].split(' ')
114
114
115 def check_heads():
115 def check_heads():
116 heads = map(hex, repo.heads())
116 heads = map(hex, repo.heads())
117 return their_heads == [hex('force')] or their_heads == heads
117 return their_heads == [hex('force')] or their_heads == heads
118
118
119 # fail early if possible
119 # fail early if possible
120 if not check_heads():
120 if not check_heads():
121 length = int(req.env.get('CONTENT_LENGTH', 0))
121 length = int(req.env.get('CONTENT_LENGTH', 0))
122 for s in util.filechunkiter(req, limit=length):
122 for s in util.filechunkiter(req, limit=length):
123 # drain incoming bundle, else client will not see
123 # drain incoming bundle, else client will not see
124 # response when run outside cgi script
124 # response when run outside cgi script
125 pass
125 pass
126 req.respond(HTTP_OK, HGTYPE)
126 req.respond(HTTP_OK, HGTYPE)
127 yield errorfmt % 'unsynced changes'
127 return errorfmt % 'unsynced changes',
128 return
129
128
130 req.respond(HTTP_OK, HGTYPE)
129 req.respond(HTTP_OK, HGTYPE)
131
130
132 # do not lock repo until all changegroup data is
131 # do not lock repo until all changegroup data is
133 # streamed. save to temporary file.
132 # streamed. save to temporary file.
134
133
135 fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
134 fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
136 fp = os.fdopen(fd, 'wb+')
135 fp = os.fdopen(fd, 'wb+')
137 try:
136 try:
138 length = int(req.env['CONTENT_LENGTH'])
137 length = int(req.env['CONTENT_LENGTH'])
139 for s in util.filechunkiter(req, limit=length):
138 for s in util.filechunkiter(req, limit=length):
140 fp.write(s)
139 fp.write(s)
141
140
142 try:
141 try:
143 lock = repo.lock()
142 lock = repo.lock()
144 try:
143 try:
145 if not check_heads():
144 if not check_heads():
146 yield errorfmt % 'unsynced changes'
145 return errorfmt % 'unsynced changes',
147 return
148
146
149 fp.seek(0)
147 fp.seek(0)
150 header = fp.read(6)
148 header = fp.read(6)
151 if header.startswith('HG') and not header.startswith('HG10'):
149 if header.startswith('HG') and not header.startswith('HG10'):
152 raise ValueError('unknown bundle version')
150 raise ValueError('unknown bundle version')
153 elif header not in changegroupmod.bundletypes:
151 elif header not in changegroupmod.bundletypes:
154 raise ValueError('unknown bundle compression type')
152 raise ValueError('unknown bundle compression type')
155 gen = changegroupmod.unbundle(header, fp)
153 gen = changegroupmod.unbundle(header, fp)
156
154
157 # send addchangegroup output to client
155 # send addchangegroup output to client
158
156
159 oldio = sys.stdout, sys.stderr
157 oldio = sys.stdout, sys.stderr
160 sys.stderr = sys.stdout = cStringIO.StringIO()
158 sys.stderr = sys.stdout = cStringIO.StringIO()
161
159
162 try:
160 try:
163 url = 'remote:%s:%s' % (proto,
161 url = 'remote:%s:%s' % (proto,
164 req.env.get('REMOTE_HOST', ''))
162 req.env.get('REMOTE_HOST', ''))
165 try:
163 try:
166 ret = repo.addchangegroup(gen, 'serve', url)
164 ret = repo.addchangegroup(gen, 'serve', url)
167 except util.Abort, inst:
165 except util.Abort, inst:
168 sys.stdout.write("abort: %s\n" % inst)
166 sys.stdout.write("abort: %s\n" % inst)
169 ret = 0
167 ret = 0
170 finally:
168 finally:
171 val = sys.stdout.getvalue()
169 val = sys.stdout.getvalue()
172 sys.stdout, sys.stderr = oldio
170 sys.stdout, sys.stderr = oldio
173 yield '%d\n%s' % (ret, val)
171 return '%d\n%s' % (ret, val),
174 finally:
172 finally:
175 del lock
173 del lock
176 except ValueError, inst:
174 except ValueError, inst:
177 yield errorfmt % inst
175 return errorfmt % inst,
178 except (OSError, IOError), inst:
176 except (OSError, IOError), inst:
179 filename = getattr(inst, 'filename', '')
177 filename = getattr(inst, 'filename', '')
180 # Don't send our filesystem layout to the client
178 # Don't send our filesystem layout to the client
181 if filename.startswith(repo.root):
179 if filename.startswith(repo.root):
182 filename = filename[len(repo.root)+1:]
180 filename = filename[len(repo.root)+1:]
183 else:
181 else:
184 filename = ''
182 filename = ''
185 error = getattr(inst, 'strerror', 'Unknown error')
183 error = getattr(inst, 'strerror', 'Unknown error')
186 if inst.errno == errno.ENOENT:
184 if inst.errno == errno.ENOENT:
187 code = HTTP_NOT_FOUND
185 code = HTTP_NOT_FOUND
188 else:
186 else:
189 code = HTTP_SERVER_ERROR
187 code = HTTP_SERVER_ERROR
190 req.respond(code)
188 req.respond(code)
191 yield '0\n%s: %s\n' % (error, filename)
189 return '0\n%s: %s\n' % (error, filename),
192 finally:
190 finally:
193 fp.close()
191 fp.close()
194 os.unlink(tempname)
192 os.unlink(tempname)
195
193
196 def stream_out(repo, req):
194 def stream_out(repo, req):
197 req.respond(HTTP_OK, HGTYPE)
195 req.respond(HTTP_OK, HGTYPE)
198 return streamclone.stream_out(repo, untrusted=True)
196 return streamclone.stream_out(repo, untrusted=True)
General Comments 0
You need to be logged in to leave comments. Login now