|
Packit |
98cdb6 |
#!/usr/bin/python
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
import xmllib;
|
|
Packit |
98cdb6 |
import sys;
|
|
Packit |
98cdb6 |
import string
|
|
Packit |
98cdb6 |
import re
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
def html_subst(s):
|
|
Packit |
98cdb6 |
if s.group(1) != None:
|
|
Packit |
98cdb6 |
return s.group(0)
|
|
Packit |
98cdb6 |
elif s.group(2) != None:
|
|
Packit |
98cdb6 |
return '' + s.group(0) + ''
|
|
Packit |
98cdb6 |
elif s.group(3) != None:
|
|
Packit |
98cdb6 |
return '' + s.group(0) + ''
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
def htmlify(str):
|
|
Packit |
98cdb6 |
return re.sub ("(<[^>]*>)|(http://[~.:/\w-]+)|([\w._!-]+@[\w_-]+).[\w_-]+", html_subst, str)
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
def bug_subst(s):
|
|
Packit |
98cdb6 |
if s.group(1) != None:
|
|
Packit |
98cdb6 |
return s.group(0)
|
|
Packit |
98cdb6 |
else:
|
|
Packit |
98cdb6 |
n = s.group(2)
|
|
Packit |
98cdb6 |
return '#%s' % (n[0:2], n, n)
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
def bugify(str):
|
|
Packit |
98cdb6 |
str = re.sub ("(<[^>]*>)|#(\d+)", bug_subst, str)
|
|
Packit |
98cdb6 |
return htmlify(str)
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
def make_id(str):
|
|
Packit |
98cdb6 |
return re.sub ("[^a-z]","-", string.lower(str))
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
class ParseError (Exception):
|
|
Packit |
98cdb6 |
pass
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
class Entry:
|
|
Packit |
98cdb6 |
def __init__(self):
|
|
Packit |
98cdb6 |
self.description = None
|
|
Packit |
98cdb6 |
self.title = None
|
|
Packit |
98cdb6 |
self.url = None
|
|
Packit |
98cdb6 |
self.contact = None
|
|
Packit |
98cdb6 |
self.bugs = None
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
def set_size(self, size):
|
|
Packit |
98cdb6 |
size = string.lower(size)
|
|
Packit |
98cdb6 |
if size == "small":
|
|
Packit |
98cdb6 |
self.size = "Small"
|
|
Packit |
98cdb6 |
elif size == "medium":
|
|
Packit |
98cdb6 |
self.size = "Medium"
|
|
Packit |
98cdb6 |
elif size == "big":
|
|
Packit |
98cdb6 |
self.size = "Big"
|
|
Packit |
98cdb6 |
else:
|
|
Packit |
98cdb6 |
raise ParseError, 'size must be "small", "medium", or "big"'
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
def output(self):
|
|
Packit |
98cdb6 |
if self.size == "Big":
|
|
Packit |
98cdb6 |
bgcolor = "#88bb88"
|
|
Packit |
98cdb6 |
elif self.size == "Medium":
|
|
Packit |
98cdb6 |
bgcolor = "#b4d4b4"
|
|
Packit |
98cdb6 |
else:
|
|
Packit |
98cdb6 |
bgcolor = "#d0e0d0"
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
print '''
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
<font size="+1">%s</font></font>
|
|
Packit |
98cdb6 |
Size: %s
|
|
Packit |
98cdb6 |
Status: %s
|
|
Packit |
98cdb6 |
Target Version: %s
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
%s
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
''' % (bgcolor, self.title, self.size, self.status, self.target, htmlify(self.description))
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
if self.url != None:
|
|
Packit |
98cdb6 |
print '''More Info:
|
|
Packit |
98cdb6 |
%s
|
|
Packit |
98cdb6 |
''' % htmlify (self.url)
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
if self.bugs != None:
|
|
Packit |
98cdb6 |
print '''Bug Reports:
|
|
Packit |
98cdb6 |
%s
|
|
Packit |
98cdb6 |
''' % bugify (self.bugs)
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
if self.contact != None:
|
|
Packit |
98cdb6 |
print '''Contact:
|
|
Packit |
98cdb6 |
%s
|
|
Packit |
98cdb6 |
''' % htmlify (self.contact)
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
print '''
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
'''
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
class Section:
|
|
Packit |
98cdb6 |
def __init__(self):
|
|
Packit |
98cdb6 |
self.title = None
|
|
Packit |
98cdb6 |
self.entries = []
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
def output(self):
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
print '' % (make_id(self.title), self.title)
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
first = 1
|
|
Packit |
98cdb6 |
for entry in self.entries:
|
|
Packit |
98cdb6 |
if not first:
|
|
Packit |
98cdb6 |
print " "
|
|
Packit |
98cdb6 |
first = 0
|
|
Packit |
98cdb6 |
entry.output()
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
class TodoParser (xmllib.XMLParser):
|
|
Packit |
98cdb6 |
def __init__(self):
|
|
Packit |
98cdb6 |
xmllib.XMLParser.__init__(self)
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
self.in_todo = 0
|
|
Packit |
98cdb6 |
self.in_data = 0
|
|
Packit |
98cdb6 |
self.data = ""
|
|
Packit |
98cdb6 |
self.section = None
|
|
Packit |
98cdb6 |
self.entry = None
|
|
Packit |
98cdb6 |
self.logourl = None
|
|
Packit |
98cdb6 |
self.title = None
|
|
Packit |
98cdb6 |
self.sections = []
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
self.entitydefs = {}
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
def start_todo(self,attributes):
|
|
Packit |
98cdb6 |
if self.in_todo:
|
|
Packit |
98cdb6 |
raise ParseError, "<todo> tags may not be nested"
|
|
Packit |
98cdb6 |
if attributes.has_key ("logourl"):
|
|
Packit |
98cdb6 |
self.logourl = attributes["logourl"]
|
|
Packit |
98cdb6 |
self.in_todo = 1
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
def end_todo(self):
|
|
Packit |
98cdb6 |
self.in_todo = 0
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
def start_section(self,attributes):
|
|
Packit |
98cdb6 |
if self.section:
|
|
Packit |
98cdb6 |
raise ParseError, "<section> tags may not be nested"
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
self.section = Section()
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
def end_section(self):
|
|
Packit |
98cdb6 |
if self.section.title == None:
|
|
Packit |
98cdb6 |
raise ParseError, "<section> requires <title>"
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
self.sections.append(self.section)
|
|
Packit |
98cdb6 |
self.section = None
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
def start_title(self,attributes):
|
|
Packit |
98cdb6 |
if not self.in_todo:
|
|
Packit |
98cdb6 |
raise ParseError, "<title> tag must be in <todo>, <section> or <entry>"
|
|
Packit |
98cdb6 |
if self.in_data:
|
|
Packit |
98cdb6 |
raise ParseError, "Unexpected <title> tag in content"
|
|
Packit |
98cdb6 |
self.in_data = 1
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
def end_title(self):
|
|
Packit |
98cdb6 |
self.in_data = 0
|
|
Packit |
98cdb6 |
if self.entry:
|
|
Packit |
98cdb6 |
self.entry.title = self.data
|
|
Packit |
98cdb6 |
elif self.section:
|
|
Packit |
98cdb6 |
self.section.title = self.data
|
|
Packit |
98cdb6 |
else:
|
|
Packit |
98cdb6 |
self.title = self.data
|
|
Packit |
98cdb6 |
self.data = ""
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
def start_description(self,attributes):
|
|
Packit |
98cdb6 |
if not self.entry:
|
|
Packit |
98cdb6 |
raise ParseError, "<description> tag must be in <entry>"
|
|
Packit |
98cdb6 |
if self.in_data:
|
|
Packit |
98cdb6 |
raise ParseError, "Unexpected <description> tag in content"
|
|
Packit |
98cdb6 |
self.in_data = 1
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
def end_description(self):
|
|
Packit |
98cdb6 |
self.in_data = 0
|
|
Packit |
98cdb6 |
self.entry.description = self.data
|
|
Packit |
98cdb6 |
self.data = ""
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
def start_url(self,attributes):
|
|
Packit |
98cdb6 |
if not self.entry:
|
|
Packit |
98cdb6 |
raise ParseError, "<url> tag must be in <entry>"
|
|
Packit |
98cdb6 |
if self.in_data:
|
|
Packit |
98cdb6 |
raise ParseError, "Unexpected <url> tag in content"
|
|
Packit |
98cdb6 |
self.in_data = 1
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
def end_url(self):
|
|
Packit |
98cdb6 |
self.in_data = 0
|
|
Packit |
98cdb6 |
self.entry.url = self.data
|
|
Packit |
98cdb6 |
self.data = ""
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
def start_contact(self,attributes):
|
|
Packit |
98cdb6 |
if not self.entry:
|
|
Packit |
98cdb6 |
raise ParseError, "<contact> tag must be in <entry>"
|
|
Packit |
98cdb6 |
if self.in_data:
|
|
Packit |
98cdb6 |
raise ParseError, "Unexpected <contact> tag in content"
|
|
Packit |
98cdb6 |
self.in_data = 1
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
def end_contact(self):
|
|
Packit |
98cdb6 |
self.in_data = 0
|
|
Packit |
98cdb6 |
self.entry.contact = self.data
|
|
Packit |
98cdb6 |
self.data = ""
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
def start_bugs(self,attributes):
|
|
Packit |
98cdb6 |
if not self.entry:
|
|
Packit |
98cdb6 |
raise ParseError, "<bugs> tag must be in <bugs>"
|
|
Packit |
98cdb6 |
if self.in_data:
|
|
Packit |
98cdb6 |
raise ParseError, "Unexpected <bugs> tag in content"
|
|
Packit |
98cdb6 |
self.in_data = 1
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
def end_bugs(self):
|
|
Packit |
98cdb6 |
self.in_data = 0
|
|
Packit |
98cdb6 |
self.entry.bugs = self.data
|
|
Packit |
98cdb6 |
self.data = ""
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
def start_entry(self,attributes):
|
|
Packit |
98cdb6 |
if not self.section:
|
|
Packit |
98cdb6 |
raise ParseError, "<entry> tag must be in <section>"
|
|
Packit |
98cdb6 |
if self.entry:
|
|
Packit |
98cdb6 |
raise ParseError, "<entry> tags may not be nested"
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
self.entry = Entry()
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
if not attributes.has_key("size"):
|
|
Packit |
98cdb6 |
raise ParseError, '"size" attribute required for entry'
|
|
Packit |
98cdb6 |
self.entry.set_size(attributes["size"])
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
if not attributes.has_key("status"):
|
|
Packit |
98cdb6 |
raise ParseError, '"status" attribute (completion percentage) required for entry'
|
|
Packit |
98cdb6 |
self.entry.status=attributes["status"]
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
if not attributes.has_key("target"):
|
|
Packit |
98cdb6 |
raise ParseError, '"target" attribute (target version) required for entry'
|
|
Packit |
98cdb6 |
self.entry.target=attributes["target"]
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
def end_entry(self):
|
|
Packit |
98cdb6 |
if self.entry.title == None:
|
|
Packit |
98cdb6 |
raise ParseError, "<entry> requires <title>"
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
if self.entry.description == None:
|
|
Packit |
98cdb6 |
raise ParseError, "<entry> requires <description>"
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
self.section.entries.append(self.entry)
|
|
Packit |
98cdb6 |
self.entry = None
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
def handle_data(self,data):
|
|
Packit |
98cdb6 |
if self.in_data:
|
|
Packit |
98cdb6 |
self.data = self.data + data
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
def unknown_starttag(self,tag,attributes):
|
|
Packit |
98cdb6 |
if not self.in_data:
|
|
Packit |
98cdb6 |
raise ParseError, "Unexpected start tag: " + tag
|
|
Packit |
98cdb6 |
else:
|
|
Packit |
98cdb6 |
self.data = self.data + "<" + tag
|
|
Packit |
98cdb6 |
for (key,val) in attributes.items():
|
|
Packit |
98cdb6 |
self.data = self.data + ' %s="%s"' % (key,val)
|
|
Packit |
98cdb6 |
self.data = self.data + ">"
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
def unknown_endtag(self,tag):
|
|
Packit |
98cdb6 |
if not self.in_data:
|
|
Packit |
98cdb6 |
raise ParseError, "Unexpected end tag: " + tag
|
|
Packit |
98cdb6 |
else:
|
|
Packit |
98cdb6 |
self.data = self.data + "</%s>" % tag
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
def syntax_error(self, err):
|
|
Packit |
98cdb6 |
if re.match("reference to unknown entity", err):
|
|
Packit |
98cdb6 |
pass
|
|
Packit |
98cdb6 |
else:
|
|
Packit |
98cdb6 |
xmllib.XMLParser.syntax_error (self, err)
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
def unknown_entityref(self,ref):
|
|
Packit |
98cdb6 |
if not self.in_data:
|
|
Packit |
98cdb6 |
raise ParseError, "Unknown entity &" + ref + ";"
|
|
Packit |
98cdb6 |
else:
|
|
Packit |
98cdb6 |
self.data = self.data + "&" + ref + ";"
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
file = open(sys.argv[1])
|
|
Packit |
98cdb6 |
parser = TodoParser()
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
lineno = 1
|
|
Packit |
98cdb6 |
while 1:
|
|
Packit |
98cdb6 |
line = file.readline()
|
|
Packit |
98cdb6 |
if line == "":
|
|
Packit |
98cdb6 |
break
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
try:
|
|
Packit |
98cdb6 |
parser.feed(line)
|
|
Packit |
98cdb6 |
except ParseError, err:
|
|
Packit |
98cdb6 |
sys.stderr.write("Parse error at line " + `lineno` + ": " + err.__str__() + "\n")
|
|
Packit |
98cdb6 |
sys.exit(1)
|
|
Packit |
98cdb6 |
except RuntimeError, err:
|
|
Packit |
98cdb6 |
sys.stderr.write(err.__str__() + "\n")
|
|
Packit |
98cdb6 |
sys.exit(1)
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
lineno = lineno + 1
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
parser.close()
|
|
Packit |
98cdb6 |
if parser.title == None:
|
|
Packit |
98cdb6 |
sys.stderr.write ("<todo> Document must have a <title>\n")
|
|
Packit |
98cdb6 |
sys.exit (1)
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
print '''
|
|
Packit |
98cdb6 |
<html>
|
|
Packit |
98cdb6 |
<head>
|
|
Packit |
98cdb6 |
<title>%s</title>
|
|
Packit |
98cdb6 |
</head>
|
|
Packit |
98cdb6 |
<body bgcolor="#ffffff">
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
%s''' % (parser.title, parser.title)
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
for section in parser.sections:
|
|
Packit |
98cdb6 |
ntasks = len(section.entries)
|
|
Packit |
98cdb6 |
id = make_id (section.title)
|
|
Packit |
98cdb6 |
if ntasks == 1:
|
|
Packit |
98cdb6 |
print '%s (1 item) ' % (id,section.title)
|
|
Packit |
98cdb6 |
else:
|
|
Packit |
98cdb6 |
print '%s (%d items) ' % (id,section.title,ntasks)
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
print '''
|
|
Packit |
98cdb6 |
'''
|
|
Packit |
98cdb6 |
if parser.logourl != None:
|
|
Packit |
98cdb6 |
print '''
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
''' % parser.logourl
|
|
Packit |
98cdb6 |
print '''
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
'''
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
first = 1
|
|
Packit |
98cdb6 |
for section in parser.sections:
|
|
Packit |
98cdb6 |
if not first:
|
|
Packit |
98cdb6 |
print "
"
|
|
Packit |
98cdb6 |
first = 0
|
|
Packit |
98cdb6 |
section.output()
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
print '''</body>
|
|
Packit |
98cdb6 |
</html>'''
|
|
Packit |
98cdb6 |
|
|
Packit |
98cdb6 |
|