##// END OF EJS Templates
[PATCH] Generate correctly XML entities for obfuscated user...
mpm@selenic.com -
r533:b8404005 default
parent child Browse files
Show More
@@ -1,719 +1,719 b''
1 # hgweb.py - web interface to a mercurial repository
1 # hgweb.py - web interface to a mercurial 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, cgi, time, re, difflib, sys, zlib
9 import os, cgi, time, re, difflib, sys, zlib
10 from mercurial.hg import *
10 from mercurial.hg import *
11 from mercurial.ui import *
11 from mercurial.ui import *
12
12
13 def templatepath():
13 def templatepath():
14 for f in "templates", "../templates":
14 for f in "templates", "../templates":
15 p = os.path.join(os.path.dirname(__file__), f)
15 p = os.path.join(os.path.dirname(__file__), f)
16 if os.path.isdir(p): return p
16 if os.path.isdir(p): return p
17
17
18 def age(t):
18 def age(t):
19 def plural(t, c):
19 def plural(t, c):
20 if c == 1: return t
20 if c == 1: return t
21 return t + "s"
21 return t + "s"
22 def fmt(t, c):
22 def fmt(t, c):
23 return "%d %s" % (c, plural(t, c))
23 return "%d %s" % (c, plural(t, c))
24
24
25 now = time.time()
25 now = time.time()
26 delta = max(1, int(now - t))
26 delta = max(1, int(now - t))
27
27
28 scales = [["second", 1],
28 scales = [["second", 1],
29 ["minute", 60],
29 ["minute", 60],
30 ["hour", 3600],
30 ["hour", 3600],
31 ["day", 3600 * 24],
31 ["day", 3600 * 24],
32 ["week", 3600 * 24 * 7],
32 ["week", 3600 * 24 * 7],
33 ["month", 3600 * 24 * 30],
33 ["month", 3600 * 24 * 30],
34 ["year", 3600 * 24 * 365]]
34 ["year", 3600 * 24 * 365]]
35
35
36 scales.reverse()
36 scales.reverse()
37
37
38 for t, s in scales:
38 for t, s in scales:
39 n = delta / s
39 n = delta / s
40 if n >= 2 or s == 1: return fmt(t, n)
40 if n >= 2 or s == 1: return fmt(t, n)
41
41
42 def nl2br(text):
42 def nl2br(text):
43 return text.replace('\n', '<br/>\n')
43 return text.replace('\n', '<br/>\n')
44
44
45 def obfuscate(text):
45 def obfuscate(text):
46 return ''.join([ '&#%d' % ord(c) for c in text ])
46 return ''.join([ '&#%d;' % ord(c) for c in text ])
47
47
48 def up(p):
48 def up(p):
49 if p[0] != "/": p = "/" + p
49 if p[0] != "/": p = "/" + p
50 if p[-1] == "/": p = p[:-1]
50 if p[-1] == "/": p = p[:-1]
51 up = os.path.dirname(p)
51 up = os.path.dirname(p)
52 if up == "/":
52 if up == "/":
53 return "/"
53 return "/"
54 return up + "/"
54 return up + "/"
55
55
56 def httphdr(type):
56 def httphdr(type):
57 print 'Content-type: %s\n' % type
57 print 'Content-type: %s\n' % type
58
58
59 def write(*things):
59 def write(*things):
60 for thing in things:
60 for thing in things:
61 if hasattr(thing, "__iter__"):
61 if hasattr(thing, "__iter__"):
62 for part in thing:
62 for part in thing:
63 write(part)
63 write(part)
64 else:
64 else:
65 sys.stdout.write(str(thing))
65 sys.stdout.write(str(thing))
66
66
67 def template(tmpl, filters = {}, **map):
67 def template(tmpl, filters = {}, **map):
68 while tmpl:
68 while tmpl:
69 m = re.search(r"#([a-zA-Z0-9]+)((\|[a-zA-Z0-9]+)*)#", tmpl)
69 m = re.search(r"#([a-zA-Z0-9]+)((\|[a-zA-Z0-9]+)*)#", tmpl)
70 if m:
70 if m:
71 yield tmpl[:m.start(0)]
71 yield tmpl[:m.start(0)]
72 v = map.get(m.group(1), "")
72 v = map.get(m.group(1), "")
73 v = callable(v) and v() or v
73 v = callable(v) and v() or v
74
74
75 fl = m.group(2)
75 fl = m.group(2)
76 if fl:
76 if fl:
77 for f in fl.split("|")[1:]:
77 for f in fl.split("|")[1:]:
78 v = filters[f](v)
78 v = filters[f](v)
79
79
80 yield v
80 yield v
81 tmpl = tmpl[m.end(0):]
81 tmpl = tmpl[m.end(0):]
82 else:
82 else:
83 yield tmpl
83 yield tmpl
84 return
84 return
85
85
86 class templater:
86 class templater:
87 def __init__(self, mapfile, filters = {}):
87 def __init__(self, mapfile, filters = {}):
88 self.cache = {}
88 self.cache = {}
89 self.map = {}
89 self.map = {}
90 self.base = os.path.dirname(mapfile)
90 self.base = os.path.dirname(mapfile)
91 self.filters = filters
91 self.filters = filters
92
92
93 for l in file(mapfile):
93 for l in file(mapfile):
94 m = re.match(r'(\S+)\s*=\s*"(.*)"$', l)
94 m = re.match(r'(\S+)\s*=\s*"(.*)"$', l)
95 if m:
95 if m:
96 self.cache[m.group(1)] = m.group(2)
96 self.cache[m.group(1)] = m.group(2)
97 else:
97 else:
98 m = re.match(r'(\S+)\s*=\s*(\S+)', l)
98 m = re.match(r'(\S+)\s*=\s*(\S+)', l)
99 if m:
99 if m:
100 self.map[m.group(1)] = os.path.join(self.base, m.group(2))
100 self.map[m.group(1)] = os.path.join(self.base, m.group(2))
101 else:
101 else:
102 raise "unknown map entry '%s'" % l
102 raise "unknown map entry '%s'" % l
103
103
104 def __call__(self, t, **map):
104 def __call__(self, t, **map):
105 try:
105 try:
106 tmpl = self.cache[t]
106 tmpl = self.cache[t]
107 except KeyError:
107 except KeyError:
108 tmpl = self.cache[t] = file(self.map[t]).read()
108 tmpl = self.cache[t] = file(self.map[t]).read()
109 return template(tmpl, self.filters, **map)
109 return template(tmpl, self.filters, **map)
110
110
111 class hgweb:
111 class hgweb:
112 maxchanges = 10
112 maxchanges = 10
113 maxfiles = 10
113 maxfiles = 10
114
114
115 def __init__(self, path, name, templates = ""):
115 def __init__(self, path, name, templates = ""):
116 self.templates = templates or templatepath()
116 self.templates = templates or templatepath()
117 self.reponame = name
117 self.reponame = name
118 self.path = path
118 self.path = path
119 self.mtime = -1
119 self.mtime = -1
120 self.viewonly = 0
120 self.viewonly = 0
121
121
122 self.filters = {
122 self.filters = {
123 "escape": cgi.escape,
123 "escape": cgi.escape,
124 "age": age,
124 "age": age,
125 "date": (lambda x: time.asctime(time.gmtime(x))),
125 "date": (lambda x: time.asctime(time.gmtime(x))),
126 "addbreaks": nl2br,
126 "addbreaks": nl2br,
127 "obfuscate": obfuscate,
127 "obfuscate": obfuscate,
128 "short": (lambda x: x[:12]),
128 "short": (lambda x: x[:12]),
129 "firstline": (lambda x: x.splitlines(1)[0]),
129 "firstline": (lambda x: x.splitlines(1)[0]),
130 "permissions": (lambda x: x and "-rwxr-xr-x" or "-rw-r--r--")
130 "permissions": (lambda x: x and "-rwxr-xr-x" or "-rw-r--r--")
131 }
131 }
132
132
133 def refresh(self):
133 def refresh(self):
134 s = os.stat(os.path.join(self.path, ".hg", "00changelog.i"))
134 s = os.stat(os.path.join(self.path, ".hg", "00changelog.i"))
135 if s.st_mtime != self.mtime:
135 if s.st_mtime != self.mtime:
136 self.mtime = s.st_mtime
136 self.mtime = s.st_mtime
137 self.repo = repository(ui(), self.path)
137 self.repo = repository(ui(), self.path)
138
138
139 def date(self, cs):
139 def date(self, cs):
140 return time.asctime(time.gmtime(float(cs[2].split(' ')[0])))
140 return time.asctime(time.gmtime(float(cs[2].split(' ')[0])))
141
141
142 def listfiles(self, files, mf):
142 def listfiles(self, files, mf):
143 for f in files[:self.maxfiles]:
143 for f in files[:self.maxfiles]:
144 yield self.t("filenodelink", node = hex(mf[f]), file = f)
144 yield self.t("filenodelink", node = hex(mf[f]), file = f)
145 if len(files) > self.maxfiles:
145 if len(files) > self.maxfiles:
146 yield self.t("fileellipses")
146 yield self.t("fileellipses")
147
147
148 def listfilediffs(self, files, changeset):
148 def listfilediffs(self, files, changeset):
149 for f in files[:self.maxfiles]:
149 for f in files[:self.maxfiles]:
150 yield self.t("filedifflink", node = hex(changeset), file = f)
150 yield self.t("filedifflink", node = hex(changeset), file = f)
151 if len(files) > self.maxfiles:
151 if len(files) > self.maxfiles:
152 yield self.t("fileellipses")
152 yield self.t("fileellipses")
153
153
154 def parent(self, t1, node=nullid, rev=-1, **args):
154 def parent(self, t1, node=nullid, rev=-1, **args):
155 if node != hex(nullid):
155 if node != hex(nullid):
156 yield self.t(t1, node = node, rev = rev, **args)
156 yield self.t(t1, node = node, rev = rev, **args)
157
157
158 def diff(self, node1, node2, files):
158 def diff(self, node1, node2, files):
159 def filterfiles(list, files):
159 def filterfiles(list, files):
160 l = [ x for x in list if x in files ]
160 l = [ x for x in list if x in files ]
161
161
162 for f in files:
162 for f in files:
163 if f[-1] != os.sep: f += os.sep
163 if f[-1] != os.sep: f += os.sep
164 l += [ x for x in list if x.startswith(f) ]
164 l += [ x for x in list if x.startswith(f) ]
165 return l
165 return l
166
166
167 parity = [0]
167 parity = [0]
168 def diffblock(diff, f, fn):
168 def diffblock(diff, f, fn):
169 yield self.t("diffblock",
169 yield self.t("diffblock",
170 lines = prettyprintlines(diff),
170 lines = prettyprintlines(diff),
171 parity = parity[0],
171 parity = parity[0],
172 file = f,
172 file = f,
173 filenode = hex(fn or nullid))
173 filenode = hex(fn or nullid))
174 parity[0] = 1 - parity[0]
174 parity[0] = 1 - parity[0]
175
175
176 def prettyprintlines(diff):
176 def prettyprintlines(diff):
177 for l in diff.splitlines(1):
177 for l in diff.splitlines(1):
178 if l.startswith('+'):
178 if l.startswith('+'):
179 yield self.t("difflineplus", line = l)
179 yield self.t("difflineplus", line = l)
180 elif l.startswith('-'):
180 elif l.startswith('-'):
181 yield self.t("difflineminus", line = l)
181 yield self.t("difflineminus", line = l)
182 elif l.startswith('@'):
182 elif l.startswith('@'):
183 yield self.t("difflineat", line = l)
183 yield self.t("difflineat", line = l)
184 else:
184 else:
185 yield self.t("diffline", line = l)
185 yield self.t("diffline", line = l)
186
186
187 r = self.repo
187 r = self.repo
188 cl = r.changelog
188 cl = r.changelog
189 mf = r.manifest
189 mf = r.manifest
190 change1 = cl.read(node1)
190 change1 = cl.read(node1)
191 change2 = cl.read(node2)
191 change2 = cl.read(node2)
192 mmap1 = mf.read(change1[0])
192 mmap1 = mf.read(change1[0])
193 mmap2 = mf.read(change2[0])
193 mmap2 = mf.read(change2[0])
194 date1 = self.date(change1)
194 date1 = self.date(change1)
195 date2 = self.date(change2)
195 date2 = self.date(change2)
196
196
197 c, a, d = r.diffrevs(node1, node2)
197 c, a, d = r.diffrevs(node1, node2)
198 c, a, d = map(lambda x: filterfiles(x, files), (c, a, d))
198 c, a, d = map(lambda x: filterfiles(x, files), (c, a, d))
199
199
200 for f in c:
200 for f in c:
201 to = r.file(f).read(mmap1[f])
201 to = r.file(f).read(mmap1[f])
202 tn = r.file(f).read(mmap2[f])
202 tn = r.file(f).read(mmap2[f])
203 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f), f, tn)
203 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f), f, tn)
204 for f in a:
204 for f in a:
205 to = None
205 to = None
206 tn = r.file(f).read(mmap2[f])
206 tn = r.file(f).read(mmap2[f])
207 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f), f, tn)
207 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f), f, tn)
208 for f in d:
208 for f in d:
209 to = r.file(f).read(mmap1[f])
209 to = r.file(f).read(mmap1[f])
210 tn = None
210 tn = None
211 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f), f, tn)
211 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f), f, tn)
212
212
213 def header(self):
213 def header(self):
214 yield self.t("header", repo = self.reponame)
214 yield self.t("header", repo = self.reponame)
215
215
216 def footer(self):
216 def footer(self):
217 yield self.t("footer", repo = self.reponame)
217 yield self.t("footer", repo = self.reponame)
218
218
219 def changelog(self, pos):
219 def changelog(self, pos):
220 def changenav():
220 def changenav():
221 def seq(factor = 1):
221 def seq(factor = 1):
222 yield 1 * factor
222 yield 1 * factor
223 yield 3 * factor
223 yield 3 * factor
224 #yield 5 * factor
224 #yield 5 * factor
225 for f in seq(factor * 10):
225 for f in seq(factor * 10):
226 yield f
226 yield f
227
227
228 l = []
228 l = []
229 for f in seq():
229 for f in seq():
230 if f < self.maxchanges / 2: continue
230 if f < self.maxchanges / 2: continue
231 if f > count: break
231 if f > count: break
232 r = "%d" % f
232 r = "%d" % f
233 if pos + f < count: l.append(("+" + r, pos + f))
233 if pos + f < count: l.append(("+" + r, pos + f))
234 if pos - f >= 0: l.insert(0, ("-" + r, pos - f))
234 if pos - f >= 0: l.insert(0, ("-" + r, pos - f))
235
235
236 yield self.t("naventry", rev = 0, label="(0)")
236 yield self.t("naventry", rev = 0, label="(0)")
237
237
238 for label, rev in l:
238 for label, rev in l:
239 yield self.t("naventry", label = label, rev = rev)
239 yield self.t("naventry", label = label, rev = rev)
240
240
241 yield self.t("naventry", label="tip")
241 yield self.t("naventry", label="tip")
242
242
243 def changelist():
243 def changelist():
244 parity = (start - end) & 1
244 parity = (start - end) & 1
245 cl = self.repo.changelog
245 cl = self.repo.changelog
246 l = [] # build a list in forward order for efficiency
246 l = [] # build a list in forward order for efficiency
247 for i in range(start, end):
247 for i in range(start, end):
248 n = cl.node(i)
248 n = cl.node(i)
249 changes = cl.read(n)
249 changes = cl.read(n)
250 hn = hex(n)
250 hn = hex(n)
251 p1, p2 = cl.parents(n)
251 p1, p2 = cl.parents(n)
252 t = float(changes[2].split(' ')[0])
252 t = float(changes[2].split(' ')[0])
253
253
254 l.insert(0, self.t(
254 l.insert(0, self.t(
255 'changelogentry',
255 'changelogentry',
256 parity = parity,
256 parity = parity,
257 author = changes[1],
257 author = changes[1],
258 parent1 = self.parent("changelogparent",
258 parent1 = self.parent("changelogparent",
259 hex(p1), cl.rev(p1)),
259 hex(p1), cl.rev(p1)),
260 parent2 = self.parent("changelogparent",
260 parent2 = self.parent("changelogparent",
261 hex(p2), cl.rev(p2)),
261 hex(p2), cl.rev(p2)),
262 p1 = hex(p1), p2 = hex(p2),
262 p1 = hex(p1), p2 = hex(p2),
263 p1rev = cl.rev(p1), p2rev = cl.rev(p2),
263 p1rev = cl.rev(p1), p2rev = cl.rev(p2),
264 manifest = hex(changes[0]),
264 manifest = hex(changes[0]),
265 desc = changes[4],
265 desc = changes[4],
266 date = t,
266 date = t,
267 files = self.listfilediffs(changes[3], n),
267 files = self.listfilediffs(changes[3], n),
268 rev = i,
268 rev = i,
269 node = hn))
269 node = hn))
270 parity = 1 - parity
270 parity = 1 - parity
271
271
272 yield l
272 yield l
273
273
274 cl = self.repo.changelog
274 cl = self.repo.changelog
275 mf = cl.read(cl.tip())[0]
275 mf = cl.read(cl.tip())[0]
276 count = cl.count()
276 count = cl.count()
277 start = max(0, pos - self.maxchanges + 1)
277 start = max(0, pos - self.maxchanges + 1)
278 end = min(count, start + self.maxchanges)
278 end = min(count, start + self.maxchanges)
279 pos = end - 1
279 pos = end - 1
280
280
281 yield self.t('changelog',
281 yield self.t('changelog',
282 header = self.header(),
282 header = self.header(),
283 footer = self.footer(),
283 footer = self.footer(),
284 repo = self.reponame,
284 repo = self.reponame,
285 changenav = changenav,
285 changenav = changenav,
286 manifest = hex(mf),
286 manifest = hex(mf),
287 rev = pos, changesets = count, entries = changelist)
287 rev = pos, changesets = count, entries = changelist)
288
288
289 def changeset(self, nodeid):
289 def changeset(self, nodeid):
290 n = bin(nodeid)
290 n = bin(nodeid)
291 cl = self.repo.changelog
291 cl = self.repo.changelog
292 changes = cl.read(n)
292 changes = cl.read(n)
293 p1, p2 = cl.parents(n)
293 p1, p2 = cl.parents(n)
294 p1rev, p2rev = cl.rev(p1), cl.rev(p2)
294 p1rev, p2rev = cl.rev(p1), cl.rev(p2)
295 t = float(changes[2].split(' ')[0])
295 t = float(changes[2].split(' ')[0])
296
296
297 files = []
297 files = []
298 mf = self.repo.manifest.read(changes[0])
298 mf = self.repo.manifest.read(changes[0])
299 for f in changes[3]:
299 for f in changes[3]:
300 files.append(self.t("filenodelink",
300 files.append(self.t("filenodelink",
301 filenode = hex(mf.get(f, nullid)), file = f))
301 filenode = hex(mf.get(f, nullid)), file = f))
302
302
303 def diff():
303 def diff():
304 yield self.diff(p1, n, changes[3])
304 yield self.diff(p1, n, changes[3])
305
305
306 yield self.t('changeset',
306 yield self.t('changeset',
307 header = self.header(),
307 header = self.header(),
308 footer = self.footer(),
308 footer = self.footer(),
309 repo = self.reponame,
309 repo = self.reponame,
310 diff = diff,
310 diff = diff,
311 rev = cl.rev(n),
311 rev = cl.rev(n),
312 node = nodeid,
312 node = nodeid,
313 parent1 = self.parent("changesetparent",
313 parent1 = self.parent("changesetparent",
314 hex(p1), cl.rev(p1)),
314 hex(p1), cl.rev(p1)),
315 parent2 = self.parent("changesetparent",
315 parent2 = self.parent("changesetparent",
316 hex(p2), cl.rev(p2)),
316 hex(p2), cl.rev(p2)),
317 p1 = hex(p1), p2 = hex(p2),
317 p1 = hex(p1), p2 = hex(p2),
318 p1rev = cl.rev(p1), p2rev = cl.rev(p2),
318 p1rev = cl.rev(p1), p2rev = cl.rev(p2),
319 manifest = hex(changes[0]),
319 manifest = hex(changes[0]),
320 author = changes[1],
320 author = changes[1],
321 desc = changes[4],
321 desc = changes[4],
322 date = t,
322 date = t,
323 files = files)
323 files = files)
324
324
325 def filelog(self, f, filenode):
325 def filelog(self, f, filenode):
326 cl = self.repo.changelog
326 cl = self.repo.changelog
327 fl = self.repo.file(f)
327 fl = self.repo.file(f)
328 count = fl.count()
328 count = fl.count()
329
329
330 def entries():
330 def entries():
331 l = []
331 l = []
332 parity = (count - 1) & 1
332 parity = (count - 1) & 1
333
333
334 for i in range(count):
334 for i in range(count):
335
335
336 n = fl.node(i)
336 n = fl.node(i)
337 lr = fl.linkrev(n)
337 lr = fl.linkrev(n)
338 cn = cl.node(lr)
338 cn = cl.node(lr)
339 cs = cl.read(cl.node(lr))
339 cs = cl.read(cl.node(lr))
340 p1, p2 = fl.parents(n)
340 p1, p2 = fl.parents(n)
341 t = float(cs[2].split(' ')[0])
341 t = float(cs[2].split(' ')[0])
342
342
343 l.insert(0, self.t("filelogentry",
343 l.insert(0, self.t("filelogentry",
344 parity = parity,
344 parity = parity,
345 filenode = hex(n),
345 filenode = hex(n),
346 filerev = i,
346 filerev = i,
347 file = f,
347 file = f,
348 node = hex(cn),
348 node = hex(cn),
349 author = cs[1],
349 author = cs[1],
350 date = t,
350 date = t,
351 desc = cs[4],
351 desc = cs[4],
352 p1 = hex(p1), p2 = hex(p2),
352 p1 = hex(p1), p2 = hex(p2),
353 p1rev = fl.rev(p1), p2rev = fl.rev(p2)))
353 p1rev = fl.rev(p1), p2rev = fl.rev(p2)))
354 parity = 1 - parity
354 parity = 1 - parity
355
355
356 yield l
356 yield l
357
357
358 yield self.t("filelog",
358 yield self.t("filelog",
359 header = self.header(),
359 header = self.header(),
360 footer = self.footer(),
360 footer = self.footer(),
361 repo = self.reponame,
361 repo = self.reponame,
362 file = f,
362 file = f,
363 filenode = filenode,
363 filenode = filenode,
364 entries = entries)
364 entries = entries)
365
365
366 def filerevision(self, f, node):
366 def filerevision(self, f, node):
367 fl = self.repo.file(f)
367 fl = self.repo.file(f)
368 n = bin(node)
368 n = bin(node)
369 text = fl.read(n)
369 text = fl.read(n)
370 changerev = fl.linkrev(n)
370 changerev = fl.linkrev(n)
371 cl = self.repo.changelog
371 cl = self.repo.changelog
372 cn = cl.node(changerev)
372 cn = cl.node(changerev)
373 cs = cl.read(cn)
373 cs = cl.read(cn)
374 p1, p2 = fl.parents(n)
374 p1, p2 = fl.parents(n)
375 t = float(cs[2].split(' ')[0])
375 t = float(cs[2].split(' ')[0])
376 mfn = cs[0]
376 mfn = cs[0]
377
377
378 def lines():
378 def lines():
379 for l, t in enumerate(text.splitlines(1)):
379 for l, t in enumerate(text.splitlines(1)):
380 yield self.t("fileline", line = t,
380 yield self.t("fileline", line = t,
381 linenumber = "% 6d" % (l + 1),
381 linenumber = "% 6d" % (l + 1),
382 parity = l & 1)
382 parity = l & 1)
383
383
384 yield self.t("filerevision", file = f,
384 yield self.t("filerevision", file = f,
385 header = self.header(),
385 header = self.header(),
386 footer = self.footer(),
386 footer = self.footer(),
387 repo = self.reponame,
387 repo = self.reponame,
388 filenode = node,
388 filenode = node,
389 path = up(f),
389 path = up(f),
390 text = lines(),
390 text = lines(),
391 rev = changerev,
391 rev = changerev,
392 node = hex(cn),
392 node = hex(cn),
393 manifest = hex(mfn),
393 manifest = hex(mfn),
394 author = cs[1],
394 author = cs[1],
395 date = t,
395 date = t,
396 parent1 = self.parent("filerevparent",
396 parent1 = self.parent("filerevparent",
397 hex(p1), fl.rev(p1), file=f),
397 hex(p1), fl.rev(p1), file=f),
398 parent2 = self.parent("filerevparent",
398 parent2 = self.parent("filerevparent",
399 hex(p2), fl.rev(p2), file=f),
399 hex(p2), fl.rev(p2), file=f),
400 p1 = hex(p1), p2 = hex(p2),
400 p1 = hex(p1), p2 = hex(p2),
401 permissions = self.repo.manifest.readflags(mfn)[f],
401 permissions = self.repo.manifest.readflags(mfn)[f],
402 p1rev = fl.rev(p1), p2rev = fl.rev(p2))
402 p1rev = fl.rev(p1), p2rev = fl.rev(p2))
403
403
404 def fileannotate(self, f, node):
404 def fileannotate(self, f, node):
405 bcache = {}
405 bcache = {}
406 ncache = {}
406 ncache = {}
407 fl = self.repo.file(f)
407 fl = self.repo.file(f)
408 n = bin(node)
408 n = bin(node)
409 changerev = fl.linkrev(n)
409 changerev = fl.linkrev(n)
410
410
411 cl = self.repo.changelog
411 cl = self.repo.changelog
412 cn = cl.node(changerev)
412 cn = cl.node(changerev)
413 cs = cl.read(cn)
413 cs = cl.read(cn)
414 p1, p2 = fl.parents(n)
414 p1, p2 = fl.parents(n)
415 t = float(cs[2].split(' ')[0])
415 t = float(cs[2].split(' ')[0])
416 mfn = cs[0]
416 mfn = cs[0]
417
417
418 def annotate():
418 def annotate():
419 parity = 1
419 parity = 1
420 last = None
420 last = None
421 for r, l in fl.annotate(n):
421 for r, l in fl.annotate(n):
422 try:
422 try:
423 cnode = ncache[r]
423 cnode = ncache[r]
424 except KeyError:
424 except KeyError:
425 cnode = ncache[r] = self.repo.changelog.node(r)
425 cnode = ncache[r] = self.repo.changelog.node(r)
426
426
427 try:
427 try:
428 name = bcache[r]
428 name = bcache[r]
429 except KeyError:
429 except KeyError:
430 cl = self.repo.changelog.read(cnode)
430 cl = self.repo.changelog.read(cnode)
431 name = cl[1]
431 name = cl[1]
432 f = name.find('@')
432 f = name.find('@')
433 if f >= 0:
433 if f >= 0:
434 name = name[:f]
434 name = name[:f]
435 bcache[r] = name
435 bcache[r] = name
436
436
437 if last != cnode:
437 if last != cnode:
438 parity = 1 - parity
438 parity = 1 - parity
439 last = cnode
439 last = cnode
440
440
441 yield self.t("annotateline",
441 yield self.t("annotateline",
442 parity = parity,
442 parity = parity,
443 node = hex(cnode),
443 node = hex(cnode),
444 rev = r,
444 rev = r,
445 author = name,
445 author = name,
446 file = f,
446 file = f,
447 line = l)
447 line = l)
448
448
449 yield self.t("fileannotate",
449 yield self.t("fileannotate",
450 header = self.header(),
450 header = self.header(),
451 footer = self.footer(),
451 footer = self.footer(),
452 repo = self.reponame,
452 repo = self.reponame,
453 file = f,
453 file = f,
454 filenode = node,
454 filenode = node,
455 annotate = annotate,
455 annotate = annotate,
456 path = up(f),
456 path = up(f),
457 rev = changerev,
457 rev = changerev,
458 node = hex(cn),
458 node = hex(cn),
459 manifest = hex(mfn),
459 manifest = hex(mfn),
460 author = cs[1],
460 author = cs[1],
461 date = t,
461 date = t,
462 parent1 = self.parent("fileannotateparent",
462 parent1 = self.parent("fileannotateparent",
463 hex(p1), fl.rev(p1), file=f),
463 hex(p1), fl.rev(p1), file=f),
464 parent2 = self.parent("fileannotateparent",
464 parent2 = self.parent("fileannotateparent",
465 hex(p2), fl.rev(p2), file=f),
465 hex(p2), fl.rev(p2), file=f),
466 p1 = hex(p1), p2 = hex(p2),
466 p1 = hex(p1), p2 = hex(p2),
467 permissions = self.repo.manifest.readflags(mfn)[f],
467 permissions = self.repo.manifest.readflags(mfn)[f],
468 p1rev = fl.rev(p1), p2rev = fl.rev(p2))
468 p1rev = fl.rev(p1), p2rev = fl.rev(p2))
469
469
470 def manifest(self, mnode, path):
470 def manifest(self, mnode, path):
471 mf = self.repo.manifest.read(bin(mnode))
471 mf = self.repo.manifest.read(bin(mnode))
472 rev = self.repo.manifest.rev(bin(mnode))
472 rev = self.repo.manifest.rev(bin(mnode))
473 node = self.repo.changelog.node(rev)
473 node = self.repo.changelog.node(rev)
474 mff=self.repo.manifest.readflags(bin(mnode))
474 mff=self.repo.manifest.readflags(bin(mnode))
475
475
476 files = {}
476 files = {}
477
477
478 p = path[1:]
478 p = path[1:]
479 l = len(p)
479 l = len(p)
480
480
481 for f,n in mf.items():
481 for f,n in mf.items():
482 if f[:l] != p:
482 if f[:l] != p:
483 continue
483 continue
484 remain = f[l:]
484 remain = f[l:]
485 if "/" in remain:
485 if "/" in remain:
486 short = remain[:remain.find("/") + 1] # bleah
486 short = remain[:remain.find("/") + 1] # bleah
487 files[short] = (f, None)
487 files[short] = (f, None)
488 else:
488 else:
489 short = os.path.basename(remain)
489 short = os.path.basename(remain)
490 files[short] = (f, n)
490 files[short] = (f, n)
491
491
492 def filelist():
492 def filelist():
493 parity = 0
493 parity = 0
494 fl = files.keys()
494 fl = files.keys()
495 fl.sort()
495 fl.sort()
496 for f in fl:
496 for f in fl:
497 full, fnode = files[f]
497 full, fnode = files[f]
498 if fnode:
498 if fnode:
499 yield self.t("manifestfileentry",
499 yield self.t("manifestfileentry",
500 file = full,
500 file = full,
501 manifest = mnode,
501 manifest = mnode,
502 filenode = hex(fnode),
502 filenode = hex(fnode),
503 parity = parity,
503 parity = parity,
504 basename = f,
504 basename = f,
505 permissions = mff[full])
505 permissions = mff[full])
506 else:
506 else:
507 yield self.t("manifestdirentry",
507 yield self.t("manifestdirentry",
508 parity = parity,
508 parity = parity,
509 path = os.path.join(path, f),
509 path = os.path.join(path, f),
510 manifest = mnode, basename = f[:-1])
510 manifest = mnode, basename = f[:-1])
511 parity = 1 - parity
511 parity = 1 - parity
512
512
513 yield self.t("manifest",
513 yield self.t("manifest",
514 header = self.header(),
514 header = self.header(),
515 footer = self.footer(),
515 footer = self.footer(),
516 repo = self.reponame,
516 repo = self.reponame,
517 manifest = mnode,
517 manifest = mnode,
518 rev = rev,
518 rev = rev,
519 node = hex(node),
519 node = hex(node),
520 path = path,
520 path = path,
521 up = up(path),
521 up = up(path),
522 entries = filelist)
522 entries = filelist)
523
523
524 def tags(self):
524 def tags(self):
525 cl = self.repo.changelog
525 cl = self.repo.changelog
526 mf = cl.read(cl.tip())[0]
526 mf = cl.read(cl.tip())[0]
527
527
528 i = self.repo.tagslist()
528 i = self.repo.tagslist()
529 i.reverse()
529 i.reverse()
530
530
531 def entries():
531 def entries():
532 parity = 0
532 parity = 0
533 for k,n in i:
533 for k,n in i:
534 yield self.t("tagentry",
534 yield self.t("tagentry",
535 parity = parity,
535 parity = parity,
536 tag = k,
536 tag = k,
537 node = hex(n))
537 node = hex(n))
538 parity = 1 - parity
538 parity = 1 - parity
539
539
540 yield self.t("tags",
540 yield self.t("tags",
541 header = self.header(),
541 header = self.header(),
542 footer = self.footer(),
542 footer = self.footer(),
543 repo = self.reponame,
543 repo = self.reponame,
544 manifest = hex(mf),
544 manifest = hex(mf),
545 entries = entries)
545 entries = entries)
546
546
547 def filediff(self, file, changeset):
547 def filediff(self, file, changeset):
548 n = bin(changeset)
548 n = bin(changeset)
549 cl = self.repo.changelog
549 cl = self.repo.changelog
550 p1 = cl.parents(n)[0]
550 p1 = cl.parents(n)[0]
551 cs = cl.read(n)
551 cs = cl.read(n)
552 mf = self.repo.manifest.read(cs[0])
552 mf = self.repo.manifest.read(cs[0])
553
553
554 def diff():
554 def diff():
555 yield self.diff(p1, n, file)
555 yield self.diff(p1, n, file)
556
556
557 yield self.t("filediff",
557 yield self.t("filediff",
558 header = self.header(),
558 header = self.header(),
559 footer = self.footer(),
559 footer = self.footer(),
560 repo = self.reponame,
560 repo = self.reponame,
561 file = file,
561 file = file,
562 filenode = hex(mf.get(file, nullid)),
562 filenode = hex(mf.get(file, nullid)),
563 node = changeset,
563 node = changeset,
564 rev = self.repo.changelog.rev(n),
564 rev = self.repo.changelog.rev(n),
565 p1 = hex(p1),
565 p1 = hex(p1),
566 p1rev = self.repo.changelog.rev(p1),
566 p1rev = self.repo.changelog.rev(p1),
567 diff = diff)
567 diff = diff)
568
568
569 # add tags to things
569 # add tags to things
570 # tags -> list of changesets corresponding to tags
570 # tags -> list of changesets corresponding to tags
571 # find tag, changeset, file
571 # find tag, changeset, file
572
572
573 def run(self):
573 def run(self):
574 self.refresh()
574 self.refresh()
575 args = cgi.parse()
575 args = cgi.parse()
576
576
577 m = os.path.join(self.templates, "map")
577 m = os.path.join(self.templates, "map")
578 if args.has_key('style'):
578 if args.has_key('style'):
579 b = os.path.basename("map-" + args['style'][0])
579 b = os.path.basename("map-" + args['style'][0])
580 p = os.path.join(self.templates, b)
580 p = os.path.join(self.templates, b)
581 if os.path.isfile(p): m = p
581 if os.path.isfile(p): m = p
582
582
583 self.t = templater(m, self.filters)
583 self.t = templater(m, self.filters)
584
584
585 if not args.has_key('cmd') or args['cmd'][0] == 'changelog':
585 if not args.has_key('cmd') or args['cmd'][0] == 'changelog':
586 hi = self.repo.changelog.count() - 1
586 hi = self.repo.changelog.count() - 1
587 if args.has_key('rev'):
587 if args.has_key('rev'):
588 hi = args['rev'][0]
588 hi = args['rev'][0]
589 try:
589 try:
590 hi = self.repo.changelog.rev(self.repo.lookup(hi))
590 hi = self.repo.changelog.rev(self.repo.lookup(hi))
591 except KeyError: pass
591 except KeyError: pass
592
592
593 write(self.changelog(hi))
593 write(self.changelog(hi))
594
594
595 elif args['cmd'][0] == 'changeset':
595 elif args['cmd'][0] == 'changeset':
596 write(self.changeset(args['node'][0]))
596 write(self.changeset(args['node'][0]))
597
597
598 elif args['cmd'][0] == 'manifest':
598 elif args['cmd'][0] == 'manifest':
599 write(self.manifest(args['manifest'][0], args['path'][0]))
599 write(self.manifest(args['manifest'][0], args['path'][0]))
600
600
601 elif args['cmd'][0] == 'tags':
601 elif args['cmd'][0] == 'tags':
602 write(self.tags())
602 write(self.tags())
603
603
604 elif args['cmd'][0] == 'filediff':
604 elif args['cmd'][0] == 'filediff':
605 write(self.filediff(args['file'][0], args['node'][0]))
605 write(self.filediff(args['file'][0], args['node'][0]))
606
606
607 elif args['cmd'][0] == 'file':
607 elif args['cmd'][0] == 'file':
608 write(self.filerevision(args['file'][0], args['filenode'][0]))
608 write(self.filerevision(args['file'][0], args['filenode'][0]))
609
609
610 elif args['cmd'][0] == 'annotate':
610 elif args['cmd'][0] == 'annotate':
611 write(self.fileannotate(args['file'][0], args['filenode'][0]))
611 write(self.fileannotate(args['file'][0], args['filenode'][0]))
612
612
613 elif args['cmd'][0] == 'filelog':
613 elif args['cmd'][0] == 'filelog':
614 write(self.filelog(args['file'][0], args['filenode'][0]))
614 write(self.filelog(args['file'][0], args['filenode'][0]))
615
615
616 elif args['cmd'][0] == 'heads':
616 elif args['cmd'][0] == 'heads':
617 httphdr("text/plain")
617 httphdr("text/plain")
618 h = self.repo.heads()
618 h = self.repo.heads()
619 sys.stdout.write(" ".join(map(hex, h)) + "\n")
619 sys.stdout.write(" ".join(map(hex, h)) + "\n")
620
620
621 elif args['cmd'][0] == 'branches':
621 elif args['cmd'][0] == 'branches':
622 httphdr("text/plain")
622 httphdr("text/plain")
623 nodes = []
623 nodes = []
624 if args.has_key('nodes'):
624 if args.has_key('nodes'):
625 nodes = map(bin, args['nodes'][0].split(" "))
625 nodes = map(bin, args['nodes'][0].split(" "))
626 for b in self.repo.branches(nodes):
626 for b in self.repo.branches(nodes):
627 sys.stdout.write(" ".join(map(hex, b)) + "\n")
627 sys.stdout.write(" ".join(map(hex, b)) + "\n")
628
628
629 elif args['cmd'][0] == 'between':
629 elif args['cmd'][0] == 'between':
630 httphdr("text/plain")
630 httphdr("text/plain")
631 nodes = []
631 nodes = []
632 if args.has_key('pairs'):
632 if args.has_key('pairs'):
633 pairs = [ map(bin, p.split("-"))
633 pairs = [ map(bin, p.split("-"))
634 for p in args['pairs'][0].split(" ") ]
634 for p in args['pairs'][0].split(" ") ]
635 for b in self.repo.between(pairs):
635 for b in self.repo.between(pairs):
636 sys.stdout.write(" ".join(map(hex, b)) + "\n")
636 sys.stdout.write(" ".join(map(hex, b)) + "\n")
637
637
638 elif args['cmd'][0] == 'changegroup':
638 elif args['cmd'][0] == 'changegroup':
639 httphdr("application/hg-changegroup")
639 httphdr("application/hg-changegroup")
640 nodes = []
640 nodes = []
641 if self.viewonly:
641 if self.viewonly:
642 return
642 return
643
643
644 if args.has_key('roots'):
644 if args.has_key('roots'):
645 nodes = map(bin, args['roots'][0].split(" "))
645 nodes = map(bin, args['roots'][0].split(" "))
646
646
647 z = zlib.compressobj()
647 z = zlib.compressobj()
648 for chunk in self.repo.changegroup(nodes):
648 for chunk in self.repo.changegroup(nodes):
649 sys.stdout.write(z.compress(chunk))
649 sys.stdout.write(z.compress(chunk))
650
650
651 sys.stdout.write(z.flush())
651 sys.stdout.write(z.flush())
652
652
653 else:
653 else:
654 write(self.t("error"))
654 write(self.t("error"))
655
655
656 def server(path, name, templates, address, port):
656 def server(path, name, templates, address, port):
657
657
658 import BaseHTTPServer
658 import BaseHTTPServer
659 import sys, os
659 import sys, os
660
660
661 class hgwebhandler(BaseHTTPServer.BaseHTTPRequestHandler):
661 class hgwebhandler(BaseHTTPServer.BaseHTTPRequestHandler):
662 def do_POST(self):
662 def do_POST(self):
663 try:
663 try:
664 self.do_hgweb()
664 self.do_hgweb()
665 except socket.error, inst:
665 except socket.error, inst:
666 if inst.args[0] != 32: raise
666 if inst.args[0] != 32: raise
667
667
668 def do_GET(self):
668 def do_GET(self):
669 self.do_POST()
669 self.do_POST()
670
670
671 def do_hgweb(self):
671 def do_hgweb(self):
672 query = ""
672 query = ""
673 p = self.path.find("?")
673 p = self.path.find("?")
674 if p:
674 if p:
675 query = self.path[p + 1:]
675 query = self.path[p + 1:]
676 query = query.replace('+', ' ')
676 query = query.replace('+', ' ')
677
677
678 env = {}
678 env = {}
679 env['GATEWAY_INTERFACE'] = 'CGI/1.1'
679 env['GATEWAY_INTERFACE'] = 'CGI/1.1'
680 env['REQUEST_METHOD'] = self.command
680 env['REQUEST_METHOD'] = self.command
681 if query:
681 if query:
682 env['QUERY_STRING'] = query
682 env['QUERY_STRING'] = query
683 host = self.address_string()
683 host = self.address_string()
684 if host != self.client_address[0]:
684 if host != self.client_address[0]:
685 env['REMOTE_HOST'] = host
685 env['REMOTE_HOST'] = host
686 env['REMOTE_ADDR'] = self.client_address[0]
686 env['REMOTE_ADDR'] = self.client_address[0]
687
687
688 if self.headers.typeheader is None:
688 if self.headers.typeheader is None:
689 env['CONTENT_TYPE'] = self.headers.type
689 env['CONTENT_TYPE'] = self.headers.type
690 else:
690 else:
691 env['CONTENT_TYPE'] = self.headers.typeheader
691 env['CONTENT_TYPE'] = self.headers.typeheader
692 length = self.headers.getheader('content-length')
692 length = self.headers.getheader('content-length')
693 if length:
693 if length:
694 env['CONTENT_LENGTH'] = length
694 env['CONTENT_LENGTH'] = length
695 accept = []
695 accept = []
696 for line in self.headers.getallmatchingheaders('accept'):
696 for line in self.headers.getallmatchingheaders('accept'):
697 if line[:1] in "\t\n\r ":
697 if line[:1] in "\t\n\r ":
698 accept.append(line.strip())
698 accept.append(line.strip())
699 else:
699 else:
700 accept = accept + line[7:].split(',')
700 accept = accept + line[7:].split(',')
701 env['HTTP_ACCEPT'] = ','.join(accept)
701 env['HTTP_ACCEPT'] = ','.join(accept)
702
702
703 os.environ.update(env)
703 os.environ.update(env)
704
704
705 save = sys.argv, sys.stdin, sys.stdout, sys.stderr
705 save = sys.argv, sys.stdin, sys.stdout, sys.stderr
706 try:
706 try:
707 sys.stdin = self.rfile
707 sys.stdin = self.rfile
708 sys.stdout = self.wfile
708 sys.stdout = self.wfile
709 sys.argv = ["hgweb.py"]
709 sys.argv = ["hgweb.py"]
710 if '=' not in query:
710 if '=' not in query:
711 sys.argv.append(query)
711 sys.argv.append(query)
712 self.send_response(200, "Script output follows")
712 self.send_response(200, "Script output follows")
713 hg.run()
713 hg.run()
714 finally:
714 finally:
715 sys.argv, sys.stdin, sys.stdout, sys.stderr = save
715 sys.argv, sys.stdin, sys.stdout, sys.stderr = save
716
716
717 hg = hgweb(path, name, templates)
717 hg = hgweb(path, name, templates)
718 httpd = BaseHTTPServer.HTTPServer((address, port), hgwebhandler)
718 httpd = BaseHTTPServer.HTTPServer((address, port), hgwebhandler)
719 httpd.serve_forever()
719 httpd.serve_forever()
General Comments 0
You need to be logged in to leave comments. Login now