This commit was generated by cvs2svn to compensate for changes in r254481,

which included commits to RCS files with non-trunk default branches.

git-svn-id: svn://10.0.0.236/trunk@254482 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
bhearsum%mozilla.com 2008-09-30 17:32:42 +00:00
parent 38bb779e51
commit 89c407431d
8 changed files with 658 additions and 0 deletions

View File

@ -0,0 +1,30 @@
Metadata-Version: 1.0
Name: buildbot
Version: 0.7.9
Summary: BuildBot build automation system
Home-page: http://buildbot.net/
Author: Brian Warner
Author-email: warner-buildbot@lothar.com
License: GNU GPL
Description:
The BuildBot is a system to automate the compile/test cycle required by
most software projects to validate code changes. By automatically
rebuilding and testing the tree each time something has changed, build
problems are pinpointed quickly, before other developers are
inconvenienced by the failure. The guilty developer can be identified
and harassed without human intervention. By running the builds on a
variety of platforms, developers who do not have the facilities to test
their changes everywhere before checkin will at least know shortly
afterwards whether they have broken the build or not. Warning counts,
lint checks, image size, compile time, and other build parameters can
be tracked over time, are more visible, and are therefore easier to
improve.
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: No Input/Output (Daemon)
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: GNU General Public License (GPL)
Classifier: Topic :: Software Development :: Build Tools
Classifier: Topic :: Software Development :: Testing

View File

