aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--becommands/html.py800
1 files changed, 363 insertions, 437 deletions
diff --git a/becommands/html.py b/becommands/html.py
index d944119..dd7ce65 100644
--- a/becommands/html.py
+++ b/becommands/html.py
@@ -46,48 +46,32 @@ def execute(args, manipulate_encodings=True):
complete(options, args, parser)
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)
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()
- bugs_active = []
- bugs_inactive = []
- 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:
- 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")
+
+ 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="""
@@ -103,294 +87,326 @@ def complete(options, args, 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, encoding):
- 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.encoding = encoding
+ 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 = os.path.abspath(os.path.expanduser(template))
+ self._load_default_templates()
- self.css_file = """
- body {
- 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;
- }
+ 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)
- .critical-row {
- background-color: #FF752A;
- width: auto;
- }
+ 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()
- .fatal-row {
- background-color: #FF3300;
- width: auto;
- }
+ 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()"
+ esc = self._escape
- .person {
- font-family: courier;
- }
+ bug.load_comments(load_full=True)
+ 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':
+ if comment.content_type == 'text/html':
+ pass # no need to escape html...
+ elif comment.content_type.startswith('text/'):
+ value = '<pre>\n'+esc(value)+'\n</pre>'
+ else:
+ value = "TODO: linkout to %s" % comment.content_type
+ else:
+ value = esc(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...
- a, a:visited {
- background: inherit;
- text-decoration: none;
- }
+ 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':'\n'.join(comment_entries),
+ 'generation_time':self.generation_time}
+ for attr in ['uuid', 'severity', 'status', 'assigned', 'target',
+ 'reporter', 'creator', 'time_string', 'summary']:
+ template_info[attr] = esc(getattr(bug, attr))
+ f = codecs.open(fullpath, "w", self.encoding)
+ f.write(self.bug_file % template_info)
+ f.close()
- a {
- color: #003d41;
- }
+ 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
- a:visited {
- color: #553d41;
- }
+ bug_entries = []
+ for b in bugs:
+ if self.verbose:
+ print "\tCreating bug entry for %s" % self.bd.bug_shortname(b)
+ template_info = {'shortname':self.bd.bug_shortname(b)}
+ for attr in ['uuid', 'severity', 'status', 'assigned', 'target',
+ 'reporter', 'creator', 'time_string', 'summary']:
+ template_info[attr] = esc(getattr(b, attr))
+ bug_entries.append(self.index_bug_entry % template_info)
+
+ 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':'\n'.join(bug_entries),
+ 'generation_time':self.generation_time}
+ if bug_type == "inactive":
+ template_info['active_class'] = 'tab nsel'
+ template_info['inactive_class'] = 'tab sel'
- ul {
- list-style-type: none;
- padding: 0;
- }
+ f = codecs.open(os.path.join(self.out_dir, filename), "w", self.encoding)
+ f.write(self.index_file % template_info)
+ f.close()
- p {
- width: auto;
+ 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;
}
- .inline-status-image {
- position: relative;
- top: 0.2em;
+ div.main {
+ padding: 20px;
+ margin: auto;
+ padding-top: 0;
+ margin-top: 1em;
+ background-color: #fcfcfc;
}
- .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;
- }
-
- table.log {
- }
-
- td {
- border-width: 0;
- border-style: none;
- padding-right: 0.5em;
- padding-left: 0.5em;
- width: auto;
+ border-style: solid;
+ border: 10px #313131;
+ border-spacing: 0;
+ 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;
- }
+ tb { border: 1px; }
tr {
- vertical-align: top;
- width: auto;
- }
-
- 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;
+ vertical-align: top;
+ width: auto;
}
- .issue-closed-fixed {
- background-image: "green-check.png";
+ td {
+ border-width: 0;
+ border-style: none;
+ padding-right: 0.5em;
+ padding-left: 0.5em;
+ width: auto;
}
- .issue-closed-wontfix {
- background-image: "red-check.png";
- }
+ img { border-style: none; }
- .issue-closed-reorg {
- background-image: "blue-check.png";
- }
-
- .inline-issue-link {
- text-decoration: underline;
+ h1 {
+ padding: 0.5em;
+ background-color: #305275;
+ margin-top: 0;
+ margin-bottom: 0;
+ color: #fff;
+ margin-left: -20px;
+ margin-right: -20px;
}
- img {
- border: 0;
+ ul {
+ list-style-type: none;
+ padding: 0;
}
+ p { width: auto; }
- 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;
+ a, a:visited {
+ background: inherit;
+ text-decoration: none;
}
+ a { color: #003d41; }
+ a:visited { color: #553d41; }
+ .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;
-
- }
-
+ /* bug index pages */
- .selected-cell {
- background-color: #e9e9e2;
+ td.tab {
+ padding-right: 1em;
+ padding-left: 1em;
}
- .plain-cell {
- background-color: #f9f9f9;
+ td.sel.tab {
+ background-color: #afafaf;
+ border: 1px solid #afafaf;
+ font-weight:bold;
}
+ td.nsel.tab { border: 0px; }
- .logcomment {
- padding-left: 4em;
- font-size: smaller;
+ table.bug_list {
+ background-color: #afafaf;
+ border: 2px solid #afafaf;
}
- .id {
- font-family: courier;
- }
+ .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; }
- .table_bug {
- background-color: #afafaf;
- border: 2px solid #afafaf;
- }
+ /* bug detail pages */
- .message {
- }
+ td.bug_detail_label { text-align: right; }
+ td.bug_detail { }
+ td.bug_comment_label { text-align: right; vertical-align: top; }
+ td.bug_comment { }
- .progress-meter-done {
- background-color: #03af00;
+ 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>
+ <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>
@@ -400,206 +416,116 @@ class BEHTMLGen():
</tr>
</table>
- <table class="table_bug">
+ <table class="bug_list">
<tbody>
- %(bug_table)s
+ %(bug_entries)s
</tbody>
</table>
-
</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>&nbsp;|&nbsp;
+ <a href="http://jigsaw.w3.org/css-validator/check?uri=referer">Validate CSS</a>
+ </p>
</div>
</body>
</html>
"""
- self.bug_line ="""
- <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.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=%(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>
-
- %(bug_lines)s
-
- %(comment_lines)s
- </tbody>
- </table>
- </div>
- <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">%(label)s :</td><td>%(value)s</td>
- </tr>
- """
-
-
- self.comment_section ="""
- <tr>
- <td align="right">Comments:
- </td>
- <td>
- %(comment)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>
"""
- 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:
- 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)
+ 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>
- 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()
+ <hr/>
- 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)
- 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>')
+ %(comment_entries)s
- stack = []
- 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
- comment_lines.append("</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:
- comment_lines.append('<div class="commentF">')
- else:
- comment_lines.append('<div class="comment">')
- comment_lines.append("<br />\n".join(lines)+"<br />\n")
- while len(stack) > 0:
- stack.pop(-1)
- comment_lines.append("</div>\n") # close every remaining <div class="comment...
- comments = self.comment_section % {'comment':'\n'.join(comment_lines)}
+ </div>
+ <h5><a href="%(up_link)s">Back to Index</a></h5>
- 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()
+ <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>&nbsp;|&nbsp;
+ <a href="http://jigsaw.w3.org/css-validator/check?uri=referer">Validate CSS</a>
+ </p>
+ </div>
- 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()"
+ </body>
+ </html>
+ """
- 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":
- 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":
- template_info['active_class'] = 'td_nsel'
- template_info['inactive_class'] = 'td_sel'
+ 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>
+ """
- f = codecs.open(os.path.join(self.out_dir, filename), "w", self.encoding)
- f.write(self.index_file % template_info)
- f.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')