##// END OF EJS Templates
paper: show branch/tags/bookmarks when diffing (issue3559)
Anton Shestakov -
r25134:339e3cc0 default
parent child Browse files
Show More
@@ -1,1326 +1,1328 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 tags=webutil.nodetagsdict(web.repo, n),
815 bookmarks=webutil.nodebookmarksdict(web.repo, n),
814 816 diff=diffs)
815 817
816 818 diff = webcommand('diff')(filediff)
817 819
818 820 @webcommand('comparison')
819 821 def comparison(web, req, tmpl):
820 822 """
821 823 /comparison/{revision}/{path}
822 824 -----------------------------
823 825
824 826 Show a comparison between the old and new versions of a file from changes
825 827 made on a particular revision.
826 828
827 829 This is similar to the ``diff`` handler. However, this form features
828 830 a split or side-by-side diff rather than a unified diff.
829 831
830 832 The ``context`` query string argument can be used to control the lines of
831 833 context in the diff.
832 834
833 835 The ``filecomparison`` template is rendered.
834 836 """
835 837 ctx = webutil.changectx(web.repo, req)
836 838 if 'file' not in req.form:
837 839 raise ErrorResponse(HTTP_NOT_FOUND, 'file not given')
838 840 path = webutil.cleanpath(web.repo, req.form['file'][0])
839 841 rename = path in ctx and webutil.renamelink(ctx[path]) or []
840 842
841 843 parsecontext = lambda v: v == 'full' and -1 or int(v)
842 844 if 'context' in req.form:
843 845 context = parsecontext(req.form['context'][0])
844 846 else:
845 847 context = parsecontext(web.config('web', 'comparisoncontext', '5'))
846 848
847 849 def filelines(f):
848 850 if util.binary(f.data()):
849 851 mt = mimetypes.guess_type(f.path())[0]
850 852 if not mt:
851 853 mt = 'application/octet-stream'
852 854 return [_('(binary file %s, hash: %s)') % (mt, hex(f.filenode()))]
853 855 return f.data().splitlines()
854 856
855 857 parent = ctx.p1()
856 858 leftrev = parent.rev()
857 859 leftnode = parent.node()
858 860 rightrev = ctx.rev()
859 861 rightnode = ctx.node()
860 862 if path in ctx:
861 863 fctx = ctx[path]
862 864 rightlines = filelines(fctx)
863 865 if path not in parent:
864 866 leftlines = ()
865 867 else:
866 868 pfctx = parent[path]
867 869 leftlines = filelines(pfctx)
868 870 else:
869 871 rightlines = ()
870 872 fctx = ctx.parents()[0][path]
871 873 leftlines = filelines(fctx)
872 874
873 875 comparison = webutil.compare(tmpl, context, leftlines, rightlines)
874 876 return tmpl('filecomparison',
875 877 file=path,
876 878 node=hex(ctx.node()),
877 879 rev=ctx.rev(),
878 880 date=ctx.date(),
879 881 desc=ctx.description(),
880 882 extra=ctx.extra(),
881 883 author=ctx.user(),
882 884 rename=rename,
883 885 branch=webutil.nodebranchnodefault(ctx),
884 886 parent=webutil.parents(fctx),
885 887 child=webutil.children(fctx),
886 888 leftrev=leftrev,
887 889 leftnode=hex(leftnode),
888 890 rightrev=rightrev,
889 891 rightnode=hex(rightnode),
890 892 comparison=comparison)
891 893
892 894 @webcommand('annotate')
893 895 def annotate(web, req, tmpl):
894 896 """
895 897 /annotate/{revision}/{path}
896 898 ---------------------------
897 899
898 900 Show changeset information for each line in a file.
899 901
900 902 The ``fileannotate`` template is rendered.
901 903 """
902 904 fctx = webutil.filectx(web.repo, req)
903 905 f = fctx.path()
904 906 parity = paritygen(web.stripecount)
905 907 diffopts = patch.difffeatureopts(web.repo.ui, untrusted=True,
906 908 section='annotate', whitespace=True)
907 909
908 910 def annotate(**map):
909 911 last = None
910 912 if util.binary(fctx.data()):
911 913 mt = (mimetypes.guess_type(fctx.path())[0]
912 914 or 'application/octet-stream')
913 915 lines = enumerate([((fctx.filectx(fctx.filerev()), 1),
914 916 '(binary:%s)' % mt)])
915 917 else:
916 918 lines = enumerate(fctx.annotate(follow=True, linenumber=True,
917 919 diffopts=diffopts))
918 920 for lineno, ((f, targetline), l) in lines:
919 921 fnode = f.filenode()
920 922
921 923 if last != fnode:
922 924 last = fnode
923 925
924 926 yield {"parity": parity.next(),
925 927 "node": f.hex(),
926 928 "rev": f.rev(),
927 929 "author": f.user(),
928 930 "desc": f.description(),
929 931 "extra": f.extra(),
930 932 "file": f.path(),
931 933 "targetline": targetline,
932 934 "line": l,
933 935 "lineno": lineno + 1,
934 936 "lineid": "l%d" % (lineno + 1),
935 937 "linenumber": "% 6d" % (lineno + 1),
936 938 "revdate": f.date()}
937 939
938 940 return tmpl("fileannotate",
939 941 file=f,
940 942 annotate=annotate,
941 943 path=webutil.up(f),
942 944 rev=fctx.rev(),
943 945 node=fctx.hex(),
944 946 author=fctx.user(),
945 947 date=fctx.date(),
946 948 desc=fctx.description(),
947 949 extra=fctx.extra(),
948 950 rename=webutil.renamelink(fctx),
949 951 branch=webutil.nodebranchnodefault(fctx),
950 952 parent=webutil.parents(fctx),
951 953 child=webutil.children(fctx),
952 954 permissions=fctx.manifest().flags(f))
953 955
954 956 @webcommand('filelog')
955 957 def filelog(web, req, tmpl):
956 958 """
957 959 /filelog/{revision}/{path}
958 960 --------------------------
959 961
960 962 Show information about the history of a file in the repository.
961 963
962 964 The ``revcount`` query string argument can be defined to control the
963 965 maximum number of entries to show.
964 966
965 967 The ``filelog`` template will be rendered.
966 968 """
967 969
968 970 try:
969 971 fctx = webutil.filectx(web.repo, req)
970 972 f = fctx.path()
971 973 fl = fctx.filelog()
972 974 except error.LookupError:
973 975 f = webutil.cleanpath(web.repo, req.form['file'][0])
974 976 fl = web.repo.file(f)
975 977 numrevs = len(fl)
976 978 if not numrevs: # file doesn't exist at all
977 979 raise
978 980 rev = webutil.changectx(web.repo, req).rev()
979 981 first = fl.linkrev(0)
980 982 if rev < first: # current rev is from before file existed
981 983 raise
982 984 frev = numrevs - 1
983 985 while fl.linkrev(frev) > rev:
984 986 frev -= 1
985 987 fctx = web.repo.filectx(f, fl.linkrev(frev))
986 988
987 989 revcount = web.maxshortchanges
988 990 if 'revcount' in req.form:
989 991 try:
990 992 revcount = int(req.form.get('revcount', [revcount])[0])
991 993 revcount = max(revcount, 1)
992 994 tmpl.defaults['sessionvars']['revcount'] = revcount
993 995 except ValueError:
994 996 pass
995 997
996 998 lessvars = copy.copy(tmpl.defaults['sessionvars'])
997 999 lessvars['revcount'] = max(revcount / 2, 1)
998 1000 morevars = copy.copy(tmpl.defaults['sessionvars'])
999 1001 morevars['revcount'] = revcount * 2
1000 1002
1001 1003 count = fctx.filerev() + 1
1002 1004 start = max(0, fctx.filerev() - revcount + 1) # first rev on this page
1003 1005 end = min(count, start + revcount) # last rev on this page
1004 1006 parity = paritygen(web.stripecount, offset=start - end)
1005 1007
1006 1008 def entries():
1007 1009 l = []
1008 1010
1009 1011 repo = web.repo
1010 1012 revs = fctx.filelog().revs(start, end - 1)
1011 1013 for i in revs:
1012 1014 iterfctx = fctx.filectx(i)
1013 1015
1014 1016 l.append({"parity": parity.next(),
1015 1017 "filerev": i,
1016 1018 "file": f,
1017 1019 "node": iterfctx.hex(),
1018 1020 "author": iterfctx.user(),
1019 1021 "date": iterfctx.date(),
1020 1022 "rename": webutil.renamelink(iterfctx),
1021 1023 "parent": webutil.parents(iterfctx),
1022 1024 "child": webutil.children(iterfctx),
1023 1025 "desc": iterfctx.description(),
1024 1026 "extra": iterfctx.extra(),
1025 1027 "tags": webutil.nodetagsdict(repo, iterfctx.node()),
1026 1028 "bookmarks": webutil.nodebookmarksdict(
1027 1029 repo, iterfctx.node()),
1028 1030 "branch": webutil.nodebranchnodefault(iterfctx),
1029 1031 "inbranch": webutil.nodeinbranch(repo, iterfctx),
1030 1032 "branches": webutil.nodebranchdict(repo, iterfctx)})
1031 1033 for e in reversed(l):
1032 1034 yield e
1033 1035
1034 1036 entries = list(entries())
1035 1037 latestentry = entries[:1]
1036 1038
1037 1039 revnav = webutil.filerevnav(web.repo, fctx.path())
1038 1040 nav = revnav.gen(end - 1, revcount, count)
1039 1041 return tmpl("filelog", file=f, node=fctx.hex(), nav=nav,
1040 1042 entries=entries,
1041 1043 latestentry=latestentry,
1042 1044 revcount=revcount, morevars=morevars, lessvars=lessvars)
1043 1045
1044 1046 @webcommand('archive')
1045 1047 def archive(web, req, tmpl):
1046 1048 """
1047 1049 /archive/{revision}.{format}[/{path}]
1048 1050 -------------------------------------
1049 1051
1050 1052 Obtain an archive of repository content.
1051 1053
1052 1054 The content and type of the archive is defined by a URL path parameter.
1053 1055 ``format`` is the file extension of the archive type to be generated. e.g.
1054 1056 ``zip`` or ``tar.bz2``. Not all archive types may be allowed by your
1055 1057 server configuration.
1056 1058
1057 1059 The optional ``path`` URL parameter controls content to include in the
1058 1060 archive. If omitted, every file in the specified revision is present in the
1059 1061 archive. If included, only the specified file or contents of the specified
1060 1062 directory will be included in the archive.
1061 1063
1062 1064 No template is used for this handler. Raw, binary content is generated.
1063 1065 """
1064 1066
1065 1067 type_ = req.form.get('type', [None])[0]
1066 1068 allowed = web.configlist("web", "allow_archive")
1067 1069 key = req.form['node'][0]
1068 1070
1069 1071 if type_ not in web.archives:
1070 1072 msg = 'Unsupported archive type: %s' % type_
1071 1073 raise ErrorResponse(HTTP_NOT_FOUND, msg)
1072 1074
1073 1075 if not ((type_ in allowed or
1074 1076 web.configbool("web", "allow" + type_, False))):
1075 1077 msg = 'Archive type not allowed: %s' % type_
1076 1078 raise ErrorResponse(HTTP_FORBIDDEN, msg)
1077 1079
1078 1080 reponame = re.sub(r"\W+", "-", os.path.basename(web.reponame))
1079 1081 cnode = web.repo.lookup(key)
1080 1082 arch_version = key
1081 1083 if cnode == key or key == 'tip':
1082 1084 arch_version = short(cnode)
1083 1085 name = "%s-%s" % (reponame, arch_version)
1084 1086
1085 1087 ctx = webutil.changectx(web.repo, req)
1086 1088 pats = []
1087 1089 matchfn = scmutil.match(ctx, [])
1088 1090 file = req.form.get('file', None)
1089 1091 if file:
1090 1092 pats = ['path:' + file[0]]
1091 1093 matchfn = scmutil.match(ctx, pats, default='path')
1092 1094 if pats:
1093 1095 files = [f for f in ctx.manifest().keys() if matchfn(f)]
1094 1096 if not files:
1095 1097 raise ErrorResponse(HTTP_NOT_FOUND,
1096 1098 'file(s) not found: %s' % file[0])
1097 1099
1098 1100 mimetype, artype, extension, encoding = web.archive_specs[type_]
1099 1101 headers = [
1100 1102 ('Content-Disposition', 'attachment; filename=%s%s' % (name, extension))
1101 1103 ]
1102 1104 if encoding:
1103 1105 headers.append(('Content-Encoding', encoding))
1104 1106 req.headers.extend(headers)
1105 1107 req.respond(HTTP_OK, mimetype)
1106 1108
1107 1109 archival.archive(web.repo, req, cnode, artype, prefix=name,
1108 1110 matchfn=matchfn,
1109 1111 subrepos=web.configbool("web", "archivesubrepos"))
1110 1112 return []
1111 1113
1112 1114
1113 1115 @webcommand('static')
1114 1116 def static(web, req, tmpl):
1115 1117 fname = req.form['file'][0]
1116 1118 # a repo owner may set web.static in .hg/hgrc to get any file
1117 1119 # readable by the user running the CGI script
1118 1120 static = web.config("web", "static", None, untrusted=False)
1119 1121 if not static:
1120 1122 tp = web.templatepath or templater.templatepaths()
1121 1123 if isinstance(tp, str):
1122 1124 tp = [tp]
1123 1125 static = [os.path.join(p, 'static') for p in tp]
1124 1126 staticfile(static, fname, req)
1125 1127 return []
1126 1128
1127 1129 @webcommand('graph')
1128 1130 def graph(web, req, tmpl):
1129 1131 """
1130 1132 /graph[/{revision}]
1131 1133 -------------------
1132 1134
1133 1135 Show information about the graphical topology of the repository.
1134 1136
1135 1137 Information rendered by this handler can be used to create visual
1136 1138 representations of repository topology.
1137 1139
1138 1140 The ``revision`` URL parameter controls the starting changeset.
1139 1141
1140 1142 The ``revcount`` query string argument can define the number of changesets
1141 1143 to show information for.
1142 1144
1143 1145 This handler will render the ``graph`` template.
1144 1146 """
1145 1147
1146 1148 ctx = webutil.changectx(web.repo, req)
1147 1149 rev = ctx.rev()
1148 1150
1149 1151 bg_height = 39
1150 1152 revcount = web.maxshortchanges
1151 1153 if 'revcount' in req.form:
1152 1154 try:
1153 1155 revcount = int(req.form.get('revcount', [revcount])[0])
1154 1156 revcount = max(revcount, 1)
1155 1157 tmpl.defaults['sessionvars']['revcount'] = revcount
1156 1158 except ValueError:
1157 1159 pass
1158 1160
1159 1161 lessvars = copy.copy(tmpl.defaults['sessionvars'])
1160 1162 lessvars['revcount'] = max(revcount / 2, 1)
1161 1163 morevars = copy.copy(tmpl.defaults['sessionvars'])
1162 1164 morevars['revcount'] = revcount * 2
1163 1165
1164 1166 count = len(web.repo)
1165 1167 pos = rev
1166 1168
1167 1169 uprev = min(max(0, count - 1), rev + revcount)
1168 1170 downrev = max(0, rev - revcount)
1169 1171 changenav = webutil.revnav(web.repo).gen(pos, revcount, count)
1170 1172
1171 1173 tree = []
1172 1174 if pos != -1:
1173 1175 allrevs = web.repo.changelog.revs(pos, 0)
1174 1176 revs = []
1175 1177 for i in allrevs:
1176 1178 revs.append(i)
1177 1179 if len(revs) >= revcount:
1178 1180 break
1179 1181
1180 1182 # We have to feed a baseset to dagwalker as it is expecting smartset
1181 1183 # object. This does not have a big impact on hgweb performance itself
1182 1184 # since hgweb graphing code is not itself lazy yet.
1183 1185 dag = graphmod.dagwalker(web.repo, revset.baseset(revs))
1184 1186 # As we said one line above... not lazy.
1185 1187 tree = list(graphmod.colored(dag, web.repo))
1186 1188
1187 1189 def getcolumns(tree):
1188 1190 cols = 0
1189 1191 for (id, type, ctx, vtx, edges) in tree:
1190 1192 if type != graphmod.CHANGESET:
1191 1193 continue
1192 1194 cols = max(cols, max([edge[0] for edge in edges] or [0]),
1193 1195 max([edge[1] for edge in edges] or [0]))
1194 1196 return cols
1195 1197
1196 1198 def graphdata(usetuples, **map):
1197 1199 data = []
1198 1200
1199 1201 row = 0
1200 1202 for (id, type, ctx, vtx, edges) in tree:
1201 1203 if type != graphmod.CHANGESET:
1202 1204 continue
1203 1205 node = str(ctx)
1204 1206 age = templatefilters.age(ctx.date())
1205 1207 desc = templatefilters.firstline(ctx.description())
1206 1208 desc = cgi.escape(templatefilters.nonempty(desc))
1207 1209 user = cgi.escape(templatefilters.person(ctx.user()))
1208 1210 branch = cgi.escape(ctx.branch())
1209 1211 try:
1210 1212 branchnode = web.repo.branchtip(branch)
1211 1213 except error.RepoLookupError:
1212 1214 branchnode = None
1213 1215 branch = branch, branchnode == ctx.node()
1214 1216
1215 1217 if usetuples:
1216 1218 data.append((node, vtx, edges, desc, user, age, branch,
1217 1219 [cgi.escape(x) for x in ctx.tags()],
1218 1220 [cgi.escape(x) for x in ctx.bookmarks()]))
1219 1221 else:
1220 1222 edgedata = [{'col': edge[0], 'nextcol': edge[1],
1221 1223 'color': (edge[2] - 1) % 6 + 1,
1222 1224 'width': edge[3], 'bcolor': edge[4]}
1223 1225 for edge in edges]
1224 1226
1225 1227 data.append(
1226 1228 {'node': node,
1227 1229 'col': vtx[0],
1228 1230 'color': (vtx[1] - 1) % 6 + 1,
1229 1231 'edges': edgedata,
1230 1232 'row': row,
1231 1233 'nextrow': row + 1,
1232 1234 'desc': desc,
1233 1235 'user': user,
1234 1236 'age': age,
1235 1237 'bookmarks': webutil.nodebookmarksdict(
1236 1238 web.repo, ctx.node()),
1237 1239 'branches': webutil.nodebranchdict(web.repo, ctx),
1238 1240 'inbranch': webutil.nodeinbranch(web.repo, ctx),
1239 1241 'tags': webutil.nodetagsdict(web.repo, ctx.node())})
1240 1242
1241 1243 row += 1
1242 1244
1243 1245 return data
1244 1246
1245 1247 cols = getcolumns(tree)
1246 1248 rows = len(tree)
1247 1249 canvasheight = (rows + 1) * bg_height - 27
1248 1250
1249 1251 return tmpl('graph', rev=rev, revcount=revcount, uprev=uprev,
1250 1252 lessvars=lessvars, morevars=morevars, downrev=downrev,
1251 1253 cols=cols, rows=rows,
1252 1254 canvaswidth=(cols + 1) * bg_height,
1253 1255 truecanvasheight=rows * bg_height,
1254 1256 canvasheight=canvasheight, bg_height=bg_height,
1255 1257 jsdata=lambda **x: graphdata(True, **x),
1256 1258 nodes=lambda **x: graphdata(False, **x),
1257 1259 node=ctx.hex(), changenav=changenav)
1258 1260
1259 1261 def _getdoc(e):
1260 1262 doc = e[0].__doc__
1261 1263 if doc:
1262 1264 doc = _(doc).split('\n')[0]
1263 1265 else:
1264 1266 doc = _('(no help text available)')
1265 1267 return doc
1266 1268
1267 1269 @webcommand('help')
1268 1270 def help(web, req, tmpl):
1269 1271 """
1270 1272 /help[/{topic}]
1271 1273 ---------------
1272 1274
1273 1275 Render help documentation.
1274 1276
1275 1277 This web command is roughly equivalent to :hg:`help`. If a ``topic``
1276 1278 is defined, that help topic will be rendered. If not, an index of
1277 1279 available help topics will be rendered.
1278 1280
1279 1281 The ``help`` template will be rendered when requesting help for a topic.
1280 1282 ``helptopics`` will be rendered for the index of help topics.
1281 1283 """
1282 1284 from mercurial import commands # avoid cycle
1283 1285 from mercurial import help as helpmod # avoid cycle
1284 1286
1285 1287 topicname = req.form.get('node', [None])[0]
1286 1288 if not topicname:
1287 1289 def topics(**map):
1288 1290 for entries, summary, _doc in helpmod.helptable:
1289 1291 yield {'topic': entries[0], 'summary': summary}
1290 1292
1291 1293 early, other = [], []
1292 1294 primary = lambda s: s.split('|')[0]
1293 1295 for c, e in commands.table.iteritems():
1294 1296 doc = _getdoc(e)
1295 1297 if 'DEPRECATED' in doc or c.startswith('debug'):
1296 1298 continue
1297 1299 cmd = primary(c)
1298 1300 if cmd.startswith('^'):
1299 1301 early.append((cmd[1:], doc))
1300 1302 else:
1301 1303 other.append((cmd, doc))
1302 1304
1303 1305 early.sort()
1304 1306 other.sort()
1305 1307
1306 1308 def earlycommands(**map):
1307 1309 for c, doc in early:
1308 1310 yield {'topic': c, 'summary': doc}
1309 1311
1310 1312 def othercommands(**map):
1311 1313 for c, doc in other:
1312 1314 yield {'topic': c, 'summary': doc}
1313 1315
1314 1316 return tmpl('helptopics', topics=topics, earlycommands=earlycommands,
1315 1317 othercommands=othercommands, title='Index')
1316 1318
1317 1319 u = webutil.wsgiui()
1318 1320 u.verbose = True
1319 1321 try:
1320 1322 doc = helpmod.help_(u, topicname)
1321 1323 except error.UnknownCommand:
1322 1324 raise ErrorResponse(HTTP_NOT_FOUND)
1323 1325 return tmpl('help', topic=topicname, doc=doc)
1324 1326
1325 1327 # tell hggettext to extract docstrings from these functions:
1326 1328 i18nfunctions = commands.values()
@@ -1,78 +1,78 b''
1 1 {header}
2 2 <title>{repo|escape}: {file|escape} diff</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 class="active">diff</li>
27 27 <li><a href="{url|urlescape}comparison/{node|short}/{file|urlescape}{sessionvars%urlparameter}">comparison</a></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>diff {file|escape} @ {rev}:{node|short}</h3>
39 <h3>diff {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 linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
70 70 <div class="sourcefirst"> line diff</div>
71 71 <div class="stripes2 diffblocks">
72 72 {diff}
73 73 </div>
74 74 </div>
75 75 </div>
76 76 </div>
77 77
78 78 {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 <h3>diff b @ 1:559edbd9ed20</h3>
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 <h3>diff a @ 1:559edbd9ed20</h3>
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 758 <h3>comparison a @ 2:d73db4d812ff</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 887 <h3>comparison a @ 3:20e80271eb7a</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 1022 <h3>comparison e @ 5:41d9fc4a6ae1</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 ..
@@ -1,239 +1,239 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 $ hg ci -Ama
9 9 adding a
10 10 $ hg rm a
11 11 $ hg ci -mdel
12 12
13 13 set up hgweb
14 14
15 15 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
16 16 $ cat hg.pid >> $DAEMON_PIDS
17 17
18 18 revision
19 19
20 20 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'rev/tip'
21 21 200 Script output follows
22 22
23 23 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
24 24 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
25 25 <head>
26 26 <link rel="icon" href="/static/hgicon.png" type="image/png" />
27 27 <meta name="robots" content="index, nofollow" />
28 28 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
29 29 <script type="text/javascript" src="/static/mercurial.js"></script>
30 30
31 31 <title>test: c78f6c5cbea9</title>
32 32 </head>
33 33 <body>
34 34 <div class="container">
35 35 <div class="menu">
36 36 <div class="logo">
37 37 <a href="http://mercurial.selenic.com/">
38 38 <img src="/static/hglogo.png" alt="mercurial" /></a>
39 39 </div>
40 40 <ul>
41 41 <li><a href="/shortlog/c78f6c5cbea9">log</a></li>
42 42 <li><a href="/graph/c78f6c5cbea9">graph</a></li>
43 43 <li><a href="/tags">tags</a></li>
44 44 <li><a href="/bookmarks">bookmarks</a></li>
45 45 <li><a href="/branches">branches</a></li>
46 46 </ul>
47 47 <ul>
48 48 <li class="active">changeset</li>
49 49 <li><a href="/raw-rev/c78f6c5cbea9">raw</a></li>
50 50 <li><a href="/file/c78f6c5cbea9">browse</a></li>
51 51 </ul>
52 52 <ul>
53 53
54 54 </ul>
55 55 <ul>
56 56 <li><a href="/help">help</a></li>
57 57 </ul>
58 58 </div>
59 59
60 60 <div class="main">
61 61
62 62 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
63 63 <h3>changeset 1:c78f6c5cbea9 <span class="tag">tip</span> </h3>
64 64
65 65 <form class="search" action="/log">
66 66
67 67 <p><input name="rev" id="search1" type="text" size="30" /></p>
68 68 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
69 69 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
70 70 </form>
71 71
72 72 <div class="description">del</div>
73 73
74 74 <table id="changesetEntry">
75 75 <tr>
76 76 <th class="author">author</th>
77 77 <td class="author">&#116;&#101;&#115;&#116;</td>
78 78 </tr>
79 79 <tr>
80 80 <th class="date">date</th>
81 81 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
82 82 </tr>
83 83 <tr>
84 84 <th class="author">parents</th>
85 85 <td class="author"><a href="/rev/cb9a9f314b8b">cb9a9f314b8b</a> </td>
86 86 </tr>
87 87 <tr>
88 88 <th class="author">children</th>
89 89 <td class="author"></td>
90 90 </tr>
91 91 <tr>
92 92 <th class="files">files</th>
93 93 <td class="files">a </td>
94 94 </tr>
95 95 <tr>
96 96 <th class="diffstat">diffstat</th>
97 97 <td class="diffstat">
98 98 1 files changed, 0 insertions(+), 1 deletions(-)
99 99
100 100 <a id="diffstatexpand" href="javascript:toggleDiffstat()">[<tt>+</tt>]</a>
101 101 <div id="diffstatdetails" style="display:none;">
102 102 <a href="javascript:toggleDiffstat()">[<tt>-</tt>]</a>
103 103 <table class="diffstat-table stripes2"> <tr>
104 104 <td class="diffstat-file"><a href="#l1.1">a</a></td>
105 105 <td class="diffstat-total" align="right">1</td>
106 106 <td class="diffstat-graph">
107 107 <span class="diffstat-add" style="width:0.0%;">&nbsp;</span>
108 108 <span class="diffstat-remove" style="width:100.0%;">&nbsp;</span>
109 109 </td>
110 110 </tr>
111 111 </table>
112 112 </div>
113 113 </td>
114 114 </tr>
115 115 </table>
116 116
117 117 <div class="overflow">
118 118 <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
119 119 <div class="sourcefirst"> line diff</div>
120 120 <div class="stripes2 diffblocks">
121 121 <div class="bottomline inc-lineno"><pre class="sourcelines wrap">
122 122 <span id="l1.1" class="minusline">--- a/a Thu Jan 01 00:00:00 1970 +0000</span><a href="#l1.1"></a>
123 123 <span id="l1.2" class="plusline">+++ /dev/null Thu Jan 01 00:00:00 1970 +0000</span><a href="#l1.2"></a>
124 124 <span id="l1.3" class="atline">@@ -1,1 +0,0 @@</span><a href="#l1.3"></a>
125 125 <span id="l1.4" class="minusline">-a</span><a href="#l1.4"></a></pre></div>
126 126 </div>
127 127 </div>
128 128
129 129 </div>
130 130 </div>
131 131 <script type="text/javascript">process_dates()</script>
132 132
133 133
134 134 </body>
135 135 </html>
136 136
137 137
138 138 diff removed file
139 139
140 140 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'diff/tip/a'
141 141 200 Script output follows
142 142
143 143 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
144 144 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
145 145 <head>
146 146 <link rel="icon" href="/static/hgicon.png" type="image/png" />
147 147 <meta name="robots" content="index, nofollow" />
148 148 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
149 149 <script type="text/javascript" src="/static/mercurial.js"></script>
150 150
151 151 <title>test: a diff</title>
152 152 </head>
153 153 <body>
154 154
155 155 <div class="container">
156 156 <div class="menu">
157 157 <div class="logo">
158 158 <a href="http://mercurial.selenic.com/">
159 159 <img src="/static/hglogo.png" alt="mercurial" /></a>
160 160 </div>
161 161 <ul>
162 162 <li><a href="/shortlog/c78f6c5cbea9">log</a></li>
163 163 <li><a href="/graph/c78f6c5cbea9">graph</a></li>
164 164 <li><a href="/tags">tags</a></li>
165 165 <li><a href="/bookmarks">bookmarks</a></li>
166 166 <li><a href="/branches">branches</a></li>
167 167 </ul>
168 168 <ul>
169 169 <li><a href="/rev/c78f6c5cbea9">changeset</a></li>
170 170 <li><a href="/file/c78f6c5cbea9">browse</a></li>
171 171 </ul>
172 172 <ul>
173 173 <li><a href="/file/c78f6c5cbea9/a">file</a></li>
174 174 <li><a href="/file/tip/a">latest</a></li>
175 175 <li class="active">diff</li>
176 176 <li><a href="/comparison/c78f6c5cbea9/a">comparison</a></li>
177 177 <li><a href="/annotate/c78f6c5cbea9/a">annotate</a></li>
178 178 <li><a href="/log/c78f6c5cbea9/a">file log</a></li>
179 179 <li><a href="/raw-file/c78f6c5cbea9/a">raw</a></li>
180 180 </ul>
181 181 <ul>
182 182 <li><a href="/help">help</a></li>
183 183 </ul>
184 184 </div>
185 185
186 186 <div class="main">
187 187 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
188 <h3>diff a @ 1:c78f6c5cbea9</h3>
188 <h3>diff a @ 1:c78f6c5cbea9 <span class="tag">tip</span> </h3>
189 189
190 190 <form class="search" action="/log">
191 191 <p></p>
192 192 <p><input name="rev" id="search1" type="text" size="30" /></p>
193 193 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
194 194 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
195 195 </form>
196 196
197 197 <div class="description">del</div>
198 198
199 199 <table id="changesetEntry">
200 200 <tr>
201 201 <th>author</th>
202 202 <td>&#116;&#101;&#115;&#116;</td>
203 203 </tr>
204 204 <tr>
205 205 <th>date</th>
206 206 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
207 207 </tr>
208 208 <tr>
209 209 <th>parents</th>
210 210 <td><a href="/file/cb9a9f314b8b/a">cb9a9f314b8b</a> </td>
211 211 </tr>
212 212 <tr>
213 213 <th>children</th>
214 214 <td></td>
215 215 </tr>
216 216 </table>
217 217
218 218 <div class="overflow">
219 219 <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
220 220 <div class="sourcefirst"> line diff</div>
221 221 <div class="stripes2 diffblocks">
222 222 <div class="bottomline inc-lineno"><pre class="sourcelines wrap">
223 223 <span id="l1.1" class="minusline">--- a/a Thu Jan 01 00:00:00 1970 +0000</span><a href="#l1.1"></a>
224 224 <span id="l1.2" class="plusline">+++ /dev/null Thu Jan 01 00:00:00 1970 +0000</span><a href="#l1.2"></a>
225 225 <span id="l1.3" class="atline">@@ -1,1 +0,0 @@</span><a href="#l1.3"></a>
226 226 <span id="l1.4" class="minusline">-a</span><a href="#l1.4"></a></pre></div>
227 227 </div>
228 228 </div>
229 229 </div>
230 230 </div>
231 231
232 232 <script type="text/javascript">process_dates()</script>
233 233
234 234
235 235 </body>
236 236 </html>
237 237
238 238
239 239 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now