@ -0,0 +1,200 @@
COPYING
CREDITS
MANIFEST.in
NEWS
README
README.w32
setup.py
bin/buildbot
buildbot/__init__.py
buildbot/buildbot.png
buildbot/buildset.py
buildbot/buildslave.py
buildbot/dnotify.py
buildbot/interfaces.py
buildbot/locks.py
buildbot/manhole.py
buildbot/master.py
buildbot/pbutil.py
buildbot/scheduler.py
buildbot/sourcestamp.py
buildbot/util.py
buildbot.egg-info/PKG-INFO
buildbot.egg-info/SOURCES.txt
buildbot.egg-info/dependency_links.txt
buildbot.egg-info/requires.txt
buildbot.egg-info/top_level.txt
buildbot/changes/__init__.py
buildbot/changes/base.py
buildbot/changes/bonsaipoller.py
buildbot/changes/changes.py
buildbot/changes/dnotify.py
buildbot/changes/freshcvs.py
buildbot/changes/hgbuildbot.py
buildbot/changes/mail.py
buildbot/changes/maildir.py
buildbot/changes/monotone.py
buildbot/changes/p4poller.py
buildbot/changes/pb.py
buildbot/changes/svnpoller.py
buildbot/clients/__init__.py
buildbot/clients/base.py
buildbot/clients/debug.glade
buildbot/clients/debug.py
buildbot/clients/gtkPanes.py
buildbot/clients/sendchange.py
buildbot/process/__init__.py
buildbot/process/base.py
buildbot/process/builder.py
buildbot/process/buildstep.py
buildbot/process/factory.py
buildbot/process/process_twisted.py
buildbot/process/properties.py
buildbot/process/step_twisted2.py
buildbot/scripts/__init__.py
buildbot/scripts/checkconfig.py
buildbot/scripts/logwatcher.py
buildbot/scripts/reconfig.py
buildbot/scripts/runner.py
buildbot/scripts/sample.cfg
buildbot/scripts/startup.py
buildbot/scripts/tryclient.py
buildbot/slave/__init__.py
buildbot/slave/bot.py
buildbot/slave/commands.py
buildbot/slave/interfaces.py
buildbot/slave/registry.py
buildbot/status/__init__.py
buildbot/status/base.py
buildbot/status/builder.py
buildbot/status/client.py
buildbot/status/html.py
buildbot/status/mail.py
buildbot/status/progress.py
buildbot/status/tests.py
buildbot/status/tinderbox.py
buildbot/status/words.py
buildbot/status/web/__init__.py
buildbot/status/web/about.py
buildbot/status/web/base.py
buildbot/status/web/baseweb.py
buildbot/status/web/build.py
buildbot/status/web/builder.py
buildbot/status/web/changes.py
buildbot/status/web/classic.css
buildbot/status/web/grid.py
buildbot/status/web/index.html
buildbot/status/web/logs.py
buildbot/status/web/robots.txt
buildbot/status/web/slaves.py
buildbot/status/web/step.py
buildbot/status/web/tests.py
buildbot/status/web/waterfall.py
buildbot/status/web/xmlrpc.py
buildbot/steps/__init__.py
buildbot/steps/dummy.py
buildbot/steps/maxq.py
buildbot/steps/python.py
buildbot/steps/python_twisted.py
buildbot/steps/shell.py
buildbot/steps/source.py
buildbot/steps/transfer.py
buildbot/steps/trigger.py
buildbot/test/__init__.py
buildbot/test/emit.py
buildbot/test/emitlogs.py
buildbot/test/runutils.py
buildbot/test/sleep.py
buildbot/test/test__versions.py
buildbot/test/test_bonsaipoller.py
buildbot/test/test_buildreq.py
buildbot/test/test_buildstep.py
buildbot/test/test_changes.py
buildbot/test/test_config.py
buildbot/test/test_control.py
buildbot/test/test_dependencies.py
buildbot/test/test_locks.py
buildbot/test/test_maildir.py
buildbot/test/test_mailparse.py
buildbot/test/test_p4poller.py
buildbot/test/test_properties.py
buildbot/test/test_run.py
buildbot/test/test_runner.py
buildbot/test/test_scheduler.py
buildbot/test/test_shell.py
buildbot/test/test_slavecommand.py
buildbot/test/test_slaves.py
buildbot/test/test_status.py
buildbot/test/test_steps.py
buildbot/test/test_svnpoller.py
buildbot/test/test_transfer.py
buildbot/test/test_twisted.py
buildbot/test/test_util.py
buildbot/test/test_vc.py
buildbot/test/test_web.py
buildbot/test/test_webparts.py
buildbot/test/mail/freshcvs.1
buildbot/test/mail/freshcvs.2
buildbot/test/mail/freshcvs.3
buildbot/test/mail/freshcvs.4
buildbot/test/mail/freshcvs.5
buildbot/test/mail/freshcvs.6
buildbot/test/mail/freshcvs.7
buildbot/test/mail/freshcvs.8
buildbot/test/mail/freshcvs.9
buildbot/test/mail/svn-commit.1
buildbot/test/mail/svn-commit.2
buildbot/test/mail/syncmail.1
buildbot/test/mail/syncmail.2
buildbot/test/mail/syncmail.3
buildbot/test/mail/syncmail.4
buildbot/test/mail/syncmail.5
buildbot/test/subdir/emit.py
contrib/README.txt
contrib/arch_buildbot.py
contrib/bb_applet.py
contrib/darcs_buildbot.py
contrib/fakechange.py
contrib/git_buildbot.py
contrib/hg_buildbot.py
contrib/run_maxq.py
contrib/svn_buildbot.py
contrib/svn_watcher.py
contrib/svnpoller.py
contrib/viewcvspoll.py
contrib/CSS/sample1.css
contrib/CSS/sample2.css
contrib/OS-X/README
contrib/OS-X/net.sourceforge.buildbot.master.plist
contrib/OS-X/net.sourceforge.buildbot.slave.plist
contrib/windows/buildbot.bat
contrib/windows/buildbot2.bat
contrib/windows/buildbot_service.py
contrib/windows/setup.py
docs/buildbot.html
docs/buildbot.info
docs/buildbot.info-1
docs/buildbot.info-2
docs/buildbot.texinfo
docs/epyrun
docs/gen-reference
docs/hexnut32.png
docs/hexnut48.png
docs/hexnut64.png
docs/examples/hello.cfg
docs/examples/twisted_master.cfg
docs/images/master.png
docs/images/master.svg
docs/images/master.txt
docs/images/overview.png
docs/images/overview.svg
docs/images/overview.txt
docs/images/slavebuilder.png
docs/images/slavebuilder.svg
docs/images/slavebuilder.txt
docs/images/slaves.png
docs/images/slaves.svg
docs/images/slaves.txt
docs/images/status.png
docs/images/status.svg
docs/images/status.txt

