The ZZ/OSS Installer lets you build and deploy applications using PEAR-like packages.
Unchain my deployment
So, you want to spice up your life and package up your app? In this article, you will first learn how to define packages, applications, and distributions. This part will give you a good sense of how to immediately utilize the downloadable version of the installer for your in-house projects. Later on, we learn how to create customized build plugins that do the actual installation work. You will learn how to develop install and upgrade plugins that, for example, set up or alter a database structure. The extra work of consequent packaging will result in a high reusability of software components and thus form the basis for professional software deployment.
To get started, download the latest version of ZZ/OSS Installer from the project's homepage. Extract the package to your Web server's document root, and point your browser to the directory the installer has been extracted to. A guided setup will ask you to specify some configuration parameters. Accepting the suggested default parameters should give you an installer that can do everything explained in this article. The source code is LGPL licensed which generally means that you can use the installer for GPL, as well as non-GPL, software projects (including closed source).
ZZ/OSS Installer features
| Provides a Web GUI aka installation wizard look and feel.
Command line interface is under development.
Allows definition of packages, applications, and distributions
in XML.
Automatic resolution of package dependencies.
Tools for easier development of packages.
Plugin framework for build routines (e.g. to set up or update
a database from SQL dumps).
Customisation of HTML layout for in-house products.
Solves the problem of applications using conflicting versions
of a PEAR package.
Supports full, minimal or customized installations.
Installer can upgrade itself.
Sources are LGPL for greater flexibility in usage |
|
Gimme structure
The ZZ/OSS Installer works with three types of installation entities: packages, applications, distributions. Packages are basically the same as PEAR packages, although they do not need to be PHP class files or related files. A package could be any collection files, be they PHP scripts, C# source files or ADA programs. We will later see what this means and how it is achieved. An application is a set of packages. Can you guess what a distribution is like? Yes, it is a collection of applications. For example: A company called Example Inc. could set up a distribution called Example Distribution. The user chooses this distribution in the installer and afterwards selects the Example Application he would like to install. In this respect, Figure 1 shows combined screenshots of the user interface and Figure 2 visualizes the hierarchy of installation entities.

Fig. 1: Installation Entities Diagram

