From warner at users.sourceforge.net Wed Aug 3 23:47:31 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 03 Aug 2005 23:47:31 +0000 Subject: [Buildbot-commits] buildbot ChangeLog,1.477,1.478 .arch-inventory,1.4,1.5 Message-ID: Update of /cvsroot/buildbot/buildbot In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv25404 Modified Files: ChangeLog .arch-inventory Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-264 Creator: Brian Warner start work on 'try', document the 'buildbot' command-line tool * buildbot/trybuild.py: new file for 'try' utilities (getSourceStamp): run in a tree, find out the baserev+patch * buildbot/test/test_vc.py (VCBase.do_getpatch): test it, implemented for SVN and Darcs, still working on Arch. I don't know how to make CVS work yet. * docs/buildbot.texinfo: document the 'buildbot' command-line tool, including the not-yet-implemented 'try' feature, and the in-flux .buildbot/ options directory. Index: .arch-inventory =================================================================== RCS file: /cvsroot/buildbot/buildbot/.arch-inventory,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- .arch-inventory 19 Jul 2005 01:55:21 -0000 1.4 +++ .arch-inventory 3 Aug 2005 23:47:29 -0000 1.5 @@ -5,3 +5,4 @@ junk ^MANIFEST$ junk ^dist$ junk ^_darcs$ +junk ^.darcs-boring$ Index: ChangeLog =================================================================== RCS file: /cvsroot/buildbot/buildbot/ChangeLog,v retrieving revision 1.477 retrieving revision 1.478 diff -u -d -r1.477 -r1.478 --- ChangeLog 20 Jul 2005 08:08:24 -0000 1.477 +++ ChangeLog 3 Aug 2005 23:47:28 -0000 1.478 @@ -1,3 +1,15 @@ +2005-08-03 Brian Warner + + * buildbot/trybuild.py: new file for 'try' utilities + (getSourceStamp): run in a tree, find out the baserev+patch + * buildbot/test/test_vc.py (VCBase.do_getpatch): test it, + implemented for SVN and Darcs, still working on Arch. I don't know + how to make CVS work yet. + + * docs/buildbot.texinfo: document the 'buildbot' command-line + tool, including the not-yet-implemented 'try' feature, and the + in-flux .buildbot/ options directory. + 2005-07-20 Brian Warner * buildbot/locks.py: added temporary id() numbers to Lock From warner at users.sourceforge.net Wed Aug 3 23:47:31 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 03 Aug 2005 23:47:31 +0000 Subject: [Buildbot-commits] buildbot/buildbot/test test_vc.py,1.36,1.37 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv25404/buildbot/test Modified Files: test_vc.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-264 Creator: Brian Warner start work on 'try', document the 'buildbot' command-line tool * buildbot/trybuild.py: new file for 'try' utilities (getSourceStamp): run in a tree, find out the baserev+patch * buildbot/test/test_vc.py (VCBase.do_getpatch): test it, implemented for SVN and Darcs, still working on Arch. I don't know how to make CVS work yet. * docs/buildbot.texinfo: document the 'buildbot' command-line tool, including the not-yet-implemented 'try' feature, and the in-flux .buildbot/ options directory. Index: test_vc.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/test/test_vc.py,v retrieving revision 1.36 retrieving revision 1.37 diff -u -d -r1.36 -r1.37 --- test_vc.py 20 Jul 2005 08:08:23 -0000 1.36 +++ test_vc.py 3 Aug 2005 23:47:29 -0000 1.37 @@ -13,7 +13,7 @@ from twisted.python import log #log.startLogging(sys.stderr) -from buildbot import master, interfaces +from buildbot import master, interfaces, trybuild from buildbot.slave import bot from buildbot.status.builder import SUCCESS, FAILURE from buildbot.process import step, base @@ -167,6 +167,29 @@ } ''' +newfiles['fail_try'] = ''' +#include + +int +main(int argc, const char *argv[]) +{ + printf("Hello world, %d\\n"); + return 0; +} +''' + +newfiles['try_patch'] = ''' +@@ -4,6 +4,6 @@ + int + main(int argc, const char *argv[]) + { +- printf("Hello world, %d\\n", bogus); ++ printf("Hello world, %d\\n"); + return 0; + } +''' + + files['fixable.c'] = ''' #include @@ -353,7 +376,8 @@ log.msg(" and stdout %s" % (out,)) log.msg(" and stderr %s" % (err,)) raise RuntimeError("command %s finished with exit code %d" - % (command, code)) + % (command, code) + + ": see logs for stdout") return out d.addCallback(check) return d @@ -366,6 +390,9 @@ os.makedirs(basedir) for f in files.keys(): open(os.path.join(basedir, f), "w").write(files[f]) + # I don't actually need these quite yet, but may soon + #os.makedirs(os.path.join(basedir, "subdir")) + #open(os.path.join(basedir, "subdir", "subfile.c"),"w").write("sub\n") def doBuild(self, shouldSucceed=True, ss=None): c = interfaces.IControl(self.master) @@ -662,6 +689,26 @@ self.failUnlessIn("Hello world", data) self.shouldNotExist(self.workdir, "newbranchfile") + def do_getpatch(self, vctype, tmpdir): + workdir = os.path.join(self.repbase, tmpdir) + self.vctype = vctype + d = self.setup_try(tmpdir) + d.addCallback(self._doGetpatch_1, workdir) + return d + def _doGetpatch_1(self, res, workdir): + d = trybuild.getSourceStamp(self.vctype, workdir) + return d + + def dumpPatch(self, patch): + # this exists to help me figure out the right 'patchlevel' value + # should be returned by trybuild.getSourceStamp + n = self.mktemp() + open(n,"w").write(patch) + d = self.runCommand(".", ["lsdiff", n]) + def p(res): print "lsdiff:", res.strip().split("\n") + d.addCallback(p) + return d + def tearDown(self): d = defer.succeed(None) @@ -747,6 +794,15 @@ shutil.rmtree(tmp) fix = deferredGenerator(fix) + def setup_try(self, tmpdir): + tmp = os.path.join(self.repbase, tmpdir) + + w = self.do(self.repbase, + "cvs -d %s checkout -d %s sample" % (self.cvsrep, tmpdir)) + yield w; w.getResult() + open(os.path.join(tmp, "fail.c"), "w").write(newfiles['fail_try']) + setup_try = deferredGenerator(setup_try) + class SVN(VCBase, unittest.TestCase): metadir = ".svn" @@ -772,6 +828,26 @@ "sample/branch") return maybeWait(d) + def testTryGetPatch(self): + # extract the base revision and patch from a modified tree + d = self.do_getpatch("svn", "svn_trydir") + d.addCallback(self._testTryGetPatch_1) + return maybeWait(d) + def _testTryGetPatch_1(self, res): + baserev, (patchlevel, patch) = res + # because of the way SVN works, the baserev we get here will be the + # latest repository revision number, which could be either 3 or 4 + # depending upon whether the other tests (specifically 'fix') have + # been run yet. + self.failUnless(baserev == 3 or baserev == 4, + "baserev was not what we expected: %s" % baserev) + # regardless of whether the patch is taken against r3 or r4, our + # patch to fail.c will still be present + self.failUnlessIn(newfiles['try_patch'], patch, + "did not see the expected patch in: %s" % patch) + self.failUnlessEqual(patchlevel, 0) + #return self.dumpPatch(patch) + def createRepository(self): self.svnrep = os.path.join(self.repbase, "SVN-Repository") tmp = os.path.join(self.repbase, "svntmp") @@ -784,7 +860,8 @@ self.populate(tmp) w = self.do(tmp, - "svn import -m sample_project_files %s" % self.svnurl_trunk) + "svn import -m sample_project_files %s" % + self.svnurl_trunk) yield w; w.getResult() shutil.rmtree(tmp) @@ -815,6 +892,15 @@ shutil.rmtree(tmp) fix = deferredGenerator(fix) + def setup_try(self, tmpdir): + tmp = os.path.join(self.repbase, tmpdir) + w = self.do(self.repbase, + "svn checkout %s %s" % (self.svnurl_trunk, tmpdir)) + yield w; w.getResult() + open(os.path.join(tmp, "fail.c"), "w").write(newfiles['fail_try']) + setup_try = deferredGenerator(setup_try) + + class Darcs(VCBase, unittest.TestCase): metadir = None # Darcs has a metadir="_darcs", but it does not have an 'export' @@ -857,6 +943,24 @@ testRetry=False) return maybeWait(d) + def testTryGetPatch(self): + # extract the base revision and patch from a modified tree + d = self.do_getpatch("darcs", "darcs_trydir") + d.addCallback(self._testTryGetPatch_1) + return maybeWait(d) + def _testTryGetPatch_1(self, res): + baserev, (patchlevel, patch) = res + self.failUnlessIn("[initial_import\ntest at buildbot.sf.net**", baserev, + "baserev was not what we expected: %s" % baserev) + # the number of revisions depends upon whether we've run the 'fix' + # method yet or not. + self.failUnless(baserev.count("[") in (1,2)) + self.failUnlessIn("initial_import\ntest at buildbot.sf.net**", baserev) + self.failUnlessIn(newfiles['try_patch'], patch, + "did not see the expected patch in: %s" % patch) + self.failUnlessEqual(patchlevel, 1) + #return self.dumpPatch(patch) + def createRepository(self): self.darcs_base = os.path.join(self.repbase, "Darcs-Repository") self.rep_trunk = os.path.join(self.darcs_base, "trunk") @@ -904,6 +1008,17 @@ shutil.rmtree(tmp) fix = deferredGenerator(fix) + def setup_try(self, tmpdir): + tmp = os.path.join(self.repbase, tmpdir) + os.makedirs(tmp) + w = self.do(tmp, "darcs initialize") + yield w; w.getResult() + w = self.do(tmp, "darcs pull -a %s" % self.rep_trunk) + yield w; w.getResult() + + open(os.path.join(tmp, "fail.c"), "w").write(newfiles['fail_try']) + setup_try = deferredGenerator(setup_try) + class Arch(VCBase, unittest.TestCase): metadir = None @@ -996,6 +1111,24 @@ d.addCallback(lambda res: self.unregisterRepository("tla")) return maybeWait(d) + def testArchTryGetPatch(self): + raise unittest.SkipTest("not yet implemented") + # extract the base revision and patch from a modified tree + self.archcmd = "tla" + d = self.unregisterRepository("tla") + d.addCallback(lambda res: + self.do_getpatch("tla", "tla_trydir")) + d.addCallback(self._testArchTryGetPatch_1) + return maybeWait(d) + def _testArchTryGetPatch_1(self, res): + baserev, (patchlevel, patch) = res + rev = "test at buildbot.sf.net--testvc/testvc--mainline--1--patch-1" + self.failUnlessEqual(baserev, rev) + self.failUnlessIn(newfiles['try_patch'], patch, + "did not see the expected patch in: %s" % patch) + self.failUnlessEqual(patchlevel, 1) + return self.dumpPatch(patch) + def testBazaar(self): # NOTE: if you have baz archive caching turned on, this may get # confused. You can use 'baz cache-config --disable' to turn it off. @@ -1291,6 +1424,42 @@ yield w; w.getResult() shutil.rmtree(tmp) fix = deferredGenerator(fix) + + def setup_try(self, tmpdir): + tmp = os.path.join(self.repbase, tmpdir) + a = "test at buildbot.sf.net--testvc" + + cmd = "%s archives %s" % (self.archcmd, a) + w = self.do(self.repbase, cmd) + yield w; out = w.getResult() + assert out + lines = out.split("\n") + coordinates = lines[1].strip() + + # now register the read-write location + w = waitForDeferred(self.registerRepository(self.archcmd, + self.archrep)) + yield w; w.getResult() + + # the 'get' syntax is different between tla and baz. baz, while + # claiming to honor an --archive argument, in fact ignores it. The + # correct invocation is 'baz get archive/revision newdir'. + if self.archcmd == 'tla': + cmd = "tla get -A %s testvc--mainline--1 %s" % (a, tmpdir) + else: + cmd = "baz get %s/testvc--mainline--1 %s" % (a, tmpdir) + w = self.do(self.repbase, cmd) + + yield w; w.getResult() + + open(os.path.join(tmp, "fail.c"), "w").write(newfiles['fail_try']) + + # now re-register the original coordinates + #w = waitForDeferred(self.registerRepository(self.archcmd, + # coordinates)) + #yield w; w.getResult() + #shutil.rmtree(tmp) + setup_try = deferredGenerator(setup_try) class Sources(unittest.TestCase): From warner at users.sourceforge.net Wed Aug 3 23:47:32 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 03 Aug 2005 23:47:32 +0000 Subject: [Buildbot-commits] buildbot/buildbot trybuild.py,NONE,1.1 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv25404/buildbot Added Files: trybuild.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-264 Creator: Brian Warner start work on 'try', document the 'buildbot' command-line tool * buildbot/trybuild.py: new file for 'try' utilities (getSourceStamp): run in a tree, find out the baserev+patch * buildbot/test/test_vc.py (VCBase.do_getpatch): test it, implemented for SVN and Darcs, still working on Arch. I don't know how to make CVS work yet. * docs/buildbot.texinfo: document the 'buildbot' command-line tool, including the not-yet-implemented 'try' feature, and the in-flux .buildbot/ options directory. --- NEW FILE: trybuild.py --- # -*- test-case-name: buildbot.test.test_vc -*- import os, re from twisted.internet import utils class SourceStampExtractor: def __init__(self, treetop): self.treetop = treetop def do(self, cmd): return utils.getProcessOutput(cmd[0], cmd[1:], env=os.environ, path=self.treetop) def get(self): d = self.getBaseRevision() d.addCallback(self.getPatch) d.addCallback(self.done) return d def readPatch(self, res, patchlevel): self.patch = (patchlevel, res) def done(self, res): return (self.baserev, self.patch) class SVNExtractor(SourceStampExtractor): patchlevel = 0 def getBaseRevision(self): d = self.do(['svn', "status", "-u"]) d.addCallback(self.parseStatus) return d def parseStatus(self, res): # svn shows the base revision for each file that has been modified or # which needs an update. You can update each file to a different # version, so each file is displayed with its individual base # revision. It also shows the repository-wide latest revision number # on the last line ("Status against revision: \d+"). # for our purposes, we use the latest revision number as the "base" # revision, and get a diff against that. This means we will get # reverse-diffs for local files that need updating, but the resulting # tree will still be correct. The only weirdness is that the baserev # that we emit may be different than the version of the tree that we # first checked out. # to do this differently would probably involve scanning the revision # numbers to find the max (or perhaps the min) revision, and then # using that as a base. for line in res.split("\n"): m = re.search(r'^Status against revision:\s+(\d+)', line) if m: num = m.group(1) self.baserev = int(num) return raise IndexError("Could not find 'Status against revision' in " "SVN output: %s" % res) def getPatch(self, res): d = self.do(["svn", "diff", "-r%d" % self.baserev]) d.addCallback(self.readPatch, self.patchlevel) return d class BazExtractor(SourceStampExtractor): def getBaseRevision(self): d = self.do(["baz", "tree-id"]) d.addCallback(self.parseStatus) return d def parseStatus(self, res): self.baserev = res.strip() def getPatch(self, res): d = self.do(["baz", "diff"]) d.addCallback(self.readPatch, 1) return d class TlaExtractor(SourceStampExtractor): def getBaseRevision(self): d = self.do(["tla", "logs", "--full", "--reverse"]) d.addCallback(self.parseStatus) return d def parseStatus(self, res): lines = res.split("\n") self.baserev = lines[0].strip() def getPatch(self, res): d = self.do(["tla", "changes", "--diffs"]) d.addCallback(self.readPatch, 1) return d class DarcsExtractor(SourceStampExtractor): patchlevel = 1 def getBaseRevision(self): d = self.do(["darcs", "changes", "--context"]) d.addCallback(self.parseStatus) return d def parseStatus(self, res): self.baserev = res # the whole context file def getPatch(self, res): d = self.do(["darcs", "diff", "-u"]) d.addCallback(self.readPatch, self.patchlevel) return d def getSourceStamp(vctype, treetop): if vctype == "cvs": raise NotImplementedError("CVSExtractor not yet implemented") elif vctype == "svn": e = SVNExtractor(treetop) elif vctype == "baz": e = BazExtractor(treetop) elif vctype == "tla": e = TlaExtractor(treetop) elif vctype == "darcs": e = DarcsExtractor(treetop) else: raise KeyError("unknown vctype '%s'" % vctype) return e.get() From warner at users.sourceforge.net Wed Aug 3 23:47:30 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 03 Aug 2005 23:47:30 +0000 Subject: [Buildbot-commits] buildbot/docs buildbot.texinfo,1.11,1.12 Message-ID: Update of /cvsroot/buildbot/buildbot/docs In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv25404/docs Modified Files: buildbot.texinfo Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-264 Creator: Brian Warner start work on 'try', document the 'buildbot' command-line tool * buildbot/trybuild.py: new file for 'try' utilities (getSourceStamp): run in a tree, find out the baserev+patch * buildbot/test/test_vc.py (VCBase.do_getpatch): test it, implemented for SVN and Darcs, still working on Arch. I don't know how to make CVS work yet. * docs/buildbot.texinfo: document the 'buildbot' command-line tool, including the not-yet-implemented 'try' feature, and the in-flux .buildbot/ options directory. Index: buildbot.texinfo =================================================================== RCS file: /cvsroot/buildbot/buildbot/docs/buildbot.texinfo,v retrieving revision 1.11 retrieving revision 1.12 diff -u -d -r1.11 -r1.12 --- buildbot.texinfo 20 Jul 2005 04:49:06 -0000 1.11 +++ buildbot.texinfo 3 Aug 2005 23:47:28 -0000 1.12 @@ -41,6 +41,7 @@ * Getting Source Code Changes:: Discovering when to run a build. * Build Process:: Controlling how each build is run. * Status Delivery:: Telling the world about the build's results. +* Command-line tool:: * Resources:: Getting help. * Developer's Appendix:: * Index:: Complete index. @@ -175,6 +176,24 @@ * IRC Bot:: * PBListener:: +Command-line tool + +* Administrator Tools:: +* Developer Tools:: +* Other Tools:: +* .buildbot config directory:: + +Developer Tools + +* statuslog:: +* statusgui:: +* try:: + +Other Tools + +* sendchange:: +* debugclient:: + @end detailmenu @end menu @@ -3336,7 +3355,7 @@ @end example - at node Status Delivery, Resources, Build Process, Top + at node Status Delivery, Command-line tool, Build Process, Top @chapter Status Delivery More details are available in the docstrings for each class, use @@ -3472,7 +3491,473 @@ status client can connect and retrieve status information. @code{buildbot statusgui} is an example of such a status client. - at node Resources, Developer's Appendix, Status Delivery, Top + at node Command-line tool, Resources, Status Delivery, Top + at chapter Command-line tool + +The @command{buildbot} command-line tool can be used to start or stop a +buildmaster or buildbot, and to interact with a running buildmaster. +Some of its subcommands are intended for buildmaster admins, while +some are for developers who are editing the code that the buildbot is +monitoring. + + at menu +* Administrator Tools:: +* Developer Tools:: +* Other Tools:: +* .buildbot config directory:: + at end menu + + at node Administrator Tools, Developer Tools, Command-line tool, Command-line tool + at section Administrator Tools + +The following @command{buildbot} sub-commands are intended for +buildmaster administrators: + + at heading master + +This creates a new directory and populates it with files that allow it +to be used as a buildmaster's base directory. + + at example +buildbot master BASEDIR + at end example + + at heading slave + +This creates a new directory and populates it with files that let it +be used as a buildslave's base directory. You must provide several +arguments, which are used to create the initial @file{buildbot.tac} +file. + + at example +buildbot slave @var{BASEDIR} @var{MASTERHOST}:@var{PORT} @var{SLAVENAME} @var{PASSWORD} + at end example + + at heading start + +This starts a buildmaster or buildslave which was already created in +the given base directory. The daemon is launched in the background, +with events logged to a file named @file{twistd.log}. + + at example +buildbot start BASEDIR + at end example + + at heading stop + +This terminates the daemon (either buildmaster or buildslave) running +in the given directory. + + at example +buildbot stop BASEDIR + at end example + + at heading sighup + +This sends a SIGHUP to the buildmaster running in the given directory, +which causes it to re-read its @file{master.cfg} file. + + at example +buildbot sighup BASEDIR + at end example + + at node Developer Tools, Other Tools, Administrator Tools, Command-line tool + at section Developer Tools + +These tools are provided for use by the developers who are working on +the code that the buildbot is monitoring. + + at menu +* statuslog:: +* statusgui:: +* try:: + at end menu + + at node statuslog, statusgui, Developer Tools, Developer Tools + at subsection statuslog + + at example +buildbot statuslog --master @var{MASTERHOST}:@var{PORT} + at end example + +This command starts a simple text-based status client, one which just +prints out a new line each time an event occurs on the buildmaster. + +The @option{--master} option provides the location of the + at code{client.PBListener} status port, used to deliver build +information to realtime status clients. The option is always in the +form of a string, with hostname and port number separated by a colon +(@code{HOSTNAME:PORTNUM}). Note that this port is @emph{not} the same +as the slaveport (although a future version may allow the same port +number to be used for both purposes). + +The @option{--master} option can also be provided by the + at code{masterstatus} name in @file{.buildbot/options} (@pxref{.buildbot +config directory}). + + at node statusgui, try, statuslog, Developer Tools + at subsection statusgui + + at example +buildbot statusgui --master @var{MASTERHOST}:@var{PORT} + at end example + +This command starts a simple Gtk+-based status client, which contains +a few boxes for each Builder that change color as events occur. It +uses the same @option{--master} argument as the @command{buildbot +statuslog} command (@pxref{statuslog}). + + at node try, , statusgui, Developer Tools + at subsection try + +This lets a developer to ask the question ``What would happen if I +committed this patch right now?''. It runs the unit test suite (across +multiple build platforms) on the developer's current code, allowing +them to make sure they will not break the tree when they finally +commit their changes. + +The @command{buildbot try} command is meant to be run from within a +developer's local tree, and starts by figuring out the base revision +of that tree (what revision was current the last time the tree was +updated), and a patch that can be applied to that revision of the tree +to make it match the developer's copy. This (revision, patch) pair is +then sent to the buildmaster, which runs a build with that +SourceStamp. By default, the tool will emit status messages as the +builds run, and will not terminate until the first failure has been +detected (or the last success). + +For this command to work, several pieces must be in place: + + at heading TryScheduler + +The buildmaster must have a @code{scheduler.TryScheduler} instance in +the config file's @code{c['schedulers']} list. This lets the +administrator control who may initiate these ``trial'' builds, which +branches are eligible for trial builds, and which Builders should be +used for them. + +The @code{TryScheduler} has various means to accept build requests: +all of them enforce more security than the usual buildmaster ports do. +The source code patch that is provided with the trial build could be +used to compromise the buildslave accounts: the usual force-build +control channels can waste buildslave time but do not allow arbitrary +commands to be executed (since the code must be checked out from the +VC repository). The @code{TryScheduler} requires a bit more +configuration to insure that it cannot be abused in this way. There +are currently two ways to set this up: + + at table @emph + at item ssh +create a command queue maildir in the buildmaster's space, admin sets +the ownership/permissions to only grant write access to trusted +developers. 'buildbot try' formats an rfc822-style message +(sourcestamp goes in a header, patch goes in the body) and adds it to +the queuedir. The config file entries used by 'buildbot try' either +specify a local queuedir (for which write and mv are used) or a remote +one (using scp and ssh). +: quite secure. -: requires fiddling outside +the buildmaster config. + +To implement this, the buildslave invokes 'ssh -l username host +buildbot tryserver ARGS', passing the patch contents over stdin. The +arguments must include the inlet directory and the revision +information. + + at item PB +each developer gets a username/passwd pair, known to the buildmaster. +'buildbot try' connects to the slaveport and identifies itself as that +user, then sends a PB command to force the build (with the +sourcestamp+diff as arguments). +: don't need a special group or +filesystem fiddling. -: depending upon the Cred mechanics used, the +password may be passed in plaintext or plaintext-equivalent. -: the +username/passwd list must be maintained by the buildmaster admin, +really you want it to remain equivalent to the VC system's list. + + at end table + + at heading locating the master + +The @command{try} command needs to be told how to connect to the + at code{TryScheduler}, and must know which of the authentication +approaches described above is in use by the buildmaster. You specify +the approach by using @option{--connect=ssh} or @option{--connect=pb} +(or @code{try_connect = 'ssh'} or @code{try_connect = 'pb'} in + at file{.buildbot.options}). + +For the PB approach, the command must be given a @option{--username} +and @option{--passwd} pair of arguments that match one of the entries +in the buildmaster's @code{tryusers} list. These arguments can also be +provided as @code{try_username} and @code{try_password} entries in the + at file{.buildbot/options} file. + +For the SSH approach, the command must be given @option{--tryhost}, + at option{--username}, and optionally @option{--password} (TODO: +really?) to get to the buildmaster host. It must also be given + at option{--trydir}, which points to the inlet directory configured +above. The trydir can be relative to the user's home directory, but +most of the time you will use an explicit path like + at file{~buildbot/project/trydir}. These arguments can be provided in + at file{.buildbot.options} as @code{try_host}, @code{try_username}, + at code{try_password}, and @code{try_dir}. + + at heading specifying the VC system + +The @command{try} command also needs to know how to take the +developer's current tree and extract the (revision, patch) +source-stamp pair. Each VC system uses a different process, so you +start by telling the @command{try} command which VC system you are +using, with an argument like @option{--vc=cvs} or @option{--vc=tla}. + + at heading finding the top of the tree + +Some VC systems (notably CVS and SVN) track each directory +more-or-less independently, which means the @command{try} command +needs to move up to the top of the project tree before it will be able +to construct a proper full-tree patch. To accomplish this, the + at command{try} command will crawl up through the parent directories +until it finds a marker file. The default name for this marker file is + at file{.buildbot-top}, so when you are using CVS or SVN you should + at code{touch .buildbot-top} from the top of your tree before running + at command{buildbot try}. Alternatively, you can use a filename like + at file{ChangeLog} or @file{README}, since many projects put one of +these files in their top-most directory (and nowhere else). To set +this filename, use @option{--try-topfile=ChangeLog}, or set it in the +options file with @code{try_topfile = 'ChangeLog'}. + +You can also manually set the top of the tree with + at option{--try-topdir=~/trees/mytree}, or @code{try_topdir = +'~/trees/mytree'}. If you use @code{try_topdir}, in a + at file{.buildbot/options} file, you will need a separate options file +for each tree you use, so it may be more convenient to use the + at code{try_topfile} approach instead. + +If the @command{try} command cannot find the top directory, it will +abort with an error message. Other VC systems which work on full +projects instead of individual directories (tla, baz, darcs, monotone) +do not require @command{try} to know the top directory, so the + at option{--try-topfile} and @option{--try-topdir} arguments will be +ignored. + + at heading determining the revision and patch + +Each VC system has a separate approach for determining the tree's base +revision and computing a patch. + + at table @code + + at item CVS +Wow, good question. We have to assume that you've done an @code{cvs +update} on the whole tree... [TODO] + + at item SVN + at command{try} does a @code{svn status -u} to find the latest +repository revision number (emitted on the last line in the ``Status +against revision: NN'' message). It then performs an @code{svn diff +-rNN} to find out how your tree differs from the repository version, +and sends the resulting patch to the buildmaster. If your tree is not +up to date, this will result in the ``try'' tree being created with +the latest revision, then @emph{backwards} patches applied to bring it +``back'' to the version you actually checked out (plus your actual +code changes), but this will still result in the correct tree being +used for the build. + + at item baz + at command{try} does a @code{baz tree-id} to determine the +fully-qualified version and patch identifier for the tree +(ARCHIVE/VERSION--patch-NN), and uses the VERSION--patch-NN component +as the base revision. It then does a @code{baz diff} to obtain the +patch. + + at item tla + at command{try} does a @code{tla tree-version} to get the +fully-qualified version identifier (ARCHIVE/VERSION), then takes the +first line of @code{tla logs --reverse} to figure out the base +revision. Then it does @code{tla changes --diffs} to obtain the patch. + + at item darcs + at code{darcs changes --context} emits a text file that contains a list +of all patches back to and including the last tag was made. This text +file (plus the location of a repository that contains all these +patches) is sufficient to re-create the tree. Therefore the contents +of this ``context'' file @emph{are} the revision stamp for a +Darcs-controlled source tree. + +So @command{try} does a @code{darcs changes --context} to determine +what your tree's base revision is, and then does a @code{darcs diff +-u} to compute the patch relative to that revision. + + at c TODO: monotone, git + at c TODO: new VC systems: mercurial (hg) + at end table + + at heading waiting for results + +If you provide the @option{--wait} option (or @code{try_wait = True} +in @file{.buildbot/options}), the @command{buildbot try} command will +wait until your changes have either been proven good or bad before +exiting. Unless you use the @option{--quiet} option (or + at code{try_quiet=True}), it will emit a progress message every 60 +seconds until the builds have completed. + + + at node Other Tools, .buildbot config directory, Developer Tools, Command-line tool + at section Other Tools + +These tools are generally used by buildmaster administrators. + + at menu +* sendchange:: +* debugclient:: + at end menu + + at node sendchange, debugclient, Other Tools, Other Tools + at subsection sendchange + +This command is used to tell the buildmaster about source changes. It +is intended to be used from within a commit script, installed on the +VC server. + + at example +buildbot sendchange --master @var{MASTERHOST}:@var{PORT} --username @var{USER} @var{FILENAMES..} + at end example + +There are other (optional) arguments which can influence the + at code{Change} that gets submitted: + + at table @code + at item --revision_number +This provides a (numeric) revision number for the change, used for VC systems +that use numeric transaction numbers (like Subversion). + + at item --revision +This provides a (string) revision specifier, for VC systems that use +strings (Arch would use something like patch-42, Darcs would use the +patch name, etc). + + at item --comments +This provides the change comments as a single argument. You may want +to use @option{--logfile} instead. + + at item --logfile +This instructs the tool to read the change comments from the given +file. If you use @code{-} as the filename, the tool will read the +change comments from stdin. + at end table + + + at node debugclient, , sendchange, Other Tools + at subsection debugclient + + at example +buildbot debugclient --master @var{MASTERHOST}:@var{PORT} --passwd @var{DEBUGPW} + at end example + +This launches a small Gtk+/Glade-based debug tool, connecting to the +buildmaster's ``debug port''. This debug port shares the same port +number as the slaveport (@pxref{Setting the slaveport}), but the + at code{debugPort} is only enabled if you set a debug password in the +buildmaster's config file (@pxref{Debug options}). The + at option{--passwd} option must match the @code{c['debugPassword']} +value. + + at option{--master} can also be provided in @file{.debug/options} by the + at code{master} key. @option{--passwd} can be provided by the + at code{debugPassword} key. + +The @code{Connect} button must be pressed before any of the other +buttons will be active. This establishes the connection to the +buildmaster. The other sections of the tool are as follows: + + at table @code + at item Reload .cfg +Forces the buildmaster to reload its @file{master.cfg} file. This is +equivalent to sending a SIGHUP to the buildmaster, but can be done +remotely through the debug port. Note that it is a good idea to be +watching the buildmaster's @file{twistd.log} as you reload the config +file, as any errors which are detected in the config file will be +announced there. + + at item Rebuild .py +(not yet implemented). The idea here is to use Twisted's ``rebuild'' +facilities to replace the buildmaster's running code with a new +version. Even if this worked, it would only be used by buildbot +developers. + + at item poke IRC +This locates a @code{words.IRC} status target and causes it to emit a +message on all the channels to which it is currently connected. This +was used to debug a problem in which the buildmaster lost the +connection to the IRC server and did not attempt to reconnect. + + at item Commit +This allows you to inject a Change, just as if a real one had been +delivered by whatever VC hook you are using. You can set the name of +the committed file and the name of the user who is doing the commit. +Optionally, you can also set a revision for the change. If the +revision you provide looks like a number, it will be sent as an +integer, otherwise it will be sent as a string. + + at item Force Build +This lets you force a Builder (selected by name) to start a build of +the current source tree. + + at item Currently +(obsolete). This was used to manually set the status of the given +Builder, but the status-assignment code was changed in an incompatible +way and these buttons are no longer meaningful. + + at end table + + + at node .buildbot config directory, , Other Tools, Command-line tool + at section .buildbot config directory + +Many of the @command{buildbot} tools must be told how to contact the +buildmaster that they interact with. This specification can be +provided as a command-line argument, but most of the time it will be +easier to set them in an ``options'' file. The @command{buildbot} +command will look for a special directory named @file{.buildbot}, +starting from the current directory (where the command was run) and +crawling upwards, eventually looking in the user's home directory. It +will look for a file named @file{options} in this directory, and will +evaluate it as a python script, looking for certain names to be set. +You can just put simple @code{name = 'value'} pairs in this file to +set the options. + +For a description of the names used in this file, please see the +documentation for the individual @command{buildbot} sub-commands. The +following is a brief sample of what this file's contents could be. + + at example +# for status-reading tools +masterstatus = 'buildbot.example.org:12345' +# for 'sendchange' or the debug port +master = 'buildbot.example.org:18990' +debugPassword = 'eiv7Po' + at end example + + at table @code + at item masterstatus +Location of the @code{client.PBListener} status port, used by + at command{statuslog} and @command{statusgui}. + + at item master +Location of the @code{debugPort} (for @command{debugclient}). Also the +location of the @code{pb.PBChangeSource} (for @command{sendchange}). +Usually shares the slaveport, but a future version may make it +possible to have these listen on a separate port number. + + at item debugPassword +Must match the value of @code{c['debugPassword']}, used to protect the +debug port, for the @command{debugclient} command. + + at item username +Provides a default username for the @command{sendchange} command. + + at end table + + + + at node Resources, Developer's Appendix, Command-line tool, Top @chapter Resources The Buildbot's home page is at @uref{http://buildbot.sourceforge.net/} From warner at users.sourceforge.net Tue Aug 9 00:43:37 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Tue, 09 Aug 2005 00:43:37 +0000 Subject: [Buildbot-commits] buildbot/buildbot/test test_web.py,1.20,1.21 test_status.py,1.22,1.23 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26164/buildbot/test Modified Files: test_web.py test_status.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-268 Creator: Brian Warner fix the large-logfile-hang against twisted-1.3.0 * buildbot/status/builder.py (LogFileProducer.resumeProducing): put off the actual resumeProducing for a moment with reactor.callLater(0). This works around a twisted-1.3.0 bug which causes large logfiles to hang midway through. * buildbot/test/test_status.py (Log.testMerge3): update to match new addEntry merging (>=chunkSize) behavior (Log.testConsumer): update to handle new callLater(0) behavior * buildbot/test/test_web.py: rearrange tests a bit, add test for both the MAX_LENGTH bugfix and the resumeProducing hang. --This line, and those below, will be ignored-- Files to commit: This list might be incomplete or outdated if editing the log message was not invoked from an up-to-date changes buffer! Index: test_status.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/test/test_status.py,v retrieving revision 1.22 retrieving revision 1.23 diff -u -d -r1.22 -r1.23 --- test_status.py 19 Jul 2005 23:11:59 -0000 1.22 +++ test_status.py 9 Aug 2005 00:43:35 -0000 1.23 @@ -8,7 +8,7 @@ from buildbot import interfaces from buildbot.sourcestamp import SourceStamp -from buildbot.twcompat import implements, providedBy +from buildbot.twcompat import implements, providedBy, maybeWait from buildbot.status import builder try: from buildbot.status import mail @@ -21,6 +21,18 @@ def getName(self): return "step" +class MyLogFileProducer(builder.LogFileProducer): + # The reactor.callLater(0) in LogFileProducer.resumeProducing is a bit of + # a nuisance from a testing point of view. This subclass adds a Deferred + # to that call so we can find out when it is complete. + def resumeProducing(self): + d = defer.Deferred() + reactor.callLater(0, self._resumeProducing, d) + return d + def _resumeProducing(self, d): + builder.LogFileProducer._resumeProducing(self) + reactor.callLater(0, d.callback, None) + class MyLog(builder.LogFile): def __init__(self, basedir, name, text=None, step=None): self.fakeBuilderBasedir = basedir @@ -33,6 +45,11 @@ def getFilename(self): return os.path.join(self.fakeBuilderBasedir, self.name) + def subscribeConsumer(self, consumer): + p = MyLogFileProducer(self, consumer) + d = p.resumeProducing() + return d + class MyHTMLLog(builder.HTMLLogFile): def __init__(self, basedir, name, html): step = MyStep() @@ -439,8 +456,8 @@ l.addStdout(10*"a") self.failUnlessEqual(list(l.getChunks()), [(builder.HEADER, "HEADER\n"), - (builder.STDOUT, 110*"a"), - (builder.STDOUT, 50*"a")]) + (builder.STDOUT, 100*"a"), + (builder.STDOUT, 60*"a")]) l.finish() self.failUnlessEqual(l.getText(), 160*"a") @@ -557,7 +574,10 @@ self.failUnless(l1.isFinished()) s = MyLogConsumer() - l1.subscribeConsumer(s) + d = l1.subscribeConsumer(s) + d.addCallback(self._testConsumer_1, s) + return maybeWait(d, 5) + def _testConsumer_1(self, res, s): self.failIf(s.chunks) self.failUnless(s.finished) self.failIf(s.producer) # producer should be registered and removed @@ -568,7 +588,10 @@ self.failUnless(l2.isFinished()) s = MyLogConsumer() - l2.subscribeConsumer(s) + d = l2.subscribeConsumer(s) + d.addCallback(self._testConsumer_2, s) + return d + def _testConsumer_2(self, res, s): self.failUnlessEqual(s.chunks, [(builder.HEADER, "HEADER\n")]) self.failUnless(s.finished) self.failIf(s.producer) # producer should be registered and removed @@ -584,15 +607,24 @@ l2.addStdout(200*"c") # HEADER,1600*a,1600*b on disk,200*c in memory s = MyLogConsumer(limit=1) - l2.subscribeConsumer(s) + d = l2.subscribeConsumer(s) + d.addCallback(self._testConsumer_3, l2, s) + return d + def _testConsumer_3(self, res, l2, s): self.failUnless(s.streaming) self.failUnlessEqual(s.chunks, [(builder.HEADER, "HEADER\n")]) s.limit = 1 - s.producer.resumeProducing() + d = s.producer.resumeProducing() + d.addCallback(self._testConsumer_4, l2, s) + return d + def _testConsumer_4(self, res, l2, s): self.failUnlessEqual(s.chunks, [(builder.HEADER, "HEADER\n"), (builder.STDOUT, 1600*"a")]) s.limit = None - s.producer.resumeProducing() + d = s.producer.resumeProducing() + d.addCallback(self._testConsumer_5, l2, s) + return d + def _testConsumer_5(self, res, l2, s): self.failUnlessEqual(s.chunks, [(builder.HEADER, "HEADER\n"), (builder.STDOUT, 1600*"a"), (builder.STDOUT, 1600*"b"), Index: test_web.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/test/test_web.py,v retrieving revision 1.20 retrieving revision 1.21 diff -u -d -r1.20 -r1.21 --- test_web.py 19 Jul 2005 23:51:52 -0000 1.20 +++ test_web.py 9 Aug 2005 00:43:35 -0000 1.21 @@ -1,12 +1,12 @@ # -*- test-case-name: buildbot.test.test_web -*- -import sys, os, os.path, time +import sys, os, os.path, time, shutil from twisted.python import log, components, util #log.startLogging(sys.stderr) from twisted.trial import unittest -from twisted.internet import reactor, defer +from twisted.internet import reactor, defer, protocol from twisted.internet.interfaces import IReactorUNIX from twisted.web import client @@ -71,8 +71,35 @@ def _shutdown_1(self, res): return self.r.publisher.broker.transport.loseConnection() +class SlowReader(protocol.Protocol): + didPause = False + count = 0 + data = "" + def __init__(self, req): + self.req = req + self.d = defer.Deferred() + def connectionMade(self): + self.transport.write(self.req) + def dataReceived(self, data): + self.data += data + self.count += len(data) + if not self.didPause and self.count > 10*1000: + self.didPause = True + self.transport.pauseProducing() + reactor.callLater(2, self.resume) + def resume(self): + self.transport.resumeProducing() + def connectionLost(self, why): + self.d.callback(None) -class WebTest(unittest.TestCase): +class CFactory(protocol.ClientFactory): + def __init__(self, p): + self.p = p + def buildProtocol(self, addr): + self.p.factory = self + return self.p + +class BaseWeb: master = None def failUnlessIn(self, substr, string): @@ -93,6 +120,8 @@ return filter(lambda child: isinstance(child, html.Waterfall), list(master)) +class Ports(BaseWeb, unittest.TestCase): + def test_webPortnum(self): # run a regular web server on a TCP socket config = base_config + "c['status'] = [html.Waterfall(http_port=0)]\n" @@ -151,6 +180,8 @@ self.failUnlessIn("BuildBot", page) return p.shutdown() + +class Waterfall(BaseWeb, unittest.TestCase): def test_waterfall(self): # this is the right way to configure the Waterfall status config1 = \ @@ -200,7 +231,8 @@ self.failUnlessIn("
  • Syncmail mailing list in maildir " + "my-maildir
  • ", changes) - def test_logfile(self): +class Logfile(BaseWeb, unittest.TestCase): + def setUp(self): config = """ from buildbot.status import html from buildbot.process.factory import BasicBuildFactory @@ -215,11 +247,14 @@ 'status': [html.Waterfall(http_port=0)], } """ - os.mkdir("test_web5") - self.master = m = ConfiguredMaster("test_web5", config) + if os.path.exists("test_logfile"): + shutil.rmtree("test_logfile") + os.mkdir("test_logfile") + self.master = m = ConfiguredMaster("test_logfile", config) m.startService() # hack to find out what randomly-assigned port it is listening on port = list(self.find_waterfall(m)[0])[0]._port.getHost().port + self.port = port # insert an event s = m.status.getBuilder("builder1") @@ -238,33 +273,85 @@ log2 = step1.addHTMLLog("error", "ouch") + log3 = step1.addLog("big") + log3.addStdout("big log\n") + for i in range(1000): + log3.addStdout("a" * 500) + log3.addStderr("b" * 500) + log3.finish() + + log4 = step1.addCompleteLog("bigcomplete", + "big2 log\n" + "a" * 1*1000*1000) + step1.step_status.stepFinished(builder.SUCCESS) bs.buildFinished() - d = client.getPage("http://localhost:%d/" % port) - d.addCallback(self._test_logfile_1, port) + + def test_logfile1(self): + d = client.getPage("http://localhost:%d/" % self.port) + d.addCallback(self._test_logfile1_1) return maybeWait(d) - test_logfile.timeout = 10 - def _test_logfile_1(self, page, port): + test_logfile1.timeout = 20 + def _test_logfile1_1(self, page): self.failUnless(page) - logurl = "http://localhost:%d/builder1/builds/0/setup/0" % port + def test_logfile2(self): + logurl = "http://localhost:%d/builder1/builds/0/setup/0" % self.port d = client.getPage(logurl) - d.addCallback(self._test_logfile_2, port) - return d - def _test_logfile_2(self, logbody, port): + d.addCallback(self._test_logfile2_1) + return maybeWait(d) + def _test_logfile2_1(self, logbody): self.failUnless(logbody) - logurl = "http://localhost:%d/builder1/builds/0/setup/0" % port + + def test_logfile3(self): + logurl = "http://localhost:%d/builder1/builds/0/setup/0" % self.port d = client.getPage(logurl + "/text") - d.addCallback(self._test_logfile_3, port) - return d - def _test_logfile_3(self, logtext, port): + d.addCallback(self._test_logfile3_1) + return maybeWait(d) + def _test_logfile3_1(self, logtext): self.failUnlessEqual(logtext, "some stdout\n") - logurl = "http://localhost:%d/builder1/builds/0/setup/1" % port + def test_logfile4(self): + logurl = "http://localhost:%d/builder1/builds/0/setup/1" % self.port d = client.getPage(logurl) - d.addCallback(self._test_logfile_4) - return d - def _test_logfile_4(self, logbody): + d.addCallback(self._test_logfile4_1) + return maybeWait(d) + def _test_logfile4_1(self, logbody): self.failUnlessEqual(logbody, "ouch") + def test_logfile5(self): + # this is log3, which is about 1MB in size, made up of alternating + # stdout/stderr chunks. buildbot-0.6.6, when run against + # twisted-1.3.0, fails to resume sending chunks after the client + # stalls for a few seconds, because of a recursive doWrite() call + # that was fixed in twisted-2.0.0 + p = SlowReader("GET /builder1/builds/0/setup/2 HTTP/1.0\r\n\r\n") + f = CFactory(p) + c = reactor.connectTCP("localhost", self.port, f) + d = p.d + d.addCallback(self._test_logfile5_1, p) + return maybeWait(d, 10) + test_logfile5.timeout = 10 + def _test_logfile5_1(self, res, p): + self.failUnlessIn("big log", p.data) + self.failUnlessIn("a"*100, p.data) + self.failUnless(p.count > 1*1000*1000) + + def test_logfile6(self): + # this is log4, which is about 1MB in size, one big chunk. + # buildbot-0.6.6 dies as the NetstringReceiver barfs on the + # saved logfile, because it was using one big chunk and exceeding + # NetstringReceiver.MAX_LENGTH + p = SlowReader("GET /builder1/builds/0/setup/3 HTTP/1.0\r\n\r\n") + f = CFactory(p) + c = reactor.connectTCP("localhost", self.port, f) + d = p.d + d.addCallback(self._test_logfile6_1, p) + return maybeWait(d, 10) + test_logfile6.timeout = 10 + def _test_logfile6_1(self, res, p): + self.failUnlessIn("big2 log", p.data) + self.failUnlessIn("a"*100, p.data) + self.failUnless(p.count > 1*1000*1000) + + From warner at users.sourceforge.net Tue Aug 9 00:43:37 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Tue, 09 Aug 2005 00:43:37 +0000 Subject: [Buildbot-commits] buildbot/buildbot/status builder.py,1.62,1.63 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/status In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26164/buildbot/status Modified Files: builder.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-268 Creator: Brian Warner fix the large-logfile-hang against twisted-1.3.0 * buildbot/status/builder.py (LogFileProducer.resumeProducing): put off the actual resumeProducing for a moment with reactor.callLater(0). This works around a twisted-1.3.0 bug which causes large logfiles to hang midway through. * buildbot/test/test_status.py (Log.testMerge3): update to match new addEntry merging (>=chunkSize) behavior (Log.testConsumer): update to handle new callLater(0) behavior * buildbot/test/test_web.py: rearrange tests a bit, add test for both the MAX_LENGTH bugfix and the resumeProducing hang. --This line, and those below, will be ignored-- Files to commit: This list might be incomplete or outdated if editing the log message was not invoked from an up-to-date changes buffer! Index: builder.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/status/builder.py,v retrieving revision 1.62 retrieving revision 1.63 diff -u -d -r1.62 -r1.63 --- builder.py 8 Aug 2005 21:39:46 -0000 1.62 +++ builder.py 9 Aug 2005 00:43:35 -0000 1.63 @@ -88,6 +88,7 @@ allowed to call stopProducing, pauseProducing, and resumeProducing on the producer instance it is given. """ + paused = False subscribed = False BUFFERSIZE = 2048 @@ -149,6 +150,17 @@ self.paused = True def resumeProducing(self): + # Twisted-1.3.0 has a bug which causes hangs when resumeProducing + # calls transport.write (there is a recursive loop, fixed in 2.0 in + # t.i.abstract.FileDescriptor.doWrite by setting the producerPaused + # flag *before* calling resumeProducing). To work around this, we + # just put off the real resumeProducing for a moment. This probably + # has a performance hit, but I'm going to assume that the log files + # are not retrieved frequently enough for it to be an issue. + + reactor.callLater(0, self._resumeProducing) + + def _resumeProducing(self): self.paused = False if not self.chunkGenerator: return From warner at users.sourceforge.net Tue Aug 9 00:43:37 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Tue, 09 Aug 2005 00:43:37 +0000 Subject: [Buildbot-commits] buildbot ChangeLog,1.479,1.480 Message-ID: Update of /cvsroot/buildbot/buildbot In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26164 Modified Files: ChangeLog Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-268 Creator: Brian Warner fix the large-logfile-hang against twisted-1.3.0 * buildbot/status/builder.py (LogFileProducer.resumeProducing): put off the actual resumeProducing for a moment with reactor.callLater(0). This works around a twisted-1.3.0 bug which causes large logfiles to hang midway through. * buildbot/test/test_status.py (Log.testMerge3): update to match new addEntry merging (>=chunkSize) behavior (Log.testConsumer): update to handle new callLater(0) behavior * buildbot/test/test_web.py: rearrange tests a bit, add test for both the MAX_LENGTH bugfix and the resumeProducing hang. --This line, and those below, will be ignored-- Files to commit: This list might be incomplete or outdated if editing the log message was not invoked from an up-to-date changes buffer! Index: ChangeLog =================================================================== RCS file: /cvsroot/buildbot/buildbot/ChangeLog,v retrieving revision 1.479 retrieving revision 1.480 diff -u -d -r1.479 -r1.480 --- ChangeLog 8 Aug 2005 21:39:46 -0000 1.479 +++ ChangeLog 9 Aug 2005 00:43:34 -0000 1.480 @@ -1,5 +1,17 @@ 2005-08-08 Brian Warner + * buildbot/test/test_status.py (Log.testMerge3): update to match new + addEntry merging (>=chunkSize) behavior + (Log.testConsumer): update to handle new callLater(0) behavior + + * buildbot/test/test_web.py: rearrange tests a bit, add test for + both the MAX_LENGTH bugfix and the resumeProducing hang. + + * buildbot/status/builder.py (LogFileProducer.resumeProducing): + put off the actual resumeProducing for a moment with + reactor.callLater(0). This works around a twisted-1.3.0 bug which + causes large logfiles to hang midway through. + * buildbot/process/step.py (BuildStep.addCompleteLog): break the logfile up into chunks, both to avoid NetstringReceiver.MAX_LENGTH and to improve memory usage when streaming the file out to a web From warner at users.sourceforge.net Mon Aug 8 21:39:48 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Mon, 08 Aug 2005 21:39:48 +0000 Subject: [Buildbot-commits] buildbot/buildbot/process step.py,1.67,1.68 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/process In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24661/buildbot/process Modified Files: step.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-266 Creator: Brian Warner deliver large addCompleteLog() files correctly Twisted's NetstringReceiver imposes a cap of 100k on the chunks of a LogFile, which causes problems when addCompleteLog() is used to create large LogFiles. * buildbot/process/step.py (BuildStep.addCompleteLog): break the logfile up into chunks, both to avoid NetstringReceiver.MAX_LENGTH and to improve memory usage when streaming the file out to a web browser. * buildbot/status/builder.py (LogFile.addEntry): change > to >= to make this work cleanly --This line, and those below, will be ignored-- Files to commit: This list might be incomplete or outdated if editing the log message was not invoked from an up-to-date changes buffer! Index: step.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/process/step.py,v retrieving revision 1.67 retrieving revision 1.68 diff -u -d -r1.67 -r1.68 --- step.py 19 Jul 2005 23:11:57 -0000 1.67 +++ step.py 8 Aug 2005 21:39:45 -0000 1.68 @@ -621,7 +621,9 @@ def addCompleteLog(self, name, text): log.msg("addCompleteLog(%s)" % name) loog = self.step_status.addLog(name) - loog.addStdout(text) + size = loog.chunkSize + for start in range(0, len(text), size): + loog.addStdout(text[start:start+size]) loog.finish() def addHTMLLog(self, name, html): From warner at users.sourceforge.net Mon Aug 8 21:39:48 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Mon, 08 Aug 2005 21:39:48 +0000 Subject: [Buildbot-commits] buildbot ChangeLog,1.478,1.479 Message-ID: Update of /cvsroot/buildbot/buildbot In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24661 Modified Files: ChangeLog Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-266 Creator: Brian Warner deliver large addCompleteLog() files correctly Twisted's NetstringReceiver imposes a cap of 100k on the chunks of a LogFile, which causes problems when addCompleteLog() is used to create large LogFiles. * buildbot/process/step.py (BuildStep.addCompleteLog): break the logfile up into chunks, both to avoid NetstringReceiver.MAX_LENGTH and to improve memory usage when streaming the file out to a web browser. * buildbot/status/builder.py (LogFile.addEntry): change > to >= to make this work cleanly --This line, and those below, will be ignored-- Files to commit: This list might be incomplete or outdated if editing the log message was not invoked from an up-to-date changes buffer! Index: ChangeLog =================================================================== RCS file: /cvsroot/buildbot/buildbot/ChangeLog,v retrieving revision 1.478 retrieving revision 1.479 diff -u -d -r1.478 -r1.479 --- ChangeLog 3 Aug 2005 23:47:28 -0000 1.478 +++ ChangeLog 8 Aug 2005 21:39:46 -0000 1.479 @@ -1,3 +1,12 @@ +2005-08-08 Brian Warner + + * buildbot/process/step.py (BuildStep.addCompleteLog): break the + logfile up into chunks, both to avoid NetstringReceiver.MAX_LENGTH + and to improve memory usage when streaming the file out to a web + browser. + * buildbot/status/builder.py (LogFile.addEntry): change > to >= to + make this work cleanly + 2005-08-03 Brian Warner * buildbot/trybuild.py: new file for 'try' utilities From warner at users.sourceforge.net Wed Aug 10 04:52:43 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 10 Aug 2005 04:52:43 +0000 Subject: [Buildbot-commits] buildbot ChangeLog,1.480,1.481 Message-ID: Update of /cvsroot/buildbot/buildbot In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5477 Modified Files: ChangeLog Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-270 Creator: Brian Warner add docs for 'try', some placeholder tests * docs/buildbot.texinfo (try): add docs on the as-yet-unimplemented Try scheduler * buildbot/test/test_buildreq.py: move Scheduling tests out to .. * buildbot/test/test_scheduler.py: .. here (Scheduling.testTryJobdir): add placeholder test for 'try' Index: ChangeLog =================================================================== RCS file: /cvsroot/buildbot/buildbot/ChangeLog,v retrieving revision 1.480 retrieving revision 1.481 diff -u -d -r1.480 -r1.481 --- ChangeLog 9 Aug 2005 00:43:34 -0000 1.480 +++ ChangeLog 10 Aug 2005 04:52:41 -0000 1.481 @@ -1,5 +1,12 @@ 2005-08-08 Brian Warner + * docs/buildbot.texinfo (try): add docs on the + as-yet-unimplemented Try scheduler + + * buildbot/test/test_buildreq.py: move Scheduling tests out to .. + * buildbot/test/test_scheduler.py: .. here + (Scheduling.testTryJobdir): add placeholder test for 'try' + * buildbot/test/test_status.py (Log.testMerge3): update to match new addEntry merging (>=chunkSize) behavior (Log.testConsumer): update to handle new callLater(0) behavior From warner at users.sourceforge.net Mon Aug 8 21:39:48 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Mon, 08 Aug 2005 21:39:48 +0000 Subject: [Buildbot-commits] buildbot/buildbot/status builder.py,1.61,1.62 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/status In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24661/buildbot/status Modified Files: builder.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-266 Creator: Brian Warner deliver large addCompleteLog() files correctly Twisted's NetstringReceiver imposes a cap of 100k on the chunks of a LogFile, which causes problems when addCompleteLog() is used to create large LogFiles. * buildbot/process/step.py (BuildStep.addCompleteLog): break the logfile up into chunks, both to avoid NetstringReceiver.MAX_LENGTH and to improve memory usage when streaming the file out to a web browser. * buildbot/status/builder.py (LogFile.addEntry): change > to >= to make this work cleanly --This line, and those below, will be ignored-- Files to commit: This list might be incomplete or outdated if editing the log message was not invoked from an up-to-date changes buffer! Index: builder.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/status/builder.py,v retrieving revision 1.61 retrieving revision 1.62 diff -u -d -r1.61 -r1.62 --- builder.py 19 Jul 2005 23:12:01 -0000 1.61 +++ builder.py 8 Aug 2005 21:39:46 -0000 1.62 @@ -363,7 +363,7 @@ self.merge() self.runEntries.append((channel, text)) self.runLength += len(text) - if self.runLength > self.chunkSize: + if self.runLength >= self.chunkSize: self.merge() for w in self.watchers: From warner at users.sourceforge.net Wed Aug 10 04:52:43 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 10 Aug 2005 04:52:43 +0000 Subject: [Buildbot-commits] buildbot/buildbot/test test_scheduler.py,NONE,1.1 test_buildreq.py,1.1,1.2 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5477/buildbot/test Modified Files: test_buildreq.py Added Files: test_scheduler.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-270 Creator: Brian Warner add docs for 'try', some placeholder tests * docs/buildbot.texinfo (try): add docs on the as-yet-unimplemented Try scheduler * buildbot/test/test_buildreq.py: move Scheduling tests out to .. * buildbot/test/test_scheduler.py: .. here (Scheduling.testTryJobdir): add placeholder test for 'try' Index: test_buildreq.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/test/test_buildreq.py,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- test_buildreq.py 19 Jul 2005 23:11:58 -0000 1.1 +++ test_buildreq.py 10 Aug 2005 04:52:41 -0000 1.2 @@ -1,10 +1,8 @@ # -*- test-case-name: buildbot.test.test_buildreq -*- from twisted.trial import unittest -from twisted.internet import defer, reactor -from twisted.application import service -from buildbot import buildset, scheduler, interfaces, sourcestamp +from buildbot import buildset, interfaces, sourcestamp from buildbot.twcompat import maybeWait from buildbot.process import base from buildbot.status import builder @@ -133,126 +131,3 @@ self.failUnlessEqual(res[1][0], "finished") self.failUnlessEqual(res[1][1], bss) - -class FakeMaster(service.MultiService): - def submitBuildSet(self, bs): - self.sets.append(bs) - -class Scheduling(unittest.TestCase): - def setUp(self): - self.master = master = FakeMaster() - master.sets = [] - master.startService() - - def tearDown(self): - d = self.master.stopService() - return maybeWait(d) - - def addScheduler(self, s): - s.setServiceParent(self.master) - - def testPeriodic1(self): - self.addScheduler(scheduler.Periodic("quickly", ["a","b"], 2)) - d = defer.Deferred() - reactor.callLater(5, d.callback, None) - d.addCallback(self._testPeriodic1_1) - return maybeWait(d) - def _testPeriodic1_1(self, res): - self.failUnless(len(self.master.sets) > 1) - s1 = self.master.sets[0] - self.failUnlessEqual(s1.builderNames, ["a","b"]) - - def testPeriodic2(self): - # Twisted-2.0 starts the TimerService right away - # Twisted-1.3 waits one interval before starting it. - # so don't bother asserting anything about it - raise unittest.SkipTest("twisted-1.3 and -2.0 are inconsistent") - self.addScheduler(scheduler.Periodic("hourly", ["a","b"], 3600)) - d = defer.Deferred() - reactor.callLater(1, d.callback, None) - d.addCallback(self._testPeriodic2_1) - return maybeWait(d) - def _testPeriodic2_1(self, res): - # the Periodic scheduler *should* fire right away - self.failUnless(self.master.sets) - - def isImportant(self, change): - if "important" in change.files: - return True - return False - - def testBranch(self): - s = scheduler.Scheduler("b1", "branch1", 2, ["a","b"], - fileIsImportant=self.isImportant) - self.addScheduler(s) - - c0 = Change("carol", ["important"], "other branch", branch="other") - s.addChange(c0) - self.failIf(s.timer) - self.failIf(s.importantChanges) - - c1 = Change("alice", ["important", "not important"], "some changes", - branch="branch1") - s.addChange(c1) - c2 = Change("bob", ["not important", "boring"], "some more changes", - branch="branch1") - s.addChange(c2) - c3 = Change("carol", ["important", "dull"], "even more changes", - branch="branch1") - s.addChange(c3) - - self.failUnlessEqual(s.importantChanges, [c1,c3]) - self.failUnlessEqual(s.unimportantChanges, [c2]) - self.failUnless(s.timer) - - d = defer.Deferred() - reactor.callLater(4, d.callback, None) - d.addCallback(self._testBranch_1) - return maybeWait(d) - def _testBranch_1(self, res): - self.failUnlessEqual(len(self.master.sets), 1) - s = self.master.sets[0].source - self.failUnlessEqual(s.branch, "branch1") - self.failUnlessEqual(s.revision, None) - self.failUnlessEqual(len(s.changes), 3) - self.failUnlessEqual(s.patch, None) - - - def testAnyBranch(self): - s = scheduler.AnyBranchScheduler("b1", None, 2, ["a","b"], - fileIsImportant=self.isImportant) - self.addScheduler(s) - - c1 = Change("alice", ["important", "not important"], "some changes", - branch="branch1") - s.addChange(c1) - c2 = Change("bob", ["not important", "boring"], "some more changes", - branch="branch1") - s.addChange(c2) - c3 = Change("carol", ["important", "dull"], "even more changes", - branch="branch1") - s.addChange(c3) - - c4 = Change("carol", ["important"], "other branch", branch="branch2") - s.addChange(c4) - - d = defer.Deferred() - reactor.callLater(4, d.callback, None) - d.addCallback(self._testAnyBranch_1) - return maybeWait(d) - def _testAnyBranch_1(self, res): - self.failUnlessEqual(len(self.master.sets), 2) - self.master.sets.sort(lambda a,b: cmp(a.source.branch, - b.source.branch)) - s1 = self.master.sets[0].source - self.failUnlessEqual(s1.branch, "branch1") - self.failUnlessEqual(s1.revision, None) - self.failUnlessEqual(len(s1.changes), 3) - self.failUnlessEqual(s1.patch, None) - - s2 = self.master.sets[1].source - self.failUnlessEqual(s2.branch, "branch2") - self.failUnlessEqual(s2.revision, None) - self.failUnlessEqual(len(s2.changes), 1) - self.failUnlessEqual(s2.patch, None) - --- NEW FILE: test_scheduler.py --- # -*- test-case-name: buildbot.test.test_scheduler -*- from twisted.trial import unittest from twisted.internet import defer, reactor from twisted.application import service from buildbot import scheduler from buildbot.twcompat import maybeWait from buildbot.changes.changes import Change class FakeMaster(service.MultiService): def submitBuildSet(self, bs): self.sets.append(bs) class Scheduling(unittest.TestCase): def setUp(self): self.master = master = FakeMaster() master.sets = [] master.startService() def tearDown(self): d = self.master.stopService() return maybeWait(d) def addScheduler(self, s): s.setServiceParent(self.master) def testPeriodic1(self): self.addScheduler(scheduler.Periodic("quickly", ["a","b"], 2)) d = defer.Deferred() reactor.callLater(5, d.callback, None) d.addCallback(self._testPeriodic1_1) return maybeWait(d) def _testPeriodic1_1(self, res): self.failUnless(len(self.master.sets) > 1) s1 = self.master.sets[0] self.failUnlessEqual(s1.builderNames, ["a","b"]) def testPeriodic2(self): # Twisted-2.0 starts the TimerService right away # Twisted-1.3 waits one interval before starting it. # so don't bother asserting anything about it raise unittest.SkipTest("twisted-1.3 and -2.0 are inconsistent") self.addScheduler(scheduler.Periodic("hourly", ["a","b"], 3600)) d = defer.Deferred() reactor.callLater(1, d.callback, None) d.addCallback(self._testPeriodic2_1) return maybeWait(d) def _testPeriodic2_1(self, res): # the Periodic scheduler *should* fire right away self.failUnless(self.master.sets) def isImportant(self, change): if "important" in change.files: return True return False def testBranch(self): s = scheduler.Scheduler("b1", "branch1", 2, ["a","b"], fileIsImportant=self.isImportant) self.addScheduler(s) c0 = Change("carol", ["important"], "other branch", branch="other") s.addChange(c0) self.failIf(s.timer) self.failIf(s.importantChanges) c1 = Change("alice", ["important", "not important"], "some changes", branch="branch1") s.addChange(c1) c2 = Change("bob", ["not important", "boring"], "some more changes", branch="branch1") s.addChange(c2) c3 = Change("carol", ["important", "dull"], "even more changes", branch="branch1") s.addChange(c3) self.failUnlessEqual(s.importantChanges, [c1,c3]) self.failUnlessEqual(s.unimportantChanges, [c2]) self.failUnless(s.timer) d = defer.Deferred() reactor.callLater(4, d.callback, None) d.addCallback(self._testBranch_1) return maybeWait(d) def _testBranch_1(self, res): self.failUnlessEqual(len(self.master.sets), 1) s = self.master.sets[0].source self.failUnlessEqual(s.branch, "branch1") self.failUnlessEqual(s.revision, None) self.failUnlessEqual(len(s.changes), 3) self.failUnlessEqual(s.patch, None) def testAnyBranch(self): s = scheduler.AnyBranchScheduler("b1", None, 2, ["a","b"], fileIsImportant=self.isImportant) self.addScheduler(s) c1 = Change("alice", ["important", "not important"], "some changes", branch="branch1") s.addChange(c1) c2 = Change("bob", ["not important", "boring"], "some more changes", branch="branch1") s.addChange(c2) c3 = Change("carol", ["important", "dull"], "even more changes", branch="branch1") s.addChange(c3) c4 = Change("carol", ["important"], "other branch", branch="branch2") s.addChange(c4) d = defer.Deferred() reactor.callLater(4, d.callback, None) d.addCallback(self._testAnyBranch_1) return maybeWait(d) def _testAnyBranch_1(self, res): self.failUnlessEqual(len(self.master.sets), 2) self.master.sets.sort(lambda a,b: cmp(a.source.branch, b.source.branch)) s1 = self.master.sets[0].source self.failUnlessEqual(s1.branch, "branch1") self.failUnlessEqual(s1.revision, None) self.failUnlessEqual(len(s1.changes), 3) self.failUnlessEqual(s1.patch, None) s2 = self.master.sets[1].source self.failUnlessEqual(s2.branch, "branch2") self.failUnlessEqual(s2.revision, None) self.failUnlessEqual(len(s2.changes), 1) self.failUnlessEqual(s2.patch, None) def testTryJobdir(self): raise unittest.SkipTest("not yet implemented") s = scheduler.Try_Jobdir("try1", ["a", "b"], "jobdir1") self.addScheduler(s) def testTryUserpass(self): raise unittest.SkipTest("not yet implemented") up = [("alice","pw1"), ("bob","pw2")] s = scheduler.Try_Userpass("try2", None, userpass=up) self.addScheduler(s) From warner at users.sourceforge.net Wed Aug 10 04:52:43 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 10 Aug 2005 04:52:43 +0000 Subject: [Buildbot-commits] buildbot/docs buildbot.texinfo,1.12,1.13 Message-ID: Update of /cvsroot/buildbot/buildbot/docs In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5477/docs Modified Files: buildbot.texinfo Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-270 Creator: Brian Warner add docs for 'try', some placeholder tests * docs/buildbot.texinfo (try): add docs on the as-yet-unimplemented Try scheduler * buildbot/test/test_buildreq.py: move Scheduling tests out to .. * buildbot/test/test_scheduler.py: .. here (Scheduling.testTryJobdir): add placeholder test for 'try' Index: buildbot.texinfo =================================================================== RCS file: /cvsroot/buildbot/buildbot/docs/buildbot.texinfo,v retrieving revision 1.12 retrieving revision 1.13 diff -u -d -r1.12 -r1.13 --- buildbot.texinfo 3 Aug 2005 23:47:28 -0000 1.12 +++ buildbot.texinfo 10 Aug 2005 04:52:41 -0000 1.13 @@ -3628,9 +3628,10 @@ For this command to work, several pieces must be in place: + @heading TryScheduler -The buildmaster must have a @code{scheduler.TryScheduler} instance in +The buildmaster must have a @code{scheduler.Try} instance in the config file's @code{c['schedulers']} list. This lets the administrator control who may initiate these ``trial'' builds, which branches are eligible for trial builds, and which Builders should be @@ -3638,42 +3639,105 @@ The @code{TryScheduler} has various means to accept build requests: all of them enforce more security than the usual buildmaster ports do. -The source code patch that is provided with the trial build could be -used to compromise the buildslave accounts: the usual force-build -control channels can waste buildslave time but do not allow arbitrary -commands to be executed (since the code must be checked out from the -VC repository). The @code{TryScheduler} requires a bit more -configuration to insure that it cannot be abused in this way. There -are currently two ways to set this up: +Any source code being built can be used to compromise the buildslave +accounts, but in general that code must be checked out from the VC +repository first, so only people with commit privileges can get +control of the buildslaves. The usual force-build control channels can +waste buildslave time but do not allow arbitrary commands to be +executed by people who don't have those commit privileges. However, +the source code patch that is provided with the trial build does not +have to go through the VC system first, so it is important to make +sure these builds cannot be abused by a non-committer to acquire as +much control over the buildslaves as a committer has. Ideally, only +developers who have commit access to the VC repository would be able +to start trial builds, but unfortunately the buildmaster does not, in +general, have access to VC system's user list. - at table @emph - at item ssh -create a command queue maildir in the buildmaster's space, admin sets -the ownership/permissions to only grant write access to trusted -developers. 'buildbot try' formats an rfc822-style message -(sourcestamp goes in a header, patch goes in the body) and adds it to -the queuedir. The config file entries used by 'buildbot try' either -specify a local queuedir (for which write and mv are used) or a remote -one (using scp and ssh). +: quite secure. -: requires fiddling outside -the buildmaster config. +As a result, the @code{TryScheduler} requires a bit more +configuration. There are currently two ways to set this up: + + at table @strong + at item jobdir (ssh) + +This approach creates a command queue directory, called the +``jobdir'', in the buildmaster's working directory. The buildmaster +admin sets the ownership and permissions of this directory to only +grant write access to the desired set of developers, all of whom must +have accounts on the machine. The @code{buildbot try} command creates +a special file containing the source stamp information and drops it in +the jobdir, just like a standard maildir. When the buildmaster notices +the new file, it unpacks the information inside and starts the builds. + +The config file entries used by 'buildbot try' either specify a local +queuedir (for which write and mv are used) or a remote one (using scp +and ssh). + +The advantage of this scheme is that it is quite secure, the +disadvantage is that it requires fiddling outside the buildmaster +config (to set the permissions on the jobdir correctly). If the +buildmaster machine happens to also house the VC repository, then it +can be fairly easy to keep the VC userlist in sync with the +trial-build userlist. If they are on different machines, this will be +much more of a hassle. It may also involve granting developer accounts +on a machine that would not otherwise require them. To implement this, the buildslave invokes 'ssh -l username host buildbot tryserver ARGS', passing the patch contents over stdin. The arguments must include the inlet directory and the revision information. - at item PB -each developer gets a username/passwd pair, known to the buildmaster. -'buildbot try' connects to the slaveport and identifies itself as that -user, then sends a PB command to force the build (with the -sourcestamp+diff as arguments). +: don't need a special group or -filesystem fiddling. -: depending upon the Cred mechanics used, the -password may be passed in plaintext or plaintext-equivalent. -: the -username/passwd list must be maintained by the buildmaster admin, -really you want it to remain equivalent to the VC system's list. + at item user+password (PB) + +In this approach, each developer gets a username/password pair, which +are all listed in the buildmaster's configuration file. When the +developer runs @code{buildbot try}, their machine connects to the +buildmaster via PB and authenticates themselves using that username +and password, then sends a PB command to start the trial build. + +The advantage of this scheme is that the entire configuration is +performed inside the buildmaster's config file. The disadvantages are +that it is less secure (while the ``cred'' authentication system does +not expose the password in plaintext over the wire, it does not offer +most of the other security properties that SSH does. In addition, the +buildmaster admin is responsible for maintaining the username/password +list, adding and deleting entries as developers come and go. @end table + +For example, to set up the ``jobdir'' style of trial build, using a +command queue directory of @file{MASTERDIR/jobdir} (and assuming that +all your project developers were members of the @code{developers} unix +group), you would first create that directory (with @command{mkdir +MASTERDIR/jobdir; chgrp developers MASTERDIR/jobdir; chmod g+rwx,o-rwx +MASTERDIR/jobdir}), and then use the following scheduler in the +buildmaster's config file: + + at example +from buildbot.scheduler import Try_Jobdir +s = Try_Jobdir("try1", ["full-linux", "full-netbsd", "full-OSX"], + jobdir="jobdir") +c['schedulers'] = [s] + at end example + +Note that you must create the jobdir before telling the buildmaster to +use this configuration, otherwise you will get an error. Also remember +that the buildmaster must be able to read and write to the jobdir as +well. Be sure to watch the @xref{Logfiles} as you start using the +jobdir, to make sure the buildmaster is happy with it. + +To use the username/password form of authentication, create a + at code{Try_Userpass} instance instead. It takes the same + at code{builderNames} argument as the @code{Try_Jobdir} form: + + at example +from buildbot.scheduler import Try_Userpass +s = Try_Userpass("try2", ["full-linux", "full-netbsd", "full-OSX"], + userpass=[("alice","pw1"), ("bob", "pw2")] ) +c['schedulers'] = [s] + at end example + + @heading locating the master The @command{try} command needs to be told how to connect to the From warner at users.sourceforge.net Wed Aug 10 04:52:55 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 10 Aug 2005 04:52:55 +0000 Subject: [Buildbot-commits] buildbot/docs buildbot.texinfo,1.13,1.14 Message-ID: Update of /cvsroot/buildbot/buildbot/docs In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5528/docs Modified Files: buildbot.texinfo Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-271 Creator: Brian Warner minor edit to buildbot.texinfo Index: buildbot.texinfo =================================================================== RCS file: /cvsroot/buildbot/buildbot/docs/buildbot.texinfo,v retrieving revision 1.13 retrieving revision 1.14 diff -u -d -r1.13 -r1.14 --- buildbot.texinfo 10 Aug 2005 04:52:41 -0000 1.13 +++ buildbot.texinfo 10 Aug 2005 04:52:53 -0000 1.14 @@ -3723,8 +3723,9 @@ Note that you must create the jobdir before telling the buildmaster to use this configuration, otherwise you will get an error. Also remember that the buildmaster must be able to read and write to the jobdir as -well. Be sure to watch the @xref{Logfiles} as you start using the -jobdir, to make sure the buildmaster is happy with it. +well. Be sure to watch the @file{twistd.log} file (@pxref{Logfiles}) +as you start using the jobdir, to make sure the buildmaster is happy +with it. To use the username/password form of authentication, create a @code{Try_Userpass} instance instead. It takes the same From warner at users.sourceforge.net Wed Aug 10 07:06:14 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 10 Aug 2005 07:06:14 +0000 Subject: [Buildbot-commits] buildbot/buildbot/scripts tryclient.py,NONE,1.1 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/scripts In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26773/buildbot/scripts Added Files: tryclient.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-273 Creator: Brian Warner implement Try_Jobdir, with a unit test * buildbot/scheduler.py (Try_Jobdir): implement the jobdir style of the TryScheduler, no buildsetID or status-tracking support yet * buildbot/test/test_scheduler.py (Scheduling.testTryJobdir): test it * buildbot/changes/maildir.py (Maildir.setBasedir): make it possible to set the basedir after __init__ time, so it is easier to use as a Service-child of the BuildMaster instance * buildbot/changes/maildirtwisted.py (MaildirService): make a form that delivers messages to its Service parent instead of requiring a subclass to be useful. This turns out to be much easier to build unit tests around. * buildbot/scripts/tryclient.py (createJob): utility code to create jobfiles, will eventually be used by 'buildbot try' --- NEW FILE: tryclient.py --- # -*- test-case-name: buildbot.test.test_scheduler -*- def ns(s): return "%d:%s," % (len(s), s) def createJob(bsid, branch, baserev, patchlevel, patch, builderNames): job = "" job += ns("1") job += ns(bsid) job += ns(branch) job += ns(baserev) job += ns("%d" % patchlevel) job += ns(patch) for bn in builderNames: job += ns(bn) return job From warner at users.sourceforge.net Wed Aug 10 07:06:14 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 10 Aug 2005 07:06:14 +0000 Subject: [Buildbot-commits] buildbot/docs buildbot.texinfo,1.14,1.15 Message-ID: Update of /cvsroot/buildbot/buildbot/docs In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26773/docs Modified Files: buildbot.texinfo Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-273 Creator: Brian Warner implement Try_Jobdir, with a unit test * buildbot/scheduler.py (Try_Jobdir): implement the jobdir style of the TryScheduler, no buildsetID or status-tracking support yet * buildbot/test/test_scheduler.py (Scheduling.testTryJobdir): test it * buildbot/changes/maildir.py (Maildir.setBasedir): make it possible to set the basedir after __init__ time, so it is easier to use as a Service-child of the BuildMaster instance * buildbot/changes/maildirtwisted.py (MaildirService): make a form that delivers messages to its Service parent instead of requiring a subclass to be useful. This turns out to be much easier to build unit tests around. * buildbot/scripts/tryclient.py (createJob): utility code to create jobfiles, will eventually be used by 'buildbot try' Index: buildbot.texinfo =================================================================== RCS file: /cvsroot/buildbot/buildbot/docs/buildbot.texinfo,v retrieving revision 1.14 retrieving revision 1.15 diff -u -d -r1.14 -r1.15 --- buildbot.texinfo 10 Aug 2005 04:52:53 -0000 1.14 +++ buildbot.texinfo 10 Aug 2005 07:06:11 -0000 1.15 @@ -3746,7 +3746,7 @@ approaches described above is in use by the buildmaster. You specify the approach by using @option{--connect=ssh} or @option{--connect=pb} (or @code{try_connect = 'ssh'} or @code{try_connect = 'pb'} in - at file{.buildbot.options}). + at file{.buildbot/options}). For the PB approach, the command must be given a @option{--username} and @option{--passwd} pair of arguments that match one of the entries From warner at users.sourceforge.net Wed Aug 10 07:06:14 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 10 Aug 2005 07:06:14 +0000 Subject: [Buildbot-commits] buildbot ChangeLog,1.481,1.482 Message-ID: Update of /cvsroot/buildbot/buildbot In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26773 Modified Files: ChangeLog Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-273 Creator: Brian Warner implement Try_Jobdir, with a unit test * buildbot/scheduler.py (Try_Jobdir): implement the jobdir style of the TryScheduler, no buildsetID or status-tracking support yet * buildbot/test/test_scheduler.py (Scheduling.testTryJobdir): test it * buildbot/changes/maildir.py (Maildir.setBasedir): make it possible to set the basedir after __init__ time, so it is easier to use as a Service-child of the BuildMaster instance * buildbot/changes/maildirtwisted.py (MaildirService): make a form that delivers messages to its Service parent instead of requiring a subclass to be useful. This turns out to be much easier to build unit tests around. * buildbot/scripts/tryclient.py (createJob): utility code to create jobfiles, will eventually be used by 'buildbot try' Index: ChangeLog =================================================================== RCS file: /cvsroot/buildbot/buildbot/ChangeLog,v retrieving revision 1.481 retrieving revision 1.482 diff -u -d -r1.481 -r1.482 --- ChangeLog 10 Aug 2005 04:52:41 -0000 1.481 +++ ChangeLog 10 Aug 2005 07:06:12 -0000 1.482 @@ -1,3 +1,21 @@ +2005-08-10 Brian Warner + + * buildbot/scheduler.py (Try_Jobdir): implement the jobdir style + of the TryScheduler, no buildsetID or status-tracking support yet + * buildbot/test/test_scheduler.py (Scheduling.testTryJobdir): test it + + * buildbot/changes/maildir.py (Maildir.setBasedir): make it + possible to set the basedir after __init__ time, so it is easier + to use as a Service-child of the BuildMaster instance + + * buildbot/changes/maildirtwisted.py (MaildirService): make a form + that delivers messages to its Service parent instead of requiring + a subclass to be useful. This turns out to be much easier to build + unit tests around. + + * buildbot/scripts/tryclient.py (createJob): utility code to + create jobfiles, will eventually be used by 'buildbot try' + 2005-08-08 Brian Warner * docs/buildbot.texinfo (try): add docs on the From warner at users.sourceforge.net Wed Aug 10 07:06:14 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 10 Aug 2005 07:06:14 +0000 Subject: [Buildbot-commits] buildbot/buildbot scheduler.py,1.3,1.4 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26773/buildbot Modified Files: scheduler.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-273 Creator: Brian Warner implement Try_Jobdir, with a unit test * buildbot/scheduler.py (Try_Jobdir): implement the jobdir style of the TryScheduler, no buildsetID or status-tracking support yet * buildbot/test/test_scheduler.py (Scheduling.testTryJobdir): test it * buildbot/changes/maildir.py (Maildir.setBasedir): make it possible to set the basedir after __init__ time, so it is easier to use as a Service-child of the BuildMaster instance * buildbot/changes/maildirtwisted.py (MaildirService): make a form that delivers messages to its Service parent instead of requiring a subclass to be useful. This turns out to be much easier to build unit tests around. * buildbot/scripts/tryclient.py (createJob): utility code to create jobfiles, will eventually be used by 'buildbot try' Index: scheduler.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/scheduler.py,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- scheduler.py 20 Jul 2005 04:49:06 -0000 1.3 +++ scheduler.py 10 Aug 2005 07:06:11 -0000 1.4 @@ -1,16 +1,18 @@ # -*- test-case-name: buildbot.test.test_dependencies -*- -import time +import time, os.path from twisted.internet import reactor from twisted.application import service, internet from twisted.python import log +from twisted.protocols import basic from buildbot import interfaces, buildset, util from buildbot.util import now from buildbot.status import builder from buildbot.twcompat import implements, providedBy from buildbot.sourcestamp import SourceStamp +from buildbot.changes import maildirtwisted class BaseScheduler(service.MultiService, util.ComparableMixin): @@ -302,3 +304,97 @@ bs = buildset.BuildSet(self.builderNames, SourceStamp(branch=self.branch)) self.submit(bs) + +class TryBase(service.MultiService, util.ComparableMixin): + if implements: + implements(interfaces.IScheduler) + else: + __implements__ = interfaces.IScheduler, + + def __init__(self, name, builderNames): + service.MultiService.__init__(self) + self.name = name + self.builderNames = builderNames + + +class BadJobfile(Exception): + pass + +class JobFileScanner(basic.NetstringReceiver): + def __init__(self): + self.strings = [] + self.transport = self # so transport.loseConnection works + self.error = False + + def stringReceived(self, s): + self.strings.append(s) + + def loseConnection(self): + self.error = True + +class Try_Jobdir(TryBase): + compare_attrs = ["name", "builderNames", "jobdir"] + + def __init__(self, name, builderNames, jobdir): + TryBase.__init__(self, name, builderNames) + self.jobdir = jobdir + self.watcher = maildirtwisted.MaildirService() + self.watcher.setServiceParent(self) + + def setServiceParent(self, parent): + self.watcher.setBasedir(os.path.join(parent.basedir, self.jobdir)) + TryBase.setServiceParent(self, parent) + + def parseJob(self, f): + # jobfiles are serialized build requests. Each is a list of + # serialized netstrings, in the following order: + # "1", the version number of this format + # buildsetID, arbitrary string, used to find the buildSet later + # branch name, "" for default-branch + # base revision + # patchlevel, usually "1" + # patch + # builderNames... + p = JobFileScanner() + p.dataReceived(f.read()) + if p.error: + raise BadJobfile("unable to parse netstrings") + s = p.strings + ver = s.pop(0) + if ver != "1": + raise BadJobfile("unknown version '%s'" % ver) + buildsetID, branch, baserev, patchlevel, diff = s[:5] + builderNames = s[5:] + if branch == "": + branch = None + patchlevel = int(patchlevel) + patch = (patchlevel, diff) + ss = SourceStamp(branch, baserev, patch) + return builderNames, ss + + def messageReceived(self, filename): + md = os.path.join(self.parent.basedir, self.jobdir) + path = os.path.join(md, "new", filename) + f = open(path, "r") + os.rename(os.path.join(md, "new", filename), + os.path.join(md, "cur", filename)) + try: + builderNames, ss = self.parseJob(f) + except BadJobfile: + log.msg("%s reports a bad jobfile in %s" % (self, filename)) + log.err() + return + # compare builderNames against self.builderNames + # TODO: think about this some more.. why bother restricting it? + # perhaps self.builderNames should be used as the default list + # instead of being used as a restriction? + for b in builderNames: + if not b in self.builderNames: + log.msg("%s got jobfile %s with builder %s" % (self, + filename, b)) + log.msg(" but that wasn't in our list: %s" + % (self.builderNames,)) + return + + bs = buildset.BuildSet(builderNames, ss) + self.parent.submitBuildSet(bs) From warner at users.sourceforge.net Wed Aug 10 07:06:14 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 10 Aug 2005 07:06:14 +0000 Subject: [Buildbot-commits] buildbot/buildbot/test test_scheduler.py,1.1,1.2 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26773/buildbot/test Modified Files: test_scheduler.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-273 Creator: Brian Warner implement Try_Jobdir, with a unit test * buildbot/scheduler.py (Try_Jobdir): implement the jobdir style of the TryScheduler, no buildsetID or status-tracking support yet * buildbot/test/test_scheduler.py (Scheduling.testTryJobdir): test it * buildbot/changes/maildir.py (Maildir.setBasedir): make it possible to set the basedir after __init__ time, so it is easier to use as a Service-child of the BuildMaster instance * buildbot/changes/maildirtwisted.py (MaildirService): make a form that delivers messages to its Service parent instead of requiring a subclass to be useful. This turns out to be much easier to build unit tests around. * buildbot/scripts/tryclient.py (createJob): utility code to create jobfiles, will eventually be used by 'buildbot try' Index: test_scheduler.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/test/test_scheduler.py,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- test_scheduler.py 10 Aug 2005 04:52:41 -0000 1.1 +++ test_scheduler.py 10 Aug 2005 07:06:12 -0000 1.2 @@ -1,5 +1,7 @@ # -*- test-case-name: buildbot.test.test_scheduler -*- +import os + from twisted.trial import unittest from twisted.internet import defer, reactor from twisted.application import service @@ -7,10 +9,16 @@ from buildbot import scheduler from buildbot.twcompat import maybeWait from buildbot.changes.changes import Change +from buildbot.scripts import tryclient + class FakeMaster(service.MultiService): + d = None def submitBuildSet(self, bs): self.sets.append(bs) + if self.d: + reactor.callLater(0, self.d.callback, bs) + self.d = None class Scheduling(unittest.TestCase): def setUp(self): @@ -129,11 +137,55 @@ self.failUnlessEqual(s2.revision, None) self.failUnlessEqual(len(s2.changes), 1) self.failUnlessEqual(s2.patch, None) - + + + def createMaildir(self, jobdir): + os.mkdir(jobdir) + os.mkdir(os.path.join(jobdir, "new")) + os.mkdir(os.path.join(jobdir, "cur")) + os.mkdir(os.path.join(jobdir, "tmp")) + + jobcounter = 1 + def pushJob(self, jobdir, job): + while 1: + filename = "job_%d" % self.jobcounter + self.jobcounter += 1 + if os.path.exists(os.path.join(jobdir, "new", filename)): + continue + if os.path.exists(os.path.join(jobdir, "tmp", filename)): + continue + if os.path.exists(os.path.join(jobdir, "cur", filename)): + continue + break + f = open(os.path.join(jobdir, "tmp", filename), "w") + f.write(job) + f.close() + os.rename(os.path.join(jobdir, "tmp", filename), + os.path.join(jobdir, "new", filename)) + def testTryJobdir(self): - raise unittest.SkipTest("not yet implemented") - s = scheduler.Try_Jobdir("try1", ["a", "b"], "jobdir1") + self.master.basedir = "try_jobdir" + os.mkdir(self.master.basedir) + jobdir = "jobdir1" + jobdir_abs = os.path.join(self.master.basedir, jobdir) + self.createMaildir(jobdir_abs) + s = scheduler.Try_Jobdir("try1", ["a", "b"], jobdir) self.addScheduler(s) + self.failIf(self.master.sets) + job1 = tryclient.createJob("buildsetID", + "branch1", "123", 1, "patch", + ["a", "b"]) + self.master.d = d = defer.Deferred() + self.pushJob(jobdir_abs, job1) + d.addCallback(self._testTryJobdir_1) + return maybeWait(d, 5) + testTryJobdir.timeout = 5 + def _testTryJobdir_1(self, bs): + self.failUnlessEqual(bs.builderNames, ["a", "b"]) + self.failUnlessEqual(bs.source.branch, "branch1") + self.failUnlessEqual(bs.source.revision, "123") + self.failUnlessEqual(bs.source.patch, (1, "patch")) + def testTryUserpass(self): raise unittest.SkipTest("not yet implemented") From warner at users.sourceforge.net Wed Aug 10 07:06:14 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 10 Aug 2005 07:06:14 +0000 Subject: [Buildbot-commits] buildbot/buildbot/changes maildirtwisted.py,1.2,1.3 maildir.py,1.5,1.6 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/changes In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26773/buildbot/changes Modified Files: maildirtwisted.py maildir.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-273 Creator: Brian Warner implement Try_Jobdir, with a unit test * buildbot/scheduler.py (Try_Jobdir): implement the jobdir style of the TryScheduler, no buildsetID or status-tracking support yet * buildbot/test/test_scheduler.py (Scheduling.testTryJobdir): test it * buildbot/changes/maildir.py (Maildir.setBasedir): make it possible to set the basedir after __init__ time, so it is easier to use as a Service-child of the BuildMaster instance * buildbot/changes/maildirtwisted.py (MaildirService): make a form that delivers messages to its Service parent instead of requiring a subclass to be useful. This turns out to be much easier to build unit tests around. * buildbot/scripts/tryclient.py (createJob): utility code to create jobfiles, will eventually be used by 'buildbot try' Index: maildir.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/changes/maildir.py,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- maildir.py 6 Sep 2004 00:30:08 -0000 1.5 +++ maildir.py 10 Aug 2005 07:06:11 -0000 1.6 @@ -23,19 +23,23 @@ started, it will run its .messageReceived method when a message is available. """ - def __init__(self, basedir): + def __init__(self, basedir=None): """Create the Maildir watcher. BASEDIR is the maildir directory (the one which contains new/ and tmp/) """ self.basedir = basedir - self.newdir = os.path.join(basedir, "new") self.files = [] self.pollinterval = 10 # only used if we don't have DNotify self.running = 0 self.dnotify = None - + + def setBasedir(self, basedir): + self.basedir = basedir + def start(self): """You must run start to receive any messages.""" + assert self.basedir + self.newdir = os.path.join(self.basedir, "new") if self.running: return self.running = 1 @@ -73,6 +77,7 @@ self.running = 0 def poll(self): + assert self.basedir # see what's new for f in self.files: if not os.path.isfile(os.path.join(self.newdir, f)): Index: maildirtwisted.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/changes/maildirtwisted.py,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- maildirtwisted.py 8 Dec 2003 19:06:39 -0000 1.2 +++ maildirtwisted.py 10 Aug 2005 07:06:11 -0000 1.3 @@ -13,9 +13,7 @@ from maildir import Maildir class MaildirTwisted(Maildir, service.Service): - def __init__(self, maildir): - Maildir.__init__(self, maildir) - self.timeout = None + timeout = None def startService(self): self.start() @@ -48,6 +46,20 @@ ## if self.callback: ## self.callback(filename) +class MaildirService(MaildirTwisted): + """I watch a maildir for new messages. I should be placed as the service + child of some MultiService instance. When running, I use the linux + dirwatcher API (if available) or poll for new files in the 'new' + subdirectory of my maildir path. When I discover a new message, I invoke + my parent's .messageReceived() method with the short filename of the new + message, so the full name of the new file can be obtained with + os.path.join(maildir, 'new', filename). I will not move or delete the + file on my own: the parent should do this in messageReceived(). + """ + def messageReceived(self, filename): + self.parent.messageReceived(filename) + + def test1(): class MaildirTest(MaildirTwisted): def messageReceived(self, filename): From warner at users.sourceforge.net Wed Aug 10 08:15:47 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 10 Aug 2005 08:15:47 +0000 Subject: [Buildbot-commits] buildbot ChangeLog,1.482,1.483 Message-ID: Update of /cvsroot/buildbot/buildbot In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8539 Modified Files: ChangeLog Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-275 Creator: Brian Warner jobdir-style 'try' framework is now 90% implemented * buildbot/scripts/runner.py: Add 'buildbot try' command, jobdir style is 90% done, still missing status reporting or waiting for the buildsets to finish, and it is completely untested. * buildbot/trybuild.py: delete file, move contents to .. * buildbot/scripts/tryclient.py (getSourceStamp): .. here * buildbot/test/test_vc.py: match the move Index: ChangeLog =================================================================== RCS file: /cvsroot/buildbot/buildbot/ChangeLog,v retrieving revision 1.482 retrieving revision 1.483 diff -u -d -r1.482 -r1.483 --- ChangeLog 10 Aug 2005 07:06:12 -0000 1.482 +++ ChangeLog 10 Aug 2005 08:15:44 -0000 1.483 @@ -1,5 +1,13 @@ 2005-08-10 Brian Warner + * buildbot/scripts/runner.py: Add 'buildbot try' command, jobdir + style is 90% done, still missing status reporting or waiting for + the buildsets to finish, and it is completely untested. + + * buildbot/trybuild.py: delete file, move contents to .. + * buildbot/scripts/tryclient.py (getSourceStamp): .. here + * buildbot/test/test_vc.py: match the move + * buildbot/scheduler.py (Try_Jobdir): implement the jobdir style of the TryScheduler, no buildsetID or status-tracking support yet * buildbot/test/test_scheduler.py (Scheduling.testTryJobdir): test it From warner at users.sourceforge.net Wed Aug 10 08:15:47 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 10 Aug 2005 08:15:47 +0000 Subject: [Buildbot-commits] buildbot/buildbot/test test_vc.py,1.37,1.38 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8539/buildbot/test Modified Files: test_vc.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-275 Creator: Brian Warner jobdir-style 'try' framework is now 90% implemented * buildbot/scripts/runner.py: Add 'buildbot try' command, jobdir style is 90% done, still missing status reporting or waiting for the buildsets to finish, and it is completely untested. * buildbot/trybuild.py: delete file, move contents to .. * buildbot/scripts/tryclient.py (getSourceStamp): .. here * buildbot/test/test_vc.py: match the move Index: test_vc.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/test/test_vc.py,v retrieving revision 1.37 retrieving revision 1.38 diff -u -d -r1.37 -r1.38 --- test_vc.py 3 Aug 2005 23:47:29 -0000 1.37 +++ test_vc.py 10 Aug 2005 08:15:44 -0000 1.38 @@ -13,13 +13,14 @@ from twisted.python import log #log.startLogging(sys.stderr) -from buildbot import master, interfaces, trybuild +from buildbot import master, interfaces from buildbot.slave import bot from buildbot.status.builder import SUCCESS, FAILURE from buildbot.process import step, base from buildbot.changes import changes from buildbot.sourcestamp import SourceStamp from buildbot.twcompat import maybeWait +from buildbot.scripts import tryclient # buildbot.twcompat will patch these into t.i.defer if necessary from twisted.internet.defer import waitForDeferred, deferredGenerator @@ -696,12 +697,12 @@ d.addCallback(self._doGetpatch_1, workdir) return d def _doGetpatch_1(self, res, workdir): - d = trybuild.getSourceStamp(self.vctype, workdir) + d = tryclient.getSourceStamp(self.vctype, workdir) return d def dumpPatch(self, patch): # this exists to help me figure out the right 'patchlevel' value - # should be returned by trybuild.getSourceStamp + # should be returned by tryclient.getSourceStamp n = self.mktemp() open(n,"w").write(patch) d = self.runCommand(".", ["lsdiff", n]) From warner at users.sourceforge.net Wed Aug 10 08:15:46 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 10 Aug 2005 08:15:46 +0000 Subject: [Buildbot-commits] buildbot/buildbot/scripts runner.py,1.30,1.31 tryclient.py,1.1,1.2 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/scripts In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8539/buildbot/scripts Modified Files: runner.py tryclient.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-275 Creator: Brian Warner jobdir-style 'try' framework is now 90% implemented * buildbot/scripts/runner.py: Add 'buildbot try' command, jobdir style is 90% done, still missing status reporting or waiting for the buildsets to finish, and it is completely untested. * buildbot/trybuild.py: delete file, move contents to .. * buildbot/scripts/tryclient.py (getSourceStamp): .. here * buildbot/test/test_vc.py: match the move Index: runner.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/scripts/runner.py,v retrieving revision 1.30 retrieving revision 1.31 diff -u -d -r1.30 -r1.31 --- runner.py 19 Jul 2005 23:12:01 -0000 1.30 +++ runner.py 10 Aug 2005 08:15:44 -0000 1.31 @@ -560,6 +560,58 @@ return d +class TryOptions(usage.Options): + optParameters = [ + ["connect", "c", None, + "how to reach the buildmaster, either 'ssh' or 'pb'"], + # for ssh, use --tryhost, --username, and --trydir + ["tryhost", None, None, + "the hostname (used by ssh) for the buildmaster"], + ["trydir", None, None, + "the directory (on the tryhost) where tryjobs are deposited"], + ["username", "u", None, "Username performing the trial build"], + # for PB, use --master, --username, and --passwd + ["passwd", None, None, "password for PB authentication"], + ["master", "m", None, + "Location of the buildmaster's PBListener (host:port)"], + + ["vc", None, None, + "The VC system in use, one of: cvs,svn,tla,baz,darcs"], + ] + + optFlags = [ + ["wait", None, "wait until the builds have finished"], + ] + + def getSynopsis(self): + return "Usage: buildbot try [options]" + +def doTry(config): + from buildbot.scripts import tryclient + tryclient.doTry(config) + +class TryServerOptions(usage.Options): + optParameters = [ + ["jobdir", None, None, "the jobdir (maildir) for submitting jobs"], + ] + +def doTryServer(config): + jobdir = os.path.expanduser(config["jobdir"]) + job = sys.stdin.read() + # now do a 'safecat'-style write to jobdir/tmp, then move atomically to + # jobdir/new . I'm just going to MD5 the contents and prepend a + # timestamp. + timestring = "%d" % time.time() + jobhash = md5.new(job).hexdigest() + fn = "%s-%s" % (timestring, jobhash) + tmpfile = os.path.join(jobdir, "tmp", fn) + newfile = os.path.join(jobdir, "new", fn) + f = open(tmpfile, "w") + f.write(job) + f.close() + os.rename(tmpfile, newfile) + + class Options(usage.Options): synopsis = "Usage: buildbot [command options]" @@ -585,7 +637,12 @@ ['statusgui', None, StatusClientOptions, "Display a small window showing current builder status"], - # TODO: 'try', 'watch' + ['try', None, TryOptions, + "Run a build with your local changes"], + ['tryserver', None, TryServerOptions, + "buildmaster-side 'try' support function, not for users"], + + # TODO: 'watch' ] def opt_version(self): @@ -630,3 +687,9 @@ statuslog(so) elif command == "statusgui": statusgui(so) + elif command == "try": + doTry(so) + elif command == "tryserver": + doTryServer(so) + + Index: tryclient.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/scripts/tryclient.py,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- tryclient.py 10 Aug 2005 07:06:11 -0000 1.1 +++ tryclient.py 10 Aug 2005 08:15:44 -0000 1.2 @@ -1,17 +1,200 @@ -# -*- test-case-name: buildbot.test.test_scheduler -*- +# -*- test-case-name: buildbot.test.test_scheduler,buildbot.test.test_vc -*- + +import os, re +from twisted.internet import utils, protocol, defer + +from buildbot.scripts import runner + +class SourceStampExtractor: + def __init__(self, treetop): + self.treetop = treetop + def do(self, cmd): + return utils.getProcessOutput(cmd[0], cmd[1:], env=os.environ, + path=self.treetop) + def get(self): + d = self.getBaseRevision() + d.addCallback(self.getPatch) + d.addCallback(self.done) + return d + def readPatch(self, res, patchlevel): + self.patch = (patchlevel, res) + def done(self, res): + return (self.baserev, self.patch) + +class SVNExtractor(SourceStampExtractor): + patchlevel = 0 + def getBaseRevision(self): + d = self.do(['svn', "status", "-u"]) + d.addCallback(self.parseStatus) + return d + def parseStatus(self, res): + # svn shows the base revision for each file that has been modified or + # which needs an update. You can update each file to a different + # version, so each file is displayed with its individual base + # revision. It also shows the repository-wide latest revision number + # on the last line ("Status against revision: \d+"). + + # for our purposes, we use the latest revision number as the "base" + # revision, and get a diff against that. This means we will get + # reverse-diffs for local files that need updating, but the resulting + # tree will still be correct. The only weirdness is that the baserev + # that we emit may be different than the version of the tree that we + # first checked out. + + # to do this differently would probably involve scanning the revision + # numbers to find the max (or perhaps the min) revision, and then + # using that as a base. + + for line in res.split("\n"): + m = re.search(r'^Status against revision:\s+(\d+)', line) + if m: + num = m.group(1) + self.baserev = int(num) + return + raise IndexError("Could not find 'Status against revision' in " + "SVN output: %s" % res) + def getPatch(self, res): + d = self.do(["svn", "diff", "-r%d" % self.baserev]) + d.addCallback(self.readPatch, self.patchlevel) + return d + +class BazExtractor(SourceStampExtractor): + def getBaseRevision(self): + d = self.do(["baz", "tree-id"]) + d.addCallback(self.parseStatus) + return d + def parseStatus(self, res): + self.baserev = res.strip() + def getPatch(self, res): + d = self.do(["baz", "diff"]) + d.addCallback(self.readPatch, 1) + return d + +class TlaExtractor(SourceStampExtractor): + def getBaseRevision(self): + d = self.do(["tla", "logs", "--full", "--reverse"]) + d.addCallback(self.parseStatus) + return d + def parseStatus(self, res): + lines = res.split("\n") + self.baserev = lines[0].strip() + def getPatch(self, res): + d = self.do(["tla", "changes", "--diffs"]) + d.addCallback(self.readPatch, 1) + return d + +class DarcsExtractor(SourceStampExtractor): + patchlevel = 1 + def getBaseRevision(self): + d = self.do(["darcs", "changes", "--context"]) + d.addCallback(self.parseStatus) + return d + def parseStatus(self, res): + self.baserev = res # the whole context file + def getPatch(self, res): + d = self.do(["darcs", "diff", "-u"]) + d.addCallback(self.readPatch, self.patchlevel) + return d + +def getSourceStamp(vctype, treetop): + if vctype == "cvs": + raise NotImplementedError("CVSExtractor not yet implemented") + elif vctype == "svn": + e = SVNExtractor(treetop) + elif vctype == "baz": + e = BazExtractor(treetop) + elif vctype == "tla": + e = TlaExtractor(treetop) + elif vctype == "darcs": + e = DarcsExtractor(treetop) + else: + raise KeyError("unknown vctype '%s'" % vctype) + return e.get() + def ns(s): return "%d:%s," % (len(s), s) -def createJob(bsid, branch, baserev, patchlevel, patch, builderNames): +def createJob(bsid, branch, baserev, patchlevel, diff, builderNames): job = "" job += ns("1") job += ns(bsid) job += ns(branch) job += ns(baserev) job += ns("%d" % patchlevel) - job += ns(patch) + job += ns(diff) for bn in builderNames: job += ns(bn) return job +def getTopdir(topfile, start=None): + if not start: + start = os.getcwd() + # TODO: now walk upwards from the current directory until we find this + # topfile + raise NotImplemented + +class RemoteTryPP(protocol.ProcessProtocol): + def __init__(self, job): + self.job = job + self.d = defer.Deferred() + def connectionMade(self): + self.transport.write(self.job) + self.transport.closeStdin() + def processEnded(self, status_object): + sig = status_object.value.signal + rc = status_object.value.exitCode + self.d.callback((sig, rc)) + +class Try: + def run(self, config): + opts = runner.loadOptions() + # common options + vc = config.get("vc", opts.get("try_vc")) + + if vc in ("cvs", "svn"): + # we need to find the tree-top + topdir = config.get("try_topdir", opts.get("try_topdir")) + if topdir: + treedir = os.path.expanduser(topdir) + else: + topfile = config.get("try-topfile", opts.get("try_topfile")) + treedir = getTopdir(topfile) + else: + treedir = os.getcwd() + ss = getSourceStamp(vc, treedir) + builderNames = [] # TODO?? + + wait = bool(config.get("wait", opts.get("try_wait"))) + bsid = "buildsetID" # TODO: generate a random (unique) string + + + connect = config.get('connect', opts.get('try_connect')) + if connect == "ssh": + tryhost = config.get("tryhost", opts.get("try_host")) + tryuser = config.get("username", opts.get("try_username")) + trydir = config.get("trydir", opts.get("try_dir")) + + patchlevel, diff = ss.patch + job = createJob(bsid, ss.branch or "", ss.revision, patchlevel, diff, + builderNames) + argv = ["ssh", "-l", tryuser, tryhost, + "buildbot", "tryserver", trydir] + # now run this command and feed the contents of 'job' into stdin + + pp = RemoteTryPP(job) + p = reactor.spawnProcess(pp, argv[0], argv, os.environ) + d = pp.d + return d + + def done(self, res): + reactor.stop() + + +def doTry(config): + t = Try() + d = t.run(config) + d.addBoth(t.done) + reactor.run() + + From warner at users.sourceforge.net Wed Aug 10 08:15:46 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 10 Aug 2005 08:15:46 +0000 Subject: [Buildbot-commits] buildbot/docs buildbot.texinfo,1.15,1.16 Message-ID: Update of /cvsroot/buildbot/buildbot/docs In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8539/docs Modified Files: buildbot.texinfo Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-275 Creator: Brian Warner jobdir-style 'try' framework is now 90% implemented * buildbot/scripts/runner.py: Add 'buildbot try' command, jobdir style is 90% done, still missing status reporting or waiting for the buildsets to finish, and it is completely untested. * buildbot/trybuild.py: delete file, move contents to .. * buildbot/scripts/tryclient.py (getSourceStamp): .. here * buildbot/test/test_vc.py: match the move Index: buildbot.texinfo =================================================================== RCS file: /cvsroot/buildbot/buildbot/docs/buildbot.texinfo,v retrieving revision 1.15 retrieving revision 1.16 diff -u -d -r1.15 -r1.16 --- buildbot.texinfo 10 Aug 2005 07:06:11 -0000 1.15 +++ buildbot.texinfo 10 Aug 2005 08:15:44 -0000 1.16 @@ -3771,6 +3771,8 @@ source-stamp pair. Each VC system uses a different process, so you start by telling the @command{try} command which VC system you are using, with an argument like @option{--vc=cvs} or @option{--vc=tla}. +This can also be provided as @code{try_vc} in + at file{.buildbot/options}. @heading finding the top of the tree From warner at users.sourceforge.net Wed Aug 10 08:15:47 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 10 Aug 2005 08:15:47 +0000 Subject: [Buildbot-commits] buildbot/buildbot trybuild.py,1.1,NONE Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8539/buildbot Removed Files: trybuild.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-275 Creator: Brian Warner jobdir-style 'try' framework is now 90% implemented * buildbot/scripts/runner.py: Add 'buildbot try' command, jobdir style is 90% done, still missing status reporting or waiting for the buildsets to finish, and it is completely untested. * buildbot/trybuild.py: delete file, move contents to .. * buildbot/scripts/tryclient.py (getSourceStamp): .. here * buildbot/test/test_vc.py: match the move --- trybuild.py DELETED --- From warner at users.sourceforge.net Thu Aug 11 08:22:19 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Thu, 11 Aug 2005 08:22:19 +0000 Subject: [Buildbot-commits] buildbot/buildbot/test test_scheduler.py,1.2,1.3 test_vc.py,1.38,1.39 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1125/buildbot/test Modified Files: test_scheduler.py test_vc.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-277 Creator: Brian Warner make 'try' actually work, mostly * docs/buildbot.texinfo (try): add --port argument to PB style * buildbot/scripts/tryclient.py (SourceStampExtractor): return an actual SourceStamp. Still need to extract a branch name, somehow. (Try): finish implementing the try client side, still need a UI for specifying which builders to use (Try.getopt): factor our options/config-file reading * buildbot/test/test_scheduler.py (Scheduling.testTryUserpass): test it * buildbot/test/test_vc.py: match SourceStampExtractor change * buildbot/scripts/runner.py (Options.opt_verbose): --verbose causes the twisted log to be sent to stderr * buildbot/scheduler.py (Try_Userpass): implement the PB style --This line, and those below, will be ignored-- Files to commit: This list might be incomplete or outdated if editing the log message was not invoked from an up-to-date changes buffer! Index: test_scheduler.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/test/test_scheduler.py,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- test_scheduler.py 10 Aug 2005 07:06:12 -0000 1.2 +++ test_scheduler.py 11 Aug 2005 08:22:17 -0000 1.3 @@ -5,8 +5,9 @@ from twisted.trial import unittest from twisted.internet import defer, reactor from twisted.application import service +from twisted.spread import pb -from buildbot import scheduler +from buildbot import scheduler, sourcestamp from buildbot.twcompat import maybeWait from buildbot.changes.changes import Change from buildbot.scripts import tryclient @@ -19,6 +20,7 @@ if self.d: reactor.callLater(0, self.d.callback, bs) self.d = None + return pb.Referenceable() # makes the cleanup work correctly class Scheduling(unittest.TestCase): def setUp(self): @@ -172,9 +174,9 @@ s = scheduler.Try_Jobdir("try1", ["a", "b"], jobdir) self.addScheduler(s) self.failIf(self.master.sets) - job1 = tryclient.createJob("buildsetID", - "branch1", "123", 1, "patch", - ["a", "b"]) + job1 = tryclient.createJobfile("buildsetID", + "branch1", "123", 1, "diff", + ["a", "b"]) self.master.d = d = defer.Deferred() self.pushJob(jobdir_abs, job1) d.addCallback(self._testTryJobdir_1) @@ -184,11 +186,46 @@ self.failUnlessEqual(bs.builderNames, ["a", "b"]) self.failUnlessEqual(bs.source.branch, "branch1") self.failUnlessEqual(bs.source.revision, "123") - self.failUnlessEqual(bs.source.patch, (1, "patch")) + self.failUnlessEqual(bs.source.patch, (1, "diff")) def testTryUserpass(self): - raise unittest.SkipTest("not yet implemented") up = [("alice","pw1"), ("bob","pw2")] - s = scheduler.Try_Userpass("try2", None, userpass=up) + s = scheduler.Try_Userpass("try2", ["a", "b"], 0, userpass=up) self.addScheduler(s) + port = s.getPort() + config = {'connect': 'pb', + 'username': 'alice', + 'passwd': 'pw1', + 'master': "localhost:%d" % port, + } + t = tryclient.Try(config) + ss = sourcestamp.SourceStamp("branch1", "123", (1, "diff")) + t.sourcestamp = ss + d2 = self.master.d = defer.Deferred() + d = t.deliverJob() + d.addCallback(self._testTryUserpass_1, t, d2) + return maybeWait(d, 5) + testTryUserpass.timeout = 5 + def _testTryUserpass_1(self, res, t, d2): + # at this point, the Try object should have a RemoteReference to the + # status object. The FakeMaster returns a stub. + self.failUnless(t.buildsetStatus) + d2.addCallback(self._testTryUserpass_2, t) + return d2 + def _testTryUserpass_2(self, bs, t): + # this should be the BuildSet submitted by the TryScheduler + self.failUnlessEqual(bs.builderNames, ["a", "b"]) + self.failUnlessEqual(bs.source.branch, "branch1") + self.failUnlessEqual(bs.source.revision, "123") + self.failUnlessEqual(bs.source.patch, (1, "diff")) + + t.cleanup() + + # twisted-2.0.1 (but not later versions) seems to require a reactor + # iteration before stopListening actually works. TODO: investigate + # this. + d = defer.Deferred() + reactor.callLater(0, d.callback, None) + return d + Index: test_vc.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/test/test_vc.py,v retrieving revision 1.38 retrieving revision 1.39 diff -u -d -r1.38 -r1.39 --- test_vc.py 10 Aug 2005 08:15:44 -0000 1.38 +++ test_vc.py 11 Aug 2005 08:22:17 -0000 1.39 @@ -834,8 +834,9 @@ d = self.do_getpatch("svn", "svn_trydir") d.addCallback(self._testTryGetPatch_1) return maybeWait(d) - def _testTryGetPatch_1(self, res): - baserev, (patchlevel, patch) = res + def _testTryGetPatch_1(self, ss): + baserev = ss.revision + (patchlevel, patch) = ss.patch # because of the way SVN works, the baserev we get here will be the # latest repository revision number, which could be either 3 or 4 # depending upon whether the other tests (specifically 'fix') have @@ -949,8 +950,9 @@ d = self.do_getpatch("darcs", "darcs_trydir") d.addCallback(self._testTryGetPatch_1) return maybeWait(d) - def _testTryGetPatch_1(self, res): - baserev, (patchlevel, patch) = res + def _testTryGetPatch_1(self, ss): + baserev = ss.revision + (patchlevel, patch) = ss.patch self.failUnlessIn("[initial_import\ntest at buildbot.sf.net**", baserev, "baserev was not what we expected: %s" % baserev) # the number of revisions depends upon whether we've run the 'fix' @@ -1121,8 +1123,9 @@ self.do_getpatch("tla", "tla_trydir")) d.addCallback(self._testArchTryGetPatch_1) return maybeWait(d) - def _testArchTryGetPatch_1(self, res): - baserev, (patchlevel, patch) = res + def _testArchTryGetPatch_1(self, ss): + baserev = ss.revision + (patchlevel, patch) = ss.patch rev = "test at buildbot.sf.net--testvc/testvc--mainline--1--patch-1" self.failUnlessEqual(baserev, rev) self.failUnlessIn(newfiles['try_patch'], patch, From warner at users.sourceforge.net Thu Aug 11 08:22:19 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Thu, 11 Aug 2005 08:22:19 +0000 Subject: [Buildbot-commits] buildbot/buildbot/scripts runner.py,1.31,1.32 tryclient.py,1.2,1.3 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/scripts In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1125/buildbot/scripts Modified Files: runner.py tryclient.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-277 Creator: Brian Warner make 'try' actually work, mostly * docs/buildbot.texinfo (try): add --port argument to PB style * buildbot/scripts/tryclient.py (SourceStampExtractor): return an actual SourceStamp. Still need to extract a branch name, somehow. (Try): finish implementing the try client side, still need a UI for specifying which builders to use (Try.getopt): factor our options/config-file reading * buildbot/test/test_scheduler.py (Scheduling.testTryUserpass): test it * buildbot/test/test_vc.py: match SourceStampExtractor change * buildbot/scripts/runner.py (Options.opt_verbose): --verbose causes the twisted log to be sent to stderr * buildbot/scheduler.py (Try_Userpass): implement the PB style --This line, and those below, will be ignored-- Files to commit: This list might be incomplete or outdated if editing the log message was not invoked from an up-to-date changes buffer! Index: runner.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/scripts/runner.py,v retrieving revision 1.31 retrieving revision 1.32 diff -u -d -r1.31 -r1.32 --- runner.py 10 Aug 2005 08:15:44 -0000 1.31 +++ runner.py 11 Aug 2005 08:22:16 -0000 1.32 @@ -571,9 +571,9 @@ "the directory (on the tryhost) where tryjobs are deposited"], ["username", "u", None, "Username performing the trial build"], # for PB, use --master, --username, and --passwd - ["passwd", None, None, "password for PB authentication"], ["master", "m", None, "Location of the buildmaster's PBListener (host:port)"], + ["passwd", None, None, "password for PB authentication"], ["vc", None, None, "The VC system in use, one of: cvs,svn,tla,baz,darcs"], @@ -588,7 +588,8 @@ def doTry(config): from buildbot.scripts import tryclient - tryclient.doTry(config) + t = tryclient.Try(config) + t.run() class TryServerOptions(usage.Options): optParameters = [ @@ -599,8 +600,8 @@ jobdir = os.path.expanduser(config["jobdir"]) job = sys.stdin.read() # now do a 'safecat'-style write to jobdir/tmp, then move atomically to - # jobdir/new . I'm just going to MD5 the contents and prepend a - # timestamp. + # jobdir/new . Rather than come up with a unique name randomly, I'm just + # going to MD5 the contents and prepend a timestamp. timestring = "%d" % time.time() jobhash = md5.new(job).hexdigest() fn = "%s-%s" % (timestring, jobhash) @@ -650,6 +651,10 @@ print "Buildbot version: %s" % buildbot.version usage.Options.opt_version(self) + def opt_verbose(self): + from twisted.python import log + log.startLogging(sys.stderr) + def postOptions(self): if not hasattr(self, 'subOptions'): raise usage.UsageError("must specify a command") Index: tryclient.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/scripts/tryclient.py,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- tryclient.py 10 Aug 2005 08:15:44 -0000 1.2 +++ tryclient.py 11 Aug 2005 08:22:16 -0000 1.3 @@ -1,17 +1,23 @@ # -*- test-case-name: buildbot.test.test_scheduler,buildbot.test.test_vc -*- import os, re -from twisted.internet import utils, protocol, defer +from twisted.internet import utils, protocol, defer, reactor +from twisted.spread import pb +from twisted.cred import credentials +from twisted.python import log +from buildbot.sourcestamp import SourceStamp from buildbot.scripts import runner class SourceStampExtractor: + branch = None def __init__(self, treetop): self.treetop = treetop def do(self, cmd): return utils.getProcessOutput(cmd[0], cmd[1:], env=os.environ, path=self.treetop) def get(self): + """Return a Deferred that fires with a SourceStamp instance.""" d = self.getBaseRevision() d.addCallback(self.getPatch) d.addCallback(self.done) @@ -19,7 +25,9 @@ def readPatch(self, res, patchlevel): self.patch = (patchlevel, res) def done(self, res): - return (self.baserev, self.patch) + # TODO: figure out the branch too + ss = SourceStamp(self.branch, self.baserev, self.patch) + return ss class SVNExtractor(SourceStampExtractor): patchlevel = 0 @@ -115,7 +123,7 @@ def ns(s): return "%d:%s," % (len(s), s) -def createJob(bsid, branch, baserev, patchlevel, diff, builderNames): +def createJobfile(bsid, branch, baserev, patchlevel, diff, builderNames): job = "" job += ns("1") job += ns(bsid) @@ -147,54 +155,139 @@ self.d.callback((sig, rc)) class Try: - def run(self, config): - opts = runner.loadOptions() + buildsetStatus = None + quiet = False + + def __init__(self, config): + self.config = config + self.opts = runner.loadOptions() + self.connect = self.getopt('connect', 'try_connect') + print "using '%s' connect method" % self.connect + self.builderNames = ["a", "b"] # TODO: add UI for this + + def getopt(self, config_name, options_name, default=None): + value = self.config.get(config_name) + if value is None: + value = self.opts.get(options_name) + if value is None: + value = default + assert value is not None + return value + + def createJob(self): + # returns a Deferred which fires when the job parameters have been + # created + config = self.config + opts = self.opts + self.bsid = "buildsetID" # TODO: generate a random (unique) string + # common options - vc = config.get("vc", opts.get("try_vc")) + vc = self.getopt("vc", "try_vc") if vc in ("cvs", "svn"): # we need to find the tree-top - topdir = config.get("try_topdir", opts.get("try_topdir")) + topdir = self.getopt("try_topdir", "try_topdir") if topdir: treedir = os.path.expanduser(topdir) else: - topfile = config.get("try-topfile", opts.get("try_topfile")) + topfile = self.getopt("try-topfile", "try_topfile") treedir = getTopdir(topfile) else: treedir = os.getcwd() - ss = getSourceStamp(vc, treedir) - builderNames = [] # TODO?? - - wait = bool(config.get("wait", opts.get("try_wait"))) - bsid = "buildsetID" # TODO: generate a random (unique) string + d = getSourceStamp(vc, treedir) + d.addCallback(self._createJob_1) + return d + def _createJob_1(self, ss): + self.sourcestamp = ss + if self.connect == "ssh": + patchlevel, diff = ss.patch + self.jobfile = createJobfile(bsid, ss.branch or "", ss.revision, + patchlevel, diff, + self.builderNames) + def deliverJob(self): + # returns a Deferred that fires when the job has been delivered + config = self.config + opts = self.opts - connect = config.get('connect', opts.get('try_connect')) - if connect == "ssh": - tryhost = config.get("tryhost", opts.get("try_host")) - tryuser = config.get("username", opts.get("try_username")) - trydir = config.get("trydir", opts.get("try_dir")) + if self.connect == "ssh": + tryhost = self.getopt("tryhost", "try_host") + tryuser = self.getopt("username", "try_username") + trydir = self.getopt("trydir", "try_dir") - patchlevel, diff = ss.patch - job = createJob(bsid, ss.branch or "", ss.revision, patchlevel, diff, - builderNames) argv = ["ssh", "-l", tryuser, tryhost, "buildbot", "tryserver", trydir] # now run this command and feed the contents of 'job' into stdin - pp = RemoteTryPP(job) + pp = RemoteTryPP(self.jobfile) p = reactor.spawnProcess(pp, argv[0], argv, os.environ) d = pp.d return d + if self.connect == "pb": + user = self.getopt("username", "try_username") + passwd = self.getopt("passwd", "try_password") + master = self.getopt("master", "try_master") + tryhost, tryport = master.split(":") + tryport = int(tryport) + f = pb.PBClientFactory() + d = f.login(credentials.UsernamePassword(user, passwd)) + reactor.connectTCP(tryhost, tryport, f) + d.addCallback(self._deliverJob_pb) + return d + raise RuntimeError("unknown connecttype '%s', should be 'ssh' or 'pb'" + % self.connect) - def done(self, res): - reactor.stop() + def _deliverJob_pb(self, remote): + ss = self.sourcestamp + d = remote.callRemote("try", + ss.branch, ss.revision, ss.patch, + self.builderNames) + d.addCallback(self._deliverJob_pb2) + return d + def _deliverJob_pb2(self, status): + self.buildsetStatus = status + return status + def getStatus(self): + # returns a Deferred that fires when the builds have finished, and + # may emit status messages while we wait + wait = bool(self.getopt("wait", "try_wait", False)) + if not self.buildsetStatus: + # contact the status port, acquire a remotereference to the + # corresponding BuildSetStatus object. + pass + pass + + def announce(self, message): + if not self.quiet: + print message + + def run(self): + # we can't do spawnProcess until we're inside reactor.run(), so get + # funky + d = defer.Deferred() + d.addCallback(lambda res: self.createJob()) + d.addCallback(lambda res: self.announce("job created")) + d.addCallback(lambda res: self.deliverJob()) + d.addCallback(lambda res: self.announce("job has been delivered")) + d.addCallback(lambda res: self.getStatus()) + d.addCallback(lambda res: self.announce("status object acquired")) + d.addErrback(log.err) + d.addCallback(self.cleanup) + d.addCallback(lambda res: reactor.stop()) + + reactor.callLater(0, d.callback, None) + reactor.run() + + def logErr(self, why): + log.err(why) + print "error during 'try' processing" + print why + + def cleanup(self, res=None): + print "cleaning up" + if self.buildsetStatus: + self.buildsetStatus.broker.transport.loseConnection() -def doTry(config): - t = Try() - d = t.run(config) - d.addBoth(t.done) - reactor.run() From warner at users.sourceforge.net Thu Aug 11 08:22:19 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Thu, 11 Aug 2005 08:22:19 +0000 Subject: [Buildbot-commits] buildbot/docs buildbot.texinfo,1.16,1.17 Message-ID: Update of /cvsroot/buildbot/buildbot/docs In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1125/docs Modified Files: buildbot.texinfo Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-277 Creator: Brian Warner make 'try' actually work, mostly * docs/buildbot.texinfo (try): add --port argument to PB style * buildbot/scripts/tryclient.py (SourceStampExtractor): return an actual SourceStamp. Still need to extract a branch name, somehow. (Try): finish implementing the try client side, still need a UI for specifying which builders to use (Try.getopt): factor our options/config-file reading * buildbot/test/test_scheduler.py (Scheduling.testTryUserpass): test it * buildbot/test/test_vc.py: match SourceStampExtractor change * buildbot/scripts/runner.py (Options.opt_verbose): --verbose causes the twisted log to be sent to stderr * buildbot/scheduler.py (Try_Userpass): implement the PB style --This line, and those below, will be ignored-- Files to commit: This list might be incomplete or outdated if editing the log message was not invoked from an up-to-date changes buffer! Index: buildbot.texinfo =================================================================== RCS file: /cvsroot/buildbot/buildbot/docs/buildbot.texinfo,v retrieving revision 1.16 retrieving revision 1.17 diff -u -d -r1.16 -r1.17 --- buildbot.texinfo 10 Aug 2005 08:15:44 -0000 1.16 +++ buildbot.texinfo 11 Aug 2005 08:22:17 -0000 1.17 @@ -3729,12 +3729,15 @@ To use the username/password form of authentication, create a @code{Try_Userpass} instance instead. It takes the same - at code{builderNames} argument as the @code{Try_Jobdir} form: + at code{builderNames} argument as the @code{Try_Jobdir} form, but +accepts an addtional @code{port} argument (to specify the TCP port to +listen on) and a @code{userpass} list of username/password pairs to +accept: @example from buildbot.scheduler import Try_Userpass s = Try_Userpass("try2", ["full-linux", "full-netbsd", "full-OSX"], - userpass=[("alice","pw1"), ("bob", "pw2")] ) + port=8031, userpass=[("alice","pw1"), ("bob", "pw2")] ) c['schedulers'] = [s] @end example @@ -3748,10 +3751,13 @@ (or @code{try_connect = 'ssh'} or @code{try_connect = 'pb'} in @file{.buildbot/options}). -For the PB approach, the command must be given a @option{--username} -and @option{--passwd} pair of arguments that match one of the entries -in the buildmaster's @code{tryusers} list. These arguments can also be -provided as @code{try_username} and @code{try_password} entries in the +For the PB approach, the command must be given a @option{--master} +argument (in the form HOST:PORT) that points to TCP port that you +picked in the @code{Try_Userpass} scheduler. It also takes a + at option{--username} and @option{--passwd} pair of arguments that match +one of the entries in the buildmaster's @code{userpass} list. These +arguments can also be provided as @code{try_master}, + at code{try_username}, and @code{try_password} entries in the @file{.buildbot/options} file. For the SSH approach, the command must be given @option{--tryhost}, From warner at users.sourceforge.net Thu Aug 11 08:22:19 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Thu, 11 Aug 2005 08:22:19 +0000 Subject: [Buildbot-commits] buildbot/buildbot scheduler.py,1.4,1.5 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1125/buildbot Modified Files: scheduler.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-277 Creator: Brian Warner make 'try' actually work, mostly * docs/buildbot.texinfo (try): add --port argument to PB style * buildbot/scripts/tryclient.py (SourceStampExtractor): return an actual SourceStamp. Still need to extract a branch name, somehow. (Try): finish implementing the try client side, still need a UI for specifying which builders to use (Try.getopt): factor our options/config-file reading * buildbot/test/test_scheduler.py (Scheduling.testTryUserpass): test it * buildbot/test/test_vc.py: match SourceStampExtractor change * buildbot/scripts/runner.py (Options.opt_verbose): --verbose causes the twisted log to be sent to stderr * buildbot/scheduler.py (Try_Userpass): implement the PB style --This line, and those below, will be ignored-- Files to commit: This list might be incomplete or outdated if editing the log message was not invoked from an up-to-date changes buffer! Index: scheduler.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/scheduler.py,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- scheduler.py 10 Aug 2005 07:06:11 -0000 1.4 +++ scheduler.py 11 Aug 2005 08:22:17 -0000 1.5 @@ -6,8 +6,10 @@ from twisted.application import service, internet from twisted.python import log from twisted.protocols import basic +from twisted.cred import portal, checkers +from twisted.spread import pb -from buildbot import interfaces, buildset, util +from buildbot import interfaces, buildset, util, pbutil from buildbot.util import now from buildbot.status import builder from buildbot.twcompat import implements, providedBy @@ -309,13 +311,17 @@ if implements: implements(interfaces.IScheduler) else: - __implements__ = interfaces.IScheduler, + __implements__ = (interfaces.IScheduler, + service.MultiService.__implements__) def __init__(self, name, builderNames): service.MultiService.__init__(self) self.name = name self.builderNames = builderNames + def listBuilderNames(self): + return self.builderNames + class BadJobfile(Exception): pass @@ -398,3 +404,61 @@ bs = buildset.BuildSet(builderNames, ss) self.parent.submitBuildSet(bs) + +class Try_Userpass(TryBase): + compare_attrs = ["name", "builderNames", "port", "userpass"] + + if implements: + implements(portal.IRealm) + else: + __implements__ = (portal.IRealm, + TryBase.__implements__) + + def __init__(self, name, builderNames, port, userpass): + TryBase.__init__(self, name, builderNames) + self.port = port + self.userpass = userpass + c = checkers.InMemoryUsernamePasswordDatabaseDontUse() + for user,passwd in self.userpass: + c.addUser(user, passwd) + + p = portal.Portal(self) + p.registerChecker(c) + f = pb.PBServerFactory(p) + s = internet.TCPServer(port, f) + s.setServiceParent(self) + + def getPort(self): + # utility method for tests: figure out which TCP port we just opened. + return self.services[0]._port.getHost().port + + def requestAvatar(self, avatarID, mind, interface): + log.msg("%s got connection from user %s" % (self, avatarID)) + assert interface == pb.IPerspective + p = Try_Userpass_Perspective(self, avatarID) + return (pb.IPerspective, p, lambda: None) + + def submitBuildSet(self, bs): + return self.parent.submitBuildSet(bs) + +class Try_Userpass_Perspective(pbutil.NewCredPerspective): + def __init__(self, parent, username): + self.parent = parent + self.username = username + + def perspective_try(self, branch, revision, patch, builderNames): + log.msg("user %s requesting build on builders %s" % (self.username, + builderNames)) + for b in builderNames: + if not b in self.parent.builderNames: + log.msg("%s got job with builder %s" % (self, b)) + log.msg(" but that wasn't in our list: %s" + % (self.parent.builderNames,)) + return + ss = SourceStamp(branch, revision, patch) + bs = buildset.BuildSet(builderNames, ss) + bss = self.parent.submitBuildSet(bs) + + # TODO: return a remotely-usable BuildSetStatus object + return bss + From warner at users.sourceforge.net Thu Aug 11 08:28:44 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Thu, 11 Aug 2005 08:28:44 +0000 Subject: [Buildbot-commits] buildbot ChangeLog,1.483,1.484 Message-ID: Update of /cvsroot/buildbot/buildbot In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2462 Modified Files: ChangeLog Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-279 Creator: Brian Warner oops, add Changelog --This line, and those below, will be ignored-- Files to commit: This list might be incomplete or outdated if editing the log message was not invoked from an up-to-date changes buffer! Index: ChangeLog =================================================================== RCS file: /cvsroot/buildbot/buildbot/ChangeLog,v retrieving revision 1.483 retrieving revision 1.484 diff -u -d -r1.483 -r1.484 --- ChangeLog 10 Aug 2005 08:15:44 -0000 1.483 +++ ChangeLog 11 Aug 2005 08:28:42 -0000 1.484 @@ -1,3 +1,21 @@ +2005-08-11 Brian Warner + + * docs/buildbot.texinfo (try): add --port argument to PB style + + * buildbot/scripts/tryclient.py (SourceStampExtractor): return an + actual SourceStamp. Still need to extract a branch name, somehow. + (Try): finish implementing the try client side, still need a UI + for specifying which builders to use + (Try.getopt): factor our options/config-file reading + * buildbot/test/test_scheduler.py (Scheduling.testTryUserpass): + test it + * buildbot/test/test_vc.py: match SourceStampExtractor change + + * buildbot/scripts/runner.py (Options.opt_verbose): --verbose + causes the twisted log to be sent to stderr + + * buildbot/scheduler.py (Try_Userpass): implement the PB style + 2005-08-10 Brian Warner * buildbot/scripts/runner.py: Add 'buildbot try' command, jobdir From warner at users.sourceforge.net Thu Aug 11 19:48:53 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Thu, 11 Aug 2005 19:48:53 +0000 Subject: [Buildbot-commits] site manual-CVS.html,1.1,1.2 Message-ID: Update of /cvsroot/buildbot/site In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22645 Modified Files: manual-CVS.html Log Message: update Index: manual-CVS.html =================================================================== RCS file: /cvsroot/buildbot/site/manual-CVS.html,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- manual-CVS.html 20 Jul 2005 07:22:20 -0000 1.1 +++ manual-CVS.html 11 Aug 2005 19:48:49 -0000 1.2 @@ -150,7 +150,23 @@
  • 7.0.3 PBListener
  • -
  • 8 Resources +
  • 8 Command-line tool + +
  • 9 Resources
  • Developer's Appendix
  • Index
  • @@ -185,8 +201,9 @@
  • Getting Source Code Changes: Discovering when to run a build.
  • Build Process: Controlling how each build is run.
  • Status Delivery: Telling the world about the build's results. -
  • Resources: Getting help. -
  • Developer's Appendix +
  • Command-line tool +
  • Resources: Getting help. +
  • Developer's Appendix
  • Index: Complete index.
  • @@ -372,6 +389,33 @@
  • IRC Bot
  • PBListener +
  • +

    Command-line tool + +

    + +

    Developer Tools + +

    + +

    Other Tools + +

    +
    @@ -3728,7 +3772,7 @@


    -Next: , +Next: , Previous: Build Process, Up: Top
    @@ -3873,13 +3917,584 @@


    -Next: , +Next: , Previous: Status Delivery, Up: Top
    -

    8 Resources

    +

    8 Command-line tool

    + +

    The buildbot command-line tool can be used to start or stop a +buildmaster or buildbot, and to interact with a running buildmaster. +Some of its subcommands are intended for buildmaster admins, while +some are for developers who are editing the code that the buildbot is +monitoring. + +

    + +
    +


    +Next: , +Previous: Command-line tool, +Up: Command-line tool +
    +
    + +

    8.1 Administrator Tools

    + +

    The following buildbot sub-commands are intended for +buildmaster administrators: + +

    master

    + +

    This creates a new directory and populates it with files that allow it +to be used as a buildmaster's base directory. + +

         buildbot master BASEDIR
    +
    +

    slave

    + +

    This creates a new directory and populates it with files that let it +be used as a buildslave's base directory. You must provide several +arguments, which are used to create the initial buildbot.tac +file. + +

         buildbot slave BASEDIR MASTERHOST:PORT SLAVENAME PASSWORD
    +
    +

    start

    + +

    This starts a buildmaster or buildslave which was already created in +the given base directory. The daemon is launched in the background, +with events logged to a file named twistd.log. + +

         buildbot start BASEDIR
    +
    +

    stop

    + +

    This terminates the daemon (either buildmaster or buildslave) running +in the given directory. + +

         buildbot stop BASEDIR
    +
    +

    sighup

    + +

    This sends a SIGHUP to the buildmaster running in the given directory, +which causes it to re-read its master.cfg file. + +

         buildbot sighup BASEDIR
    +
    +
    +


    +Next: , +Previous: Administrator Tools, +Up: Command-line tool +
    +
    + +

    8.2 Developer Tools

    + +

    These tools are provided for use by the developers who are working on +the code that the buildbot is monitoring. + +

    + +
    +


    +Next: , +Previous: Developer Tools, +Up: Developer Tools +
    +
    + +

    8.2.1 statuslog

    + +
         buildbot statuslog --master MASTERHOST:PORT
    +
    +

    This command starts a simple text-based status client, one which just +prints out a new line each time an event occurs on the buildmaster. + +

    The --master option provides the location of the +client.PBListener status port, used to deliver build +information to realtime status clients. The option is always in the +form of a string, with hostname and port number separated by a colon +(HOSTNAME:PORTNUM). Note that this port is not the same +as the slaveport (although a future version may allow the same port +number to be used for both purposes). + +

    The --master option can also be provided by the +masterstatus name in .buildbot/options (see .buildbot config directory). + +

    +


    +Next: , +Previous: statuslog, +Up: Developer Tools +
    +
    + +

    8.2.2 statusgui

    + +
         buildbot statusgui --master MASTERHOST:PORT
    +
    +

    This command starts a simple Gtk+-based status client, which contains +a few boxes for each Builder that change color as events occur. It +uses the same --master argument as the buildbot +statuslog command (see statuslog). + +

    +


    +Previous: statusgui, +Up: Developer Tools +
    +
    + +

    8.2.3 try

    + +

    This lets a developer to ask the question “What would happen if I +committed this patch right now?”. It runs the unit test suite (across +multiple build platforms) on the developer's current code, allowing +them to make sure they will not break the tree when they finally +commit their changes. + +

    The buildbot try command is meant to be run from within a +developer's local tree, and starts by figuring out the base revision +of that tree (what revision was current the last time the tree was +updated), and a patch that can be applied to that revision of the tree +to make it match the developer's copy. This (revision, patch) pair is +then sent to the buildmaster, which runs a build with that +SourceStamp. By default, the tool will emit status messages as the +builds run, and will not terminate until the first failure has been +detected (or the last success). + +

    For this command to work, several pieces must be in place: + +

    TryScheduler

    + +

    The buildmaster must have a scheduler.Try instance in +the config file's c['schedulers'] list. This lets the +administrator control who may initiate these “trial” builds, which +branches are eligible for trial builds, and which Builders should be +used for them. + +

    The TryScheduler has various means to accept build requests: +all of them enforce more security than the usual buildmaster ports do. +Any source code being built can be used to compromise the buildslave +accounts, but in general that code must be checked out from the VC +repository first, so only people with commit privileges can get +control of the buildslaves. The usual force-build control channels can +waste buildslave time but do not allow arbitrary commands to be +executed by people who don't have those commit privileges. However, +the source code patch that is provided with the trial build does not +have to go through the VC system first, so it is important to make +sure these builds cannot be abused by a non-committer to acquire as +much control over the buildslaves as a committer has. Ideally, only +developers who have commit access to the VC repository would be able +to start trial builds, but unfortunately the buildmaster does not, in +general, have access to VC system's user list. + +

    As a result, the TryScheduler requires a bit more +configuration. There are currently two ways to set this up: + +

    +
    jobdir (ssh)
    +This approach creates a command queue directory, called the +“jobdir”, in the buildmaster's working directory. The buildmaster +admin sets the ownership and permissions of this directory to only +grant write access to the desired set of developers, all of whom must +have accounts on the machine. The buildbot try command creates +a special file containing the source stamp information and drops it in +the jobdir, just like a standard maildir. When the buildmaster notices +the new file, it unpacks the information inside and starts the builds. + +

    The config file entries used by 'buildbot try' either specify a local +queuedir (for which write and mv are used) or a remote one (using scp +and ssh). + +

    The advantage of this scheme is that it is quite secure, the +disadvantage is that it requires fiddling outside the buildmaster +config (to set the permissions on the jobdir correctly). If the +buildmaster machine happens to also house the VC repository, then it +can be fairly easy to keep the VC userlist in sync with the +trial-build userlist. If they are on different machines, this will be +much more of a hassle. It may also involve granting developer accounts +on a machine that would not otherwise require them. + +

    To implement this, the buildslave invokes 'ssh -l username host +buildbot tryserver ARGS', passing the patch contents over stdin. The +arguments must include the inlet directory and the revision +information. + +

    user+password (PB)
    +In this approach, each developer gets a username/password pair, which +are all listed in the buildmaster's configuration file. When the +developer runs buildbot try, their machine connects to the +buildmaster via PB and authenticates themselves using that username +and password, then sends a PB command to start the trial build. + +

    The advantage of this scheme is that the entire configuration is +performed inside the buildmaster's config file. The disadvantages are +that it is less secure (while the “cred” authentication system does +not expose the password in plaintext over the wire, it does not offer +most of the other security properties that SSH does. In addition, the +buildmaster admin is responsible for maintaining the username/password +list, adding and deleting entries as developers come and go. + +

    + +

    For example, to set up the “jobdir” style of trial build, using a +command queue directory of MASTERDIR/jobdir (and assuming that +all your project developers were members of the developers unix +group), you would first create that directory (with mkdir +MASTERDIR/jobdir; chgrp developers MASTERDIR/jobdir; chmod g+rwx,o-rwx +MASTERDIR/jobdir), and then use the following scheduler in the +buildmaster's config file: + +

         from buildbot.scheduler import Try_Jobdir
    +     s = Try_Jobdir("try1", ["full-linux", "full-netbsd", "full-OSX"],
    +                    jobdir="jobdir")
    +     c['schedulers'] = [s]
    +
    +

    Note that you must create the jobdir before telling the buildmaster to +use this configuration, otherwise you will get an error. Also remember +that the buildmaster must be able to read and write to the jobdir as +well. Be sure to watch the twistd.log file (see Logfiles) +as you start using the jobdir, to make sure the buildmaster is happy +with it. + +

    To use the username/password form of authentication, create a +Try_Userpass instance instead. It takes the same +builderNames argument as the Try_Jobdir form, but +accepts an addtional port argument (to specify the TCP port to +listen on) and a userpass list of username/password pairs to +accept: + +

         from buildbot.scheduler import Try_Userpass
    +     s = Try_Userpass("try2", ["full-linux", "full-netbsd", "full-OSX"],
    +                      port=8031, userpass=[("alice","pw1"), ("bob", "pw2")] )
    +     c['schedulers'] = [s]
    +
    +

    locating the master

    + +

    The try command needs to be told how to connect to the +TryScheduler, and must know which of the authentication +approaches described above is in use by the buildmaster. You specify +the approach by using --connect=ssh or --connect=pb +(or try_connect = 'ssh' or try_connect = 'pb' in +.buildbot/options). + +

    For the PB approach, the command must be given a --master +argument (in the form HOST:PORT) that points to TCP port that you +picked in the Try_Userpass scheduler. It also takes a +--username and --passwd pair of arguments that match +one of the entries in the buildmaster's userpass list. These +arguments can also be provided as try_master, +try_username, and try_password entries in the +.buildbot/options file. + +

    For the SSH approach, the command must be given --tryhost, +--username, and optionally --password (TODO: +really?) to get to the buildmaster host. It must also be given +--trydir, which points to the inlet directory configured +above. The trydir can be relative to the user's home directory, but +most of the time you will use an explicit path like +~buildbot/project/trydir. These arguments can be provided in +.buildbot/options as try_host, try_username, +try_password, and try_dir. + +

    choosing the Builders

    + +

    A trial build is performed on multiple Builders at the same time, and +the developer gets to choose which Builders are used (limited to a set +selected by the buildmaster admin with the TryScheduler's +builderNames= argument). The set you choose will depend upon +what your goals are: if you are concerned about cross-platform +compatibility, you should use multiple Builders, one from each +platform of interest. You might use just one builder if that platform +has libraries or other facilities that allow better test coverage than +what you can accomplish on your own machine, or faster test runs. + +

    The set of Builders to use can be specified with multiple +--builder arguments on the command line. It can also be +specified with a single try_builders option in +.buildbot/options that uses a list of strings to specify all +the Builder names: + +

         try_builders = ["full-OSX", "full-win32", "full-linux"]
    +
    +

    specifying the VC system

    + +

    The try command also needs to know how to take the +developer's current tree and extract the (revision, patch) +source-stamp pair. Each VC system uses a different process, so you +start by telling the try command which VC system you are +using, with an argument like --vc=cvs or --vc=tla. +This can also be provided as try_vc in +.buildbot/options. + +

    finding the top of the tree

    + +

    Some VC systems (notably CVS and SVN) track each directory +more-or-less independently, which means the try command +needs to move up to the top of the project tree before it will be able +to construct a proper full-tree patch. To accomplish this, the +try command will crawl up through the parent directories +until it finds a marker file. The default name for this marker file is +.buildbot-top, so when you are using CVS or SVN you should +touch .buildbot-top from the top of your tree before running +buildbot try. Alternatively, you can use a filename like +ChangeLog or README, since many projects put one of +these files in their top-most directory (and nowhere else). To set +this filename, use --try-topfile=ChangeLog, or set it in the +options file with try_topfile = 'ChangeLog'. + +

    You can also manually set the top of the tree with +--try-topdir=~/trees/mytree, or try_topdir = +'~/trees/mytree'. If you use try_topdir, in a +.buildbot/options file, you will need a separate options file +for each tree you use, so it may be more convenient to use the +try_topfile approach instead. + +

    If the try command cannot find the top directory, it will +abort with an error message. Other VC systems which work on full +projects instead of individual directories (tla, baz, darcs, monotone) +do not require try to know the top directory, so the +--try-topfile and --try-topdir arguments will be +ignored. + +

    determining the revision and patch

    + +

    Each VC system has a separate approach for determining the tree's base +revision and computing a patch. + +

    +
    CVS
    Wow, good question. We have to assume that you've done an cvs +update on the whole tree... [TODO] + +
    SVN
    try does a svn status -u to find the latest +repository revision number (emitted on the last line in the “Status +against revision: NN” message). It then performs an svn diff +-rNN to find out how your tree differs from the repository version, +and sends the resulting patch to the buildmaster. If your tree is not +up to date, this will result in the “try” tree being created with +the latest revision, then backwards patches applied to bring it +“back” to the version you actually checked out (plus your actual +code changes), but this will still result in the correct tree being +used for the build. + +
    baz
    try does a baz tree-id to determine the +fully-qualified version and patch identifier for the tree +(ARCHIVE/VERSION–patch-NN), and uses the VERSION–patch-NN component +as the base revision. It then does a baz diff to obtain the +patch. + +
    tla
    try does a tla tree-version to get the +fully-qualified version identifier (ARCHIVE/VERSION), then takes the +first line of tla logs --reverse to figure out the base +revision. Then it does tla changes --diffs to obtain the patch. + +
    darcs
    darcs changes --context emits a text file that contains a list +of all patches back to and including the last tag was made. This text +file (plus the location of a repository that contains all these +patches) is sufficient to re-create the tree. Therefore the contents +of this “context” file are the revision stamp for a +Darcs-controlled source tree. + +

    So try does a darcs changes --context to determine +what your tree's base revision is, and then does a darcs diff +-u to compute the patch relative to that revision. + + + +

    + +

    waiting for results

    + +

    If you provide the --wait option (or try_wait = True +in .buildbot/options), the buildbot try command will +wait until your changes have either been proven good or bad before +exiting. Unless you use the --quiet option (or +try_quiet=True), it will emit a progress message every 60 +seconds until the builds have completed. + +

    + +

    8.3 Other Tools

    + +

    These tools are generally used by buildmaster administrators. + +

    + +
    +


    +Next: , +Previous: Other Tools, +Up: Other Tools +
    +
    + +

    8.3.1 sendchange

    + +

    This command is used to tell the buildmaster about source changes. It +is intended to be used from within a commit script, installed on the +VC server. + +

         buildbot sendchange --master MASTERHOST:PORT --username USER FILENAMES..
    +
    +

    There are other (optional) arguments which can influence the +Change that gets submitted: + +

    +
    --revision_number
    This provides a (numeric) revision number for the change, used for VC systems +that use numeric transaction numbers (like Subversion). + +
    --revision
    This provides a (string) revision specifier, for VC systems that use +strings (Arch would use something like patch-42, Darcs would use the +patch name, etc). + +
    --comments
    This provides the change comments as a single argument. You may want +to use --logfile instead. + +
    --logfile
    This instructs the tool to read the change comments from the given +file. If you use - as the filename, the tool will read the +change comments from stdin. +
    + +
    +


    +Previous: sendchange, +Up: Other Tools +
    +
    + +

    8.3.2 debugclient

    + +
         buildbot debugclient --master MASTERHOST:PORT --passwd DEBUGPW
    +
    +

    This launches a small Gtk+/Glade-based debug tool, connecting to the +buildmaster's “debug port”. This debug port shares the same port +number as the slaveport (see Setting the slaveport), but the +debugPort is only enabled if you set a debug password in the +buildmaster's config file (see Debug options). The +--passwd option must match the c['debugPassword'] +value. + +

    --master can also be provided in .debug/options by the +master key. --passwd can be provided by the +debugPassword key. + +

    The Connect button must be pressed before any of the other +buttons will be active. This establishes the connection to the +buildmaster. The other sections of the tool are as follows: + +

    +
    Reload .cfg
    Forces the buildmaster to reload its master.cfg file. This is +equivalent to sending a SIGHUP to the buildmaster, but can be done +remotely through the debug port. Note that it is a good idea to be +watching the buildmaster's twistd.log as you reload the config +file, as any errors which are detected in the config file will be +announced there. + +
    Rebuild .py
    (not yet implemented). The idea here is to use Twisted's “rebuild” +facilities to replace the buildmaster's running code with a new +version. Even if this worked, it would only be used by buildbot +developers. + +
    poke IRC
    This locates a words.IRC status target and causes it to emit a +message on all the channels to which it is currently connected. This +was used to debug a problem in which the buildmaster lost the +connection to the IRC server and did not attempt to reconnect. + +
    Commit
    This allows you to inject a Change, just as if a real one had been +delivered by whatever VC hook you are using. You can set the name of +the committed file and the name of the user who is doing the commit. +Optionally, you can also set a revision for the change. If the +revision you provide looks like a number, it will be sent as an +integer, otherwise it will be sent as a string. + +
    Force Build
    This lets you force a Builder (selected by name) to start a build of +the current source tree. + +
    Currently
    (obsolete). This was used to manually set the status of the given +Builder, but the status-assignment code was changed in an incompatible +way and these buttons are no longer meaningful. + +
    + +
    +


    +Previous: Other Tools, +Up: Command-line tool +
    +
    + +

    8.4 .buildbot config directory

    + +

    Many of the buildbot tools must be told how to contact the +buildmaster that they interact with. This specification can be +provided as a command-line argument, but most of the time it will be +easier to set them in an “options” file. The buildbot +command will look for a special directory named .buildbot, +starting from the current directory (where the command was run) and +crawling upwards, eventually looking in the user's home directory. It +will look for a file named options in this directory, and will +evaluate it as a python script, looking for certain names to be set. +You can just put simple name = 'value' pairs in this file to +set the options. + +

    For a description of the names used in this file, please see the +documentation for the individual buildbot sub-commands. The +following is a brief sample of what this file's contents could be. + +

         # for status-reading tools
    +     masterstatus = 'buildbot.example.org:12345'
    +     # for 'sendchange' or the debug port
    +     master = 'buildbot.example.org:18990'
    +     debugPassword = 'eiv7Po'
    +
    +
    +
    masterstatus
    Location of the client.PBListener status port, used by +statuslog and statusgui. + +
    master
    Location of the debugPort (for debugclient). Also the +location of the pb.PBChangeSource (for sendchange). +Usually shares the slaveport, but a future version may make it +possible to have these listen on a separate port number. + +
    debugPassword
    Must match the value of c['debugPassword'], used to protect the +debug port, for the debugclient command. + +
    username
    Provides a default username for the sendchange command. + +
    + +
    +


    +Next: , +Previous: Command-line tool, +Up: Top +
    +
    + +

    9 Resources

    The Buildbot's home page is at http://buildbot.sourceforge.net/ From warner at users.sourceforge.net Thu Aug 11 20:21:34 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Thu, 11 Aug 2005 20:21:34 +0000 Subject: [Buildbot-commits] buildbot/buildbot/test test_runner.py,1.8,1.9 test_scheduler.py,1.3,1.4 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29870/buildbot/test Modified Files: test_runner.py test_scheduler.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-281 Creator: Brian Warner add --builder control to 'buildbot try' * docs/buildbot.texinfo (try): document both --builder and 'try_builders' in .buildbot/options * buildbot/scripts/runner.py (TryOptions): add --builder, accumulate the values into opts['builders'] * buildbot/scripts/tryclient.py (Try.__init__): set builders * buildbot/test/test_runner.py (Try): add some quick tests to make sure 'buildbot try --options' and .buildbot/options get parsed * buildbot/test/test_scheduler.py (Scheduling.testTryUserpass): use --builder control --This line, and those below, will be ignored-- Files to commit: This list might be incomplete or outdated if editing the log message was not invoked from an up-to-date changes buffer! Index: test_runner.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/test/test_runner.py,v retrieving revision 1.8 retrieving revision 1.9 diff -u -d -r1.8 -r1.9 --- test_runner.py 22 May 2005 02:16:13 -0000 1.8 +++ test_runner.py 11 Aug 2005 20:21:30 -0000 1.9 @@ -3,9 +3,9 @@ from twisted.trial import unittest from twisted.python import runtime -import os, os.path +import os, os.path, shutil -from buildbot.scripts import runner +from buildbot.scripts import runner, tryclient class Options(unittest.TestCase): optionsFile = "SDFsfsFSdfsfsFSD" @@ -191,3 +191,49 @@ make = open(os.path.join(basedir, "Makefile.sample"), "rt").read() self.failUnlessEqual(make, oldmake, "*should* rewrite Makefile.sample") + +class Try(unittest.TestCase): + # test some aspects of the 'buildbot try' command + def makeOptions(self, contents): + if os.path.exists(".buildbot"): + shutil.rmtree(".buildbot") + os.mkdir(".buildbot") + open(os.path.join(".buildbot", "options"), "w").write(contents) + + def testGetopt1(self): + opts = "try_connect = 'ssh'\n" + "try_builders = ['a']\n" + self.makeOptions(opts) + config = runner.TryOptions() + config.parseOptions([]) + t = tryclient.Try(config) + self.failUnlessEqual(t.connect, "ssh") + self.failUnlessEqual(t.builderNames, ['a']) + + def testGetopt2(self): + opts = "" + self.makeOptions(opts) + config = runner.TryOptions() + config.parseOptions(['--connect=ssh', '--builder', 'a']) + t = tryclient.Try(config) + self.failUnlessEqual(t.connect, "ssh") + self.failUnlessEqual(t.builderNames, ['a']) + + def testGetopt3(self): + opts = "" + self.makeOptions(opts) + config = runner.TryOptions() + config.parseOptions(['--connect=ssh', + '--builder', 'a', '--builder=b']) + t = tryclient.Try(config) + self.failUnlessEqual(t.connect, "ssh") + self.failUnlessEqual(t.builderNames, ['a', 'b']) + + def testGetopt4(self): + opts = "try_connect = 'ssh'\n" + "try_builders = ['a']\n" + self.makeOptions(opts) + config = runner.TryOptions() + config.parseOptions(['--builder=b']) + t = tryclient.Try(config) + self.failUnlessEqual(t.connect, "ssh") + self.failUnlessEqual(t.builderNames, ['b']) + Index: test_scheduler.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/test/test_scheduler.py,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- test_scheduler.py 11 Aug 2005 08:22:17 -0000 1.3 +++ test_scheduler.py 11 Aug 2005 20:21:30 -0000 1.4 @@ -198,6 +198,7 @@ 'username': 'alice', 'passwd': 'pw1', 'master': "localhost:%d" % port, + 'builders': ["a", "b"], } t = tryclient.Try(config) ss = sourcestamp.SourceStamp("branch1", "123", (1, "diff")) From warner at users.sourceforge.net Thu Aug 11 20:21:35 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Thu, 11 Aug 2005 20:21:35 +0000 Subject: [Buildbot-commits] buildbot/docs buildbot.texinfo,1.17,1.18 Message-ID: Update of /cvsroot/buildbot/buildbot/docs In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29870/docs Modified Files: buildbot.texinfo Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-281 Creator: Brian Warner add --builder control to 'buildbot try' * docs/buildbot.texinfo (try): document both --builder and 'try_builders' in .buildbot/options * buildbot/scripts/runner.py (TryOptions): add --builder, accumulate the values into opts['builders'] * buildbot/scripts/tryclient.py (Try.__init__): set builders * buildbot/test/test_runner.py (Try): add some quick tests to make sure 'buildbot try --options' and .buildbot/options get parsed * buildbot/test/test_scheduler.py (Scheduling.testTryUserpass): use --builder control --This line, and those below, will be ignored-- Files to commit: This list might be incomplete or outdated if editing the log message was not invoked from an up-to-date changes buffer! Index: buildbot.texinfo =================================================================== RCS file: /cvsroot/buildbot/buildbot/docs/buildbot.texinfo,v retrieving revision 1.17 retrieving revision 1.18 diff -u -d -r1.17 -r1.18 --- buildbot.texinfo 11 Aug 2005 08:22:17 -0000 1.17 +++ buildbot.texinfo 11 Aug 2005 20:21:31 -0000 1.18 @@ -3767,9 +3767,31 @@ above. The trydir can be relative to the user's home directory, but most of the time you will use an explicit path like @file{~buildbot/project/trydir}. These arguments can be provided in - at file{.buildbot.options} as @code{try_host}, @code{try_username}, + at file{.buildbot/options} as @code{try_host}, @code{try_username}, @code{try_password}, and @code{try_dir}. + at heading choosing the Builders + +A trial build is performed on multiple Builders at the same time, and +the developer gets to choose which Builders are used (limited to a set +selected by the buildmaster admin with the TryScheduler's + at code{builderNames=} argument). The set you choose will depend upon +what your goals are: if you are concerned about cross-platform +compatibility, you should use multiple Builders, one from each +platform of interest. You might use just one builder if that platform +has libraries or other facilities that allow better test coverage than +what you can accomplish on your own machine, or faster test runs. + +The set of Builders to use can be specified with multiple + at option{--builder} arguments on the command line. It can also be +specified with a single @code{try_builders} option in + at file{.buildbot/options} that uses a list of strings to specify all +the Builder names: + + at example +try_builders = ["full-OSX", "full-win32", "full-linux"] + at end example + @heading specifying the VC system The @command{try} command also needs to know how to take the From warner at users.sourceforge.net Thu Aug 11 20:21:35 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Thu, 11 Aug 2005 20:21:35 +0000 Subject: [Buildbot-commits] buildbot/buildbot/scripts runner.py,1.32,1.33 tryclient.py,1.3,1.4 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/scripts In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29870/buildbot/scripts Modified Files: runner.py tryclient.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-281 Creator: Brian Warner add --builder control to 'buildbot try' * docs/buildbot.texinfo (try): document both --builder and 'try_builders' in .buildbot/options * buildbot/scripts/runner.py (TryOptions): add --builder, accumulate the values into opts['builders'] * buildbot/scripts/tryclient.py (Try.__init__): set builders * buildbot/test/test_runner.py (Try): add some quick tests to make sure 'buildbot try --options' and .buildbot/options get parsed * buildbot/test/test_scheduler.py (Scheduling.testTryUserpass): use --builder control --This line, and those below, will be ignored-- Files to commit: This list might be incomplete or outdated if editing the log message was not invoked from an up-to-date changes buffer! Index: runner.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/scripts/runner.py,v retrieving revision 1.32 retrieving revision 1.33 diff -u -d -r1.32 -r1.33 --- runner.py 11 Aug 2005 08:22:16 -0000 1.32 +++ runner.py 11 Aug 2005 20:21:30 -0000 1.33 @@ -577,12 +577,22 @@ ["vc", None, None, "The VC system in use, one of: cvs,svn,tla,baz,darcs"], + + ["builder", "b", None, + "Run the trial build on this Builder. Can be used multiple times."], ] optFlags = [ ["wait", None, "wait until the builds have finished"], ] + def __init__(self): + super(TryOptions, self).__init__() + self['builders'] = [] + + def opt_builder(self, option): + self['builders'].append(option) + def getSynopsis(self): return "Usage: buildbot try [options]" Index: tryclient.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/scripts/tryclient.py,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- tryclient.py 11 Aug 2005 08:22:16 -0000 1.3 +++ tryclient.py 11 Aug 2005 20:21:30 -0000 1.4 @@ -162,14 +162,15 @@ self.config = config self.opts = runner.loadOptions() self.connect = self.getopt('connect', 'try_connect') - print "using '%s' connect method" % self.connect - self.builderNames = ["a", "b"] # TODO: add UI for this + self.builderNames = self.getopt('builders', 'try_builders') + assert self.builderNames, "no builders! use --builder or " \ + "try_builders=[names..] in .buildbot/options" def getopt(self, config_name, options_name, default=None): value = self.config.get(config_name) - if value is None: + if value is None or value == []: value = self.opts.get(options_name) - if value is None: + if value is None or value == []: value = default assert value is not None return value @@ -265,6 +266,7 @@ def run(self): # we can't do spawnProcess until we're inside reactor.run(), so get # funky + print "using '%s' connect method" % self.connect d = defer.Deferred() d.addCallback(lambda res: self.createJob()) d.addCallback(lambda res: self.announce("job created")) From warner at users.sourceforge.net Thu Aug 11 20:21:36 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Thu, 11 Aug 2005 20:21:36 +0000 Subject: [Buildbot-commits] buildbot ChangeLog,1.484,1.485 Message-ID: Update of /cvsroot/buildbot/buildbot In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29870 Modified Files: ChangeLog Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-281 Creator: Brian Warner add --builder control to 'buildbot try' * docs/buildbot.texinfo (try): document both --builder and 'try_builders' in .buildbot/options * buildbot/scripts/runner.py (TryOptions): add --builder, accumulate the values into opts['builders'] * buildbot/scripts/tryclient.py (Try.__init__): set builders * buildbot/test/test_runner.py (Try): add some quick tests to make sure 'buildbot try --options' and .buildbot/options get parsed * buildbot/test/test_scheduler.py (Scheduling.testTryUserpass): use --builder control --This line, and those below, will be ignored-- Files to commit: This list might be incomplete or outdated if editing the log message was not invoked from an up-to-date changes buffer! Index: ChangeLog =================================================================== RCS file: /cvsroot/buildbot/buildbot/ChangeLog,v retrieving revision 1.484 retrieving revision 1.485 diff -u -d -r1.484 -r1.485 --- ChangeLog 11 Aug 2005 08:28:42 -0000 1.484 +++ ChangeLog 11 Aug 2005 20:21:32 -0000 1.485 @@ -1,5 +1,15 @@ 2005-08-11 Brian Warner + * docs/buildbot.texinfo (try): document both --builder and + 'try_builders' in .buildbot/options + * buildbot/scripts/runner.py (TryOptions): add --builder, + accumulate the values into opts['builders'] + * buildbot/scripts/tryclient.py (Try.__init__): set builders + * buildbot/test/test_runner.py (Try): add some quick tests to make + sure 'buildbot try --options' and .buildbot/options get parsed + * buildbot/test/test_scheduler.py (Scheduling.testTryUserpass): + use --builder control + * docs/buildbot.texinfo (try): add --port argument to PB style * buildbot/scripts/tryclient.py (SourceStampExtractor): return an From warner at users.sourceforge.net Thu Aug 11 20:27:51 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Thu, 11 Aug 2005 20:27:51 +0000 Subject: [Buildbot-commits] buildbot ChangeLog,1.485,1.486 Message-ID: Update of /cvsroot/buildbot/buildbot In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31428 Modified Files: ChangeLog Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-283 Creator: Brian Warner s/%x/%d/ for id() to avoid silly warning * buildbot/locks.py: use %d for id() instead of %x, avoid a silly warning message --This line, and those below, will be ignored-- Files to commit: This list might be incomplete or outdated if editing the log message was not invoked from an up-to-date changes buffer! Index: ChangeLog =================================================================== RCS file: /cvsroot/buildbot/buildbot/ChangeLog,v retrieving revision 1.485 retrieving revision 1.486 diff -u -d -r1.485 -r1.486 --- ChangeLog 11 Aug 2005 20:21:32 -0000 1.485 +++ ChangeLog 11 Aug 2005 20:27:48 -0000 1.486 @@ -1,5 +1,8 @@ 2005-08-11 Brian Warner + * buildbot/locks.py: use %d for id() instead of %x, avoid a silly + warning message + * docs/buildbot.texinfo (try): document both --builder and 'try_builders' in .buildbot/options * buildbot/scripts/runner.py (TryOptions): add --builder, From warner at users.sourceforge.net Thu Aug 11 20:27:50 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Thu, 11 Aug 2005 20:27:50 +0000 Subject: [Buildbot-commits] buildbot/buildbot locks.py,1.2,1.3 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31428/buildbot Modified Files: locks.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-283 Creator: Brian Warner s/%x/%d/ for id() to avoid silly warning * buildbot/locks.py: use %d for id() instead of %x, avoid a silly warning message --This line, and those below, will be ignored-- Files to commit: This list might be incomplete or outdated if editing the log message was not invoked from an up-to-date changes buffer! Index: locks.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/locks.py,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- locks.py 20 Jul 2005 08:08:24 -0000 1.2 +++ locks.py 11 Aug 2005 20:27:48 -0000 1.3 @@ -51,7 +51,7 @@ compare_attrs = ['name'] def __init__(self, name): BaseLock.__init__(self, name) - self.description = "" % (name, id(self)) + self.description = "" % (name, id(self)) def getLock(self, slave): return self @@ -66,7 +66,7 @@ slavename = slavebuilder.slave.slavename if not self.locks.has_key(slavename): lock = self.locks[slavename] = BaseLock(self.name) - lock.description = "" % (self.name, + lock.description = "" % (self.name, slavename, id(lock)) self.locks[slavename] = lock From warner at users.sourceforge.net Thu Aug 11 21:58:44 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Thu, 11 Aug 2005 21:58:44 +0000 Subject: [Buildbot-commits] buildbot/buildbot/status words.py,1.38,1.39 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/status In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv17945/buildbot/status Modified Files: words.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-285 Creator: Brian Warner repair bitrot in the IRC status bot * buildbot/master.py (DebugPerspective.perspective_pokeIRC): fix this, it got broken at some point in the last few releases * buildbot/status/words.py (IrcBuildRequest): reply was broken (IrcStatusBot.emit_status): handle new IBuilderStatus.getState, specifically the removal of ETA information from the tuple Index: words.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/status/words.py,v retrieving revision 1.38 retrieving revision 1.39 diff -u -d -r1.38 -r1.39 --- words.py 19 Jul 2005 23:12:01 -0000 1.38 +++ words.py 11 Aug 2005 21:58:42 -0000 1.39 @@ -50,10 +50,11 @@ response = "build #%d forced" % s.getNumber() if eta is not None: response = "build forced [ETA %s]" % self.parent.convertTime(eta) - self.parent.reply(reply, response) - self.parent.reply(reply, "I'll give a shout when the build finishes") + self.parent.reply(self.reply, response) + self.parent.reply(self.reply, + "I'll give a shout when the build finishes") d = s.waitUntilFinished() - d.addCallback(self.parent.buildFinished, reply) + d.addCallback(self.parent.buildFinished, self.reply) class IrcStatusBot(irc.IRCClient): @@ -351,7 +352,7 @@ def emit_status(self, reply, which): b = self.getBuilder(which) str = "%s: " % which - state, ETA, build = b.getState() + state, build = b.getState() str += state if state == "idle": last = b.getLastFinishedBuild() @@ -359,13 +360,12 @@ start,finished = last.getTimes() str += ", last build %s secs ago: %s" % \ (int(util.now() - finished), " ".join(last.getText())) - if state == "waiting": - str += " [next build in %s]" % self.convertTime(ETA) if state == "building": build = b.getCurrentBuild() assert build step = build.getCurrentStep() str += " (%s)" % " ".join(step.getText()) + ETA = build.getETA() if ETA is not None: str += " [ETA %s]" % self.convertTime(ETA) self.reply(reply, str) From warner at users.sourceforge.net Thu Aug 11 21:58:44 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Thu, 11 Aug 2005 21:58:44 +0000 Subject: [Buildbot-commits] buildbot ChangeLog,1.486,1.487 Message-ID: Update of /cvsroot/buildbot/buildbot In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv17945 Modified Files: ChangeLog Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-285 Creator: Brian Warner repair bitrot in the IRC status bot * buildbot/master.py (DebugPerspective.perspective_pokeIRC): fix this, it got broken at some point in the last few releases * buildbot/status/words.py (IrcBuildRequest): reply was broken (IrcStatusBot.emit_status): handle new IBuilderStatus.getState, specifically the removal of ETA information from the tuple Index: ChangeLog =================================================================== RCS file: /cvsroot/buildbot/buildbot/ChangeLog,v retrieving revision 1.486 retrieving revision 1.487 diff -u -d -r1.486 -r1.487 --- ChangeLog 11 Aug 2005 20:27:48 -0000 1.486 +++ ChangeLog 11 Aug 2005 21:58:41 -0000 1.487 @@ -1,5 +1,11 @@ 2005-08-11 Brian Warner + * buildbot/master.py (DebugPerspective.perspective_pokeIRC): fix + this, it got broken at some point in the last few releases + * buildbot/status/words.py (IrcBuildRequest): reply was broken + (IrcStatusBot.emit_status): handle new IBuilderStatus.getState, + specifically the removal of ETA information from the tuple + * buildbot/locks.py: use %d for id() instead of %x, avoid a silly warning message From warner at users.sourceforge.net Thu Aug 11 21:58:43 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Thu, 11 Aug 2005 21:58:43 +0000 Subject: [Buildbot-commits] buildbot/buildbot master.py,1.78,1.79 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv17945/buildbot Modified Files: master.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-285 Creator: Brian Warner repair bitrot in the IRC status bot * buildbot/master.py (DebugPerspective.perspective_pokeIRC): fix this, it got broken at some point in the last few releases * buildbot/status/words.py (IrcBuildRequest): reply was broken (IrcStatusBot.emit_status): handle new IBuilderStatus.getState, specifically the removal of ETA information from the tuple Index: master.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/master.py,v retrieving revision 1.78 retrieving revision 1.79 diff -u -d -r1.78 -r1.79 --- master.py 20 Jul 2005 05:36:55 -0000 1.78 +++ master.py 11 Aug 2005 21:58:41 -0000 1.79 @@ -449,11 +449,13 @@ self.master.loadTheConfigFile() def perspective_pokeIRC(self): print "saying something on IRC" - for bot in self.master.ircFactory.allBots.values(): - print "bot", bot - for channel in bot.channels: - print "channel", channel - bot.msg("#%s" % channel, "Ow, quit it") + from buildbot.status import words + for s in self.master: + if isinstance(s, words.IRC): + bot = s.f + for channel in bot.channels: + print " channel", channel + bot.p.msg(channel, "Ow, quit it") def perspective_print(self, msg): print "debug", msg From warner at users.sourceforge.net Mon Aug 15 18:05:09 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Mon, 15 Aug 2005 18:05:09 +0000 Subject: [Buildbot-commits] buildbot/docs buildbot.texinfo,1.18,1.19 Message-ID: Update of /cvsroot/buildbot/buildbot/docs In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26903/docs Modified Files: buildbot.texinfo Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-287 Creator: Brian Warner rewrite test_vc, make 'try' work for Darcs * buildbot/scripts/tryclient.py (getSourceStamp): extract branches where we can (Arch), add a branch= argument to set the branch used when we can't (BazExtractor): extract the branch too (TlaExtractor): same * buildbot/scripts/runner.py (TryOptions): add --branch * docs/buildbot.texinfo (try): document --branch/try_branch * buildbot/slave/commands.py (Darcs): implement get-revision for Darcs, so that 'try' will work. This requires the tempfile module from python-2.3 . * buildbot/test/test_vc.py: rewrite tests, getting better coverage of revisions, branches, and 'try' in the process. Index: buildbot.texinfo =================================================================== RCS file: /cvsroot/buildbot/buildbot/docs/buildbot.texinfo,v retrieving revision 1.18 retrieving revision 1.19 diff -u -d -r1.18 -r1.19 --- buildbot.texinfo 11 Aug 2005 20:21:31 -0000 1.18 +++ buildbot.texinfo 15 Aug 2005 18:05:06 -0000 1.19 @@ -3832,6 +3832,16 @@ @option{--try-topfile} and @option{--try-topdir} arguments will be ignored. + at heading determining the branch name + +Some VC systems record the branch information in a way that ``try'' +can locate it, in particular Arch (both @command{tla} and + at command{baz}). For the others, if you are using something other than +the default branch, you will have to tell the buildbot which branch +your tree is using. You can do this with either the @option{--branch} +argument, or a @option{try_branch} entry in the + at file{.buildbot/options} file. + @heading determining the revision and patch Each VC system has a separate approach for determining the tree's base From warner at users.sourceforge.net Mon Aug 15 18:05:09 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Mon, 15 Aug 2005 18:05:09 +0000 Subject: [Buildbot-commits] buildbot ChangeLog,1.487,1.488 Message-ID: Update of /cvsroot/buildbot/buildbot In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26903 Modified Files: ChangeLog Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-287 Creator: Brian Warner rewrite test_vc, make 'try' work for Darcs * buildbot/scripts/tryclient.py (getSourceStamp): extract branches where we can (Arch), add a branch= argument to set the branch used when we can't (BazExtractor): extract the branch too (TlaExtractor): same * buildbot/scripts/runner.py (TryOptions): add --branch * docs/buildbot.texinfo (try): document --branch/try_branch * buildbot/slave/commands.py (Darcs): implement get-revision for Darcs, so that 'try' will work. This requires the tempfile module from python-2.3 . * buildbot/test/test_vc.py: rewrite tests, getting better coverage of revisions, branches, and 'try' in the process. Index: ChangeLog =================================================================== RCS file: /cvsroot/buildbot/buildbot/ChangeLog,v retrieving revision 1.487 retrieving revision 1.488 diff -u -d -r1.487 -r1.488 --- ChangeLog 11 Aug 2005 21:58:41 -0000 1.487 +++ ChangeLog 15 Aug 2005 18:05:07 -0000 1.488 @@ -1,3 +1,20 @@ +2005-08-15 Brian Warner + + * buildbot/scripts/tryclient.py (getSourceStamp): extract branches + where we can (Arch), add a branch= argument to set the branch used + when we can't + (BazExtractor): extract the branch too + (TlaExtractor): same + * buildbot/scripts/runner.py (TryOptions): add --branch + * docs/buildbot.texinfo (try): document --branch/try_branch + + * buildbot/slave/commands.py (Darcs): implement get-revision for + Darcs, so that 'try' will work. This requires the tempfile module + from python-2.3 . + + * buildbot/test/test_vc.py: rewrite tests, getting better coverage + of revisions, branches, and 'try' in the process. + 2005-08-11 Brian Warner * buildbot/master.py (DebugPerspective.perspective_pokeIRC): fix From warner at users.sourceforge.net Mon Aug 15 18:05:08 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Mon, 15 Aug 2005 18:05:08 +0000 Subject: [Buildbot-commits] buildbot/buildbot/scripts runner.py,1.33,1.34 tryclient.py,1.4,1.5 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/scripts In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26903/buildbot/scripts Modified Files: runner.py tryclient.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-287 Creator: Brian Warner rewrite test_vc, make 'try' work for Darcs * buildbot/scripts/tryclient.py (getSourceStamp): extract branches where we can (Arch), add a branch= argument to set the branch used when we can't (BazExtractor): extract the branch too (TlaExtractor): same * buildbot/scripts/runner.py (TryOptions): add --branch * docs/buildbot.texinfo (try): document --branch/try_branch * buildbot/slave/commands.py (Darcs): implement get-revision for Darcs, so that 'try' will work. This requires the tempfile module from python-2.3 . * buildbot/test/test_vc.py: rewrite tests, getting better coverage of revisions, branches, and 'try' in the process. Index: runner.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/scripts/runner.py,v retrieving revision 1.33 retrieving revision 1.34 diff -u -d -r1.33 -r1.34 --- runner.py 11 Aug 2005 20:21:30 -0000 1.33 +++ runner.py 15 Aug 2005 18:05:05 -0000 1.34 @@ -577,6 +577,9 @@ ["vc", None, None, "The VC system in use, one of: cvs,svn,tla,baz,darcs"], + ["branch", None, None, + "The branch in use, for VC systems that can't figure it out" + " themselves"], ["builder", "b", None, "Run the trial build on this Builder. Can be used multiple times."], Index: tryclient.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/scripts/tryclient.py,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- tryclient.py 11 Aug 2005 20:21:30 -0000 1.4 +++ tryclient.py 15 Aug 2005 18:05:05 -0000 1.5 @@ -10,9 +10,11 @@ from buildbot.scripts import runner class SourceStampExtractor: - branch = None - def __init__(self, treetop): + + def __init__(self, treetop, branch): self.treetop = treetop + self.branch = branch + def do(self, cmd): return utils.getProcessOutput(cmd[0], cmd[1:], env=os.environ, path=self.treetop) @@ -56,8 +58,7 @@ for line in res.split("\n"): m = re.search(r'^Status against revision:\s+(\d+)', line) if m: - num = m.group(1) - self.baserev = int(num) + self.baserev = int(m.group(1)) return raise IndexError("Could not find 'Status against revision' in " "SVN output: %s" % res) @@ -72,7 +73,11 @@ d.addCallback(self.parseStatus) return d def parseStatus(self, res): - self.baserev = res.strip() + tid = res.strip() + slash = tid.index("/") + dd = tid.rindex("--") + self.branch = tid[slash+1:dd] + self.baserev = tid[dd+2:] def getPatch(self, res): d = self.do(["baz", "diff"]) d.addCallback(self.readPatch, 1) @@ -80,12 +85,18 @@ class TlaExtractor(SourceStampExtractor): def getBaseRevision(self): + # 'tla logs --full' gives us ARCHIVE/BRANCH--REVISION + # 'tla logs' gives us REVISION d = self.do(["tla", "logs", "--full", "--reverse"]) d.addCallback(self.parseStatus) return d def parseStatus(self, res): - lines = res.split("\n") - self.baserev = lines[0].strip() + tid = res.split("\n")[0].strip() + slash = tid.index("/") + dd = tid.rindex("--") + self.branch = tid[slash+1:dd] + self.baserev = tid[dd+2:] + def getPatch(self, res): d = self.do(["tla", "changes", "--diffs"]) d.addCallback(self.readPatch, 1) @@ -104,17 +115,19 @@ d.addCallback(self.readPatch, self.patchlevel) return d -def getSourceStamp(vctype, treetop): +def getSourceStamp(vctype, treetop, branch=None): if vctype == "cvs": + # use time.strftime("%Y-%m-%d %H:%M:%S %z", time.gmtime()), + # use in a cvs diff -D command? raise NotImplementedError("CVSExtractor not yet implemented") elif vctype == "svn": - e = SVNExtractor(treetop) + e = SVNExtractor(treetop, branch) elif vctype == "baz": - e = BazExtractor(treetop) + e = BazExtractor(treetop, branch) elif vctype == "tla": - e = TlaExtractor(treetop) + e = TlaExtractor(treetop, branch) elif vctype == "darcs": - e = DarcsExtractor(treetop) + e = DarcsExtractor(treetop, branch) else: raise KeyError("unknown vctype '%s'" % vctype) return e.get() @@ -162,6 +175,7 @@ self.config = config self.opts = runner.loadOptions() self.connect = self.getopt('connect', 'try_connect') + assert self.connect, "you must specify a connect style: ssh or pb" self.builderNames = self.getopt('builders', 'try_builders') assert self.builderNames, "no builders! use --builder or " \ "try_builders=[names..] in .buildbot/options" @@ -172,7 +186,6 @@ value = self.opts.get(options_name) if value is None or value == []: value = default - assert value is not None return value def createJob(self): @@ -184,6 +197,7 @@ # common options vc = self.getopt("vc", "try_vc") + branch = self.getopt("branch", "try_branch") if vc in ("cvs", "svn"): # we need to find the tree-top @@ -195,7 +209,7 @@ treedir = getTopdir(topfile) else: treedir = os.getcwd() - d = getSourceStamp(vc, treedir) + d = getSourceStamp(vc, treedir, branch) d.addCallback(self._createJob_1) return d def _createJob_1(self, ss): From warner at users.sourceforge.net Mon Aug 15 18:05:10 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Mon, 15 Aug 2005 18:05:10 +0000 Subject: [Buildbot-commits] buildbot/buildbot/slave commands.py,1.37,1.38 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/slave In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26903/buildbot/slave Modified Files: commands.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-287 Creator: Brian Warner rewrite test_vc, make 'try' work for Darcs * buildbot/scripts/tryclient.py (getSourceStamp): extract branches where we can (Arch), add a branch= argument to set the branch used when we can't (BazExtractor): extract the branch too (TlaExtractor): same * buildbot/scripts/runner.py (TryOptions): add --branch * docs/buildbot.texinfo (try): document --branch/try_branch * buildbot/slave/commands.py (Darcs): implement get-revision for Darcs, so that 'try' will work. This requires the tempfile module from python-2.3 . * buildbot/test/test_vc.py: rewrite tests, getting better coverage of revisions, branches, and 'try' in the process. Index: commands.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/slave/commands.py,v retrieving revision 1.37 retrieving revision 1.38 diff -u -d -r1.37 -r1.38 --- commands.py 19 Jul 2005 23:12:00 -0000 1.37 +++ commands.py 15 Aug 2005 18:05:08 -0000 1.38 @@ -970,16 +970,20 @@ SourceBase.setup(self, args) self.repourl = args['repourl'] self.sourcedata = "%s\n" % self.repourl + self.revision = self.args.get('revision') def sourcedirIsUpdateable(self): if os.path.exists(os.path.join(self.builder.basedir, self.srcdir, ".buildbot-patched")): return False + if self.revision: + # checking out a specific revision requires a full 'darcs get' + return False return os.path.isdir(os.path.join(self.builder.basedir, self.srcdir, "_darcs")) def doVCUpdate(self): - # TODO: revision + assert not self.revision # update: possible for mode in ('copy', 'update') d = os.path.join(self.builder.basedir, self.srcdir) command = ['darcs', 'pull', '--all', '--verbose'] @@ -989,16 +993,33 @@ return c.start() def doVCFull(self): - # TODO: revision # checkout or export d = self.builder.basedir command = ['darcs', 'get', '--verbose', '--partial', - '--repo-name', self.srcdir, - self.repourl] + '--repo-name', self.srcdir] + if self.revision: + # write the context to a file + import tempfile # requires python-2.3 + fd,n = tempfile.mkstemp(dir=self.builder.basedir) + f = os.fdopen(fd, "w") + f.write(self.revision) + f.close() + # tell Darcs to use that context + command.append('--context') + command.append(n) + command.append(self.repourl) + c = ShellCommand(self.builder, command, d, sendRC=False, timeout=self.timeout) self.command = c - return c.start() + d = c.start() + if self.revision: + d.addCallback(self.removeContextFile, n) + return d + + def removeContextFile(self, res, n): + os.unlink(n) + return res registerSlaveCommand("darcs", Darcs, cvs_ver) From warner at users.sourceforge.net Mon Aug 15 18:05:10 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Mon, 15 Aug 2005 18:05:10 +0000 Subject: [Buildbot-commits] buildbot/buildbot/test test_vc.py,1.39,1.40 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26903/buildbot/test Modified Files: test_vc.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-287 Creator: Brian Warner rewrite test_vc, make 'try' work for Darcs * buildbot/scripts/tryclient.py (getSourceStamp): extract branches where we can (Arch), add a branch= argument to set the branch used when we can't (BazExtractor): extract the branch too (TlaExtractor): same * buildbot/scripts/runner.py (TryOptions): add --branch * docs/buildbot.texinfo (try): document --branch/try_branch * buildbot/slave/commands.py (Darcs): implement get-revision for Darcs, so that 'try' will work. This requires the tempfile module from python-2.3 . * buildbot/test/test_vc.py: rewrite tests, getting better coverage of revisions, branches, and 'try' in the process. Index: test_vc.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/test/test_vc.py,v retrieving revision 1.39 retrieving revision 1.40 diff -u -d -r1.39 -r1.40 --- test_vc.py 11 Aug 2005 08:22:17 -0000 1.39 +++ test_vc.py 15 Aug 2005 18:05:07 -0000 1.40 @@ -2,7 +2,7 @@ from __future__ import generators -import sys, os, signal, shutil, time +import sys, os, signal, shutil, time, re from email.Utils import mktime_tz, parsedate_tz from twisted.trial import unittest @@ -113,167 +113,96 @@ """ [...1891 lines suppressed...] + self.vcargs = {'url': url, + 'archive': self.archname, + 'version': self.defaultbranch, + 'retry': (0.5, 3), + } + d = self.do_vc_once(False) + d.addCallback(self._testRetryFails_1) + return maybeWait(d) + def _testRetryFails_1(self, bs): + self.failUnlessEqual(bs.getResults(), FAILURE) - # now re-register the original coordinates - #w = waitForDeferred(self.registerRepository(self.archcmd, - # coordinates)) - #yield w; w.getResult() - #shutil.rmtree(tmp) - setup_try = deferredGenerator(setup_try) class Sources(unittest.TestCase): From warner at users.sourceforge.net Mon Aug 15 20:26:07 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Mon, 15 Aug 2005 20:26:07 +0000 Subject: [Buildbot-commits] buildbot ChangeLog,1.488,1.489 Message-ID: Update of /cvsroot/buildbot/buildbot In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30551 Modified Files: ChangeLog Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-289 Creator: Brian Warner fix test_vc failures under twisted-1.3.0: avoid nested maybeWait * buildbot/test/test_vc.py (VCBase.tearDown): provide for tearDown2, so things like Arch can unregister archives as they're shutting down. The previous subclass-override-tearDown technique resulted in a nested maybeWait() and test failures under Twisted-1.3.0 Index: ChangeLog =================================================================== RCS file: /cvsroot/buildbot/buildbot/ChangeLog,v retrieving revision 1.488 retrieving revision 1.489 diff -u -d -r1.488 -r1.489 --- ChangeLog 15 Aug 2005 18:05:07 -0000 1.488 +++ ChangeLog 15 Aug 2005 20:26:05 -0000 1.489 @@ -1,5 +1,11 @@ 2005-08-15 Brian Warner + * buildbot/test/test_vc.py (VCBase.tearDown): provide for + tearDown2, so things like Arch can unregister archives as they're + shutting down. The previous subclass-override-tearDown technique + resulted in a nested maybeWait() and test failures under + Twisted-1.3.0 + * buildbot/scripts/tryclient.py (getSourceStamp): extract branches where we can (Arch), add a branch= argument to set the branch used when we can't From warner at users.sourceforge.net Mon Aug 15 20:26:07 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Mon, 15 Aug 2005 20:26:07 +0000 Subject: [Buildbot-commits] buildbot/buildbot/test test_vc.py,1.40,1.41 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30551/buildbot/test Modified Files: test_vc.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-289 Creator: Brian Warner fix test_vc failures under twisted-1.3.0: avoid nested maybeWait * buildbot/test/test_vc.py (VCBase.tearDown): provide for tearDown2, so things like Arch can unregister archives as they're shutting down. The previous subclass-override-tearDown technique resulted in a nested maybeWait() and test failures under Twisted-1.3.0 Index: test_vc.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/test/test_vc.py,v retrieving revision 1.40 retrieving revision 1.41 diff -u -d -r1.40 -r1.41 --- test_vc.py 15 Aug 2005 18:05:07 -0000 1.40 +++ test_vc.py 15 Aug 2005 20:26:05 -0000 1.41 @@ -907,8 +907,12 @@ from twisted.protocols import http # Twisted-1.3 http._logDateTimeStop() # shut down the internal timer. DUMB! d.addCallback(lambda res: stopHTTPTimer()) + d.addCallback(lambda res: self.tearDown2()) return maybeWait(d) + def tearDown2(self): + pass + class CVSSupport(VCBase): metadir = "CVS" branchname = "branch" @@ -1310,7 +1314,7 @@ def postCreate(self, res): pass - def tearDown(self): + def tearDown2(self): if self.fixtimer: self.fixtimer.cancel() # tell tla to get rid of the leftover archive this test leaves in the @@ -1319,8 +1323,7 @@ # same name. We could use archive= to set it explicitly, but if you # change it from the default, then 'tla update' won't work. d = self.unregisterRepository() - d.addCallback(lambda res: VCBase.tearDown(self)) - return maybeWait(d) + return d def vc_create(self): # pick a hopefully unique string for the archive name, in the form From warner at users.sourceforge.net Tue Aug 16 00:23:55 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Tue, 16 Aug 2005 00:23:55 +0000 Subject: [Buildbot-commits] buildbot ChangeLog,1.489,1.490 Makefile,1.14,1.15 Message-ID: Update of /cvsroot/buildbot/buildbot In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24586 Modified Files: ChangeLog Makefile Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-291 Creator: Brian Warner implement 'try' for CVS (but it doesn't work on non-trunk) * buildbot/scripts/tryclient.py (CVSExtractor): implement 'try' for CVS trees. It doesn't work for non-trunk branches, unfortunately. * buildbot/test/test_vc.py (CVS.testTry): test it, but skip the branch test * Makefile: make it easier to test against python2.2 --This line, and those below, will be ignored-- Files to commit: This list might be incomplete or outdated if editing the log message was not invoked from an up-to-date changes buffer! Index: ChangeLog =================================================================== RCS file: /cvsroot/buildbot/buildbot/ChangeLog,v retrieving revision 1.489 retrieving revision 1.490 diff -u -d -r1.489 -r1.490 --- ChangeLog 15 Aug 2005 20:26:05 -0000 1.489 +++ ChangeLog 16 Aug 2005 00:23:52 -0000 1.490 @@ -1,5 +1,13 @@ 2005-08-15 Brian Warner + * buildbot/scripts/tryclient.py (CVSExtractor): implement 'try' + for CVS trees. It doesn't work for non-trunk branches, + unfortunately. + * buildbot/test/test_vc.py (CVS.testTry): test it, but skip the + branch test + + * Makefile: make it easier to test against python2.2 + * buildbot/test/test_vc.py (VCBase.tearDown): provide for tearDown2, so things like Arch can unregister archives as they're shutting down. The previous subclass-override-tearDown technique Index: Makefile =================================================================== RCS file: /cvsroot/buildbot/buildbot/Makefile,v retrieving revision 1.14 retrieving revision 1.15 diff -u -d -r1.14 -r1.15 --- Makefile 19 Jul 2005 23:12:00 -0000 1.14 +++ Makefile 16 Aug 2005 00:23:53 -0000 1.15 @@ -14,10 +14,11 @@ PP = PYTHONPATH=$(BBBASE):$(T) .PHONY: test +TRIAL=trial TRIALARGS=-v TEST=buildbot.test test: - $(PP) trial $(TRIALARGS) $(TEST) + $(PP) $(TRIAL) $(TRIALARGS) $(TEST) #debuild -uc -us From warner at users.sourceforge.net Tue Aug 16 00:23:55 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Tue, 16 Aug 2005 00:23:55 +0000 Subject: [Buildbot-commits] buildbot/buildbot/test test_vc.py,1.41,1.42 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24586/buildbot/test Modified Files: test_vc.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-291 Creator: Brian Warner implement 'try' for CVS (but it doesn't work on non-trunk) * buildbot/scripts/tryclient.py (CVSExtractor): implement 'try' for CVS trees. It doesn't work for non-trunk branches, unfortunately. * buildbot/test/test_vc.py (CVS.testTry): test it, but skip the branch test * Makefile: make it easier to test against python2.2 --This line, and those below, will be ignored-- Files to commit: This list might be incomplete or outdated if editing the log message was not invoked from an up-to-date changes buffer! Index: test_vc.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/test/test_vc.py,v retrieving revision 1.41 retrieving revision 1.42 diff -u -d -r1.41 -r1.42 --- test_vc.py 15 Aug 2005 20:26:05 -0000 1.41 +++ test_vc.py 16 Aug 2005 00:23:53 -0000 1.42 @@ -768,7 +768,7 @@ self.failUnlessIn("Hello world.", data) self.shouldNotExist(self.workdir, "newbranchfile") - def do_getpatch(self): + def do_getpatch(self, doBranch=True): # prepare a buildslave to do checkouts vctype = self.vctype args = self.vcargs @@ -794,7 +794,8 @@ self.trydir = os.path.join(self.repbase, tmpdir) d.addCallback(self.do_getpatch_trunkhead) d.addCallback(self.do_getpatch_trunkold) - d.addCallback(self.do_getpatch_branch) + if doBranch: + d.addCallback(self.do_getpatch_branch) d.addBoth(self.do_getpatch_finish) return d @@ -918,6 +919,7 @@ branchname = "branch" try_branchname = "branch" vctype = "step.CVS" + vctype_try = "cvs" def capable(self): if not VCS.have['cvs']: @@ -1014,6 +1016,10 @@ def testBranch(self): d = self.do_branch() return maybeWait(d) + + def testTry(self): + d = self.do_getpatch(doBranch=False) + return maybeWait(d) class SVNSupport(VCBase): From warner at users.sourceforge.net Tue Aug 16 00:23:54 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Tue, 16 Aug 2005 00:23:54 +0000 Subject: [Buildbot-commits] buildbot/buildbot/scripts tryclient.py,1.5,1.6 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/scripts In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24586/buildbot/scripts Modified Files: tryclient.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-291 Creator: Brian Warner implement 'try' for CVS (but it doesn't work on non-trunk) * buildbot/scripts/tryclient.py (CVSExtractor): implement 'try' for CVS trees. It doesn't work for non-trunk branches, unfortunately. * buildbot/test/test_vc.py (CVS.testTry): test it, but skip the branch test * Makefile: make it easier to test against python2.2 --This line, and those below, will be ignored-- Files to commit: This list might be incomplete or outdated if editing the log message was not invoked from an up-to-date changes buffer! Index: tryclient.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/scripts/tryclient.py,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- tryclient.py 15 Aug 2005 18:05:05 -0000 1.5 +++ tryclient.py 16 Aug 2005 00:23:52 -0000 1.6 @@ -1,6 +1,6 @@ # -*- test-case-name: buildbot.test.test_scheduler,buildbot.test.test_vc -*- -import os, re +import os, re, time from twisted.internet import utils, protocol, defer, reactor from twisted.spread import pb from twisted.cred import credentials @@ -8,6 +8,7 @@ from buildbot.sourcestamp import SourceStamp from buildbot.scripts import runner +from buildbot.util import now class SourceStampExtractor: @@ -31,6 +32,31 @@ ss = SourceStamp(self.branch, self.baserev, self.patch) return ss +class CVSExtractor(SourceStampExtractor): + patchlevel = 0 + def getBaseRevision(self): + # this depends upon our local clock and the repository's clock pretty + # in reasonable sync with each other + self.baserev = time.strftime("%Y-%m-%d %H:%M:%S %z", + time.gmtime(now())) + return defer.succeed(None) + + def getPatch(self, res): + # the -q tells CVS to not announce each directory as it works + if self.branch is not None: + # 'cvs diff' won't take both -r and -D at the same time (it + # ignores the -r). As best I can tell, there is no way to make + # cvs give you a diff relative to a timestamp on the non-trunk + # branch. A bare 'cvs diff' will tell you about the changes + # relative to your checked-out versions, but I know of no way to + # find out what those checked-out versions are. + raise RuntimeError("Sorry, CVS 'try' builds don't work with " + "branches") + args = ['cvs', '-q', 'diff', '-u', '-D', self.baserev] + d = self.do(args) + d.addCallback(self.readPatch, self.patchlevel) + return d + class SVNExtractor(SourceStampExtractor): patchlevel = 0 def getBaseRevision(self): @@ -117,9 +143,7 @@ def getSourceStamp(vctype, treetop, branch=None): if vctype == "cvs": - # use time.strftime("%Y-%m-%d %H:%M:%S %z", time.gmtime()), - # use in a cvs diff -D command? - raise NotImplementedError("CVSExtractor not yet implemented") + e = CVSExtractor(treetop, branch) elif vctype == "svn": e = SVNExtractor(treetop, branch) elif vctype == "baz": From warner at users.sourceforge.net Tue Aug 16 20:13:13 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Tue, 16 Aug 2005 20:13:13 +0000 Subject: [Buildbot-commits] site index.html,1.44,1.45 Message-ID: Update of /cvsroot/buildbot/site In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21599 Modified Files: index.html Log Message: add a brief description of what the buildbot actually is Index: index.html =================================================================== RCS file: /cvsroot/buildbot/site/index.html,v retrieving revision 1.44 retrieving revision 1.45 diff -u -d -r1.44 -r1.45 --- index.html 20 Jul 2005 07:22:19 -0000 1.44 +++ index.html 16 Aug 2005 20:13:09 -0000 1.45 @@ -8,7 +8,27 @@

    The BuildBot

    -Current contents: +

    from the README

    + +

    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.

    + +

    The overall goal is to reduce tree breakage and provide a platform to run +tests or code-quality checks that are too annoying or pedantic for any human +to waste their time with. Developers get immediate (and potentially public) +feedback about their changes, encouraging them to be more careful about +testing before checkin.

    + +

    Current contents:

    • The current release is buildbot-0.6.6 . You can download the source @@ -146,5 +166,5 @@ align="right" /> -Last modified: Wed Jul 20 00:16:12 PDT 2005 +Last modified: Tue Aug 16 13:12:46 PDT 2005 From warner at users.sourceforge.net Tue Aug 16 20:14:09 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Tue, 16 Aug 2005 20:14:09 +0000 Subject: [Buildbot-commits] site index.html,1.45,1.46 Message-ID: Update of /cvsroot/buildbot/site In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21751 Modified Files: index.html Log Message: make note smaller Index: index.html =================================================================== RCS file: /cvsroot/buildbot/site/index.html,v retrieving revision 1.45 retrieving revision 1.46 diff -u -d -r1.45 -r1.46 --- index.html 16 Aug 2005 20:13:09 -0000 1.45 +++ index.html 16 Aug 2005 20:14:06 -0000 1.46 @@ -8,7 +8,7 @@

      The BuildBot

      -

      from the README

      +

      (from the README)

      The BuildBot is a system to automate the compile/test cycle required by most software projects to validate code changes. By automatically rebuilding @@ -166,5 +166,5 @@ align="right" /> -Last modified: Tue Aug 16 13:12:46 PDT 2005 +Last modified: Tue Aug 16 13:13:47 PDT 2005 From warner at users.sourceforge.net Tue Aug 16 20:38:03 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Tue, 16 Aug 2005 20:38:03 +0000 Subject: [Buildbot-commits] buildbot ChangeLog,1.490,1.491 Message-ID: Update of /cvsroot/buildbot/buildbot In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26686 Modified Files: ChangeLog Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-293 Creator: Brian Warner make Darcs get-revision work under python2.2 too * buildbot/slave/commands.py (Darcs.doVCFull): fix get-revision for Darcs to not use the tempfile module, so it works under python-2.2 too. We really didn't need the full cleverness of that module, since the slave has exclusive control of its own builddir. Index: ChangeLog =================================================================== RCS file: /cvsroot/buildbot/buildbot/ChangeLog,v retrieving revision 1.490 retrieving revision 1.491 diff -u -d -r1.490 -r1.491 --- ChangeLog 16 Aug 2005 00:23:52 -0000 1.490 +++ ChangeLog 16 Aug 2005 20:38:00 -0000 1.491 @@ -1,3 +1,10 @@ +2005-08-16 Brian Warner + + * buildbot/slave/commands.py (Darcs.doVCFull): fix get-revision + for Darcs to not use the tempfile module, so it works under + python-2.2 too. We really didn't need the full cleverness of that + module, since the slave has exclusive control of its own builddir. + 2005-08-15 Brian Warner * buildbot/scripts/tryclient.py (CVSExtractor): implement 'try' From warner at users.sourceforge.net Tue Aug 16 20:38:03 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Tue, 16 Aug 2005 20:38:03 +0000 Subject: [Buildbot-commits] buildbot/buildbot/slave commands.py,1.38,1.39 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/slave In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26686/buildbot/slave Modified Files: commands.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-293 Creator: Brian Warner make Darcs get-revision work under python2.2 too * buildbot/slave/commands.py (Darcs.doVCFull): fix get-revision for Darcs to not use the tempfile module, so it works under python-2.2 too. We really didn't need the full cleverness of that module, since the slave has exclusive control of its own builddir. Index: commands.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/slave/commands.py,v retrieving revision 1.38 retrieving revision 1.39 diff -u -d -r1.38 -r1.39 --- commands.py 15 Aug 2005 18:05:08 -0000 1.38 +++ commands.py 16 Aug 2005 20:38:01 -0000 1.39 @@ -999,9 +999,8 @@ '--repo-name', self.srcdir] if self.revision: # write the context to a file - import tempfile # requires python-2.3 - fd,n = tempfile.mkstemp(dir=self.builder.basedir) - f = os.fdopen(fd, "w") + n = os.path.join(self.builder.basedir, ".darcs-context") + f = open(n, "w") # TODO: should this be 'wt'? f.write(self.revision) f.close() # tell Darcs to use that context From warner at users.sourceforge.net Wed Aug 17 02:15:39 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 17 Aug 2005 02:15:39 +0000 Subject: [Buildbot-commits] buildbot/buildbot/status client.py,1.20,1.21 base.py,1.1,1.2 builder.py,1.63,1.64 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/status In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31918/buildbot/status Modified Files: client.py base.py builder.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-295 Creator: Brian Warner implement IBuildSetStatus/IBuildRequestStatus, wire them into place * buildbot/status/builder.py: implement IBuildSetStatus and IBuildRequestStatus, wire them into place. * buildbot/buildset.py: same. Add ID, move wait-until-finished methods into the BuildSetStatus object. * buildbot/interfaces.py: same (IStatus.getBuildSets): new method to get pending BuildSets (IStatusReceiver.buildsetSubmitted): new method which hears about new BuildSets * buildbot/master.py (BuildMaster.submitBuildSet): same * buildbot/process/base.py (BuildRequest): same, replace waitUntilStarted with subscribe/unsubscribe * buildbot/process/builder.py (BuilderControl.forceBuild): use subscribe instead of waitUntilStarted * buildbot/status/base.py (StatusReceiver.buildsetSubmitted): stub for new method * buildbot/status/client.py (StatusClientPerspective.builderRemoved): same * buildbot/test/test_buildreq.py: update for new code * buildbot/test/test_control.py (Force.testRequest): same Index: base.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/status/base.py,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- base.py 17 May 2005 10:14:09 -0000 1.1 +++ base.py 17 Aug 2005 02:15:37 -0000 1.2 @@ -19,6 +19,9 @@ else: __implements__ = IStatusReceiver, + def buildsetSubmitted(self, buildset): + pass + def builderAdded(self, builderName, builder): pass Index: builder.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/status/builder.py,v retrieving revision 1.63 retrieving revision 1.64 diff -u -d -r1.63 -r1.64 --- builder.py 9 Aug 2005 00:43:35 -0000 1.63 +++ builder.py 17 Aug 2005 02:15:37 -0000 1.64 @@ -554,23 +554,96 @@ else: __implements__ = interfaces.IBuildSetStatus, - def __init__(self): - # TODO - pass - - def setSourceStamp(self, sourceStamp): - self.source = sourceStamp - def setReason(self, reason): + def __init__(self, source, reason, builderNames, bsid=None): + self.source = source self.reason = reason + self.builderNames = builderNames + self.id = bsid + self.successWatchers = [] + self.finishedWatchers = [] + self.failed = False + self.finished = False + + def setBuildRequestStatuses(self, buildRequestStatuses): + self.buildRequests = buildRequestStatuses def setResults(self, results): self.results = results + def notifySuccessWatchers(self): + for d in self.successWatchers: + d.callback(self) + self.successWatchers = [] + + def notifyFinishedWatchers(self): + self.finished = True + if not self.failed: + self.notifySuccessWatchers() + for d in self.finishedWatchers: + d.callback(self) + self.finishedWatchers = [] + + # methods for our clients + def getSourceStamp(self): return self.source def getReason(self): return self.reason def getResults(self): return self.results + def getID(self): + return self.id + + def getBuilderNames(self): + return self.builderNames + def getBuildRequests(self): + return self.buildRequests + def isFinished(self): + return self.finished + + def waitUntilSuccess(self): + if self.failed or self.finished: + # the deferreds have already fired + return defer.succeed(self) + d = defer.Deferred() + self.successWatchers.append(d) + return d + + def waitUntilFinished(self): + if self.finished: + return defer.succeed(self) + d = defer.Deferred() + self.finishedWatchers.append(d) + return d + +class BuildRequestStatus: + if implements: + implements(interfaces.IBuildRequestStatus) + else: + __implements__ = interfaces.IBuildRequestStatus, + + def __init__(self, source, builderName): + self.source = source + self.builderName = builderName + self.builds = [] # list of BuildStatus objects + self.observers = [] + + def buildStarted(self, build): + self.builds.append(build) + for o in self.observers[:]: + o(build) + + # methods called by our clients + def getSourceStamp(self): + return self.source + def getBuilderName(self): + return self.builderName + + def subscribe(self, observer): + self.observers.append(observer) + for b in self.builds: + observer(b) + def unsubscribe(self, observer): + self.observers.remove(observer) class BuildStepStatus: @@ -1587,8 +1660,12 @@ self.botmaster = botmaster self.basedir = basedir self.watchers = [] + self.activeBuildSets = [] assert os.path.isdir(basedir) + + # methods called by our clients + def getProjectName(self): return self.botmaster.parent.projectName def getProjectURL(self): @@ -1617,6 +1694,9 @@ def getSlave(self, slavename): return self.botmaster.slaves[slavename].slave_status + def getBuildSets(self): + return self.activeBuildSets[:] + def subscribe(self, target): self.watchers.append(target) for name in self.botmaster.builderNames: @@ -1624,6 +1704,9 @@ def unsubscribe(self, target): self.watchers.remove(target) + + # methods called by upstream objects + def announceNewBuilder(self, target, name, builder_status): t = target.builderAdded(name, builder_status) if t: @@ -1669,3 +1752,9 @@ def prune(self): for b in self.botmaster.builders.values(): b.builder_status.prune() + + def buildsetSubmitted(self, bss): + self.activeBuildSets.append(bss) + bss.waitUntilFinished().addCallback(self.activeBuildSets.remove) + for t in self.watchers: + t.buildsetSubmitted(bss) Index: client.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/status/client.py,v retrieving revision 1.20 retrieving revision 1.21 diff -u -d -r1.20 -r1.21 --- client.py 19 Jul 2005 23:12:01 -0000 1.20 +++ client.py 17 Aug 2005 02:15:37 -0000 1.21 @@ -317,6 +317,10 @@ self.subscribed_to_builders.remove(name) self.client.callRemote("builderRemoved", name) + def buildsetSubmitted(self, buildset): + # TODO: deliver to client, somehow + pass + # mode >= builds def buildStarted(self, name, build): self.client.callRemote("buildStarted", name, IRemote(build)) From warner at users.sourceforge.net Wed Aug 17 02:15:39 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 17 Aug 2005 02:15:39 +0000 Subject: [Buildbot-commits] buildbot/buildbot interfaces.py,1.28,1.29 buildset.py,1.1,1.2 master.py,1.79,1.80 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31918/buildbot Modified Files: interfaces.py buildset.py master.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-295 Creator: Brian Warner implement IBuildSetStatus/IBuildRequestStatus, wire them into place * buildbot/status/builder.py: implement IBuildSetStatus and IBuildRequestStatus, wire them into place. * buildbot/buildset.py: same. Add ID, move wait-until-finished methods into the BuildSetStatus object. * buildbot/interfaces.py: same (IStatus.getBuildSets): new method to get pending BuildSets (IStatusReceiver.buildsetSubmitted): new method which hears about new BuildSets * buildbot/master.py (BuildMaster.submitBuildSet): same * buildbot/process/base.py (BuildRequest): same, replace waitUntilStarted with subscribe/unsubscribe * buildbot/process/builder.py (BuilderControl.forceBuild): use subscribe instead of waitUntilStarted * buildbot/status/base.py (StatusReceiver.buildsetSubmitted): stub for new method * buildbot/status/client.py (StatusClientPerspective.builderRemoved): same * buildbot/test/test_buildreq.py: update for new code * buildbot/test/test_control.py (Force.testRequest): same Index: buildset.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/buildset.py,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- buildset.py 19 Jul 2005 23:11:59 -0000 1.1 +++ buildset.py 17 Aug 2005 02:15:36 -0000 1.2 @@ -12,35 +12,21 @@ source.revision), or a build of a certain set of Changes (source.changes=list).""" - def __init__(self, builderNames, source, reason=None): + def __init__(self, builderNames, source, reason=None, bsid=None): """ @param source: a L{SourceStamp} """ self.builderNames = builderNames self.source = source self.reason = reason - self.set_status = bss = builder.BuildSetStatus() - bss.setSourceStamp(source) - bss.setReason(reason) - self.successWatchers = [] - self.finishedWatchers = [] self.failed = False + self.status = bss = builder.BuildSetStatus(source, reason, + builderNames, bsid) def waitUntilSuccess(self): - """Return a Deferred that will fire (with an IBuildSetStatus) when we - know whether or not this BuildSet will be a complete success (all - builds succeeding). This means it will fire upon the first failing - build, or upon the last successful one.""" - # TODO: make it safe to call this after the buildset has completed - d = defer.Deferred() - self.successWatchers.append(d) - return d - + return self.status.waitUntilSuccess() def waitUntilFinished(self): - """Return a Deferred that will fire when all builds have finished.""" - d = defer.Deferred() - self.finishedWatchers.append(d) - return d + return self.status.waitUntilFinished() def start(self, builders): """This is called by the BuildMaster to actually create and submit @@ -50,38 +36,28 @@ # create the requests for b in builders: - req = base.BuildRequest(self.reason, self.source) + req = base.BuildRequest(self.reason, self.source, b.name) reqs.append((b, req)) self.requests.append(req) d = req.waitUntilFinished() d.addCallback(self.requestFinished, req) - + + # tell our status about them + req_statuses = [req.status for req in self.requests] + self.status.setBuildRequestStatuses(req_statuses) + # now submit them - self.status = {} # maps requests to BuildStatus for b,req in reqs: b.submitBuildRequest(req) def requestFinished(self, buildstatus, req): self.requests.remove(req) - self.status[req] = buildstatus if buildstatus.getResults() == builder.FAILURE: if not self.failed: - self.failed = True - self.set_status.setResults(builder.FAILURE) - self.notifySuccessWatchers() + self.failed = self.status.failed = True + self.status.setResults(builder.FAILURE) + self.status.notifySuccessWatchers() if not self.requests: - self.set_status.setResults(builder.SUCCESS) - self.notifyFinishedWatchers() - - def notifySuccessWatchers(self): - for d in self.successWatchers: - d.callback(self.set_status) - self.successWatchers = [] - - def notifyFinishedWatchers(self): - if not self.failed: - self.notifySuccessWatchers() - for d in self.finishedWatchers: - d.callback(self.set_status) - self.finishedWatchers = [] + self.status.setResults(builder.SUCCESS) + self.status.notifyFinishedWatchers() Index: interfaces.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/interfaces.py,v retrieving revision 1.28 retrieving revision 1.29 diff -u -d -r1.28 -r1.29 --- interfaces.py 20 Jul 2005 04:21:57 -0000 1.28 +++ interfaces.py 17 Aug 2005 02:15:36 -0000 1.29 @@ -95,12 +95,17 @@ def getSlave(name): """Return the ISlaveStatus object for a given named buildslave.""" + def getBuildSets(): + """Return a list of active (non-finished) IBuildSetStatus objects.""" + def subscribe(receiver): """Register an IStatusReceiver to receive new status events. The receiver will immediately be sent a set of 'builderAdded' messages for all current builders. It will receive further 'builderAdded' and 'builderRemoved' messages as the config file is reloaded and builders - come and go. No additional messages will be sent unless the receiver + come and go. It will also receive 'buildsetSubmitted' messages for + all outstanding BuildSets (and each new BuildSet that gets + submitted). No additional messages will be sent unless the receiver asks for them by calling .subscribe on the IBuilderStatus objects which accompany the addedBuilder message.""" @@ -118,22 +123,54 @@ pass def getChanges(): pass + def getID(): + """Return the BuildSet's ID string, if any. The 'try' feature uses a + random string as a BuildSetID to relate submitted jobs with the + resulting BuildSet.""" def getResponsibleUsers(): - pass + pass # not implemented def getInterestedUsers(): - pass - def getBuilds(): - """Return a list of IBuildStatus objects that represent my - component Builds.""" + pass # not implemented + def getBuilderNames(): + """Return a list of the names of all Builders on which this set will + do builds.""" + def getBuildRequests(): + """Return a list of IBuildRequestStatus objects that represent my + component Builds. This list might correspond to the Builders named by + getBuilderNames(), but if builder categories are used, or 'Builder + Aliases' are implemented, then they may not.""" def isFinished(): pass - def waitUntilFirstFailure(): - pass + def waitUntilSuccess(): + """Return a Deferred that fires (with this IBuildSetStatus object) + when the outcome of the BuildSet is known, i.e., upon the first + failure, or after all builds complete successfully.""" def waitUntilFinished(): - pass + """Return a Deferred that fires (with this IBuildSetStatus object) + when all builds have finished.""" def getResults(): pass +class IBuildRequestStatus(Interface): + """I represent a request to build a particular set of source code on a + particular Builder. These requests may be merged by the time they are + finally turned into a Build.""" + + def getSourceStamp(): + pass + def getBuilderName(): + pass + def subscribe(observer): + """Register a callable that will be invoked (with a single + IBuildStatus object) for each Build that is created to satisfy this + request. There may be multiple Builds created in an attempt to handle + the request: they may be interrupted by the user or abandoned due to + a lost slave. The last Build (the one which actually gets to run to + completion) is said to 'satisfy' the BuildRequest. The observer will + be called once for each of these Builds, both old and new.""" + def unsubscribe(observer): + """Unregister the callable that was registered with subscribe().""" + class ISlaveStatus(Interface): def getName(): @@ -639,6 +676,12 @@ """I am an object which can receive build status updates. I may be subscribed to an IStatus, an IBuilderStatus, or an IBuildStatus.""" + def buildsetSubmitted(buildset): + """A new BuildSet has been submitted to the buildmaster. + + @type buildset: implementor of L{IBuildSetStatus} + """ + def builderAdded(builderName, builder): """ A new Builder has just been added. This method may return an @@ -734,7 +777,6 @@ def submitBuildSet(buildset): """Submit a BuildSet object, which will eventually be run on all of the builders listed therein.""" - # TODO: return a status object def getBuilder(name): """Retrieve the IBuilderControl object for the given Builder.""" @@ -787,6 +829,16 @@ # the Builder column, so it kinda fits here too. class IBuildRequestControl(Interface): + def subscribe(observer): + """Register a callable that will be invoked (with a single + IBuildControl object) for each Build that is created to satisfy this + request. There may be multiple Builds created in an attempt to handle + the request: they may be interrupted by the user or abandoned due to + a lost slave. The last Build (the one which actually gets to run to + completion) is said to 'satisfy' the BuildRequest. The observer will + be called once for each of these Builds, both old and new.""" + def unsubscribe(observer): + """Unregister the callable that was registered with subscribe().""" def cancel(): """Remove the build from the pending queue. Has no effect if the build has already been started.""" Index: master.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/master.py,v retrieving revision 1.79 retrieving revision 1.80 diff -u -d -r1.79 -r1.80 --- master.py 11 Aug 2005 21:58:41 -0000 1.79 +++ master.py 17 Aug 2005 02:15:36 -0000 1.80 @@ -974,6 +974,7 @@ # now tell the BuildSet to create BuildRequests for all those # Builders and submit them bs.start(builders) + self.status.buildsetSubmitted(bs.status) class Control: @@ -990,7 +991,6 @@ def submitBuildSet(self, bs): self.master.submitBuildSet(bs) - # TODO: return a BuildSetStatus def getBuilder(self, name): b = self.master.botmaster.builders[name] From warner at users.sourceforge.net Wed Aug 17 02:15:40 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 17 Aug 2005 02:15:40 +0000 Subject: [Buildbot-commits] buildbot ChangeLog,1.491,1.492 Message-ID: Update of /cvsroot/buildbot/buildbot In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31918 Modified Files: ChangeLog Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-295 Creator: Brian Warner implement IBuildSetStatus/IBuildRequestStatus, wire them into place * buildbot/status/builder.py: implement IBuildSetStatus and IBuildRequestStatus, wire them into place. * buildbot/buildset.py: same. Add ID, move wait-until-finished methods into the BuildSetStatus object. * buildbot/interfaces.py: same (IStatus.getBuildSets): new method to get pending BuildSets (IStatusReceiver.buildsetSubmitted): new method which hears about new BuildSets * buildbot/master.py (BuildMaster.submitBuildSet): same * buildbot/process/base.py (BuildRequest): same, replace waitUntilStarted with subscribe/unsubscribe * buildbot/process/builder.py (BuilderControl.forceBuild): use subscribe instead of waitUntilStarted * buildbot/status/base.py (StatusReceiver.buildsetSubmitted): stub for new method * buildbot/status/client.py (StatusClientPerspective.builderRemoved): same * buildbot/test/test_buildreq.py: update for new code * buildbot/test/test_control.py (Force.testRequest): same Index: ChangeLog =================================================================== RCS file: /cvsroot/buildbot/buildbot/ChangeLog,v retrieving revision 1.491 retrieving revision 1.492 diff -u -d -r1.491 -r1.492 --- ChangeLog 16 Aug 2005 20:38:00 -0000 1.491 +++ ChangeLog 17 Aug 2005 02:15:38 -0000 1.492 @@ -1,5 +1,26 @@ 2005-08-16 Brian Warner + * buildbot/status/builder.py: implement IBuildSetStatus and + IBuildRequestStatus, wire them into place. + * buildbot/buildset.py: same. Add ID, move wait-until-finished + methods into the BuildSetStatus object. + * buildbot/interfaces.py: same + (IStatus.getBuildSets): new method to get pending BuildSets + (IStatusReceiver.buildsetSubmitted): new method which hears about + new BuildSets + * buildbot/master.py (BuildMaster.submitBuildSet): same + * buildbot/process/base.py (BuildRequest): same, replace + waitUntilStarted with subscribe/unsubscribe + * buildbot/process/builder.py (BuilderControl.forceBuild): use + subscribe instead of waitUntilStarted + * buildbot/status/base.py (StatusReceiver.buildsetSubmitted): stub + for new method + * buildbot/status/client.py (StatusClientPerspective.builderRemoved): + same + * buildbot/test/test_buildreq.py: update for new code + * buildbot/test/test_control.py (Force.testRequest): same + + * buildbot/slave/commands.py (Darcs.doVCFull): fix get-revision for Darcs to not use the tempfile module, so it works under python-2.2 too. We really didn't need the full cleverness of that From warner at users.sourceforge.net Wed Aug 17 02:15:40 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 17 Aug 2005 02:15:40 +0000 Subject: [Buildbot-commits] buildbot/buildbot/test test_control.py,1.7,1.8 test_buildreq.py,1.2,1.3 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31918/buildbot/test Modified Files: test_control.py test_buildreq.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-295 Creator: Brian Warner implement IBuildSetStatus/IBuildRequestStatus, wire them into place * buildbot/status/builder.py: implement IBuildSetStatus and IBuildRequestStatus, wire them into place. * buildbot/buildset.py: same. Add ID, move wait-until-finished methods into the BuildSetStatus object. * buildbot/interfaces.py: same (IStatus.getBuildSets): new method to get pending BuildSets (IStatusReceiver.buildsetSubmitted): new method which hears about new BuildSets * buildbot/master.py (BuildMaster.submitBuildSet): same * buildbot/process/base.py (BuildRequest): same, replace waitUntilStarted with subscribe/unsubscribe * buildbot/process/builder.py (BuilderControl.forceBuild): use subscribe instead of waitUntilStarted * buildbot/status/base.py (StatusReceiver.buildsetSubmitted): stub for new method * buildbot/status/client.py (StatusClientPerspective.builderRemoved): same * buildbot/test/test_buildreq.py: update for new code * buildbot/test/test_control.py (Force.testRequest): same Index: test_buildreq.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/test/test_buildreq.py,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- test_buildreq.py 10 Aug 2005 04:52:41 -0000 1.2 +++ test_buildreq.py 17 Aug 2005 02:15:38 -0000 1.3 @@ -79,6 +79,7 @@ class FakeBuilder: + name = "fake" def __init__(self): self.requests = [] def submitBuildRequest(self, req): Index: test_control.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/test/test_control.py,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- test_control.py 19 Jul 2005 23:11:58 -0000 1.7 +++ test_control.py 17 Aug 2005 02:15:38 -0000 1.8 @@ -141,7 +141,8 @@ c = interfaces.IControl(m) req = base.BuildRequest("I was bored", SourceStamp()) builder_control = c.getBuilder("force") - d = req.waitUntilStarted() + d = defer.Deferred() + req.subscribe(d.callback) builder_control.requestBuild(req) d.addCallback(self._testForce_1) return maybeWait(d) From warner at users.sourceforge.net Wed Aug 17 02:15:40 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 17 Aug 2005 02:15:40 +0000 Subject: [Buildbot-commits] buildbot/buildbot/process base.py,1.57,1.58 builder.py,1.28,1.29 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/process In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31918/buildbot/process Modified Files: base.py builder.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-295 Creator: Brian Warner implement IBuildSetStatus/IBuildRequestStatus, wire them into place * buildbot/status/builder.py: implement IBuildSetStatus and IBuildRequestStatus, wire them into place. * buildbot/buildset.py: same. Add ID, move wait-until-finished methods into the BuildSetStatus object. * buildbot/interfaces.py: same (IStatus.getBuildSets): new method to get pending BuildSets (IStatusReceiver.buildsetSubmitted): new method which hears about new BuildSets * buildbot/master.py (BuildMaster.submitBuildSet): same * buildbot/process/base.py (BuildRequest): same, replace waitUntilStarted with subscribe/unsubscribe * buildbot/process/builder.py (BuilderControl.forceBuild): use subscribe instead of waitUntilStarted * buildbot/status/base.py (StatusReceiver.buildsetSubmitted): stub for new method * buildbot/status/client.py (StatusClientPerspective.builderRemoved): same * buildbot/test/test_buildreq.py: update for new code * buildbot/test/test_control.py (Force.testRequest): same Index: base.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/process/base.py,v retrieving revision 1.57 retrieving revision 1.58 diff -u -d -r1.57 -r1.58 --- base.py 19 Jul 2005 23:23:21 -0000 1.57 +++ base.py 17 Aug 2005 02:15:37 -0000 1.58 @@ -12,7 +12,7 @@ from buildbot.twcompat import implements from buildbot.util import now from buildbot.status.builder import SUCCESS, WARNINGS, FAILURE, EXCEPTION -from buildbot.status.builder import Results +from buildbot.status.builder import Results, BuildRequestStatus from buildbot.status.progress import BuildProgress class BuildRequest: @@ -31,6 +31,9 @@ I may be part of a BuildSet, in which case I will report status results to it. + I am paired with a BuildRequestStatus object, to which I feed status + information. + @type source: a L{buildbot.buildset.SourceStamp} instance. @ivar source: the source code that this BuildRequest use @@ -55,12 +58,15 @@ else: __implements__ = interfaces.IBuildRequestControl, - def __init__(self, reason, source): + def __init__(self, reason, source, builderName=None): + # TODO: remove the =None on builderName, it is there so I don't have + # to change a lot of tests that create BuildRequest objects assert interfaces.ISourceStamp(source, None) self.reason = reason self.source = source self.start_watchers = [] self.finish_watchers = [] + self.status = BuildRequestStatus(source, builderName) def canBeMergedWith(self, other): return self.source.canBeMergedWith(other.source) @@ -76,17 +82,6 @@ reasons.append(req.reason) return ", ".join(reasons) - def waitUntilStarted(self): - """Get a Deferred that will fire (with a - L{buildbot.interfaces.IBuildControl} instance) when the build starts. - TODO: there could be multiple Builds to satisfy a BuildRequest, but - this API only allows you to wait for the first one.""" - # TODO: if you call this after the build has started, the Deferred - # will never fire. - d = defer.Deferred() - self.start_watchers.append(d) - return d - def waitUntilFinished(self): """Get a Deferred that will fire (with a L{buildbot.interfaces.IBuildStatus} instance when the build @@ -107,9 +102,11 @@ times, since interrupted builds and lost buildslaves may force multiple Builds to be run until the fate of the BuildRequest is known for certain.""" - for w in self.start_watchers: - w.callback(build) - self.start_watchers = [] + for o in self.start_watchers[:]: + # these observers get the IBuildControl + o(build) + # while these get the IBuildStatus + self.status.buildStarted(buildstatus) def finished(self, buildstatus): """This is called by the Builder when the BuildRequest has been @@ -122,6 +119,12 @@ self.finish_watchers = [] # IBuildRequestControl + + def subscribe(self, observer): + self.start_watchers.append(observer) + def unsubscribe(self, observer): + self.start_watchers.remove(observer) + def cancel(self): """Cancel this request. This can only be successful if the Build has not yet been started. Index: builder.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/process/builder.py,v retrieving revision 1.28 retrieving revision 1.29 diff -u -d -r1.28 -r1.29 --- builder.py 20 Jul 2005 05:36:56 -0000 1.28 +++ builder.py 17 Aug 2005 02:15:37 -0000 1.29 @@ -521,9 +521,13 @@ __implements__ = interfaces.IBuilderControl, def forceBuild(self, who, reason): - """This is a shortcut for building the current HEAD. You get back a - BuildRequest, just as if you'd asked politely. To get control of the - resulting build, you'll need to wait for req.waitUntilStarted(). + """This is a shortcut for building the current HEAD. + + (false: You get back a BuildRequest, just as if you'd asked politely. + To get control of the resulting build, you'll need use + req.subscribe() .) + + (true: You get back a Deferred that fires with an IBuildControl) This shortcut peeks into the Builder and raises an exception if there is no slave available, to make backwards-compatibility a little @@ -540,7 +544,22 @@ raise interfaces.NoSlaveError("There are no slaves connected") req = base.BuildRequest(reason, sourcestamp.SourceStamp()) self.requestBuild(req) - return req.waitUntilStarted() + # this is a hack that fires the Deferred for the first build and + # ignores any others + class Watcher: + def __init__(self, req): + self.req = req + def wait(self): + self.d = d = defer.Deferred() + req.subscribe(self.started) + return d + def started(self, bs): + if self.d: + self.req.unsubscribe(self.started) + self.d.callback(bs) + self.d = None + w = Watcher(req) + return w.wait() def requestBuild(self, req): self.original.submitBuildRequest(req) From warner at users.sourceforge.net Thu Aug 18 08:30:04 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Thu, 18 Aug 2005 08:30:04 +0000 Subject: [Buildbot-commits] buildbot/buildbot/scripts tryclient.py,1.6,1.7 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/scripts In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21002/buildbot/scripts Modified Files: tryclient.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-297 Creator: Brian Warner make 'try' status reporting actually work * buildbot/scripts/tryclient.py (Try): make 'try' status reporting actually work. It's functional but still kind of clunky. Also, it only works with the pb-style.. needs to be made to work with the jobdir-style too. * buildbot/status/client.py (RemoteBuildSet): new class (RemoteBuildRequest): same (RemoteBuild.remote_waitUntilFinished): return the RemoteBuild object, not the internal BuildStatus object. (RemoteBuild.remote_subscribe): new method to subscribe to builds outside of the usual buildStarted() return value. (BuildSubscriber): support class for RemoteBuild.remote_subscribe * buildbot/scheduler.py (Try_Jobdir): convey buildsetID properly (Try_Userpass_Perspective.perspective_try): return a remotely usable BuildSetStatus object * buildbot/interfaces.py (IBuildStatus): remove obsolete isStarted()/waitUntilStarted() --This line, and those below, will be ignored-- Files to commit: This list might be incomplete or outdated if editing the log message was not invoked from an up-to-date changes buffer! Index: tryclient.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/scripts/tryclient.py,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- tryclient.py 16 Aug 2005 00:23:52 -0000 1.6 +++ tryclient.py 18 Aug 2005 08:30:01 -0000 1.7 @@ -1,7 +1,7 @@ # -*- test-case-name: buildbot.test.test_scheduler,buildbot.test.test_vc -*- -import os, re, time -from twisted.internet import utils, protocol, defer, reactor +import sys, os, re, time +from twisted.internet import utils, protocol, defer, reactor, task from twisted.spread import pb from twisted.cred import credentials from twisted.python import log @@ -9,6 +9,7 @@ from buildbot.sourcestamp import SourceStamp from buildbot.scripts import runner from buildbot.util import now +from buildbot.status import builder class SourceStampExtractor: @@ -191,7 +192,7 @@ rc = status_object.value.exitCode self.d.callback((sig, rc)) -class Try: +class Try(pb.Referenceable): buildsetStatus = None quiet = False @@ -291,12 +292,147 @@ # returns a Deferred that fires when the builds have finished, and # may emit status messages while we wait wait = bool(self.getopt("wait", "try_wait", False)) - if not self.buildsetStatus: - # contact the status port, acquire a remotereference to the - # corresponding BuildSetStatus object. - pass + if not wait: + # TODO: emit the URL where they can follow the builds + return + d = self.running = defer.Deferred() + if self.buildsetStatus: + self._getStatus_1() + # TODO: contact the status port, acquire a remotereference to the + # corresponding BuildSetStatus object. + return d + + def _getStatus_1(self, res=None): + if res: + self.buildsetStatus = res + # gather the set of BuildRequests + d = self.buildsetStatus.callRemote("getBuildRequests") + d.addCallback(self._getStatus_2) + + def _getStatus_2(self, brs): + self.builderNames = [] + self.buildRequests = {} + + # self.builds holds the current BuildStatus object for each one + self.builds = {} + + # self.outstanding holds the list of builderNames which haven't + # finished yet + self.outstanding = [] + + # self.results holds the list of build results. It holds a tuple of + # (result, text) + self.results = {} + + # self.currentStep holds the name of the Step that each build is + # currently running + self.currentStep = {} + + # self.ETA holds the expected finishing time (absolute time since + # epoch) + self.ETA = {} + + for n,br in brs: + self.builderNames.append(n) + self.buildRequests[n] = br + self.builds[n] = None + self.outstanding.append(n) + self.results[n] = [None,None] + self.currentStep[n] = None + self.ETA[n] = None + # get new Builds for this buildrequest. We follow each one until + # it finishes or is interrupted. + br.callRemote("subscribe", self) + + # now that those queries are in transit, we can start the + # display-status-every-30-seconds loop + self.printloop = task.LoopingCall(self.printStatus) + self.printloop.start(3, now=False) + + + # these methods are invoked by the status objects we've subscribed to + + def remote_newbuild(self, bs, builderName): + if self.builds[builderName]: + self.builds[builderName].callRemote("unsubscribe", self) + self.builds[builderName] = bs + bs.callRemote("subscribe", self, 20) + d = bs.callRemote("waitUntilFinished") + d.addCallback(self._build_finished, builderName) + + def remote_stepStarted(self, buildername, build, stepname, step): + self.currentStep[buildername] = stepname + + def remote_stepFinished(self, buildername, build, stepname, step, results): pass + def remote_buildETAUpdate(self, buildername, build, eta): + self.ETA[buildername] = now() + eta + + def _build_finished(self, bs, builderName): + # we need to collect status from the newly-finished build. We don't + # remove the build from self.outstanding until we've collected + # everything we want. + self.builds[builderName] = None + self.ETA[builderName] = None + self.currentStep[builderName] = "finished" + d = bs.callRemote("getResults") + d.addCallback(self._build_finished_2, bs, builderName) + return d + def _build_finished_2(self, results, bs, builderName): + self.results[builderName][0] = results + d = bs.callRemote("getText") + d.addCallback(self._build_finished_3, builderName) + return d + def _build_finished_3(self, text, builderName): + self.results[builderName][1] = text + + self.outstanding.remove(builderName) + if not self.outstanding: + # all done + return self.statusDone() + + def printStatus(self): + names = self.buildRequests.keys() + names.sort() + for n in names: + if n not in self.outstanding: + # the build is finished, and we have results + code,text = self.results[n] + t = builder.Results[code] + if text: + t += " (%s)" % " ".join(text) + elif self.builds[n]: + t = self.currentStep[n] or "building" + if self.ETA[n]: + t += " [ETA %ds]" % (self.ETA[n] - now()) + else: + t = "no build" + self.announce("%s: %s" % (n, t)) + self.announce("") + + def statusDone(self): + self.printloop.stop() + print "All Builds Complete" + # TODO: include a URL for all failing builds + names = self.buildRequests.keys() + names.sort() + happy = True + for n in names: + code,text = self.results[n] + t = "%s: %s" % (n, builder.Results[code]) + if text: + t += " (%s)" % " ".join(text) + print t + if self.results[n] != builder.SUCCESS: + happy = False + + if happy: + self.exitcode = 0 + else: + self.exitcode = 1 + self.running.callback(self.exitcode) + def announce(self, message): if not self.quiet: print message @@ -305,19 +441,20 @@ # we can't do spawnProcess until we're inside reactor.run(), so get # funky print "using '%s' connect method" % self.connect + self.exitcode = 0 d = defer.Deferred() d.addCallback(lambda res: self.createJob()) d.addCallback(lambda res: self.announce("job created")) d.addCallback(lambda res: self.deliverJob()) d.addCallback(lambda res: self.announce("job has been delivered")) d.addCallback(lambda res: self.getStatus()) - d.addCallback(lambda res: self.announce("status object acquired")) d.addErrback(log.err) d.addCallback(self.cleanup) d.addCallback(lambda res: reactor.stop()) reactor.callLater(0, d.callback, None) reactor.run() + sys.exit(self.exitcode) def logErr(self, why): log.err(why) @@ -325,7 +462,6 @@ print why def cleanup(self, res=None): - print "cleaning up" if self.buildsetStatus: self.buildsetStatus.broker.transport.loseConnection() From warner at users.sourceforge.net Thu Aug 18 08:30:04 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Thu, 18 Aug 2005 08:30:04 +0000 Subject: [Buildbot-commits] buildbot/buildbot interfaces.py,1.29,1.30 scheduler.py,1.5,1.6 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21002/buildbot Modified Files: interfaces.py scheduler.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-297 Creator: Brian Warner make 'try' status reporting actually work * buildbot/scripts/tryclient.py (Try): make 'try' status reporting actually work. It's functional but still kind of clunky. Also, it only works with the pb-style.. needs to be made to work with the jobdir-style too. * buildbot/status/client.py (RemoteBuildSet): new class (RemoteBuildRequest): same (RemoteBuild.remote_waitUntilFinished): return the RemoteBuild object, not the internal BuildStatus object. (RemoteBuild.remote_subscribe): new method to subscribe to builds outside of the usual buildStarted() return value. (BuildSubscriber): support class for RemoteBuild.remote_subscribe * buildbot/scheduler.py (Try_Jobdir): convey buildsetID properly (Try_Userpass_Perspective.perspective_try): return a remotely usable BuildSetStatus object * buildbot/interfaces.py (IBuildStatus): remove obsolete isStarted()/waitUntilStarted() --This line, and those below, will be ignored-- Files to commit: This list might be incomplete or outdated if editing the log message was not invoked from an up-to-date changes buffer! Index: interfaces.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/interfaces.py,v retrieving revision 1.29 retrieving revision 1.30 diff -u -d -r1.29 -r1.30 --- interfaces.py 17 Aug 2005 02:15:36 -0000 1.29 +++ interfaces.py 18 Aug 2005 08:30:00 -0000 1.30 @@ -121,8 +121,6 @@ pass def getReason(): pass - def getChanges(): - pass def getID(): """Return the BuildSet's ID string, if any. The 'try' feature uses a random string as a BuildSetID to relate submitted jobs with the @@ -255,7 +253,7 @@ class IBuildStatus(Interface): """I represent the status of a single Build/BuildRequest. It could be - finished, in-progress, or not yet started.""" + in-progress or finished.""" def getBuilder(): """ @@ -264,15 +262,6 @@ @rtype: implementor of L{IBuilderStatus} """ - def isStarted(): - """Return a boolean. True means the build has started, False means it - is still in the pending queue.""" - - def waitUntilStarted(): - """Return a Deferred that will fire (with this IBuildStatus instance - as an argument) when the build starts. If the build has already - started, this deferred will fire right away.""" - def isFinished(): """Return a boolean. True means the build has finished, False means it is still running.""" @@ -322,8 +311,6 @@ make the Changes that went into it (build sheriffs, code-domain owners).""" - # once the build has started, the following methods become available - def getNumber(): """Within each builder, each Build has a number. Return it.""" Index: scheduler.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/scheduler.py,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- scheduler.py 11 Aug 2005 08:22:17 -0000 1.5 +++ scheduler.py 18 Aug 2005 08:30:00 -0000 1.6 @@ -376,7 +376,7 @@ patchlevel = int(patchlevel) patch = (patchlevel, diff) ss = SourceStamp(branch, baserev, patch) - return builderNames, ss + return builderNames, ss, buildsetID def messageReceived(self, filename): md = os.path.join(self.parent.basedir, self.jobdir) @@ -385,7 +385,7 @@ os.rename(os.path.join(md, "new", filename), os.path.join(md, "cur", filename)) try: - builderNames, ss = self.parseJob(f) + builderNames, ss, bsid = self.parseJob(f) except BadJobfile: log.msg("%s reports a bad jobfile in %s" % (self, filename)) log.err() @@ -402,7 +402,8 @@ % (self.builderNames,)) return - bs = buildset.BuildSet(builderNames, ss) + reason = "'try' job" + bs = buildset.BuildSet(builderNames, ss, reason=reason, bsid=bsid) self.parent.submitBuildSet(bs) class Try_Userpass(TryBase): @@ -456,9 +457,11 @@ % (self.parent.builderNames,)) return ss = SourceStamp(branch, revision, patch) - bs = buildset.BuildSet(builderNames, ss) - bss = self.parent.submitBuildSet(bs) + reason = "'try' job from user %s" % self.username + bs = buildset.BuildSet(builderNames, ss, reason=reason) + self.parent.submitBuildSet(bs) - # TODO: return a remotely-usable BuildSetStatus object - return bss + # return a remotely-usable BuildSetStatus object + from buildbot.status.client import makeRemote + return makeRemote(bs.status) From warner at users.sourceforge.net Thu Aug 18 08:30:06 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Thu, 18 Aug 2005 08:30:06 +0000 Subject: [Buildbot-commits] buildbot ChangeLog,1.492,1.493 Message-ID: Update of /cvsroot/buildbot/buildbot In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21002 Modified Files: ChangeLog Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-297 Creator: Brian Warner make 'try' status reporting actually work * buildbot/scripts/tryclient.py (Try): make 'try' status reporting actually work. It's functional but still kind of clunky. Also, it only works with the pb-style.. needs to be made to work with the jobdir-style too. * buildbot/status/client.py (RemoteBuildSet): new class (RemoteBuildRequest): same (RemoteBuild.remote_waitUntilFinished): return the RemoteBuild object, not the internal BuildStatus object. (RemoteBuild.remote_subscribe): new method to subscribe to builds outside of the usual buildStarted() return value. (BuildSubscriber): support class for RemoteBuild.remote_subscribe * buildbot/scheduler.py (Try_Jobdir): convey buildsetID properly (Try_Userpass_Perspective.perspective_try): return a remotely usable BuildSetStatus object * buildbot/interfaces.py (IBuildStatus): remove obsolete isStarted()/waitUntilStarted() --This line, and those below, will be ignored-- Files to commit: This list might be incomplete or outdated if editing the log message was not invoked from an up-to-date changes buffer! Index: ChangeLog =================================================================== RCS file: /cvsroot/buildbot/buildbot/ChangeLog,v retrieving revision 1.492 retrieving revision 1.493 diff -u -d -r1.492 -r1.493 --- ChangeLog 17 Aug 2005 02:15:38 -0000 1.492 +++ ChangeLog 18 Aug 2005 08:30:01 -0000 1.493 @@ -1,3 +1,25 @@ +2005-08-18 Brian Warner + + * buildbot/scripts/tryclient.py (Try): make 'try' status reporting + actually work. It's functional but still kind of clunky. Also, it + only works with the pb-style.. needs to be made to work with the + jobdir-style too. + + * buildbot/status/client.py (RemoteBuildSet): new class + (RemoteBuildRequest): same + (RemoteBuild.remote_waitUntilFinished): return the RemoteBuild + object, not the internal BuildStatus object. + (RemoteBuild.remote_subscribe): new method to subscribe to builds + outside of the usual buildStarted() return value. + (BuildSubscriber): support class for RemoteBuild.remote_subscribe + + * buildbot/scheduler.py (Try_Jobdir): convey buildsetID properly + (Try_Userpass_Perspective.perspective_try): return a remotely + usable BuildSetStatus object + + * buildbot/interfaces.py (IBuildStatus): remove obsolete + isStarted()/waitUntilStarted() + 2005-08-16 Brian Warner * buildbot/status/builder.py: implement IBuildSetStatus and From warner at users.sourceforge.net Thu Aug 18 08:30:04 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Thu, 18 Aug 2005 08:30:04 +0000 Subject: [Buildbot-commits] buildbot/buildbot/status client.py,1.21,1.22 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/status In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21002/buildbot/status Modified Files: client.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-297 Creator: Brian Warner make 'try' status reporting actually work * buildbot/scripts/tryclient.py (Try): make 'try' status reporting actually work. It's functional but still kind of clunky. Also, it only works with the pb-style.. needs to be made to work with the jobdir-style too. * buildbot/status/client.py (RemoteBuildSet): new class (RemoteBuildRequest): same (RemoteBuild.remote_waitUntilFinished): return the RemoteBuild object, not the internal BuildStatus object. (RemoteBuild.remote_subscribe): new method to subscribe to builds outside of the usual buildStarted() return value. (BuildSubscriber): support class for RemoteBuild.remote_subscribe * buildbot/scheduler.py (Try_Jobdir): convey buildsetID properly (Try_Userpass_Perspective.perspective_try): return a remotely usable BuildSetStatus object * buildbot/interfaces.py (IBuildStatus): remove obsolete isStarted()/waitUntilStarted() --This line, and those below, will be ignored-- Files to commit: This list might be incomplete or outdated if editing the log message was not invoked from an up-to-date changes buffer! Index: client.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/status/client.py,v retrieving revision 1.21 retrieving revision 1.22 diff -u -d -r1.21 -r1.22 --- client.py 17 Aug 2005 02:15:37 -0000 1.21 +++ client.py 18 Aug 2005 08:30:00 -0000 1.22 @@ -22,6 +22,48 @@ return None return IRemote(obj) + +class RemoteBuildSet(pb.Referenceable): + def __init__(self, buildset): + self.b = buildset + + def remote_getSourceStamp(self): + return self.b.getSourceStamp() + + def remote_getReason(self): + return self.b.getReason() + + def remote_getID(self): + return self.b.getID() + + def remote_getBuilderNames(self): + return self.b.getBuilderNames() + + def remote_getBuildRequests(self): + """Returns a list of (builderName, BuildRequest) tuples.""" + return [(br.getBuilderName(), IRemote(br)) + for br in self.b.getBuildRequests()] + + def remote_isFinished(self): + return self.b.isFinished() + + def remote_waitUntilSuccess(self): + d = self.b.waitUntilSuccess() + d.addCallback(lambda res: self) + return d + + def remote_waitUntilFinished(self): + d = self.b.waitUntilFinished() + d.addCallback(lambda res: self) + return d + + def remote_getResults(self): + return self.b.getResults() + +components.registerAdapter(RemoteBuildSet, + interfaces.IBuildSetStatus, IRemote) + + class RemoteBuilder(pb.Referenceable): def __init__(self, builder): self.b = builder @@ -51,9 +93,46 @@ components.registerAdapter(RemoteBuilder, interfaces.IBuilderStatus, IRemote) + +class RemoteBuildRequest(pb.Referenceable): + def __init__(self, buildreq): + self.b = buildreq + self.observers = [] + + def remote_getSourceStamp(self): + return self.b.getSourceStamp() + + def remote_getBuilderName(self): + return self.b.getBuilderName() + + def remote_subscribe(self, observer): + """The observer's remote_newbuild method will be called (with two + arguments: the RemoteBuild object, and our builderName) for each new + Build that is created to handle this BuildRequest.""" + self.observers.append(observer) + def send(bs): + d = observer.callRemote("newbuild", + IRemote(bs), self.b.getBuilderName()) + d.addErrback(lambda err: None) + reactor.callLater(0, self.b.subscribe, send) + + def remote_unsubscribe(self, observer): + # PB (well, at least oldpb) doesn't re-use RemoteReference instances, + # so sending the same object across the wire twice will result in two + # separate objects that compare as equal ('a is not b' and 'a == b'). + # That means we can't use a simple 'self.observers.remove(observer)' + # here. + for o in self.observers: + if o == observer: + self.observers.remove(o) + +components.registerAdapter(RemoteBuildRequest, + interfaces.IBuildRequestStatus, IRemote) + class RemoteBuild(pb.Referenceable): def __init__(self, build): self.b = build + self.observers = [] def remote_getBuilderName(self): return self.b.getBuilder().getName() @@ -82,7 +161,9 @@ def remote_waitUntilFinished(self): # the Deferred returned by callRemote() will fire when this build is # finished - return self.b.waitUntilFinished() + d = self.b.waitUntilFinished() + d.addCallback(lambda res: self) + return d def remote_getETA(self): return self.b.getETA() @@ -96,15 +177,60 @@ def remote_getColor(self): return self.b.getColor() + def remote_getResults(self): + return self.b.getResults() + def remote_getLogs(self): logs = {} for name,log in self.b.getLogs().items(): logs[name] = IRemote(log) return logs + def remote_subscribe(self, observer, updateInterval=None): + """The observer will have remote_stepStarted(buildername, build, + stepname, step), remote_stepFinished(buildername, build, stepname, + step, results), and maybe remote_buildETAUpdate(buildername, build, + eta)) messages sent to it.""" + self.observers.append(observer) + s = BuildSubscriber(observer) + self.b.subscribe(s, updateInterval) + + def remote_unsubscribe(self, observer): + # TODO: is the observer automatically unsubscribed when the build + # finishes? Or are they responsible for unsubscribing themselves + # anyway? How do we avoid a race condition here? + for o in self.observers: + if o == observer: + self.observers.remove(o) + + components.registerAdapter(RemoteBuild, interfaces.IBuildStatus, IRemote) +class BuildSubscriber: + def __init__(self, observer): + self.observer = observer + + def buildETAUpdate(self, build, eta): + self.observer.callRemote("buildETAUpdate", + build.getBuilder().getName(), + IRemote(build), + eta) + + def stepStarted(self, build, step): + self.observer.callRemote("stepStarted", + build.getBuilder().getName(), + IRemote(build), + step.getName(), IRemote(step)) + return None + + def stepFinished(self, build, step, results): + self.observer.callRemote("stepFinished", + build.getBuilder().getName(), + IRemote(build), + step.getName(), IRemote(step), + results) + class RemoteBuildStep(pb.Referenceable): def __init__(self, step): From warner at users.sourceforge.net Wed Aug 24 08:36:14 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 24 Aug 2005 08:36:14 +0000 Subject: [Buildbot-commits] site index.html,1.46,1.47 Message-ID: Update of /cvsroot/buildbot/site In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2592 Modified Files: index.html Log Message: add Ethereal Index: index.html =================================================================== RCS file: /cvsroot/buildbot/site/index.html,v retrieving revision 1.46 retrieving revision 1.47 diff -u -d -r1.46 -r1.47 --- index.html 16 Aug 2005 20:14:06 -0000 1.46 +++ index.html 24 Aug 2005 08:36:12 -0000 1.47 @@ -84,8 +84,8 @@

      • twistedmatrix.com: - The original publically-visible Buildbot installation runs the Twisted unit - test suite.
      • + The original publically-visible Buildbot installation runs the Twisted unit test suite.
      • TTimo (at Id software) is using a Buildbot for testing Wolfenstein: Enemy Territory Linux.
      • @@ -127,7 +127,8 @@
      • Rene Rivera says that the well-known Boost C++ project is moving all their testing to run under a buildbot.
      • + href="http://build.redshift-software.com:9990">buildbot, but it does + not currently (aug 2005) appear to be online yet.
      • The Monotone version control system is using a buildbot to @@ -144,6 +145,11 @@ href="http://netboxblue.com/">Netbox Blue, uses a buildbot to build and test their network security appliance.
      • +
      • Ulf Lamping reports that the Ethereal project, a well-known packet + sniffer, uses a buildbot for + their cross-platform compatibility testing.
      • +
      • install a Buildbot today and get your name added here!
      @@ -166,5 +172,5 @@ align="right" /> -Last modified: Tue Aug 16 13:13:47 PDT 2005 +Last modified: Wed Aug 24 01:35:19 PDT 2005 From warner at users.sourceforge.net Wed Aug 31 01:12:09 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 31 Aug 2005 01:12:09 +0000 Subject: [Buildbot-commits] buildbot/buildbot/test test_scheduler.py,1.4,1.5 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9855/buildbot/test Modified Files: test_scheduler.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-299 Creator: Brian Warner make jobdir-style 'try' report status properly * buildbot/scripts/tryclient.py (Try): make jobdir-style 'try' report status properly. * buildbot/status/client.py (StatusClientPerspective): add a perspective_getBuildSets method for the benefit of jobdir-style 'try'. * docs/buildbot.texinfo (try): more docs * buildbot/test/test_scheduler.py (Scheduling.testGetBuildSets): new test case Index: test_scheduler.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/test/test_scheduler.py,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- test_scheduler.py 11 Aug 2005 20:21:30 -0000 1.4 +++ test_scheduler.py 31 Aug 2005 01:12:07 -0000 1.5 @@ -7,7 +7,7 @@ from twisted.application import service from twisted.spread import pb -from buildbot import scheduler, sourcestamp +from buildbot import scheduler, sourcestamp, buildset, status from buildbot.twcompat import maybeWait from buildbot.changes.changes import Change from buildbot.scripts import tryclient @@ -230,3 +230,12 @@ reactor.callLater(0, d.callback, None) return d + def testGetBuildSets(self): + # validate IStatus.getBuildSets + s = status.builder.Status(None, ".") + bs1 = buildset.BuildSet(["a","b"], sourcestamp.SourceStamp(), + reason="one", bsid="1") + s.buildsetSubmitted(bs1.status) + self.failUnlessEqual(s.getBuildSets(), [bs1.status]) + bs1.status.notifyFinishedWatchers() + self.failUnlessEqual(s.getBuildSets(), []) From warner at users.sourceforge.net Wed Aug 31 01:12:09 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 31 Aug 2005 01:12:09 +0000 Subject: [Buildbot-commits] buildbot ChangeLog,1.493,1.494 Message-ID: Update of /cvsroot/buildbot/buildbot In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9855 Modified Files: ChangeLog Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-299 Creator: Brian Warner make jobdir-style 'try' report status properly * buildbot/scripts/tryclient.py (Try): make jobdir-style 'try' report status properly. * buildbot/status/client.py (StatusClientPerspective): add a perspective_getBuildSets method for the benefit of jobdir-style 'try'. * docs/buildbot.texinfo (try): more docs * buildbot/test/test_scheduler.py (Scheduling.testGetBuildSets): new test case Index: ChangeLog =================================================================== RCS file: /cvsroot/buildbot/buildbot/ChangeLog,v retrieving revision 1.493 retrieving revision 1.494 diff -u -d -r1.493 -r1.494 --- ChangeLog 18 Aug 2005 08:30:01 -0000 1.493 +++ ChangeLog 31 Aug 2005 01:12:07 -0000 1.494 @@ -1,3 +1,14 @@ +2005-08-30 Brian Warner + + * buildbot/scripts/tryclient.py (Try): make jobdir-style 'try' + report status properly. + * buildbot/status/client.py (StatusClientPerspective): add a + perspective_getBuildSets method for the benefit of jobdir-style + 'try'. + * docs/buildbot.texinfo (try): more docs + * buildbot/test/test_scheduler.py (Scheduling.testGetBuildSets): + new test case + 2005-08-18 Brian Warner * buildbot/scripts/tryclient.py (Try): make 'try' status reporting From warner at users.sourceforge.net Wed Aug 31 01:12:08 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 31 Aug 2005 01:12:08 +0000 Subject: [Buildbot-commits] buildbot/buildbot/scripts runner.py,1.34,1.35 tryclient.py,1.7,1.8 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/scripts In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9855/buildbot/scripts Modified Files: runner.py tryclient.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-299 Creator: Brian Warner make jobdir-style 'try' report status properly * buildbot/scripts/tryclient.py (Try): make jobdir-style 'try' report status properly. * buildbot/status/client.py (StatusClientPerspective): add a perspective_getBuildSets method for the benefit of jobdir-style 'try'. * docs/buildbot.texinfo (try): more docs * buildbot/test/test_scheduler.py (Scheduling.testGetBuildSets): new test case Index: runner.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/scripts/runner.py,v retrieving revision 1.34 retrieving revision 1.35 diff -u -d -r1.34 -r1.35 --- runner.py 15 Aug 2005 18:05:05 -0000 1.34 +++ runner.py 31 Aug 2005 01:12:06 -0000 1.35 @@ -610,6 +610,7 @@ ] def doTryServer(config): + import md5 jobdir = os.path.expanduser(config["jobdir"]) job = sys.stdin.read() # now do a 'safecat'-style write to jobdir/tmp, then move atomically to Index: tryclient.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/scripts/tryclient.py,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- tryclient.py 18 Aug 2005 08:30:01 -0000 1.7 +++ tryclient.py 31 Aug 2005 01:12:06 -0000 1.8 @@ -187,11 +187,54 @@ def connectionMade(self): self.transport.write(self.job) self.transport.closeStdin() + def outReceived(self, data): + sys.stdout.write(data) + def errReceived(self, data): + sys.stderr.write(data) def processEnded(self, status_object): sig = status_object.value.signal rc = status_object.value.exitCode + if sig != None or rc != 0: + self.d.errback(RuntimeError("remote 'buildbot tryserver' failed" + ": sig=%s, rc=%s" % (sig, rc))) + return self.d.callback((sig, rc)) +class BuildSetStatusGrabber: + retryCount = 5 # how many times to we try to grab the BuildSetStatus? + retryDelay = 3 # seconds to wait between attempts + + def __init__(self, status, bsid): + self.status = status + self.bsid = bsid + + def grab(self): + # return a Deferred that either fires with the BuildSetStatus + # reference or errbacks because we were unable to grab it + self.d = defer.Deferred() + # wait a second before querying to give the master's maildir watcher + # a chance to see the job + reactor.callLater(1, self.go) + return self.d + + def go(self, dummy=None): + if self.retryCount == 0: + raise RuntimeError("couldn't find matching buildset") + self.retryCount -= 1 + d = self.status.callRemote("getBuildSets") + d.addCallback(self._gotSets) + + def _gotSets(self, buildsets): + for bs,bsid in buildsets: + if bsid == self.bsid: + # got it + self.d.callback(bs) + return + d = defer.Deferred() + d.addCallback(self.go) + reactor.callLater(self.retryDelay, d.callback, None) + + class Try(pb.Referenceable): buildsetStatus = None quiet = False @@ -241,7 +284,8 @@ self.sourcestamp = ss if self.connect == "ssh": patchlevel, diff = ss.patch - self.jobfile = createJobfile(bsid, ss.branch or "", ss.revision, + self.jobfile = createJobfile(self.bsid, + ss.branch or "", ss.revision, patchlevel, diff, self.builderNames) @@ -256,7 +300,7 @@ trydir = self.getopt("trydir", "try_dir") argv = ["ssh", "-l", tryuser, tryhost, - "buildbot", "tryserver", trydir] + "buildbot", "tryserver", "--jobdir", trydir] # now run this command and feed the contents of 'job' into stdin pp = RemoteTryPP(self.jobfile) @@ -294,14 +338,32 @@ wait = bool(self.getopt("wait", "try_wait", False)) if not wait: # TODO: emit the URL where they can follow the builds + print "not waiting for builds to finish" return d = self.running = defer.Deferred() if self.buildsetStatus: self._getStatus_1() - # TODO: contact the status port, acquire a remotereference to the - # corresponding BuildSetStatus object. + # contact the status port + # we're probably using the ssh style + master = self.getopt("master", "masterstatus") + host, port = master.split(":") + port = int(port) + self.announce("contacting the status port at %s:%d" % (host, port)) + f = pb.PBClientFactory() + creds = credentials.UsernamePassword("statusClient", "clientpw") + d = f.login(creds) + reactor.connectTCP(host, port, f) + d.addCallback(self._getStatus_ssh_1) + return self.running + + def _getStatus_ssh_1(self, remote): + # find a remotereference to the corresponding BuildSetStatus object + self.announce("waiting for job to be accepted") + g = BuildSetStatusGrabber(remote, self.bsid) + d = g.grab() + d.addCallback(self._getStatus_1) return d - + def _getStatus_1(self, res=None): if res: self.buildsetStatus = res From warner at users.sourceforge.net Wed Aug 31 01:12:09 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 31 Aug 2005 01:12:09 +0000 Subject: [Buildbot-commits] buildbot/docs buildbot.texinfo,1.19,1.20 Message-ID: Update of /cvsroot/buildbot/buildbot/docs In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9855/docs Modified Files: buildbot.texinfo Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-299 Creator: Brian Warner make jobdir-style 'try' report status properly * buildbot/scripts/tryclient.py (Try): make jobdir-style 'try' report status properly. * buildbot/status/client.py (StatusClientPerspective): add a perspective_getBuildSets method for the benefit of jobdir-style 'try'. * docs/buildbot.texinfo (try): more docs * buildbot/test/test_scheduler.py (Scheduling.testGetBuildSets): new test case Index: buildbot.texinfo =================================================================== RCS file: /cvsroot/buildbot/buildbot/docs/buildbot.texinfo,v retrieving revision 1.19 retrieving revision 1.20 diff -u -d -r1.19 -r1.20 --- buildbot.texinfo 15 Aug 2005 18:05:06 -0000 1.19 +++ buildbot.texinfo 31 Aug 2005 01:12:06 -0000 1.20 @@ -3770,6 +3770,14 @@ @file{.buildbot/options} as @code{try_host}, @code{try_username}, @code{try_password}, and @code{try_dir}. +In addition, the SSH approach needs to connect to a PBListener status +port, so it can retrieve and report the results of the build (the PB +approach uses the existing connection to retrieve status information, +so this step is not necessary). This requires a @option{--master} +argument, or a @code{masterstatus} entry in @file{.buildbot/options}, +in the form of a HOSTNAME:PORT string. + + @heading choosing the Builders A trial build is performed on multiple Builders at the same time, and From warner at users.sourceforge.net Wed Aug 31 01:12:08 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 31 Aug 2005 01:12:08 +0000 Subject: [Buildbot-commits] buildbot/buildbot/status client.py,1.22,1.23 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/status In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9855/buildbot/status Modified Files: client.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-299 Creator: Brian Warner make jobdir-style 'try' report status properly * buildbot/scripts/tryclient.py (Try): make jobdir-style 'try' report status properly. * buildbot/status/client.py (StatusClientPerspective): add a perspective_getBuildSets method for the benefit of jobdir-style 'try'. * docs/buildbot.texinfo (try): more docs * buildbot/test/test_scheduler.py (Scheduling.testGetBuildSets): new test case Index: client.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/status/client.py,v retrieving revision 1.22 retrieving revision 1.23 diff -u -d -r1.22 -r1.23 --- client.py 18 Aug 2005 08:30:00 -0000 1.22 +++ client.py 31 Aug 2005 01:12:06 -0000 1.23 @@ -413,6 +413,11 @@ self.subscribed_to.remove(self.status) self.client = None + def perspective_getBuildSets(self): + """This returns tuples of (buildset, bsid), because that is much more + convenient for tryclient.""" + return [(IRemote(s), s.getID()) for s in self.status.getBuildSets()] + def perspective_getBuilderNames(self): return self.status.getBuilderNames() From warner at users.sourceforge.net Wed Aug 31 01:51:27 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 31 Aug 2005 01:51:27 +0000 Subject: [Buildbot-commits] buildbot ChangeLog,1.494,1.495 Message-ID: Update of /cvsroot/buildbot/buildbot In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv16222 Modified Files: ChangeLog Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-301 Creator: Brian Warner 'try': implement unique buildset IDs, getTopdir for CVS/SVN * buildbot/scripts/tryclient.py (getTopdir): implement getTopdir for 'try' on CVS/SVN * buildbot/test/test_runner.py (Try.testGetTopdir): test case * buildbot/scripts/tryclient.py (Try.createJob): implement unique buildset IDs Index: ChangeLog =================================================================== RCS file: /cvsroot/buildbot/buildbot/ChangeLog,v retrieving revision 1.494 retrieving revision 1.495 diff -u -d -r1.494 -r1.495 --- ChangeLog 31 Aug 2005 01:12:07 -0000 1.494 +++ ChangeLog 31 Aug 2005 01:51:25 -0000 1.495 @@ -1,7 +1,13 @@ 2005-08-30 Brian Warner + * buildbot/scripts/tryclient.py (getTopdir): implement getTopdir + for 'try' on CVS/SVN + * buildbot/test/test_runner.py (Try.testGetTopdir): test case + * buildbot/scripts/tryclient.py (Try): make jobdir-style 'try' report status properly. + (Try.createJob): implement unique buildset IDs + * buildbot/status/client.py (StatusClientPerspective): add a perspective_getBuildSets method for the benefit of jobdir-style 'try'. From warner at users.sourceforge.net Wed Aug 31 01:51:27 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 31 Aug 2005 01:51:27 +0000 Subject: [Buildbot-commits] buildbot/buildbot/test test_runner.py,1.9,1.10 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv16222/buildbot/test Modified Files: test_runner.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-301 Creator: Brian Warner 'try': implement unique buildset IDs, getTopdir for CVS/SVN * buildbot/scripts/tryclient.py (getTopdir): implement getTopdir for 'try' on CVS/SVN * buildbot/test/test_runner.py (Try.testGetTopdir): test case * buildbot/scripts/tryclient.py (Try.createJob): implement unique buildset IDs Index: test_runner.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/test/test_runner.py,v retrieving revision 1.9 retrieving revision 1.10 diff -u -d -r1.9 -r1.10 --- test_runner.py 11 Aug 2005 20:21:30 -0000 1.9 +++ test_runner.py 31 Aug 2005 01:51:25 -0000 1.10 @@ -237,3 +237,34 @@ self.failUnlessEqual(t.connect, "ssh") self.failUnlessEqual(t.builderNames, ['b']) + def testGetTopdir(self): + os.mkdir("gettopdir") + os.mkdir(os.path.join("gettopdir", "foo")) + os.mkdir(os.path.join("gettopdir", "foo", "bar")) + open(os.path.join("gettopdir", "1"),"w").write("1") + open(os.path.join("gettopdir", "foo", "2"),"w").write("2") + open(os.path.join("gettopdir", "foo", "bar", "3"),"w").write("3") + + target = os.path.abspath("gettopdir") + t = tryclient.getTopdir("1", "gettopdir") + self.failUnlessEqual(os.path.abspath(t), target) + t = tryclient.getTopdir("1", os.path.join("gettopdir", "foo")) + self.failUnlessEqual(os.path.abspath(t), target) + t = tryclient.getTopdir("1", os.path.join("gettopdir", "foo", "bar")) + self.failUnlessEqual(os.path.abspath(t), target) + + target = os.path.abspath(os.path.join("gettopdir", "foo")) + t = tryclient.getTopdir("2", os.path.join("gettopdir", "foo")) + self.failUnlessEqual(os.path.abspath(t), target) + t = tryclient.getTopdir("2", os.path.join("gettopdir", "foo", "bar")) + self.failUnlessEqual(os.path.abspath(t), target) + + target = os.path.abspath(os.path.join("gettopdir", "foo", "bar")) + t = tryclient.getTopdir("3", os.path.join("gettopdir", "foo", "bar")) + self.failUnlessEqual(os.path.abspath(t), target) + + nonexistent = "nonexistent\n29fis3kq\tBAR" + # hopefully there won't be a real file with that name between here + # and the filesystem root. + self.failUnlessRaises(ValueError, tryclient.getTopdir, nonexistent) + From warner at users.sourceforge.net Wed Aug 31 01:51:27 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 31 Aug 2005 01:51:27 +0000 Subject: [Buildbot-commits] buildbot/buildbot/scripts tryclient.py,1.8,1.9 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/scripts In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv16222/buildbot/scripts Modified Files: tryclient.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-301 Creator: Brian Warner 'try': implement unique buildset IDs, getTopdir for CVS/SVN * buildbot/scripts/tryclient.py (getTopdir): implement getTopdir for 'try' on CVS/SVN * buildbot/test/test_runner.py (Try.testGetTopdir): test case * buildbot/scripts/tryclient.py (Try.createJob): implement unique buildset IDs Index: tryclient.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/scripts/tryclient.py,v retrieving revision 1.8 retrieving revision 1.9 diff -u -d -r1.8 -r1.9 --- tryclient.py 31 Aug 2005 01:12:06 -0000 1.8 +++ tryclient.py 31 Aug 2005 01:51:25 -0000 1.9 @@ -1,6 +1,6 @@ # -*- test-case-name: buildbot.test.test_scheduler,buildbot.test.test_vc -*- -import sys, os, re, time +import sys, os, re, time, random from twisted.internet import utils, protocol, defer, reactor, task from twisted.spread import pb from twisted.cred import credentials @@ -174,11 +174,21 @@ return job def getTopdir(topfile, start=None): + """walk upwards from the current directory until we find this topfile""" if not start: start = os.getcwd() - # TODO: now walk upwards from the current directory until we find this - # topfile - raise NotImplemented + here = start + toomany = 20 + while toomany > 0: + if os.path.exists(os.path.join(here, topfile)): + return here + next = os.path.dirname(here) + if next == here: + break # we've hit the root + here = next + toomany -= 1 + raise ValueError("Unable to find topfile '%s' anywhere from %s upwards" + % (topfile, start)) class RemoteTryPP(protocol.ProcessProtocol): def __init__(self, job): @@ -261,7 +271,10 @@ # created config = self.config opts = self.opts - self.bsid = "buildsetID" # TODO: generate a random (unique) string + # generate a random (unique) string. It would make sense to add a + # hostname and process ID here, but a) I suspect that would cause + # windows portability problems, and b) really this is good enough + self.bsid = "%d-%s" % (time.time(), random.randint(0, 1000000)) # common options vc = self.getopt("vc", "try_vc") From warner at users.sourceforge.net Wed Aug 31 01:51:44 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 31 Aug 2005 01:51:44 +0000 Subject: [Buildbot-commits] buildbot/buildbot interfaces.py,1.30,1.31 scheduler.py,1.6,1.7 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv16253/buildbot Modified Files: interfaces.py scheduler.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-302 Creator: Brian Warner add pending/upcoming builds to the HTML "Current Activity" row * buildbot/status/html.py: add pending/upcoming builds to CurrentBox * buildbot/interfaces.py (IScheduler.getPendingBuildTimes): new method (IStatus.getSchedulers): new method * buildbot/status/builder.py (BuilderStatus): track pendingBuilds (Status.getSchedulers): implement * buildbot/process/builder.py (Builder): maintain BuilderStatus.pendingBuilds * buildbot/scheduler.py (Scheduler.getPendingBuildTimes): new method (TryBase.addChange): Try schedulers should ignore Changes --This line, and those below, will be ignored-- Files to commit: This list might be incomplete or outdated if editing the log message was not invoked from an up-to-date changes buffer! Index: interfaces.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/interfaces.py,v retrieving revision 1.30 retrieving revision 1.31 diff -u -d -r1.30 -r1.31 --- interfaces.py 18 Aug 2005 08:30:00 -0000 1.30 +++ interfaces.py 31 Aug 2005 01:51:41 -0000 1.31 @@ -48,6 +48,15 @@ """Return a list of strings indicating the Builders that this Scheduler might feed.""" + def getPendingBuildTimes(): + """Return a list of timestamps for any builds that are waiting in the + tree-stable-timer queue. This is only relevant for Change-based + schedulers, all others can just return an empty list.""" + # TODO: it might be nice to make this into getPendingBuildSets, which + # would let someone subscribe to the buildset being finished. + # However, the Scheduler doesn't actually create the buildset until + # it gets submitted, so doing this would require some major rework. + class IUpstreamScheduler(Interface): """This marks an IScheduler as being eligible for use as the 'upstream=' argument to a buildbot.scheduler.Dependent instance.""" @@ -88,6 +97,10 @@ """Return the URL of the top-most Buildbot status page, or None if this Buildbot does not provide a web status page.""" + def getSchedulers(): + """Return a list of ISchedulerStatus objects for all + currently-registered Schedulers.""" + def getBuilderNames(categories=None): """Return a list of the names of all current Builders.""" def getBuilder(name): Index: scheduler.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/scheduler.py,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- scheduler.py 18 Aug 2005 08:30:00 -0000 1.6 +++ scheduler.py 31 Aug 2005 01:51:41 -0000 1.7 @@ -116,6 +116,11 @@ def listBuilderNames(self): return self.builderNames + def getPendingBuildTimes(self): + if self.nextBuildTime is not None: + return [self.nextBuildTime] + return [] + def fileIsImportant(self, change): # note that externally-provided fileIsImportant callables are # functions, not methods, and will only receive one argument. Or you @@ -225,6 +230,13 @@ def listBuilderNames(self): return self.builderNames + def getPendingBuildTimes(self): + bts = [] + for s in self.schedulers.values(): + if s.nextBuildTime is not None: + bts.append(s.nextBuildTime) + return bts + def addChange(self, change): branch = change.branch if self.branches and branch not in self.branches: @@ -263,6 +275,10 @@ def listBuilderNames(self): return self.builderNames + def getPendingBuildTimes(self): + # report the upstream's value + return self.upstream.getPendingBuildTimes() + def startService(self): service.MultiService.startService(self) self.upstream.subscribeToSuccessfulBuilds(self.upstreamBuilt) @@ -302,6 +318,11 @@ def listBuilderNames(self): return self.builderNames + def getPendingBuildTimes(self): + # TODO: figure out when self.timer is going to fire next and report + # that + return [] + def doPeriodicBuild(self): bs = buildset.BuildSet(self.builderNames, SourceStamp(branch=self.branch)) @@ -322,6 +343,14 @@ def listBuilderNames(self): return self.builderNames + def getPendingBuildTimes(self): + # we can't predict what the developers are going to do in the future + return [] + + def addChange(self, change): + # Try schedulers ignore Changes + pass + class BadJobfile(Exception): pass From warner at users.sourceforge.net Wed Aug 31 01:51:45 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 31 Aug 2005 01:51:45 +0000 Subject: [Buildbot-commits] buildbot/buildbot/process builder.py,1.29,1.30 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/process In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv16253/buildbot/process Modified Files: builder.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-302 Creator: Brian Warner add pending/upcoming builds to the HTML "Current Activity" row * buildbot/status/html.py: add pending/upcoming builds to CurrentBox * buildbot/interfaces.py (IScheduler.getPendingBuildTimes): new method (IStatus.getSchedulers): new method * buildbot/status/builder.py (BuilderStatus): track pendingBuilds (Status.getSchedulers): implement * buildbot/process/builder.py (Builder): maintain BuilderStatus.pendingBuilds * buildbot/scheduler.py (Scheduler.getPendingBuildTimes): new method (TryBase.addChange): Try schedulers should ignore Changes --This line, and those below, will be ignored-- Files to commit: This list might be incomplete or outdated if editing the log message was not invoked from an up-to-date changes buffer! Index: builder.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/process/builder.py,v retrieving revision 1.29 retrieving revision 1.30 diff -u -d -r1.29 -r1.30 --- builder.py 17 Aug 2005 02:15:37 -0000 1.29 +++ builder.py 31 Aug 2005 01:51:43 -0000 1.30 @@ -259,11 +259,13 @@ req.submittedAt = now() self.buildable.append(req) req.requestSubmitted(self) + self.builder_status.addBuildRequest(req.status) self.maybeStartBuild() def cancelBuildRequest(self, req): if req in self.buildable: self.buildable.remove(req) + self.builder_status.removeBuildRequest(req.status) return True return False @@ -385,10 +387,12 @@ # it. Grab the oldest request, see if we can merge it with anything # else. req = self.buildable.pop(0) + self.builder_status.removeBuildRequest(req.status) mergers = [] for br in self.buildable[:]: if req.canBeMergedWith(br): self.buildable.remove(br) + self.builder_status.removeBuildRequest(br.status) mergers.append(br) requests = [req] + mergers @@ -468,6 +472,7 @@ self.building.remove(build) for req in build.requests: self.buildable.insert(0, req) # they get first priority + self.builder_status.addBuildRequest(req.status) # other notifyOnDisconnect calls will mark the slave as disconnected. # Re-try after they have fired, maybe there's another slave From warner at users.sourceforge.net Wed Aug 31 01:51:45 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 31 Aug 2005 01:51:45 +0000 Subject: [Buildbot-commits] buildbot/buildbot/status html.py,1.65,1.66 builder.py,1.64,1.65 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/status In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv16253/buildbot/status Modified Files: html.py builder.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-302 Creator: Brian Warner add pending/upcoming builds to the HTML "Current Activity" row * buildbot/status/html.py: add pending/upcoming builds to CurrentBox * buildbot/interfaces.py (IScheduler.getPendingBuildTimes): new method (IStatus.getSchedulers): new method * buildbot/status/builder.py (BuilderStatus): track pendingBuilds (Status.getSchedulers): implement * buildbot/process/builder.py (Builder): maintain BuilderStatus.pendingBuilds * buildbot/scheduler.py (Scheduler.getPendingBuildTimes): new method (TryBase.addChange): Try schedulers should ignore Changes --This line, and those below, will be ignored-- Files to commit: This list might be incomplete or outdated if editing the log message was not invoked from an up-to-date changes buffer! Index: builder.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/status/builder.py,v retrieving revision 1.64 retrieving revision 1.65 diff -u -d -r1.64 -r1.65 --- builder.py 17 Aug 2005 02:15:37 -0000 1.64 +++ builder.py 31 Aug 2005 01:51:42 -0000 1.65 @@ -1289,6 +1289,7 @@ self.lastBuildStatus = None #self.currentBig = None #self.currentSmall = None + self.pendingBuilds = [] self.nextBuild = None self.watchers = [] self.buildCache = [] # TODO: age builds out of the cache @@ -1303,6 +1304,7 @@ self.currentBuild.saveYourself() # TODO: push a 'hey, build was interrupted' event del d['currentBuild'] + del d['pendingBuilds'] del d['currentBigState'] del d['basedir'] del d['status'] @@ -1311,6 +1313,7 @@ def __setstate__(self, d): self.__dict__ = d self.buildCache = [] + self.pendingBuilds = [] self.watchers = [] # self.basedir must be filled in by our parent # self.status must be filled in by our parent @@ -1381,6 +1384,9 @@ def getSlave(self): return self.status.getSlave(self.slavename) + def getPendingBuilds(self): + return self.pendingBuilds + def getCurrentBuild(self): return self.currentBuild @@ -1499,6 +1505,11 @@ s.waitUntilFinished().addCallback(self._buildFinished) return s + def addBuildRequest(self, brstatus): + self.pendingBuilds.append(brstatus) + def removeBuildRequest(self, brstatus): + self.pendingBuilds.remove(brstatus) + # buildStarted is called by our child BuildStatus instances def buildStarted(self, s): """Now the BuildStatus object is ready to go (it knows all of its @@ -1673,6 +1684,9 @@ def getBuildbotURL(self): return self.botmaster.parent.buildbotURL + def getSchedulers(self): + return self.botmaster.parent.schedulers + def getBuilderNames(self, categories=None): if categories == None: return self.botmaster.builderNames[:] # don't let them break it Index: html.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/status/html.py,v retrieving revision 1.65 retrieving revision 1.66 diff -u -d -r1.65 -r1.66 --- html.py 19 Jul 2005 23:12:01 -0000 1.65 +++ html.py 31 Aug 2005 01:51:42 -0000 1.66 @@ -674,21 +674,49 @@ __implements__ = ICurrentBox, def formatETA(self, eta): - return time.strftime("%H:%M:%S", time.localtime(util.now()+eta)) + if eta is None: + return [] + if eta < 0: + return ["Soon"] + abstime = time.strftime("%H:%M:%S", time.localtime(util.now()+eta)) + return ["ETA in", "%d secs" % eta, "at %s" % abstime] - def getBox(self): + def getBox(self, status): + # getState() returns offline, idle, or building state, build = self.original.getState() color = "white" if state == "building": color = "yellow" - text = [state] - if state == "offline": + text = ["building"] + self.formatETA(build.getETA()) + elif state == "offline": color = "red" - if state == "building": - # TODO: ETA calculation - pass + text = ["offline"] + elif state == "idle": + text = ["idle"] + else: + # just in case I add a state and forget to update this + text = [state] + + # 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) + pbs = self.original.getPendingBuilds() + if pbs: + text.append("%d pending" % len(pbs)) + # how about upcoming ones? + upcoming = [] + builderName = self.original.getName() + for s in status.getSchedulers(): + if builderName in s.listBuilderNames(): + upcoming.extend(s.getPendingBuildTimes()) + for t in upcoming: + text.extend(["next at", + time.strftime("%H:%M:%S", time.localtime(t))]) return Box(text, color=color, class_="Activity " + state) + components.registerAdapter(CurrentBox, builder.BuilderStatus, ICurrentBox) class ChangeBox(components.Adapter): @@ -915,7 +943,7 @@ data += td("current activity", align="right", colspan=2, class_="Activity") for b in builders: - box = ICurrentBox(b).getBox() + box = ICurrentBox(b).getBox(self.status) data += box.td(align="center") data += " \n" From warner at users.sourceforge.net Wed Aug 31 01:51:45 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 31 Aug 2005 01:51:45 +0000 Subject: [Buildbot-commits] buildbot ChangeLog,1.495,1.496 Message-ID: Update of /cvsroot/buildbot/buildbot In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv16253 Modified Files: ChangeLog Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-302 Creator: Brian Warner add pending/upcoming builds to the HTML "Current Activity" row * buildbot/status/html.py: add pending/upcoming builds to CurrentBox * buildbot/interfaces.py (IScheduler.getPendingBuildTimes): new method (IStatus.getSchedulers): new method * buildbot/status/builder.py (BuilderStatus): track pendingBuilds (Status.getSchedulers): implement * buildbot/process/builder.py (Builder): maintain BuilderStatus.pendingBuilds * buildbot/scheduler.py (Scheduler.getPendingBuildTimes): new method (TryBase.addChange): Try schedulers should ignore Changes --This line, and those below, will be ignored-- Files to commit: This list might be incomplete or outdated if editing the log message was not invoked from an up-to-date changes buffer! Index: ChangeLog =================================================================== RCS file: /cvsroot/buildbot/buildbot/ChangeLog,v retrieving revision 1.495 retrieving revision 1.496 diff -u -d -r1.495 -r1.496 --- ChangeLog 31 Aug 2005 01:51:25 -0000 1.495 +++ ChangeLog 31 Aug 2005 01:51:43 -0000 1.496 @@ -1,5 +1,15 @@ 2005-08-30 Brian Warner + * buildbot/status/html.py: add pending/upcoming builds to CurrentBox + * buildbot/interfaces.py (IScheduler.getPendingBuildTimes): new method + (IStatus.getSchedulers): new method + * buildbot/status/builder.py (BuilderStatus): track pendingBuilds + (Status.getSchedulers): implement + * buildbot/process/builder.py (Builder): maintain + BuilderStatus.pendingBuilds + * buildbot/scheduler.py (Scheduler.getPendingBuildTimes): new method + (TryBase.addChange): Try schedulers should ignore Changes + * buildbot/scripts/tryclient.py (getTopdir): implement getTopdir for 'try' on CVS/SVN * buildbot/test/test_runner.py (Try.testGetTopdir): test case From warner at users.sourceforge.net Wed Aug 31 02:26:23 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 31 Aug 2005 02:26:23 +0000 Subject: [Buildbot-commits] buildbot/buildbot/scripts runner.py,1.35,1.36 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/scripts In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22093/buildbot/scripts Modified Files: runner.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-304 Creator: Brian Warner add --revision_file to the 'buildbot sendchange' args, for Darcs * buildbot/scripts/runner.py (sendchange): add --revision_file to the 'buildbot sendchange' arguments, for the Darcs context file * docs/buildbot.texinfo (sendchange): document it Index: runner.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/scripts/runner.py,v retrieving revision 1.35 retrieving revision 1.36 diff -u -d -r1.35 -r1.36 --- runner.py 31 Aug 2005 01:12:06 -0000 1.35 +++ runner.py 31 Aug 2005 02:26:21 -0000 1.36 @@ -508,14 +508,15 @@ class SendChangeOptions(usage.Options): optParameters = [ - ["master", "m", None, - "Location of the buildmaster's PBListener (host:port)"], - ["username", "u", None, "Username performing the commit"], - ["revision", "r", None, "Revision specifier (string)"], - ["revision_number", "n", None, "Revision specifier (integer)"], - ["comments", "m", None, "log message"], - ["logfile", "F", None, - "Read the log messages from this file (- for stdin)"], + ("master", "m", None, + "Location of the buildmaster's PBListener (host:port)"), + ("username", "u", None, "Username performing the commit"), + ("revision", "r", None, "Revision specifier (string)"), + ("revision_number", "n", None, "Revision specifier (integer)"), + ("revision_file", None, None, "Filename containing revision spec"), + ("comments", "m", None, "log message"), + ("logfile", "F", None, + "Read the log messages from this file (- for stdin)"), ] def getSynopsis(self): return "Usage: buildbot sendchange [options] filenames.." @@ -535,6 +536,8 @@ # SVN and P4 use numeric revisions if config.get("revision_number"): revision = int(config['revision_number']) + if config.get("revision_file"): + revision = open(config["revision_file"],"r").read() comments = config.get('comments') if not comments and config.get('logfile'): From warner at users.sourceforge.net Wed Aug 31 02:26:23 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 31 Aug 2005 02:26:23 +0000 Subject: [Buildbot-commits] buildbot/docs buildbot.texinfo,1.20,1.21 Message-ID: Update of /cvsroot/buildbot/buildbot/docs In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22093/docs Modified Files: buildbot.texinfo Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-304 Creator: Brian Warner add --revision_file to the 'buildbot sendchange' args, for Darcs * buildbot/scripts/runner.py (sendchange): add --revision_file to the 'buildbot sendchange' arguments, for the Darcs context file * docs/buildbot.texinfo (sendchange): document it Index: buildbot.texinfo =================================================================== RCS file: /cvsroot/buildbot/buildbot/docs/buildbot.texinfo,v retrieving revision 1.20 retrieving revision 1.21 diff -u -d -r1.20 -r1.21 --- buildbot.texinfo 31 Aug 2005 01:12:06 -0000 1.20 +++ buildbot.texinfo 31 Aug 2005 02:26:21 -0000 1.21 @@ -3943,8 +3943,15 @@ @item --revision This provides a (string) revision specifier, for VC systems that use -strings (Arch would use something like patch-42, Darcs would use the -patch name, etc). +strings (Arch would use something like patch-42 etc). + + at item --revision_file +This provides a filename which will be opened and the contents used as +the revision specifier. This is specifically for Darcs, which uses the +output of @command{darcs changes --context} as a revision specifier. +This context file can be a couple of kilobytes long, spanning a couple +lines per patch, and would be a hassle to pass as a command-line +argument. @item --comments This provides the change comments as a single argument. You may want From warner at users.sourceforge.net Wed Aug 31 02:26:23 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 31 Aug 2005 02:26:23 +0000 Subject: [Buildbot-commits] buildbot ChangeLog,1.496,1.497 Message-ID: Update of /cvsroot/buildbot/buildbot In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22093 Modified Files: ChangeLog Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-304 Creator: Brian Warner add --revision_file to the 'buildbot sendchange' args, for Darcs * buildbot/scripts/runner.py (sendchange): add --revision_file to the 'buildbot sendchange' arguments, for the Darcs context file * docs/buildbot.texinfo (sendchange): document it Index: ChangeLog =================================================================== RCS file: /cvsroot/buildbot/buildbot/ChangeLog,v retrieving revision 1.496 retrieving revision 1.497 diff -u -d -r1.496 -r1.497 --- ChangeLog 31 Aug 2005 01:51:43 -0000 1.496 +++ ChangeLog 31 Aug 2005 02:26:21 -0000 1.497 @@ -1,5 +1,9 @@ 2005-08-30 Brian Warner + * buildbot/scripts/runner.py (sendchange): add --revision_file to + the 'buildbot sendchange' arguments, for the Darcs context file + * docs/buildbot.texinfo (sendchange): document it + * buildbot/status/html.py: add pending/upcoming builds to CurrentBox * buildbot/interfaces.py (IScheduler.getPendingBuildTimes): new method (IStatus.getSchedulers): new method From warner at users.sourceforge.net Wed Aug 31 02:26:36 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 31 Aug 2005 02:26:36 +0000 Subject: [Buildbot-commits] buildbot/buildbot/status builder.py,1.65,1.66 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/status In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22158/buildbot/status Modified Files: builder.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-305 Creator: Brian Warner replace the overwriting-old-LogFile assertion with a warning * buildbot/status/builder.py (LogFile): remove the assertion that blows up when you try to overwrite an existing logfile, instead just emit a warning. This case gets hit when the buildmaster is killed and doesn't get a chance to write out the serialized BuilderStatus object, so the .nextBuildNumber attribute gets out of date. Index: builder.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/status/builder.py,v retrieving revision 1.65 retrieving revision 1.66 diff -u -d -r1.65 -r1.66 --- builder.py 31 Aug 2005 01:51:42 -0000 1.65 +++ builder.py 31 Aug 2005 02:26:34 -0000 1.66 @@ -228,8 +228,14 @@ self.step = parent self.name = name self.filename = logfilename - assert not os.path.exists(self.getFilename()) - self.openfile = open(self.getFilename(), "w+") + fn = self.getFilename() + if os.path.exists(fn): + # the buildmaster was probably stopped abruptly, before the + # BuilderStatus could be saved, so BuilderStatus.nextBuildNumber + # is out of date, and we're overlapping with earlier builds now. + # Warn about it, but then overwrite the old pickle file + log.msg("Warning: Overwriting old serialized Build at %s" % fn) + self.openfile = open(fn, "w+") self.runEntries = [] self.watchers = [] self.finishedWatchers = [] From warner at users.sourceforge.net Wed Aug 31 02:26:36 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 31 Aug 2005 02:26:36 +0000 Subject: [Buildbot-commits] buildbot ChangeLog,1.497,1.498 Message-ID: Update of /cvsroot/buildbot/buildbot In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22158 Modified Files: ChangeLog Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-305 Creator: Brian Warner replace the overwriting-old-LogFile assertion with a warning * buildbot/status/builder.py (LogFile): remove the assertion that blows up when you try to overwrite an existing logfile, instead just emit a warning. This case gets hit when the buildmaster is killed and doesn't get a chance to write out the serialized BuilderStatus object, so the .nextBuildNumber attribute gets out of date. Index: ChangeLog =================================================================== RCS file: /cvsroot/buildbot/buildbot/ChangeLog,v retrieving revision 1.497 retrieving revision 1.498 diff -u -d -r1.497 -r1.498 --- ChangeLog 31 Aug 2005 02:26:21 -0000 1.497 +++ ChangeLog 31 Aug 2005 02:26:34 -0000 1.498 @@ -1,5 +1,12 @@ 2005-08-30 Brian Warner + * buildbot/status/builder.py (LogFile): remove the assertion that + blows up when you try to overwrite an existing logfile, instead + just emit a warning. This case gets hit when the buildmaster is + killed and doesn't get a chance to write out the serialized + BuilderStatus object, so the .nextBuildNumber attribute gets out + of date. + * buildbot/scripts/runner.py (sendchange): add --revision_file to the 'buildbot sendchange' arguments, for the Darcs context file * docs/buildbot.texinfo (sendchange): document it From warner at users.sourceforge.net Wed Aug 31 07:21:25 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 31 Aug 2005 07:21:25 +0000 Subject: [Buildbot-commits] site manual-CVS.html,1.2,1.3 Message-ID: Update of /cvsroot/buildbot/site In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10340 Modified Files: manual-CVS.html Log Message: more Try stuff Index: manual-CVS.html =================================================================== RCS file: /cvsroot/buildbot/site/manual-CVS.html,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- manual-CVS.html 11 Aug 2005 19:48:49 -0000 1.2 +++ manual-CVS.html 31 Aug 2005 07:21:23 -0000 1.3 @@ -4211,6 +4211,13 @@ .buildbot/options as try_host, try_username, try_password, and try_dir. +

      In addition, the SSH approach needs to connect to a PBListener status +port, so it can retrieve and report the results of the build (the PB +approach uses the existing connection to retrieve status information, +so this step is not necessary). This requires a --master +argument, or a masterstatus entry in .buildbot/options, +in the form of a HOSTNAME:PORT string. +

      choosing the Builders

      A trial build is performed on multiple Builders at the same time, and @@ -4271,6 +4278,16 @@ --try-topfile and --try-topdir arguments will be ignored. +

      determining the branch name

      + +

      Some VC systems record the branch information in a way that “try” +can locate it, in particular Arch (both tla and +baz). For the others, if you are using something other than +the default branch, you will have to tell the buildbot which branch +your tree is using. You can do this with either the --branch +argument, or a try_branch entry in the +.buildbot/options file. +

      determining the revision and patch

      Each VC system has a separate approach for determining the tree's base @@ -4367,8 +4384,14 @@ that use numeric transaction numbers (like Subversion).

      --revision
      This provides a (string) revision specifier, for VC systems that use -strings (Arch would use something like patch-42, Darcs would use the -patch name, etc). +strings (Arch would use something like patch-42 etc). + +
      --revision_file
      This provides a filename which will be opened and the contents used as +the revision specifier. This is specifically for Darcs, which uses the +output of darcs changes --context as a revision specifier. +This context file can be a couple of kilobytes long, spanning a couple +lines per patch, and would be a hassle to pass as a command-line +argument.
      --comments
      This provides the change comments as a single argument. You may want to use --logfile instead. From warner at users.sourceforge.net Wed Aug 31 08:04:38 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 31 Aug 2005 08:04:38 +0000 Subject: [Buildbot-commits] buildbot ChangeLog,1.498,1.499 Message-ID: Update of /cvsroot/buildbot/buildbot In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1173 Modified Files: ChangeLog Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-307 Creator: Brian Warner remove 'eta' argument from builderChangedState methods * buildbot/status/base.py (StatusReceiver.builderChangedState): update to match correct signature: removed 'eta' argument * buildbot/status/mail.py (MailNotifier.builderChangedState): same Index: ChangeLog =================================================================== RCS file: /cvsroot/buildbot/buildbot/ChangeLog,v retrieving revision 1.498 retrieving revision 1.499 diff -u -d -r1.498 -r1.499 --- ChangeLog 31 Aug 2005 02:26:34 -0000 1.498 +++ ChangeLog 31 Aug 2005 08:04:36 -0000 1.499 @@ -1,3 +1,9 @@ +2005-08-31 Brian Warner + + * buildbot/status/base.py (StatusReceiver.builderChangedState): + update to match correct signature: removed 'eta' argument + * buildbot/status/mail.py (MailNotifier.builderChangedState): same + 2005-08-30 Brian Warner * buildbot/status/builder.py (LogFile): remove the assertion that From warner at users.sourceforge.net Wed Aug 31 08:04:38 2005 From: warner at users.sourceforge.net (Brian Warner) Date: Wed, 31 Aug 2005 08:04:38 +0000 Subject: [Buildbot-commits] buildbot/buildbot/status base.py,1.2,1.3 mail.py,1.18,1.19 Message-ID: Update of /cvsroot/buildbot/buildbot/buildbot/status In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1173/buildbot/status Modified Files: base.py mail.py Log Message: Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-307 Creator: Brian Warner remove 'eta' argument from builderChangedState methods * buildbot/status/base.py (StatusReceiver.builderChangedState): update to match correct signature: removed 'eta' argument * buildbot/status/mail.py (MailNotifier.builderChangedState): same Index: base.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/status/base.py,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- base.py 17 Aug 2005 02:15:37 -0000 1.2 +++ base.py 31 Aug 2005 08:04:36 -0000 1.3 @@ -25,7 +25,7 @@ def builderAdded(self, builderName, builder): pass - def builderChangedState(self, builderName, state, eta=None): + def builderChangedState(self, builderName, state): pass def buildStarted(self, builderName, build): Index: mail.py =================================================================== RCS file: /cvsroot/buildbot/buildbot/buildbot/status/mail.py,v retrieving revision 1.18 retrieving revision 1.19 diff -u -d -r1.18 -r1.19 --- mail.py 19 Jul 2005 23:12:01 -0000 1.18 +++ mail.py 31 Aug 2005 08:04:36 -0000 1.19 @@ -193,7 +193,7 @@ def builderRemoved(self, name): pass - def builderChangedState(self, name, state, eta): + def builderChangedState(self, name, state): pass def buildStarted(self, name, build): pass