hgweb.py
changeset 57 115106376f45
child 61 1215bf60468f
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>'