View File

@ -0,0 +1 @@
twisted >= 2.0.0

View File

@ -0,0 +1 @@
buildbot

View File

@ -0,0 +1,157 @@
import re
import weakref
from buildbot import util
class Properties(util.ComparableMixin):
"""
I represent a set of properties that can be interpolated into various
strings in buildsteps.
@ivar properties: dictionary mapping property values to tuples
(value, source), where source is a string identifing the source
of the property.
Objects of this class can be read like a dictionary -- in this case,
only the property value is returned.
As a special case, a property value of None is returned as an empty
string when used as a mapping.
"""
compare_attrs = ('properties')
def __init__(self, **kwargs):
"""
@param kwargs: initial property values (for testing)
"""
self.properties = {}
self.pmap = PropertyMap(self)
if kwargs: self.update(kwargs, "TEST")
def __getstate__(self):
d = self.__dict__.copy()
del d['pmap']
return d
def __setstate__(self, d):
self.__dict__ = d
self.pmap = PropertyMap(self)
def __getitem__(self, name):
"""Just get the value for this property."""
rv = self.properties[name][0]
return rv
def has_key(self, name):
return self.properties.has_key(name)
def getProperty(self, name, default=None):
"""Get the value for the given property."""
return self.properties.get(name, (default,))[0]
def getPropertySource(self, name):
return self.properties[name][1]
def asList(self):
"""Return the properties as a sorted list of (name, value, source)"""
l = [ (k, v[0], v[1]) for k,v in self.properties.items() ]
l.sort()
return l
def __repr__(self):
return repr(dict([ (k,v[0]) for k,v in self.properties.iteritems() ]))
def setProperty(self, name, value, source):
self.properties[name] = (value, source)
def update(self, dict, source):
"""Update this object from a dictionary, with an explicit source specified."""
for k, v in dict.items():
self.properties[k] = (v, source)
def updateFromProperties(self, other):
"""Update this object based on another object; the other object's """
self.properties.update(other.properties)
def render(self, value):
"""
Return a variant of value that has any WithProperties objects
substituted. This recurses into Python's compound data types.
"""
# we use isinstance to detect Python's standard data types, and call
# this function recursively for the values in those types
if isinstance(value, (str, unicode)):
return value
elif isinstance(value, WithProperties):
return value.render(self.pmap)
elif isinstance(value, list):
return [ self.render(e) for e in value ]
elif isinstance(value, tuple):
return tuple([ self.render(e) for e in value ])
elif isinstance(value, dict):
return dict([ (self.render(k), self.render(v)) for k,v in value.iteritems() ])
else:
return value
class PropertyMap:
"""
Privately-used mapping object to implement WithProperties' substitutions,
including the rendering of None as ''.
"""
colon_minus_re = re.compile(r"(.*):-(.*)")
colon_plus_re = re.compile(r"(.*):\+(.*)")
def __init__(self, properties):
# use weakref here to avoid a reference loop
self.properties = weakref.ref(properties)
def __getitem__(self, key):
properties = self.properties()
assert properties is not None
# %(prop:-repl)s
# if prop exists, use it; otherwise, use repl
mo = self.colon_minus_re.match(key)
if mo:
prop, repl = mo.group(1,2)
if properties.has_key(prop):
rv = properties[prop]
else:
rv = repl
else:
# %(prop:+repl)s
# if prop exists, use repl; otherwise, an empty string
mo = self.colon_plus_re.match(key)
if mo:
prop, repl = mo.group(1,2)
if properties.has_key(prop):
rv = repl
else:
rv = ''
else:
rv = properties[key]
# translate 'None' to an empty string
if rv is None: rv = ''
return rv
class WithProperties(util.ComparableMixin):
"""
This is a marker class, used fairly widely to indicate that we
want to interpolate build properties.
"""
compare_attrs = ('fmtstring', 'args')
def __init__(self, fmtstring, *args):
self.fmtstring = fmtstring
self.args = args
def render(self, pmap):
if self.args:
strings = []
for name in self.args:
strings.append(pmap[name])
s = self.fmtstring % tuple(strings)
else:
s = self.fmtstring % pmap
return s

