comparison hgweb.py @ 57:115106376f45

hgweb.py from Jake Edge remove hgweb.py from URLs so that it will work as index.cgi
author mpm@selenic.com
date Wed, 11 May 2005 17:11:10 -0800
parents
children 1215bf60468f
comparison
equal deleted inserted replaced
56:ad2ea1185f04 57:115106376f45
1 #!/usr/bin/env python
2 #
3 # hgweb.py - 0.1 - 9 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
4 # - web interface to a mercurial repository
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 # useful for debugging
10 import cgitb
11 cgitb.enable()
12
13 import os, cgi, time, re, difflib
14 from mercurial import hg, mdiff
15
16 repo_path = "." # change as needed
17
18 def nl2br(text):
19 return re.sub('\n', '<br />', text)
20
21 def obfuscate(text):
22 l = []
23 for c in text:
24 l.append('&#%d;' % ord(c))
25 return ''.join(l)
26
27 def httphdr():
28 print 'Content-type: text/html\n\n'
29
30 def htmldoctype():
31 print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">'
32
33 def htmlhead(title):
34 print '<HTML>'
35 print '<!-- created by hgweb 0.1 - jake@edge2.net -->'
36 print '<HEAD><TITLE>%s</TITLE></HEAD>' % (title, )
37 print '<style type="text/css">'
38 print 'body { font-family: sans-serif; font-size: 12px; }'
39 print 'table { font-size: 12px; }'
40 print '.errmsg { font-size: 200%; color: red; }'
41 print '.filename { font-size: 150%; color: purple; }'
42 print '.plusline { color: green; }'
43 print '.minusline { color: red; }'
44 print '.atline { color: purple; }'
45 print '</style>'
46
47 def ent_change(repo, nodeid):
48 changes = repo.changelog.read(nodeid)
49 hn = hg.hex(nodeid)
50 i = repo.changelog.rev(nodeid)
51 (h1, h2) = [ hg.hex(x) for x in repo.changelog.parents(nodeid) ]
52 datestr = time.asctime(time.gmtime(float(changes[2].split(' ')[0])))
53 mf = repo.manifest.read(changes[0])
54 print '<table width="100%" border="1">'
55 print '\t<tr><td valign="top" width="10%%">author:</td>' + \
56 '<td valign="top" width="20%%">%s</td>' % (obfuscate(changes[1]), )
57 print '\t\t<td valign="top" width="10%%">description:</td>' + \
58 '<td width="60%%">' + \
59 '<a href="?cmd=chkin;nd=%s">%s</a></td></tr>' % \
60 (hn, nl2br(changes[4]), )
61 print '\t<tr><td>date:</td><td>%s UTC</td>' % (datestr, )
62 print '\t\t<td valign="top">files:</td><td valign="top">'
63 for f in changes[3]:
64 print '\t\t<a href="?cmd=file;nd=%s;fn=%s">%s</a>' % \
65 (hg.hex(mf[f]), f, f, ),
66 print '&nbsp;&nbsp;'
67 print '\t</td></tr>'
68 # print '\t<tr><td>revision:</td><td colspan="3">%d:<a ' % (i, ) + \
69 # 'href="?cmd=rev;nd=%s">%s</a></td></tr>' % (hn, hn, )
70 print '</table><br />'
71
72 def ent_diff(a, b, fn):
73 a = a.splitlines(1)
74 b = b.splitlines(1)
75 l = difflib.unified_diff(a, b, fn, fn)
76 print '<pre>'
77 for line in l:
78 line = cgi.escape(line[:-1])
79 if line.startswith('+'):
80 print '<span class="plusline">%s</span>' % (line, )
81 elif line.startswith('-'):
82 print '<span class="minusline">%s</span>' % (line, )
83 elif line.startswith('@'):
84 print '<span class="atline">%s</span>' % (line, )
85 else:
86 print line
87 print '</pre>'
88
89 def ent_checkin(repo, nodeid):
90 changes = repo.changelog.read(nodeid)
91 hn = hg.hex(nodeid)
92 i = repo.changelog.rev(nodeid)
93 parents = repo.changelog.parents(nodeid)
94 (h1, h2) = [ hg.hex(x) for x in parents ]
95 (i1, i2) = [ repo.changelog.rev(x) for x in parents ]
96 datestr = time.asctime(time.gmtime(float(changes[2].split(' ')[0])))
97 mf = repo.manifest.read(changes[0])
98 print '<table width="100%" border="1">'
99 print '\t<tr><td>revision:</td><td colspan="3">%d:' % (i, ),
100 print '<a href="?cmd=rev;nd=%s">%s</a></td></tr>' % (hn, hn, )
101 print '\t<tr><td>parent(s):</td><td colspan="3">%d:' % (i1, )
102 print '<a href="?cmd=rev;nd=%s">%s</a>' % (h1, h1, ),
103 if i2 != -1:
104 print '&nbsp;&nbsp;%d:<a href="?cmd=rev;nd=%s">%s</a>' % \
105 (i2, h2, h2, ),
106 else:
107 print '&nbsp;&nbsp;%d:%s' % (i2, h2, ),
108 print '</td></tr>'
109 print '\t<tr><td>manifest:</td><td colspan="3">%d:' % \
110 (repo.manifest.rev(changes[0]), ),
111 print '<a href="?cmd=mf;nd=%s">%s</a></td></tr>' % \
112 (hg.hex(changes[0]), hg.hex(changes[0]), )
113 print '\t<tr><td valign="top" width="10%%">author:</td>' + \
114 '<td valign="top" width="20%%">%s</td>' % (obfuscate(changes[1]), )
115 print '\t\t<td valign="top" width="10%%">description:</td>' + \
116 '<td width="60%%">' + \
117 '<a href="?cmd=chkin;nd=%s">%s</a></td></tr>' % \
118 (hn, nl2br(changes[4]), )
119 print '\t<tr><td>date:</td><td>%s UTC</td>' % (datestr, )
120 print '\t\t<td valign="top">files:</td><td valign="top">'
121 for f in changes[3]:
122 print '\t\t<a href="?cmd=file;nd=%s&fn=%s">%s</a>' % \
123 (hg.hex(mf[f]), f, f, ),
124 print '&nbsp;&nbsp;'
125 print '\t</td></tr>'
126 print '</table><br />'
127
128 (c, a, d) = repo.diffrevs(parents[0], nodeid)
129 change = repo.changelog.read(parents[0])
130 mf2 = repo.manifest.read(change[0])
131 for f in c:
132 ent_diff(repo.file(f).read(mf2[f]), repo.file(f).read(mf[f]), f)
133 for f in a:
134 ent_diff('', repo.file(f).read(mf[f]), f)
135 for f in d:
136 ent_diff(repo.file(f).read(mf2[f]), '', f)
137
138 def ent_file(repo, nodeid, fn):
139 print '<div class="filename">%s (%s)</div>' % (fn, hg.hex(nodeid), )
140 print '<pre>'
141 print cgi.escape(repo.file(fn).read(nodeid))
142 print '</pre>'
143
144 httphdr()
145 htmldoctype()
146 htmlhead('Mercurial Web')
147
148 print '<BODY>'
149
150
151 args = cgi.parse()
152
153 ui = hg.ui()
154 repo = hg.repository(ui, repo_path)
155
156 if not args.has_key('cmd'):
157 print '<table width="100%" align="center">'
158 for i in xrange(repo.changelog.count()-1, -1, -1):
159 n = repo.changelog.node(i)
160 print '<tr><td>'
161 ent_change(repo, n)
162 print '</td></th>'
163
164 print '</table>'
165 elif args['cmd'][0] == 'chkin':
166 if not args.has_key('nd'):
167 print '<div class="errmsg">No Node!</div>'
168 else:
169 ent_checkin(repo, hg.bin(args['nd'][0]))
170 elif args['cmd'][0] == 'file':
171 if not args.has_key('nd'):
172 print '<div class="errmsg">No Node!</div>'
173 elif not args.has_key('fn'):
174 print '<div class="errmsg">No Filename!</div>'
175 else:
176 ent_file(repo, hg.bin(args['nd'][0]), args['fn'][0])
177
178 else:
179 print '<div class="errmsg">unknown command: ', args['cmd'][0], '</div>'
180
181 print '</BODY>'
182 print '</HTML>'