##// END OF EJS Templates
hgweb: fix attribute error in error response (issue2060)
Mark Determann -
r10951:5dc09507 stable
parent child Browse files
Show More
@@ -1,204 +1,206
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 of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 import cStringIO, zlib, tempfile, errno, os, sys, urllib, copy
8 import cStringIO, zlib, tempfile, errno, os, sys, urllib, copy
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 ErrorResponse, HTTP_OK, HTTP_NOT_FOUND, HTTP_SERVER_ERROR
12 from common import ErrorResponse, 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 'branchmap',
20 'branchmap',
21 ]
21 ]
22
22
23 HGTYPE = 'application/mercurial-0.1'
23 HGTYPE = 'application/mercurial-0.1'
24 basecaps = 'lookup changegroupsubset branchmap'.split()
24 basecaps = 'lookup changegroupsubset branchmap'.split()
25
25
26 def lookup(repo, req):
26 def lookup(repo, req):
27 try:
27 try:
28 r = hex(repo.lookup(req.form['key'][0]))
28 r = hex(repo.lookup(req.form['key'][0]))
29 success = 1
29 success = 1
30 except Exception, inst:
30 except Exception, inst:
31 r = str(inst)
31 r = str(inst)
32 success = 0
32 success = 0
33 resp = "%s %s\n" % (success, r)
33 resp = "%s %s\n" % (success, r)
34 req.respond(HTTP_OK, HGTYPE, length=len(resp))
34 req.respond(HTTP_OK, HGTYPE, length=len(resp))
35 yield resp
35 yield resp
36
36
37 def heads(repo, req):
37 def heads(repo, req):
38 resp = " ".join(map(hex, repo.heads())) + "\n"
38 resp = " ".join(map(hex, repo.heads())) + "\n"
39 req.respond(HTTP_OK, HGTYPE, length=len(resp))
39 req.respond(HTTP_OK, HGTYPE, length=len(resp))
40 yield resp
40 yield resp
41
41
42 def branchmap(repo, req):
42 def branchmap(repo, req):
43 branches = repo.branchmap()
43 branches = repo.branchmap()
44 heads = []
44 heads = []
45 for branch, nodes in branches.iteritems():
45 for branch, nodes in branches.iteritems():
46 branchname = urllib.quote(branch)
46 branchname = urllib.quote(branch)
47 branchnodes = [hex(node) for node in nodes]
47 branchnodes = [hex(node) for node in nodes]
48 heads.append('%s %s' % (branchname, ' '.join(branchnodes)))
48 heads.append('%s %s' % (branchname, ' '.join(branchnodes)))
49 resp = '\n'.join(heads)
49 resp = '\n'.join(heads)
50 req.respond(HTTP_OK, HGTYPE, length=len(resp))
50 req.respond(HTTP_OK, HGTYPE, length=len(resp))
51 yield resp
51 yield resp
52
52
53 def branches(repo, req):
53 def branches(repo, req):
54 nodes = []
54 nodes = []
55 if 'nodes' in req.form:
55 if 'nodes' in req.form:
56 nodes = map(bin, req.form['nodes'][0].split(" "))
56 nodes = map(bin, req.form['nodes'][0].split(" "))
57 resp = cStringIO.StringIO()
57 resp = cStringIO.StringIO()
58 for b in repo.branches(nodes):
58 for b in repo.branches(nodes):
59 resp.write(" ".join(map(hex, b)) + "\n")
59 resp.write(" ".join(map(hex, b)) + "\n")
60 resp = resp.getvalue()
60 resp = resp.getvalue()
61 req.respond(HTTP_OK, HGTYPE, length=len(resp))
61 req.respond(HTTP_OK, HGTYPE, length=len(resp))
62 yield resp
62 yield resp
63
63
64 def between(repo, req):
64 def between(repo, req):
65 pairs = [map(bin, p.split("-"))
65 pairs = [map(bin, p.split("-"))
66 for p in req.form['pairs'][0].split(" ")]
66 for p in req.form['pairs'][0].split(" ")]
67 resp = ''.join(" ".join(map(hex, b)) + "\n" for b in repo.between(pairs))
67 resp = ''.join(" ".join(map(hex, b)) + "\n" for b in repo.between(pairs))
68 req.respond(HTTP_OK, HGTYPE, length=len(resp))
68 req.respond(HTTP_OK, HGTYPE, length=len(resp))
69 yield resp
69 yield resp
70
70
71 def changegroup(repo, req):
71 def changegroup(repo, req):
72 req.respond(HTTP_OK, HGTYPE)
72 req.respond(HTTP_OK, HGTYPE)
73 nodes = []
73 nodes = []
74
74
75 if 'roots' in req.form:
75 if 'roots' in req.form:
76 nodes = map(bin, req.form['roots'][0].split(" "))
76 nodes = map(bin, req.form['roots'][0].split(" "))
77
77
78 z = zlib.compressobj()
78 z = zlib.compressobj()
79 f = repo.changegroup(nodes, 'serve')
79 f = repo.changegroup(nodes, 'serve')
80 while 1:
80 while 1:
81 chunk = f.read(4096)
81 chunk = f.read(4096)
82 if not chunk:
82 if not chunk:
83 break
83 break
84 yield z.compress(chunk)
84 yield z.compress(chunk)
85
85
86 yield z.flush()
86 yield z.flush()
87
87
88 def changegroupsubset(repo, req):
88 def changegroupsubset(repo, req):
89 req.respond(HTTP_OK, HGTYPE)
89 req.respond(HTTP_OK, HGTYPE)
90 bases = []
90 bases = []
91 heads = []
91 heads = []
92
92
93 if 'bases' in req.form:
93 if 'bases' in req.form:
94 bases = [bin(x) for x in req.form['bases'][0].split(' ')]
94 bases = [bin(x) for x in req.form['bases'][0].split(' ')]
95 if 'heads' in req.form:
95 if 'heads' in req.form:
96 heads = [bin(x) for x in req.form['heads'][0].split(' ')]
96 heads = [bin(x) for x in req.form['heads'][0].split(' ')]
97
97
98 z = zlib.compressobj()
98 z = zlib.compressobj()
99 f = repo.changegroupsubset(bases, heads, 'serve')
99 f = repo.changegroupsubset(bases, heads, 'serve')
100 while 1:
100 while 1:
101 chunk = f.read(4096)
101 chunk = f.read(4096)
102 if not chunk:
102 if not chunk:
103 break
103 break
104 yield z.compress(chunk)
104 yield z.compress(chunk)
105
105
106 yield z.flush()
106 yield z.flush()
107
107
108 def capabilities(repo, req):
108 def capabilities(repo, req):
109 caps = copy.copy(basecaps)
109 caps = copy.copy(basecaps)
110 if streamclone.allowed(repo.ui):
110 if streamclone.allowed(repo.ui):
111 caps.append('stream=%d' % repo.changelog.version)
111 caps.append('stream=%d' % repo.changelog.version)
112 if changegroupmod.bundlepriority:
112 if changegroupmod.bundlepriority:
113 caps.append('unbundle=%s' % ','.join(changegroupmod.bundlepriority))
113 caps.append('unbundle=%s' % ','.join(changegroupmod.bundlepriority))
114 rsp = ' '.join(caps)
114 rsp = ' '.join(caps)
115 req.respond(HTTP_OK, HGTYPE, length=len(rsp))
115 req.respond(HTTP_OK, HGTYPE, length=len(rsp))
116 yield rsp
116 yield rsp
117
117
118 def unbundle(repo, req):
118 def unbundle(repo, req):
119
119
120 proto = req.env.get('wsgi.url_scheme') or 'http'
120 proto = req.env.get('wsgi.url_scheme') or 'http'
121 their_heads = req.form['heads'][0].split(' ')
121 their_heads = req.form['heads'][0].split(' ')
122
122
123 def check_heads():
123 def check_heads():
124 heads = map(hex, repo.heads())
124 heads = map(hex, repo.heads())
125 return their_heads == [hex('force')] or their_heads == heads
125 return their_heads == [hex('force')] or their_heads == heads
126
126
127 # fail early if possible
127 # fail early if possible
128 if not check_heads():
128 if not check_heads():
129 req.drain()
129 req.drain()
130 raise ErrorResponse(HTTP_OK, 'unsynced changes')
130 raise ErrorResponse(HTTP_OK, 'unsynced changes')
131
131
132 # do not lock repo until all changegroup data is
132 # do not lock repo until all changegroup data is
133 # streamed. save to temporary file.
133 # streamed. save to temporary file.
134
134
135 fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
135 fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
136 fp = os.fdopen(fd, 'wb+')
136 fp = os.fdopen(fd, 'wb+')
137 try:
137 try:
138 length = int(req.env['CONTENT_LENGTH'])
138 length = int(req.env['CONTENT_LENGTH'])
139 for s in util.filechunkiter(req, limit=length):
139 for s in util.filechunkiter(req, limit=length):
140 fp.write(s)
140 fp.write(s)
141
141
142 try:
142 try:
143 lock = repo.lock()
143 lock = repo.lock()
144 try:
144 try:
145 if not check_heads():
145 if not check_heads():
146 raise ErrorResponse(HTTP_OK, 'unsynced changes')
146 raise ErrorResponse(HTTP_OK, 'unsynced changes')
147
147
148 fp.seek(0)
148 fp.seek(0)
149 header = fp.read(6)
149 header = fp.read(6)
150 if header.startswith('HG') and not header.startswith('HG10'):
150 if header.startswith('HG') and not header.startswith('HG10'):
151 raise ValueError('unknown bundle version')
151 raise ValueError('unknown bundle version')
152 elif header not in changegroupmod.bundletypes:
152 elif header not in changegroupmod.bundletypes:
153 raise ValueError('unknown bundle compression type')
153 raise ValueError('unknown bundle compression type')
154 gen = changegroupmod.unbundle(header, fp)
154 gen = changegroupmod.unbundle(header, fp)
155
155
156 # send addchangegroup output to client
156 # send addchangegroup output to client
157
157
158 oldio = sys.stdout, sys.stderr
158 oldio = sys.stdout, sys.stderr
159 sys.stderr = sys.stdout = cStringIO.StringIO()
159 sys.stderr = sys.stdout = cStringIO.StringIO()
160
160
161 try:
161 try:
162 url = 'remote:%s:%s:%s' % (
162 url = 'remote:%s:%s:%s' % (
163 proto,
163 proto,
164 urllib.quote(req.env.get('REMOTE_HOST', '')),
164 urllib.quote(req.env.get('REMOTE_HOST', '')),
165 urllib.quote(req.env.get('REMOTE_USER', '')))
165 urllib.quote(req.env.get('REMOTE_USER', '')))
166 try:
166 try:
167 ret = repo.addchangegroup(gen, 'serve', url)
167 ret = repo.addchangegroup(gen, 'serve', url)
168 except util.Abort, inst:
168 except util.Abort, inst:
169 sys.stdout.write("abort: %s\n" % inst)
169 sys.stdout.write("abort: %s\n" % inst)
170 ret = 0
170 ret = 0
171 finally:
171 finally:
172 val = sys.stdout.getvalue()
172 val = sys.stdout.getvalue()
173 sys.stdout, sys.stderr = oldio
173 sys.stdout, sys.stderr = oldio
174 req.respond(HTTP_OK, HGTYPE)
174 req.respond(HTTP_OK, HGTYPE)
175 return '%d\n%s' % (ret, val),
175 return '%d\n%s' % (ret, val),
176 finally:
176 finally:
177 lock.release()
177 lock.release()
178 except ValueError, inst:
178 except ValueError, inst:
179 raise ErrorResponse(HTTP_OK, inst)
179 raise ErrorResponse(HTTP_OK, inst)
180 except (OSError, IOError), inst:
180 except (OSError, IOError), inst:
181 error = getattr(inst, 'strerror', 'Unknown error')
181 error = getattr(inst, 'strerror', 'Unknown error')
182 if not isinstance(error, str):
183 error = 'Error: %s' % str(error)
182 if inst.errno == errno.ENOENT:
184 if inst.errno == errno.ENOENT:
183 code = HTTP_NOT_FOUND
185 code = HTTP_NOT_FOUND
184 else:
186 else:
185 code = HTTP_SERVER_ERROR
187 code = HTTP_SERVER_ERROR
186 filename = getattr(inst, 'filename', '')
188 filename = getattr(inst, 'filename', '')
187 # Don't send our filesystem layout to the client
189 # Don't send our filesystem layout to the client
188 if filename and filename.startswith(repo.root):
190 if filename and filename.startswith(repo.root):
189 filename = filename[len(repo.root)+1:]
191 filename = filename[len(repo.root)+1:]
190 text = '%s: %s' % (error, filename)
192 text = '%s: %s' % (error, filename)
191 else:
193 else:
192 text = error.replace(repo.root + os.path.sep, '')
194 text = error.replace(repo.root + os.path.sep, '')
193 raise ErrorResponse(code, text)
195 raise ErrorResponse(code, text)
194 finally:
196 finally:
195 fp.close()
197 fp.close()
196 os.unlink(tempname)
198 os.unlink(tempname)
197
199
198 def stream_out(repo, req):
200 def stream_out(repo, req):
199 req.respond(HTTP_OK, HGTYPE)
201 req.respond(HTTP_OK, HGTYPE)
200 try:
202 try:
201 for chunk in streamclone.stream_out(repo):
203 for chunk in streamclone.stream_out(repo):
202 yield chunk
204 yield chunk
203 except streamclone.StreamException, inst:
205 except streamclone.StreamException, inst:
204 yield str(inst)
206 yield str(inst)
General Comments 0
You need to be logged in to leave comments. Login now