jhbuild r2260 - in trunk: . jhbuild/buildbot/status/web



Author: fpeters
Date: Sat Aug 16 10:11:15 2008
New Revision: 2260
URL: http://svn.gnome.org/viewvc/jhbuild?rev=2260&view=rev

Log:
* jhbuild/buildbot/status/web/__init__.py,
jhbuild/buildbot/status/web/feeds.py,
jhbuild/buildbot/status/web/waterfall.py: waterfall customisation to
only display changes related to the given module; moved waterfall code
in its own module; renamed feeds module from feeder to feeds.



Added:
   trunk/jhbuild/buildbot/status/web/feeds.py   (contents, props changed)
      - copied, changed from r2258, /trunk/jhbuild/buildbot/status/web/feeder.py
   trunk/jhbuild/buildbot/status/web/waterfall.py
Removed:
   trunk/jhbuild/buildbot/status/web/feeder.py
Modified:
   trunk/ChangeLog
   trunk/jhbuild/buildbot/status/web/__init__.py

Modified: trunk/jhbuild/buildbot/status/web/__init__.py
==============================================================================
--- trunk/jhbuild/buildbot/status/web/__init__.py	(original)
+++ trunk/jhbuild/buildbot/status/web/__init__.py	Sat Aug 16 10:11:15 2008
@@ -38,7 +38,7 @@
 HtmlResource.content = content
 
 from buildbot.status.web.baseweb import WebStatus
-from feeder import WaterfallWithFeeds
+from waterfall import JhWaterfallStatusResource
 
 class ProjectsSummary(HtmlResource):
 
@@ -156,7 +156,7 @@
 
         # set up the per-module waterfalls
         for module in self.modules:
-            self.putChild(module, feeder.WaterfallWithFeeds(categories=[module]))
+            self.putChild(module, JhWaterfallStatusResource(categories=[module]))
 
         # set the summary homepage
         self.putChild("", ProjectsSummary())

Copied: trunk/jhbuild/buildbot/status/web/feeds.py (from r2258, /trunk/jhbuild/buildbot/status/web/feeder.py)
==============================================================================
--- /trunk/jhbuild/buildbot/status/web/feeder.py	(original)
+++ trunk/jhbuild/buildbot/status/web/feeds.py	Sat Aug 16 10:11:15 2008
@@ -2,7 +2,7 @@
 # Copyright Lieven Gobaerts
 # Copyright (C) 2008  apinheiro igalia com, John Carr, Frederic Peters
 #
-#   feeder.py: buildbot module RSS/Atom feeds
+#   feeds.py: RSS/Atom feeds
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -18,20 +18,15 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
-
 # Minor changes made by API (apinheiro igalia com) in order to fit with our
 # configuration and last buildbot changes
 
-import urllib, time, re
+import time, re
 
 from twisted.web.resource import Resource
-from twisted.application import strports
-from twisted.web import server, distrib
 from twisted.web import html as twhtml
 
-from buildbot import interfaces
 from buildbot.status.builder import FAILURE, SUCCESS, WARNINGS
-from buildbot.status.web.waterfall import WaterfallStatusResource
 
 class XmlResource(Resource):
     contentType = "text/xml; charset=UTF-8"
@@ -268,13 +263,3 @@
         data = ('</feed>')
         return data
 
-class WaterfallWithFeeds(WaterfallStatusResource):
-    """ Override the standard Waterfall class to add RSS and Atom feeds """
-
-    def __init__(self, *args, **kwargs):
-        WaterfallStatusResource.__init__(self, *args, **kwargs)
-
-        rss = Rss20StatusResource(self.categories)
-        self.putChild("rss", rss)
-        atom = Atom10StatusResource(self.categories)
-        self.putChild("atom", atom)

