##// END OF EJS Templates
paper: show branch/tags/bookmarks when comparing (issue3559)
Anton Shestakov -
r25135:3b689001 default
parent child Browse files
Show More
@@ -1,1328 +1,1330 b''
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 import util
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, patch
16 16 from mercurial import scmutil
17 17 from mercurial.i18n import _
18 18 from mercurial.error import ParseError, RepoLookupError, Abort
19 19 from mercurial import revset
20 20
21 21 __all__ = []
22 22 commands = {}
23 23
24 24 class webcommand(object):
25 25 """Decorator used to register a web command handler.
26 26
27 27 The decorator takes as its positional arguments the name/path the
28 28 command should be accessible under.
29 29
30 30 Usage:
31 31
32 32 @webcommand('mycommand')
33 33 def mycommand(web, req, tmpl):
34 34 pass
35 35 """
36 36
37 37 def __init__(self, name):
38 38 self.name = name
39 39
40 40 def __call__(self, func):
41 41 __all__.append(self.name)
42 42 commands[self.name] = func
43 43 return func
44 44
45 45 @webcommand('log')
46 46 def log(web, req, tmpl):
47 47 """
48 48 /log[/{revision}[/{path}]]
49 49 --------------------------
50 50
51 51 Show repository or file history.
52 52
53 53 For URLs of the form ``/log/{revision}``, a list of changesets starting at
54 54 the specified changeset identifier is shown. If ``{revision}`` is not
55 55 defined, the default is ``tip``. This form is equivalent to the
56 56 ``changelog`` handler.
57 57
58 58 For URLs of the form ``/log/{revision}/{file}``, the history for a specific
59 59 file will be shown. This form is equivalent to the ``filelog`` handler.
60 60 """
61 61
62 62 if 'file' in req.form and req.form['file'][0]:
63 63 return filelog(web, req, tmpl)
64 64 else:
65 65 return changelog(web, req, tmpl)
66 66
67 67 @webcommand('rawfile')
68 68 def rawfile(web, req, tmpl):
69 69 guessmime = web.configbool('web', 'guessmime', False)
70 70
71 71 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
72 72 if not path:
73 73 content = manifest(web, req, tmpl)
74 74 req.respond(HTTP_OK, web.ctype)
75 75 return content
76 76
77 77 try:
78 78 fctx = webutil.filectx(web.repo, req)
79 79 except error.LookupError, inst:
80 80 try:
81 81 content = manifest(web, req, tmpl)
82 82 req.respond(HTTP_OK, web.ctype)
83 83 return content
84 84 except ErrorResponse:
85 85 raise inst
86 86
87 87 path = fctx.path()
88 88 text = fctx.data()
89 89 mt = 'application/binary'
90 90 if guessmime:
91 91 mt = mimetypes.guess_type(path)[0]
92 92 if mt is None:
93 93 if util.binary(text):
94 94 mt = 'application/binary'
95 95 else:
96 96 mt = 'text/plain'
97 97 if mt.startswith('text/'):
98 98 mt += '; charset="%s"' % encoding.encoding
99 99
100 100 req.respond(HTTP_OK, mt, path, body=text)
101 101 return []
102 102
103 103 def _filerevision(web, tmpl, fctx):
104 104 f = fctx.path()
105 105 text = fctx.data()
106 106 parity = paritygen(web.stripecount)
107 107
108 108 if util.binary(text):
109 109 mt = mimetypes.guess_type(f)[0] or 'application/octet-stream'
110 110 text = '(binary:%s)' % mt
111 111
112 112 def lines():
113 113 for lineno, t in enumerate(text.splitlines(True)):
114 114 yield {"line": t,
115 115 "lineid": "l%d" % (lineno + 1),
116 116 "linenumber": "% 6d" % (lineno + 1),
117 117 "parity": parity.next()}
118 118
119 119 return tmpl("filerevision",
120 120 file=f,
121 121 path=webutil.up(f),
122 122 text=lines(),
123 123 rev=fctx.rev(),
124 124 node=fctx.hex(),
125 125 author=fctx.user(),
126 126 date=fctx.date(),
127 127 desc=fctx.description(),
128 128 extra=fctx.extra(),
129 129 branch=webutil.nodebranchnodefault(fctx),
130 130 parent=webutil.parents(fctx),
131 131 child=webutil.children(fctx),
132 132 rename=webutil.renamelink(fctx),
133 133 tags=webutil.nodetagsdict(web.repo, fctx.node()),
134 134 bookmarks=webutil.nodebookmarksdict(web.repo, fctx.node()),
135 135 permissions=fctx.manifest().flags(f))
136 136
137 137 @webcommand('file')
138 138 def file(web, req, tmpl):
139 139 """
140 140 /file/{revision}[/{path}]
141 141 -------------------------
142 142
143 143 Show information about a directory or file in the repository.
144 144
145 145 Info about the ``path`` given as a URL parameter will be rendered.
146 146
147 147 If ``path`` is a directory, information about the entries in that
148 148 directory will be rendered. This form is equivalent to the ``manifest``
149 149 handler.
150 150
151 151 If ``path`` is a file, information about that file will be shown via
152 152 the ``filerevision`` template.
153 153
154 154 If ``path`` is not defined, information about the root directory will
155 155 be rendered.
156 156 """
157 157 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
158 158 if not path:
159 159 return manifest(web, req, tmpl)
160 160 try:
161 161 return _filerevision(web, tmpl, webutil.filectx(web.repo, req))
162 162 except error.LookupError, inst:
163 163 try:
164 164 return manifest(web, req, tmpl)
165 165 except ErrorResponse:
166 166 raise inst
167 167
168 168 def _search(web, req, tmpl):
169 169 MODE_REVISION = 'rev'
170 170 MODE_KEYWORD = 'keyword'
171 171 MODE_REVSET = 'revset'
172 172
173 173 def revsearch(ctx):
174 174 yield ctx
175 175
176 176 def keywordsearch(query):
177 177 lower = encoding.lower
178 178 qw = lower(query).split()
179 179
180 180 def revgen():
181 181 cl = web.repo.changelog
182 182 for i in xrange(len(web.repo) - 1, 0, -100):
183 183 l = []
184 184 for j in cl.revs(max(0, i - 99), i):
185 185 ctx = web.repo[j]
186 186 l.append(ctx)
187 187 l.reverse()
188 188 for e in l:
189 189 yield e
190 190
191 191 for ctx in revgen():
192 192 miss = 0
193 193 for q in qw:
194 194 if not (q in lower(ctx.user()) or
195 195 q in lower(ctx.description()) or
196 196 q in lower(" ".join(ctx.files()))):
197 197 miss = 1
198 198 break
199 199 if miss:
200 200 continue
201 201
202 202 yield ctx
203 203
204 204 def revsetsearch(revs):
205 205 for r in revs:
206 206 yield web.repo[r]
207 207
208 208 searchfuncs = {
209 209 MODE_REVISION: (revsearch, 'exact revision search'),
210 210 MODE_KEYWORD: (keywordsearch, 'literal keyword search'),
211 211 MODE_REVSET: (revsetsearch, 'revset expression search'),
212 212 }
213 213
214 214 def getsearchmode(query):
215 215 try:
216 216 ctx = web.repo[query]
217 217 except (error.RepoError, error.LookupError):
218 218 # query is not an exact revision pointer, need to
219 219 # decide if it's a revset expression or keywords
220 220 pass
221 221 else:
222 222 return MODE_REVISION, ctx
223 223
224 224 revdef = 'reverse(%s)' % query
225 225 try:
226 226 tree, pos = revset.parse(revdef)
227 227 except ParseError:
228 228 # can't parse to a revset tree
229 229 return MODE_KEYWORD, query
230 230
231 231 if revset.depth(tree) <= 2:
232 232 # no revset syntax used
233 233 return MODE_KEYWORD, query
234 234
235 235 if util.any((token, (value or '')[:3]) == ('string', 're:')
236 236 for token, value, pos in revset.tokenize(revdef)):
237 237 return MODE_KEYWORD, query
238 238
239 239 funcsused = revset.funcsused(tree)
240 240 if not funcsused.issubset(revset.safesymbols):
241 241 return MODE_KEYWORD, query
242 242
243 243 mfunc = revset.match(web.repo.ui, revdef)
244 244 try:
245 245 revs = mfunc(web.repo)
246 246 return MODE_REVSET, revs
247 247 # ParseError: wrongly placed tokens, wrongs arguments, etc
248 248 # RepoLookupError: no such revision, e.g. in 'revision:'
249 249 # Abort: bookmark/tag not exists
250 250 # LookupError: ambiguous identifier, e.g. in '(bc)' on a large repo
251 251 except (ParseError, RepoLookupError, Abort, LookupError):
252 252 return MODE_KEYWORD, query
253 253
254 254 def changelist(**map):
255 255 count = 0
256 256
257 257 for ctx in searchfunc[0](funcarg):
258 258 count += 1
259 259 n = ctx.node()
260 260 showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
261 261 files = webutil.listfilediffs(tmpl, ctx.files(), n, web.maxfiles)
262 262
263 263 yield tmpl('searchentry',
264 264 parity=parity.next(),
265 265 author=ctx.user(),
266 266 parent=webutil.parents(ctx),
267 267 child=webutil.children(ctx),
268 268 changelogtag=showtags,
269 269 desc=ctx.description(),
270 270 extra=ctx.extra(),
271 271 date=ctx.date(),
272 272 files=files,
273 273 rev=ctx.rev(),
274 274 node=hex(n),
275 275 tags=webutil.nodetagsdict(web.repo, n),
276 276 bookmarks=webutil.nodebookmarksdict(web.repo, n),
277 277 inbranch=webutil.nodeinbranch(web.repo, ctx),
278 278 branches=webutil.nodebranchdict(web.repo, ctx))
279 279
280 280 if count >= revcount:
281 281 break
282 282
283 283 query = req.form['rev'][0]
284 284 revcount = web.maxchanges
285 285 if 'revcount' in req.form:
286 286 try:
287 287 revcount = int(req.form.get('revcount', [revcount])[0])
288 288 revcount = max(revcount, 1)
289 289 tmpl.defaults['sessionvars']['revcount'] = revcount
290 290 except ValueError:
291 291 pass
292 292
293 293 lessvars = copy.copy(tmpl.defaults['sessionvars'])
294 294 lessvars['revcount'] = max(revcount / 2, 1)
295 295 lessvars['rev'] = query
296 296 morevars = copy.copy(tmpl.defaults['sessionvars'])
297 297 morevars['revcount'] = revcount * 2
298 298 morevars['rev'] = query
299 299
300 300 mode, funcarg = getsearchmode(query)
301 301
302 302 if 'forcekw' in req.form:
303 303 showforcekw = ''
304 304 showunforcekw = searchfuncs[mode][1]
305 305 mode = MODE_KEYWORD
306 306 funcarg = query
307 307 else:
308 308 if mode != MODE_KEYWORD:
309 309 showforcekw = searchfuncs[MODE_KEYWORD][1]
310 310 else:
311 311 showforcekw = ''
312 312 showunforcekw = ''
313 313
314 314 searchfunc = searchfuncs[mode]
315 315
316 316 tip = web.repo['tip']
317 317 parity = paritygen(web.stripecount)
318 318
319 319 return tmpl('search', query=query, node=tip.hex(),
320 320 entries=changelist, archives=web.archivelist("tip"),
321 321 morevars=morevars, lessvars=lessvars,
322 322 modedesc=searchfunc[1],
323 323 showforcekw=showforcekw, showunforcekw=showunforcekw)
324 324
325 325 @webcommand('changelog')
326 326 def changelog(web, req, tmpl, shortlog=False):
327 327 """
328 328 /changelog[/{revision}]
329 329 -----------------------
330 330
331 331 Show information about multiple changesets.
332 332
333 333 If the optional ``revision`` URL argument is absent, information about
334 334 all changesets starting at ``tip`` will be rendered. If the ``revision``
335 335 argument is present, changesets will be shown starting from the specified
336 336 revision.
337 337
338 338 If ``revision`` is absent, the ``rev`` query string argument may be
339 339 defined. This will perform a search for changesets.
340 340
341 341 The argument for ``rev`` can be a single revision, a revision set,
342 342 or a literal keyword to search for in changeset data (equivalent to
343 343 :hg:`log -k`).
344 344
345 345 The ``revcount`` query string argument defines the maximum numbers of
346 346 changesets to render.
347 347
348 348 For non-searches, the ``changelog`` template will be rendered.
349 349 """
350 350
351 351 query = ''
352 352 if 'node' in req.form:
353 353 ctx = webutil.changectx(web.repo, req)
354 354 elif 'rev' in req.form:
355 355 return _search(web, req, tmpl)
356 356 else:
357 357 ctx = web.repo['tip']
358 358
359 359 def changelist():
360 360 revs = []
361 361 if pos != -1:
362 362 revs = web.repo.changelog.revs(pos, 0)
363 363 curcount = 0
364 364 for rev in revs:
365 365 curcount += 1
366 366 if curcount > revcount + 1:
367 367 break
368 368
369 369 entry = webutil.changelistentry(web, web.repo[rev], tmpl)
370 370 entry['parity'] = parity.next()
371 371 yield entry
372 372
373 373 if shortlog:
374 374 revcount = web.maxshortchanges
375 375 else:
376 376 revcount = web.maxchanges
377 377
378 378 if 'revcount' in req.form:
379 379 try:
380 380 revcount = int(req.form.get('revcount', [revcount])[0])
381 381 revcount = max(revcount, 1)
382 382 tmpl.defaults['sessionvars']['revcount'] = revcount
383 383 except ValueError:
384 384 pass
385 385
386 386 lessvars = copy.copy(tmpl.defaults['sessionvars'])
387 387 lessvars['revcount'] = max(revcount / 2, 1)
388 388 morevars = copy.copy(tmpl.defaults['sessionvars'])
389 389 morevars['revcount'] = revcount * 2
390 390
391 391 count = len(web.repo)
392 392 pos = ctx.rev()
393 393 parity = paritygen(web.stripecount)
394 394
395 395 changenav = webutil.revnav(web.repo).gen(pos, revcount, count)
396 396
397 397 entries = list(changelist())
398 398 latestentry = entries[:1]
399 399 if len(entries) > revcount:
400 400 nextentry = entries[-1:]
401 401 entries = entries[:-1]
402 402 else:
403 403 nextentry = []
404 404
405 405 return tmpl(shortlog and 'shortlog' or 'changelog', changenav=changenav,
406 406 node=ctx.hex(), rev=pos, changesets=count,
407 407 entries=entries,
408 408 latestentry=latestentry, nextentry=nextentry,
409 409 archives=web.archivelist("tip"), revcount=revcount,
410 410 morevars=morevars, lessvars=lessvars, query=query)
411 411
412 412 @webcommand('shortlog')
413 413 def shortlog(web, req, tmpl):
414 414 """
415 415 /shortlog
416 416 ---------
417 417
418 418 Show basic information about a set of changesets.
419 419
420 420 This accepts the same parameters as the ``changelog`` handler. The only
421 421 difference is the ``shortlog`` template will be rendered instead of the
422 422 ``changelog`` template.
423 423 """
424 424 return changelog(web, req, tmpl, shortlog=True)
425 425
426 426 @webcommand('changeset')
427 427 def changeset(web, req, tmpl):
428 428 """
429 429 /changeset[/{revision}]
430 430 -----------------------
431 431
432 432 Show information about a single changeset.
433 433
434 434 A URL path argument is the changeset identifier to show. See ``hg help
435 435 revisions`` for possible values. If not defined, the ``tip`` changeset
436 436 will be shown.
437 437
438 438 The ``changeset`` template is rendered. Contents of the ``changesettag``,
439 439 ``changesetbookmark``, ``filenodelink``, ``filenolink``, and the many
440 440 templates related to diffs may all be used to produce the output.
441 441 """
442 442 ctx = webutil.changectx(web.repo, req)
443 443
444 444 return tmpl('changeset', **webutil.changesetentry(web, req, tmpl, ctx))
445 445
446 446 rev = webcommand('rev')(changeset)
447 447
448 448 def decodepath(path):
449 449 """Hook for mapping a path in the repository to a path in the
450 450 working copy.
451 451
452 452 Extensions (e.g., largefiles) can override this to remap files in
453 453 the virtual file system presented by the manifest command below."""
454 454 return path
455 455
456 456 @webcommand('manifest')
457 457 def manifest(web, req, tmpl):
458 458 """
459 459 /manifest[/{revision}[/{path}]]
460 460 -------------------------------
461 461
462 462 Show information about a directory.
463 463
464 464 If the URL path arguments are omitted, information about the root
465 465 directory for the ``tip`` changeset will be shown.
466 466
467 467 Because this handler can only show information for directories, it
468 468 is recommended to use the ``file`` handler instead, as it can handle both
469 469 directories and files.
470 470
471 471 The ``manifest`` template will be rendered for this handler.
472 472 """
473 473 ctx = webutil.changectx(web.repo, req)
474 474 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
475 475 mf = ctx.manifest()
476 476 node = ctx.node()
477 477
478 478 files = {}
479 479 dirs = {}
480 480 parity = paritygen(web.stripecount)
481 481
482 482 if path and path[-1] != "/":
483 483 path += "/"
484 484 l = len(path)
485 485 abspath = "/" + path
486 486
487 487 for full, n in mf.iteritems():
488 488 # the virtual path (working copy path) used for the full
489 489 # (repository) path
490 490 f = decodepath(full)
491 491
492 492 if f[:l] != path:
493 493 continue
494 494 remain = f[l:]
495 495 elements = remain.split('/')
496 496 if len(elements) == 1:
497 497 files[remain] = full
498 498 else:
499 499 h = dirs # need to retain ref to dirs (root)
500 500 for elem in elements[0:-1]:
501 501 if elem not in h:
502 502 h[elem] = {}
503 503 h = h[elem]
504 504 if len(h) > 1:
505 505 break
506 506 h[None] = None # denotes files present
507 507
508 508 if mf and not files and not dirs:
509 509 raise ErrorResponse(HTTP_NOT_FOUND, 'path not found: ' + path)
510 510
511 511 def filelist(**map):
512 512 for f in sorted(files):
513 513 full = files[f]
514 514
515 515 fctx = ctx.filectx(full)
516 516 yield {"file": full,
517 517 "parity": parity.next(),
518 518 "basename": f,
519 519 "date": fctx.date(),
520 520 "size": fctx.size(),
521 521 "permissions": mf.flags(full)}
522 522
523 523 def dirlist(**map):
524 524 for d in sorted(dirs):
525 525
526 526 emptydirs = []
527 527 h = dirs[d]
528 528 while isinstance(h, dict) and len(h) == 1:
529 529 k, v = h.items()[0]
530 530 if v:
531 531 emptydirs.append(k)
532 532 h = v
533 533
534 534 path = "%s%s" % (abspath, d)
535 535 yield {"parity": parity.next(),
536 536 "path": path,
537 537 "emptydirs": "/".join(emptydirs),
538 538 "basename": d}
539 539
540 540 return tmpl("manifest",
541 541 rev=ctx.rev(),
542 542 node=hex(node),
543 543 path=abspath,
544 544 up=webutil.up(abspath),
545 545 upparity=parity.next(),
546 546 fentries=filelist,
547 547 dentries=dirlist,
548 548 archives=web.archivelist(hex(node)),
549 549 tags=webutil.nodetagsdict(web.repo, node),
550 550 bookmarks=webutil.nodebookmarksdict(web.repo, node),
551 551 branch=webutil.nodebranchnodefault(ctx),
552 552 inbranch=webutil.nodeinbranch(web.repo, ctx),
553 553 branches=webutil.nodebranchdict(web.repo, ctx))
554 554
555 555 @webcommand('tags')
556 556 def tags(web, req, tmpl):
557 557 """
558 558 /tags
559 559 -----
560 560
561 561 Show information about tags.
562 562
563 563 No arguments are accepted.
564 564
565 565 The ``tags`` template is rendered.
566 566 """
567 567 i = list(reversed(web.repo.tagslist()))
568 568 parity = paritygen(web.stripecount)
569 569
570 570 def entries(notip, latestonly, **map):
571 571 t = i
572 572 if notip:
573 573 t = [(k, n) for k, n in i if k != "tip"]
574 574 if latestonly:
575 575 t = t[:1]
576 576 for k, n in t:
577 577 yield {"parity": parity.next(),
578 578 "tag": k,
579 579 "date": web.repo[n].date(),
580 580 "node": hex(n)}
581 581
582 582 return tmpl("tags",
583 583 node=hex(web.repo.changelog.tip()),
584 584 entries=lambda **x: entries(False, False, **x),
585 585 entriesnotip=lambda **x: entries(True, False, **x),
586 586 latestentry=lambda **x: entries(True, True, **x))
587 587
588 588 @webcommand('bookmarks')
589 589 def bookmarks(web, req, tmpl):
590 590 """
591 591 /bookmarks
592 592 ----------
593 593
594 594 Show information about bookmarks.
595 595
596 596 No arguments are accepted.
597 597
598 598 The ``bookmarks`` template is rendered.
599 599 """
600 600 i = [b for b in web.repo._bookmarks.items() if b[1] in web.repo]
601 601 parity = paritygen(web.stripecount)
602 602
603 603 def entries(latestonly, **map):
604 604 if latestonly:
605 605 t = [min(i)]
606 606 else:
607 607 t = sorted(i)
608 608 for k, n in t:
609 609 yield {"parity": parity.next(),
610 610 "bookmark": k,
611 611 "date": web.repo[n].date(),
612 612 "node": hex(n)}
613 613
614 614 return tmpl("bookmarks",
615 615 node=hex(web.repo.changelog.tip()),
616 616 entries=lambda **x: entries(latestonly=False, **x),
617 617 latestentry=lambda **x: entries(latestonly=True, **x))
618 618
619 619 @webcommand('branches')
620 620 def branches(web, req, tmpl):
621 621 """
622 622 /branches
623 623 ---------
624 624
625 625 Show information about branches.
626 626
627 627 All known branches are contained in the output, even closed branches.
628 628
629 629 No arguments are accepted.
630 630
631 631 The ``branches`` template is rendered.
632 632 """
633 633 tips = []
634 634 heads = web.repo.heads()
635 635 parity = paritygen(web.stripecount)
636 636 sortkey = lambda item: (not item[1], item[0].rev())
637 637
638 638 def entries(limit, **map):
639 639 count = 0
640 640 if not tips:
641 641 for tag, hs, tip, closed in web.repo.branchmap().iterbranches():
642 642 tips.append((web.repo[tip], closed))
643 643 for ctx, closed in sorted(tips, key=sortkey, reverse=True):
644 644 if limit > 0 and count >= limit:
645 645 return
646 646 count += 1
647 647 if closed:
648 648 status = 'closed'
649 649 elif ctx.node() not in heads:
650 650 status = 'inactive'
651 651 else:
652 652 status = 'open'
653 653 yield {'parity': parity.next(),
654 654 'branch': ctx.branch(),
655 655 'status': status,
656 656 'node': ctx.hex(),
657 657 'date': ctx.date()}
658 658
659 659 return tmpl('branches', node=hex(web.repo.changelog.tip()),
660 660 entries=lambda **x: entries(0, **x),
661 661 latestentry=lambda **x: entries(1, **x))
662 662
663 663 @webcommand('summary')
664 664 def summary(web, req, tmpl):
665 665 """
666 666 /summary
667 667 --------
668 668
669 669 Show a summary of repository state.
670 670
671 671 Information about the latest changesets, bookmarks, tags, and branches
672 672 is captured by this handler.
673 673
674 674 The ``summary`` template is rendered.
675 675 """
676 676 i = reversed(web.repo.tagslist())
677 677
678 678 def tagentries(**map):
679 679 parity = paritygen(web.stripecount)
680 680 count = 0
681 681 for k, n in i:
682 682 if k == "tip": # skip tip
683 683 continue
684 684
685 685 count += 1
686 686 if count > 10: # limit to 10 tags
687 687 break
688 688
689 689 yield tmpl("tagentry",
690 690 parity=parity.next(),
691 691 tag=k,
692 692 node=hex(n),
693 693 date=web.repo[n].date())
694 694
695 695 def bookmarks(**map):
696 696 parity = paritygen(web.stripecount)
697 697 marks = [b for b in web.repo._bookmarks.items() if b[1] in web.repo]
698 698 for k, n in sorted(marks)[:10]: # limit to 10 bookmarks
699 699 yield {'parity': parity.next(),
700 700 'bookmark': k,
701 701 'date': web.repo[n].date(),
702 702 'node': hex(n)}
703 703
704 704 def branches(**map):
705 705 parity = paritygen(web.stripecount)
706 706
707 707 b = web.repo.branchmap()
708 708 l = [(-web.repo.changelog.rev(tip), tip, tag)
709 709 for tag, heads, tip, closed in b.iterbranches()]
710 710 for r, n, t in sorted(l):
711 711 yield {'parity': parity.next(),
712 712 'branch': t,
713 713 'node': hex(n),
714 714 'date': web.repo[n].date()}
715 715
716 716 def changelist(**map):
717 717 parity = paritygen(web.stripecount, offset=start - end)
718 718 l = [] # build a list in forward order for efficiency
719 719 revs = []
720 720 if start < end:
721 721 revs = web.repo.changelog.revs(start, end - 1)
722 722 for i in revs:
723 723 ctx = web.repo[i]
724 724 n = ctx.node()
725 725 hn = hex(n)
726 726
727 727 l.append(tmpl(
728 728 'shortlogentry',
729 729 parity=parity.next(),
730 730 author=ctx.user(),
731 731 desc=ctx.description(),
732 732 extra=ctx.extra(),
733 733 date=ctx.date(),
734 734 rev=i,
735 735 node=hn,
736 736 tags=webutil.nodetagsdict(web.repo, n),
737 737 bookmarks=webutil.nodebookmarksdict(web.repo, n),
738 738 inbranch=webutil.nodeinbranch(web.repo, ctx),
739 739 branches=webutil.nodebranchdict(web.repo, ctx)))
740 740
741 741 l.reverse()
742 742 yield l
743 743
744 744 tip = web.repo['tip']
745 745 count = len(web.repo)
746 746 start = max(0, count - web.maxchanges)
747 747 end = min(count, start + web.maxchanges)
748 748
749 749 return tmpl("summary",
750 750 desc=web.config("web", "description", "unknown"),
751 751 owner=get_contact(web.config) or "unknown",
752 752 lastchange=tip.date(),
753 753 tags=tagentries,
754 754 bookmarks=bookmarks,
755 755 branches=branches,
756 756 shortlog=changelist,
757 757 node=tip.hex(),
758 758 archives=web.archivelist("tip"))
759 759
760 760 @webcommand('filediff')
761 761 def filediff(web, req, tmpl):
762 762 """
763 763 /diff/{revision}/{path}
764 764 -----------------------
765 765
766 766 Show how a file changed in a particular commit.
767 767
768 768 The ``filediff`` template is rendered.
769 769
770 770 This hander is registered under both the ``/diff`` and ``/filediff``
771 771 paths. ``/diff`` is used in modern code.
772 772 """
773 773 fctx, ctx = None, None
774 774 try:
775 775 fctx = webutil.filectx(web.repo, req)
776 776 except LookupError:
777 777 ctx = webutil.changectx(web.repo, req)
778 778 path = webutil.cleanpath(web.repo, req.form['file'][0])
779 779 if path not in ctx.files():
780 780 raise
781 781
782 782 if fctx is not None:
783 783 n = fctx.node()
784 784 path = fctx.path()
785 785 ctx = fctx.changectx()
786 786 else:
787 787 n = ctx.node()
788 788 # path already defined in except clause
789 789
790 790 parity = paritygen(web.stripecount)
791 791 style = web.config('web', 'style', 'paper')
792 792 if 'style' in req.form:
793 793 style = req.form['style'][0]
794 794
795 795 diffs = webutil.diffs(web.repo, tmpl, ctx, None, [path], parity, style)
796 796 if fctx:
797 797 rename = webutil.renamelink(fctx)
798 798 ctx = fctx
799 799 else:
800 800 rename = []
801 801 ctx = ctx
802 802 return tmpl("filediff",
803 803 file=path,
804 804 node=hex(n),
805 805 rev=ctx.rev(),
806 806 date=ctx.date(),
807 807 desc=ctx.description(),
808 808 extra=ctx.extra(),
809 809 author=ctx.user(),
810 810 rename=rename,
811 811 branch=webutil.nodebranchnodefault(ctx),
812 812 parent=webutil.parents(ctx),
813 813 child=webutil.children(ctx),
814 814 tags=webutil.nodetagsdict(web.repo, n),
815 815 bookmarks=webutil.nodebookmarksdict(web.repo, n),
816 816 diff=diffs)
817 817
818 818 diff = webcommand('diff')(filediff)
819 819
820 820 @webcommand('comparison')
821 821 def comparison(web, req, tmpl):
822 822 """
823 823 /comparison/{revision}/{path}
824 824 -----------------------------
825 825
826 826 Show a comparison between the old and new versions of a file from changes
827 827 made on a particular revision.
828 828
829 829 This is similar to the ``diff`` handler. However, this form features
830 830 a split or side-by-side diff rather than a unified diff.
831 831
832 832 The ``context`` query string argument can be used to control the lines of
833 833 context in the diff.
834 834
835 835 The ``filecomparison`` template is rendered.
836 836 """
837 837 ctx = webutil.changectx(web.repo, req)
838 838 if 'file' not in req.form:
839 839 raise ErrorResponse(HTTP_NOT_FOUND, 'file not given')
840 840 path = webutil.cleanpath(web.repo, req.form['file'][0])
841 841 rename = path in ctx and webutil.renamelink(ctx[path]) or []
842 842
843 843 parsecontext = lambda v: v == 'full' and -1 or int(v)
844 844 if 'context' in req.form:
845 845 context = parsecontext(req.form['context'][0])
846 846 else:
847 847 context = parsecontext(web.config('web', 'comparisoncontext', '5'))
848 848
849 849 def filelines(f):
850 850 if util.binary(f.data()):
851 851 mt = mimetypes.guess_type(f.path())[0]
852 852 if not mt:
853 853 mt = 'application/octet-stream'
854 854 return [_('(binary file %s, hash: %s)') % (mt, hex(f.filenode()))]
855 855 return f.data().splitlines()
856 856
857 857 parent = ctx.p1()
858 858 leftrev = parent.rev()
859 859 leftnode = parent.node()
860 860 rightrev = ctx.rev()
861 861 rightnode = ctx.node()
862 862 if path in ctx:
863 863 fctx = ctx[path]
864 864 rightlines = filelines(fctx)
865 865 if path not in parent:
866 866 leftlines = ()
867 867 else:
868 868 pfctx = parent[path]
869 869 leftlines = filelines(pfctx)
870 870 else:
871 871 rightlines = ()
872 872 fctx = ctx.parents()[0][path]
873 873 leftlines = filelines(fctx)
874 874
875 875 comparison = webutil.compare(tmpl, context, leftlines, rightlines)
876 876 return tmpl('filecomparison',
877 877 file=path,
878 878 node=hex(ctx.node()),
879 879 rev=ctx.rev(),
880 880 date=ctx.date(),
881 881 desc=ctx.description(),
882 882 extra=ctx.extra(),
883 883 author=ctx.user(),
884 884 rename=rename,
885 885 branch=webutil.nodebranchnodefault(ctx),
886 886 parent=webutil.parents(fctx),
887 887 child=webutil.children(fctx),
888 tags=webutil.nodetagsdict(web.repo, ctx.node()),
889 bookmarks=webutil.nodebookmarksdict(web.repo, ctx.node()),
888 890 leftrev=leftrev,
889 891 leftnode=hex(leftnode),
890 892 rightrev=rightrev,
891 893 rightnode=hex(rightnode),
892 894 comparison=comparison)
893 895
894 896 @webcommand('annotate')
895 897 def annotate(web, req, tmpl):
896 898 """
897 899 /annotate/{revision}/{path}
898 900 ---------------------------
899 901
900 902 Show changeset information for each line in a file.
901 903
902 904 The ``fileannotate`` template is rendered.
903 905 """
904 906 fctx = webutil.filectx(web.repo, req)
905 907 f = fctx.path()
906 908 parity = paritygen(web.stripecount)
907 909 diffopts = patch.difffeatureopts(web.repo.ui, untrusted=True,
908 910 section='annotate', whitespace=True)
909 911
910 912 def annotate(**map):
911 913 last = None
912 914 if util.binary(fctx.data()):
913 915 mt = (mimetypes.guess_type(fctx.path())[0]
914 916 or 'application/octet-stream')
915 917 lines = enumerate([((fctx.filectx(fctx.filerev()), 1),
916 918 '(binary:%s)' % mt)])
917 919 else:
918 920 lines = enumerate(fctx.annotate(follow=True, linenumber=True,
919 921 diffopts=diffopts))
920 922 for lineno, ((f, targetline), l) in lines:
921 923 fnode = f.filenode()
922 924
923 925 if last != fnode:
924 926 last = fnode
925 927
926 928 yield {"parity": parity.next(),
927 929 "node": f.hex(),
928 930 "rev": f.rev(),
929 931 "author": f.user(),
930 932 "desc": f.description(),
931 933 "extra": f.extra(),
932 934 "file": f.path(),
933 935 "targetline": targetline,
934 936 "line": l,
935 937 "lineno": lineno + 1,
936 938 "lineid": "l%d" % (lineno + 1),
937 939 "linenumber": "% 6d" % (lineno + 1),
938 940 "revdate": f.date()}
939 941
940 942 return tmpl("fileannotate",
941 943 file=f,
942 944 annotate=annotate,
943 945 path=webutil.up(f),
944 946 rev=fctx.rev(),
945 947 node=fctx.hex(),
946 948 author=fctx.user(),
947 949 date=fctx.date(),
948 950 desc=fctx.description(),
949 951 extra=fctx.extra(),
950 952 rename=webutil.renamelink(fctx),
951 953 branch=webutil.nodebranchnodefault(fctx),
952 954 parent=webutil.parents(fctx),
953 955 child=webutil.children(fctx),
954 956 permissions=fctx.manifest().flags(f))
955 957
956 958 @webcommand('filelog')
957 959 def filelog(web, req, tmpl):
958 960 """
959 961 /filelog/{revision}/{path}
960 962 --------------------------
961 963
962 964 Show information about the history of a file in the repository.
963 965
964 966 The ``revcount`` query string argument can be defined to control the
965 967 maximum number of entries to show.
966 968
967 969 The ``filelog`` template will be rendered.
968 970 """
969 971
970 972 try:
971 973 fctx = webutil.filectx(web.repo, req)
972 974 f = fctx.path()
973 975 fl = fctx.filelog()
974 976 except error.LookupError:
975 977 f = webutil.cleanpath(web.repo, req.form['file'][0])
976 978 fl = web.repo.file(f)
977 979 numrevs = len(fl)
978 980 if not numrevs: # file doesn't exist at all
979 981 raise
980 982 rev = webutil.changectx(web.repo, req).rev()
981 983 first = fl.linkrev(0)
982 984 if rev < first: # current rev is from before file existed
983 985 raise
984 986 frev = numrevs - 1
985 987 while fl.linkrev(frev) > rev:
986 988 frev -= 1
987 989 fctx = web.repo.filectx(f, fl.linkrev(frev))
988 990
989 991 revcount = web.maxshortchanges
990 992 if 'revcount' in req.form:
991 993 try:
992 994 revcount = int(req.form.get('revcount', [revcount])[0])
993 995 revcount = max(revcount, 1)
994 996 tmpl.defaults['sessionvars']['revcount'] = revcount
995 997 except ValueError:
996 998 pass
997 999
998 1000 lessvars = copy.copy(tmpl.defaults['sessionvars'])
999 1001 lessvars['revcount'] = max(revcount / 2, 1)
1000 1002 morevars = copy.copy(tmpl.defaults['sessionvars'])
1001 1003 morevars['revcount'] = revcount * 2
1002 1004
1003 1005 count = fctx.filerev() + 1
1004 1006 start = max(0, fctx.filerev() - revcount + 1) # first rev on this page
1005 1007 end = min(count, start + revcount) # last rev on this page
1006 1008 parity = paritygen(web.stripecount, offset=start - end)
1007 1009
1008 1010 def entries():
1009 1011 l = []
1010 1012
1011 1013 repo = web.repo
1012 1014 revs = fctx.filelog().revs(start, end - 1)
1013 1015 for i in revs:
1014 1016 iterfctx = fctx.filectx(i)
1015 1017
1016 1018 l.append({"parity": parity.next(),
1017 1019 "filerev": i,
1018 1020 "file": f,
1019 1021 "node": iterfctx.hex(),
1020 1022 "author": iterfctx.user(),
1021 1023 "date": iterfctx.date(),
1022 1024 "rename": webutil.renamelink(iterfctx),
1023 1025 "parent": webutil.parents(iterfctx),
1024 1026 "child": webutil.children(iterfctx),
1025 1027 "desc": iterfctx.description(),
1026 1028 "extra": iterfctx.extra(),
1027 1029 "tags": webutil.nodetagsdict(repo, iterfctx.node()),
1028 1030 "bookmarks": webutil.nodebookmarksdict(
1029 1031 repo, iterfctx.node()),
1030 1032 "branch": webutil.nodebranchnodefault(iterfctx),
1031 1033 "inbranch": webutil.nodeinbranch(repo, iterfctx),
1032 1034 "branches": webutil.nodebranchdict(repo, iterfctx)})
1033 1035 for e in reversed(l):
1034 1036 yield e
1035 1037
1036 1038 entries = list(entries())
1037 1039 latestentry = entries[:1]
1038 1040
1039 1041 revnav = webutil.filerevnav(web.repo, fctx.path())
1040 1042 nav = revnav.gen(end - 1, revcount, count)
1041 1043 return tmpl("filelog", file=f, node=fctx.hex(), nav=nav,
1042 1044 entries=entries,
1043 1045 latestentry=latestentry,
1044 1046 revcount=revcount, morevars=morevars, lessvars=lessvars)
1045 1047
1046 1048 @webcommand('archive')
1047 1049 def archive(web, req, tmpl):
1048 1050 """
1049 1051 /archive/{revision}.{format}[/{path}]
1050 1052 -------------------------------------
1051 1053
1052 1054 Obtain an archive of repository content.
1053 1055
1054 1056 The content and type of the archive is defined by a URL path parameter.
1055 1057 ``format`` is the file extension of the archive type to be generated. e.g.
1056 1058 ``zip`` or ``tar.bz2``. Not all archive types may be allowed by your
1057 1059 server configuration.
1058 1060
1059 1061 The optional ``path`` URL parameter controls content to include in the
1060 1062 archive. If omitted, every file in the specified revision is present in the
1061 1063 archive. If included, only the specified file or contents of the specified
1062 1064 directory will be included in the archive.
1063 1065
1064 1066 No template is used for this handler. Raw, binary content is generated.
1065 1067 """
1066 1068
1067 1069 type_ = req.form.get('type', [None])[0]
1068 1070 allowed = web.configlist("web", "allow_archive")
1069 1071 key = req.form['node'][0]
1070 1072
1071 1073 if type_ not in web.archives:
1072 1074 msg = 'Unsupported archive type: %s' % type_
1073 1075 raise ErrorResponse(HTTP_NOT_FOUND, msg)
1074 1076
1075 1077 if not ((type_ in allowed or
1076 1078 web.configbool("web", "allow" + type_, False))):
1077 1079 msg = 'Archive type not allowed: %s' % type_
1078 1080 raise ErrorResponse(HTTP_FORBIDDEN, msg)
1079 1081
1080 1082 reponame = re.sub(r"\W+", "-", os.path.basename(web.reponame))
1081 1083 cnode = web.repo.lookup(key)
1082 1084 arch_version = key
1083 1085 if cnode == key or key == 'tip':
1084 1086 arch_version = short(cnode)
1085 1087 name = "%s-%s" % (reponame, arch_version)
1086 1088
1087 1089 ctx = webutil.changectx(web.repo, req)
1088 1090 pats = []
1089 1091 matchfn = scmutil.match(ctx, [])
1090 1092 file = req.form.get('file', None)
1091 1093 if file:
1092 1094 pats = ['path:' + file[0]]
1093 1095 matchfn = scmutil.match(ctx, pats, default='path')
1094 1096 if pats:
1095 1097 files = [f for f in ctx.manifest().keys() if matchfn(f)]
1096 1098 if not files:
1097 1099 raise ErrorResponse(HTTP_NOT_FOUND,
1098 1100 'file(s) not found: %s' % file[0])
1099 1101
1100 1102 mimetype, artype, extension, encoding = web.archive_specs[type_]
1101 1103 headers = [
1102 1104 ('Content-Disposition', 'attachment; filename=%s%s' % (name, extension))
1103 1105 ]
1104 1106 if encoding:
1105 1107 headers.append(('Content-Encoding', encoding))
1106 1108 req.headers.extend(headers)
1107 1109 req.respond(HTTP_OK, mimetype)
1108 1110
1109 1111 archival.archive(web.repo, req, cnode, artype, prefix=name,
1110 1112 matchfn=matchfn,
1111 1113 subrepos=web.configbool("web", "archivesubrepos"))
1112 1114 return []
1113 1115
1114 1116
1115 1117 @webcommand('static')
1116 1118 def static(web, req, tmpl):
1117 1119 fname = req.form['file'][0]
1118 1120 # a repo owner may set web.static in .hg/hgrc to get any file
1119 1121 # readable by the user running the CGI script
1120 1122 static = web.config("web", "static", None, untrusted=False)
1121 1123 if not static:
1122 1124 tp = web.templatepath or templater.templatepaths()
1123 1125 if isinstance(tp, str):
1124 1126 tp = [tp]
1125 1127 static = [os.path.join(p, 'static') for p in tp]
1126 1128 staticfile(static, fname, req)
1127 1129 return []
1128 1130
1129 1131 @webcommand('graph')
1130 1132 def graph(web, req, tmpl):
1131 1133 """
1132 1134 /graph[/{revision}]
1133 1135 -------------------
1134 1136
1135 1137 Show information about the graphical topology of the repository.
1136 1138
1137 1139 Information rendered by this handler can be used to create visual
1138 1140 representations of repository topology.
1139 1141
1140 1142 The ``revision`` URL parameter controls the starting changeset.
1141 1143
1142 1144 The ``revcount`` query string argument can define the number of changesets
1143 1145 to show information for.
1144 1146
1145 1147 This handler will render the ``graph`` template.
1146 1148 """
1147 1149
1148 1150 ctx = webutil.changectx(web.repo, req)
1149 1151 rev = ctx.rev()
1150 1152
1151 1153 bg_height = 39
1152 1154 revcount = web.maxshortchanges
1153 1155 if 'revcount' in req.form:
1154 1156 try:
1155 1157 revcount = int(req.form.get('revcount', [revcount])[0])
1156 1158 revcount = max(revcount, 1)
1157 1159 tmpl.defaults['sessionvars']['revcount'] = revcount
1158 1160 except ValueError:
1159 1161 pass
1160 1162
1161 1163 lessvars = copy.copy(tmpl.defaults['sessionvars'])
1162 1164 lessvars['revcount'] = max(revcount / 2, 1)
1163 1165 morevars = copy.copy(tmpl.defaults['sessionvars'])
1164 1166 morevars['revcount'] = revcount * 2
1165 1167
1166 1168 count = len(web.repo)
1167 1169 pos = rev
1168 1170
1169 1171 uprev = min(max(0, count - 1), rev + revcount)
1170 1172 downrev = max(0, rev - revcount)
1171 1173 changenav = webutil.revnav(web.repo).gen(pos, revcount, count)
1172 1174
1173 1175 tree = []
1174 1176 if pos != -1:
1175 1177 allrevs = web.repo.changelog.revs(pos, 0)
1176 1178 revs = []
1177 1179 for i in allrevs:
1178 1180 revs.append(i)
1179 1181 if len(revs) >= revcount:
1180 1182 break
1181 1183
1182 1184 # We have to feed a baseset to dagwalker as it is expecting smartset
1183 1185 # object. This does not have a big impact on hgweb performance itself
1184 1186 # since hgweb graphing code is not itself lazy yet.
1185 1187 dag = graphmod.dagwalker(web.repo, revset.baseset(revs))
1186 1188 # As we said one line above... not lazy.
1187 1189 tree = list(graphmod.colored(dag, web.repo))
1188 1190
1189 1191 def getcolumns(tree):
1190 1192 cols = 0
1191 1193 for (id, type, ctx, vtx, edges) in tree:
1192 1194 if type != graphmod.CHANGESET:
1193 1195 continue
1194 1196 cols = max(cols, max([edge[0] for edge in edges] or [0]),
1195 1197 max([edge[1] for edge in edges] or [0]))
1196 1198 return cols
1197 1199
1198 1200 def graphdata(usetuples, **map):
1199 1201 data = []
1200 1202
1201 1203 row = 0
1202 1204 for (id, type, ctx, vtx, edges) in tree:
1203 1205 if type != graphmod.CHANGESET:
1204 1206 continue
1205 1207 node = str(ctx)
1206 1208 age = templatefilters.age(ctx.date())
1207 1209 desc = templatefilters.firstline(ctx.description())
1208 1210 desc = cgi.escape(templatefilters.nonempty(desc))
1209 1211 user = cgi.escape(templatefilters.person(ctx.user()))
1210 1212 branch = cgi.escape(ctx.branch())
1211 1213 try:
1212 1214 branchnode = web.repo.branchtip(branch)
1213 1215 except error.RepoLookupError:
1214 1216 branchnode = None
1215 1217 branch = branch, branchnode == ctx.node()
1216 1218
1217 1219 if usetuples:
1218 1220 data.append((node, vtx, edges, desc, user, age, branch,
1219 1221 [cgi.escape(x) for x in ctx.tags()],
1220 1222 [cgi.escape(x) for x in ctx.bookmarks()]))
1221 1223 else:
1222 1224 edgedata = [{'col': edge[0], 'nextcol': edge[1],
1223 1225 'color': (edge[2] - 1) % 6 + 1,
1224 1226 'width': edge[3], 'bcolor': edge[4]}
1225 1227 for edge in edges]
1226 1228
1227 1229 data.append(
1228 1230 {'node': node,
1229 1231 'col': vtx[0],
1230 1232 'color': (vtx[1] - 1) % 6 + 1,
1231 1233 'edges': edgedata,
1232 1234 'row': row,
1233 1235 'nextrow': row + 1,
1234 1236 'desc': desc,
1235 1237 'user': user,
1236 1238 'age': age,
1237 1239 'bookmarks': webutil.nodebookmarksdict(
1238 1240 web.repo, ctx.node()),
1239 1241 'branches': webutil.nodebranchdict(web.repo, ctx),
1240 1242 'inbranch': webutil.nodeinbranch(web.repo, ctx),
1241 1243 'tags': webutil.nodetagsdict(web.repo, ctx.node())})
1242 1244
1243 1245 row += 1
1244 1246
1245 1247 return data
1246 1248
1247 1249 cols = getcolumns(tree)
1248 1250 rows = len(tree)
1249 1251 canvasheight = (rows + 1) * bg_height - 27
1250 1252
1251 1253 return tmpl('graph', rev=rev, revcount=revcount, uprev=uprev,
1252 1254 lessvars=lessvars, morevars=morevars, downrev=downrev,
1253 1255 cols=cols, rows=rows,
1254 1256 canvaswidth=(cols + 1) * bg_height,
1255 1257 truecanvasheight=rows * bg_height,
1256 1258 canvasheight=canvasheight, bg_height=bg_height,
1257 1259 jsdata=lambda **x: graphdata(True, **x),
1258 1260 nodes=lambda **x: graphdata(False, **x),
1259 1261 node=ctx.hex(), changenav=changenav)
1260 1262
1261 1263 def _getdoc(e):
1262 1264 doc = e[0].__doc__
1263 1265 if doc:
1264 1266 doc = _(doc).split('\n')[0]
1265 1267 else:
1266 1268 doc = _('(no help text available)')
1267 1269 return doc
1268 1270
1269 1271 @webcommand('help')
1270 1272 def help(web, req, tmpl):
1271 1273 """
1272 1274 /help[/{topic}]
1273 1275 ---------------
1274 1276
1275 1277 Render help documentation.
1276 1278
1277 1279 This web command is roughly equivalent to :hg:`help`. If a ``topic``
1278 1280 is defined, that help topic will be rendered. If not, an index of
1279 1281 available help topics will be rendered.
1280 1282
1281 1283 The ``help`` template will be rendered when requesting help for a topic.
1282 1284 ``helptopics`` will be rendered for the index of help topics.
1283 1285 """
1284 1286 from mercurial import commands # avoid cycle
1285 1287 from mercurial import help as helpmod # avoid cycle
1286 1288
1287 1289 topicname = req.form.get('node', [None])[0]
1288 1290 if not topicname:
1289 1291 def topics(**map):
1290 1292 for entries, summary, _doc in helpmod.helptable:
1291 1293 yield {'topic': entries[0], 'summary': summary}
1292 1294
1293 1295 early, other = [], []
1294 1296 primary = lambda s: s.split('|')[0]
1295 1297 for c, e in commands.table.iteritems():
1296 1298 doc = _getdoc(e)
1297 1299 if 'DEPRECATED' in doc or c.startswith('debug'):
1298 1300 continue
1299 1301 cmd = primary(c)
1300 1302 if cmd.startswith('^'):
1301 1303 early.append((cmd[1:], doc))
1302 1304 else:
1303 1305 other.append((cmd, doc))
1304 1306
1305 1307 early.sort()
1306 1308 other.sort()
1307 1309
1308 1310 def earlycommands(**map):
1309 1311 for c, doc in early:
1310 1312 yield {'topic': c, 'summary': doc}
1311 1313
1312 1314 def othercommands(**map):
1313 1315 for c, doc in other:
1314 1316 yield {'topic': c, 'summary': doc}
1315 1317
1316 1318 return tmpl('helptopics', topics=topics, earlycommands=earlycommands,
1317 1319 othercommands=othercommands, title='Index')
1318 1320
1319 1321 u = webutil.wsgiui()
1320 1322 u.verbose = True
1321 1323 try:
1322 1324 doc = helpmod.help_(u, topicname)
1323 1325 except error.UnknownCommand:
1324 1326 raise ErrorResponse(HTTP_NOT_FOUND)
1325 1327 return tmpl('help', topic=topicname, doc=doc)
1326 1328
1327 1329 # tell hggettext to extract docstrings from these functions:
1328 1330 i18nfunctions = commands.values()
@@ -1,91 +1,91 b''
1 1 {header}
2 2 <title>{repo|escape}: {file|escape} comparison</title>
3 3 </head>
4 4 <body>
5 5
6 6 <div class="container">
7 7 <div class="menu">
8 8 <div class="logo">
9 9 <a href="{logourl}">
10 10 <img src="{staticurl|urlescape}{logoimg}" alt="mercurial" /></a>
11 11 </div>
12 12 <ul>
13 13 <li><a href="{url|urlescape}shortlog/{node|short}{sessionvars%urlparameter}">log</a></li>
14 14 <li><a href="{url|urlescape}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
15 15 <li><a href="{url|urlescape}tags{sessionvars%urlparameter}">tags</a></li>
16 16 <li><a href="{url|urlescape}bookmarks{sessionvars%urlparameter}">bookmarks</a></li>
17 17 <li><a href="{url|urlescape}branches{sessionvars%urlparameter}">branches</a></li>
18 18 </ul>
19 19 <ul>
20 20 <li><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">changeset</a></li>
21 21 <li><a href="{url|urlescape}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">browse</a></li>
22 22 </ul>
23 23 <ul>
24 24 <li><a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a></li>
25 25 <li><a href="{url|urlescape}file/tip/{file|urlescape}{sessionvars%urlparameter}">latest</a></li>
26 26 <li><a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a></li>
27 27 <li class="active">comparison</li>
28 28 <li><a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a></li>
29 29 <li><a href="{url|urlescape}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file log</a></li>
30 30 <li><a href="{url|urlescape}raw-file/{node|short}/{file|urlescape}">raw</a></li>
31 31 </ul>
32 32 <ul>
33 33 <li><a href="{url|urlescape}help{sessionvars%urlparameter}">help</a></li>
34 34 </ul>
35 35 </div>
36 36
37 37 <div class="main">
38 38 <h2 class="breadcrumb"><a href="/">Mercurial</a> {pathdef%breadcrumb}</h2>
39 <h3>comparison {file|escape} @ {rev}:{node|short}</h3>
39 <h3>comparison {file|escape} @ {rev}:{node|short} {branch%changelogbranchname}{tags%changelogtag}{bookmarks%changelogtag}</h3>
40 40
41 41 <form class="search" action="{url|urlescape}log">
42 42 <p>{sessionvars%hiddenformentry}</p>
43 43 <p><input name="rev" id="search1" type="text" size="30" /></p>
44 44 <div id="hint">{searchhint}</div>
45 45 </form>
46 46
47 47 <div class="description">{desc|strip|escape|websub|nonempty}</div>
48 48
49 49 <table id="changesetEntry">
50 50 <tr>
51 51 <th>author</th>
52 52 <td>{author|obfuscate}</td>
53 53 </tr>
54 54 <tr>
55 55 <th>date</th>
56 56 <td class="date age">{date|rfc822date}</td>
57 57 </tr>
58 58 <tr>
59 59 <th>parents</th>
60 60 <td>{parent%filerevparent}</td>
61 61 </tr>
62 62 <tr>
63 63 <th>children</th>
64 64 <td>{child%filerevchild}</td>
65 65 </tr>
66 66 </table>
67 67
68 68 <div class="overflow">
69 69 <div class="sourcefirst"> comparison</div>
70 70 <div class="legend">
71 71 <span class="legendinfo equal">equal</span>
72 72 <span class="legendinfo delete">deleted</span>
73 73 <span class="legendinfo insert">inserted</span>
74 74 <span class="legendinfo replace">replaced</span>
75 75 </div>
76 76
77 77 <table class="bigtable">
78 78 <thead class="header">
79 79 <tr>
80 80 <th>{leftrev}:{leftnode|short}</th>
81 81 <th>{rightrev}:{rightnode|short}</th>
82 82 </tr>
83 83 </thead>
84 84 {comparison}
85 85 </table>
86 86
87 87 </div>
88 88 </div>
89 89 </div>
90 90
91 91 {footer}
@@ -1,1144 +1,1144 b''
1 1 #require serve
2 2
3 3 setting up repo
4 4
5 5 $ hg init test
6 6 $ cd test
7 7 $ echo a > a
8 8 $ echo b > b
9 9 $ hg ci -Ama
10 10 adding a
11 11 adding b
12 12
13 13 change permissions for git diffs
14 14
15 15 $ hg import -q --bypass - <<EOF
16 16 > # HG changeset patch
17 17 > # User test
18 18 > # Date 0 0
19 19 > b
20 20 >
21 21 > diff --git a/a b/a
22 22 > old mode 100644
23 23 > new mode 100755
24 24 > diff --git a/b b/b
25 25 > deleted file mode 100644
26 26 > --- a/b
27 27 > +++ /dev/null
28 28 > @@ -1,1 +0,0 @@
29 29 > -b
30 30 > EOF
31 31
32 32 set up hgweb
33 33
34 34 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
35 35 $ cat hg.pid >> $DAEMON_PIDS
36 36
37 37 revision
38 38
39 39 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'rev/0'
40 40 200 Script output follows
41 41
42 42 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
43 43 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
44 44 <head>
45 45 <link rel="icon" href="/static/hgicon.png" type="image/png" />
46 46 <meta name="robots" content="index, nofollow" />
47 47 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
48 48 <script type="text/javascript" src="/static/mercurial.js"></script>
49 49
50 50 <title>test: 0cd96de13884</title>
51 51 </head>
52 52 <body>
53 53 <div class="container">
54 54 <div class="menu">
55 55 <div class="logo">
56 56 <a href="http://mercurial.selenic.com/">
57 57 <img src="/static/hglogo.png" alt="mercurial" /></a>
58 58 </div>
59 59 <ul>
60 60 <li><a href="/shortlog/0cd96de13884">log</a></li>
61 61 <li><a href="/graph/0cd96de13884">graph</a></li>
62 62 <li><a href="/tags">tags</a></li>
63 63 <li><a href="/bookmarks">bookmarks</a></li>
64 64 <li><a href="/branches">branches</a></li>
65 65 </ul>
66 66 <ul>
67 67 <li class="active">changeset</li>
68 68 <li><a href="/raw-rev/0cd96de13884">raw</a></li>
69 69 <li><a href="/file/0cd96de13884">browse</a></li>
70 70 </ul>
71 71 <ul>
72 72
73 73 </ul>
74 74 <ul>
75 75 <li><a href="/help">help</a></li>
76 76 </ul>
77 77 </div>
78 78
79 79 <div class="main">
80 80
81 81 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
82 82 <h3>changeset 0:0cd96de13884 </h3>
83 83
84 84 <form class="search" action="/log">
85 85
86 86 <p><input name="rev" id="search1" type="text" size="30" /></p>
87 87 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
88 88 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
89 89 </form>
90 90
91 91 <div class="description">a</div>
92 92
93 93 <table id="changesetEntry">
94 94 <tr>
95 95 <th class="author">author</th>
96 96 <td class="author">&#116;&#101;&#115;&#116;</td>
97 97 </tr>
98 98 <tr>
99 99 <th class="date">date</th>
100 100 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
101 101 </tr>
102 102 <tr>
103 103 <th class="author">parents</th>
104 104 <td class="author"></td>
105 105 </tr>
106 106 <tr>
107 107 <th class="author">children</th>
108 108 <td class="author"> <a href="/rev/559edbd9ed20">559edbd9ed20</a></td>
109 109 </tr>
110 110 <tr>
111 111 <th class="files">files</th>
112 112 <td class="files"><a href="/file/0cd96de13884/a">a</a> <a href="/file/0cd96de13884/b">b</a> </td>
113 113 </tr>
114 114 <tr>
115 115 <th class="diffstat">diffstat</th>
116 116 <td class="diffstat">
117 117 2 files changed, 2 insertions(+), 0 deletions(-)
118 118
119 119 <a id="diffstatexpand" href="javascript:toggleDiffstat()">[<tt>+</tt>]</a>
120 120 <div id="diffstatdetails" style="display:none;">
121 121 <a href="javascript:toggleDiffstat()">[<tt>-</tt>]</a>
122 122 <table class="diffstat-table stripes2"> <tr>
123 123 <td class="diffstat-file"><a href="#l1.1">a</a></td>
124 124 <td class="diffstat-total" align="right">1</td>
125 125 <td class="diffstat-graph">
126 126 <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
127 127 <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
128 128 </td>
129 129 </tr>
130 130 <tr>
131 131 <td class="diffstat-file"><a href="#l2.1">b</a></td>
132 132 <td class="diffstat-total" align="right">1</td>
133 133 <td class="diffstat-graph">
134 134 <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
135 135 <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
136 136 </td>
137 137 </tr>
138 138 </table>
139 139 </div>
140 140 </td>
141 141 </tr>
142 142 </table>
143 143
144 144 <div class="overflow">
145 145 <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
146 146 <div class="sourcefirst"> line diff</div>
147 147 <div class="stripes2 diffblocks">
148 148 <div class="bottomline inc-lineno"><pre class="sourcelines wrap">
149 149 <span id="l1.1" class="minusline">--- /dev/null Thu Jan 01 00:00:00 1970 +0000</span><a href="#l1.1"></a>
150 150 <span id="l1.2" class="plusline">+++ b/a Thu Jan 01 00:00:00 1970 +0000</span><a href="#l1.2"></a>
151 151 <span id="l1.3" class="atline">@@ -0,0 +1,1 @@</span><a href="#l1.3"></a>
152 152 <span id="l1.4" class="plusline">+a</span><a href="#l1.4"></a></pre></div><div class="bottomline inc-lineno"><pre class="sourcelines wrap">
153 153 <span id="l2.1" class="minusline">--- /dev/null Thu Jan 01 00:00:00 1970 +0000</span><a href="#l2.1"></a>
154 154 <span id="l2.2" class="plusline">+++ b/b Thu Jan 01 00:00:00 1970 +0000</span><a href="#l2.2"></a>
155 155 <span id="l2.3" class="atline">@@ -0,0 +1,1 @@</span><a href="#l2.3"></a>
156 156 <span id="l2.4" class="plusline">+b</span><a href="#l2.4"></a></pre></div>
157 157 </div>
158 158 </div>
159 159
160 160 </div>
161 161 </div>
162 162 <script type="text/javascript">process_dates()</script>
163 163
164 164
165 165 </body>
166 166 </html>
167 167
168 168
169 169 raw revision
170 170
171 171 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'raw-rev/0'
172 172 200 Script output follows
173 173
174 174
175 175 # HG changeset patch
176 176 # User test
177 177 # Date 0 0
178 178 # Node ID 0cd96de13884b090099512d4794ae87ad067ea8e
179 179
180 180 a
181 181
182 182 diff -r 000000000000 -r 0cd96de13884 a
183 183 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
184 184 +++ b/a Thu Jan 01 00:00:00 1970 +0000
185 185 @@ -0,0 +1,1 @@
186 186 +a
187 187 diff -r 000000000000 -r 0cd96de13884 b
188 188 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
189 189 +++ b/b Thu Jan 01 00:00:00 1970 +0000
190 190 @@ -0,0 +1,1 @@
191 191 +b
192 192
193 193
194 194 diff removed file
195 195
196 196 $ hg log --template "{file_mods}\n{file_dels}\n" -r tip
197 197 a
198 198 b
199 199 $ hg parents --template "{node|short}\n" -r tip
200 200 0cd96de13884
201 201 $ hg parents --template "{node|short}\n" -r tip b
202 202 0cd96de13884
203 203
204 204 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'diff/tip/b'
205 205 200 Script output follows
206 206
207 207 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
208 208 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
209 209 <head>
210 210 <link rel="icon" href="/static/hgicon.png" type="image/png" />
211 211 <meta name="robots" content="index, nofollow" />
212 212 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
213 213 <script type="text/javascript" src="/static/mercurial.js"></script>
214 214
215 215 <title>test: b diff</title>
216 216 </head>
217 217 <body>
218 218
219 219 <div class="container">
220 220 <div class="menu">
221 221 <div class="logo">
222 222 <a href="http://mercurial.selenic.com/">
223 223 <img src="/static/hglogo.png" alt="mercurial" /></a>
224 224 </div>
225 225 <ul>
226 226 <li><a href="/shortlog/559edbd9ed20">log</a></li>
227 227 <li><a href="/graph/559edbd9ed20">graph</a></li>
228 228 <li><a href="/tags">tags</a></li>
229 229 <li><a href="/bookmarks">bookmarks</a></li>
230 230 <li><a href="/branches">branches</a></li>
231 231 </ul>
232 232 <ul>
233 233 <li><a href="/rev/559edbd9ed20">changeset</a></li>
234 234 <li><a href="/file/559edbd9ed20">browse</a></li>
235 235 </ul>
236 236 <ul>
237 237 <li><a href="/file/559edbd9ed20/b">file</a></li>
238 238 <li><a href="/file/tip/b">latest</a></li>
239 239 <li class="active">diff</li>
240 240 <li><a href="/comparison/559edbd9ed20/b">comparison</a></li>
241 241 <li><a href="/annotate/559edbd9ed20/b">annotate</a></li>
242 242 <li><a href="/log/559edbd9ed20/b">file log</a></li>
243 243 <li><a href="/raw-file/559edbd9ed20/b">raw</a></li>
244 244 </ul>
245 245 <ul>
246 246 <li><a href="/help">help</a></li>
247 247 </ul>
248 248 </div>
249 249
250 250 <div class="main">
251 251 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
252 252 <h3>diff b @ 1:559edbd9ed20 <span class="tag">tip</span> </h3>
253 253
254 254 <form class="search" action="/log">
255 255 <p></p>
256 256 <p><input name="rev" id="search1" type="text" size="30" /></p>
257 257 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
258 258 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
259 259 </form>
260 260
261 261 <div class="description">b</div>
262 262
263 263 <table id="changesetEntry">
264 264 <tr>
265 265 <th>author</th>
266 266 <td>&#116;&#101;&#115;&#116;</td>
267 267 </tr>
268 268 <tr>
269 269 <th>date</th>
270 270 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
271 271 </tr>
272 272 <tr>
273 273 <th>parents</th>
274 274 <td><a href="/file/0cd96de13884/b">0cd96de13884</a> </td>
275 275 </tr>
276 276 <tr>
277 277 <th>children</th>
278 278 <td></td>
279 279 </tr>
280 280 </table>
281 281
282 282 <div class="overflow">
283 283 <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
284 284 <div class="sourcefirst"> line diff</div>
285 285 <div class="stripes2 diffblocks">
286 286 <div class="bottomline inc-lineno"><pre class="sourcelines wrap">
287 287 <span id="l1.1" class="minusline">--- a/b Thu Jan 01 00:00:00 1970 +0000</span><a href="#l1.1"></a>
288 288 <span id="l1.2" class="plusline">+++ /dev/null Thu Jan 01 00:00:00 1970 +0000</span><a href="#l1.2"></a>
289 289 <span id="l1.3" class="atline">@@ -1,1 +0,0 @@</span><a href="#l1.3"></a>
290 290 <span id="l1.4" class="minusline">-b</span><a href="#l1.4"></a></pre></div>
291 291 </div>
292 292 </div>
293 293 </div>
294 294 </div>
295 295
296 296 <script type="text/javascript">process_dates()</script>
297 297
298 298
299 299 </body>
300 300 </html>
301 301
302 302
303 303 set up hgweb with git diffs
304 304
305 305 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
306 306 $ hg serve --config 'diff.git=1' -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
307 307 $ cat hg.pid >> $DAEMON_PIDS
308 308
309 309 revision
310 310
311 311 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'rev/0'
312 312 200 Script output follows
313 313
314 314 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
315 315 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
316 316 <head>
317 317 <link rel="icon" href="/static/hgicon.png" type="image/png" />
318 318 <meta name="robots" content="index, nofollow" />
319 319 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
320 320 <script type="text/javascript" src="/static/mercurial.js"></script>
321 321
322 322 <title>test: 0cd96de13884</title>
323 323 </head>
324 324 <body>
325 325 <div class="container">
326 326 <div class="menu">
327 327 <div class="logo">
328 328 <a href="http://mercurial.selenic.com/">
329 329 <img src="/static/hglogo.png" alt="mercurial" /></a>
330 330 </div>
331 331 <ul>
332 332 <li><a href="/shortlog/0cd96de13884">log</a></li>
333 333 <li><a href="/graph/0cd96de13884">graph</a></li>
334 334 <li><a href="/tags">tags</a></li>
335 335 <li><a href="/bookmarks">bookmarks</a></li>
336 336 <li><a href="/branches">branches</a></li>
337 337 </ul>
338 338 <ul>
339 339 <li class="active">changeset</li>
340 340 <li><a href="/raw-rev/0cd96de13884">raw</a></li>
341 341 <li><a href="/file/0cd96de13884">browse</a></li>
342 342 </ul>
343 343 <ul>
344 344
345 345 </ul>
346 346 <ul>
347 347 <li><a href="/help">help</a></li>
348 348 </ul>
349 349 </div>
350 350
351 351 <div class="main">
352 352
353 353 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
354 354 <h3>changeset 0:0cd96de13884 </h3>
355 355
356 356 <form class="search" action="/log">
357 357
358 358 <p><input name="rev" id="search1" type="text" size="30" /></p>
359 359 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
360 360 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
361 361 </form>
362 362
363 363 <div class="description">a</div>
364 364
365 365 <table id="changesetEntry">
366 366 <tr>
367 367 <th class="author">author</th>
368 368 <td class="author">&#116;&#101;&#115;&#116;</td>
369 369 </tr>
370 370 <tr>
371 371 <th class="date">date</th>
372 372 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
373 373 </tr>
374 374 <tr>
375 375 <th class="author">parents</th>
376 376 <td class="author"></td>
377 377 </tr>
378 378 <tr>
379 379 <th class="author">children</th>
380 380 <td class="author"> <a href="/rev/559edbd9ed20">559edbd9ed20</a></td>
381 381 </tr>
382 382 <tr>
383 383 <th class="files">files</th>
384 384 <td class="files"><a href="/file/0cd96de13884/a">a</a> <a href="/file/0cd96de13884/b">b</a> </td>
385 385 </tr>
386 386 <tr>
387 387 <th class="diffstat">diffstat</th>
388 388 <td class="diffstat">
389 389 2 files changed, 2 insertions(+), 0 deletions(-)
390 390
391 391 <a id="diffstatexpand" href="javascript:toggleDiffstat()">[<tt>+</tt>]</a>
392 392 <div id="diffstatdetails" style="display:none;">
393 393 <a href="javascript:toggleDiffstat()">[<tt>-</tt>]</a>
394 394 <table class="diffstat-table stripes2"> <tr>
395 395 <td class="diffstat-file"><a href="#l1.1">a</a></td>
396 396 <td class="diffstat-total" align="right">1</td>
397 397 <td class="diffstat-graph">
398 398 <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
399 399 <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
400 400 </td>
401 401 </tr>
402 402 <tr>
403 403 <td class="diffstat-file"><a href="#l2.1">b</a></td>
404 404 <td class="diffstat-total" align="right">1</td>
405 405 <td class="diffstat-graph">
406 406 <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
407 407 <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
408 408 </td>
409 409 </tr>
410 410 </table>
411 411 </div>
412 412 </td>
413 413 </tr>
414 414 </table>
415 415
416 416 <div class="overflow">
417 417 <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
418 418 <div class="sourcefirst"> line diff</div>
419 419 <div class="stripes2 diffblocks">
420 420 <div class="bottomline inc-lineno"><pre class="sourcelines wrap">
421 421 <span id="l1.1">new file mode 100644</span><a href="#l1.1"></a>
422 422 <span id="l1.2" class="minusline">--- /dev/null</span><a href="#l1.2"></a>
423 423 <span id="l1.3" class="plusline">+++ b/a</span><a href="#l1.3"></a>
424 424 <span id="l1.4" class="atline">@@ -0,0 +1,1 @@</span><a href="#l1.4"></a>
425 425 <span id="l1.5" class="plusline">+a</span><a href="#l1.5"></a></pre></div><div class="bottomline inc-lineno"><pre class="sourcelines wrap">
426 426 <span id="l2.1">new file mode 100644</span><a href="#l2.1"></a>
427 427 <span id="l2.2" class="minusline">--- /dev/null</span><a href="#l2.2"></a>
428 428 <span id="l2.3" class="plusline">+++ b/b</span><a href="#l2.3"></a>
429 429 <span id="l2.4" class="atline">@@ -0,0 +1,1 @@</span><a href="#l2.4"></a>
430 430 <span id="l2.5" class="plusline">+b</span><a href="#l2.5"></a></pre></div>
431 431 </div>
432 432 </div>
433 433
434 434 </div>
435 435 </div>
436 436 <script type="text/javascript">process_dates()</script>
437 437
438 438
439 439 </body>
440 440 </html>
441 441
442 442
443 443 revision
444 444
445 445 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'raw-rev/0'
446 446 200 Script output follows
447 447
448 448
449 449 # HG changeset patch
450 450 # User test
451 451 # Date 0 0
452 452 # Node ID 0cd96de13884b090099512d4794ae87ad067ea8e
453 453
454 454 a
455 455
456 456 diff --git a/a b/a
457 457 new file mode 100644
458 458 --- /dev/null
459 459 +++ b/a
460 460 @@ -0,0 +1,1 @@
461 461 +a
462 462 diff --git a/b b/b
463 463 new file mode 100644
464 464 --- /dev/null
465 465 +++ b/b
466 466 @@ -0,0 +1,1 @@
467 467 +b
468 468
469 469
470 470 diff modified file
471 471
472 472 $ hg log --template "{file_mods}\n{file_dels}\n" -r tip
473 473 a
474 474 b
475 475 $ hg parents --template "{node|short}\n" -r tip
476 476 0cd96de13884
477 477 $ hg parents --template "{node|short}\n" -r tip a
478 478 0cd96de13884
479 479
480 480 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'diff/tip/a'
481 481 200 Script output follows
482 482
483 483 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
484 484 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
485 485 <head>
486 486 <link rel="icon" href="/static/hgicon.png" type="image/png" />
487 487 <meta name="robots" content="index, nofollow" />
488 488 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
489 489 <script type="text/javascript" src="/static/mercurial.js"></script>
490 490
491 491 <title>test: a diff</title>
492 492 </head>
493 493 <body>
494 494
495 495 <div class="container">
496 496 <div class="menu">
497 497 <div class="logo">
498 498 <a href="http://mercurial.selenic.com/">
499 499 <img src="/static/hglogo.png" alt="mercurial" /></a>
500 500 </div>
501 501 <ul>
502 502 <li><a href="/shortlog/559edbd9ed20">log</a></li>
503 503 <li><a href="/graph/559edbd9ed20">graph</a></li>
504 504 <li><a href="/tags">tags</a></li>
505 505 <li><a href="/bookmarks">bookmarks</a></li>
506 506 <li><a href="/branches">branches</a></li>
507 507 </ul>
508 508 <ul>
509 509 <li><a href="/rev/559edbd9ed20">changeset</a></li>
510 510 <li><a href="/file/559edbd9ed20">browse</a></li>
511 511 </ul>
512 512 <ul>
513 513 <li><a href="/file/559edbd9ed20/a">file</a></li>
514 514 <li><a href="/file/tip/a">latest</a></li>
515 515 <li class="active">diff</li>
516 516 <li><a href="/comparison/559edbd9ed20/a">comparison</a></li>
517 517 <li><a href="/annotate/559edbd9ed20/a">annotate</a></li>
518 518 <li><a href="/log/559edbd9ed20/a">file log</a></li>
519 519 <li><a href="/raw-file/559edbd9ed20/a">raw</a></li>
520 520 </ul>
521 521 <ul>
522 522 <li><a href="/help">help</a></li>
523 523 </ul>
524 524 </div>
525 525
526 526 <div class="main">
527 527 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
528 528 <h3>diff a @ 1:559edbd9ed20 <span class="tag">tip</span> </h3>
529 529
530 530 <form class="search" action="/log">
531 531 <p></p>
532 532 <p><input name="rev" id="search1" type="text" size="30" /></p>
533 533 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
534 534 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
535 535 </form>
536 536
537 537 <div class="description">b</div>
538 538
539 539 <table id="changesetEntry">
540 540 <tr>
541 541 <th>author</th>
542 542 <td>&#116;&#101;&#115;&#116;</td>
543 543 </tr>
544 544 <tr>
545 545 <th>date</th>
546 546 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
547 547 </tr>
548 548 <tr>
549 549 <th>parents</th>
550 550 <td><a href="/file/0cd96de13884/a">0cd96de13884</a> </td>
551 551 </tr>
552 552 <tr>
553 553 <th>children</th>
554 554 <td></td>
555 555 </tr>
556 556 </table>
557 557
558 558 <div class="overflow">
559 559 <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
560 560 <div class="sourcefirst"> line diff</div>
561 561 <div class="stripes2 diffblocks">
562 562 <div class="bottomline inc-lineno"><pre class="sourcelines wrap">
563 563 <span id="l1.1">old mode 100644</span><a href="#l1.1"></a>
564 564 <span id="l1.2">new mode 100755</span><a href="#l1.2"></a></pre></div>
565 565 </div>
566 566 </div>
567 567 </div>
568 568 </div>
569 569
570 570 <script type="text/javascript">process_dates()</script>
571 571
572 572
573 573 </body>
574 574 </html>
575 575
576 576
577 577 comparison new file
578 578
579 579 $ hg parents --template "{rev}:{node|short}\n" -r 0
580 580 $ hg log --template "{rev}:{node|short}\n" -r 0
581 581 0:0cd96de13884
582 582
583 583 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'comparison/0/a'
584 584 200 Script output follows
585 585
586 586 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
587 587 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
588 588 <head>
589 589 <link rel="icon" href="/static/hgicon.png" type="image/png" />
590 590 <meta name="robots" content="index, nofollow" />
591 591 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
592 592 <script type="text/javascript" src="/static/mercurial.js"></script>
593 593
594 594 <title>test: a comparison</title>
595 595 </head>
596 596 <body>
597 597
598 598 <div class="container">
599 599 <div class="menu">
600 600 <div class="logo">
601 601 <a href="http://mercurial.selenic.com/">
602 602 <img src="/static/hglogo.png" alt="mercurial" /></a>
603 603 </div>
604 604 <ul>
605 605 <li><a href="/shortlog/0cd96de13884">log</a></li>
606 606 <li><a href="/graph/0cd96de13884">graph</a></li>
607 607 <li><a href="/tags">tags</a></li>
608 608 <li><a href="/bookmarks">bookmarks</a></li>
609 609 <li><a href="/branches">branches</a></li>
610 610 </ul>
611 611 <ul>
612 612 <li><a href="/rev/0cd96de13884">changeset</a></li>
613 613 <li><a href="/file/0cd96de13884">browse</a></li>
614 614 </ul>
615 615 <ul>
616 616 <li><a href="/file/0cd96de13884/a">file</a></li>
617 617 <li><a href="/file/tip/a">latest</a></li>
618 618 <li><a href="/diff/0cd96de13884/a">diff</a></li>
619 619 <li class="active">comparison</li>
620 620 <li><a href="/annotate/0cd96de13884/a">annotate</a></li>
621 621 <li><a href="/log/0cd96de13884/a">file log</a></li>
622 622 <li><a href="/raw-file/0cd96de13884/a">raw</a></li>
623 623 </ul>
624 624 <ul>
625 625 <li><a href="/help">help</a></li>
626 626 </ul>
627 627 </div>
628 628
629 629 <div class="main">
630 630 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
631 631 <h3>comparison a @ 0:0cd96de13884</h3>
632 632
633 633 <form class="search" action="/log">
634 634 <p></p>
635 635 <p><input name="rev" id="search1" type="text" size="30" /></p>
636 636 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
637 637 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
638 638 </form>
639 639
640 640 <div class="description">a</div>
641 641
642 642 <table id="changesetEntry">
643 643 <tr>
644 644 <th>author</th>
645 645 <td>&#116;&#101;&#115;&#116;</td>
646 646 </tr>
647 647 <tr>
648 648 <th>date</th>
649 649 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
650 650 </tr>
651 651 <tr>
652 652 <th>parents</th>
653 653 <td></td>
654 654 </tr>
655 655 <tr>
656 656 <th>children</th>
657 657 <td></td>
658 658 </tr>
659 659 </table>
660 660
661 661 <div class="overflow">
662 662 <div class="sourcefirst"> comparison</div>
663 663 <div class="legend">
664 664 <span class="legendinfo equal">equal</span>
665 665 <span class="legendinfo delete">deleted</span>
666 666 <span class="legendinfo insert">inserted</span>
667 667 <span class="legendinfo replace">replaced</span>
668 668 </div>
669 669
670 670 <table class="bigtable">
671 671 <thead class="header">
672 672 <tr>
673 673 <th>-1:000000000000</th>
674 674 <th>0:0cd96de13884</th>
675 675 </tr>
676 676 </thead>
677 677
678 678 <tbody class="block">
679 679
680 680 <tr id="r1">
681 681 <td class="source insert"><a href="#r1"> </a> </td>
682 682 <td class="source insert"><a href="#r1"> 1</a> a</td>
683 683 </tr>
684 684 </tbody>
685 685 </table>
686 686
687 687 </div>
688 688 </div>
689 689 </div>
690 690
691 691 <script type="text/javascript">process_dates()</script>
692 692
693 693
694 694 </body>
695 695 </html>
696 696
697 697
698 698 comparison existing file
699 699
700 700 $ hg up
701 701 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
702 702 $ echo a >> a
703 703 $ hg ci -mc
704 704
705 705 $ hg parents --template "{rev}:{node|short}\n" -r tip
706 706 1:559edbd9ed20
707 707 $ hg log --template "{rev}:{node|short}\n" -r tip
708 708 2:d73db4d812ff
709 709
710 710 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'comparison/tip/a'
711 711 200 Script output follows
712 712
713 713 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
714 714 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
715 715 <head>
716 716 <link rel="icon" href="/static/hgicon.png" type="image/png" />
717 717 <meta name="robots" content="index, nofollow" />
718 718 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
719 719 <script type="text/javascript" src="/static/mercurial.js"></script>
720 720
721 721 <title>test: a comparison</title>
722 722 </head>
723 723 <body>
724 724
725 725 <div class="container">
726 726 <div class="menu">
727 727 <div class="logo">
728 728 <a href="http://mercurial.selenic.com/">
729 729 <img src="/static/hglogo.png" alt="mercurial" /></a>
730 730 </div>
731 731 <ul>
732 732 <li><a href="/shortlog/d73db4d812ff">log</a></li>
733 733 <li><a href="/graph/d73db4d812ff">graph</a></li>
734 734 <li><a href="/tags">tags</a></li>
735 735 <li><a href="/bookmarks">bookmarks</a></li>
736 736 <li><a href="/branches">branches</a></li>
737 737 </ul>
738 738 <ul>
739 739 <li><a href="/rev/d73db4d812ff">changeset</a></li>
740 740 <li><a href="/file/d73db4d812ff">browse</a></li>
741 741 </ul>
742 742 <ul>
743 743 <li><a href="/file/d73db4d812ff/a">file</a></li>
744 744 <li><a href="/file/tip/a">latest</a></li>
745 745 <li><a href="/diff/d73db4d812ff/a">diff</a></li>
746 746 <li class="active">comparison</li>
747 747 <li><a href="/annotate/d73db4d812ff/a">annotate</a></li>
748 748 <li><a href="/log/d73db4d812ff/a">file log</a></li>
749 749 <li><a href="/raw-file/d73db4d812ff/a">raw</a></li>
750 750 </ul>
751 751 <ul>
752 752 <li><a href="/help">help</a></li>
753 753 </ul>
754 754 </div>
755 755
756 756 <div class="main">
757 757 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
758 <h3>comparison a @ 2:d73db4d812ff</h3>
758 <h3>comparison a @ 2:d73db4d812ff <span class="tag">tip</span> </h3>
759 759
760 760 <form class="search" action="/log">
761 761 <p></p>
762 762 <p><input name="rev" id="search1" type="text" size="30" /></p>
763 763 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
764 764 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
765 765 </form>
766 766
767 767 <div class="description">c</div>
768 768
769 769 <table id="changesetEntry">
770 770 <tr>
771 771 <th>author</th>
772 772 <td>&#116;&#101;&#115;&#116;</td>
773 773 </tr>
774 774 <tr>
775 775 <th>date</th>
776 776 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
777 777 </tr>
778 778 <tr>
779 779 <th>parents</th>
780 780 <td><a href="/file/0cd96de13884/a">0cd96de13884</a> </td>
781 781 </tr>
782 782 <tr>
783 783 <th>children</th>
784 784 <td></td>
785 785 </tr>
786 786 </table>
787 787
788 788 <div class="overflow">
789 789 <div class="sourcefirst"> comparison</div>
790 790 <div class="legend">
791 791 <span class="legendinfo equal">equal</span>
792 792 <span class="legendinfo delete">deleted</span>
793 793 <span class="legendinfo insert">inserted</span>
794 794 <span class="legendinfo replace">replaced</span>
795 795 </div>
796 796
797 797 <table class="bigtable">
798 798 <thead class="header">
799 799 <tr>
800 800 <th>1:559edbd9ed20</th>
801 801 <th>2:d73db4d812ff</th>
802 802 </tr>
803 803 </thead>
804 804
805 805 <tbody class="block">
806 806
807 807 <tr id="l1r1">
808 808 <td class="source equal"><a href="#l1r1"> 1</a> a</td>
809 809 <td class="source equal"><a href="#l1r1"> 1</a> a</td>
810 810 </tr>
811 811 <tr id="r2">
812 812 <td class="source insert"><a href="#r2"> </a> </td>
813 813 <td class="source insert"><a href="#r2"> 2</a> a</td>
814 814 </tr>
815 815 </tbody>
816 816 </table>
817 817
818 818 </div>
819 819 </div>
820 820 </div>
821 821
822 822 <script type="text/javascript">process_dates()</script>
823 823
824 824
825 825 </body>
826 826 </html>
827 827
828 828
829 829 comparison removed file
830 830
831 831 $ hg rm a
832 832 $ hg ci -md
833 833
834 834 $ hg parents --template "{rev}:{node|short}\n" -r tip
835 835 2:d73db4d812ff
836 836 $ hg log --template "{rev}:{node|short}\n" -r tip
837 837 3:20e80271eb7a
838 838
839 839 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'comparison/tip/a'
840 840 200 Script output follows
841 841
842 842 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
843 843 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
844 844 <head>
845 845 <link rel="icon" href="/static/hgicon.png" type="image/png" />
846 846 <meta name="robots" content="index, nofollow" />
847 847 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
848 848 <script type="text/javascript" src="/static/mercurial.js"></script>
849 849
850 850 <title>test: a comparison</title>
851 851 </head>
852 852 <body>
853 853
854 854 <div class="container">
855 855 <div class="menu">
856 856 <div class="logo">
857 857 <a href="http://mercurial.selenic.com/">
858 858 <img src="/static/hglogo.png" alt="mercurial" /></a>
859 859 </div>
860 860 <ul>
861 861 <li><a href="/shortlog/20e80271eb7a">log</a></li>
862 862 <li><a href="/graph/20e80271eb7a">graph</a></li>
863 863 <li><a href="/tags">tags</a></li>
864 864 <li><a href="/bookmarks">bookmarks</a></li>
865 865 <li><a href="/branches">branches</a></li>
866 866 </ul>
867 867 <ul>
868 868 <li><a href="/rev/20e80271eb7a">changeset</a></li>
869 869 <li><a href="/file/20e80271eb7a">browse</a></li>
870 870 </ul>
871 871 <ul>
872 872 <li><a href="/file/20e80271eb7a/a">file</a></li>
873 873 <li><a href="/file/tip/a">latest</a></li>
874 874 <li><a href="/diff/20e80271eb7a/a">diff</a></li>
875 875 <li class="active">comparison</li>
876 876 <li><a href="/annotate/20e80271eb7a/a">annotate</a></li>
877 877 <li><a href="/log/20e80271eb7a/a">file log</a></li>
878 878 <li><a href="/raw-file/20e80271eb7a/a">raw</a></li>
879 879 </ul>
880 880 <ul>
881 881 <li><a href="/help">help</a></li>
882 882 </ul>
883 883 </div>
884 884
885 885 <div class="main">
886 886 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
887 <h3>comparison a @ 3:20e80271eb7a</h3>
887 <h3>comparison a @ 3:20e80271eb7a <span class="tag">tip</span> </h3>
888 888
889 889 <form class="search" action="/log">
890 890 <p></p>
891 891 <p><input name="rev" id="search1" type="text" size="30" /></p>
892 892 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
893 893 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
894 894 </form>
895 895
896 896 <div class="description">d</div>
897 897
898 898 <table id="changesetEntry">
899 899 <tr>
900 900 <th>author</th>
901 901 <td>&#116;&#101;&#115;&#116;</td>
902 902 </tr>
903 903 <tr>
904 904 <th>date</th>
905 905 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
906 906 </tr>
907 907 <tr>
908 908 <th>parents</th>
909 909 <td><a href="/file/0cd96de13884/a">0cd96de13884</a> </td>
910 910 </tr>
911 911 <tr>
912 912 <th>children</th>
913 913 <td></td>
914 914 </tr>
915 915 </table>
916 916
917 917 <div class="overflow">
918 918 <div class="sourcefirst"> comparison</div>
919 919 <div class="legend">
920 920 <span class="legendinfo equal">equal</span>
921 921 <span class="legendinfo delete">deleted</span>
922 922 <span class="legendinfo insert">inserted</span>
923 923 <span class="legendinfo replace">replaced</span>
924 924 </div>
925 925
926 926 <table class="bigtable">
927 927 <thead class="header">
928 928 <tr>
929 929 <th>2:d73db4d812ff</th>
930 930 <th>3:20e80271eb7a</th>
931 931 </tr>
932 932 </thead>
933 933
934 934 <tbody class="block">
935 935
936 936 <tr id="l1">
937 937 <td class="source delete"><a href="#l1"> 1</a> a</td>
938 938 <td class="source delete"><a href="#l1"> </a> </td>
939 939 </tr>
940 940 <tr id="l2">
941 941 <td class="source delete"><a href="#l2"> 2</a> a</td>
942 942 <td class="source delete"><a href="#l2"> </a> </td>
943 943 </tr>
944 944 </tbody>
945 945 </table>
946 946
947 947 </div>
948 948 </div>
949 949 </div>
950 950
951 951 <script type="text/javascript">process_dates()</script>
952 952
953 953
954 954 </body>
955 955 </html>
956 956
957 957
958 958 comparison not-modified file
959 959
960 960 $ echo e > e
961 961 $ hg add e
962 962 $ hg ci -m e
963 963 $ echo f > f
964 964 $ hg add f
965 965 $ hg ci -m f
966 966 $ hg tip --template "{rev}:{node|short}\n"
967 967 5:41d9fc4a6ae1
968 968 $ hg diff -c tip e
969 969 $ hg parents --template "{rev}:{node|short}\n" -r tip
970 970 4:402bea3b0976
971 971 $ hg parents --template "{rev}:{node|short}\n" -r tip e
972 972 4:402bea3b0976
973 973
974 974 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'comparison/tip/e'
975 975 200 Script output follows
976 976
977 977 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
978 978 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
979 979 <head>
980 980 <link rel="icon" href="/static/hgicon.png" type="image/png" />
981 981 <meta name="robots" content="index, nofollow" />
982 982 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
983 983 <script type="text/javascript" src="/static/mercurial.js"></script>
984 984
985 985 <title>test: e comparison</title>
986 986 </head>
987 987 <body>
988 988
989 989 <div class="container">
990 990 <div class="menu">
991 991 <div class="logo">
992 992 <a href="http://mercurial.selenic.com/">
993 993 <img src="/static/hglogo.png" alt="mercurial" /></a>
994 994 </div>
995 995 <ul>
996 996 <li><a href="/shortlog/41d9fc4a6ae1">log</a></li>
997 997 <li><a href="/graph/41d9fc4a6ae1">graph</a></li>
998 998 <li><a href="/tags">tags</a></li>
999 999 <li><a href="/bookmarks">bookmarks</a></li>
1000 1000 <li><a href="/branches">branches</a></li>
1001 1001 </ul>
1002 1002 <ul>
1003 1003 <li><a href="/rev/41d9fc4a6ae1">changeset</a></li>
1004 1004 <li><a href="/file/41d9fc4a6ae1">browse</a></li>
1005 1005 </ul>
1006 1006 <ul>
1007 1007 <li><a href="/file/41d9fc4a6ae1/e">file</a></li>
1008 1008 <li><a href="/file/tip/e">latest</a></li>
1009 1009 <li><a href="/diff/41d9fc4a6ae1/e">diff</a></li>
1010 1010 <li class="active">comparison</li>
1011 1011 <li><a href="/annotate/41d9fc4a6ae1/e">annotate</a></li>
1012 1012 <li><a href="/log/41d9fc4a6ae1/e">file log</a></li>
1013 1013 <li><a href="/raw-file/41d9fc4a6ae1/e">raw</a></li>
1014 1014 </ul>
1015 1015 <ul>
1016 1016 <li><a href="/help">help</a></li>
1017 1017 </ul>
1018 1018 </div>
1019 1019
1020 1020 <div class="main">
1021 1021 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
1022 <h3>comparison e @ 5:41d9fc4a6ae1</h3>
1022 <h3>comparison e @ 5:41d9fc4a6ae1 <span class="tag">tip</span> </h3>
1023 1023
1024 1024 <form class="search" action="/log">
1025 1025 <p></p>
1026 1026 <p><input name="rev" id="search1" type="text" size="30" /></p>
1027 1027 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
1028 1028 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
1029 1029 </form>
1030 1030
1031 1031 <div class="description">f</div>
1032 1032
1033 1033 <table id="changesetEntry">
1034 1034 <tr>
1035 1035 <th>author</th>
1036 1036 <td>&#116;&#101;&#115;&#116;</td>
1037 1037 </tr>
1038 1038 <tr>
1039 1039 <th>date</th>
1040 1040 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1041 1041 </tr>
1042 1042 <tr>
1043 1043 <th>parents</th>
1044 1044 <td><a href="/file/402bea3b0976/e">402bea3b0976</a> </td>
1045 1045 </tr>
1046 1046 <tr>
1047 1047 <th>children</th>
1048 1048 <td></td>
1049 1049 </tr>
1050 1050 </table>
1051 1051
1052 1052 <div class="overflow">
1053 1053 <div class="sourcefirst"> comparison</div>
1054 1054 <div class="legend">
1055 1055 <span class="legendinfo equal">equal</span>
1056 1056 <span class="legendinfo delete">deleted</span>
1057 1057 <span class="legendinfo insert">inserted</span>
1058 1058 <span class="legendinfo replace">replaced</span>
1059 1059 </div>
1060 1060
1061 1061 <table class="bigtable">
1062 1062 <thead class="header">
1063 1063 <tr>
1064 1064 <th>4:402bea3b0976</th>
1065 1065 <th>5:41d9fc4a6ae1</th>
1066 1066 </tr>
1067 1067 </thead>
1068 1068
1069 1069 </table>
1070 1070
1071 1071 </div>
1072 1072 </div>
1073 1073 </div>
1074 1074
1075 1075 <script type="text/javascript">process_dates()</script>
1076 1076
1077 1077
1078 1078 </body>
1079 1079 </html>
1080 1080
1081 1081 $ cd ..
1082 1082
1083 1083 test import rev as raw-rev
1084 1084
1085 1085 $ hg clone -r0 test test1
1086 1086 adding changesets
1087 1087 adding manifests
1088 1088 adding file changes
1089 1089 added 1 changesets with 2 changes to 2 files
1090 1090 updating to branch default
1091 1091 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1092 1092 $ cd test1
1093 1093 $ hg import -q --bypass --exact http://localhost:$HGPORT/rev/1
1094 1094
1095 1095 raw revision with diff block numbers
1096 1096
1097 1097 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
1098 1098 $ cat <<EOF > .hg/hgrc
1099 1099 > [web]
1100 1100 > templates = rawdiff
1101 1101 > EOF
1102 1102 $ mkdir rawdiff
1103 1103 $ cat <<EOF > rawdiff/map
1104 1104 > mimetype = 'text/plain; charset={encoding}'
1105 1105 > changeset = '{diff}'
1106 1106 > difflineplus = '{line}'
1107 1107 > difflineminus = '{line}'
1108 1108 > difflineat = '{line}'
1109 1109 > diffline = '{line}'
1110 1110 > filenodelink = ''
1111 1111 > filenolink = ''
1112 1112 > fileline = '{line}'
1113 1113 > diffblock = 'Block: {blockno}\n{lines}\n'
1114 1114 > EOF
1115 1115 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
1116 1116 $ cat hg.pid >> $DAEMON_PIDS
1117 1117 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'raw-rev/0'
1118 1118 200 Script output follows
1119 1119
1120 1120 Block: 1
1121 1121 diff -r 000000000000 -r 0cd96de13884 a
1122 1122 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1123 1123 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1124 1124 @@ -0,0 +1,1 @@
1125 1125 +a
1126 1126
1127 1127 Block: 2
1128 1128 diff -r 000000000000 -r 0cd96de13884 b
1129 1129 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1130 1130 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1131 1131 @@ -0,0 +1,1 @@
1132 1132 +b
1133 1133
1134 1134 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
1135 1135 $ rm .hg/hgrc rawdiff/map
1136 1136 $ rmdir rawdiff
1137 1137 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
1138 1138 $ cat hg.pid >> $DAEMON_PIDS
1139 1139
1140 1140 errors
1141 1141
1142 1142 $ cat ../test/errors.log
1143 1143
1144 1144 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now