Jon AtkinsonI'm a web developer and system administrator

Sikuli desktop automation

Posted on 24th January 2010. Tagged as tips, osx, mac, desktop, sikuli

There's quite a lot of buzz around Project Sikuli at the moment, so I spent time today playing with it.

Sikuli is a GUI automation engine which uses a vision engine to identify elements on screen. In practise, it works well as a quick way to script repetitive desktop actions, without having to learn the AppleScript actions an application provides, or how to hook into a desktop accessibility framework to manipulate applications. Instead, you tell the Sikuli engine how you expect regions of the screen to look, and then how to further manipulate them with clicks, key-presses and so on.

That is quite an abstract explanation, so here is a practical example.

Every morning, when I sit down at my desk, I do two things: I do some basic maintenance on my Mac, and I print out my day planner sheet. This only takes maybe 5 minutes, but I need to wait in front of the screen and click the right buttons at the right time. That's pretty dull, so here's how I'm using Sikuli to automate that.

First of all, the maintenance script. I use CleanMyMac to perform one big system clean every morning, which requires a few steps; launching the application, scanning for files to clean, approving the list of files, running the cleaning process, then closing the application.

My Sikuli script for doing this looks like this:

The script is fairly self-explanatory. First, it switches to (or opens) the CleanMyMac application, then runs the scan process. The script sleeps for five seconds, the searches for the 'scan finished' message, and goes to sleep again until that message is displayed. Then it performs the clean operation, and again waits for the 'clean finished' message. After this, it closes the application.

At no point is this script passing events directly to the application, nor is it querying the application to get information about its state; it's just examining the frame-buffer and looking for patterns which are similar to those specified in the script. On the Sikuli website, they claim their vision engine is smart enough to still work even if an application slightly changes it's visual style, but I haven't been able to test this.

This is the script for printing my day planner:

First, it closes then re-opens Pages so that it is in a predictable state. Then, the script manipulates the 'recent documents' drop-down, to open my 'Day Sheet 2' document. Notice that the script uses the 'wait' function frequently so that the vision engine isn't searching for an image before it has been drawn by the operating system. Once the document is open, we pass the operating system the ⌘P keyboard shortcut to open the print dialogue, then click 'print'. Finally, Pages is closed, and I check my printer tray. Here's a screen-cast of this in action. Note that I use the 'Run and show each action' button to start the script. This way, you can see the vision engine matching and highlighting each element on the screen:

Sikuli does have some limitations; You can't copy and paste between scripts, which I think is due to how the IDE stores image region data on the filesystem. Also, scripts seem wedded to the IDE, so you can't launch a script without needing to click the 'run' button in the IDE, but as the IDE is really just a thin wrapper over an underlying Jython instance, I'm sure this would be possible with a little more digging.

The obvious next step is to properly test how well Sikuli does deal with visual changes; using Sikuli to test web applications would be a great addition to the toolbox (and it would eliminate the problems with brittle tools like Selenium), and the IDE and language is simple enough for non-programmers to take some of the burden of writing tests.

I'm quite looking forward to the future of Sikuli. I'd like to see this visual search technology make it into more traditional scripting environments like AppleScript, though I'm not sure that'll happen any time soon, but anything which reduces reliance on bending traditional accessibility frameworks to perform in this role is a step forward.

Django Project Base

Posted on 22nd January 2010. Tagged as django, python, javascript

"This is my project base. There are many like it, but this one is mine."

Today I finally got around to putting my Django project base on Github. I've been using this base for about six months now, and after a lot of rewrites and different approaches, it's now reasonably stable. I've been starting a lot of new projects recently, and repeatedly fixing the same small bugs in this project template, so I decided to spend a few hours this afternoon cleaning it up and making it public.

I'm not totally satisfied with my use of shell scripts to do some of the bootstrap actions (ideally I'd use Fabric for all of these tasks), and longer-term I want to make it easier to rename the django project rather than using search/replace in TextMate.

I know there are a lot of similar projects to this on Github, but none of them worked exactly like I wanted (I think too many depend on zc.buildout and similar), and while I'm not crazy about re-inventing the wheel, I hope there are enough other people out there who share my preferences who will find this useful.

Headless Virtualbox on OSX

Posted on 3rd January 2010. Tagged as tips, osx, mac, desktop, virtualbox

When I'm developing, I try to continuously deploy to a realistic environment as often as possible. This means a Debian server running a stack as close to production as I can get. Of course, I don't deploy to the actual production servers (a lesson I've learnt many times over), so I virtualise a Debian box and clone package set from the production server. Combined with bridged networking and a quick hosts file change, and I've got a production-equivalent server always available at server.local.

Hence, I use VirtualBox all the time on my Mac, and I've got at least one server instance running all the time. But the Virtualbox.app clutters up the dock, and I really just want the instance available via SSH, I don't care about actually seeing its framebuffer.

Fortunately, you can run headless Virtualbox instances on OSX. It just takes a little extra work. Assuming you installed Virtualbox in the default location, headless Virtualbox binaries live in:

$ ls /Applications/VirtualBox.app/Contents/MacOS | grep "VBoxHeadless"
VBoxHeadless
VBoxHeadless-amd64
VBoxHeadless-x86
VBoxHeadless.dylib

You can easily run an instance in headless mode by specifying the unique name of the VM on the command line (replace "Debian Server" with the name of your VM):

/Applications/Virtualbox.app/Contents/MacOS/VBoxHeadless --startvm "Debian Server"

Of course, it's a pain to have to start these instances each time you boot the host system, but you can have the VM start on login by adding a LoginHook. Here's how:

sudo defaults write com.apple.loginwindow LoginHook /Applications/Virtualbox.app/Contents/MacOS/VBoxHeadless --startvm "Debian Server"

If you want to stop the VM, just use whatever ACPI shutdown method the guest instance provides (for a Debian server, sudo /sbin/init 0 will suffice), and the VBoxHeadless process will silently quit. If you're virtualising a graphical OS, like Windows, you should probably check the documentation to use with VBoxHeadless; you can easily specify a VRDP address so you can connect to the instance via any RDP client.

Twitter

About Me

Picture of Jon Atkinson

Jon Atkinson is a web developer, sysadmin and occasional business guy. He works in the north west of England.

Jon can be contacted at , or on freenode as JonA. Also available: twitter, LinkedIn and Github.

84labs logo

I own and run 84labs, a company which provides bespoke web application development for businesses and startups.

If you're interested in working with me, take a look, then contact me via 84labs.

Testled logo

I'm one of the founders of Testled.com, a web service to provide simple remote usability testing of web sites and desktop applications

Testled.com is currently in private beta, but you can still signup for an invite.