From 833adcb9c41ff0aa82700ab0c99277d23fc18dd7 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Tue, 20 Oct 2009 08:28:35 -0400 Subject: Restructured becommands/html to make templating more flexible + general cleanups. --- becommands/html.py | 800 ++++++++++++++++++++++++----------------------------- 1 file 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("\n") # close non-parent
') + else: + comment_entries.append('
') + 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 = '
\n'+esc(value)+'\n
' + 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("
\n") # close every remaining
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> - BugsEverywhere Issue Tracker + %(title)s -
-

BugsEverywhere Bug List

+

%(index_header)s

@@ -400,206 +416,116 @@ class BEHTMLGen():
- +
- %(bug_table)s + %(bug_entries)s
-
""" - self.bug_line =""" - - %(shortname)s - %(status)s - %(severity)s - %(summary)s - %(time_string)s - - """ - - self.detail_file = """ - - - - BugsEverywhere Issue Tracker - - - - - - -
-

BugsEverywhere Bug List

-
Back to Index
-

Bug: %(shortname)s

- - - - %(bug_lines)s - - %(comment_lines)s - -
-
-
Back to Index
- - - - - """ - - self.detail_line =""" - - %(label)s :%(value)s - - """ - - - self.comment_section =""" - - Comments: - - - %(comment)s - - + self.index_bug_entry =""" + + %(shortname)s + %(status)s + %(severity)s + %(summary)s + %(time_string)s + """ - 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 = """ + + + + %(title)s + + + + + +
+

BugsEverywhere Bug List

+
Back to Index
+

Bug: %(shortname)s

+ + + + + + + + + + + + + + + + + + + + + + +
ID :%(uuid)s
Short name :%(shortname)s
Status :%(status)s
Severity :%(severity)s
Assigned :%(assigned)s
Reporter :%(reporter)s
Creator :%(creator)s
Created :%(time_string)s
Summary :%(summary)s
- 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) - 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('
') + %(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("
\n") # close non-parent
') - else: - comment_lines.append('
') - comment_lines.append("
\n".join(lines)+"
\n") - while len(stack) > 0: - stack.pop(-1) - comment_lines.append("
\n") # close every remaining
Back to Index - 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": - 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 =""" + + + + + +
Comment: + --------- Comment ---------
+ Name: %(uuid)s
+ From: %(author)s
+ Date: %(date)s
+
+ %(body)s +
+ """ - 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') -- cgit