[Buildbot-devel] adding LogObserver - the manual lost me

Grig Gheorghiu grig at agilistas.org
Fri Oct 13 15:03:55 UTC 2006


On 10/13/06, Brian Warner <warner-buildbot at lothar.com> wrote:
>
> brett <bneely at gmail.com> writes:
>
> > I'm working on a logObserver for one of my build steps.  In the
> > manual, I got here:
> >
> > To connect this parser into the Trial BuildStep, Trial.__init__ ends
> > with the following clause:
> >
> >              # this counter will feed Progress along the 'test cases'
> metric
> >              counter = TrialTestCaseCounter()
> >              self.addLogObserver('stdio', counter)
> >
> >
> > and I don't know what to do with it.  Sounds like I have to create or
> > extend __init__ for the Trial step, but I am not clear on where that
> > goes in my master.cfg .
>
> [sorry for the delay]
>
> [and sorry for the over-detailed response.. I tried to answer a number of
> other questions at the same time]
>
> You're right, using self.addLogObserver is something that needs to be done
> in
> a custom build step, which you would create by subclassing ShellCommand or
> one of the other existing BuildSteps. The 'Trial' buildstep is a subclass
> of
> ShellCommand, so it is used as an example of what you might do in your own
> subclasses of ShellCommand.
>
> Let's say that we've got some snazzy new unit-test framework called
> Framboozle. It's the hottest thing since sliced bread. It slices, it
> dices,
> it runs unit tests like there's no tomorrow. Plus if your unit tests fail,
> you can use its name for a Web 2.1 startup company, make millions of
> dollars,
> and hire engineers to fix the bugs for you, while you spend your
> afternoons
> lazily hang-gliding along a scenic pacific beach, blissfully unconcerned
> about the state of your tests.[1]
>
> To run a Framboozle-enabled test suite, you just run the 'framboozler'
> command from the top of your source code tree. The 'framboozler' command
> emits a bunch of stuff to stdout, but the most interesting bit is that it
> emits the line "FNURRRGH!" every time it finishes running a test case[2].
> You'd like to have a test-case counting LogObserver that watches for these
> lines and counts them, because counting them will help the buildbot more
> accurately calculate how long the build will take, and this will let you
> know
> exactly how long you can sneak out of the office for your hang-gliding
> lessons without anyone noticing that you're gone.
>
> This will involve writing a new BuildStep (probably named "Framboozle")
> which
> inherits from ShellCommand. The BuildStep class definition itself will
> look
> something like this:
>
> ==== START
> from buildbot.process.steps import ShellCommand, LogLineObserver
> # note that in the upcoming 0.7.5 release, this should be:
> #from buildbot.steps.shell import ShellCommand
> #from buildbot.process.buildstep import LogLineObserver
>
> class FNURRRGHCounter(LogLineObserver):
>     numTests = 0
>     def outLineReceived(self, line):
>         if "FNURRRGH!" in line:
>             self.numTests += 1
>             self.step.setProgress('tests', self.numTests)
>
> class Framboozle(ShellCommand):
>     command = ["framboozler"]
>
>     def __init__(self, **kwargs):
>         ShellCommand.__init__(self, **kwargs)   # always upcall!
>         counter = FNURRRGHCounter())
>         self.addLogObserver(counter)
>
> ==== FINISH
>
> So that's the code that we want to wind up using. How do we actually
> deploy
> it?
>
> You have a couple of different options.
>
> Option 1: The simplest technique is to simply put this text (everything
> from
> START to FINISH) in your master.cfg file, somewhere before the
> BuildFactory
> definition where you actually use it in a clause like:
>
> f = BuildFactory()
> f.addStep(SVN, svnurl="stuff")
> f.addStep(Framboozle)
>
> Remember that master.cfg is secretly just a python program with one job:
> populating the BuildmasterConfig dictionary. And python programs are
> allowed
> to define as many classes as they like. So you can define classes and use
> them in the same file, just as long as the class is defined before some
> other
> code tries to use it.
>
> This is easy, and it keeps the point of definition very close to the point
> of
> use, and whoever replaces you after that unfortunate hang-gliding accident
> will appreciate being able to easily figure out what the heck this stupid
> "Framboozle" step is doing anyways. The downside is that every time you
> reload the config file, the Framboozle class will get redefined, which
> means
> that the buildmaster will think that you've reconfigured all the Builders
> that use it, even though nothing changed. This means that all those
> Builders
> will get shutdown and restarted, interrupting any builds already in
> progress.
> Bleh.
>
> Option 2: Instead, we can put this code in a separate file, and import it
> into the master.cfg file just like we would the normal buildsteps like
> ShellCommand and SVN.
>
> Create a directory named ~/lib/python, put everything from START to FINISH
> in
> ~/lib/python/framboozle.py, and run your buildmaster using:
>
> PYTHONPATH=~/lib/python buildbot start MASTERDIR
>
> or add something like this to something like your ~/.bashrc or
> ~/.bash_profile or ~/.cshrc:
>
> export PYTHONPATH=~/lib/python
>
> Once we've done this, our master.cfg can look like:
>
> from framboozle import Framboozle
> f = BuildFactory()
> f.addStep(SVN, svnurl="stuff")
> f.addStep(Framboozle)
>
> or:
>
> import framboozle
> f = BuildFactory()
> f.addStep(SVN, svnurl="stuff")
> f.addStep(framboozle.Framboozle)
>
> (check out the python docs for details about how "import" and "from A
> import
> B" work).
>
> What we've done here is to tell python that every time it handles an
> "import"
> statement for some named module, it should look in our ~/lib/python/ for
> that
> module before it looks anywhere else. After our directories, it will try
> in a
> bunch of standard directories too (including the one where buildbot is
> installed). By setting the PYTHONPATH environment variable, you can add
> directories to the front of this search list.
>
> Python knows that once it "import"s a file, it doesn't need to re-import
> it
> again. This means that reconfiguring the buildmaster (with "buildbot
> sighup",
> for example) won't make it think the Framboozle class has changed every
> time,
> so the Builders that use it will not be spuriously restarted. On the other
> hand, you either have to start your buildmaster in a slightly weird way,
> or
> you have to modify your environment to set the PYTHONPATH variable.
>
>
> Option 3: Install this code into a standard python library directory
>
> Find out what your python's standard include path is by asking it:
>
> 80:warner at luther% python
> Python 2.4.4c0 (#2, Oct  2 2006, 00:57:46)
> [GCC 4.1.2 20060928 (prerelease) (Debian 4.1.1-15)] on linux2
> Type "help", "copyright", "credits" or "license" for more information.
> >>> import sys
> >>> print sys.path
> ['', '/usr/lib/python24.zip', '/usr/lib/python2.4',
> '/usr/lib/python2.4/plat-linux2', '/usr/lib/python2.4/lib-tk',
> '/usr/lib/python2.4/lib-dynload', '/usr/local/lib/python2.4/site-packages',
> '/usr/lib/python2.4/site-packages',
> '/usr/lib/python2.4/site-packages/Numeric',
> '/var/lib/python-support/python2.4', '/usr/lib/site-python']
> >>>
>
> In this case, putting the code into
> /usr/local/lib/python2.4/site-packages/framboozle.py would work just fine.
> We
> can use the same master.cfg "import framboozle" statement as in Option 2.
> By
> putting it in a standard include directory (instead of the decidedly
> non-standard ~/lib/python), we don't even have to set PYTHONPATH to
> anything
> special. The downside is that you probably have to be root to write to one
> of
> those standard include directories.
>
>
> Option 4: Submit the code for inclusion in the Buildbot distribution
>
> Contribute the code in an Enhancement Request on SourceForge, via
> http://buildbot.sf.net . Lobby, convince, coerce, bribe, badger, harass,
> threaten, or otherwise encourage the author to accept the patch. This lets
> you do something like:
>
> from buildbot.steps import framboozle
> f = BuildFactory()
> f.addStep(SVN, svnurl="stuff")
> f.addStep(framboozle.Framboozle)
>
> And then you don't even have to install framboozle.py anywhere on your
> system, since it will ship with Buildbot. You don't have to be root, you
> don't have to set PYTHONPATH. But you do have to make a good case for
> Framboozle being worth going into the main distribution, you'll probably
> have
> to provide docs and some unit test cases, you'll need to figure out what
> kind
> of beer the author likes, and then you'll have to wait until the next
> release. But in some environments, all this is easier than getting root on
> your buildmaster box, so the tradeoffs may actually be worth it.
>
>
>
> Putting the code in master.cfg (1) makes it available to that buildmaster
> instance. Putting it in a file in a personal library directory (2) makes
> it
> available for any buildmasters you might be running. Putting it in a file
> in
> a system-wide shared library directory (3) makes it available for any
> buildmasters that anyone on that system might be running. Getting it into
> the
> buildbot's upstream repository (4) makes it available for any buildmasters
> that anyone in the world might be running. It's all a matter of how widely
> you want to deploy that new class.
>
>
> hope that helps[3],
> -Brian
>
>
> [1]: framboozle.com is still available. Remember, I get 10% :).
> [2]: Framboozle gets very excited about running unit tests.
> [2]: boy, I should remember not to write email when it's late and I'm
> feeling
>      punchy. I come up with the weirdest things :)


Nice  tutorial, Brian -- this sort of stuff should go somewhere in the
documentation. I for one find it very helpful. I'll start working on the
framboozle framework tomorrow :-)

Grig
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://buildbot.net/pipermail/devel/attachments/20061013/adfe5631/attachment.html>


More information about the devel mailing list