![]() |
|
URL of the article:
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
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:
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 Within the ![]() Fig. 3: Installation Types Screenshot The baseinstalldir attribute of the 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 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 ![]() 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
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 Now let's draw our attention to the definition file of a package that utilizes the above build plugin (Listing 1). The
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
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:
Links and Literature
|
||
|