##// END OF EJS Templates
Install the templates where they can be found by hgweb.py...
mpm@selenic.com -
r157:2653740d default
parent child Browse files
Show More
@@ -1,575 +1,582
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 #
2 #
3 # hgweb.py - 0.2 - 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 # hgweb.py - 0.2 - 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
4 # - web interface to a mercurial repository
4 # - web interface to a mercurial repository
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
15
16 def templatepath():
17 for f in "templates/map", "../templates/map":
18 p = os.path.join(os.path.dirname(__file__), f)
19 if os.path.isfile(p): return p
20
16 def age(t):
21 def age(t):
17 def plural(t, c):
22 def plural(t, c):
18 if c == 1: return t
23 if c == 1: return t
19 return t + "s"
24 return t + "s"
20 def fmt(t, c):
25 def fmt(t, c):
21 return "%d %s" % (c, plural(t, c))
26 return "%d %s" % (c, plural(t, c))
22
27
23 now = time.time()
28 now = time.time()
24 delta = max(1, int(now - t))
29 delta = max(1, int(now - t))
25
30
26 scales = [["second", 1],
31 scales = [["second", 1],
27 ["minute", 60],
32 ["minute", 60],
28 ["hour", 3600],
33 ["hour", 3600],
29 ["day", 3600 * 24],
34 ["day", 3600 * 24],
30 ["week", 3600 * 24 * 7],
35 ["week", 3600 * 24 * 7],
31 ["month", 3600 * 24 * 30],
36 ["month", 3600 * 24 * 30],
32 ["year", 3600 * 24 * 365]]
37 ["year", 3600 * 24 * 365]]
33
38
34 scales.reverse()
39 scales.reverse()
35
40
36 for t, s in scales:
41 for t, s in scales:
37 n = delta / s
42 n = delta / s
38 if n >= 1: return fmt(t, n)
43 if n >= 1: return fmt(t, n)
39
44
40 def nl2br(text):
45 def nl2br(text):
41 return text.replace('\n', '<br/>')
46 return text.replace('\n', '<br/>')
42
47
43 def obfuscate(text):
48 def obfuscate(text):
44 return ''.join([ '&#%d' % ord(c) for c in text ])
49 return ''.join([ '&#%d' % ord(c) for c in text ])
45
50
46 def up(p):
51 def up(p):
47 if p[0] != "/": p = "/" + p
52 if p[0] != "/": p = "/" + p
48 if p[-1] == "/": p = p[:-1]
53 if p[-1] == "/": p = p[:-1]
49 up = os.path.dirname(p)
54 up = os.path.dirname(p)
50 if up == "/":
55 if up == "/":
51 return "/"
56 return "/"
52 return up + "/"
57 return up + "/"
53
58
54 def httphdr(type):
59 def httphdr(type):
55 print 'Content-type: %s\n' % type
60 print 'Content-type: %s\n' % type
56
61
57 def write(*things):
62 def write(*things):
58 for thing in things:
63 for thing in things:
59 if hasattr(thing, "__iter__"):
64 if hasattr(thing, "__iter__"):
60 for part in thing:
65 for part in thing:
61 write(part)
66 write(part)
62 else:
67 else:
63 sys.stdout.write(str(thing))
68 sys.stdout.write(str(thing))
64
69
65 def template(tmpl, **map):
70 def template(tmpl, **map):
66 while tmpl:
71 while tmpl:
67 m = re.search(r"#([a-zA-Z0-9]+)#", tmpl)
72 m = re.search(r"#([a-zA-Z0-9]+)#", tmpl)
68 if m:
73 if m:
69 yield tmpl[:m.start(0)]
74 yield tmpl[:m.start(0)]
70 v = map.get(m.group(1), "")
75 v = map.get(m.group(1), "")
71 yield callable(v) and v() or v
76 yield callable(v) and v() or v
72 tmpl = tmpl[m.end(0):]
77 tmpl = tmpl[m.end(0):]
73 else:
78 else:
74 yield tmpl
79 yield tmpl
75 return
80 return
76
81
77 class templater:
82 class templater:
78 def __init__(self, mapfile):
83 def __init__(self, mapfile):
79 self.cache = {}
84 self.cache = {}
80 self.map = {}
85 self.map = {}
81 self.base = os.path.dirname(mapfile)
86 self.base = os.path.dirname(mapfile)
82
87
83 for l in file(mapfile):
88 for l in file(mapfile):
84 m = re.match(r'(\S+)\s*=\s*"(.*)"$', l)
89 m = re.match(r'(\S+)\s*=\s*"(.*)"$', l)
85 if m:
90 if m:
86 self.cache[m.group(1)] = m.group(2)
91 self.cache[m.group(1)] = m.group(2)
87 else:
92 else:
88 m = re.match(r'(\S+)\s*=\s*(\S+)', l)
93 m = re.match(r'(\S+)\s*=\s*(\S+)', l)
89 if m:
94 if m:
90 self.map[m.group(1)] = os.path.join(self.base, m.group(2))
95 self.map[m.group(1)] = os.path.join(self.base, m.group(2))
91 else:
96 else:
92 raise "unknown map entry '%s'" % l
97 raise "unknown map entry '%s'" % l
93
98
94 def __call__(self, t, **map):
99 def __call__(self, t, **map):
95 try:
100 try:
96 tmpl = self.cache[t]
101 tmpl = self.cache[t]
97 except KeyError:
102 except KeyError:
98 tmpl = self.cache[t] = file(self.map[t]).read()
103 tmpl = self.cache[t] = file(self.map[t]).read()
99 return template(tmpl, **map)
104 return template(tmpl, **map)
100
105
101 class hgweb:
106 class hgweb:
102 maxchanges = 20
107 maxchanges = 20
103 maxfiles = 10
108 maxfiles = 10
104
109
105 def __init__(self, path, name, templatemap):
110 def __init__(self, path, name, templatemap = ""):
111 templatemap = templatemap or templatepath()
112
106 self.reponame = name
113 self.reponame = name
107 self.repo = repository(ui(), path)
114 self.repo = repository(ui(), path)
108 self.t = templater(templatemap)
115 self.t = templater(templatemap)
109
116
110 def date(self, cs):
117 def date(self, cs):
111 return time.asctime(time.gmtime(float(cs[2].split(' ')[0])))
118 return time.asctime(time.gmtime(float(cs[2].split(' ')[0])))
112
119
113 def listfiles(self, files, mf):
120 def listfiles(self, files, mf):
114 for f in files[:self.maxfiles]:
121 for f in files[:self.maxfiles]:
115 yield self.t("filenodelink", node = hex(mf[f]), file = f)
122 yield self.t("filenodelink", node = hex(mf[f]), file = f)
116 if len(files) > self.maxfiles:
123 if len(files) > self.maxfiles:
117 yield self.t("fileellipses")
124 yield self.t("fileellipses")
118
125
119 def listfilediffs(self, files, changeset):
126 def listfilediffs(self, files, changeset):
120 for f in files[:self.maxfiles]:
127 for f in files[:self.maxfiles]:
121 yield self.t("filedifflink", node = hex(changeset), file = f)
128 yield self.t("filedifflink", node = hex(changeset), file = f)
122 if len(files) > self.maxfiles:
129 if len(files) > self.maxfiles:
123 yield self.t("fileellipses")
130 yield self.t("fileellipses")
124
131
125 def parent(self, t1, node=nullid, rev=-1, **args):
132 def parent(self, t1, node=nullid, rev=-1, **args):
126 if node != hex(nullid):
133 if node != hex(nullid):
127 yield self.t(t1, node = node, rev = rev, **args)
134 yield self.t(t1, node = node, rev = rev, **args)
128
135
129 def diff(self, node1, node2, files):
136 def diff(self, node1, node2, files):
130 def filterfiles(list, files):
137 def filterfiles(list, files):
131 l = [ x for x in list if x in files ]
138 l = [ x for x in list if x in files ]
132
139
133 for f in files:
140 for f in files:
134 if f[-1] != os.sep: f += os.sep
141 if f[-1] != os.sep: f += os.sep
135 l += [ x for x in list if x.startswith(f) ]
142 l += [ x for x in list if x.startswith(f) ]
136 return l
143 return l
137
144
138 def prettyprint(diff):
145 def prettyprint(diff):
139 for l in diff.splitlines(1):
146 for l in diff.splitlines(1):
140 line = cgi.escape(l)
147 line = cgi.escape(l)
141 if line.startswith('+'):
148 if line.startswith('+'):
142 yield self.t("difflineplus", line = line)
149 yield self.t("difflineplus", line = line)
143 elif line.startswith('-'):
150 elif line.startswith('-'):
144 yield self.t("difflineminus", line = line)
151 yield self.t("difflineminus", line = line)
145 elif line.startswith('@'):
152 elif line.startswith('@'):
146 yield self.t("difflineat", line = line)
153 yield self.t("difflineat", line = line)
147 else:
154 else:
148 yield self.t("diffline", line = line)
155 yield self.t("diffline", line = line)
149
156
150 r = self.repo
157 r = self.repo
151 cl = r.changelog
158 cl = r.changelog
152 mf = r.manifest
159 mf = r.manifest
153 change1 = cl.read(node1)
160 change1 = cl.read(node1)
154 change2 = cl.read(node2)
161 change2 = cl.read(node2)
155 mmap1 = mf.read(change1[0])
162 mmap1 = mf.read(change1[0])
156 mmap2 = mf.read(change2[0])
163 mmap2 = mf.read(change2[0])
157 date1 = self.date(change1)
164 date1 = self.date(change1)
158 date2 = self.date(change2)
165 date2 = self.date(change2)
159
166
160 c, a, d = r.diffrevs(node1, node2)
167 c, a, d = r.diffrevs(node1, node2)
161 c, a, d = map(lambda x: filterfiles(x, files), (c, a, d))
168 c, a, d = map(lambda x: filterfiles(x, files), (c, a, d))
162
169
163 for f in c:
170 for f in c:
164 to = r.file(f).read(mmap1[f])
171 to = r.file(f).read(mmap1[f])
165 tn = r.file(f).read(mmap2[f])
172 tn = r.file(f).read(mmap2[f])
166 yield prettyprint(mdiff.unidiff(to, date1, tn, date2, f))
173 yield prettyprint(mdiff.unidiff(to, date1, tn, date2, f))
167 for f in a:
174 for f in a:
168 to = ""
175 to = ""
169 tn = r.file(f).read(mmap2[f])
176 tn = r.file(f).read(mmap2[f])
170 yield prettyprint(mdiff.unidiff(to, date1, tn, date2, f))
177 yield prettyprint(mdiff.unidiff(to, date1, tn, date2, f))
171 for f in d:
178 for f in d:
172 to = r.file(f).read(mmap1[f])
179 to = r.file(f).read(mmap1[f])
173 tn = ""
180 tn = ""
174 yield prettyprint(mdiff.unidiff(to, date1, tn, date2, f))
181 yield prettyprint(mdiff.unidiff(to, date1, tn, date2, f))
175
182
176 def header(self):
183 def header(self):
177 yield self.t("header", repo = self.reponame)
184 yield self.t("header", repo = self.reponame)
178
185
179 def footer(self):
186 def footer(self):
180 yield self.t("footer", repo = self.reponame)
187 yield self.t("footer", repo = self.reponame)
181
188
182 def changelog(self, pos=None):
189 def changelog(self, pos=None):
183 def changenav():
190 def changenav():
184 def seq(factor = 1):
191 def seq(factor = 1):
185 yield 1 * factor
192 yield 1 * factor
186 yield 2 * factor
193 yield 2 * factor
187 yield 5 * factor
194 yield 5 * factor
188 for f in seq(factor * 10):
195 for f in seq(factor * 10):
189 yield f
196 yield f
190
197
191 linear = range(0, count - 2, self.maxchanges)[0:8]
198 linear = range(0, count - 2, self.maxchanges)[0:8]
192
199
193 for i in linear:
200 for i in linear:
194 yield self.t("naventry", rev = max(i, 1))
201 yield self.t("naventry", rev = max(i, 1))
195
202
196 for s in seq():
203 for s in seq():
197 if s > count - 2: break
204 if s > count - 2: break
198 if s > linear[-1]:
205 if s > linear[-1]:
199 yield self.t("naventry", rev = s)
206 yield self.t("naventry", rev = s)
200
207
201 yield self.t("naventry", rev = count - 1)
208 yield self.t("naventry", rev = count - 1)
202
209
203 def changelist():
210 def changelist():
204 parity = (start - end) & 1
211 parity = (start - end) & 1
205 cl = self.repo.changelog
212 cl = self.repo.changelog
206 l = [] # build a list in forward order for efficiency
213 l = [] # build a list in forward order for efficiency
207 for i in range(start, end + 1):
214 for i in range(start, end + 1):
208 n = cl.node(i)
215 n = cl.node(i)
209 changes = cl.read(n)
216 changes = cl.read(n)
210 hn = hex(n)
217 hn = hex(n)
211 p1, p2 = cl.parents(n)
218 p1, p2 = cl.parents(n)
212 t = float(changes[2].split(' ')[0])
219 t = float(changes[2].split(' ')[0])
213
220
214 l.insert(0, self.t(
221 l.insert(0, self.t(
215 'changelogentry',
222 'changelogentry',
216 parity = parity,
223 parity = parity,
217 author = obfuscate(changes[1]),
224 author = obfuscate(changes[1]),
218 shortdesc = cgi.escape(changes[4].splitlines()[0]),
225 shortdesc = cgi.escape(changes[4].splitlines()[0]),
219 age = age(t),
226 age = age(t),
220 parent1 = self.parent("changelogparent",
227 parent1 = self.parent("changelogparent",
221 hex(p1), cl.rev(p1)),
228 hex(p1), cl.rev(p1)),
222 parent2 = self.parent("changelogparent",
229 parent2 = self.parent("changelogparent",
223 hex(p2), cl.rev(p2)),
230 hex(p2), cl.rev(p2)),
224 p1 = hex(p1), p2 = hex(p2),
231 p1 = hex(p1), p2 = hex(p2),
225 p1rev = cl.rev(p1), p2rev = cl.rev(p2),
232 p1rev = cl.rev(p1), p2rev = cl.rev(p2),
226 manifest = hex(changes[0]),
233 manifest = hex(changes[0]),
227 desc = nl2br(cgi.escape(changes[4])),
234 desc = nl2br(cgi.escape(changes[4])),
228 date = time.asctime(time.gmtime(t)),
235 date = time.asctime(time.gmtime(t)),
229 files = self.listfilediffs(changes[3], n),
236 files = self.listfilediffs(changes[3], n),
230 rev = i,
237 rev = i,
231 node = hn))
238 node = hn))
232 parity = 1 - parity
239 parity = 1 - parity
233
240
234 yield l
241 yield l
235
242
236 count = self.repo.changelog.count()
243 count = self.repo.changelog.count()
237 pos = pos or count - 1
244 pos = pos or count - 1
238 end = min(pos, count - 1)
245 end = min(pos, count - 1)
239 start = max(0, pos - self.maxchanges)
246 start = max(0, pos - self.maxchanges)
240 end = min(count - 1, start + self.maxchanges)
247 end = min(count - 1, start + self.maxchanges)
241
248
242 yield self.t('changelog',
249 yield self.t('changelog',
243 header = self.header(),
250 header = self.header(),
244 footer = self.footer(),
251 footer = self.footer(),
245 repo = self.reponame,
252 repo = self.reponame,
246 changenav = changenav,
253 changenav = changenav,
247 rev = pos, changesets = count, entries = changelist)
254 rev = pos, changesets = count, entries = changelist)
248
255
249 def changeset(self, nodeid):
256 def changeset(self, nodeid):
250 n = bin(nodeid)
257 n = bin(nodeid)
251 cl = self.repo.changelog
258 cl = self.repo.changelog
252 changes = cl.read(n)
259 changes = cl.read(n)
253 p1, p2 = cl.parents(n)
260 p1, p2 = cl.parents(n)
254 p1rev, p2rev = cl.rev(p1), cl.rev(p2)
261 p1rev, p2rev = cl.rev(p1), cl.rev(p2)
255 t = float(changes[2].split(' ')[0])
262 t = float(changes[2].split(' ')[0])
256
263
257 files = []
264 files = []
258 mf = self.repo.manifest.read(changes[0])
265 mf = self.repo.manifest.read(changes[0])
259 for f in changes[3]:
266 for f in changes[3]:
260 files.append(self.t("filenodelink",
267 files.append(self.t("filenodelink",
261 filenode = hex(mf[f]), file = f))
268 filenode = hex(mf[f]), file = f))
262
269
263 def diff():
270 def diff():
264 yield self.diff(p1, n, changes[3])
271 yield self.diff(p1, n, changes[3])
265
272
266 yield self.t('changeset',
273 yield self.t('changeset',
267 header = self.header(),
274 header = self.header(),
268 footer = self.footer(),
275 footer = self.footer(),
269 repo = self.reponame,
276 repo = self.reponame,
270 diff = diff,
277 diff = diff,
271 rev = cl.rev(n),
278 rev = cl.rev(n),
272 node = nodeid,
279 node = nodeid,
273 shortdesc = cgi.escape(changes[4].splitlines()[0]),
280 shortdesc = cgi.escape(changes[4].splitlines()[0]),
274 parent1 = self.parent("changesetparent",
281 parent1 = self.parent("changesetparent",
275 hex(p1), cl.rev(p1)),
282 hex(p1), cl.rev(p1)),
276 parent2 = self.parent("changesetparent",
283 parent2 = self.parent("changesetparent",
277 hex(p2), cl.rev(p2)),
284 hex(p2), cl.rev(p2)),
278 p1 = hex(p1), p2 = hex(p2),
285 p1 = hex(p1), p2 = hex(p2),
279 p1rev = cl.rev(p1), p2rev = cl.rev(p2),
286 p1rev = cl.rev(p1), p2rev = cl.rev(p2),
280 manifest = hex(changes[0]),
287 manifest = hex(changes[0]),
281 author = obfuscate(changes[1]),
288 author = obfuscate(changes[1]),
282 desc = nl2br(cgi.escape(changes[4])),
289 desc = nl2br(cgi.escape(changes[4])),
283 date = time.asctime(time.gmtime(t)),
290 date = time.asctime(time.gmtime(t)),
284 files = files)
291 files = files)
285
292
286 def filelog(self, f, filenode):
293 def filelog(self, f, filenode):
287 cl = self.repo.changelog
294 cl = self.repo.changelog
288 fl = self.repo.file(f)
295 fl = self.repo.file(f)
289 count = fl.count()
296 count = fl.count()
290
297
291 def entries():
298 def entries():
292 l = []
299 l = []
293 parity = (count - 1) & 1
300 parity = (count - 1) & 1
294
301
295 for i in range(count):
302 for i in range(count):
296
303
297 n = fl.node(i)
304 n = fl.node(i)
298 lr = fl.linkrev(n)
305 lr = fl.linkrev(n)
299 cn = cl.node(lr)
306 cn = cl.node(lr)
300 cs = cl.read(cl.node(lr))
307 cs = cl.read(cl.node(lr))
301 p1, p2 = fl.parents(n)
308 p1, p2 = fl.parents(n)
302 t = float(cs[2].split(' ')[0])
309 t = float(cs[2].split(' ')[0])
303
310
304 l.insert(0, self.t("filelogentry",
311 l.insert(0, self.t("filelogentry",
305 parity = parity,
312 parity = parity,
306 filenode = hex(n),
313 filenode = hex(n),
307 filerev = i,
314 filerev = i,
308 file = f,
315 file = f,
309 node = hex(cn),
316 node = hex(cn),
310 author = obfuscate(cs[1]),
317 author = obfuscate(cs[1]),
311 age = age(t),
318 age = age(t),
312 date = time.asctime(time.gmtime(t)),
319 date = time.asctime(time.gmtime(t)),
313 shortdesc = cgi.escape(cs[4].splitlines()[0]),
320 shortdesc = cgi.escape(cs[4].splitlines()[0]),
314 p1 = hex(p1), p2 = hex(p2),
321 p1 = hex(p1), p2 = hex(p2),
315 p1rev = fl.rev(p1), p2rev = fl.rev(p2)))
322 p1rev = fl.rev(p1), p2rev = fl.rev(p2)))
316 parity = 1 - parity
323 parity = 1 - parity
317
324
318 yield l
325 yield l
319
326
320 yield self.t("filelog",
327 yield self.t("filelog",
321 header = self.header(),
328 header = self.header(),
322 footer = self.footer(),
329 footer = self.footer(),
323 repo = self.reponame,
330 repo = self.reponame,
324 file = f,
331 file = f,
325 filenode = filenode,
332 filenode = filenode,
326 entries = entries)
333 entries = entries)
327
334
328 def filerevision(self, f, node):
335 def filerevision(self, f, node):
329 fl = self.repo.file(f)
336 fl = self.repo.file(f)
330 n = bin(node)
337 n = bin(node)
331 text = cgi.escape(fl.read(n))
338 text = cgi.escape(fl.read(n))
332 changerev = fl.linkrev(n)
339 changerev = fl.linkrev(n)
333 cl = self.repo.changelog
340 cl = self.repo.changelog
334 cn = cl.node(changerev)
341 cn = cl.node(changerev)
335 cs = cl.read(cn)
342 cs = cl.read(cn)
336 p1, p2 = fl.parents(n)
343 p1, p2 = fl.parents(n)
337 t = float(cs[2].split(' ')[0])
344 t = float(cs[2].split(' ')[0])
338 mfn = cs[0]
345 mfn = cs[0]
339
346
340 def lines():
347 def lines():
341 for l, t in enumerate(text.splitlines(1)):
348 for l, t in enumerate(text.splitlines(1)):
342 yield self.t("fileline",
349 yield self.t("fileline",
343 line = t,
350 line = t,
344 linenumber = "% 6d" % (l + 1),
351 linenumber = "% 6d" % (l + 1),
345 parity = l & 1)
352 parity = l & 1)
346
353
347 yield self.t("filerevision", file = f,
354 yield self.t("filerevision", file = f,
348 header = self.header(),
355 header = self.header(),
349 footer = self.footer(),
356 footer = self.footer(),
350 repo = self.reponame,
357 repo = self.reponame,
351 filenode = node,
358 filenode = node,
352 path = up(f),
359 path = up(f),
353 text = lines(),
360 text = lines(),
354 rev = changerev,
361 rev = changerev,
355 node = hex(cn),
362 node = hex(cn),
356 manifest = hex(mfn),
363 manifest = hex(mfn),
357 author = obfuscate(cs[1]),
364 author = obfuscate(cs[1]),
358 age = age(t),
365 age = age(t),
359 date = time.asctime(time.gmtime(t)),
366 date = time.asctime(time.gmtime(t)),
360 shortdesc = cgi.escape(cs[4].splitlines()[0]),
367 shortdesc = cgi.escape(cs[4].splitlines()[0]),
361 parent1 = self.parent("filerevparent",
368 parent1 = self.parent("filerevparent",
362 hex(p1), fl.rev(p1), file=f),
369 hex(p1), fl.rev(p1), file=f),
363 parent2 = self.parent("filerevparent",
370 parent2 = self.parent("filerevparent",
364 hex(p2), fl.rev(p2), file=f),
371 hex(p2), fl.rev(p2), file=f),
365 p1 = hex(p1), p2 = hex(p2),
372 p1 = hex(p1), p2 = hex(p2),
366 p1rev = fl.rev(p1), p2rev = fl.rev(p2))
373 p1rev = fl.rev(p1), p2rev = fl.rev(p2))
367
374
368
375
369 def fileannotate(self, f, node):
376 def fileannotate(self, f, node):
370 bcache = {}
377 bcache = {}
371 ncache = {}
378 ncache = {}
372 fl = self.repo.file(f)
379 fl = self.repo.file(f)
373 n = bin(node)
380 n = bin(node)
374 changerev = fl.linkrev(n)
381 changerev = fl.linkrev(n)
375
382
376 cl = self.repo.changelog
383 cl = self.repo.changelog
377 cn = cl.node(changerev)
384 cn = cl.node(changerev)
378 cs = cl.read(cn)
385 cs = cl.read(cn)
379 p1, p2 = fl.parents(n)
386 p1, p2 = fl.parents(n)
380 t = float(cs[2].split(' ')[0])
387 t = float(cs[2].split(' ')[0])
381 mfn = cs[0]
388 mfn = cs[0]
382
389
383 def annotate():
390 def annotate():
384 parity = 1
391 parity = 1
385 last = None
392 last = None
386 for r, l in fl.annotate(n):
393 for r, l in fl.annotate(n):
387 try:
394 try:
388 cnode = ncache[r]
395 cnode = ncache[r]
389 except KeyError:
396 except KeyError:
390 cnode = ncache[r] = self.repo.changelog.node(r)
397 cnode = ncache[r] = self.repo.changelog.node(r)
391
398
392 try:
399 try:
393 name = bcache[r]
400 name = bcache[r]
394 except KeyError:
401 except KeyError:
395 cl = self.repo.changelog.read(cnode)
402 cl = self.repo.changelog.read(cnode)
396 name = cl[1]
403 name = cl[1]
397 f = name.find('@')
404 f = name.find('@')
398 if f >= 0:
405 if f >= 0:
399 name = name[:f]
406 name = name[:f]
400 bcache[r] = name
407 bcache[r] = name
401
408
402 if last != cnode:
409 if last != cnode:
403 parity = 1 - parity
410 parity = 1 - parity
404 last = cnode
411 last = cnode
405
412
406 yield self.t("annotateline",
413 yield self.t("annotateline",
407 parity = parity,
414 parity = parity,
408 node = hex(cnode),
415 node = hex(cnode),
409 rev = r,
416 rev = r,
410 author = name,
417 author = name,
411 file = f,
418 file = f,
412 line = cgi.escape(l))
419 line = cgi.escape(l))
413
420
414 yield self.t("fileannotate",
421 yield self.t("fileannotate",
415 header = self.header(),
422 header = self.header(),
416 footer = self.footer(),
423 footer = self.footer(),
417 repo = self.reponame,
424 repo = self.reponame,
418 file = f,
425 file = f,
419 filenode = node,
426 filenode = node,
420 annotate = annotate,
427 annotate = annotate,
421 path = up(f),
428 path = up(f),
422 rev = changerev,
429 rev = changerev,
423 node = hex(cn),
430 node = hex(cn),
424 manifest = hex(mfn),
431 manifest = hex(mfn),
425 author = obfuscate(cs[1]),
432 author = obfuscate(cs[1]),
426 age = age(t),
433 age = age(t),
427 date = time.asctime(time.gmtime(t)),
434 date = time.asctime(time.gmtime(t)),
428 shortdesc = cgi.escape(cs[4].splitlines()[0]),
435 shortdesc = cgi.escape(cs[4].splitlines()[0]),
429 parent1 = self.parent("fileannotateparent",
436 parent1 = self.parent("fileannotateparent",
430 hex(p1), fl.rev(p1), file=f),
437 hex(p1), fl.rev(p1), file=f),
431 parent2 = self.parent("fileannotateparent",
438 parent2 = self.parent("fileannotateparent",
432 hex(p2), fl.rev(p2), file=f),
439 hex(p2), fl.rev(p2), file=f),
433 p1 = hex(p1), p2 = hex(p2),
440 p1 = hex(p1), p2 = hex(p2),
434 p1rev = fl.rev(p1), p2rev = fl.rev(p2))
441 p1rev = fl.rev(p1), p2rev = fl.rev(p2))
435
442
436 def manifest(self, mnode, path):
443 def manifest(self, mnode, path):
437 mf = self.repo.manifest.read(bin(mnode))
444 mf = self.repo.manifest.read(bin(mnode))
438 rev = self.repo.manifest.rev(bin(mnode))
445 rev = self.repo.manifest.rev(bin(mnode))
439 node = self.repo.changelog.node(rev)
446 node = self.repo.changelog.node(rev)
440
447
441 files = {}
448 files = {}
442
449
443 p = path[1:]
450 p = path[1:]
444 l = len(p)
451 l = len(p)
445
452
446 for f,n in mf.items():
453 for f,n in mf.items():
447 if f[:l] != p:
454 if f[:l] != p:
448 continue
455 continue
449 remain = f[l:]
456 remain = f[l:]
450 if "/" in remain:
457 if "/" in remain:
451 short = remain[:remain.find("/") + 1] # bleah
458 short = remain[:remain.find("/") + 1] # bleah
452 files[short] = (f, None)
459 files[short] = (f, None)
453 else:
460 else:
454 short = os.path.basename(remain)
461 short = os.path.basename(remain)
455 files[short] = (f, n)
462 files[short] = (f, n)
456
463
457 def filelist():
464 def filelist():
458 parity = 0
465 parity = 0
459 fl = files.keys()
466 fl = files.keys()
460 fl.sort()
467 fl.sort()
461 for f in fl:
468 for f in fl:
462 full, fnode = files[f]
469 full, fnode = files[f]
463 if fnode:
470 if fnode:
464 yield self.t("manifestfileentry",
471 yield self.t("manifestfileentry",
465 file = full,
472 file = full,
466 manifest = mnode,
473 manifest = mnode,
467 filenode = hex(fnode),
474 filenode = hex(fnode),
468 parity = parity,
475 parity = parity,
469 basename = f)
476 basename = f)
470 else:
477 else:
471 yield self.t("manifestdirentry",
478 yield self.t("manifestdirentry",
472 parity = parity,
479 parity = parity,
473 path = os.path.join(path, f),
480 path = os.path.join(path, f),
474 manifest = mnode, basename = f[:-1])
481 manifest = mnode, basename = f[:-1])
475 parity = 1 - parity
482 parity = 1 - parity
476
483
477 yield self.t("manifest",
484 yield self.t("manifest",
478 header = self.header(),
485 header = self.header(),
479 footer = self.footer(),
486 footer = self.footer(),
480 repo = self.reponame,
487 repo = self.reponame,
481 manifest = mnode,
488 manifest = mnode,
482 rev = rev,
489 rev = rev,
483 node = hex(node),
490 node = hex(node),
484 path = path,
491 path = path,
485 up = up(path),
492 up = up(path),
486 entries = filelist)
493 entries = filelist)
487
494
488 def filediff(self, file, changeset):
495 def filediff(self, file, changeset):
489 n = bin(changeset)
496 n = bin(changeset)
490 cl = self.repo.changelog
497 cl = self.repo.changelog
491 p1 = cl.parents(n)[0]
498 p1 = cl.parents(n)[0]
492 cs = cl.read(n)
499 cs = cl.read(n)
493 mf = self.repo.manifest.read(cs[0])
500 mf = self.repo.manifest.read(cs[0])
494
501
495 def diff():
502 def diff():
496 yield self.diff(p1, n, file)
503 yield self.diff(p1, n, file)
497
504
498 yield self.t("filediff",
505 yield self.t("filediff",
499 header = self.header(),
506 header = self.header(),
500 footer = self.footer(),
507 footer = self.footer(),
501 repo = self.reponame,
508 repo = self.reponame,
502 file = file,
509 file = file,
503 filenode = hex(mf[file]),
510 filenode = hex(mf[file]),
504 node = changeset,
511 node = changeset,
505 rev = self.repo.changelog.rev(n),
512 rev = self.repo.changelog.rev(n),
506 p1 = hex(p1),
513 p1 = hex(p1),
507 p1rev = self.repo.changelog.rev(p1),
514 p1rev = self.repo.changelog.rev(p1),
508 diff = diff)
515 diff = diff)
509
516
510 # add tags to things
517 # add tags to things
511 # tags -> list of changesets corresponding to tags
518 # tags -> list of changesets corresponding to tags
512 # find tag, changeset, file
519 # find tag, changeset, file
513
520
514 def run(self):
521 def run(self):
515 args = cgi.parse()
522 args = cgi.parse()
516
523
517 if not args.has_key('cmd') or args['cmd'][0] == 'changelog':
524 if not args.has_key('cmd') or args['cmd'][0] == 'changelog':
518 hi = self.repo.changelog.count()
525 hi = self.repo.changelog.count()
519 if args.has_key('rev'):
526 if args.has_key('rev'):
520 hi = int(args['rev'][0])
527 hi = int(args['rev'][0])
521
528
522 write(self.changelog(hi))
529 write(self.changelog(hi))
523
530
524 elif args['cmd'][0] == 'changeset':
531 elif args['cmd'][0] == 'changeset':
525 write(self.changeset(args['node'][0]))
532 write(self.changeset(args['node'][0]))
526
533
527 elif args['cmd'][0] == 'manifest':
534 elif args['cmd'][0] == 'manifest':
528 write(self.manifest(args['manifest'][0], args['path'][0]))
535 write(self.manifest(args['manifest'][0], args['path'][0]))
529
536
530 elif args['cmd'][0] == 'filediff':
537 elif args['cmd'][0] == 'filediff':
531 write(self.filediff(args['file'][0], args['node'][0]))
538 write(self.filediff(args['file'][0], args['node'][0]))
532
539
533 elif args['cmd'][0] == 'file':
540 elif args['cmd'][0] == 'file':
534 write(self.filerevision(args['file'][0], args['filenode'][0]))
541 write(self.filerevision(args['file'][0], args['filenode'][0]))
535
542
536 elif args['cmd'][0] == 'annotate':
543 elif args['cmd'][0] == 'annotate':
537 write(self.fileannotate(args['file'][0], args['filenode'][0]))
544 write(self.fileannotate(args['file'][0], args['filenode'][0]))
538
545
539 elif args['cmd'][0] == 'filelog':
546 elif args['cmd'][0] == 'filelog':
540 write(self.filelog(args['file'][0], args['filenode'][0]))
547 write(self.filelog(args['file'][0], args['filenode'][0]))
541
548
542 elif args['cmd'][0] == 'branches':
549 elif args['cmd'][0] == 'branches':
543 httphdr("text/plain")
550 httphdr("text/plain")
544 nodes = []
551 nodes = []
545 if args.has_key('nodes'):
552 if args.has_key('nodes'):
546 nodes = map(bin, args['nodes'][0].split(" "))
553 nodes = map(bin, args['nodes'][0].split(" "))
547 for b in self.repo.branches(nodes):
554 for b in self.repo.branches(nodes):
548 sys.stdout.write(" ".join(map(hex, b)) + "\n")
555 sys.stdout.write(" ".join(map(hex, b)) + "\n")
549
556
550 elif args['cmd'][0] == 'between':
557 elif args['cmd'][0] == 'between':
551 httphdr("text/plain")
558 httphdr("text/plain")
552 nodes = []
559 nodes = []
553 if args.has_key('pairs'):
560 if args.has_key('pairs'):
554 pairs = [ map(bin, p.split("-"))
561 pairs = [ map(bin, p.split("-"))
555 for p in args['pairs'][0].split(" ") ]
562 for p in args['pairs'][0].split(" ") ]
556 for b in self.repo.between(pairs):
563 for b in self.repo.between(pairs):
557 sys.stdout.write(" ".join(map(hex, b)) + "\n")
564 sys.stdout.write(" ".join(map(hex, b)) + "\n")
558
565
559 elif args['cmd'][0] == 'changegroup':
566 elif args['cmd'][0] == 'changegroup':
560 httphdr("application/hg-changegroup")
567 httphdr("application/hg-changegroup")
561 nodes = []
568 nodes = []
562 if args.has_key('roots'):
569 if args.has_key('roots'):
563 nodes = map(bin, args['roots'][0].split(" "))
570 nodes = map(bin, args['roots'][0].split(" "))
564
571
565 z = zlib.compressobj()
572 z = zlib.compressobj()
566 for chunk in self.repo.changegroup(nodes):
573 for chunk in self.repo.changegroup(nodes):
567 sys.stdout.write(z.compress(chunk))
574 sys.stdout.write(z.compress(chunk))
568
575
569 sys.stdout.write(z.flush())
576 sys.stdout.write(z.flush())
570
577
571 else:
578 else:
572 write(self.t("error"))
579 write(self.t("error"))
573
580
574 if __name__ == "__main__":
581 if __name__ == "__main__":
575 hgweb().run()
582 hgweb().run()
@@ -1,19 +1,30
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2
2
3 # This is the mercurial setup script.
3 # This is the mercurial setup script.
4 #
4 #
5 # './setup.py install', or
5 # './setup.py install', or
6 # './setup.py --help' for more options
6 # './setup.py --help' for more options
7
7
8 import glob
8 from distutils.core import setup, Extension
9 from distutils.core import setup, Extension
10 from distutils.command.install_data import install_data
11
12 class install_package_data(install_data):
13 def finalize_options(self):
14 self.set_undefined_options('install',
15 ('install_lib', 'install_dir'))
16 install_data.finalize_options(self)
9
17
10 setup(name='mercurial',
18 setup(name='mercurial',
11 version='0.4f',
19 version='0.4f',
12 author='Matt Mackall',
20 author='Matt Mackall',
13 author_email='mpm@selenic.com',
21 author_email='mpm@selenic.com',
14 url='http://selenic.com/mercurial',
22 url='http://selenic.com/mercurial',
15 description='scalable distributed SCM',
23 description='scalable distributed SCM',
16 license='GNU GPL',
24 license='GNU GPL',
17 packages=['mercurial'],
25 packages=['mercurial'],
18 ext_modules=[Extension('mercurial.mpatch', ['mercurial/mpatch.c'])],
26 ext_modules=[Extension('mercurial.mpatch', ['mercurial/mpatch.c'])],
27 data_files=[('mercurial/templates',
28 ['templates/map'] + glob.glob('templates/*.tmpl'))],
29 cmdclass = { 'install_data' : install_package_data },
19 scripts=['hg'])
30 scripts=['hg'])
General Comments 0
You need to be logged in to leave comments. Login now