[Buildbot-commits] buildbot/buildbot/status/web base.py, 1.7, 1.8 baseweb.py, 1.17, 1.18 waterfall.py, 1.12, 1.13

Brian Warner warner at users.sourceforge.net
Mon Aug 13 08:20:53 UTC 2007


Update of /cvsroot/buildbot/buildbot/buildbot/status/web
In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv13699/buildbot/status/web

Modified Files:
	base.py baseweb.py waterfall.py 
Log Message:
[project @ waterfall: add 'reload' query arg, add help page. Closes #69.]

Original author: warner at lothar.com
Date: 2007-08-13 08:16:33+00:00

Index: base.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/status/web/base.py,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- base.py	12 Aug 2007 22:23:07 -0000	1.7
+++ base.py	13 Aug 2007 08:20:51 -0000	1.8
@@ -188,6 +188,7 @@
         data += "<head>\n"
         for he in s.head_elements:
             data += " " + self.fillTemplate(he, request) + "\n"
+            data += self.head(request)
         data += "</head>\n\n"
 
         data += '<body %s>\n' % " ".join(['%s="%s"' % (k,v)
@@ -197,6 +198,9 @@
         data += self.fillTemplate(s.footer, request)
         return data
 
+    def head(self, request):
+        return ""
+
     def body(self, request):
         return "Dummy\n"
 

Index: baseweb.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/status/web/baseweb.py,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -d -r1.17 -r1.18
--- baseweb.py	12 Aug 2007 22:23:07 -0000	1.17
+++ baseweb.py	13 Aug 2007 08:20:51 -0000	1.18
@@ -126,7 +126,7 @@
         status = self.getStatus(req)
         numbuilds = int(req.args.get("numbuilds", [self.numbuilds])[0])
         builders = req.args.get("builder", [])
-        branches = req.args.get("branch", [])
+        branches = [b for b in req.args.get("branch", []) if b]
 
         g = status.generateFinishedBuilds(builders, branches, numbuilds)
 
@@ -162,7 +162,7 @@
     def body(self, req):
         status = self.getStatus(req)
         numbuilds = int(req.args.get("numbuilds", [self.numbuilds])[0])
-        branches = req.args.get("branch", [])
+        branches = [b for b in req.args.get("branch", []) if b]
 
         # walk backwards through all builds of a single builder
         g = self.builder.generateFinishedBuilds(branches, numbuilds)

Index: waterfall.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/status/web/waterfall.py,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -d -r1.12 -r1.13
--- waterfall.py	13 Aug 2007 06:33:47 -0000	1.12
+++ waterfall.py	13 Aug 2007 08:20:51 -0000	1.13
@@ -233,6 +233,167 @@
         followingEventStarts = starts
         if debug: log.msg(" fES1", starts)
 
+HELP = '''
+<form action="../waterfall" method="GET">
+
+<h1>The Waterfall Display</h1>
+
+<p>The Waterfall display can be controlled by adding query arguments to the
+URL. For example, if your Waterfall is accessed via the URL
+<tt>http://buildbot.example.org:8080</tt>, then you could add a
+<tt>branch=</tt> argument (described below) by going to
+<tt>http://buildbot.example.org:8080?branch=beta4</tt> instead. Remember that
+query arguments are separated from each other with ampersands, but they are
+separated from the main URL with a question mark, so to add a
+<tt>branch=</tt> and two <tt>builder=</tt> arguments, you would use
+<tt>http://buildbot.example.org:8080?branch=beta4&builder=unix&builder=macos</tt>.</p>
+
+<h2>Limiting the Displayed Interval</h2>
+
+<p>The <tt>last_time=</tt> argument is a unix timestamp (seconds since the
+start of 1970) that will be used as an upper bound on the interval of events
+displayed: nothing will be shown that is more recent than the given time.
+When no argument is provided, all events up to and including the most recent
+steps are included.</p>
+
+<p>The <tt>first_time=</tt> argument provides the lower bound. No events will
+be displayed that occurred <b>before</b> this timestamp. Instead of providing
+<tt>first_time=</tt>, you can provide <tt>show_time=</tt>: in this case,
+<tt>first_time</tt> will be set equal to <tt>last_time</tt> minus
+<tt>show_time</tt>. <tt>show_time</tt> overrides <tt>first_time</tt>.</p>
+
+<p>The display normally shows the latest 200 events that occurred in the
+given interval, where each timestamp on the left hand edge counts as a single
+event. You can add a <tt>num_events=</tt> argument to override this this.</p>
+
+<h2>Hiding non-Build events</h2>
+
+<p>By passing <tt>show_events=false</tt>, you can remove the "buildslave
+attached", "buildslave detached", and "builder reconfigured" events that
+appear in-between the actual builds.</p>
+
+%(show_events_input)s
+
+<h2>Showing only Certain Branches</h2>
+
+<p>If you provide one or more <tt>branch=</tt> arguments, the display will be
+limited to builds that used one of the given branches. If no <tt>branch=</tt>
+arguments are given, builds from all branches will be displayed.</p>
+
+Erase the text from these "Show Branch:" boxes to remove that branch filter.
+
+%(show_branches_input)s
+
+<h2>Limiting the Builders that are Displayed</h2>
+
+<p>By adding one or more <tt>builder=</tt> arguments, the display will be
+limited to showing builds that ran on the given builders. This serves to
+limit the display to the specific named columns. If no <tt>builder=</tt>
+arguments are provided, all Builders will be displayed.</p>
+
+<p>To view a Waterfall page with only a subset of Builders displayed, select
+the Builders you are interested in here.</p>
+
+%(show_builders_input)s
+
+
+<h2>Auto-reloading the Page</h2>
+
+<p>Adding a <tt>reload=</tt> argument will cause the page to automatically
+reload itself after that many seconds.</p>
+
+%(show_reload_input)s
+
+
+<input type="submit" value="View Waterfall" />
+</form>
+'''
+
+class WaterfallHelp(HtmlResource):
+    title = "Waterfall Help"
+
+    def __init__(self, categories=None):
+        HtmlResource.__init__(self)
+        self.categories = categories
+
+    def body(self, request):
+        data = ''
+        status = self.getStatus(request)
+
+        showEvents_checked = 'checked="checked"'
+        if request.args.get("show_events", ["true"])[0].lower() == "true":
+            showEvents_checked = ''
+        show_events_input = ('<p>'
+                             '<input type="checkbox" name="show_events" '
+                             'value="false" %s>'
+                             'Hide non-Build events'
+                             '</p>\n'
+                             ) % showEvents_checked
+
+        branches = [b
+                    for b in request.args.get("branch", [])
+                    if b]
+        branches.append('')
+        show_branches_input = '<table>\n'
+        for b in branches:
+            show_branches_input += ('<tr>'
+                                    '<td>Show Branch: '
+                                    '<input type="text" name="branch" '
+                                    'value="%s">'
+                                    '</td></tr>\n'
+                                    ) % (b,)
+        show_branches_input += '</table>\n'
+
+        # this has a set of toggle-buttons to let the user choose the
+        # builders
+        showBuilders = request.args.get("show", [])
+        showBuilders.extend(request.args.get("builder", []))
+        allBuilders = status.getBuilderNames(categories=self.categories)
+
+        show_builders_input = '<table>\n'
+        for bn in allBuilders:
+            checked = ""
+            if bn in showBuilders:
+                checked = 'checked="checked"'
+            show_builders_input += ('<tr>'
+                                    '<td><input type="checkbox"'
+                                    ' name="builder" '
+                                    'value="%s" %s></td> '
+                                    '<td>%s</td></tr>\n'
+                                    ) % (bn, checked, bn)
+        show_builders_input += '</table>\n'
+
+        # a couple of radio-button selectors for refresh time will appear
+        # just after that text
+        show_reload_input = '<table>\n'
+        times = [("none", "None"),
+                 ("30", "30 seconds"),
+                 ("60", "60 seconds"),
+                 ("300", "5 minutes"),
+                 ]
+        current_reload_time = request.args.get("reload", ["none"])
+        if current_reload_time:
+            current_reload_time = current_reload_time[0]
+        if current_reload_time not in [t[0] for t in times]:
+            times.insert(0, (current_reload_time, current_reload_time) )
+        for value, name in times:
+            checked = ""
+            if value == current_reload_time:
+                checked = 'checked="checked"'
+            show_reload_input += ('<tr>'
+                                  '<td><input type="radio" name="reload" '
+                                  'value="%s" %s></td> '
+                                  '<td>%s</td></tr>\n'
+                                  ) % (value, checked, name)
+        show_reload_input += '</table>\n'
+
+        fields = {"show_events_input": show_events_input,
+                  "show_branches_input": show_branches_input,
+                  "show_builders_input": show_builders_input,
+                  "show_reload_input": show_reload_input,
+                  }
+        data += HELP % fields
+        return data
 
 class WaterfallStatusResource(HtmlResource):
     """This builds the main status page, with the waterfall display, and
@@ -241,6 +402,7 @@
     def __init__(self, categories=None):
         HtmlResource.__init__(self)
         self.categories = categories
+        self.putChild("help", WaterfallHelp(categories))
 
     def getTitle(self, request):
         status = self.getStatus(request)
@@ -254,6 +416,23 @@
         # TODO: this wants to go away, access it through IStatus
         return request.site.buildbot_service.parent.change_svc
 
+    def get_reload_time(self, request):
+        if "reload" in request.args:
+            try:
+                reload_time = int(request.args["reload"][0])
+                if reload_time > 15:
+                    return reload_time
+            except ValueError:
+                pass
+        return None
+
+    def head(self, request):
+        head = ''
+        reload_time = self.get_reload_time(request)
+        if reload_time is not None:
+            head += '<meta http-equiv="refresh" content="%d">\n' % reload_time
+        return head
+
     def body(self, request):
         "This method builds the main waterfall display."
 
@@ -266,7 +445,8 @@
         phase = request.args.get("phase",["2"])
         phase = int(phase[0])
 
-        showBuilders = request.args.get("show", None)
+        showBuilders = request.args.get("show", [])
+        showBuilders.extend(request.args.get("builder", []))
         allBuilders = status.getBuilderNames(categories=self.categories)
         if showBuilders:
             builderNames = []
@@ -335,19 +515,42 @@
 
         data += "<hr />\n"
 
-        if timestamps:
+        def with_args(req, remove_args=[], new_args=[], new_path=None):
             # sigh, nevow makes this sort of manipulation easier
-            bottom = timestamps[-1]
-            newargs = request.args.copy()
-            newargs["last_time"] = [str(int(bottom))]
+            newargs = req.args.copy()
+            for argname in remove_args:
+                newargs[argname] = []
+            newargs["branch"] = [b for b in newargs["branch"] if b]
+            for k,v in new_args:
+                if k in newargs:
+                    newargs[k].append(v)
+                else:
+                    newargs[k] = [v]
             newquery = "&".join(["%s=%s" % (k, v)
                                  for k in newargs
                                  for v in newargs[k]
                                  ])
-            nextpage = str(request.URLPath())
-            if newquery:
-                nextpage += "?" + newquery
+            new_url = req.URLPath()
+            if new_path:
+                new_url.path = new_path
+            new_url.query = newquery
+            #if newquery:
+            #    new_url += "?" + newquery
+            return str(new_url)
+
+        if timestamps:
+            bottom = timestamps[-1]
+            nextpage = with_args(request, ["last_time"],
+                                 [("last_time", str(int(bottom)))])
             data += '<a href="%s">next page</a>\n' % nextpage
+
+        helppage = with_args(request, new_path="waterfall/help")
+        data += '<a href="%s">help</a>\n' % helppage
+
+        if self.get_reload_time(request) is not None:
+            no_reload_page = with_args(request, remove_args=["reload"])
+            data += '<a href="%s">Stop Reloading</a>\n' % no_reload_page
+
         data += "<br />\n"
 
 
@@ -421,7 +624,7 @@
         showEvents = False
         if request.args.get("show_events", ["true"])[0].lower() == "true":
             showEvents = True
-        filterBranches = request.args.get("branch", [])
+        filterBranches = [b for b in request.args.get("branch", []) if b]
         maxTime = int(request.args.get("last_time", [util.now()])[0])
         if "show_time" in request.args:
             minTime = maxTime - int(request.args["show_time"][0])





More information about the Commits mailing list