##// END OF EJS Templates
hgweb: fix handling of arguments in the between command...
Sune Foldager -
r10530:ed87b6c6 stable
parent child Browse files
Show More
@@ -1,208 +1,207
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 if 'pairs' in req.form:
66 pairs = [map(bin, p.split("-"))
65 pairs = [map(bin, p.split("-"))
67 for p in req.form['pairs'][0].split(" ")]
66 for p in req.form['pairs'][0].split(" ")]
68 resp = cStringIO.StringIO()
67 resp = cStringIO.StringIO()
69 for b in repo.between(pairs):
68 for b in repo.between(pairs):
70 resp.write(" ".join(map(hex, b)) + "\n")
69 resp.write(" ".join(map(hex, b)) + "\n")
71 resp = resp.getvalue()
70 resp = resp.getvalue()
72 req.respond(HTTP_OK, HGTYPE, length=len(resp))
71 req.respond(HTTP_OK, HGTYPE, length=len(resp))
73 yield resp
72 yield resp
74
73
75 def changegroup(repo, req):
74 def changegroup(repo, req):
76 req.respond(HTTP_OK, HGTYPE)
75 req.respond(HTTP_OK, HGTYPE)
77 nodes = []
76 nodes = []
78
77
79 if 'roots' in req.form:
78 if 'roots' in req.form:
80 nodes = map(bin, req.form['roots'][0].split(" "))
79 nodes = map(bin, req.form['roots'][0].split(" "))
81
80
82 z = zlib.compressobj()
81 z = zlib.compressobj()
83 f = repo.changegroup(nodes, 'serve')
82 f = repo.changegroup(nodes, 'serve')
84 while 1:
83 while 1:
85 chunk = f.read(4096)
84 chunk = f.read(4096)
86 if not chunk:
85 if not chunk:
87 break
86 break
88 yield z.compress(chunk)
87 yield z.compress(chunk)
89
88
90 yield z.flush()
89 yield z.flush()
91
90
92 def changegroupsubset(repo, req):
91 def changegroupsubset(repo, req):
93 req.respond(HTTP_OK, HGTYPE)
92 req.respond(HTTP_OK, HGTYPE)
94 bases = []
93 bases = []
95 heads = []
94 heads = []
96
95
97 if 'bases' in req.form:
96 if 'bases' in req.form:
98 bases = [bin(x) for x in req.form['bases'][0].split(' ')]
97 bases = [bin(x) for x in req.form['bases'][0].split(' ')]
99 if 'heads' in req.form:
98 if 'heads' in req.form:
100 heads = [bin(x) for x in req.form['heads'][0].split(' ')]
99 heads = [bin(x) for x in req.form['heads'][0].split(' ')]
101
100
102 z = zlib.compressobj()
101 z = zlib.compressobj()
103 f = repo.changegroupsubset(bases, heads, 'serve')
102 f = repo.changegroupsubset(bases, heads, 'serve')
104 while 1:
103 while 1:
105 chunk = f.read(4096)
104 chunk = f.read(4096)
106 if not chunk:
105 if not chunk:
107 break
106 break
108 yield z.compress(chunk)
107 yield z.compress(chunk)
109
108
110 yield z.flush()
109 yield z.flush()
111
110
112 def capabilities(repo, req):
111 def capabilities(repo, req):
113 caps = copy.copy(basecaps)
112 caps = copy.copy(basecaps)
114 if streamclone.allowed(repo.ui):
113 if streamclone.allowed(repo.ui):
115 caps.append('stream=%d' % repo.changelog.version)
114 caps.append('stream=%d' % repo.changelog.version)
116 if changegroupmod.bundlepriority:
115 if changegroupmod.bundlepriority:
117 caps.append('unbundle=%s' % ','.join(changegroupmod.bundlepriority))
116 caps.append('unbundle=%s' % ','.join(changegroupmod.bundlepriority))
118 rsp = ' '.join(caps)
117 rsp = ' '.join(caps)
119 req.respond(HTTP_OK, HGTYPE, length=len(rsp))
118 req.respond(HTTP_OK, HGTYPE, length=len(rsp))
120 yield rsp
119 yield rsp
121
120
122 def unbundle(repo, req):
121 def unbundle(repo, req):
123
122
124 proto = req.env.get('wsgi.url_scheme') or 'http'
123 proto = req.env.get('wsgi.url_scheme') or 'http'
125 their_heads = req.form['heads'][0].split(' ')
124 their_heads = req.form['heads'][0].split(' ')
126
125
127 def check_heads():
126 def check_heads():
128 heads = map(hex, repo.heads())
127 heads = map(hex, repo.heads())
129 return their_heads == [hex('force')] or their_heads == heads
128 return their_heads == [hex('force')] or their_heads == heads
130
129
131 # fail early if possible
130 # fail early if possible
132 if not check_heads():
131 if not check_heads():
133 req.drain()
132 req.drain()
134 raise ErrorResponse(HTTP_OK, 'unsynced changes')
133 raise ErrorResponse(HTTP_OK, 'unsynced changes')
135
134
136 # do not lock repo until all changegroup data is
135 # do not lock repo until all changegroup data is
137 # streamed. save to temporary file.
136 # streamed. save to temporary file.
138
137
139 fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
138 fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
140 fp = os.fdopen(fd, 'wb+')
139 fp = os.fdopen(fd, 'wb+')
141 try:
140 try:
142 length = int(req.env['CONTENT_LENGTH'])
141 length = int(req.env['CONTENT_LENGTH'])
143 for s in util.filechunkiter(req, limit=length):
142 for s in util.filechunkiter(req, limit=length):
144 fp.write(s)
143 fp.write(s)
145
144
146 try:
145 try:
147 lock = repo.lock()
146 lock = repo.lock()
148 try:
147 try:
149 if not check_heads():
148 if not check_heads():
150 raise ErrorResponse(HTTP_OK, 'unsynced changes')
149 raise ErrorResponse(HTTP_OK, 'unsynced changes')
151
150
152 fp.seek(0)
151 fp.seek(0)
153 header = fp.read(6)
152 header = fp.read(6)
154 if header.startswith('HG') and not header.startswith('HG10'):
153 if header.startswith('HG') and not header.startswith('HG10'):
155 raise ValueError('unknown bundle version')
154 raise ValueError('unknown bundle version')
156 elif header not in changegroupmod.bundletypes:
155 elif header not in changegroupmod.bundletypes:
157 raise ValueError('unknown bundle compression type')
156 raise ValueError('unknown bundle compression type')
158 gen = changegroupmod.unbundle(header, fp)
157 gen = changegroupmod.unbundle(header, fp)
159
158
160 # send addchangegroup output to client
159 # send addchangegroup output to client
161
160
162 oldio = sys.stdout, sys.stderr
161 oldio = sys.stdout, sys.stderr
163 sys.stderr = sys.stdout = cStringIO.StringIO()
162 sys.stderr = sys.stdout = cStringIO.StringIO()
164
163
165 try:
164 try:
166 url = 'remote:%s:%s:%s' % (
165 url = 'remote:%s:%s:%s' % (
167 proto,
166 proto,
168 urllib.quote(req.env.get('REMOTE_HOST', '')),
167 urllib.quote(req.env.get('REMOTE_HOST', '')),
169 urllib.quote(req.env.get('REMOTE_USER', '')))
168 urllib.quote(req.env.get('REMOTE_USER', '')))
170 try:
169 try:
171 ret = repo.addchangegroup(gen, 'serve', url)
170 ret = repo.addchangegroup(gen, 'serve', url)
172 except util.Abort, inst:
171 except util.Abort, inst:
173 sys.stdout.write("abort: %s\n" % inst)
172 sys.stdout.write("abort: %s\n" % inst)
174 ret = 0
173 ret = 0
175 finally:
174 finally:
176 val = sys.stdout.getvalue()
175 val = sys.stdout.getvalue()
177 sys.stdout, sys.stderr = oldio
176 sys.stdout, sys.stderr = oldio
178 req.respond(HTTP_OK, HGTYPE)
177 req.respond(HTTP_OK, HGTYPE)
179 return '%d\n%s' % (ret, val),
178 return '%d\n%s' % (ret, val),
180 finally:
179 finally:
181 lock.release()
180 lock.release()
182 except ValueError, inst:
181 except ValueError, inst:
183 raise ErrorResponse(HTTP_OK, inst)
182 raise ErrorResponse(HTTP_OK, inst)
184 except (OSError, IOError), inst:
183 except (OSError, IOError), inst:
185 error = getattr(inst, 'strerror', 'Unknown error')
184 error = getattr(inst, 'strerror', 'Unknown error')
186 if inst.errno == errno.ENOENT:
185 if inst.errno == errno.ENOENT:
187 code = HTTP_NOT_FOUND
186 code = HTTP_NOT_FOUND
188 else:
187 else:
189 code = HTTP_SERVER_ERROR
188 code = HTTP_SERVER_ERROR
190 filename = getattr(inst, 'filename', '')
189 filename = getattr(inst, 'filename', '')
191 # Don't send our filesystem layout to the client
190 # Don't send our filesystem layout to the client
192 if filename and filename.startswith(repo.root):
191 if filename and filename.startswith(repo.root):
193 filename = filename[len(repo.root)+1:]
192 filename = filename[len(repo.root)+1:]
194 text = '%s: %s' % (error, filename)
193 text = '%s: %s' % (error, filename)
195 else:
194 else:
196 text = error.replace(repo.root + os.path.sep, '')
195 text = error.replace(repo.root + os.path.sep, '')
197 raise ErrorResponse(code, text)
196 raise ErrorResponse(code, text)
198 finally:
197 finally:
199 fp.close()
198 fp.close()
200 os.unlink(tempname)
199 os.unlink(tempname)
201
200
202 def stream_out(repo, req):
201 def stream_out(repo, req):
203 req.respond(HTTP_OK, HGTYPE)
202 req.respond(HTTP_OK, HGTYPE)
204 try:
203 try:
205 for chunk in streamclone.stream_out(repo):
204 for chunk in streamclone.stream_out(repo):
206 yield chunk
205 yield chunk
207 except streamclone.StreamException, inst:
206 except streamclone.StreamException, inst:
208 yield str(inst)
207 yield str(inst)
General Comments 0
You need to be logged in to leave comments. Login now