Fig. 2: Relationship of Definition Files
Each of the three entities is defined in a separate XML document. In this article, we keep things simple and call them
package.xml (Listing 1),
application.xml (Listing 2),
distribution.xml (Listing 3). In the likely event that you have more than one application and each of them available in several release versions, you should consider including the application name and the version number in the file name. e.g.
example_application-1.0.xml,
another_application-1.1.xml, and so on.
Listing 1
example_package-1.0.xml
<?xml version="1.0" encoding="ISO-8859-1" ?>
<package version="1.0">
<name>example_package</name>
<summary>Example Package</summary>
<description>...</description>
<release>
<version>1.0</version>
<date>2003-12-18</date>
<state>stable</state>
<notes>Initial release.</notes>
<filelist>
<file role="php"
baseinstalldir="example_package/"
name="example_file.php"/>
<file role="xsl"
baseinstalldir="example_package/xsl/"
name="example_file.xsl"/>
</filelist>
<deps>
<dep type="pkg" rel="ge"
version="1.0">example_plugin</dep>
</deps>
<builds>
<build dir="example_plugin/"
plugin="example_plugin" rel="ge"
version="0.5">
<params>
<dsn>mysql://root@localhost/db</dsn>
</params>
</build>
</builds>
</release>
</package>
Listing 2
application.xml
<?xml version="1.0" encoding="ISO-8859-1" ?>
<application version="1.0">
<name>example_application</name>
<summary>Example Application</summary>
<description>...</description>
<homepage>http://www.example.com</homepage>
<release>
<version>1.0</version>
<date>2003-12-18</date>
<state>stable</state>
<notes>Initial release.</notes>
<packages>
<package
name="DB" version="1.5.0RC2"
baseinstalldir="lib/"
use="required"/>
<package
name="example_package" version="1.0"
baseinstalldir="mod/"
use="required"/>
<package
name="example_plugin"
version="1.0"
use="required"/>
<package
name="optional_example_package"
baseinstalldir="mod/"
version="0.9"/>
</packages>
</release>
</application>
Listing 3
distribution.xml
<?xml version="1.0" encoding="ISO-8859-1" ?>
<distribution version="1.0">
<name>example_distribution</name>
<summary>Example Distribution</summary>
<description>...</description>
<homepage>http://www.example.com</homepage>
<release>
<version>1.0</version>
<date>2003-12-18</date>
<state>stable</state>
<notes>Initial release.</notes>
</release>
<filelist>
<descriptor role="applications">
http://www.example.com/applications.xml
</descriptor>
</filelist>
</distribution>
There are three more definition files with a common task. They provide a list of installation entities available for a parent installation entity. Sounds complicated? Don't worry, it isn't.For example: File
packages.xml (note the plural!, Listing 4) stores condensed information about any package belonging to a certain application, such as the download location of the released packages and the related
package.xml (note the singular!). Analogously the
applications.xml (Listing 5) tells the installer which applications are part of a certain distribution, and the
distributions.xml (Listing 6) tells the installer about distributions available. The term used for this type of XML descriptor is repository definition files, because they define a collection of items as opposed to the package definition files. Figure 2 graphically sums up the hierarchy of XML descriptors.
Listing 4
packages.xml
<?xml version="1.0" encoding="ISO-8859-1" ?>
<packages version="1.0">
<package>
<name>DB</name>
<summary>
Database Abstraction Layer
</summary>
<release>
<version>1.5.0RC2</version>
<state>stable</state>
</release>
<filelist>
<descriptor type="package">
http://www.example.com/DB-1.5.0RC2.xml
</descriptor>
<file role="package">
http://pear.php.net/get/DB-1.5.0RC2.tgz
</file>
</filelist>
</package>
<package>
<name>example_plugin</name>
<summary>Example Plugin</summary>
<release>
<version>1.0</version>
<state>stable</state>
</release>
<filelist>
<descriptor type="package">
http://www.example.com/
example_plugin-1.0.xml
</descriptor>
<file role="package">
http://www.example.com/
example_plugin-1.0.tgz
</file>
</filelist>
</package>
<package>
<name>optional_example_package</name>
<summary>Optional Example Package</summary>
<release>
<version>1.0</version>
<state>stable</state>
</release>
<filelist>
<descriptor type="package">
http://www.example.com/
optional_example_package-1.0.xml
</descriptor>
<file role="package">
http://www.example.com/
optional_example_package-1.0.tgz
</file>
</filelist>
</package>
</packages>
Listing 5
applications.xml
<?xml version="1.0" encoding="ISO-8859-1" ?>
<applications version="1.0">
<application>
<name>example_application</name>
<summary>Example Application</summary>
<release>
<version>1.0</version>
<state>stable</state>
</release>
<filelist>
<descriptor role="application">
http://www.example.com/application.xml
</descriptor>
<descriptor role="packages">
http://www.example.com/packages.xml
</descriptor>
<file role="application">
http://www.example.com/
example_application-1.0.tar.gz
</file>
</filelist>
</application>
<application>
<name>another_application</name>
<summary>Another Application</summary>
<release>
<version>1.0</version>
<state>stable</state>
</release>
<filelist>
<descriptor role="application">
http://www.example.com/
another_application.xml
</descriptor>
<descriptor role="packages">
http://www.example.com/
another_packages.xml
</descriptor>
</filelist>
</application>
</applications>
Listing 6
distributions.xml
<?xml version="1.0" encoding="ISO-8859-1" ?>
<distributions version="1.0">
<distribution>
<name>example_distribution</name>
<summary>Example Distribution</summary>
<homepage>http://www.example.com</homepage>
<release>
<version>1.0</version>
<state>stable</state>
</release>
<filelist>
<descriptor role="distribution">
http://www.example.com/distribution.xml
</descriptor>
</filelist>
</distribution>
<distribution>
<name>another_distribution</name>
<summary>Another Distribution</summary>
<homepage>http://www.example.com</homepage>
<release>
<version>1.0</version>
<state>stable</state>
</release>
<filelist>
<descriptor role="distribution">
http://www.example.com/
another_distribution.xml
</descriptor>
</filelist>
</distribution>
</distributions>
Lots of XML, heh? The benefit of XML is that you can easily edit it manually. With only a handful of applications, creating the definition files manually is a reasonable option. On the other hand, with more than ten applications, a sophisticated deployment infrastructure should be implemented, sitting on top of something like an extended PEAR Web, where developers can upload released packages and compose applications as well as server-side distributions. This makes management and deployment much easier for larger development teams or cooperating organisations because it at least automates the creation of the repository definition files. Have a look at the ZZ/OSS Installer homepage for information on related software.
Let me organise you
The implemented architecture of installation entities allows one organisation to provide several distributions; for example, a stable production release of a distribution for customers and a beta distribution for in-house testing. In another scenario, cooperating organisations could implement a deployment network where they jointly provide a pool of distributions, applications, and packages. Within this deployment network, a company could easily use trusted third-party modules from other vendors in their own applications.
By design, the proposed architecture is independent from a certain programming language. Packages could contain PHP, Perl, Java, Python, Ruby, XSLT, DocBook XML, .htaccess, .htpasswd, files and so on. In practice, the ZZ/OSS Installer is implemented in PHP and thus limited to the functionality of PHP when writing installation routines for other programming languages.
Let's now jump into the details of the XML definition files.
We will package you
Packages form the basic entity of the installation process. They can contain any type of files and must contain a package definition file called
package.xml. In essence, ZZ/OSS Installer packages are an extended version of PEAR packages. This means that PEAR packages can be used in ZZ/OSS Installer out-of-the-box as available from the PEAR homepage. This also means that the general approach to packaging for ZZ/OSS Installer can be learnt from PEAR. The PEAR
package.xml has already been covered in greater detail in PHP Magazine. It's also explained online in the PEAR manual. Here, I will concentrate on the important differences with respect to PEAR:
- The plugin architecture of ZZ/OSS Installer allows one to define customized file roles and related processing handlers. For compatibility reasons, the installer ships with role handlers that do the same as the PEAR package manager would do with certain roles. For example they both copy files defined with the role php to the directory specified in the PHP include path. A customized file role could be named xsl and could be used to validate the documents before they are installed. Developing role handlers is not covered in this article. The default handlers should provide most of commonly needed functionality. If you are interested in this topic, read the section on making your own build plugins - this will take you half the way. The rest of information you need is available on the ZZ/OSS Installer homepage.
- Another amendment to the PEAR installer is the element where build plugins are defined. Such plugins are similar to role handlers, but rather relate a specified directory in a package archive to a plugin that processes the files inside the directory. Listing 1 shows a sample package.xml with a file and build definition. Build plugins are themselves deployed as packages and make use of a package definition file. This time the package definition file is extended by a element (Listing 7). More on developing build plugins follows later.
The naming convention for compressed package archives follows the PEAR standard, as do the names for archives of released applications, distributions, or plugins. For example:
example_package-1.0.tgz
example_application-1.0.tgz
example_distribution-1.0.tgz
example_plugin-1.0.tgz
App-ify
Just like one defines a PEAR package in XML, applications are defined in an
application.xml file when using the ZZ/OSS Installer. Listing 2 shows a sample application definition file. Those familiar with PEAR's
package.xml will notice that the root element has been renamed to
and that the part enclosed by the
element has been added. You can use almost any element of the
package.xml within the
application.xml, except for the
element and its children.
Within the
element of
application.xml, the packages that make up the application are defined. Each
element stores information about the name of the package, and its release version. It also indicates whether a certain package is required or optional for the application to function properly. This is done by defining or omitting the attribute
use=required
Based on the
use attribute, the installer allows for three types of installation: minimal, full and custom (Figure 3). A minimal installation comprises only those packages marked as required. The full installation includes all packages. Choosing the custom option will open the package manager interface where users can manually select or unselect certain packages for installation (Figure X). Those packages marked as required cannot be unselected as that would risk an unstable application.

