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