Magazine PDF Issue Conference Forum Software & Support Verlag











from PHP Magazine - International Edition Issue: 01.2004

Package up your App

The ZZ/OSS Installer lets you build and deploy applications using PEAR-like packages.
Sandro Zic

Developers of modular PHP applications need to maintain the components of their software across release cycles. A solution would be to use the PEAR package manager for this task. Unfortunately, it can deal with packages only and not install, upgrade, or uninstall applications in total. With the ZZ/OSS Installer, both can be done. Developers have access to a PEAR-like packaging system that is combined with a PHP-based installation wizard for in-house application releases. Furthermore, the plugin framework of the ZZ/OSS Installer allows for customized installation routines.

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)

    Software & Support Verlag - Global Alliance Program!







    -- Advertisement --
    Kelkoo price comparison in Germany
    - Mobiles
    - Furniture
    - Notebooks
    - Hotels
    - Flights
    - Digital cameras
    Software & Support Verlag GmbH