Updating branch refs/heads/master to cedc1802520b88550c8761b91e24196456c2c95d (commit) from 62de4bbbc0be59b1658d0ad5ba73890c32b64f8a (commit)
commit cedc1802520b88550c8761b91e24196456c2c95d Author: Enrico Tröger <enrico.troe...@uvena.de> Date: Fri Oct 9 23:43:55 2009 +0200 Major UI changes - Implement a very basic HTML generator - Use the default Xfce website header and CSS files for a more unique layout xfcebuildstatus.py | 295 +++++++++++++++++++++++++++++++++++++++++----------- 1 files changed, 236 insertions(+), 59 deletions(-) diff --git a/xfcebuildstatus.py b/xfcebuildstatus.py index a1ef4a6..89ffbce 100644 --- a/xfcebuildstatus.py +++ b/xfcebuildstatus.py @@ -40,19 +40,25 @@ template = """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> - <title>Xfce Buildbots Status</title> + <title>${title}</title> <meta http-equiv="content-type" content="text/html;charset=utf-8" /> <meta name="generator" content="Geany 0.19" /> + <link rel="stylesheet" media="screen" href="http://www.xfce.org/layout/css/layout.css" type="text/css" /> + <link rel="stylesheet" media="screen" href="http://www.xfce.org/layout/css/front.css" type="text/css" /> <style type="text/css"> - body, p, pre, td { - font-size: 12px; - font-family: sans-serif; + ${layout_css} + /* link styles */ + :link, :visited, :link:active, :link:active { + color: #154374; + text-decoration: underline; } - img { - border: 0px; + :link:hover, :visited:hover { + color: #000000; + text-decoration: underline; } - a { + .status_link { color: #000000; + text-decoration: none; } h1 { margin-top: 25px; @@ -68,13 +74,13 @@ template = """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" text-align: right; } .status_success { - background-color: #00ff00; + background-color: #8cff8c; } .status_failed { - background-color: #ff0000; + background-color: #ff7171; } .status_unknown { - background-color: #ffff00; + background-color: #ffff84; } .item { font-weight: bold; @@ -86,14 +92,144 @@ template = """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" </style> </head> -<body> -${content} +<body id="top"> + <div class="hidden"> + <a href="#global-contentwrap" title="Skip site navigation" accesskey="1">Skip site navigation</a> (1) + <h1>Xfce Desktop Environment</h1> + <h4>...and everything goes faster!</h4> + <hr /> + </div> + <div id="global-pagewrap"> + <div id="global-page"> + <div id="header"> + <div id="header-logo"></div> + <div id="header-right"> + <div id="header-style"> + <h2 class="hidden">Website Layout</h2> + <p>Layout: <a href="?layout=normal" title="Normal layout (Min: 740px, Max: 1000px)">Normal</a> / + <a href="?layout=liquid" title="Fluid Layout (100% Width)">Liquid</a></p> + </div> + </div> + <div id="header-menu"> + <ul> + <li><a href="${url}">Overview</a></li> + </ul> + </div> + <div id="header-white"> + <div id="header-language"> + <!-- TODO content? --> + </div> + </div> + </div> + <h3>${title}</h3> + ${content} + </div> +</div> </body> -</html>""" +</html> +""" debug_out = '' + +class HtmlGen(object): + """Very simple HTML generator""" + # TODO add_element is nice, but for nested elements this still needs to be improved + + def __init__(self, url, layout): + self.html = '' + self.title = '' + self.url = url + if layout == 'liquid': + self.layout = '#global-page { width: 100%; }' + else: + self.layout = '#global-page { min-width: 760px; max-width: 1000px; width: 100%; }' + + #---------------------------------------------------------------------- + def __nonzero__(self): + return self.html != '' + + #---------------------------------------------------------------------- + def __str__(self): + return Template(template).substitute( + url=self.url, + layout_css=self.layout, + title=self.title, + content=self.html) + + #---------------------------------------------------------------------- + def add_element(self, tagname, cdata=None, attribs={}): + """ + Generic function to generate a complete HTML tag element named tagname with the contents cdata. + If cdata is None, a single tag is created (e.g. <br /> or <hr />). If cdata is an empty string, + a normal tag is created with no contents (e.g. <td></td>). + attribs is a dictionary of tag attributes. + + @param tagname (str) + @param cdata (str) + @param attribs (dict) + """ + if not tagname: + return + + if cdata == None: + attribs_str = '' + for attr, value in attribs.items(): + attribs_str += ' %s="%s"' % (attr, value) + self.html += '<%s%s />\n' % (tagname, attribs_str) + else: + self.open_tag(tagname, attribs=attribs) + self.add_cdata(cdata) + self.close_tag(tagname) + + #---------------------------------------------------------------------- + def open_tag(self, tagname, attribs={}): + """ + Generic function to generate a HTML tag named tagname. + attribs is a dictionary of tag attributes. + + @param tagname (str) + @param attribs (dict) + """ + if not tagname: + return + + attribs_str = '' + for attr, value in attribs.items(): + attribs_str += ' %s="%s"' % (attr, value) + self.html += '<%s%s>' % (tagname, attribs_str) + + #---------------------------------------------------------------------- + def close_tag(self, tagname): + """ + Close the given tag + + @param tagname (str) + """ + if tagname: + self.html += '</%s>' % (tagname) + + #---------------------------------------------------------------------- + def add_cdata(self, cdata): + """ + Simply add the passed text to the HTML content + + @param cdata (str) + """ + if cdata: + self.html += cdata + + #---------------------------------------------------------------------- + def set_title(self, title): + """ + Set the document title + + @param title (str) + """ + self.title = title + + #---------------------------------------------------------------------- def split_builder_name(input): """ @@ -158,33 +294,38 @@ def list_to_str(input): return steps[0:-2] #---------------------------------------------------------------------- -def get_build_status_html(url, input): +def get_build_status_html(html, url, input): """ Create HTML code from the given input. + @param html (HtmlGen) @param url (str) @param input (dict) - @return html code (str) """ - result = '<table><tr>\n<td class="modules"></td>\n' + html.set_title('Xfce Buildbot Status') + html.open_tag('table') + html.open_tag('tr') + html.add_element('td', 'Module') for name in PLATFORM_NAMES.values(): - result += '<td>%s</td>\n' % name - result += '</tr>\n' + html.add_element('td', name) + html.close_tag('tr') sorted_builders = [] for x in input.items(): sorted_builders.append(x) sorted_builders.sort(cmp=lambda x,y: cmp(x[0], y[0])) - # TODO rewrite this code to be clean for module_name, status in sorted_builders: - result += '<tr>\n<td class="modules">%s</td>\n' % module_name + html.open_tag('tr') + html.add_element('td', module_name) for name in PLATFORM_NAMES: try: if status[name][0] == 'success': - result += '''<td class="status_success"><a href="%s/detail/s/%s/%d" - title="Built revision %s on %s">%s</a></td>\n''' % \ - (url, status[name][6], status[name][3], status[name][2][:7], status[name][1], status[name][0]) + link_url = '%s/detail/s/%s/%d' % (url, status[name][6], status[name][3]) + title = 'Built revision %s on %s' % (status[name][2][:7], status[name][1]) + html.open_tag('td', attribs={'class': 'status_success'}) + html.add_element('a', status[name][0], attribs={'href':link_url, 'title':title, 'class': 'status_link'}) + html.close_tag('td') elif status[name][0] == 'failure': steps = list_to_str(status[name][4]) reasons = list_to_str(status[name][5]) @@ -192,16 +333,19 @@ def get_build_status_html(url, input): (module_name, steps, status[name][1], reasons) if status[name][2]: desc += ' Revision %s' % (status[name][2][:7]) - result += '<td class="status_failed"><a href="%s/detail/f/%s/%d" title="%s">%s</a></td>\n' % \ - (url, status[name][6], status[name][3], desc, status[name][0]) + link_url = '%s/detail/f/%s/%d' % (url, status[name][6], status[name][3]) + + html.open_tag('td', {'class': 'status_failed'}) + html.add_element('a', status[name][0], attribs={'href':link_url, 'title':desc, 'class': 'status_link'}) + html.close_tag('td') else: - result += '<td class="status_unknown">unknown</td>\n' + # trigger the exception handler below + raise KeyError except KeyError: - result += '<td class="status_unknown">unknown</td>\n' - result += '</tr>\n' - result += '</table>\n' + html.add_element('td', 'unknown', attribs={'class': 'status_unknown'}) - return Template(template).substitute(content=result) + html.close_tag('tr') + html.close_tag('table') #---------------------------------------------------------------------- def get_detail_status(url, args): @@ -213,8 +357,8 @@ def get_detail_status(url, args): @return status per module (dict) """ global debug_out - server = ServerProxy(url) + server = ServerProxy(url) try: if args[1] == 's': builder = server.getBuild(args[2], int(args[3])) @@ -264,13 +408,13 @@ def format_time(duration): return ", ".join(eta_parts) #---------------------------------------------------------------------- -def get_detail_status_html(url, input): +def get_detail_status_html(html, url, input): """ Create HTML code from the given input. + @param html (HtmlGen) @param url (str) @param input (dict) - @return html code (str) """ result = '' if input: @@ -286,15 +430,37 @@ def get_detail_status_html(url, input): status_class = 'status_success' if status == 'successful' else 'status_failed' # output - result += '<h1>Build status for "%s"</h1>\n' % module_name - result += '<p><span class="item">Build result:</span> <span class="%s">%s</span></p>\n' % (status_class, status) - result += '<p><span class="item">Build started:</span> %s</p>\n' % start - result += '<p><span class="item">Build finished:</span> %s</p>\n' % end - result += '<p><span class="item">Build duration:</span> %s</p>\n' % duration - result += '<p><span class="item">Build reason:</span> %s</p>\n' % input['reason'] - result += '<p><span class="item">Built revision:</span> %s</p>\n' % input['revision'] - result += '<p><span class="item">Build steps:</span></p>' - result += '<p>\n' + html.set_title('Build Status for "%s"' % module_name) + + html.add_element('p', ' ') + html.open_tag('p') + html.add_element('span', 'Build result:', attribs={'class':'item'}) + html.add_cdata(' ') + html.add_element('span', status, attribs={'class':status_class}) + html.close_tag('p') + html.open_tag('p') + html.add_element('span', 'Build started:', attribs={'class':'item'}) + html.add_cdata(' %s' % start) + html.close_tag('p') + html.open_tag('p') + html.add_element('span', 'Build finished:', attribs={'class':'item'}) + html.add_cdata(' %s' % end) + html.close_tag('p') + html.open_tag('p') + html.add_element('span', 'Build duration:', attribs={'class':'item'}) + html.add_cdata(' %s' % duration) + html.close_tag('p') + html.open_tag('p') + html.add_element('span', 'Build reason:', attribs={'class':'item'}) + html.add_cdata(' %s' % input['reason']) + html.close_tag('p') + html.open_tag('p') + html.add_element('span', 'Build revision:', attribs={'class':'item'}) + html.add_cdata(' %s' % input['revision']) + html.close_tag('p') + html.add_element('p', 'Build steps:', attribs={'class':'item'}) + + html.open_tag('p') for step in input['steps']: # make Samuel happy :) if step['name'].startswith('chmod '): @@ -302,19 +468,27 @@ def get_detail_status_html(url, input): log_suffix = find_log(input['logs'], step['name']) log_url = '' if log_suffix: - log_url = ', <a href="%s/steps/%s/logs/%s">Logs</a>' % (input['url'], log_suffix[0], log_suffix[1]) - result += '<span class="step"><span class="item">%s: %s</span> (%s%s)</span><br/>\n' % \ - (step['name'], ' '.join(step['text']), format_time(step['end'] - step['start']), log_url) - result += '</p>\n' - result += '<p> </p>' - result += '<p><span class="item">More details:</span> <a href="%s">%s</a></p>\n' % (input['url'], input['url']) + log_url = '%s/steps/%s/logs/%s' % (input['url'], log_suffix[0], log_suffix[1]) + html.open_tag('span', attribs={'class':'step'}) + html.add_element('span', '%s: %s' % (step['name'], ' '.join(step['text'])), attribs={'class':'item'}) + html.add_cdata(' (%s ' % format_time(step['end'] - step['start'])) + html.add_element('a', 'Logs', attribs={'href':log_url}) + html.add_cdata(')') + html.close_tag('span') + html.add_element('br') + + html.close_tag('p') + html.add_element('p', ' ') + html.open_tag('p') + html.add_element('span', 'More details:', attribs={'class':'item'}) + html.add_cdata(' ') + html.add_element('a', input['url'], attribs={'href':input['url']}) + html.close_tag('p') else: # TODO do something here - result = 'Currently no information for failed builds can be retrieved :(' - pass - - return Template(template).substitute(content=result) + html.set_title('Xfce Build Status error') + html.add_element('p', 'Currently no information can be retrieved for failed builds :(') #---------------------------------------------------------------------- def parse_url(): @@ -335,14 +509,17 @@ def parse_url(): me = '' args = uri.split('/') if not args[0]: - del args[0] + del args[0] return (me, args) except: return ('', '') #---------------------------------------------------------------------- def main(): - debug = cgi.FieldStorage(keep_blank_values=True).has_key('debug') + # parse query string + fs = cgi.FieldStorage(keep_blank_values=True) + layout = fs['layout'].value if fs.has_key('layout') else 'normal' + debug = fs.has_key('debug') if debug: import cgitb cgitb.enable(display=1) @@ -350,18 +527,18 @@ def main(): # handle arguments url, args = parse_url() - output = '' headers = [] + html = HtmlGen(url, layout) if args: args_len = len(args) if args[0] == 'detail' and args_len == 4: status = get_detail_status(XMLRPC_URL, args) - output = get_detail_status_html(url, status) + get_detail_status_html(html, url, status) # fallback to overview page - if not output: + if not html: status = get_build_status(XMLRPC_URL) - output = get_build_status_html(url, status) + get_build_status_html(html, url, status) if not headers: print 'Content-type: text/html' @@ -370,7 +547,7 @@ def main(): print h print # final blank line to end HTTP headers - print output + print str(html) if debug: print debug_out print cgi.print_environ()
_______________________________________________ Xfce4-commits mailing list Xfce4-commits@xfce.org http://foo-projects.org/mailman/listinfo/xfce4-commits