View File

@ -0,0 +1,263 @@
from __future__ import generators
import sys, time, os.path
import urllib
from buildbot import util
from buildbot import version
from buildbot.status.web.base import HtmlResource
# set grid_css to the full pathname of the css file
if hasattr(sys, "frozen"):
# all 'data' files are in the directory of our executable
here = os.path.dirname(sys.executable)
grid_css = os.path.abspath(os.path.join(here, "grid.css"))
else:
# running from source; look for a sibling to __file__
up = os.path.dirname
grid_css = os.path.abspath(os.path.join(up(__file__), "grid.css"))
class ANYBRANCH: pass # a flag value, used below
class GridStatusResource(HtmlResource):
# TODO: docs
status = None
control = None
changemaster = None
def __init__(self, allowForce=True, css=None):
HtmlResource.__init__(self)
self.allowForce = allowForce
self.css = css or grid_css
def getTitle(self, request):
status = self.getStatus(request)
p = status.getProjectName()
if p:
return "BuildBot: %s" % p
else:
return "BuildBot"
def getChangemaster(self, request):
# TODO: this wants to go away, access it through IStatus
return request.site.buildbot_service.parent.change_svc
# handle reloads through an http header
# TODO: send this as a real header, rather than a tag
def get_reload_time(self, request):
if "reload" in request.args:
try:
reload_time = int(request.args["reload"][0])
return max(reload_time, 15)
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 setBuildmaster(self, buildmaster):
# self.status = buildmaster.getStatus()
# if self.allowForce:
# self.control = interfaces.IControl(buildmaster)
# else:
# self.control = None
# self.changemaster = buildmaster.change_svc
#
# # try to set the page title
# p = self.status.getProjectName()
# if p:
# self.title = "BuildBot: %s" % p
#
def build_td(self, request, build):
if not build:
return '<td class="build">&nbsp;</td>\n'
if build.isFinished():
color = build.getColor()
if color == 'green': color = '#72ff75' # the "Buildbot Green"
# get the text and annotate the first line with a link
text = build.getText()
if not text: text = [ "(no information)" ]
if text == [ "build", "successful" ]: text = [ "OK" ]
else:
color = 'yellow' # to match the yellow of the builder
text = [ 'building' ]
name = build.getBuilder().getName()
number = build.getNumber()
url = "builders/%s/builds/%d" % (name, number)
text[0] = '<a href="%s">%s</a>' % (url, text[0])
text = '<br />\n'.join(text)
return '<td class="build" bgcolor="%s">%s</td>\n' % (color, text)
def builder_td(self, request, builder):
state, builds = builder.getState()
# look for upcoming builds. We say the state is "waiting" if the
# builder is otherwise idle and there is a scheduler which tells us a
# build will be performed some time in the near future. TODO: this
# functionality used to be in BuilderStatus.. maybe this code should
# be merged back into it.
upcoming = []
builderName = builder.getName()
for s in self.getStatus(request).getSchedulers():
if builderName in s.listBuilderNames():
upcoming.extend(s.getPendingBuildTimes())
if state == "idle" and upcoming:
state = "waiting"
if state == "building":
color = "yellow"
elif state == "offline":
color = "red"
elif state == "idle":
color = "white"
elif state == "waiting":
color = "yellow"
else:
color = "white"
# TODO: for now, this pending/upcoming stuff is in the "current
# activity" box, but really it should go into a "next activity" row
# instead. The only times it should show up in "current activity" is
# when the builder is otherwise idle.
# are any builds pending? (waiting for a slave to be free)
url = 'builders/%s/' % urllib.quote(builder.getName(), safe='')
text = '<a href="%s">%s</a>' % (url, builder.getName())
pbs = builder.getPendingBuilds()
if state != 'idle' or pbs:
if pbs:
text += "<br />(%s with %d pending)" % (state, len(pbs))
else:
text += "<br />(%s)" % state
return '<td valign="center" bgcolor="%s" class="builder">%s</td>\n' % \
(color, text)
def stamp_td(self, stamp):
text = stamp.getText()
return '<td valign="bottom" class="sourcestamp">%s</td>\n' % \
"<br />".join(text)
def body(self, request):
"This method builds the main waterfall display."
# get url parameters
numBuilds = int(request.args.get("width", [5])[0])
categories = request.args.get("category", [])
branch = request.args.get("branch", [ANYBRANCH])[0]
if branch == 'trunk': branch = None
# and the data we want to render
status = self.getStatus(request)
stamps = self.getRecentSourcestamps(status, numBuilds, categories, branch)
projectURL = status.getProjectURL()
projectName = status.getProjectName()
data = '<table class="Grid" border="0" cellspacing="0">\n'
data += '<tr>\n'
data += '<td class="title"><a href="%s">%s</a>' % (projectURL, projectName)
if categories:
if len(categories) > 1:
data += '\n<br /><b>Categories:</b><br/>%s' % ('<br/>'.join(categories))
else:
data += '\n<br /><b>Category:</b> %s' % categories[0]
if branch != ANYBRANCH:
data += '\n<br /><b>Branch:</b> %s' % (branch or 'trunk')
data += '</td>\n'
for stamp in stamps:
data += self.stamp_td(stamp)
data += '</tr>\n'
sortedBuilderNames = status.getBuilderNames()[:]
sortedBuilderNames.sort()
for bn in sortedBuilderNames:
builds = [None] * len(stamps)
builder = status.getBuilder(bn)
if categories and builder.category not in categories:
continue
build = builder.getBuild(-1)
while build and None in builds:
ss = build.getSourceStamp(absolute=True)
for i in range(len(stamps)):
if ss == stamps[i] and builds[i] is None:
builds[i] = build
build = build.getPreviousBuild()
data += '<tr>\n'
data += self.builder_td(request, builder)
for build in builds:
data += self.build_td(request, build)
data += '</tr>\n'
data += '</table>\n'
# TODO: this stuff should be generated by a template of some sort
data += '<hr /><div class="footer">\n'
welcomeurl = self.path_to_root(request) + "index.html"
data += '[<a href="%s">welcome</a>]\n' % welcomeurl
data += "<br />\n"
data += '<a href="http://buildbot.sourceforge.net/">Buildbot</a>'
data += "-%s " % version
if projectName:
data += "working for the "
if projectURL:
data += "<a href=\"%s\">%s</a> project." % (projectURL,
projectName)
else:
data += "%s project." % projectName
data += "<br />\n"
data += ("Page built: " +
time.strftime("%a %d %b %Y %H:%M:%S",
time.localtime(util.now()))
+ "\n")
data += '</div>\n'
return data
def getRecentSourcestamps(self, status, numBuilds, categories, branch):
"""
get a list of the most recent NUMBUILDS SourceStamp tuples, sorted
by the earliest start we've seen for them
"""
# TODO: use baseweb's getLastNBuilds?
sourcestamps = { } # { ss-tuple : earliest time }
for bn in status.getBuilderNames():
builder = status.getBuilder(bn)
if categories and builder.category not in categories:
continue
build = builder.getBuild(-1)
while build:
ss = build.getSourceStamp(absolute=True)
start = build.getTimes()[0]
build = build.getPreviousBuild()
# skip un-started builds
if not start: continue
# skip non-matching branches
if branch != ANYBRANCH and ss.branch != branch: continue
sourcestamps[ss] = min(sourcestamps.get(ss, sys.maxint), start)
# now sort those and take the NUMBUILDS most recent
sourcestamps = sourcestamps.items()
sourcestamps.sort(lambda x, y: cmp(x[1], y[1]))
sourcestamps = map(lambda tup : tup[0], sourcestamps)
sourcestamps = sourcestamps[-numBuilds:]
return sourcestamps

View File

@ -0,0 +1,5 @@
[egg_info]
tag_build =
tag_date = 0
tag_svn_revision = 0