Showing posts with label XML. Show all posts
Showing posts with label XML. Show all posts

Friday, 30 September 2011

Integrating Phing and Growl

I've been using Phing for more than a year now and it has become central to the way I work. Phing is a task based tool like make and Apache Ant that is used for automating processes. It is primarily aimed at PHP projects, though I suppose you could use it for any project that needs an automated element. Your project has a XML file called build.xml that specifies targets - a target is a job that you want to automate. Each target is built up of a number of tasks. These tasks might be 'run my unit tests' or 'copy these files.'

To execute a target, you enter 'phing targetname' on the command line. Importantly, one target can call other targets, so you can create complex routines that are run with just one command. I use just one command, 'phing ftp' to do all of the follow:
  • Run my Unit tests - if any fail the build process stops - and generate a code coverage report
  • Minify my JavaScript and CSS files
  • Switch off any debugging code in my PHP and remove any comments
  • Remove comments from my HTML
  • Upload the whole project to the staging server

Powerful stuff but the whole process takes a few minutes from start to end. I usually issue the command and then get on with something else while I wait for the files to be FTPed. What I noticed though was that I'd often forget to keep an eye on the terminal window and I'd miss that the process was complete. I wanted a popup notice to tell me that the files had all been transferred.

This is where Growl comes in. Growl is a really neat notifications system for Mac OSX and Windows. It integrates with a large number of applications. I've integrated it with Mac Mail, so I get a nice big popup message in the middle of my primary screen whenever I get an email.

There are a couple of ways to integrate Growl into an application, but for a system like Phing, the most appropriate is to use the command line tool growlnotify. This is an Growl extra - when you download Growl for Mac OSX, for example, it comes with three extra applications including growlnotify.
You call growlnotify from the command line like this:

growlnotify -n "Phing" -m "My message" -t "Phing"

The n parameter (for name) is the name that appears in your Growl preferences, so that you can specifically configure Growl for Phing. The m parameter is obviously the message that will appear in the popup notification and the t parameter sets the title in the popup. The only caveat is that the title parameter must be last.

You can also add a s switch to make the notification sticky.

Integrating this with Phing is actually quite straight forward. Phing already has a task that executes command line programs, so my solution was to extend that task's PHP class. That Phing task is called ExecTask and is located in phing/tasks/system/ExecTask.php. My task that extends this is called GrowlNotifyTask and is located in phing/tasks/mooduino/GrowlNotifyTask.php.

Lets start with your project's build file. Near the top, in side the <project> element, you need to tell Phing about the new task - this line declares the class, tells Phing where to find it, and allows use to start using a <grown> element inside any <target> elements.

<taskdef name="grown" classname="phing.tasks.mooduino.GrowlNotifyTask" />

I wanted to use the new task as follows but have the option to override some of the defaults if I wanted.

<grown message="Copying deployment files into build directory." />

The code for the task implementation is as follows. It's quite simple; it declares five private instance variables, with public setters and getters. These instance variables correspond to the attributes of the <grown> XML element. All but the $message variables have default values, so only the message attribute is required.

The class also has a main() method that pulls together the values into a command strings, and then uses parent methods in the ExecTask class to execute the command.

<?php
require_once 'phing/tasks/system/ExecTask.php';
/**
* A Task for calling the command line tool growlnotify as a phing task.
* 
* @author Michael Hodgins
*/
class GrowlNotifyTask extends ExecTask {

	private $name = 'phing';
	private $sticky = false;
	private $message = '';
	private $identifier = 'phing';
	private $title = 'Build';
	
	public function __construct() {
		parent::__construct();
		$this->setTaskName('grown');
	}
	
	public function init() {
		parent::init();
	}
	
	public function setName($name='phing') {
		$this->name = strval($name);
		return $this;
	}
	
	public function getName() {
		return $this->name;
	}
	
	public function setSticky($sticky=true)	{
		$this->sticky = $sticky ? true : false;
		return $this;
	}
	
	public function isSticky() {
		return $this->sticky;
	}
	
	public function setMessage($message='') {
		$this->message = strval($message);
		return $this;
	}
	
	public function getMessage() {
		return $this->message;
	}
	
	public function setIdentifier($identifer='phing') {
		$this->identifier = strval($identifier);
		return $this;
	}
	
	public function getIdentifier() {
		return $this->identifier;
	}
	
	public function setTitle($title='Build') {
		$this->title = strval($title);
		return $this;
	}
	
	public function getTitle() {
		return $this->title;
	}
	
	public function main() {
		$cmd = sprintf(
			"growlnotify %s-n '%s' -d '%s' -m '%s' -t '%s'",
			$this->isSticky() ? '-s ' : '',
			$this->getName(),
			$this->getIdentifier(),
			$this->getMessage(),
			$this->getTitle()
		);
		$this->setCommand($cmd);
		$this->setEscape(false);
		parent::main();
	}
}