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