[cig-commits] r5895 - in cs/buildbot/trunk: buildbot
buildbot/changes buildbot/process buildbot/status
buildbot/steps buildbot/test contrib
leif at geodynamics.org
leif at geodynamics.org
Thu Jan 25 14:53:26 PST 2007
Author: leif
Date: 2007-01-25 14:53:26 -0800 (Thu, 25 Jan 2007)
New Revision: 5895
Modified:
cs/buildbot/trunk/buildbot/changes/changes.py
cs/buildbot/trunk/buildbot/changes/pb.py
cs/buildbot/trunk/buildbot/process/builder.py
cs/buildbot/trunk/buildbot/scheduler.py
cs/buildbot/trunk/buildbot/sourcestamp.py
cs/buildbot/trunk/buildbot/status/builder.py
cs/buildbot/trunk/buildbot/status/html.py
cs/buildbot/trunk/buildbot/steps/source.py
cs/buildbot/trunk/buildbot/test/test_scheduler.py
cs/buildbot/trunk/contrib/svn_buildbot.py
Log:
Added an additional property to BuildBot changes: 'root'. This is
useful for segregating multiple projects which share a single
repository. For example, when browsing "changes/NN" on the BuildBot
web page, instead of
Branch: mc/3D/CitcomS/trunk
it will instead be broken-out as follows:
Root: mc/3D/CitcomS/
Branch: trunk
(Is the trunk a branch? Hmmm...) The motivation here comes from the
database-style queries. For example, if one wants to see a waterfall
display of all builders for all branches of CitcomS, or just a
specific branch, it is easier to construct the query if 'branch' is
project-relative:
all branches:
http://localhost:8010/?project=CitcomS
just 'compressible':
http://localhost:8010/?project=CitcomS&branch=compressible
The first query would be messy with the (project) root and the branch
lumped together, as they were before... one would have to do some sort
of wildcard matching:
branch=mc/3D/CitcomS/*
Of course, I want the 'changes' column to only show changes relevant
to the current query (not yet implemented), so 'Change' objects must
have a project-relative 'branch'... and this change to 'Change'
ripples thoughout BuildBot as illustrated by this check-in.
Note: I did not bother updating the classes for the other (non-SVN)
source control systems, as it would be too cumbersome to test.
Modified: cs/buildbot/trunk/buildbot/changes/changes.py
===================================================================
--- cs/buildbot/trunk/buildbot/changes/changes.py 2007-01-25 20:12:24 UTC (rev 5894)
+++ cs/buildbot/trunk/buildbot/changes/changes.py 2007-01-25 22:53:26 UTC (rev 5895)
@@ -19,6 +19,7 @@
html_tmpl = """
<p>Changed by: <b>%(who)s</b><br />
Changed at: <b>%(at)s</b><br />
+%(root)s
%(branch)s
%(revision)s
<br />
@@ -59,11 +60,12 @@
number = None
links = []
+ root = None
branch = None
revision = None # used to create a source-stamp
def __init__(self, who, files, comments, isdir=0, links=[],
- revision=None, when=None, branch=None):
+ revision=None, when=None, root=None, branch=None):
self.who = who
self.files = files
self.comments = comments
@@ -73,6 +75,7 @@
if when is None:
when = util.now()
self.when = when
+ self.root = root
self.branch = branch
def asText(self):
@@ -95,6 +98,9 @@
revision = ""
if self.revision:
revision = "Revision: <b>%s</b><br />\n" % self.revision
+ root = ""
+ if self.root:
+ root = "Root: <b>%s</b><br />\n" % self.root
branch = ""
if self.branch:
branch = "Branch: <b>%s</b><br />\n" % self.branch
@@ -103,6 +109,7 @@
'at' : self.getTime(),
'files' : html.UL(links) + '\n',
'revision': revision,
+ 'root' : root,
'branch' : branch,
'comments': html.PRE(self.comments) }
return html_tmpl % kwargs
@@ -196,9 +203,10 @@
def addChange(self, change):
"""Deliver a file change event. The event should be a Change object.
This method will timestamp the object as it is received."""
- log.msg("adding change, who %s, %d files, rev=%s, branch=%s, "
+ log.msg("adding change, who %s, %d files, rev=%s, root=%s, branch=%s, "
"comments %s" % (change.who, len(change.files),
- change.revision, change.branch,
+ change.revision,
+ change.root, change.branch,
change.comments))
change.number = self.nextNumber
self.nextNumber += 1
Modified: cs/buildbot/trunk/buildbot/changes/pb.py
===================================================================
--- cs/buildbot/trunk/buildbot/changes/pb.py 2007-01-25 20:12:24 UTC (rev 5894)
+++ cs/buildbot/trunk/buildbot/changes/pb.py 2007-01-25 22:53:26 UTC (rev 5895)
@@ -32,6 +32,7 @@
change = changes.Change(changedict['who'],
pathnames,
changedict['comments'],
+ root=changedict.get('root'),
branch=changedict.get('branch'),
revision=changedict.get('revision'),
)
Modified: cs/buildbot/trunk/buildbot/process/builder.py
===================================================================
--- cs/buildbot/trunk/buildbot/process/builder.py 2007-01-25 20:12:24 UTC (rev 5894)
+++ cs/buildbot/trunk/buildbot/process/builder.py 2007-01-25 22:53:26 UTC (rev 5895)
@@ -660,9 +660,9 @@
def resubmitBuild(self, bs, reason="<rebuild, no reason given>"):
if not bs.isFinished():
return
- branch, revision, patch = bs.getSourceStamp()
+ root, branch, revision, patch = bs.getSourceStamp()
changes = bs.getChanges()
- ss = sourcestamp.SourceStamp(branch, revision, patch, changes)
+ ss = sourcestamp.SourceStamp(root, branch, revision, patch, changes)
req = base.BuildRequest(reason, ss, self.original.name)
self.requestBuild(req)
Modified: cs/buildbot/trunk/buildbot/scheduler.py
===================================================================
--- cs/buildbot/trunk/buildbot/scheduler.py 2007-01-25 20:12:24 UTC (rev 5894)
+++ cs/buildbot/trunk/buildbot/scheduler.py 2007-01-25 22:53:26 UTC (rev 5895)
@@ -76,10 +76,10 @@
"""
fileIsImportant = None
- compare_attrs = ('name', 'treeStableTimer', 'builderNames', 'branch',
+ compare_attrs = ('name', 'treeStableTimer', 'builderNames', 'root', 'branch',
'fileIsImportant')
- def __init__(self, name, branch, treeStableTimer, builderNames,
+ def __init__(self, name, root, branch, treeStableTimer, builderNames,
fileIsImportant=None):
"""
@param name: the name of this Scheduler
@@ -113,6 +113,7 @@
for b in builderNames:
assert isinstance(b, str), errmsg
self.builderNames = builderNames
+ self.root = root
self.branch = branch
if fileIsImportant:
assert callable(fileIsImportant)
@@ -132,6 +133,9 @@
return []
def addChange(self, change):
+ if change.root != self.root:
+ log.msg("%s ignoring off-root %s" % (self, change))
+ return
if change.branch != self.branch:
log.msg("%s ignoring off-branch %s" % (self, change))
return
@@ -194,10 +198,10 @@
schedulerFactory = Scheduler
fileIsImportant = None
- compare_attrs = ('name', 'branches', 'treeStableTimer', 'builderNames',
+ compare_attrs = ('name', 'roots', 'branches', 'treeStableTimer', 'builderNames',
'fileIsImportant')
- def __init__(self, name, branches, treeStableTimer, builderNames,
+ def __init__(self, name, roots, branches, treeStableTimer, builderNames,
fileIsImportant=None):
"""
@param name: the name of this Scheduler
@@ -230,6 +234,11 @@
for b in builderNames:
assert isinstance(b, str)
self.builderNames = builderNames
+ self.roots = roots
+ if self.roots == []:
+ log.msg("AnyBranchScheduler %s: roots=[], so we will ignore "
+ "all roots, and never trigger any builds. Please set "
+ "roots=None to mean 'all roots'" % self)
self.branches = branches
if self.branches == []:
log.msg("AnyBranchScheduler %s: branches=[], so we will ignore "
@@ -258,17 +267,22 @@
return bts
def addChange(self, change):
+ root = change.root
+ if self.roots is not None and root not in self.roots:
+ log.msg("%s ignoring off-root %s" % (self, change))
+ return
branch = change.branch
if self.branches is not None and branch not in self.branches:
log.msg("%s ignoring off-branch %s" % (self, change))
return
- s = self.schedulers.get(branch)
+ path = root + branch
+ s = self.schedulers.get(path)
if not s:
if branch:
- name = self.name + "." + branch
+ name = self.name + "." + root + branch
else:
- name = self.name + ".<default>"
- s = self.schedulerFactory(name, branch,
+ name = self.name + "." + root + "<default>"
+ s = self.schedulerFactory(name, root, branch,
self.treeStableTimer,
self.builderNames,
self.fileIsImportant)
@@ -276,7 +290,7 @@
s.setServiceParent(self)
# TODO: does this result in schedulers that stack up forever?
# When I make the persistify-pass, think about this some more.
- self.schedulers[branch] = s
+ self.schedulers[path] = s
s.addChange(change)
def submitBuildSet(self, bs):
Modified: cs/buildbot/trunk/buildbot/sourcestamp.py
===================================================================
--- cs/buildbot/trunk/buildbot/sourcestamp.py 2007-01-25 20:12:24 UTC (rev 5894)
+++ cs/buildbot/trunk/buildbot/sourcestamp.py 2007-01-25 22:53:26 UTC (rev 5895)
@@ -19,30 +19,34 @@
from the given branch.
"""
- # all four of these are publically visible attributes
+ # all five of these are publically visible attributes
+ root = None
branch = None
revision = None
patch = None
changes = []
- compare_attrs = ('branch', 'revision', 'patch', 'changes')
+ compare_attrs = ('root', 'branch', 'revision', 'patch', 'changes')
if implements:
implements(interfaces.ISourceStamp)
else:
__implements__ = interfaces.ISourceStamp,
- def __init__(self, branch=None, revision=None, patch=None,
+ def __init__(self, root=None, branch=None, revision=None, patch=None,
changes=None):
+ self.root = root
self.branch = branch
self.revision = revision
self.patch = patch
if changes:
self.changes = changes
+ self.root = changes[0].root
self.branch = changes[0].branch
def canBeMergedWith(self, other):
- if other.branch != self.branch:
+ if (other.root != self.root or
+ other.branch != self.branch):
return False # the builds are completely unrelated
if self.changes and other.changes:
@@ -77,7 +81,8 @@
for req in others:
assert self.canBeMergedWith(req) # should have been checked already
changes.extend(req.changes)
- newsource = SourceStamp(branch=self.branch,
+ newsource = SourceStamp(root=self.root,
+ branch=self.branch,
revision=self.revision,
patch=self.patch,
changes=changes)
Modified: cs/buildbot/trunk/buildbot/status/builder.py
===================================================================
--- cs/buildbot/trunk/buildbot/status/builder.py 2007-01-25 20:12:24 UTC (rev 5894)
+++ cs/buildbot/trunk/buildbot/status/builder.py 2007-01-25 22:53:26 UTC (rev 5895)
@@ -979,7 +979,7 @@
return self.builder.getBuild(self.number-1)
def getSourceStamp(self):
- return (self.source.branch, self.source.revision, self.source.patch)
+ return (self.source.root, self.source.branch, self.source.revision, self.source.patch)
def getReason(self):
return self.reason
Modified: cs/buildbot/trunk/buildbot/status/html.py
===================================================================
--- cs/buildbot/trunk/buildbot/status/html.py 2007-01-25 20:12:24 UTC (rev 5894)
+++ cs/buildbot/trunk/buildbot/status/html.py 2007-01-25 22:53:26 UTC (rev 5895)
@@ -334,9 +334,11 @@
data += "<h2>Buildslave:</h2>\n %s\n" % html.escape(b.getSlavename())
data += "<h2>Reason:</h2>\n%s\n" % html.escape(b.getReason())
- branch, revision, patch = b.getSourceStamp()
+ root, branch, revision, patch = b.getSourceStamp()
data += "<h2>SourceStamp:</h2>\n"
data += " <ul>\n"
+ if root:
+ data += " <li>Root: %s</li>\n" % html.escape(root)
if branch:
data += " <li>Branch: %s</li>\n" % html.escape(branch)
if revision:
Modified: cs/buildbot/trunk/buildbot/steps/source.py
===================================================================
--- cs/buildbot/trunk/buildbot/steps/source.py 2007-01-25 20:12:24 UTC (rev 5894)
+++ cs/buildbot/trunk/buildbot/steps/source.py 2007-01-25 22:53:26 UTC (rev 5895)
@@ -159,6 +159,8 @@
# what source stamp would this build like to use?
s = self.build.getSourceStamp()
+ # if root is None, then use the Step's "default" root
+ root = s.root or self.root
# if branch is None, then use the Step's "default" branch
branch = s.branch or self.branch
# if revision is None, use the latest sources (-rHEAD)
@@ -170,7 +172,7 @@
# 'patch' is None or a tuple of (patchlevel, diff)
patch = s.patch
- self.startVC(branch, revision, patch)
+ self.startVC(root, branch, revision, patch)
def commandComplete(self, cmd):
got_revision = None
@@ -346,7 +348,8 @@
name = 'svn'
- def __init__(self, svnurl=None, baseURL=None, defaultBranch=None,
+ def __init__(self, svnurl=None, baseURL=None,
+ root=None, defaultBranch=None,
directory=None, **kwargs):
"""
@type svnurl: string
@@ -378,6 +381,7 @@
self.svnurl = svnurl
self.baseURL = baseURL
+ self.root = root
self.branch = defaultBranch
Source.__init__(self, **kwargs)
@@ -392,7 +396,7 @@
lastChange = max([int(c.revision) for c in changes])
return lastChange
- def startVC(self, branch, revision, patch):
+ def startVC(self, root, branch, revision, patch):
# handle old slaves
warnings = []
@@ -407,7 +411,7 @@
# the last build used, so if we're using a non-default branch and
# either 'update' or 'copy' modes, it is safer to refuse to
# build, and tell the user they need to upgrade the buildslave.
- if (branch != self.branch
+ if ((root != self.root or branch != self.branch)
and self.args['mode'] in ("update", "copy")):
m = ("This buildslave (%s) does not know about multiple "
"branches, and using mode=%s would probably build the "
@@ -447,7 +451,7 @@
assert not branch # we need baseURL= to use branches
self.args['svnurl'] = self.svnurl
else:
- self.args['svnurl'] = self.baseURL + branch
+ self.args['svnurl'] = self.baseURL + root + branch
self.args['revision'] = revision
self.args['patch'] = patch
Modified: cs/buildbot/trunk/buildbot/test/test_scheduler.py
===================================================================
--- cs/buildbot/trunk/buildbot/test/test_scheduler.py 2007-01-25 20:12:24 UTC (rev 5894)
+++ cs/buildbot/trunk/buildbot/test/test_scheduler.py 2007-01-25 22:53:26 UTC (rev 5895)
@@ -126,7 +126,7 @@
def testAnyBranch(self):
- s = scheduler.AnyBranchScheduler("b1", None, 1, ["a","b"],
+ s = scheduler.AnyBranchScheduler("b1", None, None, 1, ["a","b"],
fileIsImportant=self.isImportant)
self.addScheduler(s)
@@ -175,7 +175,7 @@
def testAnyBranch2(self):
# like testAnyBranch but without fileIsImportant
- s = scheduler.AnyBranchScheduler("b1", None, 2, ["a","b"])
+ s = scheduler.AnyBranchScheduler("b1", None, None, 2, ["a","b"])
self.addScheduler(s)
c1 = Change("alice", ["important", "not important"], "some changes",
branch="branch1")
Modified: cs/buildbot/trunk/contrib/svn_buildbot.py
===================================================================
--- cs/buildbot/trunk/contrib/svn_buildbot.py 2007-01-25 20:12:24 UTC (rev 5894)
+++ cs/buildbot/trunk/contrib/svn_buildbot.py 2007-01-25 22:53:26 UTC (rev 5895)
@@ -119,25 +119,29 @@
# ...
#
-def split_file_branches(changed_file):
+def split_file_root_branches(changed_file):
filename = changed_file.split(os.sep)
+ rootname = []
branchname = []
while filename:
piece = filename.pop(0)
- branchname.append(piece)
if piece == 'trunk':
+ branchname.append(piece)
break
elif piece == 'branches' or piece == 'tags':
+ branchname.append(piece)
piece = filename.pop(0)
branchname.append(piece)
break
+ rootname.append(piece)
if not filename:
raise RuntimeError("cannot determine branch for '%s'" % changed_file)
+ rootname = os.sep.join(rootname) + os.sep
branchname = os.sep.join(branchname)
filename = os.sep.join(filename)
- return (branchname, filename)
+ return (rootname, branchname, filename)
-split_file = split_file_branches
+split_file = split_file_root_branches
class ChangeSender:
@@ -185,10 +189,11 @@
""" % (fltpat, expat)
sys.exit(0)
- # now see which branches are involved
- files_per_branch = {}
+ # now see which roots and branches are involved
+ branches_per_root = {}
for f in changed:
- branch, filename = split_file(f)
+ root, branch, filename = split_file(f)
+ files_per_branch = branches_per_root.setdefault(root, {})
if files_per_branch.has_key(branch):
files_per_branch[branch].append(filename)
else:
@@ -196,13 +201,16 @@
# now create the Change dictionaries
changes = []
- for branch in files_per_branch.keys():
- d = {'who': who,
- 'branch': branch,
- 'files': files_per_branch[branch],
- 'comments': message,
- 'revision': revision}
- changes.append(d)
+ for root in branches_per_root.keys():
+ files_per_branch = branches_per_root[root]
+ for branch in files_per_branch.keys():
+ d = {'who': who,
+ 'root': root,
+ 'branch': branch,
+ 'files': files_per_branch[branch],
+ 'comments': message,
+ 'revision': revision}
+ changes.append(d)
return changes
More information about the cig-commits
mailing list