Phing - Personal Build System

What is PHING and how does it help

Phing is a build tool written in PHP. It is based on the popular ANT build used in Java development. A build tool is an application which helps automate the process of building a project.

Setting it up

You need PHP. WAMP setups will work fine. If you have PEAR installed, it’s the preferred method because you can customize Phing. To test it out, you can use the phing PHAR file. A PHAR is a PHP Archive file. A single file and run it by running a PHP command like php phing.phar.

Here’s where to get Phing: https://www.phing.info/trac/wiki/Users/Installation

Documentation : https://www.phing.info/docs/guide/stable/

Here’s the build system github : Phing-Personal-Build-System-Files

Phing Basics

Phing works off of build.xml files. In a classic build system, one would write a custom build file per project. There is no requirement for the file to be named build.xml. If another name is used, it would have to be provided as a command line argument. To use custom-build.xml, phing -f custom-build.xml. Much easier to use the default and just call Phing with phing .

The build files use a specific format to perform tasks. A simple breakdown of the format is

<?xml version="1.0" encoding="UTF-8"?>
    <project name="project_name" default="task_set">
        <target name="task_set">
            <echo msg="Running phing" />

        </target>
    </project>

Can see a slightly longer example file here : Simple build.xml

Short explanation. Each build has to have a project element with name and a default target to run when called without parameters. A target is just a collection of tasks to execute. Each target has a name and can have an optional attribute for targets to run before execution. This lets you chain targets together.

When phing is called without parameters, it looks for a build.xml in the directory. It reads the build.xml in and will execute the default target defined in the project element. If you wish to run a target other than the default, you pass it as a parameter : phing other_target.

Tasks are predefined and there’s a fairly large list of available tasks like echo, copy file,make directory, move files, plus more. The documentation page has a full list, look under Core Tasks. Section C. defines Optional Tasks and these usually require installation of other packages to work, like PHPDoc,ApiGen,PHPMD,Git.

There’s lots more to cover. Check the docs. Only going to cover one more concept here and that’s a Core Type of filesets. Filesets are how you tell what files to work with. It looks something like this :

<fileset dir="etc" >
  <include name="httpd/**" />
  <include name="php.ini" />
</fileset>    

