Mercurial > hg
comparison mercurial/hgweb/protocol.py @ 6781:b4b7261164d5
hgweb: protocol functions take repo instead of web
This makes it much easier for implementers of hgweb alternatives to simply
call into protocol functions after setting up a repo and a request.
author | Dirkjan Ochtman <dirkjan@ochtman.nl> |
---|---|
date | Sun, 29 Jun 2008 11:34:36 +0200 |
parents | 4c1d67e0fa8c |
children | b9d6ab187523 |
comparison
equal
deleted
inserted
replaced
6780:4c1d67e0fa8c | 6781:b4b7261164d5 |
---|---|
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(web, req): | 24 def lookup(repo, req): |
25 try: | 25 try: |
26 r = hex(web.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 req.write(resp) | 33 req.write(resp) |
34 | 34 |
35 def heads(web, req): | 35 def heads(repo, req): |
36 resp = " ".join(map(hex, web.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 req.write(resp) | 38 req.write(resp) |
39 | 39 |
40 def branches(web, 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 web.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 req.write(resp) | 49 req.write(resp) |
50 | 50 |
51 def between(web, 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 web.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 req.write(resp) | 60 req.write(resp) |
61 | 61 |
62 def changegroup(web, 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 = web.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 req.write(z.compress(chunk)) | 75 req.write(z.compress(chunk)) |
76 | 76 |
77 req.write(z.flush()) | 77 req.write(z.flush()) |
78 | 78 |
79 def changegroupsubset(web, 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 = web.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 req.write(z.compress(chunk)) | 95 req.write(z.compress(chunk)) |
96 | 96 |
97 req.write(z.flush()) | 97 req.write(z.flush()) |
98 | 98 |
99 def capabilities(web, req): | 99 def capabilities(repo, req): |
100 caps = ['lookup', 'changegroupsubset'] | 100 caps = ['lookup', 'changegroupsubset'] |
101 if web.repo.ui.configbool('server', 'uncompressed', untrusted=True): | 101 if repo.ui.configbool('server', 'uncompressed', untrusted=True): |
102 caps.append('stream=%d' % web.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 req.write(rsp) | 107 req.write(rsp) |
108 | 108 |
109 def unbundle(web, req): | 109 def unbundle(repo, req): |
110 | 110 |
111 def bail(response, headers={}): | 111 def bail(response, headers={}): |
112 length = int(req.env.get('CONTENT_LENGTH', 0)) | 112 length = int(req.env.get('CONTENT_LENGTH', 0)) |
113 for s in util.filechunkiter(req, limit=length): | 113 for s in util.filechunkiter(req, limit=length): |
114 # drain incoming bundle, else client will not see | 114 # drain incoming bundle, else client will not see |
123 | 123 |
124 proto = req.env.get('wsgi.url_scheme') or 'http' | 124 proto = req.env.get('wsgi.url_scheme') or 'http' |
125 their_heads = req.form['heads'][0].split(' ') | 125 their_heads = req.form['heads'][0].split(' ') |
126 | 126 |
127 def check_heads(): | 127 def check_heads(): |
128 heads = map(hex, web.repo.heads()) | 128 heads = map(hex, repo.heads()) |
129 return their_heads == [hex('force')] or their_heads == heads | 129 return their_heads == [hex('force')] or their_heads == heads |
130 | 130 |
131 # fail early if possible | 131 # fail early if possible |
132 if not check_heads(): | 132 if not check_heads(): |
133 bail('unsynced changes\n') | 133 bail('unsynced changes\n') |
144 length = int(req.env['CONTENT_LENGTH']) | 144 length = int(req.env['CONTENT_LENGTH']) |
145 for s in util.filechunkiter(req, limit=length): | 145 for s in util.filechunkiter(req, limit=length): |
146 fp.write(s) | 146 fp.write(s) |
147 | 147 |
148 try: | 148 try: |
149 lock = web.repo.lock() | 149 lock = repo.lock() |
150 try: | 150 try: |
151 if not check_heads(): | 151 if not check_heads(): |
152 req.write('0\n') | 152 req.write('0\n') |
153 req.write('unsynced changes\n') | 153 req.write('unsynced changes\n') |
154 return | 154 return |
168 | 168 |
169 try: | 169 try: |
170 url = 'remote:%s:%s' % (proto, | 170 url = 'remote:%s:%s' % (proto, |
171 req.env.get('REMOTE_HOST', '')) | 171 req.env.get('REMOTE_HOST', '')) |
172 try: | 172 try: |
173 ret = web.repo.addchangegroup(gen, 'serve', url) | 173 ret = repo.addchangegroup(gen, 'serve', url) |
174 except util.Abort, inst: | 174 except util.Abort, inst: |
175 sys.stdout.write("abort: %s\n" % inst) | 175 sys.stdout.write("abort: %s\n" % inst) |
176 ret = 0 | 176 ret = 0 |
177 finally: | 177 finally: |
178 val = sys.stdout.getvalue() | 178 val = sys.stdout.getvalue() |
186 req.write(str(inst) + '\n') | 186 req.write(str(inst) + '\n') |
187 except (OSError, IOError), inst: | 187 except (OSError, IOError), inst: |
188 req.write('0\n') | 188 req.write('0\n') |
189 filename = getattr(inst, 'filename', '') | 189 filename = getattr(inst, 'filename', '') |
190 # Don't send our filesystem layout to the client | 190 # Don't send our filesystem layout to the client |
191 if filename.startswith(web.repo.root): | 191 if filename.startswith(repo.root): |
192 filename = filename[len(web.repo.root)+1:] | 192 filename = filename[len(repo.root)+1:] |
193 else: | 193 else: |
194 filename = '' | 194 filename = '' |
195 error = getattr(inst, 'strerror', 'Unknown error') | 195 error = getattr(inst, 'strerror', 'Unknown error') |
196 if inst.errno == errno.ENOENT: | 196 if inst.errno == errno.ENOENT: |
197 code = HTTP_NOT_FOUND | 197 code = HTTP_NOT_FOUND |
201 req.write('%s: %s\n' % (error, filename)) | 201 req.write('%s: %s\n' % (error, filename)) |
202 finally: | 202 finally: |
203 fp.close() | 203 fp.close() |
204 os.unlink(tempname) | 204 os.unlink(tempname) |
205 | 205 |
206 def stream_out(web, req): | 206 def stream_out(repo, req): |
207 req.respond(HTTP_OK, HGTYPE) | 207 req.respond(HTTP_OK, HGTYPE) |
208 streamclone.stream_out(web.repo, req, untrusted=True) | 208 streamclone.stream_out(repo, req, untrusted=True) |