##// END OF EJS Templates
hgweb: handle a "descend" query parameter in filelog command...
Denis Laxalde -
r31939:604d3150 default
parent child Browse files
Show More
@@ -1,1374 +1,1381 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 from __future__ import absolute_import
9 9
10 10 import cgi
11 11 import copy
12 12 import mimetypes
13 13 import os
14 14 import re
15 15
16 16 from ..i18n import _
17 17 from ..node import hex, short
18 18
19 19 from .common import (
20 20 ErrorResponse,
21 21 HTTP_FORBIDDEN,
22 22 HTTP_NOT_FOUND,
23 23 HTTP_OK,
24 24 get_contact,
25 25 paritygen,
26 26 staticfile,
27 27 )
28 28
29 29 from .. import (
30 30 archival,
31 31 context,
32 32 encoding,
33 33 error,
34 34 graphmod,
35 35 revset,
36 36 revsetlang,
37 37 scmutil,
38 38 smartset,
39 39 templatefilters,
40 40 templater,
41 41 util,
42 42 )
43 43
44 44 from . import (
45 45 webutil,
46 46 )
47 47
48 48 __all__ = []
49 49 commands = {}
50 50
51 51 class webcommand(object):
52 52 """Decorator used to register a web command handler.
53 53
54 54 The decorator takes as its positional arguments the name/path the
55 55 command should be accessible under.
56 56
57 57 Usage:
58 58
59 59 @webcommand('mycommand')
60 60 def mycommand(web, req, tmpl):
61 61 pass
62 62 """
63 63
64 64 def __init__(self, name):
65 65 self.name = name
66 66
67 67 def __call__(self, func):
68 68 __all__.append(self.name)
69 69 commands[self.name] = func
70 70 return func
71 71
72 72 @webcommand('log')
73 73 def log(web, req, tmpl):
74 74 """
75 75 /log[/{revision}[/{path}]]
76 76 --------------------------
77 77
78 78 Show repository or file history.
79 79
80 80 For URLs of the form ``/log/{revision}``, a list of changesets starting at
81 81 the specified changeset identifier is shown. If ``{revision}`` is not
82 82 defined, the default is ``tip``. This form is equivalent to the
83 83 ``changelog`` handler.
84 84
85 85 For URLs of the form ``/log/{revision}/{file}``, the history for a specific
86 86 file will be shown. This form is equivalent to the ``filelog`` handler.
87 87 """
88 88
89 89 if 'file' in req.form and req.form['file'][0]:
90 90 return filelog(web, req, tmpl)
91 91 else:
92 92 return changelog(web, req, tmpl)
93 93
94 94 @webcommand('rawfile')
95 95 def rawfile(web, req, tmpl):
96 96 guessmime = web.configbool('web', 'guessmime', False)
97 97
98 98 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
99 99 if not path:
100 100 content = manifest(web, req, tmpl)
101 101 req.respond(HTTP_OK, web.ctype)
102 102 return content
103 103
104 104 try:
105 105 fctx = webutil.filectx(web.repo, req)
106 106 except error.LookupError as inst:
107 107 try:
108 108 content = manifest(web, req, tmpl)
109 109 req.respond(HTTP_OK, web.ctype)
110 110 return content
111 111 except ErrorResponse:
112 112 raise inst
113 113
114 114 path = fctx.path()
115 115 text = fctx.data()
116 116 mt = 'application/binary'
117 117 if guessmime:
118 118 mt = mimetypes.guess_type(path)[0]
119 119 if mt is None:
120 120 if util.binary(text):
121 121 mt = 'application/binary'
122 122 else:
123 123 mt = 'text/plain'
124 124 if mt.startswith('text/'):
125 125 mt += '; charset="%s"' % encoding.encoding
126 126
127 127 req.respond(HTTP_OK, mt, path, body=text)
128 128 return []
129 129
130 130 def _filerevision(web, req, tmpl, fctx):
131 131 f = fctx.path()
132 132 text = fctx.data()
133 133 parity = paritygen(web.stripecount)
134 134
135 135 if util.binary(text):
136 136 mt = mimetypes.guess_type(f)[0] or 'application/octet-stream'
137 137 text = '(binary:%s)' % mt
138 138
139 139 def lines():
140 140 for lineno, t in enumerate(text.splitlines(True)):
141 141 yield {"line": t,
142 142 "lineid": "l%d" % (lineno + 1),
143 143 "linenumber": "% 6d" % (lineno + 1),
144 144 "parity": next(parity)}
145 145
146 146 return tmpl("filerevision",
147 147 file=f,
148 148 path=webutil.up(f),
149 149 text=lines(),
150 150 symrev=webutil.symrevorshortnode(req, fctx),
151 151 rename=webutil.renamelink(fctx),
152 152 permissions=fctx.manifest().flags(f),
153 153 **webutil.commonentry(web.repo, fctx))
154 154
155 155 @webcommand('file')
156 156 def file(web, req, tmpl):
157 157 """
158 158 /file/{revision}[/{path}]
159 159 -------------------------
160 160
161 161 Show information about a directory or file in the repository.
162 162
163 163 Info about the ``path`` given as a URL parameter will be rendered.
164 164
165 165 If ``path`` is a directory, information about the entries in that
166 166 directory will be rendered. This form is equivalent to the ``manifest``
167 167 handler.
168 168
169 169 If ``path`` is a file, information about that file will be shown via
170 170 the ``filerevision`` template.
171 171
172 172 If ``path`` is not defined, information about the root directory will
173 173 be rendered.
174 174 """
175 175 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
176 176 if not path:
177 177 return manifest(web, req, tmpl)
178 178 try:
179 179 return _filerevision(web, req, tmpl, webutil.filectx(web.repo, req))
180 180 except error.LookupError as inst:
181 181 try:
182 182 return manifest(web, req, tmpl)
183 183 except ErrorResponse:
184 184 raise inst
185 185
186 186 def _search(web, req, tmpl):
187 187 MODE_REVISION = 'rev'
188 188 MODE_KEYWORD = 'keyword'
189 189 MODE_REVSET = 'revset'
190 190
191 191 def revsearch(ctx):
192 192 yield ctx
193 193
194 194 def keywordsearch(query):
195 195 lower = encoding.lower
196 196 qw = lower(query).split()
197 197
198 198 def revgen():
199 199 cl = web.repo.changelog
200 200 for i in xrange(len(web.repo) - 1, 0, -100):
201 201 l = []
202 202 for j in cl.revs(max(0, i - 99), i):
203 203 ctx = web.repo[j]
204 204 l.append(ctx)
205 205 l.reverse()
206 206 for e in l:
207 207 yield e
208 208
209 209 for ctx in revgen():
210 210 miss = 0
211 211 for q in qw:
212 212 if not (q in lower(ctx.user()) or
213 213 q in lower(ctx.description()) or
214 214 q in lower(" ".join(ctx.files()))):
215 215 miss = 1
216 216 break
217 217 if miss:
218 218 continue
219 219
220 220 yield ctx
221 221
222 222 def revsetsearch(revs):
223 223 for r in revs:
224 224 yield web.repo[r]
225 225
226 226 searchfuncs = {
227 227 MODE_REVISION: (revsearch, 'exact revision search'),
228 228 MODE_KEYWORD: (keywordsearch, 'literal keyword search'),
229 229 MODE_REVSET: (revsetsearch, 'revset expression search'),
230 230 }
231 231
232 232 def getsearchmode(query):
233 233 try:
234 234 ctx = web.repo[query]
235 235 except (error.RepoError, error.LookupError):
236 236 # query is not an exact revision pointer, need to
237 237 # decide if it's a revset expression or keywords
238 238 pass
239 239 else:
240 240 return MODE_REVISION, ctx
241 241
242 242 revdef = 'reverse(%s)' % query
243 243 try:
244 244 tree = revsetlang.parse(revdef)
245 245 except error.ParseError:
246 246 # can't parse to a revset tree
247 247 return MODE_KEYWORD, query
248 248
249 249 if revsetlang.depth(tree) <= 2:
250 250 # no revset syntax used
251 251 return MODE_KEYWORD, query
252 252
253 253 if any((token, (value or '')[:3]) == ('string', 're:')
254 254 for token, value, pos in revsetlang.tokenize(revdef)):
255 255 return MODE_KEYWORD, query
256 256
257 257 funcsused = revsetlang.funcsused(tree)
258 258 if not funcsused.issubset(revset.safesymbols):
259 259 return MODE_KEYWORD, query
260 260
261 261 mfunc = revset.match(web.repo.ui, revdef)
262 262 try:
263 263 revs = mfunc(web.repo)
264 264 return MODE_REVSET, revs
265 265 # ParseError: wrongly placed tokens, wrongs arguments, etc
266 266 # RepoLookupError: no such revision, e.g. in 'revision:'
267 267 # Abort: bookmark/tag not exists
268 268 # LookupError: ambiguous identifier, e.g. in '(bc)' on a large repo
269 269 except (error.ParseError, error.RepoLookupError, error.Abort,
270 270 LookupError):
271 271 return MODE_KEYWORD, query
272 272
273 273 def changelist(**map):
274 274 count = 0
275 275
276 276 for ctx in searchfunc[0](funcarg):
277 277 count += 1
278 278 n = ctx.node()
279 279 showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
280 280 files = webutil.listfilediffs(tmpl, ctx.files(), n, web.maxfiles)
281 281
282 282 yield tmpl('searchentry',
283 283 parity=next(parity),
284 284 changelogtag=showtags,
285 285 files=files,
286 286 **webutil.commonentry(web.repo, ctx))
287 287
288 288 if count >= revcount:
289 289 break
290 290
291 291 query = req.form['rev'][0]
292 292 revcount = web.maxchanges
293 293 if 'revcount' in req.form:
294 294 try:
295 295 revcount = int(req.form.get('revcount', [revcount])[0])
296 296 revcount = max(revcount, 1)
297 297 tmpl.defaults['sessionvars']['revcount'] = revcount
298 298 except ValueError:
299 299 pass
300 300
301 301 lessvars = copy.copy(tmpl.defaults['sessionvars'])
302 302 lessvars['revcount'] = max(revcount / 2, 1)
303 303 lessvars['rev'] = query
304 304 morevars = copy.copy(tmpl.defaults['sessionvars'])
305 305 morevars['revcount'] = revcount * 2
306 306 morevars['rev'] = query
307 307
308 308 mode, funcarg = getsearchmode(query)
309 309
310 310 if 'forcekw' in req.form:
311 311 showforcekw = ''
312 312 showunforcekw = searchfuncs[mode][1]
313 313 mode = MODE_KEYWORD
314 314 funcarg = query
315 315 else:
316 316 if mode != MODE_KEYWORD:
317 317 showforcekw = searchfuncs[MODE_KEYWORD][1]
318 318 else:
319 319 showforcekw = ''
320 320 showunforcekw = ''
321 321
322 322 searchfunc = searchfuncs[mode]
323 323
324 324 tip = web.repo['tip']
325 325 parity = paritygen(web.stripecount)
326 326
327 327 return tmpl('search', query=query, node=tip.hex(), symrev='tip',
328 328 entries=changelist, archives=web.archivelist("tip"),
329 329 morevars=morevars, lessvars=lessvars,
330 330 modedesc=searchfunc[1],
331 331 showforcekw=showforcekw, showunforcekw=showunforcekw)
332 332
333 333 @webcommand('changelog')
334 334 def changelog(web, req, tmpl, shortlog=False):
335 335 """
336 336 /changelog[/{revision}]
337 337 -----------------------
338 338
339 339 Show information about multiple changesets.
340 340
341 341 If the optional ``revision`` URL argument is absent, information about
342 342 all changesets starting at ``tip`` will be rendered. If the ``revision``
343 343 argument is present, changesets will be shown starting from the specified
344 344 revision.
345 345
346 346 If ``revision`` is absent, the ``rev`` query string argument may be
347 347 defined. This will perform a search for changesets.
348 348
349 349 The argument for ``rev`` can be a single revision, a revision set,
350 350 or a literal keyword to search for in changeset data (equivalent to
351 351 :hg:`log -k`).
352 352
353 353 The ``revcount`` query string argument defines the maximum numbers of
354 354 changesets to render.
355 355
356 356 For non-searches, the ``changelog`` template will be rendered.
357 357 """
358 358
359 359 query = ''
360 360 if 'node' in req.form:
361 361 ctx = webutil.changectx(web.repo, req)
362 362 symrev = webutil.symrevorshortnode(req, ctx)
363 363 elif 'rev' in req.form:
364 364 return _search(web, req, tmpl)
365 365 else:
366 366 ctx = web.repo['tip']
367 367 symrev = 'tip'
368 368
369 369 def changelist():
370 370 revs = []
371 371 if pos != -1:
372 372 revs = web.repo.changelog.revs(pos, 0)
373 373 curcount = 0
374 374 for rev in revs:
375 375 curcount += 1
376 376 if curcount > revcount + 1:
377 377 break
378 378
379 379 entry = webutil.changelistentry(web, web.repo[rev], tmpl)
380 380 entry['parity'] = next(parity)
381 381 yield entry
382 382
383 383 if shortlog:
384 384 revcount = web.maxshortchanges
385 385 else:
386 386 revcount = web.maxchanges
387 387
388 388 if 'revcount' in req.form:
389 389 try:
390 390 revcount = int(req.form.get('revcount', [revcount])[0])
391 391 revcount = max(revcount, 1)
392 392 tmpl.defaults['sessionvars']['revcount'] = revcount
393 393 except ValueError:
394 394 pass
395 395
396 396 lessvars = copy.copy(tmpl.defaults['sessionvars'])
397 397 lessvars['revcount'] = max(revcount / 2, 1)
398 398 morevars = copy.copy(tmpl.defaults['sessionvars'])
399 399 morevars['revcount'] = revcount * 2
400 400
401 401 count = len(web.repo)
402 402 pos = ctx.rev()
403 403 parity = paritygen(web.stripecount)
404 404
405 405 changenav = webutil.revnav(web.repo).gen(pos, revcount, count)
406 406
407 407 entries = list(changelist())
408 408 latestentry = entries[:1]
409 409 if len(entries) > revcount:
410 410 nextentry = entries[-1:]
411 411 entries = entries[:-1]
412 412 else:
413 413 nextentry = []
414 414
415 415 return tmpl(shortlog and 'shortlog' or 'changelog', changenav=changenav,
416 416 node=ctx.hex(), rev=pos, symrev=symrev, changesets=count,
417 417 entries=entries,
418 418 latestentry=latestentry, nextentry=nextentry,
419 419 archives=web.archivelist("tip"), revcount=revcount,
420 420 morevars=morevars, lessvars=lessvars, query=query)
421 421
422 422 @webcommand('shortlog')
423 423 def shortlog(web, req, tmpl):
424 424 """
425 425 /shortlog
426 426 ---------
427 427
428 428 Show basic information about a set of changesets.
429 429
430 430 This accepts the same parameters as the ``changelog`` handler. The only
431 431 difference is the ``shortlog`` template will be rendered instead of the
432 432 ``changelog`` template.
433 433 """
434 434 return changelog(web, req, tmpl, shortlog=True)
435 435
436 436 @webcommand('changeset')
437 437 def changeset(web, req, tmpl):
438 438 """
439 439 /changeset[/{revision}]
440 440 -----------------------
441 441
442 442 Show information about a single changeset.
443 443
444 444 A URL path argument is the changeset identifier to show. See ``hg help
445 445 revisions`` for possible values. If not defined, the ``tip`` changeset
446 446 will be shown.
447 447
448 448 The ``changeset`` template is rendered. Contents of the ``changesettag``,
449 449 ``changesetbookmark``, ``filenodelink``, ``filenolink``, and the many
450 450 templates related to diffs may all be used to produce the output.
451 451 """
452 452 ctx = webutil.changectx(web.repo, req)
453 453
454 454 return tmpl('changeset', **webutil.changesetentry(web, req, tmpl, ctx))
455 455
456 456 rev = webcommand('rev')(changeset)
457 457
458 458 def decodepath(path):
459 459 """Hook for mapping a path in the repository to a path in the
460 460 working copy.
461 461
462 462 Extensions (e.g., largefiles) can override this to remap files in
463 463 the virtual file system presented by the manifest command below."""
464 464 return path
465 465
466 466 @webcommand('manifest')
467 467 def manifest(web, req, tmpl):
468 468 """
469 469 /manifest[/{revision}[/{path}]]
470 470 -------------------------------
471 471
472 472 Show information about a directory.
473 473
474 474 If the URL path arguments are omitted, information about the root
475 475 directory for the ``tip`` changeset will be shown.
476 476
477 477 Because this handler can only show information for directories, it
478 478 is recommended to use the ``file`` handler instead, as it can handle both
479 479 directories and files.
480 480
481 481 The ``manifest`` template will be rendered for this handler.
482 482 """
483 483 if 'node' in req.form:
484 484 ctx = webutil.changectx(web.repo, req)
485 485 symrev = webutil.symrevorshortnode(req, ctx)
486 486 else:
487 487 ctx = web.repo['tip']
488 488 symrev = 'tip'
489 489 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
490 490 mf = ctx.manifest()
491 491 node = ctx.node()
492 492
493 493 files = {}
494 494 dirs = {}
495 495 parity = paritygen(web.stripecount)
496 496
497 497 if path and path[-1] != "/":
498 498 path += "/"
499 499 l = len(path)
500 500 abspath = "/" + path
501 501
502 502 for full, n in mf.iteritems():
503 503 # the virtual path (working copy path) used for the full
504 504 # (repository) path
505 505 f = decodepath(full)
506 506
507 507 if f[:l] != path:
508 508 continue
509 509 remain = f[l:]
510 510 elements = remain.split('/')
511 511 if len(elements) == 1:
512 512 files[remain] = full
513 513 else:
514 514 h = dirs # need to retain ref to dirs (root)
515 515 for elem in elements[0:-1]:
516 516 if elem not in h:
517 517 h[elem] = {}
518 518 h = h[elem]
519 519 if len(h) > 1:
520 520 break
521 521 h[None] = None # denotes files present
522 522
523 523 if mf and not files and not dirs:
524 524 raise ErrorResponse(HTTP_NOT_FOUND, 'path not found: ' + path)
525 525
526 526 def filelist(**map):
527 527 for f in sorted(files):
528 528 full = files[f]
529 529
530 530 fctx = ctx.filectx(full)
531 531 yield {"file": full,
532 532 "parity": next(parity),
533 533 "basename": f,
534 534 "date": fctx.date(),
535 535 "size": fctx.size(),
536 536 "permissions": mf.flags(full)}
537 537
538 538 def dirlist(**map):
539 539 for d in sorted(dirs):
540 540
541 541 emptydirs = []
542 542 h = dirs[d]
543 543 while isinstance(h, dict) and len(h) == 1:
544 544 k, v = h.items()[0]
545 545 if v:
546 546 emptydirs.append(k)
547 547 h = v
548 548
549 549 path = "%s%s" % (abspath, d)
550 550 yield {"parity": next(parity),
551 551 "path": path,
552 552 "emptydirs": "/".join(emptydirs),
553 553 "basename": d}
554 554
555 555 return tmpl("manifest",
556 556 symrev=symrev,
557 557 path=abspath,
558 558 up=webutil.up(abspath),
559 559 upparity=next(parity),
560 560 fentries=filelist,
561 561 dentries=dirlist,
562 562 archives=web.archivelist(hex(node)),
563 563 **webutil.commonentry(web.repo, ctx))
564 564
565 565 @webcommand('tags')
566 566 def tags(web, req, tmpl):
567 567 """
568 568 /tags
569 569 -----
570 570
571 571 Show information about tags.
572 572
573 573 No arguments are accepted.
574 574
575 575 The ``tags`` template is rendered.
576 576 """
577 577 i = list(reversed(web.repo.tagslist()))
578 578 parity = paritygen(web.stripecount)
579 579
580 580 def entries(notip, latestonly, **map):
581 581 t = i
582 582 if notip:
583 583 t = [(k, n) for k, n in i if k != "tip"]
584 584 if latestonly:
585 585 t = t[:1]
586 586 for k, n in t:
587 587 yield {"parity": next(parity),
588 588 "tag": k,
589 589 "date": web.repo[n].date(),
590 590 "node": hex(n)}
591 591
592 592 return tmpl("tags",
593 593 node=hex(web.repo.changelog.tip()),
594 594 entries=lambda **x: entries(False, False, **x),
595 595 entriesnotip=lambda **x: entries(True, False, **x),
596 596 latestentry=lambda **x: entries(True, True, **x))
597 597
598 598 @webcommand('bookmarks')
599 599 def bookmarks(web, req, tmpl):
600 600 """
601 601 /bookmarks
602 602 ----------
603 603
604 604 Show information about bookmarks.
605 605
606 606 No arguments are accepted.
607 607
608 608 The ``bookmarks`` template is rendered.
609 609 """
610 610 i = [b for b in web.repo._bookmarks.items() if b[1] in web.repo]
611 611 sortkey = lambda b: (web.repo[b[1]].rev(), b[0])
612 612 i = sorted(i, key=sortkey, reverse=True)
613 613 parity = paritygen(web.stripecount)
614 614
615 615 def entries(latestonly, **map):
616 616 t = i
617 617 if latestonly:
618 618 t = i[:1]
619 619 for k, n in t:
620 620 yield {"parity": next(parity),
621 621 "bookmark": k,
622 622 "date": web.repo[n].date(),
623 623 "node": hex(n)}
624 624
625 625 if i:
626 626 latestrev = i[0][1]
627 627 else:
628 628 latestrev = -1
629 629
630 630 return tmpl("bookmarks",
631 631 node=hex(web.repo.changelog.tip()),
632 632 lastchange=[{"date": web.repo[latestrev].date()}],
633 633 entries=lambda **x: entries(latestonly=False, **x),
634 634 latestentry=lambda **x: entries(latestonly=True, **x))
635 635
636 636 @webcommand('branches')
637 637 def branches(web, req, tmpl):
638 638 """
639 639 /branches
640 640 ---------
641 641
642 642 Show information about branches.
643 643
644 644 All known branches are contained in the output, even closed branches.
645 645
646 646 No arguments are accepted.
647 647
648 648 The ``branches`` template is rendered.
649 649 """
650 650 entries = webutil.branchentries(web.repo, web.stripecount)
651 651 latestentry = webutil.branchentries(web.repo, web.stripecount, 1)
652 652 return tmpl('branches', node=hex(web.repo.changelog.tip()),
653 653 entries=entries, latestentry=latestentry)
654 654
655 655 @webcommand('summary')
656 656 def summary(web, req, tmpl):
657 657 """
658 658 /summary
659 659 --------
660 660
661 661 Show a summary of repository state.
662 662
663 663 Information about the latest changesets, bookmarks, tags, and branches
664 664 is captured by this handler.
665 665
666 666 The ``summary`` template is rendered.
667 667 """
668 668 i = reversed(web.repo.tagslist())
669 669
670 670 def tagentries(**map):
671 671 parity = paritygen(web.stripecount)
672 672 count = 0
673 673 for k, n in i:
674 674 if k == "tip": # skip tip
675 675 continue
676 676
677 677 count += 1
678 678 if count > 10: # limit to 10 tags
679 679 break
680 680
681 681 yield tmpl("tagentry",
682 682 parity=next(parity),
683 683 tag=k,
684 684 node=hex(n),
685 685 date=web.repo[n].date())
686 686
687 687 def bookmarks(**map):
688 688 parity = paritygen(web.stripecount)
689 689 marks = [b for b in web.repo._bookmarks.items() if b[1] in web.repo]
690 690 sortkey = lambda b: (web.repo[b[1]].rev(), b[0])
691 691 marks = sorted(marks, key=sortkey, reverse=True)
692 692 for k, n in marks[:10]: # limit to 10 bookmarks
693 693 yield {'parity': next(parity),
694 694 'bookmark': k,
695 695 'date': web.repo[n].date(),
696 696 'node': hex(n)}
697 697
698 698 def changelist(**map):
699 699 parity = paritygen(web.stripecount, offset=start - end)
700 700 l = [] # build a list in forward order for efficiency
701 701 revs = []
702 702 if start < end:
703 703 revs = web.repo.changelog.revs(start, end - 1)
704 704 for i in revs:
705 705 ctx = web.repo[i]
706 706
707 707 l.append(tmpl(
708 708 'shortlogentry',
709 709 parity=next(parity),
710 710 **webutil.commonentry(web.repo, ctx)))
711 711
712 712 for entry in reversed(l):
713 713 yield entry
714 714
715 715 tip = web.repo['tip']
716 716 count = len(web.repo)
717 717 start = max(0, count - web.maxchanges)
718 718 end = min(count, start + web.maxchanges)
719 719
720 720 return tmpl("summary",
721 721 desc=web.config("web", "description", "unknown"),
722 722 owner=get_contact(web.config) or "unknown",
723 723 lastchange=tip.date(),
724 724 tags=tagentries,
725 725 bookmarks=bookmarks,
726 726 branches=webutil.branchentries(web.repo, web.stripecount, 10),
727 727 shortlog=changelist,
728 728 node=tip.hex(),
729 729 symrev='tip',
730 730 archives=web.archivelist("tip"),
731 731 labels=web.configlist('web', 'labels'))
732 732
733 733 @webcommand('filediff')
734 734 def filediff(web, req, tmpl):
735 735 """
736 736 /diff/{revision}/{path}
737 737 -----------------------
738 738
739 739 Show how a file changed in a particular commit.
740 740
741 741 The ``filediff`` template is rendered.
742 742
743 743 This handler is registered under both the ``/diff`` and ``/filediff``
744 744 paths. ``/diff`` is used in modern code.
745 745 """
746 746 fctx, ctx = None, None
747 747 try:
748 748 fctx = webutil.filectx(web.repo, req)
749 749 except LookupError:
750 750 ctx = webutil.changectx(web.repo, req)
751 751 path = webutil.cleanpath(web.repo, req.form['file'][0])
752 752 if path not in ctx.files():
753 753 raise
754 754
755 755 if fctx is not None:
756 756 path = fctx.path()
757 757 ctx = fctx.changectx()
758 758 basectx = ctx.p1()
759 759
760 760 style = web.config('web', 'style', 'paper')
761 761 if 'style' in req.form:
762 762 style = req.form['style'][0]
763 763
764 764 diffs = webutil.diffs(web, tmpl, ctx, basectx, [path], style)
765 765 if fctx is not None:
766 766 rename = webutil.renamelink(fctx)
767 767 ctx = fctx
768 768 else:
769 769 rename = []
770 770 ctx = ctx
771 771 return tmpl("filediff",
772 772 file=path,
773 773 symrev=webutil.symrevorshortnode(req, ctx),
774 774 rename=rename,
775 775 diff=diffs,
776 776 **webutil.commonentry(web.repo, ctx))
777 777
778 778 diff = webcommand('diff')(filediff)
779 779
780 780 @webcommand('comparison')
781 781 def comparison(web, req, tmpl):
782 782 """
783 783 /comparison/{revision}/{path}
784 784 -----------------------------
785 785
786 786 Show a comparison between the old and new versions of a file from changes
787 787 made on a particular revision.
788 788
789 789 This is similar to the ``diff`` handler. However, this form features
790 790 a split or side-by-side diff rather than a unified diff.
791 791
792 792 The ``context`` query string argument can be used to control the lines of
793 793 context in the diff.
794 794
795 795 The ``filecomparison`` template is rendered.
796 796 """
797 797 ctx = webutil.changectx(web.repo, req)
798 798 if 'file' not in req.form:
799 799 raise ErrorResponse(HTTP_NOT_FOUND, 'file not given')
800 800 path = webutil.cleanpath(web.repo, req.form['file'][0])
801 801
802 802 parsecontext = lambda v: v == 'full' and -1 or int(v)
803 803 if 'context' in req.form:
804 804 context = parsecontext(req.form['context'][0])
805 805 else:
806 806 context = parsecontext(web.config('web', 'comparisoncontext', '5'))
807 807
808 808 def filelines(f):
809 809 if util.binary(f.data()):
810 810 mt = mimetypes.guess_type(f.path())[0]
811 811 if not mt:
812 812 mt = 'application/octet-stream'
813 813 return [_('(binary file %s, hash: %s)') % (mt, hex(f.filenode()))]
814 814 return f.data().splitlines()
815 815
816 816 fctx = None
817 817 parent = ctx.p1()
818 818 leftrev = parent.rev()
819 819 leftnode = parent.node()
820 820 rightrev = ctx.rev()
821 821 rightnode = ctx.node()
822 822 if path in ctx:
823 823 fctx = ctx[path]
824 824 rightlines = filelines(fctx)
825 825 if path not in parent:
826 826 leftlines = ()
827 827 else:
828 828 pfctx = parent[path]
829 829 leftlines = filelines(pfctx)
830 830 else:
831 831 rightlines = ()
832 832 pfctx = ctx.parents()[0][path]
833 833 leftlines = filelines(pfctx)
834 834
835 835 comparison = webutil.compare(tmpl, context, leftlines, rightlines)
836 836 if fctx is not None:
837 837 rename = webutil.renamelink(fctx)
838 838 ctx = fctx
839 839 else:
840 840 rename = []
841 841 ctx = ctx
842 842 return tmpl('filecomparison',
843 843 file=path,
844 844 symrev=webutil.symrevorshortnode(req, ctx),
845 845 rename=rename,
846 846 leftrev=leftrev,
847 847 leftnode=hex(leftnode),
848 848 rightrev=rightrev,
849 849 rightnode=hex(rightnode),
850 850 comparison=comparison,
851 851 **webutil.commonentry(web.repo, ctx))
852 852
853 853 @webcommand('annotate')
854 854 def annotate(web, req, tmpl):
855 855 """
856 856 /annotate/{revision}/{path}
857 857 ---------------------------
858 858
859 859 Show changeset information for each line in a file.
860 860
861 861 The ``fileannotate`` template is rendered.
862 862 """
863 863 fctx = webutil.filectx(web.repo, req)
864 864 f = fctx.path()
865 865 parity = paritygen(web.stripecount)
866 866
867 867 # parents() is called once per line and several lines likely belong to
868 868 # same revision. So it is worth caching.
869 869 # TODO there are still redundant operations within basefilectx.parents()
870 870 # and from the fctx.annotate() call itself that could be cached.
871 871 parentscache = {}
872 872 def parents(f):
873 873 rev = f.rev()
874 874 if rev not in parentscache:
875 875 parentscache[rev] = []
876 876 for p in f.parents():
877 877 entry = {
878 878 'node': p.hex(),
879 879 'rev': p.rev(),
880 880 }
881 881 parentscache[rev].append(entry)
882 882
883 883 for p in parentscache[rev]:
884 884 yield p
885 885
886 886 def annotate(**map):
887 887 if util.binary(fctx.data()):
888 888 mt = (mimetypes.guess_type(fctx.path())[0]
889 889 or 'application/octet-stream')
890 890 lines = [((fctx.filectx(fctx.filerev()), 1), '(binary:%s)' % mt)]
891 891 else:
892 892 lines = webutil.annotate(fctx, web.repo.ui)
893 893
894 894 previousrev = None
895 895 blockparitygen = paritygen(1)
896 896 for lineno, ((f, targetline), l) in enumerate(lines):
897 897 rev = f.rev()
898 898 if rev != previousrev:
899 899 blockhead = True
900 900 blockparity = next(blockparitygen)
901 901 else:
902 902 blockhead = None
903 903 previousrev = rev
904 904 yield {"parity": next(parity),
905 905 "node": f.hex(),
906 906 "rev": rev,
907 907 "author": f.user(),
908 908 "parents": parents(f),
909 909 "desc": f.description(),
910 910 "extra": f.extra(),
911 911 "file": f.path(),
912 912 "blockhead": blockhead,
913 913 "blockparity": blockparity,
914 914 "targetline": targetline,
915 915 "line": l,
916 916 "lineno": lineno + 1,
917 917 "lineid": "l%d" % (lineno + 1),
918 918 "linenumber": "% 6d" % (lineno + 1),
919 919 "revdate": f.date()}
920 920
921 921 return tmpl("fileannotate",
922 922 file=f,
923 923 annotate=annotate,
924 924 path=webutil.up(f),
925 925 symrev=webutil.symrevorshortnode(req, fctx),
926 926 rename=webutil.renamelink(fctx),
927 927 permissions=fctx.manifest().flags(f),
928 928 **webutil.commonentry(web.repo, fctx))
929 929
930 930 @webcommand('filelog')
931 931 def filelog(web, req, tmpl):
932 932 """
933 933 /filelog/{revision}/{path}
934 934 --------------------------
935 935
936 936 Show information about the history of a file in the repository.
937 937
938 938 The ``revcount`` query string argument can be defined to control the
939 939 maximum number of entries to show.
940 940
941 941 The ``filelog`` template will be rendered.
942 942 """
943 943
944 944 try:
945 945 fctx = webutil.filectx(web.repo, req)
946 946 f = fctx.path()
947 947 fl = fctx.filelog()
948 948 except error.LookupError:
949 949 f = webutil.cleanpath(web.repo, req.form['file'][0])
950 950 fl = web.repo.file(f)
951 951 numrevs = len(fl)
952 952 if not numrevs: # file doesn't exist at all
953 953 raise
954 954 rev = webutil.changectx(web.repo, req).rev()
955 955 first = fl.linkrev(0)
956 956 if rev < first: # current rev is from before file existed
957 957 raise
958 958 frev = numrevs - 1
959 959 while fl.linkrev(frev) > rev:
960 960 frev -= 1
961 961 fctx = web.repo.filectx(f, fl.linkrev(frev))
962 962
963 963 revcount = web.maxshortchanges
964 964 if 'revcount' in req.form:
965 965 try:
966 966 revcount = int(req.form.get('revcount', [revcount])[0])
967 967 revcount = max(revcount, 1)
968 968 tmpl.defaults['sessionvars']['revcount'] = revcount
969 969 except ValueError:
970 970 pass
971 971
972 972 lrange = webutil.linerange(req)
973 973
974 974 lessvars = copy.copy(tmpl.defaults['sessionvars'])
975 975 lessvars['revcount'] = max(revcount / 2, 1)
976 976 morevars = copy.copy(tmpl.defaults['sessionvars'])
977 977 morevars['revcount'] = revcount * 2
978 978
979 979 patch = 'patch' in req.form
980 980 if patch:
981 981 lessvars['patch'] = morevars['patch'] = req.form['patch'][0]
982 descend = 'descend' in req.form
983 if descend:
984 lessvars['descend'] = morevars['descend'] = req.form['descend'][0]
982 985
983 986 count = fctx.filerev() + 1
984 987 start = max(0, count - revcount) # first rev on this page
985 988 end = min(count, start + revcount) # last rev on this page
986 989 parity = paritygen(web.stripecount, offset=start - end)
987 990
988 991 repo = web.repo
989 992 revs = fctx.filelog().revs(start, end - 1)
990 993 entries = []
991 994
992 995 diffstyle = web.config('web', 'style', 'paper')
993 996 if 'style' in req.form:
994 997 diffstyle = req.form['style'][0]
995 998
996 999 def diff(fctx, linerange=None):
997 1000 ctx = fctx.changectx()
998 1001 basectx = ctx.p1()
999 1002 path = fctx.path()
1000 1003 return webutil.diffs(web, tmpl, ctx, basectx, [path], diffstyle,
1001 1004 linerange=linerange,
1002 1005 lineidprefix='%s-' % ctx.hex()[:12])
1003 1006
1004 1007 linerange = None
1005 1008 if lrange is not None:
1006 1009 linerange = webutil.formatlinerange(*lrange)
1007 1010 # deactivate numeric nav links when linerange is specified as this
1008 1011 # would required a dedicated "revnav" class
1009 1012 nav = None
1010 ancestors = context.blockancestors(fctx, *lrange)
1011 for i, (c, lr) in enumerate(ancestors, 1):
1013 if descend:
1014 it = context.blockdescendants(fctx, *lrange)
1015 else:
1016 it = context.blockancestors(fctx, *lrange)
1017 for i, (c, lr) in enumerate(it, 1):
1012 1018 diffs = None
1013 1019 if patch:
1014 1020 diffs = diff(c, linerange=lr)
1015 1021 # follow renames accross filtered (not in range) revisions
1016 1022 path = c.path()
1017 1023 entries.append(dict(
1018 1024 parity=next(parity),
1019 1025 filerev=c.rev(),
1020 1026 file=path,
1021 1027 diff=diffs,
1022 1028 linerange=webutil.formatlinerange(*lr),
1023 1029 **webutil.commonentry(repo, c)))
1024 1030 if i == revcount:
1025 1031 break
1026 1032 lessvars['linerange'] = webutil.formatlinerange(*lrange)
1027 1033 morevars['linerange'] = lessvars['linerange']
1028 1034 else:
1029 1035 for i in revs:
1030 1036 iterfctx = fctx.filectx(i)
1031 1037 diffs = None
1032 1038 if patch:
1033 1039 diffs = diff(iterfctx)
1034 1040 entries.append(dict(
1035 1041 parity=next(parity),
1036 1042 filerev=i,
1037 1043 file=f,
1038 1044 diff=diffs,
1039 1045 rename=webutil.renamelink(iterfctx),
1040 1046 **webutil.commonentry(repo, iterfctx)))
1041 1047 entries.reverse()
1042 1048 revnav = webutil.filerevnav(web.repo, fctx.path())
1043 1049 nav = revnav.gen(end - 1, revcount, count)
1044 1050
1045 1051 latestentry = entries[:1]
1046 1052
1047 1053 return tmpl("filelog",
1048 1054 file=f,
1049 1055 nav=nav,
1050 1056 symrev=webutil.symrevorshortnode(req, fctx),
1051 1057 entries=entries,
1058 descend=descend,
1052 1059 patch=patch,
1053 1060 latestentry=latestentry,
1054 1061 linerange=linerange,
1055 1062 revcount=revcount,
1056 1063 morevars=morevars,
1057 1064 lessvars=lessvars,
1058 1065 **webutil.commonentry(web.repo, fctx))
1059 1066
1060 1067 @webcommand('archive')
1061 1068 def archive(web, req, tmpl):
1062 1069 """
1063 1070 /archive/{revision}.{format}[/{path}]
1064 1071 -------------------------------------
1065 1072
1066 1073 Obtain an archive of repository content.
1067 1074
1068 1075 The content and type of the archive is defined by a URL path parameter.
1069 1076 ``format`` is the file extension of the archive type to be generated. e.g.
1070 1077 ``zip`` or ``tar.bz2``. Not all archive types may be allowed by your
1071 1078 server configuration.
1072 1079
1073 1080 The optional ``path`` URL parameter controls content to include in the
1074 1081 archive. If omitted, every file in the specified revision is present in the
1075 1082 archive. If included, only the specified file or contents of the specified
1076 1083 directory will be included in the archive.
1077 1084
1078 1085 No template is used for this handler. Raw, binary content is generated.
1079 1086 """
1080 1087
1081 1088 type_ = req.form.get('type', [None])[0]
1082 1089 allowed = web.configlist("web", "allow_archive")
1083 1090 key = req.form['node'][0]
1084 1091
1085 1092 if type_ not in web.archivespecs:
1086 1093 msg = 'Unsupported archive type: %s' % type_
1087 1094 raise ErrorResponse(HTTP_NOT_FOUND, msg)
1088 1095
1089 1096 if not ((type_ in allowed or
1090 1097 web.configbool("web", "allow" + type_, False))):
1091 1098 msg = 'Archive type not allowed: %s' % type_
1092 1099 raise ErrorResponse(HTTP_FORBIDDEN, msg)
1093 1100
1094 1101 reponame = re.sub(r"\W+", "-", os.path.basename(web.reponame))
1095 1102 cnode = web.repo.lookup(key)
1096 1103 arch_version = key
1097 1104 if cnode == key or key == 'tip':
1098 1105 arch_version = short(cnode)
1099 1106 name = "%s-%s" % (reponame, arch_version)
1100 1107
1101 1108 ctx = webutil.changectx(web.repo, req)
1102 1109 pats = []
1103 1110 matchfn = scmutil.match(ctx, [])
1104 1111 file = req.form.get('file', None)
1105 1112 if file:
1106 1113 pats = ['path:' + file[0]]
1107 1114 matchfn = scmutil.match(ctx, pats, default='path')
1108 1115 if pats:
1109 1116 files = [f for f in ctx.manifest().keys() if matchfn(f)]
1110 1117 if not files:
1111 1118 raise ErrorResponse(HTTP_NOT_FOUND,
1112 1119 'file(s) not found: %s' % file[0])
1113 1120
1114 1121 mimetype, artype, extension, encoding = web.archivespecs[type_]
1115 1122 headers = [
1116 1123 ('Content-Disposition', 'attachment; filename=%s%s' % (name, extension))
1117 1124 ]
1118 1125 if encoding:
1119 1126 headers.append(('Content-Encoding', encoding))
1120 1127 req.headers.extend(headers)
1121 1128 req.respond(HTTP_OK, mimetype)
1122 1129
1123 1130 archival.archive(web.repo, req, cnode, artype, prefix=name,
1124 1131 matchfn=matchfn,
1125 1132 subrepos=web.configbool("web", "archivesubrepos"))
1126 1133 return []
1127 1134
1128 1135
1129 1136 @webcommand('static')
1130 1137 def static(web, req, tmpl):
1131 1138 fname = req.form['file'][0]
1132 1139 # a repo owner may set web.static in .hg/hgrc to get any file
1133 1140 # readable by the user running the CGI script
1134 1141 static = web.config("web", "static", None, untrusted=False)
1135 1142 if not static:
1136 1143 tp = web.templatepath or templater.templatepaths()
1137 1144 if isinstance(tp, str):
1138 1145 tp = [tp]
1139 1146 static = [os.path.join(p, 'static') for p in tp]
1140 1147 staticfile(static, fname, req)
1141 1148 return []
1142 1149
1143 1150 @webcommand('graph')
1144 1151 def graph(web, req, tmpl):
1145 1152 """
1146 1153 /graph[/{revision}]
1147 1154 -------------------
1148 1155
1149 1156 Show information about the graphical topology of the repository.
1150 1157
1151 1158 Information rendered by this handler can be used to create visual
1152 1159 representations of repository topology.
1153 1160
1154 1161 The ``revision`` URL parameter controls the starting changeset.
1155 1162
1156 1163 The ``revcount`` query string argument can define the number of changesets
1157 1164 to show information for.
1158 1165
1159 1166 This handler will render the ``graph`` template.
1160 1167 """
1161 1168
1162 1169 if 'node' in req.form:
1163 1170 ctx = webutil.changectx(web.repo, req)
1164 1171 symrev = webutil.symrevorshortnode(req, ctx)
1165 1172 else:
1166 1173 ctx = web.repo['tip']
1167 1174 symrev = 'tip'
1168 1175 rev = ctx.rev()
1169 1176
1170 1177 bg_height = 39
1171 1178 revcount = web.maxshortchanges
1172 1179 if 'revcount' in req.form:
1173 1180 try:
1174 1181 revcount = int(req.form.get('revcount', [revcount])[0])
1175 1182 revcount = max(revcount, 1)
1176 1183 tmpl.defaults['sessionvars']['revcount'] = revcount
1177 1184 except ValueError:
1178 1185 pass
1179 1186
1180 1187 lessvars = copy.copy(tmpl.defaults['sessionvars'])
1181 1188 lessvars['revcount'] = max(revcount / 2, 1)
1182 1189 morevars = copy.copy(tmpl.defaults['sessionvars'])
1183 1190 morevars['revcount'] = revcount * 2
1184 1191
1185 1192 count = len(web.repo)
1186 1193 pos = rev
1187 1194
1188 1195 uprev = min(max(0, count - 1), rev + revcount)
1189 1196 downrev = max(0, rev - revcount)
1190 1197 changenav = webutil.revnav(web.repo).gen(pos, revcount, count)
1191 1198
1192 1199 tree = []
1193 1200 if pos != -1:
1194 1201 allrevs = web.repo.changelog.revs(pos, 0)
1195 1202 revs = []
1196 1203 for i in allrevs:
1197 1204 revs.append(i)
1198 1205 if len(revs) >= revcount:
1199 1206 break
1200 1207
1201 1208 # We have to feed a baseset to dagwalker as it is expecting smartset
1202 1209 # object. This does not have a big impact on hgweb performance itself
1203 1210 # since hgweb graphing code is not itself lazy yet.
1204 1211 dag = graphmod.dagwalker(web.repo, smartset.baseset(revs))
1205 1212 # As we said one line above... not lazy.
1206 1213 tree = list(graphmod.colored(dag, web.repo))
1207 1214
1208 1215 def getcolumns(tree):
1209 1216 cols = 0
1210 1217 for (id, type, ctx, vtx, edges) in tree:
1211 1218 if type != graphmod.CHANGESET:
1212 1219 continue
1213 1220 cols = max(cols, max([edge[0] for edge in edges] or [0]),
1214 1221 max([edge[1] for edge in edges] or [0]))
1215 1222 return cols
1216 1223
1217 1224 def graphdata(usetuples, encodestr):
1218 1225 data = []
1219 1226
1220 1227 row = 0
1221 1228 for (id, type, ctx, vtx, edges) in tree:
1222 1229 if type != graphmod.CHANGESET:
1223 1230 continue
1224 1231 node = str(ctx)
1225 1232 age = encodestr(templatefilters.age(ctx.date()))
1226 1233 desc = templatefilters.firstline(encodestr(ctx.description()))
1227 1234 desc = cgi.escape(templatefilters.nonempty(desc))
1228 1235 user = cgi.escape(templatefilters.person(encodestr(ctx.user())))
1229 1236 branch = cgi.escape(encodestr(ctx.branch()))
1230 1237 try:
1231 1238 branchnode = web.repo.branchtip(branch)
1232 1239 except error.RepoLookupError:
1233 1240 branchnode = None
1234 1241 branch = branch, branchnode == ctx.node()
1235 1242
1236 1243 if usetuples:
1237 1244 data.append((node, vtx, edges, desc, user, age, branch,
1238 1245 [cgi.escape(encodestr(x)) for x in ctx.tags()],
1239 1246 [cgi.escape(encodestr(x))
1240 1247 for x in ctx.bookmarks()]))
1241 1248 else:
1242 1249 edgedata = [{'col': edge[0], 'nextcol': edge[1],
1243 1250 'color': (edge[2] - 1) % 6 + 1,
1244 1251 'width': edge[3], 'bcolor': edge[4]}
1245 1252 for edge in edges]
1246 1253
1247 1254 data.append(
1248 1255 {'node': node,
1249 1256 'col': vtx[0],
1250 1257 'color': (vtx[1] - 1) % 6 + 1,
1251 1258 'edges': edgedata,
1252 1259 'row': row,
1253 1260 'nextrow': row + 1,
1254 1261 'desc': desc,
1255 1262 'user': user,
1256 1263 'age': age,
1257 1264 'bookmarks': webutil.nodebookmarksdict(
1258 1265 web.repo, ctx.node()),
1259 1266 'branches': webutil.nodebranchdict(web.repo, ctx),
1260 1267 'inbranch': webutil.nodeinbranch(web.repo, ctx),
1261 1268 'tags': webutil.nodetagsdict(web.repo, ctx.node())})
1262 1269
1263 1270 row += 1
1264 1271
1265 1272 return data
1266 1273
1267 1274 cols = getcolumns(tree)
1268 1275 rows = len(tree)
1269 1276 canvasheight = (rows + 1) * bg_height - 27
1270 1277
1271 1278 return tmpl('graph', rev=rev, symrev=symrev, revcount=revcount,
1272 1279 uprev=uprev,
1273 1280 lessvars=lessvars, morevars=morevars, downrev=downrev,
1274 1281 cols=cols, rows=rows,
1275 1282 canvaswidth=(cols + 1) * bg_height,
1276 1283 truecanvasheight=rows * bg_height,
1277 1284 canvasheight=canvasheight, bg_height=bg_height,
1278 1285 # {jsdata} will be passed to |json, so it must be in utf-8
1279 1286 jsdata=lambda **x: graphdata(True, encoding.fromlocal),
1280 1287 nodes=lambda **x: graphdata(False, str),
1281 1288 node=ctx.hex(), changenav=changenav)
1282 1289
1283 1290 def _getdoc(e):
1284 1291 doc = e[0].__doc__
1285 1292 if doc:
1286 1293 doc = _(doc).partition('\n')[0]
1287 1294 else:
1288 1295 doc = _('(no help text available)')
1289 1296 return doc
1290 1297
1291 1298 @webcommand('help')
1292 1299 def help(web, req, tmpl):
1293 1300 """
1294 1301 /help[/{topic}]
1295 1302 ---------------
1296 1303
1297 1304 Render help documentation.
1298 1305
1299 1306 This web command is roughly equivalent to :hg:`help`. If a ``topic``
1300 1307 is defined, that help topic will be rendered. If not, an index of
1301 1308 available help topics will be rendered.
1302 1309
1303 1310 The ``help`` template will be rendered when requesting help for a topic.
1304 1311 ``helptopics`` will be rendered for the index of help topics.
1305 1312 """
1306 1313 from .. import commands, help as helpmod # avoid cycle
1307 1314
1308 1315 topicname = req.form.get('node', [None])[0]
1309 1316 if not topicname:
1310 1317 def topics(**map):
1311 1318 for entries, summary, _doc in helpmod.helptable:
1312 1319 yield {'topic': entries[0], 'summary': summary}
1313 1320
1314 1321 early, other = [], []
1315 1322 primary = lambda s: s.partition('|')[0]
1316 1323 for c, e in commands.table.iteritems():
1317 1324 doc = _getdoc(e)
1318 1325 if 'DEPRECATED' in doc or c.startswith('debug'):
1319 1326 continue
1320 1327 cmd = primary(c)
1321 1328 if cmd.startswith('^'):
1322 1329 early.append((cmd[1:], doc))
1323 1330 else:
1324 1331 other.append((cmd, doc))
1325 1332
1326 1333 early.sort()
1327 1334 other.sort()
1328 1335
1329 1336 def earlycommands(**map):
1330 1337 for c, doc in early:
1331 1338 yield {'topic': c, 'summary': doc}
1332 1339
1333 1340 def othercommands(**map):
1334 1341 for c, doc in other:
1335 1342 yield {'topic': c, 'summary': doc}
1336 1343
1337 1344 return tmpl('helptopics', topics=topics, earlycommands=earlycommands,
1338 1345 othercommands=othercommands, title='Index')
1339 1346
1340 1347 # Render an index of sub-topics.
1341 1348 if topicname in helpmod.subtopics:
1342 1349 topics = []
1343 1350 for entries, summary, _doc in helpmod.subtopics[topicname]:
1344 1351 topics.append({
1345 1352 'topic': '%s.%s' % (topicname, entries[0]),
1346 1353 'basename': entries[0],
1347 1354 'summary': summary,
1348 1355 })
1349 1356
1350 1357 return tmpl('helptopics', topics=topics, title=topicname,
1351 1358 subindex=True)
1352 1359
1353 1360 u = webutil.wsgiui.load()
1354 1361 u.verbose = True
1355 1362
1356 1363 # Render a page from a sub-topic.
1357 1364 if '.' in topicname:
1358 1365 # TODO implement support for rendering sections, like
1359 1366 # `hg help` works.
1360 1367 topic, subtopic = topicname.split('.', 1)
1361 1368 if topic not in helpmod.subtopics:
1362 1369 raise ErrorResponse(HTTP_NOT_FOUND)
1363 1370 else:
1364 1371 topic = topicname
1365 1372 subtopic = None
1366 1373
1367 1374 try:
1368 1375 doc = helpmod.help_(u, topic, subtopic=subtopic)
1369 1376 except error.UnknownCommand:
1370 1377 raise ErrorResponse(HTTP_NOT_FOUND)
1371 1378 return tmpl('help', topic=topicname, doc=doc)
1372 1379
1373 1380 # tell hggettext to extract docstrings from these functions:
1374 1381 i18nfunctions = commands.values()
@@ -1,87 +1,87 b''
1 1 {header}
2 2 <title>{repo|escape}: {file|escape} history</title>
3 3 <link rel="alternate" type="application/atom+xml"
4 4 href="{url|urlescape}atom-log/tip/{file|urlescape}" title="Atom feed for {repo|escape}:{file}" />
5 5 <link rel="alternate" type="application/rss+xml"
6 6 href="{url|urlescape}rss-log/tip/{file|urlescape}" title="RSS feed for {repo|escape}:{file}" />
7 7 </head>
8 8 <body>
9 9
10 10 <div class="container">
11 11 <div class="menu">
12 12 <div class="logo">
13 13 <a href="{logourl}">
14 14 <img src="{staticurl|urlescape}{logoimg}" alt="mercurial" /></a>
15 15 </div>
16 16 <ul>
17 17 <li><a href="{url|urlescape}shortlog/{symrev}{sessionvars%urlparameter}">log</a></li>
18 18 <li><a href="{url|urlescape}graph/{symrev}{sessionvars%urlparameter}">graph</a></li>
19 19 <li><a href="{url|urlescape}tags{sessionvars%urlparameter}">tags</a></li>
20 20 <li><a href="{url|urlescape}bookmarks{sessionvars%urlparameter}">bookmarks</a></li>
21 21 <li><a href="{url|urlescape}branches{sessionvars%urlparameter}">branches</a></li>
22 22 </ul>
23 23 <ul>
24 24 <li><a href="{url|urlescape}rev/{symrev}{sessionvars%urlparameter}">changeset</a></li>
25 25 <li><a href="{url|urlescape}file/{symrev}{path|urlescape}{sessionvars%urlparameter}">browse</a></li>
26 26 </ul>
27 27 <ul>
28 28 <li><a href="{url|urlescape}file/{symrev}/{file|urlescape}{sessionvars%urlparameter}">file</a></li>
29 29 <li><a href="{url|urlescape}diff/{symrev}/{file|urlescape}{sessionvars%urlparameter}">diff</a></li>
30 30 <li><a href="{url|urlescape}comparison/{symrev}/{file|urlescape}{sessionvars%urlparameter}">comparison</a></li>
31 31 <li><a href="{url|urlescape}annotate/{symrev}/{file|urlescape}{sessionvars%urlparameter}">annotate</a></li>
32 32 <li class="active">file log</li>
33 33 <li><a href="{url|urlescape}raw-file/{symrev}/{file|urlescape}">raw</a></li>
34 34 </ul>
35 35 <ul>
36 36 <li><a href="{url|urlescape}help{sessionvars%urlparameter}">help</a></li>
37 37 </ul>
38 38 <div class="atom-logo">
39 39 <a href="{url|urlescape}atom-log/tip/{file|urlescape}" title="subscribe to atom feed">
40 40 <img class="atom-logo" src="{staticurl|urlescape}feed-icon-14x14.png" alt="atom feed" />
41 41 </a>
42 42 </div>
43 43 </div>
44 44
45 45 <div class="main">
46 46 <h2 class="breadcrumb"><a href="/">Mercurial</a> {pathdef%breadcrumb}</h2>
47 47 <h3>
48 48 log {file|escape} @ {rev}:<a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a>
49 49 {branch%changelogbranchname}{tags%changelogtag}{bookmarks%changelogtag}
50 50 {if(linerange,
51 ' (following lines {linerange} <a href="{url|urlescape}log/{symrev}/{file|urlescape}{sessionvars%urlparameter}">back to filelog</a>)')}
51 ' (following lines {linerange}{if(descend, ', descending')} <a href="{url|urlescape}log/{symrev}/{file|urlescape}{sessionvars%urlparameter}">back to filelog</a>)')}
52 52 </h3>
53 53
54 54 <form class="search" action="{url|urlescape}log">
55 55 {sessionvars%hiddenformentry}
56 56 <p><input name="rev" id="search1" type="text" size="30" /></p>
57 57 <div id="hint">{searchhint}</div>
58 58 </form>
59 59
60 60 <div class="navigate">
61 61 <a href="{url|urlescape}log/{symrev}/{file|urlescape}{lessvars%urlparameter}">less</a>
62 62 <a href="{url|urlescape}log/{symrev}/{file|urlescape}{morevars%urlparameter}">more</a>
63 63 | {nav%filenav}</div>
64 64
65 65 <table class="bigtable">
66 66 <thead>
67 67 <tr>
68 68 <th class="age">age</th>
69 69 <th class="author">author</th>
70 70 <th class="description">description</th>
71 71 </tr>
72 72 </thead>
73 73 <tbody class="stripes2">
74 74 {entries%filelogentry}
75 75 </tbody>
76 76 </table>
77 77
78 78 <div class="navigate">
79 79 <a href="{url|urlescape}log/{symrev}/{file|urlescape}{lessvars%urlparameter}">less</a>
80 80 <a href="{url|urlescape}log/{symrev}/{file|urlescape}{morevars%urlparameter}">more</a>
81 81 | {nav%filenav}
82 82 </div>
83 83
84 84 </div>
85 85 </div>
86 86
87 87 {footer}
@@ -1,1641 +1,1805 b''
1 1 #require serve
2 2
3 3 $ hg init test
4 4 $ cd test
5 5 $ echo b > b
6 6 $ hg ci -Am "b"
7 7 adding b
8 8 $ echo a > a
9 9 $ hg ci -Am "first a"
10 10 adding a
11 11 $ hg tag -r 1 a-tag
12 12 $ hg bookmark -r 1 a-bookmark
13 13 $ hg rm a
14 14 $ hg ci -m "del a"
15 15 $ hg branch a-branch
16 16 marked working directory as branch a-branch
17 17 (branches are permanent and global, did you want a bookmark?)
18 18 $ echo b > a
19 19 $ hg ci -Am "second a"
20 20 adding a
21 21 $ hg rm a
22 22 $ hg ci -m "del2 a"
23 23 $ hg mv b c
24 24 $ hg ci -m "mv b"
25 25 $ echo c >> c
26 26 $ hg ci -m "change c"
27 27 $ hg log -p
28 28 changeset: 7:46c1a66bd8fc
29 29 branch: a-branch
30 30 tag: tip
31 31 user: test
32 32 date: Thu Jan 01 00:00:00 1970 +0000
33 33 summary: change c
34 34
35 35 diff -r c9637d3cc8ef -r 46c1a66bd8fc c
36 36 --- a/c Thu Jan 01 00:00:00 1970 +0000
37 37 +++ b/c Thu Jan 01 00:00:00 1970 +0000
38 38 @@ -1,1 +1,2 @@
39 39 b
40 40 +c
41 41
42 42 changeset: 6:c9637d3cc8ef
43 43 branch: a-branch
44 44 user: test
45 45 date: Thu Jan 01 00:00:00 1970 +0000
46 46 summary: mv b
47 47
48 48 diff -r 958bd88be4eb -r c9637d3cc8ef b
49 49 --- a/b Thu Jan 01 00:00:00 1970 +0000
50 50 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
51 51 @@ -1,1 +0,0 @@
52 52 -b
53 53 diff -r 958bd88be4eb -r c9637d3cc8ef c
54 54 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
55 55 +++ b/c Thu Jan 01 00:00:00 1970 +0000
56 56 @@ -0,0 +1,1 @@
57 57 +b
58 58
59 59 changeset: 5:958bd88be4eb
60 60 branch: a-branch
61 61 user: test
62 62 date: Thu Jan 01 00:00:00 1970 +0000
63 63 summary: del2 a
64 64
65 65 diff -r 3f41bc784e7e -r 958bd88be4eb a
66 66 --- a/a Thu Jan 01 00:00:00 1970 +0000
67 67 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
68 68 @@ -1,1 +0,0 @@
69 69 -b
70 70
71 71 changeset: 4:3f41bc784e7e
72 72 branch: a-branch
73 73 user: test
74 74 date: Thu Jan 01 00:00:00 1970 +0000
75 75 summary: second a
76 76
77 77 diff -r 292258f86fdf -r 3f41bc784e7e a
78 78 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
79 79 +++ b/a Thu Jan 01 00:00:00 1970 +0000
80 80 @@ -0,0 +1,1 @@
81 81 +b
82 82
83 83 changeset: 3:292258f86fdf
84 84 user: test
85 85 date: Thu Jan 01 00:00:00 1970 +0000
86 86 summary: del a
87 87
88 88 diff -r 94c9dd5ca9b4 -r 292258f86fdf a
89 89 --- a/a Thu Jan 01 00:00:00 1970 +0000
90 90 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
91 91 @@ -1,1 +0,0 @@
92 92 -a
93 93
94 94 changeset: 2:94c9dd5ca9b4
95 95 user: test
96 96 date: Thu Jan 01 00:00:00 1970 +0000
97 97 summary: Added tag a-tag for changeset 5ed941583260
98 98
99 99 diff -r 5ed941583260 -r 94c9dd5ca9b4 .hgtags
100 100 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
101 101 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
102 102 @@ -0,0 +1,1 @@
103 103 +5ed941583260248620985524192fdc382ef57c36 a-tag
104 104
105 105 changeset: 1:5ed941583260
106 106 bookmark: a-bookmark
107 107 tag: a-tag
108 108 user: test
109 109 date: Thu Jan 01 00:00:00 1970 +0000
110 110 summary: first a
111 111
112 112 diff -r 6563da9dcf87 -r 5ed941583260 a
113 113 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
114 114 +++ b/a Thu Jan 01 00:00:00 1970 +0000
115 115 @@ -0,0 +1,1 @@
116 116 +a
117 117
118 118 changeset: 0:6563da9dcf87
119 119 user: test
120 120 date: Thu Jan 01 00:00:00 1970 +0000
121 121 summary: b
122 122
123 123 diff -r 000000000000 -r 6563da9dcf87 b
124 124 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
125 125 +++ b/b Thu Jan 01 00:00:00 1970 +0000
126 126 @@ -0,0 +1,1 @@
127 127 +b
128 128
129 129 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -E errors.log
130 130 $ cat hg.pid >> $DAEMON_PIDS
131 131
132 132 tip - two revisions
133 133
134 134 $ (get-with-headers.py localhost:$HGPORT 'log/tip/a')
135 135 200 Script output follows
136 136
137 137 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
138 138 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
139 139 <head>
140 140 <link rel="icon" href="/static/hgicon.png" type="image/png" />
141 141 <meta name="robots" content="index, nofollow" />
142 142 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
143 143 <script type="text/javascript" src="/static/mercurial.js"></script>
144 144
145 145 <title>test: a history</title>
146 146 <link rel="alternate" type="application/atom+xml"
147 147 href="/atom-log/tip/a" title="Atom feed for test:a" />
148 148 <link rel="alternate" type="application/rss+xml"
149 149 href="/rss-log/tip/a" title="RSS feed for test:a" />
150 150 </head>
151 151 <body>
152 152
153 153 <div class="container">
154 154 <div class="menu">
155 155 <div class="logo">
156 156 <a href="https://mercurial-scm.org/">
157 157 <img src="/static/hglogo.png" alt="mercurial" /></a>
158 158 </div>
159 159 <ul>
160 160 <li><a href="/shortlog/tip">log</a></li>
161 161 <li><a href="/graph/tip">graph</a></li>
162 162 <li><a href="/tags">tags</a></li>
163 163 <li><a href="/bookmarks">bookmarks</a></li>
164 164 <li><a href="/branches">branches</a></li>
165 165 </ul>
166 166 <ul>
167 167 <li><a href="/rev/tip">changeset</a></li>
168 168 <li><a href="/file/tip">browse</a></li>
169 169 </ul>
170 170 <ul>
171 171 <li><a href="/file/tip/a">file</a></li>
172 172 <li><a href="/diff/tip/a">diff</a></li>
173 173 <li><a href="/comparison/tip/a">comparison</a></li>
174 174 <li><a href="/annotate/tip/a">annotate</a></li>
175 175 <li class="active">file log</li>
176 176 <li><a href="/raw-file/tip/a">raw</a></li>
177 177 </ul>
178 178 <ul>
179 179 <li><a href="/help">help</a></li>
180 180 </ul>
181 181 <div class="atom-logo">
182 182 <a href="/atom-log/tip/a" title="subscribe to atom feed">
183 183 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="atom feed" />
184 184 </a>
185 185 </div>
186 186 </div>
187 187
188 188 <div class="main">
189 189 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
190 190 <h3>
191 191 log a @ 4:<a href="/rev/3f41bc784e7e">3f41bc784e7e</a>
192 192 <span class="branchname">a-branch</span>
193 193
194 194 </h3>
195 195
196 196 <form class="search" action="/log">
197 197
198 198 <p><input name="rev" id="search1" type="text" size="30" /></p>
199 199 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
200 200 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
201 201 </form>
202 202
203 203 <div class="navigate">
204 204 <a href="/log/tip/a?revcount=30">less</a>
205 205 <a href="/log/tip/a?revcount=120">more</a>
206 206 | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a> </div>
207 207
208 208 <table class="bigtable">
209 209 <thead>
210 210 <tr>
211 211 <th class="age">age</th>
212 212 <th class="author">author</th>
213 213 <th class="description">description</th>
214 214 </tr>
215 215 </thead>
216 216 <tbody class="stripes2">
217 217 <tr>
218 218 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
219 219 <td class="author">test</td>
220 220 <td class="description">
221 221 <a href="/rev/3f41bc784e7e">second a</a>
222 222 <span class="branchname">a-branch</span>
223 223 </td>
224 224 </tr>
225 225
226 226 <tr>
227 227 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
228 228 <td class="author">test</td>
229 229 <td class="description">
230 230 <a href="/rev/5ed941583260">first a</a>
231 231 <span class="tag">a-tag</span> <span class="tag">a-bookmark</span>
232 232 </td>
233 233 </tr>
234 234
235 235
236 236 </tbody>
237 237 </table>
238 238
239 239 <div class="navigate">
240 240 <a href="/log/tip/a?revcount=30">less</a>
241 241 <a href="/log/tip/a?revcount=120">more</a>
242 242 | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a>
243 243 </div>
244 244
245 245 </div>
246 246 </div>
247 247
248 248
249 249
250 250 </body>
251 251 </html>
252 252
253 253
254 254 second version - two revisions
255 255
256 256 $ (get-with-headers.py localhost:$HGPORT 'log/4/a')
257 257 200 Script output follows
258 258
259 259 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
260 260 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
261 261 <head>
262 262 <link rel="icon" href="/static/hgicon.png" type="image/png" />
263 263 <meta name="robots" content="index, nofollow" />
264 264 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
265 265 <script type="text/javascript" src="/static/mercurial.js"></script>
266 266
267 267 <title>test: a history</title>
268 268 <link rel="alternate" type="application/atom+xml"
269 269 href="/atom-log/tip/a" title="Atom feed for test:a" />
270 270 <link rel="alternate" type="application/rss+xml"
271 271 href="/rss-log/tip/a" title="RSS feed for test:a" />
272 272 </head>
273 273 <body>
274 274
275 275 <div class="container">
276 276 <div class="menu">
277 277 <div class="logo">
278 278 <a href="https://mercurial-scm.org/">
279 279 <img src="/static/hglogo.png" alt="mercurial" /></a>
280 280 </div>
281 281 <ul>
282 282 <li><a href="/shortlog/4">log</a></li>
283 283 <li><a href="/graph/4">graph</a></li>
284 284 <li><a href="/tags">tags</a></li>
285 285 <li><a href="/bookmarks">bookmarks</a></li>
286 286 <li><a href="/branches">branches</a></li>
287 287 </ul>
288 288 <ul>
289 289 <li><a href="/rev/4">changeset</a></li>
290 290 <li><a href="/file/4">browse</a></li>
291 291 </ul>
292 292 <ul>
293 293 <li><a href="/file/4/a">file</a></li>
294 294 <li><a href="/diff/4/a">diff</a></li>
295 295 <li><a href="/comparison/4/a">comparison</a></li>
296 296 <li><a href="/annotate/4/a">annotate</a></li>
297 297 <li class="active">file log</li>
298 298 <li><a href="/raw-file/4/a">raw</a></li>
299 299 </ul>
300 300 <ul>
301 301 <li><a href="/help">help</a></li>
302 302 </ul>
303 303 <div class="atom-logo">
304 304 <a href="/atom-log/tip/a" title="subscribe to atom feed">
305 305 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="atom feed" />
306 306 </a>
307 307 </div>
308 308 </div>
309 309
310 310 <div class="main">
311 311 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
312 312 <h3>
313 313 log a @ 4:<a href="/rev/3f41bc784e7e">3f41bc784e7e</a>
314 314 <span class="branchname">a-branch</span>
315 315
316 316 </h3>
317 317
318 318 <form class="search" action="/log">
319 319
320 320 <p><input name="rev" id="search1" type="text" size="30" /></p>
321 321 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
322 322 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
323 323 </form>
324 324
325 325 <div class="navigate">
326 326 <a href="/log/4/a?revcount=30">less</a>
327 327 <a href="/log/4/a?revcount=120">more</a>
328 328 | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a> </div>
329 329
330 330 <table class="bigtable">
331 331 <thead>
332 332 <tr>
333 333 <th class="age">age</th>
334 334 <th class="author">author</th>
335 335 <th class="description">description</th>
336 336 </tr>
337 337 </thead>
338 338 <tbody class="stripes2">
339 339 <tr>
340 340 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
341 341 <td class="author">test</td>
342 342 <td class="description">
343 343 <a href="/rev/3f41bc784e7e">second a</a>
344 344 <span class="branchname">a-branch</span>
345 345 </td>
346 346 </tr>
347 347
348 348 <tr>
349 349 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
350 350 <td class="author">test</td>
351 351 <td class="description">
352 352 <a href="/rev/5ed941583260">first a</a>
353 353 <span class="tag">a-tag</span> <span class="tag">a-bookmark</span>
354 354 </td>
355 355 </tr>
356 356
357 357
358 358 </tbody>
359 359 </table>
360 360
361 361 <div class="navigate">
362 362 <a href="/log/4/a?revcount=30">less</a>
363 363 <a href="/log/4/a?revcount=120">more</a>
364 364 | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a>
365 365 </div>
366 366
367 367 </div>
368 368 </div>
369 369
370 370
371 371
372 372 </body>
373 373 </html>
374 374
375 375
376 376 first deleted - one revision
377 377
378 378 $ (get-with-headers.py localhost:$HGPORT 'log/3/a')
379 379 200 Script output follows
380 380
381 381 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
382 382 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
383 383 <head>
384 384 <link rel="icon" href="/static/hgicon.png" type="image/png" />
385 385 <meta name="robots" content="index, nofollow" />
386 386 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
387 387 <script type="text/javascript" src="/static/mercurial.js"></script>
388 388
389 389 <title>test: a history</title>
390 390 <link rel="alternate" type="application/atom+xml"
391 391 href="/atom-log/tip/a" title="Atom feed for test:a" />
392 392 <link rel="alternate" type="application/rss+xml"
393 393 href="/rss-log/tip/a" title="RSS feed for test:a" />
394 394 </head>
395 395 <body>
396 396
397 397 <div class="container">
398 398 <div class="menu">
399 399 <div class="logo">
400 400 <a href="https://mercurial-scm.org/">
401 401 <img src="/static/hglogo.png" alt="mercurial" /></a>
402 402 </div>
403 403 <ul>
404 404 <li><a href="/shortlog/3">log</a></li>
405 405 <li><a href="/graph/3">graph</a></li>
406 406 <li><a href="/tags">tags</a></li>
407 407 <li><a href="/bookmarks">bookmarks</a></li>
408 408 <li><a href="/branches">branches</a></li>
409 409 </ul>
410 410 <ul>
411 411 <li><a href="/rev/3">changeset</a></li>
412 412 <li><a href="/file/3">browse</a></li>
413 413 </ul>
414 414 <ul>
415 415 <li><a href="/file/3/a">file</a></li>
416 416 <li><a href="/diff/3/a">diff</a></li>
417 417 <li><a href="/comparison/3/a">comparison</a></li>
418 418 <li><a href="/annotate/3/a">annotate</a></li>
419 419 <li class="active">file log</li>
420 420 <li><a href="/raw-file/3/a">raw</a></li>
421 421 </ul>
422 422 <ul>
423 423 <li><a href="/help">help</a></li>
424 424 </ul>
425 425 <div class="atom-logo">
426 426 <a href="/atom-log/tip/a" title="subscribe to atom feed">
427 427 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="atom feed" />
428 428 </a>
429 429 </div>
430 430 </div>
431 431
432 432 <div class="main">
433 433 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
434 434 <h3>
435 435 log a @ 1:<a href="/rev/5ed941583260">5ed941583260</a>
436 436 <span class="tag">a-tag</span> <span class="tag">a-bookmark</span>
437 437
438 438 </h3>
439 439
440 440 <form class="search" action="/log">
441 441
442 442 <p><input name="rev" id="search1" type="text" size="30" /></p>
443 443 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
444 444 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
445 445 </form>
446 446
447 447 <div class="navigate">
448 448 <a href="/log/3/a?revcount=30">less</a>
449 449 <a href="/log/3/a?revcount=120">more</a>
450 450 | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a> </div>
451 451
452 452 <table class="bigtable">
453 453 <thead>
454 454 <tr>
455 455 <th class="age">age</th>
456 456 <th class="author">author</th>
457 457 <th class="description">description</th>
458 458 </tr>
459 459 </thead>
460 460 <tbody class="stripes2">
461 461 <tr>
462 462 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
463 463 <td class="author">test</td>
464 464 <td class="description">
465 465 <a href="/rev/5ed941583260">first a</a>
466 466 <span class="tag">a-tag</span> <span class="tag">a-bookmark</span>
467 467 </td>
468 468 </tr>
469 469
470 470
471 471 </tbody>
472 472 </table>
473 473
474 474 <div class="navigate">
475 475 <a href="/log/3/a?revcount=30">less</a>
476 476 <a href="/log/3/a?revcount=120">more</a>
477 477 | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a>
478 478 </div>
479 479
480 480 </div>
481 481 </div>
482 482
483 483
484 484
485 485 </body>
486 486 </html>
487 487
488 488
489 489 first version - one revision
490 490
491 491 $ (get-with-headers.py localhost:$HGPORT 'log/1/a')
492 492 200 Script output follows
493 493
494 494 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
495 495 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
496 496 <head>
497 497 <link rel="icon" href="/static/hgicon.png" type="image/png" />
498 498 <meta name="robots" content="index, nofollow" />
499 499 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
500 500 <script type="text/javascript" src="/static/mercurial.js"></script>
501 501
502 502 <title>test: a history</title>
503 503 <link rel="alternate" type="application/atom+xml"
504 504 href="/atom-log/tip/a" title="Atom feed for test:a" />
505 505 <link rel="alternate" type="application/rss+xml"
506 506 href="/rss-log/tip/a" title="RSS feed for test:a" />
507 507 </head>
508 508 <body>
509 509
510 510 <div class="container">
511 511 <div class="menu">
512 512 <div class="logo">
513 513 <a href="https://mercurial-scm.org/">
514 514 <img src="/static/hglogo.png" alt="mercurial" /></a>
515 515 </div>
516 516 <ul>
517 517 <li><a href="/shortlog/1">log</a></li>
518 518 <li><a href="/graph/1">graph</a></li>
519 519 <li><a href="/tags">tags</a></li>
520 520 <li><a href="/bookmarks">bookmarks</a></li>
521 521 <li><a href="/branches">branches</a></li>
522 522 </ul>
523 523 <ul>
524 524 <li><a href="/rev/1">changeset</a></li>
525 525 <li><a href="/file/1">browse</a></li>
526 526 </ul>
527 527 <ul>
528 528 <li><a href="/file/1/a">file</a></li>
529 529 <li><a href="/diff/1/a">diff</a></li>
530 530 <li><a href="/comparison/1/a">comparison</a></li>
531 531 <li><a href="/annotate/1/a">annotate</a></li>
532 532 <li class="active">file log</li>
533 533 <li><a href="/raw-file/1/a">raw</a></li>
534 534 </ul>
535 535 <ul>
536 536 <li><a href="/help">help</a></li>
537 537 </ul>
538 538 <div class="atom-logo">
539 539 <a href="/atom-log/tip/a" title="subscribe to atom feed">
540 540 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="atom feed" />
541 541 </a>
542 542 </div>
543 543 </div>
544 544
545 545 <div class="main">
546 546 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
547 547 <h3>
548 548 log a @ 1:<a href="/rev/5ed941583260">5ed941583260</a>
549 549 <span class="tag">a-tag</span> <span class="tag">a-bookmark</span>
550 550
551 551 </h3>
552 552
553 553 <form class="search" action="/log">
554 554
555 555 <p><input name="rev" id="search1" type="text" size="30" /></p>
556 556 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
557 557 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
558 558 </form>
559 559
560 560 <div class="navigate">
561 561 <a href="/log/1/a?revcount=30">less</a>
562 562 <a href="/log/1/a?revcount=120">more</a>
563 563 | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a> </div>
564 564
565 565 <table class="bigtable">
566 566 <thead>
567 567 <tr>
568 568 <th class="age">age</th>
569 569 <th class="author">author</th>
570 570 <th class="description">description</th>
571 571 </tr>
572 572 </thead>
573 573 <tbody class="stripes2">
574 574 <tr>
575 575 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
576 576 <td class="author">test</td>
577 577 <td class="description">
578 578 <a href="/rev/5ed941583260">first a</a>
579 579 <span class="tag">a-tag</span> <span class="tag">a-bookmark</span>
580 580 </td>
581 581 </tr>
582 582
583 583
584 584 </tbody>
585 585 </table>
586 586
587 587 <div class="navigate">
588 588 <a href="/log/1/a?revcount=30">less</a>
589 589 <a href="/log/1/a?revcount=120">more</a>
590 590 | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a>
591 591 </div>
592 592
593 593 </div>
594 594 </div>
595 595
596 596
597 597
598 598 </body>
599 599 </html>
600 600
601 601
602 602 before addition - error
603 603
604 604 $ (get-with-headers.py localhost:$HGPORT 'log/0/a')
605 605 404 Not Found
606 606
607 607 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
608 608 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
609 609 <head>
610 610 <link rel="icon" href="/static/hgicon.png" type="image/png" />
611 611 <meta name="robots" content="index, nofollow" />
612 612 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
613 613 <script type="text/javascript" src="/static/mercurial.js"></script>
614 614
615 615 <title>test: error</title>
616 616 </head>
617 617 <body>
618 618
619 619 <div class="container">
620 620 <div class="menu">
621 621 <div class="logo">
622 622 <a href="https://mercurial-scm.org/">
623 623 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
624 624 </div>
625 625 <ul>
626 626 <li><a href="/shortlog">log</a></li>
627 627 <li><a href="/graph">graph</a></li>
628 628 <li><a href="/tags">tags</a></li>
629 629 <li><a href="/bookmarks">bookmarks</a></li>
630 630 <li><a href="/branches">branches</a></li>
631 631 </ul>
632 632 <ul>
633 633 <li><a href="/help">help</a></li>
634 634 </ul>
635 635 </div>
636 636
637 637 <div class="main">
638 638
639 639 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
640 640 <h3>error</h3>
641 641
642 642 <form class="search" action="/log">
643 643
644 644 <p><input name="rev" id="search1" type="text" size="30"></p>
645 645 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
646 646 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
647 647 </form>
648 648
649 649 <div class="description">
650 650 <p>
651 651 An error occurred while processing your request:
652 652 </p>
653 653 <p>
654 654 a@6563da9dcf87: not found in manifest
655 655 </p>
656 656 </div>
657 657 </div>
658 658 </div>
659 659
660 660
661 661
662 662 </body>
663 663 </html>
664 664
665 665 [1]
666 666
667 667 $ hg log -r 'followlines(c, 1:2, startrev=tip) and follow(c)'
668 668 changeset: 0:6563da9dcf87
669 669 user: test
670 670 date: Thu Jan 01 00:00:00 1970 +0000
671 671 summary: b
672 672
673 673 changeset: 7:46c1a66bd8fc
674 674 branch: a-branch
675 675 tag: tip
676 676 user: test
677 677 date: Thu Jan 01 00:00:00 1970 +0000
678 678 summary: change c
679 679
680 680 $ (get-with-headers.py localhost:$HGPORT 'log/tip/c?linerange=1:2')
681 681 200 Script output follows
682 682
683 683 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
684 684 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
685 685 <head>
686 686 <link rel="icon" href="/static/hgicon.png" type="image/png" />
687 687 <meta name="robots" content="index, nofollow" />
688 688 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
689 689 <script type="text/javascript" src="/static/mercurial.js"></script>
690 690
691 691 <title>test: c history</title>
692 692 <link rel="alternate" type="application/atom+xml"
693 693 href="/atom-log/tip/c" title="Atom feed for test:c" />
694 694 <link rel="alternate" type="application/rss+xml"
695 695 href="/rss-log/tip/c" title="RSS feed for test:c" />
696 696 </head>
697 697 <body>
698 698
699 699 <div class="container">
700 700 <div class="menu">
701 701 <div class="logo">
702 702 <a href="https://mercurial-scm.org/">
703 703 <img src="/static/hglogo.png" alt="mercurial" /></a>
704 704 </div>
705 705 <ul>
706 706 <li><a href="/shortlog/tip">log</a></li>
707 707 <li><a href="/graph/tip">graph</a></li>
708 708 <li><a href="/tags">tags</a></li>
709 709 <li><a href="/bookmarks">bookmarks</a></li>
710 710 <li><a href="/branches">branches</a></li>
711 711 </ul>
712 712 <ul>
713 713 <li><a href="/rev/tip">changeset</a></li>
714 714 <li><a href="/file/tip">browse</a></li>
715 715 </ul>
716 716 <ul>
717 717 <li><a href="/file/tip/c">file</a></li>
718 718 <li><a href="/diff/tip/c">diff</a></li>
719 719 <li><a href="/comparison/tip/c">comparison</a></li>
720 720 <li><a href="/annotate/tip/c">annotate</a></li>
721 721 <li class="active">file log</li>
722 722 <li><a href="/raw-file/tip/c">raw</a></li>
723 723 </ul>
724 724 <ul>
725 725 <li><a href="/help">help</a></li>
726 726 </ul>
727 727 <div class="atom-logo">
728 728 <a href="/atom-log/tip/c" title="subscribe to atom feed">
729 729 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="atom feed" />
730 730 </a>
731 731 </div>
732 732 </div>
733 733
734 734 <div class="main">
735 735 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
736 736 <h3>
737 737 log c @ 7:<a href="/rev/46c1a66bd8fc">46c1a66bd8fc</a>
738 738 <span class="branchname">a-branch</span> <span class="tag">tip</span>
739 739 (following lines 1:2 <a href="/log/tip/c">back to filelog</a>)
740 740 </h3>
741 741
742 742 <form class="search" action="/log">
743 743
744 744 <p><input name="rev" id="search1" type="text" size="30" /></p>
745 745 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
746 746 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
747 747 </form>
748 748
749 749 <div class="navigate">
750 750 <a href="/log/tip/c?linerange=1%3A2&revcount=30">less</a>
751 751 <a href="/log/tip/c?linerange=1%3A2&revcount=120">more</a>
752 752 | </div>
753 753
754 754 <table class="bigtable">
755 755 <thead>
756 756 <tr>
757 757 <th class="age">age</th>
758 758 <th class="author">author</th>
759 759 <th class="description">description</th>
760 760 </tr>
761 761 </thead>
762 762 <tbody class="stripes2">
763 763 <tr>
764 764 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
765 765 <td class="author">test</td>
766 766 <td class="description">
767 767 <a href="/rev/46c1a66bd8fc">change c</a>
768 768 <span class="branchhead">a-branch</span> <span class="tag">tip</span>
769 769 </td>
770 770 </tr>
771 771
772 772 <tr>
773 773 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
774 774 <td class="author">test</td>
775 775 <td class="description">
776 776 <a href="/rev/6563da9dcf87">b</a>
777 777
778 778 </td>
779 779 </tr>
780 780
781 781
782 782 </tbody>
783 783 </table>
784 784
785 785 <div class="navigate">
786 786 <a href="/log/tip/c?linerange=1%3A2&revcount=30">less</a>
787 787 <a href="/log/tip/c?linerange=1%3A2&revcount=120">more</a>
788 788 |
789 789 </div>
790 790
791 791 </div>
792 792 </div>
793 793
794 794
795 795
796 796 </body>
797 797 </html>
798 798
799 799 $ (get-with-headers.py localhost:$HGPORT 'log/tip/c?linerange=1%3A2&revcount=1')
800 800 200 Script output follows
801 801
802 802 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
803 803 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
804 804 <head>
805 805 <link rel="icon" href="/static/hgicon.png" type="image/png" />
806 806 <meta name="robots" content="index, nofollow" />
807 807 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
808 808 <script type="text/javascript" src="/static/mercurial.js"></script>
809 809
810 810 <title>test: c history</title>
811 811 <link rel="alternate" type="application/atom+xml"
812 812 href="/atom-log/tip/c" title="Atom feed for test:c" />
813 813 <link rel="alternate" type="application/rss+xml"
814 814 href="/rss-log/tip/c" title="RSS feed for test:c" />
815 815 </head>
816 816 <body>
817 817
818 818 <div class="container">
819 819 <div class="menu">
820 820 <div class="logo">
821 821 <a href="https://mercurial-scm.org/">
822 822 <img src="/static/hglogo.png" alt="mercurial" /></a>
823 823 </div>
824 824 <ul>
825 825 <li><a href="/shortlog/tip?revcount=1">log</a></li>
826 826 <li><a href="/graph/tip?revcount=1">graph</a></li>
827 827 <li><a href="/tags?revcount=1">tags</a></li>
828 828 <li><a href="/bookmarks?revcount=1">bookmarks</a></li>
829 829 <li><a href="/branches?revcount=1">branches</a></li>
830 830 </ul>
831 831 <ul>
832 832 <li><a href="/rev/tip?revcount=1">changeset</a></li>
833 833 <li><a href="/file/tip?revcount=1">browse</a></li>
834 834 </ul>
835 835 <ul>
836 836 <li><a href="/file/tip/c?revcount=1">file</a></li>
837 837 <li><a href="/diff/tip/c?revcount=1">diff</a></li>
838 838 <li><a href="/comparison/tip/c?revcount=1">comparison</a></li>
839 839 <li><a href="/annotate/tip/c?revcount=1">annotate</a></li>
840 840 <li class="active">file log</li>
841 841 <li><a href="/raw-file/tip/c">raw</a></li>
842 842 </ul>
843 843 <ul>
844 844 <li><a href="/help?revcount=1">help</a></li>
845 845 </ul>
846 846 <div class="atom-logo">
847 847 <a href="/atom-log/tip/c" title="subscribe to atom feed">
848 848 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="atom feed" />
849 849 </a>
850 850 </div>
851 851 </div>
852 852
853 853 <div class="main">
854 854 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
855 855 <h3>
856 856 log c @ 7:<a href="/rev/46c1a66bd8fc?revcount=1">46c1a66bd8fc</a>
857 857 <span class="branchname">a-branch</span> <span class="tag">tip</span>
858 858 (following lines 1:2 <a href="/log/tip/c?revcount=1">back to filelog</a>)
859 859 </h3>
860 860
861 861 <form class="search" action="/log">
862 862 <input type="hidden" name="revcount" value="1" />
863 863 <p><input name="rev" id="search1" type="text" size="30" /></p>
864 864 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
865 865 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
866 866 </form>
867 867
868 868 <div class="navigate">
869 869 <a href="/log/tip/c?linerange=1%3A2&revcount=1">less</a>
870 870 <a href="/log/tip/c?linerange=1%3A2&revcount=2">more</a>
871 871 | </div>
872 872
873 873 <table class="bigtable">
874 874 <thead>
875 875 <tr>
876 876 <th class="age">age</th>
877 877 <th class="author">author</th>
878 878 <th class="description">description</th>
879 879 </tr>
880 880 </thead>
881 881 <tbody class="stripes2">
882 882 <tr>
883 883 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
884 884 <td class="author">test</td>
885 885 <td class="description">
886 886 <a href="/rev/46c1a66bd8fc?revcount=1">change c</a>
887 887 <span class="branchhead">a-branch</span> <span class="tag">tip</span>
888 888 </td>
889 889 </tr>
890 890
891 891
892 892 </tbody>
893 893 </table>
894 894
895 895 <div class="navigate">
896 896 <a href="/log/tip/c?linerange=1%3A2&revcount=1">less</a>
897 897 <a href="/log/tip/c?linerange=1%3A2&revcount=2">more</a>
898 898 |
899 899 </div>
900 900
901 901 </div>
902 902 </div>
903 903
904 904
905 905
906 906 </body>
907 907 </html>
908 908
909 909 $ (get-with-headers.py localhost:$HGPORT 'log/3/a?linerange=1' --headeronly)
910 910 400 invalid linerange parameter
911 911 [1]
912 912 $ (get-with-headers.py localhost:$HGPORT 'log/3/a?linerange=1:a' --headeronly)
913 913 400 invalid linerange parameter
914 914 [1]
915 915 $ (get-with-headers.py localhost:$HGPORT 'log/3/a?linerange=1:2&linerange=3:4' --headeronly)
916 916 400 redundant linerange parameter
917 917 [1]
918 918 $ (get-with-headers.py localhost:$HGPORT 'log/3/a?linerange=3:2' --headeronly)
919 919 400 line range must be positive
920 920 [1]
921 921 $ (get-with-headers.py localhost:$HGPORT 'log/3/a?linerange=0:1' --headeronly)
922 922 400 fromline must be strictly positive
923 923 [1]
924 924
925 925 should show base link, use spartan because it shows it
926 926
927 927 $ (get-with-headers.py localhost:$HGPORT 'log/tip/c?style=spartan')
928 928 200 Script output follows
929 929
930 930 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
931 931 <html>
932 932 <head>
933 933 <link rel="icon" href="/static/hgicon.png" type="image/png">
934 934 <meta name="robots" content="index, nofollow" />
935 935 <link rel="stylesheet" href="/static/style.css" type="text/css" />
936 936 <script type="text/javascript" src="/static/mercurial.js"></script>
937 937
938 938 <title>test: c history</title>
939 939 <link rel="alternate" type="application/atom+xml"
940 940 href="/atom-log/tip/c" title="Atom feed for test:c">
941 941 <link rel="alternate" type="application/rss+xml"
942 942 href="/rss-log/tip/c" title="RSS feed for test:c">
943 943 </head>
944 944 <body>
945 945
946 946 <div class="buttons">
947 947 <a href="/log?style=spartan">changelog</a>
948 948 <a href="/shortlog?style=spartan">shortlog</a>
949 949 <a href="/graph?style=spartan">graph</a>
950 950 <a href="/tags?style=spartan">tags</a>
951 951 <a href="/branches?style=spartan">branches</a>
952 952 <a href="/file/tip/c?style=spartan">file</a>
953 953 <a href="/annotate/tip/c?style=spartan">annotate</a>
954 954 <a href="/help?style=spartan">help</a>
955 955 <a type="application/rss+xml" href="/rss-log/tip/c">rss</a>
956 956 <a type="application/atom+xml" href="/atom-log/tip/c" title="Atom feed for test:c">atom</a>
957 957 </div>
958 958
959 959 <h2><a href="/">Mercurial</a> / c revision history</h2>
960 960
961 961 <p>navigate: <small class="navigate"><a href="/log/c9637d3cc8ef/c?style=spartan">(0)</a> <a href="/log/tip/c?style=spartan">tip</a> </small></p>
962 962
963 963 <table class="logEntry parity0">
964 964 <tr>
965 965 <th class="label"><span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span>:</th>
966 966 <th class="firstline"><a href="/rev/46c1a66bd8fc?style=spartan">change c</a></th>
967 967 </tr>
968 968 <tr>
969 969 <th class="revision">revision 1:</th>
970 970 <td class="node">
971 971 <a href="/file/46c1a66bd8fc/c?style=spartan">46c1a66bd8fc</a>
972 972 <a href="/diff/46c1a66bd8fc/c?style=spartan">(diff)</a>
973 973 <a href="/annotate/46c1a66bd8fc/c?style=spartan">(annotate)</a>
974 974 </td>
975 975 </tr>
976 976
977 977 <tr>
978 978 <th class="author">author:</th>
979 979 <td class="author">&#116;&#101;&#115;&#116;</td>
980 980 </tr>
981 981 <tr>
982 982 <th class="date">date:</th>
983 983 <td class="date">Thu, 01 Jan 1970 00:00:00 +0000</td>
984 984 </tr>
985 985 </table>
986 986
987 987
988 988 <table class="logEntry parity1">
989 989 <tr>
990 990 <th class="label"><span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span>:</th>
991 991 <th class="firstline"><a href="/rev/c9637d3cc8ef?style=spartan">mv b</a></th>
992 992 </tr>
993 993 <tr>
994 994 <th class="revision">revision 0:</th>
995 995 <td class="node">
996 996 <a href="/file/c9637d3cc8ef/c?style=spartan">c9637d3cc8ef</a>
997 997 <a href="/diff/c9637d3cc8ef/c?style=spartan">(diff)</a>
998 998 <a href="/annotate/c9637d3cc8ef/c?style=spartan">(annotate)</a>
999 999 </td>
1000 1000 </tr>
1001 1001
1002 1002 <tr>
1003 1003 <th>base:</th>
1004 1004 <td>
1005 1005 <a href="/file/1e88685f5dde/b?style=spartan">
1006 1006 b@1e88685f5dde
1007 1007 </a>
1008 1008 </td>
1009 1009 </tr>
1010 1010 <tr>
1011 1011 <th class="author">author:</th>
1012 1012 <td class="author">&#116;&#101;&#115;&#116;</td>
1013 1013 </tr>
1014 1014 <tr>
1015 1015 <th class="date">date:</th>
1016 1016 <td class="date">Thu, 01 Jan 1970 00:00:00 +0000</td>
1017 1017 </tr>
1018 1018 </table>
1019 1019
1020 1020
1021 1021
1022 1022
1023 1023
1024 1024 <div class="logo">
1025 1025 <a href="https://mercurial-scm.org/">
1026 1026 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
1027 1027 </div>
1028 1028
1029 1029 </body>
1030 1030 </html>
1031 1031
1032 1032
1033 1033 filelog with patch
1034 1034
1035 1035 $ (get-with-headers.py localhost:$HGPORT 'log/4/a?patch=1')
1036 1036 200 Script output follows
1037 1037
1038 1038 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
1039 1039 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
1040 1040 <head>
1041 1041 <link rel="icon" href="/static/hgicon.png" type="image/png" />
1042 1042 <meta name="robots" content="index, nofollow" />
1043 1043 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
1044 1044 <script type="text/javascript" src="/static/mercurial.js"></script>
1045 1045
1046 1046 <title>test: a history</title>
1047 1047 <link rel="alternate" type="application/atom+xml"
1048 1048 href="/atom-log/tip/a" title="Atom feed for test:a" />
1049 1049 <link rel="alternate" type="application/rss+xml"
1050 1050 href="/rss-log/tip/a" title="RSS feed for test:a" />
1051 1051 </head>
1052 1052 <body>
1053 1053
1054 1054 <div class="container">
1055 1055 <div class="menu">
1056 1056 <div class="logo">
1057 1057 <a href="https://mercurial-scm.org/">
1058 1058 <img src="/static/hglogo.png" alt="mercurial" /></a>
1059 1059 </div>
1060 1060 <ul>
1061 1061 <li><a href="/shortlog/4">log</a></li>
1062 1062 <li><a href="/graph/4">graph</a></li>
1063 1063 <li><a href="/tags">tags</a></li>
1064 1064 <li><a href="/bookmarks">bookmarks</a></li>
1065 1065 <li><a href="/branches">branches</a></li>
1066 1066 </ul>
1067 1067 <ul>
1068 1068 <li><a href="/rev/4">changeset</a></li>
1069 1069 <li><a href="/file/4">browse</a></li>
1070 1070 </ul>
1071 1071 <ul>
1072 1072 <li><a href="/file/4/a">file</a></li>
1073 1073 <li><a href="/diff/4/a">diff</a></li>
1074 1074 <li><a href="/comparison/4/a">comparison</a></li>
1075 1075 <li><a href="/annotate/4/a">annotate</a></li>
1076 1076 <li class="active">file log</li>
1077 1077 <li><a href="/raw-file/4/a">raw</a></li>
1078 1078 </ul>
1079 1079 <ul>
1080 1080 <li><a href="/help">help</a></li>
1081 1081 </ul>
1082 1082 <div class="atom-logo">
1083 1083 <a href="/atom-log/tip/a" title="subscribe to atom feed">
1084 1084 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="atom feed" />
1085 1085 </a>
1086 1086 </div>
1087 1087 </div>
1088 1088
1089 1089 <div class="main">
1090 1090 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
1091 1091 <h3>
1092 1092 log a @ 4:<a href="/rev/3f41bc784e7e">3f41bc784e7e</a>
1093 1093 <span class="branchname">a-branch</span>
1094 1094
1095 1095 </h3>
1096 1096
1097 1097 <form class="search" action="/log">
1098 1098
1099 1099 <p><input name="rev" id="search1" type="text" size="30" /></p>
1100 1100 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
1101 1101 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
1102 1102 </form>
1103 1103
1104 1104 <div class="navigate">
1105 1105 <a href="/log/4/a?patch=1&revcount=30">less</a>
1106 1106 <a href="/log/4/a?patch=1&revcount=120">more</a>
1107 1107 | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a> </div>
1108 1108
1109 1109 <table class="bigtable">
1110 1110 <thead>
1111 1111 <tr>
1112 1112 <th class="age">age</th>
1113 1113 <th class="author">author</th>
1114 1114 <th class="description">description</th>
1115 1115 </tr>
1116 1116 </thead>
1117 1117 <tbody class="stripes2">
1118 1118 <tr>
1119 1119 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1120 1120 <td class="author">test</td>
1121 1121 <td class="description">
1122 1122 <a href="/rev/3f41bc784e7e">second a</a>
1123 1123 <span class="branchname">a-branch</span>
1124 1124 </td>
1125 1125 </tr>
1126 1126 <tr><td colspan="3"><div class="bottomline inc-lineno"><pre class="sourcelines wrap">
1127 1127 <span id="3f41bc784e7e-l1.1" class="minusline">--- /dev/null Thu Jan 01 00:00:00 1970 +0000</span><a href="#3f41bc784e7e-l1.1"></a>
1128 1128 <span id="3f41bc784e7e-l1.2" class="plusline">+++ b/a Thu Jan 01 00:00:00 1970 +0000</span><a href="#3f41bc784e7e-l1.2"></a>
1129 1129 <span id="3f41bc784e7e-l1.3" class="atline">@@ -0,0 +1,1 @@</span><a href="#3f41bc784e7e-l1.3"></a>
1130 1130 <span id="3f41bc784e7e-l1.4" class="plusline">+b</span><a href="#3f41bc784e7e-l1.4"></a></pre></div></td></tr>
1131 1131 <tr>
1132 1132 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1133 1133 <td class="author">test</td>
1134 1134 <td class="description">
1135 1135 <a href="/rev/5ed941583260">first a</a>
1136 1136 <span class="tag">a-tag</span> <span class="tag">a-bookmark</span>
1137 1137 </td>
1138 1138 </tr>
1139 1139 <tr><td colspan="3"><div class="bottomline inc-lineno"><pre class="sourcelines wrap">
1140 1140 <span id="5ed941583260-l1.1" class="minusline">--- /dev/null Thu Jan 01 00:00:00 1970 +0000</span><a href="#5ed941583260-l1.1"></a>
1141 1141 <span id="5ed941583260-l1.2" class="plusline">+++ b/a Thu Jan 01 00:00:00 1970 +0000</span><a href="#5ed941583260-l1.2"></a>
1142 1142 <span id="5ed941583260-l1.3" class="atline">@@ -0,0 +1,1 @@</span><a href="#5ed941583260-l1.3"></a>
1143 1143 <span id="5ed941583260-l1.4" class="plusline">+a</span><a href="#5ed941583260-l1.4"></a></pre></div></td></tr>
1144 1144
1145 1145 </tbody>
1146 1146 </table>
1147 1147
1148 1148 <div class="navigate">
1149 1149 <a href="/log/4/a?patch=1&revcount=30">less</a>
1150 1150 <a href="/log/4/a?patch=1&revcount=120">more</a>
1151 1151 | <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a>
1152 1152 </div>
1153 1153
1154 1154 </div>
1155 1155 </div>
1156 1156
1157 1157
1158 1158
1159 1159 </body>
1160 1160 </html>
1161 1161
1162 1162 filelog with 'linerange' and 'patch'
1163 1163
1164 1164 $ cat c
1165 1165 b
1166 1166 c
1167 1167 $ cat <<EOF > c
1168 1168 > 0
1169 1169 > 0
1170 1170 > b
1171 1171 > c+
1172 1172 >
1173 1173 > a
1174 1174 > a
1175 1175 >
1176 1176 > d
1177 1177 > e
1178 1178 > f
1179 1179 > EOF
1180 1180 $ hg ci -m 'make c bigger and touch its beginning' c
1181 1181 $ cat <<EOF > c
1182 1182 > 0
1183 1183 > 0
1184 1184 > b
1185 1185 > c+
1186 1186 >
1187 1187 > a
1188 1188 > a
1189 1189 >
1190 1190 > d
1191 1191 > e+
1192 1192 > f
1193 1193 > EOF
1194 1194 $ hg ci -m 'just touch end of c' c
1195 1195 $ cat <<EOF > c
1196 1196 > 0
1197 1197 > 0
1198 1198 > b
1199 1199 > c++
1200 1200 >
1201 1201 > a
1202 1202 > a
1203 1203 >
1204 1204 > d
1205 1205 > e+
1206 1206 > f
1207 1207 > EOF
1208 1208 $ hg ci -m 'touch beginning of c' c
1209 1209 $ cat <<EOF > c
1210 1210 > 0
1211 1211 > 0
1212 1212 > b-
1213 1213 > c++
1214 1214 >
1215 1215 > a
1216 1216 > a
1217 1217 >
1218 1218 > d
1219 1219 > e+
1220 1220 > f+
1221 1221 > EOF
1222 1222 $ hg ci -m 'touching beginning and end of c' c
1223 1223 $ hg log -r 'followlines(c, 3:4, startrev=tip) and follow(c)' -p
1224 1224 changeset: 0:6563da9dcf87
1225 1225 user: test
1226 1226 date: Thu Jan 01 00:00:00 1970 +0000
1227 1227 summary: b
1228 1228
1229 1229 diff -r 000000000000 -r 6563da9dcf87 b
1230 1230 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1231 1231 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1232 1232 @@ -0,0 +1,1 @@
1233 1233 +b
1234 1234
1235 1235 changeset: 7:46c1a66bd8fc
1236 1236 branch: a-branch
1237 1237 user: test
1238 1238 date: Thu Jan 01 00:00:00 1970 +0000
1239 1239 summary: change c
1240 1240
1241 1241 diff -r c9637d3cc8ef -r 46c1a66bd8fc c
1242 1242 --- a/c Thu Jan 01 00:00:00 1970 +0000
1243 1243 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1244 1244 @@ -1,1 +1,2 @@
1245 1245 b
1246 1246 +c
1247 1247
1248 1248 changeset: 8:5c6574614c37
1249 1249 branch: a-branch
1250 1250 user: test
1251 1251 date: Thu Jan 01 00:00:00 1970 +0000
1252 1252 summary: make c bigger and touch its beginning
1253 1253
1254 1254 diff -r 46c1a66bd8fc -r 5c6574614c37 c
1255 1255 --- a/c Thu Jan 01 00:00:00 1970 +0000
1256 1256 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1257 1257 @@ -1,2 +1,11 @@
1258 1258 +0
1259 1259 +0
1260 1260 b
1261 1261 -c
1262 1262 +c+
1263 1263 +
1264 1264 +a
1265 1265 +a
1266 1266 +
1267 1267 +d
1268 1268 +e
1269 1269 +f
1270 1270
1271 1271 changeset: 10:e95928d60479
1272 1272 branch: a-branch
1273 1273 user: test
1274 1274 date: Thu Jan 01 00:00:00 1970 +0000
1275 1275 summary: touch beginning of c
1276 1276
1277 1277 diff -r e1d3e9c5a23f -r e95928d60479 c
1278 1278 --- a/c Thu Jan 01 00:00:00 1970 +0000
1279 1279 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1280 1280 @@ -1,7 +1,7 @@
1281 1281 0
1282 1282 0
1283 1283 b
1284 1284 -c+
1285 1285 +c++
1286 1286
1287 1287 a
1288 1288 a
1289 1289
1290 1290 changeset: 11:fb9bc322513a
1291 1291 branch: a-branch
1292 1292 tag: tip
1293 1293 user: test
1294 1294 date: Thu Jan 01 00:00:00 1970 +0000
1295 1295 summary: touching beginning and end of c
1296 1296
1297 1297 diff -r e95928d60479 -r fb9bc322513a c
1298 1298 --- a/c Thu Jan 01 00:00:00 1970 +0000
1299 1299 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1300 1300 @@ -1,6 +1,6 @@
1301 1301 0
1302 1302 0
1303 1303 -b
1304 1304 +b-
1305 1305 c++
1306 1306
1307 1307 a
1308 1308 @@ -8,4 +8,4 @@
1309 1309
1310 1310 d
1311 1311 e+
1312 1312 -f
1313 1313 +f+
1314 1314
1315 1315 $ (get-with-headers.py localhost:$HGPORT 'log/tip/c?linerange=3:4&patch=')
1316 1316 200 Script output follows
1317 1317
1318 1318 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
1319 1319 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
1320 1320 <head>
1321 1321 <link rel="icon" href="/static/hgicon.png" type="image/png" />
1322 1322 <meta name="robots" content="index, nofollow" />
1323 1323 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
1324 1324 <script type="text/javascript" src="/static/mercurial.js"></script>
1325 1325
1326 1326 <title>test: c history</title>
1327 1327 <link rel="alternate" type="application/atom+xml"
1328 1328 href="/atom-log/tip/c" title="Atom feed for test:c" />
1329 1329 <link rel="alternate" type="application/rss+xml"
1330 1330 href="/rss-log/tip/c" title="RSS feed for test:c" />
1331 1331 </head>
1332 1332 <body>
1333 1333
1334 1334 <div class="container">
1335 1335 <div class="menu">
1336 1336 <div class="logo">
1337 1337 <a href="https://mercurial-scm.org/">
1338 1338 <img src="/static/hglogo.png" alt="mercurial" /></a>
1339 1339 </div>
1340 1340 <ul>
1341 1341 <li><a href="/shortlog/tip">log</a></li>
1342 1342 <li><a href="/graph/tip">graph</a></li>
1343 1343 <li><a href="/tags">tags</a></li>
1344 1344 <li><a href="/bookmarks">bookmarks</a></li>
1345 1345 <li><a href="/branches">branches</a></li>
1346 1346 </ul>
1347 1347 <ul>
1348 1348 <li><a href="/rev/tip">changeset</a></li>
1349 1349 <li><a href="/file/tip">browse</a></li>
1350 1350 </ul>
1351 1351 <ul>
1352 1352 <li><a href="/file/tip/c">file</a></li>
1353 1353 <li><a href="/diff/tip/c">diff</a></li>
1354 1354 <li><a href="/comparison/tip/c">comparison</a></li>
1355 1355 <li><a href="/annotate/tip/c">annotate</a></li>
1356 1356 <li class="active">file log</li>
1357 1357 <li><a href="/raw-file/tip/c">raw</a></li>
1358 1358 </ul>
1359 1359 <ul>
1360 1360 <li><a href="/help">help</a></li>
1361 1361 </ul>
1362 1362 <div class="atom-logo">
1363 1363 <a href="/atom-log/tip/c" title="subscribe to atom feed">
1364 1364 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="atom feed" />
1365 1365 </a>
1366 1366 </div>
1367 1367 </div>
1368 1368
1369 1369 <div class="main">
1370 1370 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
1371 1371 <h3>
1372 1372 log c @ 11:<a href="/rev/fb9bc322513a">fb9bc322513a</a>
1373 1373 <span class="branchname">a-branch</span> <span class="tag">tip</span>
1374 1374 (following lines 3:4 <a href="/log/tip/c">back to filelog</a>)
1375 1375 </h3>
1376 1376
1377 1377 <form class="search" action="/log">
1378 1378
1379 1379 <p><input name="rev" id="search1" type="text" size="30" /></p>
1380 1380 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
1381 1381 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
1382 1382 </form>
1383 1383
1384 1384 <div class="navigate">
1385 1385 <a href="/log/tip/c?linerange=3%3A4&patch=&revcount=30">less</a>
1386 1386 <a href="/log/tip/c?linerange=3%3A4&patch=&revcount=120">more</a>
1387 1387 | </div>
1388 1388
1389 1389 <table class="bigtable">
1390 1390 <thead>
1391 1391 <tr>
1392 1392 <th class="age">age</th>
1393 1393 <th class="author">author</th>
1394 1394 <th class="description">description</th>
1395 1395 </tr>
1396 1396 </thead>
1397 1397 <tbody class="stripes2">
1398 1398 <tr>
1399 1399 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1400 1400 <td class="author">test</td>
1401 1401 <td class="description">
1402 1402 <a href="/rev/fb9bc322513a">touching beginning and end of c</a>
1403 1403 <span class="branchhead">a-branch</span> <span class="tag">tip</span>
1404 1404 </td>
1405 1405 </tr>
1406 1406 <tr><td colspan="3"><div class="bottomline inc-lineno"><pre class="sourcelines wrap">
1407 1407 <span id="fb9bc322513a-l1.1" class="minusline">--- a/c Thu Jan 01 00:00:00 1970 +0000</span><a href="#fb9bc322513a-l1.1"></a>
1408 1408 <span id="fb9bc322513a-l1.2" class="plusline">+++ b/c Thu Jan 01 00:00:00 1970 +0000</span><a href="#fb9bc322513a-l1.2"></a>
1409 1409 <span id="fb9bc322513a-l1.3" class="atline">@@ -1,6 +1,6 @@</span><a href="#fb9bc322513a-l1.3"></a>
1410 1410 <span id="fb9bc322513a-l1.4"> 0</span><a href="#fb9bc322513a-l1.4"></a>
1411 1411 <span id="fb9bc322513a-l1.5"> 0</span><a href="#fb9bc322513a-l1.5"></a>
1412 1412 <span id="fb9bc322513a-l1.6" class="minusline">-b</span><a href="#fb9bc322513a-l1.6"></a>
1413 1413 <span id="fb9bc322513a-l1.7" class="plusline">+b-</span><a href="#fb9bc322513a-l1.7"></a>
1414 1414 <span id="fb9bc322513a-l1.8"> c++</span><a href="#fb9bc322513a-l1.8"></a>
1415 1415 <span id="fb9bc322513a-l1.9"> </span><a href="#fb9bc322513a-l1.9"></a>
1416 1416 <span id="fb9bc322513a-l1.10"> a</span><a href="#fb9bc322513a-l1.10"></a></pre></div></td></tr>
1417 1417 <tr>
1418 1418 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1419 1419 <td class="author">test</td>
1420 1420 <td class="description">
1421 1421 <a href="/rev/e95928d60479">touch beginning of c</a>
1422 1422 <span class="branchname">a-branch</span>
1423 1423 </td>
1424 1424 </tr>
1425 1425 <tr><td colspan="3"><div class="bottomline inc-lineno"><pre class="sourcelines wrap">
1426 1426 <span id="e95928d60479-l1.1" class="minusline">--- a/c Thu Jan 01 00:00:00 1970 +0000</span><a href="#e95928d60479-l1.1"></a>
1427 1427 <span id="e95928d60479-l1.2" class="plusline">+++ b/c Thu Jan 01 00:00:00 1970 +0000</span><a href="#e95928d60479-l1.2"></a>
1428 1428 <span id="e95928d60479-l1.3" class="atline">@@ -1,7 +1,7 @@</span><a href="#e95928d60479-l1.3"></a>
1429 1429 <span id="e95928d60479-l1.4"> 0</span><a href="#e95928d60479-l1.4"></a>
1430 1430 <span id="e95928d60479-l1.5"> 0</span><a href="#e95928d60479-l1.5"></a>
1431 1431 <span id="e95928d60479-l1.6"> b</span><a href="#e95928d60479-l1.6"></a>
1432 1432 <span id="e95928d60479-l1.7" class="minusline">-c+</span><a href="#e95928d60479-l1.7"></a>
1433 1433 <span id="e95928d60479-l1.8" class="plusline">+c++</span><a href="#e95928d60479-l1.8"></a>
1434 1434 <span id="e95928d60479-l1.9"> </span><a href="#e95928d60479-l1.9"></a>
1435 1435 <span id="e95928d60479-l1.10"> a</span><a href="#e95928d60479-l1.10"></a>
1436 1436 <span id="e95928d60479-l1.11"> a</span><a href="#e95928d60479-l1.11"></a></pre></div></td></tr>
1437 1437 <tr>
1438 1438 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1439 1439 <td class="author">test</td>
1440 1440 <td class="description">
1441 1441 <a href="/rev/5c6574614c37">make c bigger and touch its beginning</a>
1442 1442 <span class="branchname">a-branch</span>
1443 1443 </td>
1444 1444 </tr>
1445 1445 <tr><td colspan="3"><div class="bottomline inc-lineno"><pre class="sourcelines wrap">
1446 1446 <span id="5c6574614c37-l1.1" class="minusline">--- a/c Thu Jan 01 00:00:00 1970 +0000</span><a href="#5c6574614c37-l1.1"></a>
1447 1447 <span id="5c6574614c37-l1.2" class="plusline">+++ b/c Thu Jan 01 00:00:00 1970 +0000</span><a href="#5c6574614c37-l1.2"></a>
1448 1448 <span id="5c6574614c37-l1.3" class="atline">@@ -1,2 +1,11 @@</span><a href="#5c6574614c37-l1.3"></a>
1449 1449 <span id="5c6574614c37-l1.4" class="plusline">+0</span><a href="#5c6574614c37-l1.4"></a>
1450 1450 <span id="5c6574614c37-l1.5" class="plusline">+0</span><a href="#5c6574614c37-l1.5"></a>
1451 1451 <span id="5c6574614c37-l1.6"> b</span><a href="#5c6574614c37-l1.6"></a>
1452 1452 <span id="5c6574614c37-l1.7" class="minusline">-c</span><a href="#5c6574614c37-l1.7"></a>
1453 1453 <span id="5c6574614c37-l1.8" class="plusline">+c+</span><a href="#5c6574614c37-l1.8"></a>
1454 1454 <span id="5c6574614c37-l1.9" class="plusline">+</span><a href="#5c6574614c37-l1.9"></a>
1455 1455 <span id="5c6574614c37-l1.10" class="plusline">+a</span><a href="#5c6574614c37-l1.10"></a>
1456 1456 <span id="5c6574614c37-l1.11" class="plusline">+a</span><a href="#5c6574614c37-l1.11"></a>
1457 1457 <span id="5c6574614c37-l1.12" class="plusline">+</span><a href="#5c6574614c37-l1.12"></a>
1458 1458 <span id="5c6574614c37-l1.13" class="plusline">+d</span><a href="#5c6574614c37-l1.13"></a>
1459 1459 <span id="5c6574614c37-l1.14" class="plusline">+e</span><a href="#5c6574614c37-l1.14"></a>
1460 1460 <span id="5c6574614c37-l1.15" class="plusline">+f</span><a href="#5c6574614c37-l1.15"></a></pre></div></td></tr>
1461 1461 <tr>
1462 1462 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1463 1463 <td class="author">test</td>
1464 1464 <td class="description">
1465 1465 <a href="/rev/46c1a66bd8fc">change c</a>
1466 1466 <span class="branchname">a-branch</span>
1467 1467 </td>
1468 1468 </tr>
1469 1469 <tr><td colspan="3"><div class="bottomline inc-lineno"><pre class="sourcelines wrap">
1470 1470 <span id="46c1a66bd8fc-l1.1" class="minusline">--- a/c Thu Jan 01 00:00:00 1970 +0000</span><a href="#46c1a66bd8fc-l1.1"></a>
1471 1471 <span id="46c1a66bd8fc-l1.2" class="plusline">+++ b/c Thu Jan 01 00:00:00 1970 +0000</span><a href="#46c1a66bd8fc-l1.2"></a>
1472 1472 <span id="46c1a66bd8fc-l1.3" class="atline">@@ -1,1 +1,2 @@</span><a href="#46c1a66bd8fc-l1.3"></a>
1473 1473 <span id="46c1a66bd8fc-l1.4"> b</span><a href="#46c1a66bd8fc-l1.4"></a>
1474 1474 <span id="46c1a66bd8fc-l1.5" class="plusline">+c</span><a href="#46c1a66bd8fc-l1.5"></a></pre></div></td></tr>
1475 1475 <tr>
1476 1476 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1477 1477 <td class="author">test</td>
1478 1478 <td class="description">
1479 1479 <a href="/rev/6563da9dcf87">b</a>
1480 1480
1481 1481 </td>
1482 1482 </tr>
1483 1483 <tr><td colspan="3"><div class="bottomline inc-lineno"><pre class="sourcelines wrap">
1484 1484 <span id="6563da9dcf87-l1.1" class="minusline">--- /dev/null Thu Jan 01 00:00:00 1970 +0000</span><a href="#6563da9dcf87-l1.1"></a>
1485 1485 <span id="6563da9dcf87-l1.2" class="plusline">+++ b/b Thu Jan 01 00:00:00 1970 +0000</span><a href="#6563da9dcf87-l1.2"></a></pre></div></td></tr>
1486 1486
1487 1487 </tbody>
1488 1488 </table>
1489 1489
1490 1490 <div class="navigate">
1491 1491 <a href="/log/tip/c?linerange=3%3A4&patch=&revcount=30">less</a>
1492 1492 <a href="/log/tip/c?linerange=3%3A4&patch=&revcount=120">more</a>
1493 1493 |
1494 1494 </div>
1495 1495
1496 1496 </div>
1497 1497 </div>
1498 1498
1499 1499
1500 1500
1501 1501 </body>
1502 1502 </html>
1503 1503
1504 $ hg log -r 'followlines(c, 3:4, startrev=8, descend=True) and follow(c)' -p
1505 changeset: 10:e95928d60479
1506 branch: a-branch
1507 user: test
1508 date: Thu Jan 01 00:00:00 1970 +0000
1509 summary: touch beginning of c
1510
1511 diff -r e1d3e9c5a23f -r e95928d60479 c
1512 --- a/c Thu Jan 01 00:00:00 1970 +0000
1513 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1514 @@ -1,7 +1,7 @@
1515 0
1516 0
1517 b
1518 -c+
1519 +c++
1520
1521 a
1522 a
1523
1524 changeset: 11:fb9bc322513a
1525 branch: a-branch
1526 tag: tip
1527 user: test
1528 date: Thu Jan 01 00:00:00 1970 +0000
1529 summary: touching beginning and end of c
1530
1531 diff -r e95928d60479 -r fb9bc322513a c
1532 --- a/c Thu Jan 01 00:00:00 1970 +0000
1533 +++ b/c Thu Jan 01 00:00:00 1970 +0000
1534 @@ -1,6 +1,6 @@
1535 0
1536 0
1537 -b
1538 +b-
1539 c++
1540
1541 a
1542 @@ -8,4 +8,4 @@
1543
1544 d
1545 e+
1546 -f
1547 +f+
1548
1549 $ (get-with-headers.py localhost:$HGPORT 'log/8/c?linerange=3:4&descend=')
1550 200 Script output follows
1551
1552 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
1553 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
1554 <head>
1555 <link rel="icon" href="/static/hgicon.png" type="image/png" />
1556 <meta name="robots" content="index, nofollow" />
1557 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
1558 <script type="text/javascript" src="/static/mercurial.js"></script>
1559
1560 <title>test: c history</title>
1561 <link rel="alternate" type="application/atom+xml"
1562 href="/atom-log/tip/c" title="Atom feed for test:c" />
1563 <link rel="alternate" type="application/rss+xml"
1564 href="/rss-log/tip/c" title="RSS feed for test:c" />
1565 </head>
1566 <body>
1567
1568 <div class="container">
1569 <div class="menu">
1570 <div class="logo">
1571 <a href="https://mercurial-scm.org/">
1572 <img src="/static/hglogo.png" alt="mercurial" /></a>
1573 </div>
1574 <ul>
1575 <li><a href="/shortlog/8">log</a></li>
1576 <li><a href="/graph/8">graph</a></li>
1577 <li><a href="/tags">tags</a></li>
1578 <li><a href="/bookmarks">bookmarks</a></li>
1579 <li><a href="/branches">branches</a></li>
1580 </ul>
1581 <ul>
1582 <li><a href="/rev/8">changeset</a></li>
1583 <li><a href="/file/8">browse</a></li>
1584 </ul>
1585 <ul>
1586 <li><a href="/file/8/c">file</a></li>
1587 <li><a href="/diff/8/c">diff</a></li>
1588 <li><a href="/comparison/8/c">comparison</a></li>
1589 <li><a href="/annotate/8/c">annotate</a></li>
1590 <li class="active">file log</li>
1591 <li><a href="/raw-file/8/c">raw</a></li>
1592 </ul>
1593 <ul>
1594 <li><a href="/help">help</a></li>
1595 </ul>
1596 <div class="atom-logo">
1597 <a href="/atom-log/tip/c" title="subscribe to atom feed">
1598 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="atom feed" />
1599 </a>
1600 </div>
1601 </div>
1602
1603 <div class="main">
1604 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
1605 <h3>
1606 log c @ 8:<a href="/rev/5c6574614c37">5c6574614c37</a>
1607 <span class="branchname">a-branch</span>
1608 (following lines 3:4, descending <a href="/log/8/c">back to filelog</a>)
1609 </h3>
1610
1611 <form class="search" action="/log">
1612
1613 <p><input name="rev" id="search1" type="text" size="30" /></p>
1614 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
1615 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
1616 </form>
1617
1618 <div class="navigate">
1619 <a href="/log/8/c?descend=&linerange=3%3A4&revcount=30">less</a>
1620 <a href="/log/8/c?descend=&linerange=3%3A4&revcount=120">more</a>
1621 | </div>
1622
1623 <table class="bigtable">
1624 <thead>
1625 <tr>
1626 <th class="age">age</th>
1627 <th class="author">author</th>
1628 <th class="description">description</th>
1629 </tr>
1630 </thead>
1631 <tbody class="stripes2">
1632 <tr>
1633 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1634 <td class="author">test</td>
1635 <td class="description">
1636 <a href="/rev/e95928d60479">touch beginning of c</a>
1637 <span class="branchname">a-branch</span>
1638 </td>
1639 </tr>
1640
1641 <tr>
1642 <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1643 <td class="author">test</td>
1644 <td class="description">
1645 <a href="/rev/fb9bc322513a">touching beginning and end of c</a>
1646 <span class="branchhead">a-branch</span> <span class="tag">tip</span>
1647 </td>
1648 </tr>
1649
1650
1651 </tbody>
1652 </table>
1653
1654 <div class="navigate">
1655 <a href="/log/8/c?descend=&linerange=3%3A4&revcount=30">less</a>
1656 <a href="/log/8/c?descend=&linerange=3%3A4&revcount=120">more</a>
1657 |
1658 </div>
1659
1660 </div>
1661 </div>
1662
1663
1664
1665 </body>
1666 </html>
1667
1504 1668
1505 1669 rss log
1506 1670
1507 1671 $ (get-with-headers.py localhost:$HGPORT 'rss-log/tip/a')
1508 1672 200 Script output follows
1509 1673
1510 1674 <?xml version="1.0" encoding="ascii"?>
1511 1675 <rss version="2.0">
1512 1676 <channel>
1513 1677 <link>http://*:$HGPORT/</link> (glob)
1514 1678 <language>en-us</language>
1515 1679
1516 1680 <title>test: a history</title>
1517 1681 <description>a revision history</description>
1518 1682 <item>
1519 1683 <title>second a</title>
1520 1684 <link>http://*:$HGPORT/log/3f41bc784e7e/a</link> (glob)
1521 1685 <description><![CDATA[second a]]></description>
1522 1686 <author>&#116;&#101;&#115;&#116;</author>
1523 1687 <pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate>
1524 1688 </item>
1525 1689 <item>
1526 1690 <title>first a</title>
1527 1691 <link>http://*:$HGPORT/log/5ed941583260/a</link> (glob)
1528 1692 <description><![CDATA[first a]]></description>
1529 1693 <author>&#116;&#101;&#115;&#116;</author>
1530 1694 <pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate>
1531 1695 </item>
1532 1696
1533 1697 </channel>
1534 1698 </rss>
1535 1699
1536 1700 atom log
1537 1701
1538 1702 $ (get-with-headers.py localhost:$HGPORT 'atom-log/tip/a')
1539 1703 200 Script output follows
1540 1704
1541 1705 <?xml version="1.0" encoding="ascii"?>
1542 1706 <feed xmlns="http://www.w3.org/2005/Atom">
1543 1707 <id>http://*:$HGPORT/atom-log/tip/a</id> (glob)
1544 1708 <link rel="self" href="http://*:$HGPORT/atom-log/tip/a"/> (glob)
1545 1709 <title>test: a history</title>
1546 1710 <updated>1970-01-01T00:00:00+00:00</updated>
1547 1711
1548 1712 <entry>
1549 1713 <title>[a-branch] second a</title>
1550 1714 <id>http://*:$HGPORT/#changeset-3f41bc784e7e73035c6d47112c6cc7efb673adf8</id> (glob)
1551 1715 <link href="http://*:$HGPORT/rev/3f41bc784e7e"/> (glob)
1552 1716 <author>
1553 1717 <name>test</name>
1554 1718 <email>&#116;&#101;&#115;&#116;</email>
1555 1719 </author>
1556 1720 <updated>1970-01-01T00:00:00+00:00</updated>
1557 1721 <published>1970-01-01T00:00:00+00:00</published>
1558 1722 <content type="xhtml">
1559 1723 <table xmlns="http://www.w3.org/1999/xhtml">
1560 1724 <tr>
1561 1725 <th style="text-align:left;">changeset</th>
1562 1726 <td>3f41bc784e7e</td>
1563 1727 </tr>
1564 1728 <tr>
1565 1729 <th style="text-align:left;">branch</th>
1566 1730 <td>a-branch</td>
1567 1731 </tr>
1568 1732 <tr>
1569 1733 <th style="text-align:left;">bookmark</th>
1570 1734 <td></td>
1571 1735 </tr>
1572 1736 <tr>
1573 1737 <th style="text-align:left;">tag</th>
1574 1738 <td></td>
1575 1739 </tr>
1576 1740 <tr>
1577 1741 <th style="text-align:left;">user</th>
1578 1742 <td>&#116;&#101;&#115;&#116;</td>
1579 1743 </tr>
1580 1744 <tr>
1581 1745 <th style="text-align:left;vertical-align:top;">description</th>
1582 1746 <td>second a</td>
1583 1747 </tr>
1584 1748 <tr>
1585 1749 <th style="text-align:left;vertical-align:top;">files</th>
1586 1750 <td></td>
1587 1751 </tr>
1588 1752 </table>
1589 1753 </content>
1590 1754 </entry>
1591 1755 <entry>
1592 1756 <title>first a</title>
1593 1757 <id>http://*:$HGPORT/#changeset-5ed941583260248620985524192fdc382ef57c36</id> (glob)
1594 1758 <link href="http://*:$HGPORT/rev/5ed941583260"/> (glob)
1595 1759 <author>
1596 1760 <name>test</name>
1597 1761 <email>&#116;&#101;&#115;&#116;</email>
1598 1762 </author>
1599 1763 <updated>1970-01-01T00:00:00+00:00</updated>
1600 1764 <published>1970-01-01T00:00:00+00:00</published>
1601 1765 <content type="xhtml">
1602 1766 <table xmlns="http://www.w3.org/1999/xhtml">
1603 1767 <tr>
1604 1768 <th style="text-align:left;">changeset</th>
1605 1769 <td>5ed941583260</td>
1606 1770 </tr>
1607 1771 <tr>
1608 1772 <th style="text-align:left;">branch</th>
1609 1773 <td></td>
1610 1774 </tr>
1611 1775 <tr>
1612 1776 <th style="text-align:left;">bookmark</th>
1613 1777 <td>a-bookmark</td>
1614 1778 </tr>
1615 1779 <tr>
1616 1780 <th style="text-align:left;">tag</th>
1617 1781 <td>a-tag</td>
1618 1782 </tr>
1619 1783 <tr>
1620 1784 <th style="text-align:left;">user</th>
1621 1785 <td>&#116;&#101;&#115;&#116;</td>
1622 1786 </tr>
1623 1787 <tr>
1624 1788 <th style="text-align:left;vertical-align:top;">description</th>
1625 1789 <td>first a</td>
1626 1790 </tr>
1627 1791 <tr>
1628 1792 <th style="text-align:left;vertical-align:top;">files</th>
1629 1793 <td></td>
1630 1794 </tr>
1631 1795 </table>
1632 1796 </content>
1633 1797 </entry>
1634 1798
1635 1799 </feed>
1636 1800
1637 1801 errors
1638 1802
1639 1803 $ cat errors.log
1640 1804
1641 1805 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now