Fig. 3: Installation Types Screenshot
The
baseinstalldir attribute of the
element tells the installer the destination directory where it should install the package files to. This means that the path specified in the
baseinstalldir attribute of the
element in a
package.xml is relative to the above mentioned
baseinstalldir path. The
basinstalldir path specified in
application.xml is relative to the root directory the whole application is supposed to be installed to. The root path is specified during the guided installation process as seen in Figure 4.

Fig. 4: Application Configuration Screenshot
Papa is a distribution
Once you have defined a package and an application, describing a distribution is simple. Again, you can use almost any elements from PEAR's
package.xml, but be aware that the
element is used in a different way. Take a look at Listing 6 and you will see that here the download URL of the
applications.xml is specified in the
child element with the role applications. As explained above, the
applications.xml contains a list of condensed information about the applications belonging to a certain distribution. Let's move on and have a closer look at all three repository definition files.
Sketches of Lists
The three repository definition files
distributions.xml,
applications.xml,
packages.xml are the glue that holds together the deployment architecture. They point the installer to related package definition files or downloadable releases. Let's start with the highest repository level: As shown in Figure 5, installing a new application from an online source starts with first selecting the distribution, then the application. Based on this workflow, the installer first grabs the
distributions.xml file (Listing 6) and displays a list of those distributions marked up within the
element. The
distributions.xml file provides the starting point of the deployment infrastructure. The URL to the
distributions.xml can be specified during the guided setup of the Installer or later in the Configure Packages section.

