comparison mercurial/hgweb.py @ 142:529bf610092e

Prettify the web interface Add header, footer templates Add null parent handling Combine files and directories Add parity flag for alternating line colors Add line numbers to filerevision
author mpm@selenic.com
date Mon, 23 May 2005 20:57:48 -0800
parents c77a679e9cfa
children e8a360cd5a9f 083c38bdfa64
comparison
equal deleted inserted replaced
141:5f471a75d607 142:529bf610092e
120 for f in files[:self.maxfiles]: 120 for f in files[:self.maxfiles]:
121 yield self.t("filedifflink", node = hex(changeset), file = f) 121 yield self.t("filedifflink", node = hex(changeset), file = f)
122 if len(files) > self.maxfiles: 122 if len(files) > self.maxfiles:
123 yield self.t("fileellipses") 123 yield self.t("fileellipses")
124 124
125 def parent(self, t1, node, rev):
126 if node != hex(nullid):
127 yield self.t(t1, node = node, rev = rev)
128
125 def diff(self, node1, node2, files): 129 def diff(self, node1, node2, files):
126 def filterfiles(list, files): 130 def filterfiles(list, files):
127 l = [ x for x in list if x in files ] 131 l = [ x for x in list if x in files ]
128 132
129 for f in files: 133 for f in files:
167 for f in d: 171 for f in d:
168 to = r.file(f).read(mmap1[f]) 172 to = r.file(f).read(mmap1[f])
169 tn = "" 173 tn = ""
170 yield prettyprint(mdiff.unidiff(to, date1, tn, date2, f)) 174 yield prettyprint(mdiff.unidiff(to, date1, tn, date2, f))
171 175
176 def header(self):
177 yield self.t("header", repo = self.reponame)
178
179 def footer(self):
180 yield self.t("footer", repo = self.reponame)
181
172 def changelog(self, pos=None): 182 def changelog(self, pos=None):
173 def changenav(): 183 def changenav():
174 def seq(factor = 1): 184 def seq(factor = 1):
175 yield 1 * factor 185 yield 1 * factor
176 yield 2 * factor 186 yield 2 * factor
189 yield self.t("naventry", rev = s) 199 yield self.t("naventry", rev = s)
190 200
191 yield self.t("naventry", rev = count - 1) 201 yield self.t("naventry", rev = count - 1)
192 202
193 def changelist(): 203 def changelist():
204 parity = (start - end) & 1
194 cl = self.repo.changelog 205 cl = self.repo.changelog
195 l = [] # build a list in forward order for efficiency 206 l = [] # build a list in forward order for efficiency
196 for i in range(start, end + 1): 207 for i in range(start, end + 1):
197 n = cl.node(i) 208 n = cl.node(i)
198 changes = cl.read(n) 209 changes = cl.read(n)
200 p1, p2 = cl.parents(n) 211 p1, p2 = cl.parents(n)
201 t = float(changes[2].split(' ')[0]) 212 t = float(changes[2].split(' ')[0])
202 213
203 l.insert(0, self.t( 214 l.insert(0, self.t(
204 'changelogentry', 215 'changelogentry',
216 parity = parity,
205 author = obfuscate(changes[1]), 217 author = obfuscate(changes[1]),
206 shortdesc = cgi.escape(changes[4].splitlines()[0]), 218 shortdesc = cgi.escape(changes[4].splitlines()[0]),
207 age = age(t), 219 age = age(t),
220 parent1 = self.parent("changelogparent",
221 hex(p1), cl.rev(p1)),
222 parent2 = self.parent("changelogparent",
223 hex(p2), cl.rev(p2)),
208 p1 = hex(p1), p2 = hex(p2), 224 p1 = hex(p1), p2 = hex(p2),
209 p1rev = cl.rev(p1), p2rev = cl.rev(p2), 225 p1rev = cl.rev(p1), p2rev = cl.rev(p2),
210 manifest = hex(changes[0]), 226 manifest = hex(changes[0]),
211 desc = nl2br(cgi.escape(changes[4])), 227 desc = nl2br(cgi.escape(changes[4])),
212 date = time.asctime(time.gmtime(t)), 228 date = time.asctime(time.gmtime(t)),
213 files = self.listfilediffs(changes[3], n), 229 files = self.listfilediffs(changes[3], n),
214 rev = i, 230 rev = i,
215 node = hn)) 231 node = hn))
232 parity = 1 - parity
216 233
217 yield l 234 yield l
218 235
219 count = self.repo.changelog.count() 236 count = self.repo.changelog.count()
220 pos = pos or count - 1 237 pos = pos or count - 1
221 end = min(pos, count - 1) 238 end = min(pos, count - 1)
222 start = max(0, pos - self.maxchanges) 239 start = max(0, pos - self.maxchanges)
223 end = min(count - 1, start + self.maxchanges) 240 end = min(count - 1, start + self.maxchanges)
224 241
225 yield self.t('changelog', repo = self.reponame, changenav = changenav, 242 yield self.t('changelog',
226 rev = pos, changesets = count, changelist = changelist) 243 header = self.header(),
244 footer = self.footer(),
245 repo = self.reponame,
246 changenav = changenav,
247 rev = pos, changesets = count, entries = changelist)
227 248
228 def changeset(self, nodeid): 249 def changeset(self, nodeid):
229 n = bin(nodeid) 250 n = bin(nodeid)
230 cl = self.repo.changelog 251 cl = self.repo.changelog
231 changes = cl.read(n) 252 changes = cl.read(n)
241 262
242 def diff(): 263 def diff():
243 yield self.diff(p1, n, changes[3]) 264 yield self.diff(p1, n, changes[3])
244 265
245 yield self.t('changeset', 266 yield self.t('changeset',
267 header = self.header(),
268 footer = self.footer(),
269 repo = self.reponame,
246 diff = diff, 270 diff = diff,
247 rev = cl.rev(n), 271 rev = cl.rev(n),
248 node = nodeid, 272 node = nodeid,
249 shortdesc = cgi.escape(changes[4].splitlines()[0]), 273 shortdesc = cgi.escape(changes[4].splitlines()[0]),
274 parent1 = self.parent("changesetparent",
275 hex(p1), cl.rev(p1)),
276 parent2 = self.parent("changesetparent",
277 hex(p2), cl.rev(p2)),
250 p1 = hex(p1), p2 = hex(p2), 278 p1 = hex(p1), p2 = hex(p2),
251 p1rev = cl.rev(p1), p2rev = cl.rev(p2), 279 p1rev = cl.rev(p1), p2rev = cl.rev(p2),
252 manifest = hex(changes[0]), 280 manifest = hex(changes[0]),
253 author = obfuscate(changes[1]), 281 author = obfuscate(changes[1]),
254 desc = nl2br(cgi.escape(changes[4])), 282 desc = nl2br(cgi.escape(changes[4])),
260 fl = self.repo.file(f) 288 fl = self.repo.file(f)
261 count = fl.count() 289 count = fl.count()
262 290
263 def entries(): 291 def entries():
264 l = [] 292 l = []
293 parity = (count - 1) & 1
294
265 for i in range(count): 295 for i in range(count):
266 296
267 n = fl.node(i) 297 n = fl.node(i)
268 lr = fl.linkrev(n) 298 lr = fl.linkrev(n)
269 cn = cl.node(lr) 299 cn = cl.node(lr)
270 cs = cl.read(cl.node(lr)) 300 cs = cl.read(cl.node(lr))
271 p1, p2 = fl.parents(n) 301 p1, p2 = fl.parents(n)
272 t = float(cs[2].split(' ')[0]) 302 t = float(cs[2].split(' ')[0])
273 303
274 l.insert(0, self.t("filelogentry", 304 l.insert(0, self.t("filelogentry",
305 parity = parity,
275 filenode = hex(n), 306 filenode = hex(n),
276 filerev = i, 307 filerev = i,
277 file = f, 308 file = f,
278 node = hex(cn), 309 node = hex(cn),
279 author = obfuscate(cs[1]), 310 author = obfuscate(cs[1]),
280 age = age(t), 311 age = age(t),
281 date = time.asctime(time.gmtime(t)), 312 date = time.asctime(time.gmtime(t)),
282 shortdesc = cgi.escape(cs[4].splitlines()[0]), 313 shortdesc = cgi.escape(cs[4].splitlines()[0]),
283 p1 = hex(p1), p2 = hex(p2), 314 p1 = hex(p1), p2 = hex(p2),
284 p1rev = fl.rev(p1), p2rev = fl.rev(p2))) 315 p1rev = fl.rev(p1), p2rev = fl.rev(p2)))
316 parity = 1 - parity
285 317
286 yield l 318 yield l
287 319
288 yield self.t("filelog", 320 yield self.t("filelog",
321 header = self.header(),
322 footer = self.footer(),
323 repo = self.reponame,
289 file = f, 324 file = f,
290 filenode = filenode, 325 filenode = filenode,
291 entries = entries) 326 entries = entries)
292 327
293 def filerevision(self, f, node): 328 def filerevision(self, f, node):
299 cn = cl.node(changerev) 334 cn = cl.node(changerev)
300 cs = cl.read(cn) 335 cs = cl.read(cn)
301 p1, p2 = fl.parents(n) 336 p1, p2 = fl.parents(n)
302 t = float(cs[2].split(' ')[0]) 337 t = float(cs[2].split(' ')[0])
303 mfn = cs[0] 338 mfn = cs[0]
339
340 def lines():
341 for l, t in enumerate(text.splitlines(1)):
342 yield self.t("fileline",
343 line = t,
344 linenumber = "% 6d" % (l + 1),
345 parity = l & 1)
304 346
305 yield self.t("filerevision", file = f, 347 yield self.t("filerevision", file = f,
348 header = self.header(),
349 footer = self.footer(),
350 repo = self.reponame,
306 filenode = node, 351 filenode = node,
307 path = up(f), 352 path = up(f),
308 text = text, 353 text = lines(),
309 rev = changerev, 354 rev = changerev,
310 node = hex(cn), 355 node = hex(cn),
311 manifest = hex(mfn), 356 manifest = hex(mfn),
312 author = obfuscate(cs[1]), 357 author = obfuscate(cs[1]),
313 age = age(t), 358 age = age(t),
314 date = time.asctime(time.gmtime(t)), 359 date = time.asctime(time.gmtime(t)),
315 shortdesc = cgi.escape(cs[4].splitlines()[0]), 360 shortdesc = cgi.escape(cs[4].splitlines()[0]),
361 parent1 = self.parent("filerevparent",
362 hex(p1), fl.rev(p1)),
363 parent2 = self.parent("filerevparent",
364 hex(p2), fl.rev(p2)),
316 p1 = hex(p1), p2 = hex(p2), 365 p1 = hex(p1), p2 = hex(p2),
317 p1rev = fl.rev(p1), p2rev = fl.rev(p2)) 366 p1rev = fl.rev(p1), p2rev = fl.rev(p2))
318 367
319 368
320 def fileannotate(self, f, node): 369 def fileannotate(self, f, node):
330 p1, p2 = fl.parents(n) 379 p1, p2 = fl.parents(n)
331 t = float(cs[2].split(' ')[0]) 380 t = float(cs[2].split(' ')[0])
332 mfn = cs[0] 381 mfn = cs[0]
333 382
334 def annotate(): 383 def annotate():
384 parity = 1
385 last = None
335 for r, l in fl.annotate(n): 386 for r, l in fl.annotate(n):
336 try: 387 try:
337 cnode = ncache[r] 388 cnode = ncache[r]
338 except KeyError: 389 except KeyError:
339 cnode = ncache[r] = self.repo.changelog.node(r) 390 cnode = ncache[r] = self.repo.changelog.node(r)
346 f = name.find('@') 397 f = name.find('@')
347 if f >= 0: 398 if f >= 0:
348 name = name[:f] 399 name = name[:f]
349 bcache[r] = name 400 bcache[r] = name
350 401
402 if last != cnode:
403 parity = 1 - parity
404 last = cnode
405
351 yield self.t("annotateline", 406 yield self.t("annotateline",
407 parity = parity,
352 node = hex(cnode), 408 node = hex(cnode),
353 rev = r, 409 rev = r,
354 author = name, 410 author = name,
355 file = f, 411 file = f,
356 line = cgi.escape(l)) 412 line = cgi.escape(l))
357 413
358 yield self.t("fileannotate", 414 yield self.t("fileannotate",
415 header = self.header(),
416 footer = self.footer(),
417 repo = self.reponame,
359 file = f, 418 file = f,
360 filenode = node, 419 filenode = node,
361 annotate = annotate, 420 annotate = annotate,
362 path = up(f), 421 path = up(f),
363 rev = changerev, 422 rev = changerev,
365 manifest = hex(mfn), 424 manifest = hex(mfn),
366 author = obfuscate(cs[1]), 425 author = obfuscate(cs[1]),
367 age = age(t), 426 age = age(t),
368 date = time.asctime(time.gmtime(t)), 427 date = time.asctime(time.gmtime(t)),
369 shortdesc = cgi.escape(cs[4].splitlines()[0]), 428 shortdesc = cgi.escape(cs[4].splitlines()[0]),
429 parent1 = self.parent("filerevparent",
430 hex(p1), fl.rev(p1)),
431 parent2 = self.parent("filerevparent",
432 hex(p2), fl.rev(p2)),
370 p1 = hex(p1), p2 = hex(p2), 433 p1 = hex(p1), p2 = hex(p2),
371 p1rev = fl.rev(p1), p2rev = fl.rev(p2)) 434 p1rev = fl.rev(p1), p2rev = fl.rev(p2))
372 435
373 def manifest(self, mnode, path): 436 def manifest(self, mnode, path):
374 mf = self.repo.manifest.read(bin(mnode)) 437 mf = self.repo.manifest.read(bin(mnode))
375 rev = self.repo.manifest.rev(bin(mnode)) 438 rev = self.repo.manifest.rev(bin(mnode))
376 node = self.repo.changelog.node(rev) 439 node = self.repo.changelog.node(rev)
377 440
378 dirs = {}
379 files = {} 441 files = {}
380 short = {} 442
381
382 p = path[1:] 443 p = path[1:]
383 l = len(p) 444 l = len(p)
384 445
385 for f,n in mf.items(): 446 for f,n in mf.items():
386 if f[:l] != p: 447 if f[:l] != p:
387 continue 448 continue
388 remain = f[l:] 449 remain = f[l:]
389 if "/" in remain: 450 if "/" in remain:
390 short = remain[:remain.find("/") + 1] # bleah 451 short = remain[:remain.find("/") + 1] # bleah
391 dirs[short] = 1 452 files[short] = (f, None)
392 else: 453 else:
393 short = os.path.basename(remain) 454 short = os.path.basename(remain)
394 files[short] = (f, n) 455 files[short] = (f, n)
395 456
396 def dirlist():
397 dl = dirs.keys()
398 dl.sort()
399
400 for d in dl:
401 yield self.t("manifestdirentry",
402 path = os.path.join(path, d),
403 manifest = mnode, basename = d[:-1])
404
405 def filelist(): 457 def filelist():
458 parity = 0
406 fl = files.keys() 459 fl = files.keys()
407 fl.sort() 460 fl.sort()
408 for f in fl: 461 for f in fl:
409 full, fnode = files[f] 462 full, fnode = files[f]
410 yield self.t("manifestfileentry", 463 if fnode:
411 file = full, manifest = mnode, filenode = hex(fnode), 464 yield self.t("manifestfileentry",
412 basename = f) 465 file = full,
466 manifest = mnode,
467 filenode = hex(fnode),
468 parity = parity,
469 basename = f)
470 else:
471 yield self.t("manifestdirentry",
472 parity = parity,
473 path = os.path.join(path, f),
474 manifest = mnode, basename = f[:-1])
475 parity = 1 - parity
413 476
414 yield self.t("manifest", 477 yield self.t("manifest",
478 header = self.header(),
479 footer = self.footer(),
480 repo = self.reponame,
415 manifest = mnode, 481 manifest = mnode,
416 rev = rev, 482 rev = rev,
417 node = hex(node), 483 node = hex(node),
418 path = path, 484 path = path,
419 up = up(path), 485 up = up(path),
420 dirs = dirlist, 486 entries = filelist)
421 files = filelist)
422 487
423 def filediff(self, file, changeset): 488 def filediff(self, file, changeset):
424 n = bin(changeset) 489 n = bin(changeset)
425 cl = self.repo.changelog 490 cl = self.repo.changelog
426 p1 = cl.parents(n)[0] 491 p1 = cl.parents(n)[0]
429 494
430 def diff(): 495 def diff():
431 yield self.diff(p1, n, file) 496 yield self.diff(p1, n, file)
432 497
433 yield self.t("filediff", 498 yield self.t("filediff",
499 header = self.header(),
500 footer = self.footer(),
501 repo = self.reponame,
434 file = file, 502 file = file,
435 filenode = hex(mf[file]), 503 filenode = hex(mf[file]),
436 node = changeset, 504 node = changeset,
437 rev = self.repo.changelog.rev(n), 505 rev = self.repo.changelog.rev(n),
438 p1 = hex(p1), 506 p1 = hex(p1),
439 p1rev = self.repo.changelog.rev(p1), 507 p1rev = self.repo.changelog.rev(p1),
440 diff = diff) 508 diff = diff)
441 509
442 # header and footer, css
443 # add tags to things 510 # add tags to things
444 # show parents
445 # diff between rev and parent in changeset and file
446 # manifest links
447 # browse at top
448 # tags -> list of changesets corresponding to tags 511 # tags -> list of changesets corresponding to tags
449 # find tag, changeset, file 512 # find tag, changeset, file
450 513
451 def run(self): 514 def run(self):
452 args = cgi.parse() 515 args = cgi.parse()