[Xfce4-commits] <xfce-buildbot-scripts:master> Major UI changes

Enrico Tröger noreply at xfce.org
Sat Oct 10 00:20:02 CEST 2009


Updating branch refs/heads/master
         to cedc1802520b88550c8761b91e24196456c2c95d (commit)
       from 62de4bbbc0be59b1658d0ad5ba73890c32b64f8a (commit)

commit cedc1802520b88550c8761b91e24196456c2c95d
Author: Enrico Tröger <enrico.troeger at 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()



More information about the Xfce4-commits mailing list