Fig.5: Selecting Distribution and Application
After selecting a distribution, the installer downloads the corresponding
applications.xml definition file and displays a list of applications. Listing 5 shows that within the
element of the
applications.xml, every application specifies its
application.xml and the
packages.xml that holds the complete list of related packages. Optionally, the location of a compressed archive can be provided with the
element. This application archive gets downloaded by the installer and contains all files needed to install the application, including the following files placed in the root directory of the archive (see Listing 8 in relation to the sample application):
- distribution.xml,
- application.xml,
- packages.xml,
- the compressed archives of all packages (which include the package.xml themselves for each package).
Listing 7
example_plugin-1.0.xml
<?xml version="1.0" encoding="ISO-8859-1" ?>
<package version="1.0">
<name>example_plugin</name>
<summary>Example Plugin</summary>
<description>...</description>
<release>
<version>1.0</version>
<date>2003-12-18</date>
<state>stable</state>
<notes>Initial release.</notes>
<deps>
<dep type="pkg" rel="ge"
version="1.5.0RC2">DB</dep>
</deps>
<plugin>
<file name="plugin_install.php"/>
</plugin>
</release>
</package>
Listing 8
Directory structure of application archive
example_application-1.0.tgz
/example_application-1.0/
distribution.xml
application.xml
packages.xml
DB-1.5.0.tgz
example_package-1.0.tgz
example_plugin-1.0.tgz
example_package_optional-0.9.tgz
The same can be done for distributions, where the
distributions.xml can optionally specify the URL to a compressed archive of all applications, packages, definition files needed to install them - although, in practice, this might mean downloading a large
.tgz file.
Based on the previous information, understanding
packages.xml is easy. Each package is stored with some general information and pointers to its
package.xml as well as the downloadable tar file. Those familiar with PEAR might ask Why specify the
package.xml, if it is already contained in the tar file?. Although this is true for PEAR packages, it provides more flexibility concerning third-party packages that might not include a
packge.xml or provide a
package.xml you would like to overwrite. In this case it makes sense for you to be able to treat the package definition file separately from the package archive.
Imagine integrating phpMyAdmin into the installation process of an application. Doing it the PEAR way would mean downloading a phpMyAdmin release, writing the
package.xml, adding it to the release, uploading the modified release somewhere, finally specify the URL to the modified release in the
packages.xml. Doing it the ZZ/OSS way shortens this procedure: writing the
package.xml, uploading it somewhere, specifying in the
packages.xml the URL to the download location of the original phpMyAdmin release and the
package.xml. Voil?now phpMyAdmin can be installed with the ZZ/OSS Installer.
Overwriting a
package.xml already contained in a PEAR-style package becomes necessary when one wants to use the extended features of ZZ/OSS Installer. This is especially true if such packages should make use of build plugins. Building plugins are the next topic we shed a light on.
Plugins just want to have fun
The ZZ/OSS Installer does not actually know how to install packages or applications. In fact, it only knows how to integrate plugins in its own framework. It is these plugins that actually do the installation work. Seen from this perspective, the installer provides a very flexible framework that follows a design philosophy similar to that used by the Eclipse project. A default plugin ships with the Installer for installing package files with the roles known used in PEAR. Other plugins for common tasks are available for download from the installer homepage. For more specific tasks, build plugins can be developed with little effort.
We start by introspecting the XML definition file of a build plugin as in Listing 7. A build plugin is a special type of package with special elements in the
package.xml that specify its characteristics. The
element actually makes the difference by enclosing the path to the plugin files. A build plugin must at least contain a file called
plugin_install.php which does the installation work. This file must explicitly be named this way, otherwise the ZZ/OSS Installer will not find it. There also must be a
plugin_uninstall.php script for rolling back an installation and a
plugin_role.php script for customized file role handlers. Upon installation of the plugin, the files will be moved to the directory named by the package name and its version in the installer's plugins/ directory. If you are interested in developing uninstall or role plugin files, please consult the ZZ/OSS Installer Web site.
Now let's draw our attention to the definition file of a package that utilizes the above build plugin (Listing 1). The
section is where the package refers to the plugin. Each
element specifies the name of the plugin in the
plugin attribute, the plugin version it needs, and the directory within the package archive that holds the files being processed by the plugin. Additionally, plugin-specific parameters can be provided within the
element.
If we look inside the sketch of a sample
plugin_install.php routine (Listing 9), we see how the plugin routine makes use of the plugin parameters provided by the installer. Here's an excerpt from the ZZ/OSS Installer homepage where all parameters are listed:
- $GLOBALS['ZI']['application_root'] - The absolute root path of the application, e.g. /srv/www/htdocs/
- $GLOBALS['ZI']['application_url'] - The base URL of the application, e.g. www.example.com/
- $GLOBALS['ZI']['application_demo'] - Boolean flag indicating whether demo data should also be installed.
- $GLOBALS['ZI']['package_root'] - The absolute path to the directory where the package files are copied to. The path is composed of the application root directory plus the baseinstalldir path defined in the corresponding application.xml.
- $GLOBALS['ZI']['plugin_root'] - Path to the build files as specified in the definition file of the package currently being installed. This path is related to the currently executed plugin.
- $GLOBALS['ZI']['plugin_params'] - An associative array of the parameters defined within the section of package.xml.
Listing 9
plugin_install.php
<?php
/*
* This install plugin reads the SQL dump from
* a package's plugin directory. For
* simplicity reasons, the dump stores only one
* CREATE TABLE statement.
*/
$dump = file_get_contents(
$GLOBALS['ZI']['plugin_root'].'dump.sql');
// Include PEAR::DB
require_once 'DB.php';
// To connect to the DB, use the DSN specified
// in the build parameter section of package.xml.
$db = DB::connect(
$GLOBALS['ZI']['plugin_params']['dsn']);
// Execute the SQL statement.
$db->query($dump);
?>
Make it real of dependencies
Just like repository definition files are the glue of the deployment architecture, so are dependencies the mortar that makes the application functionality rock solid. As Listing 1 and Listing 7 show, dependencies are defined in a
package.xml exactly as in PEAR. The installer features automatic dependency resolution. It checks for missing packages and, if necessary, downloads them from the specified locations (Figure 6 shows a package manager screenshot indicating packages that need to be downloaded with an arrow). During daily use at ZZ/OSS , we figured out that the highest flexibility in release management can be gained by separating runtime code from build files:

