# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""Generate a static HTML dump of the current repository status"""
from libbe import cmdutil, bugdir, bug
-#from html_data import *
-import codecs, os, re, string, time
+import codecs, os, os.path, re, string, time
import xml.sax.saxutils, htmlentitydefs
__desc__ = __doc__
>>> bd = bugdir.SimpleBugDir()
>>> os.chdir(bd.root)
>>> execute([], manipulate_encodings=False)
- Creating the html output in html_export
>>> os.path.exists("./html_export")
True
>>> os.path.exists("./html_export/index.html")
parser = get_parser()
options, args = parser.parse_args(args)
complete(options, args, parser)
- cmdutil.default_complete(options, args, parser,
- bugid_args={0: lambda bug : bug.active==False})
+ cmdutil.default_complete(options, args, parser)
if len(args) == 0:
out_dir = options.outdir
_css_file = template
if options.verbose == True:
print "Creating the html output in %s using %s template"%(out_dir, _css_file)
- else:
- out_dir = args[0]
if len(args) > 0:
raise cmdutil.UsageError, "Too many arguments."
bd = bugdir.BugDir(from_disk=True,
manipulate_encodings=manipulate_encodings)
bd.load_all_bugs()
- status_list = bug.status_values
- severity_list = bug.severity_values
- st = {}
- se = {}
- stime = {}
bugs_active = []
bugs_inactive = []
- for s in status_list:
- st[s] = 0
- for b in sorted(bd, reverse=True):
- stime[b.uuid] = b.time
- if b.active == True:
- bugs_active.append(b)
+ bugs = [b for b in bd]
+ bugs.sort()
+ bugs_active = [b for b in bugs if b.active == True]
+ bugs_inactive = [b for b in bugs if b.active != True]
+
+ html_gen = BEHTMLGen(bd, template, options.verbose, bd.encoding)
+ html_gen.create_output_directories(out_dir)
+ html_gen.write_css_file()
+ for b in bugs:
+ if b.active:
+ up_link = "../index.html"
else:
- bugs_inactive.append(b)
- st[b.status] += 1
- ordered_bug_list = sorted([(value,key) for (key,value) in stime.items()])
- ordered_bug_list_in = sorted([(value,key) for (key,value) in stime.items()])
- #open_bug_list = sorted([(value,key) for (key,value) in bugs.items()])
-
- html_gen = BEHTMLGen(bd, template, options.verbose)
- html_gen.create_index_file(out_dir, st, bugs_active, ordered_bug_list, "active", bd.encoding)
- html_gen.create_index_file(out_dir, st, bugs_inactive, ordered_bug_list, "inactive", bd.encoding)
+ up_link = "../index_inactive.html"
+ html_gen.write_detail_file(b, up_link)
+ html_gen.write_index_file(bugs_active, "active")
+ html_gen.write_index_file(bugs_inactive, "inactive")
def get_parser():
parser = cmdutil.CmdOptionParser("be html [options]")
return "".join(chars)
class BEHTMLGen():
- def __init__(self, bd, template, verbose):
+ def __init__(self, bd, template, verbose, encoding):
self.index_value = ""
self.bd = bd
self.verbose = verbose
+ self.encoding = encoding
if template == None:
self.template = "default"
else:
- self.template = template
+ self.template = os.path.abspath(os.path.expanduser(template))
self.css_file = """
body {
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>BugsEverywhere Issue Tracker</title>
- <meta http-equiv="Content-Type" content="text/html; charset=%s" />
+ <meta http-equiv="Content-Type" content="text/html; charset=%(charset)s" />
<link rel="stylesheet" href="style.css" type="text/css" />
</head>
<body>
<table>
<tr>
- <td class="%s"><a href="index.html">Active Bugs</a></td>
- <td class="%s"><a href="index_inactive.html">Inactive Bugs</a></td>
+ <td class="%(active_class)s"><a href="index.html">Active Bugs</a></td>
+ <td class="%(inactive_class)s"><a href="index_inactive.html">Inactive Bugs</a></td>
</tr>
</table>
<table class="table_bug">
<tbody>
- %s
+ %(bug_table)s
</tbody>
</table>
</div>
- <div class="footer">Generated by <a href="http://www.bugseverywhere.org/">BugsEverywhere</a> on %s</div>
+ <div class="footer">
+ <p>Generated by <a href="http://www.bugseverywhere.org/">
+ BugsEverywhere</a> on %(generation_time)s</p>
+ </div>
</body>
</html>
"""
self.bug_line ="""
- <tr class="%s-row">
- <td ><a href="bugs/%s.html">%s</a></td>
- <td ><a href="bugs/%s.html">%s</a></td>
- <td><a href="bugs/%s.html">%s</a></td>
- <td><a href="bugs/%s.html">%s</a></td>
- <td><a href="bugs/%s.html">%s</a></td>
+ <tr class="%(severity)s-row">
+ <td ><a href="bugs/%(uuid)s.html">%(shortname)s</a></td>
+ <td ><a href="bugs/%(uuid)s.html">%(status)s</a></td>
+ <td><a href="bugs/%(uuid)s.html">%(severity)s</a></td>
+ <td><a href="bugs/%(uuid)s.html">%(summary)s</a></td>
+ <td><a href="bugs/%(uuid)s.html">%(time_string)s</a></td>
</tr>
"""
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>BugsEverywhere Issue Tracker</title>
- <meta http-equiv="Content-Type" content="text/html; charset=%s" />
+ <meta http-equiv="Content-Type" content="text/html; charset=%(charset)s" />
<link rel="stylesheet" href="../style.css" type="text/css" />
</head>
<body>
<div class="main">
<h1>BugsEverywhere Bug List</h1>
- <h5><a href="%%s">Back to Index</a></h5>
- <h2>Bug: _bug_id_</h2>
+ <h5><a href="%(up_link)s">Back to Index</a></h5>
+ <h2>Bug: %(shortname)s</h2>
<table >
<tbody>
- %s
+ %(bug_lines)s
- %s
+ %(comment_lines)s
</tbody>
</table>
</div>
- <h5><a href="%s">Back to Index</a></h5>
+ <h5><a href="%(up_link)s">Back to Index</a></h5>
<div class="footer">Generated by <a href="http://www.bugseverywhere.org/">BugsEverywhere</a>.</div>
</body>
</html>
self.detail_line ="""
<tr>
- <td align="right">%s</td><td>%s</td>
+ <td align="right">%(label)s :</td><td>%(value)s</td>
</tr>
"""
<td align="right">Comments:
</td>
<td>
- %s
+ %(comment)s
</td>
</tr>
"""
if template != None:
+ for filename,attr in [('style.css','css_file'),
+ ('index_file.tpl','index_file'),
+ ('detail_file.tpl','detail_file'),
+ ('comment_section.tpl','comment_section')]:
+ fullpath = os.path.join(self.template, filename)
+ if os.path.exists(fullpath):
+ f = codecs.open(fullpath, "r", self.encoding)
+ setattr(self, attr, f.read())
+ f.close()
+
+ def create_output_directories(self, out_dir):
+ if self.verbose:
+ print "Creating output directories"
+ self.out_dir = os.path.abspath(os.path.expanduser(out_dir))
+ if not os.path.exists(self.out_dir):
try:
- FI = open("%s/style.css"%self.template)
- self.css_file = FI.read()
- FI.close()
- except:
- pass
- try:
- FI = open("%s/index_file.tpl"%self.template)
- self.index_first = FI.read()
- FI.close()
- except:
- pass
-
- try:
- FI.open("%s/detail_file.tpl"%self.template)
- self.detail_first = FI.read()
- FI.close()
- except:
- pass
- try:
- FI.open("%s/comment_section.tpl"%self.template)
- self.comment_section = FI.read()
- FI.close()
- except:
- pass
-
- def create_index_file(self, out_dir_path, summary, bugs, ordered_bug, fileid, encoding):
-
- try:
- os.stat(out_dir_path)
- except:
- try:
- os.mkdir(out_dir_path)
+ os.mkdir(self.out_dir)
except:
- raise cmdutil.UsageError, "Cannot create output directory."
- try:
- FO = codecs.open(out_dir_path+"/style.css", "w", encoding)
- FO.write(self.css_file)
- FO.close()
- except:
- raise cmdutil.UsageError, "Cannot create the style.css file."
-
- try:
- os.mkdir(out_dir_path+"/bugs")
- except:
- pass
-
- try:
- if fileid == "active":
- if self.verbose:
- print "Creating active bug index..."
- FO = codecs.open(out_dir_path+"/index.html", "w", encoding)
- if fileid == "inactive":
- if self.verbose:
- print "Creating inactive bug index..."
- FO = codecs.open(out_dir_path+"/index_inactive.html", "w", encoding)
- except:
- raise cmdutil.UsageError, "Cannot create the index.html file."
-
- c = 0
- t = len(bugs) - 1
- line = ""
- for l in range(t, -1, -1):
- if self.verbose:
- print "Creating bug entry: %s"%escape(bugs[l].uuid[0:3])
- line += self.bug_line%(escape(bugs[l].severity),
- escape(bugs[l].uuid), escape(bugs[l].uuid[0:3]),
- escape(bugs[l].uuid), escape(bugs[l].status),
- escape(bugs[l].uuid), escape(bugs[l].severity),
- escape(bugs[l].uuid), escape(bugs[l].summary),
- escape(bugs[l].uuid), escape(bugs[l].time_string)
- )
- c += 1
- if self.verbose:
- print "\tCreating detail entry for bug: %s"%escape(bugs[l].uuid[0:3])
- self.create_detail_file(bugs[l], out_dir_path, fileid, encoding)
- when = time.ctime()
-
- try:
- if fileid == "active":
- if self.verbose:
- print "Writing active bug index..."
- FO.write(self.index_file%(encoding, 'td_sel','td_nsel', line, when))
- if fileid == "inactive":
- if self.verbose:
- print "Writing inactive bug index..."
- FO.write(self.index_file%(encoding,'td_nsel','td_sel', line, when))
- except:
- raise cmdutil.UsageError, "Cannot create the index.html file."
-
-
- def create_detail_file(self, bug, out_dir_path, fileid, encoding):
- f = "%s.html"%bug.uuid
- p = out_dir_path+"/bugs/"+f
- try:
- FD = codecs.open(p, "w", encoding)
- except:
- raise cmdutil.UsageError, "Cannot create the detail html file."
-
+ raise cmdutil.UsageError, "Cannot create output directory '%s'." % self.out_dir
+ self.out_dir_bugs = os.path.join(self.out_dir, "bugs")
+ if not os.path.exists(self.out_dir_bugs):
+ os.mkdir(self.out_dir_bugs)
+
+ def write_css_file(self):
+ if self.verbose:
+ print "Writing css file"
+ assert hasattr(self, "out_dir"), "Must run after ._create_output_directories()"
+ f = codecs.open(os.path.join(self.out_dir,"style.css"), "w", self.encoding)
+ f.write(self.css_file)
+ f.close()
+
+ def write_detail_file(self, bug, up_link):
+ if self.verbose:
+ print "\tCreating detail entry for bug: %s" % escape(self.bd.bug_shortname(bug))
+ assert hasattr(self, "out_dir_bugs"), "Must run after ._create_output_directories()"
detail_file_ = re.sub('_bug_id_', bug.uuid[0:3], self.detail_file)
bug_ = self.bd.bug_from_shortname(bug.uuid)
bug_.load_comments(load_full=True)
- det_line = ""
- det_line += self.detail_line%("ID : ", bug.uuid)
- det_line += self.detail_line%("Short name : ", escape(bug.uuid[0:3]))
- det_line += self.detail_line%("Severity : ", escape(bug.severity))
- det_line += self.detail_line%("Status : ", escape(bug.status))
- det_line += self.detail_line%("Assigned : ", escape(bug.assigned))
- det_line += self.detail_line%("Target : ", escape(bug.target))
- det_line += self.detail_line%("Reporter : ", escape(bug.reporter))
- det_line += self.detail_line%("Creator : ", escape(bug.creator))
- det_line += self.detail_line%("Created : ", escape(bug.time_string))
- det_line += self.detail_line%("Summary : ", escape(bug.summary))
- det_line += """<tr><td colspan="2"><hr /></td></tr>"""
-
- tr = []
- b = ''
- level = 0
+ detail_lines = []
+ for label,value in [('ID', bug.uuid),
+ ('Short name', escape(self.bd.bug_shortname(bug))),
+ ('Severity', escape(bug.severity)),
+ ('Status', escape(bug.status)),
+ ('Assigned', escape(bug.assigned)),
+ ('Target', escape(bug.target)),
+ ('Reporter', escape(bug.reporter)),
+ ('Creator', escape(bug.creator)),
+ ('Created', escape(bug.time_string)),
+ ('Summary', escape(bug.summary)),
+ ]:
+ detail_lines.append(self.detail_line % {'label':label, 'value':value})
+ detail_lines.append('<tr><td colspan="2"><hr /></td></tr>')
+
stack = []
- com = ""
+ comment_lines = []
for depth,comment in bug_.comment_root.thread(flatten=False):
while len(stack) > depth:
stack.pop(-1) # pop non-parents off the stack
- com += "</div>\n" # close non-parent <div class="comment...
+ comment_lines.append("</div>\n") # close non-parent <div class="comment...
assert len(stack) == depth
stack.append(comment)
lines = ["--------- Comment ---------",
""]
lines.extend(escape(comment.body).splitlines())
if depth == 0:
- com += '<div class="commentF">'
+ comment_lines.append('<div class="commentF">')
else:
- com += '<div class="comment">'
- #FD.write("<br />\n".join(lines)+"<br />\n")
- com += "<br />\n".join(lines)+"<br />\n"
+ comment_lines.append('<div class="comment">')
+ comment_lines.append("<br />\n".join(lines)+"<br />\n")
while len(stack) > 0:
stack.pop(-1)
- com += "</div>\n" # close every remaining <div class="comment...
- comments = self.comment_section%com
+ comment_lines.append("</div>\n") # close every remaining <div class="comment...
+ comments = self.comment_section % {'comment':'\n'.join(comment_lines)}
+
+ filename = "%s.html" % bug.uuid
+ fullpath = os.path.join(self.out_dir_bugs, filename)
+ template_info = {'charset':self.encoding,
+ 'shortname':self.bd.bug_shortname(bug),
+ 'up_link':up_link,
+ 'bug_lines':'\n'.join(detail_lines),
+ 'comment_lines':comments}
+ f = codecs.open(fullpath, "w", self.encoding)
+ f.write(detail_file_ % template_info)
+ f.close()
+
+ def write_index_file(self, bugs, fileid):
+ if self.verbose:
+ print "Writing %s index file for %d bugs" % (fileid, len(bugs))
+ assert hasattr(self, "out_dir"), "Must run after ._create_output_directories()"
+
+ bug_lines = []
+ for b in bugs:
+ if self.verbose:
+ print "Creating bug entry: %s" % escape(self.bd.bug_shortname(b))
+ template_info = {'uuid':b.uuid,
+ 'shortname':self.bd.bug_shortname(b),
+ 'status':b.status,
+ 'severity':b.severity,
+ 'summary':b.summary,
+ 'time_string':b.time_string}
+ bug_lines.append(self.bug_line % template_info)
if fileid == "active":
- FD.write(detail_file_%(encoding, "../index.html", det_line, comments, "../index.html"))
+ filename = "index.html"
+ elif fileid == "inactive":
+ filename = "index_inactive.html"
+ else:
+ raise Exception, "Unrecognized fileid: '%s'" % fileid
+ template_info = {'charset':self.encoding,
+ 'active_class':'td_sel',
+ 'inactive_class':'td_nsel',
+ 'bug_table':'\n'.join(bug_lines),
+ 'generation_time':time.ctime()}
if fileid == "inactive":
- FD.write(detail_file_%(encoding, "../index_inactive.html", det_line, comments, "../index_inactive.html"))
- FD.close()
+ template_info['active_class'] = 'td_nsel'
+ template_info['inactive_class'] = 'td_sel'
+
+ f = codecs.open(os.path.join(self.out_dir, filename), "w", self.encoding)
+ f.write(self.index_file % template_info)
+ f.close()