Alien-SVN
view release on metacpan or search on metacpan
src/subversion/tools/dev/contribulyze.py view on Meta::CPAN
except AttributeError:
my_getopt = getopt.getopt
try:
# Python >=3.0
from urllib.parse import quote as urllib_parse_quote
except ImportError:
# Python <3.0
from urllib import quote as urllib_parse_quote
# Warnings and errors start with these strings. They are typically
# followed by a colon and a space, as in "%s: " ==> "WARNING: ".
warning_prefix = 'WARNING'
error_prefix = 'ERROR'
def complain(msg, fatal=False):
"""Print MSG as a warning, or if FATAL is true, print it as an error
and exit."""
prefix = 'WARNING: '
if fatal:
prefix = 'ERROR: '
sys.stderr.write(prefix + msg + '\n')
if fatal:
sys.exit(1)
def html_spam_guard(addr, entities_only=False):
"""Return a spam-protected version of email ADDR that renders the
same in HTML as the original address. If ENTITIES_ONLY, use a less
thorough mangling scheme involving entities only, avoiding the use
of tags."""
if entities_only:
def mangle(x):
return "&#%d;" % ord (x)
else:
def mangle(x):
return "<span>&#%d;</span>" % ord(x)
return "".join(map(mangle, addr))
def escape_html(str):
"""Return an HTML-escaped version of STR."""
return str.replace('&', '&').replace('<', '<').replace('>', '>')
_spam_guard_in_html_block_re = re.compile(r'<([^&]*@[^&]*)>')
def _spam_guard_in_html_block_func(m):
return "<%s>" % html_spam_guard(m.group(1))
def spam_guard_in_html_block(str):
"""Take a block of HTML data, and run html_spam_guard() on parts of it."""
return _spam_guard_in_html_block_re.subn(_spam_guard_in_html_block_func,
str)[0]
def html_header(title, page_heading=None, highlight_targets=False):
"""Write HTML file header. TITLE and PAGE_HEADING parameters are
expected to already by HTML-escaped if needed. If HIGHLIGHT_TARGETS
is true, then write out a style header that causes anchor targets to be
surrounded by a red border when they are jumped to."""
if not page_heading:
page_heading = title
s = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"\n'
s += ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n'
s += '<html><head>\n'
s += '<meta http-equiv="Content-Type"'
s += ' content="text/html; charset=UTF-8" />\n'
if highlight_targets:
s += '<style type="text/css">\n'
s += ':target { border: 2px solid red; }\n'
s += '</style>\n'
s += '<title>%s</title>\n' % title
s += '</head>\n\n'
s += '<body style="text-color: black; background-color: white">\n\n'
s += '<h1 style="text-align: center">%s</h1>\n\n' % page_heading
s += '<hr />\n\n'
return s
def html_footer():
return '\n</body>\n</html>\n'
class Contributor(object):
# Map contributor names to contributor instances, so that there
# exists exactly one instance associated with a given name.
# Fold names with email addresses. That is, if we see someone
# listed first with just an email address, but later with a real
# name and that same email address together, we create only one
# instance, and store it under both the email and the real name.
all_contributors = { }
def __init__(self, username, real_name, email):
"""Instantiate a contributor. Don't use this to generate a
Contributor for an external caller, though, use .get() instead."""
self.real_name = real_name
self.username = username
self.email = email
self.is_committer = False # Assume not until hear otherwise.
self.is_full_committer = False # Assume not until hear otherwise.
# Map verbs (e.g., "Patch", "Suggested", "Review") to lists of
# LogMessage objects. For example, the log messages stored under
# "Patch" represent all the revisions for which this contributor
# contributed a patch.
self.activities = { }
def add_activity(self, field_name, log):
"""Record that this contributor was active in FIELD_NAME in LOG."""
logs = self.activities.get(field_name)
if not logs:
logs = [ ]
self.activities[field_name] = logs
if not log in logs:
logs.append(log)
@staticmethod
def get(username, real_name, email):
"""If this contributor is already registered, just return it;
otherwise, register it then return it. Hint: use parse() to
generate the arguments."""
c = None
for key in username, real_name, email:
if key and key in Contributor.all_contributors:
( run in 0.551 second using v1.01-cache-2.11-cpan-119454b85a5 )