Fig. 6: Package Manager Screenshot
- Module scripts or class files should be managed in a package of their own, e.g. example_package.mod-1.0.tgz and example_package.lib-1.0.tgz.
- Related build files should be put in another package, e.g. example_package.builds-1.0.tgz
- Relate these packages to each other, along with the build plugin package, by defining the necessary dependencies.
With ZZ/OSS Installer, dependencies become a strong ally when composing a flexible, yet reliable release infrastructure. This is mainly due to the flexibility of the ZZ/OSS Installer architecture that separates installation entities (packages, applications and distributions) from plugins.
Summary
This article gave an overview of the basic features of the ZZ/OSS Installer. The features discussed here only account for roughly one-third of all currently implemented functionality. The project's homepage is a good start to dig deeper into further topics like:
- how to bundle applications with the installer to distribute them e.g. on a CD or via the Internet;
- how to make use of the configuration plugin to make packages configurable in a granular fashion. e.g. to define DB connection parameters, data storage directories, etc.
ZZ/OSS, the German company behind the installer, has deployed its applications with the ZZ/OSS Installer for one year. The Swiss company Bitflux recently decided to make their PHP applications use the ZZ/OSS Installer as well. Thanks to Zak Greant who reviewed this text.
Links and Literature
- ZZ/OSS Installer homepage: www.zzoss.com/projects/installer
- PEAR homepage: pear.php.net
- Alexander Merz: PEAR based deployment, International PHP Magazine 2.03, p. 53ff. package.xml in International PHP Magazine
- Stig Saether Bakken: Introduction to PEAR, International PHP Magazine 2.03, p. 45ff. package.xml in PEAR Manual pear.php.net/manual/en/developers.packagedef.php
- PhpMyAdmin: www.phpmyadmin.org
- Music titles associated with article headlines
- Unchain my heart (Joe Cocker), Gimme shelter (U2), Let me entertain you (Robbie Williams), We will rock you (Queen), Mystify (INXS), Papa was a rolling stone (The Tempatations), Sketches of Spain (Miles Davis), Girls just want to have fun (Cindy Lauper), Make it real of fantasy (Scorpions)