Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/buildbot/contrib/bb_applet.py
diff options
context:
space:
mode:
Diffstat (limited to 'buildbot/contrib/bb_applet.py')
-rwxr-xr-xbuildbot/contrib/bb_applet.py413
1 files changed, 0 insertions, 413 deletions
diff --git a/buildbot/contrib/bb_applet.py b/buildbot/contrib/bb_applet.py
deleted file mode 100755
index 8430a2f..0000000
--- a/buildbot/contrib/bb_applet.py
+++ /dev/null
@@ -1,413 +0,0 @@
-#! /usr/bin/python
-
-# This is a Gnome-2 panel applet that uses the
-# buildbot.status.client.PBListener interface to display a terse summary of
-# the buildmaster. It displays one column per builder, with a box on top for
-# the status of the most recent build (red, green, or orange), and a somewhat
-# smaller box on the bottom for the current state of the builder (white for
-# idle, yellow for building, red for offline). There are tooltips available
-# to tell you which box is which.
-
-# Edit the line at the beginning of the MyApplet class to fill in the host
-# and portnumber of your buildmaster's PBListener status port. Eventually
-# this will move into a preferences dialog, but first we must create a
-# preferences dialog.
-
-# See the notes at the end for installation hints and support files (you
-# cannot simply run this script from the shell). You must create a bonobo
-# .server file that points to this script, and put the .server file somewhere
-# that bonobo will look for it. Only then will this applet appear in the
-# panel's "Add Applet" menu.
-
-# Note: These applets are run in an environment that throws away stdout and
-# stderr. Any logging must be done with syslog or explicitly to a file.
-# Exceptions are particularly annoying in such an environment.
-
-# -Brian Warner, warner@lothar.com
-
-if 0:
- import sys
- dpipe = open("/tmp/applet.log", "a", 1)
- sys.stdout = dpipe
- sys.stderr = dpipe
- print "starting"
-
-from twisted.internet import gtk2reactor
-gtk2reactor.install()
-
-import gtk
-import gnomeapplet
-
-# preferences are not yet implemented
-MENU = """
-<popup name="button3">
- <menuitem name="Connect" verb="Connect" label="Connect"
- pixtype="stock" pixname="gtk-refresh"/>
- <menuitem name="Disconnect" verb="Disconnect" label="Disconnect"
- pixtype="stock" pixname="gtk-stop"/>
- <menuitem name="Prefs" verb="Props" label="_Preferences..."
- pixtype="stock" pixname="gtk-properties"/>
-</popup>
-"""
-
-from twisted.spread import pb
-from twisted.cred import credentials
-
-# sigh, these constants should cross the wire as strings, not integers
-SUCCESS, WARNINGS, FAILURE, SKIPPED, EXCEPTION = range(5)
-Results = ["success", "warnings", "failure", "skipped", "exception"]
-
-
-class Box:
-
- def __init__(self, buildername, hbox, tips, size, hslice):
- self.buildername = buildername
- self.hbox = hbox
- self.tips = tips
- self.state = "idle"
- self.eta = None
- self.last_results = None
- self.last_text = None
- self.size = size
- self.hslice = hslice
-
- def create(self):
- self.vbox = gtk.VBox(False)
- l = gtk.Label(".")
- self.current_box = box = gtk.EventBox()
- # these size requests are somewhat non-deterministic. I think it
- # depends upon how large label is, or how much space was already
- # consumed when the box is added.
- self.current_box.set_size_request(self.hslice, self.size * 0.75)
- box.add(l)
- self.vbox.pack_end(box)
- self.current_box.modify_bg(gtk.STATE_NORMAL,
- gtk.gdk.color_parse("gray50"))
-
- l2 = gtk.Label(".")
- self.last_box = gtk.EventBox()
- self.current_box.set_size_request(self.hslice, self.size * 0.25)
- self.last_box.add(l2)
- self.vbox.pack_end(self.last_box, True, True)
- self.vbox.show_all()
- self.hbox.pack_start(self.vbox, True, True)
-
- def remove(self):
- self.hbox.remove(self.box)
-
- def set_state(self, state):
- self.state = state
- self.update()
-
- def set_eta(self, eta):
- self.eta = eta
- self.update()
-
- def set_last_build_results(self, results):
- self.last_results = results
- self.update()
-
- def set_last_build_text(self, text):
- self.last_text = text
- self.update()
-
- def update(self):
- currentmap = {"offline": "red",
- "idle": "white",
- "waiting": "yellow",
- "interlocked": "yellow",
- "building": "yellow",
- }
- color = currentmap[self.state]
- self.current_box.modify_bg(gtk.STATE_NORMAL,
- gtk.gdk.color_parse(color))
- lastmap = {None: "gray50",
- SUCCESS: "green",
- WARNINGS: "orange",
- FAILURE: "red",
- EXCEPTION: "purple",
- }
- last_color = lastmap[self.last_results]
- self.last_box.modify_bg(gtk.STATE_NORMAL,
- gtk.gdk.color_parse(last_color))
- current_tip = "%s:\n%s" % (self.buildername, self.state)
- if self.eta is not None:
- current_tip += " (ETA=%ds)" % self.eta
- self.tips.set_tip(self.current_box, current_tip)
- last_tip = "%s:\n" % self.buildername
- if self.last_text:
- last_tip += "\n".join(self.last_text)
- else:
- last_tip += "no builds"
- self.tips.set_tip(self.last_box, last_tip)
-
-
-class MyApplet(pb.Referenceable):
- # CHANGE THIS TO POINT TO YOUR BUILDMASTER
- buildmaster = "buildmaster.example.org", 12345
- filled = None
-
- def __init__(self, container):
- self.applet = container
- self.size = container.get_size()
- self.hslice = self.size / 4
- container.set_size_request(self.size, self.size)
- self.fill_nut()
- verbs = [("Props", self.menu_preferences),
- ("Connect", self.menu_connect),
- ("Disconnect", self.menu_disconnect),
- ]
- container.setup_menu(MENU, verbs)
- self.boxes = {}
- self.connect()
-
- def fill(self, what):
- if self.filled:
- self.applet.remove(self.filled)
- self.filled = None
- self.applet.add(what)
- self.filled = what
- self.applet.show_all()
-
- def fill_nut(self):
- i = gtk.Image()
- i.set_from_file("/tmp/nut32.png")
- self.fill(i)
-
- def fill_hbox(self):
- self.hbox = gtk.HBox(True)
- self.fill(self.hbox)
-
- def connect(self):
- host, port = self.buildmaster
- cf = pb.PBClientFactory()
- creds = credentials.UsernamePassword("statusClient", "clientpw")
- d = cf.login(creds)
- reactor.connectTCP(host, port, cf)
- d.addCallback(self.connected)
- return d
-
- def connected(self, ref):
- print "connected"
- ref.notifyOnDisconnect(self.disconnected)
- self.remote = ref
- self.remote.callRemote("subscribe", "steps", 5, self)
- self.fill_hbox()
- self.tips = gtk.Tooltips()
- self.tips.enable()
-
- def disconnect(self):
- self.remote.broker.transport.loseConnection()
-
- def disconnected(self, *args):
- print "disconnected"
- self.fill_nut()
-
- def remote_builderAdded(self, buildername, builder):
- print "builderAdded", buildername
- box = Box(buildername, self.hbox, self.tips, self.size, self.hslice)
- self.boxes[buildername] = box
- box.create()
- self.applet.set_size_request(self.hslice * len(self.boxes),
- self.size)
- d = builder.callRemote("getLastFinishedBuild")
-
- def _got(build):
- if build:
- d1 = build.callRemote("getResults")
- d1.addCallback(box.set_last_build_results)
- d2 = build.callRemote("getText")
- d2.addCallback(box.set_last_build_text)
- d.addCallback(_got)
-
- def remote_builderRemoved(self, buildername):
- self.boxes[buildername].remove()
- del self.boxes[buildername]
- self.applet.set_size_request(self.hslice * len(self.boxes),
- self.size)
-
- def remote_builderChangedState(self, buildername, state, eta):
- self.boxes[buildername].set_state(state)
- self.boxes[buildername].set_eta(eta)
- print "change", buildername, state, eta
-
- def remote_buildStarted(self, buildername, build):
- print "buildStarted", buildername
-
- def remote_buildFinished(self, buildername, build, results):
- print "buildFinished", results
- box = self.boxes[buildername]
- box.set_eta(None)
- d1 = build.callRemote("getResults")
- d1.addCallback(box.set_last_build_results)
- d2 = build.callRemote("getText")
- d2.addCallback(box.set_last_build_text)
-
- def remote_buildETAUpdate(self, buildername, build, eta):
- self.boxes[buildername].set_eta(eta)
- print "ETA", buildername, eta
-
- def remote_stepStarted(self, buildername, build, stepname, step):
- print "stepStarted", buildername, stepname
-
- def remote_stepFinished(self, buildername, build, stepname, step, results):
- pass
-
- def menu_preferences(self, event, data=None):
- print "prefs!"
- p = Prefs(self)
- p.create()
-
- def set_buildmaster(self, buildmaster):
- host, port = buildmaster.split(":")
- self.buildmaster = host, int(port)
- self.disconnect()
- reactor.callLater(0.5, self.connect)
-
- def menu_connect(self, event, data=None):
- self.connect()
-
- def menu_disconnect(self, event, data=None):
- self.disconnect()
-
-
-class Prefs:
-
- def __init__(self, parent):
- self.parent = parent
-
- def create(self):
- self.w = w = gtk.Window()
- v = gtk.VBox()
- h = gtk.HBox()
- h.pack_start(gtk.Label("buildmaster (host:port) : "))
- self.buildmaster_entry = b = gtk.Entry()
- if self.parent.buildmaster:
- host, port = self.parent.buildmaster
- b.set_text("%s:%d" % (host, port))
- h.pack_start(b)
- v.add(h)
-
- b = gtk.Button("Ok")
- b.connect("clicked", self.done)
- v.add(b)
-
- w.add(v)
- w.show_all()
-
- def done(self, widget):
- buildmaster = self.buildmaster_entry.get_text()
- self.parent.set_buildmaster(buildmaster)
- self.w.unmap()
-
-
-def factory(applet, iid):
- MyApplet(applet)
- applet.show_all()
- return True
-
-
-from twisted.internet import reactor
-
-# instead of reactor.run(), we do the following:
-reactor.startRunning()
-reactor.simulate()
-gnomeapplet.bonobo_factory("OAFIID:GNOME_Buildbot_Factory",
- gnomeapplet.Applet.__gtype__,
- "buildbot", "0", factory)
-
-# code ends here: bonobo_factory runs gtk.mainloop() internally and
-# doesn't return until the program ends
-
-# SUPPORTING FILES:
-
-# save the following as ~/lib/bonobo/servers/bb_applet.server, and update all
-# the pathnames to match your system
-bb_applet_server = """
-<oaf_info>
-
-<oaf_server iid="OAFIID:GNOME_Buildbot_Factory"
- type="exe"
- location="/home/warner/stuff/buildbot-trunk/contrib/bb_applet.py">
-
- <oaf_attribute name="repo_ids" type="stringv">
- <item value="IDL:Bonobo/GenericFactory:1.0"/>
- <item value="IDL:Bonobo/Unknown:1.0"/>
- </oaf_attribute>
- <oaf_attribute name="name" type="string" value="Buildbot Factory"/>
- <oaf_attribute name="description" type="string" value="Test"/>
-</oaf_server>
-
-<oaf_server iid="OAFIID:GNOME_Buildbot"
- type="factory"
- location="OAFIID:GNOME_Buildbot_Factory">
-
- <oaf_attribute name="repo_ids" type="stringv">
- <item value="IDL:GNOME/Vertigo/PanelAppletShell:1.0"/>
- <item value="IDL:Bonobo/Control:1.0"/>
- <item value="IDL:Bonobo/Unknown:1.0"/>
- </oaf_attribute>
- <oaf_attribute name="name" type="string" value="Buildbot"/>
- <oaf_attribute name="description" type="string"
- value="Watch Buildbot status"
- />
- <oaf_attribute name="panel:category" type="string" value="Utility"/>
- <oaf_attribute name="panel:icon" type="string"
- value="/home/warner/stuff/buildbot-trunk/doc/hexnut32.png"
- />
-
-</oaf_server>
-
-</oaf_info>
-"""
-
-# a quick rundown on the Gnome2 applet scheme (probably wrong: there are
-# better docs out there that you should be following instead)
-# http://www.pycage.de/howto_bonobo.html describes a lot of
-# the base Bonobo stuff.
-# http://www.daa.com.au/pipermail/pygtk/2002-September/003393.html
-
-# bb_applet.server must be in your $BONOBO_ACTIVATION_PATH . I use
-# ~/lib/bonobo/servers . This environment variable is read by
-# bonobo-activation-server, so it must be set before you start any Gnome
-# stuff. I set it in ~/.bash_profile . You can also put it in
-# /usr/lib/bonobo/servers/ , which is probably on the default
-# $BONOBO_ACTIVATION_PATH, so you won't have to update anything.
-
-# It is safest to put this in place before bonobo-activation-server is
-# started, which may mean before any Gnome program is running. It may or may
-# not detect bb_applet.server if it is installed afterwards.. there seem to
-# be hooks, some of which involve FAM, but I never managed to make them work.
-# The file must have a name that ends in .server or it will be ignored.
-
-# The .server file registers two OAF ids and tells the activation-server how
-# to create those objects. The first is the GNOME_Buildbot_Factory, and is
-# created by running the bb_applet.py script. The second is the
-# GNOME_Buildbot applet itself, and is created by asking the
-# GNOME_Buildbot_Factory to make it.
-
-# gnome-panel's "Add To Panel" menu will gather all the OAF ids that claim
-# to implement the "IDL:GNOME/Vertigo/PanelAppletShell:1.0" in its
-# "repo_ids" attribute. The sub-menu is determined by the "panel:category"
-# attribute. The icon comes from "panel:icon", the text displayed in the
-# menu comes from "name", the text in the tool-tip comes from "description".
-
-# The factory() function is called when a new applet is created. It receives
-# a container that should be populated with the actual applet contents (in
-# this case a Button).
-
-# If you're hacking on the code, just modify bb_applet.py and then kill -9
-# the running applet: the panel will ask you if you'd like to re-load the
-# applet, and when you say 'yes', bb_applet.py will be re-executed. Note that
-# 'kill PID' won't work because the program is sitting in C code, and SIGINT
-# isn't delivered until after it surfaces to python, which will be never.
-
-# Running bb_applet.py by itself will result in a factory instance being
-# created and then sitting around forever waiting for the activation-server
-# to ask it to make an applet. This isn't very useful.
-
-# The "location" filename in bb_applet.server must point to bb_applet.py, and
-# bb_applet.py must be executable.
-
-# Enjoy!
-# -Brian Warner