diff --git a/mozilla/tools/buildbot/buildbot.egg-info/PKG-INFO b/mozilla/tools/buildbot/buildbot.egg-info/PKG-INFO new file mode 100644 index 00000000000..8b1ce9f9fca --- /dev/null +++ b/mozilla/tools/buildbot/buildbot.egg-info/PKG-INFO @@ -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 diff --git a/mozilla/tools/buildbot/buildbot.egg-info/SOURCES.txt b/mozilla/tools/buildbot/buildbot.egg-info/SOURCES.txt new file mode 100644 index 00000000000..a3907ea4746 --- /dev/null +++ b/mozilla/tools/buildbot/buildbot.egg-info/SOURCES.txt @@ -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 \ No newline at end of file diff --git a/mozilla/tools/buildbot/buildbot.egg-info/dependency_links.txt b/mozilla/tools/buildbot/buildbot.egg-info/dependency_links.txt new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/mozilla/tools/buildbot/buildbot.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/mozilla/tools/buildbot/buildbot.egg-info/requires.txt b/mozilla/tools/buildbot/buildbot.egg-info/requires.txt new file mode 100644 index 00000000000..de1910fb903 --- /dev/null +++ b/mozilla/tools/buildbot/buildbot.egg-info/requires.txt @@ -0,0 +1 @@ +twisted >= 2.0.0 \ No newline at end of file diff --git a/mozilla/tools/buildbot/buildbot.egg-info/top_level.txt b/mozilla/tools/buildbot/buildbot.egg-info/top_level.txt new file mode 100644 index 00000000000..8683f0a6985 --- /dev/null +++ b/mozilla/tools/buildbot/buildbot.egg-info/top_level.txt @@ -0,0 +1 @@ +buildbot diff --git a/mozilla/tools/buildbot/buildbot/process/properties.py b/mozilla/tools/buildbot/buildbot/process/properties.py new file mode 100644 index 00000000000..60e8646af43 --- /dev/null +++ b/mozilla/tools/buildbot/buildbot/process/properties.py @@ -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 diff --git a/mozilla/tools/buildbot/buildbot/status/web/grid.py b/mozilla/tools/buildbot/buildbot/status/web/grid.py new file mode 100644 index 00000000000..59a25aa0df5 --- /dev/null +++ b/mozilla/tools/buildbot/buildbot/status/web/grid.py @@ -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 += '\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 ' \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] = '%s' % (url, text[0]) + text = '
\n'.join(text) + + return '%s\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 = '%s' % (url, builder.getName()) + pbs = builder.getPendingBuilds() + if state != 'idle' or pbs: + if pbs: + text += "
(%s with %d pending)" % (state, len(pbs)) + else: + text += "
(%s)" % state + + return '%s\n' % \ + (color, text) + + def stamp_td(self, stamp): + text = stamp.getText() + return '%s\n' % \ + "
".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 = '\n' + data += '\n' + data += '\n' + for stamp in stamps: + data += self.stamp_td(stamp) + data += '\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 += '\n' + data += self.builder_td(request, builder) + for build in builds: + data += self.build_td(request, build) + data += '\n' + + data += '
%s' % (projectURL, projectName) + if categories: + if len(categories) > 1: + data += '\n
Categories:
%s' % ('
'.join(categories)) + else: + data += '\n
Category: %s' % categories[0] + if branch != ANYBRANCH: + data += '\n
Branch: %s' % (branch or 'trunk') + data += '
\n' + + # TODO: this stuff should be generated by a template of some sort + data += '
\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 + diff --git a/mozilla/tools/buildbot/setup.cfg b/mozilla/tools/buildbot/setup.cfg new file mode 100644 index 00000000000..861a9f55426 --- /dev/null +++ b/mozilla/tools/buildbot/setup.cfg @@ -0,0 +1,5 @@ +[egg_info] +tag_build = +tag_date = 0 +tag_svn_revision = 0 +