diff options
-rw-r--r-- | becommands/html.py | 313 |
1 files changed, 141 insertions, 172 deletions
diff --git a/becommands/html.py b/becommands/html.py index e965724..d944119 100644 --- a/becommands/html.py +++ b/becommands/html.py @@ -16,8 +16,7 @@ # 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__ @@ -28,7 +27,6 @@ def execute(args, manipulate_encodings=True): >>> 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") @@ -46,8 +44,7 @@ def execute(args, manipulate_encodings=True): 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 @@ -58,37 +55,30 @@ def execute(args, manipulate_encodings=True): _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]") @@ -126,14 +116,15 @@ def escape(string): 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 { @@ -392,7 +383,7 @@ class BEHTMLGen(): <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> @@ -404,34 +395,37 @@ class BEHTMLGen(): <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> """ @@ -441,7 +435,7 @@ class BEHTMLGen(): <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> @@ -449,18 +443,18 @@ class BEHTMLGen(): <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> @@ -469,7 +463,7 @@ class BEHTMLGen(): self.detail_line =""" <tr> - <td align="right">%s</td><td>%s</td> + <td align="right">%(label)s :</td><td>%(value)s</td> </tr> """ @@ -479,137 +473,72 @@ class BEHTMLGen(): <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 ---------", @@ -619,18 +548,58 @@ class BEHTMLGen(): ""] 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() |