diff options
author | Gianluca Montecchi <gian@grys.it> | 2009-10-20 23:08:57 +0200 |
---|---|---|
committer | Gianluca Montecchi <gian@grys.it> | 2009-10-20 23:08:57 +0200 |
commit | 70af336493d976ec064049d4e6d112c28b13d207 (patch) | |
tree | 7d34248892103904c5a1c69915df6578d625d406 /becommands/html.py | |
parent | 56ac90c26de76167871ec489260580c2c5cf0d4d (diff) | |
download | bugseverywhere-70af336493d976ec064049d4e6d112c28b13d207.tar.gz |
merged with Trevor branch
Diffstat (limited to 'becommands/html.py')
-rw-r--r-- | becommands/html.py | 966 |
1 files changed, 444 insertions, 522 deletions
diff --git a/becommands/html.py b/becommands/html.py index d5c4771..21e80c3 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,58 +44,34 @@ 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 - template = options.template - if template == None: - _css_file = "default" - else: - _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." - + raise cmdutil.UsageError, 'Too many arguments.' + + template = options.template 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) - 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) - + + html_gen = HTMLGen(bd, template=options.template, verbose=options.verbose, + title=options.title, ) + html_gen.run(options.out_dir) + def get_parser(): - parser = cmdutil.CmdOptionParser("be html [options]") - parser.add_option("-o", "--output", metavar="export_dir", dest="outdir", - help="Set the output path, default is ./html_export", default="html_export") - parser.add_option("-t", "--template-dir", metavar="template", dest="template", - help="Use a different template, default is empty", default=None) - parser.add_option("-v", "--verbose", action="store_true", metavar="verbose", dest="verbose", - help="Verbose output, default is no", default=False) + parser = cmdutil.CmdOptionParser('be html [options]') + parser.add_option('-o', '--output', metavar='DIR', dest='out_dir', + help='Set the output path (%default)', default='./html_export') + parser.add_option('-t', '--template-dir', metavar='DIR', dest='template', + help='Use a different template, defaults to internal templates', default=None) + parser.add_option('--title', metavar='STRING', dest='title', + help='Set the bug repository title (%default)', + default='BugsEverywhere Issue Tracker') + parser.add_option('--index-header', metavar='STRING', dest='index_header', + help='Set the index page headers (%default)', + default='BugsEverywhere Bug List') + parser.add_option('-v', '--verbose', action='store_true', metavar='verbose', dest='verbose', + help='Verbose output, default is no', default=False) return parser longhelp=""" @@ -112,527 +86,475 @@ def complete(options, args, parser): for option, value in cmdutil.option_value_pairs(options, parser): if "--complete" in args: raise cmdutil.GetCompletions() # no positional arguments for list - - -def escape(string): - if string == None: - return "" - chars = [] - for char in xml.sax.saxutils.escape(string): - codepoint = ord(char) - if codepoint in htmlentitydefs.codepoint2name: - char = "&%s;" % htmlentitydefs.codepoint2name[codepoint] - chars.append(char) - return "".join(chars) - -class BEHTMLGen(): - def __init__(self, bd, template, verbose): - self.index_value = "" + +class HTMLGen (object): + def __init__(self, bd, template=None, verbose=False, encoding=None, + title="Site Title", index_header="Index Header", + ): + self.generation_time = time.ctime() self.bd = bd self.verbose = verbose + self.title = title + self.index_header = index_header + + if encoding != None: + self.encoding = encoding + else: + self.encoding = self.bd.encoding if template == None: self.template = "default" else: - self.template = template + self.template = os.path.abspath(os.path.expanduser(template)) + self._load_default_templates() + + if template != None: + self._load_user_templates() + + def run(self, out_dir): + if self.verbose == True: + print "Creating the html output in %s using templates in %s" \ + % (out_dir, self.template) + + bugs_active = [] + bugs_inactive = [] + bugs = [b for b in self.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] + + self._create_output_directories(out_dir) + self._write_css_file() + for b in bugs: + if b.active: + up_link = "../index.html" + else: + up_link = "../index_inactive.html" + self._write_bug_file(b, up_link) + self._write_index_file(bugs_active, title=self.title, + index_header=self.index_header, bug_type="active") + self._write_index_file(bugs_inactive, title=self.title, + index_header=self.index_header, bug_type="inactive") + + 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: + os.mkdir(self.out_dir) + except: + 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_bug_file(self, bug, up_link): + if self.verbose: + print "\tCreating bug file for %s" % self.bd.bug_shortname(bug) + assert hasattr(self, "out_dir_bugs"), "Must run after ._create_output_directories()" + + bug.load_comments(load_full=True) + comment_entries = self._generate_bug_comment_entries(bug) + filename = "%s.html" % bug.uuid + fullpath = os.path.join(self.out_dir_bugs, filename) + template_info = {'title':self.title, + 'charset':self.encoding, + 'up_link':up_link, + 'shortname':self.bd.bug_shortname(bug), + 'comment_entries':comment_entries, + 'generation_time':self.generation_time} + for attr in ['uuid', 'severity', 'status', 'assigned', 'target', + 'reporter', 'creator', 'time_string', 'summary']: + template_info[attr] = self._escape(getattr(bug, attr)) + f = codecs.open(fullpath, "w", self.encoding) + f.write(self.bug_file % template_info) + f.close() + + def _generate_bug_comment_entries(self, bug): + assert hasattr(self, "out_dir_bugs"), "Must run after ._create_output_directories()" + + stack = [] + comment_entries = [] + for depth,comment in bug.comment_root.thread(flatten=False): + while len(stack) > depth: + stack.pop(-1) # pop non-parents off the stack + comment_entries.append("</div>\n") # close non-parent <div class="comment... + assert len(stack) == depth + stack.append(comment) + if depth == 0: + comment_entries.append('<div class="comment root">') + else: + comment_entries.append('<div class="comment">') + template_info = {} + for attr in ['uuid', 'author', 'date', 'body']: + value = getattr(comment, attr) + if attr == 'body': + save_body = False + if comment.content_type == 'text/html': + pass # no need to escape html... + elif comment.content_type.startswith('text/'): + value = '<pre>\n'+self._escape(value)+'\n</pre>' + elif comment.content_type.startswith('image/'): + save_body = True + value = '<img src="./%s/%s" />' \ + % (bug.uuid, comment.uuid) + else: + save_body = True + value = '<a href="./%s/%s">Link to %s file</a>.' \ + % (bug.uuid, comment.uuid, comment.content_type) + if save_body == True: + per_bug_dir = os.path.join(self.out_dir_bugs, bug.uuid) + if not os.path.exists(per_bug_dir): + os.mkdir(per_bug_dir) + comment_path = os.path.join(per_bug_dir, comment.uuid) + f = codecs.open(os.path.join(per_bug_dir, '.htaccess'), + 'a', self.encoding) + f.write('<Files %s>\n ForceType %s\n</Files>' \ + % (comment.uuid, comment.content_type)) + f.close() + f = open(os.path.join(per_bug_dir, comment.uuid), "wb") + f.write(comment.body) + f.close + else: + value = self._escape(value) + template_info[attr] = value + comment_entries.append(self.bug_comment_entry % template_info) + while len(stack) > 0: + stack.pop(-1) + comment_entries.append("</div>\n") # close every remaining <div class="comment... + return '\n'.join(comment_entries) + + def _write_index_file(self, bugs, title, index_header, bug_type="active"): + if self.verbose: + print "Writing %s index file for %d bugs" % (bug_type, len(bugs)) + assert hasattr(self, "out_dir"), "Must run after ._create_output_directories()" + esc = self._escape + + bug_entries = self._generate_index_bug_entries(bugs) + + if bug_type == "active": + filename = "index.html" + elif bug_type == "inactive": + filename = "index_inactive.html" + else: + raise Exception, "Unrecognized bug_type: '%s'" % bug_type + template_info = {'title':title, + 'index_header':index_header, + 'charset':self.encoding, + 'active_class':'tab sel', + 'inactive_class':'tab nsel', + 'bug_entries':bug_entries, + 'generation_time':self.generation_time} + if bug_type == "inactive": + template_info['active_class'] = 'tab nsel' + template_info['inactive_class'] = 'tab sel' + + f = codecs.open(os.path.join(self.out_dir, filename), "w", self.encoding) + f.write(self.index_file % template_info) + f.close() + + def _generate_index_bug_entries(self, bugs): + bug_entries = [] + for bug in bugs: + if self.verbose: + print "\tCreating bug entry for %s" % self.bd.bug_shortname(bug) + template_info = {'shortname':self.bd.bug_shortname(bug)} + for attr in ['uuid', 'severity', 'status', 'assigned', 'target', + 'reporter', 'creator', 'time_string', 'summary']: + template_info[attr] = self._escape(getattr(bug, attr)) + bug_entries.append(self.index_bug_entry % template_info) + return '\n'.join(bug_entries) + def _escape(self, string): + if string == None: + return "" + chars = [] + for char in string: + codepoint = ord(char) + if codepoint in htmlentitydefs.codepoint2name: + char = "&%s;" % htmlentitydefs.codepoint2name[codepoint] + #else: xml.sax.saxutils.escape(char) + chars.append(char) + return "".join(chars) + + def _load_user_templates(self): + for filename,attr in [('style.css','css_file'), + ('index_file.tpl','index_file'), + ('index_bug_entry.tpl','index_bug_entry'), + ('bug_file.tpl','bug_file'), + ('bug_comment_entry.tpl','bug_comment_entry')]: + 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 _load_default_templates(self): self.css_file = """ body { - font-family: "lucida grande", "sans serif"; - color: #333; - width: auto; - margin: auto; + font-family: "lucida grande", "sans serif"; + color: #333; + width: auto; + margin: auto; } - - + div.main { - padding: 20px; - margin: auto; - padding-top: 0; - margin-top: 1em; - background-color: #fcfcfc; - } - - .comment { - padding: 20px; - margin: auto; - padding-top: 20px; - margin-top: 0; - } - - .commentF { - padding: 0px; - margin: auto; - padding-top: 0px; - paddin-bottom: 20px; - margin-top: 0; - } - - tb { - border = 1; - } - - .wishlist-row { - background-color: #B4FF9B; - width: auto; - } - - .minor-row { - background-color: #FCFF98; - width: auto; - } - - - .serious-row { - background-color: #FFB648; - width: auto; - } - - .critical-row { - background-color: #FF752A; - width: auto; - } - - .fatal-row { - background-color: #FF3300; - width: auto; + padding: 20px; + margin: auto; + padding-top: 0; + margin-top: 1em; + background-color: #fcfcfc; } - - .person { - font-family: courier; - } - - a, a:visited { - background: inherit; - text-decoration: none; - } - - a { - color: #003d41; - } - - a:visited { - color: #553d41; - } - - ul { - list-style-type: none; - padding: 0; - } - - p { - width: auto; - } - - .inline-status-image { - position: relative; - top: 0.2em; - } - - .dimmed { - color: #bbb; + + div.footer { + font-size: small; + padding-left: 20px; + padding-right: 20px; + padding-top: 5px; + padding-bottom: 5px; + margin: auto; + background: #305275; + color: #fffee7; } - + table { - border-style: 10px solid #313131; - border-spacing: 0; - width: auto; + border-style: solid; + border: 10px #313131; + border-spacing: 0; + width: auto; } - - table.log { + + tb { border: 1px; } + + tr { + vertical-align: top; + width: auto; } - + td { - border-width: 0; - border-style: none; - padding-right: 0.5em; - padding-left: 0.5em; - width: auto; + border-width: 0; + border-style: none; + padding-right: 0.5em; + padding-left: 0.5em; + width: auto; } - - .td_sel { - background-color: #afafaf; - border: 1px solid #afafaf; - font-weight:bold; - padding-right: 1em; - padding-left: 1em; - - } - - .td_nsel { - border: 0px; - padding-right: 1em; - padding-left: 1em; - } - - tr { - vertical-align: top; - width: auto; - } - + + img { border-style: none; } + h1 { - padding: 0.5em; - background-color: #305275; - margin-top: 0; - margin-bottom: 0; - color: #fff; - margin-left: -20px; - margin-right: -20px; - } - - wid { - text-transform: uppercase; - font-size: smaller; - margin-top: 1em; - margin-left: -0.5em; - /*background: #fffbce;*/ - /*background: #628a0d;*/ - padding: 5px; - color: #305275; - } - - .attrname { - text-align: right; - font-size: smaller; - } - - .attrval { - color: #222; - } - - .issue-closed-fixed { - background-image: "green-check.png"; - } - - .issue-closed-wontfix { - background-image: "red-check.png"; - } - - .issue-closed-reorg { - background-image: "blue-check.png"; - } - - .inline-issue-link { - text-decoration: underline; - } - - img { - border: 0; - } - - - div.footer { - font-size: small; - padding-left: 20px; - padding-right: 20px; - padding-top: 5px; - padding-bottom: 5px; - margin: auto; - background: #305275; - color: #fffee7; - } - - .footer a { - color: #508d91; - } - - - .header { - font-family: "lucida grande", "sans serif"; - font-size: smaller; - background-color: #a9a9a9; - text-align: left; - - padding-right: 0.5em; - padding-left: 0.5em; - + padding: 0.5em; + background-color: #305275; + margin-top: 0; + margin-bottom: 0; + color: #fff; + margin-left: -20px; + margin-right: -20px; } - - - .selected-cell { - background-color: #e9e9e2; - } - - .plain-cell { - background-color: #f9f9f9; + + ul { + list-style-type: none; + padding: 0; } - - - .logcomment { - padding-left: 4em; - font-size: smaller; + + p { width: auto; } + + a, a:visited { + background: inherit; + text-decoration: none; } - - .id { - font-family: courier; + + a { color: #003d41; } + a:visited { color: #553d41; } + .footer a { color: #508d91; } + + /* bug index pages */ + + td.tab { + padding-right: 1em; + padding-left: 1em; } - - .table_bug { - background-color: #afafaf; - border: 2px solid #afafaf; + + td.sel.tab { + background-color: #afafaf; + border: 1px solid #afafaf; + font-weight:bold; } - - .message { + + td.nsel.tab { border: 0px; } + + table.bug_list { + background-color: #afafaf; + border: 2px solid #afafaf; } - - .progress-meter-done { - background-color: #03af00; + + .bug_list tr { width: auto; } + tr.wishlist { background-color: #B4FF9B; } + tr.minor { background-color: #FCFF98; } + tr.serious { background-color: #FFB648; } + tr.critical { background-color: #FF752A; } + tr.fatal { background-color: #FF3300; } + + /* bug detail pages */ + + td.bug_detail_label { text-align: right; } + td.bug_detail { } + td.bug_comment_label { text-align: right; vertical-align: top; } + td.bug_comment { } + + div.comment { + padding: 20px; + padding-top: 20px; + margin: auto; + margin-top: 0; } - - .progress-meter-undone { - background-color: #ddd; + + div.root.comment { + padding: 0px; + /* padding-top: 0px; */ + padding-bottom: 20px; } - - .progress-meter { - } - """ - + """ + self.index_file = """ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <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" /> + <title>%(title)s</title> + <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> + <h1>%(index_header)s</h1> <p></p> <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"> + <table class="bug_list"> <tbody> - - %s - + + %(bug_entries)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> + <p> + <a href="http://validator.w3.org/check?uri=referer">Validate XHTML</a> | + <a href="http://jigsaw.w3.org/css-validator/check?uri=referer">Validate CSS</a> + </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> - """ - - self.detail_file = """ - <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> - <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" /> - <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> - <table > - <tbody> - - %s - - %s - </tbody> - </table> - </div> - <h5><a href="%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> - </tr> + + self.index_bug_entry =""" + <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> """ - - self.comment_section =""" - <tr> - <td align="right">Comments: - </td> - <td> - %s - </td> - </tr> + self.bug_file = """ + <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> + <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head> + <title>%(title)s</title> + <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="%(up_link)s">Back to Index</a></h5> + <h2>Bug: %(shortname)s</h2> + <table> + <tbody> + + <tr><td class="bug_detail_label">ID :</td> + <td class="bug_detail">%(uuid)s</td></tr> + <tr><td class="bug_detail_label">Short name :</td> + <td class="bug_detail">%(shortname)s</td></tr> + <tr><td class="bug_detail_label">Status :</td> + <td class="bug_detail">%(status)s</td></tr> + <tr><td class="bug_detail_label">Severity :</td> + <td class="bug_detail">%(severity)s</td></tr> + <tr><td class="bug_detail_label">Assigned :</td> + <td class="bug_detail">%(assigned)s</td></tr> + <tr><td class="bug_detail_label">Reporter :</td> + <td class="bug_detail">%(reporter)s</td></tr> + <tr><td class="bug_detail_label">Creator :</td> + <td class="bug_detail">%(creator)s</td></tr> + <tr><td class="bug_detail_label">Created :</td> + <td class="bug_detail">%(time_string)s</td></tr> + <tr><td class="bug_detail_label">Summary :</td> + <td class="bug_detail">%(summary)s</td></tr> + </tbody> + </table> + + <hr/> + + %(comment_entries)s + + </div> + <h5><a href="%(up_link)s">Back to Index</a></h5> + + <div class="footer"> + <p>Generated by <a href="http://www.bugseverywhere.org/"> + BugsEverywhere</a> on %(generation_time)s</p> + <p> + <a href="http://validator.w3.org/check?uri=referer">Validate XHTML</a> | + <a href="http://jigsaw.w3.org/css-validator/check?uri=referer">Validate CSS</a> + </p> + </div> + + </body> + </html> """ - if template != None: - 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 + self.bug_comment_entry =""" + <table> + <tr> + <td class="bug_comment_label">Comment:</td> + <td class="bug_comment"> + --------- Comment ---------<br/> + Name: %(uuid)s<br/> + From: %(author)s<br/> + Date: %(date)s<br/> + <br/> + %(body)s + </td> + </tr> + </table> + """ - 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) - 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." - - 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 - stack = [] - com = "" - 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... - assert len(stack) == depth - stack.append(comment) - lines = ["--------- Comment ---------", - "Name: %s" % comment.uuid, - "From: %s" % escape(comment.author), - "Date: %s" % escape(comment.date), - ""] - lines.extend(escape(comment.body).splitlines()) - if depth == 0: - com += '<div class="commentF">' - else: - com += '<div class="comment">' - #FD.write("<br />\n".join(lines)+"<br />\n") - com += "<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 - - if fileid == "active": - FD.write(detail_file_%(encoding, "../index.html", det_line, comments, "../index.html")) - if fileid == "inactive": - FD.write(detail_file_%(encoding, "../index_inactive.html", det_line, comments, "../index_inactive.html")) - FD.close() - - + # strip leading whitespace + for attr in ['css_file', 'index_file', 'index_bug_entry', 'bug_file', + 'bug_comment_entry']: + value = getattr(self, attr) + value = '\n'.join(value.split('\n'+' '*12)) + setattr(self, attr, value.strip()+'\n') |