Friday, 17 July 2009

Plugin Crazy!

So after creating my first proper plugin, post-to-facebook, I decided to have a go at creating another one. This one was created after I set up a blog for my dad to post updates and photos to so that he wouldn't have to resend the same emails to different people. The after giving him a brief overview of how to post items and upload photos I noticed that the images he was uploaded were to large to be correctly displayed, when using the light box plugin. So from this I decided to write a plugin that would allow for the maximum size an uploaded image can be, and if it is larger it is resized. I'll submit it to wordpress for download. This plugin is ideal for people who don't want to worry about resizing their images before they post them to wordpress, this is ideal with. The plugin homepage is can be found on the page resize-on-upload-plugin

Tuesday, 14 July 2009

'Post to Facebook' Wordpress Plugin

post-to-facebook screenshot

After wanting to be able to post stuff to my facebook account from my blog for no other reason than "I Can", I looked around at the plugins that exist at the moment. The ones that I found worked but they were not what I wanted. The closest I got was the plugin Publish To Facebook. What I didn't like about this plugin was that it highjacked the publish/update button. What I wanted was the ability to press a button and publish to facebook for only the posts that choose. So I decided to write my own plugin, that add a button to the edit page to do just this.

The can for the moment the source code can be checked out from bazaar repository, then simply upload the folder to the wp-content/plugins and you're good to go. If you don't like or use bazaar you can download the tar ball.

Download: post-to-facebook.tar.gz

bzr branch http://bzr.yeticode.co.uk/post-to-facebook

Monday, 13 July 2009

Python and CCTray Again

So after creating a python script that would use my tux droid to notify me when a build failed I decided to extend the script a little further. I decoupled it from the tux droid code and added in a status menu. It still requires that CruiseControl.NET has the webdashboard installed. This is my first venture into using GTK with python, as well as threads.

One of the problems that I encountered when trying to use thread was that they were not behaving correctly. The Thread would appear to start however it would not run. This was easy to fix but adding the following line to initialize the threading.


gtk.gdk.threads_init()


In addition to this the class that was running the thread not only had to inherit from the threading.Thread object but had to explicitly call the init on the threads base class


class ccnetworker(threading.Thread):

# init
def __init__(self,xmlPath,pycctray):
threading.Thread.__init__(self)
self.xmlPath = xmlPath
self.pycctray = pycctray


Below is a screen shot of the system tray menu, listing the projects that are available to be force built.

pycctray screenshot


# example usage
python pycctray.py http://localhost/ccnet/XmlServerReport.aspx


You can get the latest source from the bazaar repository


bzr branch http://bzr.yeticode.co.uk/pycctray


Alternatively you can download the source files on their own: pycctray.tar.gz

Friday, 10 July 2009

Tux Droid with Cruise Control .NET

Tux Droid

So after having my tux droid for a while I decided to put it to good use, opposed to making it swear at my housemates, which no matter how entertaining it was did not seem very productive.
I decided to write a small script that would notify me when a build from Cruise Control.NET failed, or when a broken build has successfully been built. At the moment the tux droid speaks a simple message and flaps it wings a little.

The script uses the tux droid python API to make the noises and pulls down an Xml file, via CruiseControl.NET, using urllib and xml.dom, fairly simple stuff.

You can get a copy of the source, which might be more up-to-date, frm the bzr repository.

# bzr branch http://bzr.yeticode.co.uk/ccnet-tuxbot



Usage:
# python ccnet.py http://localhost/ccnet/XmlServerReport.aspx


download ccnet.py
Update 11-07-2009 12:00AM: update notifcations in ccnet.py script.

#!/usr/bin/python
import sys
import urllib
import time
from xml.dom import minidom
from tuxisalive.api import *

def main(xmlPath):
# load the inital settings that we will use to compare against
projects = []

dom = minidom.parse(urllib.urlopen(xmlPath))
for node in dom.getElementsByTagName('Project'):
projects.append({
'name': node.getAttribute('name'),
'lastBuildStatus': node.getAttribute('lastBuildStatus'),
'lastBuildTime': node.getAttribute('lastBuildTime')
})

# start a loop that will check for a build event every 10 seconds
while True:
try:
dom = minidom.parse(urllib.urlopen(xmlPath))
new_projects = []
for node in dom.getElementsByTagName('Project'):
new_projects.append({
'name': node.getAttribute('name'),
'lastBuildStatus': node.getAttribute('lastBuildStatus'),
'lastBuildTime': node.getAttribute('lastBuildTime')
})
for project in new_projects:
# check to see if the project is in the current list
projectFound = False
for p in projects:
if p['name'] == project['name']:
projectFound = True
# check the status of the project against the old status
# ignore if the old status is failed
if (p['lastBuildStatus'] != 'Failure') and (project['lastBuildStatus'] == 'Failure'):
display_message_fail(project)
if (p['lastBuildStatus'] == 'Failure') and (project['lastBuildStatus'] == 'Success'):
display_message_success(project)
if (project['lastBuildStatus'] == 'Success') and (project['lastBuildTime'] != p['lastBuildTime'] ):
display_message_success_build_again(project)

# reset the project status
p['lastBuildStatus'] = project['lastBuildStatus']
p['lastBuildTime'] = project['lastBuildTime']
if not projectFound:
projects.append(project)
display_message_newproject(project)
time.sleep(10)
except KeyboardInterrupt:
# exit time
break

def display_message_fail(project):
msg = 'Someone has broken the %s build' % (project['name'])
speakPhrase(msg)

def display_message_success(project):
msg = '%s is now fixed' % (project['name'])
speakPhrase(msg)

def display_message_new(project):
msg = '%s has been added to cruise control' % (project['name'])
speakPhrase(msg)

def display_message_success_build_again(project):
msg = '%s has successfuly been built' % (project['name'])
speakPhrase(msg)

def speakPhrase(msg):
tux.mouth.open()

tux.tts.setLocutor("Lucy")
tux.tts.speak(msg.encode('utf-8'));
print msg
tux.flippers.on(4)

tux.mouth.close()

def tuxConnect():
""" Wait connected """
tux.server.autoConnect(CLIENT_LEVEL_RESTRICTED, 'TuxPidgin', 'NONE')
if tux.server.waitConnected(10.0):
if tux.dongle.waitConnected(10.0):
if tux.radio.waitConnected(10.0):
return True
else:
print "radio not connected"
return False
else:
print "radio not connected"
return False
else:
print "server not connected"
return False

def printUsage():
print "ccnet.py [url]"
print "\turl - Url of CruiseControl.NET"
print "\t\t eg. http://localhost/ccnet/XmlServerReport.aspx"

if __name__ == "__main__":
if len(sys.argv) == 2:

tgp_ip = "127.0.0.1"
tgp_port = 270
tux = TuxAPI(tgp_ip, tgp_port)
if not tuxConnect():
sys.exit(1)
tux.tts.setEncoding("utf-8")

speakPhrase("Starting Build Bot")
main(sys.argv[1])
speakPhrase("Stopping Build Bot")
tux.server.disconnect()
tux.destroy()
sys.exit(0)
else:
printUsage()