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