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