I'm a huge fan of Phing and use it regularly for build and deployment tasks. Often, I'll ask about a plugin that I wish existed, and get a very courteous "patches welcome" from the nice people in the #phing channel on freenode. This has happened a few times, so I thought I should probably look at how to make a new phing plugin, this article shows you how to make the simplest thing I could think of: a simple "hello world" plugin.
Setting Up From Source
First of all, you'll need a copy of phing you can edit, and the best way to do that is to fork their github repo https://github.com/phingofficial/phing to your own account, and clone that onto your development machine (if you're new to github, I wrote an article about that too).
The program you want to run is in bin/phing in the project you cloned, I used an example config file called hello.xml (by default it looks for build.xml):
bin/phing -f hello.xml
Creating Your Plugin
To create a plugin for phing, you'll need to add something in the classes/phing/tasks/ext/ directory. For a simple plugin, this will be a single file as you see in this example, but you can also add a directory to hold any additional classes or code that your plugin will need; just look at what's already there for the best examples.
There are three things you need to know about your plugin:
- You should check any dependencies in the init() method of your new class
- The real work in your plugin is done in the main() method
- To give output, use $this->log
With all that in mind, here's my task class, named HelloTask and located in classes/phing/tasks/ext/HelloTask.php:
<?php /** * Dummy task as proof of concept * * @author Lorna Mitchell * @package phing.tasks.ext */ class HelloTask extends Task { /** * do the work */ public function main() { $this->log("Greetings, " . $this->name); } public function setName($name) { $this->name = $name; } }
Before we can use this class as a new target though, we need to let Phing know it is there, by adding it to the defaults.properties file (full path: classes/phing/tasks/defaults.properties), like so:
hello=phing.tasks.ext.HelloTask
Using Your New Plugin
Regular users of Phing will know that to configure it, you specify a target, and add tasks to that target. What we have created here is a task. Here's the configuration file I used to try out using my plugin, with a single project and defaulting to the only target:
<?xml version="1.0"?> <project name="hello" default="hello"> <target name="hello"> <hello name="Orbit" /> </target> </project>
(Orbit is a cat, in case you are wondering! Photos are available)
If any of this is unfamiliar, then I recommend you take a diversion over to the Phing documentation as it is excellent, then come back to here.
When I run this, I get:
$ bin/phing -f hello.xml
Buildfile: /home/lorna/svndir/phing/hello.xml
hello > hello:
[hello] Greetings, Orbit
BUILD FINISHED
Total time: 0.0428 seconds
Yay, the plugin is working! But we skated over some important stuff regarding the name parameter, so let's look at that in more detail.
Parameters and Phing Plugins
The configuration file can hold any parameters you care to pass, but your class needs to know what to do with them! This example had a single parameter called "name", and all you have to do is declare a setter method for that parameter - in this case a name attribute is handled by a setName() setter, called when the task is created.
Now you can create a phing plugin (or contribute additional features to an existing one) yourself, what are you waiting for? What will you build? Personally I'd like to see a Mercurial plugin for phing, so I'm helping out with the PEAR VersionControl_Hg project to work towards that goal ... watch this space.