##// END OF EJS Templates
hgweb: fixes invalid parents / children in comparison...
wujek srujek -
r17303:06217d3c stable
parent child Browse files
Show More
@@ -1,972 +1,972
1 1 #
2 2 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 import os, mimetypes, re, cgi, copy
9 9 import webutil
10 10 from mercurial import error, encoding, archival, templater, templatefilters
11 11 from mercurial.node import short, hex, nullid
12 12 from mercurial.util import binary
13 13 from common import paritygen, staticfile, get_contact, ErrorResponse
14 14 from common import HTTP_OK, HTTP_FORBIDDEN, HTTP_NOT_FOUND
15 15 from mercurial import graphmod, patch
16 16 from mercurial import help as helpmod
17 17 from mercurial.i18n import _
18 18
19 19 # __all__ is populated with the allowed commands. Be sure to add to it if
20 20 # you're adding a new command, or the new command won't work.
21 21
22 22 __all__ = [
23 23 'log', 'rawfile', 'file', 'changelog', 'shortlog', 'changeset', 'rev',
24 24 'manifest', 'tags', 'bookmarks', 'branches', 'summary', 'filediff', 'diff',
25 25 'comparison', 'annotate', 'filelog', 'archive', 'static', 'graph', 'help',
26 26 ]
27 27
28 28 def log(web, req, tmpl):
29 29 if 'file' in req.form and req.form['file'][0]:
30 30 return filelog(web, req, tmpl)
31 31 else:
32 32 return changelog(web, req, tmpl)
33 33
34 34 def rawfile(web, req, tmpl):
35 35 guessmime = web.configbool('web', 'guessmime', False)
36 36
37 37 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
38 38 if not path:
39 39 content = manifest(web, req, tmpl)
40 40 req.respond(HTTP_OK, web.ctype)
41 41 return content
42 42
43 43 try:
44 44 fctx = webutil.filectx(web.repo, req)
45 45 except error.LookupError, inst:
46 46 try:
47 47 content = manifest(web, req, tmpl)
48 48 req.respond(HTTP_OK, web.ctype)
49 49 return content
50 50 except ErrorResponse:
51 51 raise inst
52 52
53 53 path = fctx.path()
54 54 text = fctx.data()
55 55 mt = 'application/binary'
56 56 if guessmime:
57 57 mt = mimetypes.guess_type(path)[0]
58 58 if mt is None:
59 59 mt = binary(text) and 'application/binary' or 'text/plain'
60 60 if mt.startswith('text/'):
61 61 mt += '; charset="%s"' % encoding.encoding
62 62
63 63 req.respond(HTTP_OK, mt, path, len(text))
64 64 return [text]
65 65
66 66 def _filerevision(web, tmpl, fctx):
67 67 f = fctx.path()
68 68 text = fctx.data()
69 69 parity = paritygen(web.stripecount)
70 70
71 71 if binary(text):
72 72 mt = mimetypes.guess_type(f)[0] or 'application/octet-stream'
73 73 text = '(binary:%s)' % mt
74 74
75 75 def lines():
76 76 for lineno, t in enumerate(text.splitlines(True)):
77 77 yield {"line": t,
78 78 "lineid": "l%d" % (lineno + 1),
79 79 "linenumber": "% 6d" % (lineno + 1),
80 80 "parity": parity.next()}
81 81
82 82 return tmpl("filerevision",
83 83 file=f,
84 84 path=webutil.up(f),
85 85 text=lines(),
86 86 rev=fctx.rev(),
87 87 node=fctx.hex(),
88 88 author=fctx.user(),
89 89 date=fctx.date(),
90 90 desc=fctx.description(),
91 91 branch=webutil.nodebranchnodefault(fctx),
92 92 parent=webutil.parents(fctx),
93 93 child=webutil.children(fctx),
94 94 rename=webutil.renamelink(fctx),
95 95 permissions=fctx.manifest().flags(f))
96 96
97 97 def file(web, req, tmpl):
98 98 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
99 99 if not path:
100 100 return manifest(web, req, tmpl)
101 101 try:
102 102 return _filerevision(web, tmpl, webutil.filectx(web.repo, req))
103 103 except error.LookupError, inst:
104 104 try:
105 105 return manifest(web, req, tmpl)
106 106 except ErrorResponse:
107 107 raise inst
108 108
109 109 def _search(web, req, tmpl):
110 110
111 111 query = req.form['rev'][0]
112 112 revcount = web.maxchanges
113 113 if 'revcount' in req.form:
114 114 revcount = int(req.form.get('revcount', [revcount])[0])
115 115 revcount = max(revcount, 1)
116 116 tmpl.defaults['sessionvars']['revcount'] = revcount
117 117
118 118 lessvars = copy.copy(tmpl.defaults['sessionvars'])
119 119 lessvars['revcount'] = max(revcount / 2, 1)
120 120 lessvars['rev'] = query
121 121 morevars = copy.copy(tmpl.defaults['sessionvars'])
122 122 morevars['revcount'] = revcount * 2
123 123 morevars['rev'] = query
124 124
125 125 def changelist(**map):
126 126 count = 0
127 127 lower = encoding.lower
128 128 qw = lower(query).split()
129 129
130 130 def revgen():
131 131 for i in xrange(len(web.repo) - 1, 0, -100):
132 132 l = []
133 133 for j in xrange(max(0, i - 100), i + 1):
134 134 ctx = web.repo[j]
135 135 l.append(ctx)
136 136 l.reverse()
137 137 for e in l:
138 138 yield e
139 139
140 140 for ctx in revgen():
141 141 miss = 0
142 142 for q in qw:
143 143 if not (q in lower(ctx.user()) or
144 144 q in lower(ctx.description()) or
145 145 q in lower(" ".join(ctx.files()))):
146 146 miss = 1
147 147 break
148 148 if miss:
149 149 continue
150 150
151 151 count += 1
152 152 n = ctx.node()
153 153 showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
154 154 files = webutil.listfilediffs(tmpl, ctx.files(), n, web.maxfiles)
155 155
156 156 yield tmpl('searchentry',
157 157 parity=parity.next(),
158 158 author=ctx.user(),
159 159 parent=webutil.parents(ctx),
160 160 child=webutil.children(ctx),
161 161 changelogtag=showtags,
162 162 desc=ctx.description(),
163 163 date=ctx.date(),
164 164 files=files,
165 165 rev=ctx.rev(),
166 166 node=hex(n),
167 167 tags=webutil.nodetagsdict(web.repo, n),
168 168 bookmarks=webutil.nodebookmarksdict(web.repo, n),
169 169 inbranch=webutil.nodeinbranch(web.repo, ctx),
170 170 branches=webutil.nodebranchdict(web.repo, ctx))
171 171
172 172 if count >= revcount:
173 173 break
174 174
175 175 tip = web.repo['tip']
176 176 parity = paritygen(web.stripecount)
177 177
178 178 return tmpl('search', query=query, node=tip.hex(),
179 179 entries=changelist, archives=web.archivelist("tip"),
180 180 morevars=morevars, lessvars=lessvars)
181 181
182 182 def changelog(web, req, tmpl, shortlog=False):
183 183
184 184 if 'node' in req.form:
185 185 ctx = webutil.changectx(web.repo, req)
186 186 else:
187 187 if 'rev' in req.form:
188 188 hi = req.form['rev'][0]
189 189 else:
190 190 hi = len(web.repo) - 1
191 191 try:
192 192 ctx = web.repo[hi]
193 193 except error.RepoError:
194 194 return _search(web, req, tmpl) # XXX redirect to 404 page?
195 195
196 196 def changelist(limit=0, **map):
197 197 l = [] # build a list in forward order for efficiency
198 198 for i in xrange(start, end):
199 199 ctx = web.repo[i]
200 200 n = ctx.node()
201 201 showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
202 202 files = webutil.listfilediffs(tmpl, ctx.files(), n, web.maxfiles)
203 203
204 204 l.insert(0, {"parity": parity.next(),
205 205 "author": ctx.user(),
206 206 "parent": webutil.parents(ctx, i - 1),
207 207 "child": webutil.children(ctx, i + 1),
208 208 "changelogtag": showtags,
209 209 "desc": ctx.description(),
210 210 "date": ctx.date(),
211 211 "files": files,
212 212 "rev": i,
213 213 "node": hex(n),
214 214 "tags": webutil.nodetagsdict(web.repo, n),
215 215 "bookmarks": webutil.nodebookmarksdict(web.repo, n),
216 216 "inbranch": webutil.nodeinbranch(web.repo, ctx),
217 217 "branches": webutil.nodebranchdict(web.repo, ctx)
218 218 })
219 219
220 220 if limit > 0:
221 221 l = l[:limit]
222 222
223 223 for e in l:
224 224 yield e
225 225
226 226 revcount = shortlog and web.maxshortchanges or web.maxchanges
227 227 if 'revcount' in req.form:
228 228 revcount = int(req.form.get('revcount', [revcount])[0])
229 229 revcount = max(revcount, 1)
230 230 tmpl.defaults['sessionvars']['revcount'] = revcount
231 231
232 232 lessvars = copy.copy(tmpl.defaults['sessionvars'])
233 233 lessvars['revcount'] = max(revcount / 2, 1)
234 234 morevars = copy.copy(tmpl.defaults['sessionvars'])
235 235 morevars['revcount'] = revcount * 2
236 236
237 237 count = len(web.repo)
238 238 pos = ctx.rev()
239 239 start = max(0, pos - revcount + 1)
240 240 end = min(count, start + revcount)
241 241 pos = end - 1
242 242 parity = paritygen(web.stripecount, offset=start - end)
243 243
244 244 changenav = webutil.revnavgen(pos, revcount, count, web.repo.changectx)
245 245
246 246 return tmpl(shortlog and 'shortlog' or 'changelog', changenav=changenav,
247 247 node=ctx.hex(), rev=pos, changesets=count,
248 248 entries=lambda **x: changelist(limit=0,**x),
249 249 latestentry=lambda **x: changelist(limit=1,**x),
250 250 archives=web.archivelist("tip"), revcount=revcount,
251 251 morevars=morevars, lessvars=lessvars)
252 252
253 253 def shortlog(web, req, tmpl):
254 254 return changelog(web, req, tmpl, shortlog = True)
255 255
256 256 def changeset(web, req, tmpl):
257 257 ctx = webutil.changectx(web.repo, req)
258 258 showtags = webutil.showtag(web.repo, tmpl, 'changesettag', ctx.node())
259 259 showbookmarks = webutil.showbookmark(web.repo, tmpl, 'changesetbookmark',
260 260 ctx.node())
261 261 showbranch = webutil.nodebranchnodefault(ctx)
262 262
263 263 files = []
264 264 parity = paritygen(web.stripecount)
265 265 for blockno, f in enumerate(ctx.files()):
266 266 template = f in ctx and 'filenodelink' or 'filenolink'
267 267 files.append(tmpl(template,
268 268 node=ctx.hex(), file=f, blockno=blockno + 1,
269 269 parity=parity.next()))
270 270
271 271 style = web.config('web', 'style', 'paper')
272 272 if 'style' in req.form:
273 273 style = req.form['style'][0]
274 274
275 275 parity = paritygen(web.stripecount)
276 276 diffs = webutil.diffs(web.repo, tmpl, ctx, None, parity, style)
277 277
278 278 parity = paritygen(web.stripecount)
279 279 diffstatgen = webutil.diffstatgen(ctx)
280 280 diffstat = webutil.diffstat(tmpl, ctx, diffstatgen, parity)
281 281
282 282 return tmpl('changeset',
283 283 diff=diffs,
284 284 rev=ctx.rev(),
285 285 node=ctx.hex(),
286 286 parent=webutil.parents(ctx),
287 287 child=webutil.children(ctx),
288 288 changesettag=showtags,
289 289 changesetbookmark=showbookmarks,
290 290 changesetbranch=showbranch,
291 291 author=ctx.user(),
292 292 desc=ctx.description(),
293 293 date=ctx.date(),
294 294 files=files,
295 295 diffsummary=lambda **x: webutil.diffsummary(diffstatgen),
296 296 diffstat=diffstat,
297 297 archives=web.archivelist(ctx.hex()),
298 298 tags=webutil.nodetagsdict(web.repo, ctx.node()),
299 299 bookmarks=webutil.nodebookmarksdict(web.repo, ctx.node()),
300 300 branch=webutil.nodebranchnodefault(ctx),
301 301 inbranch=webutil.nodeinbranch(web.repo, ctx),
302 302 branches=webutil.nodebranchdict(web.repo, ctx))
303 303
304 304 rev = changeset
305 305
306 306 def decodepath(path):
307 307 """Hook for mapping a path in the repository to a path in the
308 308 working copy.
309 309
310 310 Extensions (e.g., largefiles) can override this to remap files in
311 311 the virtual file system presented by the manifest command below."""
312 312 return path
313 313
314 314 def manifest(web, req, tmpl):
315 315 ctx = webutil.changectx(web.repo, req)
316 316 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
317 317 mf = ctx.manifest()
318 318 node = ctx.node()
319 319
320 320 files = {}
321 321 dirs = {}
322 322 parity = paritygen(web.stripecount)
323 323
324 324 if path and path[-1] != "/":
325 325 path += "/"
326 326 l = len(path)
327 327 abspath = "/" + path
328 328
329 329 for full, n in mf.iteritems():
330 330 # the virtual path (working copy path) used for the full
331 331 # (repository) path
332 332 f = decodepath(full)
333 333
334 334 if f[:l] != path:
335 335 continue
336 336 remain = f[l:]
337 337 elements = remain.split('/')
338 338 if len(elements) == 1:
339 339 files[remain] = full
340 340 else:
341 341 h = dirs # need to retain ref to dirs (root)
342 342 for elem in elements[0:-1]:
343 343 if elem not in h:
344 344 h[elem] = {}
345 345 h = h[elem]
346 346 if len(h) > 1:
347 347 break
348 348 h[None] = None # denotes files present
349 349
350 350 if mf and not files and not dirs:
351 351 raise ErrorResponse(HTTP_NOT_FOUND, 'path not found: ' + path)
352 352
353 353 def filelist(**map):
354 354 for f in sorted(files):
355 355 full = files[f]
356 356
357 357 fctx = ctx.filectx(full)
358 358 yield {"file": full,
359 359 "parity": parity.next(),
360 360 "basename": f,
361 361 "date": fctx.date(),
362 362 "size": fctx.size(),
363 363 "permissions": mf.flags(full)}
364 364
365 365 def dirlist(**map):
366 366 for d in sorted(dirs):
367 367
368 368 emptydirs = []
369 369 h = dirs[d]
370 370 while isinstance(h, dict) and len(h) == 1:
371 371 k, v = h.items()[0]
372 372 if v:
373 373 emptydirs.append(k)
374 374 h = v
375 375
376 376 path = "%s%s" % (abspath, d)
377 377 yield {"parity": parity.next(),
378 378 "path": path,
379 379 "emptydirs": "/".join(emptydirs),
380 380 "basename": d}
381 381
382 382 return tmpl("manifest",
383 383 rev=ctx.rev(),
384 384 node=hex(node),
385 385 path=abspath,
386 386 up=webutil.up(abspath),
387 387 upparity=parity.next(),
388 388 fentries=filelist,
389 389 dentries=dirlist,
390 390 archives=web.archivelist(hex(node)),
391 391 tags=webutil.nodetagsdict(web.repo, node),
392 392 bookmarks=webutil.nodebookmarksdict(web.repo, node),
393 393 inbranch=webutil.nodeinbranch(web.repo, ctx),
394 394 branches=webutil.nodebranchdict(web.repo, ctx))
395 395
396 396 def tags(web, req, tmpl):
397 397 i = reversed(web.repo.tagslist())
398 398 parity = paritygen(web.stripecount)
399 399
400 400 def entries(notip=False, limit=0, **map):
401 401 count = 0
402 402 for k, n in i:
403 403 if notip and k == "tip":
404 404 continue
405 405 if limit > 0 and count >= limit:
406 406 continue
407 407 count = count + 1
408 408 yield {"parity": parity.next(),
409 409 "tag": k,
410 410 "date": web.repo[n].date(),
411 411 "node": hex(n)}
412 412
413 413 return tmpl("tags",
414 414 node=hex(web.repo.changelog.tip()),
415 415 entries=lambda **x: entries(False, 0, **x),
416 416 entriesnotip=lambda **x: entries(True, 0, **x),
417 417 latestentry=lambda **x: entries(True, 1, **x))
418 418
419 419 def bookmarks(web, req, tmpl):
420 420 i = web.repo._bookmarks.items()
421 421 parity = paritygen(web.stripecount)
422 422
423 423 def entries(limit=0, **map):
424 424 count = 0
425 425 for k, n in sorted(i):
426 426 if limit > 0 and count >= limit:
427 427 continue
428 428 count = count + 1
429 429 yield {"parity": parity.next(),
430 430 "bookmark": k,
431 431 "date": web.repo[n].date(),
432 432 "node": hex(n)}
433 433
434 434 return tmpl("bookmarks",
435 435 node=hex(web.repo.changelog.tip()),
436 436 entries=lambda **x: entries(0, **x),
437 437 latestentry=lambda **x: entries(1, **x))
438 438
439 439 def branches(web, req, tmpl):
440 440 tips = (web.repo[n] for t, n in web.repo.branchtags().iteritems())
441 441 heads = web.repo.heads()
442 442 parity = paritygen(web.stripecount)
443 443 sortkey = lambda ctx: (not ctx.closesbranch(), ctx.rev())
444 444
445 445 def entries(limit, **map):
446 446 count = 0
447 447 for ctx in sorted(tips, key=sortkey, reverse=True):
448 448 if limit > 0 and count >= limit:
449 449 return
450 450 count += 1
451 451 if not web.repo.branchheads(ctx.branch()):
452 452 status = 'closed'
453 453 elif ctx.node() not in heads:
454 454 status = 'inactive'
455 455 else:
456 456 status = 'open'
457 457 yield {'parity': parity.next(),
458 458 'branch': ctx.branch(),
459 459 'status': status,
460 460 'node': ctx.hex(),
461 461 'date': ctx.date()}
462 462
463 463 return tmpl('branches', node=hex(web.repo.changelog.tip()),
464 464 entries=lambda **x: entries(0, **x),
465 465 latestentry=lambda **x: entries(1, **x))
466 466
467 467 def summary(web, req, tmpl):
468 468 i = reversed(web.repo.tagslist())
469 469
470 470 def tagentries(**map):
471 471 parity = paritygen(web.stripecount)
472 472 count = 0
473 473 for k, n in i:
474 474 if k == "tip": # skip tip
475 475 continue
476 476
477 477 count += 1
478 478 if count > 10: # limit to 10 tags
479 479 break
480 480
481 481 yield tmpl("tagentry",
482 482 parity=parity.next(),
483 483 tag=k,
484 484 node=hex(n),
485 485 date=web.repo[n].date())
486 486
487 487 def bookmarks(**map):
488 488 parity = paritygen(web.stripecount)
489 489 b = web.repo._bookmarks.items()
490 490 for k, n in sorted(b)[:10]: # limit to 10 bookmarks
491 491 yield {'parity': parity.next(),
492 492 'bookmark': k,
493 493 'date': web.repo[n].date(),
494 494 'node': hex(n)}
495 495
496 496 def branches(**map):
497 497 parity = paritygen(web.stripecount)
498 498
499 499 b = web.repo.branchtags()
500 500 l = [(-web.repo.changelog.rev(n), n, t) for t, n in b.iteritems()]
501 501 for r, n, t in sorted(l):
502 502 yield {'parity': parity.next(),
503 503 'branch': t,
504 504 'node': hex(n),
505 505 'date': web.repo[n].date()}
506 506
507 507 def changelist(**map):
508 508 parity = paritygen(web.stripecount, offset=start - end)
509 509 l = [] # build a list in forward order for efficiency
510 510 for i in xrange(start, end):
511 511 ctx = web.repo[i]
512 512 n = ctx.node()
513 513 hn = hex(n)
514 514
515 515 l.insert(0, tmpl(
516 516 'shortlogentry',
517 517 parity=parity.next(),
518 518 author=ctx.user(),
519 519 desc=ctx.description(),
520 520 date=ctx.date(),
521 521 rev=i,
522 522 node=hn,
523 523 tags=webutil.nodetagsdict(web.repo, n),
524 524 bookmarks=webutil.nodebookmarksdict(web.repo, n),
525 525 inbranch=webutil.nodeinbranch(web.repo, ctx),
526 526 branches=webutil.nodebranchdict(web.repo, ctx)))
527 527
528 528 yield l
529 529
530 530 tip = web.repo['tip']
531 531 count = len(web.repo)
532 532 start = max(0, count - web.maxchanges)
533 533 end = min(count, start + web.maxchanges)
534 534
535 535 return tmpl("summary",
536 536 desc=web.config("web", "description", "unknown"),
537 537 owner=get_contact(web.config) or "unknown",
538 538 lastchange=tip.date(),
539 539 tags=tagentries,
540 540 bookmarks=bookmarks,
541 541 branches=branches,
542 542 shortlog=changelist,
543 543 node=tip.hex(),
544 544 archives=web.archivelist("tip"))
545 545
546 546 def filediff(web, req, tmpl):
547 547 fctx, ctx = None, None
548 548 try:
549 549 fctx = webutil.filectx(web.repo, req)
550 550 except LookupError:
551 551 ctx = webutil.changectx(web.repo, req)
552 552 path = webutil.cleanpath(web.repo, req.form['file'][0])
553 553 if path not in ctx.files():
554 554 raise
555 555
556 556 if fctx is not None:
557 557 n = fctx.node()
558 558 path = fctx.path()
559 559 ctx = fctx.changectx()
560 560 else:
561 561 n = ctx.node()
562 562 # path already defined in except clause
563 563
564 564 parity = paritygen(web.stripecount)
565 565 style = web.config('web', 'style', 'paper')
566 566 if 'style' in req.form:
567 567 style = req.form['style'][0]
568 568
569 569 diffs = webutil.diffs(web.repo, tmpl, ctx, [path], parity, style)
570 570 rename = fctx and webutil.renamelink(fctx) or []
571 571 ctx = fctx and fctx or ctx
572 572 return tmpl("filediff",
573 573 file=path,
574 574 node=hex(n),
575 575 rev=ctx.rev(),
576 576 date=ctx.date(),
577 577 desc=ctx.description(),
578 578 author=ctx.user(),
579 579 rename=rename,
580 580 branch=webutil.nodebranchnodefault(ctx),
581 581 parent=webutil.parents(ctx),
582 582 child=webutil.children(ctx),
583 583 diff=diffs)
584 584
585 585 diff = filediff
586 586
587 587 def comparison(web, req, tmpl):
588 588 ctx = webutil.changectx(web.repo, req)
589 589 if 'file' not in req.form:
590 590 raise ErrorResponse(HTTP_NOT_FOUND, 'file not given')
591 591 path = webutil.cleanpath(web.repo, req.form['file'][0])
592 592 rename = path in ctx and webutil.renamelink(ctx[path]) or []
593 593
594 594 parsecontext = lambda v: v == 'full' and -1 or int(v)
595 595 if 'context' in req.form:
596 596 context = parsecontext(req.form['context'][0])
597 597 else:
598 598 context = parsecontext(web.config('web', 'comparisoncontext', '5'))
599 599
600 600 def filelines(f):
601 601 if binary(f.data()):
602 602 mt = mimetypes.guess_type(f.path())[0]
603 603 if not mt:
604 604 mt = 'application/octet-stream'
605 605 return [_('(binary file %s, hash: %s)') % (mt, hex(f.filenode()))]
606 606 return f.data().splitlines()
607 607
608 608 if path in ctx:
609 609 fctx = ctx[path]
610 610 rightrev = fctx.filerev()
611 611 rightnode = fctx.filenode()
612 612 rightlines = filelines(fctx)
613 613 parents = fctx.parents()
614 614 if not parents:
615 615 leftrev = -1
616 616 leftnode = nullid
617 617 leftlines = ()
618 618 else:
619 619 pfctx = parents[0]
620 620 leftrev = pfctx.filerev()
621 621 leftnode = pfctx.filenode()
622 622 leftlines = filelines(pfctx)
623 623 else:
624 624 rightrev = -1
625 625 rightnode = nullid
626 626 rightlines = ()
627 627 fctx = ctx.parents()[0][path]
628 628 leftrev = fctx.filerev()
629 629 leftnode = fctx.filenode()
630 630 leftlines = filelines(fctx)
631 631
632 632 comparison = webutil.compare(tmpl, context, leftlines, rightlines)
633 633 return tmpl('filecomparison',
634 634 file=path,
635 635 node=hex(ctx.node()),
636 636 rev=ctx.rev(),
637 637 date=ctx.date(),
638 638 desc=ctx.description(),
639 639 author=ctx.user(),
640 640 rename=rename,
641 641 branch=webutil.nodebranchnodefault(ctx),
642 parent=webutil.parents(ctx),
643 child=webutil.children(ctx),
642 parent=webutil.parents(fctx),
643 child=webutil.children(fctx),
644 644 leftrev=leftrev,
645 645 leftnode=hex(leftnode),
646 646 rightrev=rightrev,
647 647 rightnode=hex(rightnode),
648 648 comparison=comparison)
649 649
650 650 def annotate(web, req, tmpl):
651 651 fctx = webutil.filectx(web.repo, req)
652 652 f = fctx.path()
653 653 parity = paritygen(web.stripecount)
654 654 diffopts = patch.diffopts(web.repo.ui, untrusted=True, section='annotate')
655 655
656 656 def annotate(**map):
657 657 last = None
658 658 if binary(fctx.data()):
659 659 mt = (mimetypes.guess_type(fctx.path())[0]
660 660 or 'application/octet-stream')
661 661 lines = enumerate([((fctx.filectx(fctx.filerev()), 1),
662 662 '(binary:%s)' % mt)])
663 663 else:
664 664 lines = enumerate(fctx.annotate(follow=True, linenumber=True,
665 665 diffopts=diffopts))
666 666 for lineno, ((f, targetline), l) in lines:
667 667 fnode = f.filenode()
668 668
669 669 if last != fnode:
670 670 last = fnode
671 671
672 672 yield {"parity": parity.next(),
673 673 "node": f.hex(),
674 674 "rev": f.rev(),
675 675 "author": f.user(),
676 676 "desc": f.description(),
677 677 "file": f.path(),
678 678 "targetline": targetline,
679 679 "line": l,
680 680 "lineid": "l%d" % (lineno + 1),
681 681 "linenumber": "% 6d" % (lineno + 1),
682 682 "revdate": f.date()}
683 683
684 684 return tmpl("fileannotate",
685 685 file=f,
686 686 annotate=annotate,
687 687 path=webutil.up(f),
688 688 rev=fctx.rev(),
689 689 node=fctx.hex(),
690 690 author=fctx.user(),
691 691 date=fctx.date(),
692 692 desc=fctx.description(),
693 693 rename=webutil.renamelink(fctx),
694 694 branch=webutil.nodebranchnodefault(fctx),
695 695 parent=webutil.parents(fctx),
696 696 child=webutil.children(fctx),
697 697 permissions=fctx.manifest().flags(f))
698 698
699 699 def filelog(web, req, tmpl):
700 700
701 701 try:
702 702 fctx = webutil.filectx(web.repo, req)
703 703 f = fctx.path()
704 704 fl = fctx.filelog()
705 705 except error.LookupError:
706 706 f = webutil.cleanpath(web.repo, req.form['file'][0])
707 707 fl = web.repo.file(f)
708 708 numrevs = len(fl)
709 709 if not numrevs: # file doesn't exist at all
710 710 raise
711 711 rev = webutil.changectx(web.repo, req).rev()
712 712 first = fl.linkrev(0)
713 713 if rev < first: # current rev is from before file existed
714 714 raise
715 715 frev = numrevs - 1
716 716 while fl.linkrev(frev) > rev:
717 717 frev -= 1
718 718 fctx = web.repo.filectx(f, fl.linkrev(frev))
719 719
720 720 revcount = web.maxshortchanges
721 721 if 'revcount' in req.form:
722 722 revcount = int(req.form.get('revcount', [revcount])[0])
723 723 revcount = max(revcount, 1)
724 724 tmpl.defaults['sessionvars']['revcount'] = revcount
725 725
726 726 lessvars = copy.copy(tmpl.defaults['sessionvars'])
727 727 lessvars['revcount'] = max(revcount / 2, 1)
728 728 morevars = copy.copy(tmpl.defaults['sessionvars'])
729 729 morevars['revcount'] = revcount * 2
730 730
731 731 count = fctx.filerev() + 1
732 732 start = max(0, fctx.filerev() - revcount + 1) # first rev on this page
733 733 end = min(count, start + revcount) # last rev on this page
734 734 parity = paritygen(web.stripecount, offset=start - end)
735 735
736 736 def entries(limit=0, **map):
737 737 l = []
738 738
739 739 repo = web.repo
740 740 for i in xrange(start, end):
741 741 iterfctx = fctx.filectx(i)
742 742
743 743 l.insert(0, {"parity": parity.next(),
744 744 "filerev": i,
745 745 "file": f,
746 746 "node": iterfctx.hex(),
747 747 "author": iterfctx.user(),
748 748 "date": iterfctx.date(),
749 749 "rename": webutil.renamelink(iterfctx),
750 750 "parent": webutil.parents(iterfctx),
751 751 "child": webutil.children(iterfctx),
752 752 "desc": iterfctx.description(),
753 753 "tags": webutil.nodetagsdict(repo, iterfctx.node()),
754 754 "bookmarks": webutil.nodebookmarksdict(
755 755 repo, iterfctx.node()),
756 756 "branch": webutil.nodebranchnodefault(iterfctx),
757 757 "inbranch": webutil.nodeinbranch(repo, iterfctx),
758 758 "branches": webutil.nodebranchdict(repo, iterfctx)})
759 759
760 760 if limit > 0:
761 761 l = l[:limit]
762 762
763 763 for e in l:
764 764 yield e
765 765
766 766 nodefunc = lambda x: fctx.filectx(fileid=x)
767 767 nav = webutil.revnavgen(end - 1, revcount, count, nodefunc)
768 768 return tmpl("filelog", file=f, node=fctx.hex(), nav=nav,
769 769 entries=lambda **x: entries(limit=0, **x),
770 770 latestentry=lambda **x: entries(limit=1, **x),
771 771 revcount=revcount, morevars=morevars, lessvars=lessvars)
772 772
773 773 def archive(web, req, tmpl):
774 774 type_ = req.form.get('type', [None])[0]
775 775 allowed = web.configlist("web", "allow_archive")
776 776 key = req.form['node'][0]
777 777
778 778 if type_ not in web.archives:
779 779 msg = 'Unsupported archive type: %s' % type_
780 780 raise ErrorResponse(HTTP_NOT_FOUND, msg)
781 781
782 782 if not ((type_ in allowed or
783 783 web.configbool("web", "allow" + type_, False))):
784 784 msg = 'Archive type not allowed: %s' % type_
785 785 raise ErrorResponse(HTTP_FORBIDDEN, msg)
786 786
787 787 reponame = re.sub(r"\W+", "-", os.path.basename(web.reponame))
788 788 cnode = web.repo.lookup(key)
789 789 arch_version = key
790 790 if cnode == key or key == 'tip':
791 791 arch_version = short(cnode)
792 792 name = "%s-%s" % (reponame, arch_version)
793 793 mimetype, artype, extension, encoding = web.archive_specs[type_]
794 794 headers = [
795 795 ('Content-Type', mimetype),
796 796 ('Content-Disposition', 'attachment; filename=%s%s' % (name, extension))
797 797 ]
798 798 if encoding:
799 799 headers.append(('Content-Encoding', encoding))
800 800 req.header(headers)
801 801 req.respond(HTTP_OK)
802 802 archival.archive(web.repo, req, cnode, artype, prefix=name)
803 803 return []
804 804
805 805
806 806 def static(web, req, tmpl):
807 807 fname = req.form['file'][0]
808 808 # a repo owner may set web.static in .hg/hgrc to get any file
809 809 # readable by the user running the CGI script
810 810 static = web.config("web", "static", None, untrusted=False)
811 811 if not static:
812 812 tp = web.templatepath or templater.templatepath()
813 813 if isinstance(tp, str):
814 814 tp = [tp]
815 815 static = [os.path.join(p, 'static') for p in tp]
816 816 return [staticfile(static, fname, req)]
817 817
818 818 def graph(web, req, tmpl):
819 819
820 820 rev = webutil.changectx(web.repo, req).rev()
821 821 bg_height = 39
822 822 revcount = web.maxshortchanges
823 823 if 'revcount' in req.form:
824 824 revcount = int(req.form.get('revcount', [revcount])[0])
825 825 revcount = max(revcount, 1)
826 826 tmpl.defaults['sessionvars']['revcount'] = revcount
827 827
828 828 lessvars = copy.copy(tmpl.defaults['sessionvars'])
829 829 lessvars['revcount'] = max(revcount / 2, 1)
830 830 morevars = copy.copy(tmpl.defaults['sessionvars'])
831 831 morevars['revcount'] = revcount * 2
832 832
833 833 max_rev = len(web.repo) - 1
834 834 revcount = min(max_rev, revcount)
835 835 revnode = web.repo.changelog.node(rev)
836 836 revnode_hex = hex(revnode)
837 837 uprev = min(max_rev, rev + revcount)
838 838 downrev = max(0, rev - revcount)
839 839 count = len(web.repo)
840 840 changenav = webutil.revnavgen(rev, revcount, count, web.repo.changectx)
841 841 startrev = rev
842 842 # if starting revision is less than 60 set it to uprev
843 843 if rev < web.maxshortchanges:
844 844 startrev = uprev
845 845
846 846 dag = graphmod.dagwalker(web.repo, range(startrev, downrev - 1, -1))
847 847 tree = list(graphmod.colored(dag, web.repo))
848 848
849 849 def getcolumns(tree):
850 850 cols = 0
851 851 for (id, type, ctx, vtx, edges) in tree:
852 852 if type != graphmod.CHANGESET:
853 853 continue
854 854 cols = max(cols, max([edge[0] for edge in edges] or [0]),
855 855 max([edge[1] for edge in edges] or [0]))
856 856 return cols
857 857
858 858 def graphdata(usetuples, **map):
859 859 data = []
860 860
861 861 row = 0
862 862 for (id, type, ctx, vtx, edges) in tree:
863 863 if type != graphmod.CHANGESET:
864 864 continue
865 865 node = str(ctx)
866 866 age = templatefilters.age(ctx.date())
867 867 desc = templatefilters.firstline(ctx.description())
868 868 desc = cgi.escape(templatefilters.nonempty(desc))
869 869 user = cgi.escape(templatefilters.person(ctx.user()))
870 870 branch = ctx.branch()
871 871 try:
872 872 branchnode = web.repo.branchtip(branch)
873 873 except error.RepoLookupError:
874 874 branchnode = None
875 875 branch = branch, branchnode == ctx.node()
876 876
877 877 if usetuples:
878 878 data.append((node, vtx, edges, desc, user, age, branch,
879 879 ctx.tags(), ctx.bookmarks()))
880 880 else:
881 881 edgedata = [dict(col=edge[0], nextcol=edge[1],
882 882 color=(edge[2] - 1) % 6 + 1,
883 883 width=edge[3], bcolor=edge[4])
884 884 for edge in edges]
885 885
886 886 data.append(
887 887 dict(node=node,
888 888 col=vtx[0],
889 889 color=(vtx[1] - 1) % 6 + 1,
890 890 edges=edgedata,
891 891 row=row,
892 892 nextrow=row + 1,
893 893 desc=desc,
894 894 user=user,
895 895 age=age,
896 896 bookmarks=webutil.nodebookmarksdict(
897 897 web.repo, ctx.node()),
898 898 branches=webutil.nodebranchdict(web.repo, ctx),
899 899 inbranch=webutil.nodeinbranch(web.repo, ctx),
900 900 tags=webutil.nodetagsdict(web.repo, ctx.node())))
901 901
902 902 row += 1
903 903
904 904 return data
905 905
906 906 cols = getcolumns(tree)
907 907 rows = len(tree)
908 908 canvasheight = (rows + 1) * bg_height - 27
909 909
910 910 return tmpl('graph', rev=rev, revcount=revcount, uprev=uprev,
911 911 lessvars=lessvars, morevars=morevars, downrev=downrev,
912 912 cols=cols, rows=rows,
913 913 canvaswidth=(cols + 1) * bg_height,
914 914 truecanvasheight=rows * bg_height,
915 915 canvasheight=canvasheight, bg_height=bg_height,
916 916 jsdata=lambda **x: graphdata(True, **x),
917 917 nodes=lambda **x: graphdata(False, **x),
918 918 node=revnode_hex, changenav=changenav)
919 919
920 920 def _getdoc(e):
921 921 doc = e[0].__doc__
922 922 if doc:
923 923 doc = _(doc).split('\n')[0]
924 924 else:
925 925 doc = _('(no help text available)')
926 926 return doc
927 927
928 928 def help(web, req, tmpl):
929 929 from mercurial import commands # avoid cycle
930 930
931 931 topicname = req.form.get('node', [None])[0]
932 932 if not topicname:
933 933 def topics(**map):
934 934 for entries, summary, _ in helpmod.helptable:
935 935 entries = sorted(entries, key=len)
936 936 yield {'topic': entries[-1], 'summary': summary}
937 937
938 938 early, other = [], []
939 939 primary = lambda s: s.split('|')[0]
940 940 for c, e in commands.table.iteritems():
941 941 doc = _getdoc(e)
942 942 if 'DEPRECATED' in doc or c.startswith('debug'):
943 943 continue
944 944 cmd = primary(c)
945 945 if cmd.startswith('^'):
946 946 early.append((cmd[1:], doc))
947 947 else:
948 948 other.append((cmd, doc))
949 949
950 950 early.sort()
951 951 other.sort()
952 952
953 953 def earlycommands(**map):
954 954 for c, doc in early:
955 955 yield {'topic': c, 'summary': doc}
956 956
957 957 def othercommands(**map):
958 958 for c, doc in other:
959 959 yield {'topic': c, 'summary': doc}
960 960
961 961 return tmpl('helptopics', topics=topics, earlycommands=earlycommands,
962 962 othercommands=othercommands, title='Index')
963 963
964 964 u = webutil.wsgiui()
965 965 u.pushbuffer()
966 966 u.verbose = True
967 967 try:
968 968 commands.help_(u, topicname)
969 969 except error.UnknownCommand:
970 970 raise ErrorResponse(HTTP_NOT_FOUND)
971 971 doc = u.popbuffer()
972 972 return tmpl('help', topic=topicname, doc=doc)
@@ -1,986 +1,986
1 1 $ "$TESTDIR/hghave" serve || exit 80
2 2
3 3 setting up repo
4 4
5 5 $ hg init test
6 6 $ cd test
7 7 $ echo a > a
8 8 $ echo b > b
9 9 $ hg ci -Ama
10 10 adding a
11 11 adding b
12 12
13 13 change permissions for git diffs
14 14
15 15 $ hg import -q --bypass - <<EOF
16 16 > # HG changeset patch
17 17 > # User test
18 18 > # Date 0 0
19 19 > b
20 20 >
21 21 > diff --git a/a b/a
22 22 > old mode 100644
23 23 > new mode 100755
24 24 > diff --git a/b b/b
25 25 > deleted file mode 100644
26 26 > --- a/b
27 27 > +++ /dev/null
28 28 > @@ -1,1 +0,0 @@
29 29 > -b
30 30 > EOF
31 31
32 32 set up hgweb
33 33
34 34 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
35 35 $ cat hg.pid >> $DAEMON_PIDS
36 36
37 37 revision
38 38
39 39 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'rev/0'
40 40 200 Script output follows
41 41
42 42 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
43 43 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
44 44 <head>
45 45 <link rel="icon" href="/static/hgicon.png" type="image/png" />
46 46 <meta name="robots" content="index, nofollow" />
47 47 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
48 48 <script type="text/javascript" src="/static/mercurial.js"></script>
49 49
50 50 <title>test: 0cd96de13884</title>
51 51 </head>
52 52 <body>
53 53 <div class="container">
54 54 <div class="menu">
55 55 <div class="logo">
56 56 <a href="http://mercurial.selenic.com/">
57 57 <img src="/static/hglogo.png" alt="mercurial" /></a>
58 58 </div>
59 59 <ul>
60 60 <li><a href="/shortlog/0cd96de13884">log</a></li>
61 61 <li><a href="/graph/0cd96de13884">graph</a></li>
62 62 <li><a href="/tags">tags</a></li>
63 63 <li><a href="/bookmarks">bookmarks</a></li>
64 64 <li><a href="/branches">branches</a></li>
65 65 </ul>
66 66 <ul>
67 67 <li class="active">changeset</li>
68 68 <li><a href="/raw-rev/0cd96de13884">raw</a></li>
69 69 <li><a href="/file/0cd96de13884">browse</a></li>
70 70 </ul>
71 71 <ul>
72 72
73 73 </ul>
74 74 <ul>
75 75 <li><a href="/help">help</a></li>
76 76 </ul>
77 77 </div>
78 78
79 79 <div class="main">
80 80
81 81 <h2><a href="/">test</a></h2>
82 82 <h3>changeset 0:0cd96de13884 </h3>
83 83
84 84 <form class="search" action="/log">
85 85
86 86 <p><input name="rev" id="search1" type="text" size="30" /></p>
87 87 <div id="hint">find changesets by author, revision,
88 88 files, or words in the commit message</div>
89 89 </form>
90 90
91 91 <div class="description">a</div>
92 92
93 93 <table id="changesetEntry">
94 94 <tr>
95 95 <th class="author">author</th>
96 96 <td class="author">&#116;&#101;&#115;&#116;</td>
97 97 </tr>
98 98 <tr>
99 99 <th class="date">date</th>
100 100 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td></tr>
101 101 <tr>
102 102 <th class="author">parents</th>
103 103 <td class="author"></td>
104 104 </tr>
105 105 <tr>
106 106 <th class="author">children</th>
107 107 <td class="author"> <a href="/rev/559edbd9ed20">559edbd9ed20</a></td>
108 108 </tr>
109 109 <tr>
110 110 <th class="files">files</th>
111 111 <td class="files"><a href="/file/0cd96de13884/a">a</a> <a href="/file/0cd96de13884/b">b</a> </td>
112 112 </tr>
113 113 <tr>
114 114 <th class="diffstat">diffstat</th>
115 115 <td class="diffstat">
116 116 2 files changed, 2 insertions(+), 0 deletions(-)
117 117
118 118 <a id="diffstatexpand" href="javascript:showDiffstat()"/>[<tt>+</tt>]</a>
119 119 <div id="diffstatdetails" style="display:none;">
120 120 <a href="javascript:hideDiffstat()"/>[<tt>-</tt>]</a>
121 121 <p>
122 122 <table> <tr class="parity0">
123 123 <td class="diffstat-file"><a href="#l1.1">a</a></td>
124 124 <td class="diffstat-total" align="right">1</td>
125 125 <td class="diffstat-graph">
126 126 <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
127 127 <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
128 128 </td>
129 129 </tr>
130 130 <tr class="parity1">
131 131 <td class="diffstat-file"><a href="#l2.1">b</a></td>
132 132 <td class="diffstat-total" align="right">1</td>
133 133 <td class="diffstat-graph">
134 134 <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
135 135 <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
136 136 </td>
137 137 </tr>
138 138 </table>
139 139 </div>
140 140 </td>
141 141 </tr>
142 142 </table>
143 143
144 144 <div class="overflow">
145 145 <div class="sourcefirst"> line diff</div>
146 146
147 147 <div class="source bottomline parity0"><pre><a href="#l1.1" id="l1.1"> 1.1</a> <span class="minusline">--- /dev/null Thu Jan 01 00:00:00 1970 +0000
148 148 </span><a href="#l1.2" id="l1.2"> 1.2</a> <span class="plusline">+++ b/a Thu Jan 01 00:00:00 1970 +0000
149 149 </span><a href="#l1.3" id="l1.3"> 1.3</a> <span class="atline">@@ -0,0 +1,1 @@
150 150 </span><a href="#l1.4" id="l1.4"> 1.4</a> <span class="plusline">+a
151 151 </span></pre></div><div class="source bottomline parity1"><pre><a href="#l2.1" id="l2.1"> 2.1</a> <span class="minusline">--- /dev/null Thu Jan 01 00:00:00 1970 +0000
152 152 </span><a href="#l2.2" id="l2.2"> 2.2</a> <span class="plusline">+++ b/b Thu Jan 01 00:00:00 1970 +0000
153 153 </span><a href="#l2.3" id="l2.3"> 2.3</a> <span class="atline">@@ -0,0 +1,1 @@
154 154 </span><a href="#l2.4" id="l2.4"> 2.4</a> <span class="plusline">+b
155 155 </span></pre></div>
156 156 </div>
157 157
158 158 </div>
159 159 </div>
160 160 <script type="text/javascript">process_dates()</script>
161 161
162 162
163 163 </body>
164 164 </html>
165 165
166 166
167 167 raw revision
168 168
169 169 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'raw-rev/0'
170 170 200 Script output follows
171 171
172 172
173 173 # HG changeset patch
174 174 # User test
175 175 # Date 0 0
176 176 # Node ID 0cd96de13884b090099512d4794ae87ad067ea8e
177 177
178 178 a
179 179
180 180 diff -r 000000000000 -r 0cd96de13884 a
181 181 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
182 182 +++ b/a Thu Jan 01 00:00:00 1970 +0000
183 183 @@ -0,0 +1,1 @@
184 184 +a
185 185 diff -r 000000000000 -r 0cd96de13884 b
186 186 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
187 187 +++ b/b Thu Jan 01 00:00:00 1970 +0000
188 188 @@ -0,0 +1,1 @@
189 189 +b
190 190
191 191
192 192 diff removed file
193 193
194 194 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'diff/tip/b'
195 195 200 Script output follows
196 196
197 197 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
198 198 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
199 199 <head>
200 200 <link rel="icon" href="/static/hgicon.png" type="image/png" />
201 201 <meta name="robots" content="index, nofollow" />
202 202 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
203 203 <script type="text/javascript" src="/static/mercurial.js"></script>
204 204
205 205 <title>test: b diff</title>
206 206 </head>
207 207 <body>
208 208
209 209 <div class="container">
210 210 <div class="menu">
211 211 <div class="logo">
212 212 <a href="http://mercurial.selenic.com/">
213 213 <img src="/static/hglogo.png" alt="mercurial" /></a>
214 214 </div>
215 215 <ul>
216 216 <li><a href="/shortlog/559edbd9ed20">log</a></li>
217 217 <li><a href="/graph/559edbd9ed20">graph</a></li>
218 218 <li><a href="/tags">tags</a></li>
219 219 <li><a href="/bookmarks">bookmarks</a></li>
220 220 <li><a href="/branches">branches</a></li>
221 221 </ul>
222 222 <ul>
223 223 <li><a href="/rev/559edbd9ed20">changeset</a></li>
224 224 <li><a href="/file/559edbd9ed20">browse</a></li>
225 225 </ul>
226 226 <ul>
227 227 <li><a href="/file/559edbd9ed20/b">file</a></li>
228 228 <li><a href="/file/tip/b">latest</a></li>
229 229 <li class="active">diff</li>
230 230 <li><a href="/comparison/559edbd9ed20/b">comparison</a></li>
231 231 <li><a href="/annotate/559edbd9ed20/b">annotate</a></li>
232 232 <li><a href="/log/559edbd9ed20/b">file log</a></li>
233 233 <li><a href="/raw-file/559edbd9ed20/b">raw</a></li>
234 234 </ul>
235 235 <ul>
236 236 <li><a href="/help">help</a></li>
237 237 </ul>
238 238 </div>
239 239
240 240 <div class="main">
241 241 <h2><a href="/">test</a></h2>
242 242 <h3>diff b @ 1:559edbd9ed20</h3>
243 243
244 244 <form class="search" action="/log">
245 245 <p></p>
246 246 <p><input name="rev" id="search1" type="text" size="30" /></p>
247 247 <div id="hint">find changesets by author, revision,
248 248 files, or words in the commit message</div>
249 249 </form>
250 250
251 251 <div class="description">b</div>
252 252
253 253 <table id="changesetEntry">
254 254 <tr>
255 255 <th>author</th>
256 256 <td>&#116;&#101;&#115;&#116;</td>
257 257 </tr>
258 258 <tr>
259 259 <th>date</th>
260 260 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
261 261 </tr>
262 262 <tr>
263 263 <th>parents</th>
264 264 <td><a href="/file/0cd96de13884/b">0cd96de13884</a> </td>
265 265 </tr>
266 266 <tr>
267 267 <th>children</th>
268 268 <td></td>
269 269 </tr>
270 270
271 271 </table>
272 272
273 273 <div class="overflow">
274 274 <div class="sourcefirst"> line diff</div>
275 275
276 276 <div class="source bottomline parity0"><pre><a href="#l1.1" id="l1.1"> 1.1</a> <span class="minusline">--- a/b Thu Jan 01 00:00:00 1970 +0000
277 277 </span><a href="#l1.2" id="l1.2"> 1.2</a> <span class="plusline">+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
278 278 </span><a href="#l1.3" id="l1.3"> 1.3</a> <span class="atline">@@ -1,1 +0,0 @@
279 279 </span><a href="#l1.4" id="l1.4"> 1.4</a> <span class="minusline">-b
280 280 </span></pre></div>
281 281 </div>
282 282 </div>
283 283 </div>
284 284
285 285 <script type="text/javascript">process_dates()</script>
286 286
287 287
288 288 </body>
289 289 </html>
290 290
291 291
292 292 set up hgweb with git diffs
293 293
294 294 $ "$TESTDIR/killdaemons.py"
295 295 $ hg serve --config 'diff.git=1' -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
296 296 $ cat hg.pid >> $DAEMON_PIDS
297 297
298 298 revision
299 299
300 300 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'rev/0'
301 301 200 Script output follows
302 302
303 303 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
304 304 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
305 305 <head>
306 306 <link rel="icon" href="/static/hgicon.png" type="image/png" />
307 307 <meta name="robots" content="index, nofollow" />
308 308 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
309 309 <script type="text/javascript" src="/static/mercurial.js"></script>
310 310
311 311 <title>test: 0cd96de13884</title>
312 312 </head>
313 313 <body>
314 314 <div class="container">
315 315 <div class="menu">
316 316 <div class="logo">
317 317 <a href="http://mercurial.selenic.com/">
318 318 <img src="/static/hglogo.png" alt="mercurial" /></a>
319 319 </div>
320 320 <ul>
321 321 <li><a href="/shortlog/0cd96de13884">log</a></li>
322 322 <li><a href="/graph/0cd96de13884">graph</a></li>
323 323 <li><a href="/tags">tags</a></li>
324 324 <li><a href="/bookmarks">bookmarks</a></li>
325 325 <li><a href="/branches">branches</a></li>
326 326 </ul>
327 327 <ul>
328 328 <li class="active">changeset</li>
329 329 <li><a href="/raw-rev/0cd96de13884">raw</a></li>
330 330 <li><a href="/file/0cd96de13884">browse</a></li>
331 331 </ul>
332 332 <ul>
333 333
334 334 </ul>
335 335 <ul>
336 336 <li><a href="/help">help</a></li>
337 337 </ul>
338 338 </div>
339 339
340 340 <div class="main">
341 341
342 342 <h2><a href="/">test</a></h2>
343 343 <h3>changeset 0:0cd96de13884 </h3>
344 344
345 345 <form class="search" action="/log">
346 346
347 347 <p><input name="rev" id="search1" type="text" size="30" /></p>
348 348 <div id="hint">find changesets by author, revision,
349 349 files, or words in the commit message</div>
350 350 </form>
351 351
352 352 <div class="description">a</div>
353 353
354 354 <table id="changesetEntry">
355 355 <tr>
356 356 <th class="author">author</th>
357 357 <td class="author">&#116;&#101;&#115;&#116;</td>
358 358 </tr>
359 359 <tr>
360 360 <th class="date">date</th>
361 361 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td></tr>
362 362 <tr>
363 363 <th class="author">parents</th>
364 364 <td class="author"></td>
365 365 </tr>
366 366 <tr>
367 367 <th class="author">children</th>
368 368 <td class="author"> <a href="/rev/559edbd9ed20">559edbd9ed20</a></td>
369 369 </tr>
370 370 <tr>
371 371 <th class="files">files</th>
372 372 <td class="files"><a href="/file/0cd96de13884/a">a</a> <a href="/file/0cd96de13884/b">b</a> </td>
373 373 </tr>
374 374 <tr>
375 375 <th class="diffstat">diffstat</th>
376 376 <td class="diffstat">
377 377 2 files changed, 2 insertions(+), 0 deletions(-)
378 378
379 379 <a id="diffstatexpand" href="javascript:showDiffstat()"/>[<tt>+</tt>]</a>
380 380 <div id="diffstatdetails" style="display:none;">
381 381 <a href="javascript:hideDiffstat()"/>[<tt>-</tt>]</a>
382 382 <p>
383 383 <table> <tr class="parity0">
384 384 <td class="diffstat-file"><a href="#l1.1">a</a></td>
385 385 <td class="diffstat-total" align="right">1</td>
386 386 <td class="diffstat-graph">
387 387 <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
388 388 <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
389 389 </td>
390 390 </tr>
391 391 <tr class="parity1">
392 392 <td class="diffstat-file"><a href="#l2.1">b</a></td>
393 393 <td class="diffstat-total" align="right">1</td>
394 394 <td class="diffstat-graph">
395 395 <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
396 396 <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
397 397 </td>
398 398 </tr>
399 399 </table>
400 400 </div>
401 401 </td>
402 402 </tr>
403 403 </table>
404 404
405 405 <div class="overflow">
406 406 <div class="sourcefirst"> line diff</div>
407 407
408 408 <div class="source bottomline parity0"><pre><a href="#l1.1" id="l1.1"> 1.1</a> new file mode 100644
409 409 <a href="#l1.2" id="l1.2"> 1.2</a> <span class="minusline">--- /dev/null
410 410 </span><a href="#l1.3" id="l1.3"> 1.3</a> <span class="plusline">+++ b/a
411 411 </span><a href="#l1.4" id="l1.4"> 1.4</a> <span class="atline">@@ -0,0 +1,1 @@
412 412 </span><a href="#l1.5" id="l1.5"> 1.5</a> <span class="plusline">+a
413 413 </span></pre></div><div class="source bottomline parity1"><pre><a href="#l2.1" id="l2.1"> 2.1</a> new file mode 100644
414 414 <a href="#l2.2" id="l2.2"> 2.2</a> <span class="minusline">--- /dev/null
415 415 </span><a href="#l2.3" id="l2.3"> 2.3</a> <span class="plusline">+++ b/b
416 416 </span><a href="#l2.4" id="l2.4"> 2.4</a> <span class="atline">@@ -0,0 +1,1 @@
417 417 </span><a href="#l2.5" id="l2.5"> 2.5</a> <span class="plusline">+b
418 418 </span></pre></div>
419 419 </div>
420 420
421 421 </div>
422 422 </div>
423 423 <script type="text/javascript">process_dates()</script>
424 424
425 425
426 426 </body>
427 427 </html>
428 428
429 429
430 430 revision
431 431
432 432 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'raw-rev/0'
433 433 200 Script output follows
434 434
435 435
436 436 # HG changeset patch
437 437 # User test
438 438 # Date 0 0
439 439 # Node ID 0cd96de13884b090099512d4794ae87ad067ea8e
440 440
441 441 a
442 442
443 443 diff --git a/a b/a
444 444 new file mode 100644
445 445 --- /dev/null
446 446 +++ b/a
447 447 @@ -0,0 +1,1 @@
448 448 +a
449 449 diff --git a/b b/b
450 450 new file mode 100644
451 451 --- /dev/null
452 452 +++ b/b
453 453 @@ -0,0 +1,1 @@
454 454 +b
455 455
456 456
457 457 diff removed file
458 458
459 459 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'diff/tip/a'
460 460 200 Script output follows
461 461
462 462 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
463 463 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
464 464 <head>
465 465 <link rel="icon" href="/static/hgicon.png" type="image/png" />
466 466 <meta name="robots" content="index, nofollow" />
467 467 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
468 468 <script type="text/javascript" src="/static/mercurial.js"></script>
469 469
470 470 <title>test: a diff</title>
471 471 </head>
472 472 <body>
473 473
474 474 <div class="container">
475 475 <div class="menu">
476 476 <div class="logo">
477 477 <a href="http://mercurial.selenic.com/">
478 478 <img src="/static/hglogo.png" alt="mercurial" /></a>
479 479 </div>
480 480 <ul>
481 481 <li><a href="/shortlog/559edbd9ed20">log</a></li>
482 482 <li><a href="/graph/559edbd9ed20">graph</a></li>
483 483 <li><a href="/tags">tags</a></li>
484 484 <li><a href="/bookmarks">bookmarks</a></li>
485 485 <li><a href="/branches">branches</a></li>
486 486 </ul>
487 487 <ul>
488 488 <li><a href="/rev/559edbd9ed20">changeset</a></li>
489 489 <li><a href="/file/559edbd9ed20">browse</a></li>
490 490 </ul>
491 491 <ul>
492 492 <li><a href="/file/559edbd9ed20/a">file</a></li>
493 493 <li><a href="/file/tip/a">latest</a></li>
494 494 <li class="active">diff</li>
495 495 <li><a href="/comparison/559edbd9ed20/a">comparison</a></li>
496 496 <li><a href="/annotate/559edbd9ed20/a">annotate</a></li>
497 497 <li><a href="/log/559edbd9ed20/a">file log</a></li>
498 498 <li><a href="/raw-file/559edbd9ed20/a">raw</a></li>
499 499 </ul>
500 500 <ul>
501 501 <li><a href="/help">help</a></li>
502 502 </ul>
503 503 </div>
504 504
505 505 <div class="main">
506 506 <h2><a href="/">test</a></h2>
507 507 <h3>diff a @ 1:559edbd9ed20</h3>
508 508
509 509 <form class="search" action="/log">
510 510 <p></p>
511 511 <p><input name="rev" id="search1" type="text" size="30" /></p>
512 512 <div id="hint">find changesets by author, revision,
513 513 files, or words in the commit message</div>
514 514 </form>
515 515
516 516 <div class="description">b</div>
517 517
518 518 <table id="changesetEntry">
519 519 <tr>
520 520 <th>author</th>
521 521 <td>&#116;&#101;&#115;&#116;</td>
522 522 </tr>
523 523 <tr>
524 524 <th>date</th>
525 525 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
526 526 </tr>
527 527 <tr>
528 528 <th>parents</th>
529 529 <td></td>
530 530 </tr>
531 531 <tr>
532 532 <th>children</th>
533 533 <td></td>
534 534 </tr>
535 535
536 536 </table>
537 537
538 538 <div class="overflow">
539 539 <div class="sourcefirst"> line diff</div>
540 540
541 541 <div class="source bottomline parity0"><pre><a href="#l1.1" id="l1.1"> 1.1</a> old mode 100644
542 542 <a href="#l1.2" id="l1.2"> 1.2</a> new mode 100755
543 543 </pre></div>
544 544 </div>
545 545 </div>
546 546 </div>
547 547
548 548 <script type="text/javascript">process_dates()</script>
549 549
550 550
551 551 </body>
552 552 </html>
553 553
554 554
555 555 comparison new file
556 556
557 557 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'comparison/0/a'
558 558 200 Script output follows
559 559
560 560 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
561 561 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
562 562 <head>
563 563 <link rel="icon" href="/static/hgicon.png" type="image/png" />
564 564 <meta name="robots" content="index, nofollow" />
565 565 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
566 566 <script type="text/javascript" src="/static/mercurial.js"></script>
567 567
568 568 <title>test: a comparison</title>
569 569 </head>
570 570 <body>
571 571
572 572 <div class="container">
573 573 <div class="menu">
574 574 <div class="logo">
575 575 <a href="http://mercurial.selenic.com/">
576 576 <img src="/static/hglogo.png" alt="mercurial" /></a>
577 577 </div>
578 578 <ul>
579 579 <li><a href="/shortlog/0cd96de13884">log</a></li>
580 580 <li><a href="/graph/0cd96de13884">graph</a></li>
581 581 <li><a href="/tags">tags</a></li>
582 582 <li><a href="/bookmarks">bookmarks</a></li>
583 583 <li><a href="/branches">branches</a></li>
584 584 </ul>
585 585 <ul>
586 586 <li><a href="/rev/0cd96de13884">changeset</a></li>
587 587 <li><a href="/file/0cd96de13884">browse</a></li>
588 588 </ul>
589 589 <ul>
590 590 <li><a href="/file/0cd96de13884/a">file</a></li>
591 591 <li><a href="/file/tip/a">latest</a></li>
592 592 <li><a href="/diff/0cd96de13884/a">diff</a></li>
593 593 <li class="active">comparison</li>
594 594 <li><a href="/annotate/0cd96de13884/a">annotate</a></li>
595 595 <li><a href="/log/0cd96de13884/a">file log</a></li>
596 596 <li><a href="/raw-file/0cd96de13884/a">raw</a></li>
597 597 </ul>
598 598 <ul>
599 599 <li><a href="/help">help</a></li>
600 600 </ul>
601 601 </div>
602 602
603 603 <div class="main">
604 604 <h2><a href="/">test</a></h2>
605 605 <h3>comparison a @ 0:0cd96de13884</h3>
606 606
607 607 <form class="search" action="/log">
608 608 <p></p>
609 609 <p><input name="rev" id="search1" type="text" size="30" /></p>
610 610 <div id="hint">find changesets by author, revision,
611 611 files, or words in the commit message</div>
612 612 </form>
613 613
614 614 <div class="description">a</div>
615 615
616 616 <table id="changesetEntry">
617 617 <tr>
618 618 <th>author</th>
619 619 <td>&#116;&#101;&#115;&#116;</td>
620 620 </tr>
621 621 <tr>
622 622 <th>date</th>
623 623 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
624 624 </tr>
625 625 <tr>
626 626 <th>parents</th>
627 627 <td></td>
628 628 </tr>
629 629 <tr>
630 630 <th>children</th>
631 <td><a href="/file/559edbd9ed20/a">559edbd9ed20</a> </td>
631 <td></td>
632 632 </tr>
633 633
634 634 </table>
635 635
636 636 <div class="overflow">
637 637 <div class="sourcefirst"> comparison</div>
638 638 <div class="legend">
639 639 <span class="legendinfo equal">equal</span>
640 640 <span class="legendinfo delete">deleted</span>
641 641 <span class="legendinfo insert">inserted</span>
642 642 <span class="legendinfo replace">replaced</span>
643 643 </div>
644 644
645 645 <table class="bigtable">
646 646 <thead class="header">
647 647 <tr>
648 648 <th>-1:000000000000</th>
649 649 <th>0:b789fdd96dc2</th>
650 650 </tr>
651 651 </thead>
652 652
653 653 <tbody class="block">
654 654
655 655 <tr>
656 656 <td class="source insert"><a href="#r1" id="r1"> </a> </td>
657 657 <td class="source insert"><a href="#r1" id="r1"> 1</a> a</td>
658 658 </tr>
659 659 </tbody>
660 660 </table>
661 661
662 662 </div>
663 663 </div>
664 664 </div>
665 665
666 666 <script type="text/javascript">process_dates()</script>
667 667
668 668
669 669 </body>
670 670 </html>
671 671
672 672
673 673 comparison existing file
674 674
675 675 $ hg up
676 676 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
677 677 $ echo a >> a
678 678 $ hg ci -mc
679 679 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'comparison/tip/a'
680 680 200 Script output follows
681 681
682 682 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
683 683 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
684 684 <head>
685 685 <link rel="icon" href="/static/hgicon.png" type="image/png" />
686 686 <meta name="robots" content="index, nofollow" />
687 687 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
688 688 <script type="text/javascript" src="/static/mercurial.js"></script>
689 689
690 690 <title>test: a comparison</title>
691 691 </head>
692 692 <body>
693 693
694 694 <div class="container">
695 695 <div class="menu">
696 696 <div class="logo">
697 697 <a href="http://mercurial.selenic.com/">
698 698 <img src="/static/hglogo.png" alt="mercurial" /></a>
699 699 </div>
700 700 <ul>
701 701 <li><a href="/shortlog/d73db4d812ff">log</a></li>
702 702 <li><a href="/graph/d73db4d812ff">graph</a></li>
703 703 <li><a href="/tags">tags</a></li>
704 704 <li><a href="/bookmarks">bookmarks</a></li>
705 705 <li><a href="/branches">branches</a></li>
706 706 </ul>
707 707 <ul>
708 708 <li><a href="/rev/d73db4d812ff">changeset</a></li>
709 709 <li><a href="/file/d73db4d812ff">browse</a></li>
710 710 </ul>
711 711 <ul>
712 712 <li><a href="/file/d73db4d812ff/a">file</a></li>
713 713 <li><a href="/file/tip/a">latest</a></li>
714 714 <li><a href="/diff/d73db4d812ff/a">diff</a></li>
715 715 <li class="active">comparison</li>
716 716 <li><a href="/annotate/d73db4d812ff/a">annotate</a></li>
717 717 <li><a href="/log/d73db4d812ff/a">file log</a></li>
718 718 <li><a href="/raw-file/d73db4d812ff/a">raw</a></li>
719 719 </ul>
720 720 <ul>
721 721 <li><a href="/help">help</a></li>
722 722 </ul>
723 723 </div>
724 724
725 725 <div class="main">
726 726 <h2><a href="/">test</a></h2>
727 727 <h3>comparison a @ 2:d73db4d812ff</h3>
728 728
729 729 <form class="search" action="/log">
730 730 <p></p>
731 731 <p><input name="rev" id="search1" type="text" size="30" /></p>
732 732 <div id="hint">find changesets by author, revision,
733 733 files, or words in the commit message</div>
734 734 </form>
735 735
736 736 <div class="description">c</div>
737 737
738 738 <table id="changesetEntry">
739 739 <tr>
740 740 <th>author</th>
741 741 <td>&#116;&#101;&#115;&#116;</td>
742 742 </tr>
743 743 <tr>
744 744 <th>date</th>
745 745 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
746 746 </tr>
747 747 <tr>
748 748 <th>parents</th>
749 <td><a href="/file/559edbd9ed20/a">559edbd9ed20</a> </td>
749 <td><a href="/file/0cd96de13884/a">0cd96de13884</a> </td>
750 750 </tr>
751 751 <tr>
752 752 <th>children</th>
753 753 <td></td>
754 754 </tr>
755 755
756 756 </table>
757 757
758 758 <div class="overflow">
759 759 <div class="sourcefirst"> comparison</div>
760 760 <div class="legend">
761 761 <span class="legendinfo equal">equal</span>
762 762 <span class="legendinfo delete">deleted</span>
763 763 <span class="legendinfo insert">inserted</span>
764 764 <span class="legendinfo replace">replaced</span>
765 765 </div>
766 766
767 767 <table class="bigtable">
768 768 <thead class="header">
769 769 <tr>
770 770 <th>0:b789fdd96dc2</th>
771 771 <th>1:a80d06849b33</th>
772 772 </tr>
773 773 </thead>
774 774
775 775 <tbody class="block">
776 776
777 777 <tr>
778 778 <td class="source equal"><a href="#l1r1" id="l1r1"> 1</a> a</td>
779 779 <td class="source equal"><a href="#l1r1" id="l1r1"> 1</a> a</td>
780 780 </tr>
781 781 <tr>
782 782 <td class="source insert"><a href="#r2" id="r2"> </a> </td>
783 783 <td class="source insert"><a href="#r2" id="r2"> 2</a> a</td>
784 784 </tr>
785 785 </tbody>
786 786 </table>
787 787
788 788 </div>
789 789 </div>
790 790 </div>
791 791
792 792 <script type="text/javascript">process_dates()</script>
793 793
794 794
795 795 </body>
796 796 </html>
797 797
798 798
799 799 comparison removed file
800 800
801 801 $ hg rm a
802 802 $ hg ci -md
803 803 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'comparison/tip/a'
804 804 200 Script output follows
805 805
806 806 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
807 807 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
808 808 <head>
809 809 <link rel="icon" href="/static/hgicon.png" type="image/png" />
810 810 <meta name="robots" content="index, nofollow" />
811 811 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
812 812 <script type="text/javascript" src="/static/mercurial.js"></script>
813 813
814 814 <title>test: a comparison</title>
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="http://mercurial.selenic.com/">
822 822 <img src="/static/hglogo.png" alt="mercurial" /></a>
823 823 </div>
824 824 <ul>
825 825 <li><a href="/shortlog/20e80271eb7a">log</a></li>
826 826 <li><a href="/graph/20e80271eb7a">graph</a></li>
827 827 <li><a href="/tags">tags</a></li>
828 828 <li><a href="/bookmarks">bookmarks</a></li>
829 829 <li><a href="/branches">branches</a></li>
830 830 </ul>
831 831 <ul>
832 832 <li><a href="/rev/20e80271eb7a">changeset</a></li>
833 833 <li><a href="/file/20e80271eb7a">browse</a></li>
834 834 </ul>
835 835 <ul>
836 836 <li><a href="/file/20e80271eb7a/a">file</a></li>
837 837 <li><a href="/file/tip/a">latest</a></li>
838 838 <li><a href="/diff/20e80271eb7a/a">diff</a></li>
839 839 <li class="active">comparison</li>
840 840 <li><a href="/annotate/20e80271eb7a/a">annotate</a></li>
841 841 <li><a href="/log/20e80271eb7a/a">file log</a></li>
842 842 <li><a href="/raw-file/20e80271eb7a/a">raw</a></li>
843 843 </ul>
844 844 <ul>
845 845 <li><a href="/help">help</a></li>
846 846 </ul>
847 847 </div>
848 848
849 849 <div class="main">
850 850 <h2><a href="/">test</a></h2>
851 851 <h3>comparison a @ 3:20e80271eb7a</h3>
852 852
853 853 <form class="search" action="/log">
854 854 <p></p>
855 855 <p><input name="rev" id="search1" type="text" size="30" /></p>
856 856 <div id="hint">find changesets by author, revision,
857 857 files, or words in the commit message</div>
858 858 </form>
859 859
860 860 <div class="description">d</div>
861 861
862 862 <table id="changesetEntry">
863 863 <tr>
864 864 <th>author</th>
865 865 <td>&#116;&#101;&#115;&#116;</td>
866 866 </tr>
867 867 <tr>
868 868 <th>date</th>
869 869 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
870 870 </tr>
871 871 <tr>
872 872 <th>parents</th>
873 <td><a href="/file/d73db4d812ff/a">d73db4d812ff</a> </td>
873 <td><a href="/file/0cd96de13884/a">0cd96de13884</a> </td>
874 874 </tr>
875 875 <tr>
876 876 <th>children</th>
877 877 <td></td>
878 878 </tr>
879 879
880 880 </table>
881 881
882 882 <div class="overflow">
883 883 <div class="sourcefirst"> comparison</div>
884 884 <div class="legend">
885 885 <span class="legendinfo equal">equal</span>
886 886 <span class="legendinfo delete">deleted</span>
887 887 <span class="legendinfo insert">inserted</span>
888 888 <span class="legendinfo replace">replaced</span>
889 889 </div>
890 890
891 891 <table class="bigtable">
892 892 <thead class="header">
893 893 <tr>
894 894 <th>1:a80d06849b33</th>
895 895 <th>-1:000000000000</th>
896 896 </tr>
897 897 </thead>
898 898
899 899 <tbody class="block">
900 900
901 901 <tr>
902 902 <td class="source delete"><a href="#l1" id="l1"> 1</a> a</td>
903 903 <td class="source delete"><a href="#l1" id="l1"> </a> </td>
904 904 </tr>
905 905 <tr>
906 906 <td class="source delete"><a href="#l2" id="l2"> 2</a> a</td>
907 907 <td class="source delete"><a href="#l2" id="l2"> </a> </td>
908 908 </tr>
909 909 </tbody>
910 910 </table>
911 911
912 912 </div>
913 913 </div>
914 914 </div>
915 915
916 916 <script type="text/javascript">process_dates()</script>
917 917
918 918
919 919 </body>
920 920 </html>
921 921
922 922
923 923 $ cd ..
924 924
925 925 test import rev as raw-rev
926 926
927 927 $ hg clone -r0 test test1
928 928 adding changesets
929 929 adding manifests
930 930 adding file changes
931 931 added 1 changesets with 2 changes to 2 files
932 932 updating to branch default
933 933 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
934 934 $ cd test1
935 935 $ hg import -q --bypass --exact http://localhost:$HGPORT/rev/1
936 936
937 937 raw revision with diff block numbers
938 938
939 939 $ "$TESTDIR/killdaemons.py"
940 940 $ cat <<EOF > .hg/hgrc
941 941 > [web]
942 942 > templates = rawdiff
943 943 > EOF
944 944 $ mkdir rawdiff
945 945 $ cat <<EOF > rawdiff/map
946 946 > mimetype = 'text/plain; charset={encoding}'
947 947 > changeset = '{diff}'
948 948 > difflineplus = '{line}'
949 949 > difflineminus = '{line}'
950 950 > difflineat = '{line}'
951 951 > diffline = '{line}'
952 952 > filenodelink = ''
953 953 > filenolink = ''
954 954 > fileline = '{line}'
955 955 > diffblock = 'Block: {blockno}\n{lines}\n'
956 956 > EOF
957 957 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
958 958 $ cat hg.pid >> $DAEMON_PIDS
959 959 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'raw-rev/0'
960 960 200 Script output follows
961 961
962 962 Block: 1
963 963 diff -r 000000000000 -r 0cd96de13884 a
964 964 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
965 965 +++ b/a Thu Jan 01 00:00:00 1970 +0000
966 966 @@ -0,0 +1,1 @@
967 967 +a
968 968
969 969 Block: 2
970 970 diff -r 000000000000 -r 0cd96de13884 b
971 971 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
972 972 +++ b/b Thu Jan 01 00:00:00 1970 +0000
973 973 @@ -0,0 +1,1 @@
974 974 +b
975 975
976 976 $ "$TESTDIR/killdaemons.py"
977 977 $ rm .hg/hgrc rawdiff/map
978 978 $ rmdir rawdiff
979 979 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
980 980 $ cat hg.pid >> $DAEMON_PIDS
981 981
982 982 errors
983 983
984 984 $ cat ../test/errors.log
985 985
986 986 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now