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