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