Show More
@@ -0,0 +1,182 b'' | |||||
|
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 ' ' | |||
|
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 ' %d:<a href="?cmd=rev;nd=%s">%s</a>' % \ | |||
|
105 | (i2, h2, h2, ), | |||
|
106 | else: | |||
|
107 | print ' %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 ' ' | |||
|
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>' |
General Comments 0
You need to be logged in to leave comments.
Login now