##// END OF EJS Templates
hgweb: add bookmarks listing to summary page of gitweb/monoblue styles
Yuya Nishihara -
r13924:ea726c97 default
parent child Browse files
Show More
@@ -1,819 +1,829
1 1 #
2 2 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 import os, mimetypes, re, cgi, copy
9 9 import webutil
10 10 from mercurial import error, encoding, archival, templater, templatefilters
11 11 from mercurial.node import short, hex
12 12 from mercurial.util import binary
13 13 from common import paritygen, staticfile, get_contact, ErrorResponse
14 14 from common import HTTP_OK, HTTP_FORBIDDEN, HTTP_NOT_FOUND
15 15 from mercurial import graphmod
16 16 from mercurial import help as helpmod
17 17 from mercurial.i18n import _
18 18
19 19 # __all__ is populated with the allowed commands. Be sure to add to it if
20 20 # you're adding a new command, or the new command won't work.
21 21
22 22 __all__ = [
23 23 'log', 'rawfile', 'file', 'changelog', 'shortlog', 'changeset', 'rev',
24 24 'manifest', 'tags', 'bookmarks', 'branches', 'summary', 'filediff', 'diff',
25 25 'annotate', 'filelog', 'archive', 'static', 'graph', 'help',
26 26 ]
27 27
28 28 def log(web, req, tmpl):
29 29 if 'file' in req.form and req.form['file'][0]:
30 30 return filelog(web, req, tmpl)
31 31 else:
32 32 return changelog(web, req, tmpl)
33 33
34 34 def rawfile(web, req, tmpl):
35 35 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
36 36 if not path:
37 37 content = manifest(web, req, tmpl)
38 38 req.respond(HTTP_OK, web.ctype)
39 39 return content
40 40
41 41 try:
42 42 fctx = webutil.filectx(web.repo, req)
43 43 except error.LookupError, inst:
44 44 try:
45 45 content = manifest(web, req, tmpl)
46 46 req.respond(HTTP_OK, web.ctype)
47 47 return content
48 48 except ErrorResponse:
49 49 raise inst
50 50
51 51 path = fctx.path()
52 52 text = fctx.data()
53 53 mt = mimetypes.guess_type(path)[0]
54 54 if mt is None:
55 55 mt = binary(text) and 'application/octet-stream' or 'text/plain'
56 56 if mt.startswith('text/'):
57 57 mt += '; charset="%s"' % encoding.encoding
58 58
59 59 req.respond(HTTP_OK, mt, path, len(text))
60 60 return [text]
61 61
62 62 def _filerevision(web, tmpl, fctx):
63 63 f = fctx.path()
64 64 text = fctx.data()
65 65 parity = paritygen(web.stripecount)
66 66
67 67 if binary(text):
68 68 mt = mimetypes.guess_type(f)[0] or 'application/octet-stream'
69 69 text = '(binary:%s)' % mt
70 70
71 71 def lines():
72 72 for lineno, t in enumerate(text.splitlines(True)):
73 73 yield {"line": t,
74 74 "lineid": "l%d" % (lineno + 1),
75 75 "linenumber": "% 6d" % (lineno + 1),
76 76 "parity": parity.next()}
77 77
78 78 return tmpl("filerevision",
79 79 file=f,
80 80 path=webutil.up(f),
81 81 text=lines(),
82 82 rev=fctx.rev(),
83 83 node=hex(fctx.node()),
84 84 author=fctx.user(),
85 85 date=fctx.date(),
86 86 desc=fctx.description(),
87 87 branch=webutil.nodebranchnodefault(fctx),
88 88 parent=webutil.parents(fctx),
89 89 child=webutil.children(fctx),
90 90 rename=webutil.renamelink(fctx),
91 91 permissions=fctx.manifest().flags(f))
92 92
93 93 def file(web, req, tmpl):
94 94 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
95 95 if not path:
96 96 return manifest(web, req, tmpl)
97 97 try:
98 98 return _filerevision(web, tmpl, webutil.filectx(web.repo, req))
99 99 except error.LookupError, inst:
100 100 try:
101 101 return manifest(web, req, tmpl)
102 102 except ErrorResponse:
103 103 raise inst
104 104
105 105 def _search(web, req, tmpl):
106 106
107 107 query = req.form['rev'][0]
108 108 revcount = web.maxchanges
109 109 if 'revcount' in req.form:
110 110 revcount = int(req.form.get('revcount', [revcount])[0])
111 111 tmpl.defaults['sessionvars']['revcount'] = revcount
112 112
113 113 lessvars = copy.copy(tmpl.defaults['sessionvars'])
114 114 lessvars['revcount'] = revcount / 2
115 115 lessvars['rev'] = query
116 116 morevars = copy.copy(tmpl.defaults['sessionvars'])
117 117 morevars['revcount'] = revcount * 2
118 118 morevars['rev'] = query
119 119
120 120 def changelist(**map):
121 121 count = 0
122 122 qw = query.lower().split()
123 123
124 124 def revgen():
125 125 for i in xrange(len(web.repo) - 1, 0, -100):
126 126 l = []
127 127 for j in xrange(max(0, i - 100), i + 1):
128 128 ctx = web.repo[j]
129 129 l.append(ctx)
130 130 l.reverse()
131 131 for e in l:
132 132 yield e
133 133
134 134 for ctx in revgen():
135 135 miss = 0
136 136 for q in qw:
137 137 if not (q in ctx.user().lower() or
138 138 q in ctx.description().lower() or
139 139 q in " ".join(ctx.files()).lower()):
140 140 miss = 1
141 141 break
142 142 if miss:
143 143 continue
144 144
145 145 count += 1
146 146 n = ctx.node()
147 147 showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
148 148 files = webutil.listfilediffs(tmpl, ctx.files(), n, web.maxfiles)
149 149
150 150 yield tmpl('searchentry',
151 151 parity=parity.next(),
152 152 author=ctx.user(),
153 153 parent=webutil.parents(ctx),
154 154 child=webutil.children(ctx),
155 155 changelogtag=showtags,
156 156 desc=ctx.description(),
157 157 date=ctx.date(),
158 158 files=files,
159 159 rev=ctx.rev(),
160 160 node=hex(n),
161 161 tags=webutil.nodetagsdict(web.repo, n),
162 162 bookmarks=webutil.nodebookmarksdict(web.repo, n),
163 163 inbranch=webutil.nodeinbranch(web.repo, ctx),
164 164 branches=webutil.nodebranchdict(web.repo, ctx))
165 165
166 166 if count >= revcount:
167 167 break
168 168
169 169 tip = web.repo['tip']
170 170 parity = paritygen(web.stripecount)
171 171
172 172 return tmpl('search', query=query, node=tip.hex(),
173 173 entries=changelist, archives=web.archivelist("tip"),
174 174 morevars=morevars, lessvars=lessvars)
175 175
176 176 def changelog(web, req, tmpl, shortlog=False):
177 177
178 178 if 'node' in req.form:
179 179 ctx = webutil.changectx(web.repo, req)
180 180 else:
181 181 if 'rev' in req.form:
182 182 hi = req.form['rev'][0]
183 183 else:
184 184 hi = len(web.repo) - 1
185 185 try:
186 186 ctx = web.repo[hi]
187 187 except error.RepoError:
188 188 return _search(web, req, tmpl) # XXX redirect to 404 page?
189 189
190 190 def changelist(limit=0, **map):
191 191 l = [] # build a list in forward order for efficiency
192 192 for i in xrange(start, end):
193 193 ctx = web.repo[i]
194 194 n = ctx.node()
195 195 showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
196 196 files = webutil.listfilediffs(tmpl, ctx.files(), n, web.maxfiles)
197 197
198 198 l.insert(0, {"parity": parity.next(),
199 199 "author": ctx.user(),
200 200 "parent": webutil.parents(ctx, i - 1),
201 201 "child": webutil.children(ctx, i + 1),
202 202 "changelogtag": showtags,
203 203 "desc": ctx.description(),
204 204 "date": ctx.date(),
205 205 "files": files,
206 206 "rev": i,
207 207 "node": hex(n),
208 208 "tags": webutil.nodetagsdict(web.repo, n),
209 209 "bookmarks": webutil.nodebookmarksdict(web.repo, n),
210 210 "inbranch": webutil.nodeinbranch(web.repo, ctx),
211 211 "branches": webutil.nodebranchdict(web.repo, ctx)
212 212 })
213 213
214 214 if limit > 0:
215 215 l = l[:limit]
216 216
217 217 for e in l:
218 218 yield e
219 219
220 220 revcount = shortlog and web.maxshortchanges or web.maxchanges
221 221 if 'revcount' in req.form:
222 222 revcount = int(req.form.get('revcount', [revcount])[0])
223 223 tmpl.defaults['sessionvars']['revcount'] = revcount
224 224
225 225 lessvars = copy.copy(tmpl.defaults['sessionvars'])
226 226 lessvars['revcount'] = revcount / 2
227 227 morevars = copy.copy(tmpl.defaults['sessionvars'])
228 228 morevars['revcount'] = revcount * 2
229 229
230 230 count = len(web.repo)
231 231 pos = ctx.rev()
232 232 start = max(0, pos - revcount + 1)
233 233 end = min(count, start + revcount)
234 234 pos = end - 1
235 235 parity = paritygen(web.stripecount, offset=start - end)
236 236
237 237 changenav = webutil.revnavgen(pos, revcount, count, web.repo.changectx)
238 238
239 239 return tmpl(shortlog and 'shortlog' or 'changelog', changenav=changenav,
240 240 node=hex(ctx.node()), rev=pos, changesets=count,
241 241 entries=lambda **x: changelist(limit=0,**x),
242 242 latestentry=lambda **x: changelist(limit=1,**x),
243 243 archives=web.archivelist("tip"), revcount=revcount,
244 244 morevars=morevars, lessvars=lessvars)
245 245
246 246 def shortlog(web, req, tmpl):
247 247 return changelog(web, req, tmpl, shortlog = True)
248 248
249 249 def changeset(web, req, tmpl):
250 250 ctx = webutil.changectx(web.repo, req)
251 251 showtags = webutil.showtag(web.repo, tmpl, 'changesettag', ctx.node())
252 252 showbookmarks = webutil.showbookmark(web.repo, tmpl, 'changesetbookmark',
253 253 ctx.node())
254 254 showbranch = webutil.nodebranchnodefault(ctx)
255 255
256 256 files = []
257 257 parity = paritygen(web.stripecount)
258 258 for f in ctx.files():
259 259 template = f in ctx and 'filenodelink' or 'filenolink'
260 260 files.append(tmpl(template,
261 261 node=ctx.hex(), file=f,
262 262 parity=parity.next()))
263 263
264 264 parity = paritygen(web.stripecount)
265 265 style = web.config('web', 'style', 'paper')
266 266 if 'style' in req.form:
267 267 style = req.form['style'][0]
268 268
269 269 diffs = webutil.diffs(web.repo, tmpl, ctx, None, parity, style)
270 270 return tmpl('changeset',
271 271 diff=diffs,
272 272 rev=ctx.rev(),
273 273 node=ctx.hex(),
274 274 parent=webutil.parents(ctx),
275 275 child=webutil.children(ctx),
276 276 changesettag=showtags,
277 277 changesetbookmark=showbookmarks,
278 278 changesetbranch=showbranch,
279 279 author=ctx.user(),
280 280 desc=ctx.description(),
281 281 date=ctx.date(),
282 282 files=files,
283 283 archives=web.archivelist(ctx.hex()),
284 284 tags=webutil.nodetagsdict(web.repo, ctx.node()),
285 285 bookmarks=webutil.nodebookmarksdict(web.repo, ctx.node()),
286 286 branch=webutil.nodebranchnodefault(ctx),
287 287 inbranch=webutil.nodeinbranch(web.repo, ctx),
288 288 branches=webutil.nodebranchdict(web.repo, ctx))
289 289
290 290 rev = changeset
291 291
292 292 def manifest(web, req, tmpl):
293 293 ctx = webutil.changectx(web.repo, req)
294 294 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
295 295 mf = ctx.manifest()
296 296 node = ctx.node()
297 297
298 298 files = {}
299 299 dirs = {}
300 300 parity = paritygen(web.stripecount)
301 301
302 302 if path and path[-1] != "/":
303 303 path += "/"
304 304 l = len(path)
305 305 abspath = "/" + path
306 306
307 307 for f, n in mf.iteritems():
308 308 if f[:l] != path:
309 309 continue
310 310 remain = f[l:]
311 311 elements = remain.split('/')
312 312 if len(elements) == 1:
313 313 files[remain] = f
314 314 else:
315 315 h = dirs # need to retain ref to dirs (root)
316 316 for elem in elements[0:-1]:
317 317 if elem not in h:
318 318 h[elem] = {}
319 319 h = h[elem]
320 320 if len(h) > 1:
321 321 break
322 322 h[None] = None # denotes files present
323 323
324 324 if mf and not files and not dirs:
325 325 raise ErrorResponse(HTTP_NOT_FOUND, 'path not found: ' + path)
326 326
327 327 def filelist(**map):
328 328 for f in sorted(files):
329 329 full = files[f]
330 330
331 331 fctx = ctx.filectx(full)
332 332 yield {"file": full,
333 333 "parity": parity.next(),
334 334 "basename": f,
335 335 "date": fctx.date(),
336 336 "size": fctx.size(),
337 337 "permissions": mf.flags(full)}
338 338
339 339 def dirlist(**map):
340 340 for d in sorted(dirs):
341 341
342 342 emptydirs = []
343 343 h = dirs[d]
344 344 while isinstance(h, dict) and len(h) == 1:
345 345 k, v = h.items()[0]
346 346 if v:
347 347 emptydirs.append(k)
348 348 h = v
349 349
350 350 path = "%s%s" % (abspath, d)
351 351 yield {"parity": parity.next(),
352 352 "path": path,
353 353 "emptydirs": "/".join(emptydirs),
354 354 "basename": d}
355 355
356 356 return tmpl("manifest",
357 357 rev=ctx.rev(),
358 358 node=hex(node),
359 359 path=abspath,
360 360 up=webutil.up(abspath),
361 361 upparity=parity.next(),
362 362 fentries=filelist,
363 363 dentries=dirlist,
364 364 archives=web.archivelist(hex(node)),
365 365 tags=webutil.nodetagsdict(web.repo, node),
366 366 bookmarks=webutil.nodebookmarksdict(web.repo, node),
367 367 inbranch=webutil.nodeinbranch(web.repo, ctx),
368 368 branches=webutil.nodebranchdict(web.repo, ctx))
369 369
370 370 def tags(web, req, tmpl):
371 371 i = web.repo.tagslist()
372 372 i.reverse()
373 373 parity = paritygen(web.stripecount)
374 374
375 375 def entries(notip=False, limit=0, **map):
376 376 count = 0
377 377 for k, n in i:
378 378 if notip and k == "tip":
379 379 continue
380 380 if limit > 0 and count >= limit:
381 381 continue
382 382 count = count + 1
383 383 yield {"parity": parity.next(),
384 384 "tag": k,
385 385 "date": web.repo[n].date(),
386 386 "node": hex(n)}
387 387
388 388 return tmpl("tags",
389 389 node=hex(web.repo.changelog.tip()),
390 390 entries=lambda **x: entries(False, 0, **x),
391 391 entriesnotip=lambda **x: entries(True, 0, **x),
392 392 latestentry=lambda **x: entries(True, 1, **x))
393 393
394 394 def bookmarks(web, req, tmpl):
395 395 i = web.repo._bookmarks.items()
396 396 parity = paritygen(web.stripecount)
397 397
398 398 def entries(limit=0, **map):
399 399 count = 0
400 400 for k, n in sorted(i):
401 401 if limit > 0 and count >= limit:
402 402 continue
403 403 count = count + 1
404 404 yield {"parity": parity.next(),
405 405 "bookmark": k,
406 406 "date": web.repo[n].date(),
407 407 "node": hex(n)}
408 408
409 409 return tmpl("bookmarks",
410 410 node=hex(web.repo.changelog.tip()),
411 411 entries=lambda **x: entries(0, **x),
412 412 latestentry=lambda **x: entries(1, **x))
413 413
414 414 def branches(web, req, tmpl):
415 415 tips = (web.repo[n] for t, n in web.repo.branchtags().iteritems())
416 416 heads = web.repo.heads()
417 417 parity = paritygen(web.stripecount)
418 418 sortkey = lambda ctx: ('close' not in ctx.extra(), ctx.rev())
419 419
420 420 def entries(limit, **map):
421 421 count = 0
422 422 for ctx in sorted(tips, key=sortkey, reverse=True):
423 423 if limit > 0 and count >= limit:
424 424 return
425 425 count += 1
426 426 if ctx.node() not in heads:
427 427 status = 'inactive'
428 428 elif not web.repo.branchheads(ctx.branch()):
429 429 status = 'closed'
430 430 else:
431 431 status = 'open'
432 432 yield {'parity': parity.next(),
433 433 'branch': ctx.branch(),
434 434 'status': status,
435 435 'node': ctx.hex(),
436 436 'date': ctx.date()}
437 437
438 438 return tmpl('branches', node=hex(web.repo.changelog.tip()),
439 439 entries=lambda **x: entries(0, **x),
440 440 latestentry=lambda **x: entries(1, **x))
441 441
442 442 def summary(web, req, tmpl):
443 443 i = web.repo.tagslist()
444 444 i.reverse()
445 445
446 446 def tagentries(**map):
447 447 parity = paritygen(web.stripecount)
448 448 count = 0
449 449 for k, n in i:
450 450 if k == "tip": # skip tip
451 451 continue
452 452
453 453 count += 1
454 454 if count > 10: # limit to 10 tags
455 455 break
456 456
457 457 yield tmpl("tagentry",
458 458 parity=parity.next(),
459 459 tag=k,
460 460 node=hex(n),
461 461 date=web.repo[n].date())
462 462
463 def bookmarks(**map):
464 parity = paritygen(web.stripecount)
465 b = web.repo._bookmarks.items()
466 for k, n in sorted(b)[:10]: # limit to 10 bookmarks
467 yield {'parity': parity.next(),
468 'bookmark': k,
469 'date': web.repo[n].date(),
470 'node': hex(n)}
471
463 472 def branches(**map):
464 473 parity = paritygen(web.stripecount)
465 474
466 475 b = web.repo.branchtags()
467 476 l = [(-web.repo.changelog.rev(n), n, t) for t, n in b.iteritems()]
468 477 for r, n, t in sorted(l):
469 478 yield {'parity': parity.next(),
470 479 'branch': t,
471 480 'node': hex(n),
472 481 'date': web.repo[n].date()}
473 482
474 483 def changelist(**map):
475 484 parity = paritygen(web.stripecount, offset=start - end)
476 485 l = [] # build a list in forward order for efficiency
477 486 for i in xrange(start, end):
478 487 ctx = web.repo[i]
479 488 n = ctx.node()
480 489 hn = hex(n)
481 490
482 491 l.insert(0, tmpl(
483 492 'shortlogentry',
484 493 parity=parity.next(),
485 494 author=ctx.user(),
486 495 desc=ctx.description(),
487 496 date=ctx.date(),
488 497 rev=i,
489 498 node=hn,
490 499 tags=webutil.nodetagsdict(web.repo, n),
491 500 bookmarks=webutil.nodebookmarksdict(web.repo, n),
492 501 inbranch=webutil.nodeinbranch(web.repo, ctx),
493 502 branches=webutil.nodebranchdict(web.repo, ctx)))
494 503
495 504 yield l
496 505
497 506 tip = web.repo['tip']
498 507 count = len(web.repo)
499 508 start = max(0, count - web.maxchanges)
500 509 end = min(count, start + web.maxchanges)
501 510
502 511 return tmpl("summary",
503 512 desc=web.config("web", "description", "unknown"),
504 513 owner=get_contact(web.config) or "unknown",
505 514 lastchange=tip.date(),
506 515 tags=tagentries,
516 bookmarks=bookmarks,
507 517 branches=branches,
508 518 shortlog=changelist,
509 519 node=tip.hex(),
510 520 archives=web.archivelist("tip"))
511 521
512 522 def filediff(web, req, tmpl):
513 523 fctx, ctx = None, None
514 524 try:
515 525 fctx = webutil.filectx(web.repo, req)
516 526 except LookupError:
517 527 ctx = webutil.changectx(web.repo, req)
518 528 path = webutil.cleanpath(web.repo, req.form['file'][0])
519 529 if path not in ctx.files():
520 530 raise
521 531
522 532 if fctx is not None:
523 533 n = fctx.node()
524 534 path = fctx.path()
525 535 else:
526 536 n = ctx.node()
527 537 # path already defined in except clause
528 538
529 539 parity = paritygen(web.stripecount)
530 540 style = web.config('web', 'style', 'paper')
531 541 if 'style' in req.form:
532 542 style = req.form['style'][0]
533 543
534 544 diffs = webutil.diffs(web.repo, tmpl, fctx or ctx, [path], parity, style)
535 545 rename = fctx and webutil.renamelink(fctx) or []
536 546 ctx = fctx and fctx or ctx
537 547 return tmpl("filediff",
538 548 file=path,
539 549 node=hex(n),
540 550 rev=ctx.rev(),
541 551 date=ctx.date(),
542 552 desc=ctx.description(),
543 553 author=ctx.user(),
544 554 rename=rename,
545 555 branch=webutil.nodebranchnodefault(ctx),
546 556 parent=webutil.parents(ctx),
547 557 child=webutil.children(ctx),
548 558 diff=diffs)
549 559
550 560 diff = filediff
551 561
552 562 def annotate(web, req, tmpl):
553 563 fctx = webutil.filectx(web.repo, req)
554 564 f = fctx.path()
555 565 parity = paritygen(web.stripecount)
556 566
557 567 def annotate(**map):
558 568 last = None
559 569 if binary(fctx.data()):
560 570 mt = (mimetypes.guess_type(fctx.path())[0]
561 571 or 'application/octet-stream')
562 572 lines = enumerate([((fctx.filectx(fctx.filerev()), 1),
563 573 '(binary:%s)' % mt)])
564 574 else:
565 575 lines = enumerate(fctx.annotate(follow=True, linenumber=True))
566 576 for lineno, ((f, targetline), l) in lines:
567 577 fnode = f.filenode()
568 578
569 579 if last != fnode:
570 580 last = fnode
571 581
572 582 yield {"parity": parity.next(),
573 583 "node": hex(f.node()),
574 584 "rev": f.rev(),
575 585 "author": f.user(),
576 586 "desc": f.description(),
577 587 "file": f.path(),
578 588 "targetline": targetline,
579 589 "line": l,
580 590 "lineid": "l%d" % (lineno + 1),
581 591 "linenumber": "% 6d" % (lineno + 1),
582 592 "revdate": f.date()}
583 593
584 594 return tmpl("fileannotate",
585 595 file=f,
586 596 annotate=annotate,
587 597 path=webutil.up(f),
588 598 rev=fctx.rev(),
589 599 node=hex(fctx.node()),
590 600 author=fctx.user(),
591 601 date=fctx.date(),
592 602 desc=fctx.description(),
593 603 rename=webutil.renamelink(fctx),
594 604 branch=webutil.nodebranchnodefault(fctx),
595 605 parent=webutil.parents(fctx),
596 606 child=webutil.children(fctx),
597 607 permissions=fctx.manifest().flags(f))
598 608
599 609 def filelog(web, req, tmpl):
600 610
601 611 try:
602 612 fctx = webutil.filectx(web.repo, req)
603 613 f = fctx.path()
604 614 fl = fctx.filelog()
605 615 except error.LookupError:
606 616 f = webutil.cleanpath(web.repo, req.form['file'][0])
607 617 fl = web.repo.file(f)
608 618 numrevs = len(fl)
609 619 if not numrevs: # file doesn't exist at all
610 620 raise
611 621 rev = webutil.changectx(web.repo, req).rev()
612 622 first = fl.linkrev(0)
613 623 if rev < first: # current rev is from before file existed
614 624 raise
615 625 frev = numrevs - 1
616 626 while fl.linkrev(frev) > rev:
617 627 frev -= 1
618 628 fctx = web.repo.filectx(f, fl.linkrev(frev))
619 629
620 630 revcount = web.maxshortchanges
621 631 if 'revcount' in req.form:
622 632 revcount = int(req.form.get('revcount', [revcount])[0])
623 633 tmpl.defaults['sessionvars']['revcount'] = revcount
624 634
625 635 lessvars = copy.copy(tmpl.defaults['sessionvars'])
626 636 lessvars['revcount'] = revcount / 2
627 637 morevars = copy.copy(tmpl.defaults['sessionvars'])
628 638 morevars['revcount'] = revcount * 2
629 639
630 640 count = fctx.filerev() + 1
631 641 start = max(0, fctx.filerev() - revcount + 1) # first rev on this page
632 642 end = min(count, start + revcount) # last rev on this page
633 643 parity = paritygen(web.stripecount, offset=start - end)
634 644
635 645 def entries(limit=0, **map):
636 646 l = []
637 647
638 648 repo = web.repo
639 649 for i in xrange(start, end):
640 650 iterfctx = fctx.filectx(i)
641 651
642 652 l.insert(0, {"parity": parity.next(),
643 653 "filerev": i,
644 654 "file": f,
645 655 "node": hex(iterfctx.node()),
646 656 "author": iterfctx.user(),
647 657 "date": iterfctx.date(),
648 658 "rename": webutil.renamelink(iterfctx),
649 659 "parent": webutil.parents(iterfctx),
650 660 "child": webutil.children(iterfctx),
651 661 "desc": iterfctx.description(),
652 662 "tags": webutil.nodetagsdict(repo, iterfctx.node()),
653 663 "bookmarks": webutil.nodebookmarksdict(
654 664 repo, iterfctx.node()),
655 665 "branch": webutil.nodebranchnodefault(iterfctx),
656 666 "inbranch": webutil.nodeinbranch(repo, iterfctx),
657 667 "branches": webutil.nodebranchdict(repo, iterfctx)})
658 668
659 669 if limit > 0:
660 670 l = l[:limit]
661 671
662 672 for e in l:
663 673 yield e
664 674
665 675 nodefunc = lambda x: fctx.filectx(fileid=x)
666 676 nav = webutil.revnavgen(end - 1, revcount, count, nodefunc)
667 677 return tmpl("filelog", file=f, node=hex(fctx.node()), nav=nav,
668 678 entries=lambda **x: entries(limit=0, **x),
669 679 latestentry=lambda **x: entries(limit=1, **x),
670 680 revcount=revcount, morevars=morevars, lessvars=lessvars)
671 681
672 682 def archive(web, req, tmpl):
673 683 type_ = req.form.get('type', [None])[0]
674 684 allowed = web.configlist("web", "allow_archive")
675 685 key = req.form['node'][0]
676 686
677 687 if type_ not in web.archives:
678 688 msg = 'Unsupported archive type: %s' % type_
679 689 raise ErrorResponse(HTTP_NOT_FOUND, msg)
680 690
681 691 if not ((type_ in allowed or
682 692 web.configbool("web", "allow" + type_, False))):
683 693 msg = 'Archive type not allowed: %s' % type_
684 694 raise ErrorResponse(HTTP_FORBIDDEN, msg)
685 695
686 696 reponame = re.sub(r"\W+", "-", os.path.basename(web.reponame))
687 697 cnode = web.repo.lookup(key)
688 698 arch_version = key
689 699 if cnode == key or key == 'tip':
690 700 arch_version = short(cnode)
691 701 name = "%s-%s" % (reponame, arch_version)
692 702 mimetype, artype, extension, encoding = web.archive_specs[type_]
693 703 headers = [
694 704 ('Content-Type', mimetype),
695 705 ('Content-Disposition', 'attachment; filename=%s%s' % (name, extension))
696 706 ]
697 707 if encoding:
698 708 headers.append(('Content-Encoding', encoding))
699 709 req.header(headers)
700 710 req.respond(HTTP_OK)
701 711 archival.archive(web.repo, req, cnode, artype, prefix=name)
702 712 return []
703 713
704 714
705 715 def static(web, req, tmpl):
706 716 fname = req.form['file'][0]
707 717 # a repo owner may set web.static in .hg/hgrc to get any file
708 718 # readable by the user running the CGI script
709 719 static = web.config("web", "static", None, untrusted=False)
710 720 if not static:
711 721 tp = web.templatepath or templater.templatepath()
712 722 if isinstance(tp, str):
713 723 tp = [tp]
714 724 static = [os.path.join(p, 'static') for p in tp]
715 725 return [staticfile(static, fname, req)]
716 726
717 727 def graph(web, req, tmpl):
718 728
719 729 rev = webutil.changectx(web.repo, req).rev()
720 730 bg_height = 39
721 731 revcount = web.maxshortchanges
722 732 if 'revcount' in req.form:
723 733 revcount = int(req.form.get('revcount', [revcount])[0])
724 734 tmpl.defaults['sessionvars']['revcount'] = revcount
725 735
726 736 lessvars = copy.copy(tmpl.defaults['sessionvars'])
727 737 lessvars['revcount'] = revcount / 2
728 738 morevars = copy.copy(tmpl.defaults['sessionvars'])
729 739 morevars['revcount'] = revcount * 2
730 740
731 741 max_rev = len(web.repo) - 1
732 742 revcount = min(max_rev, revcount)
733 743 revnode = web.repo.changelog.node(rev)
734 744 revnode_hex = hex(revnode)
735 745 uprev = min(max_rev, rev + revcount)
736 746 downrev = max(0, rev - revcount)
737 747 count = len(web.repo)
738 748 changenav = webutil.revnavgen(rev, revcount, count, web.repo.changectx)
739 749 startrev = rev
740 750 # if starting revision is less than 60 set it to uprev
741 751 if rev < web.maxshortchanges:
742 752 startrev = uprev
743 753
744 754 dag = graphmod.revisions(web.repo, startrev, downrev)
745 755 tree = list(graphmod.colored(dag))
746 756 canvasheight = (len(tree) + 1) * bg_height - 27
747 757 data = []
748 758 for (id, type, ctx, vtx, edges) in tree:
749 759 if type != graphmod.CHANGESET:
750 760 continue
751 761 node = short(ctx.node())
752 762 age = templatefilters.age(ctx.date())
753 763 desc = templatefilters.firstline(ctx.description())
754 764 desc = cgi.escape(templatefilters.nonempty(desc))
755 765 user = cgi.escape(templatefilters.person(ctx.user()))
756 766 branch = ctx.branch()
757 767 branch = branch, web.repo.branchtags().get(branch) == ctx.node()
758 768 data.append((node, vtx, edges, desc, user, age, branch, ctx.tags(),
759 769 ctx.bookmarks()))
760 770
761 771 return tmpl('graph', rev=rev, revcount=revcount, uprev=uprev,
762 772 lessvars=lessvars, morevars=morevars, downrev=downrev,
763 773 canvasheight=canvasheight, jsdata=data, bg_height=bg_height,
764 774 node=revnode_hex, changenav=changenav)
765 775
766 776 def _getdoc(e):
767 777 doc = e[0].__doc__
768 778 if doc:
769 779 doc = doc.split('\n')[0]
770 780 else:
771 781 doc = _('(no help text available)')
772 782 return doc
773 783
774 784 def help(web, req, tmpl):
775 785 from mercurial import commands # avoid cycle
776 786
777 787 topicname = req.form.get('node', [None])[0]
778 788 if not topicname:
779 789 topic = []
780 790
781 791 def topics(**map):
782 792 for entries, summary, _ in helpmod.helptable:
783 793 entries = sorted(entries, key=len)
784 794 yield {'topic': entries[-1], 'summary': summary}
785 795
786 796 early, other = [], []
787 797 primary = lambda s: s.split('|')[0]
788 798 for c, e in commands.table.iteritems():
789 799 doc = _getdoc(e)
790 800 if 'DEPRECATED' in doc or c.startswith('debug'):
791 801 continue
792 802 cmd = primary(c)
793 803 if cmd.startswith('^'):
794 804 early.append((cmd[1:], doc))
795 805 else:
796 806 other.append((cmd, doc))
797 807
798 808 early.sort()
799 809 other.sort()
800 810
801 811 def earlycommands(**map):
802 812 for c, doc in early:
803 813 yield {'topic': c, 'summary': doc}
804 814
805 815 def othercommands(**map):
806 816 for c, doc in other:
807 817 yield {'topic': c, 'summary': doc}
808 818
809 819 return tmpl('helptopics', topics=topics, earlycommands=earlycommands,
810 820 othercommands=othercommands, title='Index')
811 821
812 822 u = webutil.wsgiui()
813 823 u.pushbuffer()
814 824 try:
815 825 commands.help_(u, topicname)
816 826 except error.UnknownCommand:
817 827 raise ErrorResponse(HTTP_NOT_FOUND)
818 828 doc = u.popbuffer()
819 829 return tmpl('help', topic=topicname, doc=doc)
@@ -1,60 +1,66
1 1 {header}
2 2 <title>{repo|escape}: Summary</title>
3 3 <link rel="alternate" type="application/atom+xml"
4 4 href="{url}atom-log" title="Atom feed for {repo|escape}"/>
5 5 <link rel="alternate" type="application/rss+xml"
6 6 href="{url}rss-log" title="RSS feed for {repo|escape}"/>
7 7 </head>
8 8 <body>
9 9
10 10 <div class="page_header">
11 11 <a href="http://mercurial.selenic.com/" title="Mercurial" style="float: right;">Mercurial</a><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / summary
12 12
13 13 <form action="{url}log">
14 14 {sessionvars%hiddenformentry}
15 15 <div class="search">
16 16 <input type="text" name="rev" />
17 17 </div>
18 18 </form>
19 19 </div>
20 20
21 21 <div class="page_nav">
22 22 summary |
23 23 <a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a> |
24 24 <a href="{url}log{sessionvars%urlparameter}">changelog</a> |
25 25 <a href="{url}graph{sessionvars%urlparameter}">graph</a> |
26 26 <a href="{url}tags{sessionvars%urlparameter}">tags</a> |
27 27 <a href="{url}bookmarks{sessionvars%urlparameter}">bookmarks</a> |
28 28 <a href="{url}branches{sessionvars%urlparameter}">branches</a> |
29 29 <a href="{url}file/{node|short}{sessionvars%urlparameter}">files</a>{archives%archiveentry} |
30 30 <a href="{url}help{sessionvars%urlparameter}">help</a>
31 31 <br/>
32 32 </div>
33 33
34 34 <div class="title">&nbsp;</div>
35 35 <table cellspacing="0">
36 36 <tr><td>description</td><td>{desc}</td></tr>
37 37 <tr><td>owner</td><td>{owner|obfuscate}</td></tr>
38 38 <tr><td>last change</td><td>{lastchange|rfc822date}</td></tr>
39 39 </table>
40 40
41 41 <div><a class="title" href="{url}shortlog{sessionvars%urlparameter}">changes</a></div>
42 42 <table cellspacing="0">
43 43 {shortlog}
44 44 <tr class="light"><td colspan="4"><a class="list" href="{url}shortlog{sessionvars%urlparameter}">...</a></td></tr>
45 45 </table>
46 46
47 47 <div><a class="title" href="{url}tags{sessionvars%urlparameter}">tags</a></div>
48 48 <table cellspacing="0">
49 49 {tags}
50 50 <tr class="light"><td colspan="3"><a class="list" href="{url}tags{sessionvars%urlparameter}">...</a></td></tr>
51 51 </table>
52 52
53 <div><a class="title" href="{url}bookmarks{sessionvars%urlparameter}">bookmarks</a></div>
54 <table cellspacing="0">
55 {bookmarks%bookmarkentry}
56 <tr class="light"><td colspan="3"><a class="list" href="{url}bookmarks{sessionvars%urlparameter}">...</a></td></tr>
57 </table>
58
53 59 <div><a class="title" href="#">branches</a></div>
54 60 <table cellspacing="0">
55 61 {branches%branchentry}
56 62 <tr class="light">
57 63 <td colspan="4"><a class="list" href="#">...</a></td>
58 64 </tr>
59 65 </table>
60 66 {footer}
@@ -1,68 +1,76
1 1 {header}
2 2 <title>{repo|escape}: Summary</title>
3 3 <link rel="alternate" type="application/atom+xml" href="{url}atom-log" title="Atom feed for {repo|escape}"/>
4 4 <link rel="alternate" type="application/rss+xml" href="{url}rss-log" title="RSS feed for {repo|escape}"/>
5 5 </head>
6 6
7 7 <body>
8 8 <div id="container">
9 9 <div class="page-header">
10 10 <h1><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / summary</h1>
11 11
12 12 <form action="{url}log">
13 13 {sessionvars%hiddenformentry}
14 14 <dl class="search">
15 15 <dt><label>Search: </label></dt>
16 16 <dd><input type="text" name="rev" /></dd>
17 17 </dl>
18 18 </form>
19 19
20 20 <ul class="page-nav">
21 21 <li class="current">summary</li>
22 22 <li><a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a></li>
23 23 <li><a href="{url}log{sessionvars%urlparameter}">changelog</a></li>
24 24 <li><a href="{url}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
25 25 <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
26 26 <li><a href="{url}bookmarks{sessionvars%urlparameter}">bookmarks</a></li>
27 27 <li><a href="{url}branches{sessionvars%urlparameter}">branches</a></li>
28 28 <li><a href="{url}file/{node|short}{sessionvars%urlparameter}">files</a></li>
29 29 <li><a href="{url}help{sessionvars%urlparameter}">help</a></li>
30 30 </ul>
31 31 </div>
32 32
33 33 <h2 class="no-link no-border">Mercurial Repository Overview</h2>
34 34 <dl class="overview">
35 35 <dt>name</dt>
36 36 <dd>{repo|escape}</dd>
37 37 <dt>description</dt>
38 38 <dd>{desc}</dd>
39 39 <dt>owner</dt>
40 40 <dd>{owner|obfuscate}</dd>
41 41 <dt>last change</dt>
42 42 <dd>{lastchange|rfc822date}</dd>
43 43 </dl>
44 44
45 45 <h2><a href="{url}shortlog{sessionvars%urlparameter}">Changes</a></h2>
46 46 <table>
47 47 {shortlog}
48 48 <tr class="light">
49 49 <td colspan="4"><a class="list" href="{url}shortlog{sessionvars%urlparameter}">...</a></td>
50 50 </tr>
51 51 </table>
52 52
53 53 <h2><a href="{url}tags{sessionvars%urlparameter}">Tags</a></h2>
54 54 <table>
55 55 {tags}
56 56 <tr class="light">
57 57 <td colspan="3"><a class="list" href="{url}tags{sessionvars%urlparameter}">...</a></td>
58 58 </tr>
59 59 </table>
60 60
61 <h2><a href="{url}bookmarks{sessionvars%urlparameter}">Bookmarks</a></h2>
62 <table>
63 {bookmarks%bookmarkentry}
64 <tr class="light">
65 <td colspan="3"><a class="list" href="{url}bookmarks{sessionvars%urlparameter}">...</a></td>
66 </tr>
67 </table>
68
61 69 <h2 class="no-link">Branches</h2>
62 70 <table>
63 71 {branches%branchentry}
64 72 <tr class="light">
65 73 <td colspan="4"><a class="list" href="#">...</a></td>
66 74 </tr>
67 75 </table>
68 76 {footer}
@@ -1,1095 +1,1119
1 1 An attempt at more fully testing the hgweb web interface.
2 2 The following things are tested elsewhere and are therefore omitted:
3 3 - archive, tested in test-archive
4 4 - unbundle, tested in test-push-http
5 5 - changegroupsubset, tested in test-pull
6 6
7 7 Set up the repo
8 8
9 9 $ hg init test
10 10 $ cd test
11 11 $ mkdir da
12 12 $ echo foo > da/foo
13 13 $ echo foo > foo
14 14 $ hg ci -Ambase
15 15 adding da/foo
16 16 adding foo
17 17 $ hg tag 1.0
18 18 $ hg bookmark something
19 19 $ hg bookmark -r0 anotherthing
20 20 $ echo another > foo
21 21 $ hg branch stable
22 22 marked working directory as branch stable
23 23 $ hg ci -Ambranch
24 24 $ hg serve --config server.uncompressed=False -n test -p $HGPORT -d --pid-file=hg.pid -E errors.log
25 25 $ cat hg.pid >> $DAEMON_PIDS
26 26
27 27 Logs and changes
28 28
29 29 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/log/?style=atom'
30 30 200 Script output follows
31 31
32 32 <?xml version="1.0" encoding="ascii"?>
33 33 <feed xmlns="http://www.w3.org/2005/Atom">
34 34 <!-- Changelog -->
35 35 <id>http://*:$HGPORT/</id> (glob)
36 36 <link rel="self" href="http://*:$HGPORT/atom-log"/> (glob)
37 37 <link rel="alternate" href="http://*:$HGPORT/"/> (glob)
38 38 <title>test Changelog</title>
39 39 <updated>1970-01-01T00:00:00+00:00</updated>
40 40
41 41 <entry>
42 42 <title>branch</title>
43 43 <id>http://*:$HGPORT/#changeset-1d22e65f027e5a0609357e7d8e7508cd2ba5d2fe</id> (glob)
44 44 <link href="http://*:$HGPORT/rev/1d22e65f027e"/> (glob)
45 45 <author>
46 46 <name>test</name>
47 47 <email>&#116;&#101;&#115;&#116;</email>
48 48 </author>
49 49 <updated>1970-01-01T00:00:00+00:00</updated>
50 50 <published>1970-01-01T00:00:00+00:00</published>
51 51 <content type="xhtml">
52 52 <div xmlns="http://www.w3.org/1999/xhtml">
53 53 <pre xml:space="preserve">branch</pre>
54 54 </div>
55 55 </content>
56 56 </entry>
57 57 <entry>
58 58 <title>Added tag 1.0 for changeset 2ef0ac749a14</title>
59 59 <id>http://*:$HGPORT/#changeset-a4f92ed23982be056b9852de5dfe873eaac7f0de</id> (glob)
60 60 <link href="http://*:$HGPORT/rev/a4f92ed23982"/> (glob)
61 61 <author>
62 62 <name>test</name>
63 63 <email>&#116;&#101;&#115;&#116;</email>
64 64 </author>
65 65 <updated>1970-01-01T00:00:00+00:00</updated>
66 66 <published>1970-01-01T00:00:00+00:00</published>
67 67 <content type="xhtml">
68 68 <div xmlns="http://www.w3.org/1999/xhtml">
69 69 <pre xml:space="preserve">Added tag 1.0 for changeset 2ef0ac749a14</pre>
70 70 </div>
71 71 </content>
72 72 </entry>
73 73 <entry>
74 74 <title>base</title>
75 75 <id>http://*:$HGPORT/#changeset-2ef0ac749a14e4f57a5a822464a0902c6f7f448f</id> (glob)
76 76 <link href="http://*:$HGPORT/rev/2ef0ac749a14"/> (glob)
77 77 <author>
78 78 <name>test</name>
79 79 <email>&#116;&#101;&#115;&#116;</email>
80 80 </author>
81 81 <updated>1970-01-01T00:00:00+00:00</updated>
82 82 <published>1970-01-01T00:00:00+00:00</published>
83 83 <content type="xhtml">
84 84 <div xmlns="http://www.w3.org/1999/xhtml">
85 85 <pre xml:space="preserve">base</pre>
86 86 </div>
87 87 </content>
88 88 </entry>
89 89
90 90 </feed>
91 91 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/log/1/?style=atom'
92 92 200 Script output follows
93 93
94 94 <?xml version="1.0" encoding="ascii"?>
95 95 <feed xmlns="http://www.w3.org/2005/Atom">
96 96 <!-- Changelog -->
97 97 <id>http://*:$HGPORT/</id> (glob)
98 98 <link rel="self" href="http://*:$HGPORT/atom-log"/> (glob)
99 99 <link rel="alternate" href="http://*:$HGPORT/"/> (glob)
100 100 <title>test Changelog</title>
101 101 <updated>1970-01-01T00:00:00+00:00</updated>
102 102
103 103 <entry>
104 104 <title>branch</title>
105 105 <id>http://*:$HGPORT/#changeset-1d22e65f027e5a0609357e7d8e7508cd2ba5d2fe</id> (glob)
106 106 <link href="http://*:$HGPORT/rev/1d22e65f027e"/> (glob)
107 107 <author>
108 108 <name>test</name>
109 109 <email>&#116;&#101;&#115;&#116;</email>
110 110 </author>
111 111 <updated>1970-01-01T00:00:00+00:00</updated>
112 112 <published>1970-01-01T00:00:00+00:00</published>
113 113 <content type="xhtml">
114 114 <div xmlns="http://www.w3.org/1999/xhtml">
115 115 <pre xml:space="preserve">branch</pre>
116 116 </div>
117 117 </content>
118 118 </entry>
119 119 <entry>
120 120 <title>Added tag 1.0 for changeset 2ef0ac749a14</title>
121 121 <id>http://*:$HGPORT/#changeset-a4f92ed23982be056b9852de5dfe873eaac7f0de</id> (glob)
122 122 <link href="http://*:$HGPORT/rev/a4f92ed23982"/> (glob)
123 123 <author>
124 124 <name>test</name>
125 125 <email>&#116;&#101;&#115;&#116;</email>
126 126 </author>
127 127 <updated>1970-01-01T00:00:00+00:00</updated>
128 128 <published>1970-01-01T00:00:00+00:00</published>
129 129 <content type="xhtml">
130 130 <div xmlns="http://www.w3.org/1999/xhtml">
131 131 <pre xml:space="preserve">Added tag 1.0 for changeset 2ef0ac749a14</pre>
132 132 </div>
133 133 </content>
134 134 </entry>
135 135 <entry>
136 136 <title>base</title>
137 137 <id>http://*:$HGPORT/#changeset-2ef0ac749a14e4f57a5a822464a0902c6f7f448f</id> (glob)
138 138 <link href="http://*:$HGPORT/rev/2ef0ac749a14"/> (glob)
139 139 <author>
140 140 <name>test</name>
141 141 <email>&#116;&#101;&#115;&#116;</email>
142 142 </author>
143 143 <updated>1970-01-01T00:00:00+00:00</updated>
144 144 <published>1970-01-01T00:00:00+00:00</published>
145 145 <content type="xhtml">
146 146 <div xmlns="http://www.w3.org/1999/xhtml">
147 147 <pre xml:space="preserve">base</pre>
148 148 </div>
149 149 </content>
150 150 </entry>
151 151
152 152 </feed>
153 153 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/log/1/foo/?style=atom'
154 154 200 Script output follows
155 155
156 156 <?xml version="1.0" encoding="ascii"?>
157 157 <feed xmlns="http://www.w3.org/2005/Atom">
158 158 <id>http://*:$HGPORT/atom-log/tip/foo</id> (glob)
159 159 <link rel="self" href="http://*:$HGPORT/atom-log/tip/foo"/> (glob)
160 160 <title>test: foo history</title>
161 161 <updated>1970-01-01T00:00:00+00:00</updated>
162 162
163 163 <entry>
164 164 <title>base</title>
165 165 <id>http://*:$HGPORT/#changeset-2ef0ac749a14e4f57a5a822464a0902c6f7f448f</id> (glob)
166 166 <link href="http://*:$HGPORT/rev/2ef0ac749a14"/> (glob)
167 167 <author>
168 168 <name>test</name>
169 169 <email>&#116;&#101;&#115;&#116;</email>
170 170 </author>
171 171 <updated>1970-01-01T00:00:00+00:00</updated>
172 172 <published>1970-01-01T00:00:00+00:00</published>
173 173 <content type="xhtml">
174 174 <div xmlns="http://www.w3.org/1999/xhtml">
175 175 <pre xml:space="preserve">base</pre>
176 176 </div>
177 177 </content>
178 178 </entry>
179 179
180 180 </feed>
181 181 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/shortlog/'
182 182 200 Script output follows
183 183
184 184 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
185 185 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
186 186 <head>
187 187 <link rel="icon" href="/static/hgicon.png" type="image/png" />
188 188 <meta name="robots" content="index, nofollow" />
189 189 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
190 190
191 191 <title>test: log</title>
192 192 <link rel="alternate" type="application/atom+xml"
193 193 href="/atom-log" title="Atom feed for test" />
194 194 <link rel="alternate" type="application/rss+xml"
195 195 href="/rss-log" title="RSS feed for test" />
196 196 </head>
197 197 <body>
198 198
199 199 <div class="container">
200 200 <div class="menu">
201 201 <div class="logo">
202 202 <a href="http://mercurial.selenic.com/">
203 203 <img src="/static/hglogo.png" alt="mercurial" /></a>
204 204 </div>
205 205 <ul>
206 206 <li class="active">log</li>
207 207 <li><a href="/graph/1d22e65f027e">graph</a></li>
208 208 <li><a href="/tags">tags</a></li>
209 209 <li><a href="/bookmarks">bookmarks</a></li>
210 210 <li><a href="/branches">branches</a></li>
211 211 </ul>
212 212 <ul>
213 213 <li><a href="/rev/1d22e65f027e">changeset</a></li>
214 214 <li><a href="/file/1d22e65f027e">browse</a></li>
215 215 </ul>
216 216 <ul>
217 217
218 218 </ul>
219 219 <ul>
220 220 <li><a href="/help">help</a></li>
221 221 </ul>
222 222 </div>
223 223
224 224 <div class="main">
225 225 <h2><a href="/">test</a></h2>
226 226 <h3>log</h3>
227 227
228 228 <form class="search" action="/log">
229 229
230 230 <p><input name="rev" id="search1" type="text" size="30" /></p>
231 231 <div id="hint">find changesets by author, revision,
232 232 files, or words in the commit message</div>
233 233 </form>
234 234
235 235 <div class="navigate">
236 236 <a href="/shortlog/2?revcount=30">less</a>
237 237 <a href="/shortlog/2?revcount=120">more</a>
238 238 | rev 2: <a href="/shortlog/2ef0ac749a14">(0)</a> <a href="/shortlog/tip">tip</a>
239 239 </div>
240 240
241 241 <table class="bigtable">
242 242 <tr>
243 243 <th class="age">age</th>
244 244 <th class="author">author</th>
245 245 <th class="description">description</th>
246 246 </tr>
247 247 <tr class="parity0">
248 248 <td class="age">1970-01-01</td>
249 249 <td class="author">test</td>
250 250 <td class="description"><a href="/rev/1d22e65f027e">branch</a><span class="branchhead">stable</span> <span class="tag">tip</span> <span class="tag">something</span> </td>
251 251 </tr>
252 252 <tr class="parity1">
253 253 <td class="age">1970-01-01</td>
254 254 <td class="author">test</td>
255 255 <td class="description"><a href="/rev/a4f92ed23982">Added tag 1.0 for changeset 2ef0ac749a14</a><span class="branchhead">default</span> </td>
256 256 </tr>
257 257 <tr class="parity0">
258 258 <td class="age">1970-01-01</td>
259 259 <td class="author">test</td>
260 260 <td class="description"><a href="/rev/2ef0ac749a14">base</a><span class="tag">1.0</span> <span class="tag">anotherthing</span> </td>
261 261 </tr>
262 262
263 263 </table>
264 264
265 265 <div class="navigate">
266 266 <a href="/shortlog/2?revcount=30">less</a>
267 267 <a href="/shortlog/2?revcount=120">more</a>
268 268 | rev 2: <a href="/shortlog/2ef0ac749a14">(0)</a> <a href="/shortlog/tip">tip</a>
269 269 </div>
270 270
271 271 </div>
272 272 </div>
273 273
274 274
275 275
276 276 </body>
277 277 </html>
278 278
279 279 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/rev/0/'
280 280 200 Script output follows
281 281
282 282 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
283 283 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
284 284 <head>
285 285 <link rel="icon" href="/static/hgicon.png" type="image/png" />
286 286 <meta name="robots" content="index, nofollow" />
287 287 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
288 288
289 289 <title>test: 2ef0ac749a14</title>
290 290 </head>
291 291 <body>
292 292 <div class="container">
293 293 <div class="menu">
294 294 <div class="logo">
295 295 <a href="http://mercurial.selenic.com/">
296 296 <img src="/static/hglogo.png" alt="mercurial" /></a>
297 297 </div>
298 298 <ul>
299 299 <li><a href="/shortlog/2ef0ac749a14">log</a></li>
300 300 <li><a href="/graph/2ef0ac749a14">graph</a></li>
301 301 <li><a href="/tags">tags</a></li>
302 302 <li><a href="/bookmarks">bookmarks</a></li>
303 303 <li><a href="/branches">branches</a></li>
304 304 </ul>
305 305 <ul>
306 306 <li class="active">changeset</li>
307 307 <li><a href="/raw-rev/2ef0ac749a14">raw</a></li>
308 308 <li><a href="/file/2ef0ac749a14">browse</a></li>
309 309 </ul>
310 310 <ul>
311 311
312 312 </ul>
313 313 <ul>
314 314 <li><a href="/help">help</a></li>
315 315 </ul>
316 316 </div>
317 317
318 318 <div class="main">
319 319
320 320 <h2><a href="/">test</a></h2>
321 321 <h3>changeset 0:2ef0ac749a14 <span class="tag">1.0</span> <span class="tag">anotherthing</span> </h3>
322 322
323 323 <form class="search" action="/log">
324 324
325 325 <p><input name="rev" id="search1" type="text" size="30" /></p>
326 326 <div id="hint">find changesets by author, revision,
327 327 files, or words in the commit message</div>
328 328 </form>
329 329
330 330 <div class="description">base</div>
331 331
332 332 <table id="changesetEntry">
333 333 <tr>
334 334 <th class="author">author</th>
335 335 <td class="author">&#116;&#101;&#115;&#116;</td>
336 336 </tr>
337 337 <tr>
338 338 <th class="date">date</th>
339 339 <td class="date">Thu Jan 01 00:00:00 1970 +0000 (1970-01-01)</td></tr>
340 340 <tr>
341 341 <th class="author">parents</th>
342 342 <td class="author"></td>
343 343 </tr>
344 344 <tr>
345 345 <th class="author">children</th>
346 346 <td class="author"> <a href="/rev/a4f92ed23982">a4f92ed23982</a></td>
347 347 </tr>
348 348 <tr>
349 349 <th class="files">files</th>
350 350 <td class="files"><a href="/file/2ef0ac749a14/da/foo">da/foo</a> <a href="/file/2ef0ac749a14/foo">foo</a> </td>
351 351 </tr>
352 352 </table>
353 353
354 354 <div class="overflow">
355 355 <div class="sourcefirst"> line diff</div>
356 356
357 357 <div class="source bottomline parity0"><pre><a href="#l1.1" id="l1.1"> 1.1</a> <span class="minusline">--- /dev/null Thu Jan 01 00:00:00 1970 +0000
358 358 </span><a href="#l1.2" id="l1.2"> 1.2</a> <span class="plusline">+++ b/da/foo Thu Jan 01 00:00:00 1970 +0000
359 359 </span><a href="#l1.3" id="l1.3"> 1.3</a> <span class="atline">@@ -0,0 +1,1 @@
360 360 </span><a href="#l1.4" id="l1.4"> 1.4</a> <span class="plusline">+foo
361 361 </span></pre></div><div class="source bottomline parity1"><pre><a href="#l2.1" id="l2.1"> 2.1</a> <span class="minusline">--- /dev/null Thu Jan 01 00:00:00 1970 +0000
362 362 </span><a href="#l2.2" id="l2.2"> 2.2</a> <span class="plusline">+++ b/foo Thu Jan 01 00:00:00 1970 +0000
363 363 </span><a href="#l2.3" id="l2.3"> 2.3</a> <span class="atline">@@ -0,0 +1,1 @@
364 364 </span><a href="#l2.4" id="l2.4"> 2.4</a> <span class="plusline">+foo
365 365 </span></pre></div>
366 366 </div>
367 367
368 368 </div>
369 369 </div>
370 370
371 371
372 372 </body>
373 373 </html>
374 374
375 375 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/rev/1/?style=raw'
376 376 200 Script output follows
377 377
378 378
379 379 # HG changeset patch
380 380 # User test
381 381 # Date 0 0
382 382 # Node ID a4f92ed23982be056b9852de5dfe873eaac7f0de
383 383 # Parent 2ef0ac749a14e4f57a5a822464a0902c6f7f448f
384 384 Added tag 1.0 for changeset 2ef0ac749a14
385 385
386 386 diff -r 2ef0ac749a14 -r a4f92ed23982 .hgtags
387 387 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
388 388 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
389 389 @@ -0,0 +1,1 @@
390 390 +2ef0ac749a14e4f57a5a822464a0902c6f7f448f 1.0
391 391
392 392 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/log?rev=base'
393 393 200 Script output follows
394 394
395 395 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
396 396 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
397 397 <head>
398 398 <link rel="icon" href="/static/hgicon.png" type="image/png" />
399 399 <meta name="robots" content="index, nofollow" />
400 400 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
401 401
402 402 <title>test: searching for base</title>
403 403 </head>
404 404 <body>
405 405
406 406 <div class="container">
407 407 <div class="menu">
408 408 <div class="logo">
409 409 <a href="http://mercurial.selenic.com/">
410 410 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
411 411 </div>
412 412 <ul>
413 413 <li><a href="/shortlog">log</a></li>
414 414 <li><a href="/graph">graph</a></li>
415 415 <li><a href="/tags">tags</a></li>
416 416 <li><a href="/bookmarks">bookmarks</a></li>
417 417 <li><a href="/branches">branches</a></li>
418 418 <li><a href="/help">help</a></li>
419 419 </ul>
420 420 </div>
421 421
422 422 <div class="main">
423 423 <h2><a href="/">test</a></h2>
424 424 <h3>searching for 'base'</h3>
425 425
426 426 <form class="search" action="/log">
427 427
428 428 <p><input name="rev" id="search1" type="text" size="30"></p>
429 429 <div id="hint">find changesets by author, revision,
430 430 files, or words in the commit message</div>
431 431 </form>
432 432
433 433 <div class="navigate">
434 434 <a href="/search/?rev=base&revcount=5">less</a>
435 435 <a href="/search/?rev=base&revcount=20">more</a>
436 436 </div>
437 437
438 438 <table class="bigtable">
439 439 <tr>
440 440 <th class="age">age</th>
441 441 <th class="author">author</th>
442 442 <th class="description">description</th>
443 443 </tr>
444 444 <tr class="parity0">
445 445 <td class="age">1970-01-01</td>
446 446 <td class="author">test</td>
447 447 <td class="description"><a href="/rev/2ef0ac749a14">base</a><span class="tag">1.0</span> <span class="tag">anotherthing</span> </td>
448 448 </tr>
449 449
450 450 </table>
451 451
452 452 <div class="navigate">
453 453 <a href="/search/?rev=base&revcount=5">less</a>
454 454 <a href="/search/?rev=base&revcount=20">more</a>
455 455 </div>
456 456
457 457 </div>
458 458 </div>
459 459
460 460
461 461
462 462 </body>
463 463 </html>
464 464
465 465
466 466 File-related
467 467
468 468 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/file/1/foo/?style=raw'
469 469 200 Script output follows
470 470
471 471 foo
472 472 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/annotate/1/foo/?style=raw'
473 473 200 Script output follows
474 474
475 475
476 476 test@0: foo
477 477
478 478
479 479
480 480
481 481 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/file/1/?style=raw'
482 482 200 Script output follows
483 483
484 484
485 485 drwxr-xr-x da
486 486 -rw-r--r-- 45 .hgtags
487 487 -rw-r--r-- 4 foo
488 488
489 489
490 490 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/file/1/foo'
491 491 200 Script output follows
492 492
493 493 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
494 494 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
495 495 <head>
496 496 <link rel="icon" href="/static/hgicon.png" type="image/png" />
497 497 <meta name="robots" content="index, nofollow" />
498 498 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
499 499
500 500 <title>test: a4f92ed23982 foo</title>
501 501 </head>
502 502 <body>
503 503
504 504 <div class="container">
505 505 <div class="menu">
506 506 <div class="logo">
507 507 <a href="http://mercurial.selenic.com/">
508 508 <img src="/static/hglogo.png" alt="mercurial" /></a>
509 509 </div>
510 510 <ul>
511 511 <li><a href="/shortlog/a4f92ed23982">log</a></li>
512 512 <li><a href="/graph/a4f92ed23982">graph</a></li>
513 513 <li><a href="/tags">tags</a></li>
514 514 <li><a href="/branches">branches</a></li>
515 515 </ul>
516 516 <ul>
517 517 <li><a href="/rev/a4f92ed23982">changeset</a></li>
518 518 <li><a href="/file/a4f92ed23982/">browse</a></li>
519 519 </ul>
520 520 <ul>
521 521 <li class="active">file</li>
522 522 <li><a href="/file/tip/foo">latest</a></li>
523 523 <li><a href="/diff/a4f92ed23982/foo">diff</a></li>
524 524 <li><a href="/annotate/a4f92ed23982/foo">annotate</a></li>
525 525 <li><a href="/log/a4f92ed23982/foo">file log</a></li>
526 526 <li><a href="/raw-file/a4f92ed23982/foo">raw</a></li>
527 527 </ul>
528 528 <ul>
529 529 <li><a href="/help">help</a></li>
530 530 </ul>
531 531 </div>
532 532
533 533 <div class="main">
534 534 <h2><a href="/">test</a></h2>
535 535 <h3>view foo @ 1:a4f92ed23982</h3>
536 536
537 537 <form class="search" action="/log">
538 538
539 539 <p><input name="rev" id="search1" type="text" size="30" /></p>
540 540 <div id="hint">find changesets by author, revision,
541 541 files, or words in the commit message</div>
542 542 </form>
543 543
544 544 <div class="description">Added tag 1.0 for changeset 2ef0ac749a14</div>
545 545
546 546 <table id="changesetEntry">
547 547 <tr>
548 548 <th class="author">author</th>
549 549 <td class="author">&#116;&#101;&#115;&#116;</td>
550 550 </tr>
551 551 <tr>
552 552 <th class="date">date</th>
553 553 <td class="date">Thu Jan 01 00:00:00 1970 +0000 (1970-01-01)</td>
554 554 </tr>
555 555 <tr>
556 556 <th class="author">parents</th>
557 557 <td class="author"></td>
558 558 </tr>
559 559 <tr>
560 560 <th class="author">children</th>
561 561 <td class="author"><a href="/file/1d22e65f027e/foo">1d22e65f027e</a> </td>
562 562 </tr>
563 563
564 564 </table>
565 565
566 566 <div class="overflow">
567 567 <div class="sourcefirst"> line source</div>
568 568
569 569 <div class="parity0 source"><a href="#l1" id="l1"> 1</a> foo
570 570 </div>
571 571 <div class="sourcelast"></div>
572 572 </div>
573 573 </div>
574 574 </div>
575 575
576 576
577 577
578 578 </body>
579 579 </html>
580 580
581 581 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/filediff/1/foo/?style=raw'
582 582 200 Script output follows
583 583
584 584
585 585 diff -r 000000000000 -r a4f92ed23982 foo
586 586 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
587 587 +++ b/foo Thu Jan 01 00:00:00 1970 +0000
588 588 @@ -0,0 +1,1 @@
589 589 +foo
590 590
591 591
592 592
593 593
594 594
595 595 Overviews
596 596
597 597 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/raw-tags'
598 598 200 Script output follows
599 599
600 600 tip 1d22e65f027e5a0609357e7d8e7508cd2ba5d2fe
601 601 1.0 2ef0ac749a14e4f57a5a822464a0902c6f7f448f
602 602 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/raw-branches'
603 603 200 Script output follows
604 604
605 605 stable 1d22e65f027e5a0609357e7d8e7508cd2ba5d2fe open
606 606 default a4f92ed23982be056b9852de5dfe873eaac7f0de inactive
607 607 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/raw-bookmarks'
608 608 200 Script output follows
609 609
610 610 anotherthing 2ef0ac749a14e4f57a5a822464a0902c6f7f448f
611 611 something 1d22e65f027e5a0609357e7d8e7508cd2ba5d2fe
612 612 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/summary/?style=gitweb'
613 613 200 Script output follows
614 614
615 615 <?xml version="1.0" encoding="ascii"?>
616 616 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
617 617 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
618 618 <head>
619 619 <link rel="icon" href="/static/hgicon.png" type="image/png" />
620 620 <meta name="robots" content="index, nofollow"/>
621 621 <link rel="stylesheet" href="/static/style-gitweb.css" type="text/css" />
622 622
623 623
624 624 <title>test: Summary</title>
625 625 <link rel="alternate" type="application/atom+xml"
626 626 href="/atom-log" title="Atom feed for test"/>
627 627 <link rel="alternate" type="application/rss+xml"
628 628 href="/rss-log" title="RSS feed for test"/>
629 629 </head>
630 630 <body>
631 631
632 632 <div class="page_header">
633 633 <a href="http://mercurial.selenic.com/" title="Mercurial" style="float: right;">Mercurial</a><a href="/summary?style=gitweb">test</a> / summary
634 634
635 635 <form action="/log">
636 636 <input type="hidden" name="style" value="gitweb" />
637 637 <div class="search">
638 638 <input type="text" name="rev" />
639 639 </div>
640 640 </form>
641 641 </div>
642 642
643 643 <div class="page_nav">
644 644 summary |
645 645 <a href="/shortlog?style=gitweb">shortlog</a> |
646 646 <a href="/log?style=gitweb">changelog</a> |
647 647 <a href="/graph?style=gitweb">graph</a> |
648 648 <a href="/tags?style=gitweb">tags</a> |
649 649 <a href="/bookmarks?style=gitweb">bookmarks</a> |
650 650 <a href="/branches?style=gitweb">branches</a> |
651 651 <a href="/file/1d22e65f027e?style=gitweb">files</a> |
652 652 <a href="/help?style=gitweb">help</a>
653 653 <br/>
654 654 </div>
655 655
656 656 <div class="title">&nbsp;</div>
657 657 <table cellspacing="0">
658 658 <tr><td>description</td><td>unknown</td></tr>
659 659 <tr><td>owner</td><td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td></tr>
660 660 <tr><td>last change</td><td>Thu, 01 Jan 1970 00:00:00 +0000</td></tr>
661 661 </table>
662 662
663 663 <div><a class="title" href="/shortlog?style=gitweb">changes</a></div>
664 664 <table cellspacing="0">
665 665
666 666 <tr class="parity0">
667 667 <td class="age"><i>1970-01-01</i></td>
668 668 <td><i>test</i></td>
669 669 <td>
670 670 <a class="list" href="/rev/1d22e65f027e?style=gitweb">
671 671 <b>branch</b>
672 672 <span class="logtags"><span class="branchtag" title="stable">stable</span> <span class="tagtag" title="tip">tip</span> <span class="bookmarktag" title="something">something</span> </span>
673 673 </a>
674 674 </td>
675 675 <td class="link" nowrap>
676 676 <a href="/rev/1d22e65f027e?style=gitweb">changeset</a> |
677 677 <a href="/file/1d22e65f027e?style=gitweb">files</a>
678 678 </td>
679 679 </tr>
680 680 <tr class="parity1">
681 681 <td class="age"><i>1970-01-01</i></td>
682 682 <td><i>test</i></td>
683 683 <td>
684 684 <a class="list" href="/rev/a4f92ed23982?style=gitweb">
685 685 <b>Added tag 1.0 for changeset 2ef0ac749a14</b>
686 686 <span class="logtags"><span class="branchtag" title="default">default</span> </span>
687 687 </a>
688 688 </td>
689 689 <td class="link" nowrap>
690 690 <a href="/rev/a4f92ed23982?style=gitweb">changeset</a> |
691 691 <a href="/file/a4f92ed23982?style=gitweb">files</a>
692 692 </td>
693 693 </tr>
694 694 <tr class="parity0">
695 695 <td class="age"><i>1970-01-01</i></td>
696 696 <td><i>test</i></td>
697 697 <td>
698 698 <a class="list" href="/rev/2ef0ac749a14?style=gitweb">
699 699 <b>base</b>
700 700 <span class="logtags"><span class="tagtag" title="1.0">1.0</span> <span class="bookmarktag" title="anotherthing">anotherthing</span> </span>
701 701 </a>
702 702 </td>
703 703 <td class="link" nowrap>
704 704 <a href="/rev/2ef0ac749a14?style=gitweb">changeset</a> |
705 705 <a href="/file/2ef0ac749a14?style=gitweb">files</a>
706 706 </td>
707 707 </tr>
708 708 <tr class="light"><td colspan="4"><a class="list" href="/shortlog?style=gitweb">...</a></td></tr>
709 709 </table>
710 710
711 711 <div><a class="title" href="/tags?style=gitweb">tags</a></div>
712 712 <table cellspacing="0">
713 713
714 714 <tr class="parity0">
715 715 <td class="age"><i>1970-01-01</i></td>
716 716 <td><a class="list" href="/rev/2ef0ac749a14?style=gitweb"><b>1.0</b></a></td>
717 717 <td class="link">
718 718 <a href="/rev/2ef0ac749a14?style=gitweb">changeset</a> |
719 719 <a href="/log/2ef0ac749a14?style=gitweb">changelog</a> |
720 720 <a href="/file/2ef0ac749a14?style=gitweb">files</a>
721 721 </td>
722 722 </tr>
723 723 <tr class="light"><td colspan="3"><a class="list" href="/tags?style=gitweb">...</a></td></tr>
724 724 </table>
725 725
726 <div><a class="title" href="/bookmarks?style=gitweb">bookmarks</a></div>
727 <table cellspacing="0">
728
729 <tr class="parity0">
730 <td class="age"><i>1970-01-01</i></td>
731 <td><a class="list" href="/rev/2ef0ac749a14?style=gitweb"><b>anotherthing</b></a></td>
732 <td class="link">
733 <a href="/rev/2ef0ac749a14?style=gitweb">changeset</a> |
734 <a href="/log/2ef0ac749a14?style=gitweb">changelog</a> |
735 <a href="/file/2ef0ac749a14?style=gitweb">files</a>
736 </td>
737 </tr>
738 <tr class="parity1">
739 <td class="age"><i>1970-01-01</i></td>
740 <td><a class="list" href="/rev/1d22e65f027e?style=gitweb"><b>something</b></a></td>
741 <td class="link">
742 <a href="/rev/1d22e65f027e?style=gitweb">changeset</a> |
743 <a href="/log/1d22e65f027e?style=gitweb">changelog</a> |
744 <a href="/file/1d22e65f027e?style=gitweb">files</a>
745 </td>
746 </tr>
747 <tr class="light"><td colspan="3"><a class="list" href="/bookmarks?style=gitweb">...</a></td></tr>
748 </table>
749
726 750 <div><a class="title" href="#">branches</a></div>
727 751 <table cellspacing="0">
728 752
729 753 <tr class="parity0">
730 754 <td class="age"><i>1970-01-01</i></td>
731 755 <td><a class="list" href="/shortlog/1d22e65f027e?style=gitweb"><b>1d22e65f027e</b></a></td>
732 756 <td class="">stable</td>
733 757 <td class="link">
734 758 <a href="/changeset/1d22e65f027e?style=gitweb">changeset</a> |
735 759 <a href="/log/1d22e65f027e?style=gitweb">changelog</a> |
736 760 <a href="/file/1d22e65f027e?style=gitweb">files</a>
737 761 </td>
738 762 </tr>
739 763 <tr class="parity1">
740 764 <td class="age"><i>1970-01-01</i></td>
741 765 <td><a class="list" href="/shortlog/a4f92ed23982?style=gitweb"><b>a4f92ed23982</b></a></td>
742 766 <td class="">default</td>
743 767 <td class="link">
744 768 <a href="/changeset/a4f92ed23982?style=gitweb">changeset</a> |
745 769 <a href="/log/a4f92ed23982?style=gitweb">changelog</a> |
746 770 <a href="/file/a4f92ed23982?style=gitweb">files</a>
747 771 </td>
748 772 </tr>
749 773 <tr class="light">
750 774 <td colspan="4"><a class="list" href="#">...</a></td>
751 775 </tr>
752 776 </table>
753 777 <div class="page_footer">
754 778 <div class="page_footer_text">test</div>
755 779 <div class="rss_logo">
756 780 <a href="/rss-log">RSS</a>
757 781 <a href="/atom-log">Atom</a>
758 782 </div>
759 783 <br />
760 784
761 785 </div>
762 786 </body>
763 787 </html>
764 788
765 789 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/graph/?style=gitweb'
766 790 200 Script output follows
767 791
768 792 <?xml version="1.0" encoding="ascii"?>
769 793 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
770 794 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
771 795 <head>
772 796 <link rel="icon" href="/static/hgicon.png" type="image/png" />
773 797 <meta name="robots" content="index, nofollow"/>
774 798 <link rel="stylesheet" href="/static/style-gitweb.css" type="text/css" />
775 799
776 800
777 801 <title>test: Graph</title>
778 802 <link rel="alternate" type="application/atom+xml"
779 803 href="/atom-log" title="Atom feed for test"/>
780 804 <link rel="alternate" type="application/rss+xml"
781 805 href="/rss-log" title="RSS feed for test"/>
782 806 <!--[if IE]><script type="text/javascript" src="/static/excanvas.js"></script><![endif]-->
783 807 </head>
784 808 <body>
785 809
786 810 <div class="page_header">
787 811 <a href="http://mercurial.selenic.com/" title="Mercurial" style="float: right;">Mercurial</a><a href="/summary?style=gitweb">test</a> / graph
788 812 </div>
789 813
790 814 <form action="/log">
791 815 <input type="hidden" name="style" value="gitweb" />
792 816 <div class="search">
793 817 <input type="text" name="rev" />
794 818 </div>
795 819 </form>
796 820 <div class="page_nav">
797 821 <a href="/summary?style=gitweb">summary</a> |
798 822 <a href="/shortlog?style=gitweb">shortlog</a> |
799 823 <a href="/log/2?style=gitweb">changelog</a> |
800 824 graph |
801 825 <a href="/tags?style=gitweb">tags</a> |
802 826 <a href="/bookmarks?style=gitweb">bookmarks</a> |
803 827 <a href="/branches?style=gitweb">branches</a> |
804 828 <a href="/file/1d22e65f027e?style=gitweb">files</a> |
805 829 <a href="/help?style=gitweb">help</a>
806 830 <br/>
807 831 <a href="/graph/2?style=gitweb&revcount=30">less</a>
808 832 <a href="/graph/2?style=gitweb&revcount=120">more</a>
809 833 | <a href="/graph/2ef0ac749a14?style=gitweb">(0)</a> <a href="/graph/2ef0ac749a14?style=gitweb">-2</a> <a href="/graph/tip?style=gitweb">tip</a> <br/>
810 834 </div>
811 835
812 836 <div class="title">&nbsp;</div>
813 837
814 838 <noscript>The revision graph only works with JavaScript-enabled browsers.</noscript>
815 839
816 840 <div id="wrapper">
817 841 <ul id="nodebgs"></ul>
818 842 <canvas id="graph" width="480" height="129"></canvas>
819 843 <ul id="graphnodes"></ul>
820 844 </div>
821 845
822 846 <script type="text/javascript" src="/static/graph.js"></script>
823 847 <script>
824 848 <!-- hide script content
825 849
826 850 var data = [["1d22e65f027e", [0, 1], [[0, 0, 1]], "branch", "test", "1970-01-01", ["stable", true], ["tip"], ["something"]], ["a4f92ed23982", [0, 1], [[0, 0, 1]], "Added tag 1.0 for changeset 2ef0ac749a14", "test", "1970-01-01", ["default", true], [], []], ["2ef0ac749a14", [0, 1], [], "base", "test", "1970-01-01", ["default", false], ["1.0"], ["anotherthing"]]];
827 851 var graph = new Graph();
828 852 graph.scale(39);
829 853
830 854 graph.edge = function(x0, y0, x1, y1, color) {
831 855
832 856 this.setColor(color, 0.0, 0.65);
833 857 this.ctx.beginPath();
834 858 this.ctx.moveTo(x0, y0);
835 859 this.ctx.lineTo(x1, y1);
836 860 this.ctx.stroke();
837 861
838 862 }
839 863
840 864 var revlink = '<li style="_STYLE"><span class="desc">';
841 865 revlink += '<a class="list" href="/rev/_NODEID?style=gitweb" title="_NODEID"><b>_DESC</b></a>';
842 866 revlink += '</span> _TAGS';
843 867 revlink += '<span class="info">_DATE, by _USER</span></li>';
844 868
845 869 graph.vertex = function(x, y, color, parity, cur) {
846 870
847 871 this.ctx.beginPath();
848 872 color = this.setColor(color, 0.25, 0.75);
849 873 this.ctx.arc(x, y, radius, 0, Math.PI * 2, true);
850 874 this.ctx.fill();
851 875
852 876 var bg = '<li class="bg parity' + parity + '"></li>';
853 877 var left = (this.columns + 1) * this.bg_height;
854 878 var nstyle = 'padding-left: ' + left + 'px;';
855 879 var item = revlink.replace(/_STYLE/, nstyle);
856 880 item = item.replace(/_PARITY/, 'parity' + parity);
857 881 item = item.replace(/_NODEID/, cur[0]);
858 882 item = item.replace(/_NODEID/, cur[0]);
859 883 item = item.replace(/_DESC/, cur[3]);
860 884 item = item.replace(/_USER/, cur[4]);
861 885 item = item.replace(/_DATE/, cur[5]);
862 886
863 887 var tagspan = '';
864 888 if (cur[7].length || cur[8].length || (cur[6][0] != 'default' || cur[6][1])) {
865 889 tagspan = '<span class="logtags">';
866 890 if (cur[6][1]) {
867 891 tagspan += '<span class="branchtag" title="' + cur[6][0] + '">';
868 892 tagspan += cur[6][0] + '</span> ';
869 893 } else if (!cur[6][1] && cur[6][0] != 'default') {
870 894 tagspan += '<span class="inbranchtag" title="' + cur[6][0] + '">';
871 895 tagspan += cur[6][0] + '</span> ';
872 896 }
873 897 if (cur[7].length) {
874 898 for (var t in cur[7]) {
875 899 var tag = cur[7][t];
876 900 tagspan += '<span class="tagtag">' + tag + '</span> ';
877 901 }
878 902 }
879 903 if (cur[8].length) {
880 904 for (var t in cur[8]) {
881 905 var bookmark = cur[8][t];
882 906 tagspan += '<span class="bookmarktag">' + bookmark + '</span> ';
883 907 }
884 908 }
885 909 tagspan += '</span>';
886 910 }
887 911
888 912 item = item.replace(/_TAGS/, tagspan);
889 913 return [bg, item];
890 914
891 915 }
892 916
893 917 graph.render(data);
894 918
895 919 // stop hiding script -->
896 920 </script>
897 921
898 922 <div class="page_nav">
899 923 <a href="/graph/2?style=gitweb&revcount=30">less</a>
900 924 <a href="/graph/2?style=gitweb&revcount=120">more</a>
901 925 | <a href="/graph/2ef0ac749a14?style=gitweb">(0)</a> <a href="/graph/2ef0ac749a14?style=gitweb">-2</a> <a href="/graph/tip?style=gitweb">tip</a>
902 926 </div>
903 927
904 928 <div class="page_footer">
905 929 <div class="page_footer_text">test</div>
906 930 <div class="rss_logo">
907 931 <a href="/rss-log">RSS</a>
908 932 <a href="/atom-log">Atom</a>
909 933 </div>
910 934 <br />
911 935
912 936 </div>
913 937 </body>
914 938 </html>
915 939
916 940
917 941 capabilities
918 942
919 943 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=capabilities'; echo
920 944 200 Script output follows
921 945
922 946 lookup changegroupsubset branchmap pushkey known getbundle unbundle=HG10GZ,HG10BZ,HG10UN
923 947
924 948 heads
925 949
926 950 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=heads'
927 951 200 Script output follows
928 952
929 953 1d22e65f027e5a0609357e7d8e7508cd2ba5d2fe
930 954
931 955 branches
932 956
933 957 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=branches&nodes=0000000000000000000000000000000000000000'
934 958 200 Script output follows
935 959
936 960 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
937 961
938 962 changegroup
939 963
940 964 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=changegroup&roots=0000000000000000000000000000000000000000'
941 965 200 Script output follows
942 966
943 967 x\x9c\xbdTMHUA\x14\xbe\xa8\xf9\xec\xda&\x10\x11*\xb8\x88\x81\x99\xbef\xe6\xce\xbdw\xc6\xf2a\x16E\x1b\x11[%\x98\xcc\xaf\x8f\x8c\xf7\xc0\xf7\x82 (esc)
944 968 4\x11KP2m\x95\xad*\xabE\x05AP\xd0\xc22Z\x14\xf9\x03\xb9j\xa3\x9b$\xa4MJ\xb4\x90\xc0\x9a\x9bO0\x10\xdf\x13\xa2\x81\x0f\x869g\xe6|\xe7\x9c\xef\x8ceY\xf7\xa2KO\xd2\xb7K\x16~\\n\xe9\xad\x90w\x86\xab\x93W\x8e\xdf\xb0r\\Y\xee6(\xa2)\xf6\x95\xc6\x01\xe4\x1az\x80R\xe8kN\x98\xe7R\xa4\xa9K@\xe0!A\xb4k\xa7U*m\x03\x07\xd8\x92\x1d\xd2\xc9\xa4\x1d\xc2\xe6,\xa5\xcc+\x1f\xef\xafDgi\xef\xab\x1d\x1d\xb7\x9a\xe7[W\xfbc\x8f\xde-\xcd\xe7\xcaz\xb3\xbb\x19\xd3\x81\x10>c>\x08\x00"X\x11\xc2\x84@\xd2\xe7B*L\x00\x01P\x04R\xc3@\xbaB0\xdb8#\x83:\x83\xa2h\xbc=\xcd\xdaS\xe1Y,L\xd3\xa0\xf2\xa8\x94J:\xe6\xd8\x81Q\xe0\xe8d\xa7#\xe2,\xd1\xaeR*\xed \xa5\x01\x13\x01\xa6\x0cb\xe3;\xbe\xaf\xfcK[^wK\xe1N\xaf\xbbk\xe8B\xd1\xf4\xc1\x07\xb3\xab[\x10\xfdkmvwcB\xa6\xa4\xd4G\xc4D\xc2\x141\xad\x91\x10\x00\x08J\x81\xcb}\xee \xee+W\xba\x8a\x80\x90|\xd4\xa0\xd6\xa0\xd4T\xde\xe1\x9d,!\xe2\xb5\xa94\xe3\xe7\xd5\x9f\x06\x18\xcba\x03aP\xb8f\xcd\x04\x1a_\\9\xf1\xed\xe4\x9e\xe5\xa6\xd1\xd2\x9f\x03\xa7o\xae\x90H\xf3\xfb\xef\xffH3\xadk (esc)
945 969 \xb0\x90\x92\x88\xb9\x14"\x068\xc2\x1e@\x00\xbb\x8a)\xd3'\x859 (esc)
946 970 \xa8\x80\x84S \xa5\xbd-g\x13`\xe4\xdc\xc3H^\xdf\xe2\xc0TM\xc7\xf4BO\xcf\xde\xae\xe5\xae#\x1frM(K\x97`F\x19\x16s\x05GD\xb9\x01\xc1\x00+\x8c|\x9fp\xc11\xf0\x14\x00\x9cJ\x82<\xe0\x12\x9f\xc1\x90\xd0\xf5\xc8\x19>Pr\xaa\xeaW\xf5\xc4\xae\xd1\xfc\x17\xcf'\x13u\xb1\x9e\xcdHnC\x0e\xcc`\xc8\xa0&\xac\x0e\xf1|\x8c\x10$\xc4\x8c\xa2p\x05`\xdc\x08 \x80\xc4\xd7Rr-\x94\x10\x102\xedi;\xf3f\xf1z\x16\x86\xdb\xd8d\xe5\xe7\x8b\xf5\x8d\rzp\xb2\xfe\xac\xf5\xf2\xd3\xfe\xfckws\xedt\x96b\xd5l\x1c\x0b\x85\xb5\x170\x8f\x11\x84\xb0\x8f\x19\xa0\x00 _\x07\x1ac\xa2\xc3\x89Z\xe7\x96\xf9 \xccNFg\xc7F\xaa\x8a+\x9a\x9cc_\x17\x1b\x17\x9e]z38<\x97+\xb5,",\xc8\xc8?\\\x91\xff\x17.~U\x96\x97\xf5%\xdeN<\x8e\xf5\x97%\xe7^\xcfL\xed~\xda\x96k\xdc->\x86\x02\x83"\x96H\xa6\xe3\xaas=-\xeb7\xe5\xda\x8f\xbc (no-eol) (esc)
947 971
948 972 stream_out
949 973
950 974 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=stream_out'
951 975 200 Script output follows
952 976
953 977 1
954 978
955 979 failing unbundle, requires POST request
956 980
957 981 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=unbundle'
958 982 405 push requires POST request
959 983
960 984 0
961 985 push requires POST request
962 986 [1]
963 987
964 988 Static files
965 989
966 990 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/static/style.css'
967 991 200 Script output follows
968 992
969 993 a { text-decoration:none; }
970 994 .age { white-space:nowrap; }
971 995 .date { white-space:nowrap; }
972 996 .indexlinks { white-space:nowrap; }
973 997 .parity0 { background-color: #ddd; }
974 998 .parity1 { background-color: #eee; }
975 999 .lineno { width: 60px; color: #aaa; font-size: smaller;
976 1000 text-align: right; }
977 1001 .plusline { color: green; }
978 1002 .minusline { color: red; }
979 1003 .atline { color: purple; }
980 1004 .annotate { font-size: smaller; text-align: right; padding-right: 1em; }
981 1005 .buttons a {
982 1006 background-color: #666;
983 1007 padding: 2pt;
984 1008 color: white;
985 1009 font-family: sans;
986 1010 font-weight: bold;
987 1011 }
988 1012 .navigate a {
989 1013 background-color: #ccc;
990 1014 padding: 2pt;
991 1015 font-family: sans;
992 1016 color: black;
993 1017 }
994 1018
995 1019 .metatag {
996 1020 background-color: #888;
997 1021 color: white;
998 1022 text-align: right;
999 1023 }
1000 1024
1001 1025 /* Common */
1002 1026 pre { margin: 0; }
1003 1027
1004 1028 .logo {
1005 1029 float: right;
1006 1030 clear: right;
1007 1031 }
1008 1032
1009 1033 /* Changelog/Filelog entries */
1010 1034 .logEntry { width: 100%; }
1011 1035 .logEntry .age { width: 15%; }
1012 1036 .logEntry th { font-weight: normal; text-align: right; vertical-align: top; }
1013 1037 .logEntry th.age, .logEntry th.firstline { font-weight: bold; }
1014 1038 .logEntry th.firstline { text-align: left; width: inherit; }
1015 1039
1016 1040 /* Shortlog entries */
1017 1041 .slogEntry { width: 100%; }
1018 1042 .slogEntry .age { width: 8em; }
1019 1043 .slogEntry td { font-weight: normal; text-align: left; vertical-align: top; }
1020 1044 .slogEntry td.author { width: 15em; }
1021 1045
1022 1046 /* Tag entries */
1023 1047 #tagEntries { list-style: none; margin: 0; padding: 0; }
1024 1048 #tagEntries .tagEntry { list-style: none; margin: 0; padding: 0; }
1025 1049
1026 1050 /* Changeset entry */
1027 1051 #changesetEntry { }
1028 1052 #changesetEntry th { font-weight: normal; background-color: #888; color: #fff; text-align: right; }
1029 1053 #changesetEntry th.files, #changesetEntry th.description { vertical-align: top; }
1030 1054
1031 1055 /* File diff view */
1032 1056 #filediffEntry { }
1033 1057 #filediffEntry th { font-weight: normal; background-color: #888; color: #fff; text-align: right; }
1034 1058
1035 1059 /* Graph */
1036 1060 div#wrapper {
1037 1061 position: relative;
1038 1062 margin: 0;
1039 1063 padding: 0;
1040 1064 }
1041 1065
1042 1066 canvas {
1043 1067 position: absolute;
1044 1068 z-index: 5;
1045 1069 top: -0.6em;
1046 1070 margin: 0;
1047 1071 }
1048 1072
1049 1073 ul#nodebgs {
1050 1074 list-style: none inside none;
1051 1075 padding: 0;
1052 1076 margin: 0;
1053 1077 top: -0.7em;
1054 1078 }
1055 1079
1056 1080 ul#graphnodes li, ul#nodebgs li {
1057 1081 height: 39px;
1058 1082 }
1059 1083
1060 1084 ul#graphnodes {
1061 1085 position: absolute;
1062 1086 z-index: 10;
1063 1087 top: -0.85em;
1064 1088 list-style: none inside none;
1065 1089 padding: 0;
1066 1090 }
1067 1091
1068 1092 ul#graphnodes li .info {
1069 1093 display: block;
1070 1094 font-size: 70%;
1071 1095 position: relative;
1072 1096 top: -1px;
1073 1097 }
1074 1098
1075 1099 Stop and restart with HGENCODING=cp932
1076 1100
1077 1101 $ "$TESTDIR/killdaemons.py"
1078 1102 $ HGENCODING=cp932 hg serve --config server.uncompressed=False -n test \
1079 1103 > -p $HGPORT -d --pid-file=hg.pid -E errors.log
1080 1104 $ cat hg.pid >> $DAEMON_PIDS
1081 1105
1082 1106 commit message with Japanese Kanji 'Noh', which ends with '\x5c'
1083 1107
1084 1108 $ echo foo >> foo
1085 1109 $ HGENCODING=cp932 hg ci -m `python -c 'print("\x94\x5c")'`
1086 1110
1087 1111 Graph json escape of multibyte character
1088 1112
1089 1113 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/graph/' \
1090 1114 > | grep '^var data ='
1091 1115 var data = [["40b4d6888e92", [0, 1], [[0, 0, 1]], "\u80fd", "test", "1970-01-01", ["stable", true], ["tip"], ["something"]], ["1d22e65f027e", [0, 1], [[0, 0, 1]], "branch", "test", "1970-01-01", ["stable", false], [], []], ["a4f92ed23982", [0, 1], [[0, 0, 1]], "Added tag 1.0 for changeset 2ef0ac749a14", "test", "1970-01-01", ["default", true], [], []], ["2ef0ac749a14", [0, 1], [], "base", "test", "1970-01-01", ["default", false], ["1.0"], ["anotherthing"]]];
1092 1116
1093 1117 ERRORS ENCOUNTERED
1094 1118
1095 1119 $ cat errors.log
General Comments 0
You need to be logged in to leave comments. Login now