Added: trunk/jhbuild/buildbot/status/web/waterfall.py
==============================================================================
--- (empty file)
+++ trunk/jhbuild/buildbot/status/web/waterfall.py	Sat Aug 16 10:11:15 2008
@@ -0,0 +1,182 @@
+# jhbuild - a build script for GNOME 1.x and 2.x
+# Copyright (C) 2008  apinheiro igalia com, John Carr, Frederic Peters
+#
+#   waterfall.py: custom waterfall display
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+from buildbot.changes.changes import Change
+from buildbot import interfaces, util
+from buildbot.status import builder
+from buildbot.status.web.waterfall import WaterfallStatusResource, insertGaps
+
+from buildbot.status.web.base import Box, HtmlResource, IBox, ICurrentBox, \
+     ITopBox, td, build_get_class, path_to_build, path_to_step, map_branches
+
+from feeds import Rss20StatusResource, Atom10StatusResource
+
+
+class JhWaterfallStatusResource(WaterfallStatusResource):
+    """ Override the standard Waterfall class to add RSS and Atom feeds """
+
+    def __init__(self, *args, **kwargs):
+        WaterfallStatusResource.__init__(self, *args, **kwargs)
+
+        rss = Rss20StatusResource(self.categories)
+        self.putChild("rss", rss)
+        atom = Atom10StatusResource(self.categories)
+        self.putChild("atom", atom)
+
+ 
+    def buildGrid(self, request, builders):
+        debug = False
+        # TODO: see if we can use a cached copy
+
+        showEvents = False
+        if request.args.get("show_events", ["true"])[0].lower() == "true":
+            showEvents = True
+        filterBranches = [b for b in request.args.get("branch", []) if b]
+        filterBranches = map_branches(filterBranches)
+        maxTime = int(request.args.get("last_time", [util.now()])[0])
+        if "show_time" in request.args:
+            minTime = maxTime - int(request.args["show_time"][0])
+        elif "first_time" in request.args:
+            minTime = int(request.args["first_time"][0])
+        else:
+            minTime = None
+        spanLength = 10  # ten-second chunks
+        maxPageLen = int(request.args.get("num_events", [200])[0])
+
+        # first step is to walk backwards in time, asking each column
+        # (commit, all builders) if they have any events there. Build up the
+        # array of events, and stop when we have a reasonable number.
+            
+        commit_source = self.getChangemaster(request)
+
+        lastEventTime = util.now()
+        sources = [commit_source] + builders
+        changeNames = ["changes"]
+        builderNames = map(lambda builder: builder.getName(), builders)
+        sourceNames = changeNames + builderNames
+        sourceEvents = []
+        sourceGenerators = []
+        projectName = str(self.categories[0])
+
+        def get_event_from(g):
+            try:
+                while True:
+                    e = g.next()
+                    # e might be builder.BuildStepStatus,
+                    # builder.BuildStatus, builder.Event,
+                    # waterfall.Spacer(builder.Event), or changes.Change .
+                    # The showEvents=False flag means we should hide
+                    # builder.Event .
+                    if not showEvents and isinstance(e, builder.Event):
+                        continue
+                    if isinstance(e, Change) and hasattr(e, 'project') and \
+                            e.project != projectName:
+                        continue
+                    break
+                event = interfaces.IStatusEvent(e)
+                if debug:
+                    log.msg("gen %s gave1 %s" % (g, event.getText()))
+            except StopIteration:
+                event = None
+            return event
+
+        for s in sources:
+            gen = insertGaps(s.eventGenerator(filterBranches), lastEventTime)
+            sourceGenerators.append(gen)
+            # get the first event
+            sourceEvents.append(get_event_from(gen))
+        eventGrid = []
+        timestamps = []
+
+        lastEventTime = 0
+        for e in sourceEvents:
+            if e and e.getTimes()[0] > lastEventTime:
+                lastEventTime = e.getTimes()[0]
+        if lastEventTime == 0:
+            lastEventTime = util.now()
+
+        spanStart = lastEventTime - spanLength
+        debugGather = 0
+
+        while 1:
+            if debugGather: log.msg("checking (%s,]" % spanStart)
+            # the tableau of potential events is in sourceEvents[]. The
+            # window crawls backwards, and we examine one source at a time.
+            # If the source's top-most event is in the window, is it pushed
+            # onto the events[] array and the tableau is refilled. This
+            # continues until the tableau event is not in the window (or is
+            # missing).
+
+            spanEvents = [] # for all sources, in this span. row of eventGrid
+            firstTimestamp = None # timestamp of first event in the span
+            lastTimestamp = None # last pre-span event, for next span
+
+            for c in range(len(sourceGenerators)):
+                events = [] # for this source, in this span. cell of eventGrid
+                event = sourceEvents[c]
+                while event and spanStart < event.getTimes()[0]:
+                    # to look at windows that don't end with the present,
+                    # condition the .append on event.time <= spanFinish
+                    if not IBox(event, None):
+                        log.msg("BAD EVENT", event, event.getText())
+                        assert 0
+                    if debug:
+                        log.msg("pushing", event.getText(), event)
+                    events.append(event)
+                    starts, finishes = event.getTimes()
+                    firstTimestamp = util.earlier(firstTimestamp, starts)
+                    event = get_event_from(sourceGenerators[c])
+                if debug:
+                    log.msg("finished span")
+
+                if event:
+                    # this is the last pre-span event for this source
+                    lastTimestamp = util.later(lastTimestamp,
+                                               event.getTimes()[0])
+                if debugGather:
+                    log.msg(" got %s from %s" % (events, sourceNames[c]))
+                sourceEvents[c] = event # refill the tableau
+                spanEvents.append(events)
+
+            # only show events older than maxTime. This makes it possible to
+            # visit a page that shows what it would be like to scroll off the
+            # bottom of this one.
+            if firstTimestamp is not None and firstTimestamp <= maxTime:
+                eventGrid.append(spanEvents)
+                timestamps.append(firstTimestamp)
+
+            if lastTimestamp:
+                spanStart = lastTimestamp - spanLength
+            else:
+                # no more events
+                break
+            if minTime is not None and lastTimestamp < minTime:
+                break
+
+            if len(timestamps) > maxPageLen:
+                break
+            
+            
+            # now loop
+            
+        # loop is finished. now we have eventGrid[] and timestamps[]
+        if debugGather: log.msg("finished loop")
+        assert(len(timestamps) == len(eventGrid))
+        return (changeNames, builderNames, timestamps, eventGrid, sourceEvents)
+



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]