Mercurial > public > mercurial-scm > hg
annotate mercurial/hgweb.py @ 857:41b344235bb7
[PATCH] Propagate the template map though recursively
This patch allows propagates the template map though recursively
though all the templates.
This allows for some hgweb template cleanup patches as well as it makes
writing new skins/themes for hgweb much much easier. (I'm planing to
write several basic ones.)
author | Jeff Sipek <jeffpc@optonline.net> |
---|---|
date | Mon, 08 Aug 2005 19:49:34 -0800 |
parents | 9c918287d10b |
children | c333dfa8fa1a |
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 | |
825
0108c602feb9
Add an option to hg serve to serve file using IPv6
Samuel Tardieu <sam@rfc1149.net>
parents:
753
diff
changeset
|
9 import os, cgi, time, re, difflib, socket, 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), "") | |
857
41b344235bb7
[PATCH] Propagate the template map though recursively
Jeff Sipek <jeffpc@optonline.net>
parents:
839
diff
changeset
|
73 v = callable(v) and v(**map) or v |
201
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) |
645
a55048b2ae3a
this patch permits hgweb to show the deleted files in the changeset diff
kreijack@inwind.REMOVEME.it
parents:
635
diff
changeset
|
211 if files: |
a55048b2ae3a
this patch permits hgweb to show the deleted files in the changeset diff
kreijack@inwind.REMOVEME.it
parents:
635
diff
changeset
|
212 c, a, d = map(lambda x: filterfiles(x, files), (c, a, d)) |
131 | 213 |
138 | 214 for f in c: |
215 to = r.file(f).read(mmap1[f]) | |
216 tn = r.file(f).read(mmap2[f]) | |
172
e9b1147db448
hgweb: alternating colors for multifile diffs
mpm@selenic.com
parents:
168
diff
changeset
|
217 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f), f, tn) |
138 | 218 for f in a: |
265
7ca05593bd30
hgweb: fix non-existent source or destination for diff
mpm@selenic.com
parents:
258
diff
changeset
|
219 to = None |
138 | 220 tn = r.file(f).read(mmap2[f]) |
172
e9b1147db448
hgweb: alternating colors for multifile diffs
mpm@selenic.com
parents:
168
diff
changeset
|
221 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f), f, tn) |
138 | 222 for f in d: |
223 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
|
224 tn = None |
172
e9b1147db448
hgweb: alternating colors for multifile diffs
mpm@selenic.com
parents:
168
diff
changeset
|
225 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f), f, tn) |
131 | 226 |
180 | 227 def changelog(self, pos): |
857
41b344235bb7
[PATCH] Propagate the template map though recursively
Jeff Sipek <jeffpc@optonline.net>
parents:
839
diff
changeset
|
228 def changenav(**map): |
138 | 229 def seq(factor = 1): |
230 yield 1 * factor | |
173
8da1df932c16
hgweb: make navigation of changesets a bit nicer
mpm@selenic.com
parents:
172
diff
changeset
|
231 yield 3 * factor |
8da1df932c16
hgweb: make navigation of changesets a bit nicer
mpm@selenic.com
parents:
172
diff
changeset
|
232 #yield 5 * factor |
138 | 233 for f in seq(factor * 10): |
234 yield f | |
131 | 235 |
173
8da1df932c16
hgweb: make navigation of changesets a bit nicer
mpm@selenic.com
parents:
172
diff
changeset
|
236 l = [] |
8da1df932c16
hgweb: make navigation of changesets a bit nicer
mpm@selenic.com
parents:
172
diff
changeset
|
237 for f in seq(): |
8da1df932c16
hgweb: make navigation of changesets a bit nicer
mpm@selenic.com
parents:
172
diff
changeset
|
238 if f < self.maxchanges / 2: continue |
8da1df932c16
hgweb: make navigation of changesets a bit nicer
mpm@selenic.com
parents:
172
diff
changeset
|
239 if f > count: break |
8da1df932c16
hgweb: make navigation of changesets a bit nicer
mpm@selenic.com
parents:
172
diff
changeset
|
240 r = "%d" % f |
351 | 241 if pos + f < count: l.append(("+" + r, pos + f)) |
242 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
|
243 |
8da1df932c16
hgweb: make navigation of changesets a bit nicer
mpm@selenic.com
parents:
172
diff
changeset
|
244 yield self.t("naventry", rev = 0, label="(0)") |
515 | 245 |
173
8da1df932c16
hgweb: make navigation of changesets a bit nicer
mpm@selenic.com
parents:
172
diff
changeset
|
246 for label, rev in l: |
8da1df932c16
hgweb: make navigation of changesets a bit nicer
mpm@selenic.com
parents:
172
diff
changeset
|
247 yield self.t("naventry", label = label, rev = rev) |
8da1df932c16
hgweb: make navigation of changesets a bit nicer
mpm@selenic.com
parents:
172
diff
changeset
|
248 |
198
c88ef31fb5c0
hgweb: fix tip so that it doesn't need refreshing
mpm@selenic.com
parents:
197
diff
changeset
|
249 yield self.t("naventry", label="tip") |
131 | 250 |
857
41b344235bb7
[PATCH] Propagate the template map though recursively
Jeff Sipek <jeffpc@optonline.net>
parents:
839
diff
changeset
|
251 def changelist(**map): |
142 | 252 parity = (start - end) & 1 |
138 | 253 cl = self.repo.changelog |
254 l = [] # build a list in forward order for efficiency | |
351 | 255 for i in range(start, end): |
138 | 256 n = cl.node(i) |
257 changes = cl.read(n) | |
258 hn = hex(n) | |
259 t = float(changes[2].split(' ')[0]) | |
131 | 260 |
138 | 261 l.insert(0, self.t( |
262 'changelogentry', | |
142 | 263 parity = parity, |
201
f918a6fa2572
hgweb: add template filters, template style maps, and raw pages
mpm@selenic.com
parents:
198
diff
changeset
|
264 author = changes[1], |
570
2ee819a950aa
[PATCH 2/5]: cleaning the template parent management in hgweb
mpm@selenic.com
parents:
569
diff
changeset
|
265 parent = self.parents("changelogparent", |
569
3e347929f5f9
[PATCH 1/5]: cleaning the template parent management in hgweb
mpm@selenic.com
parents:
568
diff
changeset
|
266 cl.parents(n), cl.rev), |
568 | 267 changelogtag = self.showtag("changelogtag",n), |
138 | 268 manifest = hex(changes[0]), |
201
f918a6fa2572
hgweb: add template filters, template style maps, and raw pages
mpm@selenic.com
parents:
198
diff
changeset
|
269 desc = changes[4], |
f918a6fa2572
hgweb: add template filters, template style maps, and raw pages
mpm@selenic.com
parents:
198
diff
changeset
|
270 date = t, |
138 | 271 files = self.listfilediffs(changes[3], n), |
272 rev = i, | |
273 node = hn)) | |
142 | 274 parity = 1 - parity |
138 | 275 |
276 yield l | |
131 | 277 |
168 | 278 cl = self.repo.changelog |
279 mf = cl.read(cl.tip())[0] | |
280 count = cl.count() | |
351 | 281 start = max(0, pos - self.maxchanges + 1) |
282 end = min(count, start + self.maxchanges) | |
283 pos = end - 1 | |
138 | 284 |
142 | 285 yield self.t('changelog', |
286 changenav = changenav, | |
168 | 287 manifest = hex(mf), |
142 | 288 rev = pos, changesets = count, entries = changelist) |
131 | 289 |
538 | 290 def search(self, query): |
291 | |
857
41b344235bb7
[PATCH] Propagate the template map though recursively
Jeff Sipek <jeffpc@optonline.net>
parents:
839
diff
changeset
|
292 def changelist(**map): |
538 | 293 cl = self.repo.changelog |
294 count = 0 | |
295 qw = query.lower().split() | |
296 | |
297 def revgen(): | |
298 for i in range(cl.count() - 1, 0, -100): | |
299 l = [] | |
300 for j in range(max(0, i - 100), i): | |
301 n = cl.node(j) | |
302 changes = cl.read(n) | |
303 l.insert(0, (n, j, changes)) | |
304 for e in l: | |
305 yield e | |
306 | |
307 for n, i, changes in revgen(): | |
308 miss = 0 | |
309 for q in qw: | |
310 if not (q in changes[1].lower() or | |
311 q in changes[4].lower() or | |
312 q in " ".join(changes[3][:20]).lower()): | |
313 miss = 1 | |
314 break | |
315 if miss: continue | |
316 | |
317 count += 1 | |
318 hn = hex(n) | |
319 t = float(changes[2].split(' ')[0]) | |
320 | |
321 yield self.t( | |
322 'searchentry', | |
323 parity = count & 1, | |
324 author = changes[1], | |
570
2ee819a950aa
[PATCH 2/5]: cleaning the template parent management in hgweb
mpm@selenic.com
parents:
569
diff
changeset
|
325 parent = self.parents("changelogparent", |
569
3e347929f5f9
[PATCH 1/5]: cleaning the template parent management in hgweb
mpm@selenic.com
parents:
568
diff
changeset
|
326 cl.parents(n), cl.rev), |
568 | 327 changelogtag = self.showtag("changelogtag",n), |
538 | 328 manifest = hex(changes[0]), |
329 desc = changes[4], | |
330 date = t, | |
331 files = self.listfilediffs(changes[3], n), | |
332 rev = i, | |
333 node = hn) | |
334 | |
335 if count >= self.maxchanges: break | |
336 | |
337 cl = self.repo.changelog | |
338 mf = cl.read(cl.tip())[0] | |
339 | |
340 yield self.t('search', | |
341 query = query, | |
342 manifest = hex(mf), | |
343 entries = changelist) | |
344 | |
138 | 345 def changeset(self, nodeid): |
346 n = bin(nodeid) | |
347 cl = self.repo.changelog | |
348 changes = cl.read(n) | |
598
f8d44a2e6928
[PATCH 4/5]: cleaning the template parent management in hgweb
mpm@selenic.com
parents:
582
diff
changeset
|
349 p1 = cl.parents(n)[0] |
138 | 350 t = float(changes[2].split(' ')[0]) |
515 | 351 |
133
fb84d3e71042
added template support for some hgweb output, also, template files for
jake@edge2.net
parents:
132
diff
changeset
|
352 files = [] |
138 | 353 mf = self.repo.manifest.read(changes[0]) |
131 | 354 for f in changes[3]: |
138 | 355 files.append(self.t("filenodelink", |
369
09f24af48b82
hgweb: fix deleted file in changeset key error
mpm@selenic.com
parents:
366
diff
changeset
|
356 filenode = hex(mf.get(f, nullid)), file = f)) |
138 | 357 |
857
41b344235bb7
[PATCH] Propagate the template map though recursively
Jeff Sipek <jeffpc@optonline.net>
parents:
839
diff
changeset
|
358 def diff(**map): |
645
a55048b2ae3a
this patch permits hgweb to show the deleted files in the changeset diff
kreijack@inwind.REMOVEME.it
parents:
635
diff
changeset
|
359 yield self.diff(p1, n, None) |
131 | 360 |
138 | 361 yield self.t('changeset', |
362 diff = diff, | |
363 rev = cl.rev(n), | |
364 node = nodeid, | |
570
2ee819a950aa
[PATCH 2/5]: cleaning the template parent management in hgweb
mpm@selenic.com
parents:
569
diff
changeset
|
365 parent = self.parents("changesetparent", |
569
3e347929f5f9
[PATCH 1/5]: cleaning the template parent management in hgweb
mpm@selenic.com
parents:
568
diff
changeset
|
366 cl.parents(n), cl.rev), |
568 | 367 changesettag = self.showtag("changesettag",n), |
138 | 368 manifest = hex(changes[0]), |
201
f918a6fa2572
hgweb: add template filters, template style maps, and raw pages
mpm@selenic.com
parents:
198
diff
changeset
|
369 author = changes[1], |
f918a6fa2572
hgweb: add template filters, template style maps, and raw pages
mpm@selenic.com
parents:
198
diff
changeset
|
370 desc = changes[4], |
f918a6fa2572
hgweb: add template filters, template style maps, and raw pages
mpm@selenic.com
parents:
198
diff
changeset
|
371 date = t, |
138 | 372 files = files) |
131 | 373 |
138 | 374 def filelog(self, f, filenode): |
375 cl = self.repo.changelog | |
376 fl = self.repo.file(f) | |
377 count = fl.count() | |
378 | |
857
41b344235bb7
[PATCH] Propagate the template map though recursively
Jeff Sipek <jeffpc@optonline.net>
parents:
839
diff
changeset
|
379 def entries(**map): |
138 | 380 l = [] |
142 | 381 parity = (count - 1) & 1 |
515 | 382 |
138 | 383 for i in range(count): |
384 | |
385 n = fl.node(i) | |
386 lr = fl.linkrev(n) | |
387 cn = cl.node(lr) | |
388 cs = cl.read(cl.node(lr)) | |
389 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
|
390 |
138 | 391 l.insert(0, self.t("filelogentry", |
142 | 392 parity = parity, |
138 | 393 filenode = hex(n), |
394 filerev = i, | |
395 file = f, | |
396 node = hex(cn), | |
201
f918a6fa2572
hgweb: add template filters, template style maps, and raw pages
mpm@selenic.com
parents:
198
diff
changeset
|
397 author = cs[1], |
f918a6fa2572
hgweb: add template filters, template style maps, and raw pages
mpm@selenic.com
parents:
198
diff
changeset
|
398 date = t, |
598
f8d44a2e6928
[PATCH 4/5]: cleaning the template parent management in hgweb
mpm@selenic.com
parents:
582
diff
changeset
|
399 parent = self.parents("filelogparent", |
f8d44a2e6928
[PATCH 4/5]: cleaning the template parent management in hgweb
mpm@selenic.com
parents:
582
diff
changeset
|
400 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
|
401 desc = cs[4])) |
142 | 402 parity = 1 - parity |
138 | 403 |
404 yield l | |
405 | |
406 yield self.t("filelog", | |
407 file = f, | |
408 filenode = filenode, | |
409 entries = entries) | |
131 | 410 |
138 | 411 def filerevision(self, f, node): |
412 fl = self.repo.file(f) | |
413 n = bin(node) | |
201
f918a6fa2572
hgweb: add template filters, template style maps, and raw pages
mpm@selenic.com
parents:
198
diff
changeset
|
414 text = fl.read(n) |
138 | 415 changerev = fl.linkrev(n) |
416 cl = self.repo.changelog | |
417 cn = cl.node(changerev) | |
418 cs = cl.read(cn) | |
419 t = float(cs[2].split(' ')[0]) | |
420 mfn = cs[0] | |
142 | 421 |
422 def lines(): | |
423 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
|
424 yield self.t("fileline", line = t, |
142 | 425 linenumber = "% 6d" % (l + 1), |
426 parity = l & 1) | |
359 | 427 |
138 | 428 yield self.t("filerevision", file = f, |
429 filenode = node, | |
430 path = up(f), | |
142 | 431 text = lines(), |
138 | 432 rev = changerev, |
433 node = hex(cn), | |
434 manifest = hex(mfn), | |
201
f918a6fa2572
hgweb: add template filters, template style maps, and raw pages
mpm@selenic.com
parents:
198
diff
changeset
|
435 author = cs[1], |
f918a6fa2572
hgweb: add template filters, template style maps, and raw pages
mpm@selenic.com
parents:
198
diff
changeset
|
436 date = t, |
570
2ee819a950aa
[PATCH 2/5]: cleaning the template parent management in hgweb
mpm@selenic.com
parents:
569
diff
changeset
|
437 parent = self.parents("filerevparent", |
569
3e347929f5f9
[PATCH 1/5]: cleaning the template parent management in hgweb
mpm@selenic.com
parents:
568
diff
changeset
|
438 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
|
439 permissions = self.repo.manifest.readflags(mfn)[f]) |
138 | 440 |
441 def fileannotate(self, f, node): | |
442 bcache = {} | |
443 ncache = {} | |
444 fl = self.repo.file(f) | |
445 n = bin(node) | |
446 changerev = fl.linkrev(n) | |
447 | |
448 cl = self.repo.changelog | |
449 cn = cl.node(changerev) | |
450 cs = cl.read(cn) | |
451 t = float(cs[2].split(' ')[0]) | |
452 mfn = cs[0] | |
131 | 453 |
857
41b344235bb7
[PATCH] Propagate the template map though recursively
Jeff Sipek <jeffpc@optonline.net>
parents:
839
diff
changeset
|
454 def annotate(**map): |
142 | 455 parity = 1 |
456 last = None | |
138 | 457 for r, l in fl.annotate(n): |
458 try: | |
459 cnode = ncache[r] | |
460 except KeyError: | |
461 cnode = ncache[r] = self.repo.changelog.node(r) | |
515 | 462 |
138 | 463 try: |
464 name = bcache[r] | |
465 except KeyError: | |
466 cl = self.repo.changelog.read(cnode) | |
467 name = cl[1] | |
468 f = name.find('@') | |
469 if f >= 0: | |
470 name = name[:f] | |
534
ab0d1bfeee7c
[PATCH] Handle 'name firstname <email@server>' correctly in annotate
mpm@selenic.com
parents:
533
diff
changeset
|
471 f = name.find('<') |
ab0d1bfeee7c
[PATCH] Handle 'name firstname <email@server>' correctly in annotate
mpm@selenic.com
parents:
533
diff
changeset
|
472 if f >= 0: |
ab0d1bfeee7c
[PATCH] Handle 'name firstname <email@server>' correctly in annotate
mpm@selenic.com
parents:
533
diff
changeset
|
473 name = name[f+1:] |
138 | 474 bcache[r] = name |
131 | 475 |
142 | 476 if last != cnode: |
477 parity = 1 - parity | |
478 last = cnode | |
479 | |
138 | 480 yield self.t("annotateline", |
142 | 481 parity = parity, |
138 | 482 node = hex(cnode), |
483 rev = r, | |
484 author = name, | |
485 file = f, | |
201
f918a6fa2572
hgweb: add template filters, template style maps, and raw pages
mpm@selenic.com
parents:
198
diff
changeset
|
486 line = l) |
138 | 487 |
488 yield self.t("fileannotate", | |
489 file = f, | |
490 filenode = node, | |
491 annotate = annotate, | |
492 path = up(f), | |
493 rev = changerev, | |
494 node = hex(cn), | |
495 manifest = hex(mfn), | |
201
f918a6fa2572
hgweb: add template filters, template style maps, and raw pages
mpm@selenic.com
parents:
198
diff
changeset
|
496 author = cs[1], |
f918a6fa2572
hgweb: add template filters, template style maps, and raw pages
mpm@selenic.com
parents:
198
diff
changeset
|
497 date = t, |
570
2ee819a950aa
[PATCH 2/5]: cleaning the template parent management in hgweb
mpm@selenic.com
parents:
569
diff
changeset
|
498 parent = self.parents("fileannotateparent", |
569
3e347929f5f9
[PATCH 1/5]: cleaning the template parent management in hgweb
mpm@selenic.com
parents:
568
diff
changeset
|
499 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
|
500 permissions = self.repo.manifest.readflags(mfn)[f]) |
136 | 501 |
138 | 502 def manifest(self, mnode, path): |
503 mf = self.repo.manifest.read(bin(mnode)) | |
504 rev = self.repo.manifest.rev(bin(mnode)) | |
505 node = self.repo.changelog.node(rev) | |
359 | 506 mff=self.repo.manifest.readflags(bin(mnode)) |
138 | 507 |
508 files = {} | |
515 | 509 |
138 | 510 p = path[1:] |
511 l = len(p) | |
131 | 512 |
138 | 513 for f,n in mf.items(): |
514 if f[:l] != p: | |
515 continue | |
516 remain = f[l:] | |
517 if "/" in remain: | |
518 short = remain[:remain.find("/") + 1] # bleah | |
142 | 519 files[short] = (f, None) |
138 | 520 else: |
521 short = os.path.basename(remain) | |
522 files[short] = (f, n) | |
131 | 523 |
857
41b344235bb7
[PATCH] Propagate the template map though recursively
Jeff Sipek <jeffpc@optonline.net>
parents:
839
diff
changeset
|
524 def filelist(**map): |
142 | 525 parity = 0 |
138 | 526 fl = files.keys() |
527 fl.sort() | |
528 for f in fl: | |
529 full, fnode = files[f] | |
142 | 530 if fnode: |
531 yield self.t("manifestfileentry", | |
532 file = full, | |
533 manifest = mnode, | |
534 filenode = hex(fnode), | |
535 parity = parity, | |
515 | 536 basename = f, |
359 | 537 permissions = mff[full]) |
142 | 538 else: |
539 yield self.t("manifestdirentry", | |
540 parity = parity, | |
541 path = os.path.join(path, f), | |
542 manifest = mnode, basename = f[:-1]) | |
543 parity = 1 - parity | |
138 | 544 |
545 yield self.t("manifest", | |
546 manifest = mnode, | |
547 rev = rev, | |
548 node = hex(node), | |
549 path = path, | |
550 up = up(path), | |
142 | 551 entries = filelist) |
131 | 552 |
168 | 553 def tags(self): |
554 cl = self.repo.changelog | |
555 mf = cl.read(cl.tip())[0] | |
556 | |
343 | 557 i = self.repo.tagslist() |
558 i.reverse() | |
168 | 559 |
857
41b344235bb7
[PATCH] Propagate the template map though recursively
Jeff Sipek <jeffpc@optonline.net>
parents:
839
diff
changeset
|
560 def entries(**map): |
168 | 561 parity = 0 |
562 for k,n in i: | |
563 yield self.t("tagentry", | |
564 parity = parity, | |
565 tag = k, | |
566 node = hex(n)) | |
567 parity = 1 - parity | |
568 | |
569 yield self.t("tags", | |
570 manifest = hex(mf), | |
571 entries = entries) | |
572 | |
138 | 573 def filediff(self, file, changeset): |
574 n = bin(changeset) | |
575 cl = self.repo.changelog | |
576 p1 = cl.parents(n)[0] | |
577 cs = cl.read(n) | |
578 mf = self.repo.manifest.read(cs[0]) | |
515 | 579 |
857
41b344235bb7
[PATCH] Propagate the template map though recursively
Jeff Sipek <jeffpc@optonline.net>
parents:
839
diff
changeset
|
580 def diff(**map): |
138 | 581 yield self.diff(p1, n, file) |
131 | 582 |
138 | 583 yield self.t("filediff", |
584 file = file, | |
376
fadc9e126369
hgweb: fix deleted file in filediff key error
Thomas Arendsen Hein <thomas@intevation.de>
parents:
369
diff
changeset
|
585 filenode = hex(mf.get(file, nullid)), |
138 | 586 node = changeset, |
587 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
|
588 parent = self.parents("filediffparent", |
c7364b985ca2
[PATCH 3/5]: cleaning the template parent management in hgweb
mpm@selenic.com
parents:
570
diff
changeset
|
589 cl.parents(n), cl.rev), |
138 | 590 diff = diff) |
515 | 591 |
138 | 592 # add tags to things |
593 # tags -> list of changesets corresponding to tags | |
594 # find tag, changeset, file | |
131 | 595 |
132 | 596 def run(self): |
857
41b344235bb7
[PATCH] Propagate the template map though recursively
Jeff Sipek <jeffpc@optonline.net>
parents:
839
diff
changeset
|
597 def header(**map): |
41b344235bb7
[PATCH] Propagate the template map though recursively
Jeff Sipek <jeffpc@optonline.net>
parents:
839
diff
changeset
|
598 yield self.t("header", **map) |
41b344235bb7
[PATCH] Propagate the template map though recursively
Jeff Sipek <jeffpc@optonline.net>
parents:
839
diff
changeset
|
599 |
41b344235bb7
[PATCH] Propagate the template map though recursively
Jeff Sipek <jeffpc@optonline.net>
parents:
839
diff
changeset
|
600 def footer(**map): |
41b344235bb7
[PATCH] Propagate the template map though recursively
Jeff Sipek <jeffpc@optonline.net>
parents:
839
diff
changeset
|
601 yield self.t("footer", **map) |
41b344235bb7
[PATCH] Propagate the template map though recursively
Jeff Sipek <jeffpc@optonline.net>
parents:
839
diff
changeset
|
602 |
258 | 603 self.refresh() |
132 | 604 args = cgi.parse() |
605 | |
201
f918a6fa2572
hgweb: add template filters, template style maps, and raw pages
mpm@selenic.com
parents:
198
diff
changeset
|
606 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
|
607 if args.has_key('style'): |
f918a6fa2572
hgweb: add template filters, template style maps, and raw pages
mpm@selenic.com
parents:
198
diff
changeset
|
608 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
|
609 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
|
610 if os.path.isfile(p): m = p |
515 | 611 |
601 | 612 port = os.environ["SERVER_PORT"] |
613 port = port != "80" and (":" + port) or "" | |
620
7369ec5d93f2
Attempt to handle RSS URIs properly
Matt Mackall <mpm@selenic.com>
parents:
605
diff
changeset
|
614 uri = os.environ["REQUEST_URI"] |
7369ec5d93f2
Attempt to handle RSS URIs properly
Matt Mackall <mpm@selenic.com>
parents:
605
diff
changeset
|
615 if "?" in uri: uri = uri.split("?")[0] |
7369ec5d93f2
Attempt to handle RSS URIs properly
Matt Mackall <mpm@selenic.com>
parents:
605
diff
changeset
|
616 url = "http://%s%s%s" % (os.environ["SERVER_NAME"], port, uri) |
601 | 617 |
618 self.t = templater(m, self.filters, | |
619 {"url":url, | |
620 "repo":self.reponame, | |
857
41b344235bb7
[PATCH] Propagate the template map though recursively
Jeff Sipek <jeffpc@optonline.net>
parents:
839
diff
changeset
|
621 "header":header, |
41b344235bb7
[PATCH] Propagate the template map though recursively
Jeff Sipek <jeffpc@optonline.net>
parents:
839
diff
changeset
|
622 "footer":footer, |
601 | 623 }) |
201
f918a6fa2572
hgweb: add template filters, template style maps, and raw pages
mpm@selenic.com
parents:
198
diff
changeset
|
624 |
138 | 625 if not args.has_key('cmd') or args['cmd'][0] == 'changelog': |
538 | 626 c = self.repo.changelog.count() - 1 |
627 hi = c | |
153
e8a360cd5a9f
changed pos to rev for changelog cmd, changed & to ;
jake@edge2.net
parents:
142
diff
changeset
|
628 if args.has_key('rev'): |
165 | 629 hi = args['rev'][0] |
166
39624c47060f
hgweb: don't blow up on search for unknown keys
mpm@selenic.com
parents:
165
diff
changeset
|
630 try: |
39624c47060f
hgweb: don't blow up on search for unknown keys
mpm@selenic.com
parents:
165
diff
changeset
|
631 hi = self.repo.changelog.rev(self.repo.lookup(hi)) |
688 | 632 except RepoError: |
538 | 633 write(self.search(hi)) |
634 return | |
575 | 635 |
138 | 636 write(self.changelog(hi)) |
515 | 637 |
138 | 638 elif args['cmd'][0] == 'changeset': |
639 write(self.changeset(args['node'][0])) | |
640 | |
641 elif args['cmd'][0] == 'manifest': | |
642 write(self.manifest(args['manifest'][0], args['path'][0])) | |
643 | |
168 | 644 elif args['cmd'][0] == 'tags': |
645 write(self.tags()) | |
646 | |
138 | 647 elif args['cmd'][0] == 'filediff': |
648 write(self.filediff(args['file'][0], args['node'][0])) | |
131 | 649 |
132 | 650 elif args['cmd'][0] == 'file': |
138 | 651 write(self.filerevision(args['file'][0], args['filenode'][0])) |
131 | 652 |
138 | 653 elif args['cmd'][0] == 'annotate': |
654 write(self.fileannotate(args['file'][0], args['filenode'][0])) | |
131 | 655 |
138 | 656 elif args['cmd'][0] == 'filelog': |
657 write(self.filelog(args['file'][0], args['filenode'][0])) | |
136 | 658 |
222 | 659 elif args['cmd'][0] == 'heads': |
751
0b245edec124
When pulling from a non hg repository URL (e.g. http://www.kernel.org/hg)
Muli Ben-Yehuda <mulix@mulix.org>
parents:
688
diff
changeset
|
660 httphdr("application/mercurial-0.1") |
222 | 661 h = self.repo.heads() |
662 sys.stdout.write(" ".join(map(hex, h)) + "\n") | |
663 | |
132 | 664 elif args['cmd'][0] == 'branches': |
751
0b245edec124
When pulling from a non hg repository URL (e.g. http://www.kernel.org/hg)
Muli Ben-Yehuda <mulix@mulix.org>
parents:
688
diff
changeset
|
665 httphdr("application/mercurial-0.1") |
132 | 666 nodes = [] |
667 if args.has_key('nodes'): | |
138 | 668 nodes = map(bin, args['nodes'][0].split(" ")) |
669 for b in self.repo.branches(nodes): | |
670 sys.stdout.write(" ".join(map(hex, b)) + "\n") | |
131 | 671 |
132 | 672 elif args['cmd'][0] == 'between': |
753 | 673 httphdr("application/mercurial-0.1") |
132 | 674 nodes = [] |
675 if args.has_key('pairs'): | |
138 | 676 pairs = [ map(bin, p.split("-")) |
132 | 677 for p in args['pairs'][0].split(" ") ] |
138 | 678 for b in self.repo.between(pairs): |
679 sys.stdout.write(" ".join(map(hex, b)) + "\n") | |
132 | 680 |
681 elif args['cmd'][0] == 'changegroup': | |
751
0b245edec124
When pulling from a non hg repository URL (e.g. http://www.kernel.org/hg)
Muli Ben-Yehuda <mulix@mulix.org>
parents:
688
diff
changeset
|
682 httphdr("application/mercurial-0.1") |
132 | 683 nodes = [] |
197 | 684 if self.viewonly: |
685 return | |
686 | |
132 | 687 if args.has_key('roots'): |
138 | 688 nodes = map(bin, args['roots'][0].split(" ")) |
131 | 689 |
132 | 690 z = zlib.compressobj() |
635
85e2209d401c
Protocol switch from using generators to stream-like objects.
Matt Mackall <mpm@selenic.com>
parents:
620
diff
changeset
|
691 f = self.repo.changegroup(nodes) |
85e2209d401c
Protocol switch from using generators to stream-like objects.
Matt Mackall <mpm@selenic.com>
parents:
620
diff
changeset
|
692 while 1: |
85e2209d401c
Protocol switch from using generators to stream-like objects.
Matt Mackall <mpm@selenic.com>
parents:
620
diff
changeset
|
693 chunk = f.read(4096) |
85e2209d401c
Protocol switch from using generators to stream-like objects.
Matt Mackall <mpm@selenic.com>
parents:
620
diff
changeset
|
694 if not chunk: break |
132 | 695 sys.stdout.write(z.compress(chunk)) |
696 | |
697 sys.stdout.write(z.flush()) | |
131 | 698 |
132 | 699 else: |
138 | 700 write(self.t("error")) |
131 | 701 |
825
0108c602feb9
Add an option to hg serve to serve file using IPv6
Samuel Tardieu <sam@rfc1149.net>
parents:
753
diff
changeset
|
702 def create_server(path, name, templates, address, port, use_ipv6 = False, |
605
8e82fd763be2
[PATCH] Get "hg serve" to optionally log accesses and errors to files
mpm@selenic.com
parents:
603
diff
changeset
|
703 accesslog = sys.stdout, errorlog = sys.stderr): |
158
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
704 |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
705 import BaseHTTPServer |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
706 |
825
0108c602feb9
Add an option to hg serve to serve file using IPv6
Samuel Tardieu <sam@rfc1149.net>
parents:
753
diff
changeset
|
707 class IPv6HTTPServer(BaseHTTPServer.HTTPServer): |
0108c602feb9
Add an option to hg serve to serve file using IPv6
Samuel Tardieu <sam@rfc1149.net>
parents:
753
diff
changeset
|
708 address_family = socket.AF_INET6 |
0108c602feb9
Add an option to hg serve to serve file using IPv6
Samuel Tardieu <sam@rfc1149.net>
parents:
753
diff
changeset
|
709 |
158
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
710 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
|
711 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
|
712 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
|
713 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
|
714 format % args)) |
8e82fd763be2
[PATCH] Get "hg serve" to optionally log accesses and errors to files
mpm@selenic.com
parents:
603
diff
changeset
|
715 |
8e82fd763be2
[PATCH] Get "hg serve" to optionally log accesses and errors to files
mpm@selenic.com
parents:
603
diff
changeset
|
716 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
|
717 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
|
718 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
|
719 format % args)) |
8e82fd763be2
[PATCH] Get "hg serve" to optionally log accesses and errors to files
mpm@selenic.com
parents:
603
diff
changeset
|
720 |
158
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
721 def do_POST(self): |
271 | 722 try: |
723 self.do_hgweb() | |
724 except socket.error, inst: | |
725 if inst.args[0] != 32: raise | |
158
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
726 |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
727 def do_GET(self): |
271 | 728 self.do_POST() |
158
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
729 |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
730 def do_hgweb(self): |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
731 query = "" |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
732 p = self.path.find("?") |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
733 if p: |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
734 query = self.path[p + 1:] |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
735 query = query.replace('+', ' ') |
515 | 736 |
158
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
737 env = {} |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
738 env['GATEWAY_INTERFACE'] = 'CGI/1.1' |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
739 env['REQUEST_METHOD'] = self.command |
599 | 740 env['SERVER_NAME'] = self.server.server_name |
741 env['SERVER_PORT'] = str(self.server.server_port) | |
742 env['REQUEST_URI'] = "/" | |
158
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
743 if query: |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
744 env['QUERY_STRING'] = query |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
745 host = self.address_string() |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
746 if host != self.client_address[0]: |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
747 env['REMOTE_HOST'] = host |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
748 env['REMOTE_ADDR'] = self.client_address[0] |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
749 |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
750 if self.headers.typeheader is None: |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
751 env['CONTENT_TYPE'] = self.headers.type |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
752 else: |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
753 env['CONTENT_TYPE'] = self.headers.typeheader |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
754 length = self.headers.getheader('content-length') |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
755 if length: |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
756 env['CONTENT_LENGTH'] = length |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
757 accept = [] |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
758 for line in self.headers.getallmatchingheaders('accept'): |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
759 if line[:1] in "\t\n\r ": |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
760 accept.append(line.strip()) |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
761 else: |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
762 accept = accept + line[7:].split(',') |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
763 env['HTTP_ACCEPT'] = ','.join(accept) |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
764 |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
765 os.environ.update(env) |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
766 |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
767 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
|
768 try: |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
769 sys.stdin = self.rfile |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
770 sys.stdout = self.wfile |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
771 sys.argv = ["hgweb.py"] |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
772 if '=' not in query: |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
773 sys.argv.append(query) |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
774 self.send_response(200, "Script output follows") |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
775 hg.run() |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
776 finally: |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
777 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
|
778 |
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
779 hg = hgweb(path, name, templates) |
825
0108c602feb9
Add an option to hg serve to serve file using IPv6
Samuel Tardieu <sam@rfc1149.net>
parents:
753
diff
changeset
|
780 if use_ipv6: |
0108c602feb9
Add an option to hg serve to serve file using IPv6
Samuel Tardieu <sam@rfc1149.net>
parents:
753
diff
changeset
|
781 return IPv6HTTPServer((address, port), hgwebhandler) |
0108c602feb9
Add an option to hg serve to serve file using IPv6
Samuel Tardieu <sam@rfc1149.net>
parents:
753
diff
changeset
|
782 else: |
0108c602feb9
Add an option to hg serve to serve file using IPv6
Samuel Tardieu <sam@rfc1149.net>
parents:
753
diff
changeset
|
783 return BaseHTTPServer.HTTPServer((address, port), hgwebhandler) |
603
bc5d058e65e9
[PATCH] Get "hg serve" to print the URL being served
mpm@selenic.com
parents:
601
diff
changeset
|
784 |
825
0108c602feb9
Add an option to hg serve to serve file using IPv6
Samuel Tardieu <sam@rfc1149.net>
parents:
753
diff
changeset
|
785 def server(path, name, templates, address, port, use_ipv6 = False, |
605
8e82fd763be2
[PATCH] Get "hg serve" to optionally log accesses and errors to files
mpm@selenic.com
parents:
603
diff
changeset
|
786 accesslog = sys.stdout, errorlog = sys.stderr): |
825
0108c602feb9
Add an option to hg serve to serve file using IPv6
Samuel Tardieu <sam@rfc1149.net>
parents:
753
diff
changeset
|
787 httpd = create_server(path, name, templates, address, port, use_ipv6, |
605
8e82fd763be2
[PATCH] Get "hg serve" to optionally log accesses and errors to files
mpm@selenic.com
parents:
603
diff
changeset
|
788 accesslog, errorlog) |
158
be7103467d2e
Add 'hg serve' command for stand-alone server
mpm@selenic.com
parents:
157
diff
changeset
|
789 httpd.serve_forever() |