##// END OF EJS Templates
hgweb: split "verbs" into methods.
Vadim Gelfer -
r2436:f910b91d default
parent child Browse files
Show More
@@ -1,828 +1,835
1 # hgweb/hgweb_mod.py - Web interface for a repository.
1 # hgweb/hgweb_mod.py - Web interface for a repository.
2 #
2 #
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
4 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 # Copyright 2005 Matt Mackall <mpm@selenic.com>
5 #
5 #
6 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
8
8
9 import os
9 import os
10 import os.path
10 import os.path
11 import mimetypes
11 import mimetypes
12 from mercurial.demandload import demandload
12 from mercurial.demandload import demandload
13 demandload(globals(), "re zlib ConfigParser cStringIO")
13 demandload(globals(), "re zlib ConfigParser cStringIO")
14 demandload(globals(), "mercurial:mdiff,ui,hg,util,archival,templater")
14 demandload(globals(), "mercurial:mdiff,ui,hg,util,archival,templater")
15 demandload(globals(), "mercurial.hgweb.request:hgrequest")
15 demandload(globals(), "mercurial.hgweb.request:hgrequest")
16 demandload(globals(), "mercurial.hgweb.common:get_mtime,staticfile")
16 demandload(globals(), "mercurial.hgweb.common:get_mtime,staticfile")
17 from mercurial.node import *
17 from mercurial.node import *
18 from mercurial.i18n import gettext as _
18 from mercurial.i18n import gettext as _
19
19
20 def _up(p):
20 def _up(p):
21 if p[0] != "/":
21 if p[0] != "/":
22 p = "/" + p
22 p = "/" + p
23 if p[-1] == "/":
23 if p[-1] == "/":
24 p = p[:-1]
24 p = p[:-1]
25 up = os.path.dirname(p)
25 up = os.path.dirname(p)
26 if up == "/":
26 if up == "/":
27 return "/"
27 return "/"
28 return up + "/"
28 return up + "/"
29
29
30 class hgweb(object):
30 class hgweb(object):
31 def __init__(self, repo, name=None):
31 def __init__(self, repo, name=None):
32 if type(repo) == type(""):
32 if type(repo) == type(""):
33 self.repo = hg.repository(ui.ui(), repo)
33 self.repo = hg.repository(ui.ui(), repo)
34 else:
34 else:
35 self.repo = repo
35 self.repo = repo
36
36
37 self.mtime = -1
37 self.mtime = -1
38 self.reponame = name
38 self.reponame = name
39 self.archives = 'zip', 'gz', 'bz2'
39 self.archives = 'zip', 'gz', 'bz2'
40 self.templatepath = self.repo.ui.config("web", "templates",
41 templater.templatepath())
40
42
41 def refresh(self):
43 def refresh(self):
42 mtime = get_mtime(self.repo.root)
44 mtime = get_mtime(self.repo.root)
43 if mtime != self.mtime:
45 if mtime != self.mtime:
44 self.mtime = mtime
46 self.mtime = mtime
45 self.repo = hg.repository(self.repo.ui, self.repo.root)
47 self.repo = hg.repository(self.repo.ui, self.repo.root)
46 self.maxchanges = int(self.repo.ui.config("web", "maxchanges", 10))
48 self.maxchanges = int(self.repo.ui.config("web", "maxchanges", 10))
47 self.maxfiles = int(self.repo.ui.config("web", "maxfiles", 10))
49 self.maxfiles = int(self.repo.ui.config("web", "maxfiles", 10))
48 self.allowpull = self.repo.ui.configbool("web", "allowpull", True)
50 self.allowpull = self.repo.ui.configbool("web", "allowpull", True)
49
51
50 def archivelist(self, nodeid):
52 def archivelist(self, nodeid):
51 allowed = (self.repo.ui.config("web", "allow_archive", "")
53 allowed = (self.repo.ui.config("web", "allow_archive", "")
52 .replace(",", " ").split())
54 .replace(",", " ").split())
53 for i in self.archives:
55 for i in self.archives:
54 if i in allowed or self.repo.ui.configbool("web", "allow" + i):
56 if i in allowed or self.repo.ui.configbool("web", "allow" + i):
55 yield {"type" : i, "node" : nodeid, "url": ""}
57 yield {"type" : i, "node" : nodeid, "url": ""}
56
58
57 def listfiles(self, files, mf):
59 def listfiles(self, files, mf):
58 for f in files[:self.maxfiles]:
60 for f in files[:self.maxfiles]:
59 yield self.t("filenodelink", node=hex(mf[f]), file=f)
61 yield self.t("filenodelink", node=hex(mf[f]), file=f)
60 if len(files) > self.maxfiles:
62 if len(files) > self.maxfiles:
61 yield self.t("fileellipses")
63 yield self.t("fileellipses")
62
64
63 def listfilediffs(self, files, changeset):
65 def listfilediffs(self, files, changeset):
64 for f in files[:self.maxfiles]:
66 for f in files[:self.maxfiles]:
65 yield self.t("filedifflink", node=hex(changeset), file=f)
67 yield self.t("filedifflink", node=hex(changeset), file=f)
66 if len(files) > self.maxfiles:
68 if len(files) > self.maxfiles:
67 yield self.t("fileellipses")
69 yield self.t("fileellipses")
68
70
69 def siblings(self, siblings=[], rev=None, hiderev=None, **args):
71 def siblings(self, siblings=[], rev=None, hiderev=None, **args):
70 if not rev:
72 if not rev:
71 rev = lambda x: ""
73 rev = lambda x: ""
72 siblings = [s for s in siblings if s != nullid]
74 siblings = [s for s in siblings if s != nullid]
73 if len(siblings) == 1 and rev(siblings[0]) == hiderev:
75 if len(siblings) == 1 and rev(siblings[0]) == hiderev:
74 return
76 return
75 for s in siblings:
77 for s in siblings:
76 yield dict(node=hex(s), rev=rev(s), **args)
78 yield dict(node=hex(s), rev=rev(s), **args)
77
79
78 def renamelink(self, fl, node):
80 def renamelink(self, fl, node):
79 r = fl.renamed(node)
81 r = fl.renamed(node)
80 if r:
82 if r:
81 return [dict(file=r[0], node=hex(r[1]))]
83 return [dict(file=r[0], node=hex(r[1]))]
82 return []
84 return []
83
85
84 def showtag(self, t1, node=nullid, **args):
86 def showtag(self, t1, node=nullid, **args):
85 for t in self.repo.nodetags(node):
87 for t in self.repo.nodetags(node):
86 yield self.t(t1, tag=t, **args)
88 yield self.t(t1, tag=t, **args)
87
89
88 def diff(self, node1, node2, files):
90 def diff(self, node1, node2, files):
89 def filterfiles(filters, files):
91 def filterfiles(filters, files):
90 l = [x for x in files if x in filters]
92 l = [x for x in files if x in filters]
91
93
92 for t in filters:
94 for t in filters:
93 if t and t[-1] != os.sep:
95 if t and t[-1] != os.sep:
94 t += os.sep
96 t += os.sep
95 l += [x for x in files if x.startswith(t)]
97 l += [x for x in files if x.startswith(t)]
96 return l
98 return l
97
99
98 parity = [0]
100 parity = [0]
99 def diffblock(diff, f, fn):
101 def diffblock(diff, f, fn):
100 yield self.t("diffblock",
102 yield self.t("diffblock",
101 lines=prettyprintlines(diff),
103 lines=prettyprintlines(diff),
102 parity=parity[0],
104 parity=parity[0],
103 file=f,
105 file=f,
104 filenode=hex(fn or nullid))
106 filenode=hex(fn or nullid))
105 parity[0] = 1 - parity[0]
107 parity[0] = 1 - parity[0]
106
108
107 def prettyprintlines(diff):
109 def prettyprintlines(diff):
108 for l in diff.splitlines(1):
110 for l in diff.splitlines(1):
109 if l.startswith('+'):
111 if l.startswith('+'):
110 yield self.t("difflineplus", line=l)
112 yield self.t("difflineplus", line=l)
111 elif l.startswith('-'):
113 elif l.startswith('-'):
112 yield self.t("difflineminus", line=l)
114 yield self.t("difflineminus", line=l)
113 elif l.startswith('@'):
115 elif l.startswith('@'):
114 yield self.t("difflineat", line=l)
116 yield self.t("difflineat", line=l)
115 else:
117 else:
116 yield self.t("diffline", line=l)
118 yield self.t("diffline", line=l)
117
119
118 r = self.repo
120 r = self.repo
119 cl = r.changelog
121 cl = r.changelog
120 mf = r.manifest
122 mf = r.manifest
121 change1 = cl.read(node1)
123 change1 = cl.read(node1)
122 change2 = cl.read(node2)
124 change2 = cl.read(node2)
123 mmap1 = mf.read(change1[0])
125 mmap1 = mf.read(change1[0])
124 mmap2 = mf.read(change2[0])
126 mmap2 = mf.read(change2[0])
125 date1 = util.datestr(change1[2])
127 date1 = util.datestr(change1[2])
126 date2 = util.datestr(change2[2])
128 date2 = util.datestr(change2[2])
127
129
128 modified, added, removed, deleted, unknown = r.changes(node1, node2)
130 modified, added, removed, deleted, unknown = r.changes(node1, node2)
129 if files:
131 if files:
130 modified, added, removed = map(lambda x: filterfiles(files, x),
132 modified, added, removed = map(lambda x: filterfiles(files, x),
131 (modified, added, removed))
133 (modified, added, removed))
132
134
133 diffopts = self.repo.ui.diffopts()
135 diffopts = self.repo.ui.diffopts()
134 showfunc = diffopts['showfunc']
136 showfunc = diffopts['showfunc']
135 ignorews = diffopts['ignorews']
137 ignorews = diffopts['ignorews']
136 for f in modified:
138 for f in modified:
137 to = r.file(f).read(mmap1[f])
139 to = r.file(f).read(mmap1[f])
138 tn = r.file(f).read(mmap2[f])
140 tn = r.file(f).read(mmap2[f])
139 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
141 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
140 showfunc=showfunc, ignorews=ignorews), f, tn)
142 showfunc=showfunc, ignorews=ignorews), f, tn)
141 for f in added:
143 for f in added:
142 to = None
144 to = None
143 tn = r.file(f).read(mmap2[f])
145 tn = r.file(f).read(mmap2[f])
144 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
146 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
145 showfunc=showfunc, ignorews=ignorews), f, tn)
147 showfunc=showfunc, ignorews=ignorews), f, tn)
146 for f in removed:
148 for f in removed:
147 to = r.file(f).read(mmap1[f])
149 to = r.file(f).read(mmap1[f])
148 tn = None
150 tn = None
149 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
151 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
150 showfunc=showfunc, ignorews=ignorews), f, tn)
152 showfunc=showfunc, ignorews=ignorews), f, tn)
151
153
152 def changelog(self, pos):
154 def changelog(self, pos):
153 def changenav(**map):
155 def changenav(**map):
154 def seq(factor, maxchanges=None):
156 def seq(factor, maxchanges=None):
155 if maxchanges:
157 if maxchanges:
156 yield maxchanges
158 yield maxchanges
157 if maxchanges >= 20 and maxchanges <= 40:
159 if maxchanges >= 20 and maxchanges <= 40:
158 yield 50
160 yield 50
159 else:
161 else:
160 yield 1 * factor
162 yield 1 * factor
161 yield 3 * factor
163 yield 3 * factor
162 for f in seq(factor * 10):
164 for f in seq(factor * 10):
163 yield f
165 yield f
164
166
165 l = []
167 l = []
166 last = 0
168 last = 0
167 for f in seq(1, self.maxchanges):
169 for f in seq(1, self.maxchanges):
168 if f < self.maxchanges or f <= last:
170 if f < self.maxchanges or f <= last:
169 continue
171 continue
170 if f > count:
172 if f > count:
171 break
173 break
172 last = f
174 last = f
173 r = "%d" % f
175 r = "%d" % f
174 if pos + f < count:
176 if pos + f < count:
175 l.append(("+" + r, pos + f))
177 l.append(("+" + r, pos + f))
176 if pos - f >= 0:
178 if pos - f >= 0:
177 l.insert(0, ("-" + r, pos - f))
179 l.insert(0, ("-" + r, pos - f))
178
180
179 yield {"rev": 0, "label": "(0)"}
181 yield {"rev": 0, "label": "(0)"}
180
182
181 for label, rev in l:
183 for label, rev in l:
182 yield {"label": label, "rev": rev}
184 yield {"label": label, "rev": rev}
183
185
184 yield {"label": "tip", "rev": "tip"}
186 yield {"label": "tip", "rev": "tip"}
185
187
186 def changelist(**map):
188 def changelist(**map):
187 parity = (start - end) & 1
189 parity = (start - end) & 1
188 cl = self.repo.changelog
190 cl = self.repo.changelog
189 l = [] # build a list in forward order for efficiency
191 l = [] # build a list in forward order for efficiency
190 for i in range(start, end):
192 for i in range(start, end):
191 n = cl.node(i)
193 n = cl.node(i)
192 changes = cl.read(n)
194 changes = cl.read(n)
193 hn = hex(n)
195 hn = hex(n)
194
196
195 l.insert(0, {"parity": parity,
197 l.insert(0, {"parity": parity,
196 "author": changes[1],
198 "author": changes[1],
197 "parent": self.siblings(cl.parents(n), cl.rev,
199 "parent": self.siblings(cl.parents(n), cl.rev,
198 cl.rev(n) - 1),
200 cl.rev(n) - 1),
199 "child": self.siblings(cl.children(n), cl.rev,
201 "child": self.siblings(cl.children(n), cl.rev,
200 cl.rev(n) + 1),
202 cl.rev(n) + 1),
201 "changelogtag": self.showtag("changelogtag",n),
203 "changelogtag": self.showtag("changelogtag",n),
202 "manifest": hex(changes[0]),
204 "manifest": hex(changes[0]),
203 "desc": changes[4],
205 "desc": changes[4],
204 "date": changes[2],
206 "date": changes[2],
205 "files": self.listfilediffs(changes[3], n),
207 "files": self.listfilediffs(changes[3], n),
206 "rev": i,
208 "rev": i,
207 "node": hn})
209 "node": hn})
208 parity = 1 - parity
210 parity = 1 - parity
209
211
210 for e in l:
212 for e in l:
211 yield e
213 yield e
212
214
213 cl = self.repo.changelog
215 cl = self.repo.changelog
214 mf = cl.read(cl.tip())[0]
216 mf = cl.read(cl.tip())[0]
215 count = cl.count()
217 count = cl.count()
216 start = max(0, pos - self.maxchanges + 1)
218 start = max(0, pos - self.maxchanges + 1)
217 end = min(count, start + self.maxchanges)
219 end = min(count, start + self.maxchanges)
218 pos = end - 1
220 pos = end - 1
219
221
220 yield self.t('changelog',
222 yield self.t('changelog',
221 changenav=changenav,
223 changenav=changenav,
222 manifest=hex(mf),
224 manifest=hex(mf),
223 rev=pos, changesets=count, entries=changelist,
225 rev=pos, changesets=count, entries=changelist,
224 archives=self.archivelist("tip"))
226 archives=self.archivelist("tip"))
225
227
226 def search(self, query):
228 def search(self, query):
227
229
228 def changelist(**map):
230 def changelist(**map):
229 cl = self.repo.changelog
231 cl = self.repo.changelog
230 count = 0
232 count = 0
231 qw = query.lower().split()
233 qw = query.lower().split()
232
234
233 def revgen():
235 def revgen():
234 for i in range(cl.count() - 1, 0, -100):
236 for i in range(cl.count() - 1, 0, -100):
235 l = []
237 l = []
236 for j in range(max(0, i - 100), i):
238 for j in range(max(0, i - 100), i):
237 n = cl.node(j)
239 n = cl.node(j)
238 changes = cl.read(n)
240 changes = cl.read(n)
239 l.append((n, j, changes))
241 l.append((n, j, changes))
240 l.reverse()
242 l.reverse()
241 for e in l:
243 for e in l:
242 yield e
244 yield e
243
245
244 for n, i, changes in revgen():
246 for n, i, changes in revgen():
245 miss = 0
247 miss = 0
246 for q in qw:
248 for q in qw:
247 if not (q in changes[1].lower() or
249 if not (q in changes[1].lower() or
248 q in changes[4].lower() or
250 q in changes[4].lower() or
249 q in " ".join(changes[3][:20]).lower()):
251 q in " ".join(changes[3][:20]).lower()):
250 miss = 1
252 miss = 1
251 break
253 break
252 if miss:
254 if miss:
253 continue
255 continue
254
256
255 count += 1
257 count += 1
256 hn = hex(n)
258 hn = hex(n)
257
259
258 yield self.t('searchentry',
260 yield self.t('searchentry',
259 parity=count & 1,
261 parity=count & 1,
260 author=changes[1],
262 author=changes[1],
261 parent=self.siblings(cl.parents(n), cl.rev),
263 parent=self.siblings(cl.parents(n), cl.rev),
262 child=self.siblings(cl.children(n), cl.rev),
264 child=self.siblings(cl.children(n), cl.rev),
263 changelogtag=self.showtag("changelogtag",n),
265 changelogtag=self.showtag("changelogtag",n),
264 manifest=hex(changes[0]),
266 manifest=hex(changes[0]),
265 desc=changes[4],
267 desc=changes[4],
266 date=changes[2],
268 date=changes[2],
267 files=self.listfilediffs(changes[3], n),
269 files=self.listfilediffs(changes[3], n),
268 rev=i,
270 rev=i,
269 node=hn)
271 node=hn)
270
272
271 if count >= self.maxchanges:
273 if count >= self.maxchanges:
272 break
274 break
273
275
274 cl = self.repo.changelog
276 cl = self.repo.changelog
275 mf = cl.read(cl.tip())[0]
277 mf = cl.read(cl.tip())[0]
276
278
277 yield self.t('search',
279 yield self.t('search',
278 query=query,
280 query=query,
279 manifest=hex(mf),
281 manifest=hex(mf),
280 entries=changelist)
282 entries=changelist)
281
283
282 def changeset(self, nodeid):
284 def changeset(self, nodeid):
283 cl = self.repo.changelog
285 cl = self.repo.changelog
284 n = self.repo.lookup(nodeid)
286 n = self.repo.lookup(nodeid)
285 nodeid = hex(n)
287 nodeid = hex(n)
286 changes = cl.read(n)
288 changes = cl.read(n)
287 p1 = cl.parents(n)[0]
289 p1 = cl.parents(n)[0]
288
290
289 files = []
291 files = []
290 mf = self.repo.manifest.read(changes[0])
292 mf = self.repo.manifest.read(changes[0])
291 for f in changes[3]:
293 for f in changes[3]:
292 files.append(self.t("filenodelink",
294 files.append(self.t("filenodelink",
293 filenode=hex(mf.get(f, nullid)), file=f))
295 filenode=hex(mf.get(f, nullid)), file=f))
294
296
295 def diff(**map):
297 def diff(**map):
296 yield self.diff(p1, n, None)
298 yield self.diff(p1, n, None)
297
299
298 yield self.t('changeset',
300 yield self.t('changeset',
299 diff=diff,
301 diff=diff,
300 rev=cl.rev(n),
302 rev=cl.rev(n),
301 node=nodeid,
303 node=nodeid,
302 parent=self.siblings(cl.parents(n), cl.rev),
304 parent=self.siblings(cl.parents(n), cl.rev),
303 child=self.siblings(cl.children(n), cl.rev),
305 child=self.siblings(cl.children(n), cl.rev),
304 changesettag=self.showtag("changesettag",n),
306 changesettag=self.showtag("changesettag",n),
305 manifest=hex(changes[0]),
307 manifest=hex(changes[0]),
306 author=changes[1],
308 author=changes[1],
307 desc=changes[4],
309 desc=changes[4],
308 date=changes[2],
310 date=changes[2],
309 files=files,
311 files=files,
310 archives=self.archivelist(nodeid))
312 archives=self.archivelist(nodeid))
311
313
312 def filelog(self, f, filenode):
314 def filelog(self, f, filenode):
313 cl = self.repo.changelog
315 cl = self.repo.changelog
314 fl = self.repo.file(f)
316 fl = self.repo.file(f)
315 filenode = hex(fl.lookup(filenode))
317 filenode = hex(fl.lookup(filenode))
316 count = fl.count()
318 count = fl.count()
317
319
318 def entries(**map):
320 def entries(**map):
319 l = []
321 l = []
320 parity = (count - 1) & 1
322 parity = (count - 1) & 1
321
323
322 for i in range(count):
324 for i in range(count):
323 n = fl.node(i)
325 n = fl.node(i)
324 lr = fl.linkrev(n)
326 lr = fl.linkrev(n)
325 cn = cl.node(lr)
327 cn = cl.node(lr)
326 cs = cl.read(cl.node(lr))
328 cs = cl.read(cl.node(lr))
327
329
328 l.insert(0, {"parity": parity,
330 l.insert(0, {"parity": parity,
329 "filenode": hex(n),
331 "filenode": hex(n),
330 "filerev": i,
332 "filerev": i,
331 "file": f,
333 "file": f,
332 "node": hex(cn),
334 "node": hex(cn),
333 "author": cs[1],
335 "author": cs[1],
334 "date": cs[2],
336 "date": cs[2],
335 "rename": self.renamelink(fl, n),
337 "rename": self.renamelink(fl, n),
336 "parent": self.siblings(fl.parents(n),
338 "parent": self.siblings(fl.parents(n),
337 fl.rev, file=f),
339 fl.rev, file=f),
338 "child": self.siblings(fl.children(n),
340 "child": self.siblings(fl.children(n),
339 fl.rev, file=f),
341 fl.rev, file=f),
340 "desc": cs[4]})
342 "desc": cs[4]})
341 parity = 1 - parity
343 parity = 1 - parity
342
344
343 for e in l:
345 for e in l:
344 yield e
346 yield e
345
347
346 yield self.t("filelog", file=f, filenode=filenode, entries=entries)
348 yield self.t("filelog", file=f, filenode=filenode, entries=entries)
347
349
348 def filerevision(self, f, node):
350 def filerevision(self, f, node):
349 fl = self.repo.file(f)
351 fl = self.repo.file(f)
350 n = fl.lookup(node)
352 n = fl.lookup(node)
351 node = hex(n)
353 node = hex(n)
352 text = fl.read(n)
354 text = fl.read(n)
353 changerev = fl.linkrev(n)
355 changerev = fl.linkrev(n)
354 cl = self.repo.changelog
356 cl = self.repo.changelog
355 cn = cl.node(changerev)
357 cn = cl.node(changerev)
356 cs = cl.read(cn)
358 cs = cl.read(cn)
357 mfn = cs[0]
359 mfn = cs[0]
358
360
359 mt = mimetypes.guess_type(f)[0]
361 mt = mimetypes.guess_type(f)[0]
360 rawtext = text
362 rawtext = text
361 if util.binary(text):
363 if util.binary(text):
362 mt = mt or 'application/octet-stream'
364 mt = mt or 'application/octet-stream'
363 text = "(binary:%s)" % mt
365 text = "(binary:%s)" % mt
364 mt = mt or 'text/plain'
366 mt = mt or 'text/plain'
365
367
366 def lines():
368 def lines():
367 for l, t in enumerate(text.splitlines(1)):
369 for l, t in enumerate(text.splitlines(1)):
368 yield {"line": t,
370 yield {"line": t,
369 "linenumber": "% 6d" % (l + 1),
371 "linenumber": "% 6d" % (l + 1),
370 "parity": l & 1}
372 "parity": l & 1}
371
373
372 yield self.t("filerevision",
374 yield self.t("filerevision",
373 file=f,
375 file=f,
374 filenode=node,
376 filenode=node,
375 path=_up(f),
377 path=_up(f),
376 text=lines(),
378 text=lines(),
377 raw=rawtext,
379 raw=rawtext,
378 mimetype=mt,
380 mimetype=mt,
379 rev=changerev,
381 rev=changerev,
380 node=hex(cn),
382 node=hex(cn),
381 manifest=hex(mfn),
383 manifest=hex(mfn),
382 author=cs[1],
384 author=cs[1],
383 date=cs[2],
385 date=cs[2],
384 parent=self.siblings(fl.parents(n), fl.rev, file=f),
386 parent=self.siblings(fl.parents(n), fl.rev, file=f),
385 child=self.siblings(fl.children(n), fl.rev, file=f),
387 child=self.siblings(fl.children(n), fl.rev, file=f),
386 rename=self.renamelink(fl, n),
388 rename=self.renamelink(fl, n),
387 permissions=self.repo.manifest.readflags(mfn)[f])
389 permissions=self.repo.manifest.readflags(mfn)[f])
388
390
389 def fileannotate(self, f, node):
391 def fileannotate(self, f, node):
390 bcache = {}
392 bcache = {}
391 ncache = {}
393 ncache = {}
392 fl = self.repo.file(f)
394 fl = self.repo.file(f)
393 n = fl.lookup(node)
395 n = fl.lookup(node)
394 node = hex(n)
396 node = hex(n)
395 changerev = fl.linkrev(n)
397 changerev = fl.linkrev(n)
396
398
397 cl = self.repo.changelog
399 cl = self.repo.changelog
398 cn = cl.node(changerev)
400 cn = cl.node(changerev)
399 cs = cl.read(cn)
401 cs = cl.read(cn)
400 mfn = cs[0]
402 mfn = cs[0]
401
403
402 def annotate(**map):
404 def annotate(**map):
403 parity = 1
405 parity = 1
404 last = None
406 last = None
405 for r, l in fl.annotate(n):
407 for r, l in fl.annotate(n):
406 try:
408 try:
407 cnode = ncache[r]
409 cnode = ncache[r]
408 except KeyError:
410 except KeyError:
409 cnode = ncache[r] = self.repo.changelog.node(r)
411 cnode = ncache[r] = self.repo.changelog.node(r)
410
412
411 try:
413 try:
412 name = bcache[r]
414 name = bcache[r]
413 except KeyError:
415 except KeyError:
414 cl = self.repo.changelog.read(cnode)
416 cl = self.repo.changelog.read(cnode)
415 bcache[r] = name = self.repo.ui.shortuser(cl[1])
417 bcache[r] = name = self.repo.ui.shortuser(cl[1])
416
418
417 if last != cnode:
419 if last != cnode:
418 parity = 1 - parity
420 parity = 1 - parity
419 last = cnode
421 last = cnode
420
422
421 yield {"parity": parity,
423 yield {"parity": parity,
422 "node": hex(cnode),
424 "node": hex(cnode),
423 "rev": r,
425 "rev": r,
424 "author": name,
426 "author": name,
425 "file": f,
427 "file": f,
426 "line": l}
428 "line": l}
427
429
428 yield self.t("fileannotate",
430 yield self.t("fileannotate",
429 file=f,
431 file=f,
430 filenode=node,
432 filenode=node,
431 annotate=annotate,
433 annotate=annotate,
432 path=_up(f),
434 path=_up(f),
433 rev=changerev,
435 rev=changerev,
434 node=hex(cn),
436 node=hex(cn),
435 manifest=hex(mfn),
437 manifest=hex(mfn),
436 author=cs[1],
438 author=cs[1],
437 date=cs[2],
439 date=cs[2],
438 rename=self.renamelink(fl, n),
440 rename=self.renamelink(fl, n),
439 parent=self.siblings(fl.parents(n), fl.rev, file=f),
441 parent=self.siblings(fl.parents(n), fl.rev, file=f),
440 child=self.siblings(fl.children(n), fl.rev, file=f),
442 child=self.siblings(fl.children(n), fl.rev, file=f),
441 permissions=self.repo.manifest.readflags(mfn)[f])
443 permissions=self.repo.manifest.readflags(mfn)[f])
442
444
443 def manifest(self, mnode, path):
445 def manifest(self, mnode, path):
444 man = self.repo.manifest
446 man = self.repo.manifest
445 mn = man.lookup(mnode)
447 mn = man.lookup(mnode)
446 mnode = hex(mn)
448 mnode = hex(mn)
447 mf = man.read(mn)
449 mf = man.read(mn)
448 rev = man.rev(mn)
450 rev = man.rev(mn)
449 changerev = man.linkrev(mn)
451 changerev = man.linkrev(mn)
450 node = self.repo.changelog.node(changerev)
452 node = self.repo.changelog.node(changerev)
451 mff = man.readflags(mn)
453 mff = man.readflags(mn)
452
454
453 files = {}
455 files = {}
454
456
455 p = path[1:]
457 p = path[1:]
456 if p and p[-1] != "/":
458 if p and p[-1] != "/":
457 p += "/"
459 p += "/"
458 l = len(p)
460 l = len(p)
459
461
460 for f,n in mf.items():
462 for f,n in mf.items():
461 if f[:l] != p:
463 if f[:l] != p:
462 continue
464 continue
463 remain = f[l:]
465 remain = f[l:]
464 if "/" in remain:
466 if "/" in remain:
465 short = remain[:remain.find("/") + 1] # bleah
467 short = remain[:remain.find("/") + 1] # bleah
466 files[short] = (f, None)
468 files[short] = (f, None)
467 else:
469 else:
468 short = os.path.basename(remain)
470 short = os.path.basename(remain)
469 files[short] = (f, n)
471 files[short] = (f, n)
470
472
471 def filelist(**map):
473 def filelist(**map):
472 parity = 0
474 parity = 0
473 fl = files.keys()
475 fl = files.keys()
474 fl.sort()
476 fl.sort()
475 for f in fl:
477 for f in fl:
476 full, fnode = files[f]
478 full, fnode = files[f]
477 if not fnode:
479 if not fnode:
478 continue
480 continue
479
481
480 yield {"file": full,
482 yield {"file": full,
481 "manifest": mnode,
483 "manifest": mnode,
482 "filenode": hex(fnode),
484 "filenode": hex(fnode),
483 "parity": parity,
485 "parity": parity,
484 "basename": f,
486 "basename": f,
485 "permissions": mff[full]}
487 "permissions": mff[full]}
486 parity = 1 - parity
488 parity = 1 - parity
487
489
488 def dirlist(**map):
490 def dirlist(**map):
489 parity = 0
491 parity = 0
490 fl = files.keys()
492 fl = files.keys()
491 fl.sort()
493 fl.sort()
492 for f in fl:
494 for f in fl:
493 full, fnode = files[f]
495 full, fnode = files[f]
494 if fnode:
496 if fnode:
495 continue
497 continue
496
498
497 yield {"parity": parity,
499 yield {"parity": parity,
498 "path": os.path.join(path, f),
500 "path": os.path.join(path, f),
499 "manifest": mnode,
501 "manifest": mnode,
500 "basename": f[:-1]}
502 "basename": f[:-1]}
501 parity = 1 - parity
503 parity = 1 - parity
502
504
503 yield self.t("manifest",
505 yield self.t("manifest",
504 manifest=mnode,
506 manifest=mnode,
505 rev=rev,
507 rev=rev,
506 node=hex(node),
508 node=hex(node),
507 path=path,
509 path=path,
508 up=_up(path),
510 up=_up(path),
509 fentries=filelist,
511 fentries=filelist,
510 dentries=dirlist,
512 dentries=dirlist,
511 archives=self.archivelist(hex(node)))
513 archives=self.archivelist(hex(node)))
512
514
513 def tags(self):
515 def tags(self):
514 cl = self.repo.changelog
516 cl = self.repo.changelog
515 mf = cl.read(cl.tip())[0]
517 mf = cl.read(cl.tip())[0]
516
518
517 i = self.repo.tagslist()
519 i = self.repo.tagslist()
518 i.reverse()
520 i.reverse()
519
521
520 def entries(notip=False, **map):
522 def entries(notip=False, **map):
521 parity = 0
523 parity = 0
522 for k,n in i:
524 for k,n in i:
523 if notip and k == "tip": continue
525 if notip and k == "tip": continue
524 yield {"parity": parity,
526 yield {"parity": parity,
525 "tag": k,
527 "tag": k,
526 "tagmanifest": hex(cl.read(n)[0]),
528 "tagmanifest": hex(cl.read(n)[0]),
527 "date": cl.read(n)[2],
529 "date": cl.read(n)[2],
528 "node": hex(n)}
530 "node": hex(n)}
529 parity = 1 - parity
531 parity = 1 - parity
530
532
531 yield self.t("tags",
533 yield self.t("tags",
532 manifest=hex(mf),
534 manifest=hex(mf),
533 entries=lambda **x: entries(False, **x),
535 entries=lambda **x: entries(False, **x),
534 entriesnotip=lambda **x: entries(True, **x))
536 entriesnotip=lambda **x: entries(True, **x))
535
537
536 def summary(self):
538 def summary(self):
537 cl = self.repo.changelog
539 cl = self.repo.changelog
538 mf = cl.read(cl.tip())[0]
540 mf = cl.read(cl.tip())[0]
539
541
540 i = self.repo.tagslist()
542 i = self.repo.tagslist()
541 i.reverse()
543 i.reverse()
542
544
543 def tagentries(**map):
545 def tagentries(**map):
544 parity = 0
546 parity = 0
545 count = 0
547 count = 0
546 for k,n in i:
548 for k,n in i:
547 if k == "tip": # skip tip
549 if k == "tip": # skip tip
548 continue;
550 continue;
549
551
550 count += 1
552 count += 1
551 if count > 10: # limit to 10 tags
553 if count > 10: # limit to 10 tags
552 break;
554 break;
553
555
554 c = cl.read(n)
556 c = cl.read(n)
555 m = c[0]
557 m = c[0]
556 t = c[2]
558 t = c[2]
557
559
558 yield self.t("tagentry",
560 yield self.t("tagentry",
559 parity = parity,
561 parity = parity,
560 tag = k,
562 tag = k,
561 node = hex(n),
563 node = hex(n),
562 date = t,
564 date = t,
563 tagmanifest = hex(m))
565 tagmanifest = hex(m))
564 parity = 1 - parity
566 parity = 1 - parity
565
567
566 def changelist(**map):
568 def changelist(**map):
567 parity = 0
569 parity = 0
568 cl = self.repo.changelog
570 cl = self.repo.changelog
569 l = [] # build a list in forward order for efficiency
571 l = [] # build a list in forward order for efficiency
570 for i in range(start, end):
572 for i in range(start, end):
571 n = cl.node(i)
573 n = cl.node(i)
572 changes = cl.read(n)
574 changes = cl.read(n)
573 hn = hex(n)
575 hn = hex(n)
574 t = changes[2]
576 t = changes[2]
575
577
576 l.insert(0, self.t(
578 l.insert(0, self.t(
577 'shortlogentry',
579 'shortlogentry',
578 parity = parity,
580 parity = parity,
579 author = changes[1],
581 author = changes[1],
580 manifest = hex(changes[0]),
582 manifest = hex(changes[0]),
581 desc = changes[4],
583 desc = changes[4],
582 date = t,
584 date = t,
583 rev = i,
585 rev = i,
584 node = hn))
586 node = hn))
585 parity = 1 - parity
587 parity = 1 - parity
586
588
587 yield l
589 yield l
588
590
589 cl = self.repo.changelog
591 cl = self.repo.changelog
590 mf = cl.read(cl.tip())[0]
592 mf = cl.read(cl.tip())[0]
591 count = cl.count()
593 count = cl.count()
592 start = max(0, count - self.maxchanges)
594 start = max(0, count - self.maxchanges)
593 end = min(count, start + self.maxchanges)
595 end = min(count, start + self.maxchanges)
594
596
595 yield self.t("summary",
597 yield self.t("summary",
596 desc = self.repo.ui.config("web", "description", "unknown"),
598 desc = self.repo.ui.config("web", "description", "unknown"),
597 owner = (self.repo.ui.config("ui", "username") or # preferred
599 owner = (self.repo.ui.config("ui", "username") or # preferred
598 self.repo.ui.config("web", "contact") or # deprecated
600 self.repo.ui.config("web", "contact") or # deprecated
599 self.repo.ui.config("web", "author", "unknown")), # also
601 self.repo.ui.config("web", "author", "unknown")), # also
600 lastchange = (0, 0), # FIXME
602 lastchange = (0, 0), # FIXME
601 manifest = hex(mf),
603 manifest = hex(mf),
602 tags = tagentries,
604 tags = tagentries,
603 shortlog = changelist)
605 shortlog = changelist)
604
606
605 def filediff(self, file, changeset):
607 def filediff(self, file, changeset):
606 cl = self.repo.changelog
608 cl = self.repo.changelog
607 n = self.repo.lookup(changeset)
609 n = self.repo.lookup(changeset)
608 changeset = hex(n)
610 changeset = hex(n)
609 p1 = cl.parents(n)[0]
611 p1 = cl.parents(n)[0]
610 cs = cl.read(n)
612 cs = cl.read(n)
611 mf = self.repo.manifest.read(cs[0])
613 mf = self.repo.manifest.read(cs[0])
612
614
613 def diff(**map):
615 def diff(**map):
614 yield self.diff(p1, n, [file])
616 yield self.diff(p1, n, [file])
615
617
616 yield self.t("filediff",
618 yield self.t("filediff",
617 file=file,
619 file=file,
618 filenode=hex(mf.get(file, nullid)),
620 filenode=hex(mf.get(file, nullid)),
619 node=changeset,
621 node=changeset,
620 rev=self.repo.changelog.rev(n),
622 rev=self.repo.changelog.rev(n),
621 parent=self.siblings(cl.parents(n), cl.rev),
623 parent=self.siblings(cl.parents(n), cl.rev),
622 child=self.siblings(cl.children(n), cl.rev),
624 child=self.siblings(cl.children(n), cl.rev),
623 diff=diff)
625 diff=diff)
624
626
625 archive_specs = {
627 archive_specs = {
626 'bz2': ('application/x-tar', 'tbz2', '.tar.bz2', None),
628 'bz2': ('application/x-tar', 'tbz2', '.tar.bz2', None),
627 'gz': ('application/x-tar', 'tgz', '.tar.gz', None),
629 'gz': ('application/x-tar', 'tgz', '.tar.gz', None),
628 'zip': ('application/zip', 'zip', '.zip', None),
630 'zip': ('application/zip', 'zip', '.zip', None),
629 }
631 }
630
632
631 def archive(self, req, cnode, type_):
633 def archive(self, req, cnode, type_):
632 reponame = re.sub(r"\W+", "-", os.path.basename(self.reponame))
634 reponame = re.sub(r"\W+", "-", os.path.basename(self.reponame))
633 name = "%s-%s" % (reponame, short(cnode))
635 name = "%s-%s" % (reponame, short(cnode))
634 mimetype, artype, extension, encoding = self.archive_specs[type_]
636 mimetype, artype, extension, encoding = self.archive_specs[type_]
635 headers = [('Content-type', mimetype),
637 headers = [('Content-type', mimetype),
636 ('Content-disposition', 'attachment; filename=%s%s' %
638 ('Content-disposition', 'attachment; filename=%s%s' %
637 (name, extension))]
639 (name, extension))]
638 if encoding:
640 if encoding:
639 headers.append(('Content-encoding', encoding))
641 headers.append(('Content-encoding', encoding))
640 req.header(headers)
642 req.header(headers)
641 archival.archive(self.repo, req.out, cnode, artype, prefix=name)
643 archival.archive(self.repo, req.out, cnode, artype, prefix=name)
642
644
643 # add tags to things
645 # add tags to things
644 # tags -> list of changesets corresponding to tags
646 # tags -> list of changesets corresponding to tags
645 # find tag, changeset, file
647 # find tag, changeset, file
646
648
649 def cleanpath(self, path):
650 p = util.normpath(path)
651 if p[:2] == "..":
652 raise Exception("suspicious path")
653 return p
654
647 def run(self, req=hgrequest()):
655 def run(self, req=hgrequest()):
648 def clean(path):
649 p = util.normpath(path)
650 if p[:2] == "..":
651 raise Exception("suspicious path")
652 return p
653
654 def header(**map):
656 def header(**map):
655 yield self.t("header", **map)
657 yield self.t("header", **map)
656
658
657 def footer(**map):
659 def footer(**map):
658 yield self.t("footer",
660 yield self.t("footer",
659 motd=self.repo.ui.config("web", "motd", ""),
661 motd=self.repo.ui.config("web", "motd", ""),
660 **map)
662 **map)
661
663
662 def expand_form(form):
664 def expand_form(form):
663 shortcuts = {
665 shortcuts = {
664 'cl': [('cmd', ['changelog']), ('rev', None)],
666 'cl': [('cmd', ['changelog']), ('rev', None)],
665 'cs': [('cmd', ['changeset']), ('node', None)],
667 'cs': [('cmd', ['changeset']), ('node', None)],
666 'f': [('cmd', ['file']), ('filenode', None)],
668 'f': [('cmd', ['file']), ('filenode', None)],
667 'fl': [('cmd', ['filelog']), ('filenode', None)],
669 'fl': [('cmd', ['filelog']), ('filenode', None)],
668 'fd': [('cmd', ['filediff']), ('node', None)],
670 'fd': [('cmd', ['filediff']), ('node', None)],
669 'fa': [('cmd', ['annotate']), ('filenode', None)],
671 'fa': [('cmd', ['annotate']), ('filenode', None)],
670 'mf': [('cmd', ['manifest']), ('manifest', None)],
672 'mf': [('cmd', ['manifest']), ('manifest', None)],
671 'ca': [('cmd', ['archive']), ('node', None)],
673 'ca': [('cmd', ['archive']), ('node', None)],
672 'tags': [('cmd', ['tags'])],
674 'tags': [('cmd', ['tags'])],
673 'tip': [('cmd', ['changeset']), ('node', ['tip'])],
675 'tip': [('cmd', ['changeset']), ('node', ['tip'])],
674 'static': [('cmd', ['static']), ('file', None)]
676 'static': [('cmd', ['static']), ('file', None)]
675 }
677 }
676
678
677 for k in shortcuts.iterkeys():
679 for k in shortcuts.iterkeys():
678 if form.has_key(k):
680 if form.has_key(k):
679 for name, value in shortcuts[k]:
681 for name, value in shortcuts[k]:
680 if value is None:
682 if value is None:
681 value = form[k]
683 value = form[k]
682 form[name] = value
684 form[name] = value
683 del form[k]
685 del form[k]
684
686
685 self.refresh()
687 self.refresh()
686
688
687 expand_form(req.form)
689 expand_form(req.form)
688
690
689 t = self.repo.ui.config("web", "templates", templater.templatepath())
691 m = os.path.join(self.templatepath, "map")
690 static = self.repo.ui.config("web", "static", os.path.join(t,"static"))
691 m = os.path.join(t, "map")
692 style = self.repo.ui.config("web", "style", "")
692 style = self.repo.ui.config("web", "style", "")
693 if req.form.has_key('style'):
693 if req.form.has_key('style'):
694 style = req.form['style'][0]
694 style = req.form['style'][0]
695 if style:
695 if style:
696 b = os.path.basename("map-" + style)
696 b = os.path.basename("map-" + style)
697 p = os.path.join(t, b)
697 p = os.path.join(self.templatepath, b)
698 if os.path.isfile(p):
698 if os.path.isfile(p):
699 m = p
699 m = p
700
700
701 port = req.env["SERVER_PORT"]
701 port = req.env["SERVER_PORT"]
702 port = port != "80" and (":" + port) or ""
702 port = port != "80" and (":" + port) or ""
703 uri = req.env["REQUEST_URI"]
703 uri = req.env["REQUEST_URI"]
704 if "?" in uri:
704 if "?" in uri:
705 uri = uri.split("?")[0]
705 uri = uri.split("?")[0]
706 url = "http://%s%s%s" % (req.env["SERVER_NAME"], port, uri)
706 url = "http://%s%s%s" % (req.env["SERVER_NAME"], port, uri)
707 if not self.reponame:
707 if not self.reponame:
708 self.reponame = (self.repo.ui.config("web", "name")
708 self.reponame = (self.repo.ui.config("web", "name")
709 or uri.strip('/') or self.repo.root)
709 or uri.strip('/') or self.repo.root)
710
710
711 self.t = templater.templater(m, templater.common_filters,
711 self.t = templater.templater(m, templater.common_filters,
712 defaults={"url": url,
712 defaults={"url": url,
713 "repo": self.reponame,
713 "repo": self.reponame,
714 "header": header,
714 "header": header,
715 "footer": footer,
715 "footer": footer,
716 })
716 })
717
717
718 if not req.form.has_key('cmd'):
718 if not req.form.has_key('cmd'):
719 req.form['cmd'] = [self.t.cache['default'],]
719 req.form['cmd'] = [self.t.cache['default'],]
720
720
721 cmd = req.form['cmd'][0]
721 cmd = req.form['cmd'][0]
722 if cmd == 'changelog':
723 hi = self.repo.changelog.count() - 1
724 if req.form.has_key('rev'):
725 hi = req.form['rev'][0]
726 try:
727 hi = self.repo.changelog.rev(self.repo.lookup(hi))
728 except hg.RepoError:
729 req.write(self.search(hi)) # XXX redirect to 404 page?
730 return
731
722
732 req.write(self.changelog(hi))
723 method = getattr(self, 'do_' + cmd, None)
733
724 if method:
734 elif cmd == 'changeset':
725 method(req)
735 req.write(self.changeset(req.form['node'][0]))
736
737 elif cmd == 'manifest':
738 req.write(self.manifest(req.form['manifest'][0],
739 clean(req.form['path'][0])))
740
741 elif cmd == 'tags':
742 req.write(self.tags())
743
744 elif cmd == 'summary':
745 req.write(self.summary())
746
747 elif cmd == 'filediff':
748 req.write(self.filediff(clean(req.form['file'][0]),
749 req.form['node'][0]))
750
751 elif cmd == 'file':
752 req.write(self.filerevision(clean(req.form['file'][0]),
753 req.form['filenode'][0]))
754
755 elif cmd == 'annotate':
756 req.write(self.fileannotate(clean(req.form['file'][0]),
757 req.form['filenode'][0]))
758
759 elif cmd == 'filelog':
760 req.write(self.filelog(clean(req.form['file'][0]),
761 req.form['filenode'][0]))
762
763 elif cmd == 'heads':
764 resp = " ".join(map(hex, self.repo.heads())) + "\n"
765 req.httphdr("application/mercurial-0.1", length=len(resp))
766 req.write(resp)
767
768 elif cmd == 'branches':
769 nodes = []
770 if req.form.has_key('nodes'):
771 nodes = map(bin, req.form['nodes'][0].split(" "))
772 resp = cStringIO.StringIO()
773 for b in self.repo.branches(nodes):
774 resp.write(" ".join(map(hex, b)) + "\n")
775 resp = resp.getvalue()
776 req.httphdr("application/mercurial-0.1", length=len(resp))
777 req.write(resp)
778
779 elif cmd == 'between':
780 nodes = []
781 if req.form.has_key('pairs'):
782 pairs = [map(bin, p.split("-"))
783 for p in req.form['pairs'][0].split(" ")]
784 resp = cStringIO.StringIO()
785 for b in self.repo.between(pairs):
786 resp.write(" ".join(map(hex, b)) + "\n")
787 resp = resp.getvalue()
788 req.httphdr("application/mercurial-0.1", length=len(resp))
789 req.write(resp)
790
791 elif cmd == 'changegroup':
792 req.httphdr("application/mercurial-0.1")
793 nodes = []
794 if not self.allowpull:
795 return
796
797 if req.form.has_key('roots'):
798 nodes = map(bin, req.form['roots'][0].split(" "))
799
800 z = zlib.compressobj()
801 f = self.repo.changegroup(nodes, 'serve')
802 while 1:
803 chunk = f.read(4096)
804 if not chunk:
805 break
806 req.write(z.compress(chunk))
807
808 req.write(z.flush())
809
810 elif cmd == 'archive':
811 changeset = self.repo.lookup(req.form['node'][0])
812 type_ = req.form['type'][0]
813 allowed = self.repo.ui.config("web", "allow_archive", "").split()
814 if (type_ in self.archives and (type_ in allowed or
815 self.repo.ui.configbool("web", "allow" + type_, False))):
816 self.archive(req, changeset, type_)
817 return
818
819 req.write(self.t("error"))
820
821 elif cmd == 'static':
822 fname = req.form['file'][0]
823 req.write(staticfile(static, fname)
824 or self.t("error", error="%r not found" % fname))
825
826 else:
726 else:
827 req.write(self.t("error"))
727 req.write(self.t("error"))
828 req.done()
728 req.done()
729
730 def do_changelog(self, req):
731 hi = self.repo.changelog.count() - 1
732 if req.form.has_key('rev'):
733 hi = req.form['rev'][0]
734 try:
735 hi = self.repo.changelog.rev(self.repo.lookup(hi))
736 except hg.RepoError:
737 req.write(self.search(hi)) # XXX redirect to 404 page?
738 return
739
740 req.write(self.changelog(hi))
741
742 def do_changeset(self, req):
743 req.write(self.changeset(req.form['node'][0]))
744
745 def do_manifest(self, req):
746 req.write(self.manifest(req.form['manifest'][0],
747 self.cleanpath(req.form['path'][0])))
748
749 def do_tags(self, req):
750 req.write(self.tags())
751
752 def do_summary(self, req):
753 req.write(self.summary())
754
755 def do_filediff(self, req):
756 req.write(self.filediff(self.cleanpath(req.form['file'][0]),
757 req.form['node'][0]))
758
759 def do_file(self, req):
760 req.write(self.filerevision(self.cleanpath(req.form['file'][0]),
761 req.form['filenode'][0]))
762
763 def do_annotate(self, req):
764 req.write(self.fileannotate(self.cleanpath(req.form['file'][0]),
765 req.form['filenode'][0]))
766
767 def do_filelog(self, req):
768 req.write(self.filelog(self.cleanpath(req.form['file'][0]),
769 req.form['filenode'][0]))
770
771 def do_heads(self, req):
772 resp = " ".join(map(hex, self.repo.heads())) + "\n"
773 req.httphdr("application/mercurial-0.1", length=len(resp))
774 req.write(resp)
775
776 def do_branches(self, req):
777 nodes = []
778 if req.form.has_key('nodes'):
779 nodes = map(bin, req.form['nodes'][0].split(" "))
780 resp = cStringIO.StringIO()
781 for b in self.repo.branches(nodes):
782 resp.write(" ".join(map(hex, b)) + "\n")
783 resp = resp.getvalue()
784 req.httphdr("application/mercurial-0.1", length=len(resp))
785 req.write(resp)
786
787 def do_between(self, req):
788 nodes = []
789 if req.form.has_key('pairs'):
790 pairs = [map(bin, p.split("-"))
791 for p in req.form['pairs'][0].split(" ")]
792 resp = cStringIO.StringIO()
793 for b in self.repo.between(pairs):
794 resp.write(" ".join(map(hex, b)) + "\n")
795 resp = resp.getvalue()
796 req.httphdr("application/mercurial-0.1", length=len(resp))
797 req.write(resp)
798
799 def do_changegroup(self, req):
800 req.httphdr("application/mercurial-0.1")
801 nodes = []
802 if not self.allowpull:
803 return
804
805 if req.form.has_key('roots'):
806 nodes = map(bin, req.form['roots'][0].split(" "))
807
808 z = zlib.compressobj()
809 f = self.repo.changegroup(nodes, 'serve')
810 while 1:
811 chunk = f.read(4096)
812 if not chunk:
813 break
814 req.write(z.compress(chunk))
815
816 req.write(z.flush())
817
818 def do_archive(self, req):
819 changeset = self.repo.lookup(req.form['node'][0])
820 type_ = req.form['type'][0]
821 allowed = self.repo.ui.config("web", "allow_archive", "").split()
822 if (type_ in self.archives and (type_ in allowed or
823 self.repo.ui.configbool("web", "allow" + type_, False))):
824 self.archive(req, changeset, type_)
825 return
826
827 req.write(self.t("error"))
828
829 def do_static(self, req):
830 fname = req.form['file'][0]
831 static = self.repo.ui.config("web", "static",
832 os.path.join(self.templatepath,
833 "static"))
834 req.write(staticfile(static, fname)
835 or self.t("error", error="%r not found" % fname))
General Comments 0
You need to be logged in to leave comments. Login now