]> granicus.if.org Git - php/commitdiff
experimental code shuffling, moved download() into a new class, PEAR_Downloader.
authorGreg Beaver <cellog@php.net>
Sun, 30 Nov 2003 05:39:02 +0000 (05:39 +0000)
committerGreg Beaver <cellog@php.net>
Sun, 30 Nov 2003 05:39:02 +0000 (05:39 +0000)
Reasons:
- 7 parameters for a method with lots of pass by reference
  implies the need to save state, i.e. use an object
- cleaner code.  download() can be easily split into 4 separate but related methods
- Installer.php is now exclusively used for installation
- future extensibility: switching to channels or local package repositories from
  using PEAR_Remote is easy.  Simply extend the API for PEAR_Downloader:
  no changes needed to the installer at all

to install for testing purposes, use

pear upgrade --force package-PEAR-new-Downloader.xml

to uninstall, use

pear upgrade --force package-PEAR.xml

pear/PEAR/Command/Install-using-downloader.php [new file with mode: 0644]
pear/PEAR/Downloader.php [new file with mode: 0644]
pear/PEAR/Installer-minus-download.php [new file with mode: 0644]
pear/package-PEAR-new-Downloader.xml [new file with mode: 0644]

diff --git a/pear/PEAR/Command/Install-using-downloader.php b/pear/PEAR/Command/Install-using-downloader.php
new file mode 100644 (file)
index 0000000..06cde17
--- /dev/null
@@ -0,0 +1,535 @@
+<?php
+//
+// +----------------------------------------------------------------------+
+// | PHP Version 4                                                        |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1997-2003 The PHP Group                                |
+// +----------------------------------------------------------------------+
+// | This source file is subject to version 3.0 of the PHP license,       |
+// | that is bundled with this package in the file LICENSE, and is        |
+// | available through the world-wide-web at the following url:           |
+// | http://www.php.net/license/3_0.txt.                                  |
+// | If you did not receive a copy of the PHP license and are unable to   |
+// | obtain it through the world-wide-web, please send a note to          |
+// | license@php.net so we can mail you a copy immediately.               |
+// +----------------------------------------------------------------------+
+// | Author: Stig Sæther Bakken <ssb@php.net>                             |
+// +----------------------------------------------------------------------+
+//
+// $Id$
+
+require_once "PEAR/Command/Common.php";
+require_once "PEAR/Installer.php";
+
+/**
+ * PEAR commands for installation or deinstallation/upgrading of
+ * packages.
+ *
+ */
+class PEAR_Command_Install extends PEAR_Command_Common
+{
+    // {{{ properties
+
+    var $commands = array(
+        'install' => array(
+            'summary' => 'Install Package',
+            'function' => 'doInstall',
+            'shortcut' => 'i',
+            'options' => array(
+                'force' => array(
+                    'shortopt' => 'f',
+                    'doc' => 'will overwrite newer installed packages',
+                    ),
+                'nodeps' => array(
+                    'shortopt' => 'n',
+                    'doc' => 'ignore dependencies, install anyway',
+                    ),
+                'register-only' => array(
+                    'shortopt' => 'r',
+                    'doc' => 'do not install files, only register the package as installed',
+                    ),
+                'soft' => array(
+                    'shortopt' => 's',
+                    'doc' => 'soft install, fail silently, or upgrade if already installed',
+                    ),
+                'nobuild' => array(
+                    'shortopt' => 'B',
+                    'doc' => 'don\'t build C extensions',
+                    ),
+                'nocompress' => array(
+                    'shortopt' => 'Z',
+                    'doc' => 'request uncompressed files when downloading',
+                    ),
+                'installroot' => array(
+                    'shortopt' => 'R',
+                    'arg' => 'DIR',
+                    'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
+                    ),
+                'ignore-errors' => array(
+                    'doc' => 'force install even if there were errors',
+                    ),
+                'alldeps' => array(
+                    'shortopt' => 'a',
+                    'doc' => 'install all required and optional dependencies',
+                    ),
+                'onlyreqdeps' => array(
+                    'shortopt' => 'o',
+                    'doc' => 'install all required dependencies',
+                    ),
+                ),
+            'doc' => '<package> ...
+Installs one or more PEAR packages.  You can specify a package to
+install in four ways:
+
+"Package-1.0.tgz" : installs from a local file
+
+"http://example.com/Package-1.0.tgz" : installs from
+anywhere on the net.
+
+"package.xml" : installs the package described in
+package.xml.  Useful for testing, or for wrapping a PEAR package in
+another package manager such as RPM.
+
+"Package" : queries your configured server
+({config master_server}) and downloads the newest package with
+the preferred quality/state ({config preferred_state}).
+
+More than one package may be specified at once.  It is ok to mix these
+four ways of specifying packages.
+'),
+        'upgrade' => array(
+            'summary' => 'Upgrade Package',
+            'function' => 'doInstall',
+            'shortcut' => 'up',
+            'options' => array(
+                'force' => array(
+                    'shortopt' => 'f',
+                    'doc' => 'overwrite newer installed packages',
+                    ),
+                'nodeps' => array(
+                    'shortopt' => 'n',
+                    'doc' => 'ignore dependencies, upgrade anyway',
+                    ),
+                'register-only' => array(
+                    'shortopt' => 'r',
+                    'doc' => 'do not install files, only register the package as upgraded',
+                    ),
+                'nobuild' => array(
+                    'shortopt' => 'B',
+                    'doc' => 'don\'t build C extensions',
+                    ),
+                'nocompress' => array(
+                    'shortopt' => 'Z',
+                    'doc' => 'request uncompressed files when downloading',
+                    ),
+                'installroot' => array(
+                    'shortopt' => 'R',
+                    'arg' => 'DIR',
+                    'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
+                    ),
+                'ignore-errors' => array(
+                    'doc' => 'force install even if there were errors',
+                    ),
+                'alldeps' => array(
+                    'shortopt' => 'a',
+                    'doc' => 'install all required and optional dependencies',
+                    ),
+                'onlyreqdeps' => array(
+                    'shortopt' => 'o',
+                    'doc' => 'install all required dependencies',
+                    ),
+                ),
+            'doc' => '<package> ...
+Upgrades one or more PEAR packages.  See documentation for the
+"install" command for ways to specify a package.
+
+When upgrading, your package will be updated if the provided new
+package has a higher version number (use the -f option if you need to
+upgrade anyway).
+
+More than one package may be specified at once.
+'),
+        'upgrade-all' => array(
+            'summary' => 'Upgrade All Packages',
+            'function' => 'doInstall',
+            'shortcut' => 'ua',
+            'options' => array(
+                'nodeps' => array(
+                    'shortopt' => 'n',
+                    'doc' => 'ignore dependencies, upgrade anyway',
+                    ),
+                'register-only' => array(
+                    'shortopt' => 'r',
+                    'doc' => 'do not install files, only register the package as upgraded',
+                    ),
+                'nobuild' => array(
+                    'shortopt' => 'B',
+                    'doc' => 'don\'t build C extensions',
+                    ),
+                'nocompress' => array(
+                    'shortopt' => 'Z',
+                    'doc' => 'request uncompressed files when downloading',
+                    ),
+                'installroot' => array(
+                    'shortopt' => 'R',
+                    'arg' => 'DIR',
+                    'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
+                    ),
+                'ignore-errors' => array(
+                    'doc' => 'force install even if there were errors',
+                    ),
+                ),
+            'doc' => '
+Upgrades all packages that have a newer release available.  Upgrades are
+done only if there is a release available of the state specified in
+"preferred_state" (currently {config preferred_state}), or a state considered
+more stable.
+'),
+        'uninstall' => array(
+            'summary' => 'Un-install Package',
+            'function' => 'doUninstall',
+            'shortcut' => 'un',
+            'options' => array(
+                'nodeps' => array(
+                    'shortopt' => 'n',
+                    'doc' => 'ignore dependencies, uninstall anyway',
+                    ),
+                'register-only' => array(
+                    'shortopt' => 'r',
+                    'doc' => 'do not remove files, only register the packages as not installed',
+                    ),
+                'installroot' => array(
+                    'shortopt' => 'R',
+                    'arg' => 'DIR',
+                    'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
+                    ),
+                'ignore-errors' => array(
+                    'doc' => 'force install even if there were errors',
+                    ),
+                ),
+            'doc' => '<package> ...
+Uninstalls one or more PEAR packages.  More than one package may be
+specified at once.
+'),
+        'bundle' => array(
+            'summary' => 'Unpacks a Pecl Package',
+            'function' => 'doBundle',
+            'shortcut' => 'bun',
+            'options' => array(
+                'destination' => array(
+                   'shortopt' => 'd',
+                    'arg' => 'DIR',
+                    'doc' => 'Optional destination directory for unpacking (defaults to current path or "ext" if exists)',
+                    ),
+                'force' => array(
+                    'shortopt' => 'f',
+                    'doc' => 'Force the unpacking even if there were errors in the package',
+                ),
+            ),
+            'doc' => '<package>
+Unpacks a Pecl Package into the selected location. It will download the
+package if needed.
+'),
+        'revert' => array(
+            'summary' => 'Revert the Most Recent Upgrade of a Package',
+            'function' => 'doRevert',
+            'shortcut' => 'r',
+            'options' => array(
+                'force' => array(
+                    'shortopt' => 'f',
+                    'doc' => 'Force the revert even if there were errors',
+                    ),
+                'installroot' => array(
+                    'shortopt' => 'R',
+                    'arg' => 'DIR',
+                    'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
+                    ),
+                'deps' => array(
+                    'shortopt' => 'd',
+                    'doc' => 'revert any dependencies that are incompatible with earlier versions',
+                    ),
+                ),
+            'doc' => '<package> ...
+This command may only be used after a pear upgrade <package> has
+been executed.  pear revert will revert a package to the previously
+installed version number.  This command will only work once, and will
+fail if any packages depend on the newer version.'),
+    );
+
+    // }}}
+    // {{{ constructor
+
+    /**
+     * PEAR_Command_Install constructor.
+     *
+     * @access public
+     */
+    function PEAR_Command_Install(&$ui, &$config)
+    {
+        parent::PEAR_Command_Common($ui, $config);
+    }
+
+    // }}}
+
+    // {{{ doInstall()
+
+    function doInstall($command, $options, $params)
+    {
+        require_once 'PEAR/Downloader.php';
+        if (empty($this->installer)) {
+            $this->installer = &new PEAR_Installer($this->ui);
+        }
+        if ($command == 'upgrade') {
+            $options['upgrade'] = true;
+        }
+        if ($command == 'upgrade-all') {
+            include_once "PEAR/Remote.php";
+            $options['upgrade'] = true;
+            $remote = &new PEAR_Remote($this->config);
+            $state = $this->config->get('preferred_state');
+            if (empty($state) || $state == 'any') {
+                $latest = $remote->call("package.listLatestReleases");
+            } else {
+                $latest = $remote->call("package.listLatestReleases", $state);
+            }
+            if (PEAR::isError($latest)) {
+                return $latest;
+            }
+            $reg = new PEAR_Registry($this->config->get('php_dir'));
+            $installed = array_flip($reg->listPackages());
+            $params = array();
+            foreach ($latest as $package => $info) {
+                $package = strtolower($package);
+                if (!isset($installed[$package])) {
+                    // skip packages we don't have installed
+                    continue;
+                }
+                $inst_version = $reg->packageInfo($package, 'version');
+                if (version_compare("$info[version]", "$inst_version", "le")) {
+                    // installed version is up-to-date
+                    continue;
+                }
+                $params[] = $package;
+                $this->ui->outputData(array('data' => "Will upgrade $package"), $command);
+            }
+        }
+        $this->downloader = &new PEAR_Downloader($this->ui, $options, $this->config);
+        $errors = array();
+        $downloaded = array();
+        $this->downloader->download($params);
+        if ($command != 'upgrade-all') {
+            for ($i = 0; $i < count($params); $i++) {
+                $params[$i] = $this->downloader->extractDownloadFileName($params[$i], $_tmp);
+            }
+        }
+        $errors = $this->downloader->getErrorMsgs();
+        if (count($errors)) {
+            $err['data'] = array($errors);
+            $err['headline'] = 'Install Errors';
+            $this->ui->outputData($err);
+            return $this->raiseError("$command failed");
+        }
+        $downloaded = $this->downloader->getDownloadedPackages();
+        $this->installer->sortPkgDeps($downloaded);
+        foreach ($downloaded as $pkg) {
+            $bn = basename($pkg['file']);
+            $info = $this->installer->install($pkg['file'], $options, $this->config);
+            if (is_array($info)) {
+                if ($this->config->get('verbose') > 0) {
+                    $label = "$info[package] $info[version]";
+                    $out = array('data' => "$command ok: $label");
+                    if (isset($info['release_warnings'])) {
+                        $out['release_warnings'] = $info['release_warnings'];
+                    }
+                    $this->ui->outputData($out, $command);
+                }
+            } else {
+                return $this->raiseError("$command failed");
+            }
+        }
+        return true;
+    }
+
+    // }}}
+    // {{{ doUninstall()
+
+    function doUninstall($command, $options, $params)
+    {
+        if (empty($this->installer)) {
+            $this->installer = &new PEAR_Installer($this->ui);
+        }
+        if (sizeof($params) < 1) {
+            return $this->raiseError("Please supply the package(s) you want to uninstall");
+        }
+        include_once 'PEAR/Registry.php';
+        $reg = new PEAR_Registry($this->config->get('php_dir'));
+        $newparams = array();
+        $badparams = array();
+        foreach ($params as $pkg) {
+            $info = $reg->packageInfo($pkg);
+            if ($info === null) {
+                $badparams[] = $pkg;
+            } else {
+                $newparams[] = $info;
+            }
+        }
+        PEAR_Common::sortPkgDeps($newparams, true);
+        $params = array();
+        foreach($newparams as $info) {
+            $params[] = $info['info']['package'];
+        }
+        $params = array_merge($params, $badparams);
+        foreach ($params as $pkg) {
+            if ($this->installer->uninstall($pkg, $options)) {
+                if ($this->config->get('verbose') > 0) {
+                    $this->ui->outputData("uninstall ok: $pkg", $command);
+                }
+            } else {
+                return $this->raiseError("uninstall failed: $pkg");
+            }
+        }
+        return true;
+    }
+
+    // }}}
+
+
+    // }}}
+    // {{{ doBundle()
+    /*
+    (cox) It just downloads and untars the package, does not do
+            any check that the PEAR_Installer::_installFile() does.
+    */
+
+    function doBundle($command, $options, $params)
+    {
+        if (empty($this->installer)) {
+            $this->installer = &new PEAR_Downloader($this->ui);
+        }
+        $installer = &$this->installer;
+        if (sizeof($params) < 1) {
+            return $this->raiseError("Please supply the package you want to bundle");
+        }
+        $pkgfile = $params[0];
+        $need_download = false;
+        if (preg_match('#^(http|ftp)://#', $pkgfile)) {
+            $need_download = true;
+        } elseif (!@is_file($pkgfile)) {
+            if ($installer->validPackageName($pkgfile)) {
+                $pkgfile = $installer->getPackageDownloadUrl($pkgfile);
+                $need_download = true;
+            } else {
+                if (strlen($pkgfile)) {
+                    return $this->raiseError("Could not open the package file: $pkgfile");
+                } else {
+                    return $this->raiseError("No package file given");
+                }
+            }
+        }
+
+        // Download package -----------------------------------------------
+        if ($need_download) {
+            $downloaddir = $installer->config->get('download_dir');
+            if (empty($downloaddir)) {
+                if (PEAR::isError($downloaddir = System::mktemp('-d'))) {
+                    return $downloaddir;
+                }
+                $installer->log(2, '+ tmp dir created at ' . $downloaddir);
+            }
+            $callback = $this->ui ? array(&$installer, '_downloadCallback') : null;
+            $file = $installer->downloadHttp($pkgfile, $this->ui, $downloaddir, $callback);
+            if (PEAR::isError($file)) {
+                return $this->raiseError($file);
+            }
+            $pkgfile = $file;
+        }
+
+       // Parse xml file -----------------------------------------------
+        $pkginfo = $installer->infoFromTgzFile($pkgfile);
+        if (PEAR::isError($pkginfo)) {
+            return $this->raiseError($pkginfo);
+        }
+        $installer->validatePackageInfo($pkginfo, $errors, $warnings);
+        // XXX We allow warnings, do we have to do it?
+        if (count($errors)) {
+             if (empty($options['force'])) {
+                return $this->raiseError("The following errors where found:\n".
+                                                 implode("\n", $errors));
+            } else {
+                $this->log(0, "warning : the following errors were found:\n".
+                           implode("\n", $errors));
+            }
+        }
+        $pkgname = $pkginfo['package'];
+
+        // Unpacking -------------------------------------------------
+
+        if (isset($options['destination'])) {
+            if (!is_dir($options['destination'])) {
+                System::mkdir('-p ' . $options['destination']);
+            }
+            $dest = realpath($options['destination']);
+        } else {
+            $pwd = getcwd();
+            if (is_dir($pwd . DIRECTORY_SEPARATOR . 'ext')) {
+                $dest = $pwd . DIRECTORY_SEPARATOR . 'ext';
+            } else {
+                $dest = $pwd;
+            }
+        }
+        $dest .= DIRECTORY_SEPARATOR . $pkgname;
+        $orig = $pkgname . '-' . $pkginfo['version'];
+
+        $tar = new Archive_Tar($pkgfile);
+        if (!@$tar->extractModify($dest, $orig)) {
+            return $this->raiseError("unable to unpack $pkgfile");
+        }
+        $this->ui->outputData("Package ready at '$dest'");
+    // }}}
+    }
+
+    // }}}
+    // {{{ doRevert()
+    function doRevert($command, $options, $params)
+    {
+        if (empty($this->installer)) {
+            $this->installer = &new PEAR_Installer($this->ui);
+        }
+        if (sizeof($params) < 1) {
+            return $this->raiseError("Please supply the package(s) you want to revert");
+        }
+        include_once 'PEAR/Registry.php';
+        $reg = new PEAR_Registry($this->config->get('php_dir'));
+        $newparams = array();
+        $badparams = array();
+        foreach ($params as $pkg) {
+            $info = $reg->packageInfo($pkg);
+            if ($info === null) {
+                $badparams[]['info']['package'] = $pkg;
+            } else {
+                $newparams = array_merge($newparams,
+                    $this->installer->processRevertDeps($info, $options, $config, $reg));
+                $newparams[] = $info;
+            }
+        }
+        PEAR_Common::sortPkgDeps($newparams, true);
+        $params = array();
+        $params = array_merge($newparams, $badparams);
+        foreach ($params as $pkg) {
+            if (!PEAR::isError($this->installer->revert($pkg['info']['package'],
+                               $options, $this->config))) {
+                if ($this->config->get('verbose') > 0) {
+                    $this->ui->outputData('revert ok: ' . $pkg['info']['package'], $command);
+                }
+            } else {
+                $this->ui->outputData('revert failed: ');
+                return $this->raiseError($pkg);
+            }
+        }
+        return true;
+    }
+
+    // }}}
+
+}
+?>
diff --git a/pear/PEAR/Downloader.php b/pear/PEAR/Downloader.php
new file mode 100644 (file)
index 0000000..2b3dec4
--- /dev/null
@@ -0,0 +1,588 @@
+<?php
+//
+// +----------------------------------------------------------------------+
+// | PHP Version 4                                                        |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1997-2003 The PHP Group                                |
+// +----------------------------------------------------------------------+
+// | This source file is subject to version 3.0 of the PHP license,       |
+// | that is bundled with this package in the file LICENSE, and is        |
+// | available through the world-wide-web at the following url:           |
+// | http://www.php.net/license/3_0.txt.                                  |
+// | If you did not receive a copy of the PHP license and are unable to   |
+// | obtain it through the world-wide-web, please send a note to          |
+// | license@php.net so we can mail you a copy immediately.               |
+// +----------------------------------------------------------------------+
+// | Authors: Stig Bakken <ssb@php.net>                                   |
+// |          Tomas V.V.Cox <cox@idecnet.com>                             |
+// |          Martin Jansen <mj@php.net>                                  |
+// +----------------------------------------------------------------------+
+//
+// $Id$
+
+require_once 'PEAR/Common.php';
+require_once 'PEAR/Registry.php';
+require_once 'PEAR/Dependency.php';
+require_once 'PEAR/Remote.php';
+require_once 'System.php';
+
+/**
+ * Administration class used to download PEAR packages and maintain the
+ * installed package database.
+ *
+ * @since PEAR 1.4
+ * @author Greg Beaver <cellog@php.net>
+ */
+class PEAR_Downloader extends PEAR_Common
+{
+    /**
+     * @var PEAR_Config
+     * @access private
+     */
+    var $_config;
+
+    /**
+     * @var PEAR_Registry
+     * @access private
+     */
+    var $_registry;
+
+    /**
+     * @var PEAR_Remote
+     * @access private
+     */
+    var $_remote;
+
+    /**
+     * Preferred Installation State (snapshot, devel, alpha, beta, stable)
+     * @var string|null
+     * @access private
+     */
+    var $_preferredState;
+
+    /**
+     * Options from command-line passed to Install.
+     * 
+     * Recognized options:<br />
+     *  - onlyreqdeps   : install all required dependencies as well
+     *  - alldeps       : install all dependencies, including optional
+     *  - installroot   : base relative path to install files in
+     *  - force         : force a download even if warnings would prevent it
+     * @see PEAR_Command_Install
+     * @access private
+     * @var array
+     */
+    var $_options;
+
+    /**
+     * Downloaded Packages after a call to download().
+     * 
+     * Format of each entry:
+     *
+     * <code>
+     * array('pkg' => 'package_name', 'file' => '/path/to/local/file',
+     *    'info' => array() // parsed package.xml
+     * );
+     * </code>
+     * @access private
+     * @var array
+     */
+    var $_downloadedPackages = array();
+
+    /**
+     * Packages slated for download.
+     * 
+     * This is used to prevent downloading a package more than once should it be a dependency
+     * for two packages to be installed.
+     * Format of each entry:
+     *
+     * <pre>
+     * array('package_name1' => parsed package.xml, 'package_name2' => parsed package.xml,
+     * );
+     * </pre>
+     * @access private
+     * @var array
+     */
+    var $_toDownload = array();
+    
+    /**
+     * Array of every package installed, with names lower-cased.
+     * 
+     * Format:
+     * <code>
+     * array('package1' => 0, 'package2' => 1, );
+     * </code>
+     * @var array
+     */
+    var $_installed = array();
+    
+    /**
+     * @var array
+     * @access private
+     */
+    var $_errorStack = array();
+
+    // {{{ PEAR_Downloader()
+    
+    function PEAR_Downloader(&$ui, $options, &$config)
+    {
+        $this->_options = $options;
+        $this->_config = &$config;
+        $this->_preferredState = $this->_config->get('preferred_state');
+        if (!$this->_preferredState) {
+            // don't inadvertantly use a non-set preferred_state
+            $this->_preferredState = null;
+        }
+
+        $php_dir = $this->_config->get('php_dir');
+        if (isset($this->_options['installroot'])) {
+            if (substr($this->_options['installroot'], -1) == DIRECTORY_SEPARATOR) {
+                $this->_options['installroot'] = substr($this->_options['installroot'], 0, -1);
+            }
+            $php_dir = $this->_prependPath($php_dir, $this->_options['installroot']);
+        }
+        $this->_registry = &new PEAR_Registry($php_dir);
+        $this->_remote = &new PEAR_Remote($config);
+
+        if (isset($this->_options['alldeps']) || isset($this->_options['onlyreqdeps'])) {
+            $this->_installed = $this->_registry->listPackages();
+            array_walk($this->_installed, create_function('&$v,$k','$v = strtolower($v);'));
+            $this->_installed = array_flip($this->_installed);
+        }
+        parent::PEAR_Common($ui);
+    }
+    
+    // }}}
+    // {{{ _downloadFile()
+    /**
+     * @param string filename to download
+     * @param string version/state
+     * @param string original value passed to command-line
+     * @param string|null preferred state (snapshot/devel/alpha/beta/stable)
+     *                    Defaults to configuration preferred state
+     * @return null|PEAR_Error|string
+     * @access private
+     */
+    function _downloadFile($pkgfile, $version, $origpkgfile, $state = null)
+    {
+        if (is_null($state)) {
+            $state = $this->_preferredState;
+        }
+        // {{{ check the package filename, and whether it's already installed
+        $need_download = false;
+        if (preg_match('#^(http|ftp)://#', $pkgfile)) {
+            $need_download = true;
+        } elseif (!@is_file($pkgfile)) {
+            if ($this->validPackageName($pkgfile)) {
+                if ($this->_registry->packageExists($pkgfile)) {
+                    if (empty($this->_options['upgrade']) && empty($this->_options['force'])) {
+                        $errors[] = "$pkgfile already installed";
+                        return;
+                    }
+                }
+                $pkgfile = $this->getPackageDownloadUrl($pkgfile, $version);
+                $need_download = true;
+            } else {
+                if (strlen($pkgfile)) {
+                    $errors[] = "Could not open the package file: $pkgfile";
+                } else {
+                    $errors[] = "No package file given";
+                }
+                return;
+            }
+        }
+        // }}}
+
+        // {{{ Download package -----------------------------------------------
+        if ($need_download) {
+            $downloaddir = $this->_config->get('download_dir');
+            if (empty($downloaddir)) {
+                if (PEAR::isError($downloaddir = System::mktemp('-d'))) {
+                    return $downloaddir;
+                }
+                $this->log(3, '+ tmp dir created at ' . $downloaddir);
+            }
+            $callback = $this->ui ? array(&$this, '_downloadCallback') : null;
+            $this->pushErrorHandling(PEAR_ERROR_RETURN);
+            $file = $this->downloadHttp($pkgfile, $this->ui, $downloaddir, $callback);
+            $this->popErrorHandling();
+            if (PEAR::isError($file)) {
+                if ($this->validPackageName($origpkgfile)) {
+                    if (!PEAR::isError($info = $this->_remote->call('package.info',
+                          $origpkgfile))) {
+                        if (!count($info['releases'])) {
+                            return $this->raiseError('Package ' . $origpkgfile .
+                            ' has no releases');
+                        } else {
+                            return $this->raiseError('No releases of preferred state "'
+                            . $state . '" exist for package ' . $origpkgfile .
+                            '.  Use ' . $origpkgfile . '-state to install another' .
+                            ' state (like ' . $origpkgfile .'-beta)',
+                            PEAR_INSTALLER_ERROR_NO_PREF_STATE);
+                        }
+                    } else {
+                        return $pkgfile;
+                    }
+                } else {
+                    return $this->raiseError($file);
+                }
+            }
+            $pkgfile = $file;
+        }
+        // }}}
+        return $pkgfile;
+    }
+    // }}}
+    // {{{ getPackageDownloadUrl()
+
+    function getPackageDownloadUrl($package, $version = null)
+    {
+        if ($version) {
+            $package .= "-$version";
+        }
+        if ($this === null || $this->_config === null) {
+            $package = "http://pear.php.net/get/$package";
+        } else {
+            $package = "http://" . $this->_config->get('master_server') .
+                "/get/$package";
+        }
+        if (!extension_loaded("zlib")) {
+            $package .= '?uncompress=yes';
+        }
+        return $package;
+    }
+
+    // }}}
+    // {{{ extractDownloadFileName($pkgfile, &$version)
+
+    function extractDownloadFileName($pkgfile, &$version)
+    {
+        if (@is_file($pkgfile)) {
+            return $pkgfile;
+        }
+        // regex defined in Common.php
+        if (preg_match(PEAR_COMMON_PACKAGE_DOWNLOAD_PREG, $pkgfile, $m)) {
+            $version = (isset($m[3])) ? $m[3] : null;
+            return $m[1];
+        }
+        $version = null;
+        return $pkgfile;
+    }
+
+    // }}}
+
+    // }}}
+    // {{{ getDownloadedPackages()
+
+    /**
+     * Retrieve a list of downloaded packages after a call to {@link download()}.
+     * 
+     * Also resets the list of downloaded packages.
+     * @return array
+     */
+    function getDownloadedPackages()
+    {
+        $ret = $this->_downloadedPackages;
+        $this->_downloadedPackages = array();
+        $this->_toDownload = array();
+        return $ret;
+    }
+
+    // }}}
+    // {{{ download()
+
+    /**
+     * Download any files and their dependencies, if necessary
+     *
+     * @param array a mixed list of package names, local files, or package.xml
+     */
+    function download($packages)
+    {
+        $mywillinstall = array();
+        $state = $this->_preferredState;
+
+        // {{{ download files in this list if necessary
+        foreach($packages as $pkgfile) {
+            if (!is_file($pkgfile)) {
+                $pkgfile = $this->_downloadNonFile($pkgfile);
+                if (PEAR::isError($pkgfile)) {
+                    return $pkgfile;
+                }
+                if ($pkgfile === false) {
+                    continue;
+                }
+            } // end is_file()
+            $tempinfo = $this->infoFromAny($pkgfile);
+            if (isset($this->_options['alldeps']) || isset($this->_options['onlyreqdeps'])) {
+                // ignore dependencies if there are any errors
+                if (!PEAR::isError($tempinfo)) {
+                    $mywillinstall[strtolower($tempinfo['package'])] = @$tempinfo['release_deps'];
+                }
+            }
+            $this->_downloadedPackages[] = array('pkg' => $tempinfo['package'],
+                                       'file' => $pkgfile, 'info' => $tempinfo);
+        } // end foreach($packages)
+        // }}}
+
+        // {{{ extract dependencies from downloaded files and then download
+        // them if necessary
+        if (isset($this->_options['alldeps']) || isset($this->_options['onlyreqdeps'])) {
+            $deppackages = array();
+            foreach ($mywillinstall as $package => $alldeps) {
+                if (!is_array($alldeps)) {
+                    // there are no dependencies
+                    continue;
+                }
+                foreach($alldeps as $info) {
+                    if ($info['type'] != 'pkg') {
+                        continue;
+                    }
+                    $ret = $this->_processDependency($info, $mywillinstall);
+                    if ($ret === false) {
+                        continue;
+                    }
+                    if (PEAR::isError($ret)) {
+                        return $ret;
+                    }
+                    $deppackages[] = $ret;
+                } // foreach($alldeps
+            }
+
+            if (count($deppackages)) {
+                // check dependencies' dependencies
+                // combine the list of packages to install
+                $temppack = array();
+                foreach($this->_downloadedPackages as $p) {
+                    $temppack[] = strtolower($p['info']['package']);
+                }
+                foreach($deppackages as $pack) {
+                    $temppack[] = strtolower($pack);
+                }
+                $this->_toDownload = array_merge($this->_toDownload, $temppack);
+                $this->download($deppackages);
+            }
+        } // }}} if --alldeps or --onlyreqdeps
+    }
+
+    // }}}
+    // {{{ _downloadNonFile($pkgfile)
+    
+    /**
+     * @return false|PEAR_Error|string false if loop should be broken out of,
+     *                                 string if the file was downloaded,
+     *                                 PEAR_Error on exception
+     * @access private
+     */
+    function _downloadNonFile($pkgfile)
+    {
+        $origpkgfile = $pkgfile;
+        $state = null;
+        $pkgfile = $this->extractDownloadFileName($pkgfile, $version);
+        if (preg_match('#^(http|ftp)://#', $pkgfile)) {
+            $pkgfile = $this->_downloadFile($pkgfile, $version, $origpkgfile);
+            if (PEAR::isError($pkgfile)) {
+                return $pkgfile;
+            }
+            $tempinfo = $this->infoFromAny($pkgfile);
+            if (isset($this->_options['alldeps']) || isset($this->_options['onlyreqdeps'])) {
+                // ignore dependencies if there are any errors
+                if (!PEAR::isError($tempinfo)) {
+                    $mywillinstall[strtolower($tempinfo['package'])] = @$tempinfo['release_deps'];
+                }
+            }
+            $this->_downloadedPackages[] = array('pkg' => $tempinfo['package'],
+                                       'file' => $pkgfile, 'info' => $tempinfo);
+            return false;
+        }
+        if (!$this->validPackageName($pkgfile)) {
+            return $this->raiseError("Package name '$pkgfile' not valid");
+        }
+        // ignore packages that are installed unless we are upgrading
+        $curinfo = $this->_registry->packageInfo($pkgfile);
+        if ($this->_registry->packageExists($pkgfile)
+              && empty($this->_options['upgrade']) && empty($this->_options['force'])) {
+            $this->log(0, "Package '{$curinfo['package']}' already installed, skipping");
+            return false;
+        }
+        $curver = $curinfo['version'];
+        $releases = $this->_remote->call('package.info', $pkgfile, 'releases');
+        if (!count($releases)) {
+            return $this->raiseError("No releases found for package '$pkgfile'");
+        }
+        // Want a specific version/state
+        if ($version !== null) {
+            // Passed Foo-1.2
+            if ($this->validPackageVersion($version)) {
+                if (!isset($releases[$version])) {
+                    return $this->raiseError("No release with version '$version' found for '$pkgfile'");
+                }
+            // Passed Foo-alpha
+            } elseif (in_array($version, $this->getReleaseStates())) {
+                $state = $version;
+                $version = 0;
+                foreach ($releases as $ver => $inf) {
+                    if ($inf['state'] == $state && version_compare("$version", "$ver") < 0) {
+                        $version = $ver;
+                    }
+                }
+                if ($version == 0) {
+                    return $this->raiseError("No release with state '$state' found for '$pkgfile'");
+                }
+            // invalid postfix passed
+            } else {
+                return $this->raiseError("Invalid postfix '-$version', be sure to pass a valid PEAR ".
+                                         "version number or release state");
+            }
+        // Guess what to download
+        } else {
+            $states = $this->betterStates($this->_preferredState, true);
+            $possible = false;
+            $version = 0;
+            foreach ($releases as $ver => $inf) {
+                if (in_array($inf['state'], $states) && version_compare("$version", "$ver") < 0) {
+                    $version = $ver;
+                }
+            }
+            if ($version == 0 && !isset($this->_options['force'])) {
+                return $this->raiseError('No release with state equal to: \'' . implode(', ', $states) .
+                                         "' found for '$pkgfile'");
+            } elseif ($version == 0) {
+                $this->log(0, "Warning: $pkgfile is state '$inf[state]' which is less stable " .
+                              "than state '$state'");
+            }
+        }
+        // Check if we haven't already the version
+        if (empty($this->_options['force'])) {
+            if ($curinfo['version'] == $version) {
+                $this->log(0, "Package '{$curinfo['package']}-{$curinfo['version']}' already installed, skipping");
+                return false;
+            } elseif (version_compare("$version", "{$curinfo['version']}") < 0) {
+                $this->log(0, "Already got '{$curinfo['package']}-{$curinfo['version']}' greater than requested '$version', skipping");
+                return false;
+            }
+        }
+        return $this->_downloadFile($pkgfile, $version, $origpkgfile, $state);
+    }
+    
+    // }}}
+    // {{{ _processDependency($info)
+    
+    /**
+     * Process a dependency, download if necessary
+     * @param array dependency information from PEAR_Remote call
+     * @param array packages that will be installed in this iteration
+     * @return false|string|PEAR_Error
+     * @access private
+     */
+    function _processDependency($info, $mywillinstall)
+    {
+        $state = $this->_preferredState;
+        if (!isset($this->_options['alldeps']) && isset($info['optional']) &&
+              $info['optional'] == 'yes') {
+            // skip optional deps
+            $this->log(0, "skipping Package $package optional dependency $info[name]");
+            return false;
+        }
+        // {{{ get releases
+        $releases = $this->_remote->call('package.info', $info['name'], 'releases');
+        if (PEAR::isError($releases)) {
+            return $releases;
+        }
+        if (!count($releases)) {
+            if (!isset($this->_installed[strtolower($info['name'])])) {
+                $this->pushError("Package $package dependency $info[name] ".
+                            "has no releases");
+            }
+            return false;
+        }
+        $found = false;
+        $save = $releases;
+        while(count($releases) && !$found) {
+            if (!empty($state) && $state != 'any') {
+                list($release_version, $release) = each($releases);
+                if ($state != $release['state'] &&
+                    !in_array($release['state'], $this->betterStates($state)))
+                {
+                    // drop this release - it ain't stable enough
+                    array_shift($releases);
+                } else {
+                    $found = true;
+                }
+            } else {
+                $found = true;
+            }
+        }
+        if (!count($releases) && !$found) {
+            $get = array();
+            foreach($save as $release) {
+                $get = array_merge($get,
+                    $this->betterStates($release['state'], true));
+            }
+            $savestate = array_shift($get);
+            $this->pushError( "Release for $package dependency $info[name] " .
+                "has state '$savestate', requires $state");
+            continue;
+        }
+        if (in_array(strtolower($info['name']), $this->_toDownload) ||
+              isset($mywillinstall[strtolower($info['name'])])) {
+            // skip upgrade check for packages we will install
+            continue;
+        }
+        if (!isset($this->_installed[strtolower($info['name'])])) {
+            // check to see if we can install the specific version required
+            if ($info['rel'] == 'eq') {
+                return $info['name'] . '-' . $info['version'];
+            }
+            // skip upgrade check for packages we don't have installed
+            return $info['name'];
+        }
+        // }}}
+
+        // {{{ see if a dependency must be upgraded
+        $inst_version = $this->_registry->packageInfo($info['name'], 'version');
+        if (!isset($info['version'])) {
+            // this is a rel='has' dependency, check against latest
+            if (version_compare($release_version, $inst_version, 'le')) {
+                return false;
+            } else {
+                return $info['name'];
+            }
+        }
+        if (version_compare($info['version'], $inst_version, 'le')) {
+            // installed version is up-to-date
+            return false;
+        }
+        return $info['name'];
+    }
+    
+    // }}}
+    // {{{ pushError($errmsg, $code)
+    
+    /**
+     * @param string
+     * @param integer
+     */
+    function pushError($errmsg, $code = -1)
+    {
+        array_push($this->_errorStack, array($errmsg, $code));
+    }
+    
+    // }}}
+    // {{{ getErrorMsgs()
+    
+    function getErrorMsgs()
+    {
+        $msgs = array();
+        $errs = $this->_errorStack;
+        foreach ($errs as $err) {
+            $msgs[] = $err[0];
+        }
+        $this->_errorStack = array();
+        return $msgs;
+    }
+    
+    // }}}
+}
+// }}}
+
+?>
diff --git a/pear/PEAR/Installer-minus-download.php b/pear/PEAR/Installer-minus-download.php
new file mode 100644 (file)
index 0000000..b966b51
--- /dev/null
@@ -0,0 +1,1023 @@
+<?php
+//
+// +----------------------------------------------------------------------+
+// | PHP Version 4                                                        |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1997-2003 The PHP Group                                |
+// +----------------------------------------------------------------------+
+// | This source file is subject to version 3.0 of the PHP license,       |
+// | that is bundled with this package in the file LICENSE, and is        |
+// | available through the world-wide-web at the following url:           |
+// | http://www.php.net/license/3_0.txt.                                  |
+// | If you did not receive a copy of the PHP license and are unable to   |
+// | obtain it through the world-wide-web, please send a note to          |
+// | license@php.net so we can mail you a copy immediately.               |
+// +----------------------------------------------------------------------+
+// | Authors: Stig Bakken <ssb@php.net>                                   |
+// |          Tomas V.V.Cox <cox@idecnet.com>                             |
+// |          Martin Jansen <mj@php.net>                                  |
+// +----------------------------------------------------------------------+
+//
+// $Id$
+
+require_once 'PEAR/Common.php';
+require_once 'PEAR/Registry.php';
+require_once 'PEAR/Dependency.php';
+require_once 'System.php';
+
+define('PEAR_INSTALLER_OK',       1);
+define('PEAR_INSTALLER_FAILED',   0);
+define('PEAR_INSTALLER_SKIPPED', -1);
+define('PEAR_INSTALLER_ERROR_NO_PREF_STATE', 2);
+
+/**
+ * Administration class used to install PEAR packages and maintain the
+ * installed package database.
+ *
+ * TODO:
+ *   - Check dependencies break on package uninstall (when no force given)
+ *   - add a guessInstallDest() method with the code from _installFile() and
+ *     use that method in Registry::_rebuildFileMap() & Command_Registry::doList(),
+ *     others..
+ *
+ * @since PHP 4.0.2
+ * @author Stig Bakken <ssb@php.net>
+ * @author Martin Jansen <mj@php.net>
+ */
+class PEAR_Installer extends PEAR_Common
+{
+    // {{{ properties
+
+    /** name of the package directory, for example Foo-1.0
+     * @var string
+     */
+    var $pkgdir;
+
+    /** directory where PHP code files go
+     * @var string
+     */
+    var $phpdir;
+
+    /** directory where PHP extension files go
+     * @var string
+     */
+    var $extdir;
+
+    /** directory where documentation goes
+     * @var string
+     */
+    var $docdir;
+
+    /** installation root directory (ala PHP's INSTALL_ROOT or
+     * automake's DESTDIR
+     * @var string
+     */
+    var $installroot = '';
+
+    /** debug level
+     * @var int
+     */
+    var $debug = 1;
+
+    /** temporary directory
+     * @var string
+     */
+    var $tmpdir;
+
+    /** PEAR_Registry object used by the installer
+     * @var object
+     */
+    var $registry;
+
+    /** List of file transactions queued for an install/upgrade/uninstall.
+     *
+     *  Format:
+     *    array(
+     *      0 => array("rename => array("from-file", "to-file")),
+     *      1 => array("delete" => array("file-to-delete")),
+     *      ...
+     *    )
+     *
+     * @var array
+     */
+    var $file_operations = array();
+
+    // }}}
+
+    // {{{ constructor
+
+    /**
+     * PEAR_Installer constructor.
+     *
+     * @param object $ui user interface object (instance of PEAR_Frontend_*)
+     *
+     * @access public
+     */
+    function PEAR_Installer(&$ui)
+    {
+        parent::PEAR_Common();
+        $this->setFrontendObject($ui);
+        $this->debug = $this->config->get('verbose');
+        //$this->registry = &new PEAR_Registry($this->config->get('php_dir'));
+    }
+
+    // }}}
+
+    // {{{ _deletePackageFiles()
+
+    /**
+     * Delete a package's installed files, does not remove empty directories.
+     *
+     * @param string $package package name
+     *
+     * @return bool TRUE on success, or a PEAR error on failure
+     *
+     * @access private
+     */
+    function _deletePackageFiles($package)
+    {
+        if (!strlen($package)) {
+            return $this->raiseError("No package to uninstall given");
+        }
+        $filelist = $this->registry->packageInfo($package, 'filelist');
+        if ($filelist == null) {
+            return $this->raiseError("$package not installed");
+        }
+        foreach ($filelist as $file => $props) {
+            if (empty($props['installed_as'])) {
+                continue;
+            }
+            $path = $this->_prependPath($props['installed_as'], $this->installroot);
+            $this->addFileOperation('delete', array($path));
+        }
+        return true;
+    }
+
+    // }}}
+    // {{{ _installFile()
+
+    /**
+     * @param string filename
+     * @param array attributes from <file> tag in package.xml
+     * @param string path to install the file in
+     * @param array options from command-line
+     * @access private
+     */
+    function _installFile($file, $atts, $tmp_path, $options)
+    {
+        // {{{ return if this file is meant for another platform
+        static $os;
+        if (isset($atts['platform'])) {
+            if (empty($os)) {
+                include_once "OS/Guess.php";
+                $os = new OS_Guess();
+            }
+            if (!$os->matchSignature($atts['platform'])) {
+                $this->log(3, "skipped $file (meant for $atts[platform], we are ".$os->getSignature().")");
+                return PEAR_INSTALLER_SKIPPED;
+            }
+        }
+        // }}}
+
+        // {{{ assemble the destination paths
+        switch ($atts['role']) {
+            case 'doc':
+            case 'data':
+            case 'test':
+                $dest_dir = $this->config->get($atts['role'] . '_dir') .
+                            DIRECTORY_SEPARATOR . $this->pkginfo['package'];
+                unset($atts['baseinstalldir']);
+                break;
+            case 'ext':
+            case 'php':
+                $dest_dir = $this->config->get($atts['role'] . '_dir');
+                break;
+            case 'script':
+                $dest_dir = $this->config->get('bin_dir');
+                break;
+            case 'src':
+            case 'extsrc':
+                $this->source_files++;
+                return;
+            default:
+                return $this->raiseError("Invalid role `$atts[role]' for file $file");
+        }
+        $save_destdir = $dest_dir;
+        if (!empty($atts['baseinstalldir'])) {
+            $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir'];
+        }
+        if (dirname($file) != '.' && empty($atts['install-as'])) {
+            $dest_dir .= DIRECTORY_SEPARATOR . dirname($file);
+        }
+        if (empty($atts['install-as'])) {
+            $dest_file = $dest_dir . DIRECTORY_SEPARATOR . basename($file);
+        } else {
+            $dest_file = $dest_dir . DIRECTORY_SEPARATOR . $atts['install-as'];
+        }
+        $orig_file = $tmp_path . DIRECTORY_SEPARATOR . $file;
+
+        // Clean up the DIRECTORY_SEPARATOR mess
+        $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR;
+        list($dest_file, $orig_file) = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"),
+                                                    DIRECTORY_SEPARATOR,
+                                                    array($dest_file, $orig_file));
+        $installed_as = $dest_file;
+        $final_dest_file = $this->_prependPath($dest_file, $this->installroot);
+        $dest_dir = dirname($final_dest_file);
+        $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file);
+        // }}}
+
+        if (!@is_dir($dest_dir)) {
+            if (!$this->mkDirHier($dest_dir)) {
+                return $this->raiseError("failed to mkdir $dest_dir",
+                                         PEAR_INSTALLER_FAILED);
+            }
+            $this->log(3, "+ mkdir $dest_dir");
+        }
+        if (empty($atts['replacements'])) {
+            if (!file_exists($orig_file)) {
+                return $this->raiseError("file does not exist",
+                                         PEAR_INSTALLER_FAILED);
+            }
+            if (!@copy($orig_file, $dest_file)) {
+                return $this->raiseError("failed to write $dest_file",
+                                         PEAR_INSTALLER_FAILED);
+            }
+            $this->log(3, "+ cp $orig_file $dest_file");
+            if (isset($atts['md5sum'])) {
+                $md5sum = md5_file($dest_file);
+            }
+        } else {
+            // {{{ file with replacements
+            if (!file_exists($orig_file)) {
+                return $this->raiseError("file does not exist",
+                                         PEAR_INSTALLER_FAILED);
+            }
+            $fp = fopen($orig_file, "r");
+            $contents = fread($fp, filesize($orig_file));
+            fclose($fp);
+            if (isset($atts['md5sum'])) {
+                $md5sum = md5($contents);
+            }
+            $subst_from = $subst_to = array();
+            foreach ($atts['replacements'] as $a) {
+                $to = '';
+                if ($a['type'] == 'php-const') {
+                    if (preg_match('/^[a-z0-9_]+$/i', $a['to'])) {
+                        eval("\$to = $a[to];");
+                    } else {
+                        $this->log(0, "invalid php-const replacement: $a[to]");
+                        continue;
+                    }
+                } elseif ($a['type'] == 'pear-config') {
+                    $to = $this->config->get($a['to']);
+                    if (is_null($to)) {
+                        $this->log(0, "invalid pear-config replacement: $a[to]");
+                        continue;
+                    }
+                } elseif ($a['type'] == 'package-info') {
+                    if (isset($this->pkginfo[$a['to']]) && is_string($this->pkginfo[$a['to']])) {
+                        $to = $this->pkginfo[$a['to']];
+                    } else {
+                        $this->log(0, "invalid package-info replacement: $a[to]");
+                        continue;
+                    }
+                }
+                if (!is_null($to)) {
+                    $subst_from[] = $a['from'];
+                    $subst_to[] = $to;
+                }
+            }
+            $this->log(3, "doing ".sizeof($subst_from)." substitution(s) for $final_dest_file");
+            if (sizeof($subst_from)) {
+                $contents = str_replace($subst_from, $subst_to, $contents);
+            }
+            $wp = @fopen($dest_file, "wb");
+            if (!is_resource($wp)) {
+                return $this->raiseError("failed to create $dest_file: $php_errormsg",
+                                         PEAR_INSTALLER_FAILED);
+            }
+            if (!fwrite($wp, $contents)) {
+                return $this->raiseError("failed writing to $dest_file: $php_errormsg",
+                                         PEAR_INSTALLER_FAILED);
+            }
+            fclose($wp);
+            // }}}
+        }
+        // {{{ check the md5
+        if (isset($md5sum)) {
+            if (strtolower($md5sum) == strtolower($atts['md5sum'])) {
+                $this->log(2, "md5sum ok: $final_dest_file");
+            } else {
+                if (empty($options['force'])) {
+                    // delete the file
+                    @unlink($dest_file);
+                    return $this->raiseError("bad md5sum for file $final_dest_file",
+                                             PEAR_INSTALLER_FAILED);
+                } else {
+                    $this->log(0, "warning : bad md5sum for file $final_dest_file");
+                }
+            }
+        }
+        // }}}
+        // {{{ set file permissions
+        if (!OS_WINDOWS) {
+            if ($atts['role'] == 'script') {
+                $mode = 0777 & ~(int)octdec($this->config->get('umask'));
+                $this->log(3, "+ chmod +x $dest_file");
+            } else {
+                $mode = 0666 & ~(int)octdec($this->config->get('umask'));
+            }
+            $this->addFileOperation("chmod", array($mode, $dest_file));
+            if (!@chmod($dest_file, $mode)) {
+                $this->log(0, "failed to change mode of $dest_file");
+            }
+        }
+        // }}}
+        $this->addFileOperation("rename", array($dest_file, $final_dest_file));
+        // Store the full path where the file was installed for easy unistall
+        $this->addFileOperation("installed_as", array($file, $installed_as,
+                                $save_destdir, dirname(substr($dest_file, strlen($save_destdir)))));
+
+        //$this->log(2, "installed: $dest_file");
+        return PEAR_INSTALLER_OK;
+    }
+
+    // }}}
+    // {{{ addFileOperation()
+
+    /**
+     * Add a file operation to the current file transaction.
+     *
+     * @see startFileTransaction()
+     * @var string $type This can be one of:
+     *    - rename:  rename a file ($data has 2 values)
+     *    - chmod:   change permissions on a file ($data has 2 values)
+     *    - delete:  delete a file ($data has 1 value)
+     *    - rmdir:   delete a directory if empty ($data has 1 value)
+     *    - installed_as: mark a file as installed ($data has 4 values).
+     * @var array $data For all file operations, this array must contain the
+     *    full path to the file or directory that is being operated on.  For
+     *    the rename command, the first parameter must be the file to rename,
+     *    the second its new name.
+     *
+     *    The installed_as operation contains 4 elements in this order:
+     *    1. Filename as listed in the filelist element from package.xml
+     *    2. Full path to the installed file
+     *    3. Full path from the php_dir configuration variable used in this
+     *       installation
+     *    4. Relative path from the php_dir that this file is installed in
+     */
+    function addFileOperation($type, $data)
+    {
+        if (!is_array($data)) {
+            return $this->raiseError('Internal Error: $data in addFileOperation'
+                . ' must be an array, was ' . gettype($data));
+        }
+        if ($type == 'chmod') {
+            $octmode = decoct($data[0]);
+            $this->log(3, "adding to transaction: $type $octmode $data[1]");
+        } else {
+            $this->log(3, "adding to transaction: $type " . implode(" ", $data));
+        }
+        $this->file_operations[] = array($type, $data);
+    }
+
+    // }}}
+    // {{{ startFileTransaction()
+
+    function startFileTransaction($rollback_in_case = false)
+    {
+        if (count($this->file_operations) && $rollback_in_case) {
+            $this->rollbackFileTransaction();
+        }
+        $this->file_operations = array();
+    }
+
+    // }}}
+    // {{{ commitFileTransaction()
+
+    function commitFileTransaction()
+    {
+        $n = count($this->file_operations);
+        $this->log(2, "about to commit $n file operations");
+        // {{{ first, check permissions and such manually
+        $errors = array();
+        foreach ($this->file_operations as $tr) {
+            list($type, $data) = $tr;
+            switch ($type) {
+                case 'rename':
+                    if (!file_exists($data[0])) {
+                        $errors[] = "cannot rename file $data[0], doesn't exist";
+                    }
+                    // check that dest dir. is writable
+                    if (!is_writable(dirname($data[1]))) {
+                        $errors[] = "permission denied ($type): $data[1]";
+                    }
+                    break;
+                case 'chmod':
+                    // check that file is writable
+                    if (!is_writable($data[1])) {
+                        $errors[] = "permission denied ($type): $data[1] " . decoct($data[0]);
+                    }
+                    break;
+                case 'delete':
+                    if (!file_exists($data[0])) {
+                        $this->log(2, "warning: file $data[0] doesn't exist, can't be deleted");
+                    }
+                    // check that directory is writable
+                    if (file_exists($data[0]) && !is_writable(dirname($data[0]))) {
+                        $errors[] = "permission denied ($type): $data[0]";
+                    }
+                    break;
+            }
+
+        }
+        // }}}
+        $m = sizeof($errors);
+        if ($m > 0) {
+            foreach ($errors as $error) {
+                $this->log(1, $error);
+            }
+            return false;
+        }
+        // {{{ really commit the transaction
+        foreach ($this->file_operations as $tr) {
+            list($type, $data) = $tr;
+            switch ($type) {
+                case 'rename':
+                    @unlink($data[1]);
+                    @rename($data[0], $data[1]);
+                    $this->log(3, "+ mv $data[0] $data[1]");
+                    break;
+                case 'chmod':
+                    @chmod($data[1], $data[0]);
+                    $octmode = decoct($data[0]);
+                    $this->log(3, "+ chmod $octmode $data[1]");
+                    break;
+                case 'delete':
+                    @unlink($data[0]);
+                    $this->log(3, "+ rm $data[0]");
+                    break;
+                case 'rmdir':
+                    @rmdir($data[0]);
+                    $this->log(3, "+ rmdir $data[0]");
+                    break;
+                case 'installed_as':
+                    $this->pkginfo['filelist'][$data[0]]['installed_as'] = $data[1];
+                    if (!isset($this->pkginfo['filelist']['dirtree'][dirname($data[1])])) {
+                        $this->pkginfo['filelist']['dirtree'][dirname($data[1])] = true;
+                        while(!empty($data[3]) && $data[3] != '/' && $data[3] != '\\'
+                              && $data[3] != '.') {
+                            $this->pkginfo['filelist']['dirtree']
+                                [$this->_prependPath($data[3], $data[2])] = true;
+                            $data[3] = dirname($data[3]);
+                        }
+                    }
+                    break;
+            }
+        }
+        // }}}
+        $this->log(2, "successfully committed $n file operations");
+        $this->file_operations = array();
+        return true;
+    }
+
+    // }}}
+    // {{{ rollbackFileTransaction()
+
+    function rollbackFileTransaction()
+    {
+        $n = count($this->file_operations);
+        $this->log(2, "rolling back $n file operations");
+        foreach ($this->file_operations as $tr) {
+            list($type, $data) = $tr;
+            switch ($type) {
+                case 'rename':
+                    @unlink($data[0]);
+                    $this->log(3, "+ rm $data[0]");
+                    break;
+                case 'mkdir':
+                    @rmdir($data[0]);
+                    $this->log(3, "+ rmdir $data[0]");
+                    break;
+                case 'chmod':
+                    break;
+                case 'delete':
+                    break;
+                case 'installed_as':
+                    if (isset($this->pkginfo['filelist'])) {
+                        unset($this->pkginfo['filelist'][$data[0]]['installed_as']);
+                    }
+                    if (isset($this->pkginfo['filelist']['dirtree'][dirname($data[1])])) {
+                        unset($this->pkginfo['filelist']['dirtree'][dirname($data[1])]);
+                        while(!empty($data[3]) && $data[3] != '/' && $data[3] != '\\'
+                              && $data[3] != '.') {
+                            unset($this->pkginfo['filelist']['dirtree']
+                                [$this->_prependPath($data[3], $data[2])]);
+                            $data[3] = dirname($data[3]);
+                        }
+                    }
+                    if (isset($this->pkginfo['filelist']['dirtree'])
+                          && !count($this->pkginfo['filelist']['dirtree'])) {
+                        unset($this->pkginfo['filelist']['dirtree']);
+                    }
+                    break;
+            }
+        }
+        $this->file_operations = array();
+    }
+
+    // }}}
+    // {{{ mkDirHier($dir)
+
+    function mkDirHier($dir)
+    {
+        $this->addFileOperation('mkdir', array($dir));
+        return parent::mkDirHier($dir);
+    }
+
+    // }}}
+    // {{{ _prependPath($path, $prepend)
+
+    function _prependPath($path, $prepend)
+    {
+        if (strlen($prepend) > 0) {
+            if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) {
+                $path = $prepend . substr($path, 2);
+            } else {
+                $path = $prepend . $path;
+            }
+        }
+        return $path;
+    }
+
+    // }}}
+    // {{{ install()
+
+    /**
+     * Installs the files within the package file specified.
+     *
+     * @param string $pkgfile path to the package file
+     * @param array $options
+     * recognized options:
+     * - installroot   : optional prefix directory for installation
+     * - force         : force installation
+     * - register-only : update registry but don't install files
+     * - upgrade       : upgrade existing install
+     * - soft          : fail silently
+     * - nodeps        : ignore dependency conflicts/missing dependencies
+     * - alldeps       : install all dependencies
+     * - onlyreqdeps   : install only required dependencies
+     *
+     * @return array|PEAR_Error package info if successful
+     */
+
+    function install($pkgfile, $options = array())
+    {
+        $php_dir = $this->config->get('php_dir');
+        if (isset($options['installroot'])) {
+            if (substr($options['installroot'], -1) == DIRECTORY_SEPARATOR) {
+                $options['installroot'] = substr($options['installroot'], 0, -1);
+            }
+            $php_dir = $this->_prependPath($php_dir, $options['installroot']);
+            $this->installroot = $options['installroot'];
+        } else {
+            $this->installroot = '';
+        }
+        $this->registry = &new PEAR_Registry($php_dir);
+        //  ==> XXX should be removed later on
+        $flag_old_format = false;
+
+        if (substr($pkgfile, -4) == '.xml') {
+            $descfile = $pkgfile;
+        } else {
+            // {{{ Decompress pack in tmp dir -------------------------------------
+
+            // To allow relative package file names
+            $pkgfile = realpath($pkgfile);
+
+            if (PEAR::isError($tmpdir = System::mktemp('-d'))) {
+                return $tmpdir;
+            }
+            $this->log(3, '+ tmp dir created at ' . $tmpdir);
+
+            $tar = new Archive_Tar($pkgfile);
+            if (!@$tar->extract($tmpdir)) {
+                return $this->raiseError("unable to unpack $pkgfile");
+            }
+
+            // {{{ Look for existing package file
+            $descfile = $tmpdir . DIRECTORY_SEPARATOR . 'package.xml';
+
+            if (!is_file($descfile)) {
+                // ----- Look for old package archive format
+                // In this format the package.xml file was inside the
+                // Package-n.n directory
+                $dp = opendir($tmpdir);
+                do {
+                    $pkgdir = readdir($dp);
+                } while ($pkgdir{0} == '.');
+
+                $descfile = $tmpdir . DIRECTORY_SEPARATOR . $pkgdir . DIRECTORY_SEPARATOR . 'package.xml';
+                $flag_old_format = true;
+                $this->log(0, "warning : you are using an archive with an old format");
+            }
+            // }}}
+            // <== XXX This part should be removed later on
+            // }}}
+        }
+
+        if (!is_file($descfile)) {
+            return $this->raiseError("no package.xml file after extracting the archive");
+        }
+
+        // Parse xml file -----------------------------------------------
+        $pkginfo = $this->infoFromDescriptionFile($descfile);
+        if (PEAR::isError($pkginfo)) {
+            return $pkginfo;
+        }
+        $this->validatePackageInfo($pkginfo, $errors, $warnings);
+        // XXX We allow warnings, do we have to do it?
+        if (count($errors)) {
+            if (empty($options['force'])) {
+                return $this->raiseError("The following errors where found (use force option to install anyway):\n".
+                                         implode("\n", $errors));
+            } else {
+                $this->log(0, "warning : the following errors were found:\n".
+                           implode("\n", $errors));
+            }
+        }
+
+        $pkgname = $pkginfo['package'];
+
+        // {{{ Check dependencies -------------------------------------------
+        if (isset($pkginfo['release_deps']) && empty($options['nodeps'])) {
+            $dep_errors = '';
+            $error = $this->checkDeps($pkginfo, $dep_errors);
+            if ($error == true) {
+                if (empty($options['soft'])) {
+                    $this->log(0, substr($dep_errors, 1));
+                }
+                return $this->raiseError("$pkgname: Dependencies failed");
+            } else if (!empty($dep_errors)) {
+                // Print optional dependencies
+                if (empty($options['soft'])) {
+                    $this->log(0, $dep_errors);
+                }
+            }
+        }
+        // }}}
+
+        // {{{ checks to do when not in "force" mode
+        if (empty($options['force'])) {
+            $test = $this->registry->checkFileMap($pkginfo);
+            if (sizeof($test)) {
+                $tmp = $test;
+                foreach ($tmp as $file => $pkg) {
+                    if ($pkg == $pkgname) {
+                        unset($test[$file]);
+                    }
+                }
+                if (sizeof($test)) {
+                    $msg = "$pkgname: conflicting files found:\n";
+                    $longest = max(array_map("strlen", array_keys($test)));
+                    $fmt = "%${longest}s (%s)\n";
+                    foreach ($test as $file => $pkg) {
+                        $msg .= sprintf($fmt, $file, $pkg);
+                    }
+                    return $this->raiseError($msg);
+                }
+            }
+        }
+        // }}}
+
+        $this->startFileTransaction();
+
+        if (empty($options['upgrade'])) {
+            // checks to do only when installing new packages
+            if (empty($options['force']) && $this->registry->packageExists($pkgname)) {
+                return $this->raiseError("$pkgname already installed");
+            }
+        } else {
+            if ($this->registry->packageExists($pkgname)) {
+                $v1 = $this->registry->packageInfo($pkgname, 'version');
+                $v2 = $pkginfo['version'];
+                $cmp = version_compare("$v1", "$v2", 'gt');
+                if (empty($options['force']) && !version_compare("$v2", "$v1", 'gt')) {
+                    return $this->raiseError("upgrade to a newer version ($v2 is not newer than $v1)");
+                }
+                if (empty($options['register-only'])) {
+                    // when upgrading, remove old release's files first:
+                    if (PEAR::isError($err = $this->_deletePackageFiles($pkgname))) {
+                        return $this->raiseError($err);
+                    }
+                }
+            }
+        }
+
+        // {{{ Copy files to dest dir ---------------------------------------
+
+        // info from the package it self we want to access from _installFile
+        $this->pkginfo = &$pkginfo;
+        // used to determine whether we should build any C code
+        $this->source_files = 0;
+
+        if (empty($options['register-only'])) {
+            if (!is_dir($php_dir)) {
+                return $this->raiseError("no script destination directory\n",
+                                         null, PEAR_ERROR_DIE);
+            }
+
+            $tmp_path = dirname($descfile);
+            if (substr($pkgfile, -4) != '.xml') {
+                $tmp_path .= DIRECTORY_SEPARATOR . $pkgname . '-' . $pkginfo['version'];
+            }
+
+            //  ==> XXX This part should be removed later on
+            if ($flag_old_format) {
+                $tmp_path = dirname($descfile);
+            }
+            // <== XXX This part should be removed later on
+
+            // {{{ install files
+            foreach ($pkginfo['filelist'] as $file => $atts) {
+                $this->expectError(PEAR_INSTALLER_FAILED);
+                $res = $this->_installFile($file, $atts, $tmp_path, $options);
+                $this->popExpect();
+                if (PEAR::isError($res)) {
+                    if (empty($options['ignore-errors'])) {
+                        $this->rollbackFileTransaction();
+                        if ($res->getMessage() == "file does not exist") {
+                            $this->raiseError("file $file in package.xml does not exist");
+                        }
+                        return $this->raiseError($res);
+                    } else {
+                        $this->log(0, "Warning: " . $res->getMessage());
+                    }
+                }
+                if ($res != PEAR_INSTALLER_OK) {
+                    // Do not register files that were not installed
+                    unset($pkginfo['filelist'][$file]);
+                }
+            }
+            // }}}
+
+            // {{{ compile and install source files
+            if ($this->source_files > 0 && empty($options['nobuild'])) {
+                $this->log(1, "$this->source_files source files, building");
+                $bob = &new PEAR_Builder($this->ui);
+                $bob->debug = $this->debug;
+                $built = $bob->build($descfile, array(&$this, '_buildCallback'));
+                if (PEAR::isError($built)) {
+                    $this->rollbackFileTransaction();
+                    return $built;
+                }
+                $this->log(1, "\nBuild process completed successfully");
+                foreach ($built as $ext) {
+                    $bn = basename($ext['file']);
+                    list($_ext_name, ) = explode('.', $bn);
+                    if (extension_loaded($_ext_name)) {
+                        $this->raiseError("Extension '$_ext_name' already loaded. Please unload it ".
+                                          "in your php.ini file prior to install or upgrade it.");
+                    }
+                    $dest = $this->config->get('ext_dir') . DIRECTORY_SEPARATOR . $bn;
+                    $this->log(1, "Installing '$bn' at ext_dir ($dest)");
+                    $this->log(3, "+ cp $ext[file] ext_dir ($dest)");
+                    $copyto = $this->_prependPath($dest, $this->installroot);
+                    if (!@copy($ext['file'], $copyto)) {
+                        $this->rollbackFileTransaction();
+                        return $this->raiseError("failed to copy $bn to $copyto");
+                    }
+                    $pkginfo['filelist'][$bn] = array(
+                        'role' => 'ext',
+                        'installed_as' => $dest,
+                        'php_api' => $ext['php_api'],
+                        'zend_mod_api' => $ext['zend_mod_api'],
+                        'zend_ext_api' => $ext['zend_ext_api'],
+                        );
+                }
+            }
+            // }}}
+        }
+
+        if (!$this->commitFileTransaction()) {
+            $this->rollbackFileTransaction();
+            return $this->raiseError("commit failed", PEAR_INSTALLER_FAILED);
+        }
+        // }}}
+
+        $ret = false;
+        // {{{ Register that the package is installed -----------------------
+        if (empty($options['upgrade'])) {
+            // if 'force' is used, replace the info in registry
+            if (!empty($options['force']) && $this->registry->packageExists($pkgname)) {
+                $this->registry->deletePackage($pkgname);
+            }
+            $ret = $this->registry->addPackage($pkgname, $pkginfo);
+        } else {
+            // new: upgrade installs a package if it isn't installed
+            if (!$this->registry->packageExists($pkgname)) {
+                $ret = $this->registry->addPackage($pkgname, $pkginfo);
+            } else {
+                $ret = $this->registry->updatePackage($pkgname, $pkginfo, false);
+            }
+        }
+        if (!$ret) {
+            return $this->raiseError("Adding package $pkgname to registry failed");
+        }
+        // }}}
+        return $pkginfo;
+    }
+
+    // }}}
+    // {{{ uninstall()
+
+    /**
+     * Uninstall a package
+     *
+     * This method removes all files installed by the application, and then
+     * removes any empty directories.
+     * @param string package name
+     * @param array Command-line options.  Possibilities include:
+     *
+     *              - installroot: base installation dir, if not the default
+     */
+    function uninstall($package, $options = array())
+    {
+        $php_dir = $this->config->get('php_dir');
+        if (isset($options['installroot'])) {
+            if (substr($options['installroot'], -1) == DIRECTORY_SEPARATOR) {
+                $options['installroot'] = substr($options['installroot'], 0, -1);
+            }
+            $this->installroot = $options['installroot'];
+            $php_dir = $this->_prependPath($php_dir, $this->installroot);
+        } else {
+            $this->installroot = '';
+        }
+        $this->registry = &new PEAR_Registry($php_dir);
+        $filelist = $this->registry->packageInfo($package, 'filelist');
+        if ($filelist == null) {
+            return $this->raiseError("$package not installed");
+        }
+        if (empty($options['nodeps'])) {
+            $depchecker = &new PEAR_Dependency($this->registry);
+            $error = $depchecker->checkPackageUninstall($errors, $warning, $package);
+            if ($error) {
+                return $this->raiseError($errors . 'uninstall failed');
+            }
+            if ($warning) {
+                $this->log(0, $warning);
+            }
+        }
+        // {{{ Delete the files
+        $this->startFileTransaction();
+        if (PEAR::isError($err = $this->_deletePackageFiles($package))) {
+            $this->rollbackFileTransaction();
+            return $this->raiseError($err);
+        }
+        if (!$this->commitFileTransaction()) {
+            $this->rollbackFileTransaction();
+            return $this->raiseError("uninstall failed");
+        } else {
+            $this->startFileTransaction();
+            if (!isset($filelist['dirtree']) || !count($filelist['dirtree'])) {
+                return $this->registry->deletePackage($package);
+            }
+            // attempt to delete empty directories
+            uksort($filelist['dirtree'], array($this, '_sortDirs'));
+            foreach($filelist['dirtree'] as $dir => $notused) {
+                $this->addFileOperation('rmdir', array($dir));
+            }
+            if (!$this->commitFileTransaction()) {
+                $this->rollbackFileTransaction();
+            }
+        }
+        // }}}
+
+        // Register that the package is no longer installed
+        return $this->registry->deletePackage($package);
+    }
+
+    // }}}
+    // {{{ _sortDirs()
+    function _sortDirs($a, $b)
+    {
+        if (strnatcmp($a, $b) == -1) return 1;
+        if (strnatcmp($a, $b) == 1) return -1;
+        return 0;
+    }
+
+    // }}}
+    // {{{ checkDeps()
+
+    /**
+     * Check if the package meets all dependencies
+     *
+     * @param  array   Package information (passed by reference)
+     * @param  string  Error message (passed by reference)
+     * @return boolean False when no error occured, otherwise true
+     */
+    function checkDeps(&$pkginfo, &$errors)
+    {
+        if (empty($this->registry)) {
+            $this->registry = &new PEAR_Registry($this->config->get('php_dir'));
+        }
+        $depchecker = &new PEAR_Dependency($this->registry);
+        $error = $errors = '';
+        $failed_deps = $optional_deps = array();
+        if (is_array($pkginfo['release_deps'])) {
+            foreach($pkginfo['release_deps'] as $dep) {
+                $code = $depchecker->callCheckMethod($error, $dep);
+                if ($code) {
+                    if (isset($dep['optional']) && $dep['optional'] == 'yes') {
+                        $optional_deps[] = array($dep, $code, $error);
+                    } else {
+                        $failed_deps[] = array($dep, $code, $error);
+                    }
+                }
+            }
+            // {{{ failed dependencies
+            $n = count($failed_deps);
+            if ($n > 0) {
+                for ($i = 0; $i < $n; $i++) {
+                    if (isset($failed_deps[$i]['type'])) {
+                        $type = $failed_deps[$i]['type'];
+                    } else {
+                        $type = 'pkg';
+                    }
+                    switch ($failed_deps[$i][1]) {
+                        case PEAR_DEPENDENCY_MISSING:
+                            if ($type == 'pkg') {
+                                // install
+                            }
+                            $errors .= "\n" . $failed_deps[$i][2];
+                            break;
+                        case PEAR_DEPENDENCY_UPGRADE_MINOR:
+                            if ($type == 'pkg') {
+                                // upgrade
+                            }
+                            $errors .= "\n" . $failed_deps[$i][2];
+                            break;
+                        default:
+                            $errors .= "\n" . $failed_deps[$i][2];
+                            break;
+                    }
+                }
+                return true;
+            }
+            // }}}
+
+            // {{{ optional dependencies
+            $count_optional = count($optional_deps);
+            if ($count_optional > 0) {
+                $errors = "Optional dependencies:";
+
+                for ($i = 0; $i < $count_optional; $i++) {
+                    if (isset($optional_deps[$i]['type'])) {
+                        $type = $optional_deps[$i]['type'];
+                    } else {
+                        $type = 'pkg';
+                    }
+                    switch ($optional_deps[$i][1]) {
+                        case PEAR_DEPENDENCY_MISSING:
+                        case PEAR_DEPENDENCY_UPGRADE_MINOR:
+                        default:
+                            $errors .= "\n" . $optional_deps[$i][2];
+                            break;
+                    }
+                }
+                return false;
+            }
+            // }}}
+        }
+        return false;
+    }
+
+    // }}}
+    // {{{ _buildCallback()
+
+    function _buildCallback($what, $data)
+    {
+        if (($what == 'cmdoutput' && $this->debug > 1) ||
+            ($what == 'output' && $this->debug > 0)) {
+            $this->ui->outputData(rtrim($data), 'build');
+        }
+    }
+
+    // }}}
+}
+
+// {{{ md5_file() utility function
+if (!function_exists("md5_file")) {
+    function md5_file($filename) {
+        $fp = fopen($filename, "r");
+        if (!$fp) return null;
+        $contents = fread($fp, filesize($filename));
+        fclose($fp);
+        return md5($contents);
+    }
+}
+// }}}
+
+?>
diff --git a/pear/package-PEAR-new-Downloader.xml b/pear/package-PEAR-new-Downloader.xml
new file mode 100644 (file)
index 0000000..9ecb1a5
--- /dev/null
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE package SYSTEM "package.dtd">
+<package version="1.0">
+  <name>PEAR</name>
+  <summary>PEAR Base System</summary>
+  <description>The PEAR package contains:
+ * the PEAR base class
+ * the PEAR_Error error handling mechanism
+ * the PEAR installer, for creating, distributing
+   and installing packages
+ * the OS_Guess class for retrieving info about the OS
+   where PHP is running on
+ * the System class for quick handling common operations
+   with files and directories
+</description>
+  <license>PHP License</license>
+  <maintainers>
+    <maintainer>
+      <user>ssb</user>
+      <role>lead</role>
+      <name>Stig Sæther Bakken</name>
+      <email>stig@php.net</email>
+    </maintainer>
+    <maintainer>
+      <user>cox</user>
+      <role>lead</role>
+      <name>Tomas V.V.Cox</name>
+      <email>cox@idecnet.com</email>
+    </maintainer>
+    <maintainer>
+      <user>mj</user>
+      <role>developer</role>
+      <name>Martin Jansen</name>
+      <email>mj@php.net</email>
+    </maintainer>
+    <maintainer>
+      <user>pajoye</user>
+      <role>developer</role>
+      <name>Pierre-Alain Joye</name>
+      <email>pajoye@pearfr.org</email>
+    </maintainer>
+    <maintainer>
+      <user>cellog</user>
+      <role>developer</role>
+      <name>Greg Beaver</name>
+      <email>cellog@php.net</email>
+    </maintainer>
+  </maintainers>
+  <release>
+    <version>1.4a1</version>
+    <date>2003-11-17</date>
+    <state>alpha</state>
+    <notes>
+PEAR Installer:
+
+* Bug #171 --alldeps with a rel=&quot;eq&quot; should install the required version, if possible
+* Bug #249 installing from an url doesnt work
+* Bug #248 --force command does not work as expected
+* Bug #293 [Patch] PEAR_Error not calling static method callbacks for error-handler
+* Bug #324 pear -G gives Fatal Error (PHP-GTK not installed, but error is at engine level)
+
+    </notes>
+    <provides type="class" name="OS_Guess" />
+    <provides type="class" name="System" />
+    <provides type="function" name="md5_file" />
+    <filelist>
+      <file role="data" name="package.dtd"/>
+      <file role="data" name="template.spec"/>
+      <file role="php" name="PEAR.php"/>
+      <file role="php" name="System.php"/>
+      <dir name="PEAR">
+        <file role="php" name="Autoloader.php"/>
+        <file role="php" name="Command.php"/>
+        <dir name="Command">
+          <file role="php" name="Auth.php"/>
+          <file role="php" name="Build.php"/>
+          <file role="php" name="Common.php"/>
+          <file role="php" name="Config.php"/>
+          <file role="php" name="Install-using-downloader.php" install-as="PEAR/Command/Install.php"/>
+          <file role="php" name="Package.php"/>
+          <file role="php" name="Registry.php"/>
+          <file role="php" name="Remote.php"/>
+          <file role="php" name="Mirror.php"/>
+        </dir>
+        <file role="php" name="Common.php"/>
+        <file role="php" name="Config.php"/>
+        <file role="php" name="Dependency.php"/>
+        <dir name="Frontend">
+          <file role="php" name="CLI.php"/>
+        </dir>
+        <file role="php" name="Builder.php"/>
+        <file role="php" name="Installer-minus-download.php" install-as="PEAR/Installer.php" />
+        <file role="php" name="Downloader.php"/>
+        <file role="php" name="Packager.php"/>
+        <file role="php" name="Registry.php"/>
+        <file role="php" name="Remote.php"/>
+      </dir>
+      <dir name="OS">
+        <file role="php" name="Guess.php"/>
+      </dir>
+      <dir name="scripts" baseinstalldir="/">
+        <file role="script" install-as="pear" name="pear.sh">
+          <replace from="@php_bin@" to="php_bin" type="pear-config"/>
+          <replace from="@php_dir@" to="php_dir" type="pear-config"/>
+          <replace from="@pear_version@" to="version" type="package-info"/>
+          <replace from="@include_path@" to="php_dir" type="pear-config"/>
+        </file>
+        <file role="script" platform="windows" install-as="pear.bat" name="pear.bat">
+        <replace from="@bin_dir@" to="bin_dir" type="pear-config"/>
+        <replace from="@php_bin@" to="php_bin" type="pear-config"/>
+        <replace from="@include_path@" to="php_dir" type="pear-config"/>
+        </file>
+        <file role="php" install-as="pearcmd.php" name="pearcmd.php">
+          <replace from="@php_bin@" to="php_bin" type="pear-config"/>
+          <replace from="@php_dir@" to="php_dir" type="pear-config"/>
+          <replace from="@pear_version@" to="version" type="package-info"/>
+          <replace from="@include_path@" to="php_dir" type="pear-config"/>
+        </file>
+      </dir>
+    </filelist>
+    <deps>
+      <dep type="php" rel="ge" version="4.1"/>
+      <dep type="pkg" rel="ge" version="1.1">Archive_Tar</dep>
+      <dep type="pkg" rel="ge" version="1.0">Console_Getopt</dep>
+      <dep type="pkg" rel="ge" version="1.0.4">XML_RPC</dep>
+      <dep type="ext" rel="has" optional="yes">xmlrpc</dep>
+      <dep type="ext" rel="has">xml</dep>
+    </deps>
+  </release>
+</package>