148 lines
4.7 KiB
Python
148 lines
4.7 KiB
Python
#!/usr/bin/env python
|
|
# -*-python-*-
|
|
#
|
|
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
|
|
# Copyright (C) 2000 Curt Hagenlocher <curt@hagenlocher.org>
|
|
#
|
|
# By using this file, you agree to the terms and conditions set forth in
|
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
|
# distribution or at http://viewvc.org/license-1.html.
|
|
#
|
|
# For more information, visit http://viewvc.org/
|
|
#
|
|
# -----------------------------------------------------------------------
|
|
#
|
|
# blame.py: Annotate each line of a CVS file with its author,
|
|
# revision #, date, etc.
|
|
#
|
|
# -----------------------------------------------------------------------
|
|
#
|
|
# This file is based on the cvsblame.pl portion of the Bonsai CVS tool,
|
|
# developed by Steve Lamm for Netscape Communications Corporation. More
|
|
# information about Bonsai can be found at
|
|
# http://www.mozilla.org/bonsai.html
|
|
#
|
|
# cvsblame.pl, in turn, was based on Scott Furman's cvsblame script
|
|
#
|
|
# -----------------------------------------------------------------------
|
|
|
|
import sys
|
|
import os
|
|
import re
|
|
import time
|
|
import math
|
|
|
|
from common import _item
|
|
import vclib
|
|
import sapi
|
|
|
|
re_includes = re.compile('\\#(\\s*)include(\\s*)"(.*?)"')
|
|
|
|
def link_includes(text, repos, path_parts, include_url):
|
|
match = re_includes.match(text)
|
|
if match:
|
|
incfile = match.group(3)
|
|
include_path_parts = path_parts[:-1]
|
|
for part in filter(None, incfile.split('/')):
|
|
if part == "..":
|
|
if not include_path_parts:
|
|
# nothing left to pop; don't bother marking up this include.
|
|
return text
|
|
include_path_parts.pop()
|
|
elif part and part != ".":
|
|
include_path_parts.append(part)
|
|
|
|
include_path = None
|
|
try:
|
|
if repos.itemtype(include_path_parts, None) == vclib.FILE:
|
|
include_path = '/'.join(include_path_parts)
|
|
except vclib.ItemNotFound:
|
|
pass
|
|
|
|
if include_path:
|
|
return '#%sinclude%s<a href="%s">"%s"</a>' % \
|
|
(match.group(1), match.group(2),
|
|
include_url.replace('/WHERE/', include_path), incfile)
|
|
|
|
return text
|
|
|
|
|
|
class HTMLBlameSource:
|
|
"""Wrapper around a the object by the vclib.annotate() which does
|
|
HTML escaping, diff URL generation, and #include linking."""
|
|
def __init__(self, repos, path_parts, diff_url, include_url, opt_rev=None):
|
|
self.repos = repos
|
|
self.path_parts = path_parts
|
|
self.diff_url = diff_url
|
|
self.include_url = include_url
|
|
self.annotation, self.revision = self.repos.annotate(path_parts, opt_rev,
|
|
True)
|
|
|
|
def __getitem__(self, idx):
|
|
item = self.annotation.__getitem__(idx)
|
|
diff_url = None
|
|
if item.prev_rev:
|
|
diff_url = '%sr1=%s&r2=%s' % (self.diff_url, item.prev_rev, item.rev)
|
|
thisline = link_includes(sapi.escape(item.text), self.repos,
|
|
self.path_parts, self.include_url)
|
|
return _item(text=thisline, line_number=item.line_number,
|
|
rev=item.rev, prev_rev=item.prev_rev,
|
|
diff_url=diff_url, date=item.date, author=item.author)
|
|
|
|
|
|
def blame(repos, path_parts, diff_url, include_url, opt_rev=None):
|
|
source = HTMLBlameSource(repos, path_parts, diff_url, include_url, opt_rev)
|
|
return source, source.revision
|
|
|
|
|
|
def make_html(root, rcs_path):
|
|
import vclib.ccvs.blame
|
|
bs = vclib.ccvs.blame.BlameSource(os.path.join(root, rcs_path))
|
|
|
|
line = 0
|
|
old_revision = 0
|
|
row_color = 'ffffff'
|
|
rev_count = 0
|
|
|
|
align = ' style="text-align: %s;"'
|
|
|
|
sys.stdout.write('<table cellpadding="2" cellspacing="2" style="font-family: monospace; whitespace: pre;">\n')
|
|
for line_data in bs:
|
|
revision = line_data.rev
|
|
thisline = line_data.text
|
|
line = line_data.line_number
|
|
author = line_data.author
|
|
prev_rev = line_data.prev_rev
|
|
|
|
if old_revision != revision and line != 1:
|
|
if row_color == 'ffffff':
|
|
row_color = 'e7e7e7'
|
|
else:
|
|
row_color = 'ffffff'
|
|
|
|
sys.stdout.write('<tr id="l%d" style="background-color: #%s; vertical-align: center;">' % (line, row_color))
|
|
sys.stdout.write('<td%s>%d</td>' % (align % 'right', line))
|
|
|
|
if old_revision != revision or rev_count > 20:
|
|
sys.stdout.write('<td%s>%s</td>' % (align % 'right', author or ' '))
|
|
sys.stdout.write('<td%s>%s</td>' % (align % 'left', revision))
|
|
old_revision = revision
|
|
rev_count = 0
|
|
else:
|
|
sys.stdout.write('<td> </td><td> </td>')
|
|
rev_count = rev_count + 1
|
|
|
|
sys.stdout.write('<td%s>%s</td></tr>\n' % (align % 'left', thisline.rstrip() or ' '))
|
|
sys.stdout.write('</table>\n')
|
|
|
|
|
|
def main():
|
|
import sys
|
|
if len(sys.argv) != 3:
|
|
print 'USAGE: %s cvsroot rcs-file' % sys.argv[0]
|
|
sys.exit(1)
|
|
make_html(sys.argv[1], sys.argv[2])
|
|
|
|
if __name__ == '__main__':
|
|
main()
|