Translated this means in the etc directory include all files in the httpd directory recursively include any file/subdirectory found and include etc/php.ini in the file set. Note the use of the double asterik. A single asterik means give me all files in this directory. The double means all files and all files in subdirectories. If you wish to exclude directories, the . should work. Standard path conventions apply. . means this directory , `./’ means this directory , ‘…/’ means the parent directory and so on.

Building a Personal Build System

This is the hands on part. I’m going to provide the build files and directory structure to a system. The system is a work in progress and is going to change often. It’s going from simple to complex. Which should provide the flexibility to see how it works and let you start customizing your own system.

This is on windows (yes, I know).

There’s two folders : C:\work and C:\phing-repo

The work directory is the work space for projects. There’s a build.xml here which does the following:

If phing is called without a parameter, it displays a message to run phing skeleton. This is prevent accidentally starting the process which would require a project name to be entered. Typing phing skeleton will start the ‘zero’ target because it is a dependecy of the ‘skeleton’ target.

Zero prompts for a project name. Type the name of the project, note it will overwrite the project if it already exists. Zero loads a properties file from phing-repo named zero.properties. This contains specific information for the overall system configuration, path names mainly and information about you, email, name,etc. This can be edited to include whatever you want. These properties are available as variables in phing build files after they are loaded. They can be referenced usiing this format ${property_name}. Note you can group variables using .'s. For instance, author.name would be called using ${author.name}. There’s tasks which can work with groups so you can echo the entire author. group of variables.

Skeleton runs next and it performs some simple actions. Creates a directory with the project name. Inside that directory is created src/ and dist/ directories. A basic build.xml is copied from phing-repo to project_name directory. Another properties is written out which contains the project name. Finally version.txt is copied over.

Build is finished.

Back at the command prompt, type cd project_name. Type phing .

Should get a result like this :

    C:\work\rose>phing
    Buildfile: C:\work\rose\build.xml

    skeleton > zero:

     [property] Loading C:\phing-repo\zero.properties
     [property] Loading C:\work\rose\build.properties
         [echo] rose

    skeleton > build:

         [echo] Customize your build process for rose
       [delete] Deleting directory C:\work\rose\dist
        [mkdir] Created dir: C:\work\rose\dist

    BUILD FINISHED

    Total time: 1.8645 second

Super simple and almost useless. From this point you would add files to src/, customize the build.xml and your finished project would be in dist/ . It’s important to remember you only edit the build.xml in the project_name folder. If you change the work/build.xml, it’ll cause problems.

Adding Features

Let’s create a slightly more complex build type for use in the work directory. This will create a basic website structure which will be placed in the project src directory. The project build file will be expanded to give us a few more options as well such as deploying the files to a local web server so the project can be viewed.

If we add more build types, we will have to edit the skeleton project because there would be two build.xml files in the phing-repo. Those could be named different and change the name when moved over. We don’t want lots of files floating around the top level of phing-repo. Keeping it organized will be important when it comes time expand the system. Will create a directory called ‘types’ just to organize things.

Files for this step are in the simple-v2 folder. You can delete the contents of work/ and phing-repo/ and replace them with files from simple-v2/phing-repo being placed in C:\phing-repo. All other files/folders in simple-v2/ go into C:\work.

First let’s make our adjustments. In phing-repo we add two folders, shared and types. Move version.txt and zero.properties into shared. Rename build.xml to simple-build.xml. We’re going to edit the work/build.xml by modifying the default target but we should update the file paths for skeleton. We’re also going to change the hardcoded paths for the repo directory to use variables.

The new lines for copying the build.xml, the location of the zero.properties file, and version.txt will be updated.

<copy file="${config.repo.dir}/types/simple-build.xml" tofile="${projectname}/build.xml" overwrite="true">
</copy>
 <copy file="${config.repo.dir}/shared/version.txt" tofile="${projectname}/version.txt" overwrite="true"/>

The default message should be changed as well since we have types we can no longer provide a simple message. Ideally we would list the available project types to be created. Keep in mind we want to be able to define multiple project types to help with development as much as possible. As you customize the process, you will want to add your own project types to this system. There’s no way to get a list of available targets from within a build file. We have to resort to executing a system call to phing using the -l switch to get the targets. How this works isn’t being covered so just use it, if curious you can expect the code. On the TARGET element, the hidden=“true” attribute is set to remove some targets from the listing.

A new target has to be created. The project type will be a simple HTML site setup. Going to add a basic HTML index page, some common page types, common directories like template,media. We also want some common files used for websites like robots.txt. These files will be copied from phing-repo to project_name/src when the build process runs. The build.xml file for this project type will have some increased functionality.

in phing-repo/types we create a directory named html . Add files/folders, whatever we want. Then all it takes is a phing html and the files will be copied into place.

The normal process when running a build would be take the source files from src/ and perform some tasks on them. Before you do that, the files in src/ can be modified to match the project. The development part of the process. Add content, images, write some CSS, whatever it is that needs to be done. When complete, run phing with the build target. In this case it just copies the files over.

Might be asking, ‘why even bother?’. This is a simple process for an example. The functionality to be added at this point would be more complex with the additional processing requirement. This is what we want to add.

These should ideally be written so the build process itself can contain more advanced functionality but it doesn’t require additional modification to these targets.

Starting with the first target. Increment the version of the project. The version format is three numbers joined by periods. 0.0.0 - first is major, second is minor, third is patch. We want to prompt for the type to increment. Incrementing it is easy.

Again this is straight forward. We call the zip task. Provide a FILESET, put the resulting file in the project root directory. Added creating a tar.gz of the dist/ folder (so could offer the choice of download formats). These targets were added :

Only thing to note is that the zipdist and tardist, rerun the build target before compressing the files.

** Note ** The ziptask requires php_zip.dll . You may not have it on your system and will have to grab a copy from here : https://pecl.php.net/package/zip/1.12.4/windows .Place the .dll in C:\wamp\bin\php\php5.x.x\ext. If you still get an error ,it must be enabled in php.ini (not from the WAMP menu but in C:\wamp\bin\php\php5.x.x\php.ini , this is the command line ini file for php).

Be very careful with version.txt or any property loaded through Phing. extra lines will be considered part of the property. For example if version.txt has an extra line, it will cause tar and zip tasks to both fail. Zip will say it worked. Tar will say it failed.

Last two are local and build . build is just a straight copy from src/ to dist/ . local runs build first then copies the dist/ folder contents to the config.web.dir folder which is defined in zero.properties , default is C:\wamp\www\workspaces .

One last target which should be added is a ‘full run’ target which would be taking the above targets in a sequence, ie a build. I have to test these targets before that can be added. I’ll correct the html-build.xml before posting to github so you can reference the file with some assurance it actually works.

Last problem is using the depends attribute results in the target ‘zero’ running multiple times. Removing the depends=“zero” and performing a check for the variables is one option. Or to only run zero if the properties aren’t set is a better option. Believe the latter is the best option. Will also have to update the property versionnumber after levelup runs.

What’s next ?

Want to add more of a task runner style project type. Downloading Wordpress, creating a database, copying the files over to the web directory.

Adding the Markdown, Template and LESS task types and using them in another project type is also on the list.

Before the markdown/template/less combination, a project type to just render Markdown files should provide a stepping stone.

A project type using composer to install php packages and creating a build ready to deploy to the web.

Final thoughts

The second project type took much longer to complete and test than expected. Which prevented from adding the Wordpress project type. I’ll just have to expand this to at least a 3 part post to cover the process of creating a Build System with Phing. This post is probably a bit disjointed and lacks some details on the process. If any part isn’t clear, let me know and I’ll gladly expand on any points I’m capable of addressing. If you follow the steps and get your own build system going, let me know.

Intro - expectations and an example

A build tool can aid development by automating tasks. Do not assume using a build tool will speed up development. How it helps is by defining the process or workflow of projects. I often call it the transition from ‘I’m building a website’ to ‘I’m building version 0.2.2 of project X’.

Let’s take a simple example as to how it can help. We have ten articles that are in Markdown format. We want to process these with Markdown and save as HTML files for later use in a website. There’s several options for how you complete this task. Could write a script to parse the output in PHP using PHPMarkdown, use an online tool to convert to html, or use a desktop program like MarkDownPad. Using MarkDownPad the process is open file, convert to html, save result to file, close source file. Repeat. Boring, mundane task. Perfect thing to automate.

Build Tool vs. Task Runner

Two very popular tools in web development as of 2015 are grunt and gulp. Both node.js projects which are task runners/build tools. How does Phing compare to them? Grunt and Gulp are better for front end projects. Almost everything Phing does they can do and in some cases they perform better. But they are written in Javascript. You have to write the build files in javascript. They have a large number of files. Some issues on windows with long path names.

Phing - good points (IMO)

XML build files are better because it removes the need for knowing PHP to use the tool. XML files are easier to generate from forms than programming languages like PHP or javascript. Being XML, a build file can be validated.

Verisioning

If you plan to use Phing for project releases, you need to understand the 0.0.0 format. This is a simple system to define the Major Version . Minor Version . BugFix of a project. Major should denote significant changes in project execuction or a break in compability with prior versions. Can also be used to denote marked feature increases. Minor is for changes which do not result in major changes to the nature of the project. Patch is just a fix release.

More info here : http://semver.org/