##// END OF EJS Templates
Add multiple keyword search to hgweb...
mpm@selenic.com -
r538:7140bc78 default
parent child Browse files
Show More
@@ -0,0 +1,28 b''
1 #header#
2 <title>#repo|escape#: searching for #query|escape#</title>
3 </head>
4 <body>
5
6 <div class="buttons">
7 <a href="?cmd=changelog;rev=#rev#">changelog</a>
8 <a href="?cmd=tags">tags</a>
9 <a href="?cmd=manifest;manifest=#manifest#;path=/">manifest</a>
10 </div>
11
12 <h2>searching for #query|escape#</h2>
13
14 <form>
15 search:
16 <input type="hidden" name="cmd" value="changelog">
17 <input name="rev" type="text" width="30" value="#query|escape#">
18 </form>
19
20 #entries#
21
22 <form>
23 search:
24 <input type="hidden" name="cmd" value="changelog">
25 <input name="rev" type="text" width="30">
26 </form>
27
28 #footer#
@@ -0,0 +1,22 b''
1 <div class="parity#parity#">
2 <table width="100%" cellpadding="0" cellspacing="0">
3 <tr>
4 <td align="right" width="15%"><b>#date|age# ago:&nbsp;</b></td>
5 <td><b>#desc|firstline|escape#</b></td></tr>
6 <tr>
7 <td align="right">changeset #rev#:&nbsp;</td>
8 <td><a href="?cmd=changeset;node=#node#">#node|short#</a></td></tr>
9 #parent1#
10 #parent2#
11 <tr>
12 <td align="right">author:&nbsp;</td>
13 <td>#author|obfuscate#</td></tr>
14 <tr>
15 <td align="right">date:&nbsp;</td>
16 <td>#date|date#</td></tr>
17 <tr>
18 <td align="right" valign="top"><a href="?cmd=manifest;manifest=#manifest#;path=/">files</a>:&nbsp;</td>
19 <td>#files#</td></tr>
20 </table>
21 </div>
22
@@ -1,722 +1,787 b''
1 1 # hgweb.py - web interface to a mercurial repository
2 2 #
3 3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
4 4 # Copyright 2005 Matt Mackall <mpm@selenic.com>
5 5 #
6 6 # This software may be used and distributed according to the terms
7 7 # of the GNU General Public License, incorporated herein by reference.
8 8
9 9 import os, cgi, time, re, difflib, sys, zlib
10 10 from mercurial.hg import *
11 11 from mercurial.ui import *
12 12
13 13 def templatepath():
14 14 for f in "templates", "../templates":
15 15 p = os.path.join(os.path.dirname(__file__), f)
16 16 if os.path.isdir(p): return p
17 17
18 18 def age(t):
19 19 def plural(t, c):
20 20 if c == 1: return t
21 21 return t + "s"
22 22 def fmt(t, c):
23 23 return "%d %s" % (c, plural(t, c))
24 24
25 25 now = time.time()
26 26 delta = max(1, int(now - t))
27 27
28 28 scales = [["second", 1],
29 29 ["minute", 60],
30 30 ["hour", 3600],
31 31 ["day", 3600 * 24],
32 32 ["week", 3600 * 24 * 7],
33 33 ["month", 3600 * 24 * 30],
34 34 ["year", 3600 * 24 * 365]]
35 35
36 36 scales.reverse()
37 37
38 38 for t, s in scales:
39 39 n = delta / s
40 40 if n >= 2 or s == 1: return fmt(t, n)
41 41
42 42 def nl2br(text):
43 43 return text.replace('\n', '<br/>\n')
44 44
45 45 def obfuscate(text):
46 46 return ''.join([ '&#%d;' % ord(c) for c in text ])
47 47
48 48 def up(p):
49 49 if p[0] != "/": p = "/" + p
50 50 if p[-1] == "/": p = p[:-1]
51 51 up = os.path.dirname(p)
52 52 if up == "/":
53 53 return "/"
54 54 return up + "/"
55 55
56 56 def httphdr(type):
57 57 print 'Content-type: %s\n' % type
58 58
59 59 def write(*things):
60 60 for thing in things:
61 61 if hasattr(thing, "__iter__"):
62 62 for part in thing:
63 63 write(part)
64 64 else:
65 65 sys.stdout.write(str(thing))
66 66
67 67 def template(tmpl, filters = {}, **map):
68 68 while tmpl:
69 69 m = re.search(r"#([a-zA-Z0-9]+)((\|[a-zA-Z0-9]+)*)#", tmpl)
70 70 if m:
71 71 yield tmpl[:m.start(0)]
72 72 v = map.get(m.group(1), "")
73 73 v = callable(v) and v() or v
74 74
75 75 fl = m.group(2)
76 76 if fl:
77 77 for f in fl.split("|")[1:]:
78 78 v = filters[f](v)
79 79
80 80 yield v
81 81 tmpl = tmpl[m.end(0):]
82 82 else:
83 83 yield tmpl
84 84 return
85 85
86 86 class templater:
87 87 def __init__(self, mapfile, filters = {}):
88 88 self.cache = {}
89 89 self.map = {}
90 90 self.base = os.path.dirname(mapfile)
91 91 self.filters = filters
92 92
93 93 for l in file(mapfile):
94 94 m = re.match(r'(\S+)\s*=\s*"(.*)"$', l)
95 95 if m:
96 96 self.cache[m.group(1)] = m.group(2)
97 97 else:
98 98 m = re.match(r'(\S+)\s*=\s*(\S+)', l)
99 99 if m:
100 100 self.map[m.group(1)] = os.path.join(self.base, m.group(2))
101 101 else:
102 102 raise "unknown map entry '%s'" % l
103 103
104 104 def __call__(self, t, **map):
105 105 try:
106 106 tmpl = self.cache[t]
107 107 except KeyError:
108 108 tmpl = self.cache[t] = file(self.map[t]).read()
109 109 return template(tmpl, self.filters, **map)
110 110
111 111 class hgweb:
112 112 maxchanges = 10
113 113 maxfiles = 10
114 114
115 115 def __init__(self, path, name, templates = ""):
116 116 self.templates = templates or templatepath()
117 117 self.reponame = name
118 118 self.path = path
119 119 self.mtime = -1
120 120 self.viewonly = 0
121 121
122 122 self.filters = {
123 123 "escape": cgi.escape,
124 124 "age": age,
125 125 "date": (lambda x: time.asctime(time.gmtime(x))),
126 126 "addbreaks": nl2br,
127 127 "obfuscate": obfuscate,
128 128 "short": (lambda x: x[:12]),
129 129 "firstline": (lambda x: x.splitlines(1)[0]),
130 130 "permissions": (lambda x: x and "-rwxr-xr-x" or "-rw-r--r--")
131 131 }
132 132
133 133 def refresh(self):
134 134 s = os.stat(os.path.join(self.path, ".hg", "00changelog.i"))
135 135 if s.st_mtime != self.mtime:
136 136 self.mtime = s.st_mtime
137 137 self.repo = repository(ui(), self.path)
138 138
139 139 def date(self, cs):
140 140 return time.asctime(time.gmtime(float(cs[2].split(' ')[0])))
141 141
142 142 def listfiles(self, files, mf):
143 143 for f in files[:self.maxfiles]:
144 144 yield self.t("filenodelink", node = hex(mf[f]), file = f)
145 145 if len(files) > self.maxfiles:
146 146 yield self.t("fileellipses")
147 147
148 148 def listfilediffs(self, files, changeset):
149 149 for f in files[:self.maxfiles]:
150 150 yield self.t("filedifflink", node = hex(changeset), file = f)
151 151 if len(files) > self.maxfiles:
152 152 yield self.t("fileellipses")
153 153
154 154 def parent(self, t1, node=nullid, rev=-1, **args):
155 155 if node != hex(nullid):
156 156 yield self.t(t1, node = node, rev = rev, **args)
157 157
158 158 def diff(self, node1, node2, files):
159 159 def filterfiles(list, files):
160 160 l = [ x for x in list if x in files ]
161 161
162 162 for f in files:
163 163 if f[-1] != os.sep: f += os.sep
164 164 l += [ x for x in list if x.startswith(f) ]
165 165 return l
166 166
167 167 parity = [0]
168 168 def diffblock(diff, f, fn):
169 169 yield self.t("diffblock",
170 170 lines = prettyprintlines(diff),
171 171 parity = parity[0],
172 172 file = f,
173 173 filenode = hex(fn or nullid))
174 174 parity[0] = 1 - parity[0]
175 175
176 176 def prettyprintlines(diff):
177 177 for l in diff.splitlines(1):
178 178 if l.startswith('+'):
179 179 yield self.t("difflineplus", line = l)
180 180 elif l.startswith('-'):
181 181 yield self.t("difflineminus", line = l)
182 182 elif l.startswith('@'):
183 183 yield self.t("difflineat", line = l)
184 184 else:
185 185 yield self.t("diffline", line = l)
186 186
187 187 r = self.repo
188 188 cl = r.changelog
189 189 mf = r.manifest
190 190 change1 = cl.read(node1)
191 191 change2 = cl.read(node2)
192 192 mmap1 = mf.read(change1[0])
193 193 mmap2 = mf.read(change2[0])
194 194 date1 = self.date(change1)
195 195 date2 = self.date(change2)
196 196
197 197 c, a, d = r.changes(node1, node2)
198 198 c, a, d = map(lambda x: filterfiles(x, files), (c, a, d))
199 199
200 200 for f in c:
201 201 to = r.file(f).read(mmap1[f])
202 202 tn = r.file(f).read(mmap2[f])
203 203 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f), f, tn)
204 204 for f in a:
205 205 to = None
206 206 tn = r.file(f).read(mmap2[f])
207 207 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f), f, tn)
208 208 for f in d:
209 209 to = r.file(f).read(mmap1[f])
210 210 tn = None
211 211 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f), f, tn)
212 212
213 213 def header(self):
214 214 yield self.t("header", repo = self.reponame)
215 215
216 216 def footer(self):
217 217 yield self.t("footer", repo = self.reponame)
218 218
219 219 def changelog(self, pos):
220 220 def changenav():
221 221 def seq(factor = 1):
222 222 yield 1 * factor
223 223 yield 3 * factor
224 224 #yield 5 * factor
225 225 for f in seq(factor * 10):
226 226 yield f
227 227
228 228 l = []
229 229 for f in seq():
230 230 if f < self.maxchanges / 2: continue
231 231 if f > count: break
232 232 r = "%d" % f
233 233 if pos + f < count: l.append(("+" + r, pos + f))
234 234 if pos - f >= 0: l.insert(0, ("-" + r, pos - f))
235 235
236 236 yield self.t("naventry", rev = 0, label="(0)")
237 237
238 238 for label, rev in l:
239 239 yield self.t("naventry", label = label, rev = rev)
240 240
241 241 yield self.t("naventry", label="tip")
242 242
243 243 def changelist():
244 244 parity = (start - end) & 1
245 245 cl = self.repo.changelog
246 246 l = [] # build a list in forward order for efficiency
247 247 for i in range(start, end):
248 248 n = cl.node(i)
249 249 changes = cl.read(n)
250 250 hn = hex(n)
251 251 p1, p2 = cl.parents(n)
252 252 t = float(changes[2].split(' ')[0])
253 253
254 254 l.insert(0, self.t(
255 255 'changelogentry',
256 256 parity = parity,
257 257 author = changes[1],
258 258 parent1 = self.parent("changelogparent",
259 259 hex(p1), cl.rev(p1)),
260 260 parent2 = self.parent("changelogparent",
261 261 hex(p2), cl.rev(p2)),
262 262 p1 = hex(p1), p2 = hex(p2),
263 263 p1rev = cl.rev(p1), p2rev = cl.rev(p2),
264 264 manifest = hex(changes[0]),
265 265 desc = changes[4],
266 266 date = t,
267 267 files = self.listfilediffs(changes[3], n),
268 268 rev = i,
269 269 node = hn))
270 270 parity = 1 - parity
271 271
272 272 yield l
273 273
274 274 cl = self.repo.changelog
275 275 mf = cl.read(cl.tip())[0]
276 276 count = cl.count()
277 277 start = max(0, pos - self.maxchanges + 1)
278 278 end = min(count, start + self.maxchanges)
279 279 pos = end - 1
280 280
281 281 yield self.t('changelog',
282 282 header = self.header(),
283 283 footer = self.footer(),
284 284 repo = self.reponame,
285 285 changenav = changenav,
286 286 manifest = hex(mf),
287 287 rev = pos, changesets = count, entries = changelist)
288 288
289 def search(self, query):
290
291 def changelist():
292 cl = self.repo.changelog
293 count = 0
294 qw = query.lower().split()
295
296 def revgen():
297 for i in range(cl.count() - 1, 0, -100):
298 l = []
299 for j in range(max(0, i - 100), i):
300 n = cl.node(j)
301 changes = cl.read(n)
302 l.insert(0, (n, j, changes))
303 for e in l:
304 yield e
305
306 for n, i, changes in revgen():
307 miss = 0
308 for q in qw:
309 if not (q in changes[1].lower() or
310 q in changes[4].lower() or
311 q in " ".join(changes[3][:20]).lower()):
312 miss = 1
313 break
314 if miss: continue
315
316 count += 1
317 hn = hex(n)
318 p1, p2 = cl.parents(n)
319 t = float(changes[2].split(' ')[0])
320
321 yield self.t(
322 'searchentry',
323 parity = count & 1,
324 author = changes[1],
325 parent1 = self.parent("changelogparent",
326 hex(p1), cl.rev(p1)),
327 parent2 = self.parent("changelogparent",
328 hex(p2), cl.rev(p2)),
329 p1 = hex(p1), p2 = hex(p2),
330 p1rev = cl.rev(p1), p2rev = cl.rev(p2),
331 manifest = hex(changes[0]),
332 desc = changes[4],
333 date = t,
334 files = self.listfilediffs(changes[3], n),
335 rev = i,
336 node = hn)
337
338 if count >= self.maxchanges: break
339
340 cl = self.repo.changelog
341 mf = cl.read(cl.tip())[0]
342
343 yield self.t('search',
344 header = self.header(),
345 footer = self.footer(),
346 query = query,
347 repo = self.reponame,
348 manifest = hex(mf),
349 entries = changelist)
350
289 351 def changeset(self, nodeid):
290 352 n = bin(nodeid)
291 353 cl = self.repo.changelog
292 354 changes = cl.read(n)
293 355 p1, p2 = cl.parents(n)
294 356 p1rev, p2rev = cl.rev(p1), cl.rev(p2)
295 357 t = float(changes[2].split(' ')[0])
296 358
297 359 files = []
298 360 mf = self.repo.manifest.read(changes[0])
299 361 for f in changes[3]:
300 362 files.append(self.t("filenodelink",
301 363 filenode = hex(mf.get(f, nullid)), file = f))
302 364
303 365 def diff():
304 366 yield self.diff(p1, n, changes[3])
305 367
306 368 yield self.t('changeset',
307 369 header = self.header(),
308 370 footer = self.footer(),
309 371 repo = self.reponame,
310 372 diff = diff,
311 373 rev = cl.rev(n),
312 374 node = nodeid,
313 375 parent1 = self.parent("changesetparent",
314 376 hex(p1), cl.rev(p1)),
315 377 parent2 = self.parent("changesetparent",
316 378 hex(p2), cl.rev(p2)),
317 379 p1 = hex(p1), p2 = hex(p2),
318 380 p1rev = cl.rev(p1), p2rev = cl.rev(p2),
319 381 manifest = hex(changes[0]),
320 382 author = changes[1],
321 383 desc = changes[4],
322 384 date = t,
323 385 files = files)
324 386
325 387 def filelog(self, f, filenode):
326 388 cl = self.repo.changelog
327 389 fl = self.repo.file(f)
328 390 count = fl.count()
329 391
330 392 def entries():
331 393 l = []
332 394 parity = (count - 1) & 1
333 395
334 396 for i in range(count):
335 397
336 398 n = fl.node(i)
337 399 lr = fl.linkrev(n)
338 400 cn = cl.node(lr)
339 401 cs = cl.read(cl.node(lr))
340 402 p1, p2 = fl.parents(n)
341 403 t = float(cs[2].split(' ')[0])
342 404
343 405 l.insert(0, self.t("filelogentry",
344 406 parity = parity,
345 407 filenode = hex(n),
346 408 filerev = i,
347 409 file = f,
348 410 node = hex(cn),
349 411 author = cs[1],
350 412 date = t,
351 413 desc = cs[4],
352 414 p1 = hex(p1), p2 = hex(p2),
353 415 p1rev = fl.rev(p1), p2rev = fl.rev(p2)))
354 416 parity = 1 - parity
355 417
356 418 yield l
357 419
358 420 yield self.t("filelog",
359 421 header = self.header(),
360 422 footer = self.footer(),
361 423 repo = self.reponame,
362 424 file = f,
363 425 filenode = filenode,
364 426 entries = entries)
365 427
366 428 def filerevision(self, f, node):
367 429 fl = self.repo.file(f)
368 430 n = bin(node)
369 431 text = fl.read(n)
370 432 changerev = fl.linkrev(n)
371 433 cl = self.repo.changelog
372 434 cn = cl.node(changerev)
373 435 cs = cl.read(cn)
374 436 p1, p2 = fl.parents(n)
375 437 t = float(cs[2].split(' ')[0])
376 438 mfn = cs[0]
377 439
378 440 def lines():
379 441 for l, t in enumerate(text.splitlines(1)):
380 442 yield self.t("fileline", line = t,
381 443 linenumber = "% 6d" % (l + 1),
382 444 parity = l & 1)
383 445
384 446 yield self.t("filerevision", file = f,
385 447 header = self.header(),
386 448 footer = self.footer(),
387 449 repo = self.reponame,
388 450 filenode = node,
389 451 path = up(f),
390 452 text = lines(),
391 453 rev = changerev,
392 454 node = hex(cn),
393 455 manifest = hex(mfn),
394 456 author = cs[1],
395 457 date = t,
396 458 parent1 = self.parent("filerevparent",
397 459 hex(p1), fl.rev(p1), file=f),
398 460 parent2 = self.parent("filerevparent",
399 461 hex(p2), fl.rev(p2), file=f),
400 462 p1 = hex(p1), p2 = hex(p2),
401 463 permissions = self.repo.manifest.readflags(mfn)[f],
402 464 p1rev = fl.rev(p1), p2rev = fl.rev(p2))
403 465
404 466 def fileannotate(self, f, node):
405 467 bcache = {}
406 468 ncache = {}
407 469 fl = self.repo.file(f)
408 470 n = bin(node)
409 471 changerev = fl.linkrev(n)
410 472
411 473 cl = self.repo.changelog
412 474 cn = cl.node(changerev)
413 475 cs = cl.read(cn)
414 476 p1, p2 = fl.parents(n)
415 477 t = float(cs[2].split(' ')[0])
416 478 mfn = cs[0]
417 479
418 480 def annotate():
419 481 parity = 1
420 482 last = None
421 483 for r, l in fl.annotate(n):
422 484 try:
423 485 cnode = ncache[r]
424 486 except KeyError:
425 487 cnode = ncache[r] = self.repo.changelog.node(r)
426 488
427 489 try:
428 490 name = bcache[r]
429 491 except KeyError:
430 492 cl = self.repo.changelog.read(cnode)
431 493 name = cl[1]
432 494 f = name.find('@')
433 495 if f >= 0:
434 496 name = name[:f]
435 497 f = name.find('<')
436 498 if f >= 0:
437 499 name = name[f+1:]
438 500 bcache[r] = name
439 501
440 502 if last != cnode:
441 503 parity = 1 - parity
442 504 last = cnode
443 505
444 506 yield self.t("annotateline",
445 507 parity = parity,
446 508 node = hex(cnode),
447 509 rev = r,
448 510 author = name,
449 511 file = f,
450 512 line = l)
451 513
452 514 yield self.t("fileannotate",
453 515 header = self.header(),
454 516 footer = self.footer(),
455 517 repo = self.reponame,
456 518 file = f,
457 519 filenode = node,
458 520 annotate = annotate,
459 521 path = up(f),
460 522 rev = changerev,
461 523 node = hex(cn),
462 524 manifest = hex(mfn),
463 525 author = cs[1],
464 526 date = t,
465 527 parent1 = self.parent("fileannotateparent",
466 528 hex(p1), fl.rev(p1), file=f),
467 529 parent2 = self.parent("fileannotateparent",
468 530 hex(p2), fl.rev(p2), file=f),
469 531 p1 = hex(p1), p2 = hex(p2),
470 532 permissions = self.repo.manifest.readflags(mfn)[f],
471 533 p1rev = fl.rev(p1), p2rev = fl.rev(p2))
472 534
473 535 def manifest(self, mnode, path):
474 536 mf = self.repo.manifest.read(bin(mnode))
475 537 rev = self.repo.manifest.rev(bin(mnode))
476 538 node = self.repo.changelog.node(rev)
477 539 mff=self.repo.manifest.readflags(bin(mnode))
478 540
479 541 files = {}
480 542
481 543 p = path[1:]
482 544 l = len(p)
483 545
484 546 for f,n in mf.items():
485 547 if f[:l] != p:
486 548 continue
487 549 remain = f[l:]
488 550 if "/" in remain:
489 551 short = remain[:remain.find("/") + 1] # bleah
490 552 files[short] = (f, None)
491 553 else:
492 554 short = os.path.basename(remain)
493 555 files[short] = (f, n)
494 556
495 557 def filelist():
496 558 parity = 0
497 559 fl = files.keys()
498 560 fl.sort()
499 561 for f in fl:
500 562 full, fnode = files[f]
501 563 if fnode:
502 564 yield self.t("manifestfileentry",
503 565 file = full,
504 566 manifest = mnode,
505 567 filenode = hex(fnode),
506 568 parity = parity,
507 569 basename = f,
508 570 permissions = mff[full])
509 571 else:
510 572 yield self.t("manifestdirentry",
511 573 parity = parity,
512 574 path = os.path.join(path, f),
513 575 manifest = mnode, basename = f[:-1])
514 576 parity = 1 - parity
515 577
516 578 yield self.t("manifest",
517 579 header = self.header(),
518 580 footer = self.footer(),
519 581 repo = self.reponame,
520 582 manifest = mnode,
521 583 rev = rev,
522 584 node = hex(node),
523 585 path = path,
524 586 up = up(path),
525 587 entries = filelist)
526 588
527 589 def tags(self):
528 590 cl = self.repo.changelog
529 591 mf = cl.read(cl.tip())[0]
530 592
531 593 i = self.repo.tagslist()
532 594 i.reverse()
533 595
534 596 def entries():
535 597 parity = 0
536 598 for k,n in i:
537 599 yield self.t("tagentry",
538 600 parity = parity,
539 601 tag = k,
540 602 node = hex(n))
541 603 parity = 1 - parity
542 604
543 605 yield self.t("tags",
544 606 header = self.header(),
545 607 footer = self.footer(),
546 608 repo = self.reponame,
547 609 manifest = hex(mf),
548 610 entries = entries)
549 611
550 612 def filediff(self, file, changeset):
551 613 n = bin(changeset)
552 614 cl = self.repo.changelog
553 615 p1 = cl.parents(n)[0]
554 616 cs = cl.read(n)
555 617 mf = self.repo.manifest.read(cs[0])
556 618
557 619 def diff():
558 620 yield self.diff(p1, n, file)
559 621
560 622 yield self.t("filediff",
561 623 header = self.header(),
562 624 footer = self.footer(),
563 625 repo = self.reponame,
564 626 file = file,
565 627 filenode = hex(mf.get(file, nullid)),
566 628 node = changeset,
567 629 rev = self.repo.changelog.rev(n),
568 630 p1 = hex(p1),
569 631 p1rev = self.repo.changelog.rev(p1),
570 632 diff = diff)
571 633
572 634 # add tags to things
573 635 # tags -> list of changesets corresponding to tags
574 636 # find tag, changeset, file
575 637
576 638 def run(self):
577 639 self.refresh()
578 640 args = cgi.parse()
579 641
580 642 m = os.path.join(self.templates, "map")
581 643 if args.has_key('style'):
582 644 b = os.path.basename("map-" + args['style'][0])
583 645 p = os.path.join(self.templates, b)
584 646 if os.path.isfile(p): m = p
585 647
586 648 self.t = templater(m, self.filters)
587 649
588 650 if not args.has_key('cmd') or args['cmd'][0] == 'changelog':
589 hi = self.repo.changelog.count() - 1
651 c = self.repo.changelog.count() - 1
652 hi = c
590 653 if args.has_key('rev'):
591 654 hi = args['rev'][0]
592 655 try:
593 656 hi = self.repo.changelog.rev(self.repo.lookup(hi))
594 except KeyError: pass
595
657 except KeyError:
658 write(self.search(hi))
659 return
660
596 661 write(self.changelog(hi))
597 662
598 663 elif args['cmd'][0] == 'changeset':
599 664 write(self.changeset(args['node'][0]))
600 665
601 666 elif args['cmd'][0] == 'manifest':
602 667 write(self.manifest(args['manifest'][0], args['path'][0]))
603 668
604 669 elif args['cmd'][0] == 'tags':
605 670 write(self.tags())
606 671
607 672 elif args['cmd'][0] == 'filediff':
608 673 write(self.filediff(args['file'][0], args['node'][0]))
609 674
610 675 elif args['cmd'][0] == 'file':
611 676 write(self.filerevision(args['file'][0], args['filenode'][0]))
612 677
613 678 elif args['cmd'][0] == 'annotate':
614 679 write(self.fileannotate(args['file'][0], args['filenode'][0]))
615 680
616 681 elif args['cmd'][0] == 'filelog':
617 682 write(self.filelog(args['file'][0], args['filenode'][0]))
618 683
619 684 elif args['cmd'][0] == 'heads':
620 685 httphdr("text/plain")
621 686 h = self.repo.heads()
622 687 sys.stdout.write(" ".join(map(hex, h)) + "\n")
623 688
624 689 elif args['cmd'][0] == 'branches':
625 690 httphdr("text/plain")
626 691 nodes = []
627 692 if args.has_key('nodes'):
628 693 nodes = map(bin, args['nodes'][0].split(" "))
629 694 for b in self.repo.branches(nodes):
630 695 sys.stdout.write(" ".join(map(hex, b)) + "\n")
631 696
632 697 elif args['cmd'][0] == 'between':
633 698 httphdr("text/plain")
634 699 nodes = []
635 700 if args.has_key('pairs'):
636 701 pairs = [ map(bin, p.split("-"))
637 702 for p in args['pairs'][0].split(" ") ]
638 703 for b in self.repo.between(pairs):
639 704 sys.stdout.write(" ".join(map(hex, b)) + "\n")
640 705
641 706 elif args['cmd'][0] == 'changegroup':
642 707 httphdr("application/hg-changegroup")
643 708 nodes = []
644 709 if self.viewonly:
645 710 return
646 711
647 712 if args.has_key('roots'):
648 713 nodes = map(bin, args['roots'][0].split(" "))
649 714
650 715 z = zlib.compressobj()
651 716 for chunk in self.repo.changegroup(nodes):
652 717 sys.stdout.write(z.compress(chunk))
653 718
654 719 sys.stdout.write(z.flush())
655 720
656 721 else:
657 722 write(self.t("error"))
658 723
659 724 def server(path, name, templates, address, port):
660 725
661 726 import BaseHTTPServer
662 727 import sys, os
663 728
664 729 class hgwebhandler(BaseHTTPServer.BaseHTTPRequestHandler):
665 730 def do_POST(self):
666 731 try:
667 732 self.do_hgweb()
668 733 except socket.error, inst:
669 734 if inst.args[0] != 32: raise
670 735
671 736 def do_GET(self):
672 737 self.do_POST()
673 738
674 739 def do_hgweb(self):
675 740 query = ""
676 741 p = self.path.find("?")
677 742 if p:
678 743 query = self.path[p + 1:]
679 744 query = query.replace('+', ' ')
680 745
681 746 env = {}
682 747 env['GATEWAY_INTERFACE'] = 'CGI/1.1'
683 748 env['REQUEST_METHOD'] = self.command
684 749 if query:
685 750 env['QUERY_STRING'] = query
686 751 host = self.address_string()
687 752 if host != self.client_address[0]:
688 753 env['REMOTE_HOST'] = host
689 754 env['REMOTE_ADDR'] = self.client_address[0]
690 755
691 756 if self.headers.typeheader is None:
692 757 env['CONTENT_TYPE'] = self.headers.type
693 758 else:
694 759 env['CONTENT_TYPE'] = self.headers.typeheader
695 760 length = self.headers.getheader('content-length')
696 761 if length:
697 762 env['CONTENT_LENGTH'] = length
698 763 accept = []
699 764 for line in self.headers.getallmatchingheaders('accept'):
700 765 if line[:1] in "\t\n\r ":
701 766 accept.append(line.strip())
702 767 else:
703 768 accept = accept + line[7:].split(',')
704 769 env['HTTP_ACCEPT'] = ','.join(accept)
705 770
706 771 os.environ.update(env)
707 772
708 773 save = sys.argv, sys.stdin, sys.stdout, sys.stderr
709 774 try:
710 775 sys.stdin = self.rfile
711 776 sys.stdout = self.wfile
712 777 sys.argv = ["hgweb.py"]
713 778 if '=' not in query:
714 779 sys.argv.append(query)
715 780 self.send_response(200, "Script output follows")
716 781 hg.run()
717 782 finally:
718 783 sys.argv, sys.stdin, sys.stdout, sys.stderr = save
719 784
720 785 hg = hgweb(path, name, templates)
721 786 httpd = BaseHTTPServer.HTTPServer((address, port), hgwebhandler)
722 787 httpd.serve_forever()
@@ -1,30 +1,32 b''
1 1 header = header.tmpl
2 2 footer = footer.tmpl
3 search = search.tmpl
3 4 changelog = changelog.tmpl
4 5 naventry = "<a href="?cmd=changelog;rev=#rev#">#label#</a> "
5 6 filedifflink = "<a href="?cmd=filediff;node=#node#;file=#file#">#file#</a> "
6 7 filenodelink = "<a href="?cmd=file;filenode=#filenode#;file=#file#">#file#</a> "
7 8 fileellipses = "..."
8 9 changelogentry = changelogentry.tmpl
10 searchentry = searchentry.tmpl
9 11 changeset = changeset.tmpl
10 12 manifest = manifest.tmpl
11 13 manifestdirentry = "<tr class="parity#parity#"><td><tt>drwxr-xr-x</tt>&nbsp;<td><a href="?cmd=manifest;manifest=#manifest#;path=#path#">#basename#/</a>"
12 14 manifestfileentry = "<tr class="parity#parity#"><td><tt>#permissions|permissions#</tt>&nbsp;<td><a href="?cmd=file;filenode=#filenode#;file=#file#">#basename#</a>"
13 15 filerevision = filerevision.tmpl
14 16 fileannotate = fileannotate.tmpl
15 17 filediff = filediff.tmpl
16 18 filelog = filelog.tmpl
17 19 fileline = "<div class="parity#parity#"><span class="lineno">#linenumber# </span>#line|escape#</div>"
18 20 filelogentry = filelogentry.tmpl
19 21 annotateline = "<tr class="parity#parity#"><td class="annotate"><a href="?cmd=changeset;node=#node#">#author|obfuscate#@#rev#</a></td><td><pre>#line|escape#</pre></td></tr>"
20 22 difflineplus = "<span class="plusline">#line|escape#</span>"
21 23 difflineminus = "<span class="minusline">#line|escape#</span>"
22 24 difflineat = "<span class="atline">#line|escape#</span>"
23 25 diffline = "#line|escape#"
24 26 changelogparent = "<tr><td align="right">parent:&nbsp;</td><td><a href="?cmd=changeset;node=#node#">#node|short#</a></td></tr>"
25 27 changesetparent = "<tr><td class="metatag">parent:</td><td><a href="?cmd=changeset;node=#node#">#node|short#</a></td></tr>"
26 28 filerevparent = "<tr><td class="metatag">parent:</td><td><a href="?cmd=file;file=#file#;filenode=#node#">#node|short#</a></td></tr>"
27 29 fileannotateparent = "<tr><td class="metatag">parent:</td><td><a href="?cmd=annotate;file=#file#;filenode=#node#">#node|short#</a></td></tr>"
28 30 tags = tags.tmpl
29 31 tagentry = "<div class="parity#parity#"><tt>#node#</tt> <a href="?cmd=changeset;node=#node#">#tag#</a><br /></div>"
30 32 diffblock = "<div class="parity#parity#">#lines#</div>"
General Comments 0
You need to be logged in to leave comments. Login now