]> granicus.if.org Git - php/commitdiff
upgrade PEAR from 1.3.6 to new 1.4.3
authorGreg Beaver <cellog@php.net>
Wed, 2 Nov 2005 16:58:17 +0000 (16:58 +0000)
committerGreg Beaver <cellog@php.net>
Wed, 2 Nov 2005 16:58:17 +0000 (16:58 +0000)
remove unit tests - they live in pear-core/tests now

175 files changed:
pear/CMD.php [deleted file]
pear/OS/Guess.php
pear/PEAR.php
pear/PEAR/Autoloader.php
pear/PEAR/Builder.php
pear/PEAR/ChannelFile.php [new file with mode: 0644]
pear/PEAR/ChannelFile/Parser.php [new file with mode: 0644]
pear/PEAR/Command.php
pear/PEAR/Command/Auth.php
pear/PEAR/Command/Auth.xml [new file with mode: 0644]
pear/PEAR/Command/Build.php
pear/PEAR/Command/Build.xml [new file with mode: 0644]
pear/PEAR/Command/Channels.php [new file with mode: 0644]
pear/PEAR/Command/Channels.xml [new file with mode: 0644]
pear/PEAR/Command/Common.php
pear/PEAR/Command/Config.php
pear/PEAR/Command/Config.xml [new file with mode: 0644]
pear/PEAR/Command/Install.php
pear/PEAR/Command/Install.xml [new file with mode: 0644]
pear/PEAR/Command/Mirror.php
pear/PEAR/Command/Mirror.xml [new file with mode: 0644]
pear/PEAR/Command/Package.php
pear/PEAR/Command/Package.xml [new file with mode: 0644]
pear/PEAR/Command/Pickle.php [new file with mode: 0644]
pear/PEAR/Command/Pickle.xml [new file with mode: 0644]
pear/PEAR/Command/Registry.php
pear/PEAR/Command/Registry.xml [new file with mode: 0644]
pear/PEAR/Command/Remote.php
pear/PEAR/Command/Remote.xml [new file with mode: 0644]
pear/PEAR/Command/Test.php [new file with mode: 0644]
pear/PEAR/Command/Test.xml [new file with mode: 0644]
pear/PEAR/Common.php
pear/PEAR/Config.php
pear/PEAR/Dependency.php
pear/PEAR/Dependency2.php [new file with mode: 0644]
pear/PEAR/DependencyDB.php [new file with mode: 0644]
pear/PEAR/Downloader.php
pear/PEAR/Downloader/Package.php [new file with mode: 0644]
pear/PEAR/ErrorStack.php
pear/PEAR/Exception.php
pear/PEAR/Frontend.php [new file with mode: 0644]
pear/PEAR/Frontend/CLI.php
pear/PEAR/Installer.php
pear/PEAR/Installer/Role.php [new file with mode: 0644]
pear/PEAR/Installer/Role/Common.php [new file with mode: 0644]
pear/PEAR/Installer/Role/Data.php [new file with mode: 0644]
pear/PEAR/Installer/Role/Data.xml [new file with mode: 0644]
pear/PEAR/Installer/Role/Doc.php [new file with mode: 0644]
pear/PEAR/Installer/Role/Doc.xml [new file with mode: 0644]
pear/PEAR/Installer/Role/Ext.php [new file with mode: 0644]
pear/PEAR/Installer/Role/Ext.xml [new file with mode: 0644]
pear/PEAR/Installer/Role/Php.php [new file with mode: 0644]
pear/PEAR/Installer/Role/Php.xml [new file with mode: 0644]
pear/PEAR/Installer/Role/Script.php [new file with mode: 0644]
pear/PEAR/Installer/Role/Script.xml [new file with mode: 0644]
pear/PEAR/Installer/Role/Src.php [new file with mode: 0644]
pear/PEAR/Installer/Role/Src.xml [new file with mode: 0644]
pear/PEAR/Installer/Role/Test.php [new file with mode: 0644]
pear/PEAR/Installer/Role/Test.xml [new file with mode: 0644]
pear/PEAR/PackageFile.php [new file with mode: 0644]
pear/PEAR/PackageFile/Generator/v1.php [new file with mode: 0644]
pear/PEAR/PackageFile/Generator/v2.php [new file with mode: 0644]
pear/PEAR/PackageFile/Parser/v1.php [new file with mode: 0644]
pear/PEAR/PackageFile/Parser/v2.php [new file with mode: 0644]
pear/PEAR/PackageFile/v1.php [new file with mode: 0644]
pear/PEAR/PackageFile/v2.php [new file with mode: 0644]
pear/PEAR/PackageFile/v2/Validator.php [new file with mode: 0644]
pear/PEAR/PackageFile/v2/rw.php [new file with mode: 0644]
pear/PEAR/Packager.php
pear/PEAR/REST.php [new file with mode: 0644]
pear/PEAR/REST/10.php [new file with mode: 0644]
pear/PEAR/REST/11.php [new file with mode: 0644]
pear/PEAR/Registry.php
pear/PEAR/Remote.php
pear/PEAR/RunTest.php
pear/PEAR/Task/Common.php [new file with mode: 0644]
pear/PEAR/Task/Postinstallscript.php [new file with mode: 0644]
pear/PEAR/Task/Postinstallscript/rw.php [new file with mode: 0644]
pear/PEAR/Task/Replace.php [new file with mode: 0644]
pear/PEAR/Task/Replace/rw.php [new file with mode: 0644]
pear/PEAR/Task/Unixeol.php [new file with mode: 0644]
pear/PEAR/Task/Unixeol/rw.php [new file with mode: 0644]
pear/PEAR/Task/Windowseol.php [new file with mode: 0644]
pear/PEAR/Task/Windowseol/rw.php [new file with mode: 0644]
pear/PEAR/Task/test.dat [new file with mode: 0644]
pear/PEAR/Task/test.php [new file with mode: 0644]
pear/PEAR/Validate.php [new file with mode: 0644]
pear/PEAR/Validator/PECL.php [new file with mode: 0644]
pear/PEAR/XMLParser.php [new file with mode: 0644]
pear/System.php
pear/install-pear.php
pear/package-PEAR.xml
pear/package.dtd
pear/package2.xml [new file with mode: 0644]
pear/scripts/pear.bat
pear/scripts/pearcmd.php
pear/scripts/peardev.bat [new file with mode: 0644]
pear/scripts/peardev.sh [new file with mode: 0644]
pear/scripts/pearwin.php [deleted file]
pear/scripts/pecl.bat [new file with mode: 0644]
pear/scripts/pecl.sh [new file with mode: 0644]
pear/scripts/peclcmd.php [new file with mode: 0644]
pear/template.spec
pear/tests/PEAR_ErrorStack/Error_Stack_TestCase_getErrorMessage.php [deleted file]
pear/tests/PEAR_ErrorStack/Error_Stack_TestCase_getErrorMessageTemplate.php [deleted file]
pear/tests/PEAR_ErrorStack/Error_Stack_TestCase_getErrors.php [deleted file]
pear/tests/PEAR_ErrorStack/Error_Stack_TestCase_pushpop.php [deleted file]
pear/tests/PEAR_ErrorStack/Error_Stack_TestCase_pushpopcallback.php [deleted file]
pear/tests/PEAR_ErrorStack/Error_Stack_TestCase_pushpopstatic.php [deleted file]
pear/tests/PEAR_ErrorStack/Error_Stack_TestCase_singleton.php [deleted file]
pear/tests/PEAR_ErrorStack/Error_Stack_TestCase_staticGetErrors.php [deleted file]
pear/tests/PEAR_ErrorStack/HTML_TestListener.php [deleted file]
pear/tests/PEAR_ErrorStack/TestUnit.php [deleted file]
pear/tests/PEAR_ErrorStack/base_regression.php [deleted file]
pear/tests/PEAR_ErrorStack/stylesheet.css [deleted file]
pear/tests/PEAR_ErrorStack/testsuite.php [deleted file]
pear/tests/common_sortPkgDeps1_package.xml [deleted file]
pear/tests/common_sortPkgDeps2_package.xml [deleted file]
pear/tests/common_sortPkgDeps3_package.xml [deleted file]
pear/tests/common_sortPkgDeps4_package.xml [deleted file]
pear/tests/common_sortPkgDeps5_package.xml [deleted file]
pear/tests/common_sortPkgDeps6_package.xml [deleted file]
pear/tests/dirtree/multiplepackages/pkg1file.php [deleted file]
pear/tests/dirtree/multiplepackages/pkg2file.php [deleted file]
pear/tests/dirtree/nestedroot/emptydir/fakefile1.php [deleted file]
pear/tests/dirtree/nestedroot/emptydir/nesteddir/nestedfile.php [deleted file]
pear/tests/dirtree/nestedroot/rootfile.php [deleted file]
pear/tests/dirtree/package-fail.xml [deleted file]
pear/tests/dirtree/package.xml [deleted file]
pear/tests/dirtree/package2.xml [deleted file]
pear/tests/dirtree/pkg1-1.0.tgz [deleted file]
pear/tests/dirtree/pkg2-1.0.tgz [deleted file]
pear/tests/merge.input [deleted file]
pear/tests/pear1.phpt [deleted file]
pear/tests/pear2.phpt [deleted file]
pear/tests/pear_autoloader.phpt [deleted file]
pear/tests/pear_common_analyzeSC.phpt [deleted file]
pear/tests/pear_common_buildProvidesArray.phpt [deleted file]
pear/tests/pear_common_downloadHttp.phpt [deleted file]
pear/tests/pear_common_infoFromString.phpt [deleted file]
pear/tests/pear_common_sortPkgDeps.phpt [deleted file]
pear/tests/pear_common_validPackageVersion.phpt [deleted file]
pear/tests/pear_config.phpt [deleted file]
pear/tests/pear_dependency_checkExtension.phpt [deleted file]
pear/tests/pear_dependency_checkPackage.phpt [deleted file]
pear/tests/pear_dependency_checkPackageUninstall.phpt [deleted file]
pear/tests/pear_downloader_invalid.phpt [deleted file]
pear/tests/pear_downloader_new.phpt [deleted file]
pear/tests/pear_downloader_old.phpt [deleted file]
pear/tests/pear_error.phpt [deleted file]
pear/tests/pear_error2.phpt [deleted file]
pear/tests/pear_error3.phpt [deleted file]
pear/tests/pear_error4.phpt [deleted file]
pear/tests/pear_installer1.phpt [deleted file]
pear/tests/pear_installer2.phpt [deleted file]
pear/tests/pear_installer3.phpt [deleted file]
pear/tests/pear_installer4.phpt [deleted file]
pear/tests/pear_installer5.phpt [deleted file]
pear/tests/pear_packager.phpt [deleted file]
pear/tests/pear_registry.phpt [deleted file]
pear/tests/pear_system.phpt [deleted file]
pear/tests/php.ini [deleted file]
pear/tests/system.input [deleted file]
pear/tests/test-pkg6/goompness/Mopreeb.php [deleted file]
pear/tests/test-pkg6/goompness/oggbrzitzkee.php [deleted file]
pear/tests/test-pkg6/invalidtgz.tgz [deleted file]
pear/tests/test-pkg6/nopackagexml.tgz [deleted file]
pear/tests/test-pkg6/package.xml [deleted file]
pear/tests/test-pkg6/pkg6-1.1.tgz [deleted file]
pear/tests/test-pkg6/pkg6-2.0b1.tgz [deleted file]
pear/tests/test-pkg6/zoorb.php [deleted file]
pear/tests/testdownload.tgz [deleted file]
pear/tests/toonew.conf [deleted file]
pear/tests/user.input [deleted file]
pear/tests/user2.input [deleted file]

diff --git a/pear/CMD.php b/pear/CMD.php
deleted file mode 100755 (executable)
index 2bf82de..0000000
+++ /dev/null
@@ -1,285 +0,0 @@
-<?php
-//
-// +----------------------------------------------------------------------+
-// | PHP Version 5                                                        |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2004 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: Anders Johannsen <anders@johannsen.com>                      |
-// +----------------------------------------------------------------------+
-//
-define('CMD_RCSID', '$Id$');
-
-/**
- * The Cmd:: class implements an abstraction for various ways 
- * of executing commands (directly using the backtick operator,
- * as a background task after the script has terminated using
- * register_shutdown_function() or as a detached process using nohup).
- *
- * @author  Anders Johannsen <anders@johannsen.com>
- * @version $Revision$
- **/
-
-require_once 'PEAR.php';
-
-
-class Cmd extends PEAR
-{
-    var $arrSetting     = array();
-    var $arrConstant    = array();
-    var $arrCommand     = array();
-        
-    /**
-     * Class constructor
-     * 
-     * Defines all necessary constants and sets defaults
-     * 
-     * @author Anders Johannsen <anders@johannsen.com>
-     *
-     * @access public
-     * 
-     **/
-        
-    function Cmd ()
-    {
-        // Defining constants
-        $this->arrConstant  = array ("CMD_SEQUENCE",
-                                     "CMD_SHUTDOWN",
-                                     "CMD_SHELL",
-                                     "CMD_OUTPUT",
-                                     "CMD_NOHUP",
-                                     "CMD_VERBOSE"
-                                     );
-                
-        foreach ($this->arrConstant as $key => $value) {
-            if (!defined($value)) {
-                define($value, $key);
-            }
-        }
-                
-        // Setting default values
-        $this->arrSetting[CMD_SEQUENCE]     = true; 
-        $this->arrSetting[CMD_SHUTDOWN]     = false; 
-        $this->arrSetting[CMD_OUTPUT]       = false; 
-        $this->arrSetting[CMD_NOHUP]        = false; 
-        $this->arrSetting[CMD_VERBOSE]      = false; 
-                
-        $arrShell = array ("sh", "bash", "zsh", "tcsh", "csh", "ash", "sash", "esh", "ksh");
-                                   
-        foreach ($arrShell as $shell) {
-            if ($this->arrSetting[CMD_SHELL] = $this->which($shell)) {
-                break;
-            } 
-        }
-                
-        if (empty($this->arrSetting[CMD_SHELL])) {
-            $this->raiseError("No shell found");
-        }
-    }
-        
-    /**
-     * Sets any option
-     * 
-     * The options are currently:
-     * CMD_SHUTDOWN : Execute commands via a shutdown function 
-     * CMD_SHELL    : Path to shell
-     * CMD_OUTPUT   : Output stdout from process
-     * CMD_NOHUP    : Use nohup to detach process
-     * CMD_VERBOSE  : Print errors to stdout
-     *
-     * @param $option is a constant, which corresponds to the
-     * option that should be changed
-     *
-     * @param $setting is the value of the option currently
-     * being toggled.
-     *
-     * @return bool true if succes, else false
-     *
-     * @access public
-     * 
-     * @author Anders Johannsen <anders@johannsen.com>
-     * 
-     **/
-        
-    function setOption ($option, $setting)
-    {
-        if (empty($this->arrConstant[$option])) {
-            $this->raiseError("No such option: $option");
-            return false;
-        }
-    
-                
-        switch ($option) {
-        case CMD_OUTPUT:
-        case CMD_SHUTDOWN:
-        case CMD_VERBOSE:
-        case CMD_SEQUENCE:
-            $this->arrSetting[$option] = $setting;
-            return true;
-            break;
-            
-        case CMD_SHELL:
-            if (is_executable($setting)) {
-                $this->arrSetting[$option] = $setting;
-                return true;
-            } else {
-                $this->raiseError("No such shell: $setting");
-                return false;
-            }
-            break;
-            
-                    
-        case CMD_NOHUP:
-            if  (empty($setting)) {
-                $this->arrSetting[$option] = false;
-                
-            } else if ($location = $this->which("nohup")) {
-                $this->arrSetting[$option] = true;
-                
-            } else {
-                $this->raiseError("Nohup was not found on your system");
-                return false;
-            }
-            break;
-            
-        }
-    }
-    
-    /**
-     * Add command for execution
-     *
-     * @param $command accepts both arrays and regular strings
-     *
-     * @return bool true if succes, else false
-     *
-     * @access public
-     * 
-     * @author Anders Johannsen <anders@johannsen.com>
-     *
-     **/
-        
-    function command($command) 
-    {
-        if (is_array($command)) {
-            foreach ($command as $key => $value) {
-                $this->arrCommand[] = $value;
-            }
-            return true;
-
-        } else if (is_string($command)) {
-            $this->arrCommand[] = $command;
-            return true;
-        }
-                
-        $this->raiseError("Argument not valid");
-        return false;
-    }
-        
-    /**
-     * Executes the code according to given options
-     *
-     * @return bool true if succes, else false
-     *
-     * @access public
-     * 
-     * @author Anders Johannsen <anders@johannsen.com>
-     *
-     **/
-        
-    function exec() 
-    {
-        // Warning about impossible mix of options
-        if (!empty($this->arrSetting[CMD_OUTPUT])) {
-            if (!empty($this->arrSetting[CMD_SHUTDOWN]) || !empty($this->arrSetting[CMD_NOHUP])) {
-                $this->raiseError("Error: Commands executed via shutdown functions or nohup cannot return output");
-                return false;
-            }
-        }
-                
-        // Building command
-        $strCommand = implode(";", $this->arrCommand);
-                
-        $strExec    = "echo '$strCommand' | ".$this->arrSetting[CMD_SHELL];
-                
-        if (empty($this->arrSetting[CMD_OUTPUT])) {
-            $strExec = $strExec . ' > /dev/null';
-        }
-                
-        if (!empty($this->arrSetting[CMD_NOHUP])) {
-            $strExec = 'nohup ' . $strExec;
-        }
-                
-        // Executing 
-        if (!empty($this->arrSetting[CMD_SHUTDOWN])) {
-            $line = "system(\"$strExec\");";
-            $function = create_function('', $line);
-            register_shutdown_function($function);
-            return true;
-        } else {
-            return `$strExec`;
-        }
-    }
-
-    /**
-     * Errorhandler. If option CMD_VERBOSE is true,
-     * the error is printed to stdout, otherwise it 
-     * is available in lastError
-     *
-     * @return bool always returns true 
-     *
-     * @access private
-     * 
-     * @author Anders Johannsen <anders@johannsen.com>
-     **/
-        
-    function raiseError($strError) 
-    {
-        if (!empty($this->arrSetting[CMD_VERBOSE])) {
-            echo $strError;
-        } else {
-            $this->lastError = $strError;
-        }
-        
-        return true;
-    }
-        
-    /**
-     * Functionality similiar to unix 'which'. Searches the path
-     * for the specified program. 
-     *
-     * @param $cmd name of the executable to search for 
-     *
-     * @return string returns the full path if found,
-     * false if not
-     *
-     * @access private
-     * 
-     * @author Anders Johannsen <anders@johannsen.com>
-     **/
-        
-    function which($cmd) 
-    {
-        global $HTTP_ENV_VARS;
-                
-        $arrPath = explode(":", $HTTP_ENV_VARS['PATH']);
-            
-        foreach ($arrPath as $path) {
-            $location = $path . "/" . $cmd;
-                            
-            if (is_executable($location)) {
-                return $location;
-            }
-        }
-        return false;
-    }   
-}
-    
-?>
index f0566c1ec103251f76fad4b2f396f3575cff2c85..3766e74799a0627eab4253c439a80f79ec31ae2e 100644 (file)
@@ -1,23 +1,25 @@
 <?php
-//
-// +----------------------------------------------------------------------+
-// | PHP Version 5                                                        |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2004 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>                                   |
-// |                                                                      |
-// +----------------------------------------------------------------------+
-//
-// $Id$
+/**
+ * The OS_Guess class
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Gregory Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since PEAR 0.1
+ */
 
 // {{{ uname examples
 
  * - define endianness, to allow matchSignature("bigend") etc.
  */
 
+/**
+ * Retrieves information about the current operating system
+ *
+ * This class uses php_uname() to grok information about the current OS
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Gregory Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 0.1
+ */
 class OS_Guess
 {
     var $sysname;
@@ -124,10 +141,10 @@ class OS_Guess
         }
 
         switch ($sysname) {
-            case 'AIX':
+            case 'AIX' :
                 $release = "$parts[3].$parts[2]";
                 break;
-            case 'Windows':
+            case 'Windows' :
                 switch ($parts[1]) {
                     case '95/98':
                         $release = '9x';
@@ -138,7 +155,7 @@ class OS_Guess
                 }
                 $cpu = 'i386';
                 break;
-            case 'Linux':
+            case 'Linux' :
                 $extra = $this->_detectGlibcVersion();
                 // use only the first two digits from the kernel version
                 $release = ereg_replace('^([[:digit:]]+\.[[:digit:]]+).*', '\1', $parts[2]);
@@ -180,9 +197,48 @@ class OS_Guess
 
     function _detectGlibcVersion()
     {
-        // Use glibc's <features.h> header file to
-        // get major and minor version number:
+        static $glibc = false;
+        if ($glibc !== false) {
+            return $glibc; // no need to run this multiple times
+        }
         include_once "System.php";
+        if (!file_exists('/usr/bin/cpp') || !is_executable('/usr/bin/cpp')) {
+            // Use glibc's <features.h> header file to
+            // get major and minor version number:
+            if ($features_file = @fopen('/usr/include/features.h', 'rb') ) {
+                while (!feof($features_file)) {
+                    $line = fgets($features_file, 8192);
+                    if (!$line || (strpos($line, '#define') === false)) {
+                        continue;
+                    }
+                    if (strpos($line, '__GLIBC__')) {
+                        // major version number #define __GLIBC__ version
+                        $line = preg_split('/\s+/', $line);
+                        $glibc_major = trim($line[2]);
+                        if (isset($glibc_minor)) {
+                            break;
+                        }
+                        continue;
+                    }
+                    if (strpos($line, '__GLIBC_MINOR__'))  {
+                        // got the minor version number
+                        // #define __GLIBC_MINOR__ version
+                        $line = preg_split('/\s+/', $line);
+                        $glibc_minor = trim($line[2]);
+                        if (isset($glibc_major)) {
+                            break;
+                        }
+                        continue;
+                    }
+                }
+                fclose($features_file);
+                if (!isset($glibc_major) || !isset($glibc_minor)) {
+                    return $glibc = '';
+                }
+                return $glibc = 'glibc' . trim($glibc_major) . "." . trim($glibc_minor) ;
+            }
+            return $glibc = '';
+        }
         $tmpfile = System::mktemp("glibctest");
         $fp = fopen($tmpfile, "w");
         fwrite($fp, "#include <features.h>\n__GLIBC__ __GLIBC_MINOR__\n");
@@ -206,9 +262,9 @@ class OS_Guess
             }
         }
         if (!($major && $minor)) {
-            return '';
+            return $glibc = '';
         }
-        return "glibc{$major}.{$minor}";
+        return $glibc = "glibc{$major}.{$minor}";
     }
 
     function getSignature()
index 6e1892d66fdf9dbd95e6248342609369c65b9da4..7b3d64c2687780f6496a4c2bd9b7f9c369c57037 100644 (file)
@@ -1,26 +1,33 @@
 <?php
-//
-// +--------------------------------------------------------------------+
-// | PEAR, the PHP Extension and Application Repository                 |
-// +--------------------------------------------------------------------+
-// | Copyright (c) 1997-2004 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: Sterling Hughes <sterling@php.net>                        |
-// |          Stig Bakken <ssb@php.net>                                 |
-// |          Tomas V.V.Cox <cox@idecnet.com>                           |
-// +--------------------------------------------------------------------+
-//
-// $Id$
-//
+/**
+ * PEAR, the PHP Extension and Application Repository
+ *
+ * PEAR class and PEAR_Error class
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Sterling Hughes <sterling@php.net>
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Tomas V.V.Cox <cox@idecnet.com>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 0.1
+ */
 
+/**#@+
+ * ERROR constants
+ */
 define('PEAR_ERROR_RETURN',     1);
 define('PEAR_ERROR_PRINT',      2);
 define('PEAR_ERROR_TRIGGER',    4);
@@ -31,6 +38,7 @@ define('PEAR_ERROR_CALLBACK',  16);
  * @deprecated
  */
 define('PEAR_ERROR_EXCEPTION', 32);
+/**#@-*/
 define('PEAR_ZE2', (function_exists('version_compare') &&
                     version_compare(zend_version(), "2-dev", "ge")));
 
@@ -78,9 +86,18 @@ $GLOBALS['_PEAR_error_handler_stack']    = array();
  * IMPORTANT! To use the emulated destructors you need to create the
  * objects by reference: $obj =& new PEAR_child;
  *
- * @since PHP 4.0.2
- * @author Stig Bakken <ssb@php.net>
- * @see http://pear.php.net/manual/
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Tomas V.V. Cox <cox@idecnet.com>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @see        PEAR_Error
+ * @since      Class available since PHP 4.0.2
+ * @link        http://pear.php.net/manual/en/core.pear.php#core.pear.pear
  */
 class PEAR
 {
@@ -773,7 +790,23 @@ function _PEAR_call_destructors()
 }
 
 // }}}
-
+/**
+ * Standard PEAR error class for PHP 4
+ *
+ * This class is supserseded by {@link PEAR_Exception} in PHP 5
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Tomas V.V. Cox <cox@idecnet.com>
+ * @author     Gregory Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/manual/en/core.pear.pear-error.php
+ * @see        PEAR::raiseError(), PEAR::throwError()
+ * @since      Class available since PHP 4.0.2
+ */
 class PEAR_Error
 {
     // {{{ properties
@@ -863,8 +896,8 @@ class PEAR_Error
             }
         }
         if ($this->mode & PEAR_ERROR_EXCEPTION) {
-            trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_ErrorStack for exceptions", E_USER_WARNING);
-            eval('$e = new Exception($this->message, $this->code);$e->PEAR_Error = $this;throw($e);');
+            trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_Exception for exceptions", E_USER_WARNING);
+            eval('$e = new Exception($this->message, $this->code);throw($e);');
         }
     }
 
@@ -979,6 +1012,9 @@ class PEAR_Error
      */
     function getBacktrace($frame = null)
     {
+        if (defined('PEAR_IGNORE_BACKTRACE')) {
+            return null;
+        }
         if ($frame === null) {
             return $this->backtrace;
         }
index 09e8736d844aebc68492f790794336f63237d37a..561917bf1319aabc193acee02c177a19196ad280 100644 (file)
@@ -1,29 +1,36 @@
 <?php
+/**
+ * Class auto-loader
+ *
+ * PHP versions 4
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/manual/en/core.ppm.php#core.ppm.pear-autoloader
+ * @since      File available since Release 0.1
+ * @deprecated File deprecated in Release 1.4.0a1
+ */
+
 // /* vim: set expandtab tabstop=4 shiftwidth=4: */
-// +----------------------------------------------------------------------+
-// | PHP Version 5                                                        |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2004 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 Bakken <ssb@php.net>                                    |
-// |                                                                      |
-// +----------------------------------------------------------------------+
-//
-// $Id$
 
 if (!extension_loaded("overload")) {
     // die hard without ext/overload
     die("Rebuild PHP with the `overload' extension to use PEAR_Autoloader");
 }
 
+/**
+ * Include for PEAR_Error and PEAR classes
+ */
 require_once "PEAR.php";
 
 /**
@@ -38,7 +45,15 @@ require_once "PEAR.php";
  * methods, an instance of each class providing separated methods is
  * stored and called every time the aggregated method is called.
  *
- * @author Stig Sæther Bakken <ssb@php.net>
+ * @category   pear
+ * @package    PEAR
+ * @author Stig Bakken <ssb@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/manual/en/core.ppm.php#core.ppm.pear-autoloader
+ * @since      File available since Release 0.1
+ * @deprecated File deprecated in Release 1.4.0a1
  */
 class PEAR_Autoloader extends PEAR
 {
index 0f37d24acb02fbae27dfab017a64630843d4353d..c9d5455eb2d8d0130cb0282f7dc4f5aed2ba7607 100644 (file)
@@ -1,29 +1,44 @@
 <?php
-//
-// +----------------------------------------------------------------------+
-// | PHP Version 5                                                        |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2004 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 Sæther Bakken <ssb@php.net>                            |
-// +----------------------------------------------------------------------+
-//
-// $Id$
+/**
+ * PEAR_Builder for building PHP extensions (PECL packages)
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 0.1
+ */
 
+/**
+ * Needed for extending PEAR_Builder
+ */
 require_once 'PEAR/Common.php';
-
+require_once 'PEAR/PackageFile.php';
 /**
  * Class to handle building (compiling) extensions.
  *
- * @author Stig Sæther Bakken <ssb@php.net>
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @PEAR-VER@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since PHP 4.0.2
+ * @see        http://pear.php.net/manual/en/core.ppm.pear-builder.php
  */
 class PEAR_Builder extends PEAR_Common
 {
@@ -66,10 +81,16 @@ class PEAR_Builder extends PEAR_Common
      */
     function _build_win32($descfile, $callback = null)
     {
-        if (PEAR::isError($info = $this->infoFromDescriptionFile($descfile))) {
-            return $info;
+        if (is_object($descfile)) {
+            $pkg = $descfile;
+        } else {
+            $pf = &new PEAR_PackageFile($this->config, $this->debug);
+            $pkg = &$pf->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL);
+            if (PEAR::isError($pkg)) {
+                return $pkg;
+            }
         }
-        $dir = dirname($descfile);
+        $dir = dirname($pkg->getArchiveFile());
         $old_cwd = getcwd();
 
         if (!@chdir($dir)) {
@@ -77,7 +98,7 @@ class PEAR_Builder extends PEAR_Common
         }
         $this->log(2, "building in $dir");
 
-        $dsp = $info['package'].'.dsp';
+        $dsp = $pkg->getPackage().'.dsp';
         if (!@is_file("$dir/$dsp")) {
             return $this->raiseError("The DSP $dsp does not exist.");
         }
@@ -93,7 +114,7 @@ class PEAR_Builder extends PEAR_Common
         // figure out the build platform and type
         $platform = 'Win32';
         $buildtype = 'Release';
-        if (preg_match('/.*?'.$info['package'].'\s-\s(\w+)\s(.*?)-+/i',$this->_firstline,$matches)) {
+        if (preg_match('/.*?'.$pkg->getPackage().'\s-\s(\w+)\s(.*?)-+/i',$this->_firstline,$matches)) {
             $platform = $matches[1];
             $buildtype = $matches[2];
         }
@@ -115,7 +136,7 @@ class PEAR_Builder extends PEAR_Common
         // this regex depends on the build platform and type having been
         // correctly identified above.
         $regex ='/.*?!IF\s+"\$\(CFG\)"\s+==\s+("'.
-                    $info['package'].'\s-\s'.
+                    $pkg->getPackage().'\s-\s'.
                     $platform.'\s'.
                     $buildtype.'").*?'.
                     '\/out:"(.*?)"/is';
@@ -200,7 +221,8 @@ class PEAR_Builder extends PEAR_Common
      * directory, but compiles in a temporary directory
      * (/var/tmp/pear-build-USER/PACKAGE-VERSION).
      *
-     * @param string $descfile path to XML package description file
+     * @param string|PEAR_PackageFile_v* $descfile path to XML package description file, or
+     *               a PEAR_PackageFile object
      *
      * @param mixed $callback callback function used to report output,
      * see PEAR_Builder::_runCommand for details
@@ -216,7 +238,6 @@ class PEAR_Builder extends PEAR_Common
      * @access public
      *
      * @see PEAR_Builder::_runCommand
-     * @see PEAR_Common::infoFromDescriptionFile
      */
     function build($descfile, $callback = null)
     {
@@ -226,15 +247,22 @@ class PEAR_Builder extends PEAR_Common
         if (PEAR_OS != 'Unix') {
             return $this->raiseError("building extensions not supported on this platform");
         }
-        if (PEAR::isError($info = $this->infoFromDescriptionFile($descfile))) {
-            return $info;
+        if (is_object($descfile)) {
+            $pkg = $descfile;
+            $descfile = $pkg->getPackageFile();
+        } else {
+            $pf = &new PEAR_PackageFile($this->config);
+            $pkg = &$pf->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL);
+            if (PEAR::isError($pkg)) {
+                return $pkg;
+            }
         }
         $dir = dirname($descfile);
         $old_cwd = getcwd();
         if (!@chdir($dir)) {
             return $this->raiseError("could not chdir to $dir");
         }
-        $vdir = "$info[package]-$info[version]";
+        $vdir = $pkg->getPackage() . '-' . $pkg->getVersion();
         if (is_dir($vdir)) {
             chdir($vdir);
         }
@@ -252,8 +280,9 @@ class PEAR_Builder extends PEAR_Common
 
         // {{{ start of interactive part
         $configure_command = "$dir/configure";
-        if (isset($info['configure_options'])) {
-            foreach ($info['configure_options'] as $o) {
+        $configure_options = $pkg->getConfigureOptions();
+        if ($configure_options) {
+            foreach ($configure_options as $o) {
                 list($r) = $this->ui->userDialog('build',
                                                  array($o['prompt']),
                                                  array('text'),
@@ -273,8 +302,8 @@ class PEAR_Builder extends PEAR_Common
             $user='defaultuser';
         }
         $build_basedir = "/var/tmp/pear-build-$user";
-        $build_dir = "$build_basedir/$info[package]-$info[version]";
-        $inst_dir = "$build_basedir/install-$info[package]-$info[version]";
+        $build_dir = "$build_basedir/$vdir";
+        $inst_dir = "$build_basedir/install-$vdir";
         $this->log(1, "building in $build_dir");
         if (is_dir($build_dir)) {
             System::rm(array('-rf', $build_dir));
diff --git a/pear/PEAR/ChannelFile.php b/pear/PEAR/ChannelFile.php
new file mode 100644 (file)
index 0000000..adb4f05
--- /dev/null
@@ -0,0 +1,1601 @@
+<?php
+/**
+ * PEAR_ChannelFile, the channel handling class
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a1
+ */
+
+/**
+ * Needed for error handling
+ */
+require_once 'PEAR/ErrorStack.php';
+require_once 'PEAR/XMLParser.php';
+require_once 'PEAR/Common.php';
+
+/**
+ * Error code if the channel.xml <channel> tag does not contain a valid version
+ */
+define('PEAR_CHANNELFILE_ERROR_NO_VERSION', 1);
+/**
+ * Error code if the channel.xml <channel> tag version is not supported (version 1.0 is the only supported version,
+ * currently
+ */
+define('PEAR_CHANNELFILE_ERROR_INVALID_VERSION', 2);
+
+/**
+ * Error code if parsing is attempted with no xml extension
+ */
+define('PEAR_CHANNELFILE_ERROR_NO_XML_EXT', 3);
+
+/**
+ * Error code if creating the xml parser resource fails
+ */
+define('PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER', 4);
+
+/**
+ * Error code used for all sax xml parsing errors
+ */
+define('PEAR_CHANNELFILE_ERROR_PARSER_ERROR', 5);
+
+/**#@+
+ * Validation errors
+ */
+/**
+ * Error code when channel name is missing
+ */
+define('PEAR_CHANNELFILE_ERROR_NO_NAME', 6);
+/**
+ * Error code when channel name is invalid
+ */
+define('PEAR_CHANNELFILE_ERROR_INVALID_NAME', 7);
+/**
+ * Error code when channel summary is missing
+ */
+define('PEAR_CHANNELFILE_ERROR_NO_SUMMARY', 8);
+/**
+ * Error code when channel summary is multi-line
+ */
+define('PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY', 9);
+/**
+ * Error code when channel server is missing for xmlrpc or soap protocol
+ */
+define('PEAR_CHANNELFILE_ERROR_NO_HOST', 10);
+/**
+ * Error code when channel server is invalid for xmlrpc or soap protocol
+ */
+define('PEAR_CHANNELFILE_ERROR_INVALID_HOST', 11);
+/**
+ * Error code when a mirror name is invalid
+ */
+define('PEAR_CHANNELFILE_ERROR_INVALID_MIRROR', 21);
+/**
+ * Error code when a mirror type is invalid
+ */
+define('PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE', 22);
+/**
+ * Error code when an attempt is made to generate xml, but the parsed content is invalid
+ */
+define('PEAR_CHANNELFILE_ERROR_INVALID', 23);
+/**
+ * Error code when an empty package name validate regex is passed in
+ */
+define('PEAR_CHANNELFILE_ERROR_EMPTY_REGEX', 24);
+/**
+ * Error code when a <function> tag has no version
+ */
+define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION', 25);
+/**
+ * Error code when a <function> tag has no name
+ */
+define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME', 26);
+/**
+ * Error code when a <validatepackage> tag has no name
+ */
+define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME', 27);
+/**
+ * Error code when a <validatepackage> tag has no version attribute
+ */
+define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION', 28);
+/**
+ * Error code when a mirror does not exist but is called for in one of the set*
+ * methods.
+ */
+define('PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND', 32);
+/**
+ * Error code when a server port is not numeric
+ */
+define('PEAR_CHANNELFILE_ERROR_INVALID_PORT', 33);
+/**
+ * Error code when <static> contains no version attribute
+ */
+define('PEAR_CHANNELFILE_ERROR_NO_STATICVERSION', 34);
+/**
+ * Error code when <baseurl> contains no type attribute in a <rest> protocol definition
+ */
+define('PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE', 35);
+/** 
+ * Error code when a mirror is defined and the channel.xml represents the __uri pseudo-channel
+ */
+define('PEAR_CHANNELFILE_URI_CANT_MIRROR', 36);
+/** 
+ * Error code when ssl attribute is present and is not "yes"
+ */
+define('PEAR_CHANNELFILE_ERROR_INVALID_SSL', 37);
+/**#@-*/
+
+/**
+ * Mirror types allowed.  Currently only internet servers are recognized.
+ */
+$GLOBALS['_PEAR_CHANNELS_MIRROR_TYPES'] =  array('server');
+
+
+/**
+ * The Channel handling class
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
+ */
+class PEAR_ChannelFile {
+    /**
+     * @access private
+     * @var PEAR_ErrorStack
+     * @access private
+     */
+    var $_stack;
+    
+    /**
+     * Supported channel.xml versions, for parsing
+     * @var array
+     * @access private
+     */
+    var $_supportedVersions = array('1.0');
+
+    /**
+     * Parsed channel information
+     * @var array
+     * @access private
+     */
+    var $_channelInfo;
+
+    /**
+     * index into the subchannels array, used for parsing xml
+     * @var int
+     * @access private
+     */
+    var $_subchannelIndex;
+
+    /**
+     * index into the mirrors array, used for parsing xml
+     * @var int
+     * @access private
+     */
+    var $_mirrorIndex;
+    
+    /**
+     * Flag used to determine the validity of parsed content
+     * @var boolean
+     * @access private
+     */
+    var $_isValid = false;
+
+    function PEAR_ChannelFile()
+    {
+        $this->_stack = &new PEAR_ErrorStack('PEAR_ChannelFile');
+        $this->_stack->setErrorMessageTemplate($this->_getErrorMessage());
+        $this->_isValid = false;
+    }
+    
+    /**
+     * @return array
+     * @access protected
+     */
+    function _getErrorMessage()
+    {
+        return
+            array(
+                PEAR_CHANNELFILE_ERROR_INVALID_VERSION =>
+                    'While parsing channel.xml, an invalid version number "%version% was passed in, expecting one of %versions%',
+                PEAR_CHANNELFILE_ERROR_NO_VERSION =>
+                    'No version number found in <channel> tag',
+                PEAR_CHANNELFILE_ERROR_NO_XML_EXT =>
+                    '%error%',
+                PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER =>
+                    'Unable to create XML parser',
+                PEAR_CHANNELFILE_ERROR_PARSER_ERROR =>
+                    '%error%',
+                PEAR_CHANNELFILE_ERROR_NO_NAME =>
+                    'Missing channel name',
+                PEAR_CHANNELFILE_ERROR_INVALID_NAME =>
+                    'Invalid channel %tag% "%name%"',
+                PEAR_CHANNELFILE_ERROR_NO_SUMMARY =>
+                    'Missing channel summary',
+                PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY =>
+                    'Channel summary should be on one line, but is multi-line',
+                PEAR_CHANNELFILE_ERROR_NO_HOST =>
+                    'Missing channel server for %type% server',
+                PEAR_CHANNELFILE_ERROR_INVALID_HOST =>
+                    'Server name "%server%" is invalid for %type% server',
+                PEAR_CHANNELFILE_ERROR_INVALID_MIRROR =>
+                    'Invalid mirror name "%name%", mirror type %type%',
+                PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE =>
+                    'Invalid mirror type "%type%"',
+                PEAR_CHANNELFILE_ERROR_INVALID =>
+                    'Cannot generate xml, contents are invalid',
+                PEAR_CHANNELFILE_ERROR_EMPTY_REGEX =>
+                    'packagenameregex cannot be empty',
+                PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION =>
+                    '%parent% %protocol% function has no version',
+                PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME =>
+                    '%parent% %protocol% function has no name',
+                PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE =>
+                    '%parent% rest baseurl has no type',
+                PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME =>
+                    'Validation package has no name in <validatepackage> tag',
+                PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION =>
+                    'Validation package "%package%" has no version',
+                PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND =>
+                    'Mirror "%mirror%" does not exist',
+                PEAR_CHANNELFILE_ERROR_INVALID_PORT =>
+                    'Port "%port%" must be numeric',
+                PEAR_CHANNELFILE_ERROR_NO_STATICVERSION =>
+                    '<static> tag must contain version attribute',
+                PEAR_CHANNELFILE_URI_CANT_MIRROR =>
+                    'The __uri pseudo-channel cannot have mirrors',
+                PEAR_CHANNELFILE_ERROR_INVALID_SSL =>
+                    '%server% has invalid ssl attribute "%ssl%" can only be yes or not present',
+            );
+    }
+
+    /**
+     * @param string contents of package.xml file
+     * @return bool success of parsing
+     */
+    function fromXmlString($data)
+    {
+        if (preg_match('/<channel\s+version="([0-9]+\.[0-9]+)"/', $data, $channelversion)) {
+            if (!in_array($channelversion[1], $this->_supportedVersions)) {
+                $this->_stack->push(PEAR_CHANNELFILE_ERROR_INVALID_VERSION, 'error',
+                    array('version' => $channelversion[1]));
+                return false;
+            }
+            $parser = new PEAR_XMLParser;
+            $result = $parser->parse($data);
+            if ($result !== true) {
+                if ($result->getCode() == 1) {
+                    $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_XML_EXT, 'error',
+                        array('error' => $error));
+                } else {
+                    $this->_stack->push(PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER, 'error');
+                }
+                return false;
+            }
+            $this->_channelInfo = $parser->getData();
+            return true;
+        } else {
+            $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_VERSION, 'error', array('xml' => $data));
+            return false;
+        }
+    }
+    
+    /**
+     * @return array
+     */
+    function toArray()
+    {
+        if (!$this->_isValid && !$this->validate()) {
+            return false;
+        }
+        return $this->_channelInfo;
+    }
+    
+    /**
+     * @param array
+     * @static
+     * @return PEAR_ChannelFile|false false if invalid
+     */
+    function &fromArray($data, $compatibility = false, $stackClass = 'PEAR_ErrorStack')
+    {
+        $a = new PEAR_ChannelFile($compatibility, $stackClass);
+        $a->_fromArray($data);
+        if (!$a->validate()) {
+            $a = false;
+            return $a;
+        }
+        return $a;
+    }
+    
+    /**
+     * @param array
+     * @access private
+     */
+    function _fromArray($data)
+    {
+        $this->_channelInfo = $data;
+    }
+    
+    /**
+     * Wrapper to {@link PEAR_ErrorStack::getErrors()}
+     * @param boolean determines whether to purge the error stack after retrieving
+     * @return array
+     */
+    function getErrors($purge = false)
+    {
+        return $this->_stack->getErrors($purge);
+    }
+
+    /**
+     * Unindent given string (?)
+     *
+     * @param string $str The string that has to be unindented.
+     * @return string
+     * @access private
+     */
+    function _unIndent($str)
+    {
+        // remove leading newlines
+        $str = preg_replace('/^[\r\n]+/', '', $str);
+        // find whitespace at the beginning of the first line
+        $indent_len = strspn($str, " \t");
+        $indent = substr($str, 0, $indent_len);
+        $data = '';
+        // remove the same amount of whitespace from following lines
+        foreach (explode("\n", $str) as $line) {
+            if (substr($line, 0, $indent_len) == $indent) {
+                $data .= substr($line, $indent_len) . "\n";
+            }
+        }
+        return $data;
+    }
+
+    /**
+     * Parse a channel.xml file.  Expects the name of
+     * a channel xml file as input.
+     *
+     * @param string  $descfile  name of channel xml file
+     * @return bool success of parsing
+     */
+    function fromXmlFile($descfile)
+    {
+        if (!@is_file($descfile) || !is_readable($descfile) ||
+             (!$fp = @fopen($descfile, 'r'))) {
+            require_once 'PEAR.php';
+            return PEAR::raiseError("Unable to open $descfile");
+        }
+
+        // read the whole thing so we only get one cdata callback
+        // for each block of cdata
+        if (function_exists('file_get_contents')) {
+            fclose($fp);
+            $data = file_get_contents($descfile);
+        } else {
+            $data = fread($fp, filesize($descfile));
+            fclose($fp);
+        }
+        return $this->fromXmlString($data);
+    }
+
+    /**
+     * Parse channel information from different sources
+     *
+     * This method is able to extract information about a channel
+     * from an .xml file or a string
+     *
+     * @access public
+     * @param  string Filename of the source or the source itself
+     * @return bool
+     */
+    function fromAny($info)
+    {
+        if (is_string($info) && file_exists($info) && strlen($info) < 255) {
+            $tmp = substr($info, -4);
+            if ($tmp == '.xml') {
+                $info = $this->fromXmlFile($info);
+            } else {
+                $fp = fopen($info, "r");
+                $test = fread($fp, 5);
+                fclose($fp);
+                if ($test == "<?xml") {
+                    $info = $this->fromXmlFile($info);
+                }
+            }
+            if (PEAR::isError($info)) {
+                require_once 'PEAR.php';
+                return PEAR::raiseError($info);
+            }
+        }
+        if (is_string($info)) {
+            $info = $this->fromXmlString($info);
+        }
+        return $info;
+    }
+
+    /**
+     * Return an XML document based on previous parsing and modifications
+     *
+     * @return string XML data
+     *
+     * @access public
+     */
+    function toXml()
+    {
+        if (!$this->_isValid && !$this->validate()) {
+            $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID);
+            return false;
+        }
+        if (!isset($this->_channelInfo['attribs']['version'])) {
+            $this->_channelInfo['attribs']['version'] = '1.0';
+        }
+        $channelInfo = $this->_channelInfo;
+        $ret = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n";
+        $ret .= "<channel version=\"" .
+            $channelInfo['attribs']['version'] . "\" xmlns=\"http://pear.php.net/channel-1.0\"
+  xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
+  xsi:schemaLocation=\"http://pear.php.net/dtd/channel-"
+            . $channelInfo['attribs']['version'] . " http://pear.php.net/dtd/channel-" .
+            $channelInfo['attribs']['version'] . ".xsd\">
+ <name>$channelInfo[name]</name>
+ <summary>" . htmlspecialchars($channelInfo['summary'])."</summary>
+";
+        if (isset($channelInfo['suggestedalias'])) {
+            $ret .= ' <suggestedalias>' . $channelInfo['suggestedalias'] . "</suggestedalias>\n";
+        }
+        if (isset($channelInfo['validatepackage'])) {
+            $ret .= ' <validatepackage version="' .
+                $channelInfo['validatepackage']['attribs']['version']. '">' .
+                htmlspecialchars($channelInfo['validatepackage']['_content']) .
+                "</validatepackage>\n";
+        }
+        $ret .= " <servers>\n";
+        $ret .= '  <primary';
+        if (isset($channelInfo['servers']['primary']['attribs']['ssl'])) {
+            $ret .= ' ssl="' . $channelInfo['servers']['primary']['attribs']['ssl'] . '"';
+        }
+        if (isset($channelInfo['servers']['primary']['attribs']['port'])) {
+            $ret .= ' port="' . $channelInfo['servers']['primary']['attribs']['port'] . '"';
+        }
+        $ret .= ">\n";
+        if (isset($channelInfo['servers']['primary']['xmlrpc'])) {
+            $ret .= $this->_makeXmlrpcXml($channelInfo['servers']['primary']['xmlrpc'], '   ');
+        }
+        if (isset($channelInfo['servers']['primary']['rest'])) {
+            $ret .= $this->_makeRestXml($channelInfo['servers']['primary']['rest'], '   ');
+        }
+        if (isset($channelInfo['servers']['primary']['soap'])) {
+            $ret .= $this->_makeSoapXml($channelInfo['servers']['primary']['soap'], '   ');
+        }
+        $ret .= "  </primary>\n";
+        if (isset($channelInfo['servers']['mirror'])) {
+            $ret .= $this->_makeMirrorsXml($channelInfo);
+        }
+        $ret .= " </servers>\n";
+        $ret .= "</channel>";
+        return str_replace("\r", "\n", str_replace("\r\n", "\n", $ret));
+    }
+
+    /**
+     * Generate the <xmlrpc> tag
+     * @access private
+     */
+    function _makeXmlrpcXml($info, $indent)
+    {
+        $ret = $indent . "<xmlrpc";
+        if (isset($info['attribs']['path'])) {
+            $ret .= ' path="' . htmlspecialchars($info['attribs']['path']) . '"';
+        }
+        $ret .= ">\n";
+        $ret .= $this->_makeFunctionsXml($info['function'], "$indent ");
+        $ret .= $indent . "</xmlrpc>\n";
+        return $ret;
+    }
+
+    /**
+     * Generate the <soap> tag
+     * @access private
+     */
+    function _makeSoapXml($info, $indent)
+    {
+        $ret = $indent . "<soap";
+        if (isset($info['attribs']['path'])) {
+            $ret .= ' path="' . htmlspecialchars($info['attribs']['path']) . '"';
+        }
+        $ret .= ">\n";
+        $ret .= $this->_makeFunctionsXml($info['function'], "$indent ");
+        $ret .= $indent . "</soap>\n";
+        return $ret;
+    }
+
+    /**
+     * Generate the <rest> tag
+     * @access private
+     */
+    function _makeRestXml($info, $indent)
+    {
+        $ret = $indent . "<rest>\n";
+        if (!isset($info['baseurl'][0])) {
+            $info['baseurl'] = array($info['baseurl']);
+        }
+        foreach ($info['baseurl'] as $url) {
+            $ret .= "$indent <baseurl type=\"" . $url['attribs']['type'] . "\"";
+            $ret .= ">" . $url['_content'] . "</baseurl>\n";
+        }
+        $ret .= $indent . "</rest>\n";
+        return $ret;
+    }
+
+    /**
+     * Generate the <mirrors> tag
+     * @access private
+     */
+    function _makeMirrorsXml($channelInfo)
+    {
+        $ret = "";
+        if (!isset($channelInfo['servers']['mirror'][0])) {
+            $channelInfo['servers']['mirror'] = array($channelInfo['servers']['mirror']);
+        }
+        foreach ($channelInfo['servers']['mirror'] as $mirror) {
+            $ret .= '  <mirror host="' . $mirror['attribs']['host'] . '"';
+            if (isset($mirror['attribs']['port'])) {
+                $ret .= ' port="' . $mirror['attribs']['port'] . '"';
+            }
+            if (isset($mirror['attribs']['ssl'])) {
+                $ret .= ' ssl="' . $mirror['attribs']['ssl'] . '"';
+            }
+            $ret .= ">\n";
+            if (isset($mirror['xmlrpc']) || isset($mirror['soap'])) {
+                if (isset($mirror['xmlrpc'])) {
+                    $ret .= $this->_makeXmlrpcXml($mirror['xmlrpc'], '   ');
+                }
+                if (isset($mirror['rest'])) {
+                    $ret .= $this->_makeRestXml($mirror['rest'], '   ');
+                }
+                if (isset($mirror['soap'])) {
+                    $ret .= $this->_makeSoapXml($mirror['soap'], '   ');
+                }
+                $ret .= "  </mirror>\n";
+            } else {
+                $ret .= "/>\n";
+            }
+        }
+        return $ret;
+    }
+
+    /**
+     * Generate the <functions> tag
+     * @access private
+     */
+    function _makeFunctionsXml($functions, $indent, $rest = false)
+    {
+        $ret = '';
+        if (!isset($functions[0])) {
+            $functions = array($functions);
+        }
+        foreach ($functions as $function) {
+            $ret .= "$indent<function version=\"" . $function['attribs']['version'] . "\"";
+            if ($rest) {
+                $ret .= ' uri="' . $function['attribs']['uri'] . '"';
+            }
+            $ret .= ">" . $function['_content'] . "</function>\n";
+        }
+        return $ret;
+    }
+
+    /**
+     * Validation error.  Also marks the object contents as invalid
+     * @param error code
+     * @param array error information
+     * @access private
+     */
+    function _validateError($code, $params = array())
+    {
+        $this->_stack->push($code, 'error', $params);
+        $this->_isValid = false;
+    }
+
+    /**
+     * Validation warning.  Does not mark the object contents invalid.
+     * @param error code
+     * @param array error information
+     * @access private
+     */
+    function _validateWarning($code, $params = array())
+    {
+        $this->_stack->push($code, 'warning', $params);
+    }
+
+    /**
+     * Validate parsed file.
+     *
+     * @access public
+     * @return boolean
+     */
+    function validate()
+    {
+        $this->_isValid = true;
+        $info = $this->_channelInfo;
+        if (empty($info['name'])) {
+            $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_NAME);
+        } elseif (!$this->validChannelServer($info['name'])) {
+            if ($info['name'] != '__uri') {
+                $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, array('tag' => 'name',
+                    'name' => $info['name']));
+            }
+        }
+        if (empty($info['summary'])) {
+            $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY);
+        } elseif (strpos(trim($info['summary']), "\n") !== false) {
+            $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY,
+                array('summary' => $info['summary']));
+        }
+        if (isset($info['suggestedalias'])) {
+            if (!$this->validChannelServer($info['suggestedalias'])) {
+                $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
+                    array('tag' => 'suggestedalias', 'name' =>$info['suggestedalias']));
+            }
+        }
+        if (isset($info['localalias'])) {
+            if (!$this->validChannelServer($info['localalias'])) {
+                $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
+                    array('tag' => 'localalias', 'name' =>$info['localalias']));
+            }
+        }
+        if (isset($info['validatepackage'])) {
+            if (!isset($info['validatepackage']['_content'])) {
+                $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME);
+            }
+            if (!isset($info['validatepackage']['attribs']['version'])) {
+                $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION,
+                    array('package' => @$info['validatepackage']['_content']));
+            }
+        }
+        if (isset($info['servers']['primary']['attribs']['port']) &&
+              !is_numeric($info['servers']['primary']['attribs']['port'])) {
+            $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_PORT,
+                array('port' => $info['servers']['primary']['attribs']['port']));
+        }
+        if (isset($info['servers']['primary']['attribs']['ssl']) &&
+              $info['servers']['primary']['attribs']['ssl'] != 'yes') {
+            $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL,
+                array('ssl' => $info['servers']['primary']['attribs']['ssl'],
+                    'server' => $info['name']));
+        }
+
+        if (isset($info['servers']['primary']['xmlrpc']) &&
+              isset($info['servers']['primary']['xmlrpc']['function'])) {
+            $this->_validateFunctions('xmlrpc', $info['servers']['primary']['xmlrpc']['function']);
+        }
+        if (isset($info['servers']['primary']['soap']) &&
+              isset($info['servers']['primary']['soap']['function'])) {
+            $this->_validateFunctions('soap', $info['servers']['primary']['soap']['function']);
+        }
+        if (isset($info['servers']['primary']['rest']) &&
+              isset($info['servers']['primary']['rest']['baseurl'])) {
+            $this->_validateFunctions('rest', $info['servers']['primary']['rest']['baseurl']);
+        }
+        if (isset($info['servers']['mirror'])) {
+            if ($this->_channelInfo['name'] == '__uri') {
+                $this->_validateError(PEAR_CHANNELFILE_URI_CANT_MIRROR);
+            }
+            if (!isset($info['servers']['mirror'][0])) {
+                $info['servers']['mirror'] = array($info['servers']['mirror']);
+            }
+            $i = 0;
+            foreach ($info['servers']['mirror'] as $mirror) {
+                if (!isset($mirror['attribs']['host'])) {
+                    $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_HOST,
+                      array('type' => 'mirror'));
+                } elseif (!$this->validChannelServer($mirror['attribs']['host'])) {
+                    $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_HOST,
+                        array('server' => $mirror['attribs']['host'], 'type' => 'mirror'));
+                }
+                if (isset($mirror['attribs']['ssl']) && $mirror['attribs']['ssl'] != 'yes') {
+                    $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL,
+                        array('ssl' => $info['ssl'], 'server' => $mirror['attribs']['host']));
+                }
+                if (isset($mirror['xmlrpc'])) {
+                    $this->_validateFunctions('xmlrpc',
+                        $mirror['xmlrpc']['function'], $mirror['attribs']['host']);
+                }
+                if (isset($mirror['soap'])) {
+                    $this->_validateFunctions('soap', $mirror['soap']['function'],
+                        $mirror['attribs']['host']);
+                }
+                if (isset($mirror['rest'])) {
+                    $this->_validateFunctions('rest', $mirror['rest']['baseurl'],
+                        $mirror['attribs']['host']);
+                }
+            }
+        }
+        return $this->_isValid;
+    }
+
+    /**
+     * @param string xmlrpc or soap - protocol name this function applies to
+     * @param array the functions
+     * @param string the name of the parent element (mirror name, for instance)
+     */
+    function _validateFunctions($protocol, $functions, $parent = '')
+    {
+        if (!isset($functions[0])) {
+            $functions = array($functions);
+        }
+        foreach ($functions as $function) {
+            if (!isset($function['_content']) || empty($function['_content'])) {
+                $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME,
+                    array('parent' => $parent, 'protocol' => $protocol));
+            }
+            if ($protocol == 'rest') {
+                if (!isset($function['attribs']['type']) ||
+                      empty($function['attribs']['type'])) {
+                    $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_BASEURLTYPE,
+                        array('parent' => $parent, 'protocol' => $protocol));
+                }
+            } else {
+                if (!isset($function['attribs']['version']) ||
+                      empty($function['attribs']['version'])) {
+                    $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION,
+                        array('parent' => $parent, 'protocol' => $protocol));
+                }
+            }
+        }
+    }
+
+    /**
+     * Test whether a string contains a valid channel server.
+     * @param string $ver the package version to test
+     * @return bool
+     */
+    function validChannelServer($server)
+    {
+        if ($server == '__uri') {
+            return true;
+        }
+        return (bool) preg_match(PEAR_CHANNELS_SERVER_PREG, $server);
+    }
+
+    /**
+     * @return string|false
+     */
+    function getName()
+    {
+        if (isset($this->_channelInfo['name'])) {
+            return $this->_channelInfo['name'];
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * @return string|false
+     */
+    function getServer()
+    {
+        if (isset($this->_channelInfo['name'])) {
+            return $this->_channelInfo['name'];
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * @return int|80 port number to connect to
+     */
+    function getPort($mirror = false)
+    {
+        if ($mirror) {
+            if ($mir = $this->getMirror($mirror)) {
+                if (isset($mir['attribs']['port'])) {
+                    return $mir['attribs']['port'];
+                } else {
+                    if ($this->getSSL($mirror)) {
+                        return 443;
+                    }
+                    return 80;
+                }
+            }
+            return false;
+        }
+        if (isset($this->_channelInfo['servers']['primary']['attribs']['port'])) {
+            return $this->_channelInfo['servers']['primary']['attribs']['port'];
+        }
+        if ($this->getSSL()) {
+            return 443;
+        }
+        return 80;
+    }
+
+    /**
+     * @return bool Determines whether secure sockets layer (SSL) is used to connect to this channel
+     */
+    function getSSL($mirror = false)
+    {
+        if ($mirror) {
+            if ($mir = $this->getMirror($mirror)) {
+                if (isset($mir['attribs']['ssl'])) {
+                    return true;
+                } else {
+                    return false;
+                }
+            }
+            return false;
+        }
+        if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * @return string|false
+     */
+    function getSummary()
+    {
+        if (isset($this->_channelInfo['summary'])) {
+            return $this->_channelInfo['summary'];
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * @param string xmlrpc or soap
+     * @param string|false mirror name or false for primary server
+     */
+    function getPath($protocol, $mirror = false)
+    {   
+        if (!in_array($protocol, array('xmlrpc', 'soap'))) {
+            return false;
+        }
+        if ($mirror) {
+            if (!($mir = $this->getMirror($mirror))) {
+                return false;
+            }
+            if (isset($mir[$protocol]['attribs']['path'])) {
+                return $mir[$protocol]['attribs']['path'];
+            } else {
+                return $protocol . '.php';
+            }
+        } elseif (isset($this->_channelInfo['servers']['primary'][$protocol]['attribs']['path'])) {
+            return $this->_channelInfo['servers']['primary'][$protocol]['attribs']['path'];
+        }
+        return $protocol . '.php';
+    }
+
+    /**
+     * @param string protocol type (xmlrpc, soap)
+     * @param string Mirror name
+     * @return array|false
+     */
+    function getFunctions($protocol, $mirror = false)
+    {
+        if ($this->getName() == '__uri') {
+            return false;
+        }
+        if ($protocol == 'rest') {
+            $function = 'baseurl';
+        } else {
+            $function = 'function';
+        }
+        if ($mirror) {
+            if ($mir = $this->getMirror($mirror)) {
+                if (isset($mir[$protocol][$function])) {
+                    return $mir[$protocol][$function];
+                }
+            }
+            return false;
+        }
+        if (isset($this->_channelInfo['servers']['primary'][$protocol][$function])) {
+            return $this->_channelInfo['servers']['primary'][$protocol][$function];
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * @param string Protocol type
+     * @param string Function name (null to return the
+     *               first protocol of the type requested)
+     * @param string Mirror name, if any
+     * @return array
+     */
+     function getFunction($type, $name = null, $mirror = false)
+     {
+        $protocols = $this->getFunctions($type, $mirror);
+        if (!$protocols) {
+            return false;
+        }
+        foreach ($protocols as $protocol) {
+            if ($name === null) {
+                return $protocol;
+            }
+            if ($protocol['_content'] != $name) {
+                continue;
+            }
+            return $protocol;
+        }
+        return false;
+     }
+
+    /**
+     * @param string protocol type
+     * @param string protocol name
+     * @param string version
+     * @param string mirror name
+     * @return boolean
+     */
+    function supports($type, $name = null, $mirror = false, $version = '1.0')
+    {
+        $protocols = $this->getFunctions($type, $mirror);
+        if (!$protocols) {
+            return false;
+        }
+        foreach ($protocols as $protocol) {
+            if ($protocol['attribs']['version'] != $version) {
+                continue;
+            }
+            if ($name === null) {
+                return true;
+            }
+            if ($protocol['_content'] != $name) {
+                continue;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Determines whether a channel supports Representational State Transfer (REST) protocols
+     * for retrieving channel information
+     * @param string
+     * @return bool
+     */
+    function supportsREST($mirror = false)
+    {
+        if ($mirror == $this->_channelInfo['name']) {
+            $mirror = false;
+        }
+        if ($mirror) {
+            if ($mir = $this->getMirror($mirror)) {
+                return isset($mir['rest']);
+            }
+            return false;
+        }
+        return isset($this->_channelInfo['servers']['primary']['rest']);
+    }
+
+    /**
+     * Get the URL to access a base resource.
+     *
+     * Hyperlinks in the returned xml will be used to retrieve the proper information
+     * needed.  This allows extreme extensibility and flexibility in implementation
+     * @param string Resource Type to retrieve
+     */
+    function getBaseURL($resourceType, $mirror = false)
+    {
+        if ($mirror == $this->_channelInfo['name']) {
+            $mirror = false;
+        }
+        if ($mirror) {
+            if ($mir = $this->getMirror($mirror)) {
+                $rest = $mir['rest'];
+            } else {
+                return false;
+            }
+            $server = $mirror;
+        } else {
+            $rest = $this->_channelInfo['servers']['primary']['rest'];
+            $server = $this->getServer();
+        }
+        if (!isset($rest['baseurl'][0])) {
+            $rest['baseurl'] = array($rest['baseurl']);
+        }
+        foreach ($rest['baseurl'] as $baseurl) {
+            if (strtolower($baseurl['attribs']['type']) == strtolower($resourceType)) {
+                return $baseurl['_content'];
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Since REST does not implement RPC, provide this as a logical wrapper around
+     * resetFunctions for REST
+     * @param string|false mirror name, if any
+     */
+    function resetREST($mirror = false)
+    {
+        return $this->resetFunctions('rest', $mirror);
+    }
+
+    /**
+     * Empty all protocol definitions
+     * @param string protocol type (xmlrpc, soap)
+     * @param string|false mirror name, if any
+     */
+    function resetFunctions($type, $mirror = false)
+    {
+        if ($mirror) {
+            if (isset($this->_channelInfo['servers']['mirror'])) {
+                $mirrors = $this->_channelInfo['servers']['mirror'];
+                if (!isset($mirrors[0])) {
+                    $mirrors = array($mirrors);
+                }
+                foreach ($mirrors as $i => $mir) {
+                    if ($mir['attribs']['host'] == $mirror) {
+                        if (isset($this->_channelInfo['servers']['mirror'][$i][$type])) {
+                            unset($this->_channelInfo['servers']['mirror'][$i][$type]);
+                        }
+                        return true;
+                    }
+                }
+                return false;
+            } else {
+                return false;
+            }
+        } else {
+            if (isset($this->_channelInfo['servers']['primary'][$type])) {
+                unset($this->_channelInfo['servers']['primary'][$type]);
+            }
+            return true;
+        }
+    }
+
+    /**
+     * Set a channel's protocols to the protocols supported by pearweb
+     */
+    function setDefaultPEARProtocols($version = '1.0', $mirror = false)
+    {
+        switch ($version) {
+            case '1.0' :
+                $this->resetFunctions('xmlrpc', $mirror);
+                $this->resetFunctions('soap', $mirror);
+                $this->resetREST($mirror);
+                $this->addFunction('xmlrpc', '1.0', 'logintest', $mirror);
+                $this->addFunction('xmlrpc', '1.0', 'package.listLatestReleases', $mirror);
+                $this->addFunction('xmlrpc', '1.0', 'package.listAll', $mirror);
+                $this->addFunction('xmlrpc', '1.0', 'package.info', $mirror);
+                $this->addFunction('xmlrpc', '1.0', 'package.getDownloadURL', $mirror);
+                $this->addFunction('xmlrpc', '1.1', 'package.getDownloadURL', $mirror);
+                $this->addFunction('xmlrpc', '1.0', 'package.getDepDownloadURL', $mirror);
+                $this->addFunction('xmlrpc', '1.1', 'package.getDepDownloadURL', $mirror);
+                $this->addFunction('xmlrpc', '1.0', 'package.search', $mirror);
+                $this->addFunction('xmlrpc', '1.0', 'channel.listAll', $mirror);
+                return true;
+            break;
+            default :
+                return false;
+            break;
+        }
+    }
+    
+    /**
+     * @return array
+     */
+    function getMirrors()
+    {
+        if (isset($this->_channelInfo['servers']['mirror'])) {
+            $mirrors = $this->_channelInfo['servers']['mirror'];
+            if (!isset($mirrors[0])) {
+                $mirrors = array($mirrors);
+            }
+            return $mirrors;
+        } else {
+            return array();
+        }
+    }
+
+    /**
+     * Get the unserialized XML representing a mirror
+     * @return array|false
+     */
+    function getMirror($server)
+    {
+        foreach ($this->getMirrors() as $mirror) {
+            if ($mirror['attribs']['host'] == $server) {
+                return $mirror;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @param string
+     * @return string|false
+     * @error PEAR_CHANNELFILE_ERROR_NO_NAME
+     * @error PEAR_CHANNELFILE_ERROR_INVALID_NAME
+     */
+    function setName($name)
+    {
+        return $this->setServer($name);
+    }
+
+    /**
+     * Set the socket number (port) that is used to connect to this channel
+     * @param integer
+     * @param string|false name of the mirror server, or false for the primary
+     */
+    function setPort($port, $mirror = false)
+    {
+        if ($mirror) {
+            if (!isset($this->_channelInfo['servers']['mirror'])) {
+                $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
+                    array('mirror' => $mirror));
+                return false;
+            }
+            $setmirror = false;
+            if (isset($this->_channelInfo['servers']['mirror'][0])) {
+                foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
+                    if ($mirror == $mir['attribs']['host']) {
+                        $this->_channelInfo['servers']['mirror'][$i]['attribs']['port'] = $port;
+                        return true;
+                    }
+                }
+                return false;
+            } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
+                $this->_channelInfo['servers']['mirror']['attribs']['port'] = $port;
+                $this->_isValid = false;
+                return true;
+            }
+        }
+        $this->_channelInfo['servers']['primary']['attribs']['port'] = $port;
+        $this->_isValid = false;
+        return true;
+    }
+
+    /**
+     * Set the socket number (port) that is used to connect to this channel
+     * @param bool Determines whether to turn on SSL support or turn it off
+     * @param string|false name of the mirror server, or false for the primary
+     */
+    function setSSL($ssl = true, $mirror = false)
+    {
+        if ($mirror) {
+            if (!isset($this->_channelInfo['servers']['mirror'])) {
+                $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
+                    array('mirror' => $mirror));
+                return false;
+            }
+            $setmirror = false;
+            if (isset($this->_channelInfo['servers']['mirror'][0])) {
+                foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
+                    if ($mirror == $mir['attribs']['host']) {
+                        if (!$ssl) {
+                            if (isset($this->_channelInfo['servers']['mirror'][$i]
+                                  ['attribs']['ssl'])) {
+                                unset($this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl']);
+                            }
+                        } else {
+                            $this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl'] = 'yes';
+                        }
+                        return true;
+                    }
+                }
+                return false;
+            } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
+                if (!$ssl) {
+                    if (isset($this->_channelInfo['servers']['mirror']['attribs']['ssl'])) {
+                        unset($this->_channelInfo['servers']['mirror']['attribs']['ssl']);
+                    }
+                } else {
+                    $this->_channelInfo['servers']['mirror']['attribs']['ssl'] = 'yes';
+                }
+                $this->_isValid = false;
+                return true;
+            }
+        }
+        if ($ssl) {
+            $this->_channelInfo['servers']['primary']['attribs']['ssl'] = 'yes';
+        } else {
+            if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) {
+                unset($this->_channelInfo['servers']['primary']['attribs']['ssl']);
+            }
+        }
+        $this->_isValid = false;
+        return true;
+    }
+
+    /**
+     * Set the socket number (port) that is used to connect to this channel
+     * @param integer
+     * @param string|false name of the mirror server, or false for the primary
+     */
+    function setPath($protocol, $path, $mirror = false)
+    {
+        if (!in_array($protocol, array('xmlrpc', 'soap'))) {
+            return false;
+        }
+        if ($mirror) {
+            if (!isset($this->_channelInfo['servers']['mirror'])) {
+                $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
+                    array('mirror' => $mirror));
+                return false;
+            }
+            $setmirror = false;
+            if (isset($this->_channelInfo['servers']['mirror'][0])) {
+                foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
+                    if ($mirror == $mir['attribs']['host']) {
+                        $this->_channelInfo['servers']['mirror'][$i][$protocol]['attribs']['path'] =
+                            $path;
+                        return true;
+                    }
+                }
+                $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
+                    array('mirror' => $mirror));
+                return false;
+            } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
+                $this->_channelInfo['servers']['mirror'][$protocol]['attribs']['path'] = $path;
+                $this->_isValid = false;
+                return true;
+            }
+        }
+        $this->_channelInfo['servers']['primary'][$protocol]['attribs']['path'] = $path;
+        $this->_isValid = false;
+        return true;
+    }
+
+    /**
+     * @param string
+     * @return string|false
+     * @error PEAR_CHANNELFILE_ERROR_NO_SERVER
+     * @error PEAR_CHANNELFILE_ERROR_INVALID_SERVER
+     */
+    function setServer($server, $mirror = false)
+    {
+        if (empty($server)) {
+            $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SERVER);
+            return false;
+        } elseif (!$this->validChannelServer($server)) {
+            $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
+                array('tag' => 'name', 'name' => $server));
+            return false;
+        }
+        if ($mirror) {
+            $found = false;
+            foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
+                if ($mirror == $mir['attribs']['host']) {
+                    $found = true;
+                    break;
+                }
+            }
+            if (!$found) {
+                $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
+                    array('mirror' => $mirror));
+                return false;
+            }
+            $this->_channelInfo['mirror'][$i]['attribs']['host'] = $server;
+            return true;
+        }
+        $this->_channelInfo['name'] = $server;
+        return true;
+    }
+
+    /**
+     * @param string
+     * @return boolean success
+     * @error PEAR_CHANNELFILE_ERROR_NO_SUMMARY
+     * @warning PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY
+     */
+    function setSummary($summary)
+    {
+        if (empty($summary)) {
+            $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY);
+            return false;
+        } elseif (strpos(trim($summary), "\n") !== false) {
+            $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY,
+                array('summary' => $summary));
+        }
+        $this->_channelInfo['summary'] = $summary;
+        return true;
+    }
+
+    /**
+     * @param string
+     * @param boolean determines whether the alias is in channel.xml or local
+     * @return boolean success
+     */
+    function setAlias($alias, $local = false)
+    {
+        if (!$this->validChannelServer($alias)) {
+            $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
+                array('tag' => 'suggestedalias', 'name' => $alias));
+            return false;
+        }
+        if ($local) {
+            $this->_channelInfo['localalias'] = $alias;
+        } else {
+            $this->_channelInfo['suggestedalias'] = $alias;
+        }
+        return true;
+    }
+
+    /**
+     * @return string
+     */
+    function getAlias()
+    {
+        if (isset($this->_channelInfo['localalias'])) {
+            return $this->_channelInfo['localalias'];
+        }
+        if (isset($this->_channelInfo['suggestedalias'])) {
+            return $this->_channelInfo['suggestedalias'];
+        }
+        if (isset($this->_channelInfo['name'])) {
+            return $this->_channelInfo['name'];
+        }
+    }
+
+    /**
+     * Set the package validation object if it differs from PEAR's default
+     * The class must be includeable via changing _ in the classname to path separator,
+     * but no checking of this is made.
+     * @param string|false pass in false to reset to the default packagename regex
+     * @return boolean success
+     */
+    function setValidationPackage($validateclass, $version)
+    {
+        if (empty($validateclass)) {
+            unset($this->_channelInfo['validatepackage']);
+        }
+        $this->_channelInfo['validatepackage'] = array('_content' => $validateclass);
+        $this->_channelInfo['validatepackage']['attribs'] = array('version' => $version);
+    }
+
+    /**
+     * Add a protocol to the provides section
+     * @param string protocol type
+     * @param string protocol version
+     * @param string protocol name, if any
+     * @param string mirror name, if this is a mirror's protocol
+     * @return bool
+     */
+    function addFunction($type, $version, $name = '', $mirror = false)
+    {
+        if ($mirror) {
+            return $this->addMirrorFunction($mirror, $type, $version, $name);
+        }
+        $set = array('attribs' => array('version' => $version), '_content' => $name);
+        if (!isset($this->_channelInfo['servers']['primary'][$type]['function'])) {
+            $this->_channelInfo['servers']['primary'][$type]['function'] = $set;
+            $this->_isValid = false;
+            return true;
+        } elseif (!isset($this->_channelInfo['servers']['primary'][$type]['function'][0])) {
+            $this->_channelInfo['servers']['primary'][$type]['function'] = array(
+                $this->_channelInfo['servers']['primary'][$type]['function']);
+        }
+        $this->_channelInfo['servers']['primary'][$type]['function'][] = $set;
+        return true;
+    }
+    /**
+     * Add a protocol to a mirror's provides section
+     * @param string mirror name (server)
+     * @param string protocol type
+     * @param string protocol version
+     * @param string protocol name, if any
+     */
+    function addMirrorFunction($mirror, $type, $version, $name = '')
+    {
+        $found = false;
+        if (!isset($this->_channelInfo['servers']['mirror'])) {
+            $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
+                array('mirror' => $mirror));
+            return false;
+        }
+        $setmirror = false;
+        if (isset($this->_channelInfo['servers']['mirror'][0])) {
+            foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
+                if ($mirror == $mir['attribs']['host']) {
+                    $setmirror = &$this->_channelInfo['servers']['mirror'][$i];
+                    break;
+                }
+            }
+        } else {
+            if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
+                $setmirror = &$this->_channelInfo['servers']['mirror'];
+            }
+        }
+        if (!$setmirror) {
+            $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
+                array('mirror' => $mirror));
+            return false;
+        }
+        $set = array('attribs' => array('version' => $version), '_content' => $name);
+        if (!isset($setmirror[$type]['function'])) {
+            $setmirror[$type]['function'] = $set;
+            $this->_isValid = false;
+            return true;
+        } elseif (!isset($setmirror[$type]['function'][0])) {
+            $setmirror[$type]['function'] = array($setmirror[$type]['function']);
+        }
+        $setmirror[$type]['function'][] = $set;
+        $this->_isValid = false;
+        return true;
+    }
+
+    /**
+     * @param string Resource Type this url links to
+     * @param string URL
+     * @param string|false mirror name, if this is not a primary server REST base URL
+     */
+    function setBaseURL($resourceType, $url, $mirror = false)
+    {
+        if ($mirror) {
+            $found = false;
+            if (!isset($this->_channelInfo['servers']['mirror'])) {
+                $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
+                    array('mirror' => $mirror));
+                return false;
+            }
+            $setmirror = false;
+            if (isset($this->_channelInfo['servers']['mirror'][0])) {
+                foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
+                    if ($mirror == $mir['attribs']['host']) {
+                        $setmirror = &$this->_channelInfo['servers']['mirror'][$i];
+                        break;
+                    }
+                }
+            } else {
+                if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
+                    $setmirror = &$this->_channelInfo['servers']['mirror'];
+                }
+            }
+        } else {
+            $setmirror = &$this->_channelInfo['servers']['primary'];
+        }
+        $set = array('attribs' => array('type' => $resourceType), '_content' => $url);
+        if (!isset($setmirror['rest']['baseurl'])) {
+            $setmirror['rest']['baseurl'] = $set;
+            $this->_isValid = false;
+            return true;
+        } elseif (!isset($setmirror['rest']['baseurl'][0])) {
+            $setmirror['rest']['baseurl'] = array($setmirror['rest']['baseurl']);
+        }
+        foreach ($setmirror['rest']['baseurl'] as $i => $url) {
+            if ($url['attribs']['type'] == $resourceType) {
+                $this->_isValid = false;
+                $setmirror['rest']['baseurl'][$i] = $set;
+                return true;
+            }
+        }
+        $setmirror['rest']['baseurl'][] = $set;
+        $this->_isValid = false;
+        return true;
+    }
+
+    /**
+     * @param string mirror server
+     * @param int mirror http port
+     * @return boolean
+     */
+    function addMirror($server, $port = null)
+    {
+        if ($this->_channelInfo['name'] == '__uri') {
+            return false; // the __uri channel cannot have mirrors by definition
+        }
+        $set = array('attribs' => array('host' => $server));
+        if (is_numeric($port)) {
+            $set['attribs']['port'] = $port;
+        }
+        if (!isset($this->_channelInfo['servers']['mirror'])) {
+            $this->_channelInfo['servers']['mirror'] = $set;
+            return true;
+        } else {
+            if (!isset($this->_channelInfo['servers']['mirror'][0])) {
+                $this->_channelInfo['servers']['mirror'] =
+                    array($this->_channelInfo['servers']['mirror']);
+            }
+        }
+        $this->_channelInfo['servers']['mirror'][] = $set;
+        return true;
+    }
+
+    /**
+     * Retrieve the name of the validation package for this channel
+     * @return string|false
+     */
+    function getValidationPackage()
+    {
+        if (!$this->_isValid && !$this->validate()) {
+            return false;
+        }
+        if (!isset($this->_channelInfo['validatepackage'])) {
+            return array('attribs' => array('version' => 'default'),
+                '_content' => 'PEAR_Validate');
+        }
+        return $this->_channelInfo['validatepackage'];
+    }
+
+    /**
+     * Retrieve the object that can be used for custom validation
+     * @param string|false the name of the package to validate.  If the package is
+     *                     the channel validation package, PEAR_Validate is returned
+     * @return PEAR_Validate|false false is returned if the validation package
+     *         cannot be located
+     */
+    function &getValidationObject($package = false)
+    {
+        if (!class_exists('PEAR_Validate')) {
+            require_once 'PEAR/Validate.php';
+        }
+        if (!$this->_isValid) {
+            if (!$this->validate()) {
+                $a = false;
+                return $a;
+            }
+        }
+        if (isset($this->_channelInfo['validatepackage'])) {
+            if ($package == $this->_channelInfo['validatepackage']) {
+                // channel validation packages are always validated by PEAR_Validate
+                $val = &new PEAR_Validate;
+                return $val;
+            }
+            if (!class_exists(str_replace('.', '_',
+                  $this->_channelInfo['validatepackage']['_content']))) {
+                if ($this->isIncludeable(str_replace('_', '/',
+                      $this->_channelInfo['validatepackage']['_content']) . '.php')) {
+                    include_once str_replace('_', '/',
+                        $this->_channelInfo['validatepackage']['_content']) . '.php';
+                    $vclass = str_replace('.', '_',
+                        $this->_channelInfo['validatepackage']['_content']);
+                    $val = &new $vclass;
+                } else {
+                    $a = false;
+                    return $a;
+                }
+            } else {
+                $vclass = str_replace('.', '_',
+                    $this->_channelInfo['validatepackage']['_content']);
+                $val = &new $vclass;
+            }
+        } else {
+            $val = &new PEAR_Validate;
+        }
+        return $val;
+    }
+
+    function isIncludeable($path)
+    {
+        $possibilities = explode(PATH_SEPARATOR, ini_get('include_path'));
+        foreach ($possibilities as $dir) {
+            if (file_exists($dir . DIRECTORY_SEPARATOR . $path)
+                  && is_readable($dir . DIRECTORY_SEPARATOR . $path)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * This function is used by the channel updater and retrieves a value set by
+     * the registry, or the current time if it has not been set
+     * @return string
+     */
+    function lastModified()
+    {
+        if (isset($this->_channelInfo['_lastmodified'])) {
+            return $this->_channelInfo['_lastmodified'];
+        }
+        return time();
+    }
+}
+?>
diff --git a/pear/PEAR/ChannelFile/Parser.php b/pear/PEAR/ChannelFile/Parser.php
new file mode 100644 (file)
index 0000000..687bbbc
--- /dev/null
@@ -0,0 +1,73 @@
+<?php
+/**
+ * PEAR_ChannelFile_Parser for parsing channel.xml
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a1
+ */
+
+/**
+ * base xml parser class
+ */
+require_once 'PEAR/XMLParser.php';
+require_once 'PEAR/ChannelFile.php';
+/**
+ * Parser for channel.xml
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
+ */
+class PEAR_ChannelFile_Parser extends PEAR_XMLParser
+{
+    var $_config;
+    var $_logger;
+    var $_registry;
+
+    function setConfig(&$c)
+    {
+        $this->_config = &$c;
+        $this->_registry = &$c->getRegistry();
+    }
+
+    function setLogger(&$l)
+    {
+        $this->_logger = &$l;
+    }
+
+    function parse($data, $file)
+    {
+        if (PEAR::isError($err = parent::parse($data, $file))) {
+            return $err;
+        }
+        $ret = new PEAR_ChannelFile;
+        $ret->setConfig($this->_config);
+        if (isset($this->_logger)) {
+            $ret->setLogger($this->_logger);
+        }
+        $ret->fromArray($this->_unserializedData);
+        // make sure the filelist is in the easy to read format needed
+        $ret->flattenFilelist();
+        $ret->setPackagefile($file, $archive);
+        return $ret;
+    }
+}
+?>
\ No newline at end of file
index 49bb72b24c096ca2a2fa50f67362525fec46e141..2e143a46e7beafac13e71a98f49c925f6ddfb394 100644 (file)
@@ -1,25 +1,32 @@
 <?php
-//
-// +----------------------------------------------------------------------+
-// | PHP Version 5                                                        |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2004 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 Bakken <ssb@php.net>                                    |
-// +----------------------------------------------------------------------+
-//
-// $Id$
-
+/**
+ * PEAR_Command, command pattern class
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 0.1
+ */
 
-require_once "PEAR.php";
+/**
+ * Needed for error handling
+ */
+require_once 'PEAR.php';
+require_once 'PEAR/Frontend.php';
+require_once 'PEAR/XMLParser.php';
 
 /**
  * List of commands and what classes they are implemented in.
@@ -39,18 +46,6 @@ $GLOBALS['_PEAR_Command_shortcuts'] = array();
  */
 $GLOBALS['_PEAR_Command_objects'] = array();
 
-/**
- * Which user interface class is being used.
- * @var string class name
- */
-$GLOBALS['_PEAR_Command_uiclass'] = 'PEAR_Frontend_CLI';
-
-/**
- * Instance of $_PEAR_Command_uiclass.
- * @var object
- */
-$GLOBALS['_PEAR_Command_uiobject'] = null;
-
 /**
  * PEAR command class, a simple factory class for administrative
  * commands.
@@ -93,6 +88,15 @@ $GLOBALS['_PEAR_Command_uiobject'] = null;
  * - DON'T USE EXIT OR DIE! Always use pear errors.  From static
  *   classes do PEAR::raiseError(), from other classes do
  *   $this->raiseError().
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 0.1
  */
 class PEAR_Command
 {
@@ -109,7 +113,7 @@ class PEAR_Command
      * @access public
      * @static
      */
-    function factory($command, &$config)
+    function &factory($command, &$config)
     {
         if (empty($GLOBALS['_PEAR_Command_commandlist'])) {
             PEAR_Command::registerCommands();
@@ -118,13 +122,35 @@ class PEAR_Command
             $command = $GLOBALS['_PEAR_Command_shortcuts'][$command];
         }
         if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) {
-            return PEAR::raiseError("unknown command `$command'");
+            $a = PEAR::raiseError("unknown command `$command'");
+            return $a;
+        }
+        $class = $GLOBALS['_PEAR_Command_commandlist'][$command];
+        if (!class_exists($class)) {
+            require_once $GLOBALS['_PEAR_Command_objects'][$class];
         }
+        if (!class_exists($class)) {
+            $a = PEAR::raiseError("unknown command `$command'");
+            return $a;
+        }
+        $ui =& PEAR_Command::getFrontendObject();
+        $obj = &new $class($ui, $config);
+        return $obj;
+    }
+
+    // }}}
+    // {{{ & getObject()
+    function &getObject($command)
+    {
         $class = $GLOBALS['_PEAR_Command_commandlist'][$command];
+        if (!class_exists($class)) {
+            require_once $GLOBALS['_PEAR_Command_objects'][$class];
+        }
         if (!class_exists($class)) {
             return PEAR::raiseError("unknown command `$command'");
         }
         $ui =& PEAR_Command::getFrontendObject();
+        $config = &PEAR_Config::singleton();
         $obj = &new $class($ui, $config);
         return $obj;
     }
@@ -135,15 +161,13 @@ class PEAR_Command
     /**
      * Get instance of frontend object.
      *
-     * @return object
+     * @return object|PEAR_Error
      * @static
      */
     function &getFrontendObject()
     {
-        if (empty($GLOBALS['_PEAR_Command_uiobject'])) {
-            $GLOBALS['_PEAR_Command_uiobject'] = &new $GLOBALS['_PEAR_Command_uiclass'];
-        }
-        return $GLOBALS['_PEAR_Command_uiobject'];
+        $a = &PEAR_Frontend::singleton();
+        return $a;
     }
 
     // }}}
@@ -159,59 +183,13 @@ class PEAR_Command
      */
     function &setFrontendClass($uiclass)
     {
-        if (is_object($GLOBALS['_PEAR_Command_uiobject']) &&
-              is_a($GLOBALS['_PEAR_Command_uiobject'], $uiclass)) {
-            return $GLOBALS['_PEAR_Command_uiobject'];
-        }
-        if (!class_exists($uiclass)) {
-            $file = str_replace('_', '/', $uiclass) . '.php';
-            if (PEAR_Command::isIncludeable($file)) {
-                include_once $file;
-            }
-        }
-        if (class_exists($uiclass)) {
-            $obj = &new $uiclass;
-            // quick test to see if this class implements a few of the most
-            // important frontend methods
-            if (method_exists($obj, 'userConfirm')) {
-                $GLOBALS['_PEAR_Command_uiobject'] = &$obj;
-                $GLOBALS['_PEAR_Command_uiclass'] = $uiclass;
-                return $obj;
-            } else {
-                $err = PEAR::raiseError("not a frontend class: $uiclass");
-                return $err;
-            }
-        }
-        $err = PEAR::raiseError("no such class: $uiclass");
-        return $err;
+        $a = &PEAR_Frontend::setFrontendClass($uiclass);
+        return $a;
     }
 
     // }}}
     // {{{ setFrontendType()
 
-    // }}}
-    // {{{ isIncludeable()
-
-    /**
-     * @param string $path relative or absolute include path
-     * @return boolean
-     * @static
-     */
-    function isIncludeable($path)
-    {
-        if (file_exists($path) && is_readable($path)) {
-            return true;
-        }
-        $ipath = explode(PATH_SEPARATOR, ini_get('include_path'));
-        foreach ($ipath as $include) {
-            $test = realpath($include . DIRECTORY_SEPARATOR . $path);
-            if (file_exists($test) && is_readable($test)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     /**
      * Set current frontend.
      *
@@ -249,6 +227,7 @@ class PEAR_Command
      */
     function registerCommands($merge = false, $dir = null)
     {
+        $parser = new PEAR_XMLParser;
         if ($dir === null) {
             $dir = dirname(__FILE__) . '/Command';
         }
@@ -260,26 +239,51 @@ class PEAR_Command
             $GLOBALS['_PEAR_Command_commandlist'] = array();
         }
         while ($entry = readdir($dp)) {
-            if ($entry{0} == '.' || substr($entry, -4) != '.php' || $entry == 'Common.php') {
+            if ($entry{0} == '.' || substr($entry, -4) != '.xml') {
                 continue;
             }
             $class = "PEAR_Command_".substr($entry, 0, -4);
             $file = "$dir/$entry";
-            include_once $file;
+            $parser->parse(file_get_contents($file));
+            $implements = $parser->getData();
             // List of commands
             if (empty($GLOBALS['_PEAR_Command_objects'][$class])) {
-                $GLOBALS['_PEAR_Command_objects'][$class] = &new $class($ui, $config);
+                $GLOBALS['_PEAR_Command_objects'][$class] = "$dir/" . substr($entry, 0, -4) .
+                    '.php';
             }
-            $implements = $GLOBALS['_PEAR_Command_objects'][$class]->getCommands();
             foreach ($implements as $command => $desc) {
+                if ($command == 'attribs') {
+                    continue;
+                }
+                if (isset($GLOBALS['_PEAR_Command_commandlist'][$command])) {
+                    return PEAR::raiseError('Command "' . $command . '" already registered in ' .
+                        'class "' . $GLOBALS['_PEAR_Command_commandlist'][$command] . '"');
+                }
                 $GLOBALS['_PEAR_Command_commandlist'][$command] = $class;
-                $GLOBALS['_PEAR_Command_commanddesc'][$command] = $desc;
-            }
-            $shortcuts = $GLOBALS['_PEAR_Command_objects'][$class]->getShortcuts();
-            foreach ($shortcuts as $shortcut => $command) {
-                $GLOBALS['_PEAR_Command_shortcuts'][$shortcut] = $command;
+                $GLOBALS['_PEAR_Command_commanddesc'][$command] = $desc['summary'];
+                if (isset($desc['shortcut'])) {
+                    $shortcut = $desc['shortcut'];
+                    if (isset($GLOBALS['_PEAR_Command_shortcuts'][$shortcut])) {
+                        return PEAR::raiseError('Command shortcut "' . $shortcut . '" already ' .
+                            'registered to command "' . $command . '" in class "' .
+                            $GLOBALS['_PEAR_Command_commandlist'][$command] . '"');
+                    }
+                    $GLOBALS['_PEAR_Command_shortcuts'][$shortcut] = $command;
+                }
+                if (isset($desc['options']) && $desc['options']) {
+                    foreach ($desc['options'] as $oname => $option) {
+                        if (isset($option['shortopt']) && strlen($option['shortopt']) > 1) {
+                            return PEAR::raiseError('Option "' . $oname . '" short option "' .
+                                $option['shortopt'] . '" must be ' .
+                                'only 1 character in Command "' . $command . '" in class "' .
+                                $class . '"');
+                        }
+                    }
+                }
             }
         }
+        ksort($GLOBALS['_PEAR_Command_shortcuts']);
+        ksort($GLOBALS['_PEAR_Command_commandlist']);
         @closedir($dp);
         return true;
     }
@@ -343,11 +347,13 @@ class PEAR_Command
         if (empty($GLOBALS['_PEAR_Command_commandlist'])) {
             PEAR_Command::registerCommands();
         }
+        if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) {
+            $command = $GLOBALS['_PEAR_Command_shortcuts'][$command];
+        }
         if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) {
             return null;
         }
-        $class = $GLOBALS['_PEAR_Command_commandlist'][$command];
-        $obj = &$GLOBALS['_PEAR_Command_objects'][$class];
+        $obj = &PEAR_Command::getObject($command);
         return $obj->getGetoptArgs($command, $short_args, $long_args);
     }
 
@@ -386,9 +392,12 @@ class PEAR_Command
     function getHelp($command)
     {
         $cmds = PEAR_Command::getCommands();
+        if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) {
+            $command = $GLOBALS['_PEAR_Command_shortcuts'][$command];
+        }
         if (isset($cmds[$command])) {
-            $class = $cmds[$command];
-            return $GLOBALS['_PEAR_Command_objects'][$class]->getHelp($command);
+            $obj = &PEAR_Command::getObject($command);
+            return $obj->getHelp($command);
         }
         return false;
     }
index 6578ee4399d49d718c62c8389c582252d20d8268..4b0c1abe10af12a6012114b636d38be5d6734350 100644 (file)
@@ -1,30 +1,44 @@
 <?php
-//
-// +----------------------------------------------------------------------+
-// | PHP Version 5                                                        |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2004 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 Bakken <ssb@php.net>                                    |
-// +----------------------------------------------------------------------+
-//
-// $Id$
+/**
+ * PEAR_Command_Auth (login, logout commands)
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 0.1
+ */
 
-require_once "PEAR/Command/Common.php";
-require_once "PEAR/Remote.php";
-require_once "PEAR/Config.php";
+/**
+ * base class
+ */
+require_once 'PEAR/Command/Common.php';
+require_once 'PEAR/Config.php';
 
 /**
- * PEAR commands for managing configuration data.
+ * PEAR commands for login/logout
  *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 0.1
  */
 class PEAR_Command_Auth extends PEAR_Command_Common
 {
@@ -84,15 +98,18 @@ password from your user configuration.',
      *
      * @param array $params list of additional parameters
      *
-     * @return bool TRUE on success, FALSE for unknown commands, or
+     * @return bool TRUE on success or
      * a PEAR error on failure
      *
      * @access public
      */
     function doLogin($command, $options, $params)
     {
-        $server = $this->config->get('master_server');
-        $remote = new PEAR_Remote($this->config);
+        $reg = &$this->config->getRegistry();
+        $channel = $this->config->get('default_channel');
+        $chan = $reg->getChannel($channel);
+        $server = $this->config->get('preferred_mirror');
+        $remote = &$this->config->getRemote();
         $username = $this->config->get('username');
         if (empty($username)) {
             $username = @$_ENV['USER'];
@@ -110,17 +127,21 @@ password from your user configuration.',
         
         $this->config->set('username', $username);
         $this->config->set('password', $password);
-        
-        $remote->expectError(401);
-        $ok = $remote->call('logintest');
-        $remote->popExpect();
+
+        if ($chan->supportsREST()) {
+            $ok = true;
+        } else {
+            $remote->expectError(401);
+            $ok = $remote->call('logintest');
+            $remote->popExpect();
+        }
         if ($ok === true) {
             $this->ui->outputData("Logged in.", $command);
             $this->config->store();
         } else {
             return $this->raiseError("Login failed!");
         }
-
+        return true;
     }
 
     // }}}
@@ -135,18 +156,22 @@ password from your user configuration.',
      *
      * @param array $params list of additional parameters
      *
-     * @return bool TRUE on success, FALSE for unknown commands, or
+     * @return bool TRUE on success or
      * a PEAR error on failure
      *
      * @access public
      */
     function doLogout($command, $options, $params)
     {
-        $server = $this->config->get('master_server');
+        $reg = &$this->config->getRegistry();
+        $channel = $this->config->get('default_channel');
+        $chan = $reg->getChannel($channel);
+        $server = $this->config->get('preferred_mirror');
         $this->ui->outputData("Logging out from $server.", $command);
         $this->config->remove('username');
         $this->config->remove('password');
         $this->config->store();
+        return true;
     }
 
     // }}}
diff --git a/pear/PEAR/Command/Auth.xml b/pear/PEAR/Command/Auth.xml
new file mode 100644 (file)
index 0000000..bfc28da
--- /dev/null
@@ -0,0 +1,25 @@
+<commands version="1.0">
+ <login>
+  <summary>Connects and authenticates to remote server</summary>
+  <shortcut>li</shortcut>
+  <function>doLogin</function>
+  <options />
+  <doc>
+Log in to the remote server.  To use remote functions in the installer
+that require any kind of privileges, you need to log in first.  The
+username and password you enter here will be stored in your per-user
+PEAR configuration (~/.pearrc on Unix-like systems).  After logging
+in, your username and password will be sent along in subsequent
+operations on the remote server.</doc>
+ </login>
+ <logout>
+  <summary>Logs out from the remote server</summary>
+  <shortcut>lo</shortcut>
+  <function>doLogout</function>
+  <options />
+  <doc>
+Logs out from the remote server.  This command does not actually
+connect to the remote server, it only deletes the stored username and
+password from your user configuration.</doc>
+ </logout>
+</commands>
\ No newline at end of file
index e07dc290649b3e45e191aec58ba54bf06fe2a243..1c8223df969b11ee347171f6ba312afbc4896247 100644 (file)
@@ -1,31 +1,45 @@
 <?php
-//
-// +----------------------------------------------------------------------+
-// | PHP Version 5                                                        |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2004 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 Bakken <ssb@php.net>                                    |
-// |         Tomas V.V.Cox <cox@idecnet.com>                              |
-// |                                                                      |
-// +----------------------------------------------------------------------+
-//
-// $Id$
+/**
+ * PEAR_Command_Auth (build command)
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Tomas V.V.Cox <cox@idecnet.com>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 0.1
+ */
 
-require_once "PEAR/Command/Common.php";
-require_once "PEAR/Builder.php";
+/**
+ * base class
+ */
+require_once 'PEAR/Command/Common.php';
 
 /**
  * PEAR commands for building extensions.
  *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Tomas V.V.Cox <cox@idecnet.com>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 0.1
  */
 class PEAR_Command_Build extends PEAR_Command_Common
 {
@@ -62,6 +76,7 @@ Builds one or more extensions contained in a package.'
 
     function doBuild($command, $options, $params)
     {
+        require_once 'PEAR/Builder.php';
         if (sizeof($params) < 1) {
             $params[0] = 'package.xml';
         }
diff --git a/pear/PEAR/Command/Build.xml b/pear/PEAR/Command/Build.xml
new file mode 100644 (file)
index 0000000..ec4e6f5
--- /dev/null
@@ -0,0 +1,10 @@
+<commands version="1.0">
+ <build>
+  <summary>Build an Extension From C Source</summary>
+  <function>doBuild</function>
+  <shortcut>b</shortcut>
+  <options />
+  <doc>[package.xml]
+Builds one or more extensions contained in a package.</doc>
+ </build>
+</commands>
\ No newline at end of file
diff --git a/pear/PEAR/Command/Channels.php b/pear/PEAR/Command/Channels.php
new file mode 100644 (file)
index 0000000..cf7f83b
--- /dev/null
@@ -0,0 +1,770 @@
+<?php
+// /* vim: set expandtab tabstop=4 shiftwidth=4: */
+/**
+ * PEAR_Command_Channels (list-channels, update-channels, channel-delete, channel-add,
+ * channel-update, channel-info, channel-alias, channel-discover commands)
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a1
+ */
+
+/**
+ * base class
+ */
+require_once 'PEAR/Command/Common.php';
+
+/**
+ * PEAR commands for managing channels.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
+ */
+class PEAR_Command_Channels extends PEAR_Command_Common
+{
+    // {{{ properties
+
+    var $commands = array(
+        'list-channels' => array(
+            'summary' => 'List Available Channels',
+            'function' => 'doList',
+            'shortcut' => 'lc',
+            'options' => array(),
+            'doc' => '
+List all available channels for installation.
+',
+            ),
+        'update-channels' => array(
+            'summary' => 'Update the Channel List',
+            'function' => 'doUpdateAll',
+            'shortcut' => 'uc',
+            'options' => array(),
+            'doc' => '
+List all installed packages in all channels.
+'
+            ),
+        'channel-delete' => array(
+            'summary' => 'Remove a Channel From the List',
+            'function' => 'doDelete',
+            'shortcut' => 'cde',
+            'options' => array(),
+            'doc' => '<channel name>
+Delete a channel from the registry.  You may not
+remove any channel that has installed packages.
+'
+            ),
+        'channel-add' => array(
+            'summary' => 'Add a Channel',
+            'function' => 'doAdd',
+            'shortcut' => 'ca',
+            'options' => array(),
+            'doc' => '<channel.xml>
+Add a private channel to the channel list.  Note that all
+public channels should be synced using "update-channels".
+Parameter may be either a local file or remote URL to a
+channel.xml.
+'
+            ),
+        'channel-update' => array(
+            'summary' => 'Update an Existing Channel',
+            'function' => 'doUpdate',
+            'shortcut' => 'cu',
+            'options' => array(
+                'force' => array(
+                    'shortopt' => 'f',
+                    'doc' => 'will force download of new channel.xml if an existing channel name is used',
+                    ),
+                'channel' => array(
+                    'shortopt' => 'c',
+                    'arg' => 'CHANNEL',
+                    'doc' => 'will force download of new channel.xml if an existing channel name is used',
+                    ),
+),
+            'doc' => '[<channel.xml>|<channel name>]
+Update a channel in the channel list directly.  Note that all
+public channels can be synced using "update-channels".
+Parameter may be a local or remote channel.xml, or the name of
+an existing channel.
+'
+            ),
+        'channel-info' => array(
+            'summary' => 'Retrieve Information on a Channel',
+            'function' => 'doInfo',
+            'shortcut' => 'ci',
+            'options' => array(),
+            'doc' => '<package>
+List the files in an installed package.
+'
+            ),
+        'channel-alias' => array(
+            'summary' => 'Specify an alias to a channel name',
+            'function' => 'doAlias',
+            'shortcut' => 'cha',
+            'options' => array(),
+            'doc' => '<channel> <alias>
+Specify a specific alias to use for a channel name.
+The alias may not be an existing channel name or
+alias.
+'
+            ),
+        'channel-discover' => array(
+            'summary' => 'Initialize a Channel from its server',
+            'function' => 'doDiscover',
+            'shortcut' => 'di',
+            'options' => array(),
+            'doc' => '<package>
+List the files in an installed package.
+'
+            ),
+        );
+
+    // }}}
+    // {{{ constructor
+
+    /**
+     * PEAR_Command_Registry constructor.
+     *
+     * @access public
+     */
+    function PEAR_Command_Channels(&$ui, &$config)
+    {
+        parent::PEAR_Command_Common($ui, $config);
+    }
+
+    // }}}
+
+    // {{{ doList()
+    
+    function _sortChannels($a, $b)
+    {
+        return strnatcasecmp($a->getName(), $b->getName());
+    }
+
+    function doList($command, $options, $params)
+    {
+        $reg = &$this->config->getRegistry();
+        $registered = $reg->getChannels();
+        usort($registered, array(&$this, '_sortchannels'));
+        $i = $j = 0;
+        $data = array(
+            'caption' => 'Registered Channels:',
+            'border' => true,
+            'headline' => array('Channel', 'Summary')
+            );
+        foreach ($registered as $channel) {
+            $data['data'][] = array($channel->getName(),
+                                      $channel->getSummary());
+        }
+        if (count($registered)==0) {
+            $data = '(no registered channels)';
+        }
+        $this->ui->outputData($data, $command);
+        return true;
+    }
+    
+    function doUpdateAll($command, $options, $params)
+    {
+        $reg = &$this->config->getRegistry();
+        $savechannel = $this->config->get('default_channel');
+        if (isset($options['channel'])) {
+            if (!$reg->channelExists($options['channel'])) {
+                return $this->raiseError('Unknown channel "' . $options['channel'] . '"');
+            }
+            $this->config->set('default_channel', $options['channel']);
+        } else {
+            $this->config->set('default_channel', 'pear.php.net');
+        }
+        $remote = &$this->config->getRemote();
+        $channels = $remote->call('channel.listAll');
+        if (PEAR::isError($channels)) {
+            $this->config->set('default_channel', $savechannel);
+            return $channels;
+        }
+        if (!is_array($channels) || isset($channels['faultCode'])) {
+            $this->config->set('default_channel', $savechannel);
+            return $this->raiseError("Incorrect channel listing returned from channel '$chan'");
+        }
+        if (!count($channels)) {
+            $data = 'no updates available';
+        }
+        $dl = &$this->getDownloader();
+        if (!class_exists('System')) {
+            require_once 'System.php';
+        }
+        $tmpdir = System::mktemp(array('-d'));
+        foreach ($channels as $channel) {
+            $channel = $channel[0];
+            $save = $channel;
+            if ($reg->channelExists($channel, true)) {
+                $this->ui->outputData("Updating channel \"$channel\"", $command);
+                $test = $reg->getChannel($channel, true);
+                if (!$test) {
+                    $this->ui->outputData("Channel '$channel' is corrupt in registry!", $command);
+                    $lastmodified = false;
+                } else {
+                    $lastmodified = $test->lastModified();
+                    
+                }
+                PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+                $contents = $dl->downloadHttp('http://' . $test->getName() . '/channel.xml',
+                    $this->ui, $tmpdir, null, $lastmodified);
+                PEAR::staticPopErrorHandling();
+                if (PEAR::isError($contents)) {
+                    $this->ui->outputData('ERROR: Cannot retrieve channel.xml for channel "' .
+                        $test->getName() . '"', $command);
+                    continue;
+                }
+                if (!$contents) {
+                    $this->ui->outputData("Channel \"$channel\" is up-to-date", $command);
+                    continue;
+                }
+                list($contents, $lastmodified) = $contents;
+                $info = implode('', file($contents));
+                if (!$info) {
+                    $this->ui->outputData("Channel \"$channel\" is up-to-date", $command);
+                    continue;
+                }
+                if (!class_exists('PEAR_ChannelFile')) {
+                    require_once 'PEAR/ChannelFile.php';
+                }
+                $channelinfo = new PEAR_ChannelFile;
+                $channelinfo->fromXmlString($info);
+                if ($channelinfo->getErrors()) {
+                    $this->ui->outputData("Downloaded channel data from channel \"$channel\" " . 
+                        'is corrupt, skipping', $command);
+                    continue;
+                }
+                $channel = $channelinfo;
+                if ($channel->getName() != $save) {
+                    $this->ui->outputData('ERROR: Security risk - downloaded channel ' .
+                        'definition file for channel "'
+                        . $channel->getName() . ' from channel "' . $save .
+                        '".  To use anyway, use channel-update', $command);
+                    continue;
+                }
+                $reg->updateChannel($channel, $lastmodified);
+            } else {
+                if ($reg->isAlias($channel)) {
+                    $temp = &$reg->getChannel($channel);
+                    $temp->setAlias($temp->getName(), true); // set the alias to the channel name
+                    if ($reg->channelExists($temp->getName())) {
+                        $this->ui->outputData('ERROR: existing channel "' . $temp->getName() .
+                            '" is aliased to "' . $channel . '" already and cannot be ' .
+                            're-aliased to "' . $temp->getName() . '" because a channel with ' .
+                            'that name or alias already exists!  Please re-alias and try ' .
+                            'again.', $command);
+                        continue;
+                    }
+                }
+                $this->ui->outputData("Adding new channel \"$channel\"", $command);
+                PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+                $contents = $dl->downloadHttp('http://' . $channel . '/channel.xml',
+                    $this->ui, $tmpdir, null, false);
+                PEAR::staticPopErrorHandling();
+                if (PEAR::isError($contents)) {
+                    $this->ui->outputData('ERROR: Cannot retrieve channel.xml for channel "' .
+                        $channel . '"', $command);
+                    continue;
+                }
+                list($contents, $lastmodified) = $contents;
+                $info = implode('', file($contents));
+                if (!class_exists('PEAR_ChannelFile')) {
+                    require_once 'PEAR/ChannelFile.php';
+                }
+                $channelinfo = new PEAR_Channelfile;
+                $channelinfo->fromXmlString($info);
+                if ($channelinfo->getErrors()) {
+                    $this->ui->outputData("Downloaded channel data from channel \"$channel\"" .
+                        ' is corrupt, skipping', $command);
+                    continue;
+                }
+                $channel = $channelinfo;
+                if ($channel->getName() != $save) {
+                    $this->ui->outputData('ERROR: Security risk - downloaded channel ' .
+                        'definition file for channel "'
+                        . $channel->getName() . '" from channel "' . $save .
+                        '".  To use anyway, use channel-update', $command);
+                    continue;
+                }
+                $reg->addChannel($channel, $lastmodified);
+            }
+        }
+        $this->config->set('default_channel', $savechannel);
+        $this->ui->outputData('update-channels complete', $command);
+        return true;
+    }
+    
+    function doInfo($command, $options, $params)
+    {
+        if (sizeof($params) != 1) {
+            return $this->raiseError("No channel specified");
+        }
+        $reg = &$this->config->getRegistry();
+        $channel = strtolower($params[0]);
+        if ($reg->channelExists($channel)) {
+            $chan = $reg->getChannel($channel);
+        } else {
+            if (strpos($channel, '://')) {
+                $downloader = &$this->getDownloader();
+                if (!class_exists('System')) {
+                    require_once 'System.php';
+                }
+                $tmpdir = System::mktemp(array('-d'));
+                PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+                $loc = $downloader->downloadHttp($channel, $this->ui, $tmpdir);
+                PEAR::staticPopErrorHandling();
+                if (PEAR::isError($loc)) {
+                    return $this->raiseError('Cannot open "' . $channel . '"');
+                } else {
+                    $contents = implode('', file($loc));
+                }
+            } else {
+                $fp = @fopen($params[0], 'r');
+                if (!$fp) {
+                    if (@file_exists($params[0])) {
+                        return $this->raiseError('Cannot open "' . $params[0] . '"');
+                    } else {
+                        return $this->raiseError('Unknown channel "' . $channel . '"');
+                    }
+                }
+                $contents = '';
+                while (!feof($fp)) {
+                    $contents .= fread($fp, 1024);
+                }
+                fclose($fp);
+            }
+            if (!class_exists('PEAR_ChannelFile')) {
+                require_once 'PEAR/ChannelFile.php';
+            }
+            $chan = new PEAR_ChannelFile;
+            $chan->fromXmlString($contents);
+            $chan->validate();
+            if ($errs = $chan->getErrors(true)) {
+                foreach ($errs as $err) {
+                    $this->ui->outputData($err['level'] . ': ' . $err['message']);
+                }
+                return $this->raiseError('Channel file "' . $params[0] . '" is not valid');
+            }
+        }
+        if ($chan) {
+            $channel = $chan->getName();
+            $caption = 'Channel ' . $channel . ' Information:';
+            $data1 = array(
+                'caption' => $caption,
+                'border' => true);
+            $data1['data']['server'] = array('Name and Server', $chan->getName());
+            if ($chan->getAlias() != $chan->getName()) {
+                $data1['data']['alias'] = array('Alias', $chan->getAlias());
+            }
+            $data1['data']['summary'] = array('Summary', $chan->getSummary());
+            $validate = $chan->getValidationPackage();
+            $data1['data']['vpackage'] = array('Validation Package Name', $validate['_content']);
+            $data1['data']['vpackageversion'] =
+                array('Validation Package Version', $validate['attribs']['version']);
+            $d = array();
+            $d['main'] = $data1;
+
+            $data['data'] = array();
+            $data['caption'] = 'Server Capabilities';
+            $data['headline'] = array('Type', 'Version/REST type', 'Function Name/REST base');
+            $capabilities = $chan->getFunctions('xmlrpc');
+            $soaps = $chan->getFunctions('soap');
+            if ($capabilities || $soaps || $chan->supportsREST()) {
+                if ($capabilities) {
+                    if (!isset($capabilities[0])) {
+                        $capabilities = array($capabilities);
+                    }
+                    foreach ($capabilities as $protocol) {
+                        $data['data'][] = array('xmlrpc', $protocol['attribs']['version'],
+                            $protocol['_content']);
+                    }
+                }
+                if ($soaps) {
+                    if (!isset($soaps[0])) {
+                        $soaps = array($soaps);
+                    }
+                    foreach ($soaps as $protocol) {
+                        $data['data'][] = array('soap', $protocol['attribs']['version'],
+                            $protocol['_content']);
+                    }
+                }
+                if ($chan->supportsREST()) {
+                    $funcs = $chan->getFunctions('rest');
+                    if (!isset($funcs[0])) {
+                        $funcs = array($funcs);
+                    }
+                    foreach ($funcs as $protocol) {
+                        $data['data'][] = array('rest', $protocol['attribs']['type'],
+                            $protocol['_content']); 
+                    }
+                }
+            } else {
+                $data['data'][] = array('No supported protocols');
+            }
+            $d['protocols'] = $data;
+            $data['data'] = array();
+            $mirrors = $chan->getMirrors();
+            if ($mirrors) {
+                $data['caption'] = 'Channel ' . $channel . ' Mirrors:';
+                unset($data['headline']);
+                foreach ($mirrors as $mirror) {
+                    $data['data'][] = array($mirror['attribs']['host']);
+                    $d['mirrors'] = $data;
+                }
+                foreach ($mirrors as $mirror) {
+                    $data['data'] = array();
+                    $data['caption'] = 'Mirror ' . $mirror['attribs']['host'] . ' Capabilities';
+                    $data['headline'] = array('Type', 'Version/REST type', 'Function Name/REST base');
+                    $capabilities = $chan->getFunctions('xmlrpc', $mirror['attribs']['host']);
+                    $soaps = $chan->getFunctions('soap', $mirror['attribs']['host']);
+                    if ($capabilities || $soaps || $chan->supportsREST($mirror['attribs']['host'])) {
+                        if ($capabilities) {
+                            if (!isset($capabilities[0])) {
+                                $capabilities = array($capabilities);
+                            }
+                            foreach ($capabilities as $protocol) {
+                                $data['data'][] = array('xmlrpc', $protocol['attribs']['version'],
+                                    $protocol['_content']);
+                            }
+                        }
+                        if ($soaps) {
+                            if (!isset($soaps[0])) {
+                                $soaps = array($soaps);
+                            }
+                            foreach ($soaps as $protocol) {
+                                $data['data'][] = array('soap', $protocol['attribs']['version'],
+                                    $protocol['_content']);
+                            }
+                        }
+                        if ($chan->supportsREST($mirror['attribs']['host'])) {
+                            $funcs = $chan->getFunctions('rest', $mirror['attribs']['host']);
+                            if (!isset($funcs[0])) {
+                                $funcs = array($funcs);
+                            }
+                            foreach ($funcs as $protocol) {
+                                $data['data'][] = array('rest', $protocol['attribs']['type'],
+                                    $protocol['_content']); 
+                            }
+                        }
+                    } else {
+                        $data['data'][] = array('No supported protocols');
+                    }
+                    $d['mirrorprotocols'] = $data;
+                }
+            }
+            $this->ui->outputData($d, 'channel-info');
+        } else {
+            return $this->raiseError('Serious error: Channel "' . $params[0] .
+                '" has a corrupted registry entry');
+        }
+    }
+
+    // }}}
+    
+    function doDelete($command, $options, $params)
+    {
+        if (sizeof($params) != 1) {
+            return $this->raiseError('channel-delete: no channel specified');
+        }
+        $reg = &$this->config->getRegistry();
+        if (!$reg->channelExists($params[0])) {
+            return $this->raiseError('channel-delete: channel "' . $params[0] . '" does not exist');
+        }
+        $channel = $reg->channelName($params[0]);
+        if ($channel == 'pear.php.net') {
+            return $this->raiseError('Cannot delete the pear.php.net channel');
+        }
+        if ($channel == 'pecl.php.net') {
+            return $this->raiseError('Cannot delete the pecl.php.net channel');
+        }
+        if ($channel == '__uri') {
+            return $this->raiseError('Cannot delete the __uri pseudo-channel');
+        }
+        if (PEAR::isError($err = $reg->listPackages($channel))) {
+            return $err;
+        }
+        if (count($err)) {
+            return $this->raiseError('Channel "' . $channel .
+                '" has installed packages, cannot delete');
+        }
+        if (!$reg->deleteChannel($channel)) {
+            return $this->raiseError('Channel "' . $channel . '" deletion failed');
+        } else {
+            $this->config->deleteChannel($channel);
+            $this->ui->outputData('Channel "' . $channel . '" deleted', $command);
+        }
+    }
+
+    function doAdd($command, $options, $params)
+    {
+        if (sizeof($params) != 1) {
+            return $this->raiseError('channel-add: no channel file specified');
+        }
+        if (strpos($params[0], '://')) {
+            $downloader = &$this->getDownloader();
+            if (!class_exists('System')) {
+                require_once 'System.php';
+            }
+            $tmpdir = System::mktemp(array('-d'));
+            PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+            $loc = $downloader->downloadHttp($params[0], $this->ui, $tmpdir, null, false);
+            PEAR::staticPopErrorHandling();
+            if (PEAR::isError($loc)) {
+                return $this->raiseError('channel-add: Cannot open "' . $params[0] . '"');
+            } else {
+                list($loc, $lastmodified) = $loc;
+                $contents = implode('', file($loc));
+            }
+        } else {
+            $lastmodified = false;
+            $fp = @fopen($params[0], 'r');
+            if (!$fp) {
+                return $this->raiseError('channel-add: cannot open "' . $params[0] . '"');
+            }
+            $contents = '';
+            while (!feof($fp)) {
+                $contents .= fread($fp, 1024);
+            }
+            fclose($fp);
+        }
+        if (!class_exists('PEAR_ChannelFile')) {
+            require_once 'PEAR/ChannelFile.php';
+        }
+        $channel = new PEAR_ChannelFile;
+        PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+        $result = $channel->fromXmlString($contents);
+        PEAR::staticPopErrorHandling();
+        if (!$result) {
+            $exit = false;
+            if (count($errors = $channel->getErrors(true))) {
+                foreach ($errors as $error) {
+                    $this->ui->outputData(ucfirst($error['level'] . ': ' . $error['message']));
+                    if (!$exit) {
+                        $exit = $error['level'] == 'error' ? true : false;
+                    }
+                }
+                if ($exit) {
+                    return $this->raiseError('channel-add: invalid channel.xml file');
+                }
+            }
+        }
+        $reg = &$this->config->getRegistry();
+        if ($reg->channelExists($channel->getName())) {
+            return $this->raiseError('channel-add: Channel "' . $channel->getName() .
+                '" exists, use channel-update to update entry');
+        }
+        $ret = $reg->addChannel($channel, $lastmodified);
+        if (PEAR::isError($ret)) {
+            return $ret;
+        }
+        if (!$ret) {
+            return $this->raiseError('channel-add: adding Channel "' . $channel->getName() .
+                '" to registry failed');
+        }
+        $this->config->setChannels($reg->listChannels());
+        $this->config->writeConfigFile();
+        $this->ui->outputData('Adding Channel "' . $channel->getName() . '" succeeded', $command);
+    }
+
+    function doUpdate($command, $options, $params)
+    {
+        if (!class_exists('System')) {
+            require_once 'System.php';
+        }
+        $tmpdir = System::mktemp(array('-d'));
+        $reg = &$this->config->getRegistry();
+        if (sizeof($params) != 1) {
+            return $this->raiseError("No channel file specified");
+        }
+        $lastmodified = false;
+        if ((!file_exists($params[0]) || is_dir($params[0]))
+              && $reg->channelExists(strtolower($params[0]))) {
+            $c = $reg->getChannel(strtolower($params[0]));
+            $this->ui->outputData('Retrieving channel.xml from remote server');
+            $dl = &$this->getDownloader(array());
+            // if force is specified, use a timestamp of "1" to force retrieval
+            $lastmodified = isset($options['force']) ? false : $c->lastModified();
+            PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+            $contents = $dl->downloadHttp('http://' . $c->getName() . '/channel.xml',
+                $this->ui, $tmpdir, null, $lastmodified);
+            PEAR::staticPopErrorHandling();
+            if (PEAR::isError($contents)) {
+                return $this->raiseError('Cannot retrieve channel.xml for channel "' .
+                    $c->getName() . '"');
+            }
+            list($contents, $lastmodified) = $contents;
+            if (!$contents) {
+                $this->ui->outputData("Channel $params[0] channel.xml is up to date");
+                return;
+            }
+            $contents = implode('', file($contents));
+            if (!class_exists('PEAR_ChannelFile')) {
+                require_once 'PEAR/ChannelFile.php';
+            }
+            $channel = new PEAR_ChannelFile;
+            $channel->fromXmlString($contents);
+            if (!$channel->getErrors()) {
+                // security check: is the downloaded file for the channel we got it from?
+                if (strtolower($channel->getName()) != strtolower($c->getName())) {
+                    if (isset($options['force'])) {
+                        $this->ui->log(0, 'WARNING: downloaded channel definition file' .
+                            ' for channel "' . $channel->getName() . '" from channel "' .
+                            strtolower($c->getName()) . '"');
+                    } else {
+                        return $this->raiseError('ERROR: downloaded channel definition file' .
+                            ' for channel "' . $channel->getName() . '" from channel "' .
+                            strtolower($c->getName()) . '"');
+                    }
+                }
+            }
+        } else {
+            if (strpos($params[0], '://')) {
+                $dl = &$this->getDownloader();
+                PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+                $loc = $dl->downloadHttp($params[0],
+                    $this->ui, $tmpdir, null, $lastmodified);
+                PEAR::staticPopErrorHandling();
+                if (PEAR::isError($loc)) {
+                    return $this->raiseError("Cannot open " . $params[0]);
+                } else {
+                    list($loc, $lastmodified) = $loc;
+                    $contents = implode('', file($loc));
+                }
+            } else {
+                $fp = @fopen($params[0], 'r');
+                if (!$fp) {
+                    return $this->raiseError("Cannot open " . $params[0]);
+                }
+                $contents = '';
+                while (!feof($fp)) {
+                    $contents .= fread($fp, 1024);
+                }
+                fclose($fp);
+            }
+            if (!class_exists('PEAR_ChannelFile')) {
+                require_once 'PEAR/ChannelFile.php';
+            }
+            $channel = new PEAR_ChannelFile;
+            $channel->fromXmlString($contents);
+        }
+        $exit = false;
+        if (count($errors = $channel->getErrors(true))) {
+            foreach ($errors as $error) {
+                $this->ui->outputData(ucfirst($error['level'] . ': ' . $error['message']));
+                if (!$exit) {
+                    $exit = $error['level'] == 'error' ? true : false;
+                }
+            }
+            if ($exit) {
+                return $this->raiseError('Invalid channel.xml file');
+            }
+        }
+        if (!$reg->channelExists($channel->getName())) {
+            return $this->raiseError('Error: Channel "' . $channel->getName() .
+                '" does not exist, use channel-add to add an entry');
+        }
+        $ret = $reg->updateChannel($channel, $lastmodified);
+        if (PEAR::isError($ret)) {
+            return $ret;
+        }
+        if (!$ret) {
+            return $this->raiseError('Updating Channel "' . $channel->getName() .
+                '" in registry failed');
+        }
+        $this->config->setChannels($reg->listChannels());
+        $this->config->writeConfigFile();
+        $this->ui->outputData('Update of Channel "' . $channel->getName() . '" succeeded');
+    }
+
+    function &getDownloader()
+    {
+        if (!class_exists('PEAR_Downloader')) {
+            require_once 'PEAR/Downloader.php';
+        }
+        $a = new PEAR_Downloader($this->ui, array(), $this->config);
+        return $a;
+    }
+
+    function doAlias($command, $options, $params)
+    {
+        $reg = &$this->config->getRegistry();
+        if (sizeof($params) == 1) {
+            return $this->raiseError('No channel alias specified');
+        }
+        if (sizeof($params) != 2) {
+            return $this->raiseError(
+                'Invalid format, correct is: channel-alias channel alias');
+        }
+        if (!$reg->channelExists($params[0], true)) {
+            if ($reg->isAlias($params[0])) {
+                $extra = ' (use "channel-alias ' . $reg->channelName($params[0]) . ' ' .
+                    strtolower($params[1]) . '")';
+            } else {
+                $extra = '';
+            }
+            return $this->raiseError('"' . $params[0] . '" is not a valid channel' . $extra);
+        }
+        if ($reg->isAlias($params[1])) {
+            return $this->raiseError('Channel "' . $reg->channelName($params[1]) . '" is ' .
+                'already aliased to "' . strtolower($params[1]) . '", cannot re-alias');
+        }
+        $chan = &$reg->getChannel($params[0]);
+        if (!$chan) {
+            return $this->raiseError('Corrupt registry?  Error retrieving channel "' . $params[0] .
+                '" information');
+        }
+        // make it a local alias
+        if (!$chan->setAlias(strtolower($params[1]), true)) {
+            return $this->raiseError('Alias "' . strtolower($params[1]) .
+                '" is not a valid channel alias');
+        }
+        $reg->updateChannel($chan);
+        $this->ui->outputData('Channel "' . $chan->getName() . '" aliased successfully to "' .
+            strtolower($params[1]) . '"');
+    }
+
+    function doDiscover($command, $options, $params)
+    {
+        $reg = &$this->config->getRegistry();
+        if (sizeof($params) != 1) {
+            return $this->raiseError("No channel server specified");
+        }
+        if ($reg->channelExists($params[0])) {
+            if ($reg->isAlias($params[0])) {
+                return $this->raiseError("A channel alias named \"$params[0]\" " .
+                    'already exists, aliasing channel "' . $reg->channelName($params[0])
+                    . '"');
+            } else {
+                return $this->raiseError("Channel \"$params[0]\" is already initialized");
+            }
+        }
+        $this->pushErrorHandling(PEAR_ERROR_RETURN);
+        $err = $this->doAdd($command, $options, array('http://' . $params[0] . '/channel.xml'));
+        $this->popErrorHandling();
+        if (PEAR::isError($err)) {
+            return $this->raiseError("Discovery of channel \"$params[0]\" failed");
+        }
+        $this->ui->outputData("Discovery of channel \"$params[0]\" succeeded", $command);
+    }
+}
+?>
diff --git a/pear/PEAR/Command/Channels.xml b/pear/PEAR/Command/Channels.xml
new file mode 100644 (file)
index 0000000..fc3739b
--- /dev/null
@@ -0,0 +1,93 @@
+<commands version="1.0">
+ <list-channels>
+  <summary>List Available Channels</summary>
+  <function>doList</function>
+  <shortcut>lc</shortcut>
+  <options />
+  <doc>
+List all available channels for installation.
+</doc>
+ </list-channels>
+ <update-channels>
+  <summary>Update the Channel List</summary>
+  <function>doUpdateAll</function>
+  <shortcut>uc</shortcut>
+  <options />
+  <doc>
+List all installed packages in all channels.
+</doc>
+ </update-channels>
+ <channel-delete>
+  <summary>Remove a Channel From the List</summary>
+  <function>doDelete</function>
+  <shortcut>cde</shortcut>
+  <options />
+  <doc>&lt;channel name&gt;
+Delete a channel from the registry.  You may not
+remove any channel that has installed packages.
+</doc>
+ </channel-delete>
+ <channel-add>
+  <summary>Add a Channel</summary>
+  <function>doAdd</function>
+  <shortcut>ca</shortcut>
+  <options />
+  <doc>&lt;channel.xml&gt;
+Add a private channel to the channel list.  Note that all
+public channels should be synced using &quot;update-channels&quot;.
+Parameter may be either a local file or remote URL to a
+channel.xml.
+</doc>
+ </channel-add>
+ <channel-update>
+  <summary>Update an Existing Channel</summary>
+  <function>doUpdate</function>
+  <shortcut>cu</shortcut>
+  <options>
+   <force>
+    <shortopt>f</shortopt>
+    <doc>will force download of new channel.xml if an existing channel name is used</doc>
+   </force>
+   <channel>
+    <shortopt>c</shortopt>
+    <arg>CHANNEL</arg>
+    <doc>will force download of new channel.xml if an existing channel name is used</doc>
+   </channel>
+  </options>
+  <doc>[&lt;channel.xml&gt;|&lt;channel name&gt;]
+Update a channel in the channel list directly.  Note that all
+public channels can be synced using &quot;update-channels&quot;.
+Parameter may be a local or remote channel.xml, or the name of
+an existing channel.
+</doc>
+ </channel-update>
+ <channel-info>
+  <summary>Retrieve Information on a Channel</summary>
+  <function>doInfo</function>
+  <shortcut>ci</shortcut>
+  <options />
+  <doc>&lt;package&gt;
+List the files in an installed package.
+</doc>
+ </channel-info>
+ <channel-alias>
+  <summary>Specify an alias to a channel name</summary>
+  <function>doAlias</function>
+  <shortcut>cha</shortcut>
+  <options />
+  <doc>&lt;channel&gt; &lt;alias&gt;
+Specify a specific alias to use for a channel name.
+The alias may not be an existing channel name or
+alias.
+</doc>
+ </channel-alias>
+ <channel-discover>
+  <summary>Initialize a Channel from its server</summary>
+  <function>doDiscover</function>
+  <shortcut>di</shortcut>
+  <options />
+  <doc>&lt;package&gt;
+List the files in an installed package.
+</doc>
+ </channel-discover>
+</commands>
\ No newline at end of file
index 50d09a2657f5175186cfa397c8ee6553629b9391..c200e80ceba7af79e39e9c0003b965406d4b521d 100644 (file)
@@ -1,25 +1,44 @@
 <?php
-//
-// +----------------------------------------------------------------------+
-// | PHP Version 5                                                        |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2004 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.php";
+/**
+ * PEAR_Command_Common base class
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 0.1
+ */
 
+/**
+ * base class
+ */
+require_once 'PEAR.php';
+
+/**
+ * PEAR commands base class
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 0.1
+ */
 class PEAR_Command_Common extends PEAR
 {
     // {{{ properties
@@ -28,9 +47,14 @@ class PEAR_Command_Common extends PEAR
      * PEAR_Config object used to pass user system and configuration
      * on when executing commands
      *
-     * @var object
+     * @var PEAR_Config
      */
     var $config;
+    /**
+     * @var PEAR_Registry
+     * @access protected
+     */
+    var $_registry;
 
     /**
      * User Interface object, for all interaction with the user.
@@ -117,6 +141,10 @@ class PEAR_Command_Common extends PEAR
 
     function getOptions($command)
     {
+        $shortcuts = $this->getShortcuts();
+        if (isset($shortcuts[$command])) {
+            $command = $shortcuts[$command];
+        }
         return @$this->commands[$command]['options'];
     }
 
@@ -127,10 +155,10 @@ class PEAR_Command_Common extends PEAR
     {
         $short_args = "";
         $long_args = array();
-        if (empty($this->commands[$command])) {
+        if (empty($this->commands[$command]) || empty($this->commands[$command]['options'])) {
             return;
         }
-        reset($this->commands[$command]);
+        reset($this->commands[$command]['options']);
         while (list($option, $info) = each($this->commands[$command]['options'])) {
             $larg = $sarg = '';
             if (isset($info['arg'])) {
index edf518fe98d2c9733f3f5a04622004b91103be72..cc3db6c4843f7da5e960b2a24a2a4490e925bf83 100644 (file)
@@ -1,31 +1,43 @@
 <?php
-//
-// +----------------------------------------------------------------------+
-// | PHP Version 5                                                        |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2004 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 Bakken <ssb@php.net>                                    |
-// |         Tomas V.V.Cox <cox@idecnet.com>                              |
-// |                                                                      |
-// +----------------------------------------------------------------------+
-//
-// $Id$
-
-require_once "PEAR/Command/Common.php";
-require_once "PEAR/Config.php";
+/**
+ * PEAR_Command_Config (config-show, config-get, config-set, config-help, config-create commands)
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 0.1
+ */
+
+/**
+ * base class
+ */
+require_once 'PEAR/Command/Common.php';
 
 /**
  * PEAR commands for managing configuration data.
  *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 0.1
  */
 class PEAR_Command_Config extends PEAR_Command_Common
 {
@@ -36,39 +48,62 @@ class PEAR_Command_Config extends PEAR_Command_Common
             'summary' => 'Show All Settings',
             'function' => 'doConfigShow',
             'shortcut' => 'csh',
-            'options' => array(),
-            'doc' => '
+            'options' => array(
+                'channel' => array(
+                    'shortopt' => 'c',
+                    'doc' => 'show configuration variables for another channel',
+                    'arg' => 'CHAN',
+                    ),
+),
+            'doc' => '[layer]
 Displays all configuration values.  An optional argument
 may be used to tell which configuration layer to display.  Valid
-configuration layers are "user", "system" and "default".
+configuration layers are "user", "system" and "default". To display
+configurations for different channels, set the default_channel
+configuration variable and run config-show again.
 ',
             ),
         'config-get' => array(
             'summary' => 'Show One Setting',
             'function' => 'doConfigGet',
             'shortcut' => 'cg',
-            'options' => array(),
+            'options' => array(
+                'channel' => array(
+                    'shortopt' => 'c',
+                    'doc' => 'show configuration variables for another channel',
+                    'arg' => 'CHAN',
+                    ),
+),
             'doc' => '<parameter> [layer]
 Displays the value of one configuration parameter.  The
 first argument is the name of the parameter, an optional second argument
 may be used to tell which configuration layer to look in.  Valid configuration
 layers are "user", "system" and "default".  If no layer is specified, a value
 will be picked from the first layer that defines the parameter, in the order
-just specified.
+just specified.  The configuration value will be retrieved for the channel
+specified by the default_channel configuration variable.
 ',
             ),
         'config-set' => array(
             'summary' => 'Change Setting',
             'function' => 'doConfigSet',
             'shortcut' => 'cs',
-            'options' => array(),
+            'options' => array(
+                'channel' => array(
+                    'shortopt' => 'c',
+                    'doc' => 'show configuration variables for another channel',
+                    'arg' => 'CHAN',
+                    ),
+),
             'doc' => '<parameter> <value> [layer]
 Sets the value of one configuration parameter.  The first argument is
 the name of the parameter, the second argument is the new value.  Some
 parameters are subject to validation, and the command will fail with
 an error message if the new value does not make sense.  An optional
 third argument may be used to specify in which layer to set the
-configuration parameter.  The default layer is "user".
+configuration parameter.  The default layer is "user".  The
+configuration value will be set for the current channel, which
+is controlled by the default_channel configuration variable.
 ',
             ),
         'config-help' => array(
@@ -81,6 +116,24 @@ Displays help for a configuration parameter.  Without arguments it
 displays help for all configuration parameters.
 ',
            ),
+        'config-create' => array(
+            'summary' => 'Create a Default configuration file',
+            'function' => 'doConfigCreate',
+            'shortcut' => 'coc',
+            'options' => array(
+                'windows' => array(
+                    'shortopt' => 'w',
+                    'doc' => 'create a config file for a windows install',
+                    ),
+            ),
+            'doc' => '<root path> <filename>
+Create a default configuration file with all directory configuration
+variables set to subdirectories of <root path>, and save it as <filename>.
+This is useful especially for creating a configuration file for a remote
+PEAR installation (using the --remoteconfig option of install, upgrade,
+and uninstall).
+',
+            ),
         );
 
     // }}}
@@ -104,14 +157,20 @@ displays help for all configuration parameters.
     {
         // $params[0] -> the layer
         if ($error = $this->_checkLayer(@$params[0])) {
-            return $this->raiseError($error);
+            return $this->raiseError("config-show:$error");
         }
         $keys = $this->config->getKeys();
         sort($keys);
-        $data = array('caption' => 'Configuration:');
+        $channel = isset($options['channel']) ? $options['channel'] :
+            $this->config->get('default_channel');
+        $reg = &$this->config->getRegistry();
+        if (!$reg->channelExists($channel)) {
+            return $this->raiseError('Channel "' . $channel . '" does not exist');
+        }
+        $data = array('caption' => 'Configuration (channel ' . $channel . '):');
         foreach ($keys as $key) {
             $type = $this->config->getType($key);
-            $value = $this->config->get($key, @$params[0]);
+            $value = $this->config->get($key, @$params[0], $channel);
             if ($type == 'password' && $value) {
                 $value = '********';
             }
@@ -122,6 +181,10 @@ displays help for all configuration parameters.
             }
             $data['data'][$this->config->getGroup($key)][] = array($this->config->getPrompt($key) , $key, $value);
         }
+        foreach ($this->config->getLayers() as $layer) {
+            $data['data']['Config Files'][] = array(ucfirst($layer) . ' Configuration File', 'Filename' , $this->config->getConfFile($layer));
+        }
+        
         $this->ui->outputData($data, $command);
         return true;
     }
@@ -134,15 +197,23 @@ displays help for all configuration parameters.
         // $params[0] -> the parameter
         // $params[1] -> the layer
         if ($error = $this->_checkLayer(@$params[1])) {
-            return $this->raiseError($error);
+            return $this->raiseError("config-get:$error");
+        }
+        $channel = isset($options['channel']) ? $options['channel'] :
+            $this->config->get('default_channel');
+        $reg = &$this->config->getRegistry();
+        if (!$reg->channelExists($channel)) {
+            return $this->raiseError('Channel "' . $channel . '" does not exist');
         }
         if (sizeof($params) < 1 || sizeof($params) > 2) {
             return $this->raiseError("config-get expects 1 or 2 parameters");
-        } elseif (sizeof($params) == 1) {
-            $this->ui->outputData($this->config->get($params[0]), $command);
         } else {
-            $data = $this->config->get($params[0], $params[1]);
-            $this->ui->outputData($data, $command);
+            if (count($params) == 1) {
+                $layer = null;
+            } else {
+                $layer = $params[1];
+            }
+            $this->ui->outputData($this->config->get($params[0], $layer, $channel), $command);
         }
         return true;
     }
@@ -162,17 +233,37 @@ displays help for all configuration parameters.
         }
         if ($error = $this->_checkLayer(@$params[2])) {
             $failmsg .= $error;
-            return PEAR::raiseError($failmsg);
+            return PEAR::raiseError("config-set:$failmsg");
+        }
+        $channel = isset($options['channel']) ? $options['channel'] :
+            $this->config->get('default_channel');
+        $reg = &$this->config->getRegistry();
+        if (!$reg->channelExists($channel)) {
+            return $this->raiseError('Channel "' . $channel . '" does not exist');
         }
+        if ($params[0] == 'default_channel') {
+            if (!$reg->channelExists($params[1])) {
+                return $this->raiseError('Channel "' . $params[1] . '" does not exist');
+            }
+        }
+        if (count($params) == 2) {
+            array_push($params, 'user');
+            $layer = 'user';
+        } else {
+            $layer = $params[2];
+        }
+        array_push($params, $channel);
         if (!call_user_func_array(array(&$this->config, 'set'), $params))
         {
-            $failmsg = "config-set (" . implode(", ", $params) . ") failed";
+            array_pop($params);
+            $failmsg = "config-set (" . implode(", ", $params) . ") failed, channel $channel";
         } else {
-            $this->config->store();
+            $this->config->store($layer);
         }
         if ($failmsg) {
             return $this->raiseError($failmsg);
         }
+        $this->ui->outputData('config-set succeeded', $command);
         return true;
     }
 
@@ -200,6 +291,91 @@ displays help for all configuration parameters.
     }
 
     // }}}
+    // {{{ doConfigCreate()
+
+    function doConfigCreate($command, $options, $params)
+    {
+        if (count($params) != 2) {
+            return PEAR::raiseError('config-create: must have 2 parameters, root path and ' .
+                'filename to save as');
+        }
+        $root = $params[0];
+        // Clean up the DIRECTORY_SEPARATOR mess
+        $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR;
+        $root = preg_replace(array('!\\\\+!', '!/+!', "!$ds2+!"),
+                             array('/', '/', '/'),
+                            $root);
+        if ($root{0} != '/') {
+            if (isset($options['windows'])) {
+                if (!preg_match('/^[A-Za-z]:/', $root)) {
+                    return PEAR::raiseError('Root directory must be an absolute path beginning ' .
+                        'with "\\" or "C:\\", was: "' . $root . '"');
+                }
+            } else {
+                return PEAR::raiseError('Root directory must be an absolute path beginning ' .
+                    'with "/", was: "' . $root . '"');
+            }
+        }
+        $windows = isset($options['windows']);
+        if ($windows) {
+            $root = str_replace('/', '\\', $root);
+        }
+        if (!file_exists($params[1])) {
+            if (!@touch($params[1])) {
+                return PEAR::raiseError('Could not create "' . $params[1] . '"');
+            }
+        }
+        $params[1] = realpath($params[1]);
+        $config = &new PEAR_Config($params[1], '#no#system#config#', false, false);
+        if ($root{strlen($root) - 1} == '/') {
+            $root = substr($root, 0, strlen($root) - 1);
+        }
+        $config->noRegistry();
+        $config->set('php_dir', $windows ? "$root\\pear\\php" : "$root/pear/php", 'user');
+        $config->set('data_dir', $windows ? "$root\\pear\\data" : "$root/pear/data");
+        $config->set('ext_dir', $windows ? "$root\\pear\\ext" : "$root/pear/ext");
+        $config->set('doc_dir', $windows ? "$root\\pear\\docs" : "$root/pear/docs");
+        $config->set('test_dir', $windows ? "$root\\pear\\tests" : "$root/pear/tests");
+        $config->set('cache_dir', $windows ? "$root\\pear\\cache" : "$root/pear/cache");
+        $config->set('bin_dir', $windows ? "$root\\pear" : "$root/pear");
+        $config->writeConfigFile();
+        $this->_showConfig($config);
+        $this->ui->outputData('Successfully created default configuration file "' . $params[1] . '"',
+            $command);
+    }
+
+    // }}}
+
+    function _showConfig(&$config)
+    {
+        $params = array('user');
+        $keys = $config->getKeys();
+        sort($keys);
+        $channel = 'pear.php.net';
+        $data = array('caption' => 'Configuration (channel ' . $channel . '):');
+        foreach ($keys as $key) {
+            $type = $config->getType($key);
+            $value = $config->get($key, 'user', $channel);
+            if ($type == 'password' && $value) {
+                $value = '********';
+            }
+            if ($value === false) {
+                $value = 'false';
+            } elseif ($value === true) {
+                $value = 'true';
+            }
+            $data['data'][$config->getGroup($key)][] =
+                array($config->getPrompt($key) , $key, $value);
+        }
+        foreach ($config->getLayers() as $layer) {
+            $data['data']['Config Files'][] =
+                array(ucfirst($layer) . ' Configuration File', 'Filename' ,
+                    $config->getConfFile($layer));
+        }
+        
+        $this->ui->outputData($data, 'config-show');
+        return true;
+    }
     // {{{ _checkLayer()
 
     /**
diff --git a/pear/PEAR/Command/Config.xml b/pear/PEAR/Command/Config.xml
new file mode 100644 (file)
index 0000000..f64a925
--- /dev/null
@@ -0,0 +1,92 @@
+<commands version="1.0">
+ <config-show>
+  <summary>Show All Settings</summary>
+  <function>doConfigShow</function>
+  <shortcut>csh</shortcut>
+  <options>
+   <channel>
+    <shortopt>c</shortopt>
+    <doc>show configuration variables for another channel</doc>
+    <arg>CHAN</arg>
+   </channel>
+  </options>
+  <doc>[layer]
+Displays all configuration values.  An optional argument
+may be used to tell which configuration layer to display.  Valid
+configuration layers are &quot;user&quot;, &quot;system&quot; and &quot;default&quot;. To display
+configurations for different channels, set the default_channel
+configuration variable and run config-show again.
+</doc>
+ </config-show>
+ <config-get>
+  <summary>Show One Setting</summary>
+  <function>doConfigGet</function>
+  <shortcut>cg</shortcut>
+  <options>
+   <channel>
+    <shortopt>c</shortopt>
+    <doc>show configuration variables for another channel</doc>
+    <arg>CHAN</arg>
+   </channel>
+  </options>
+  <doc>&lt;parameter&gt; [layer]
+Displays the value of one configuration parameter.  The
+first argument is the name of the parameter, an optional second argument
+may be used to tell which configuration layer to look in.  Valid configuration
+layers are &quot;user&quot;, &quot;system&quot; and &quot;default&quot;.  If no layer is specified, a value
+will be picked from the first layer that defines the parameter, in the order
+just specified.  The configuration value will be retrieved for the channel
+specified by the default_channel configuration variable.
+</doc>
+ </config-get>
+ <config-set>
+  <summary>Change Setting</summary>
+  <function>doConfigSet</function>
+  <shortcut>cs</shortcut>
+  <options>
+   <channel>
+    <shortopt>c</shortopt>
+    <doc>show configuration variables for another channel</doc>
+    <arg>CHAN</arg>
+   </channel>
+  </options>
+  <doc>&lt;parameter&gt; &lt;value&gt; [layer]
+Sets the value of one configuration parameter.  The first argument is
+the name of the parameter, the second argument is the new value.  Some
+parameters are subject to validation, and the command will fail with
+an error message if the new value does not make sense.  An optional
+third argument may be used to specify in which layer to set the
+configuration parameter.  The default layer is &quot;user&quot;.  The
+configuration value will be set for the current channel, which
+is controlled by the default_channel configuration variable.
+</doc>
+ </config-set>
+ <config-help>
+  <summary>Show Information About Setting</summary>
+  <function>doConfigHelp</function>
+  <shortcut>ch</shortcut>
+  <options />
+  <doc>[parameter]
+Displays help for a configuration parameter.  Without arguments it
+displays help for all configuration parameters.
+</doc>
+ </config-help>
+ <config-create>
+  <summary>Create a Default configuration file</summary>
+  <function>doConfigCreate</function>
+  <shortcut>coc</shortcut>
+  <options>
+   <windows>
+    <shortopt>w</shortopt>
+    <doc>create a config file for a windows install</doc>
+   </windows>
+  </options>
+  <doc>&lt;root path&gt; &lt;filename&gt;
+Create a default configuration file with all directory configuration
+variables set to subdirectories of &lt;root path&gt;, and save it as &lt;filename&gt;.
+This is useful especially for creating a configuration file for a remote
+PEAR installation (using the --remoteconfig option of install, upgrade,
+and uninstall).
+</doc>
+ </config-create>
+</commands>
\ No newline at end of file
index 7a89c7cddd62df5edc5ced4432fdf480cbe3ee4e..b454b65a20d3877df4362cf7c6e320928822766b 100644 (file)
@@ -1,30 +1,44 @@
 <?php
-//
-// +----------------------------------------------------------------------+
-// | PHP Version 5                                                        |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2004 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$
+/**
+ * PEAR_Command_Install (install, upgrade, upgrade-all, uninstall, bundle, run-scripts commands)
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 0.1
+ */
 
-require_once "PEAR/Command/Common.php";
-require_once "PEAR/Installer.php";
+/**
+ * base class
+ */
+require_once 'PEAR/Command/Common.php';
 
 /**
  * PEAR commands for installation or deinstallation/upgrading of
  * packages.
  *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 0.1
  */
 class PEAR_Command_Install extends PEAR_Command_Common
 {
@@ -40,6 +54,10 @@ class PEAR_Command_Install extends PEAR_Command_Common
                     'shortopt' => 'f',
                     'doc' => 'will overwrite newer installed packages',
                     ),
+                'loose' => array(
+                    'shortopt' => 'l',
+                    'doc' => 'do not check for recommended dependency version',
+                    ),
                 'nodeps' => array(
                     'shortopt' => 'n',
                     'doc' => 'ignore dependencies, install anyway',
@@ -76,8 +94,16 @@ class PEAR_Command_Install extends PEAR_Command_Common
                     'shortopt' => 'o',
                     'doc' => 'install all required dependencies',
                     ),
+                'offline' => array(
+                    'shortopt' => 'O',
+                    'doc' => 'do not attempt to download any urls or contact channels',
+                    ),
+                'pretend' => array(
+                    'shortopt' => 'p',
+                    'doc' => 'Only list the packages that would be downloaded',
+                    ),
                 ),
-            'doc' => '<package> ...
+            'doc' => '[channel/]<package> ...
 Installs one or more PEAR packages.  You can specify a package to
 install in four ways:
 
@@ -90,10 +116,17 @@ anywhere on the net.
 package.xml.  Useful for testing, or for wrapping a PEAR package in
 another package manager such as RPM.
 
-"Package" : queries your configured server
+"Package[-version/state][.tar]" : queries your default channel\'s server
 ({config master_server}) and downloads the newest package with
 the preferred quality/state ({config preferred_state}).
 
+To retrieve Package version 1.1, use "Package-1.1," to retrieve
+Package state beta, use "Package-beta."  To retrieve an uncompressed
+file, append .tar (make sure there is no file by the same name first)
+
+To download a package from another channel, prefix with the channel name like
+"channel/Package"
+
 More than one package may be specified at once.  It is ok to mix these
 four ways of specifying packages.
 '),
@@ -106,6 +139,10 @@ four ways of specifying packages.
                     'shortopt' => 'f',
                     'doc' => 'overwrite newer installed packages',
                     ),
+                'loose' => array(
+                    'shortopt' => 'l',
+                    'doc' => 'do not check for recommended dependency version',
+                    ),
                 'nodeps' => array(
                     'shortopt' => 'n',
                     'doc' => 'ignore dependencies, upgrade anyway',
@@ -138,6 +175,14 @@ four ways of specifying packages.
                     'shortopt' => 'o',
                     'doc' => 'install all required dependencies',
                     ),
+                'offline' => array(
+                    'shortopt' => 'O',
+                    'doc' => 'do not attempt to download any urls or contact channels',
+                    ),
+                'pretend' => array(
+                    'shortopt' => 'p',
+                    'doc' => 'Only list the packages that would be downloaded',
+                    ),
                 ),
             'doc' => '<package> ...
 Upgrades one or more PEAR packages.  See documentation for the
@@ -178,6 +223,9 @@ More than one package may be specified at once.
                 'ignore-errors' => array(
                     'doc' => 'force install even if there were errors',
                     ),
+                'loose' => array(
+                    'doc' => 'do not check for recommended dependency version',
+                    ),
                 ),
             'doc' => '
 Upgrades all packages that have a newer release available.  Upgrades are
@@ -206,10 +254,15 @@ more stable.
                 'ignore-errors' => array(
                     'doc' => 'force install even if there were errors',
                     ),
+                'offline' => array(
+                    'shortopt' => 'O',
+                    'doc' => 'do not attempt to uninstall remotely',
+                    ),
                 ),
-            'doc' => '<package> ...
+            'doc' => '[channel/]<package> ...
 Uninstalls one or more PEAR packages.  More than one package may be
-specified at once.
+specified at once.  Prefix with channel name to uninstall from a
+channel not in your default channel ({config default_channel})
 '),
         'bundle' => array(
             'summary' => 'Unpacks a Pecl Package',
@@ -229,6 +282,15 @@ specified at once.
             'doc' => '<package>
 Unpacks a Pecl Package into the selected location. It will download the
 package if needed.
+'),
+        'run-scripts' => array(
+            'summary' => 'Run Post-Install Scripts bundled with a package',
+            'function' => 'doRunScripts',
+            'shortcut' => 'rs',
+            'options' => array(
+            ),
+            'doc' => '<package>
+Run post-installation scripts in package <package>, if any exist.
 '),
     );
 
@@ -247,82 +309,244 @@ package if needed.
 
     // }}}
 
+    /**
+     * For unit testing purposes
+     */
+    function &getDownloader(&$ui, $options, &$config)
+    {
+        if (!class_exists('PEAR_Downloader')) {
+            require_once 'PEAR/Downloader.php';
+        }
+        $a = &new PEAR_Downloader($ui, $options, $config);
+        return $a;
+    }
+
+    /**
+     * For unit testing purposes
+     */
+    function &getInstaller(&$ui)
+    {
+        if (!class_exists('PEAR_Installer')) {
+            require_once 'PEAR/Installer.php';
+        }
+        $a = &new PEAR_Installer($ui);
+        return $a;
+    }
+
     // {{{ doInstall()
 
     function doInstall($command, $options, $params)
     {
-        require_once 'PEAR/Downloader.php';
         if (empty($this->installer)) {
-            $this->installer = &new PEAR_Installer($this->ui);
+            $this->installer = &$this->getInstaller($this->ui);
         }
         if ($command == 'upgrade') {
             $options['upgrade'] = true;
         }
+        $reg = &$this->config->getRegistry();
         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());
+            $reg = &$this->config->getRegistry();
+            $savechannel = $this->config->get('default_channel');
             $params = array();
-            foreach ($latest as $package => $info) {
-                $package = strtolower($package);
-                if (!isset($installed[$package])) {
-                    // skip packages we don't have installed
+            foreach ($reg->listChannels() as $channel) {
+                if ($channel == '__uri') {
                     continue;
                 }
-                $inst_version = $reg->packageInfo($package, 'version');
-                if (version_compare("$info[version]", "$inst_version", "le")) {
-                    // installed version is up-to-date
+                $this->config->set('default_channel', $channel);
+                $chan = &$reg->getChannel($channel);
+                if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
+                      $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
+                    $dorest = true;
+                    unset($remote);
+                } else {
+                    $dorest = false;
+                    $remote = &$this->config->getRemote($this->config);
+                }
+                $state = $this->config->get('preferred_state');
+                $installed = array_flip($reg->listPackages($channel));
+                PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+                if ($dorest) {
+                    $rest = &$this->config->getREST('1.0', array());
+                    $latest = $rest->listLatestUpgrades($base, $state, $installed, $channel, $reg);
+                } else {
+                    if (empty($state) || $state == 'any') {
+                        $latest = $remote->call("package.listLatestReleases");
+                    } else {
+                        $latest = $remote->call("package.listLatestReleases", $state);
+                    }
+                }
+                PEAR::staticPopErrorHandling();
+                if (PEAR::isError($latest) || !is_array($latest)) {
                     continue;
                 }
-                $params[] = $package;
-                $this->ui->outputData(array('data' => "Will upgrade $package"), $command);
+                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', $channel);
+                    if (version_compare("$info[version]", "$inst_version", "le")) {
+                        // installed version is up-to-date
+                        continue;
+                    }
+                    $params[] = $reg->parsedPackageNameToString(array('package' => $package,
+                        'channel' => $channel));
+                    $this->ui->outputData(array('data' => "Will upgrade $package"), $command);
+                }
             }
+            $this->config->set('default_channel', $savechannel);
         }
-        $this->downloader = &new PEAR_Downloader($this->ui, $options, $this->config);
+        $this->downloader = &$this->getDownloader($this->ui, $options, $this->config);
         $errors = array();
         $downloaded = array();
-        $this->downloader->download($params);
+        $downloaded = &$this->downloader->download($params);
         $errors = $this->downloader->getErrorMsgs();
         if (count($errors)) {
-            $err['data'] = array($errors);
+            foreach ($errors as $error) {
+                $err['data'][] = array($error);
+            }
             $err['headline'] = 'Install Errors';
             $this->ui->outputData($err);
-            return $this->raiseError("$command failed");
+            if (!count($downloaded)) {
+                return $this->raiseError("$command failed");
+            }
         }
-        $downloaded = $this->downloader->getDownloadedPackages();
-        $this->installer->sortPkgDeps($downloaded);
-        foreach ($downloaded as $pkg) {
-            PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
-            $info = $this->installer->install($pkg['file'], $options, $this->config);
-            PEAR::popErrorHandling();
+        $data = array(
+            'headline' => 'Packages that would be Installed'
+        );
+        if (isset($options['pretend'])) {
+            foreach ($downloaded as $package) {
+                $data['data'][] = array($reg->parsedPackageNameToString($package->getParsedPackage()));
+            }
+            $this->ui->outputData($data, 'pretend');
+            return true;
+        }
+        $this->installer->setOptions($options);
+        $this->installer->sortPackagesForInstall($downloaded);
+        if (PEAR::isError($err = $this->installer->setDownloadedPackages($downloaded))) {
+            $this->raiseError($err->getMessage());
+            return true;
+        }
+        $extrainfo = array();
+        foreach ($downloaded as $param) {
+            PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+            $info = $this->installer->install($param, $options);
+            PEAR::staticPopErrorHandling();
             if (PEAR::isError($info)) {
-                $this->ui->outputData('ERROR: ' .$info->getMessage());
-                continue;
+                $oldinfo = $info;
+                $pkg = &$param->getPackageFile();
+                if ($info->getCode() != PEAR_INSTALLER_NOBINARY) {
+                    if (!($info = $pkg->installBinary($this->installer))) {
+                        $this->ui->outputData('ERROR: ' .$oldinfo->getMessage());
+                        continue;
+                    }
+                    // we just installed a different package than requested,
+                    // let's change the param and info so that the rest of this works
+                    $param = $info[0];
+                    $info = $info[1];
+                }
             }
             if (is_array($info)) {
+                if ($param->getPackageType() == 'extsrc' ||
+                      $param->getPackageType() == 'extbin') {
+                    $pkg = &$param->getPackageFile();
+                    if ($instbin = $pkg->getInstalledBinary()) {
+                        $instpkg = &$reg->getPackage($instbin, $pkg->getChannel());
+                    } else {
+                        $instpkg = &$reg->getPackage($pkg->getPackage(), $pkg->getChannel());
+                    }
+                    foreach ($instpkg->getFilelist() as $name => $atts) {
+                        $pinfo = pathinfo($atts['installed_as']);
+                        if (!isset($pinfo['extension']) ||
+                              in_array($pinfo['extension'], array('c', 'h'))) {
+                            continue; // make sure we don't match php_blah.h
+                        }
+                        if ((strpos($pinfo['basename'], 'php_') === 0 &&
+                              $pinfo['extension'] == 'dll') ||
+                              // most unices
+                              $pinfo['extension'] == 'so' ||
+                              // hp-ux
+                              $pinfo['extension'] == 'sl') {
+                            $extrainfo[] = 'You should add "extension=' . $pinfo['basename']
+                                . '" to php.ini';
+                            break;
+                        }
+                    }
+                }
                 if ($this->config->get('verbose') > 0) {
-                    $label = "$info[package] $info[version]";
+                    $channel = $param->getChannel();
+                    $label = $reg->parsedPackageNameToString(
+                        array(
+                            'channel' => $channel,
+                            'package' => $param->getPackage(),
+                            'version' => $param->getVersion(),
+                        ));
                     $out = array('data' => "$command ok: $label");
                     if (isset($info['release_warnings'])) {
                         $out['release_warnings'] = $info['release_warnings'];
                     }
                     $this->ui->outputData($out, $command);
+                    if (!isset($options['register-only']) && !isset($options['offline'])) {
+                        if ($this->config->isDefinedLayer('ftp')) {
+                            PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+                            $info = $this->installer->ftpInstall($param);
+                            PEAR::staticPopErrorHandling();
+                            if (PEAR::isError($info)) {
+                                $this->ui->outputData($info->getMessage());
+                                $this->ui->outputData("remote install failed: $label");
+                            } else {
+                                $this->ui->outputData("remote install ok: $label");
+                            }
+                        }
+                    }
+                }
+                $deps = $param->getDeps();
+                if ($deps) {
+                    if (isset($deps['group'])) {
+                        $groups = $deps['group'];
+                        if (!isset($groups[0])) {
+                            $groups = array($groups);
+                        }
+                        foreach ($groups as $group) {
+                            if ($group['attribs']['name'] == 'default') {
+                                // default group is always installed, unless the user
+                                // explicitly chooses to install another group
+                                continue;
+                            }
+                            $this->ui->outputData($param->getPackage() . ': Optional feature ' .
+                                $group['attribs']['name'] . ' available (' .
+                                $group['attribs']['hint'] . ')');
+                        }
+                        $extrainfo[] = 'To install use "pear install ' .
+                            $param->getPackage() . '#featurename"';
+                    }
+                }
+                if (isset($options['installroot'])) {
+                    $reg = &$this->config->getRegistry();
+                }
+                $pkg = &$reg->getPackage($param->getPackage(), $param->getChannel());
+                $pkg->setConfig($this->config);
+                if ($list = $pkg->listPostinstallScripts()) {
+                    $pn = $reg->parsedPackageNameToString(array('channel' =>
+                        $param->getChannel(), 'package' => $param->getPackage()), true);
+                    $extrainfo[] = $pn . ' has post-install scripts:';
+                    foreach ($list as $file) {
+                        $extrainfo[] = $file;
+                    }
+                    $extrainfo[] = 'Use "pear run-scripts ' . $pn . '" to run';
+                    $extrainfo[] = 'DO NOT RUN SCRIPTS FROM UNTRUSTED SOURCES';
                 }
             } else {
                 return $this->raiseError("$command failed");
             }
         }
+        if (count($extrainfo)) {
+            foreach ($extrainfo as $info) {
+                $this->ui->outputData($info);
+            }
+        }
         return true;
     }
 
@@ -332,35 +556,111 @@ package if needed.
     function doUninstall($command, $options, $params)
     {
         if (empty($this->installer)) {
-            $this->installer = &new PEAR_Installer($this->ui);
+            $this->installer = &$this->getInstaller($this->ui);
+        }
+        if (isset($options['remoteconfig'])) {
+            $e = $this->config->readFTPConfigFile($options['remoteconfig']);
+            if (!PEAR::isError($e)) {
+                $this->installer->setConfig($this->config);
+            }
         }
         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'));
+        $reg = &$this->config->getRegistry();
         $newparams = array();
         $badparams = array();
         foreach ($params as $pkg) {
-            $info = $reg->packageInfo($pkg);
+            $channel = $this->config->get('default_channel');
+            PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+            $parsed = $reg->parsePackageName($pkg, $channel);
+            PEAR::staticPopErrorHandling();
+            if (!$parsed || PEAR::isError($parsed)) {
+                $badparams[] = $pkg;
+                continue;
+            }
+            $package = $parsed['package'];
+            $channel = $parsed['channel'];
+            $info = &$reg->getPackage($package, $channel);
+            if ($info === null &&
+                 ($channel == 'pear.php.net' || $channel == 'pecl.php.net')) {
+                // make sure this isn't a package that has flipped from pear to pecl but
+                // used a package.xml 1.0
+                $testc = ($channel == 'pear.php.net') ? 'pecl.php.net' : 'pear.php.net';
+                $info = &$reg->getPackage($package, $testc);
+                if ($info !== null) {
+                    $channel = $testc;
+                }
+            }
             if ($info === null) {
                 $badparams[] = $pkg;
             } else {
-                $newparams[] = $info;
+                $newparams[] = &$info;
+                // check for binary packages (this is an alias for those packages if so)
+                if ($installedbinary = $info->getInstalledBinary()) {
+                    $this->ui->log('adding binary package ' .
+                        $reg->parsedPackageNameToString(array('channel' => $channel,
+                            'package' => $installedbinary), true));
+                    $newparams[] = &$reg->getPackage($installedbinary, $channel);
+                }
+                // add the contents of a dependency group to the list of installed packages
+                if (isset($parsed['group'])) {
+                    $group = $info->getDependencyGroup($parsed['group']);
+                    if ($group) {
+                        $installed = &$reg->getInstalledGroup($group);
+                        if ($installed) {
+                            foreach ($installed as $i => $p) {
+                                $newparams[] = &$installed[$i];
+                            }
+                        }
+                    }
+                }
             }
         }
-        $this->installer->sortPkgDeps($newparams, true);
-        $params = array();
-        foreach($newparams as $info) {
-            $params[] = $info['info']['package'];
+        $err = $this->installer->sortPackagesForUninstall($newparams);
+        if (PEAR::isError($err)) {
+            $this->ui->outputData($err->getMessage(), $command);
+            return true;
         }
+        $params = $newparams;
+        // twist this to use it to check on whether dependent packages are also being uninstalled
+        // for circular dependencies like subpackages
+        $this->installer->setUninstallPackages($newparams);
         $params = array_merge($params, $badparams);
         foreach ($params as $pkg) {
-            if ($this->installer->uninstall($pkg, $options)) {
+            $this->installer->pushErrorHandling(PEAR_ERROR_RETURN);
+            if ($err = $this->installer->uninstall($pkg, $options)) {
+                $this->installer->popErrorHandling();
+                if (PEAR::isError($err)) {
+                    $this->ui->outputData($err->getMessage(), $command);
+                    continue;
+                }
+                $savepkg = $pkg;
                 if ($this->config->get('verbose') > 0) {
+                    if (is_object($pkg)) {
+                        $pkg = $reg->parsedPackageNameToString($pkg);
+                    }
                     $this->ui->outputData("uninstall ok: $pkg", $command);
                 }
+                if (!isset($options['offline']) && is_object($savepkg) &&
+                      defined('PEAR_REMOTEINSTALL_OK')) {
+                    if ($this->config->isDefinedLayer('ftp')) {
+                        $this->installer->pushErrorHandling(PEAR_ERROR_RETURN);
+                        $info = $this->installer->ftpUninstall($savepkg);
+                        $this->installer->popErrorHandling();
+                        if (PEAR::isError($info)) {
+                            $this->ui->outputData($info->getMessage());
+                            $this->ui->outputData("remote uninstall failed: $pkg");
+                        } else {
+                            $this->ui->outputData("remote uninstall ok: $pkg");
+                        }
+                    }
+                }
             } else {
+                $this->installer->popErrorHandling();
+                if (is_object($pkg)) {
+                    $pkg = $reg->parsedPackageNameToString($pkg);
+                }
                 return $this->raiseError("uninstall failed: $pkg");
             }
         }
@@ -379,66 +679,12 @@ package if needed.
 
     function doBundle($command, $options, $params)
     {
-        if (empty($this->installer)) {
-            $this->installer = &new PEAR_Downloader($this->ui);
-        }
-        $installer = &$this->installer;
+        $downloader = &$this->getDownloader($this->ui, array('force' => true, 'nodeps' => true,
+            'soft' => true), $this->config);
+        $reg = &$this->config->getRegistry();
         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'])) {
@@ -453,12 +699,22 @@ package if needed.
                 $dest = $pwd;
             }
         }
+        $downloader->setDownloadDir($dest);
+        $result = &$downloader->download(array($params[0]));
+        if (PEAR::isError($result)) {
+            return $result;
+        }
+        $pkgfile = &$result[0]->getPackageFile();
+        $pkgname = $pkgfile->getName();
+        $pkgversion = $pkgfile->getVersion();
+
+        // Unpacking -------------------------------------------------
         $dest .= DIRECTORY_SEPARATOR . $pkgname;
-        $orig = $pkgname . '-' . $pkginfo['version'];
+        $orig = $pkgname . '-' . $pkgversion;
 
-        $tar = new Archive_Tar($pkgfile);
+        $tar = &new Archive_Tar($pkgfile->getArchiveFile());
         if (!@$tar->extractModify($dest, $orig)) {
-            return $this->raiseError("unable to unpack $pkgfile");
+            return $this->raiseError('unable to unpack ' . $pkgfile->getArchiveFile());
         }
         $this->ui->outputData("Package ready at '$dest'");
     // }}}
@@ -466,5 +722,27 @@ package if needed.
 
     // }}}
 
+    function doRunScripts($command, $options, $params)
+    {
+        if (!isset($params[0])) {
+            return $this->raiseError('run-scripts expects 1 parameter: a package name');
+        }
+        $reg = &$this->config->getRegistry();
+        PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+        $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel'));
+        PEAR::staticPopErrorHandling();
+        if (PEAR::isError($parsed)) {
+            return $this->raiseError($parsed);
+        }
+        $package = &$reg->getPackage($parsed['package'], $parsed['channel']);
+        if (is_object($package)) {
+            $package->setConfig($this->config);
+            $package->runPostinstallScripts();
+        } else {
+            return $this->raiseError('Could not retrieve package "' . $params[0] . '" from registry');
+        }
+        $this->ui->outputData('Install scripts complete', $command);
+        return true;
+    }
 }
 ?>
diff --git a/pear/PEAR/Command/Install.xml b/pear/PEAR/Command/Install.xml
new file mode 100644 (file)
index 0000000..ccb9ecf
--- /dev/null
@@ -0,0 +1,254 @@
+<commands version="1.0">
+ <install>
+  <summary>Install Package</summary>
+  <function>doInstall</function>
+  <shortcut>i</shortcut>
+  <options>
+   <force>
+    <shortopt>f</shortopt>
+    <doc>will overwrite newer installed packages</doc>
+   </force>
+   <loose>
+    <shortopt>l</shortopt>
+    <doc>do not check for recommended dependency version</doc>
+   </loose>
+   <nodeps>
+    <shortopt>n</shortopt>
+    <doc>ignore dependencies, install anyway</doc>
+   </nodeps>
+   <register-only>
+    <shortopt>r</shortopt>
+    <doc>do not install files, only register the package as installed</doc>
+   </register-only>
+   <soft>
+    <shortopt>s</shortopt>
+    <doc>soft install, fail silently, or upgrade if already installed</doc>
+   </soft>
+   <nobuild>
+    <shortopt>B</shortopt>
+    <doc>don&apos;t build C extensions</doc>
+   </nobuild>
+   <nocompress>
+    <shortopt>Z</shortopt>
+    <doc>request uncompressed files when downloading</doc>
+   </nocompress>
+   <installroot>
+    <shortopt>R</shortopt>
+    <arg>DIR</arg>
+    <doc>root directory used when installing files (ala PHP&apos;s INSTALL_ROOT)</doc>
+   </installroot>
+   <ignore-errors>
+    <doc>force install even if there were errors</doc>
+   </ignore-errors>
+   <alldeps>
+    <shortopt>a</shortopt>
+    <doc>install all required and optional dependencies</doc>
+   </alldeps>
+   <onlyreqdeps>
+    <shortopt>o</shortopt>
+    <doc>install all required dependencies</doc>
+   </onlyreqdeps>
+   <offline>
+    <shortopt>O</shortopt>
+    <doc>do not attempt to download any urls or contact channels</doc>
+   </offline>
+   <pretend>
+    <shortopt>p</shortopt>
+    <doc>Only list the packages that would be downloaded</doc>
+   </pretend>
+  </options>
+  <doc>[channel/]&lt;package&gt; ...
+Installs one or more PEAR packages.  You can specify a package to
+install in four ways:
+
+&quot;Package-1.0.tgz&quot; : installs from a local file
+
+&quot;http://example.com/Package-1.0.tgz&quot; : installs from
+anywhere on the net.
+
+&quot;package.xml&quot; : installs the package described in
+package.xml.  Useful for testing, or for wrapping a PEAR package in
+another package manager such as RPM.
+
+&quot;Package[-version/state][.tar]&quot; : queries your default channel&apos;s server
+({config master_server}) and downloads the newest package with
+the preferred quality/state ({config preferred_state}).
+
+To retrieve Package version 1.1, use &quot;Package-1.1,&quot; to retrieve
+Package state beta, use &quot;Package-beta.&quot;  To retrieve an uncompressed
+file, append .tar (make sure there is no file by the same name first)
+
+To download a package from another channel, prefix with the channel name like
+&quot;channel/Package&quot;
+
+More than one package may be specified at once.  It is ok to mix these
+four ways of specifying packages.
+</doc>
+ </install>
+ <upgrade>
+  <summary>Upgrade Package</summary>
+  <function>doInstall</function>
+  <shortcut>up</shortcut>
+  <options>
+   <force>
+    <shortopt>f</shortopt>
+    <doc>overwrite newer installed packages</doc>
+   </force>
+   <loose>
+    <shortopt>l</shortopt>
+    <doc>do not check for recommended dependency version</doc>
+   </loose>
+   <nodeps>
+    <shortopt>n</shortopt>
+    <doc>ignore dependencies, upgrade anyway</doc>
+   </nodeps>
+   <register-only>
+    <shortopt>r</shortopt>
+    <doc>do not install files, only register the package as upgraded</doc>
+   </register-only>
+   <nobuild>
+    <shortopt>B</shortopt>
+    <doc>don&apos;t build C extensions</doc>
+   </nobuild>
+   <nocompress>
+    <shortopt>Z</shortopt>
+    <doc>request uncompressed files when downloading</doc>
+   </nocompress>
+   <installroot>
+    <shortopt>R</shortopt>
+    <arg>DIR</arg>
+    <doc>root directory used when installing files (ala PHP&apos;s INSTALL_ROOT)</doc>
+   </installroot>
+   <ignore-errors>
+    <doc>force install even if there were errors</doc>
+   </ignore-errors>
+   <alldeps>
+    <shortopt>a</shortopt>
+    <doc>install all required and optional dependencies</doc>
+   </alldeps>
+   <onlyreqdeps>
+    <shortopt>o</shortopt>
+    <doc>install all required dependencies</doc>
+   </onlyreqdeps>
+   <offline>
+    <shortopt>O</shortopt>
+    <doc>do not attempt to download any urls or contact channels</doc>
+   </offline>
+   <pretend>
+    <shortopt>p</shortopt>
+    <doc>Only list the packages that would be downloaded</doc>
+   </pretend>
+  </options>
+  <doc>&lt;package&gt; ...
+Upgrades one or more PEAR packages.  See documentation for the
+&quot;install&quot; 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.
+</doc>
+ </upgrade>
+ <upgrade-all>
+  <summary>Upgrade All Packages</summary>
+  <function>doInstall</function>
+  <shortcut>ua</shortcut>
+  <options>
+   <nodeps>
+    <shortopt>n</shortopt>
+    <doc>ignore dependencies, upgrade anyway</doc>
+   </nodeps>
+   <register-only>
+    <shortopt>r</shortopt>
+    <doc>do not install files, only register the package as upgraded</doc>
+   </register-only>
+   <nobuild>
+    <shortopt>B</shortopt>
+    <doc>don&apos;t build C extensions</doc>
+   </nobuild>
+   <nocompress>
+    <shortopt>Z</shortopt>
+    <doc>request uncompressed files when downloading</doc>
+   </nocompress>
+   <installroot>
+    <shortopt>R</shortopt>
+    <arg>DIR</arg>
+    <doc>root directory used when installing files (ala PHP&apos;s INSTALL_ROOT)</doc>
+   </installroot>
+   <ignore-errors>
+    <doc>force install even if there were errors</doc>
+   </ignore-errors>
+   <loose>
+    <doc>do not check for recommended dependency version</doc>
+   </loose>
+  </options>
+  <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
+&quot;preferred_state&quot; (currently {config preferred_state}), or a state considered
+more stable.
+</doc>
+ </upgrade-all>
+ <uninstall>
+  <summary>Un-install Package</summary>
+  <function>doUninstall</function>
+  <shortcut>un</shortcut>
+  <options>
+   <nodeps>
+    <shortopt>n</shortopt>
+    <doc>ignore dependencies, uninstall anyway</doc>
+   </nodeps>
+   <register-only>
+    <shortopt>r</shortopt>
+    <doc>do not remove files, only register the packages as not installed</doc>
+   </register-only>
+   <installroot>
+    <shortopt>R</shortopt>
+    <arg>DIR</arg>
+    <doc>root directory used when installing files (ala PHP&apos;s INSTALL_ROOT)</doc>
+   </installroot>
+   <ignore-errors>
+    <doc>force install even if there were errors</doc>
+   </ignore-errors>
+   <offline>
+    <shortopt>O</shortopt>
+    <doc>do not attempt to uninstall remotely</doc>
+   </offline>
+  </options>
+  <doc>[channel/]&lt;package&gt; ...
+Uninstalls one or more PEAR packages.  More than one package may be
+specified at once.  Prefix with channel name to uninstall from a
+channel not in your default channel ({config default_channel})
+</doc>
+ </uninstall>
+ <bundle>
+  <summary>Unpacks a Pecl Package</summary>
+  <function>doBundle</function>
+  <shortcut>bun</shortcut>
+  <options>
+   <destination>
+    <shortopt>d</shortopt>
+    <arg>DIR</arg>
+    <doc>Optional destination directory for unpacking (defaults to current path or &quot;ext&quot; if exists)</doc>
+   </destination>
+   <force>
+    <shortopt>f</shortopt>
+    <doc>Force the unpacking even if there were errors in the package</doc>
+   </force>
+  </options>
+  <doc>&lt;package&gt;
+Unpacks a Pecl Package into the selected location. It will download the
+package if needed.
+</doc>
+ </bundle>
+ <run-scripts>
+  <summary>Run Post-Install Scripts bundled with a package</summary>
+  <function>doRunScripts</function>
+  <shortcut>rs</shortcut>
+  <options />
+  <doc>&lt;package&gt;
+Run post-installation scripts in package &lt;package&gt;, if any exist.
+</doc>
+ </run-scripts>
+</commands>
\ No newline at end of file
index 267c1e83280a1f03ac9c5b47c1b22e5b853789eb..4731098bd5615d1cc8457b8665303cba950f267f 100644 (file)
@@ -1,32 +1,41 @@
 <?php
-//
-// +----------------------------------------------------------------------+
-// | PHP Version 5                                                        |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2004 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: Alexander Merz <alexmerz@php.net>                            |
-// |                                                                      |
-// +----------------------------------------------------------------------+
-//
-// $Id$
+/**
+ * PEAR_Command_Mirror (download-all command)
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Alexander Merz <alexmerz@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.2.0
+ */
 
-require_once "PEAR/Command/Common.php";
-require_once "PEAR/Command.php";
-require_once "PEAR/Remote.php";
-require_once "PEAR.php";
+/**
+ * base class
+ */
+require_once 'PEAR/Command/Common.php';
 
 /**
  * PEAR commands for providing file mirrors
  *
+ * @category   pear
+ * @package    PEAR
+ * @author     Alexander Merz <alexmerz@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.2.0
  */
 class PEAR_Command_Mirror extends PEAR_Command_Common
 {
@@ -34,13 +43,21 @@ class PEAR_Command_Mirror extends PEAR_Command_Common
 
     var $commands = array(
         'download-all' => array(
-            'summary' => 'Downloads each available package from master_server',
+            'summary' => 'Downloads each available package from the default channel',
             'function' => 'doDownloadAll',
             'shortcut' => 'da',
-            'options' => array(),
+            'options' => array(
+                'channel' =>
+                    array(
+                    'shortopt' => 'c',
+                    'doc' => 'specify a channel other than the default channel',
+                    'arg' => 'CHAN',
+                    ),
+                ),
             'doc' => '
-           Requests a list of available packages from the package server
-           (master_server) and downloads them to current working directory'
+Requests a list of available packages from the default channel ({config default_channel})
+and downloads them to current working directory.  Note: only
+packages within preferred_state ({config preferred_state}) will be downloaded'
             ),
         );
 
@@ -62,6 +79,15 @@ class PEAR_Command_Mirror extends PEAR_Command_Common
 
     // }}}
 
+    /**
+     * For unit-testing
+     */
+    function &factory($a)
+    {
+        $a = &PEAR_Command::factory($a, $this->config);
+        return $a;
+    }
+
     // {{{ doDownloadAll()
     /**
     * retrieves a list of avaible Packages from master server
@@ -76,24 +102,44 @@ class PEAR_Command_Mirror extends PEAR_Command_Common
     */
     function doDownloadAll($command, $options, $params)
     {
-        $this->config->set("php_dir", "."); 
-        $remote = &new PEAR_Remote($this->config);
-        $remoteInfo = $remote->call("package.listAll");
+        $savechannel = $this->config->get('default_channel');
+        $reg = &$this->config->getRegistry();
+        $channel = isset($options['channel']) ? $options['channel'] :
+            $this->config->get('default_channel');
+        if (!$reg->channelExists($channel)) {
+            $this->config->set('default_channel', $savechannel);
+            return $this->raiseError('Channel "' . $channel . '" does not exist');
+        }
+        $this->config->set('default_channel', $channel);
+        $this->ui->outputData('Using Channel ' . $this->config->get('default_channel'));
+        $chan = $reg->getChannel($channel);
+        if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
+              $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
+            $rest = &$this->config->getREST('1.0', array());
+            $remoteInfo = array_flip($rest->listPackages($base));
+        } else {
+            $remote = &$this->config->getRemote();
+            $stable = ($this->config->get('preferred_state') == 'stable');
+            $remoteInfo = $remote->call("package.listAll", true, $stable, false);
+        }
         if (PEAR::isError($remoteInfo)) {
             return $remoteInfo;
         }
-        $cmd = &PEAR_Command::factory("download", $this->config);
+        $cmd = &$this->factory("download");
         if (PEAR::isError($cmd)) {
             return $cmd;
         }
-        foreach ($remoteInfo as $pkgn => $pkg) {
-            /**
-             * Error handling not neccesary, because already done by 
-             * the download command
-             */
-            $cmd->run("download", array(), array($pkgn));
+        /**
+         * Error handling not necessary, because already done by 
+         * the download command
+         */
+        PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+        $err = $cmd->run('download', array('downloadonly' => true), array_keys($remoteInfo));
+        PEAR::staticPopErrorHandling();
+        $this->config->set('default_channel', $savechannel);
+        if (PEAR::isError($err)) {
+            $this->ui->outputData($err->getMessage());
         }
-
         return true;
     }
 
diff --git a/pear/PEAR/Command/Mirror.xml b/pear/PEAR/Command/Mirror.xml
new file mode 100644 (file)
index 0000000..fe8be9d
--- /dev/null
@@ -0,0 +1,18 @@
+<commands version="1.0">
+ <download-all>
+  <summary>Downloads each available package from the default channel</summary>
+  <function>doDownloadAll</function>
+  <shortcut>da</shortcut>
+  <options>
+   <channel>
+    <shortopt>c</shortopt>
+    <doc>specify a channel other than the default channel</doc>
+    <arg>CHAN</arg>
+   </channel>
+  </options>
+  <doc>
+Requests a list of available packages from the default channel ({config default_channel})
+and downloads them to current working directory.  Note: only
+packages within preferred_state ({config preferred_state}) will be downloaded</doc>
+ </download-all>
+</commands>
\ No newline at end of file
index 0923a517755520e4574d34a8a816ed5a4cf29f63..e945179407b7fab4d30c74fa980e42450d225b18 100644 (file)
@@ -1,28 +1,48 @@
 <?php
-//
-// +----------------------------------------------------------------------+
-// | PHP Version 5                                                        |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2004 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>                                   |
-// |          Martin Jansen <mj@php.net>                                  |
-// |          Greg Beaver <cellog@php.net>                                |
-// +----------------------------------------------------------------------+
-//
-// $Id$
-
-require_once 'PEAR/Common.php';
+/**
+ * PEAR_Command_Package (package, package-validate, cvsdiff, cvstag, package-dependencies,
+ * sign, makerpm, convert commands)
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Martin Jansen <mj@php.net>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 0.1
+ */
+
+/**
+ * base class
+ */
 require_once 'PEAR/Command/Common.php';
 
+/**
+ * PEAR commands for login/logout
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Martin Jansen <mj@php.net>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 0.1
+ */
+
 class PEAR_Command_Package extends PEAR_Command_Common
 {
     // {{{ properties
@@ -42,9 +62,13 @@ class PEAR_Command_Package extends PEAR_Command_Common
                     'doc' => 'Print the name of the packaged file.',
                     ),
                 ),
-            'doc' => '[descfile]
+            'doc' => '[descfile] [descfile2]
 Creates a PEAR package from its description file (usually called
-package.xml).
+package.xml).  If a second packagefile is passed in, then
+the packager will check to make sure that one is a package.xml
+version 1.0, and the other is a package.xml version 2.0.  The
+package.xml version 1.0 will be saved as "package.xml" in the archive,
+and the other as "package2.xml" in the archive"
 '
             ),
         'package-validate' => array(
@@ -144,36 +168,17 @@ of a specific release.
                     'doc' => 'Don\'t do anything, just pretend',
                     ),
                 ),
-            'doc' => '<package.xml>
+            'doc' => '<package.xml> [files...]
 Sets a CVS tag on all files in a package.  Use this command after you have
 packaged a distribution tarball with the "package" command to tag what
 revisions of what files were in that release.  If need to fix something
 after running cvstag once, but before the tarball is released to the public,
 use the "slide" option to move the release tag.
+
+to include files (such as a second package.xml, or tests not included in the
+release), pass them as additional parameters.
 ',
             ),
-        'run-tests' => array(
-            'summary' => 'Run Regression Tests',
-            'function' => 'doRunTests',
-            'shortcut' => 'rt',
-            'options' => array(
-                'recur' => array(
-                    'shortopt' => 'r',
-                    'doc' => 'Run tests in child directories, recursively.  4 dirs deep maximum',
-                ),
-                'ini' => array(
-                    'shortopt' => 'i',
-                    'doc' => 'actual string of settings to pass to php in format " -d setting=blah"',
-                    'arg' => 'SETTINGS'
-                ),
-                'realtimelog' => array(
-                    'shortopt' => 'l',
-                    'doc' => 'Log test runs/results as they are run',
-                ),
-            ),
-            'doc' => '[testfile|dir ...]
-Run regression tests with PHP\'s regression testing script (run-tests.php).',
-            ),
         'package-dependencies' => array(
             'summary' => 'Show package dependencies',
             'function' => 'doPackageDependencies',
@@ -220,6 +225,24 @@ $ rpm -bb PEAR::Net_Socket-1.0.spec
 Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
 ',
             ),
+        'convert' => array(
+            'summary' => 'Convert a package.xml 1.0 to package.xml 2.0 format',
+            'function' => 'doConvert',
+            'shortcut' => 'c2',
+            'options' => array(
+                'flat' => array(
+                    'shortopt' => 'f',
+                    'doc' => 'do not beautify the filelist.',
+                    ),
+                ),
+            'doc' => '[descfile] [descfile2]
+Converts a package.xml in 1.0 format into a package.xml
+in 2.0 format.  The new file will be named package2.xml by default,
+and package.xml will be used as the old file by default.
+This is not the most intelligent conversion, and should only be
+used for automated conversion or learning the format.
+'
+            ),
         );
 
     var $output;
@@ -259,33 +282,54 @@ Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
     }
 
     // }}}
+    function &getPackager()
+    {
+        if (!class_exists('PEAR_Packager')) {
+            require_once 'PEAR/Packager.php';
+        }
+        $a = &new PEAR_Packager;
+        return $a;
+    }
+
+    function &getPackageFile($config, $debug = false, $tmpdir = null)
+    {
+        if (!class_exists('PEAR_Common')) {
+            require_once 'PEAR/Common.php';
+        }
+        if (!class_exists('PEAR/PackageFile.php')) {
+            require_once 'PEAR/PackageFile.php';
+        }
+        $a = &new PEAR_PackageFile($config, $debug, $tmpdir);
+        $common = new PEAR_Common;
+        $common->ui = $this->ui;
+        $a->setLogger($common);
+        return $a;
+    }
     // {{{ doPackage()
 
     function doPackage($command, $options, $params)
     {
         $this->output = '';
-        include_once 'PEAR/Packager.php';
-        if (sizeof($params) < 1) {
-            $params[0] = "package.xml";
-        }
         $pkginfofile = isset($params[0]) ? $params[0] : 'package.xml';
-        $packager =& new PEAR_Packager();
-        $err = $warn = array();
-        $dir = dirname($pkginfofile);
+        $pkg2 = isset($params[1]) ? $params[1] : null;
+        if (!$pkg2 && !isset($params[0])) {
+            if (file_exists('package2.xml')) {
+                $pkg2 = 'package2.xml';
+            }
+        }
+        $packager = &$this->getPackager();
         $compress = empty($options['nocompress']) ? true : false;
-        $result = $packager->package($pkginfofile, $compress);
+        $result = $packager->package($pkginfofile, $compress, $pkg2);
         if (PEAR::isError($result)) {
-            $this->ui->outputData($this->output, $command);
             return $this->raiseError($result);
         }
         // Don't want output, only the package file name just created
         if (isset($options['showname'])) {
             $this->output = $result;
         }
-        if (PEAR::isError($result)) {
-            $this->output .= "Package failed: ".$result->getMessage();
+        if ($this->output) {
+            $this->ui->outputData($this->output, $command);
         }
-        $this->ui->outputData($this->output, $command);
         return true;
     }
 
@@ -298,22 +342,44 @@ Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
         if (sizeof($params) < 1) {
             $params[0] = "package.xml";
         }
-        $obj = new PEAR_Common;
-        $info = null;
-        if ($fp = @fopen($params[0], "r")) {
-            $test = fread($fp, 5);
-            fclose($fp);
-            if ($test == "<?xml") {
-                $info = $obj->infoFromDescriptionFile($params[0]);
-            }
-        }
-        if (empty($info)) {
-            $info = $obj->infoFromTgzFile($params[0]);
+        $obj = &$this->getPackageFile($this->config, $this->_debug);
+        $obj->rawReturn();
+        PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+        $info = $obj->fromTgzFile($params[0], PEAR_VALIDATE_NORMAL);
+        if (PEAR::isError($info)) {
+            $info = $obj->fromPackageFile($params[0], PEAR_VALIDATE_NORMAL);
+        } else {
+            $archive = $info->getArchiveFile();
+            $tar = &new Archive_Tar($archive);
+            $tar->extract(dirname($info->getPackageFile()));
+            $info->setPackageFile(dirname($info->getPackageFile()) . DIRECTORY_SEPARATOR .
+                $info->getPackage() . '-' . $info->getVersion() . DIRECTORY_SEPARATOR .
+                basename($info->getPackageFile()));
         }
+        PEAR::staticPopErrorHandling();
         if (PEAR::isError($info)) {
             return $this->raiseError($info);
         }
-        $obj->validatePackageInfo($info, $err, $warn);
+        $valid = false;
+        if ($info->getPackagexmlVersion() == '2.0') {
+            if ($valid = $info->validate(PEAR_VALIDATE_NORMAL)) {
+                $info->flattenFileList();
+                $valid = $info->validate(PEAR_VALIDATE_PACKAGING);
+            }
+        } else {
+            $valid = $info->validate(PEAR_VALIDATE_PACKAGING);
+        }
+        $err = array();
+        $warn = array();
+        if (!$valid) {
+            foreach ($info->getValidationWarnings() as $error) {
+                if ($error['level'] == 'warning') {
+                    $warn[] = $error['message'];
+                } else {
+                    $err[] = $error['message'];
+                }
+            }
+        }
         $this->_displayValidationResults($err, $warn);
         $this->ui->outputData($this->output, $command);
         return true;
@@ -330,21 +396,29 @@ Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
             $help = $this->getHelp($command);
             return $this->raiseError("$command: missing parameter: $help[0]");
         }
-        $obj = new PEAR_Common;
-        $info = $obj->infoFromDescriptionFile($params[0]);
+        $obj = &$this->getPackageFile($this->config, $this->_debug);
+        $info = $obj->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
         if (PEAR::isError($info)) {
             return $this->raiseError($info);
         }
         $err = $warn = array();
-        $obj->validatePackageInfo($info, $err, $warn);
+        if (!$info->validate()) {
+            foreach ($info->getValidationWarnings() as $error) {
+                if ($error['level'] == 'warning') {
+                    $warn[] = $error['message'];
+                } else {
+                    $err[] = $error['message'];
+                }
+            }
+        }
         if (!$this->_displayValidationResults($err, $warn, true)) {
             $this->ui->outputData($this->output, $command);
-            break;
+            return $this->raiseError('CVS tag failed');
         }
-        $version = $info['version'];
+        $version = $info->getVersion();
         $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $version);
         $cvstag = "RELEASE_$cvsversion";
-        $files = array_keys($info['filelist']);
+        $files = array_keys($info->getFilelist());
         $command = "cvs";
         if (isset($options['quiet'])) {
             $command .= ' -q';
@@ -360,6 +434,11 @@ Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
             $command .= ' -d';
         }
         $command .= ' ' . $cvstag . ' ' . escapeshellarg($params[0]);
+        array_shift($params);
+        if (count($params)) {
+            // add in additional files to be tagged
+            $files = array_merge($files, $params);
+        }
         foreach ($files as $file) {
             $command .= ' ' . escapeshellarg($file);
         }
@@ -388,12 +467,27 @@ Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
             $help = $this->getHelp($command);
             return $this->raiseError("$command: missing parameter: $help[0]");
         }
-        $obj = new PEAR_Common;
-        $info = $obj->infoFromDescriptionFile($params[0]);
+        $obj = &$this->getPackageFile($this->config, $this->_debug);
+        $info = $obj->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
         if (PEAR::isError($info)) {
             return $this->raiseError($info);
         }
-        $files = array_keys($info['filelist']);
+        $err = $warn = array();
+        if (!$info->validate()) {
+            foreach ($info->getValidationWarnings() as $error) {
+                if ($error['level'] == 'warning') {
+                    $warn[] = $error['message'];
+                } else {
+                    $err[] = $error['message'];
+                }
+            }
+        }
+        if (!$this->_displayValidationResults($err, $warn, true)) {
+            $this->ui->outputData($this->output, $command);
+            return $this->raiseError('CVS diff failed');
+        }
+        $info1 = $info->getFilelist();
+        $files = $info1;
         $cmd = "cvs";
         if (isset($options['quiet'])) {
             $cmd .= ' -q';
@@ -425,7 +519,7 @@ Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
             }
         }
         foreach ($files as $file) {
-            $cmd .= ' ' . escapeshellarg($file);
+            $cmd .= ' ' . escapeshellarg($file['name']);
         }
         if ($this->config->get('verbose') > 1) {
             $this->output .= "+ $cmd\n";
@@ -441,126 +535,6 @@ Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
         return true;
     }
 
-    // }}}
-    // {{{ doRunTests()
-
-    function doRunTests($command, $options, $params)
-    {
-        include_once 'PEAR/RunTest.php';
-        $log = new PEAR_Common;
-        $log->ui = &$this->ui; // slightly hacky, but it will work
-        $run = new PEAR_RunTest($log);
-        $tests = array();
-        if (isset($options['recur'])) {
-            $depth = 4;
-        } else {
-            $depth = 1;
-        }
-        if (!count($params)) {
-            $params[] = '.';
-        }
-        foreach ($params as $p) {
-            if (is_dir($p)) {
-                $dir = System::find(array($p, '-type', 'f',
-                                            '-maxdepth', $depth,
-                                            '-name', '*.phpt'));
-                $tests = array_merge($tests, $dir);
-            } else {
-                if (!@file_exists($p)) {
-                    if (!preg_match('/\.phpt$/', $p)) {
-                        $p .= '.phpt';
-                    }
-                    $dir = System::find(array(dirname($p), '-type', 'f',
-                                                '-maxdepth', $depth,
-                                                '-name', $p));
-                    $tests = array_merge($tests, $dir);
-                } else {
-                    $tests[] = $p;
-                }
-            }
-        }
-        $ini_settings = '';
-        if (isset($options['ini'])) {
-            $ini_settings .= $options['ini'];
-        }
-        if (isset($_ENV['TEST_PHP_INCLUDE_PATH'])) {
-            $ini_settings .= " -d include_path={$_ENV['TEST_PHP_INCLUDE_PATH']}";
-        }
-        if ($ini_settings) {
-            $this->ui->outputData('Using INI settings: "' . $ini_settings . '"');
-        }
-        $skipped = $passed = $failed = array();
-        $this->ui->outputData('Running ' . count($tests) . ' tests', $command);
-        $start = time();
-        if (isset($options['realtimelog'])) {
-            @unlink('run-tests.log');
-        }
-        foreach ($tests as $t) {
-            if (isset($options['realtimelog'])) {
-                $fp = @fopen('run-tests.log', 'a');
-                if ($fp) {
-                    fwrite($fp, "Running test $t...");
-                    fclose($fp);
-                }
-            }
-            $result = $run->run($t, $ini_settings);
-            if (OS_WINDOWS) {
-                for($i=0;$i<2000;$i++) {
-                    $i = $i; // delay - race conditions on windows
-                }
-            }
-            if (isset($options['realtimelog'])) {
-                $fp = @fopen('run-tests.log', 'a');
-                if ($fp) {
-                    fwrite($fp, "$result\n");
-                    fclose($fp);
-                }
-            }
-            if ($result == 'FAILED') {
-               $failed[] = $t;
-            }
-            if ($result == 'PASSED') {
-               $passed[] = $t;
-            }
-            if ($result == 'SKIPPED') {
-               $skipped[] = $t;
-            }
-        }
-        $total = date('i:s', time() - $start);
-        if (count($failed)) {
-            $output = "TOTAL TIME: $total\n";
-            $output .= count($passed) . " PASSED TESTS\n";
-            $output .= count($skipped) . " SKIPPED TESTS\n";
-               $output .= count($failed) . " FAILED TESTS:\n";
-               foreach ($failed as $failure) {
-                       $output .= $failure . "\n";
-               }
-            if (isset($options['realtimelog'])) {
-                $fp = @fopen('run-tests.log', 'a');
-            } else {
-                $fp = @fopen('run-tests.log', 'w');
-            }
-            if ($fp) {
-                fwrite($fp, $output, strlen($output));
-                fclose($fp);
-                $this->ui->outputData('wrote log to "' . realpath('run-tests.log') . '"', $command);
-            }
-        } elseif (@file_exists('run-tests.log') && !@is_dir('run-tests.log')) {
-            @unlink('run-tests.log');
-        }
-        $this->ui->outputData('TOTAL TIME: ' . $total);
-        $this->ui->outputData(count($passed) . ' PASSED TESTS', $command);
-        $this->ui->outputData(count($skipped) . ' SKIPPED TESTS', $command);
-        if (count($failed)) {
-               $this->ui->outputData(count($failed) . ' FAILED TESTS:', $command);
-               foreach ($failed as $failure) {
-                       $this->ui->outputData($failure, $command);
-               }
-        }
-
-        return true;
-    }
-
     // }}}
     // {{{ doPackageDependencies()
 
@@ -570,46 +544,119 @@ Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
         if (sizeof($params) != 1) {
             return $this->raiseError("bad parameter(s), try \"help $command\"");
         }
-
-        $obj = new PEAR_Common();
-        if (PEAR::isError($info = $obj->infoFromAny($params[0]))) {
+        $obj = &$this->getPackageFile($this->config, $this->_debug);
+        $info = $obj->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
+        if (PEAR::isError($info)) {
             return $this->raiseError($info);
         }
+        $deps = $info->getDeps();
+        if (is_array($deps)) {
+            if ($info->getPackagexmlVersion() == '1.0') {
+                $data = array(
+                    'caption' => 'Dependencies for pear/' . $info->getPackage(),
+                    'border' => true,
+                    'headline' => array("Required?", "Type", "Name", "Relation", "Version"),
+                    );
+
+                foreach ($deps as $d) {
+                    if (isset($d['optional'])) {
+                        if ($d['optional'] == 'yes') {
+                            $req = 'No';
+                        } else {
+                            $req = 'Yes';
+                        }
+                    } else {
+                        $req = 'Yes';
+                    }
+                    if (isset($this->_deps_rel_trans[$d['rel']])) {
+                        $rel = $this->_deps_rel_trans[$d['rel']];
+                    } else {
+                        $rel = $d['rel'];
+                    }
 
-        if (is_array($info['release_deps'])) {
-            $data = array(
-                'caption' => 'Dependencies for ' . $info['package'],
-                'border' => true,
-                'headline' => array("Type", "Name", "Relation", "Version"),
-                );
-
-            foreach ($info['release_deps'] as $d) {
+                    if (isset($this->_deps_type_trans[$d['type']])) {
+                        $type = ucfirst($this->_deps_type_trans[$d['type']]);
+                    } else {
+                        $type = $d['type'];
+                    }
 
-                if (isset($this->_deps_rel_trans[$d['rel']])) {
-                    $rel = $this->_deps_rel_trans[$d['rel']];
-                } else {
-                    $rel = $d['rel'];
-                }
+                    if (isset($d['name'])) {
+                        $name = $d['name'];
+                    } else {
+                        $name = '';
+                    }
 
-                if (isset($this->_deps_type_trans[$d['type']])) {
-                    $type = ucfirst($this->_deps_type_trans[$d['type']]);
-                } else {
-                    $type = $d['type'];
-                }
+                    if (isset($d['version'])) {
+                        $version = $d['version'];
+                    } else {
+                        $version = '';
+                    }
 
-                if (isset($d['name'])) {
-                    $name = $d['name'];
-                } else {
-                    $name = '';
+                    $data['data'][] = array($req, $type, $name, $rel, $version);
                 }
-
-                if (isset($d['version'])) {
-                    $version = $d['version'];
-                } else {
-                    $version = '';
+            } else { // package.xml 2.0 dependencies display
+                require_once 'PEAR/Dependency2.php';
+                $deps = $info->getDependencies();
+                $reg = &$this->config->getRegistry();
+                if (is_array($deps)) {
+                    $d = new PEAR_Dependency2($this->config, array(), '');
+                    $data = array(
+                        'caption' => 'Dependencies for ' . $info->getPackage(),
+                        'border' => true,
+                        'headline' => array("Required?", "Type", "Name", 'Versioning', 'Group'),
+                        );
+                    foreach ($deps as $type => $subd) {
+                        $req = ($type == 'required') ? 'Yes' : 'No';
+                        if ($type == 'group') {
+                            $group = $subd['attribs']['name'];
+                        } else {
+                            $group = '';
+                        }
+                        if (!isset($subd[0])) {
+                            $subd = array($subd);
+                        }
+                        foreach ($subd as $groupa) {
+                            foreach ($groupa as $deptype => $depinfo) {
+                                if ($deptype == 'attribs') {
+                                    continue;
+                                }
+                                if ($deptype == 'pearinstaller') {
+                                    $deptype = 'pear Installer';
+                                }
+                                if (!isset($depinfo[0])) {
+                                    $depinfo = array($depinfo);
+                                }
+                                foreach ($depinfo as $inf) {
+                                    $name = '';
+                                    if (isset($inf['channel'])) {
+                                        $alias = $reg->channelAlias($inf['channel']);
+                                        if (!$alias) {
+                                            $alias = '(channel?) ' .$inf['channel'];
+                                        }
+                                        $name = $alias . '/';
+                                    }
+                                    if (isset($inf['name'])) {
+                                        $name .= $inf['name'];
+                                    } elseif (isset($inf['pattern'])) {
+                                        $name .= $inf['pattern'];
+                                    } else {
+                                        $name .= '';
+                                    }
+                                    if (isset($inf['uri'])) {
+                                        $name .= ' [' . $inf['uri'] .  ']';
+                                    }
+                                    if (isset($inf['conflicts'])) {
+                                        $ver = 'conflicts';
+                                    } else {
+                                        $ver = $d->_getExtraString($inf);
+                                    }
+                                    $data['data'][] = array($req, ucfirst($deptype), $name,
+                                        $ver, $group);
+                                }
+                            }
+                        }
+                    }
                 }
-
-                $data['data'][] = array($type, $name, $rel, $version);
             }
 
             $this->ui->outputData($data, $command);
@@ -625,6 +672,8 @@ Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
 
     function doSign($command, $options, $params)
     {
+        require_once 'System.php';
+        require_once 'Archive/Tar.php';
         // should move most of this code into PEAR_Packager
         // so it'll be easy to implement "pear package --sign"
         if (sizeof($params) != 1) {
@@ -633,30 +682,34 @@ Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
         if (!file_exists($params[0])) {
             return $this->raiseError("file does not exist: $params[0]");
         }
-        $obj = new PEAR_Common;
-        $info = $obj->infoFromTgzFile($params[0]);
+        $obj = $this->getPackageFile($this->config, $this->_debug);
+        $info = $obj->fromTgzFile($params[0], PEAR_VALIDATE_NORMAL);
         if (PEAR::isError($info)) {
             return $this->raiseError($info);
         }
-        include_once "Archive/Tar.php";
-        include_once "System.php";
         $tar = new Archive_Tar($params[0]);
         $tmpdir = System::mktemp('-d pearsign');
-        if (!$tar->extractList('package.xml package.sig', $tmpdir)) {
-            return $this->raiseError("failed to extract tar file");
+        if (!$tar->extractList('package2.xml package.sig', $tmpdir)) {
+            if (!$tar->extractList('package.xml package.sig', $tmpdir)) {
+                return $this->raiseError("failed to extract tar file");
+            }
         }
         if (file_exists("$tmpdir/package.sig")) {
             return $this->raiseError("package already signed");
         }
+        $packagexml = 'package.xml';
+        if (file_exists("$tmpdir/package2.xml")) {
+            $packagexml = 'package2.xml';
+        }
         @unlink("$tmpdir/package.sig");
         $input = $this->ui->userDialog($command,
                                        array('GnuPG Passphrase'),
                                        array('password'));
-        $gpg = popen("gpg --batch --passphrase-fd 0 --armor --detach-sign --output $tmpdir/package.sig $tmpdir/package.xml 2>/dev/null", "w");
+        $gpg = popen("gpg --batch --passphrase-fd 0 --armor --detach-sign --output $tmpdir/package.sig $tmpdir/$packagexml 2>/dev/null", "w");
         if (!$gpg) {
             return $this->raiseError("gpg command failed");
         }
-        fwrite($gpg, "$input[0]\r");
+        fwrite($gpg, "$input[0]\n");
         if (pclose($gpg) || !file_exists("$tmpdir/package.sig")) {
             return $this->raiseError("gpg sign failed");
         }
@@ -665,6 +718,19 @@ Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
     }
 
     // }}}
+
+    /**
+     * For unit testing purposes
+     */
+    function &getInstaller(&$ui)
+    {
+        if (!class_exists('PEAR_Installer')) {
+            require_once 'PEAR/Installer.php';
+        }
+        $a = &new PEAR_Installer($ui);
+        return $a;
+    }
+
     // {{{ doMakeRPM()
 
     /*
@@ -672,118 +738,131 @@ Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
     (cox)
 
     TODO:
-
         - Fill the rpm dependencies in the template file.
 
     IDEAS:
-
         - Instead of mapping the role to rpm vars, perhaps it's better
-
           to use directly the pear cmd to install the files by itself
-
           in %postrun so:
-
           pear -d php_dir=%{_libdir}/php/pear -d test_dir=.. <package>
-
     */
 
     function doMakeRPM($command, $options, $params)
     {
+        require_once 'System.php';
+        require_once 'Archive/Tar.php';
         if (sizeof($params) != 1) {
             return $this->raiseError("bad parameter(s), try \"help $command\"");
         }
         if (!file_exists($params[0])) {
             return $this->raiseError("file does not exist: $params[0]");
         }
-        include_once "Archive/Tar.php";
-        include_once "PEAR/Installer.php";
-        include_once "System.php";
-        $tar = new Archive_Tar($params[0]);
-        $tmpdir = System::mktemp('-d pear2rpm');
-        $instroot = System::mktemp('-d pear2rpm');
+        $reg = &$this->config->getRegistry();
+        $pkg = &$this->getPackageFile($this->config, $this->_debug);
+        $pf = &$pkg->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
+        if (PEAR::isError($pf)) {
+            $u = $pf->getUserinfo();
+            if (is_array($u)) {
+                foreach ($u as $err) {
+                    if (is_array($err)) {
+                        $err = $err['message'];
+                    }
+                    $this->ui->outputData($err);
+                }
+            }
+            return $this->raiseError("$params[0] is not a valid package");
+        }
+        $tmpdir = System::mktemp(array('-d', 'pear2rpm'));
+        $instroot = System::mktemp(array('-d', 'pear2rpm'));
         $tmp = $this->config->get('verbose');
         $this->config->set('verbose', 0);
-        $installer = new PEAR_Installer($this->ui);
+        $installer = $this->getInstaller($this->ui);
+        require_once 'PEAR/Downloader/Package.php';
+        $pack = new PEAR_Downloader_Package($installer);
+        $pack->setPackageFile($pf);
+        $params[0] = &$pack;
+        $installer->setOptions(array('installroot' => $instroot,
+                                          'nodeps' => true, 'soft' => true));
+        $installer->setDownloadedPackages($params);
         $info = $installer->install($params[0],
                                     array('installroot' => $instroot,
-                                          'nodeps' => true));
-        $pkgdir = "$info[package]-$info[version]";
+                                          'nodeps' => true, 'soft' => true));
+        $pkgdir = $pf->getPackage() . '-' . $pf->getVersion();
         $info['rpm_xml_dir'] = '/var/lib/pear';
         $this->config->set('verbose', $tmp);
-        if (!$tar->extractList("package.xml", $tmpdir, $pkgdir)) {
-            return $this->raiseError("failed to extract $params[0]");
-        }
-        if (!file_exists("$tmpdir/package.xml")) {
-            return $this->raiseError("no package.xml found in $params[0]");
-        }
         if (isset($options['spec-template'])) {
             $spec_template = $options['spec-template'];
         } else {
-            $spec_template = $this->config->get('data_dir') .
-                '/PEAR/template.spec';
+            $spec_template = '@DATA-DIR@/PEAR/template.spec';
         }
+        $info['possible_channel'] = '';
+        $info['extra_config'] = '';
         if (isset($options['rpm-pkgname'])) {
             $rpm_pkgname_format = $options['rpm-pkgname'];
         } else {
-            $rpm_pkgname_format = "PEAR::%s";
+            if ($pf->getChannel() == 'pear.php.net' || $pf->getChannel() == 'pecl.php.net') {
+                $alias = 'PEAR';
+            } else {
+                $chan = &$reg->getChannel($pf->getChannel());
+                $alias = $chan->getAlias();
+                $alias = strtoupper($alias);
+                $info['possible_channel'] = $pf->getChannel() . '/';
+            }
+            $rpm_pkgname_format = $alias . '::%s';
         }
 
         $info['extra_headers'] = '';
         $info['doc_files'] = '';
         $info['files'] = '';
-        $info['rpm_package'] = sprintf($rpm_pkgname_format, $info['package']);
+        $info['package2xml'] = '';
+        $info['rpm_package'] = sprintf($rpm_pkgname_format, $pf->getPackage());
         $srcfiles = 0;
         foreach ($info['filelist'] as $name => $attr) {
-
             if (!isset($attr['role'])) {
                 continue;
             }
             $name = preg_replace('![/:\\\\]!', '/', $name);
             if ($attr['role'] == 'doc') {
                 $info['doc_files'] .= " $name";
-
             // Map role to the rpm vars
             } else {
-
                 $c_prefix = '%{_libdir}/php/pear';
-
                 switch ($attr['role']) {
-
                     case 'php':
-
-                        $prefix = $c_prefix; break;
-
+                        $prefix = $c_prefix;
+                    break;
                     case 'ext':
-
-                        $prefix = '%{_libdir}/php'; break; // XXX good place?
-
+                        $prefix = '%{_libdir}/php';
+                    break; // XXX good place?
                     case 'src':
-
                         $srcfiles++;
-
-                        $prefix = '%{_includedir}/php'; break; // XXX good place?
-
+                        $prefix = '%{_includedir}/php';
+                    break; // XXX good place?
                     case 'test':
-
-                        $prefix = "$c_prefix/tests/" . $info['package']; break;
-
+                        $prefix = "$c_prefix/tests/" . $pf->getPackage();
+                    break;
                     case 'data':
-
-                        $prefix = "$c_prefix/data/" . $info['package']; break;
-
+                        $prefix = "$c_prefix/data/" . $pf->getPackage();
+                    break;
                     case 'script':
-
-                        $prefix = '%{_bindir}'; break;
-
+                        $prefix = '%{_bindir}';
+                    break;
+                    default: // non-standard roles
+                        $prefix = "$c_prefix/$attr[role]/" . $pf->getPackage();
+                        $info['extra_config'] .=
+                        "\n        -d {$attr[role]}_dir=$c_prefix/{$attr[role]} \\";
+                        $this->ui->outputData('WARNING: role "' . $attr['role'] . '" used, ' .
+                            'and will be installed in "' . $c_prefix . '/' . $attr['role'] .
+                            '/' . $pf->getPackage() .
+                            ' - hand-edit the final .spec if this is wrong', $command);
+                    break;
                 }
-
                 $name = str_replace('\\', '/', $name);
                 $info['files'] .= "$prefix/$name\n";
-
             }
         }
         if ($srcfiles > 0) {
-            include_once "OS/Guess.php";
+            require_once 'OS/Guess.php';
             $os = new OS_Guess;
             $arch = $os->getCpu();
         } else {
@@ -792,6 +871,11 @@ Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
         $cfg = array('master_server', 'php_dir', 'ext_dir', 'doc_dir',
                      'bin_dir', 'data_dir', 'test_dir');
         foreach ($cfg as $k) {
+            if ($k == 'master_server') {
+                $chan = $reg->getChannel($pf->getChannel());
+                $info[$k] = $chan->getServer();
+                continue;
+            }
             $info[$k] = $this->config->get($k);
         }
         $info['arch'] = $arch;
@@ -799,8 +883,194 @@ Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
         if (!$fp) {
             return $this->raiseError("could not open RPM spec file template $spec_template: $php_errormsg");
         }
-        $spec_contents = preg_replace('/@([a-z0-9_-]+)@/e', '$info["\1"]', fread($fp, filesize($spec_template)));
-        fclose($fp);
+        $info['package'] = $pf->getPackage();
+        $info['version'] = $pf->getVersion();
+        $info['release_license'] = $pf->getLicense();
+        if ($pf->getDeps()) {
+            if ($pf->getPackagexmlVersion() == '1.0') {
+                $requires = $conflicts = array();
+                foreach ($pf->getDeps() as $dep) {
+                    if (isset($dep['optional']) && $dep['optional'] == 'yes') {
+                        continue;
+                    }
+                    if ($dep['type'] != 'pkg') {
+                        continue;
+                    }
+                    if (isset($dep['channel']) && $dep['channel'] != 'pear.php.net' &&
+                          $dep['channel'] != 'pecl.php.net') {
+                        $chan = &$reg->getChannel($dep['channel']);
+                        $package = strtoupper($chan->getAlias()) . '::' . $dep['name'];
+                    } else {
+                        $package = 'PEAR::' . $dep['name'];
+                    }
+                    $trans = array(
+                        '>' => '>',
+                        '<' => '<',
+                        '>=' => '>=',
+                        '<=' => '<=',
+                        '=' => '=',
+                        'gt' => '>',
+                        'lt' => '<',
+                        'ge' => '>=',
+                        'le' => '<=',
+                        'eq' => '=',
+                    );
+                    if ($dep['rel'] == 'has') {
+                        $requires[] = $package;
+                    } elseif ($dep['rel'] == 'not') {
+                        $conflicts[] = $package;
+                    } elseif ($dep['rel'] == 'ne') {
+                        $conflicts[] = $package . ' = ' . $dep['version'];
+                    } elseif (isset($trans[$dep['rel']])) {
+                        $requires[] = $package . ' ' . $trans[$dep['rel']] . ' ' . $dep['version'];
+                    }
+                }
+                if (count($requires)) {
+                    $info['extra_headers'] .= 'Requires: ' . implode(', ', $requires) . "\n";
+                }
+                if (count($conflicts)) {
+                    $info['extra_headers'] .= 'Conflicts: ' . implode(', ', $conflicts) . "\n";
+                }
+            } else {
+                $info['package2xml'] = '2'; // tell the spec to use package2.xml
+                $requires = $conflicts = array();
+                $deps = $pf->getDeps(true);
+                if (isset($deps['required']['package'])) {
+                    if (!isset($deps['required']['package'][0])) {
+                        $deps['required']['package'] = array($deps['required']['package']);
+                    }
+                    foreach ($deps['required']['package'] as $dep) {
+                        if ($dep['channel'] != 'pear.php.net' &&  $dep['channel'] != 'pecl.php.net') {
+                            $chan = &$reg->getChannel($dep['channel']);
+                            $package = strtoupper($chan->getAlias()) . '::' . $dep['name'];
+                        } else {
+                            $package = 'PEAR::' . $dep['name'];
+                        }
+                        if (isset($dep['conflicts']) && (isset($dep['min']) ||
+                              isset($dep['max']))) {
+                            $deprange = array();
+                            if (isset($dep['min'])) {
+                                $deprange[] = array($dep['min'],'>=');
+                            }
+                            if (isset($dep['max'])) {
+                                $deprange[] = array($dep['max'], '<=');
+                            }
+                            if (isset($dep['exclude'])) {
+                                if (!is_array($dep['exclude']) ||
+                                      !isset($dep['exclude'][0])) {
+                                    $dep['exclude'] = array($dep['exclude']);
+                                }
+                                if (count($deprange)) {
+                                    $excl = $dep['exclude'];
+                                    // change >= to > if excluding the min version
+                                    // change <= to < if excluding the max version
+                                    for($i = 0; $i < count($excl); $i++) {
+                                        if (isset($deprange[0]) &&
+                                              $excl[$i] == $deprange[0][0]) {
+                                            $deprange[0][1] = '<';
+                                            unset($dep['exclude'][$i]);
+                                        }
+                                        if (isset($deprange[1]) &&
+                                              $excl[$i] == $deprange[1][0]) {
+                                            $deprange[1][1] = '>';
+                                            unset($dep['exclude'][$i]);
+                                        }
+                                    }
+                                }
+                                if (count($dep['exclude'])) {
+                                    $dep['exclude'] = array_values($dep['exclude']);
+                                    $newdeprange = array();
+                                    // remove excludes that are outside the existing range
+                                    for ($i = 0; $i < count($dep['exclude']); $i++) {
+                                        if ($dep['exclude'][$i] < $dep['min'] ||
+                                              $dep['exclude'][$i] > $dep['max']) {
+                                            unset($dep['exclude'][$i]);
+                                        }
+                                    }
+                                    $dep['exclude'] = array_values($dep['exclude']);
+                                    usort($dep['exclude'], 'version_compare');
+                                    // take the remaining excludes and
+                                    // split the dependency into sub-ranges
+                                    $lastmin = $deprange[0];
+                                    for ($i = 0; $i < count($dep['exclude']) - 1; $i++) {
+                                        $newdeprange[] = '(' .
+                                            $package . " {$lastmin[1]} {$lastmin[0]} and " .
+                                            $package . ' < ' . $dep['exclude'][$i] . ')';
+                                        $lastmin = array($dep['exclude'][$i], '>');
+                                    }
+                                    if (isset($dep['max'])) {
+                                        $newdeprange[] = '(' . $package .
+                                            " {$lastmin[1]} {$lastmin[0]} and " .
+                                            $package . ' < ' . $dep['max'] . ')';
+                                    }
+                                    $conflicts[] = implode(' or ', $deprange);
+                                } else {
+                                    $conflicts[] = $package .
+                                        " {$deprange[0][1]} {$deprange[0][0]}" .
+                                        (isset($deprange[1]) ? 
+                                        " and $package {$deprange[1][1]} {$deprange[1][0]}"
+                                        : '');
+                                }
+                            }
+                            continue;
+                        }
+                        if (!isset($dep['min']) && !isset($dep['max']) &&
+                              !isset($dep['exclude'])) {
+                            if (isset($dep['conflicts'])) {
+                                $conflicts[] = $package;
+                            } else {
+                                $requires[] = $package;
+                            }
+                        } else {
+                            if (isset($dep['min'])) {
+                                $requires[] = $package . ' >= ' . $dep['min'];
+                            }
+                            if (isset($dep['max'])) {
+                                $requires[] = $package . ' <= ' . $dep['max'];
+                            }
+                            if (isset($dep['exclude'])) {
+                                $ex = $dep['exclude'];
+                                if (!is_array($ex)) {
+                                    $ex = array($ex);
+                                }
+                                foreach ($ex as $ver) {
+                                    $conflicts[] = $package . ' = ' . $ver;
+                                }
+                            }
+                        }
+                    }
+                    require_once 'Archive/Tar.php';
+                    $tar = new Archive_Tar($pf->getArchiveFile());
+                    $tar->pushErrorHandling(PEAR_ERROR_RETURN);
+                    $a = $tar->extractInString('package2.xml');
+                    $tar->popErrorHandling();
+                    if ($a === null || PEAR::isError($a)) {
+                        $info['package2xml'] = '';
+                        // this doesn't have a package.xml version 1.0
+                        $requires[] = 'PEAR::PEAR >= ' .
+                            $deps['required']['pearinstaller']['min'];
+                    }
+                    if (count($requires)) {
+                        $info['extra_headers'] .= 'Requires: ' . implode(', ', $requires) . "\n";
+                    }
+                    if (count($conflicts)) {
+                        $info['extra_headers'] .= 'Conflicts: ' . implode(', ', $conflicts) . "\n";
+                    }
+                }
+            }
+        }
+
+        // remove the trailing newline
+        $info['extra_headers'] = trim($info['extra_headers']);
+        if (function_exists('file_get_contents')) {
+            fclose($fp);
+            $spec_contents = preg_replace('/@([a-z0-9_-]+)@/e', '$info["\1"]',
+                file_get_contents($spec_template));
+        } else {
+            $spec_contents = preg_replace('/@([a-z0-9_-]+)@/e', '$info["\1"]',
+                fread($fp, filesize($spec_template)));
+            fclose($fp);
+        }
         $spec_file = "$info[rpm_package]-$info[version].spec";
         $wp = fopen($spec_file, "wb");
         if (!$wp) {
@@ -813,6 +1083,50 @@ Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
         return true;
     }
 
+    function doConvert($command, $options, $params)
+    {
+        $packagexml = isset($params[0]) ? $params[0] : 'package.xml';
+        $newpackagexml = isset($params[1]) ? $params[1] : dirname($packagexml) .
+            DIRECTORY_SEPARATOR . 'package2.xml';
+        $pkg = &$this->getPackageFile($this->config, $this->_debug);
+        PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+        $pf = $pkg->fromPackageFile($packagexml, PEAR_VALIDATE_NORMAL);
+        PEAR::staticPopErrorHandling();
+        if (!PEAR::isError($pf)) {
+            if (is_a($pf, 'PEAR_PackageFile_v2')) {
+                $this->ui->outputData($packagexml . ' is already a package.xml version 2.0');
+                return true;
+            }
+            $gen = &$pf->getDefaultGenerator();
+            $newpf = &$gen->toV2();
+            $newpf->setPackagefile($newpackagexml);
+            $gen = &$newpf->getDefaultGenerator();
+            PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+            $state = (isset($options['flat']) ? PEAR_VALIDATE_PACKAGING : PEAR_VALIDATE_NORMAL);
+            $saved = $gen->toPackageFile(dirname($newpackagexml), $state,
+                basename($newpackagexml));
+            PEAR::staticPopErrorHandling();
+            if (PEAR::isError($saved)) {
+                if (is_array($saved->getUserInfo())) {
+                    foreach ($saved->getUserInfo() as $warning) {
+                        $this->ui->outputData($warning['message']);
+                    }
+                }
+                $this->ui->outputData($saved->getMessage());
+                return true;
+            }
+            $this->ui->outputData('Wrote new version 2.0 package.xml to "' . $saved . '"');
+            return true;
+        } else {
+            if (is_array($pf->getUserInfo())) {
+                foreach ($pf->getUserInfo() as $warning) {
+                    $this->ui->outputData($warning['message']);
+                }
+            }
+            return $this->raiseError($pf);
+        }
+    }
+
     // }}}
 }
 
diff --git a/pear/PEAR/Command/Package.xml b/pear/PEAR/Command/Package.xml
new file mode 100644 (file)
index 0000000..69bc626
--- /dev/null
@@ -0,0 +1,194 @@
+<commands version="1.0">
+ <package>
+  <summary>Build Package</summary>
+  <function>doPackage</function>
+  <shortcut>p</shortcut>
+  <options>
+   <nocompress>
+    <shortopt>Z</shortopt>
+    <doc>Do not gzip the package file</doc>
+   </nocompress>
+   <showname>
+    <shortopt>n</shortopt>
+    <doc>Print the name of the packaged file.</doc>
+   </showname>
+  </options>
+  <doc>[descfile] [descfile2]
+Creates a PEAR package from its description file (usually called
+package.xml).  If a second packagefile is passed in, then
+the packager will check to make sure that one is a package.xml
+version 1.0, and the other is a package.xml version 2.0.  The
+package.xml version 1.0 will be saved as &quot;package.xml&quot; in the archive,
+and the other as &quot;package2.xml&quot; in the archive&quot;
+</doc>
+ </package>
+ <package-validate>
+  <summary>Validate Package Consistency</summary>
+  <function>doPackageValidate</function>
+  <shortcut>pv</shortcut>
+  <options />
+  <doc>
+</doc>
+ </package-validate>
+ <cvsdiff>
+  <summary>Run a &quot;cvs diff&quot; for all files in a package</summary>
+  <function>doCvsDiff</function>
+  <shortcut>cd</shortcut>
+  <options>
+   <quiet>
+    <shortopt>q</shortopt>
+    <doc>Be quiet</doc>
+   </quiet>
+   <reallyquiet>
+    <shortopt>Q</shortopt>
+    <doc>Be really quiet</doc>
+   </reallyquiet>
+   <date>
+    <shortopt>D</shortopt>
+    <doc>Diff against revision of DATE</doc>
+    <arg>DATE</arg>
+   </date>
+   <release>
+    <shortopt>R</shortopt>
+    <doc>Diff against tag for package release REL</doc>
+    <arg>REL</arg>
+   </release>
+   <revision>
+    <shortopt>r</shortopt>
+    <doc>Diff against revision REV</doc>
+    <arg>REV</arg>
+   </revision>
+   <context>
+    <shortopt>c</shortopt>
+    <doc>Generate context diff</doc>
+   </context>
+   <unified>
+    <shortopt>u</shortopt>
+    <doc>Generate unified diff</doc>
+   </unified>
+   <ignore-case>
+    <shortopt>i</shortopt>
+    <doc>Ignore case, consider upper- and lower-case letters equivalent</doc>
+   </ignore-case>
+   <ignore-whitespace>
+    <shortopt>b</shortopt>
+    <doc>Ignore changes in amount of white space</doc>
+   </ignore-whitespace>
+   <ignore-blank-lines>
+    <shortopt>B</shortopt>
+    <doc>Ignore changes that insert or delete blank lines</doc>
+   </ignore-blank-lines>
+   <brief>
+    <doc>Report only whether the files differ, no details</doc>
+   </brief>
+   <dry-run>
+    <shortopt>n</shortopt>
+    <doc>Don&apos;t do anything, just pretend</doc>
+   </dry-run>
+  </options>
+  <doc>&lt;package.xml&gt;
+Compares all the files in a package.  Without any options, this
+command will compare the current code with the last checked-in code.
+Using the -r or -R option you may compare the current code with that
+of a specific release.
+</doc>
+ </cvsdiff>
+ <cvstag>
+  <summary>Set CVS Release Tag</summary>
+  <function>doCvsTag</function>
+  <shortcut>ct</shortcut>
+  <options>
+   <quiet>
+    <shortopt>q</shortopt>
+    <doc>Be quiet</doc>
+   </quiet>
+   <reallyquiet>
+    <shortopt>Q</shortopt>
+    <doc>Be really quiet</doc>
+   </reallyquiet>
+   <slide>
+    <shortopt>F</shortopt>
+    <doc>Move (slide) tag if it exists</doc>
+   </slide>
+   <delete>
+    <shortopt>d</shortopt>
+    <doc>Remove tag</doc>
+   </delete>
+   <dry-run>
+    <shortopt>n</shortopt>
+    <doc>Don&apos;t do anything, just pretend</doc>
+   </dry-run>
+  </options>
+  <doc>&lt;package.xml&gt;
+Sets a CVS tag on all files in a package.  Use this command after you have
+packaged a distribution tarball with the &quot;package&quot; command to tag what
+revisions of what files were in that release.  If need to fix something
+after running cvstag once, but before the tarball is released to the public,
+use the &quot;slide&quot; option to move the release tag.
+</doc>
+ </cvstag>
+ <package-dependencies>
+  <summary>Show package dependencies</summary>
+  <function>doPackageDependencies</function>
+  <shortcut>pd</shortcut>
+  <options />
+  <doc>
+List all depencies the package has.</doc>
+ </package-dependencies>
+ <sign>
+  <summary>Sign a package distribution file</summary>
+  <function>doSign</function>
+  <shortcut>si</shortcut>
+  <options />
+  <doc>&lt;package-file&gt;
+Signs a package distribution (.tar or .tgz) file with GnuPG.</doc>
+ </sign>
+ <makerpm>
+  <summary>Builds an RPM spec file from a PEAR package</summary>
+  <function>doMakeRPM</function>
+  <shortcut>rpm</shortcut>
+  <options>
+   <spec-template>
+    <shortopt>t</shortopt>
+    <arg>FILE</arg>
+    <doc>Use FILE as RPM spec file template</doc>
+   </spec-template>
+   <rpm-pkgname>
+    <shortopt>p</shortopt>
+    <arg>FORMAT</arg>
+    <doc>Use FORMAT as format string for RPM package name, %s is replaced
+by the PEAR package name, defaults to &quot;PEAR::%s&quot;.</doc>
+   </rpm-pkgname>
+  </options>
+  <doc>&lt;package-file&gt;
+
+Creates an RPM .spec file for wrapping a PEAR package inside an RPM
+package.  Intended to be used from the SPECS directory, with the PEAR
+package tarball in the SOURCES directory:
+
+$ pear makerpm ../SOURCES/Net_Socket-1.0.tgz
+Wrote RPM spec file PEAR::Net_Geo-1.0.spec
+$ rpm -bb PEAR::Net_Socket-1.0.spec
+...
+Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
+</doc>
+ </makerpm>
+ <convert>
+  <summary>Convert a package.xml 1.0 to package.xml 2.0 format</summary>
+  <function>doConvert</function>
+  <shortcut>c2</shortcut>
+  <options>
+   <flat>
+    <shortopt>f</shortopt>
+    <doc>do not beautify the filelist.</doc>
+   </flat>
+  </options>
+  <doc>[descfile] [descfile2]
+Converts a package.xml in 1.0 format into a package.xml
+in 2.0 format.  The new file will be named package2.xml by default,
+and package.xml will be used as the old file by default.
+This is not the most intelligent conversion, and should only be
+used for automated conversion or learning the format.
+</doc>
+ </convert>
+</commands>
\ No newline at end of file
diff --git a/pear/PEAR/Command/Pickle.php b/pear/PEAR/Command/Pickle.php
new file mode 100644 (file)
index 0000000..5abe427
--- /dev/null
@@ -0,0 +1,376 @@
+<?php
+/**
+ * PEAR_Command_Pickle (pickle command)
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.1
+ */
+
+/**
+ * base class
+ */
+require_once 'PEAR/Command/Common.php';
+
+/**
+ * PEAR commands for login/logout
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.1
+ */
+
+class PEAR_Command_Pickle extends PEAR_Command_Common
+{
+    var $commands = array(
+        'pickle' => array(
+            'summary' => 'Build PECL Package',
+            'function' => 'doPackage',
+            'shortcut' => 'pi',
+            'options' => array(
+                'nocompress' => array(
+                    'shortopt' => 'Z',
+                    'doc' => 'Do not gzip the package file'
+                    ),
+                'showname' => array(
+                    'shortopt' => 'n',
+                    'doc' => 'Print the name of the packaged file.',
+                    ),
+                ),
+            'doc' => '[descfile]
+Creates a PECL package from its package2.xml file.
+
+An automatic conversion will be made to a package.xml 1.0 and written out to
+disk in the current directory as "package.xml".  Note that
+only simple package.xml 2.0 will be converted.  package.xml 2.0 with:
+
+ - dependency types other than required/optional PECL package/ext/php/pearinstaller
+ - more than one extsrcrelease
+ - extbinrelease, phprelease, or bundle release type
+ - dependency groups
+ - ignore tags in release filelist
+ - tasks other than replace
+ - custom roles
+
+will cause pickle to fail, and output an error message.  If your package2.xml
+uses any of these features, you are best off using PEAR_PackageFileManager to
+generate both package.xml.
+'
+            ),
+        );
+
+    /**
+     * PEAR_Command_Package constructor.
+     *
+     * @access public
+     */
+    function PEAR_Command_Pickle(&$ui, &$config)
+    {
+        parent::PEAR_Command_Common($ui, $config);
+    }
+
+
+    /**
+     * For unit-testing ease
+     *
+     * @return PEAR_Packager
+     */
+    function &getPackager()
+    {
+        if (!class_exists('PEAR_Packager')) {
+            require_once 'PEAR/Packager.php';
+        }
+        $a = &new PEAR_Packager;
+        return $a;
+    }
+
+    /**
+     * For unit-testing ease
+     *
+     * @param PEAR_Config $config
+     * @param bool $debug
+     * @param string|null $tmpdir
+     * @return PEAR_PackageFile
+     */
+    function &getPackageFile($config, $debug = false, $tmpdir = null)
+    {
+        if (!class_exists('PEAR_Common')) {
+            require_once 'PEAR/Common.php';
+        }
+        if (!class_exists('PEAR/PackageFile.php')) {
+            require_once 'PEAR/PackageFile.php';
+        }
+        $a = &new PEAR_PackageFile($config, $debug, $tmpdir);
+        $common = new PEAR_Common;
+        $common->ui = $this->ui;
+        $a->setLogger($common);
+        return $a;
+    }
+
+    function doPackage($command, $options, $params)
+    {
+        $this->output = '';
+        $pkginfofile = isset($params[0]) ? $params[0] : 'package2.xml';
+        $packager = &$this->getPackager();
+        if (PEAR::isError($err = $this->_convertPackage($pkginfofile))) {
+            return $err;
+        }
+        $compress = empty($options['nocompress']) ? true : false;
+        $result = $packager->package($pkginfofile, $compress, 'package.xml');
+        if (PEAR::isError($result)) {
+            return $this->raiseError($result);
+        }
+        // Don't want output, only the package file name just created
+        if (isset($options['showname'])) {
+            $this->ui->outputData($result, $command);
+        }
+        return true;
+    }
+
+    function _convertPackage($packagexml)
+    {
+        $pkg = &$this->getPackageFile($this->config);
+        $pf2 = &$pkg->fromPackageFile($packagexml, PEAR_VALIDATE_NORMAL);
+        if (!is_a($pf2, 'PEAR_PackageFile_v2')) {
+            return $this->raiseError('Cannot process "' .
+                $packagexml . '", is not a package.xml 2.0');
+        }
+        require_once 'PEAR/PackageFile/v1.php';
+        $pf = new PEAR_PackageFile_v1;
+        $pf->setConfig($this->config);
+        if (is_array($pf2->getPackageType() != 'extsrc')) {
+            return $this->raiseError('Cannot safely convert "' . $packagexml .
+            '", is not an extension source package.  Using a PEAR_PackageFileManager-based ' .
+            'script is an option');
+        }
+        if (is_array($pf2->getUsesRole())) {
+            return $this->raiseError('Cannot safely convert "' . $packagexml .
+            '", contains custom roles.  Using a PEAR_PackageFileManager-based script or ' .
+            'the convert command is an option');
+        }
+        if (is_array($pf2->getUsesTask())) {
+            return $this->raiseError('Cannot safely convert "' . $packagexml .
+            '", contains custom tasks.  Using a PEAR_PackageFileManager-based script or ' .
+            'the convert command is an option');
+        }
+        $deps = $pf2->getDependencies();
+        if (isset($deps['group'])) {
+            return $this->raiseError('Cannot safely convert "' . $packagexml .
+            '", contains dependency groups.  Using a PEAR_PackageFileManager-based script ' .
+            'or the convert command is an option');
+        }
+        if (isset($deps['required']['subpackage']) ||
+              isset($deps['optional']['subpackage'])) {
+            return $this->raiseError('Cannot safely convert "' . $packagexml .
+            '", contains subpackage dependencies.  Using a PEAR_PackageFileManager-based  '.
+            'script is an option');
+        }
+        if (isset($deps['required']['os'])) {
+            return $this->raiseError('Cannot safely convert "' . $packagexml .
+            '", contains os dependencies.  Using a PEAR_PackageFileManager-based  '.
+            'script is an option');
+        }
+        if (isset($deps['required']['arch'])) {
+            return $this->raiseError('Cannot safely convert "' . $packagexml .
+            '", contains arch dependencies.  Using a PEAR_PackageFileManager-based  '.
+            'script is an option');
+        }
+        $pf->setPackage($pf2->getPackage());
+        $pf->setSummary($pf2->getSummary());
+        $pf->setDescription($pf2->getDescription());
+        foreach ($pf2->getMaintainers() as $maintainer) {
+            $pf->addMaintainer($maintainer['role'], $maintainer['handle'],
+                $maintainer['name'], $maintainer['email']);
+        }
+        $pf->setVersion($pf2->getVersion());
+        $pf->setDate($pf2->getDate());
+        $pf->setLicense($pf2->getLicense());
+        $pf->setState($pf2->getState());
+        $pf->setNotes($pf2->getNotes());
+        $pf->addPhpDep($deps['required']['php']['min'], 'ge');
+        if (isset($deps['required']['php']['max'])) {
+            $pf->addPhpDep($deps['required']['php']['max'], 'le');
+        }
+        if (isset($deps['required']['package'])) {
+            if (!isset($deps['required']['package'][0])) {
+                $deps['required']['package'] = array($deps['required']['package']);
+            }
+            foreach ($deps['required']['package'] as $dep) {
+                if (!isset($dep['channel'])) {
+                    return $this->raiseError('Cannot safely convert "' . $packagexml . '"' .
+                    ' contains uri-based dependency on a package.  Using a ' .
+                    'PEAR_PackageFileManager-based script is an option');
+                }
+                if ($dep['channel'] != 'pear.php.net' && $dep['channel'] != 'pecl.php.net') {
+                    return $this->raiseError('Cannot safely convert "' . $packagexml . '"' .
+                    ' contains dependency on a non-standard channel package.  Using a ' .
+                    'PEAR_PackageFileManager-based script is an option');
+                }
+                if (isset($dep['conflicts'])) {
+                    return $this->raiseError('Cannot safely convert "' . $packagexml . '"' .
+                    ' contains conflicts dependency.  Using a ' .
+                    'PEAR_PackageFileManager-based script is an option');
+                }
+                if (isset($dep['exclude'])) {
+                    $this->ui->outputData('WARNING: exclude tags are ignored in conversion');
+                }
+                if (isset($dep['min'])) {
+                    $pf->addPackageDep($dep['name'], $dep['min'], 'ge');
+                }
+                if (isset($dep['max'])) {
+                    $pf->addPackageDep($dep['name'], $dep['max'], 'le');
+                }
+            }
+        }
+        if (isset($deps['required']['extension'])) {
+            if (!isset($deps['required']['extension'][0])) {
+                $deps['required']['extension'] = array($deps['required']['extension']);
+            }
+            foreach ($deps['required']['extension'] as $dep) {
+                if (isset($dep['conflicts'])) {
+                    return $this->raiseError('Cannot safely convert "' . $packagexml . '"' .
+                    ' contains conflicts dependency.  Using a ' .
+                    'PEAR_PackageFileManager-based script is an option');
+                }
+                if (isset($dep['exclude'])) {
+                    $this->ui->outputData('WARNING: exclude tags are ignored in conversion');
+                }
+                if (isset($dep['min'])) {
+                    $pf->addExtensionDep($dep['name'], $dep['min'], 'ge');
+                }
+                if (isset($dep['max'])) {
+                    $pf->addExtensionDep($dep['name'], $dep['max'], 'le');
+                }
+            }
+        }
+        if (isset($deps['optional']['package'])) {
+            if (!isset($deps['optional']['package'][0])) {
+                $deps['optional']['package'] = array($deps['optional']['package']);
+            }
+            foreach ($deps['optional']['package'] as $dep) {
+                if (!isset($dep['channel'])) {
+                    return $this->raiseError('Cannot safely convert "' . $packagexml . '"' .
+                    ' contains uri-based dependency on a package.  Using a ' .
+                    'PEAR_PackageFileManager-based script is an option');
+                }
+                if ($dep['channel'] != 'pear.php.net' && $dep['channel'] != 'pecl.php.net') {
+                    return $this->raiseError('Cannot safely convert "' . $packagexml . '"' .
+                    ' contains dependency on a non-standard channel package.  Using a ' .
+                    'PEAR_PackageFileManager-based script is an option');
+                }
+                if (isset($dep['exclude'])) {
+                    $this->ui->outputData('WARNING: exclude tags are ignored in conversion');
+                }
+                if (isset($dep['min'])) {
+                    $pf->addPackageDep($dep['name'], $dep['min'], 'ge', 'yes');
+                }
+                if (isset($dep['max'])) {
+                    $pf->addPackageDep($dep['name'], $dep['max'], 'le', 'yes');
+                }
+            }
+        }
+        if (isset($deps['optional']['extension'])) {
+            if (!isset($deps['optional']['extension'][0])) {
+                $deps['optional']['extension'] = array($deps['optional']['extension']);
+            }
+            foreach ($deps['optional']['extension'] as $dep) {
+                if (isset($dep['exclude'])) {
+                    $this->ui->outputData('WARNING: exclude tags are ignored in conversion');
+                }
+                if (isset($dep['min'])) {
+                    $pf->addExtensionDep($dep['name'], $dep['min'], 'ge', 'yes');
+                }
+                if (isset($dep['max'])) {
+                    $pf->addExtensionDep($dep['name'], $dep['max'], 'le', 'yes');
+                }
+            }
+        }
+        $contents = $pf2->getContents();
+        $release = $pf2->getReleases();
+        if (isset($releases[0])) {
+            return $this->raiseError('Cannot safely process "' . $packagexml . '" contains ' 
+            . 'multiple extsrcrelease tags.  Using a PEAR_PackageFileManager-based script ' .
+            'or the convert command is an option');
+        }
+        if ($configoptions = $pf2->getConfigureOptions()) {
+            foreach ($configoptions as $option) {
+                $pf->addConfigureOption($option['name'], $option['prompt'],
+                    isset($option['default']) ? $option['default'] : false);
+            }
+        }
+        if (isset($release['filelist']['ignore'])) {
+            return $this->raiseError('Cannot safely process "' . $packagexml . '" contains ' 
+            . 'ignore tags.  Using a PEAR_PackageFileManager-based script or the convert' .
+            ' command is an option');
+        }
+        if (isset($release['filelist']['install']) &&
+              !isset($release['filelist']['install'][0])) {
+            $release['filelist']['install'] = array($release['filelist']['install']);
+        }
+        if (isset($contents['dir']['attribs']['baseinstalldir'])) {
+            $baseinstalldir = $contents['dir']['attribs']['baseinstalldir'];
+        } else {
+            $baseinstalldir = false;
+        }
+        if (!isset($contents['dir']['file'][0])) {
+            $contents['dir']['file'] = array($contents['dir']['file']);
+        }
+        foreach ($contents['dir']['file'] as $file) {
+            if ($baseinstalldir && !isset($file['attribs']['baseinstalldir'])) {
+                $file['attribs']['baseinstalldir'] = $baseinstalldir;
+            }
+            $processFile = $file;
+            unset($processFile['attribs']);
+            if (count($processFile)) {
+                foreach ($processFile as $name => $task) {
+                    if ($name != $pf2->getTasksNs() . ':replace') {
+                        return $this->raiseError('Cannot safely process "' . $packagexml .
+                        '" contains tasks other than replace.  Using a ' .
+                        'PEAR_PackageFileManager-based script is an option.');
+                    }
+                    $file['attribs']['replace'][] = $task;
+                }
+            }
+            if (!in_array($file['attribs']['role'], PEAR_Common::getFileRoles())) {
+                return $this->raiseError('Cannot safely convert "' . $packagexml .
+                '", contains custom roles.  Using a PEAR_PackageFileManager-based script ' .
+                'or the convert command is an option');
+            }
+            if (isset($release['filelist']['install'])) {
+                foreach ($release['filelist']['install'] as $installas) {
+                    if ($installas['attribs']['name'] == $file['attribs']['name']) {
+                        $file['attribs']['install-as'] = $installas['attribs']['as'];
+                    }
+                }
+            }
+            $pf->addFile('/', $file['attribs']['name'], $file['attribs']);
+        }
+        if ($pf2->getChangeLog()) {
+            $this->ui->outputData('WARNING: changelog is not translated to package.xml ' .
+                '1.0, use PEAR_PackageFileManager-based script if you need changelog-' .
+                'translation for package.xml 1.0');
+        }
+        $gen = &$pf->getDefaultGenerator();
+        $gen->toPackageFile('.');
+    }
+}
+
+?>
diff --git a/pear/PEAR/Command/Pickle.xml b/pear/PEAR/Command/Pickle.xml
new file mode 100644 (file)
index 0000000..550186f
--- /dev/null
@@ -0,0 +1,40 @@
+<commands version="1.0">
+ <pickle>
+  <summary>Build PECL Package</summary>
+  <function>doPackage</function>
+  <shortcut>pi</shortcut>
+  <options>
+   <nocompress>
+    <shortopt>Z</shortopt>
+    <doc>Do not gzip the package file</doc>
+   </nocompress>
+   <showname>
+    <shortopt>n</shortopt>
+    <doc>Print the name of the packaged file.</doc>
+   </showname>
+  </options>
+  <doc>[descfile] [descfile2]
+Creates a PECL package from its description file (usually called
+package.xml).  If a second packagefile is passed in, then
+the packager will check to make sure that one is a package.xml
+version 1.0, and the other is a package.xml version 2.0.  The
+package.xml version 1.0 will be saved as &quot;package.xml&quot; in the archive,
+and the other as &quot;package2.xml&quot; in the archive&quot;
+
+If no second file is passed in, and [descfile] is a package.xml 2.0,
+an automatic conversion will be made to a package.xml 1.0.  Note that
+only simple package.xml 2.0 will be converted.  package.xml 2.0 with:
+
+ - dependency types other than required/optional PECL package/ext/php/pearinstaller
+ - more than one extsrcrelease
+ - extbinrelease, phprelease, or bundle release type
+ - dependency groups
+ - ignore tags in release filelist
+ - tasks other than replace
+ - custom roles
+
+will cause pickle to fail, and output an error message.  If your package2.xml
+uses any of these features, you are best off using PEAR_PackageFileManager to
+generate both package.xml.</doc>
+ </pickle>
+</commands>
\ No newline at end of file
index e1f6f74a9cd082f504b3cf2f295b7b23b4ba606e..24094456faba5897b5b11339edaf633f0f6c145f 100644 (file)
@@ -1,44 +1,79 @@
 <?php
-// /* vim: set expandtab tabstop=4 shiftwidth=4: */
-// +----------------------------------------------------------------------+
-// | PHP Version 5                                                        |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2004 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 Bakken <ssb@php.net>                                    |
-// |                                                                      |
-// +----------------------------------------------------------------------+
-//
-// $Id$
+/**
+ * PEAR_Command_Registry (list, list-files, shell-test, info commands)
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 0.1
+ */
 
+/**
+ * base class
+ */
 require_once 'PEAR/Command/Common.php';
-require_once 'PEAR/Registry.php';
-require_once 'PEAR/Config.php';
 
+/**
+ * PEAR commands for registry manipulation
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 0.1
+ */
 class PEAR_Command_Registry extends PEAR_Command_Common
 {
     // {{{ properties
 
     var $commands = array(
         'list' => array(
-            'summary' => 'List Installed Packages',
+            'summary' => 'List Installed Packages In The Default Channel',
             'function' => 'doList',
             'shortcut' => 'l',
-            'options' => array(),
-            'doc' => '[package]
+            'options' => array(
+                'channel' => array(
+                    'shortopt' => 'c',
+                    'doc' => 'list installed packages from this channel',
+                    'arg' => 'CHAN',
+                    ),
+                'allchannels' => array(
+                    'shortopt' => 'a',
+                    'doc' => 'list installed packages from all channels',
+                    ),
+                ),
+            'doc' => '<package>
 If invoked without parameters, this command lists the PEAR packages
-installed in your php_dir ({config php_dir)).  With a parameter, it
-lists the files in that package.
+installed in your php_dir ({config php_dir}).  With a parameter, it
+lists the files in a package.
 ',
             ),
+        'list-files' => array(
+            'summary' => 'List Files In Installed Package',
+            'function' => 'doFileList',
+            'shortcut' => 'fl',
+            'options' => array(),
+            'doc' => '<package>
+List the files in an installed package.
+'
+            ),
         'shell-test' => array(
             'summary' => 'Shell Script Test',
             'function' => 'doShellTest',
@@ -81,58 +116,128 @@ installed package.'
 
     function _sortinfo($a, $b)
     {
-        return strcmp($a['package'], $b['package']);
+        $apackage = isset($a['package']) ? $a['package'] : $a['name'];
+        $bpackage = isset($b['package']) ? $b['package'] : $b['name'];
+        return strcmp($apackage, $bpackage);
     }
 
     function doList($command, $options, $params)
     {
-        $reg = new PEAR_Registry($this->config->get('php_dir'));
-        if (sizeof($params) == 0) {
-            $installed = $reg->packageInfo();
-            usort($installed, array(&$this, '_sortinfo'));
+        if (isset($options['allchannels'])) {
+            return $this->doListAll($command, array(), $params);
+        }
+        $reg = &$this->config->getRegistry();
+        if (count($params) == 1) {
+            return $this->doFileList($command, $options, $params);
+        }
+        if (isset($options['channel'])) {
+            if ($reg->channelExists($options['channel'])) {
+                $channel = $reg->channelName($options['channel']);
+            } else {
+                return $this->raiseError('Channel "' . $options['channel'] .'" does not exist');
+            }
+        } else {
+            $channel = $this->config->get('default_channel');
+        }
+        $installed = $reg->packageInfo(null, null, $channel);
+        usort($installed, array(&$this, '_sortinfo'));
+        $i = $j = 0;
+        $data = array(
+            'caption' => 'Installed packages, channel ' .
+                $channel . ':',
+            'border' => true,
+            'headline' => array('Package', 'Version', 'State')
+            );
+        foreach ($installed as $package) {
+            $pobj = $reg->getPackage(isset($package['package']) ?
+                                        $package['package'] : $package['name'], $channel);
+            $data['data'][] = array($pobj->getPackage(), $pobj->getVersion(),
+                                    $pobj->getState() ? $pobj->getState() : null);
+        }
+        if (count($installed)==0) {
+            $data = '(no packages installed from channel ' . $channel . ')';
+        }
+        $this->ui->outputData($data, $command);
+        return true;
+    }
+    
+    function doListAll($command, $options, $params)
+    {
+        $reg = &$this->config->getRegistry();
+        $installed = $reg->packageInfo(null, null, null);
+        foreach ($installed as $channel => $packages) {
+            usort($packages, array($this, '_sortinfo'));
             $i = $j = 0;
             $data = array(
-                'caption' => 'Installed packages:',
+                'caption' => 'Installed packages, channel ' . $channel . ':',
                 'border' => true,
                 'headline' => array('Package', 'Version', 'State')
                 );
-            foreach ($installed as $package) {
-                $data['data'][] = array($package['package'],
-                                          $package['version'],
-                                          @$package['release_state']);
+            foreach ($packages as $package) {
+                $pobj = $reg->getPackage(isset($package['package']) ?
+                                            $package['package'] : $package['name'], $channel);
+                $data['data'][] = array($pobj->getPackage(), $pobj->getVersion(),
+                                        $pobj->getState() ? $pobj->getState() : null);
             }
-            if (count($installed)==0) {
-                $data = '(no packages installed)';
+            if (count($packages)==0) {
+                $data = array(
+                    'caption' => 'Installed packages, channel ' . $channel . ':',
+                    'border' => true,
+                    'data' => array(array('(no packages installed)')),
+                    );
             }
             $this->ui->outputData($data, $command);
-        } else {
-            if (file_exists($params[0]) && !is_dir($params[0])) {
-                include_once "PEAR/Common.php";
-                $obj = &new PEAR_Common;
-                $info = $obj->infoFromAny($params[0]);
-                $headings = array('Package File', 'Install Path');
-                $installed = false;
-            } else {
-                $info = $reg->packageInfo($params[0]);
-                $headings = array('Type', 'Install Path');
-                $installed = true;
-            }
-            if (PEAR::isError($info)) {
-                return $this->raiseError($info);
-            }
-            if ($info === null) {
-                return $this->raiseError("`$params[0]' not installed");
+        }
+        return true;
+    }
+    
+    function doFileList($command, $options, $params)
+    {
+        if (count($params) != 1) {
+            return $this->raiseError('list-files expects 1 parameter');
+        }
+        $reg = &$this->config->getRegistry();
+        if (!is_dir($params[0]) && (file_exists($params[0]) || $fp = @fopen($params[0],
+              'r'))) {
+            @fclose($fp);
+            if (!class_exists('PEAR_PackageFile')) {
+                require_once 'PEAR/PackageFile.php';
             }
-            $list = $info['filelist'];
-            if ($installed) {
-                $caption = 'Installed Files For ' . $params[0];
-            } else {
-                $caption = 'Contents of ' . basename($params[0]);
+            $pkg = &new PEAR_PackageFile($this->config, $this->_debug);
+            PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+            $info = &$pkg->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
+            PEAR::staticPopErrorHandling();
+            $headings = array('Package File', 'Install Path');
+            $installed = false;
+        } else {
+            PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+            $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel'));
+            PEAR::staticPopErrorHandling();
+            if (PEAR::isError($parsed)) {
+                return $this->raiseError($parsed);
             }
-            $data = array(
-                'caption' => $caption,
-                'border' => true,
-                'headline' => $headings);
+            $info = &$reg->getPackage($parsed['package'], $parsed['channel']);
+            $headings = array('Type', 'Install Path');
+            $installed = true;
+        }
+        if (PEAR::isError($info)) {
+            return $this->raiseError($info);
+        }
+        if ($info === null) {
+            return $this->raiseError("`$params[0]' not installed");
+        }
+        $list = ($info->getPackagexmlVersion() == '1.0' || $installed) ?
+            $info->getFilelist() : $info->getContents();
+        if ($installed) {
+            $caption = 'Installed Files For ' . $params[0];
+        } else {
+            $caption = 'Contents of ' . basename($params[0]);
+        }
+        $data = array(
+            'caption' => $caption,
+            'border' => true,
+            'headline' => $headings);
+        if ($info->getPackagexmlVersion() == '1.0' || $installed) {
             foreach ($list as $file => $att) {
                 if ($installed) {
                     if (empty($att['installed_as'])) {
@@ -140,7 +245,8 @@ installed package.'
                     }
                     $data['data'][] = array($att['role'], $att['installed_as']);
                 } else {
-                    if (isset($att['baseinstalldir'])) {
+                    if (isset($att['baseinstalldir']) && !in_array($att['role'],
+                          array('test', 'data', 'doc'))) {
                         $dest = $att['baseinstalldir'] . DIRECTORY_SEPARATOR .
                             $file;
                     } else {
@@ -149,29 +255,52 @@ installed package.'
                     switch ($att['role']) {
                         case 'test':
                         case 'data':
-                            if ($installed) {
-                                break 2;
-                            }
-                            $dest = '-- will not be installed --';
-                            break;
                         case 'doc':
-                            $dest = $this->config->get('doc_dir') . DIRECTORY_SEPARATOR .
-                                $dest;
+                            $role = $att['role'];
+                            if ($role == 'test') {
+                                $role .= 's';
+                            }
+                            $dest = $this->config->get($role . '_dir') . DIRECTORY_SEPARATOR .
+                                $info->getPackage() . DIRECTORY_SEPARATOR . $dest;
                             break;
                         case 'php':
                         default:
                             $dest = $this->config->get('php_dir') . DIRECTORY_SEPARATOR .
                                 $dest;
                     }
-                    $dest = preg_replace('!/+!', '/', $dest);
+                    $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR;
+                    $dest = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"),
+                                                    array(DIRECTORY_SEPARATOR,
+                                                          DIRECTORY_SEPARATOR,
+                                                          DIRECTORY_SEPARATOR),
+                                                    $dest);
                     $file = preg_replace('!/+!', '/', $file);
                     $data['data'][] = array($file, $dest);
                 }
             }
-            $this->ui->outputData($data, $command);
-
-
+        } else { // package.xml 2.0, not installed
+            if (!isset($list['dir']['file'][0])) {
+                $list['dir']['file'] = array($list['dir']['file']);
+            }
+            foreach ($list['dir']['file'] as $att) {
+                $att = $att['attribs'];
+                $file = $att['name'];
+                $role = &PEAR_Installer_Role::factory($info, $att['role'], $this->config);
+                $role->setup($this, $info, $att, $file);
+                if (!$role->isInstallable()) {
+                    $dest = '(not installable)';
+                } else {
+                    $dest = $role->processInstallation($info, $att, $file, '');
+                    if (PEAR::isError($dest)) {
+                        $dest = '(Unknown role "' . $att['role'] . ')';
+                    } else {
+                        list(,, $dest) = $dest;
+                    }
+                }
+                $data['data'][] = array($file, $dest);
+            }
         }
+        $this->ui->outputData($data, $command);
         return true;
     }
 
@@ -181,21 +310,34 @@ installed package.'
     function doShellTest($command, $options, $params)
     {
         $this->pushErrorHandling(PEAR_ERROR_RETURN);
-        $reg = &new PEAR_Registry($this->config->get('php_dir'));
+        $reg = &$this->config->getRegistry();
+        $info = $reg->parsePackageName($params[0], $this->config->get('default_channel'));
+        if (PEAR::isError($info)) {
+            exit(1); // invalid package name
+        }
+        $package = $info['package'];
+        $channel = $info['channel'];
         // "pear shell-test Foo"
+        if (!$reg->packageExists($package, $channel)) {
+            if ($channel == 'pecl.php.net') {
+                if ($reg->packageExists($package, 'pear.php.net')) {
+                    $channel = 'pear.php.net'; // magically change channels for extensions
+                }
+            }
+        }
         if (sizeof($params) == 1) {
-            if (!$reg->packageExists($params[0])) {
+            if (!$reg->packageExists($package, $channel)) {
                 exit(1);
             }
             // "pear shell-test Foo 1.0"
         } elseif (sizeof($params) == 2) {
-            $v = $reg->packageInfo($params[0], 'version');
+            $v = $reg->packageInfo($package, 'version', $channel);
             if (!$v || !version_compare("$v", "{$params[1]}", "ge")) {
                 exit(1);
             }
             // "pear shell-test Foo ge 1.0"
         } elseif (sizeof($params) == 3) {
-            $v = $reg->packageInfo($params[0], 'version');
+            $v = $reg->packageInfo($package, 'version', $channel);
             if (!$v || !version_compare("$v", "{$params[2]}", $params[1])) {
                 exit(1);
             }
@@ -211,27 +353,68 @@ installed package.'
 
     function doInfo($command, $options, $params)
     {
-        // $params[0] The package for showing info
-        if (sizeof($params) != 1) {
-            return $this->raiseError("This command only accepts one param: ".
-                                     "the package you want information");
-        }
-        if (@is_file($params[0])) {
-            $obj  = &new PEAR_Common();
-            $info = $obj->infoFromAny($params[0]);
+        if (count($params) != 1) {
+            return $this->raiseError('pear info expects 1 parameter');
+        }
+        $info = false;
+        $reg = &$this->config->getRegistry();
+        if ((@is_file($params[0]) && !is_dir($params[0])) || $fp = @fopen($params[0], 'r')) {
+            @fclose($fp);
+            if (!class_exists('PEAR_PackageFile')) {
+                require_once 'PEAR/PackageFile.php';
+            }
+            $pkg = &new PEAR_PackageFile($this->config, $this->_debug);
+            PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+            $obj = &$pkg->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
+            PEAR::staticPopErrorHandling();
+            if (PEAR::isError($obj)) {
+                $uinfo = $obj->getUserInfo();
+                if (is_array($uinfo)) {
+                    foreach ($uinfo as $message) {
+                        if (is_array($message)) {
+                            $message = $message['message'];
+                        }
+                        $this->ui->outputData($message);
+                    }
+                }
+                return $this->raiseError($obj);
+            }
+            if ($obj->getPackagexmlVersion() == '1.0') {
+                $info = $obj->toArray();
+            } else {
+                return $this->_doInfo2($command, $options, $params, $obj, false);
+            }
         } else {
-            $reg = &new PEAR_Registry($this->config->get('php_dir'));
-            $info = $reg->packageInfo($params[0]);
+            $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel'));
+            if (PEAR::isError($parsed)) {
+                return $this->raiseError($parsed);
+            }
+            $package = $parsed['package'];
+            $channel = $parsed['channel'];
+            $info = $reg->packageInfo($package, null, $channel);
+            if (isset($info['old'])) {
+                $obj = $reg->getPackage($package, $channel);
+                return $this->_doInfo2($command, $options, $params, $obj, true);
+            }
         }
         if (PEAR::isError($info)) {
             return $info;
         }
         if (empty($info)) {
-            $this->raiseError("Nothing found for `$params[0]'");
+            $this->raiseError("No information found for `$params[0]'");
             return;
         }
         unset($info['filelist']);
+        unset($info['dirtree']);
         unset($info['changelog']);
+        if (isset($info['xsdversion'])) {
+            $info['package.xml version'] = $info['xsdversion'];
+            unset($info['xsdversion']);
+        }
+        if (isset($info['packagerversion'])) {
+            $info['packaged with PEAR version'] = $info['packagerversion'];
+            unset($info['packagerversion']);
+        }
         $keys = array_keys($info);
         $longtext = array('description', 'summary');
         foreach ($keys as $key) {
@@ -279,7 +462,12 @@ installed package.'
                             } else {
                                 $version = '';
                             }
-                            $dstr .= "$type $name$rel $version\n";
+                            if (isset($d['optional']) && $d['optional'] == 'yes') {
+                                $optional = ' (optional)';
+                            } else {
+                                $optional = '';
+                            }
+                            $dstr .= "$type $name$rel $version$optional\n";
                         }
                         $info[$key] = $dstr;
                         break;
@@ -315,6 +503,16 @@ installed package.'
                         $info[$key] = $pstr;
                         break;
                     }
+                    case 'configure_options' : {
+                        foreach ($info[$key] as $i => $p) {
+                            $info[$key][$i] = array_map(null, array_keys($p), array_values($p));
+                            $info[$key][$i] = array_map(create_function('$a',
+                                'return join(" = ",$a);'), $info[$key][$i]);
+                            $info[$key][$i] = implode(', ', $info[$key][$i]);
+                        }
+                        $info[$key] = implode("\n", $info[$key]);
+                        break;
+                    }
                     default: {
                         $info[$key] = implode(", ", $info[$key]);
                         break;
@@ -325,6 +523,9 @@ installed package.'
                 $hdate = date('Y-m-d', $info[$key]);
                 unset($info[$key]);
                 $info['Last Modified'] = $hdate;
+            } elseif ($key == '_lastversion') {
+                $info['Last Installed Version'] = $info[$key] ? $info[$key] : '- None -';
+                unset($info[$key]);
             } else {
                 $info[$key] = trim($info[$key]);
                 if (in_array($key, $longtext)) {
@@ -346,6 +547,451 @@ installed package.'
     }
 
     // }}}
+
+    /**
+     * @access private
+     */
+    function _doInfo2($command, $options, $params, &$obj, $installed)
+    {
+        $reg = &$this->config->getRegistry();
+        $caption = 'About ' . $obj->getChannel() . '/' .$obj->getPackage() . '-' .
+            $obj->getVersion();
+        $data = array(
+            'caption' => $caption,
+            'border' => true);
+        switch ($obj->getPackageType()) {
+            case 'php' :
+                $release = 'PEAR-style PHP-based Package';
+            break;
+            case 'extsrc' :
+                $release = 'PECL-style PHP extension (source code)';
+            break;
+            case 'extbin' :
+                $release = 'PECL-style PHP extension (binary)';
+            break;
+            case 'bundle' :
+                $release = 'Package bundle (collection of packages)';
+            break;
+        }
+        $extends = $obj->getExtends();
+        $extends = $extends ?
+            $obj->getPackage() . ' (extends ' . $extends . ')' : $obj->getPackage();
+        if ($src = $obj->getSourcePackage()) {
+            $extends .= ' (source package ' . $src['channel'] . '/' . $src['package'] . ')';
+        }
+        $info = array(
+            'Release Type' => $release,
+            'Name' => $extends,
+            'Channel' => $obj->getChannel(),
+            'Summary' => preg_replace('/  +/', ' ', $obj->getSummary()),
+            'Description' => preg_replace('/  +/', ' ', $obj->getDescription()),
+            );
+        $info['Maintainers'] = '';
+        foreach (array('lead', 'developer', 'contributor', 'helper') as $role) {
+            $leads = $obj->{"get{$role}s"}();
+            if (!$leads) {
+                continue;
+            }
+            if (isset($leads['active'])) {
+                $leads = array($leads);
+            }
+            foreach ($leads as $lead) {
+                if (!empty($info['Maintainers'])) {
+                    $info['Maintainers'] .= "\n";
+                }
+                $info['Maintainers'] .= $lead['name'] . ' <';
+                $info['Maintainers'] .= $lead['email'] . "> ($role)";
+            }
+        }
+        $info['Release Date'] = $obj->getDate();
+        if ($time = $obj->getTime()) {
+            $info['Release Date'] .= ' ' . $time;
+        }
+        $info['Release Version'] = $obj->getVersion() . ' (' . $obj->getState() . ')';
+        $info['API Version'] = $obj->getVersion('api') . ' (' . $obj->getState('api') . ')';
+        $info['License'] = $obj->getLicense();
+        $uri = $obj->getLicenseLocation();
+        if ($uri) {
+            if (isset($uri['uri'])) {
+                $info['License'] .= ' (' . $uri['uri'] . ')';
+            } else {
+                $extra = $obj->getInstalledLocation($info['filesource']);
+                if ($extra) {
+                    $info['License'] .= ' (' . $uri['filesource'] . ')';
+                }
+            }
+        }
+        $info['Release Notes'] = $obj->getNotes();
+        if ($compat = $obj->getCompatible()) {
+            $info['Compatible with'] = '';
+            foreach ($compat as $package) {
+                $info['Compatible with'] .= $package['channel'] . '/' . $package['package'] .
+                    "\nVersions >= " . $package['min'] . ', <= ' . $package['max'];
+                if (isset($package['exclude'])) {
+                    if (is_array($package['exclude'])) {
+                        $package['exclude'] = implode(', ', $package['exclude']);
+                    }
+                    if (!isset($info['Not Compatible with'])) {
+                        $info['Not Compatible with'] = '';
+                    } else {
+                        $info['Not Compatible with'] .= "\n";
+                    }
+                    $info['Not Compatible with'] .= $package['channel'] . '/' .
+                        $package['package'] . "\nVersions " . $package['exclude'];
+                }
+            }
+        }
+        $usesrole = $obj->getUsesrole();
+        if ($usesrole) {
+            if (!isset($usesrole[0])) {
+                $usesrole = array($usesrole);
+            }
+            foreach ($usesrole as $roledata) {
+                if (isset($info['Uses Custom Roles'])) {
+                    $info['Uses Custom Roles'] .= "\n";
+                } else {
+                    $info['Uses Custom Roles'] = '';
+                }
+                if (isset($roledata['package'])) {
+                    $rolepackage = $reg->parsedPackageNameToString($roledata, true);
+                } else {
+                    $rolepackage = $roledata['uri'];
+                }
+                $info['Uses Custom Roles'] .= $roledata['role'] . ' (' . $rolepackage . ')';
+            }
+        }
+        $usestask = $obj->getUsestask();
+        if ($usestask) {
+            if (!isset($usestask[0])) {
+                $usestask = array($usestask);
+            }
+            foreach ($usestask as $taskdata) {
+                if (isset($info['Uses Custom Tasks'])) {
+                    $info['Uses Custom Tasks'] .= "\n";
+                } else {
+                    $info['Uses Custom Tasks'] = '';
+                }
+                if (isset($taskdata['package'])) {
+                    $taskpackage = $reg->parsedPackageNameToString($taskdata, true);
+                } else {
+                    $taskpackage = $taskdata['uri'];
+                }
+                $info['Uses Custom Tasks'] .= $taskdata['task'] . ' (' . $taskpackage . ')';
+            }
+        }
+        $deps = $obj->getDependencies();
+        $info['Required Dependencies'] = 'PHP version ' . $deps['required']['php']['min'];
+        if (isset($deps['required']['php']['max'])) {
+            $info['Required Dependencies'] .= '-' . $deps['required']['php']['max'] . "\n";
+        } else {
+            $info['Required Dependencies'] .= "\n";
+        }
+        if (isset($deps['required']['php']['exclude'])) {
+            if (!isset($info['Not Compatible with'])) {
+                $info['Not Compatible with'] = '';
+            } else {
+                $info['Not Compatible with'] .= "\n";
+            }
+            if (is_array($deps['required']['php']['exclude'])) {
+                $deps['required']['php']['exclude'] =
+                    implode(', ', $deps['required']['php']['exclude']);
+            }
+            $info['Not Compatible with'] .= "PHP versions\n  " .
+                $deps['required']['php']['exclude'];
+        }
+        $info['Required Dependencies'] .= 'PEAR installer version';
+        if (isset($deps['required']['pearinstaller']['max'])) {
+            $info['Required Dependencies'] .= 's ' .
+                $deps['required']['pearinstaller']['min'] . '-' .
+                $deps['required']['pearinstaller']['max'];
+        } else {
+            $info['Required Dependencies'] .= ' ' .
+                $deps['required']['pearinstaller']['min'] . ' or newer';
+        }
+        if (isset($deps['required']['pearinstaller']['exclude'])) {
+            if (!isset($info['Not Compatible with'])) {
+                $info['Not Compatible with'] = '';
+            } else {
+                $info['Not Compatible with'] .= "\n";
+            }
+            if (is_array($deps['required']['pearinstaller']['exclude'])) {
+                $deps['required']['pearinstaller']['exclude'] =
+                    implode(', ', $deps['required']['pearinstaller']['exclude']);
+            }
+            $info['Not Compatible with'] .= "PEAR installer\n  Versions " .
+                $deps['required']['pearinstaller']['exclude'];
+        }
+        foreach (array('Package', 'Extension') as $type) {
+            $index = strtolower($type);
+            if (isset($deps['required'][$index])) {
+                if (isset($deps['required'][$index]['name'])) {
+                    $deps['required'][$index] = array($deps['required'][$index]);
+                }
+                foreach ($deps['required'][$index] as $package) {
+                    if (isset($package['conflicts'])) {
+                        $infoindex = 'Not Compatible with';
+                        if (!isset($info['Not Compatible with'])) {
+                            $info['Not Compatible with'] = '';
+                        } else {
+                            $info['Not Compatible with'] .= "\n";
+                        }
+                    } else {
+                        $infoindex = 'Required Dependencies';
+                        $info[$infoindex] .= "\n";
+                    }
+                    if ($index == 'extension') {
+                        $name = $package['name'];
+                    } else {
+                        if (isset($package['channel'])) {
+                            $name = $package['channel'] . '/' . $package['name'];
+                        } else {
+                            $name = '__uri/' . $package['name'] . ' (static URI)';
+                        }
+                    }
+                    $info[$infoindex] .= "$type $name";
+                    if (isset($package['uri'])) {
+                        $info[$infoindex] .= "\n  Download URI: $package[uri]";
+                        continue;
+                    }
+                    if (isset($package['max']) && isset($package['min'])) {
+                        $info[$infoindex] .= " \n  Versions " .
+                            $package['min'] . '-' . $package['max'];
+                    } elseif (isset($package['min'])) {
+                        $info[$infoindex] .= " \n  Version " .
+                            $package['min'] . ' or newer';
+                    } elseif (isset($package['max'])) {
+                        $info[$infoindex] .= " \n  Version " .
+                            $package['max'] . ' or older';
+                    }
+                    if (isset($package['recommended'])) {
+                        $info[$infoindex] .= "\n  Recommended version: $package[recommended]";
+                    }
+                    if (isset($package['exclude'])) {
+                        if (!isset($info['Not Compatible with'])) {
+                            $info['Not Compatible with'] = '';
+                        } else {
+                            $info['Not Compatible with'] .= "\n";
+                        }
+                        if (is_array($package['exclude'])) {
+                            $package['exclude'] = implode(', ', $package['exclude']);
+                        }
+                        $package['package'] = $package['name']; // for parsedPackageNameToString
+                         if (isset($package['conflicts'])) {
+                            $info['Not Compatible with'] .= '=> except ';
+                        }
+                       $info['Not Compatible with'] .= 'Package ' .
+                            $reg->parsedPackageNameToString($package, true);
+                        $info['Not Compatible with'] .= "\n  Versions " . $package['exclude'];
+                    }
+                }
+            }
+        }
+        if (isset($deps['required']['os'])) {
+            if (isset($deps['required']['os']['name'])) {
+                $dep['required']['os']['name'] = array($dep['required']['os']['name']);
+            }
+            foreach ($dep['required']['os'] as $os) {
+                if (isset($os['conflicts']) && $os['conflicts'] == 'yes') {
+                    if (!isset($info['Not Compatible with'])) {
+                        $info['Not Compatible with'] = '';
+                    } else {
+                        $info['Not Compatible with'] .= "\n";
+                    }
+                    $info['Not Compatible with'] .= "$os[name] Operating System";
+                } else {
+                    $info['Required Dependencies'] .= "\n";
+                    $info['Required Dependencies'] .= "$os[name] Operating System";
+                }
+            }
+        }
+        if (isset($deps['required']['arch'])) {
+            if (isset($deps['required']['arch']['pattern'])) {
+                $dep['required']['arch']['pattern'] = array($dep['required']['os']['pattern']);
+            }
+            foreach ($dep['required']['arch'] as $os) {
+                if (isset($os['conflicts']) && $os['conflicts'] == 'yes') {
+                    if (!isset($info['Not Compatible with'])) {
+                        $info['Not Compatible with'] = '';
+                    } else {
+                        $info['Not Compatible with'] .= "\n";
+                    }
+                    $info['Not Compatible with'] .= "OS/Arch matching pattern '/$os[pattern]/'";
+                } else {
+                    $info['Required Dependencies'] .= "\n";
+                    $info['Required Dependencies'] .= "OS/Arch matching pattern '/$os[pattern]/'";
+                }
+            }
+        }
+        if (isset($deps['optional'])) {
+            foreach (array('Package', 'Extension') as $type) {
+                $index = strtolower($type);
+                if (isset($deps['optional'][$index])) {
+                    if (isset($deps['optional'][$index]['name'])) {
+                        $deps['optional'][$index] = array($deps['optional'][$index]);
+                    }
+                    foreach ($deps['optional'][$index] as $package) {
+                        if (isset($package['conflicts']) && $package['conflicts'] == 'yes') {
+                            $infoindex = 'Not Compatible with';
+                            if (!isset($info['Not Compatible with'])) {
+                                $info['Not Compatible with'] = '';
+                            } else {
+                                $info['Not Compatible with'] .= "\n";
+                            }
+                        } else {
+                            $infoindex = 'Optional Dependencies';
+                            if (!isset($info['Optional Dependencies'])) {
+                                $info['Optional Dependencies'] = '';
+                            } else {
+                                $info['Optional Dependencies'] .= "\n";
+                            }
+                        }
+                        if ($index == 'extension') {
+                            $name = $package['name'];
+                        } else {
+                            if (isset($package['channel'])) {
+                                $name = $package['channel'] . '/' . $package['name'];
+                            } else {
+                                $name = '__uri/' . $package['name'] . ' (static URI)';
+                            }
+                        }
+                        $info[$infoindex] .= "$type $name";
+                        if (isset($package['uri'])) {
+                            $info[$infoindex] .= "\n  Download URI: $package[uri]";
+                            continue;
+                        }
+                        if ($infoindex == 'Not Compatible with') {
+                            // conflicts is only used to say that all versions conflict
+                            continue;
+                        }
+                        if (isset($package['max']) && isset($package['min'])) {
+                            $info[$infoindex] .= " \n  Versions " .
+                                $package['min'] . '-' . $package['max'];
+                        } elseif (isset($package['min'])) {
+                            $info[$infoindex] .= " \n  Version " .
+                                $package['min'] . ' or newer';
+                        } elseif (isset($package['max'])) {
+                            $info[$infoindex] .= " \n  Version " .
+                                $package['min'] . ' or older';
+                        }
+                        if (isset($package['recommended'])) {
+                            $info[$infoindex] .= "\n  Recommended version: $package[recommended]";
+                        }
+                        if (isset($package['exclude'])) {
+                            if (!isset($info['Not Compatible with'])) {
+                                $info['Not Compatible with'] = '';
+                            } else {
+                                $info['Not Compatible with'] .= "\n";
+                            }
+                            if (is_array($package['exclude'])) {
+                                $package['exclude'] = implode(', ', $package['exclude']);
+                            }
+                            $info['Not Compatible with'] .= "Package $package\n  Versions " .
+                                $package['exclude'];
+                        }
+                    }
+                }
+            }
+        }
+        if (isset($deps['group'])) {
+            if (!isset($deps['group'][0])) {
+                $deps['group'] = array($deps['group']);
+            }
+            foreach ($deps['group'] as $group) {
+                $info['Dependency Group ' . $group['attribs']['name']] = $group['attribs']['hint'];
+                $groupindex = $group['attribs']['name'] . ' Contents';
+                $info[$groupindex] = '';
+                foreach (array('Package', 'Extension') as $type) {
+                    $index = strtolower($type);
+                    if (isset($group[$index])) {
+                        if (isset($group[$index]['name'])) {
+                            $group[$index] = array($group[$index]);
+                        }
+                        foreach ($group[$index] as $package) {
+                            if (!empty($info[$groupindex])) {
+                                $info[$groupindex] .= "\n";
+                            }
+                            if ($index == 'extension') {
+                                $name = $package['name'];
+                            } else {
+                                if (isset($package['channel'])) {
+                                    $name = $package['channel'] . '/' . $package['name'];
+                                } else {
+                                    $name = '__uri/' . $package['name'] . ' (static URI)';
+                                }
+                            }
+                            if (isset($package['uri'])) {
+                                if (isset($package['conflicts']) && $package['conflicts'] == 'yes') {
+                                    $info[$groupindex] .= "Not Compatible with $type $name";
+                                } else {
+                                    $info[$groupindex] .= "$type $name";
+                                }
+                                $info[$groupindex] .= "\n  Download URI: $package[uri]";
+                                continue;
+                            }
+                            if (isset($package['conflicts']) && $package['conflicts'] == 'yes') {
+                                $info[$groupindex] .= "Not Compatible with $type $name";
+                                continue;
+                            }
+                            $info[$groupindex] .= "$type $name";
+                            if (isset($package['max']) && isset($package['min'])) {
+                                $info[$groupindex] .= " \n  Versions " .
+                                    $package['min'] . '-' . $package['max'];
+                            } elseif (isset($package['min'])) {
+                                $info[$groupindex] .= " \n  Version " .
+                                    $package['min'] . ' or newer';
+                            } elseif (isset($package['max'])) {
+                                $info[$groupindex] .= " \n  Version " .
+                                    $package['min'] . ' or older';
+                            }
+                            if (isset($package['recommended'])) {
+                                $info[$groupindex] .= "\n  Recommended version: $package[recommended]";
+                            }
+                            if (isset($package['exclude'])) {
+                                if (!isset($info['Not Compatible with'])) {
+                                    $info['Not Compatible with'] = '';
+                                } else {
+                                    $info[$groupindex] .= "Not Compatible with\n";
+                                }
+                                if (is_array($package['exclude'])) {
+                                    $package['exclude'] = implode(', ', $package['exclude']);
+                                }
+                                $info[$groupindex] .= "  Package $package\n  Versions " .
+                                    $package['exclude'];
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        if ($obj->getPackageType() == 'bundle') {
+            $info['Bundled Packages'] = '';
+            foreach ($obj->getBundledPackages() as $package) {
+                if (!empty($info['Bundled Packages'])) {
+                    $info['Bundled Packages'] .= "\n";
+                }
+                if (isset($package['uri'])) {
+                    $info['Bundled Packages'] .= '__uri/' . $package['name'];
+                    $info['Bundled Packages'] .= "\n  (URI: $package[uri]";
+                } else {
+                    $info['Bundled Packages'] .= $package['channel'] . '/' . $package['name'];
+                }
+            }
+        }
+        $info['package.xml version'] = '2.0';
+        if ($installed) {
+            if ($obj->getLastModified()) {
+                $info['Last Modified'] = date('Y-m-d H:m', $obj->getLastModified());
+            }
+            $v = $obj->getLastInstalledVersion();
+            $info['Last Installed Version'] = $v ? $v : '- None -';
+        }
+        foreach ($info as $key => $value) {
+            $data['data'][] = array($key, $value);
+        }
+        $data['raw'] = $obj->getArray(); // no validation needed
+
+        $this->ui->outputData($data, 'package-info');
+    }
 }
 
 ?>
diff --git a/pear/PEAR/Command/Registry.xml b/pear/PEAR/Command/Registry.xml
new file mode 100644 (file)
index 0000000..57a55b9
--- /dev/null
@@ -0,0 +1,54 @@
+<commands version="1.0">
+ <list>
+  <summary>List Installed Packages In The Default Channel</summary>
+  <function>doList</function>
+  <shortcut>l</shortcut>
+  <options>
+   <channel>
+    <shortopt>c</shortopt>
+    <doc>list installed packages from this channel</doc>
+    <arg>CHAN</arg>
+   </channel>
+   <allchannels>
+    <shortopt>a</shortopt>
+    <doc>list installed packages from all channels</doc>
+   </allchannels>
+  </options>
+  <doc>&lt;package&gt;
+If invoked without parameters, this command lists the PEAR packages
+installed in your php_dir ({config php_dir}).  With a parameter, it
+lists the files in a package.
+</doc>
+ </list>
+ <list-files>
+  <summary>List Files In Installed Package</summary>
+  <function>doFileList</function>
+  <shortcut>fl</shortcut>
+  <options />
+  <doc>&lt;package&gt;
+List the files in an installed package.
+</doc>
+ </list-files>
+ <shell-test>
+  <summary>Shell Script Test</summary>
+  <function>doShellTest</function>
+  <shortcut>st</shortcut>
+  <options />
+  <doc>&lt;package&gt; [[relation] version]
+Tests if a package is installed in the system. Will exit(1) if it is not.
+   &lt;relation&gt;   The version comparison operator. One of:
+                &lt;, lt, &lt;=, le, &gt;, gt, &gt;=, ge, ==, =, eq, !=, &lt;&gt;, ne
+   &lt;version&gt;    The version to compare with
+</doc>
+ </shell-test>
+ <info>
+  <summary>Display information about a package</summary>
+  <function>doInfo</function>
+  <shortcut>in</shortcut>
+  <options />
+  <doc>&lt;package&gt;
+Displays information about a package. The package argument may be a
+local package file, an URL to a package file, or the name of an
+installed package.</doc>
+ </info>
+</commands>
\ No newline at end of file
index 5ff2dc3ae10aa0287fe42fa63d6820f9bd12d263..0b1d09f1b53b26bfee36bc764f21e9b2aee98a25 100644 (file)
@@ -1,29 +1,46 @@
 <?php
-// /* vim: set expandtab tabstop=4 shiftwidth=4: */
-// +----------------------------------------------------------------------+
-// | PHP Version 5                                                        |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2004 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 Bakken <ssb@php.net>                                    |
-// |                                                                      |
-// +----------------------------------------------------------------------+
-//
-// $Id$
-
+/**
+ * PEAR_Command_Remote (remote-info, list-upgrades, remote-list, search, list-all, download,
+ * clear-cache commands)
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 0.1
+ */
+
+/**
+ * base class
+ */
 require_once 'PEAR/Command/Common.php';
-require_once 'PEAR/Common.php';
-require_once 'PEAR/Remote.php';
-require_once 'PEAR/Registry.php';
-
+require_once 'PEAR/REST.php';
+
+/**
+ * PEAR commands for remote server querying
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 0.1
+ */
 class PEAR_Command_Remote extends PEAR_Command_Common
 {
     // {{{ command definitions
@@ -42,15 +59,23 @@ Get details on a package from the server.',
             'function' => 'doListUpgrades',
             'shortcut' => 'lu',
             'options' => array(),
-            'doc' => '
+            'doc' => '[preferred_state]
 List releases on the server of packages you have installed where
-a newer version is available with the same release state (stable etc.).'
+a newer version is available with the same release state (stable etc.)
+or the state passed as the second parameter.'
             ),
         'remote-list' => array(
             'summary' => 'List Remote Packages',
             'function' => 'doRemoteList',
             'shortcut' => 'rl',
-            'options' => array(),
+            'options' => array(
+                'channel' =>
+                    array(
+                    'shortopt' => 'c',
+                    'doc' => 'specify a channel other than the default channel',
+                    'arg' => 'CHAN',
+                    )
+                ),
             'doc' => '
 Lists the packages available on the configured server along with the
 latest stable release of each package.',
@@ -59,16 +84,32 @@ latest stable release of each package.',
             'summary' => 'Search remote package database',
             'function' => 'doSearch',
             'shortcut' => 'sp',
-            'options' => array(),
-            'doc' => '
-Lists all packages which match the search parameters (first param
-is package name, second package info)',
+            'options' => array(
+                'channel' =>
+                    array(
+                    'shortopt' => 'c',
+                    'doc' => 'specify a channel other than the default channel',
+                    'arg' => 'CHAN',
+                    )
+                ),
+            'doc' => '[packagename] [packageinfo]
+Lists all packages which match the search parameters.  The first
+parameter is a fragment of a packagename.  The default channel
+will be used unless explicitly overridden.  The second parameter
+will be used to match any portion of the summary/description',
             ),
         'list-all' => array(
             'summary' => 'List All Packages',
             'function' => 'doListAll',
             'shortcut' => 'la',
-            'options' => array(),
+            'options' => array(
+                'channel' =>
+                    array(
+                    'shortopt' => 'c',
+                    'doc' => 'specify a channel other than the default channel',
+                    'arg' => 'CHAN',
+                    )
+                ),
             'doc' => '
 Lists the packages available on the configured server along with the
 latest stable release of each package.',
@@ -83,18 +124,18 @@ latest stable release of each package.',
                     'doc' => 'download an uncompressed (.tar) file',
                     ),
                 ),
-            'doc' => '{package|package-version}
-Download a package tarball.  The file will be named as suggested by the
+            'doc' => '<package>...
+Download package tarballs.  The files will be named as suggested by the
 server, for example if you download the DB package and the latest stable
-version of DB is 1.2, the downloaded file will be DB-1.2.tgz.',
+version of DB is 1.6.5, the downloaded file will be DB-1.6.5.tgz.',
             ),
         'clear-cache' => array(
-            'summary' => 'Clear XML-RPC Cache',
+            'summary' => 'Clear Web Services Cache',
             'function' => 'doClearCache',
             'shortcut' => 'cc',
             'options' => array(),
             'doc' => '
-Clear the XML-RPC cache.  See also the cache_ttl configuration
+Clear the XML-RPC/REST cache.  See also the cache_ttl configuration
 parameter.
 ',
             ),
@@ -115,6 +156,20 @@ parameter.
 
     // }}}
 
+    function _checkChannelForStatus($channel, $chan)
+    {
+        $rest = new PEAR_REST($this->config);
+        PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+        $a = $rest->downloadHttp('http://' . $channel .
+            '/channel.xml', $chan->lastModified());
+        PEAR::staticPopErrorHandling();
+        if (!PEAR::isError($a) && $a) {
+            $this->ouputData('WARNING: channel "' . $channel . '" has ' .
+                'updated its protocols, use "channel-update ' . $channel .
+                '" to update');
+        }
+    }
+
     // {{{ doRemoteInfo()
 
     function doRemoteInfo($command, $options, $params)
@@ -122,17 +177,42 @@ parameter.
         if (sizeof($params) != 1) {
             return $this->raiseError("$command expects one param: the remote package name");
         }
-        $r = new PEAR_Remote($this->config);
-        $info = $r->call('package.info', $params[0]);
+        $savechannel = $channel = $this->config->get('default_channel');
+        $reg = &$this->config->getRegistry();
+        $package = $params[0];
+        $parsed = $reg->parsePackageName($package, $channel);
+        if (PEAR::isError($parsed)) {
+            return $this->raiseError('Invalid package name "' . $package . '"');
+        }
+        
+        $channel = $parsed['channel'];
+        $this->config->set('default_channel', $channel);
+        $chan = $reg->getChannel($channel);
+        $this->_checkChannelForStatus($channel, $chan);
+        if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
+              $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
+            $rest = &$this->config->getREST('1.0', array());
+            $info = $rest->packageInfo($base, $parsed['package']);
+        } else {
+            $r = &$this->config->getRemote();
+            $info = $r->call('package.info', $parsed['package']);
+        }
         if (PEAR::isError($info)) {
+            $this->config->set('default_channel', $savechannel);
             return $this->raiseError($info);
         }
+        if (!isset($info['name'])) {
+            return $this->raiseError('No remote package "' . $package . '" was found');
+        }
 
-        $reg = new PEAR_Registry($this->config->get('php_dir'));
-        $installed = $reg->packageInfo($info['name']);
+        $installed = $reg->packageInfo($info['name'], null, $channel);
         $info['installed'] = $installed['version'] ? $installed['version'] : '- no -';
+        if (is_array($info['installed'])) {
+            $info['installed'] = $info['installed']['release'];
+        }
 
         $this->ui->outputData($info, $command);
+        $this->config->set('default_channel', $savechannel);
 
         return true;
     }
@@ -142,27 +222,60 @@ parameter.
 
     function doRemoteList($command, $options, $params)
     {
-        $r = new PEAR_Remote($this->config);
+        $savechannel = $channel = $this->config->get('default_channel');
+        $reg = &$this->config->getRegistry();
+        if (isset($options['channel'])) {
+            $channel = $options['channel'];
+            if ($reg->channelExists($channel)) {
+                $this->config->set('default_channel', $channel);
+            } else {
+                return $this->raiseError('Channel "' . $channel . '" does not exist');
+            }
+        }
+        $chan = $reg->getChannel($channel);
+        $this->_checkChannelForStatus($channel, $chan);
         $list_options = false;
-        if ($this->config->get('preferred_state') == 'stable')
+        if ($this->config->get('preferred_state') == 'stable') {
             $list_options = true;
-        $available = $r->call('package.listAll', $list_options);
+        }
+        if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
+              $base = $chan->getBaseURL('REST1.1', $this->config->get('preferred_mirror'))) {
+            // use faster list-all if available
+            $rest = &$this->config->getREST('1.1', array());
+            $available = $rest->listAll($base, $list_options);
+        } elseif ($chan->supportsREST($this->config->get('preferred_mirror')) &&
+              $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
+            $rest = &$this->config->getREST('1.0', array());
+            $available = $rest->listAll($base, $list_options);
+        } else {
+            $r = &$this->config->getRemote();
+            if ($channel == 'pear.php.net') {
+                // hack because of poor pearweb design
+                $available = $r->call('package.listAll', true, $list_options, false);
+            } else {
+                $available = $r->call('package.listAll', true, $list_options);
+            }
+        }
         if (PEAR::isError($available)) {
+            $this->config->set('default_channel', $savechannel);
             return $this->raiseError($available);
         }
         $i = $j = 0;
         $data = array(
-            'caption' => 'Available packages:',
+            'caption' => 'Channel ' . $channel . ' Available packages:',
             'border' => true,
             'headline' => array('Package', 'Version'),
             );
-        foreach ($available as $name => $info) {
-            $data['data'][] = array($name, isset($info['stable']) ? $info['stable'] : '-n/a-');
-        }
         if (count($available)==0) {
-            $data = '(no packages installed yet)';
+            $data = '(no packages available yet)';
+        } else {
+            foreach ($available as $name => $info) {
+                $data['data'][] = array($name, (isset($info['stable']) && $info['stable'])
+                    ? $info['stable'] : '-n/a-');
+            }
         }
         $this->ui->outputData($data, $command);
+        $this->config->set('default_channel', $savechannel);
         return true;
     }
 
@@ -171,40 +284,71 @@ parameter.
 
     function doListAll($command, $options, $params)
     {
-        $r = new PEAR_Remote($this->config);
-        $reg = new PEAR_Registry($this->config->get('php_dir'));
+        $savechannel = $channel = $this->config->get('default_channel');
+        $reg = &$this->config->getRegistry();
+        if (isset($options['channel'])) {
+            $channel = $options['channel'];
+            if ($reg->channelExists($channel)) {
+                $this->config->set('default_channel', $channel);
+            } else {
+                return $this->raiseError("Channel \"$channel\" does not exist");
+            }
+        }
         $list_options = false;
-        if ($this->config->get('preferred_state') == 'stable')
+        if ($this->config->get('preferred_state') == 'stable') {
             $list_options = true;
-        $available = $r->call('package.listAll', $list_options);
-        if (PEAR::isError($available)) {
-            return $this->raiseError($available);
         }
-        if (!is_array($available)) {
-            return $this->raiseError('The package list could not be fetched from the remote server. Please try again. (Debug info: "'.$available.'")');
+        $chan = $reg->getChannel($channel);
+        $this->_checkChannelForStatus($channel, $chan);
+        if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
+              $base = $chan->getBaseURL('REST1.1', $this->config->get('preferred_mirror'))) {
+            // use faster list-all if available
+            $rest = &$this->config->getREST('1.1', array());
+            $available = $rest->listAll($base, $list_options, false);
+        } elseif ($chan->supportsREST($this->config->get('preferred_mirror')) &&
+              $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
+            $rest = &$this->config->getREST('1.0', array());
+            $available = $rest->listAll($base, $list_options, false);
+        } else {
+            $r = &$this->config->getRemote();
+            if ($channel == 'pear.php.net') {
+                // hack because of poor pearweb design
+                $available = $r->call('package.listAll', true, $list_options, false);
+            } else {
+                $available = $r->call('package.listAll', true, $list_options);
+            }
+        }
+        if (PEAR::isError($available)) {
+            $this->config->set('default_channel', $savechannel);
+            return $this->raiseError('The package list could not be fetched from the remote server. Please try again. (Debug info: "' . $available->getMessage() . '")');
         }
         $data = array(
             'caption' => 'All packages:',
             'border' => true,
             'headline' => array('Package', 'Latest', 'Local'),
             );
-        $local_pkgs = $reg->listPackages();
-        
+        $local_pkgs = $reg->listPackages($channel);
+
         foreach ($available as $name => $info) {
-            $installed = $reg->packageInfo($name);
+            $installed = $reg->packageInfo($name, null, $channel);
+            if (is_array($installed['version'])) {
+                $installed['version'] = $installed['version']['release'];
+            }
             $desc = $info['summary'];
-            if (isset($params[$name]))
+            if (isset($params[$name])) {
                 $desc .= "\n\n".$info['description'];
-
+            }
             if (isset($options['mode']))
             {
-                if ($options['mode'] == 'installed' && !isset($installed['version']))
+                if ($options['mode'] == 'installed' && !isset($installed['version'])) {
                     continue;
-                if ($options['mode'] == 'notinstalled' && isset($installed['version']))
+                }
+                if ($options['mode'] == 'notinstalled' && isset($installed['version'])) {
                     continue;
+                }
                 if ($options['mode'] == 'upgrades'
-                    && (!isset($installed['version']) || $installed['version'] == $info['stable']))
-                {
+                      && (!isset($installed['version']) || version_compare($installed['version'],
+                      $info['stable'], '>='))) {
                     continue;
                 }
             }
@@ -213,26 +357,35 @@ parameter.
                 unset($local_pkgs[$pos]);
             }
 
+            if (isset($info['stable']) && !$info['stable']) {
+                $info['stable'] = null;
+            }
             $data['data'][$info['category']][] = array(
-                $name,
+                $reg->channelAlias($channel) . '/' . $name,
                 @$info['stable'],
                 @$installed['version'],
                 @$desc,
                 @$info['deps'],
                 );
         }
-        
+
+        if (isset($options['mode']) && in_array($options['mode'], array('notinstalled', 'upgrades'))) {
+            $this->config->set('default_channel', $savechannel);
+            $this->ui->outputData($data, $command);
+            return true;
+        }
         foreach ($local_pkgs as $name) {
-            $info = $reg->packageInfo($name);
+            $info = &$reg->getPackage($name, $channel);
             $data['data']['Local'][] = array(
-                $info['package'], 
+                $reg->channelAlias($channel) . '/' . $info->getPackage(),
                 '',
-                $info['version'],
-                $info['summary'],
-                @$info['release_deps']
+                $info->getVersion(),
+                $info->getSummary(),
+                $info->getDeps()
                 );
         }
 
+        $this->config->set('default_channel', $savechannel);
         $this->ui->outputData($data, $command);
         return true;
     }
@@ -248,77 +401,105 @@ parameter.
             return $this->raiseError('no valid search string supplied');
         };
 
-        $r = new PEAR_Remote($this->config);
-        $reg = new PEAR_Registry($this->config->get('php_dir'));
-        $available = $r->call('package.listAll', true, false);
+        $savechannel = $channel = $this->config->get('default_channel');
+        $reg = &$this->config->getRegistry();
+        $package = $params[0];
+        $summary = isset($params[1]) ? $params[1] : false;
+        if (isset($options['channel'])) {
+            $reg = &$this->config->getRegistry();
+            $channel = $options['channel'];
+            if ($reg->channelExists($channel)) {
+                $this->config->set('default_channel', $channel);
+            } else {
+                return $this->raiseError('Channel "' . $channel . '" does not exist');
+            }
+        }
+        $chan = $reg->getChannel($channel);
+        $this->_checkChannelForStatus($channel, $chan);
+        if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
+              $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
+            $rest = &$this->config->getREST('1.0', array());
+            $available = $rest->listAll($base, false, false, $package, $summary);
+        } else {
+            $r = &$this->config->getRemote();
+            $available = $r->call('package.search', $package, $summary, true, 
+                $this->config->get('preferred_state') == 'stable', true);
+        }
         if (PEAR::isError($available)) {
+            $this->config->set('default_channel', $savechannel);
             return $this->raiseError($available);
         }
+        if (!$available) {
+            return $this->raiseError('no packages found that match pattern "' . $package . '"');
+        }
         $data = array(
-            'caption' => 'Matched packages:',
+            'caption' => 'Matched packages, channel ' . $channel . ':',
             'border' => true,
             'headline' => array('Package', 'Stable/(Latest)', 'Local'),
             );
 
         foreach ($available as $name => $info) {
-            $found = (!empty($params[0]) && stristr($name, $params[0]) !== false);
-            if (!$found && !(isset($params[1]) && !empty($params[1])
-                && (stristr($info['summary'], $params[1]) !== false
-                    || stristr($info['description'], $params[1]) !== false)))
-            {
-                continue;
-            };
-
-            $installed = $reg->packageInfo($name);
+            $installed = $reg->packageInfo($name, null, $channel);
             $desc = $info['summary'];
             if (isset($params[$name]))
                 $desc .= "\n\n".$info['description'];
 
             $unstable = '';
             if ($info['unstable']) {
-                $unstable = '/(' . $info['unstable'] . $info['state'] . ')';
+                $unstable = '/(' . $info['unstable'] . ' ' . $info['state'] . ')';
             }
             if (!isset($info['stable']) || !$info['stable']) {
                 $info['stable'] = 'none';
             }
+            $version = is_array($installed['version']) ? $installed['version']['release'] :
+                $installed['version'];
             $data['data'][$info['category']][] = array(
                 $name,
                 $info['stable'] . $unstable,
-                $installed['version'],
+                $version,
                 $desc,
                 );
         }
-        if (!isset($data['data'])) {
-            return $this->raiseError('no packages found');
-        }
         $this->ui->outputData($data, $command);
+        $this->config->set('default_channel', $channel);
         return true;
     }
 
     // }}}
+    function &getDownloader($options)
+    {
+        if (!class_exists('PEAR_Downloader')) {
+            require_once 'PEAR/Downloader.php';
+        }
+        $a = &new PEAR_Downloader($this->ui, $options, $this->config);
+        return $a;
+    }
     // {{{ doDownload()
 
     function doDownload($command, $options, $params)
     {
-        //$params[0] -> The package to download
-        if (count($params) != 1) {
-            return PEAR::raiseError("download expects one argument: the package to download");
-        }
-        $server = $this->config->get('master_server');
-        if (!ereg('^http://', $params[0])) {
-            $getoption = isset($options['nocompress'])&&$options['nocompress']==1?'?uncompress=on':'';
-            $pkgfile = "http://$server/get/$params[0]".$getoption;
-        } else {
-            $pkgfile = $params[0];
+        // make certain that dependencies are ignored
+        $options['downloadonly'] = 1;
+        $downloader = &$this->getDownloader($options);
+        $downloader->setDownloadDir(getcwd());
+        $errors = array();
+        $downloaded = array();
+        $err = $downloader->download($params);
+        if (PEAR::isError($err)) {
+            return $err;
+        }
+        $errors = $downloader->getErrorMsgs();
+        if (count($errors)) {
+            $errinfo = array();
+            $errinfo['data'] = array($errors);
+            $errinfo['headline'] = 'Download Errors';
+            $this->ui->outputData($errinfo);
+            return $this->raiseError("$command failed");
         }
-        $this->bytes_downloaded = 0;
-        $saved = PEAR_Common::downloadHttp($pkgfile, $this->ui, '.',
-                                           array(&$this, 'downloadCallback'));
-        if (PEAR::isError($saved)) {
-            return $this->raiseError($saved);
+        $downloaded = $downloader->getDownloadedPackages();
+        foreach ($downloaded as $pkg) {
+            $this->ui->outputData("File $pkg[file] downloaded", $command);
         }
-        $fname = basename($saved);
-        $this->ui->outputData("File $fname downloaded ($this->bytes_downloaded bytes)", $command);
         return true;
     }
 
@@ -334,61 +515,91 @@ parameter.
 
     function doListUpgrades($command, $options, $params)
     {
-        include_once "PEAR/Registry.php";
-        $remote = new PEAR_Remote($this->config);
-        if (empty($params[0])) {
-            $state = $this->config->get('preferred_state');
-        } else {
-            $state = $params[0];
-        }
-        $caption = 'Available Upgrades';
-        if (empty($state) || $state == 'any') {
-            $latest = $remote->call("package.listLatestReleases");
-        } else {
-            $latest = $remote->call("package.listLatestReleases", $state);
-            $caption .= ' (' . implode(', ', PEAR_Common::betterStates($state, true)) . ')';
-        }
-        $caption .= ':';
-        if (PEAR::isError($latest)) {
-            return $latest;
-        }
-        $reg = new PEAR_Registry($this->config->get('php_dir'));
-        $inst = array_flip($reg->listPackages());
-        $data = array(
-            'caption' => $caption,
-            'border' => 1,
-            'headline' => array('Package', 'Local', 'Remote', 'Size'),
-            );
-        foreach ((array)$latest as $pkg => $info) {
-            $package = strtolower($pkg);
-            if (!isset($inst[$package])) {
-                // skip packages we don't have installed
+        require_once 'PEAR/Common.php';
+        $savechannel = $channel = $this->config->get('default_channel');
+        $reg = &$this->config->getRegistry();
+        foreach ($reg->listChannels() as $channel) {
+            $inst = array_flip($reg->listPackages($channel));
+            if (!count($inst)) {
                 continue;
             }
-            extract($info);
-            $pkginfo = $reg->packageInfo($package);
-            $inst_version = $pkginfo['version'];
-            $inst_state   = $pkginfo['release_state'];
-            if (version_compare("$version", "$inst_version", "le")) {
-                // installed version is up-to-date
+            if ($channel == '__uri') {
                 continue;
             }
-            if ($filesize >= 20480) {
-                $filesize += 1024 - ($filesize % 1024);
-                $fs = sprintf("%dkB", $filesize / 1024);
-            } elseif ($filesize > 0) {
-                $filesize += 103 - ($filesize % 103);
-                $fs = sprintf("%.1fkB", $filesize / 1024.0);
+            $this->config->set('default_channel', $channel);
+            if (empty($params[0])) {
+                $state = $this->config->get('preferred_state');
             } else {
-                $fs = "  -"; // XXX center instead
+                $state = $params[0];
+            }
+            $caption = $channel . ' Available Upgrades';
+            $chan = $reg->getChannel($channel);
+            $this->_checkChannelForStatus($channel, $chan);
+            if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
+                  $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
+                $rest = &$this->config->getREST('1.0', array());
+                if (empty($state) || $state == 'any') {
+                    $state = false;
+                } else {
+                    $caption .= ' (' . implode(', ', PEAR_Common::betterStates($state, true)) . ')';
+                }
+                $latest = $rest->listLatestUpgrades($base, $state, $inst, $channel, $reg);
+            } else {
+                $remote = &$this->config->getRemote();
+                $remote->pushErrorHandling(PEAR_ERROR_RETURN);
+                if (empty($state) || $state == 'any') {
+                    $latest = $remote->call("package.listLatestReleases");
+                } else {
+                    $latest = $remote->call("package.listLatestReleases", $state);
+                    $caption .= ' (' . implode(', ', PEAR_Common::betterStates($state, true)) . ')';
+                }
+                $remote->popErrorHandling();
+            }
+            if (PEAR::isError($latest)) {
+                $this->ui->outputData($latest->getMessage());
+                continue;
+            }
+            $caption .= ':';
+            if (PEAR::isError($latest)) {
+                $this->config->set('default_channel', $savechannel);
+                return $latest;
+            }
+            $data = array(
+                'caption' => $caption,
+                'border' => 1,
+                'headline' => array('Channel', 'Package', 'Local', 'Remote', 'Size'),
+                );
+            foreach ((array)$latest as $pkg => $info) {
+                $package = strtolower($pkg);
+                if (!isset($inst[$package])) {
+                    // skip packages we don't have installed
+                    continue;
+                }
+                extract($info);
+                $inst_version = $reg->packageInfo($package, 'version', $channel);
+                $inst_state   = $reg->packageInfo($package, 'release_state', $channel);
+                if (version_compare("$version", "$inst_version", "le")) {
+                    // installed version is up-to-date
+                    continue;
+                }
+                if ($filesize >= 20480) {
+                    $filesize += 1024 - ($filesize % 1024);
+                    $fs = sprintf("%dkB", $filesize / 1024);
+                } elseif ($filesize > 0) {
+                    $filesize += 103 - ($filesize % 103);
+                    $fs = sprintf("%.1fkB", $filesize / 1024.0);
+                } else {
+                    $fs = "  -"; // XXX center instead
+                }
+                $data['data'][] = array($channel, $pkg, "$inst_version ($inst_state)", "$version ($state)", $fs);
+            }
+            if (empty($data['data'])) {
+                $this->ui->outputData('Channel ' . $channel . ': No upgrades available');
+            } else {
+                $this->ui->outputData($data, $command);
             }
-            $data['data'][] = array($pkg, "$inst_version ($inst_state)", "$version ($state)", $fs);
-        }
-        if (empty($data['data'])) {
-            $this->ui->outputData('No upgrades available');
-        } else {
-            $this->ui->outputData($data, $command);
         }
+        $this->config->set('default_channel', $savechannel);
         return true;
     }
 
@@ -408,7 +619,8 @@ parameter.
         }
         $num = 0;
         while ($ent = readdir($dp)) {
-            if (preg_match('/^xmlrpc_cache_[a-z0-9]{32}$/', $ent)) {
+            if (preg_match('/^xmlrpc_cache_[a-z0-9]{32}$/', $ent) ||
+                  preg_match('/rest.cache(file|id)$/', $ent)) {
                 $path = $cache_dir . DIRECTORY_SEPARATOR . $ent;
                 $ok = @unlink($path);
                 if ($ok) {
diff --git a/pear/PEAR/Command/Remote.xml b/pear/PEAR/Command/Remote.xml
new file mode 100644 (file)
index 0000000..7c43a88
--- /dev/null
@@ -0,0 +1,92 @@
+<commands version="1.0">
+ <remote-info>
+  <summary>Information About Remote Packages</summary>
+  <function>doRemoteInfo</function>
+  <shortcut>ri</shortcut>
+  <options />
+  <doc>&lt;package&gt;
+Get details on a package from the server.</doc>
+ </remote-info>
+ <list-upgrades>
+  <summary>List Available Upgrades</summary>
+  <function>doListUpgrades</function>
+  <shortcut>lu</shortcut>
+  <options />
+  <doc>[preferred_state]
+List releases on the server of packages you have installed where
+a newer version is available with the same release state (stable etc.)
+or the state passed as the second parameter.</doc>
+ </list-upgrades>
+ <remote-list>
+  <summary>List Remote Packages</summary>
+  <function>doRemoteList</function>
+  <shortcut>rl</shortcut>
+  <options>
+   <channel>
+    <shortopt>c</shortopt>
+    <doc>specify a channel other than the default channel</doc>
+    <arg>CHAN</arg>
+   </channel>
+  </options>
+  <doc>
+Lists the packages available on the configured server along with the
+latest stable release of each package.</doc>
+ </remote-list>
+ <search>
+  <summary>Search remote package database</summary>
+  <function>doSearch</function>
+  <shortcut>sp</shortcut>
+  <options>
+   <channel>
+    <shortopt>c</shortopt>
+    <doc>specify a channel other than the default channel</doc>
+    <arg>CHAN</arg>
+   </channel>
+  </options>
+  <doc>[packagename] [packageinfo]
+Lists all packages which match the search parameters.  The first
+parameter is a fragment of a packagename.  The default channel
+will be used unless explicitly overridden.  The second parameter
+will be used to match any portion of the summary/description</doc>
+ </search>
+ <list-all>
+  <summary>List All Packages</summary>
+  <function>doListAll</function>
+  <shortcut>la</shortcut>
+  <options>
+   <channel>
+    <shortopt>c</shortopt>
+    <doc>specify a channel other than the default channel</doc>
+    <arg>CHAN</arg>
+   </channel>
+  </options>
+  <doc>
+Lists the packages available on the configured server along with the
+latest stable release of each package.</doc>
+ </list-all>
+ <download>
+  <summary>Download Package</summary>
+  <function>doDownload</function>
+  <shortcut>d</shortcut>
+  <options>
+   <nocompress>
+    <shortopt>Z</shortopt>
+    <doc>download an uncompressed (.tar) file</doc>
+   </nocompress>
+  </options>
+  <doc>&lt;package&gt;...
+Download package tarballs.  The files will be named as suggested by the
+server, for example if you download the DB package and the latest stable
+version of DB is 1.6.5, the downloaded file will be DB-1.6.5.tgz.</doc>
+ </download>
+ <clear-cache>
+  <summary>Clear Web Services Cache</summary>
+  <function>doClearCache</function>
+  <shortcut>cc</shortcut>
+  <options />
+  <doc>
+Clear the XML-RPC/REST cache.  See also the cache_ttl configuration
+parameter.
+</doc>
+ </clear-cache>
+</commands>
\ No newline at end of file
diff --git a/pear/PEAR/Command/Test.php b/pear/PEAR/Command/Test.php
new file mode 100644 (file)
index 0000000..4759ce8
--- /dev/null
@@ -0,0 +1,257 @@
+<?php
+/**
+ * PEAR_Command_Test (run-tests)
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Martin Jansen <mj@php.net>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 0.1
+ */
+
+/**
+ * base class
+ */
+require_once 'PEAR/Command/Common.php';
+
+/**
+ * PEAR commands for login/logout
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Martin Jansen <mj@php.net>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 0.1
+ */
+
+class PEAR_Command_Test extends PEAR_Command_Common
+{
+    // {{{ properties
+
+    var $commands = array(
+        'run-tests' => array(
+            'summary' => 'Run Regression Tests',
+            'function' => 'doRunTests',
+            'shortcut' => 'rt',
+            'options' => array(
+                'recur' => array(
+                    'shortopt' => 'r',
+                    'doc' => 'Run tests in child directories, recursively.  4 dirs deep maximum',
+                ),
+                'ini' => array(
+                    'shortopt' => 'i',
+                    'doc' => 'actual string of settings to pass to php in format " -d setting=blah"',
+                    'arg' => 'SETTINGS'
+                ),
+                'realtimelog' => array(
+                    'shortopt' => 'l',
+                    'doc' => 'Log test runs/results as they are run',
+                ),
+                'quiet' => array(
+                    'shortopt' => 'q',
+                    'doc' => 'Only display detail for failed tests',
+                ),
+                'simple' => array(
+                    'shortopt' => 's',
+                    'doc' => 'Display simple output for all tests',
+                ),
+                'package' => array(
+                    'shortopt' => 'p',
+                    'doc' => 'Treat parameters as installed packages from which to run tests',
+                ),
+            ),
+            'doc' => '[testfile|dir ...]
+Run regression tests with PHP\'s regression testing script (run-tests.php).',
+            ),
+        );
+
+    var $output;
+
+    // }}}
+    // {{{ constructor
+
+    /**
+     * PEAR_Command_Test constructor.
+     *
+     * @access public
+     */
+    function PEAR_Command_Test(&$ui, &$config)
+    {
+        parent::PEAR_Command_Common($ui, $config);
+    }
+
+    // }}}
+    // {{{ doRunTests()
+
+    function doRunTests($command, $options, $params)
+    {
+        require_once 'PEAR/Common.php';
+        require_once 'PEAR/RunTest.php';
+        require_once 'System.php';
+        $log = new PEAR_Common;
+        $log->ui = &$this->ui; // slightly hacky, but it will work
+        $run = new PEAR_RunTest($log, $options);
+        $tests = array();
+        if (isset($options['recur'])) {
+            $depth = 4;
+        } else {
+            $depth = 1;
+        }
+        if (!count($params)) {
+            $params[] = '.';
+        }
+        if (isset($options['package'])) {
+            $oldparams = $params;
+            $params = array();
+            $reg = &$this->config->getRegistry();
+            foreach ($oldparams as $param) {
+                $pname = $reg->parsePackageName($param, $this->config->get('default_channel'));
+                if (PEAR::isError($pname)) {
+                    return $this->raiseError($pname);
+                }
+                $package = &$reg->getPackage($pname['package'], $pname['channel']);
+                if (!$package) {
+                    return PEAR::raiseError('Unknown package "' .
+                        $reg->parsedPackageNameToString($pname) . '"');
+                }
+                $filelist = $package->getFilelist();
+                foreach ($filelist as $name => $atts) {
+                    if (isset($atts['role']) && $atts['role'] != 'test') {
+                        continue;
+                    }
+                    if (!preg_match('/\.phpt$/', $name)) {
+                        continue;
+                    }
+                    $params[] = $atts['installed_as'];
+                }
+            }
+        }
+        foreach ($params as $p) {
+            if (is_dir($p)) {
+                $dir = System::find(array($p, '-type', 'f',
+                                            '-maxdepth', $depth,
+                                            '-name', '*.phpt'));
+                $tests = array_merge($tests, $dir);
+            } else {
+                if (!@file_exists($p)) {
+                    if (!preg_match('/\.phpt$/', $p)) {
+                        $p .= '.phpt';
+                    }
+                    $dir = System::find(array(dirname($p), '-type', 'f',
+                                                '-maxdepth', $depth,
+                                                '-name', $p));
+                    $tests = array_merge($tests, $dir);
+                } else {
+                    $tests[] = $p;
+                }
+            }
+        }
+        $ini_settings = '';
+        if (isset($options['ini'])) {
+            $ini_settings .= $options['ini'];
+        }
+        if (isset($_ENV['TEST_PHP_INCLUDE_PATH'])) {
+            $ini_settings .= " -d include_path={$_ENV['TEST_PHP_INCLUDE_PATH']}";
+        }
+        if ($ini_settings) {
+            $this->ui->outputData('Using INI settings: "' . $ini_settings . '"');
+        }
+        $skipped = $passed = $failed = array();
+        $this->ui->outputData('Running ' . count($tests) . ' tests', $command);
+        $start = time();
+        if (isset($options['realtimelog'])) {
+            @unlink('run-tests.log');
+        }
+        foreach ($tests as $t) {
+            if (isset($options['realtimelog'])) {
+                $fp = @fopen('run-tests.log', 'a');
+                if ($fp) {
+                    fwrite($fp, "Running test $t...");
+                    fclose($fp);
+                }
+            }
+            PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+            $result = $run->run($t, $ini_settings);
+            PEAR::staticPopErrorHandling();
+            if (PEAR::isError($result)) {
+                $this->ui->log(0, $result->getMessage());
+                continue;
+            }
+            if (OS_WINDOWS) {
+                for($i=0;$i<2000;$i++) {
+                    $i = $i; // delay - race conditions on windows
+                }
+            }
+            if (isset($options['realtimelog'])) {
+                $fp = @fopen('run-tests.log', 'a');
+                if ($fp) {
+                    fwrite($fp, "$result\n");
+                    fclose($fp);
+                }
+            }
+            if ($result == 'FAILED') {
+               $failed[] = $t;
+            }
+            if ($result == 'PASSED') {
+               $passed[] = $t;
+            }
+            if ($result == 'SKIPPED') {
+               $skipped[] = $t;
+            }
+        }
+        $total = date('i:s', time() - $start);
+        if (count($failed)) {
+            $output = "TOTAL TIME: $total\n";
+            $output .= count($passed) . " PASSED TESTS\n";
+            $output .= count($skipped) . " SKIPPED TESTS\n";
+               $output .= count($failed) . " FAILED TESTS:\n";
+               foreach ($failed as $failure) {
+                       $output .= $failure . "\n";
+               }
+            if (isset($options['realtimelog'])) {
+                $fp = @fopen('run-tests.log', 'a');
+            } else {
+                $fp = @fopen('run-tests.log', 'w');
+            }
+            if ($fp) {
+                fwrite($fp, $output, strlen($output));
+                fclose($fp);
+                $this->ui->outputData('wrote log to "' . realpath('run-tests.log') . '"', $command);
+            }
+        } elseif (@file_exists('run-tests.log') && !@is_dir('run-tests.log')) {
+            @unlink('run-tests.log');
+        }
+        $this->ui->outputData('TOTAL TIME: ' . $total);
+        $this->ui->outputData(count($passed) . ' PASSED TESTS', $command);
+        $this->ui->outputData(count($skipped) . ' SKIPPED TESTS', $command);
+        if (count($failed)) {
+               $this->ui->outputData(count($failed) . ' FAILED TESTS:', $command);
+               foreach ($failed as $failure) {
+                       $this->ui->outputData($failure, $command);
+               }
+        }
+
+        return true;
+    }
+    // }}}
+}
+
+?>
diff --git a/pear/PEAR/Command/Test.xml b/pear/PEAR/Command/Test.xml
new file mode 100644 (file)
index 0000000..30659bc
--- /dev/null
@@ -0,0 +1,36 @@
+<commands version="1.0">
+ <run-tests>
+  <summary>Run Regression Tests</summary>
+  <function>doRunTests</function>
+  <shortcut>rt</shortcut>
+  <options>
+   <recur>
+    <shortopt>r</shortopt>
+    <doc>Run tests in child directories, recursively.  4 dirs deep maximum</doc>
+   </recur>
+   <ini>
+    <shortopt>i</shortopt>
+    <doc>actual string of settings to pass to php in format &quot; -d setting=blah&quot;</doc>
+    <arg>SETTINGS</arg>
+   </ini>
+   <realtimelog>
+    <shortopt>l</shortopt>
+    <doc>Log test runs/results as they are run</doc>
+   </realtimelog>
+   <quiet>
+    <shortopt>q</shortopt>
+    <doc>Only display detail for failed tests</doc>
+   </quiet>
+   <simple>
+    <shortopt>s</shortopt>
+    <doc>Display simple output for all tests</doc>
+   </simple>
+   <package>
+    <shortopt>p</shortopt>
+    <doc>Treat parameters as installed packages from which to run tests</doc>
+   </package>
+  </options>
+  <doc>[testfile|dir ...]
+Run regression tests with PHP&apos;s regression testing script (run-tests.php).</doc>
+ </run-tests>
+</commands>
\ No newline at end of file
index cfb73c6031864d5f461d938ec8e8d00a1db9feaa..adbac84853b0e3ad27a39bec735665c59bec0b3d 100644 (file)
@@ -1,28 +1,32 @@
 <?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>                             |
-// +----------------------------------------------------------------------+
-//
-// $Id$
+/**
+ * PEAR_Common, the base class for the PEAR Installer
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Tomas V. V. Cox <cox@idecnet.com>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 0.1.0
+ * @deprecated File deprecated since Release 1.4.0a1
+ */
 
+/**
+ * Include error handling
+ */
 require_once 'PEAR.php';
-require_once 'Archive/Tar.php';
-require_once 'System.php';
-require_once 'PEAR/Config.php';
 
 // {{{ constants and globals
 
@@ -38,7 +42,25 @@ define('_PEAR_COMMON_PACKAGE_VERSION_PREG', '\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?');
 define('PEAR_COMMON_PACKAGE_VERSION_PREG', '/^' . _PEAR_COMMON_PACKAGE_VERSION_PREG . '$/i');
 
 // XXX far from perfect :-)
-define('PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '/^(' . _PEAR_COMMON_PACKAGE_NAME_PREG . ')(-([.0-9a-zA-Z]+))?$/');
+define('_PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '(' . _PEAR_COMMON_PACKAGE_NAME_PREG .
+    ')(-([.0-9a-zA-Z]+))?');
+define('PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_PACKAGE_DOWNLOAD_PREG .
+    '$/');
+
+define('_PEAR_CHANNELS_NAME_PREG', '[A-Za-z][a-zA-Z0-9_\.]+');
+define('PEAR_CHANNELS_NAME_PREG', '/^' . _PEAR_CHANNELS_NAME_PREG . '$/');
+
+// this should allow any dns or IP address, plus a path - NO UNDERSCORES ALLOWED
+define('_PEAR_CHANNELS_SERVER_PREG', '[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*(\/[a-zA-Z0-9-]+)*');
+define('PEAR_CHANNELS_SERVER_PREG', '/^' . _PEAR_CHANNELS_SERVER_PREG . '$/i');
+
+define('_PEAR_CHANNELS_PACKAGE_PREG',  '(' ._PEAR_CHANNELS_SERVER_PREG . ')\/('
+         . _PEAR_COMMON_PACKAGE_NAME_PREG . ')');
+define('PEAR_CHANNELS_PACKAGE_PREG', '/^' . _PEAR_CHANNELS_PACKAGE_PREG . '$/i');
+
+define('_PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '(' . _PEAR_CHANNELS_NAME_PREG . ')::('
+    . _PEAR_COMMON_PACKAGE_NAME_PREG . ')(-([.0-9a-zA-Z]+))?');
+define('PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_CHANNEL_DOWNLOAD_PREG . '$/');
 
 /**
  * List of temporary files and directories registered by
@@ -99,8 +121,18 @@ $GLOBALS['_PEAR_Common_script_phases'] = array('pre-install', 'post-install', 'p
 
 /**
  * Class providing common functionality for PEAR administration classes.
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Tomas V. V. Cox <cox@idecnet.com>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
  * @deprecated This class will disappear, and its components will be spread
- *             into smaller classes, like the AT&T breakup
+ *             into smaller classes, like the AT&T breakup, as of Release 1.4.0a1
  */
 class PEAR_Common extends PEAR
 {
@@ -176,6 +208,9 @@ class PEAR_Common extends PEAR
         $tempfiles =& $GLOBALS['_PEAR_Common_tempfiles'];
         while ($file = array_shift($tempfiles)) {
             if (@is_dir($file)) {
+                if (!class_exists('System')) {
+                    require_once 'System.php';
+                }
                 System::rm(array('-rf', $file));
             } elseif (file_exists($file)) {
                 unlink($file);
@@ -199,7 +234,10 @@ class PEAR_Common extends PEAR
      */
     function addTempFile($file)
     {
-        $GLOBALS['_PEAR_Common_tempfiles'][] = $file;
+        if (!class_exists('PEAR_Frontend')) {
+            require_once 'PEAR/Frontend.php';
+        }
+        PEAR_Frontend::addTempFile($file);
     }
 
     // }}}
@@ -218,6 +256,9 @@ class PEAR_Common extends PEAR
     function mkDirHier($dir)
     {
         $this->log(2, "+ create dir $dir");
+        if (!class_exists('System')) {
+            require_once 'System.php';
+        }
         return System::mkDir(array('-p', $dir));
     }
 
@@ -233,12 +274,17 @@ class PEAR_Common extends PEAR
      * @return void
      *
      * @access public
+     * @static
      */
     function log($level, $msg, $append_crlf = true)
     {
         if ($this->debug >= $level) {
-            if (is_object($this->ui)) {
-                $this->ui->log($msg, $append_crlf);
+            if (!class_exists('PEAR_Frontend')) {
+                require_once 'PEAR/Frontend.php';
+            }
+            $ui = &PEAR_Frontend::singleton();
+            if (is_a($ui, 'PEAR_Frontend')) {
+                $ui->log($msg, $append_crlf);
             } else {
                 print "$msg\n";
             }
@@ -267,6 +313,9 @@ class PEAR_Common extends PEAR
             $topt = array();
         }
         $topt = array_merge($topt, array('-d', 'pear'));
+        if (!class_exists('System')) {
+            require_once 'System.php';
+        }
         if (!$tmpdir = System::mktemp($topt)) {
             return false;
         }
@@ -291,396 +340,6 @@ class PEAR_Common extends PEAR
 
     // }}}
 
-    // {{{ _unIndent()
-
-    /**
-     * Unindent given string (?)
-     *
-     * @param string $str The string that has to be unindented.
-     * @return string
-     * @access private
-     */
-    function _unIndent($str)
-    {
-        // remove leading newlines
-        $str = preg_replace('/^[\r\n]+/', '', $str);
-        // find whitespace at the beginning of the first line
-        $indent_len = strspn($str, " \t");
-        $indent = substr($str, 0, $indent_len);
-        $data = '';
-        // remove the same amount of whitespace from following lines
-        foreach (explode("\n", $str) as $line) {
-            if (substr($line, 0, $indent_len) == $indent) {
-                $data .= substr($line, $indent_len) . "\n";
-            }
-        }
-        return $data;
-    }
-
-    // }}}
-    // {{{ _element_start()
-
-    /**
-     * XML parser callback for starting elements.  Used while package
-     * format version is not yet known.
-     *
-     * @param resource  $xp       XML parser resource
-     * @param string    $name     name of starting element
-     * @param array     $attribs  element attributes, name => value
-     *
-     * @return void
-     *
-     * @access private
-     */
-    function _element_start($xp, $name, $attribs)
-    {
-        array_push($this->element_stack, $name);
-        $this->current_element = $name;
-        $spos = sizeof($this->element_stack) - 2;
-        $this->prev_element = ($spos >= 0) ? $this->element_stack[$spos] : '';
-        $this->current_attributes = $attribs;
-        switch ($name) {
-            case 'package': {
-                $this->_validPackageFile = true;
-                if (isset($attribs['version'])) {
-                    $vs = preg_replace('/[^0-9a-z]/', '_', $attribs['version']);
-                } else {
-                    $vs = '1_0';
-                }
-                $elem_start = '_element_start_'. $vs;
-                $elem_end = '_element_end_'. $vs;
-                $cdata = '_pkginfo_cdata_'. $vs;
-                if (!method_exists($this, $elem_start) ||
-                      !method_exists($this, $elem_end) ||
-                      !method_exists($this, $cdata)) {
-                    $this->raiseError("No handlers for package.xml version $attribs[version]");
-                    return;
-                }
-                xml_set_element_handler($xp, $elem_start, $elem_end);
-                xml_set_character_data_handler($xp, $cdata);
-                break;
-            }
-        }
-    }
-
-    // }}}
-    // {{{ _element_end()
-
-    /**
-     * XML parser callback for ending elements.  Used while package
-     * format version is not yet known.
-     *
-     * @param resource  $xp    XML parser resource
-     * @param string    $name  name of ending element
-     *
-     * @return void
-     *
-     * @access private
-     */
-    function _element_end($xp, $name)
-    {
-    }
-
-    // }}}
-
-    // Support for package DTD v1.0:
-    // {{{ _element_start_1_0()
-
-    /**
-     * XML parser callback for ending elements.  Used for version 1.0
-     * packages.
-     *
-     * @param resource  $xp    XML parser resource
-     * @param string    $name  name of ending element
-     *
-     * @return void
-     *
-     * @access private
-     */
-    function _element_start_1_0($xp, $name, $attribs)
-    {
-        array_push($this->element_stack, $name);
-        $this->current_element = $name;
-        $spos = sizeof($this->element_stack) - 2;
-        $this->prev_element = ($spos >= 0) ? $this->element_stack[$spos] : '';
-        $this->current_attributes = $attribs;
-        $this->cdata = '';
-        switch ($name) {
-            case 'dir':
-                if ($this->in_changelog) {
-                    break;
-                }
-                if ($attribs['name'] != '/') {
-                    $this->dir_names[] = $attribs['name'];
-                }
-                if (isset($attribs['baseinstalldir'])) {
-                    $this->dir_install = $attribs['baseinstalldir'];
-                }
-                if (isset($attribs['role'])) {
-                    $this->dir_role = $attribs['role'];
-                }
-                break;
-            case 'file':
-                if ($this->in_changelog) {
-                    break;
-                }
-                if (isset($attribs['name'])) {
-                    $path = '';
-                    if (count($this->dir_names)) {
-                        foreach ($this->dir_names as $dir) {
-                            $path .= $dir . DIRECTORY_SEPARATOR;
-                        }
-                    }
-                    $path .= $attribs['name'];
-                    unset($attribs['name']);
-                    $this->current_path = $path;
-                    $this->filelist[$path] = $attribs;
-                    // Set the baseinstalldir only if the file don't have this attrib
-                    if (!isset($this->filelist[$path]['baseinstalldir']) &&
-                        isset($this->dir_install))
-                    {
-                        $this->filelist[$path]['baseinstalldir'] = $this->dir_install;
-                    }
-                    // Set the Role
-                    if (!isset($this->filelist[$path]['role']) && isset($this->dir_role)) {
-                        $this->filelist[$path]['role'] = $this->dir_role;
-                    }
-                }
-                break;
-            case 'replace':
-                if (!$this->in_changelog) {
-                    $this->filelist[$this->current_path]['replacements'][] = $attribs;
-                }
-                break;
-            case 'maintainers':
-                $this->pkginfo['maintainers'] = array();
-                $this->m_i = 0; // maintainers array index
-                break;
-            case 'maintainer':
-                // compatibility check
-                if (!isset($this->pkginfo['maintainers'])) {
-                    $this->pkginfo['maintainers'] = array();
-                    $this->m_i = 0;
-                }
-                $this->pkginfo['maintainers'][$this->m_i] = array();
-                $this->current_maintainer =& $this->pkginfo['maintainers'][$this->m_i];
-                break;
-            case 'changelog':
-                $this->pkginfo['changelog'] = array();
-                $this->c_i = 0; // changelog array index
-                $this->in_changelog = true;
-                break;
-            case 'release':
-                if ($this->in_changelog) {
-                    $this->pkginfo['changelog'][$this->c_i] = array();
-                    $this->current_release = &$this->pkginfo['changelog'][$this->c_i];
-                } else {
-                    $this->current_release = &$this->pkginfo;
-                }
-                break;
-            case 'deps':
-                if (!$this->in_changelog) {
-                    $this->pkginfo['release_deps'] = array();
-                }
-                break;
-            case 'dep':
-                // dependencies array index
-                if (!$this->in_changelog) {
-                    $this->d_i++;
-                    $this->pkginfo['release_deps'][$this->d_i] = $attribs;
-                }
-                break;
-            case 'configureoptions':
-                if (!$this->in_changelog) {
-                    $this->pkginfo['configure_options'] = array();
-                }
-                break;
-            case 'configureoption':
-                if (!$this->in_changelog) {
-                    $this->pkginfo['configure_options'][] = $attribs;
-                }
-                break;
-            case 'provides':
-                if (empty($attribs['type']) || empty($attribs['name'])) {
-                    break;
-                }
-                $attribs['explicit'] = true;
-                $this->pkginfo['provides']["$attribs[type];$attribs[name]"] = $attribs;
-                break;
-        }
-    }
-
-    // }}}
-    // {{{ _element_end_1_0()
-
-    /**
-     * XML parser callback for ending elements.  Used for version 1.0
-     * packages.
-     *
-     * @param resource  $xp    XML parser resource
-     * @param string    $name  name of ending element
-     *
-     * @return void
-     *
-     * @access private
-     */
-    function _element_end_1_0($xp, $name)
-    {
-        $data = trim($this->cdata);
-        switch ($name) {
-            case 'name':
-                switch ($this->prev_element) {
-                    case 'package':
-                        // XXX should we check the package name here?
-                        $this->pkginfo['package'] = ereg_replace('[^a-zA-Z0-9._]', '_', $data);
-                        break;
-                    case 'maintainer':
-                        $this->current_maintainer['name'] = $data;
-                        break;
-                }
-                break;
-            case 'summary':
-                $this->pkginfo['summary'] = $data;
-                break;
-            case 'description':
-                $data = $this->_unIndent($this->cdata);
-                $this->pkginfo['description'] = $data;
-                break;
-            case 'user':
-                $this->current_maintainer['handle'] = $data;
-                break;
-            case 'email':
-                $this->current_maintainer['email'] = $data;
-                break;
-            case 'role':
-                $this->current_maintainer['role'] = $data;
-                break;
-            case 'version':
-                $data = ereg_replace ('[^a-zA-Z0-9._\-]', '_', $data);
-                if ($this->in_changelog) {
-                    $this->current_release['version'] = $data;
-                } else {
-                    $this->pkginfo['version'] = $data;
-                }
-                break;
-            case 'date':
-                if ($this->in_changelog) {
-                    $this->current_release['release_date'] = $data;
-                } else {
-                    $this->pkginfo['release_date'] = $data;
-                }
-                break;
-            case 'notes':
-                // try to "de-indent" release notes in case someone
-                // has been over-indenting their xml ;-)
-                $data = $this->_unIndent($this->cdata);
-                if ($this->in_changelog) {
-                    $this->current_release['release_notes'] = $data;
-                } else {
-                    $this->pkginfo['release_notes'] = $data;
-                }
-                break;
-            case 'warnings':
-                if ($this->in_changelog) {
-                    $this->current_release['release_warnings'] = $data;
-                } else {
-                    $this->pkginfo['release_warnings'] = $data;
-                }
-                break;
-            case 'state':
-                if ($this->in_changelog) {
-                    $this->current_release['release_state'] = $data;
-                } else {
-                    $this->pkginfo['release_state'] = $data;
-                }
-                break;
-            case 'license':
-                if ($this->in_changelog) {
-                    $this->current_release['release_license'] = $data;
-                } else {
-                    $this->pkginfo['release_license'] = $data;
-                }
-                break;
-            case 'dep':
-                if ($data && !$this->in_changelog) {
-                    $this->pkginfo['release_deps'][$this->d_i]['name'] = $data;
-                }
-                break;
-            case 'dir':
-                if ($this->in_changelog) {
-                    break;
-                }
-                array_pop($this->dir_names);
-                break;
-            case 'file':
-                if ($this->in_changelog) {
-                    break;
-                }
-                if ($data) {
-                    $path = '';
-                    if (count($this->dir_names)) {
-                        foreach ($this->dir_names as $dir) {
-                            $path .= $dir . DIRECTORY_SEPARATOR;
-                        }
-                    }
-                    $path .= $data;
-                    $this->filelist[$path] = $this->current_attributes;
-                    // Set the baseinstalldir only if the file don't have this attrib
-                    if (!isset($this->filelist[$path]['baseinstalldir']) &&
-                        isset($this->dir_install))
-                    {
-                        $this->filelist[$path]['baseinstalldir'] = $this->dir_install;
-                    }
-                    // Set the Role
-                    if (!isset($this->filelist[$path]['role']) && isset($this->dir_role)) {
-                        $this->filelist[$path]['role'] = $this->dir_role;
-                    }
-                }
-                break;
-            case 'maintainer':
-                if (empty($this->pkginfo['maintainers'][$this->m_i]['role'])) {
-                    $this->pkginfo['maintainers'][$this->m_i]['role'] = 'lead';
-                }
-                $this->m_i++;
-                break;
-            case 'release':
-                if ($this->in_changelog) {
-                    $this->c_i++;
-                }
-                break;
-            case 'changelog':
-                $this->in_changelog = false;
-                break;
-        }
-        array_pop($this->element_stack);
-        $spos = sizeof($this->element_stack) - 1;
-        $this->current_element = ($spos > 0) ? $this->element_stack[$spos] : '';
-        $this->cdata = '';
-    }
-
-    // }}}
-    // {{{ _pkginfo_cdata_1_0()
-
-    /**
-     * XML parser callback for character data.  Used for version 1.0
-     * packages.
-     *
-     * @param resource  $xp    XML parser resource
-     * @param string    $name  character data
-     *
-     * @return void
-     *
-     * @access private
-     */
-    function _pkginfo_cdata_1_0($xp, $data)
-    {
-        if (isset($this->cdata)) {
-            $this->cdata .= $data;
-        }
-    }
-
-    // }}}
-
     // {{{ infoFromTgzFile()
 
     /**
@@ -692,43 +351,23 @@ class PEAR_Common extends PEAR
      * @return array  array with package information
      *
      * @access public
+     * @deprecated use PEAR_PackageFile->fromTgzFile() instead
      *
      */
     function infoFromTgzFile($file)
     {
-        if (!@is_file($file)) {
-            return $this->raiseError("could not open file \"$file\"");
-        }
-        $tar = new Archive_Tar($file);
-        if ($this->debug <= 1) {
-            $tar->pushErrorHandling(PEAR_ERROR_RETURN);
-        }
-        $content = $tar->listContent();
-        if ($this->debug <= 1) {
-            $tar->popErrorHandling();
-        }
-        if (!is_array($content)) {
-            $file = realpath($file);
-            return $this->raiseError("Could not get contents of package \"$file\"".
-                                     '. Invalid tgz file.');
-        }
-        $xml = null;
-        foreach ($content as $file) {
-            $name = $file['filename'];
-            if ($name == 'package.xml') {
-                $xml = $name;
-                break;
-            } elseif (ereg('package.xml$', $name, $match)) {
-                $xml = $match[0];
-                break;
+        $packagefile = &new PEAR_PackageFile($this->config);
+        $pf = &$packagefile->fromTgzFile($file, PEAR_VALIDATE_NORMAL);
+        if (PEAR::isError($pf)) {
+            $errs = $pf->getUserinfo();
+            if (is_array($errs)) {
+                foreach ($errs as $error) {
+                    $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
+                }
             }
+            return $pf;
         }
-        $tmpdir = System::mkTemp(array('-d', 'pear'));
-        $this->addTempFile($tmpdir);
-        if (!$xml || !$tar->extractList(array($xml), $tmpdir)) {
-            return $this->raiseError('could not extract the package.xml file');
-        }
-        return $this->infoFromDescriptionFile("$tmpdir/$xml");
+        return $this->_postProcessValidPackagexml($pf);
     }
 
     // }}}
@@ -743,19 +382,23 @@ class PEAR_Common extends PEAR
      * @return array  array with package information
      *
      * @access public
+     * @deprecated use PEAR_PackageFile->fromPackageFile() instead
      *
      */
     function infoFromDescriptionFile($descfile)
     {
-        if (!@is_file($descfile) || !is_readable($descfile) ||
-             (!$fp = @fopen($descfile, 'r'))) {
-            return $this->raiseError("Unable to open $descfile");
+        $packagefile = &new PEAR_PackageFile($this->config);
+        $pf = &$packagefile->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL);
+        if (PEAR::isError($pf)) {
+            $errs = $pf->getUserinfo();
+            if (is_array($errs)) {
+                foreach ($errs as $error) {
+                    $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
+                }
+            }
+            return $pf;
         }
-
-        // read the whole thing so we only get one cdata callback
-        // for each block of cdata
-        $data = fread($fp, filesize($descfile));
-        return $this->infoFromString($data);
+        return $this->_postProcessValidPackagexml($pf);
     }
 
     // }}}
@@ -765,62 +408,65 @@ class PEAR_Common extends PEAR
      * Returns information about a package file.  Expects the contents
      * of a package xml file as input.
      *
-     * @param string  $data  name of package xml file
+     * @param string  $data  contents of package.xml file
      *
      * @return array   array with package information
      *
      * @access public
+     * @deprecated use PEAR_PackageFile->fromXmlstring() instead
      *
      */
     function infoFromString($data)
     {
-        require_once('PEAR/Dependency.php');
-        if (PEAR_Dependency::checkExtension($error, 'xml')) {
-            return $this->raiseError($error);
-        }
-        $xp = @xml_parser_create();
-        if (!$xp) {
-            return $this->raiseError('Unable to create XML parser');
-        }
-        xml_set_object($xp, $this);
-        xml_set_element_handler($xp, '_element_start', '_element_end');
-        xml_set_character_data_handler($xp, '_pkginfo_cdata');
-        xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, false);
-
-        $this->element_stack = array();
-        $this->pkginfo = array('provides' => array());
-        $this->current_element = false;
-        unset($this->dir_install);
-        $this->pkginfo['filelist'] = array();
-        $this->filelist =& $this->pkginfo['filelist'];
-        $this->dir_names = array();
-        $this->in_changelog = false;
-        $this->d_i = 0;
-        $this->cdata = '';
-        $this->_validPackageFile = false;
-
-        if (!xml_parse($xp, $data, 1)) {
-            $code = xml_get_error_code($xp);
-            $msg = sprintf("XML error: %s at line %d",
-                           xml_error_string($code),
-                           xml_get_current_line_number($xp));
-            xml_parser_free($xp);
-            return $this->raiseError($msg, $code);
-        }
-
-        xml_parser_free($xp);
-
-        if (!$this->_validPackageFile) {
-            return $this->raiseError('Invalid Package File, no <package> tag');
-        }
-        foreach ($this->pkginfo as $k => $v) {
-            if (!is_array($v)) {
-                $this->pkginfo[$k] = trim($v);
+        $packagefile = &new PEAR_PackageFile($this->config);
+        $pf = &$packagefile->fromXmlString($data, PEAR_VALIDATE_NORMAL, false);
+        if (PEAR::isError($pf)) {
+            $errs = $pf->getUserinfo();
+            if (is_array($errs)) {
+                foreach ($errs as $error) {
+                    $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
+                }
             }
+            return $pf;
         }
-        return $this->pkginfo;
+        return $this->_postProcessValidPackagexml($pf);
     }
     // }}}
+
+    /**
+     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+     * @return array
+     */
+    function _postProcessValidPackagexml(&$pf)
+    {
+        if (is_a($pf, 'PEAR_PackageFile_v2')) {
+            // sort of make this into a package.xml 1.0-style array
+            // changelog is not converted to old format.
+            $arr = $pf->toArray(true);
+            $arr = array_merge($arr, $arr['old']);
+            unset($arr['old']);
+            unset($arr['xsdversion']);
+            unset($arr['contents']);
+            unset($arr['compatible']);
+            unset($arr['channel']);
+            unset($arr['uri']);
+            unset($arr['dependencies']);
+            unset($arr['phprelease']);
+            unset($arr['extsrcrelease']);
+            unset($arr['extbinrelease']);
+            unset($arr['bundle']);
+            unset($arr['lead']);
+            unset($arr['developer']);
+            unset($arr['helper']);
+            unset($arr['contributor']);
+            $arr['filelist'] = $pf->getFilelist();
+            $this->pkginfo = $arr;
+            return $arr;
+        } else {
+            $this->pkginfo = $pf->toArray();
+            return $this->pkginfo;
+        }
+    }
     // {{{ infoFromAny()
 
     /**
@@ -832,28 +478,23 @@ class PEAR_Common extends PEAR
      * @access public
      * @param  string Filename of the source ('package.xml', '<package>.tgz')
      * @return string
+     * @deprecated use PEAR_PackageFile->fromAnyFile() instead
      */
     function infoFromAny($info)
     {
         if (is_string($info) && file_exists($info)) {
-            $tmp = substr($info, -4);
-            if ($tmp == '.xml') {
-                $info = $this->infoFromDescriptionFile($info);
-            } elseif ($tmp == '.tar' || $tmp == '.tgz') {
-                $info = $this->infoFromTgzFile($info);
-            } else {
-                $fp = fopen($info, "r");
-                $test = fread($fp, 5);
-                fclose($fp);
-                if ($test == "<?xml") {
-                    $info = $this->infoFromDescriptionFile($info);
-                } else {
-                    $info = $this->infoFromTgzFile($info);
+            $packagefile = &new PEAR_PackageFile($this->config);
+            $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL);
+            if (PEAR::isError($pf)) {
+                $errs = $pf->getUserinfo();
+                if (is_array($errs)) {
+                    foreach ($errs as $error) {
+                        $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
+                    }
                 }
+                return $pf;
             }
-            if (PEAR::isError($info)) {
-                return $this->raiseError($info);
-            }
+            return $this->_postProcessValidPackagexml($pf);
         }
         return $info;
     }
@@ -870,159 +511,15 @@ class PEAR_Common extends PEAR
      * @return string XML data
      *
      * @access public
+     * @deprecated use a PEAR_PackageFile_v* object's generator instead
      */
     function xmlFromInfo($pkginfo)
     {
-        static $maint_map = array(
-            "handle" => "user",
-            "name" => "name",
-            "email" => "email",
-            "role" => "role",
-            );
-        $ret = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n";
-        $ret .= "<!DOCTYPE package SYSTEM \"http://pear.php.net/dtd/package-1.0\">\n";
-        $ret .= "<package version=\"1.0\">
-  <name>$pkginfo[package]</name>
-  <summary>".htmlspecialchars($pkginfo['summary'])."</summary>
-  <description>".htmlspecialchars($pkginfo['description'])."</description>
-  <maintainers>
-";
-        foreach ($pkginfo['maintainers'] as $maint) {
-            $ret .= "    <maintainer>\n";
-            foreach ($maint_map as $idx => $elm) {
-                $ret .= "      <$elm>";
-                $ret .= htmlspecialchars($maint[$idx]);
-                $ret .= "</$elm>\n";
-            }
-            $ret .= "    </maintainer>\n";
-        }
-        $ret .= "  </maintainers>\n";
-        $ret .= $this->_makeReleaseXml($pkginfo);
-        if (@sizeof($pkginfo['changelog']) > 0) {
-            $ret .= "  <changelog>\n";
-            foreach ($pkginfo['changelog'] as $oldrelease) {
-                $ret .= $this->_makeReleaseXml($oldrelease, true);
-            }
-            $ret .= "  </changelog>\n";
-        }
-        $ret .= "</package>\n";
-        return $ret;
-    }
-
-    // }}}
-    // {{{ _makeReleaseXml()
-
-    /**
-     * Generate part of an XML description with release information.
-     *
-     * @param array  $pkginfo    array with release information
-     * @param bool   $changelog  whether the result will be in a changelog element
-     *
-     * @return string XML data
-     *
-     * @access private
-     */
-    function _makeReleaseXml($pkginfo, $changelog = false)
-    {
-        // XXX QUOTE ENTITIES IN PCDATA, OR EMBED IN CDATA BLOCKS!!
-        $indent = $changelog ? "  " : "";
-        $ret = "$indent  <release>\n";
-        if (!empty($pkginfo['version'])) {
-            $ret .= "$indent    <version>$pkginfo[version]</version>\n";
-        }
-        if (!empty($pkginfo['release_date'])) {
-            $ret .= "$indent    <date>$pkginfo[release_date]</date>\n";
-        }
-        if (!empty($pkginfo['release_license'])) {
-            $ret .= "$indent    <license>$pkginfo[release_license]</license>\n";
-        }
-        if (!empty($pkginfo['release_state'])) {
-            $ret .= "$indent    <state>$pkginfo[release_state]</state>\n";
-        }
-        if (!empty($pkginfo['release_notes'])) {
-            $ret .= "$indent    <notes>".htmlspecialchars($pkginfo['release_notes'])."</notes>\n";
-        }
-        if (!empty($pkginfo['release_warnings'])) {
-            $ret .= "$indent    <warnings>".htmlspecialchars($pkginfo['release_warnings'])."</warnings>\n";
-        }
-        if (isset($pkginfo['release_deps']) && sizeof($pkginfo['release_deps']) > 0) {
-            $ret .= "$indent    <deps>\n";
-            foreach ($pkginfo['release_deps'] as $dep) {
-                $ret .= "$indent      <dep type=\"$dep[type]\" rel=\"$dep[rel]\"";
-                if (isset($dep['version'])) {
-                    $ret .= " version=\"$dep[version]\"";
-                }
-                if (isset($dep['optional'])) {
-                    $ret .= " optional=\"$dep[optional]\"";
-                }
-                if (isset($dep['name'])) {
-                    $ret .= ">$dep[name]</dep>\n";
-                } else {
-                    $ret .= "/>\n";
-                }
-            }
-            $ret .= "$indent    </deps>\n";
-        }
-        if (isset($pkginfo['configure_options'])) {
-            $ret .= "$indent    <configureoptions>\n";
-            foreach ($pkginfo['configure_options'] as $c) {
-                $ret .= "$indent      <configureoption name=\"".
-                    htmlspecialchars($c['name']) . "\"";
-                if (isset($c['default'])) {
-                    $ret .= " default=\"" . htmlspecialchars($c['default']) . "\"";
-                }
-                $ret .= " prompt=\"" . htmlspecialchars($c['prompt']) . "\"";
-                $ret .= "/>\n";
-            }
-            $ret .= "$indent    </configureoptions>\n";
-        }
-        if (isset($pkginfo['provides'])) {
-            foreach ($pkginfo['provides'] as $key => $what) {
-                $ret .= "$indent    <provides type=\"$what[type]\" ";
-                $ret .= "name=\"$what[name]\" ";
-                if (isset($what['extends'])) {
-                    $ret .= "extends=\"$what[extends]\" ";
-                }
-                $ret .= "/>\n";
-            }
-        }
-        if (isset($pkginfo['filelist'])) {
-            $ret .= "$indent    <filelist>\n";
-            foreach ($pkginfo['filelist'] as $file => $fa) {
-                @$ret .= "$indent      <file role=\"$fa[role]\"";
-                if (isset($fa['baseinstalldir'])) {
-                    $ret .= ' baseinstalldir="' .
-                        htmlspecialchars($fa['baseinstalldir']) . '"';
-                }
-                if (isset($fa['md5sum'])) {
-                    $ret .= " md5sum=\"$fa[md5sum]\"";
-                }
-                if (isset($fa['platform'])) {
-                    $ret .= " platform=\"$fa[platform]\"";
-                }
-                if (!empty($fa['install-as'])) {
-                    $ret .= ' install-as="' .
-                        htmlspecialchars($fa['install-as']) . '"';
-                }
-                $ret .= ' name="' . htmlspecialchars($file) . '"';
-                if (empty($fa['replacements'])) {
-                    $ret .= "/>\n";
-                } else {
-                    $ret .= ">\n";
-                    foreach ($fa['replacements'] as $r) {
-                        $ret .= "$indent        <replace";
-                        foreach ($r as $k => $v) {
-                            $ret .= " $k=\"" . htmlspecialchars($v) .'"';
-                        }
-                        $ret .= "/>\n";
-                    }
-                    @$ret .= "$indent      </file>\n";
-                }
-            }
-            $ret .= "$indent    </filelist>\n";
-        }
-        $ret .= "$indent  </release>\n";
-        return $ret;
+        $config = &PEAR_Config::singleton();
+        $packagefile = &new PEAR_PackageFile($config);
+        $pf = &$packagefile->fromArray($pkginfo);
+        $gen = &$pf->getDefaultGenerator();
+        return $gen->toXml(PEAR_VALIDATE_PACKAGING);
     }
 
     // }}}
@@ -1039,183 +536,32 @@ class PEAR_Common extends PEAR
      *                may be found, or empty if they are not available
      * @access public
      * @return boolean
+     * @deprecated use the validation of PEAR_PackageFile objects
      */
     function validatePackageInfo($info, &$errors, &$warnings, $dir_prefix = '')
     {
-        if (PEAR::isError($info = $this->infoFromAny($info))) {
-            return $this->raiseError($info);
-        }
-        if (!is_array($info)) {
-            return false;
-        }
-
-        $errors = array();
-        $warnings = array();
-        if (!isset($info['package'])) {
-            $errors[] = 'missing package name';
-        } elseif (!$this->validPackageName($info['package'])) {
-            $errors[] = 'invalid package name';
-        }
-        $this->_packageName = $pn = $info['package'];
-
-        if (empty($info['summary'])) {
-            $errors[] = 'missing summary';
-        } elseif (strpos(trim($info['summary']), "\n") !== false) {
-            $warnings[] = 'summary should be on a single line';
-        }
-        if (empty($info['description'])) {
-            $errors[] = 'missing description';
-        }
-        if (empty($info['release_license'])) {
-            $errors[] = 'missing license';
-        }
-        if (!isset($info['version'])) {
-            $errors[] = 'missing version';
-        } elseif (!$this->validPackageVersion($info['version'])) {
-            $errors[] = 'invalid package release version';
-        }
-        if (empty($info['release_state'])) {
-            $errors[] = 'missing release state';
-        } elseif (!in_array($info['release_state'], PEAR_Common::getReleaseStates())) {
-            $errors[] = "invalid release state `$info[release_state]', should be one of: "
-                . implode(' ', PEAR_Common::getReleaseStates());
-        }
-        if (empty($info['release_date'])) {
-            $errors[] = 'missing release date';
-        } elseif (!preg_match('/^\d{4}-\d\d-\d\d$/', $info['release_date'])) {
-            $errors[] = "invalid release date `$info[release_date]', format is YYYY-MM-DD";
-        }
-        if (empty($info['release_notes'])) {
-            $errors[] = "missing release notes";
-        }
-        if (empty($info['maintainers'])) {
-            $errors[] = 'no maintainer(s)';
+        $config = &PEAR_Config::singleton();
+        $packagefile = &new PEAR_PackageFile($config);
+        PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+        if (strpos($info, '<?xml') !== false) {
+            $pf = &$packagefile->fromXmlString($info, PEAR_VALIDATE_NORMAL, '');
         } else {
-            $i = 1;
-            foreach ($info['maintainers'] as $m) {
-                if (empty($m['handle'])) {
-                    $errors[] = "maintainer $i: missing handle";
-                }
-                if (empty($m['role'])) {
-                    $errors[] = "maintainer $i: missing role";
-                } elseif (!in_array($m['role'], PEAR_Common::getUserRoles())) {
-                    $errors[] = "maintainer $i: invalid role `$m[role]', should be one of: "
-                        . implode(' ', PEAR_Common::getUserRoles());
-                }
-                if (empty($m['name'])) {
-                    $errors[] = "maintainer $i: missing name";
-                }
-                if (empty($m['email'])) {
-                    $errors[] = "maintainer $i: missing email";
-                }
-                $i++;
-            }
-        }
-        if (!empty($info['release_deps'])) {
-            $i = 1;
-            foreach ($info['release_deps'] as $d) {
-                if (empty($d['type'])) {
-                    $errors[] = "dependency $i: missing type";
-                } elseif (!in_array($d['type'], PEAR_Common::getDependencyTypes())) {
-                    $errors[] = "dependency $i: invalid type '$d[type]', should be one of: " .
-                        implode(' ', PEAR_Common::getDependencyTypes());
-                }
-                if (empty($d['rel'])) {
-                    $errors[] = "dependency $i: missing relation";
-                } elseif (!in_array($d['rel'], PEAR_Common::getDependencyRelations())) {
-                    $errors[] = "dependency $i: invalid relation '$d[rel]', should be one of: "
-                        . implode(' ', PEAR_Common::getDependencyRelations());
-                }
-                if (!empty($d['optional'])) {
-                    if (!in_array($d['optional'], array('yes', 'no'))) {
-                        $errors[] = "dependency $i: invalid relation optional attribute '$d[optional]', should be one of: yes no";
+            $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL);
+        }
+        PEAR::staticPopErrorHandling();
+        if (PEAR::isError($pf)) {
+            $errs = $pf->getUserinfo();
+            if (is_array($errs)) {
+                foreach ($errs as $error) {
+                    if ($error['level'] == 'error') {
+                        $errors[] = $error['message'];
                     } else {
-                        if (($d['rel'] == 'not' || $d['rel'] == 'ne') && $d['optional'] == 'yes') {
-                            $errors[] = "dependency $i: 'not' and 'ne' dependencies cannot be " .
-                                "optional";
-                        }
+                        $warnings[] = $error['message'];
                     }
                 }
-                if ($d['rel'] != 'not' && $d['rel'] != 'has' && empty($d['version'])) {
-                    $warnings[] = "dependency $i: missing version";
-                } elseif (($d['rel'] == 'not' || $d['rel'] == 'has') && !empty($d['version'])) {
-                    $warnings[] = "dependency $i: version ignored for `$d[rel]' dependencies";
-                }
-                if ($d['rel'] == 'not' && !empty($d['version'])) {
-                    $warnings[] = "dependency $i: 'not' defines a total conflict, to exclude " .
-                        "specific versions, use 'ne'";
-                }
-                if ($d['type'] == 'php' && !empty($d['name'])) {
-                    $warnings[] = "dependency $i: name ignored for php type dependencies";
-                } elseif ($d['type'] != 'php' && empty($d['name'])) {
-                    $errors[] = "dependency $i: missing name";
-                }
-                if ($d['type'] == 'php' && $d['rel'] == 'not') {
-                    $errors[] = "dependency $i: PHP dependencies cannot use 'not' " .
-                        "rel, use 'ne' to exclude versions";
-                }
-                $i++;
-            }
-        }
-        if (!empty($info['configure_options'])) {
-            $i = 1;
-            foreach ($info['configure_options'] as $c) {
-                if (empty($c['name'])) {
-                    $errors[] = "configure option $i: missing name";
-                }
-                if (empty($c['prompt'])) {
-                    $errors[] = "configure option $i: missing prompt";
-                }
-                $i++;
-            }
-        }
-        if (empty($info['filelist'])) {
-            $errors[] = 'no files';
-        } else {
-            foreach ($info['filelist'] as $file => $fa) {
-                if (empty($fa['role'])) {
-                    $errors[] = "file $file: missing role";
-                    continue;
-                } elseif (!in_array($fa['role'], PEAR_Common::getFileRoles())) {
-                    $errors[] = "file $file: invalid role, should be one of: "
-                        . implode(' ', PEAR_Common::getFileRoles());
-                }
-                if ($fa['role'] == 'php' && $dir_prefix) {
-                    $this->log(1, "Analyzing $file");
-                    $srcinfo = $this->analyzeSourceCode($dir_prefix . DIRECTORY_SEPARATOR . $file);
-                    if ($srcinfo) {
-                        $this->buildProvidesArray($srcinfo);
-                    }
-                }
-
-                // (ssb) Any checks we can do for baseinstalldir?
-                // (cox) Perhaps checks that either the target dir and
-                //       baseInstall doesn't cointain "../../"
-            }
-        }
-        $this->_packageName = $pn = $info['package'];
-        $pnl = strlen($pn);
-        foreach ((array)$this->pkginfo['provides'] as $key => $what) {
-            if (isset($what['explicit'])) {
-                // skip conformance checks if the provides entry is
-                // specified in the package.xml file
-                continue;
-            }
-            extract($what);
-            if ($type == 'class') {
-                if (!strncasecmp($name, $pn, $pnl)) {
-                    continue;
-                }
-                $warnings[] = "in $file: class \"$name\" not prefixed with package name \"$pn\"";
-            } elseif ($type == 'function') {
-                if (strstr($name, '::') || !strncasecmp($name, $pn, $pnl)) {
-                    continue;
-                }
-                $warnings[] = "in $file: function \"$name\" not prefixed with package name \"$pn\"";
             }
+            return false;
         }
-
-
         return true;
     }
 
@@ -1314,7 +660,13 @@ class PEAR_Common extends PEAR
         if (!$fp = @fopen($file, "r")) {
             return false;
         }
-        $contents = fread($fp, filesize($file));
+        if (function_exists('file_get_contents')) {
+            fclose($fp);
+            $contents = file_get_contents($file);
+        } else {
+            $contents = fread($fp, filesize($file));
+            fclose($fp);
+        }
         $tokens = token_get_all($contents);
 /*
         for ($i = 0; $i < sizeof($tokens); $i++) {
@@ -1360,6 +712,7 @@ class PEAR_Common extends PEAR
                     continue;
                 } else {
                     $inquote = false;
+                    continue;
                 }
             }
             switch ($token) {
@@ -1396,7 +749,7 @@ class PEAR_Common extends PEAR
                     $interface = true;
                 case T_CLASS:
                     if (($current_class_level != -1) || ($current_function_level != -1)) {
-                        PEAR::raiseError("Parser error: Invalid PHP file $file",
+                        PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"",
                             PEAR_COMMON_ERROR_INVALIDPHP);
                         return false;
                     }
@@ -1410,9 +763,10 @@ class PEAR_Common extends PEAR
                     if (version_compare(zend_version(), '2.0', '<')) {
                         if (in_array(strtolower($data),
                             array('public', 'private', 'protected', 'abstract',
-                                  'interface', 'implements', 'clone', 'throw') 
+                                  'interface', 'implements', 'throw') 
                                  )) {
-                            PEAR::raiseError('Error: PHP5 packages must be packaged by php 5 PEAR');
+                            PEAR::raiseError('Error: PHP5 token encountered in ' . $file . 
+                            'packaging should be done in PHP 5');
                             return false;
                         }
                     }
@@ -1460,7 +814,7 @@ class PEAR_Common extends PEAR
                     continue 2;
                 case T_DOUBLE_COLON:
                     if (!($tokens[$i - 1][0] == T_WHITESPACE || $tokens[$i - 1][0] == T_STRING)) {
-                        PEAR::raiseError("Parser error: Invalid PHP file $file",
+                        PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"",
                             PEAR_COMMON_ERROR_INVALIDPHP);
                         return false;
                     }
@@ -1738,357 +1092,38 @@ class PEAR_Common extends PEAR
      *                 getCode().
      *
      * @access public
+     * @deprecated in favor of PEAR_Downloader::downloadHttp()
      */
     function downloadHttp($url, &$ui, $save_dir = '.', $callback = null)
     {
-        if ($callback) {
-            call_user_func($callback, 'setup', array(&$ui));
-        }
-        if (preg_match('!^http://([^/:?#]*)(:(\d+))?(/.*)!', $url, $matches)) {
-            list(,$host,,$port,$path) = $matches;
-        }
-        if (isset($this)) {
-            $config = &$this->config;
-        } else {
-            $config = &PEAR_Config::singleton();
-        }
-        $proxy_host = $proxy_port = $proxy_user = $proxy_pass = '';
-        if ($proxy = parse_url($config->get('http_proxy'))) {
-            $proxy_host = @$proxy['host'];
-            $proxy_port = @$proxy['port'];
-            $proxy_user = @$proxy['user'];
-            $proxy_pass = @$proxy['pass'];
-
-            if ($proxy_port == '') {
-                $proxy_port = 8080;
-            }
-            if ($callback) {
-                call_user_func($callback, 'message', "Using HTTP proxy $host:$port");
-            }
-        }
-        if (empty($port)) {
-            $port = 80;
-        }
-        if ($proxy_host != '') {
-            $fp = @fsockopen($proxy_host, $proxy_port, $errno, $errstr);
-            if (!$fp) {
-                if ($callback) {
-                    call_user_func($callback, 'connfailed', array($proxy_host, $proxy_port,
-                                                                  $errno, $errstr));
-                }
-                return PEAR::raiseError("Connection to `$proxy_host:$proxy_port' failed: $errstr", $errno);
-            }
-            $request = "GET $url HTTP/1.0\r\n";
-        } else {
-            $fp = @fsockopen($host, $port, $errno, $errstr);
-            if (!$fp) {
-                if ($callback) {
-                    call_user_func($callback, 'connfailed', array($host, $port,
-                                                                  $errno, $errstr));
-                }
-                return PEAR::raiseError("Connection to `$host:$port' failed: $errstr", $errno);
-            }
-            $request = "GET $path HTTP/1.0\r\n";
-        }
-        $request .= "Host: $host:$port\r\n".
-            "User-Agent: PHP/".PHP_VERSION."\r\n";
-        if ($proxy_host != '' && $proxy_user != '') {
-            $request .= 'Proxy-Authorization: Basic ' .
-                base64_encode($proxy_user . ':' . $proxy_pass) . "\r\n";
-        }
-        $request .= "\r\n";
-        fwrite($fp, $request);
-        $headers = array();
-        while (trim($line = fgets($fp, 1024))) {
-            if (preg_match('/^([^:]+):\s+(.*)\s*$/', $line, $matches)) {
-                $headers[strtolower($matches[1])] = trim($matches[2]);
-            } elseif (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) {
-                if ($matches[1] != 200) {
-                    return PEAR::raiseError("File http://$host:$port$path not valid (received: $line)");
-                }
-            }
-        }
-        if (isset($headers['content-disposition']) &&
-            preg_match('/\sfilename=\"([^;]*\S)\"\s*(;|$)/', $headers['content-disposition'], $matches)) {
-            $save_as = basename($matches[1]);
-        } else {
-            $save_as = basename($url);
-        }
-        if ($callback) {
-            $tmp = call_user_func($callback, 'saveas', $save_as);
-            if ($tmp) {
-                $save_as = $tmp;
-            }
-        }
-        $dest_file = $save_dir . DIRECTORY_SEPARATOR . $save_as;
-        if (!$wp = @fopen($dest_file, 'wb')) {
-            fclose($fp);
-            if ($callback) {
-                call_user_func($callback, 'writefailed', array($dest_file, $php_errormsg));
-            }
-            return PEAR::raiseError("could not open $dest_file for writing");
-        }
-        if (isset($headers['content-length'])) {
-            $length = $headers['content-length'];
-        } else {
-            $length = -1;
-        }
-        $bytes = 0;
-        if ($callback) {
-            call_user_func($callback, 'start', array(basename($dest_file), $length));
-        }
-        while ($data = @fread($fp, 1024)) {
-            $bytes += strlen($data);
-            if ($callback) {
-                call_user_func($callback, 'bytesread', $bytes);
-            }
-            if (!@fwrite($wp, $data)) {
-                fclose($fp);
-                if ($callback) {
-                    call_user_func($callback, 'writefailed', array($dest_file, $php_errormsg));
-                }
-                return PEAR::raiseError("$dest_file: write failed ($php_errormsg)");
-            }
-        }
-        fclose($fp);
-        fclose($wp);
-        if ($callback) {
-            call_user_func($callback, 'done', $bytes);
-        }
-        return $dest_file;
-    }
-
-    // }}}
-    // {{{ sortPkgDeps()
-
-    /**
-     * Sort a list of arrays of array(downloaded packagefilename) by dependency.
-     *
-     * It also removes duplicate dependencies
-     * @param array
-     * @param boolean Sort packages in reverse order if true
-     * @return array array of array(packagefilename, package.xml contents)
-     */
-    function sortPkgDeps(&$packages, $uninstall = false)
-    {
-        $ret = array();
-        if ($uninstall) {
-            foreach($packages as $packageinfo) {
-                $ret[] = array('info' => $packageinfo);
-            }
-        } else {
-            foreach($packages as $packagefile) {
-                if (!is_array($packagefile)) {
-                    $ret[] = array('file' => $packagefile,
-                                   'info' => $a = $this->infoFromAny($packagefile),
-                                   'pkg' => $a['package']);
-                } else {
-                    $ret[] = $packagefile;
-                }
-            }
-        }
-        $checkdupes = array();
-        $newret = array();
-        foreach($ret as $i => $p) {
-            if (!isset($checkdupes[$p['info']['package']])) {
-                $checkdupes[$p['info']['package']][] = $i;
-                $newret[] = $p;
-            }
+        if (!class_exists('PEAR_Downloader')) {
+            require_once 'PEAR/Downloader.php';
         }
-        $this->_packageSortTree = $this->_getPkgDepTree($newret);
-
-        $func = $uninstall ? '_sortPkgDepsRev' : '_sortPkgDeps';
-        usort($newret, array(&$this, $func));
-        $this->_packageSortTree = null;
-        $packages = $newret;
+        return PEAR_Downloader::downloadHttp($url, $ui, $save_dir, $callback);
     }
 
     // }}}
-    // {{{ _sortPkgDeps()
 
     /**
-     * Compare two package's package.xml, and sort
-     * so that dependencies are installed first
-     *
-     * This is a crude compare, real dependency checking is done on install.
-     * The only purpose this serves is to make the command-line
-     * order-independent (you can list a dependent package first, and
-     * installation occurs in the order required)
-     * @access private
-     */
-    function _sortPkgDeps($p1, $p2)
-    {
-        $p1name = $p1['info']['package'];
-        $p2name = $p2['info']['package'];
-        $p1deps = $this->_getPkgDeps($p1);
-        $p2deps = $this->_getPkgDeps($p2);
-        if (!count($p1deps) && !count($p2deps)) {
-            return 0; // order makes no difference
-        }
-        if (!count($p1deps)) {
-            return -1; // package 2 has dependencies, package 1 doesn't
-        }
-        if (!count($p2deps)) {
-            return 1; // package 1 has dependencies, package 2 doesn't
-        }
-        // both have dependencies
-        if (in_array($p1name, $p2deps)) {
-            return -1; // put package 1 first: package 2 depends on package 1
-        }
-        if (in_array($p2name, $p1deps)) {
-            return 1; // put package 2 first: package 1 depends on package 2
-        }
-        if ($this->_removedDependency($p1name, $p2name)) {
-            return -1; // put package 1 first: package 2 depends on packages that depend on package 1
-        }
-        if ($this->_removedDependency($p2name, $p1name)) {
-            return 1; // put package 2 first: package 1 depends on packages that depend on package 2
-        }
-        // doesn't really matter if neither depends on the other
-        return 0;
-    }
-
-    // }}}
-    // {{{ _sortPkgDepsRev()
-
-    /**
-     * Compare two package's package.xml, and sort
-     * so that dependencies are uninstalled last
-     *
-     * This is a crude compare, real dependency checking is done on uninstall.
-     * The only purpose this serves is to make the command-line
-     * order-independent (you can list a dependency first, and
-     * uninstallation occurs in the order required)
-     * @access private
-     */
-    function _sortPkgDepsRev($p1, $p2)
-    {
-        $p1name = $p1['info']['package'];
-        $p2name = $p2['info']['package'];
-        $p1deps = $this->_getRevPkgDeps($p1);
-        $p2deps = $this->_getRevPkgDeps($p2);
-        if (!count($p1deps) && !count($p2deps)) {
-            return 0; // order makes no difference
-        }
-        if (!count($p1deps)) {
-            return 1; // package 2 has dependencies, package 1 doesn't
-        }
-        if (!count($p2deps)) {
-            return -1; // package 2 has dependencies, package 1 doesn't
-        }
-        // both have dependencies
-        if (in_array($p1name, $p2deps)) {
-            return 1; // put package 1 last
-        }
-        if (in_array($p2name, $p1deps)) {
-            return -1; // put package 2 last
-        }
-        if ($this->_removedDependency($p1name, $p2name)) {
-            return 1; // put package 1 last: package 2 depends on packages that depend on package 1
-        }
-        if ($this->_removedDependency($p2name, $p1name)) {
-            return -1; // put package 2 last: package 1 depends on packages that depend on package 2
-        }
-        // doesn't really matter if neither depends on the other
-        return 0;
-    }
-
-    // }}}
-    // {{{ _getPkgDeps()
-
-    /**
-     * get an array of package dependency names
-     * @param array
-     * @return array
-     * @access private
-     */
-    function _getPkgDeps($p)
-    {
-        if (!isset($p['info']['releases'])) {
-            return $this->_getRevPkgDeps($p);
-        }
-        $rel = array_shift($p['info']['releases']);
-        if (!isset($rel['deps'])) {
-            return array();
-        }
-        $ret = array();
-        foreach($rel['deps'] as $dep) {
-            if ($dep['type'] == 'pkg') {
-                $ret[] = $dep['name'];
-            }
-        }
-        return $ret;
-    }
-
-    // }}}
-    // {{{ _getPkgDeps()
-
-    /**
-     * get an array representation of the package dependency tree
-     * @return array
-     * @access private
-     */
-    function _getPkgDepTree($packages)
-    {
-        $tree = array();
-        foreach ($packages as $p) {
-            $package = $p['info']['package'];
-            $deps = $this->_getPkgDeps($p);
-            $tree[$package] = $deps;
-        }
-        return $tree;
-    }
-
-    // }}}
-    // {{{ _removedDependency($p1, $p2)
-
-    /**
-     * get an array of package dependency names for uninstall
-     * @param string package 1 name
-     * @param string package 2 name
-     * @return bool
-     * @access private
-     */
-    function _removedDependency($p1, $p2)
-    {
-        if (empty($this->_packageSortTree[$p2])) {
-            return false;
-        }
-        if (!in_array($p1, $this->_packageSortTree[$p2])) {
-            foreach ($this->_packageSortTree[$p2] as $potential) {
-                if ($this->_removedDependency($p1, $potential)) {
-                    return true;
-                }
-            }
-            return false;
-        }
-        return true;
-    }
-
-    // }}}
-    // {{{ _getRevPkgDeps()
-
-    /**
-     * get an array of package dependency names for uninstall
-     * @param array
-     * @return array
-     * @access private
+     * @param string $path relative or absolute include path
+     * @return boolean
+     * @static
      */
-    function _getRevPkgDeps($p)
+    function isIncludeable($path)
     {
-        if (!isset($p['info']['release_deps'])) {
-            return array();
-        }
-        $ret = array();
-        foreach($p['info']['release_deps'] as $dep) {
-            if ($dep['type'] == 'pkg') {
-                $ret[] = $dep['name'];
+        if (file_exists($path) && is_readable($path)) {
+            return true;
+        }
+        $ipath = explode(PATH_SEPARATOR, ini_get('include_path'));
+        foreach ($ipath as $include) {
+            $test = realpath($include . DIRECTORY_SEPARATOR . $path);
+            if (file_exists($test) && is_readable($test)) {
+                return true;
             }
         }
-        return $ret;
+        return false;
     }
-
-    // }}}
 }
-
-?>
+require_once 'PEAR/Config.php';
+require_once 'PEAR/PackageFile.php';
+?>
\ No newline at end of file
index a8c073b9df7e5fa024795ff287d8b667996e49e7..e3fd104f37526360df0643012cfe150f08b1f9b8 100644 (file)
@@ -1,25 +1,34 @@
 <?php
-//
-// +----------------------------------------------------------------------+
-// | PHP Version 5                                                        |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2004 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 Bakken <ssb@php.net>                                    |
-// +----------------------------------------------------------------------+
-//
-// $Id$
+/**
+ * PEAR_Config, customized configuration handling for the PEAR Installer
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 0.1
+ */
 
+/**
+ * Required for error handling
+ */
 require_once 'PEAR.php';
+require_once 'PEAR/Registry.php';
+require_once 'PEAR/Installer/Role.php';
 require_once 'System.php';
+require_once 'PEAR/Remote.php';
 
 /**
  * Last created PEAR_Config instance.
@@ -38,6 +47,15 @@ if (!defined('PEAR_INSTALL_DIR') || !PEAR_INSTALL_DIR) {
 // PHP_ prefix is for some security, PHP protects environment
 // variables starting with PHP_*.
 
+// default channel and preferred mirror is based on whether we are invoked through
+// the "pear" or the "pecl" command
+
+if (!defined('PEAR_RUNTYPE') || PEAR_RUNTYPE == 'pear') {
+    define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pear.php.net');
+} else {
+    define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pecl.php.net');
+}
+
 if (getenv('PHP_PEAR_SYSCONF_DIR')) {
     define('PEAR_CONFIG_SYSCONFDIR', getenv('PHP_PEAR_SYSCONF_DIR'));
 } elseif (getenv('SystemRoot')) {
@@ -192,6 +210,15 @@ if (getenv('PHP_PEAR_SIG_KEYDIR')) {
 /**
  * This is a class for storing configuration data, keeping track of
  * which are system-defined, user-defined or defaulted.
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 0.1
  */
 class PEAR_Config extends PEAR
 {
@@ -208,7 +235,7 @@ class PEAR_Config extends PEAR
         );
 
     var $layers = array();
-
+    
     /**
      * Configuration data, two-dimensional array where the first
      * dimension is the config layer ('user', 'system' and 'default'),
@@ -226,6 +253,62 @@ class PEAR_Config extends PEAR
         'system' => array(),
         'default' => array(),
         );
+    
+    /**
+     * Configuration values that can be set for a channel
+     *
+     * All other configuration values can only have a global value
+     * @var array
+     * @access private
+     */
+    var $_channelConfigInfo = array(
+        'php_dir', 'ext_dir', 'doc_dir', 'bin_dir', 'data_dir',
+        'test_dir', 'php_bin', 'username', 'password', 'verbose',
+        'preferred_state', 'umask', 'preferred_mirror',
+        );
+
+    /**
+     * Channels that can be accessed
+     * @see setChannels()
+     * @var array
+     * @access private
+     */
+    var $_channels = array('pear.php.net', 'pecl.php.net', '__uri');
+
+    /**
+     * This variable is used to control the directory values returned
+     * @see setInstallRoot();
+     * @var string|false
+     * @access private
+     */
+    var $_installRoot = false;
+
+    /**
+     * If requested, this will always refer to the registry
+     * contained in php_dir
+     * @var PEAR_Registry
+     */
+    var $_registry = array();
+
+    /**
+     * @var array
+     * @access private
+     */
+    var $_regInitialized = array();
+
+    /**
+     * @var bool
+     * @access private
+     */
+    var $_noRegistry = false;
+
+    /**
+     * amount of errors found while parsing config
+     * @var integer
+     * @access private
+     */
+    var $_errorsFound = 0;
+    var $_lastError = null;
 
     /**
      * Information about the configuration data.  Stores the type,
@@ -235,12 +318,41 @@ class PEAR_Config extends PEAR
      * @var array layer => array(infotype => value, ...)
      */
     var $configuration_info = array(
+        // Channels/Internet Access
+        'default_channel' => array(
+            'type' => 'string',
+            'default' => PEAR_CONFIG_DEFAULT_CHANNEL,
+            'doc' => 'the default channel to use for all non explicit commands',
+            'prompt' => 'Default Channel',
+            'group' => 'Internet Access',
+            ),
+        'preferred_mirror' => array(
+            'type' => 'string',
+            'default' => PEAR_CONFIG_DEFAULT_CHANNEL,
+            'doc' => 'the default server or mirror to use for channel actions',
+            'prompt' => 'Default Channel Mirror',
+            'group' => 'Internet Access',
+            ),
+        'remote_config' => array(
+            'type' => 'password',
+            'default' => '',
+            'doc' => 'ftp url of remote configuration file to use for synchronized install',
+            'prompt' => 'Remote Configuration File',
+            'group' => 'Internet Access',
+            ),
+        'auto_discover' => array(
+            'type' => 'integer',
+            'default' => 0,
+            'doc' => 'whether to automatically discover new channels',
+            'prompt' => 'Auto-discover new Channels',
+            'group' => 'Internet Access',
+            ),
         // Internet Access
         'master_server' => array(
             'type' => 'string',
             'default' => 'pear.php.net',
-            'doc' => 'name of the main PEAR server',
-            'prompt' => 'PEAR server',
+            'doc' => 'name of the main PEAR server [NOT USED IN THIS VERSION]',
+            'prompt' => 'PEAR server [DEPRECATED]',
             'group' => 'Internet Access',
             ),
         'http_proxy' => array(
@@ -380,12 +492,13 @@ class PEAR_Config extends PEAR
             'group' => 'Maintainers',
             ),
         'sig_keydir' => array(
-            'type' => 'string',
+            'type' => 'directory',
             'default' => PEAR_CONFIG_DEFAULT_SIG_KEYDIR,
-            'doc' => 'which package signature mechanism to use',
+            'doc' => 'directory where signature keys are located',
             'prompt' => 'Signature Key Directory',
             'group' => 'Maintainers',
             ),
+        // __channels is reserved - used for channel-specific configuration
         );
 
     // }}}
@@ -395,16 +508,22 @@ class PEAR_Config extends PEAR
     /**
      * Constructor.
      *
-     * @param string (optional) file to read user-defined options from
-     * @param string (optional) file to read system-wide defaults from
+     * @param string file to read user-defined options from
+     * @param string file to read system-wide defaults from
+     * @param bool   determines whether a registry object "follows"
+     *               the value of php_dir (is automatically created
+     *               and moved when php_dir is changed)
+     * @param bool   if true, fails if configuration files cannot be loaded
      *
      * @access public
      *
      * @see PEAR_Config::singleton
      */
-    function PEAR_Config($user_file = '', $system_file = '')
+    function PEAR_Config($user_file = '', $system_file = '', $ftp_file = false,
+                         $strict = true)
     {
         $this->PEAR();
+        PEAR_Installer_Role::initializeConfig($this);
         $sl = DIRECTORY_SEPARATOR;
         if (empty($user_file)) {
             if (OS_WINDOWS) {
@@ -420,18 +539,42 @@ class PEAR_Config extends PEAR
                 $system_file = PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.conf';
             }
         }
+
         $this->layers = array_keys($this->configuration);
         $this->files['user'] = $user_file;
         $this->files['system'] = $system_file;
-        if ($user_file && file_exists($user_file)) {
-            $this->readConfigFile($user_file);
+        if ($user_file && @file_exists($user_file)) {
+            $this->pushErrorHandling(PEAR_ERROR_RETURN);
+            $this->readConfigFile($user_file, 'user', $strict);
+            $this->popErrorHandling();
+            if ($this->_errorsFound > 0) {
+                return;
+            }
+        }
+
+        if ($system_file && @file_exists($system_file)) {
+            $this->mergeConfigFile($system_file, false, 'system', $strict);
+            if ($this->_errorsFound > 0) {
+                return;
+            }
+
         }
-        if ($system_file && file_exists($system_file)) {
-            $this->mergeConfigFile($system_file, false, 'system');
+
+        if (!$ftp_file) {
+            $ftp_file = $this->get('remote_config');
+        }
+
+        if ($ftp_file && defined('PEAR_REMOTEINSTALL_OK')) {
+            $this->readFTPConfigFile($ftp_file);
         }
+
         foreach ($this->configuration_info as $key => $info) {
             $this->configuration['default'][$key] = $info['default'];
         }
+
+        $this->_registry['default'] = &new PEAR_Registry($this->configuration['default']['php_dir']);
+        $this->_registry['default']->setConfig($this);
+        $this->_regInitialized['default'] = false;
         //$GLOBALS['_PEAR_Config_instance'] = &$this;
     }
 
@@ -453,16 +596,38 @@ class PEAR_Config extends PEAR
      *
      * @see PEAR_Config::PEAR_Config
      */
-    function &singleton($user_file = '', $system_file = '')
+    function &singleton($user_file = '', $system_file = '', $strict = true)
     {
         if (is_object($GLOBALS['_PEAR_Config_instance'])) {
             return $GLOBALS['_PEAR_Config_instance'];
         }
-        $GLOBALS['_PEAR_Config_instance'] =
-             &new PEAR_Config($user_file, $system_file);
+
+        $t_conf = &new PEAR_Config($user_file, $system_file, false, $strict);
+        if ($t_conf->_errorsFound > 0) {
+             return $t_conf->lastError;
+        }
+
+        $GLOBALS['_PEAR_Config_instance'] = &$t_conf;
         return $GLOBALS['_PEAR_Config_instance'];
     }
 
+    // }}}
+    // {{{ validConfiguration()
+
+    /**
+     * Determine whether any configuration files have been detected, and whether a
+     * registry object can be retrieved from this configuration.
+     * @return bool
+     * @since PEAR 1.4.0a1
+     */
+    function validConfiguration()
+    {
+        if ($this->isDefinedLayer('user') || $this->isDefinedLayer('system')) {
+            return true;
+        }
+        return false;
+    }
+
     // }}}
     // {{{ readConfigFile([file], [layer])
 
@@ -470,35 +635,158 @@ class PEAR_Config extends PEAR
      * Reads configuration data from a file.  All existing values in
      * the config layer are discarded and replaced with data from the
      * file.
-     *
-     * @param string (optional) file to read from, if NULL or not
-     * specified, the last-used file for the same layer (second param)
-     * is used
-     *
-     * @param string (optional) config layer to insert data into
-     * ('user' or 'system')
-     *
+     * @param string file to read from, if NULL or not specified, the
+     *               last-used file for the same layer (second param) is used
+     * @param string config layer to insert data into ('user' or 'system')
      * @return bool TRUE on success or a PEAR error on failure
-     *
-     * @access public
      */
-    function readConfigFile($file = null, $layer = 'user')
+    function readConfigFile($file = null, $layer = 'user', $strict = true)
     {
         if (empty($this->files[$layer])) {
-            return $this->raiseError("unknown config file type `$layer'");
+            return $this->raiseError("unknown config layer `$layer'");
         }
+
         if ($file === null) {
             $file = $this->files[$layer];
         }
+
         $data = $this->_readConfigDataFrom($file);
+
         if (PEAR::isError($data)) {
-            return $data;
+            if ($strict) {
+                $this->_errorsFound++;
+                $this->lastError = $data;
+
+                return $data;
+            } else {
+                return true;
+            }
+        } else {
+            $this->files[$layer] = $file;
         }
+
         $this->_decodeInput($data);
         $this->configuration[$layer] = $data;
+        $this->_setupChannels();
+        if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) {
+            $this->_registry[$layer] = &new PEAR_Registry($phpdir);
+            $this->_registry[$layer]->setConfig($this);
+            $this->_regInitialized[$layer] = false;
+        } else {
+            unset($this->_registry[$layer]);
+        }
         return true;
     }
 
+    // }}}
+
+    /**
+     * @param string url to the remote config file, like ftp://www.example.com/pear/config.ini
+     * @return true|PEAR_Error
+     */
+    function readFTPConfigFile($path)
+    {
+        do { // poor man's try
+            if (!class_exists('Net_FTP')) {
+                if (!class_exists('PEAR_Common')) {
+                    require_once 'PEAR/Common.php';
+                }
+                if (PEAR_Common::isIncludeable('Net/FTP.php')) {
+                    include_once 'Net/FTP.php';
+                }
+            }
+            if (class_exists('Net_FTP') &&
+                  (class_exists('PEAR_FTP') || PEAR_Common::isIncludeable('PEAR/FTP.php'))) {
+                require_once 'PEAR/FTP.php';
+                $this->_ftp = &new PEAR_FTP;
+                $this->_ftp->pushErrorHandling(PEAR_ERROR_RETURN);
+                $e = $this->_ftp->init($path);
+                if (PEAR::isError($e)) {
+                    $this->_ftp->popErrorHandling();
+                    return $e;
+                }
+                $tmp = System::mktemp('-d');
+                PEAR_Common::addTempFile($tmp);
+                $e = $this->_ftp->get(basename($path), $tmp . DIRECTORY_SEPARATOR .
+                    'pear.ini', false, FTP_BINARY);
+                if (PEAR::isError($e)) {
+                    $this->_ftp->popErrorHandling();
+                    return $e;
+                }
+                PEAR_Common::addTempFile($tmp . DIRECTORY_SEPARATOR . 'pear.ini');
+                $this->_ftp->disconnect();
+                $this->_ftp->popErrorHandling();
+                $this->files['ftp'] = $tmp . DIRECTORY_SEPARATOR . 'pear.ini';
+                $e = $this->readConfigFile(null, 'ftp');
+                if (PEAR::isError($e)) {
+                    return $e;
+                }
+                $fail = array();
+                foreach ($this->configuration_info as $key => $val) {
+                    if (in_array($this->getGroup($key),
+                          array('File Locations', 'File Locations (Advanced)')) &&
+                          $this->getType($key) == 'directory') {
+                        // any directory configs must be set for this to work
+                        if (!isset($this->configuration['ftp'][$key])) {
+                            $fail[] = $key;
+                        }
+                    }
+                }
+                if (count($fail)) {
+                    $fail = '"' . implode('", "', $fail) . '"';
+                    unset($this->files['ftp']);
+                    unset($this->configuration['ftp']);
+                    return PEAR::raiseError('ERROR: Ftp configuration file must set all ' .
+                        'directory configuration variables.  These variables were not set: ' .
+                        $fail);
+                } else {
+                    return true;
+                }
+            } else {
+                return PEAR::raiseError('Net_FTP must be installed to use remote config');
+            }
+        } while (false); // poor man's catch
+        unset($this->files['ftp']);
+        return PEAR::raiseError('no remote host specified');
+    }
+
+    // {{{ _setupChannels()
+    
+    /**
+     * Reads the existing configurations and creates the _channels array from it
+     */
+    function _setupChannels()
+    {
+        $set = array_flip(array_values($this->_channels));
+        foreach ($this->configuration as $layer => $data) {
+            $i = 1000;
+            if (isset($data['__channels'])) {
+                foreach ($data['__channels'] as $channel => $info) {
+                    $set[$channel] = $i++;
+                }
+            }
+        }
+        $this->_channels = array_values(array_flip($set));
+        $this->setChannels($this->_channels);
+    }
+
+    // }}}
+    // {{{ deleteChannel(channel)
+
+    function deleteChannel($channel)
+    {
+        foreach ($this->configuration as $layer => $data) {
+            if (isset($data['__channels'])) {
+                if (isset($data['__channels'][strtolower($channel)])) {
+                    unset($this->configuration[$layer]['__channels'][strtolower($channel)]);
+                }
+            }
+        }
+        $this->_channels = array_flip($this->_channels);
+        unset($this->_channels[strtolower($channel)]);
+        $this->_channels = array_flip($this->_channels);
+    }
+
     // }}}
     // {{{ mergeConfigFile(file, [override], [layer])
 
@@ -506,60 +794,95 @@ class PEAR_Config extends PEAR
      * Merges data into a config layer from a file.  Does the same
      * thing as readConfigFile, except it does not replace all
      * existing values in the config layer.
-     *
      * @param string file to read from
-     *
-     * @param bool (optional) whether to overwrite existing data
-     * (default TRUE)
-     *
-     * @param string config layer to insert data into ('user' or
-     * 'system')
-     *
+     * @param bool whether to overwrite existing data (default TRUE)
+     * @param string config layer to insert data into ('user' or 'system')
+     * @param string if true, errors are returned if file opening fails
      * @return bool TRUE on success or a PEAR error on failure
-     *
-     * @access public.
      */
-    function mergeConfigFile($file, $override = true, $layer = 'user')
+    function mergeConfigFile($file, $override = true, $layer = 'user', $strict = true)
     {
         if (empty($this->files[$layer])) {
-            return $this->raiseError("unknown config file type `$layer'");
+            return $this->raiseError("unknown config layer `$layer'");
         }
         if ($file === null) {
             $file = $this->files[$layer];
         }
         $data = $this->_readConfigDataFrom($file);
         if (PEAR::isError($data)) {
-            return $data;
+            if ($strict) {
+                $this->_errorsFound++;
+                $this->lastError = $data;
+
+                return $data;
+            } else {
+                return true;
+            }
         }
         $this->_decodeInput($data);
         if ($override) {
-            $this->configuration[$layer] = array_merge($this->configuration[$layer], $data);
+            $this->configuration[$layer] =
+                PEAR_Config::arrayMergeRecursive($this->configuration[$layer], $data);
+        } else {
+            $this->configuration[$layer] =
+                PEAR_Config::arrayMergeRecursive($data, $this->configuration[$layer]);
+        }
+        $this->_setupChannels();
+        if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) {
+            $this->_registry[$layer] = &new PEAR_Registry($phpdir);
+            $this->_registry[$layer]->setConfig($this);
+            $this->_regInitialized[$layer] = false;
         } else {
-            $this->configuration[$layer] = array_merge($data, $this->configuration[$layer]);
+            unset($this->_registry[$layer]);
         }
         return true;
     }
 
+    // }}}
+    // {{{ arrayMergeRecursive($arr2, $arr1)
+    /**
+     * @param array
+     * @param array
+     * @return array
+     * @static
+     */
+    function arrayMergeRecursive($arr2, $arr1)
+    {
+        $ret = array();
+        foreach ($arr2 as $key => $data) {
+            if (!isset($arr1[$key])) {
+                $ret[$key] = $data;
+                unset($arr1[$key]);
+                continue;
+            }
+            if (is_array($data)) {
+                if (!is_array($arr1[$key])) {
+                    $ret[$key] = $arr1[$key];
+                    unset($arr1[$key]);
+                    continue;
+                }
+                $ret[$key] = PEAR_Config::arrayMergeRecursive($arr1[$key], $arr2[$key]);
+                unset($arr1[$key]);
+            }
+        }
+        return array_merge($ret, $arr1);
+    }
+
     // }}}
     // {{{ writeConfigFile([file], [layer])
 
     /**
      * Writes data into a config layer from a file.
      *
-     * @param string file to read from
-     *
-     * @param bool (optional) whether to overwrite existing data
-     * (default TRUE)
-     *
+     * @param string|null file to read from, or null for default
      * @param string config layer to insert data into ('user' or
-     * 'system')
-     *
+     *               'system')
+     * @param string|null data to write to config file or null for internal data [DEPRECATED]
      * @return bool TRUE on success or a PEAR error on failure
-     *
-     * @access public.
      */
     function writeConfigFile($file = null, $layer = 'user', $data = null)
     {
+        $this->_lazyChannelSetup($layer);
         if ($layer == 'both' || $layer == 'all') {
             foreach ($this->files as $type => $file) {
                 $err = $this->writeConfigFile($file, $type, $data);
@@ -617,30 +940,57 @@ class PEAR_Config extends PEAR
         $size = filesize($file);
         $rt = get_magic_quotes_runtime();
         set_magic_quotes_runtime(0);
-        $contents = fread($fp, $size);
+        if (function_exists('file_get_contents')) {
+            fclose($fp);
+            $contents = file_get_contents($file);
+        } else {
+            $contents = @fread($fp, $size);
+            fclose($fp);
+        }
+        if (empty($contents)) {
+            return $this->raiseError('Configuration file "' . $file . '" is empty');
+        }
+        
         set_magic_quotes_runtime($rt);
-        fclose($fp);
-        $version = '0.1';
+
+        $version = false;
         if (preg_match('/^#PEAR_Config\s+(\S+)\s+/si', $contents, $matches)) {
             $version = $matches[1];
             $contents = substr($contents, strlen($matches[0]));
+        } else {
+            // Museum config file
+            if (substr($contents,0,2) == 'a:') {
+                $version = '0.1';
+            }
         }
-        if (version_compare("$version", '1', '<')) {
+        if ($version && version_compare("$version", '1', '<')) {
+
+            // no '@', it is possible that unserialize
+            // raises a notice but it seems to block IO to
+            // STDOUT if a '@' is used and a notice is raise
             $data = unserialize($contents);
+
+            if (!is_array($data) && !$data) {
+                if ($contents == serialize(false)) {
+                    $data = array();
+                } else {
+                    $err = $this->raiseError("PEAR_Config: bad data in $file");
+                    return $err;
+                }
+            }
             if (!is_array($data)) {
                 if (strlen(trim($contents)) > 0) {
                     $error = "PEAR_Config: bad data in $file";
-//                if (isset($this)) {
-                    return $this->raiseError($error);
-//                } else {
-//                    return PEAR::raiseError($error);
+                    $err = $this->raiseError($error);
+                    return $err;
                 } else {
                     $data = array();
                 }
             }
         // add parsing of newer formats here...
         } else {
-            return $this->raiseError("$file: unknown version `$version'");
+            $err = $this->raiseError("$file: unknown version `$version'");
+            return $err; 
         }
         return $data;
     }
@@ -659,6 +1009,55 @@ class PEAR_Config extends PEAR
     }
 
     // }}}
+
+    /**
+     * @param array information on a role as parsed from its xml file
+     * @return true|PEAR_Error
+     * @access private
+     */
+    function _addConfigVars($vars)
+    {
+        if (count($vars) > 3) {
+            return $this->raiseError('Roles can only define 3 new config variables or less');
+        }
+        foreach ($vars as $name => $var) {
+            if (!is_array($var)) {
+                return $this->raiseError('Configuration information must be an array');
+            }
+            if (!isset($var['type'])) {
+                return $this->raiseError('Configuration information must contain a type');
+            } else {
+                if (!in_array($var['type'],
+                      array('string', 'mask', 'password', 'directory', 'file', 'set'))) {
+                    return $this->raiseError(
+                        'Configuration type must be one of directory, file, string, ' .
+                        'mask, set, or password');
+                }
+            }
+            if (!isset($var['default'])) {
+                return $this->raiseError(
+                    'Configuration information must contain a default value ("default" index)');
+            }
+            if (!isset($var['doc'])) {
+                return $this->raiseError(
+                    'Configuration information must contain a summary ("doc" index)');
+            }
+            if (!isset($var['prompt'])) {
+                return $this->raiseError(
+                    'Configuration information must contain a simple prompt ("prompt" index)');
+            }
+            if (!isset($var['group'])) {
+                return $this->raiseError(
+                    'Configuration information must contain a simple group ("group" index)');
+            }
+            if (isset($this->configuration_info[$name])) {
+                return $this->raiseError('Configuration variable "' . $name .
+                    '" already exists');
+            }
+            $this->configuration_info[$name] = $var;
+        }
+        return true;
+    }
     // {{{ _encodeOutput(&data)
 
     /**
@@ -675,6 +1074,11 @@ class PEAR_Config extends PEAR
     function _encodeOutput(&$data)
     {
         foreach ($data as $key => $value) {
+            if ($key == '__channels') {
+                foreach ($data['__channels'] as $channel => $blah) {
+                    $this->_encodeOutput($data['__channels'][$channel]);
+                }
+            }
             if (!isset($this->configuration_info[$key])) {
                 continue;
             }
@@ -715,6 +1119,11 @@ class PEAR_Config extends PEAR
             return true;
         }
         foreach ($data as $key => $value) {
+            if ($key == '__channels') {
+                foreach ($data['__channels'] as $channel => $blah) {
+                    $this->_decodeInput($data['__channels'][$channel]);
+                }
+            }
             if (!isset($this->configuration_info[$key])) {
                 continue;
             }
@@ -734,8 +1143,41 @@ class PEAR_Config extends PEAR
     }
 
     // }}}
-    // {{{ get(key, [layer])
+    // {{{ getDefaultChannel([layer])
+    /**
+     * Retrieve the default channel.
+     *
+     * On startup, channels are not initialized, so if the default channel is not
+     * pear.php.net, then initialize the config.
+     * @param string registry layer
+     * @return string|false
+     */
+    function getDefaultChannel($layer = null)
+    {
+        $ret = false;
+        if ($layer === null) {
+            foreach ($this->layers as $layer) {
+                if (isset($this->configuration[$layer]['default_channel'])) {
+                    $ret = $this->configuration[$layer]['default_channel'];
+                    break;
+                }
+            }
+        } elseif (isset($this->configuration[$layer]['default_channel'])) {
+            $ret = $this->configuration[$layer]['default_channel'];
+        }
+        if ($ret == 'pear.php.net' && defined('PEAR_RUNTYPE') && PEAR_RUNTYPE == 'pecl') {
+            $ret = 'pecl.php.net';
+        }
+        if ($ret) {
+            if ($ret != 'pear.php.net') {
+                $this->_lazyChannelSetup();
+            }
+            return $ret;
+        }
+        return PEAR_CONFIG_DEFAULT_CHANNEL;
+    }
 
+    // {{{ get(key, [layer])
     /**
      * Returns a configuration value, prioritizing layers as per the
      * layers property.
@@ -746,20 +1188,133 @@ class PEAR_Config extends PEAR
      *
      * @access public
      */
-    function get($key, $layer = null)
+    function get($key, $layer = null, $channel = false)
     {
+        if (!isset($this->configuration_info[$key])) {
+            return null;
+        }
+        if ($key == '__channels') {
+            return null;
+        }
+        if ($key == 'default_channel') {
+            return $this->getDefaultChannel($layer);
+        }
+        if (!$channel) {
+            $channel = $this->getDefaultChannel();
+        } elseif ($channel != 'pear.php.net') {
+            $this->_lazyChannelSetup();
+        }
+        $channel = strtolower($channel);
+        
+        $test = (in_array($key, $this->_channelConfigInfo)) ?
+            $this->_getChannelValue($key, $layer, $channel) :
+            null;
+        if ($test !== null) {
+            if ($this->_installRoot) {
+                if (in_array($this->getGroup($key),
+                      array('File Locations', 'File Locations (Advanced)')) &&
+                      $this->getType($key) == 'directory') {
+                    return $this->_prependPath($test, $this->_installRoot);
+                }
+            }
+            return $test;
+        }
         if ($layer === null) {
             foreach ($this->layers as $layer) {
                 if (isset($this->configuration[$layer][$key])) {
-                    return $this->configuration[$layer][$key];
+                    $test = $this->configuration[$layer][$key];
+                    if ($this->_installRoot) {
+                        if (in_array($this->getGroup($key),
+                              array('File Locations', 'File Locations (Advanced)')) &&
+                              $this->getType($key) == 'directory') {
+                            return $this->_prependPath($test, $this->_installRoot);
+                        }
+                    }
+                    if ($key == 'preferred_mirror') {
+                        $reg = &$this->getRegistry();
+                        if (is_object($reg)) {
+                            $chan = &$reg->getChannel($channel);
+                            if (!$chan->getMirror($test) && $chan->getName() != $test) {
+                                return $channel; // mirror does not exist
+                            }
+                        }
+                    }
+                    return $test;
                 }
             }
         } elseif (isset($this->configuration[$layer][$key])) {
-            return $this->configuration[$layer][$key];
+            $test = $this->configuration[$layer][$key];
+            if ($this->_installRoot) {
+                if (in_array($this->getGroup($key),
+                      array('File Locations', 'File Locations (Advanced)')) &&
+                      $this->getType($key) == 'directory') {
+                    return $this->_prependPath($test, $this->_installRoot);
+                }
+            }
+            if ($key == 'preferred_mirror') {
+                $reg = &$this->getRegistry();
+                if (is_object($reg)) {
+                    $chan = &$reg->getChannel($channel);
+                    if (!$chan->getMirror($test) && $chan->getName() != $test) {
+                        return $channel; // mirror does not exist
+                    }
+                }
+            }
+            return $test;
         }
         return null;
     }
 
+    // }}}
+    // {{{ _getChannelValue(key, value, [layer])
+    /**
+     * Returns a channel-specific configuration value, prioritizing layers as per the
+     * layers property.
+     *
+     * @param string config key
+     *
+     * @return mixed the config value, or NULL if not found
+     *
+     * @access private
+     */
+    function _getChannelValue($key, $layer, $channel)
+    {
+        if ($key == '__channels' || $channel == 'pear.php.net') {
+            return null;
+        }
+        $ret = null;
+        if ($layer === null) {
+            foreach ($this->layers as $ilayer) {
+                if (isset($this->configuration[$ilayer]['__channels'][$channel][$key])) {
+                    $ret = $this->configuration[$ilayer]['__channels'][$channel][$key];
+                    break;
+                }
+            }
+        } elseif (isset($this->configuration[$layer]['__channels'][$channel][$key])) {
+            $ret = $this->configuration[$layer]['__channels'][$channel][$key];
+        }
+        if ($key == 'preferred_mirror') {
+            if ($ret !== null) {
+                $reg = &$this->getRegistry($layer);
+                if (is_object($reg)) {
+                    $chan = &$reg->getChannel($channel);
+                    if (!$chan->getMirror($ret) && $chan->getName() != $ret) {
+                        return $channel; // mirror does not exist
+                    }
+                }
+                return $ret;
+            }
+            if ($channel == $this->getDefaultChannel($layer)) {
+                return $channel; // we must use the channel name as the preferred mirror
+                                 // if the user has not chosen an alternate
+            } else {
+                return $this->getDefaultChannel($layer);
+            }
+        }
+        return $ret;
+    }
+
+
     // }}}
     // {{{ set(key, value, [layer])
 
@@ -770,17 +1325,38 @@ class PEAR_Config extends PEAR
      * variable will be validated against its legal values.
      *
      * @param string config key
-     *
      * @param string config value
-     *
      * @param string (optional) config layer
-     *
+     * @param string channel to set this value for, or null for global value
      * @return bool TRUE on success, FALSE on failure
-     *
-     * @access public
      */
-    function set($key, $value, $layer = 'user')
+    function set($key, $value, $layer = 'user', $channel = false)
     {
+        if ($key == '__channels') {
+            return false;
+        }
+        if (!isset($this->configuration[$layer])) {
+            return false;
+        }
+        if ($key == 'default_channel') {
+            // can only set this value globally
+            $channel = 'pear.php.net';
+            if ($value != 'pear.php.net') {
+                $this->_lazyChannelSetup($layer);
+            }
+        }
+        if ($key == 'preferred_mirror') {
+            if ($channel == '__uri') {
+                return false; // can't set the __uri pseudo-channel's mirror
+            }
+            $reg = &$this->getRegistry($layer);
+            if (is_object($reg)) {
+                $chan = &$reg->getChannel($channel ? $channel : 'pear.php.net');
+                if (!$chan->getMirror($value) && $chan->getName() != $value) {
+                    return false; // mirror does not exist
+                }
+            }
+        }
         if (empty($this->configuration_info[$key])) {
             return false;
         }
@@ -804,7 +1380,119 @@ class PEAR_Config extends PEAR
                 break;
             }
         }
+        if (!$channel) {
+            $channel = $this->get('default_channel', null, 'pear.php.net');
+        }
+        if (!in_array($channel, $this->_channels)) {
+            $this->_lazyChannelSetup($layer);
+            $reg = &$this->getRegistry($layer);
+            if ($reg) {
+                $channel = $reg->channelName($channel);
+            }
+            if (!in_array($channel, $this->_channels)) {
+                return false;
+            }
+        }
+        if ($channel != 'pear.php.net') {
+            if (in_array($key, $this->_channelConfigInfo)) {
+                $this->configuration[$layer]['__channels'][$channel][$key] = $value;
+                return true;
+            } else {
+                return false;
+            }
+        } else {
+            if ($key == 'default_channel') {
+                if (!isset($reg)) {
+                    $reg = &$this->getRegistry($layer);
+                    if (!$reg) {
+                        $reg = &$this->getRegistry();
+                    }
+                }
+                if ($reg) {
+                    $value = $reg->channelName($value);
+                }
+                if (!$value) {
+                    return false;
+                }
+            }
+        }
         $this->configuration[$layer][$key] = $value;
+        if ($key == 'php_dir' && !$this->_noRegistry) {
+            if (!isset($this->_registry[$layer]) ||
+                  $value != $this->_registry[$layer]->install_dir) {
+                $this->_registry[$layer] = &new PEAR_Registry($value);
+                $this->_regInitialized[$layer] = false;
+                $this->_registry[$layer]->setConfig($this);
+            }
+        }
+        return true;
+    }
+
+    // }}}
+    function _lazyChannelSetup($uselayer = false)
+    {
+        if ($this->_noRegistry) {
+            return;
+        }
+        $merge = false;
+        foreach ($this->_registry as $layer => $p) {
+            if ($uselayer && $uselayer != $layer) {
+                continue;
+            }
+            if (!$this->_regInitialized[$layer]) {
+                if ($layer == 'default' && isset($this->_registry['user']) ||
+                      isset($this->_registry['system'])) {
+                    // only use the default registry if there are no alternatives
+                    continue;
+                }
+                if (!is_object($this->_registry[$layer])) {
+                    if ($phpdir = $this->get('php_dir', $layer, 'pear.php.net')) {
+                        $this->_registry[$layer] = &new PEAR_Registry($phpdir);
+                        $this->_registry[$layer]->setConfig($this);
+                        $this->_regInitialized[$layer] = false;
+                    } else {
+                        unset($this->_registry[$layer]);
+                        return;
+                    }
+                }
+                $this->setChannels($this->_registry[$layer]->listChannels(), $merge);
+                $this->_regInitialized[$layer] = true;
+                $merge = true;
+            }
+        }
+    }
+    // {{{ setChannels()
+    
+    /**
+     * Set the list of channels.
+     *
+     * This should be set via a call to {@link PEAR_Registry::listChannels()}
+     * @param array
+     * @param bool
+     * @return bool success of operation
+     */
+    function setChannels($channels, $merge = false)
+    {
+        if (!is_array($channels)) {
+            return false;
+        }
+        if ($merge) {
+            $this->_channels = array_merge($this->_channels, $channels);
+        } else {
+            $this->_channels = $channels;
+        }
+        foreach ($channels as $channel) {
+            $channel = strtolower($channel);
+            if ($channel == 'pear.php.net') {
+                continue;
+            }
+            foreach ($this->layers as $layer) {
+                if (!isset($this->configuration[$layer]['__channels'][$channel])
+                      || !is_array($this->configuration[$layer]['__channels'][$channel])) {
+                    $this->configuration[$layer]['__channels'][$channel] = array();
+                }
+            }
+        }
         return true;
     }
 
@@ -963,7 +1651,7 @@ class PEAR_Config extends PEAR
             }
             return array_keys($valid_set);
         }
-        return false;
+        return null;
     }
 
     // }}}
@@ -980,7 +1668,14 @@ class PEAR_Config extends PEAR
     {
         $keys = array();
         foreach ($this->layers as $layer) {
-            $keys = array_merge($keys, $this->configuration[$layer]);
+            $test = $this->configuration[$layer];
+            if (isset($test['__channels'])) {
+                foreach ($test['__channels'] as $channel => $configs) {
+                    $keys = array_merge($keys, $configs);
+                }
+            }
+            unset($test['__channels']);
+            $keys = array_merge($keys, $test);
         }
         return array_keys($keys);
     }
@@ -1001,6 +1696,13 @@ class PEAR_Config extends PEAR
      */
     function remove($key, $layer = 'user')
     {
+        $channel = $this->getDefaultChannel();
+        if ($channel !== 'pear.php.net') {
+            if (isset($this->configuration[$layer]['__channels'][$channel][$key])) {
+                unset($this->configuration[$layer]['__channels'][$channel][$key]);
+                return true;
+            }
+        }
         if (isset($this->configuration[$layer][$key])) {
             unset($this->configuration[$layer][$key]);
             return true;
@@ -1074,15 +1776,31 @@ class PEAR_Config extends PEAR
      * Tells what config layer that gets to define a key.
      *
      * @param string config key
+     * @param boolean return the defining channel
+     *
+     * @return string|array the config layer, or an empty string if not found.
      *
-     * @return string the config layer, or an empty string if not found
+     *         if $returnchannel, the return is an array array('layer' => layername,
+     *         'channel' => channelname), or an empty string if not found
      *
      * @access public
      */
-    function definedBy($key)
+    function definedBy($key, $returnchannel = false)
     {
         foreach ($this->layers as $layer) {
+            $channel = $this->getDefaultChannel();
+            if ($channel !== 'pear.php.net') {
+                if (isset($this->configuration[$layer]['__channels'][$channel][$key])) {
+                    if ($returnchannel) {
+                        return array('layer' => $layer, 'channel' => $channel);
+                    }
+                    return $layer;
+                }
+            }
             if (isset($this->configuration[$layer][$key])) {
+                if ($returnchannel) {
+                    return array('layer' => $layer, 'channel' => 'pear.php.net');
+                }
                 return $layer;
             }
         }
@@ -1164,6 +1882,142 @@ class PEAR_Config extends PEAR
     }
 
     // }}}
+    // {{{ apiVersion()
+    function apiVersion()
+    {
+        return '1.1';
+    }
+    // }}}
+
+    /**
+     * @return PEAR_Registry
+     */
+    function &getRegistry($use = null)
+    {
+        if ($use === null) {
+            $layer = 'user';
+        } else {
+            $layer = $use;
+        }
+        if (isset($this->_registry[$layer])) {
+            return $this->_registry[$layer];
+        } elseif ($use === null && isset($this->_registry['system'])) {
+            return $this->_registry['system'];
+        } elseif ($use === null && isset($this->_registry['default'])) {
+            return $this->_registry['default'];
+        } elseif ($use) {
+            $a = false;
+            return $a;
+        } else {
+            // only go here if null was passed in
+            die("CRITICAL ERROR: Registry could not be initialized from any value");
+        }
+    }
+    /**
+     * This is to allow customization like the use of installroot
+     * @param PEAR_Registry
+     * @return bool
+     */
+    function setRegistry(&$reg, $layer = 'user')
+    {
+        if ($this->_noRegistry) {
+            return false;
+        }
+        if (!in_array($layer, array('user', 'system'))) {
+            return false;
+        }
+        $this->_registry[$layer] = &$reg;
+        if (is_object($reg)) {
+            $this->_registry[$layer]->setConfig($this);
+        }
+        return true;
+    }
+
+    function noRegistry()
+    {
+        $this->_noRegistry = true;
+    }
+
+    /**
+     * @return PEAR_Remote
+     */
+    function &getRemote()
+    {
+        $remote = &new PEAR_Remote($this);
+        return $remote;
+    }
+
+    /**
+     * @return PEAR_REST
+     */
+    function &getREST($version, $options = array())
+    {
+        $version = str_replace('.', '', $version);
+        if (!class_exists($class = 'PEAR_REST_' . $version)) {
+            require_once 'PEAR/REST/' . $version . '.php';
+        }
+        $remote = &new $class($this, $options);
+        return $remote;
+    }
+
+    /**
+     * The ftp server is set in {@link readFTPConfigFile()}.  It exists only if a
+     * remote configuration file has been specified
+     * @return PEAR_FTP|false
+     */
+    function &getFTP()
+    {
+        if (isset($this->_ftp)) {
+            return $this->_ftp;
+        } else {
+            $a = false;
+            return $a;
+        }
+    }
+
+    // {{{ _prependPath($path, $prepend)
+
+    function _prependPath($path, $prepend)
+    {
+        if (strlen($prepend) > 0) {
+            if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) {
+                if (preg_match('/^[a-z]:/i', $prepend)) {
+                    $prepend = substr($prepend, 2);
+                } elseif ($prepend{0} != '\\') {
+                    $prepend = "\\$prepend";
+                }
+                $path = substr($path, 0, 2) . $prepend . substr($path, 2);
+            } else {
+                $path = $prepend . $path;
+            }
+        }
+        return $path;
+    }
+    // }}}
+
+    /**
+     * @param string|false installation directory to prepend to all _dir variables, or false to
+     *                     disable
+     */
+    function setInstallRoot($root)
+    {
+        if (substr($root, -1) == DIRECTORY_SEPARATOR) {
+            $root = substr($root, 0, -1);
+        }
+        $old = $this->_installRoot;
+        $this->_installRoot = $root;
+        if (($old != $root) && !$this->_noRegistry) {
+            foreach (array_keys($this->_registry) as $layer) {
+                if ($layer == 'ftp' || !isset($this->_registry[$layer])) {
+                    continue;
+                }
+                $this->_registry[$layer] =
+                    &new PEAR_Registry($this->get('php_dir', $layer, 'pear.php.net'));
+                $this->_registry[$layer]->setConfig($this);
+                $this->_regInitialized[$layer] = false;
+            }
+        }
+    }
 }
 
 ?>
index ec2bd7e86d833e86736d35285a3bf75366b54486..17691687c73591d7d6e70555dde5ceb9f66df6c3 100644 (file)
 // |          Stig Bakken <ssb@php.net>                                   |
 // +----------------------------------------------------------------------+
 //
+// THIS FILE IS DEPRECATED IN FAVOR OF DEPENDENCY2.PHP, AND IS NOT USED IN THE INSTALLER
 // $Id$
 
 require_once "PEAR.php";
+require_once "OS/Guess.php";
 
 define('PEAR_DEPENDENCY_MISSING',        -1);
 define('PEAR_DEPENDENCY_CONFLICT',       -2);
@@ -82,12 +84,13 @@ class PEAR_Dependency
         $rel = isset($opts['rel']) ? $opts['rel'] : 'has';
         $req = isset($opts['version']) ? $opts['version'] : null;
         $name = isset($opts['name']) ? $opts['name'] : null;
+        $channel = isset($opts['channel']) ? $opts['channel'] : 'pear.php.net';
         $opt = (isset($opts['optional']) && $opts['optional'] == 'yes') ?
             $opts['optional'] : null;
         $errmsg = '';
         switch ($opts['type']) {
             case 'pkg':
-                return $this->checkPackage($errmsg, $name, $req, $rel, $opt);
+                return $this->checkPackage($errmsg, $name, $req, $rel, $opt, $channel);
                 break;
             case 'ext':
                 return $this->checkExtension($errmsg, $name, $req, $rel, $opt);
@@ -123,29 +126,30 @@ class PEAR_Dependency
      * @param string $req       The package version required
      * @param string $relation  How to compare versions with each other
      * @param bool   $opt       Whether the relationship is optional
+     * @param string $channel   Channel name
      *
      * @return mixed bool false if no error or the error string
      */
     function checkPackage(&$errmsg, $name, $req = null, $relation = 'has',
-                          $opt = false)
+                          $opt = false, $channel = 'pear.php.net')
     {
         if (is_string($req) && substr($req, 0, 2) == 'v.') {
             $req = substr($req, 2);
         }
         switch ($relation) {
             case 'has':
-                if (!$this->registry->packageExists($name)) {
+                if (!$this->registry->packageExists($name, $channel)) {
                     if ($opt) {
-                        $errmsg = "package `$name' is recommended to utilize some features.";
+                        $errmsg = "package `$channel/$name' is recommended to utilize some features.";
                         return PEAR_DEPENDENCY_MISSING_OPTIONAL;
                     }
-                    $errmsg = "requires package `$name'";
+                    $errmsg = "requires package `$channel/$name'";
                     return PEAR_DEPENDENCY_MISSING;
                 }
                 return false;
             case 'not':
-                if ($this->registry->packageExists($name)) {
-                    $errmsg = "conflicts with package `$name'";
+                if ($this->registry->packageExists($name, $channel)) {
+                    $errmsg = "conflicts with package `$channel/$name'";
                     return PEAR_DEPENDENCY_CONFLICT;
                 }
                 return false;
@@ -155,26 +159,26 @@ class PEAR_Dependency
             case 'ne':
             case 'ge':
             case 'gt':
-                $version = $this->registry->packageInfo($name, 'version');
-                if (!$this->registry->packageExists($name)
+                $version = $this->registry->packageInfo($name, 'version', $channel);
+                if (!$this->registry->packageExists($name, $channel)
                     || !version_compare("$version", "$req", $relation))
                 {
                     $code = $this->codeFromRelation($relation, $version, $req, $opt);
                     if ($opt) {
-                        $errmsg = "package `$name' version " . $this->signOperator($relation) .
+                        $errmsg = "package `$channel/$name' version " . $this->signOperator($relation) .
                             " $req is recommended to utilize some features.";
                         if ($version) {
                             $errmsg .= "  Installed version is $version";
                         }
                         return $code;
                     }
-                    $errmsg = "requires package `$name' " .
+                    $errmsg = "requires package `$channel/$name' " .
                         $this->signOperator($relation) . " $req";
                     return $code;
                 }
                 return false;
         }
-        $errmsg = "relation '$relation' with requirement '$req' is not supported (name=$name)";
+        $errmsg = "relation '$relation' with requirement '$req' is not supported (name=$channel/$name)";
         return PEAR_DEPENDENCY_BAD_DEPENDENCY;
     }
 
@@ -187,30 +191,36 @@ class PEAR_Dependency
      * @param string $error     The resultant error string
      * @param string $warning   The resultant warning string
      * @param string $name      Name of the package to test
+     * @param string $channel   Channel name of the package
      *
      * @return bool true if there were errors
      */
-    function checkPackageUninstall(&$error, &$warning, $package)
+    function checkPackageUninstall(&$error, &$warning, $package, $channel = 'pear.php.net')
     {
+        $channel = strtolower($channel);
         $error = null;
-        $packages = $this->registry->listPackages();
-        foreach ($packages as $pkg) {
-            if ($pkg == $package) {
-                continue;
-            }
-            $deps = $this->registry->packageInfo($pkg, 'release_deps');
-            if (empty($deps)) {
-                continue;
-            }
-            foreach ($deps as $dep) {
-                if ($dep['type'] == 'pkg' && strcasecmp($dep['name'], $package) == 0) {
-                    if ($dep['rel'] == 'ne' || $dep['rel'] == 'not') {
-                        continue;
-                    }
-                    if (isset($dep['optional']) && $dep['optional'] == 'yes') {
-                        $warning .= "\nWarning: Package '$pkg' optionally depends on '$package'";
-                    } else {
-                        $error .= "Package '$pkg' depends on '$package'\n";
+        $channels = $this->registry->listAllPackages();
+        foreach ($channels as $channelname => $packages) {
+            foreach ($packages as $pkg) {
+                if ($pkg == $package && $channel == $channelname) {
+                    continue;
+                }
+                $deps = $this->registry->packageInfo($pkg, 'release_deps', $channel);
+                if (empty($deps)) {
+                    continue;
+                }
+                foreach ($deps as $dep) {
+                    $depchannel = isset($dep['channel']) ? $dep['channel'] : 'pear.php.net';
+                    if ($dep['type'] == 'pkg' && (strcasecmp($dep['name'], $package) == 0) &&
+                          ($depchannel == $channel)) {
+                        if ($dep['rel'] == 'ne') {
+                            continue;
+                        }
+                        if (isset($dep['optional']) && $dep['optional'] == 'yes') {
+                            $warning .= "\nWarning: Package '$depchannel/$pkg' optionally depends on '$channel:/package'";
+                        } else {
+                            $error .= "Package '$depchannel/$pkg' depends on '$channel/$package'\n";
+                        }
                     }
                 }
             }
@@ -244,7 +254,7 @@ class PEAR_Dependency
         }
 
         if (!extension_loaded($name)) {
-            if ($relation == 'not') {
+            if ($relation == 'ne') {
                 return false;
             }
             if ($opt) {
@@ -293,7 +303,6 @@ class PEAR_Dependency
         // comma separated values or something similar to PEAR_OS
         static $myos;
         if (empty($myos)) {
-            include_once "OS/Guess.php";
             $myos = new OS_Guess();
         }
         // only 'has' relation is currently supported
@@ -322,8 +331,7 @@ class PEAR_Dependency
             return false;
         }
         if ($relation == 'not') {
-            $errmsg = 'Invalid dependency - "not" is not allowed for php dependencies, ' .
-                'php cannot conflict with itself';
+            $errmsg = "Invalid dependency - 'not' is allowed when specifying PHP, you must run PHP in PHP";
             return PEAR_DEPENDENCY_BAD_DEPENDENCY;
         }
         if (substr($req, 0, 2) == 'v.') {
diff --git a/pear/PEAR/Dependency2.php b/pear/PEAR/Dependency2.php
new file mode 100644 (file)
index 0000000..3771c5f
--- /dev/null
@@ -0,0 +1,1195 @@
+<?php
+/**
+ * PEAR_Dependency2, advanced dependency validation
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a1
+ */
+
+/**
+ * Required for the PEAR_VALIDATE_* constants
+ */
+require_once 'PEAR/Validate.php';
+
+/**
+ * Dependency check for PEAR packages
+ *
+ * This class handles both version 1.0 and 2.0 dependencies
+ * WARNING: *any* changes to this class must be duplicated in the
+ * test_PEAR_Dependency2 class found in tests/PEAR_Dependency2/setup.php.inc,
+ * or unit tests will not actually validate the changes
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @PEAR-VER@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
+ */
+class PEAR_Dependency2
+{
+    /**
+     * One of the PEAR_VALIDATE_* states
+     * @see PEAR_VALIDATE_NORMAL
+     * @var integer
+     */
+    var $_state;
+    /**
+     * Command-line options to install/upgrade/uninstall commands
+     * @param array
+     */
+    var $_options;
+    /**
+     * @var OS_Guess
+     */
+    var $_os;
+    /**
+     * @var PEAR_Registry
+     */
+    var $_registry;
+    /**
+     * @var PEAR_Config
+     */
+    var $_config;
+    /**
+     * @var PEAR_DependencyDB
+     */
+    var $_dependencydb;
+    /**
+     * Output of PEAR_Registry::parsedPackageName()
+     * @var array
+     */
+    var $_currentPackage;
+    /**
+     * @param PEAR_Config
+     * @param array installation options
+     * @param array format of PEAR_Registry::parsedPackageName()
+     * @param int installation state (one of PEAR_VALIDATE_*)
+     */
+    function PEAR_Dependency2(&$config, $installoptions, $package,
+                              $state = PEAR_VALIDATE_INSTALLING)
+    {
+        $this->_config = &$config;
+        $this->_registry = &$config->getRegistry();
+        if (!class_exists('PEAR_DependencyDB')) {
+            require_once 'PEAR/DependencyDB.php';
+        }
+        $this->_dependencydb = &PEAR_DependencyDB::singleton($config);
+        $this->_options = $installoptions;
+        $this->_state = $state;
+        if (!class_exists('OS_Guess')) {
+            require_once 'OS/Guess.php';
+        }
+        $this->_os = new OS_Guess;
+        $this->_currentPackage = $package;
+    }
+
+    function _getExtraString($dep)
+    {
+        $extra = ' (';
+        if (isset($dep['uri'])) {
+            return '';
+        }
+        if (isset($dep['recommended'])) {
+            $extra .= 'recommended version ' . $dep['recommended'];
+        } else {
+            if (isset($dep['min'])) {
+                $extra .= 'version >= ' . $dep['min'];
+            }
+            if (isset($dep['max'])) {
+                if ($extra != ' (') {
+                    $extra .= ', ';
+                }
+                $extra .= 'version <= ' . $dep['max'];
+            }
+            if (isset($dep['exclude'])) {
+                if (!is_array($dep['exclude'])) {
+                    $dep['exclude'] = array($dep['exclude']);
+                }
+                if ($extra != ' (') {
+                    $extra .= ', ';
+                }
+                $extra .= 'excluded versions: ';
+                foreach ($dep['exclude'] as $i => $exclude) {
+                    if ($i) {
+                        $extra .= ', ';
+                    }
+                    $extra .= $exclude;
+                }
+            }
+        }
+        $extra .= ')';
+        if ($extra == ' ()') {
+            $extra = '';
+        }
+        return $extra;
+    }
+
+    /**
+     * This makes unit-testing a heck of a lot easier
+     */
+    function getPHP_OS()
+    {
+        return PHP_OS;
+    }
+
+    /**
+     * This makes unit-testing a heck of a lot easier
+     */
+    function getsysname()
+    {
+        return $this->_os->getSysname();
+    }
+
+    /**
+     * Specify a dependency on an OS.  Use arch for detailed os/processor information
+     *
+     * There are two generic OS dependencies that will be the most common, unix and windows.
+     * Other options are linux, freebsd, darwin (OS X), sunos, irix, hpux, aix
+     */
+    function validateOsDependency($dep)
+    {
+        if ($this->_state != PEAR_VALIDATE_INSTALLING &&
+              $this->_state != PEAR_VALIDATE_DOWNLOADING) {
+            return true;
+        }
+        if (isset($dep['conflicts'])) {
+            $not = true;
+        } else {
+            $not = false;
+        }
+        if ($dep['name'] == '*') {
+            return true;
+        }
+        switch (strtolower($dep['name'])) {
+            case 'windows' :
+                if ($not) {
+                    if (strtolower(substr($this->getPHP_OS(), 0, 3)) == 'win') {
+                        if (!isset($this->_options['nodeps']) &&
+                              !isset($this->_options['force'])) {
+                            return $this->raiseError("Cannot install %s on Windows");
+                        } else {
+                            return $this->warning("warning: Cannot install %s on Windows");
+                        }
+                    }
+                } else {
+                    if (strtolower(substr($this->getPHP_OS(), 0, 3)) != 'win') {
+                        if (!isset($this->_options['nodeps']) &&
+                              !isset($this->_options['force'])) {
+                            return $this->raiseError("Can only install %s on Windows");
+                        } else {
+                            return $this->warning("warning: Can only install %s on Windows");
+                        }
+                    }
+                }
+            break;
+            case 'unix' :
+                $unices = array('linux', 'freebsd', 'darwin', 'sunos', 'irix', 'hpux', 'aix');
+                if ($not) {
+                    if (in_array($this->getSysname(), $unices)) {
+                        if (!isset($this->_options['nodeps']) &&
+                              !isset($this->_options['force'])) {
+                            return $this->raiseError("Cannot install %s on any Unix system");
+                        } else {
+                            return $this->warning(
+                                "warning: Cannot install %s on any Unix system");
+                        }
+                    }
+                } else {
+                    if (!in_array($this->getSysname(), $unices)) {
+                        if (!isset($this->_options['nodeps']) &&
+                              !isset($this->_options['force'])) {
+                            return $this->raiseError("Can only install %s on a Unix system");
+                        } else {
+                            return $this->warning(
+                                "warning: Can only install %s on a Unix system");
+                        }
+                    }
+                }
+            break;
+            default :
+                if ($not) {
+                    if (strtolower($dep['name']) == strtolower($this->getSysname())) {
+                        if (!isset($this->_options['nodeps']) &&
+                              !isset($this->_options['force'])) {
+                            return $this->raiseError('Cannot install %s on ' . $dep['name'] .
+                                ' operating system');
+                        } else {
+                            return $this->warning('warning: Cannot install %s on ' .
+                                $dep['name'] . ' operating system');
+                        }
+                    }
+                } else {
+                    if (strtolower($dep['name']) != strtolower($this->getSysname())) {
+                        if (!isset($this->_options['nodeps']) &&
+                              !isset($this->_options['force'])) {
+                            return $this->raiseError('Cannot install %s on ' .
+                                $this->getSysname() .
+                                ' operating system, can only install on ' . $dep['name']);
+                        } else {
+                            return $this->warning('warning: Cannot install %s on ' .
+                                $this->getSysname() .
+                                ' operating system, can only install on ' . $dep['name']);
+                        }
+                    }
+                }
+        }
+        return true;
+    }
+
+    /**
+     * This makes unit-testing a heck of a lot easier
+     */
+    function matchSignature($pattern)
+    {
+        return $this->_os->matchSignature($pattern);
+    }
+
+    /**
+     * Specify a complex dependency on an OS/processor/kernel version,
+     * Use OS for simple operating system dependency.
+     *
+     * This is the only dependency that accepts an eregable pattern.  The pattern
+     * will be matched against the php_uname() output parsed by OS_Guess
+     */
+    function validateArchDependency($dep)
+    {
+        if ($this->_state != PEAR_VALIDATE_INSTALLING) {
+            return true;
+        }
+        if (isset($dep['conflicts'])) {
+            $not = true;
+        } else {
+            $not = false;
+        }
+        if (!$this->matchSignature($dep['pattern'])) {
+            if (!$not) {
+                if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+                    return $this->raiseError('%s Architecture dependency failed, does not ' .
+                        'match "' . $dep['pattern'] . '"');
+                } else {
+                    return $this->warning('warning: %s Architecture dependency failed, does ' .
+                        'not match "' . $dep['pattern'] . '"');
+                }
+            }
+            return true;
+        } else {
+            if ($not) {
+                if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+                    return $this->raiseError('%s Architecture dependency failed, required "' .
+                        $dep['pattern'] . '"');
+                } else {
+                    return $this->warning('warning: %s Architecture dependency failed, ' .
+                        'required "' . $dep['pattern'] . '"');
+                }
+            }
+            return true;
+        }
+    }
+
+    /**
+     * This makes unit-testing a heck of a lot easier
+     */
+    function extension_loaded($name)
+    {
+        return extension_loaded($name);
+    }
+
+    /**
+     * This makes unit-testing a heck of a lot easier
+     */
+    function phpversion($name = null)
+    {
+        if ($name !== null) {
+            return phpversion($name);
+        } else {
+            return phpversion();
+        }
+    }
+
+    function validateExtensionDependency($dep, $required = true)
+    {
+        if ($this->_state != PEAR_VALIDATE_INSTALLING &&
+              $this->_state != PEAR_VALIDATE_DOWNLOADING) {
+            return true;
+        }
+        $loaded = $this->extension_loaded($dep['name']);
+        $extra = $this->_getExtraString($dep);
+        if (isset($dep['exclude'])) {
+            if (!is_array($dep['exclude'])) {
+                $dep['exclude'] = array($dep['exclude']);
+            }
+        }
+        if (!isset($dep['min']) && !isset($dep['max']) &&
+              !isset($dep['recommended']) && !isset($dep['exclude'])) {
+            if ($loaded) {
+                if (isset($dep['conflicts'])) {
+                    if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+                        return $this->raiseError('%s conflicts with PHP extension "' .
+                            $dep['name'] . '"' . $extra);
+                    } else {
+                        return $this->warning('warning: %s conflicts with PHP extension "' .
+                            $dep['name'] . '"' . $extra);
+                    }
+                }
+                return true;
+            } else {
+                if (isset($dep['conflicts'])) {
+                    return true;
+                }
+                if ($required) {
+                    if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+                        return $this->raiseError('%s requires PHP extension "' .
+                            $dep['name'] . '"' . $extra);
+                    } else {
+                        return $this->warning('warning: %s requires PHP extension "' .
+                            $dep['name'] . '"' . $extra);
+                    }
+                } else {
+                    return $this->warning('%s can optionally use PHP extension "' .
+                        $dep['name'] . '"' . $extra);
+                }
+            }
+        }
+        if (!$loaded) {
+            if (isset($dep['conflicts'])) {
+                return true;
+            }
+            if (!$required) {
+                return $this->warning('%s can optionally use PHP extension "' .
+                    $dep['name'] . '"' . $extra);
+            } else {
+                if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+                    return $this->raiseError('%s requires PHP extension "' . $dep['name'] .
+                        '"' . $extra);
+                }
+                    return $this->warning('warning: %s requires PHP extension "' . $dep['name'] .
+                        '"' . $extra);
+            }
+        }
+        $version = (string) $this->phpversion($dep['name']);
+        if (empty($version)) {
+            $version = '0';
+        }
+        $fail = false;
+        if (isset($dep['min'])) {
+            if (!version_compare($version, $dep['min'], '>=')) {
+                $fail = true;
+            }
+        }
+        if (isset($dep['max'])) {
+            if (!version_compare($version, $dep['max'], '<=')) {
+                $fail = true;
+            }
+        }
+        if ($fail && !isset($dep['conflicts'])) {
+            if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+                return $this->raiseError('%s requires PHP extension "' . $dep['name'] .
+                    '"' . $extra . ', installed version is ' . $version);
+            } else {
+                return $this->warning('warning: %s requires PHP extension "' . $dep['name'] .
+                    '"' . $extra . ', installed version is ' . $version);
+            }
+        } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail && isset($dep['conflicts'])) {
+            if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+                return $this->raiseError('%s conflicts with PHP extension "' .
+                    $dep['name'] . '"' . $extra . ', installed version is ' . $version);
+            } else {
+                return $this->warning('warning: %s conflicts with PHP extension "' .
+                    $dep['name'] . '"' . $extra . ', installed version is ' . $version);
+            }
+        }
+        if (isset($dep['exclude'])) {
+            foreach ($dep['exclude'] as $exclude) {
+                if (version_compare($version, $exclude, '==')) {
+                    if (isset($dep['conflicts'])) {
+                        continue;
+                    }
+                    if (!isset($this->_options['nodeps']) &&
+                          !isset($this->_options['force'])) {
+                        return $this->raiseError('%s is not compatible with PHP extension "' .
+                            $dep['name'] . '" version ' .
+                            $exclude);
+                    } else {
+                        return $this->warning('warning: %s is not compatible with PHP extension "' .
+                            $dep['name'] . '" version ' .
+                            $exclude);
+                    }
+                } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) {
+                    if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+                        return $this->raiseError('%s conflicts with PHP extension "' .
+                            $dep['name'] . '"' . $extra . ', installed version is ' . $version);
+                    } else {
+                        return $this->warning('warning: %s conflicts with PHP extension "' .
+                            $dep['name'] . '"' . $extra . ', installed version is ' . $version);
+                    }
+                }
+            }
+        }
+        if (isset($dep['recommended'])) {
+            if (version_compare($version, $dep['recommended'], '==')) {
+                return true;
+            } else {
+                if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+                    return $this->raiseError('%s dependency: PHP extension ' . $dep['name'] .
+                        ' version "' . $version . '"' .
+                        ' is not the recommended version "' . $dep['recommended'] .
+                        '", but may be compatible, use --force to install');
+                } else {
+                    return $this->warning('warning: %s dependency: PHP extension ' .
+                        $dep['name'] . ' version "' . $version . '"' .
+                        ' is not the recommended version "' . $dep['recommended'].'"');
+                }
+            }
+        }
+        return true;
+    }
+
+    function validatePhpDependency($dep)
+    {
+        if ($this->_state != PEAR_VALIDATE_INSTALLING &&
+              $this->_state != PEAR_VALIDATE_DOWNLOADING) {
+            return true;
+        }
+        $version = $this->phpversion();
+        $extra = $this->_getExtraString($dep);
+        if (isset($dep['exclude'])) {
+            if (!is_array($dep['exclude'])) {
+                $dep['exclude'] = array($dep['exclude']);
+            }
+        }
+        if (isset($dep['min'])) {
+            if (!version_compare($version, $dep['min'], '>=')) {
+                if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+                    return $this->raiseError('%s requires PHP' .
+                        $extra . ', installed version is ' . $version);
+                } else {
+                    return $this->warning('warning: %s requires PHP' .
+                        $extra . ', installed version is ' . $version);
+                }
+            }
+        }
+        if (isset($dep['max'])) {
+            if (!version_compare($version, $dep['max'], '<=')) {
+                if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+                    return $this->raiseError('%s requires PHP' .
+                        $extra . ', installed version is ' . $version);
+                } else {
+                    return $this->warning('warning: %s requires PHP' .
+                        $extra . ', installed version is ' . $version);
+                }
+            }
+        }
+        if (isset($dep['exclude'])) {
+            foreach ($dep['exclude'] as $exclude) {
+                if (version_compare($version, $exclude, '==')) {
+                    if (!isset($this->_options['nodeps']) &&
+                          !isset($this->_options['force'])) {
+                        return $this->raiseError('%s is not compatible with PHP version ' .
+                            $exclude);
+                    } else {
+                        return $this->warning(
+                            'warning: %s is not compatible with PHP version ' .
+                            $exclude);
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * This makes unit-testing a heck of a lot easier
+     */
+    function getPEARVersion()
+    {
+        return '@PEAR-VER@';
+    }
+
+    function validatePearinstallerDependency($dep)
+    {
+        $pearversion = $this->getPEARVersion();
+        $extra = $this->_getExtraString($dep);
+        if (isset($dep['exclude'])) {
+            if (!is_array($dep['exclude'])) {
+                $dep['exclude'] = array($dep['exclude']);
+            }
+        }
+        if (version_compare($pearversion, $dep['min'], '<')) {
+            if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+                return $this->raiseError('%s requires PEAR Installer' . $extra .
+                    ', installed version is ' . $pearversion);
+            } else {
+                return $this->warning('warning: %s requires PEAR Installer' . $extra .
+                    ', installed version is ' . $pearversion);
+            }
+        }
+        if (isset($dep['max'])) {
+            if (version_compare($pearversion, $dep['max'], '>')) {
+                if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+                    return $this->raiseError('%s requires PEAR Installer' . $extra .
+                        ', installed version is ' . $pearversion);
+                } else {
+                    return $this->warning('warning: %s requires PEAR Installer' . $extra .
+                        ', installed version is ' . $pearversion);
+                }
+            }
+        }
+        if (isset($dep['exclude'])) {
+            if (!isset($dep['exclude'][0])) {
+                $dep['exclude'] = array($dep['exclude']);
+            }
+            foreach ($dep['exclude'] as $exclude) {
+                if (version_compare($exclude, $pearversion, '==')) {
+                    if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+                        return $this->raiseError('%s is not compatible with PEAR Installer ' .
+                            'version ' . $exclude);
+                    } else {
+                        return $this->warning('warning: %s is not compatible with PEAR ' .
+                            'Installer version ' . $exclude);
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+    function validateSubpackageDependency($dep, $required, $params)
+    {
+        return $this->validatePackageDependency($dep, $required, $params);
+    }
+
+    /**
+     * @param array dependency information (2.0 format)
+     * @param boolean whether this is a required dependency
+     * @param array a list of downloaded packages to be installed, if any
+     * @param boolean if true, then deps on pear.php.net that fail will also check
+     *                against pecl.php.net packages to accomodate extensions that have
+     *                moved to pecl.php.net from pear.php.net
+     */
+    function validatePackageDependency($dep, $required, $params, $depv1 = false)
+    {
+        if ($this->_state != PEAR_VALIDATE_INSTALLING &&
+              $this->_state != PEAR_VALIDATE_DOWNLOADING) {
+            return true;
+        }
+        if (isset($dep['providesextension'])) {
+            if ($this->extension_loaded($dep['providesextension'])) {
+                $save = $dep;
+                $subdep = $dep;
+                $subdep['name'] = $subdep['providesextension'];
+                PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+                $ret = $this->validateExtensionDependency($subdep, $required);
+                PEAR::popErrorHandling();
+                if (!PEAR::isError($ret)) {
+                    return true;
+                }
+            }
+        }
+        if ($this->_state == PEAR_VALIDATE_INSTALLING) {
+            return $this->_validatePackageInstall($dep, $required, $depv1);
+        }
+        if ($this->_state == PEAR_VALIDATE_DOWNLOADING) {
+            return $this->_validatePackageDownload($dep, $required, $params, $depv1);
+        }
+    }
+
+    function _validatePackageDownload($dep, $required, $params, $depv1 = false)
+    {
+        $dep['package'] = $dep['name'];
+        if (isset($dep['uri'])) {
+            $dep['channel'] = '__uri';
+        }
+        $depname = $this->_registry->parsedPackageNameToString($dep, true);
+        $found = false;
+        foreach ($params as $param) {
+            if ($param->isEqual(
+                  array('package' => $dep['name'],
+                        'channel' => $dep['channel']))) {
+                $found = true;
+                break;
+            }
+            if ($depv1 && $dep['channel'] == 'pear.php.net') {
+                if ($param->isEqual(
+                  array('package' => $dep['name'],
+                        'channel' => 'pecl.php.net'))) {
+                    $found = true;
+                    break;
+                }
+            }
+        }
+        if (!$found && isset($dep['providesextension'])) {
+            foreach ($params as $param) {
+                if ($param->isExtension($dep['providesextension'])) {
+                    $found = true;
+                    break;
+                }
+            }
+        }
+        if ($found) {
+            $version = $param->getVersion();
+            $installed = false;
+            $downloaded = true;
+        } else {
+            if ($this->_registry->packageExists($dep['name'], $dep['channel'])) {
+                $installed = true;
+                $downloaded = false;
+                $version = $this->_registry->packageinfo($dep['name'], 'version',
+                    $dep['channel']);
+            } else {
+                if ($dep['channel'] == 'pecl.php.net' && $this->_registry->packageExists($dep['name'],
+                      'pear.php.net')) {
+                    $installed = true;
+                    $downloaded = false;
+                    $version = $this->_registry->packageinfo($dep['name'], 'version',
+                        'pear.php.net');
+                } else {
+                    $version = 'not installed or downloaded';
+                    $installed = false;
+                    $downloaded = false;
+                }
+            }
+        }
+        $extra = $this->_getExtraString($dep);
+        if (isset($dep['exclude'])) {
+            if (!is_array($dep['exclude'])) {
+                $dep['exclude'] = array($dep['exclude']);
+            }
+        }
+        if (!isset($dep['min']) && !isset($dep['max']) &&
+              !isset($dep['recommended']) && !isset($dep['exclude'])) {
+            if ($installed || $downloaded) {
+                $installed = $installed ? 'installed' : 'downloaded';
+                if (isset($dep['conflicts'])) {
+                    if ($version) {
+                        $rest = ", $installed version is " . $version;
+                    } else {
+                        $rest = '';
+                    }
+                    if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+                        return $this->raiseError('%s conflicts with package "' . $depname . '"' .
+                            $extra . $rest);
+                    } else {
+                        return $this->warning('warning: %s conflicts with package "' . $depname . '"' .
+                            $extra . $rest);
+                    }
+                }
+                return true;
+            } else {
+                if (isset($dep['conflicts'])) {
+                    return true;
+                }
+                if ($required) {
+                    if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+                        return $this->raiseError('%s requires package "' . $depname . '"' .
+                            $extra);
+                    } else {
+                        return $this->warning('warning: %s requires package "' . $depname . '"' .
+                            $extra);
+                    }
+                } else {
+                    return $this->warning('%s can optionally use package "' . $depname . '"' .
+                        $extra);
+                }
+            }
+        }
+        if (!$installed && !$downloaded) {
+            if (isset($dep['conflicts'])) {
+                return true;
+            }
+            if ($required) {
+                if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+                    return $this->raiseError('%s requires package "' . $depname . '"' .
+                        $extra);
+                } else {
+                    return $this->warning('warning: %s requires package "' . $depname . '"' .
+                        $extra);
+                }
+            } else {
+                return $this->warning('%s can optionally use package "' . $depname . '"' .
+                    $extra);
+            }
+        }
+        $fail = false;
+        if (isset($dep['min'])) {
+            if (version_compare($version, $dep['min'], '<')) {
+                $fail = true;
+            }
+        }
+        if (isset($dep['max'])) {
+            if (version_compare($version, $dep['max'], '>')) {
+                $fail = true;
+            }
+        }
+        if ($fail && !isset($dep['conflicts'])) {
+            $installed = $installed ? 'installed' : 'downloaded';
+            $dep['package'] = $dep['name'];
+            $dep = $this->_registry->parsedPackageNameToString($dep, true);
+            if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+                return $this->raiseError('%s requires package "' . $depname . '"' .
+                    $extra . ", $installed version is " . $version);
+            } else {
+                return $this->warning('warning: %s requires package "' . $depname . '"' .
+                    $extra . ", $installed version is " . $version);
+            }
+        } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail &&
+              isset($dep['conflicts']) && !isset($dep['exclude'])) {
+            $installed = $installed ? 'installed' : 'downloaded';
+            if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+                return $this->raiseError('%s conflicts with package "' . $depname . '"' . $extra .
+                    ", $installed version is " . $version);
+            } else {
+                return $this->warning('warning: %s conflicts with package "' . $depname . '"' .
+                    $extra . ", $installed version is " . $version);
+            }
+        }
+        if (isset($dep['exclude'])) {
+            $installed = $installed ? 'installed' : 'downloaded';
+            foreach ($dep['exclude'] as $exclude) {
+                if (version_compare($version, $exclude, '==') && !isset($dep['conflicts'])) {
+                    if (!isset($this->_options['nodeps']) &&
+                          !isset($this->_options['force'])) {
+                        return $this->raiseError('%s is not compatible with ' .
+                            $installed . ' package "' .
+                            $depname . '" version ' .
+                            $exclude);
+                    } else {
+                        return $this->warning('warning: %s is not compatible with ' .
+                            $installed . ' package "' .
+                            $depname . '" version ' .
+                            $exclude);
+                    }
+                } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) {
+                    $installed = $installed ? 'installed' : 'downloaded';
+                    if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+                        return $this->raiseError('%s conflicts with package "' . $depname . '"' .
+                            $extra . ", $installed version is " . $version);
+                    } else {
+                        return $this->warning('warning: %s conflicts with package "' . $depname . '"' .
+                            $extra . ", $installed version is " . $version);
+                    }
+                }
+            }
+        }
+        if (isset($dep['recommended'])) {
+            $installed = $installed ? 'installed' : 'downloaded';
+            if (version_compare($version, $dep['recommended'], '==')) {
+                return true;
+            } else {
+                if (!$found && $installed) {
+                    $param = $this->_registry->getPackage($dep['name'], $dep['channel']);
+                }
+                if ($param) {
+                    $found = false;
+                    foreach ($params as $parent) {
+                        if ($parent->isEqual($this->_currentPackage)) {
+                            $found = true;
+                            break;
+                        }
+                    }
+                    if ($found) {
+                        if ($param->isCompatible($parent)) {
+                            return true;
+                        }
+                    } else { // this is for validPackage() calls
+                        $parent = $this->_registry->getPackage($this->_currentPackage['package'],
+                            $this->_currentPackage['channel']);
+                        if ($parent !== null) {
+                            if ($param->isCompatible($parent)) {
+                                return true;
+                            }
+                        }
+                    }
+                }
+                if (!isset($this->_options['nodeps']) && !isset($this->_options['force']) &&
+                      !isset($this->_options['loose'])) {
+                    return $this->raiseError('%s dependency package "' . $depname .
+                        '" ' . $installed . ' version ' . $version . 
+                        ' is not the recommended version ' . $dep['recommended'] .
+                        ', but may be compatible, use --force to install');
+                } else {
+                    return $this->warning('warning: %s dependency package "' . $depname .
+                        '" ' . $installed . ' version ' . $version .
+                        ' is not the recommended version ' . $dep['recommended']);
+                }
+            }
+        }
+        return true;
+    }
+
+    function _validatePackageInstall($dep, $required, $depv1 = false)
+    {
+        return $this->_validatePackageDownload($dep, $required, array(), $depv1);
+    }
+
+    /**
+     * Verify that uninstalling packages passed in to command line is OK.
+     *
+     * @param PEAR_Installer $dl
+     * @return PEAR_Error|true
+     */
+    function validatePackageUninstall(&$dl)
+    {
+        if (PEAR::isError($this->_dependencydb)) {
+            return $this->_dependencydb;
+        }
+        $params = array();
+        // construct an array of "downloaded" packages to fool the package dependency checker
+        // into using these to validate uninstalls of circular dependencies
+        $downloaded = &$dl->getUninstallPackages();
+        foreach ($downloaded as $i => $pf) {
+            if (!class_exists('PEAR_Downloader_Package')) {
+                require_once 'PEAR/Downloader/Package.php';
+            }
+            $dp = &new PEAR_Downloader_Package($dl);
+            $dp->setPackageFile($downloaded[$i]);
+            $params[$i] = &$dp;
+        }
+        $deps = $this->_dependencydb->getDependentPackageDependencies($this->_currentPackage);
+        $fail = false;
+        if ($deps) {
+            foreach ($deps as $channel => $info) {
+                foreach ($info as $package => $ds) {
+                    foreach ($ds as $d) {
+                        $d['dep']['package'] = $d['dep']['name'];
+                        $checker = &new PEAR_Dependency2($this->_config, $this->_options,
+                            array('channel' => $channel, 'package' => $package), $this->_state);
+                        $dep = $d['dep'];
+                        $required = $d['type'] == 'required';
+                        $ret = $checker->_validatePackageUninstall($dep, $required, $params, $dl);
+                        if (is_array($ret)) {
+                            $dl->log(0, $ret[0]);
+                        } elseif (PEAR::isError($ret)) {
+                            $dl->log(0, $ret->getMessage());
+                            $fail = true;
+                        }
+                    }
+                }
+            }
+        }
+        if ($fail) {
+            if (isset($this->_options['nodeps']) || isset($this->_options['force'])) {
+                return $this->warning(
+                    'warning: %s should not be uninstalled, other installed packages depend ' .
+                    'on this package');
+            } else {
+                return $this->raiseError(
+                    '%s cannot be uninstalled, other installed packages depend on this package');
+            }
+        }
+        return true;
+    }
+
+    function _validatePackageUninstall($dep, $required, $params, &$dl)
+    {
+        $dep['package'] = $dep['name'];
+        $depname = $this->_registry->parsedPackageNameToString($dep, true);
+        $found = false;
+        foreach ($params as $param) {
+            if ($param->isEqual($this->_currentPackage)) {
+                $found = true;
+                break;
+            }
+        }
+        $version = $this->_registry->packageinfo($dep['name'], 'version',
+            $dep['channel']);
+        if (!$version) {
+            return true;
+        }
+        $extra = $this->_getExtraString($dep);
+        if (isset($dep['exclude'])) {
+            if (!is_array($dep['exclude'])) {
+                $dep['exclude'] = array($dep['exclude']);
+            }
+        }
+        if (isset($dep['conflicts'])) {
+            return true; // uninstall OK - these packages conflict (probably installed with --force)
+        }
+        if (!isset($dep['min']) && !isset($dep['max'])) {
+            if ($required) {
+                if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+                    return $this->raiseError('%s' . $extra . ' is required by installed package "' .
+                        $depname . '"');
+                } else {
+                    return $this->warning('warning: %s' . $extra .
+                        ' is required by installed package "' . $depname . '"');
+                }
+            } else {
+                return $this->warning('%s' . $extra .
+                    ' can be optionally used by installed package "' . $depname . '"');
+            }
+        }
+        $fail = false;
+        if (isset($dep['min'])) {
+            if (version_compare($version, $dep['min'], '>=')) {
+                $fail = true;
+            }
+        }
+        if (isset($dep['max'])) {
+            if (version_compare($version, $dep['max'], '<=')) {
+                $fail = true;
+            }
+        }
+        if ($fail) {
+            if ($found) {
+                if (!isset($dl->___checked[$this->_currentPackage['channel']]
+                      [$this->_currentPackage['package']])) {
+                    $dl->___checked[$this->_currentPackage['channel']]
+                      [$this->_currentPackage['package']] = true;
+                    $deps = $this->_dependencydb->getDependentPackageDependencies(
+                        $this->_currentPackage);
+                    if ($deps) {
+                        foreach ($deps as $channel => $info) {
+                            foreach ($info as $package => $ds) {
+                                foreach ($ds as $d) {
+                                    $d['dep']['package'] = $d['dep']['name'];
+                                    $checker = &new PEAR_Dependency2($this->_config, $this->_options,
+                                        array('channel' => $channel, 'package' => $package),
+                                        $this->_state);
+                                    $dep = $d['dep'];
+                                    $required = $d['type'] == 'required';
+                                    $ret = $checker->_validatePackageUninstall($dep, $required, $params,
+                                        $dl);
+                                    if (PEAR::isError($ret)) {
+                                        $fail = true;
+                                        break 3;
+                                    }
+                                }
+                            }
+                            $fail = false;
+                        }
+                    }
+                } else {
+                    return true;
+                }
+            }
+            if (!$fail) {
+                return true;
+            }
+            if ($required) {
+                if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+                    return $this->raiseError($depname . $extra . ' is required by installed package' .
+                        ' "%s"');
+                } else {
+                    return $this->warning('warning: ' . $depname . $extra .
+                        ' is required by installed package "%s"');
+                }
+            } else {
+                return $this->warning($depname . $extra . ' can be optionally used by installed package' .
+                        ' "%s"');
+            }
+        }
+        return true;
+    }
+
+    /**
+     * validate a downloaded package against installed packages
+     * 
+     * As of PEAR 1.4.3, this will only validate
+     *
+     * @param array|PEAR_Downloader_Package|PEAR_PackageFile_v1|PEAR_PackageFile_v2
+     *              $pkg package identifier (either
+     *                   array('package' => blah, 'channel' => blah) or an array with
+     *                   index 'info' referencing an object)
+     * @param PEAR_Downloader $dl
+     * @param array $params full list of packages to install
+     * @return true|PEAR_Error
+     */
+    function validatePackage($pkg, &$dl, $params = array())
+    {
+        if (is_array($pkg) && isset($pkg['info'])) {
+            $deps = $this->_dependencydb->getDependentPackageDependencies($pkg['info']);
+        } else {
+            $deps = $this->_dependencydb->getDependentPackageDependencies($pkg);
+        }
+        $fail = false;
+        if ($deps) {
+            if (!class_exists('PEAR_Downloader_Package')) {
+                require_once 'PEAR/Downloader/Package.php';
+            }
+            $dp = &new PEAR_Downloader_Package($dl);
+            if (is_object($pkg)) {
+                $dp->setPackageFile($pkg);
+            } else {
+                $dp->setDownloadURL($pkg);
+            }
+            PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+            foreach ($deps as $channel => $info) {
+                foreach ($info as $package => $ds) {
+                    foreach ($params as $packd) {
+                        if (strtolower($packd->getPackage()) == strtolower($package) &&
+                              $packd->getChannel() == $channel) {
+                            $dl->log(3, 'skipping installed package check of "' .
+                                        $this->_registry->parsedPackageNameToString(
+                                            array('channel' => $channel, 'package' => $package),
+                                            true) .
+                                        '", version "' . $packd->getVersion() . '" will be ' .
+                                        'downloaded and installed');
+                            continue 2; // jump to next package
+                        }
+                    }
+                    foreach ($ds as $d) {
+                        $checker = &new PEAR_Dependency2($this->_config, $this->_options,
+                            array('channel' => $channel, 'package' => $package), $this->_state);
+                        $dep = $d['dep'];
+                        $required = $d['type'] == 'required';
+                        $ret = $checker->_validatePackageDownload($dep, $required, array(&$dp));
+                        if (is_array($ret)) {
+                            $dl->log(0, $ret[0]);
+                        } elseif (PEAR::isError($ret)) {
+                            $dl->log(0, $ret->getMessage());
+                            $fail = true;
+                        }
+                    }
+                }
+            }
+            PEAR::popErrorHandling();
+        }
+        if ($fail) {
+            return $this->raiseError(
+                '%s cannot be installed, conflicts with installed packages');
+        }
+        return true;
+    }
+
+    /**
+     * validate a package.xml 1.0 dependency
+     */
+    function validateDependency1($dep, $params = array())
+    {
+        if (!isset($dep['optional'])) {
+            $dep['optional'] = 'no';
+        }
+        list($newdep, $type) = $this->normalizeDep($dep);
+        if (!$newdep) {
+            return $this->raiseError("Invalid Dependency");
+        }
+        if (method_exists($this, "validate{$type}Dependency")) {
+            return $this->{"validate{$type}Dependency"}($newdep, $dep['optional'] == 'no',
+                $params, true);
+        }
+    }
+
+    /**
+     * Convert a 1.0 dep into a 2.0 dep
+     */
+    function normalizeDep($dep)
+    {
+        $types = array(
+            'pkg' => 'Package',
+            'ext' => 'Extension',
+            'os' => 'Os',
+            'php' => 'Php'
+        );
+        if (isset($types[$dep['type']])) {
+            $type = $types[$dep['type']];
+        } else {
+            return array(false, false);
+        }
+        $newdep = array();
+        switch ($type) {
+            case 'Package' :
+                $newdep['channel'] = 'pear.php.net';
+            case 'Extension' :
+            case 'Os' :
+                $newdep['name'] = $dep['name'];
+            break;
+        }
+        $dep['rel'] = PEAR_Dependency2::signOperator($dep['rel']);
+        switch ($dep['rel']) {
+            case 'has' :
+                return array($newdep, $type);
+            break;
+            case 'not' :
+                $newdep['conflicts'] = true;
+            break;
+            case '>=' :
+            case '>' :
+                $newdep['min'] = $dep['version'];
+                if ($dep['rel'] == '>') {
+                    $newdep['exclude'] = $dep['version'];
+                }
+            break;
+            case '<=' :
+            case '<' :
+                $newdep['max'] = $dep['version'];
+                if ($dep['rel'] == '<') {
+                    $newdep['exclude'] = $dep['version'];
+                }
+            break;
+            case 'ne' :
+            case '!=' :
+                $newdep['min'] = '0';
+                $newdep['max'] = '100000';
+                $newdep['exclude'] = $dep['version'];
+            break;
+            case '==' :
+                $newdep['min'] = $dep['version'];
+                $newdep['max'] = $dep['version'];
+            break;
+        }
+        if ($type == 'Php') {
+            if (!isset($newdep['min'])) {
+                $newdep['min'] = '4.2.0';
+            }
+            if (!isset($newdep['max'])) {
+                $newdep['max'] = '6.0.0';
+            }
+        }
+        return array($newdep, $type);
+    }
+
+    /**
+     * Converts text comparing operators to them sign equivalents
+     *
+     * Example: 'ge' to '>='
+     *
+     * @access public
+     * @param  string Operator
+     * @return string Sign equivalent
+     */
+    function signOperator($operator)
+    {
+        switch($operator) {
+            case 'lt': return '<';
+            case 'le': return '<=';
+            case 'gt': return '>';
+            case 'ge': return '>=';
+            case 'eq': return '==';
+            case 'ne': return '!=';
+            default:
+                return $operator;
+        }
+    }
+
+    function raiseError($msg)
+    {
+        if (isset($this->_options['ignore-errors'])) {
+            return $this->warning($msg);
+        }
+        return PEAR::raiseError(sprintf($msg, $this->_registry->parsedPackageNameToString(
+            $this->_currentPackage, true)));
+    }
+
+    function warning($msg)
+    {
+        return array(sprintf($msg, $this->_registry->parsedPackageNameToString(
+            $this->_currentPackage, true)));
+    }
+}
+?>
\ No newline at end of file
diff --git a/pear/PEAR/DependencyDB.php b/pear/PEAR/DependencyDB.php
new file mode 100644 (file)
index 0000000..77be5b8
--- /dev/null
@@ -0,0 +1,655 @@
+<?php
+/**
+ * PEAR_DependencyDB, advanced installed packages dependency database
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Tomas V. V. Cox <cox@idecnet.com>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a1
+ */
+
+/**
+ * Needed for error handling
+ */
+require_once 'PEAR.php';
+require_once 'PEAR/Config.php';
+
+/**
+ * Track dependency relationships between installed packages
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @author     Tomas V.V.Cox <cox@idec.net.com>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
+ */
+class PEAR_DependencyDB
+{
+    // {{{ properties
+
+    /**
+     * This is initialized by {@link setConfig()}
+     * @var PEAR_Config
+     * @access private
+     */
+    var $_config;
+    /**
+     * This is initialized by {@link setConfig()}
+     * @var PEAR_Registry
+     * @access private
+     */
+    var $_registry;
+    /**
+     * Filename of the dependency DB (usually .depdb)
+     * @var string
+     * @access private
+     */
+    var $_depdb = false;
+    /**
+     * File name of the lockfile (usually .depdblock)
+     * @var string
+     * @access private
+     */
+    var $_lockfile = false;
+    /**
+     * Open file resource for locking the lockfile
+     * @var resource|false
+     * @access private
+     */
+    var $_lockFp = false;
+    /**
+     * API version of this class, used to validate a file on-disk
+     * @var string
+     * @access private
+     */
+    var $_version = '1.0';
+    /**
+     * Cached dependency database file
+     * @var array|null
+     * @access private
+     */
+    var $_cache;
+
+    // }}}
+    // {{{ & singleton()
+
+    /**
+     * Get a raw dependency database.  Calls setConfig() and assertDepsDB()
+     * @param PEAR_Config
+     * @param string|false full path to the dependency database, or false to use default
+     * @return PEAR_DependencyDB|PEAR_Error
+     * @static
+     */
+    function &singleton(&$config, $depdb = false)
+    {
+        if (!isset($GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE']
+              [$config->get('php_dir', null, 'pear.php.net')])) {
+            $a = new PEAR_DependencyDB;
+            $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE']
+              [$config->get('php_dir', null, 'pear.php.net')] = &$a;
+            $a->setConfig($config, $depdb);
+            if (PEAR::isError($e = $a->assertDepsDB())) {
+                return $e;
+            }
+        }
+        return $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE']
+              [$config->get('php_dir', null, 'pear.php.net')];
+    }
+
+    /**
+     * Set up the registry/location of dependency DB
+     * @param PEAR_Config|false
+     * @param string|false full path to the dependency database, or false to use default
+     */
+    function setConfig(&$config, $depdb = false)
+    {
+        if (!$config) {
+            $this->_config = &PEAR_Config::singleton();
+        } else {
+            $this->_config = &$config;
+        }
+        $this->_registry = &$this->_config->getRegistry();
+        if (!$depdb) {
+            $this->_depdb = $this->_config->get('php_dir', null, 'pear.php.net') .
+                DIRECTORY_SEPARATOR . '.depdb';
+        } else {
+            $this->_depdb = $depdb;
+        }
+        $this->_lockfile = dirname($this->_depdb) . DIRECTORY_SEPARATOR . '.depdblock';
+    }
+    // }}}
+
+    function hasWriteAccess()
+    {
+        if (!@file_exists($this->_depdb)) {
+            $dir = $this->_depdb;
+            while ($dir && $dir != '.') {
+                $dir = dirname($dir); // cd ..
+                if ($dir != '.' && @file_exists($dir)) {
+                    if (@is_writeable($dir)) {
+                        return true;
+                    } else {
+                        return false;
+                    }
+                }
+            }
+            return false;
+        }
+        return @is_writeable($this->_depdb);
+    }
+
+    // {{{ assertDepsDB()
+
+    /**
+     * Create the dependency database, if it doesn't exist.  Error if the database is
+     * newer than the code reading it.
+     * @return void|PEAR_Error
+     */
+    function assertDepsDB()
+    {
+        if (!is_file($this->_depdb)) {
+            $this->rebuildDB();
+        } else {
+            $depdb = $this->_getDepDB();
+            // Datatype format has been changed, rebuild the Deps DB
+            if ($depdb['_version'] < $this->_version) {
+                $this->rebuildDB();
+            }
+            if ($depdb['_version']{0} > $this->_version{0}) {
+                return PEAR::raiseError('Dependency database is version ' .
+                    $depdb['_version'] . ', and we are version ' .
+                    $this->_version . ', cannot continue');
+            }
+        }
+    }
+
+    /**
+     * Get a list of installed packages that depend on this package
+     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array
+     * @return array|false
+     */
+    function getDependentPackages(&$pkg)
+    {
+        $data = $this->_getDepDB();
+        if (is_object($pkg)) {
+            $channel = strtolower($pkg->getChannel());
+            $package = strtolower($pkg->getPackage());
+        } else {
+            $channel = strtolower($pkg['channel']);
+            $package = strtolower($pkg['package']);
+        }
+        if (isset($data['packages'][$channel][$package])) {
+            return $data['packages'][$channel][$package];
+        }
+        return false;
+    }
+
+    /**
+     * Get a list of the actual dependencies of installed packages that depend on
+     * a package.
+     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array
+     * @return array|false
+     */
+    function getDependentPackageDependencies(&$pkg)
+    {
+        $data = $this->_getDepDB();
+        if (is_object($pkg)) {
+            $channel = strtolower($pkg->getChannel());
+            $package = strtolower($pkg->getPackage());
+        } else {
+            $channel = strtolower($pkg['channel']);
+            $package = strtolower($pkg['package']);
+        }
+        $depend = $this->getDependentPackages($pkg);
+        if (!$depend) {
+            return false;
+        }
+        $dependencies = array();
+        foreach ($depend as $info) {
+            $temp = $this->getDependencies($info);
+            foreach ($temp as $dep) {
+                if (strtolower($dep['dep']['channel']) == strtolower($channel) &&
+                      strtolower($dep['dep']['name']) == strtolower($package)) {
+                    $dependencies[$info['channel']][$info['package']][] = $dep;
+                }
+            }
+        }
+        return $dependencies;
+    }
+
+    /**
+     * Get a list of dependencies of this installed package
+     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array
+     * @return array|false
+     */
+    function getDependencies(&$pkg)
+    {
+        if (is_object($pkg)) {
+            $channel = strtolower($pkg->getChannel());
+            $package = strtolower($pkg->getPackage());
+        } else {
+            $channel = strtolower($pkg['channel']);
+            $package = strtolower($pkg['package']);
+        }
+        $data = $this->_getDepDB();
+        if (isset($data['dependencies'][$channel][$package])) {
+            return $data['dependencies'][$channel][$package];
+        }
+        return false;
+    }
+
+    /**
+     * Determine whether $parent depends on $child, near or deep
+     * @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2
+     * @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2
+     */
+    function dependsOn($parent, $child)
+    {
+        $c = array();
+        $this->_getDepDB();
+        return $this->_dependsOn($parent, $child, $c);
+    }
+    
+    function _dependsOn($parent, $child, &$checked)
+    {
+        if (is_object($parent)) {
+            $channel = strtolower($parent->getChannel());
+            $package = strtolower($parent->getPackage());
+        } else {
+            $channel = strtolower($parent['channel']);
+            $package = strtolower($parent['package']);
+        }
+        if (is_object($child)) {
+            $depchannel = strtolower($child->getChannel());
+            $deppackage = strtolower($child->getPackage());
+        } else {
+            $depchannel = strtolower($child['channel']);
+            $deppackage = strtolower($child['package']);
+        }
+        if (isset($checked[$channel][$package][$depchannel][$deppackage])) {
+            return false; // avoid endless recursion
+        }
+        $checked[$channel][$package][$depchannel][$deppackage] = true;
+        if (!isset($this->_cache['dependencies'][$channel][$package])) {
+            return false;
+        }
+        foreach ($this->_cache['dependencies'][$channel][$package] as $info) {
+            if (strtolower($info['dep']['channel']) == strtolower($depchannel) &&
+                  strtolower($info['dep']['name']) == strtolower($deppackage)) {
+                return true;
+            }
+        }
+        foreach ($this->_cache['dependencies'][$channel][$package] as $info) {
+            if ($this->_dependsOn(array(
+                    'channel' => $info['dep']['channel'],
+                    'package' => $info['dep']['name']), $child, $checked)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Register dependencies of a package that is being installed or upgraded
+     * @param PEAR_PackageFile_v2|PEAR_PackageFile_v2
+     */
+    function installPackage(&$package)
+    {
+        $data = $this->_getDepDB();
+        unset($this->_cache);
+        $this->_setPackageDeps($data, $package);
+        $this->_writeDepDB($data);
+    }
+
+    /**
+     * Remove dependencies of a package that is being uninstalled, or upgraded.
+     *
+     * Upgraded packages first uninstall, then install
+     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array If an array, then it must have
+     *        indices 'channel' and 'package'
+     */
+    function uninstallPackage(&$pkg)
+    {
+        $data = $this->_getDepDB();
+        unset($this->_cache);
+        if (is_object($pkg)) {
+            $channel = strtolower($pkg->getChannel());
+            $package = strtolower($pkg->getPackage());
+        } else {
+            $channel = strtolower($pkg['channel']);
+            $package = strtolower($pkg['package']);
+        }
+        if (!isset($data['dependencies'][$channel][$package])) {
+            return true;
+        }
+        foreach ($data['dependencies'][$channel][$package] as $dep) {
+            $found = false;
+            if (isset($dep['dep']['uri'])) {
+                $depchannel = '__uri';
+            } else {
+                $depchannel = strtolower($dep['dep']['channel']);
+            }
+            if (isset($data['packages'][$depchannel][strtolower($dep['dep']['name'])])) {
+                foreach ($data['packages'][$depchannel][strtolower($dep['dep']['name'])] as
+                      $i => $info) {
+                    if ($info['channel'] == $channel &&
+                          $info['package'] == $package) {
+                        $found = true;
+                        break;
+                    }
+                }
+            }
+            if ($found) {
+                unset($data['packages'][$depchannel][strtolower($dep['dep']['name'])][$i]);
+                if (!count($data['packages'][$depchannel][strtolower($dep['dep']['name'])])) {
+                    unset($data['packages'][$depchannel][strtolower($dep['dep']['name'])]);
+                    if (!count($data['packages'][$depchannel])) {
+                        unset($data['packages'][$depchannel]);
+                    }
+                } else {
+                    $data['packages'][$depchannel][strtolower($dep['dep']['name'])] =
+                        array_values(
+                            $data['packages'][$depchannel][strtolower($dep['dep']['name'])]);
+                }
+            }
+        }
+        unset($data['dependencies'][$channel][$package]);
+        if (!count($data['dependencies'][$channel])) {
+            unset($data['dependencies'][$channel]);
+        }
+        if (!count($data['dependencies'])) {
+            unset($data['dependencies']);
+        }
+        if (!count($data['packages'])) {
+            unset($data['packages']);
+        }
+        $this->_writeDepDB($data);
+    }
+
+    /**
+     * Rebuild the dependency DB by reading registry entries.
+     * @return true|PEAR_Error
+     */
+    function rebuildDB()
+    {
+        $depdb = array('_version' => $this->_version);
+        if (!$this->hasWriteAccess()) {
+            // allow startup for read-only with older Registry
+            return $depdb;
+        }
+        $packages = $this->_registry->listAllPackages();
+        foreach ($packages as $channel => $ps) {
+            foreach ($ps as $package) {
+                $package = $this->_registry->getPackage($package, $channel);
+                $this->_setPackageDeps($depdb, $package);
+            }
+        }
+        $error = $this->_writeDepDB($depdb);
+        if (PEAR::isError($error)) {
+            return $error;
+        }
+        $this->_cache = $depdb;
+        return true;
+    }
+
+    /**
+     * Register usage of the dependency DB to prevent race conditions
+     * @param int one of the LOCK_* constants
+     * @return true|PEAR_Error
+     * @access private
+     */
+    function _lock($mode = LOCK_EX)
+    {
+        if (!eregi('Windows 9', php_uname())) {
+            if ($mode != LOCK_UN && is_resource($this->_lockFp)) {
+                // XXX does not check type of lock (LOCK_SH/LOCK_EX)
+                return true;
+            }
+            $open_mode = 'w';
+            // XXX People reported problems with LOCK_SH and 'w'
+            if ($mode === LOCK_SH) {
+                if (@!is_file($this->_lockfile)) {
+                    touch($this->_lockfile);
+                }
+                $open_mode = 'r';
+            }
+
+            if (!is_resource($this->_lockFp)) {
+                $this->_lockFp = @fopen($this->_lockfile, $open_mode);
+            }
+            if (!is_resource($this->_lockFp)) {
+                return PEAR::raiseError("could not create Dependency lock file" .
+                                         (isset($php_errormsg) ? ": " . $php_errormsg : ""));
+            }
+            if (!(int)flock($this->_lockFp, $mode)) {
+                switch ($mode) {
+                    case LOCK_SH: $str = 'shared';    break;
+                    case LOCK_EX: $str = 'exclusive'; break;
+                    case LOCK_UN: $str = 'unlock';    break;
+                    default:      $str = 'unknown';   break;
+                }
+                return PEAR::raiseError("could not acquire $str lock ($this->_lockfile)");
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Release usage of dependency DB
+     * @return true|PEAR_Error
+     * @access private
+     */
+    function _unlock()
+    {
+        $ret = $this->_lock(LOCK_UN);
+        if (is_resource($this->_lockFp)) {
+            fclose($this->_lockFp);
+        }
+        $this->_lockFp = null;
+        return $ret;
+    }
+
+    /**
+     * Load the dependency database from disk, or return the cache
+     * @return array|PEAR_Error
+     */
+    function _getDepDB()
+    {
+        if (!$this->hasWriteAccess()) {
+            return array('_version' => $this->_version);
+        }
+        if (isset($this->_cache)) {
+            return $this->_cache;
+        }
+        if (!$fp = fopen($this->_depdb, 'r')) {
+            $err = PEAR::raiseError("Could not open dependencies file `".$this->_depdb."'");
+            return $err;
+        }
+        $rt = get_magic_quotes_runtime();
+        set_magic_quotes_runtime(0);
+        clearstatcache();
+        if (function_exists('file_get_contents')) {
+            fclose($fp);
+            $data = unserialize(file_get_contents($this->_depdb));
+        } else {
+            $data = unserialize(fread($fp, filesize($this->_depdb)));
+            fclose($fp);
+        }
+        set_magic_quotes_runtime($rt);
+        $this->_cache = $data;
+        return $data;
+    }
+
+    /**
+     * Write out the dependency database to disk
+     * @param array the database
+     * @return true|PEAR_Error
+     * @access private
+     */
+    function _writeDepDB(&$deps)
+    {
+        if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
+            return $e;
+        }
+        if (!$fp = fopen($this->_depdb, 'wb')) {
+            $this->_unlock();
+            return PEAR::raiseError("Could not open dependencies file `".$this->_depdb."' for writing");
+        }
+        $rt = get_magic_quotes_runtime();
+        set_magic_quotes_runtime(0);
+        fwrite($fp, serialize($deps));
+        set_magic_quotes_runtime($rt);
+        fclose($fp);
+        $this->_unlock();
+        $this->_cache = $deps;
+        return true;
+    }
+
+    /**
+     * Register all dependencies from a package in the dependencies database, in essence
+     * "installing" the package's dependency information
+     * @param array the database
+     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+     * @access private
+     */
+    function _setPackageDeps(&$data, &$pkg)
+    {
+        $pkg->setConfig($this->_config);
+        if ($pkg->getPackagexmlVersion() == '1.0') {
+            $gen = &$pkg->getDefaultGenerator();
+            $deps = $gen->dependenciesToV2();
+        } else {
+            $deps = $pkg->getDeps(true);
+        }
+        if (!$deps) {
+            return;
+        }
+        $data['dependencies'][strtolower($pkg->getChannel())][strtolower($pkg->getPackage())]
+            = array();
+        if (isset($deps['required']['package'])) {
+            if (!isset($deps['required']['package'][0])) {
+                $deps['required']['package'] = array($deps['required']['package']);
+            }
+            foreach ($deps['required']['package'] as $dep) {
+                $this->_registerDep($data, $pkg, $dep, 'required');
+            }
+        }
+        if (isset($deps['optional']['package'])) {
+            if (!isset($deps['optional']['package'][0])) {
+                $deps['optional']['package'] = array($deps['optional']['package']);
+            }
+            foreach ($deps['optional']['package'] as $dep) {
+                $this->_registerDep($data, $pkg, $dep, 'optional');
+            }
+        }
+        if (isset($deps['required']['subpackage'])) {
+            if (!isset($deps['required']['subpackage'][0])) {
+                $deps['required']['subpackage'] = array($deps['required']['subpackage']);
+            }
+            foreach ($deps['required']['subpackage'] as $dep) {
+                $this->_registerDep($data, $pkg, $dep, 'required');
+            }
+        }
+        if (isset($deps['optional']['subpackage'])) {
+            if (!isset($deps['optional']['subpackage'][0])) {
+                $deps['optional']['subpackage'] = array($deps['optional']['subpackage']);
+            }
+            foreach ($deps['optional']['subpackage'] as $dep) {
+                $this->_registerDep($data, $pkg, $dep, 'optional');
+            }
+        }
+        if (isset($deps['group'])) {
+            if (!isset($deps['group'][0])) {
+                $deps['group'] = array($deps['group']);
+            }
+            foreach ($deps['group'] as $group) {
+                if (isset($group['package'])) {
+                    if (!isset($group['package'][0])) {
+                        $group['package'] = array($group['package']);
+                    }
+                    foreach ($group['package'] as $dep) {
+                        $this->_registerDep($data, $pkg, $dep, 'optional',
+                            $group['attribs']['name']);
+                    }
+                }
+                if (isset($group['subpackage'])) {
+                    if (!isset($group['subpackage'][0])) {
+                        $group['subpackage'] = array($group['subpackage']);
+                    }
+                    foreach ($group['subpackage'] as $dep) {
+                        $this->_registerDep($data, $pkg, $dep, 'optional',
+                            $group['attribs']['name']);
+                    }
+                }
+            }
+        }
+        if ($data['dependencies'][strtolower($pkg->getChannel())]
+              [strtolower($pkg->getPackage())] == array()) {
+            unset($data['dependencies'][strtolower($pkg->getChannel())]
+              [strtolower($pkg->getPackage())]);
+            if (!count($data['dependencies'][strtolower($pkg->getChannel())])) {
+                unset($data['dependencies'][strtolower($pkg->getChannel())]);
+            }
+        }
+    }
+
+    /**
+     * @param array the database
+     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+     * @param array the specific dependency
+     * @param required|optional whether this is a required or an optional dep
+     * @param string|false dependency group this dependency is from, or false for ordinary dep
+     */
+    function _registerDep(&$data, &$pkg, $dep, $type, $group = false)
+    {
+        $info = array(
+            'dep' => $dep,
+            'type' => $type,
+            'group' => $group);
+
+        if (isset($dep['channel'])) {
+            $depchannel = $dep['channel'];
+        } else {
+            $depchannel = '__uri';
+        }
+        $data['dependencies'][strtolower($pkg->getChannel())][strtolower($pkg->getPackage())][]
+            = $info;
+        if (isset($data['packages'][strtolower($depchannel)][strtolower($dep['name'])])) {
+            $found = false;
+            foreach ($data['packages'][strtolower($depchannel)][strtolower($dep['name'])]
+                  as $i => $p) {
+                if ($p['channel'] == strtolower($pkg->getChannel()) &&
+                      $p['package'] == strtolower($pkg->getPackage())) {
+                    $found = true;
+                    break;
+                }
+            }
+            if (!$found) {
+                $data['packages'][strtolower($depchannel)][strtolower($dep['name'])][]
+                    = array('channel' => strtolower($pkg->getChannel()),
+                            'package' => strtolower($pkg->getPackage()));
+            }
+        } else {
+            $data['packages'][strtolower($depchannel)][strtolower($dep['name'])][]
+                = array('channel' => strtolower($pkg->getChannel()),
+                        'package' => strtolower($pkg->getPackage()));
+        }
+    }
+}
+?>
\ No newline at end of file
index 793cc0410e7f155829b2227bc2d0f9a2d900e3cb..08a35c0016575804a685ba36d2a6f091b5efe9dd 100644 (file)
@@ -1,31 +1,32 @@
 <?php
-//
-// +----------------------------------------------------------------------+
-// | PHP Version 5                                                        |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2004 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$
+/**
+ * PEAR_Downloader, the PEAR Installer's download utility class
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Tomas V. V. Cox <cox@idecnet.com>
+ * @author     Martin Jansen <mj@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.3.0
+ */
 
+/**
+ * Needed for constants, extending
+ */
 require_once 'PEAR/Common.php';
-require_once 'PEAR/Registry.php';
-require_once 'PEAR/Dependency.php';
-require_once 'PEAR/Remote.php';
-require_once 'System.php';
-
 
 define('PEAR_INSTALLER_OK',       1);
 define('PEAR_INSTALLER_FAILED',   0);
@@ -33,20 +34,23 @@ define('PEAR_INSTALLER_SKIPPED', -1);
 define('PEAR_INSTALLER_ERROR_NO_PREF_STATE', 2);
 
 /**
- * Administration class used to download PEAR packages and maintain the
- * installed package database.
+ * Administration class used to download anything from the internet (PEAR Packages,
+ * static URLs, xml files)
  *
- * @since PEAR 1.4
- * @author Greg Beaver <cellog@php.net>
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Tomas V. V. Cox <cox@idecnet.com>
+ * @author     Martin Jansen <mj@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.3.0
  */
 class PEAR_Downloader extends PEAR_Common
 {
-    /**
-     * @var PEAR_Config
-     * @access private
-     */
-    var $_config;
-
     /**
      * @var PEAR_Registry
      * @access private
@@ -74,6 +78,7 @@ class PEAR_Downloader extends PEAR_Common
      *  - alldeps       : install all dependencies, including optional
      *  - installroot   : base relative path to install files in
      *  - force         : force a download even if warnings would prevent it
+     *  - nocompress    : download uncompressed tarballs
      * @see PEAR_Command_Install
      * @access private
      * @var array
@@ -127,480 +132,848 @@ class PEAR_Downloader extends PEAR_Common
      * @access private
      */
     var $_errorStack = array();
+    
+    /**
+     * @var boolean
+     * @access private
+     */
+    var $_internalDownload = false;
+
+    /**
+     * Temporary variable used in sorting packages by dependency in {@link sortPkgDeps()}
+     * @var array
+     * @access private
+     */
+    var $_packageSortTree;
 
+    /**
+     * Temporary directory, or configuration value where downloads will occur
+     * @var string
+     */
+    var $_downloadDir;
     // {{{ PEAR_Downloader()
 
+    /**
+     * @param PEAR_Frontend_*
+     * @param array
+     * @param PEAR_Config
+     */
     function PEAR_Downloader(&$ui, $options, &$config)
     {
+        parent::PEAR_Common();
         $this->_options = $options;
-        $this->_config = &$config;
-        $this->_preferredState = $this->_config->get('preferred_state');
+        $this->config = &$config;
+        $this->_preferredState = $this->config->get('preferred_state');
         $this->ui = &$ui;
         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->config->setInstallRoot($this->_options['installroot']);
         }
-        $this->_registry = &new PEAR_Registry($php_dir);
-        $this->_remote = &new PEAR_Remote($config);
+        $this->_registry = &$config->getRegistry();
+        $this->_remote = &$config->getRemote();
 
         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);
+            $this->_installed = $this->_registry->listAllPackages();
+            foreach ($this->_installed as $key => $unused) {
+                if (!count($unused)) {
+                    continue;
+                }
+                @array_walk($this->_installed[$key], 'strtolower');
+            }
         }
-        parent::PEAR_Common();
     }
 
-    // }}}
-    // {{{ configSet()
-    function configSet($key, $value, $layer = 'user')
+    /**
+     * Attempt to discover a channel's remote capabilities from
+     * its server name
+     * @param string
+     * @return boolean
+     */
+    function discover($channel)
     {
-        $this->_config->set($key, $value, $layer);
-        $this->_preferredState = $this->_config->get('preferred_state');
-        if (!$this->_preferredState) {
-            // don't inadvertantly use a non-set preferred_state
-            $this->_preferredState = null;
+        $this->log(1, 'Attempting to discover channel "' . $channel . '"...');
+        PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+        $callback = $this->ui ? array(&$this, '_downloadCallback') : null;
+        if (!class_exists('System')) {
+            require_once 'System.php';
         }
+        $a = $this->downloadHttp('http://' . $channel . '/channel.xml', $this->ui,
+            System::mktemp(array('-d')), $callback, false);
+        PEAR::popErrorHandling();
+        if (PEAR::isError($a)) {
+            return false;
+        }
+        list($a, $lastmodified) = $a;
+        if (!class_exists('PEAR/ChannelFile.php')) {
+            require_once 'PEAR/ChannelFile.php';
+        }
+        $b = new PEAR_ChannelFile;
+        if ($b->fromXmlFile($a)) {
+            @unlink($a);
+            if ($this->config->get('auto_discover')) {
+                $this->_registry->addChannel($b, $lastmodified);
+                $alias = $b->getName();
+                if ($b->getName() == $this->_registry->channelName($b->getAlias())) {
+                    $alias = $b->getAlias();
+                }
+                $this->log(1, 'Auto-discovered channel "' . $channel .
+                    '", alias "' . $alias . '", adding to registry');
+            }
+            return true;
+        }
+        @unlink($a);
+        return false;
     }
 
-    // }}}
-    // {{{ setOptions()
-    function setOptions($options)
+    /**
+     * For simpler unit-testing
+     * @param PEAR_Downloader
+     * @return PEAR_Downloader_Package
+     */
+    function &newDownloaderPackage(&$t)
     {
-        $this->_options = $options;
+        if (!class_exists('PEAR_Downloader_Package')) {
+            require_once 'PEAR/Downloader/Package.php';
+        }
+        $a = &new PEAR_Downloader_Package($t);
+        return $a;
     }
 
-    // }}}
-    // {{{ _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
+     * For simpler unit-testing
+     * @param PEAR_Config
+     * @param array
+     * @param array
+     * @param int
      */
-    function _downloadFile($pkgfile, $version, $origpkgfile, $state = null)
+    function &getDependency2Object(&$c, $i, $p, $s)
     {
-        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;
-                    }
+        if (!class_exists('PEAR/Dependency2.php')) {
+            require_once 'PEAR/Dependency2.php';
+        }
+        $z = &new PEAR_Dependency2($c, $i, $p, $s);
+        return $z;
+    }
+
+    function &download($params)
+    {
+        if (!count($params)) {
+            $a = array();
+            return $a;
+        }
+        if (!isset($this->_registry)) {
+            $this->_registry = &$this->config->getRegistry();
+        }
+        if (!isset($this->_remote)) {
+            $this->_remote = &$this->config->getRemote();
+        }
+        $channelschecked = array();
+        // convert all parameters into PEAR_Downloader_Package objects
+        foreach ($params as $i => $param) {
+            $params[$i] = &$this->newDownloaderPackage($this);
+            PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+            $err = $params[$i]->initialize($param);
+            PEAR::staticPopErrorHandling();
+            if (PEAR::isError($err)) {
+                if (!isset($this->_options['soft'])) {
+                    $this->log(0, $err->getMessage());
                 }
-                $pkgfile = $this->getPackageDownloadUrl($pkgfile, $version);
-                $need_download = true;
+                $params[$i] = false;
+                if (is_object($param)) {
+                    $param = $param->getChannel() . '/' . $param->getPackage();
+                }
+                $this->pushError('Package "' . $param . '" is not valid',
+                    PEAR_INSTALLER_SKIPPED);
             } 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);
+                if ($params[$i] && !isset($channelschecked[$params[$i]->getChannel()]) &&
+                      !isset($this->_options['offline'])) {
+                    $channelschecked[$params[$i]->getChannel()] = true;
+                    PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+                    if (!class_exists('System')) {
+                        require_once 'System.php';
+                    }
+                    $curchannel = &$this->_registry->getChannel($params[$i]->getChannel());
+                    $a = $this->downloadHttp('http://' . $params[$i]->getChannel() .
+                        '/channel.xml', $this->ui,
+                        System::mktemp(array('-d')), null, $curchannel->lastModified());
+                    PEAR::staticPopErrorHandling();
+                    if (PEAR::isError($a) || !$a) {
+                        continue;
+                    }
+                    $this->log(0, 'WARNING: channel "' . $params[$i]->getChannel() . '" has ' .
+                        'updated its protocols, use "channel-update ' . $params[$i]->getChannel() .
+                        '" to update');
+                }
+                if ($params[$i] && !isset($this->_options['downloadonly'])) {
+                    $checkdir = $this->config->get('php_dir', null, $params[$i]->getChannel());
+                    while ($checkdir && $checkdir != '/' && !file_exists($checkdir)) {
+                        $checkdir = dirname($checkdir);
+                    }
+                    if ($checkdir == '.') {
+                        $checkdir = '/';
+                    }
+                    if (!@is_writeable($checkdir)) {
+                        return PEAR::raiseError('Cannot install, php_dir for channel "' .
+                            $params[$i]->getChannel() . '" is not writeable by the current user');
+                    }
+                }
+            }
+        }
+        unset($channelschecked);
+        PEAR_Downloader_Package::removeDuplicates($params);
+        if (!count($params)) {
+            $a = array();
+            return $a;
+        }
+        if (!isset($this->_options['nodeps']) && !isset($this->_options['offline'])) {
+            $reverify = true;
+            while ($reverify) {
+                $reverify = false;
+                foreach ($params as $i => $param) {
+                    $ret = $params[$i]->detectDependencies($params);
+                    if (PEAR::isError($ret)) {
+                        $reverify = true;
+                        $params[$i] = false;
+                        PEAR_Downloader_Package::removeDuplicates($params);
+                        if (!isset($this->_options['soft'])) {
+                            $this->log(0, $ret->getMessage());
                         }
-                    } else {
-                        return $pkgfile;
+                        continue 2;
                     }
-                } else {
-                    return $this->raiseError($file);
                 }
             }
-            $pkgfile = $file;
         }
-        // }}}
-        return $pkgfile;
+        if (isset($this->_options['offline'])) {
+            $this->log(3, 'Skipping dependency download check, --offline specified');
+        }
+        if (!count($params)) {
+            $a = array();
+            return $a;
+        }
+        while (PEAR_Downloader_Package::mergeDependencies($params));
+        PEAR_Downloader_Package::removeInstalled($params);
+        if (!count($params)) {
+            $this->pushError('No valid packages found', PEAR_INSTALLER_FAILED);
+            $a = array();
+            return $a;
+        }
+        PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+        $err = $this->analyzeDependencies($params);
+        PEAR::popErrorHandling();
+        if (!count($params)) {
+            $this->pushError('No valid packages found', PEAR_INSTALLER_FAILED);
+            $a = array();
+            return $a;
+        }
+        $ret = array();
+        $newparams = array();
+        if (isset($this->_options['pretend'])) {
+            return $params;
+        }
+        foreach ($params as $i => $package) {
+            PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+            $pf = &$params[$i]->download();
+            PEAR::staticPopErrorHandling();
+            if (PEAR::isError($pf)) {
+                if (!isset($this->_options['soft'])) {
+                    $this->log(1, $pf->getMessage());
+                    $this->log(0, 'Error: cannot download "' .
+                        $this->_registry->parsedPackageNameToString($package->getParsedPackage(),
+                            true) .
+                        '"');
+                }
+                continue;
+            }
+            $newparams[] = &$params[$i];
+            $ret[] = array('file' => $pf->getArchiveFile(),
+                                   'info' => &$pf,
+                                   'pkg' => $pf->getPackage());
+        }
+        $this->_downloadedPackages = $ret;
+        return $newparams;
     }
-    // }}}
-    // {{{ getPackageDownloadUrl()
 
-    function getPackageDownloadUrl($package, $version = null)
+    /**
+     * @param array all packages to be installed
+     */
+    function analyzeDependencies(&$params)
     {
-        if ($version) {
-            $package .= "-$version";
+        $hasfailed = $failed = false;
+        if (isset($this->_options['downloadonly'])) {
+            return;
         }
-        if ($this === null || $this->_config === null) {
-            $package = "http://pear.php.net/get/$package";
-        } else {
-            $package = "http://" . $this->_config->get('master_server') .
-                "/get/$package";
+        PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+        $redo = true;
+        $reset = false;
+        while ($redo) {
+            $redo = false;
+            foreach ($params as $i => $param) {
+                $deps = $param->getDeps();
+                if (!$deps) {
+                    $depchecker = &$this->getDependency2Object($this->config, $this->getOptions(),
+                        $param->getParsedPackage(), PEAR_VALIDATE_DOWNLOADING);
+                    if ($param->getType() == 'xmlrpc') {
+                        $send = $param->getDownloadURL();
+                    } else {
+                        $send = $param->getPackageFile();
+                    }
+                    $installcheck = $depchecker->validatePackage($send, $this, $params);
+                    if (PEAR::isError($installcheck)) {
+                        if (!isset($this->_options['soft'])) {
+                            $this->log(0, $installcheck->getMessage());
+                        }
+                        $hasfailed = true;
+                        $params[$i] = false;
+                        $reset = true;
+                        $redo = true;
+                        $failed = false;
+                        PEAR_Downloader_Package::removeDuplicates($params);
+                        continue 2;
+                    }
+                    continue;
+                }
+                if (!$reset && $param->alreadyValidated()) {
+                    continue;
+                }
+                if (count($deps)) {
+                    $depchecker = &$this->getDependency2Object($this->config, $this->getOptions(),
+                        $param->getParsedPackage(), PEAR_VALIDATE_DOWNLOADING);
+                    if ($param->getType() == 'xmlrpc') {
+                        $send = $param->getDownloadURL();
+                    } else {
+                        $send = $param->getPackageFile();
+                    }
+                    $installcheck = $depchecker->validatePackage($send, $this, $params);
+                    if (PEAR::isError($installcheck)) {
+                        if (!isset($this->_options['soft'])) {
+                            $this->log(0, $installcheck->getMessage());
+                        }
+                        $hasfailed = true;
+                        $params[$i] = false;
+                        $reset = true;
+                        $redo = true;
+                        $failed = false;
+                        PEAR_Downloader_Package::removeDuplicates($params);
+                        continue 2;
+                    }
+                    $failed = false;
+                    if (isset($deps['required'])) {
+                        foreach ($deps['required'] as $type => $dep) {
+                            // note: Dependency2 will never return a PEAR_Error if ignore-errors
+                            // is specified, so soft is needed to turn off logging
+                            if (!isset($dep[0])) {
+                                if (PEAR::isError($e = $depchecker->{"validate{$type}Dependency"}($dep,
+                                      true, $params))) {
+                                    $failed = true;
+                                    if (!isset($this->_options['soft'])) {
+                                        $this->log(0, $e->getMessage());
+                                    }
+                                } elseif (is_array($e) && !$param->alreadyValidated()) {
+                                    if (!isset($this->_options['soft'])) {
+                                        $this->log(0, $e[0]);
+                                    }
+                                }
+                            } else {
+                                foreach ($dep as $d) {
+                                    if (PEAR::isError($e =
+                                          $depchecker->{"validate{$type}Dependency"}($d,
+                                          true, $params))) {
+                                        $failed = true;
+                                        if (!isset($this->_options['soft'])) {
+                                            $this->log(0, $e->getMessage());
+                                        }
+                                    } elseif (is_array($e) && !$param->alreadyValidated()) {
+                                        if (!isset($this->_options['soft'])) {
+                                            $this->log(0, $e[0]);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                        if (isset($deps['optional'])) {
+                            foreach ($deps['optional'] as $type => $dep) {
+                                if (!isset($dep[0])) {
+                                    if (PEAR::isError($e =
+                                          $depchecker->{"validate{$type}Dependency"}($dep,
+                                          false, $params))) {
+                                        $failed = true;
+                                        if (!isset($this->_options['soft'])) {
+                                            $this->log(0, $e->getMessage());
+                                        }
+                                    } elseif (is_array($e) && !$param->alreadyValidated()) {
+                                        if (!isset($this->_options['soft'])) {
+                                            $this->log(0, $e[0]);
+                                        }
+                                    }
+                                } else {
+                                    foreach ($dep as $d) {
+                                        if (PEAR::isError($e =
+                                              $depchecker->{"validate{$type}Dependency"}($d,
+                                              false, $params))) {
+                                            $failed = true;
+                                            if (!isset($this->_options['soft'])) {
+                                                $this->log(0, $e->getMessage());
+                                            }
+                                        } elseif (is_array($e) && !$param->alreadyValidated()) {
+                                            if (!isset($this->_options['soft'])) {
+                                                $this->log(0, $e[0]);
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                        $groupname = $param->getGroup();
+                        if (isset($deps['group']) && $groupname) {
+                            if (!isset($deps['group'][0])) {
+                                $deps['group'] = array($deps['group']);
+                            }
+                            $found = false;
+                            foreach ($deps['group'] as $group) {
+                                if ($group['attribs']['name'] == $groupname) {
+                                    $found = true;
+                                    break;
+                                }
+                            }
+                            if ($found) {
+                                unset($group['attribs']);
+                                foreach ($group as $type => $dep) {
+                                    if (!isset($dep[0])) {
+                                        if (PEAR::isError($e =
+                                              $depchecker->{"validate{$type}Dependency"}($dep,
+                                              false, $params))) {
+                                            $failed = true;
+                                            if (!isset($this->_options['soft'])) {
+                                                $this->log(0, $e->getMessage());
+                                            }
+                                        } elseif (is_array($e) && !$param->alreadyValidated()) {
+                                            if (!isset($this->_options['soft'])) {
+                                                $this->log(0, $e[0]);
+                                            }
+                                        }
+                                    } else {
+                                        foreach ($dep as $d) {
+                                            if (PEAR::isError($e =
+                                                  $depchecker->{"validate{$type}Dependency"}($d,
+                                                  false, $params))) {
+                                                $failed = true;
+                                                if (!isset($this->_options['soft'])) {
+                                                    $this->log(0, $e->getMessage());
+                                                }
+                                            } elseif (is_array($e) && !$param->alreadyValidated()) {
+                                                if (!isset($this->_options['soft'])) {
+                                                    $this->log(0, $e[0]);
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    } else {
+                        foreach ($deps as $dep) {
+                            if (PEAR::isError($e = $depchecker->validateDependency1($dep, $params))) {
+                                $failed = true;
+                                if (!isset($this->_options['soft'])) {
+                                    $this->log(0, $e->getMessage());
+                                }
+                            } elseif (is_array($e) && !$param->alreadyValidated()) {
+                                if (!isset($this->_options['soft'])) {
+                                    $this->log(0, $e[0]);
+                                }
+                            }
+                        }
+                    }
+                    $params[$i]->setValidated();
+                }
+                if ($failed) {
+                    $hasfailed = true;
+                    $params[$i] = false;
+                    $reset = true;
+                    $redo = true;
+                    $failed = false;
+                    PEAR_Downloader_Package::removeDuplicates($params);
+                    continue 2;
+                }
+            }
         }
-        if (!extension_loaded("zlib")) {
-            $package .= '?uncompress=yes';
+        PEAR::staticPopErrorHandling();
+        if ($hasfailed && (isset($this->_options['ignore-errors']) ||
+              isset($this->_options['nodeps']))) {
+            // this is probably not needed, but just in case
+            if (!isset($this->_options['soft'])) {
+                $this->log(0, 'WARNING: dependencies failed');
+            }
         }
-        return $package;
     }
 
-    // }}}
-    // {{{ extractDownloadFileName($pkgfile, &$version)
-
-    function extractDownloadFileName($pkgfile, &$version)
+    /**
+     * Retrieve the directory that downloads will happen in
+     * @access private
+     * @return string
+     */
+    function getDownloadDir()
     {
-        if (@is_file($pkgfile)) {
-            return $pkgfile;
+        if (isset($this->_downloadDir)) {
+            return $this->_downloadDir;
         }
-        // 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];
+        $downloaddir = $this->config->get('download_dir');
+        if (empty($downloaddir)) {
+            if (!class_exists('System')) {
+                require_once 'System.php';
+            }
+            if (PEAR::isError($downloaddir = System::mktemp('-d'))) {
+                return $downloaddir;
+            }
+            $this->log(3, '+ tmp dir created at ' . $downloaddir);
         }
-        $version = null;
-        return $pkgfile;
+        return $this->_downloadDir = $downloaddir;
     }
 
-    // }}}
+    function setDownloadDir($dir)
+    {
+        $this->_downloadDir = $dir;
+    }
 
     // }}}
-    // {{{ getDownloadedPackages()
-
-    /**
-     * Retrieve a list of downloaded packages after a call to {@link download()}.
-     *
-     * Also resets the list of downloaded packages.
-     * @return array
-     */
-    function getDownloadedPackages()
+    // {{{ configSet()
+    function configSet($key, $value, $layer = 'user', $channel = false)
     {
-        $ret = $this->_downloadedPackages;
-        $this->_downloadedPackages = array();
-        $this->_toDownload = array();
-        return $ret;
+        $this->config->set($key, $value, $layer, $channel);
+        $this->_preferredState = $this->config->get('preferred_state', null, $channel);
+        if (!$this->_preferredState) {
+            // don't inadvertantly use a non-set preferred_state
+            $this->_preferredState = null;
+        }
     }
 
     // }}}
-    // {{{ download()
+    // {{{ setOptions()
+    function setOptions($options)
+    {
+        $this->_options = $options;
+    }
 
-    /**
-     * Download any files and their dependencies, if necessary
-     *
-     * BC-compatible method name
-     * @param array a mixed list of package names, local files, or package.xml
-     */
-    function download($packages)
+    // }}}
+    // {{{ setOptions()
+    function getOptions()
     {
-        return $this->doDownload($packages);
+        return $this->_options;
     }
 
     // }}}
-    // {{{ doDownload()
 
     /**
-     * Download any files and their dependencies, if necessary
-     *
-     * @param array a mixed list of package names, local files, or package.xml
+     * For simpler unit-testing
+     * @param PEAR_Config
+     * @param int
+     * @param string
      */
-    function doDownload($packages)
+    function &getPackagefileObject(&$c, $d, $t = false)
     {
-        $mywillinstall = array();
-        $state = $this->_preferredState;
-
-        // {{{ download files in this list if necessary
-        foreach($packages as $pkgfile) {
-            $need_download = false;
-            if (!is_file($pkgfile)) {
-                if (preg_match('#^(http|ftp)://#', $pkgfile)) {
-                    $need_download = true;
-                }
-                $pkgfile = $this->_downloadNonFile($pkgfile);
-                if (PEAR::isError($pkgfile)) {
-                    return $pkgfile;
-                }
-                if ($pkgfile === false) {
-                    continue;
-                }
-            } // end is_file()
-
-            $tempinfo = $this->infoFromAny($pkgfile);
-            if ($need_download) {
-                $this->_toDownload[] = $tempinfo['package'];
-            }
-            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;
-                }
-                $fail = false;
-                foreach ($alldeps as $info) {
-                    if ($info['type'] != 'pkg') {
-                        continue;
-                    }
-                    $ret = $this->_processDependency($package, $info, $mywillinstall);
-                    if ($ret === false) {
-                        continue;
-                    }
-                    if ($ret === 0) {
-                        $fail = true;
-                        continue;
-                    }
-                    if (PEAR::isError($ret)) {
-                        return $ret;
-                    }
-                    $deppackages[] = $ret;
-                } // foreach($alldeps
-                if ($fail) {
-                    $deppackages = array();
-                }
-            }
-
-            if (count($deppackages)) {
-                $this->doDownload($deppackages);
-            }
-        } // }}} if --alldeps or --onlyreqdeps
+        if (!class_exists('PEAR_PackageFile')) {
+            require_once 'PEAR/PackageFile.php';
+        }
+        $a = &new PEAR_PackageFile($c, $d, $t);
+        return $a;
     }
 
-    // }}}
-    // {{{ _downloadNonFile($pkgfile)
+    // {{{ _getPackageDownloadUrl()
 
     /**
-     * @return false|PEAR_Error|string false if loop should be broken out of,
-     *                                 string if the file was downloaded,
-     *                                 PEAR_Error on exception
+     * @param array output of {@link parsePackageName()}
      * @access private
      */
-    function _downloadNonFile($pkgfile)
+    function _getPackageDownloadUrl($parr)
     {
-        $origpkgfile = $pkgfile;
-        $state = null;
-        $pkgfile = $this->extractDownloadFileName($pkgfile, $version);
-        if (preg_match('#^(http|ftp)://#', $pkgfile)) {
-            return $this->_downloadFile($pkgfile, $version, $origpkgfile);
-        }
-        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;
-        }
-        if (in_array($pkgfile, $this->_toDownload)) {
-            return false;
-        }
-        $releases = $this->_remote->call('package.info', $pkgfile, 'releases', true);
-        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;
+        $curchannel = $this->config->get('default_channel');
+        $this->configSet('default_channel', $parr['channel']);
+        // getDownloadURL returns an array.  On error, it only contains information
+        // on the latest release as array(version, info).  On success it contains
+        // array(version, info, download url string)
+        $state = isset($parr['state']) ? $parr['state'] : $this->config->get('preferred_state');
+        if (!$this->_registry->channelExists($parr['channel'])) {
+            do {
+                if ($this->config->get('auto_discover')) {
+                    if ($this->discover($parr['channel'])) {
                         break;
                     }
                 }
-                if ($version == 0) {
-                    return $this->raiseError("No release with state '$state' found for '$pkgfile'");
+                return PEAR::raiseError('Unknown remote channel: ' . $remotechannel);
+            } while (false);
+        }
+        $chan = &$this->_registry->getChannel($parr['channel']);
+        $version = $this->_registry->packageInfo($parr['package'], 'version',
+            $parr['channel']);
+        if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
+              $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
+            $rest = &$this->config->getREST('1.0', $this->_options);
+            if (!isset($parr['version']) && !isset($parr['state']) && $version
+                  && !isset($this->_options['downloadonly'])) {
+                $url = $rest->getDownloadURL($base, $parr, $state, $version);
+            } else {
+                $url = $rest->getDownloadURL($base, $parr, $state, false);
+            }
+            if (PEAR::isError($url)) {
+                return $url;
+            }
+            if ($parr['channel'] != $curchannel) {
+                $this->configSet('default_channel', $curchannel);
+            }
+            if (!is_array($url)) {
+                return $url;
+            }
+            $url['raw'] = false; // no checking is necessary for REST
+            if (!is_array($url['info'])) {
+                return PEAR::raiseError('Invalid remote dependencies retrieved from REST - ' .
+                    'this should never happen');
+            }
+            if (isset($url['info']['required']) || $url['compatible']) {
+                require_once 'PEAR/PackageFile/v2.php';
+                $pf = new PEAR_PackageFile_v2;
+                $pf->setRawChannel($parr['channel']);
+                if ($url['compatible']) {
+                    $pf->setRawCompatible($url['compatible']);
                 }
-            // invalid suffix passed
             } else {
-                return $this->raiseError("Invalid suffix '-$version', be sure to pass a valid PEAR ".
-                                         "version number or release state");
+                require_once 'PEAR/PackageFile/v1.php';
+                $pf = new PEAR_PackageFile_v1;
             }
-        // Guess what to download
-        } else {
-            $states = $this->betterStates($this->_preferredState, true);
-            $possible = false;
-            $version = 0;
-            $higher_version = 0;
-            $prev_hi_ver = 0;
-            foreach ($releases as $ver => $inf) {
-                if (in_array($inf['state'], $states) && version_compare("$version", "$ver") < 0) {
-                    $version = $ver;
-                    break;
-                } else {
-                    $ver = (string)$ver;
-                    if (version_compare($prev_hi_ver, $ver) < 0) {
-                        $prev_hi_ver = $higher_version = $ver;
-                    }
-                               }
+            $pf->setRawPackage($url['package']);
+            $pf->setDeps($url['info']);
+            $pf->setRawState($url['stability']);
+            $url['info'] = &$pf;
+            if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) {
+                $ext = '.tar';
+            } else {
+                $ext = '.tgz';
             }
-            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 '" . $releases[$higher_version]['state'] . "' which is less stable " .
-                              "than state '$this->_preferredState'");
+            if (is_array($url)) {
+                if (isset($url['url'])) {
+                    $url['url'] .= $ext;
+                }
+            }
+            return $url;
+        } elseif ($chan->supports('xmlrpc', 'package.getDownloadURL', false, '1.1')) {
+            // don't install with the old version information unless we're doing a plain
+            // vanilla simple installation.  If the user says to install a particular
+            // version or state, ignore the current installed version
+            if (!isset($parr['version']) && !isset($parr['state']) && $version
+                  && !isset($this->_options['downloadonly'])) {
+                $url = $this->_remote->call('package.getDownloadURL', $parr, $state, $version);
+            } else {
+                $url = $this->_remote->call('package.getDownloadURL', $parr, $state);
             }
+        } else {
+            $url = $this->_remote->call('package.getDownloadURL', $parr, $state);
+        }
+        if (PEAR::isError($url)) {
+            return $url;
+        }
+        if ($parr['channel'] != $curchannel) {
+            $this->configSet('default_channel', $curchannel);
+        }
+        if (isset($url['__PEAR_ERROR_CLASS__'])) {
+            return PEAR::raiseError($url['message']);
+        }
+        if (!is_array($url)) {
+            return $url;
+        }
+        $url['raw'] = $url['info'];
+        if (isset($this->_options['downloadonly'])) {
+            $pkg = &$this->getPackagefileObject($this->config, $this->debug);
+        } else {
+            $pkg = &$this->getPackagefileObject($this->config, $this->debug,
+                $this->getDownloadDir());
         }
-        // Check if we haven't already the version
-        if (empty($this->_options['force']) && !is_null($curinfo)) {
-            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, "Package '{$curinfo['package']}' version '{$curinfo['version']}' " .
-                              " is installed and {$curinfo['version']} is > requested '$version', skipping");
-                return false;
+        PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+        $pinfo = &$pkg->fromXmlString($url['info'], PEAR_VALIDATE_DOWNLOADING, 'remote');
+        PEAR::staticPopErrorHandling();
+        if (PEAR::isError($pinfo)) {
+            if (!isset($this->_options['soft'])) {
+                $this->log(0, $pinfo->getMessage());
             }
+            return PEAR::raiseError('Remote package.xml is not valid - this should never happen');
         }
-        $this->_toDownload[] = $pkgfile;
-        return $this->_downloadFile($pkgfile, $version, $origpkgfile, $state);
+        $url['info'] = &$pinfo;
+        if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) {
+            $ext = '.tar';
+        } else {
+            $ext = '.tgz';
+        }
+        if (is_array($url)) {
+            if (isset($url['url'])) {
+                $url['url'] .= $ext;
+            }
+        }
+        return $url;
     }
-
     // }}}
-    // {{{ _processDependency($package, $info, $mywillinstall)
+    // {{{ getDepPackageDownloadUrl()
 
     /**
-     * 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
+     * @param array dependency array
      * @access private
-     * @todo Add test for relation 'lt'/'le' -> make sure that the dependency requested is
-     *       in fact lower than the required value.  This will be very important for BC dependencies
      */
-    function _processDependency($package, $info, $mywillinstall)
+    function _getDepPackageDownloadUrl($dep, $parr)
     {
-        $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;
+        $xsdversion = isset($dep['rel']) ? '1.0' : '2.0';
+        $curchannel = $this->config->get('default_channel');
+        if (isset($dep['channel'])) {
+            $remotechannel = $dep['channel'];
+        } else {
+            $remotechannel = 'pear.php.net';
         }
-        // {{{ get releases
-        $releases = $this->_remote->call('package.info', $info['name'], 'releases', true);
-        if (PEAR::isError($releases)) {
-            return $releases;
+        if (!$this->_registry->channelExists($remotechannel)) {
+            do {
+                if ($this->config->get('auto_discover')) {
+                    if ($this->discover($remotechannel)) {
+                        break;
+                    }
+                }
+                return PEAR::raiseError('Unknown remote channel: ' . $remotechannel);
+            } while (false);
         }
-        if (!count($releases)) {
-            if (!isset($this->_installed[strtolower($info['name'])])) {
-                $this->pushError("Package '$package' dependency '$info[name]' ".
-                            "has no releases");
-            }
-            return false;
+        $this->configSet('default_channel', $remotechannel);
+        $state = isset($parr['state']) ? $parr['state'] : $this->config->get('preferred_state');
+        if (isset($parr['state']) && isset($parr['version'])) {
+            unset($parr['state']);
         }
-        $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;
+        $chan = &$this->_registry->getChannel($remotechannel);
+        $version = $this->_registry->packageInfo($dep['name'], 'version',
+            $remotechannel);
+        if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
+              $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
+            $rest = &$this->config->getREST('1.0', $this->_options);
+            $url = $rest->getDepDownloadURL($base, $xsdversion, $dep, $parr,
+                    $state, $version);
+            if (PEAR::isError($url)) {
+                return $url;
+            }
+            if ($parr['channel'] != $curchannel) {
+                $this->configSet('default_channel', $curchannel);
+            }
+            if (!is_array($url)) {
+                return $url;
+            }
+            $url['raw'] = false; // no checking is necessary for REST
+            if (!is_array($url['info'])) {
+                return PEAR::raiseError('Invalid remote dependencies retrieved from REST - ' .
+                    'this should never happen');
+            }
+            if (isset($url['info']['required'])) {
+                if (!class_exists('PEAR_PackageFile_v2')) {
+                    require_once 'PEAR/PackageFile/v2.php';
                 }
+                $pf = new PEAR_PackageFile_v2;
+                $pf->setRawChannel($remotechannel);
             } else {
-                $found = true;
+                if (!class_exists('PEAR_PackageFile_v1')) {
+                    require_once 'PEAR/PackageFile/v1.php';
+                }
+                $pf = new PEAR_PackageFile_v1;
             }
-        }
-        if (!count($releases) && !$found) {
-            $get = array();
-            foreach($save as $release) {
-                $get = array_merge($get,
-                    $this->betterStates($release['state'], true));
+            $pf->setRawPackage($url['package']);
+            $pf->setDeps($url['info']);
+            $pf->setRawState($url['stability']);
+            $url['info'] = &$pf;
+            if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) {
+                $ext = '.tar';
+            } else {
+                $ext = '.tgz';
+            }
+            if (is_array($url)) {
+                if (isset($url['url'])) {
+                    $url['url'] .= $ext;
+                }
             }
-            $savestate = array_shift($get);
-            $this->pushError( "Release for '$package' dependency '$info[name]' " .
-                "has state '$savestate', requires '$state'");
-            return 0;
+            return $url;
+        } elseif ($chan->supports('xmlrpc', 'package.getDepDownloadURL', false, '1.1')) {
+            if ($version) {
+                $url = $this->_remote->call('package.getDepDownloadURL', $xsdversion, $dep, $parr,
+                    $state, $version);
+            } else {
+                $url = $this->_remote->call('package.getDepDownloadURL', $xsdversion, $dep, $parr,
+                    $state);
+            }
+        } else {
+            $url = $this->_remote->call('package.getDepDownloadURL', $xsdversion, $dep, $parr, $state);
         }
-        if (in_array(strtolower($info['name']), $this->_toDownload) ||
-              isset($mywillinstall[strtolower($info['name'])])) {
-            // skip upgrade check for packages we will install
-            return false;
+        if ($parr['channel'] != $curchannel) {
+            $this->configSet('default_channel', $curchannel);
         }
-        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'];
+        if (!is_array($url)) {
+            return $url;
+        }
+        if (isset($url['__PEAR_ERROR_CLASS__'])) {
+            return PEAR::raiseError($url['message']);
+        }
+        $url['raw'] = $url['info'];
+        $pkg = &$this->getPackagefileObject($this->config, $this->debug);
+        PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+        $pinfo = &$pkg->fromXmlString($url['info'], PEAR_VALIDATE_DOWNLOADING, 'remote');
+        PEAR::staticPopErrorHandling();
+        if (PEAR::isError($pinfo)) {
+            if (!isset($this->_options['soft'])) {
+                $this->log(0, $pinfo->getMessage());
             }
-            // skip upgrade check for packages we don't have installed
-            return $info['name'];
+            return PEAR::raiseError('Remote package.xml is not valid - this should never happen');
         }
-        // }}}
-
-        // {{{ 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;
+        $url['info'] = &$pinfo;
+        if (is_array($url)) {
+            if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) {
+                $ext = '.tar';
             } else {
-                return $info['name'];
+                $ext = '.tgz';
+            }
+            if (isset($url['url'])) {
+                $url['url'] .= $ext;
             }
         }
-        if (version_compare($info['version'], $inst_version, 'le')) {
-            // installed version is up-to-date
-            return false;
+        return $url;
+    }
+    // }}}
+    // {{{ getPackageDownloadUrl()
+
+    /**
+     * @deprecated in favor of _getPackageDownloadUrl
+     */
+    function getPackageDownloadUrl($package, $version = null, $channel = false)
+    {
+        if ($version) {
+            $package .= "-$version";
+        }
+        if ($this === null || $this->_registry === null) {
+            $package = "http://pear.php.net/get/$package";
+        } else {
+            $chan = $this->_registry->getChannel($channel);
+            $package = "http://" . $chan->getServer() . "/get/$package";
         }
-        return $info['name'];
+        if (!extension_loaded("zlib")) {
+            $package .= '?uncompress=yes';
+        }
+        return $package;
+    }
+
+    // }}}
+    // {{{ 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;
     }
 
     // }}}
@@ -640,7 +1013,12 @@ class PEAR_Downloader extends PEAR_Common
     {
         if (strlen($prepend) > 0) {
             if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) {
-                $path = $prepend . substr($path, 2);
+                if (preg_match('/^[a-z]:/i', $prepend)) {
+                    $prepend = substr($prepend, 2);
+                } elseif ($prepend{0} != '\\') {
+                    $prepend = "\\$prepend";
+                }
+                $path = substr($path, 0, 2) . $prepend . substr($path, 2);
             } else {
                 $path = $prepend . $path;
             }
@@ -674,7 +1052,414 @@ class PEAR_Downloader extends PEAR_Common
     }
 
     // }}}
+
+    /**
+     * for BC
+     */
+    function sortPkgDeps(&$packages, $uninstall = false)
+    {
+        $uninstall ? 
+            $this->sortPackagesForUninstall($packages) :
+            $this->sortPackagesForInstall($packages);
+    }
+
+    function _getDepTreeDP($package, $packages, &$deps, &$checked)
+    {
+        $pf = $package->getPackageFile();
+        $checked[strtolower($package->getChannel())][strtolower($package->getPackage())]
+            = true;
+        $pdeps = $pf->getDeps(true);
+        if (!$pdeps) {
+            return;
+        }
+        if ($pf->getPackagexmlVersion() == '1.0') {
+            foreach ($pdeps as $dep) {
+                if ($dep['type'] != 'pkg') {
+                    continue;
+                }
+                $deps['pear.php.net'][strtolower($dep['name'])] = true;
+                foreach ($packages as $p) {
+                    $dep['channel'] = 'pear.php.net';
+                    $dep['package'] = $dep['name'];
+                    if ($p->isEqual($dep)) {
+                        if (!isset($checked[strtolower($p->getChannel())]
+                              [strtolower($p->getPackage())])) {
+                            // add the dependency's dependencies to the tree
+                            $this->_getDepTreeDP($p, $packages, $deps, $checked);
+                        }
+                    }
+                }
+            }
+        } else {
+            $tdeps = array();
+            if (isset($pdeps['required']['package'])) {
+                $t = $pdeps['required']['package'];
+                if (!isset($t[0])) {
+                    $t = array($t);
+                }
+                $tdeps = array_merge($tdeps, $t);
+            }
+            if (isset($pdeps['required']['subpackage'])) {
+                $t = $pdeps['required']['subpackage'];
+                if (!isset($t[0])) {
+                    $t = array($t);
+                }
+                $tdeps = array_merge($tdeps, $t);
+            }
+            if (isset($pdeps['optional']['package'])) {
+                $t = $pdeps['optional']['package'];
+                if (!isset($t[0])) {
+                    $t = array($t);
+                }
+                $tdeps = array_merge($tdeps, $t);
+            }
+            if (isset($pdeps['optional']['subpackage'])) {
+                $t = $pdeps['optional']['subpackage'];
+                if (!isset($t[0])) {
+                    $t = array($t);
+                }
+                $tdeps = array_merge($tdeps, $t);
+            }
+            if (isset($pdeps['group'])) {
+                if (!isset($pdeps['group'][0])) {
+                    $pdeps['group'] = array($pdeps['group']);
+                }
+                foreach ($pdeps['group'] as $group) {
+                    if (isset($group['package'])) {
+                        $t = $group['package'];
+                        if (!isset($t[0])) {
+                            $t = array($t);
+                        }
+                        $tdeps = array_merge($tdeps, $t);
+                    }
+                    if (isset($group['subpackage'])) {
+                        $t = $group['subpackage'];
+                        if (!isset($t[0])) {
+                            $t = array($t);
+                        }
+                        $tdeps = array_merge($tdeps, $t);
+                    }
+                }
+            }
+            foreach ($tdeps as $dep) {
+                if (!isset($dep['channel'])) {
+                    $depchannel = '__uri';
+                } else {
+                    $depchannel = $dep['channel'];
+                }
+                $deps[$depchannel][strtolower($dep['name'])] = true;
+                foreach ($packages as $p) {
+                    $dep['channel'] = $depchannel;
+                    $dep['package'] = $dep['name'];
+                    if ($p->isEqual($dep)) {
+                        if (!isset($checked[strtolower($p->getChannel())]
+                              [strtolower($p->getPackage())])) {
+                            // add the dependency's dependencies to the tree
+                            $this->_getDepTreeDP($p, $packages, $deps, $checked);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Sort a list of arrays of array(downloaded packagefilename) by dependency.
+     *
+     * It also removes duplicate dependencies
+     * @param array an array of downloaded PEAR_Downloader_Packages
+     * @return array array of array(packagefilename, package.xml contents)
+     */
+    function sortPackagesForInstall(&$packages)
+    {
+        foreach ($packages as $i => $package) {
+            $checked = $deps = array();
+            $this->_getDepTreeDP($packages[$i], $packages, $deps, $checked);
+            $this->_depTree[$package->getChannel()][$package->getPackage()] = $deps;
+        }
+        usort($packages, array(&$this, '_sortInstall'));
+    }
+
+    function _dependsOn($a, $b)
+    {
+        return $this->_checkDepTree(strtolower($a->getChannel()), strtolower($a->getPackage()),
+            $b);
+    }
+
+    function _checkDepTree($channel, $package, $b, $checked = array())
+    {
+        $checked[$channel][$package] = true;
+        if (!isset($this->_depTree[$channel][$package])) {
+            return false;
+        }
+        if (isset($this->_depTree[$channel][$package][strtolower($b->getChannel())]
+              [strtolower($b->getPackage())])) {
+            return true;
+        }
+        foreach ($this->_depTree[$channel][$package] as $ch => $packages) {
+            foreach ($packages as $pa => $true) {
+                if ($this->_checkDepTree($ch, $pa, $b, $checked)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    function _sortInstall($a, $b)
+    {
+        if (!$a->getDeps() && !$b->getDeps()) {
+            return 0; // neither package has dependencies, order is insignificant
+        }
+        if ($a->getDeps() && !$b->getDeps()) {
+            return 1; // $a must be installed after $b because $a has dependencies
+        }
+        if (!$a->getDeps() && $b->getDeps()) {
+            return -1; // $b must be installed after $a because $b has dependencies
+        }
+        // both packages have dependencies
+        if ($this->_dependsOn($a, $b)) {
+            return 1;
+        }
+        if ($this->_dependsOn($b, $a)) {
+            return -1;
+        }
+        return 0;
+    }
+
+    /**
+     * Download a file through HTTP.  Considers suggested file name in
+     * Content-disposition: header and can run a callback function for
+     * different events.  The callback will be called with two
+     * parameters: the callback type, and parameters.  The implemented
+     * callback types are:
+     *
+     *  'setup'       called at the very beginning, parameter is a UI object
+     *                that should be used for all output
+     *  'message'     the parameter is a string with an informational message
+     *  'saveas'      may be used to save with a different file name, the
+     *                parameter is the filename that is about to be used.
+     *                If a 'saveas' callback returns a non-empty string,
+     *                that file name will be used as the filename instead.
+     *                Note that $save_dir will not be affected by this, only
+     *                the basename of the file.
+     *  'start'       download is starting, parameter is number of bytes
+     *                that are expected, or -1 if unknown
+     *  'bytesread'   parameter is the number of bytes read so far
+     *  'done'        download is complete, parameter is the total number
+     *                of bytes read
+     *  'connfailed'  if the TCP/SSL connection fails, this callback is called
+     *                with array(host,port,errno,errmsg)
+     *  'writefailed' if writing to disk fails, this callback is called
+     *                with array(destfile,errmsg)
+     *
+     * If an HTTP proxy has been configured (http_proxy PEAR_Config
+     * setting), the proxy will be used.
+     *
+     * @param string  $url       the URL to download
+     * @param object  $ui        PEAR_Frontend_* instance
+     * @param object  $config    PEAR_Config instance
+     * @param string  $save_dir  directory to save file in
+     * @param mixed   $callback  function/method to call for status
+     *                           updates
+     * @param false|string|array $lastmodified header values to check against for caching
+     *                           use false to return the header values from this download
+     * @param false|array $accept Accept headers to send
+     * @return string|array  Returns the full path of the downloaded file or a PEAR
+     *                       error on failure.  If the error is caused by
+     *                       socket-related errors, the error object will
+     *                       have the fsockopen error code available through
+     *                       getCode().  If caching is requested, then return the header
+     *                       values.
+     *
+     * @access public
+     */
+    function downloadHttp($url, &$ui, $save_dir = '.', $callback = null, $lastmodified = null,
+                          $accept = false)
+    {
+        if ($callback) {
+            call_user_func($callback, 'setup', array(&$ui));
+        }
+        $info = parse_url($url);
+        if (!isset($info['scheme']) || !in_array($info['scheme'], array('http', 'https'))) {
+            return PEAR::raiseError('Cannot download non-http URL "' . $url . '"');
+        }
+        if (!isset($info['host'])) {
+            return PEAR::raiseError('Cannot download from non-URL "' . $url . '"');
+        } else {
+            $host = @$info['host'];
+            $port = @$info['port'];
+            $path = @$info['path'];
+        }
+        if (isset($this)) {
+            $config = &$this->config;
+        } else {
+            $config = &PEAR_Config::singleton();
+        }
+        $proxy_host = $proxy_port = $proxy_user = $proxy_pass = '';
+        if ($config->get('http_proxy')&& 
+              $proxy = parse_url($config->get('http_proxy'))) {
+            $proxy_host = @$proxy['host'];
+            if (isset($proxy['scheme']) && $proxy['scheme'] == 'https') {
+                $proxy_host = 'ssl://' . $proxy_host;
+            }
+            $proxy_port = @$proxy['port'];
+            $proxy_user = @$proxy['user'];
+            $proxy_pass = @$proxy['pass'];
+
+            if ($proxy_port == '') {
+                $proxy_port = 8080;
+            }
+            if ($callback) {
+                call_user_func($callback, 'message', "Using HTTP proxy $host:$port");
+            }
+        }
+        if (empty($port)) {
+            if (isset($info['scheme']) && $info['scheme'] == 'https') {
+                $port = 443;
+            } else {
+                $port = 80;
+            }
+        }
+        if ($proxy_host != '') {
+            $fp = @fsockopen($proxy_host, $proxy_port, $errno, $errstr);
+            if (!$fp) {
+                if ($callback) {
+                    call_user_func($callback, 'connfailed', array($proxy_host, $proxy_port,
+                                                                  $errno, $errstr));
+                }
+                return PEAR::raiseError("Connection to `$proxy_host:$proxy_port' failed: $errstr", $errno);
+            }
+            if ($lastmodified === false || $lastmodified) {
+                $request = "GET $url HTTP/1.1\r\n";
+            } else {
+                $request = "GET $url HTTP/1.0\r\n";
+            }
+        } else {
+            if (isset($info['scheme']) && $info['scheme'] == 'https') {
+                $host = 'ssl://' . $host;
+            }
+            $fp = @fsockopen($host, $port, $errno, $errstr);
+            if (!$fp) {
+                if ($callback) {
+                    call_user_func($callback, 'connfailed', array($host, $port,
+                                                                  $errno, $errstr));
+                }
+                return PEAR::raiseError("Connection to `$host:$port' failed: $errstr", $errno);
+            }
+            if ($lastmodified === false || $lastmodified) {
+                $request = "GET $path HTTP/1.1\r\n";
+            } else {
+                $request = "GET $path HTTP/1.0\r\n";
+            }
+        }
+        $ifmodifiedsince = '';
+        if (is_array($lastmodified)) {
+            if (isset($lastmodified['Last-Modified'])) {
+                $ifmodifiedsince = 'If-Modified-Since: ' . $lastmodified['Last-Modified'] . "\r\n";
+            }
+            if (isset($lastmodified['ETag'])) {
+                $ifmodifiedsince .= "If-None-Match: $lastmodified[ETag]\r\n";
+            }
+        } else {
+            $ifmodifiedsince = ($lastmodified ? "If-Modified-Since: $lastmodified\r\n" : '');
+        }
+        $request .= "Host: $host:$port\r\n" . $ifmodifiedsince .
+            "User-Agent: PEAR/@package_version@/PHP/" . PHP_VERSION . "\r\n";
+        if (isset($this)) { // only pass in authentication for non-static calls
+            $username = $config->get('username');
+            $password = $config->get('password');
+            if ($username && $password) {
+                $tmp = base64_encode("$username:$password");
+                $request .= "Authorization: Basic $tmp\r\n";
+            }
+        }
+        if ($proxy_host != '' && $proxy_user != '') {
+            $request .= 'Proxy-Authorization: Basic ' .
+                base64_encode($proxy_user . ':' . $proxy_pass) . "\r\n";
+        }
+        if ($accept) {
+            $request .= 'Accept: ' . implode(', ', $accept) . "\r\n";
+        }
+        $request .= "Connection: close\r\n";
+        $request .= "\r\n";
+        fwrite($fp, $request);
+        $headers = array();
+        while (trim($line = fgets($fp, 1024))) {
+            if (preg_match('/^([^:]+):\s+(.*)\s*$/', $line, $matches)) {
+                $headers[strtolower($matches[1])] = trim($matches[2]);
+            } elseif (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) {
+                if ($matches[1] == 304 && ($lastmodified || ($lastmodified === false))) {
+                    return false;
+                }
+                if ($matches[1] != 200) {
+                    return PEAR::raiseError("File http://$host:$port$path not valid (received: $line)");
+                }
+            }
+        }
+        if (isset($headers['content-disposition']) &&
+            preg_match('/\sfilename=\"([^;]*\S)\"\s*(;|$)/', $headers['content-disposition'], $matches)) {
+            $save_as = basename($matches[1]);
+        } else {
+            $save_as = basename($url);
+        }
+        if ($callback) {
+            $tmp = call_user_func($callback, 'saveas', $save_as);
+            if ($tmp) {
+                $save_as = $tmp;
+            }
+        }
+        $dest_file = $save_dir . DIRECTORY_SEPARATOR . $save_as;
+        if (!$wp = @fopen($dest_file, 'wb')) {
+            fclose($fp);
+            if ($callback) {
+                call_user_func($callback, 'writefailed', array($dest_file, $php_errormsg));
+            }
+            return PEAR::raiseError("could not open $dest_file for writing");
+        }
+        if (isset($headers['content-length'])) {
+            $length = $headers['content-length'];
+        } else {
+            $length = -1;
+        }
+        $bytes = 0;
+        if ($callback) {
+            call_user_func($callback, 'start', array(basename($dest_file), $length));
+        }
+        while ($data = @fread($fp, 1024)) {
+            $bytes += strlen($data);
+            if ($callback) {
+                call_user_func($callback, 'bytesread', $bytes);
+            }
+            if (!@fwrite($wp, $data)) {
+                fclose($fp);
+                if ($callback) {
+                    call_user_func($callback, 'writefailed', array($dest_file, $php_errormsg));
+                }
+                return PEAR::raiseError("$dest_file: write failed ($php_errormsg)");
+            }
+        }
+        fclose($fp);
+        fclose($wp);
+        if ($callback) {
+            call_user_func($callback, 'done', $bytes);
+        }
+        if ($lastmodified === false || $lastmodified) {
+            if (isset($headers['etag'])) {
+                $lastmodified = array('ETag' => $headers['etag']);
+            }
+            if (isset($headers['last-modified'])) {
+                if (is_array($lastmodified)) {
+                    $lastmodified['Last-Modified'] = $headers['last-modified'];
+                } else {
+                    $lastmodified = $headers['last-modified'];
+                }
+            }
+            return array($dest_file, $lastmodified, $headers);
+        }
+        return $dest_file;
+    }
 }
 // }}}
 
-?>
+?>
\ No newline at end of file
diff --git a/pear/PEAR/Downloader/Package.php b/pear/PEAR/Downloader/Package.php
new file mode 100644 (file)
index 0000000..9680325
--- /dev/null
@@ -0,0 +1,1678 @@
+<?php
+/**
+ * PEAR_Downloader_Package
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a1
+ */
+/**
+ * Coordinates download parameters and manages their dependencies
+ * prior to downloading them.
+ *
+ * Input can come from three sources:
+ *
+ * - local files (archives or package.xml)
+ * - remote files (downloadable urls)
+ * - abstract package names
+ *
+ * The first two elements are handled cleanly by PEAR_PackageFile, but the third requires
+ * accessing pearweb's xml-rpc interface to determine necessary dependencies, and the
+ * format returned of dependencies is slightly different from that used in package.xml.
+ *
+ * This class hides the differences between these elements, and makes automatic
+ * dependency resolution a piece of cake.  It also manages conflicts when
+ * two classes depend on incompatible dependencies, or differing versions of the same
+ * package dependency.  In addition, download will not be attempted if the php version is
+ * not supported, PEAR installer version is not supported, or non-PECL extensions are not
+ * installed.
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @PEAR-VER@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
+ */
+class PEAR_Downloader_Package
+{
+    /**
+     * @var PEAR_Downloader
+     */
+    var $_downloader;
+    /**
+     * @var PEAR_Config
+     */
+    var $_config;
+    /**
+     * @var PEAR_Registry
+     */
+    var $_registry;
+    /**
+     * @var PEAR_PackageFile_v1|PEAR_PackageFile|v2
+     */
+    var $_packagefile;
+    /**
+     * @var array
+     */
+    var $_parsedname;
+    /**
+     * @var array
+     */
+    var $_downloadURL;
+    /**
+     * @var array
+     */
+    var $_downloadDeps = array();
+    /**
+     * @var boolean
+     */
+    var $_valid = false;
+    /**
+     * @var boolean
+     */
+    var $_analyzed = false;
+    /**
+     * if this or a parent package was invoked with Package-state, this is set to the
+     * state variable.
+     *
+     * This allows temporary reassignment of preferred_state for a parent package and all of
+     * its dependencies.
+     * @var string|false
+     */
+    var $_explicitState = false;
+    /**
+     * If this package is invoked with Package#group, this variable will be true
+     */
+    var $_explicitGroup = false;
+    /**
+     * Package type local|url|xmlrpc
+     * @var string
+     */
+    var $_type;
+    /**
+     * Contents of package.xml, if downloaded from a remote channel
+     * @var string|false
+     * @access private
+     */
+    var $_rawpackagefile;
+    /**
+     * @var boolean
+     * @access private
+     */
+    var $_validated = false;
+
+    /**
+     * @param PEAR_Config
+     */
+    function PEAR_Downloader_Package(&$downloader)
+    {
+        $this->_downloader = &$downloader;
+        $this->_config = &$this->_downloader->config;
+        $this->_registry = &$this->_config->getRegistry();
+        $this->_valid = $this->_analyzed = false;
+    }
+
+    /**
+     * Parse the input and determine whether this is a local file, a remote uri, or an
+     * abstract package name.
+     *
+     * This is the heart of the PEAR_Downloader_Package(), and is used in
+     * {@link PEAR_Downloader::download()}
+     * @param string
+     * @return void|PEAR_Error
+     */
+    function initialize($param)
+    {
+        $origErr = $this->_fromFile($param);
+        if (!$this->_valid) {
+            $options = $this->_downloader->getOptions();
+            if (isset($options['offline'])) {
+                if (PEAR::isError($origErr)) {
+                    if (!isset($options['soft'])) {
+                        $this->_downloader->log(0, $origErr->getMessage());
+                    }
+                }
+                return PEAR::raiseError('Cannot download non-local package "' . $param . '"');
+            }
+            $err = $this->_fromUrl($param);
+            if (PEAR::isError($err) || !$this->_valid) {
+                if ($this->_type == 'url') {
+                    if (PEAR::isError($err)) {
+                        if (!isset($options['soft'])) {
+                            $this->_downloader->log(0, $err->getMessage());
+                        }
+                    }
+                    return PEAR::raiseError("Invalid or missing remote package file");
+                }
+                $err = $this->_fromString($param);
+                if (PEAR::isError($err) || !$this->_valid) {
+                    if (isset($this->_type) && $this->_type == 'local' &&
+                          PEAR::isError($origErr)) {
+                        if (is_array($origErr->getUserInfo())) {
+                            foreach ($origErr->getUserInfo() as $err) {
+                                if (is_array($err)) {
+                                    $err = $err['message'];
+                                }
+                                if (!isset($options['soft'])) {
+                                    $this->_downloader->log(0, $err);
+                                }
+                            }
+                        }
+                        if (!isset($options['soft'])) {
+                            $this->_downloader->log(0, $origErr->getMessage());
+                        }
+                        if (is_array($param)) {
+                            $param = $this->_registry->parsedPackageNameToString($param,
+                                true);
+                        }
+                        return PEAR::raiseError(
+                            "Cannot initialize '$param', invalid or missing package file");
+                    }
+                    if (PEAR::isError($err)) {
+                        if (!isset($options['soft'])) {
+                            $this->_downloader->log(0, $err->getMessage());
+                        }
+                    }
+                    if (is_array($param)) {
+                        $param = $this->_registry->parsedPackageNameToString($param, true);
+                    }
+                    return PEAR::raiseError(
+                        "Cannot initialize '$param', invalid or missing package file");
+                }
+            }
+        }
+    }
+
+    /**
+     * Retrieve any non-local packages
+     * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|PEAR_Error
+     */
+    function &download()
+    {
+        if (isset($this->_packagefile)) {
+            return $this->_packagefile;
+        }
+        if (isset($this->_downloadURL['url'])) {
+            $this->_isvalid = false;
+            $info = $this->getParsedPackage();
+            foreach ($info as $i => $p) {
+                $info[$i] = strtolower($p);
+            }
+            $err = $this->_fromUrl($this->_downloadURL['url'],
+                $this->_registry->parsedPackageNameToString($this->_parsedname, true));
+            $newinfo = $this->getParsedPackage();
+            foreach ($newinfo as $i => $p) {
+                $newinfo[$i] = strtolower($p);
+            }
+            if ($info != $newinfo) {
+                do {
+                    if ($info['package'] == 'pecl.php.net' && $newinfo['package'] == 'pear.php.net') {
+                        $info['package'] = 'pear.php.net';
+                        if ($info == $newinfo) {
+                            // skip the channel check if a pecl package says it's a PEAR package
+                            break;
+                        }
+                    }
+                    return PEAR::raiseError('CRITICAL ERROR: We are ' .
+                        $this->_registry->parsedPackageNameToString($info) . ', but the file ' .
+                        'downloaded claims to be ' .
+                        $this->_registry->parsedPackageNameToString($this->getParsedPackage()));
+                } while (false);
+            }
+            if (PEAR::isError($err) || !$this->_valid) {
+                return $err;
+            }
+        }
+        $this->_type = 'local';
+        return $this->_packagefile;
+    }
+
+    function &getPackageFile()
+    {
+        return $this->_packagefile;
+    }
+
+    function &getDownloader()
+    {
+        return $this->_downloader;
+    }
+
+    function getType() 
+    {
+        return $this->_type;
+    }
+
+    /**
+     * Like {@link initialize()}, but operates on a dependency
+     */
+    function fromDepURL($dep)
+    {
+        $this->_downloadURL = $dep;
+        if (isset($dep['uri'])) {
+            $options = $this->_downloader->getOptions();
+            if (!extension_loaded("zlib") || isset($options['nocompress'])) {
+                $ext = '.tar';
+            } else {
+                $ext = '.tgz';
+            }
+            PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+            $err = $this->_fromUrl($dep['uri'] . $ext);
+            PEAR::popErrorHandling();
+            if (PEAR::isError($err)) {
+                if (!isset($options['soft'])) {
+                    $this->_downloader->log(0, $err->getMessage());
+                }
+                return PEAR::raiseError('Invalid uri dependency "' . $dep['uri'] . $ext . '", ' .
+                    'cannot download');
+            }
+        } else {
+            $this->_parsedname =
+                array(
+                    'package' => $dep['info']->getPackage(),
+                    'channel' => $dep['info']->getChannel(),
+                    'version' => $dep['version']
+                );
+            if (!isset($dep['nodefault'])) {
+                $this->_parsedname['group'] = 'default'; // download the default dependency group
+                $this->_explicitGroup = false;
+            }
+            $this->_rawpackagefile = $dep['raw'];
+        }
+    }
+
+    function detectDependencies($params)
+    {
+        $options = $this->_downloader->getOptions();
+        if (isset($options['downloadonly'])) {
+            return;
+        }
+        if (isset($options['offline'])) {
+            $this->_downloader->log(3, 'Skipping dependency download check, --offline specified');
+            return;
+        }
+        $pname = $this->getParsedPackage();
+        if (!$pname) {
+            return;
+        }
+        $deps = $this->getDeps();
+        if (!$deps) {
+            return;
+        }
+        if (isset($deps['required'])) { // package.xml 2.0
+            return $this->_detect2($deps, $pname, $options, $params);
+        } else {
+            return $this->_detect1($deps, $pname, $options, $params);
+        }
+    }
+
+    function setValidated()
+    {
+        $this->_validated = true;
+    }
+
+    function alreadyValidated()
+    {
+        return $this->_validated;
+    }
+
+    /**
+     * Remove packages to be downloaded that are already installed
+     * @param array of PEAR_Downloader_Package objects
+     * @static
+     */
+    function removeInstalled(&$params)
+    {
+        if (!isset($params[0])) {
+            return;
+        }
+        $options = $params[0]->_downloader->getOptions();
+        if (!isset($options['downloadonly'])) {
+            foreach ($params as $i => $param) {
+                // remove self if already installed with this version
+                // this does not need any pecl magic - we only remove exact matches
+                if ($param->_registry->packageExists($param->getPackage(), $param->getChannel())) {
+                    if (version_compare($param->_registry->packageInfo($param->getPackage(), 'version',
+                          $param->getChannel()), $param->getVersion(), '==')) {
+                        if (!isset($options['force'])) {
+                            $info = $param->getParsedPackage();
+                            unset($info['version']);
+                            unset($info['state']);
+                            if (!isset($options['soft'])) {
+                                $param->_downloader->log(1, 'Skipping package "' .
+                                    $param->getShortName() .
+                                    '", already installed as version ' .
+                                    $param->_registry->packageInfo($param->getPackage(),
+                                        'version', $param->getChannel()));
+                            }
+                            $params[$i] = false;
+                        }
+                    } elseif (!isset($options['force']) && !isset($options['upgrade']) &&
+                          !isset($options['soft'])) {
+                        $info = $param->getParsedPackage();
+                        $param->_downloader->log(1, 'Skipping package "' .
+                            $param->getShortName() .
+                            '", already installed as version ' .
+                            $param->_registry->packageInfo($param->getPackage(), 'version',
+                                $param->getChannel()));
+                        $params[$i] = false;
+                    }
+                }
+            }
+        }
+        PEAR_Downloader_Package::removeDuplicates($params);
+    }
+
+    function _detect2($deps, $pname, $options, $params)
+    {
+        $this->_downloadDeps = array();
+        $groupnotfound = false;
+        foreach (array('package', 'subpackage') as $packagetype) {
+            // get required dependency group
+            if (isset($deps['required'][$packagetype])) {
+                if (isset($deps['required'][$packagetype][0])) {
+                    foreach ($deps['required'][$packagetype] as $dep) {
+                        if (isset($dep['conflicts'])) {
+                            // skip any package that this package conflicts with
+                            continue;
+                        }
+                        $ret = $this->_detect2Dep($dep, $pname, 'required', $params);
+                        if (is_array($ret)) {
+                            $this->_downloadDeps[] = $ret;
+                        }
+                    }
+                } else {
+                    $dep = $deps['required'][$packagetype];
+                    if (!isset($dep['conflicts'])) {
+                        // skip any package that this package conflicts with
+                        $ret = $this->_detect2Dep($dep, $pname, 'required', $params);
+                        if (is_array($ret)) {
+                            $this->_downloadDeps[] = $ret;
+                        }
+                    }
+                }
+            }
+            // get optional dependency group, if any
+            if (isset($deps['optional'][$packagetype])) {
+                $skipnames = array();
+                if (!isset($deps['optional'][$packagetype][0])) {
+                    $deps['optional'][$packagetype] = array($deps['optional'][$packagetype]);
+                }
+                foreach ($deps['optional'][$packagetype] as $dep) {
+                    $skip = false;
+                    if (!isset($options['alldeps'])) {
+                        $dep['package'] = $dep['name'];
+                        if (!isset($options['soft'])) {
+                            $this->_downloader->log(3, 'Notice: package "' .
+                              $this->_registry->parsedPackageNameToString($this->getParsedPackage(),
+                                    true) . '" optional dependency "' .
+                                $this->_registry->parsedPackageNameToString(array('package' =>
+                                    $dep['name'], 'channel' => 'pear.php.net'), true) .
+                                '" will not be automatically downloaded');
+                        }
+                        $skipnames[] = $this->_registry->parsedPackageNameToString($dep, true);
+                        $skip = true;
+                        unset($dep['package']);
+                    }
+                    if (!($ret = $this->_detect2Dep($dep, $pname, 'optional', $params))) {
+                        $dep['package'] = $dep['name'];
+                        if (@$skipnames[count($skipnames) - 1] ==
+                              $this->_registry->parsedPackageNameToString($dep, true)) {
+                            array_pop($skipnames);
+                        }
+                    }
+                    if (!$skip && is_array($ret)) {
+                        $this->_downloadDeps[] = $ret;
+                    }
+                }
+                if (count($skipnames)) {
+                    if (!isset($options['soft'])) {
+                        $this->_downloader->log(1, 'Did not download optional dependencies: ' .
+                            implode(', ', $skipnames) .
+                            ', use --alldeps to download automatically');
+                    }
+                }
+            }
+            // get requested dependency group, if any
+            $groupname = $this->getGroup();
+            $explicit = $this->_explicitGroup;
+            if (!$groupname) {
+                if ($this->canDefault()) {
+                    $groupname = 'default'; // try the default dependency group
+                } else {
+                    continue;
+                }
+            }
+            if ($groupnotfound) {
+                continue;
+            }
+            if (isset($deps['group'])) {
+                if (isset($deps['group']['attribs'])) {
+                    if (strtolower($deps['group']['attribs']['name']) == strtolower($groupname)) {
+                        $group = $deps['group'];
+                    } elseif ($explicit) {
+                        if (!isset($options['soft'])) {
+                            $this->_downloader->log(0, 'Warning: package "' .
+                                $this->_registry->parsedPackageNameToString($pname, true) .
+                                '" has no dependency ' . 'group named "' . $groupname . '"');
+                        }
+                        $groupnotfound = true;
+                        continue;
+                    }
+                } else {
+                    $found = false;
+                    foreach ($deps['group'] as $group) {
+                        if (strtolower($group['attribs']['name']) == strtolower($groupname)) {
+                            $found = true;
+                            break;
+                        }
+                    }
+                    if (!$found) {
+                        if ($explicit) {
+                            if (!isset($options['soft'])) {
+                                $this->_downloader->log(0, 'Warning: package "' .
+                                    $this->_registry->parsedPackageNameToString($pname, true) .
+                                    '" has no dependency ' . 'group named "' . $groupname . '"');
+                            }
+                        }
+                        $groupnotfound = true;
+                        continue;
+                    }
+                }
+            }
+            if (isset($group)) {
+                if (isset($group[$packagetype])) {
+                    if (isset($group[$packagetype][0])) {
+                        foreach ($group[$packagetype] as $dep) {
+                            $ret = $this->_detect2Dep($dep, $pname, 'dependency group "' .
+                                $group['attribs']['name'] . '"', $params);
+                            if (is_array($ret)) {
+                                $this->_downloadDeps[] = $ret;
+                            }
+                        }
+                    } else {
+                        $ret = $this->_detect2Dep($group[$packagetype], $pname,
+                            'dependency group "' .
+                            $group['attribs']['name'] . '"', $params);
+                        if (is_array($ret)) {
+                            $this->_downloadDeps[] = $ret;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    function _detect2Dep($dep, $pname, $group, $params)
+    {
+        if (isset($dep['conflicts'])) {
+            return true;
+        }
+        $options = $this->_downloader->getOptions();
+        if (isset($dep['uri'])) {
+            return array('uri' => $dep['uri'], 'dep' => $dep);;
+        }
+        $testdep = $dep;
+        $testdep['package'] = $dep['name'];
+        if (PEAR_Downloader_Package::willDownload($testdep, $params)) {
+            $dep['package'] = $dep['name'];
+            if (!isset($options['soft'])) {
+                $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group .
+                    ' dependency "' .
+                    $this->_registry->parsedPackageNameToString($dep, true) .
+                    '", will be installed');
+            }
+            return false;
+        }
+        $options = $this->_downloader->getOptions();
+        PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+        if ($this->_explicitState) {
+            $pname['state'] = $this->_explicitState;
+        }
+        $url =
+            $this->_downloader->_getDepPackageDownloadUrl($dep, $pname);
+        if (PEAR::isError($url)) {
+            PEAR::popErrorHandling();
+            return $url;
+        }
+        $dep['package'] = $dep['name'];
+        $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params, $group == 'optional' &&
+            !isset($options['alldeps']));
+        PEAR::popErrorHandling();
+        if (PEAR::isError($ret)) {
+            if (!isset($options['soft'])) {
+                $this->_downloader->log(0, $ret->getMessage());
+            }
+            return false;
+        } else {
+            // check to see if a dep is already installed and is the same or newer
+            if (!isset($dep['min']) && !isset($dep['max']) && !isset($dep['recommended'])) {
+                $oper = 'has';
+            } else {
+                $oper = 'gt';
+            }
+            // do not try to move this before getDepPackageDownloadURL
+            // we can't determine whether upgrade is necessary until we know what
+            // version would be downloaded
+            if (!isset($options['force']) && $this->isInstalled($ret, $oper)) {
+                $version = $this->_registry->packageInfo($dep['name'], 'version',
+                    $dep['channel']);
+                $dep['package'] = $dep['name'];
+                if (!isset($options['soft'])) {
+                    $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group .
+                        ' dependency "' .
+                    $this->_registry->parsedPackageNameToString($dep, true) .
+                        '" version ' . $url['version'] . ', already installed as version ' .
+                        $version);
+                }
+                return false;
+            }
+        }
+        if (isset($dep['nodefault'])) {
+            $ret['nodefault'] = true;
+        }
+        return $ret;
+    }
+
+    function _detect1($deps, $pname, $options, $params)
+    {
+        $this->_downloadDeps = array();
+        $skipnames = array();
+        foreach ($deps as $dep) {
+            $nodownload = false;
+            if ($dep['type'] == 'pkg') {
+                $dep['channel'] = 'pear.php.net';
+                $dep['package'] = $dep['name'];
+                switch ($dep['rel']) {
+                    case 'not' :
+                        continue 2;
+                    case 'ge' :
+                    case 'eq' :
+                    case 'gt' :
+                    case 'has' :
+                        $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
+                            'required' :
+                            'optional';
+                        if (PEAR_Downloader_Package::willDownload($dep, $params)) {
+                            $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group
+                                . ' dependency "' .
+                                $this->_registry->parsedPackageNameToString($dep, true) .
+                                '", will be installed');
+                            continue 2;
+                        }
+                        $fakedp = new PEAR_PackageFile_v1;
+                        $fakedp->setPackage($dep['name']);
+                        // skip internet check if we are not upgrading (bug #5810)
+                        if (!isset($options['upgrade']) && $this->isInstalled(
+                              $fakedp, $dep['rel'])) {
+                            $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group
+                                . ' dependency "' .
+                                $this->_registry->parsedPackageNameToString($dep, true) .
+                                '", is already installed');
+                            continue 2;
+                        }
+                }
+                PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+                if ($this->_explicitState) {
+                    $pname['state'] = $this->_explicitState;
+                }
+                $url =
+                    $this->_downloader->_getDepPackageDownloadUrl($dep, $pname);
+                $chan = 'pear.php.net';
+                if (PEAR::isError($url)) {
+                    // check to see if this is a pecl package that has jumped
+                    // from pear.php.net to pecl.php.net channel
+                    if (!class_exists('PEAR_Dependency2')) {
+                        require_once 'PEAR/Dependency2.php';
+                    }
+                    $newdep = PEAR_Dependency2::normalizeDep($dep);
+                    $newdep = $newdep[0];
+                    $newdep['channel'] = 'pecl.php.net';
+                    $chan = 'pecl.php.net';
+                    $url =
+                        $this->_downloader->_getDepPackageDownloadUrl($newdep, $pname);
+                    $obj = &$this->_registry->getPackage($dep['name']);
+                    if (PEAR::isError($url)) {
+                        PEAR::popErrorHandling();
+                        if ($obj !== null && $this->isInstalled($obj, $dep['rel'])) {
+                            $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
+                                'required' :
+                                'optional';
+                            $dep['package'] = $dep['name'];
+                            if (!isset($options['soft'])) {
+                                $this->_downloader->log(3, $this->getShortName() .
+                                    ': Skipping ' . $group . ' dependency "' .
+                                    $this->_registry->parsedPackageNameToString($dep, true) .
+                                    '", already installed as version ' . $obj->getVersion());
+                            }
+                            if (@$skipnames[count($skipnames) - 1] ==
+                                  $this->_registry->parsedPackageNameToString($dep, true)) {
+                                array_pop($skipnames);
+                            }
+                            continue;
+                        } else {
+                            if (isset($dep['optional']) && $dep['optional'] == 'yes') {
+                                $this->_downloader->log(2, $this->getShortName() .
+                                    ': Skipping ' . $group
+                                    . ' dependency "' .
+                                    $this->_registry->parsedPackageNameToString($dep, true) .
+                                    '", no releases exist');
+                                continue;
+                            } else {
+                                return $url;
+                            }
+                        }
+                    }
+                }
+                PEAR::popErrorHandling();
+                if (!isset($options['alldeps'])) {
+                    if (isset($dep['optional']) && $dep['optional'] == 'yes') {
+                        if (!isset($options['soft'])) {
+                            $this->_downloader->log(3, 'Notice: package "' .
+                                $this->getShortName() .
+                                '" optional dependency "' .
+                                $this->_registry->parsedPackageNameToString(
+                                    array('channel' => $chan, 'package' =>
+                                    $dep['name']), true) .
+                                '" will not be automatically downloaded');
+                        }
+                        $skipnames[] = $this->_registry->parsedPackageNameToString(
+                                array('channel' => $chan, 'package' =>
+                                $dep['name']), true);
+                        $nodownload = true;
+                    }
+                }
+                if (!isset($options['alldeps']) && !isset($options['onlyreqdeps'])) {
+                    if (!isset($dep['optional']) || $dep['optional'] == 'no') {
+                        if (!isset($options['soft'])) {
+                            $this->_downloader->log(3, 'Notice: package "' .
+                                $this->getShortName() .
+                                '" required dependency "' .
+                                $this->_registry->parsedPackageNameToString(
+                                    array('channel' => $chan, 'package' =>
+                                    $dep['name']), true) .
+                                '" will not be automatically downloaded');
+                        }
+                        $skipnames[] = $this->_registry->parsedPackageNameToString(
+                                array('channel' => $chan, 'package' =>
+                                $dep['name']), true);
+                        $nodownload = true;
+                    }
+                }
+                // check to see if a dep is already installed
+                // do not try to move this before getDepPackageDownloadURL
+                // we can't determine whether upgrade is necessary until we know what
+                // version would be downloaded
+                if (!isset($options['force']) && $this->isInstalled(
+                        $url, $dep['rel'])) {
+                    $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
+                        'required' :
+                        'optional';
+                    $dep['package'] = $dep['name'];
+                    if (isset($newdep)) {
+                        $version = $this->_registry->packageInfo($newdep['name'], 'version',
+                            $newdep['channel']);
+                    } else {
+                        $version = $this->_registry->packageInfo($dep['name'], 'version');
+                    }
+                    $dep['version'] = $url['version'];
+                    if (!isset($options['soft'])) {
+                        $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group .
+                            ' dependency "' .
+                            $this->_registry->parsedPackageNameToString($dep, true) .
+                            '", already installed as version ' . $version);
+                    }
+                    if (@$skipnames[count($skipnames) - 1] ==
+                          $this->_registry->parsedPackageNameToString($dep, true)) {
+                        array_pop($skipnames);
+                    }
+                    continue;
+                }
+                if ($nodownload) {
+                    continue;
+                }
+                PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+                if (isset($newdep)) {
+                    $dep = $newdep;
+                }
+                $dep['package'] = $dep['name'];
+                $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params,
+                    isset($dep['optional']) && $dep['optional'] == 'yes' &&
+                    !isset($options['alldeps']));
+                PEAR::popErrorHandling();
+                if (PEAR::isError($ret)) {
+                    if (!isset($options['soft'])) {
+                        $this->_downloader->log(0, $ret->getMessage());
+                    }
+                    continue;
+                }
+                $this->_downloadDeps[] = $ret;
+            }
+        }
+        if (count($skipnames)) {
+            if (!isset($options['soft'])) {
+                $this->_downloader->log(1, 'Did not download dependencies: ' .
+                    implode(', ', $skipnames) .
+                    ', use --alldeps or --onlyreqdeps to download automatically');
+            }
+        }
+    }
+
+    function setDownloadURL($pkg)
+    {
+        $this->_downloadURL = $pkg;
+    }
+
+    /**
+     * Set the package.xml object for this downloaded package
+     *
+     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 $pkg
+     */
+    function setPackageFile(&$pkg)
+    {
+        $this->_packagefile = &$pkg;
+    }
+
+    function getShortName()
+    {
+        return $this->_registry->parsedPackageNameToString(array('channel' => $this->getChannel(),
+            'package' => $this->getPackage()), true);
+    }
+
+    function getParsedPackage()
+    {   
+        if (isset($this->_packagefile) || isset($this->_parsedname)) {
+            return array('channel' => $this->getChannel(),
+                'package' => $this->getPackage(),
+                'version' => $this->getVersion());
+        }
+        return false;
+    }
+
+    function getDownloadURL()
+    {
+        return $this->_downloadURL;
+    }
+
+    function canDefault()
+    {
+        if (isset($this->_downloadURL)) {
+            if (isset($this->_downloadURL['nodefault'])) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    function getPackage()
+    {
+        if (isset($this->_packagefile)) {
+            return $this->_packagefile->getPackage();
+        } elseif (isset($this->_downloadURL['info'])) {
+            return $this->_downloadURL['info']->getPackage();
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+     */
+    function isSubpackage(&$pf)
+    {
+        if (isset($this->_packagefile)) {
+            return $this->_packagefile->isSubpackage($pf);
+        } elseif (isset($this->_downloadURL['info'])) {
+            return $this->_downloadURL['info']->isSubpackage($pf);
+        } else {
+            return false;
+        }
+    }
+
+    function getPackageType()
+    {
+        if (isset($this->_packagefile)) {
+            return $this->_packagefile->getPackageType();
+        } elseif (isset($this->_downloadURL['info'])) {
+            return $this->_downloadURL['info']->getPackageType();
+        } else {
+            return false;
+        }
+    }
+
+    function isBundle()
+    {
+        if (isset($this->_packagefile)) {
+            return $this->_packagefile->getPackageType() == 'bundle';
+        } else {
+            return false;
+        }
+    }
+
+    function getPackageXmlVersion()
+    {
+        if (isset($this->_packagefile)) {
+            return $this->_packagefile->getPackagexmlVersion();
+        } elseif (isset($this->_downloadURL['info'])) {
+            return $this->_downloadURL['info']->getPackagexmlVersion();
+        } else {
+            return '1.0';
+        }
+    }
+
+    function getChannel()
+    {
+        if (isset($this->_packagefile)) {
+            return $this->_packagefile->getChannel();
+        } elseif (isset($this->_downloadURL['info'])) {
+            return $this->_downloadURL['info']->getChannel();
+        } else {
+            return false;
+        }
+    }
+
+    function getURI()
+    {
+        if (isset($this->_packagefile)) {
+            return $this->_packagefile->getURI();
+        } elseif (isset($this->_downloadURL['info'])) {
+            return $this->_downloadURL['info']->getURI();
+        } else {
+            return false;
+        }
+    }
+
+    function getVersion()
+    {
+        if (isset($this->_packagefile)) {
+            return $this->_packagefile->getVersion();
+        } elseif (isset($this->_downloadURL['version'])) {
+            return $this->_downloadURL['version'];
+        } else {
+            return false;
+        }
+    }
+
+    function isCompatible($pf)
+    {
+        if (isset($this->_packagefile)) {
+            return $this->_packagefile->isCompatible($pf);
+        } elseif (isset($this->_downloadURL['info'])) {
+            return $this->_downloadURL['info']->isCompatible($pf);
+        } else {
+            return true;
+        }
+    }
+
+    function setGroup($group)
+    {
+        $this->_parsedname['group'] = $group;
+    }
+
+    function getGroup()
+    {
+        if (isset($this->_parsedname['group'])) {
+            return $this->_parsedname['group'];
+        } else {
+            return '';
+        }
+    }
+
+    function isExtension($name)
+    {
+        if (isset($this->_packagefile)) {
+            return $this->_packagefile->isExtension($name);
+        } elseif (isset($this->_downloadURL['info'])) {
+            return $this->_downloadURL['info']->getProvidesExtension() == $name;
+        } else {
+            return false;
+        }
+    }
+
+    function getDeps()
+    {
+        if (isset($this->_packagefile)) {
+            if ($this->_packagefile->getPackagexmlVersion() == '2.0') {
+                return $this->_packagefile->getDeps(true);
+            } else {
+                return $this->_packagefile->getDeps();
+            }
+        } elseif (isset($this->_downloadURL['info'])) {
+            if ($this->_downloadURL['info']->getPackagexmlVersion() == '2.0') {
+                return $this->_downloadURL['info']->getDeps(true);
+            } else {
+                return $this->_downloadURL['info']->getDeps();
+            }
+        } else {
+            return array();
+        }
+    }
+
+    /**
+     * @param array Parsed array from {@link PEAR_Registry::parsePackageName()} or a dependency
+     *                     returned from getDepDownloadURL()
+     */
+    function isEqual($param)
+    {
+        if (is_object($param)) {
+            $channel = $param->getChannel();
+            $package = $param->getPackage();
+            if ($param->getURI()) {
+                $param = array(
+                    'channel' => $param->getChannel(),
+                    'package' => $param->getPackage(),
+                    'version' => $param->getVersion(),
+                    'uri' => $param->getURI(),
+                );
+            } else {
+                $param = array(
+                    'channel' => $param->getChannel(),
+                    'package' => $param->getPackage(),
+                    'version' => $param->getVersion(),
+                );
+            }
+        } else {
+            if (isset($param['uri'])) {
+                $param['channel'] = '__uri';
+                $param['package'] = $param['dep']['name'];
+            }
+            $package = isset($param['package']) ? $param['package'] :
+                $param['info']->getPackage();
+            $channel = isset($param['channel']) ? $param['channel'] :
+                $param['info']->getChannel();
+            if (isset($param['rel'])) {
+                if (!class_exists('PEAR_Dependency2')) {
+                    require_once 'PEAR/Dependency2.php';
+                }
+                $newdep = PEAR_Dependency2::normalizeDep($param);
+                $newdep = $newdep[0];
+            } elseif (isset($param['min'])) {
+                $newdep = $param;
+            }
+        }
+        if (isset($newdep)) {
+            if (!isset($newdep['min'])) {
+                $newdep['min'] = '0';
+            }
+            if (!isset($newdep['max'])) {
+                $newdep['max'] = '100000000000000000000';
+            }
+            // use magic to support pecl packages suddenly jumping to the pecl channel
+            // we need to support both dependency possibilities
+            if ($channel == 'pear.php.net' && $this->getChannel() == 'pecl.php.net') {
+                if ($package == $this->getPackage()) {
+                    $channel = 'pecl.php.net';
+                }
+            }
+            if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') {
+                if ($package == $this->getPackage()) {
+                    $channel = 'pear.php.net';
+                }
+            }
+            return (strtolower($package) == strtolower($this->getPackage()) &&
+                $channel == $this->getChannel() &&
+                version_compare($newdep['min'], $this->getVersion(), '<=') &&
+                version_compare($newdep['max'], $this->getVersion(), '>='));
+        }
+        // use magic to support pecl packages suddenly jumping to the pecl channel
+        if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') {
+            if (strtolower($package) == strtolower($this->getPackage())) {
+                $channel = 'pear.php.net';
+            }
+        }
+        if (isset($param['version'])) {
+            return (strtolower($package) == strtolower($this->getPackage()) &&
+                $channel == $this->getChannel() &&
+                $param['version'] == $this->getVersion());
+        } else {
+            return strtolower($package) == strtolower($this->getPackage()) &&
+                $channel == $this->getChannel();
+        }
+    }
+
+    function isInstalled($dep, $oper = '==')
+    {
+        if (!$dep) {
+            return false;
+        }
+        if ($oper != 'ge' && $oper != 'gt' && $oper != 'has' && $oper != '==') {
+            return false;
+        }
+        if (is_object($dep)) {
+            $package = $dep->getPackage();
+            $channel = $dep->getChannel();
+            if ($dep->getURI()) {
+                $dep = array(
+                    'uri' => $dep->getURI(),
+                    'version' => $dep->getVersion(),
+                );
+            } else {
+                $dep = array(
+                    'version' => $dep->getVersion(),
+                );
+            }
+        } else {
+            if (isset($dep['uri'])) {
+                $channel = '__uri';
+                $package = $dep['dep']['name'];
+            } else {
+                $channel = $dep['info']->getChannel();
+                $package = $dep['info']->getPackage();
+            }
+        }
+        $options = $this->_downloader->getOptions();
+        $test = $this->_registry->packageExists($package, $channel);
+        if (!$test && $channel == 'pecl.php.net') {
+            // do magic to allow upgrading from old pecl packages to new ones
+            $test = $this->_registry->packageExists($package, 'pear.php.net');
+            $channel = 'pear.php.net';
+        }
+        if ($test) {
+            if (isset($dep['uri'])) {
+                if ($this->_registry->packageInfo($package, 'uri', '__uri') == $dep['uri']) {
+                    return true;
+                }
+            }
+            if (isset($options['upgrade'])) {
+                if ($oper == 'has') {
+                    if (version_compare($this->_registry->packageInfo(
+                          $package, 'version', $channel),
+                          $dep['version'], '>=')) {
+                        return true;
+                    } else {
+                        return false;
+                    }
+                } else {
+                    if (version_compare($this->_registry->packageInfo(
+                          $package, 'version', $channel),
+                          $dep['version'], '>=')) {
+                        return true;
+                    }
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * @param array
+     * @static
+     */
+    function removeDuplicates(&$params)
+    {
+        $pnames = array();
+        foreach ($params as $i => $param) {
+            if (!$param) {
+                continue;
+            }
+            if ($param->getPackage()) {
+                $pnames[$i] = $param->getChannel() . '/' .
+                    $param->getPackage() . '-' . $param->getVersion() . '#' . $param->getGroup();
+            }
+        }
+        $pnames = array_unique($pnames);
+        $unset = array_diff(array_keys($params), array_keys($pnames));
+        $testp = array_flip($pnames);
+        foreach ($params as $i => $param) {
+            if (!$param) {
+                $unset[] = $i;
+                continue;
+            }
+            if (!is_a($param, 'PEAR_Downloader_Package')) {
+                $unset[] = $i;
+                continue;
+            }
+            if (!isset($testp[$param->getChannel() . '/' . $param->getPackage() . '-' .
+                  $param->getVersion() . '#' . $param->getGroup()])) {
+                $unset[] = $i;
+            }
+        }
+        foreach ($unset as $i) {
+            unset($params[$i]);
+        }
+        $ret = array();
+        foreach ($params as $i => $param) {
+            $ret[] = &$params[$i];
+        }
+        $params = array();
+        foreach ($ret as $i => $param) {
+            $params[] = &$ret[$i];
+        }
+    }
+
+    function explicitState()
+    {
+        return $this->_explicitState;
+    }
+
+    function setExplicitState($s)
+    {
+        $this->_explicitState = $s;
+    }
+
+    /**
+     * @static
+     */
+    function mergeDependencies(&$params)
+    {
+        $newparams = array();
+        $bundles = array();
+        foreach ($params as $i => $param) {
+            if (!$param->isBundle()) {
+                continue;
+            }
+            $bundles[] = $i;
+            $pf = &$param->getPackageFile();
+            $newdeps = array();
+            $contents = $pf->getBundledPackages();
+            if (!is_array($contents)) {
+                $contents = array($contents);
+            }
+            foreach ($contents as $file) {
+                $filecontents = $pf->getFileContents($file);
+                $dl = &$param->getDownloader();
+                $options = $dl->getOptions();
+                $fp = @fopen($dl->getDownloadDir() . DIRECTORY_SEPARATOR . $file, 'wb');
+                if (!$fp) {
+                    continue;
+                }
+                fwrite($fp, $filecontents, strlen($filecontents));
+                fclose($fp);
+                if ($s = $params[$i]->explicitState()) {
+                    $obj->setExplicitState($s);
+                }
+                $obj = &new PEAR_Downloader_Package($params[$i]->getDownloader());
+                PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+                $e = $obj->_fromFile($a = $dl->getDownloadDir() . DIRECTORY_SEPARATOR . $file);
+                PEAR::popErrorHandling();
+                if (PEAR::isError($e)) {
+                    if (!isset($options['soft'])) {
+                        $dl->log(0, $e->getMessage());
+                    }
+                    continue;
+                }
+                $j = &$obj;
+                if (!PEAR_Downloader_Package::willDownload($j,
+                      array_merge($params, $newparams)) && !$param->isInstalled($j)) {
+                    $newparams[] = &$j;
+                }
+            }
+        }
+        foreach ($bundles as $i) {
+            unset($params[$i]); // remove bundles - only their contents matter for installation
+        }
+        PEAR_Downloader_Package::removeDuplicates($params); // strip any unset indices
+        if (count($newparams)) { // add in bundled packages for install
+            foreach ($newparams as $i => $unused) {
+                $params[] = &$newparams[$i];
+            }
+            $newparams = array();
+        }
+        foreach ($params as $i => $param) {
+            $newdeps = array();
+            foreach ($param->_downloadDeps as $dep) {
+                if (!PEAR_Downloader_Package::willDownload($dep,
+                      array_merge($params, $newparams)) && !$param->isInstalled($dep)) {
+                    $newdeps[] = $dep;
+                } else {
+                    // detect versioning conflicts here
+                }
+            }
+            // convert the dependencies into PEAR_Downloader_Package objects for the next time
+            // around
+            $params[$i]->_downloadDeps = array();
+            foreach ($newdeps as $dep) {
+                $obj = &new PEAR_Downloader_Package($params[$i]->getDownloader());
+                if ($s = $params[$i]->explicitState()) {
+                    $obj->setExplicitState($s);
+                }
+                PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+                $e = $obj->fromDepURL($dep);
+                PEAR::popErrorHandling();
+                if (PEAR::isError($e)) {
+                    if (!isset($options['soft'])) {
+                        $obj->_downloader->log(0, $e->getMessage());
+                    }
+                    continue;
+                }
+                $e = $obj->detectDependencies($params);
+                if (PEAR::isError($e)) {
+                    if (!isset($options['soft'])) {
+                        $obj->_downloader->log(0, $e->getMessage());
+                    }
+                }
+                $j = &$obj;
+                $newparams[] = &$j;
+            }
+        }
+        if (count($newparams)) {
+            foreach ($newparams as $i => $unused) {
+                $params[] = &$newparams[$i];
+            }
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+
+    /**
+     * @static
+     */
+    function willDownload($param, $params)
+    {
+        if (!is_array($params)) {
+            return false;
+        }
+        foreach ($params as $obj) {
+            if ($obj->isEqual($param)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * For simpler unit-testing
+     * @param PEAR_Config
+     * @param int
+     * @param string
+     */
+    function &getPackagefileObject(&$c, $d, $t = false)
+    {
+        $a = &new PEAR_PackageFile($c, $d, $t);
+        return $a;
+    }
+
+
+    /**
+     * This will retrieve from a local file if possible, and parse out
+     * a group name as well.  The original parameter will be modified to reflect this.
+     * @param string|array can be a parsed package name as well
+     * @access private
+     */
+    function _fromFile(&$param)
+    {
+        if (is_string($param) && !@is_file($param)) {
+            $test = explode('#', $param);
+            $group = array_pop($test);
+            if (@is_file(implode('#', $test))) {
+                $this->setGroup($group);
+                $param = implode('#', $test);
+                $this->_explicitGroup = true;
+            }
+        }
+        if (@is_file($param)) {
+            $this->_type = 'local';
+            $options = $this->_downloader->getOptions();
+            if (isset($options['downloadonly'])) {
+                $pkg = &$this->getPackagefileObject($this->_config,
+                    $this->_downloader->_debug);
+            } else {
+                $pkg = &$this->getPackagefileObject($this->_config,
+                    $this->_downloader->_debug, $this->_downloader->getDownloadDir());
+            }
+            PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+            $pf = &$pkg->fromAnyFile($param, PEAR_VALIDATE_INSTALLING);
+            PEAR::popErrorHandling();
+            if (PEAR::isError($pf)) {
+                $this->_valid = false;
+                return $pf;
+            }
+            $this->_packagefile = &$pf;
+            if (!$this->getGroup()) {
+                $this->setGroup('default'); // install the default dependency group
+            }
+            return $this->_valid = true;
+        }
+        return $this->_valid = false;
+    }
+
+    function _fromUrl($param, $saveparam = '')
+    {
+        if (!is_array($param) &&
+              (preg_match('#^(http|ftp)://#', $param))) {
+            $options = $this->_downloader->getOptions();
+            $this->_type = 'url';
+            $callback = $this->_downloader->ui ?
+                array(&$this->_downloader, '_downloadCallback') : null;
+            $this->_downloader->pushErrorHandling(PEAR_ERROR_RETURN);
+            $file = $this->_downloader->downloadHttp($param, $this->_downloader->ui,
+                $this->_downloader->getDownloadDir(), $callback);
+            $this->_downloader->popErrorHandling();
+            if (PEAR::isError($file)) {
+                if (!empty($saveparam)) {
+                    $saveparam = ", cannot download \"$saveparam\"";
+                }
+                $err = PEAR::raiseError('Could not download from "' . $param .
+                    '"' . $saveparam);
+                    return $err;
+            }
+            if ($this->_rawpackagefile) {
+                require_once 'Archive/Tar.php';
+                $tar = &new Archive_Tar($file);
+                $packagexml = $tar->extractInString('package2.xml');
+                if (!$packagexml) {
+                    $packagexml = $tar->extractInString('package.xml');
+                }
+                if (str_replace(array("\n", "\r"), array('',''), $packagexml) !=
+                      str_replace(array("\n", "\r"), array('',''), $this->_rawpackagefile)) {
+                    if ($this->getChannel() == 'pear.php.net') {
+                        // be more lax for the existing PEAR packages that have not-ok
+                        // characters in their package.xml
+                        $this->_downloader->log(0, 'CRITICAL WARNING: The "' .
+                            $this->getPackage() . '" package has invalid characters in its ' .
+                            'package.xml.  The next version of PEAR may not be able to install ' .
+                            'this package for security reasons.  Please open a bug report at ' .
+                            'http://pear.php.net/package/' . $this->getPackage() . '/bugs');
+                    } else {
+                        return PEAR::raiseError('CRITICAL ERROR: package.xml downloaded does ' .
+                            'not match value returned from xml-rpc');
+                    }
+                }
+            }
+            // whew, download worked!
+            if (isset($options['downloadonly'])) {
+                $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->debug);
+            } else {
+                $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->debug,
+                    $this->_downloader->getDownloadDir());
+            }
+            PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+            $pf = &$pkg->fromAnyFile($file, PEAR_VALIDATE_INSTALLING);
+            PEAR::popErrorHandling();
+            if (PEAR::isError($pf)) {
+                if (is_array($pf->getUserInfo())) {
+                    foreach ($pf->getUserInfo() as $err) {
+                        if (is_array($err)) {
+                            $err = $err['message'];
+                        }
+                        if (!isset($options['soft'])) {
+                            $this->_downloader->log(0, "Validation Error: $err");
+                        }
+                    }
+                }
+                if (!isset($options['soft'])) {
+                    $this->_downloader->log(0, $pf->getMessage());
+                }
+                $err = PEAR::raiseError('Download of "' . ($saveparam ? $saveparam :
+                    $param) . '" succeeded, but it is not a valid package archive');
+                $this->_valid = false;
+                return $err;
+            }
+            $this->_packagefile = &$pf;
+            $this->setGroup('default'); // install the default dependency group
+            return $this->_valid = true;
+        }
+        return $this->_valid = false;
+    }
+
+    /**
+     *
+     * @param string|array pass in an array of format
+     *                     array(
+     *                      'package' => 'pname',
+     *                     ['channel' => 'channame',]
+     *                     ['version' => 'version',]
+     *                     ['state' => 'state',])
+     *                     or a string of format [channame/]pname[-version|-state]
+     */
+    function _fromString($param)
+    {
+        $options = $this->_downloader->getOptions();
+        PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+        $pname = $this->_registry->parsePackageName($param,
+            $this->_config->get('default_channel'));
+        PEAR::popErrorHandling();
+        if (PEAR::isError($pname)) {
+            if ($pname->getCode() == 'invalid') {
+                $this->_valid = false;
+                return false;
+            }
+            if ($pname->getCode() == 'channel') {
+                $parsed = $pname->getUserInfo();
+                if ($this->_downloader->discover($parsed['channel'])) {
+                    if ($this->_config->get('auto_discover')) {
+                        PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+                        $pname = $this->_registry->parsePackageName($param,
+                            $this->_config->get('default_channel'));
+                        PEAR::popErrorHandling();
+                    } else {
+                        if (!isset($options['soft'])) {
+                            $this->_downloader->log(0, 'Channel "' . $parsed['channel'] .
+                                '" is not initialized, use ' .
+                                '"pear channel-discover ' . $parsed['channel'] . '" to initialize' .
+                                'or pear config-set auto_discover 1');
+                        }
+                    }
+                }
+                if (PEAR::isError($pname)) {
+                    if (!isset($options['soft'])) {
+                        $this->_downloader->log(0, $pname->getMessage());
+                    }
+                    if (is_array($param)) {
+                        $param = $this->_registry->parsedPackageNameToString($param);
+                    }
+                    $err = PEAR::raiseError('invalid package name/package file "' .
+                        $param . '"');
+                    $this->_valid = false;
+                    return $err;
+                }
+            } else {
+                if (!isset($options['soft'])) {
+                    $this->_downloader->log(0, $pname->getMessage());
+                }
+                $err = PEAR::raiseError('invalid package name/package file "' .
+                    $param . '"');
+                $this->_valid = false;
+                return $err;
+            }
+        }
+        if (!isset($this->_type)) {
+            $this->_type = 'xmlrpc';
+        }
+        $this->_parsedname = $pname;
+        if (isset($pname['state'])) {
+            $this->_explicitState = $pname['state'];
+        } else {
+            $this->_explicitState = false;
+        }
+        if (isset($pname['group'])) {
+            $this->_explicitGroup = true;
+        } else {
+            $this->_explicitGroup = false;
+        }
+        $info = $this->_downloader->_getPackageDownloadUrl($pname);
+        if (PEAR::isError($info)) {
+            if ($pname['channel'] == 'pear.php.net') {
+                // try pecl
+                $pname['channel'] = 'pecl.php.net';
+                if ($test = $this->_downloader->_getPackageDownloadUrl($pname)) {
+                    if (!PEAR::isError($test)) {
+                        $info = PEAR::raiseError($info->getMessage() . ' - package ' .
+                            $this->_registry->parsedPackageNameToString($pname, true) .
+                            ' can be installed with "pecl install ' . $pname['package'] .
+                            '"');
+                    }
+                }
+            }
+            return $info;
+        }
+        $this->_rawpackagefile = $info['raw'];
+        $ret = $this->_analyzeDownloadURL($info, $param, $pname);
+        if (PEAR::isError($ret)) {
+            return $ret;
+        }
+        if ($ret) {
+            $this->_downloadURL = $ret;
+            return $this->_valid = (bool) $ret;
+        }
+    }
+
+    /**
+     * @param array output of package.getDownloadURL
+     * @param string|array|object information for detecting packages to be downloaded, and
+     *                            for errors
+     * @param array name information of the package
+     * @param array|null packages to be downloaded
+     * @param bool is this an optional dependency?
+     * @access private
+     */
+    function _analyzeDownloadURL($info, $param, $pname, $params = null, $optional = false)
+    {
+        if (!is_string($param) && PEAR_Downloader_Package::willDownload($param, $params)) {
+            return false;
+        }
+        if (!$info) {
+            if (!is_string($param)) {
+                $saveparam = ", cannot download \"$param\"";
+            } else {
+                $saveparam = '';
+            }
+            // no releases exist
+            return PEAR::raiseError('No releases for package "' .
+                $this->_registry->parsedPackageNameToString($pname, true) . '" exist' . $saveparam);
+        }
+        if (strtolower($info['info']->getChannel()) != strtolower($pname['channel'])) {
+            $err = false;
+            if ($pname['channel'] == 'pecl.php.net') {
+                if ($info['info']->getChannel() != 'pear.php.net') {
+                    $err = true;
+                }
+            } elseif ($info['info']->getChannel() == 'pecl.php.net') {
+                if ($pname['channel'] != 'pear.php.net') {
+                    $err = true;
+                }
+            } else {
+                $err = true;
+            }
+            if ($err) {
+                return PEAR::raiseError('SECURITY ERROR: package in channel "' . $pname['channel'] .
+                    '" retrieved another channel\'s name for download! ("' .
+                    $info['info']->getChannel() . '")');
+            }
+        }
+        if (!isset($info['url'])) {
+            $instead =  ', will instead download version ' . $info['version'] .
+                        ', stability "' . $info['info']->getState() . '"';
+            // releases exist, but we failed to get any
+            if (isset($this->_downloader->_options['force'])) {
+                if (isset($pname['version'])) {
+                    $vs = ', version "' . $pname['version'] . '"';
+                } elseif (isset($pname['state'])) {
+                    $vs = ', stability "' . $pname['state'] . '"';
+                } elseif ($param == 'dependency') {
+                    if (!class_exists('PEAR_Common')) {
+                        require_once 'PEAR/Common.php';
+                    }
+                    if (!in_array($info['info']->getState(),
+                          PEAR_Common::betterStates($this->_config->get('preferred_state'), true))) {
+                        if ($optional) {
+                            // don't spit out confusing error message
+                            return $this->_downloader->_getPackageDownloadUrl(
+                                array('package' => $pname['package'],
+                                      'channel' => $pname['channel'],
+                                      'version' => $info['version']));
+                        }
+                        $vs = ' within preferred state "' . $this->_config->get('preferred_state') .
+                            '"';
+                    } else {
+                        if (!class_exists('PEAR_Dependency2')) {
+                            require_once 'PEAR/Dependency2.php';
+                        }
+                        if ($optional) {
+                            // don't spit out confusing error message
+                            return $this->_downloader->_getPackageDownloadUrl(
+                                array('package' => $pname['package'],
+                                      'channel' => $pname['channel'],
+                                      'version' => $info['version']));
+                        }
+                        $vs = PEAR_Dependency2::_getExtraString($pname);
+                        $instead = '';
+                    }
+                } else {
+                    $vs = ' within preferred state "' . $this->_config->get(
+                        'preferred_state') . '"';
+                }
+                if (!isset($options['soft'])) {
+                    $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] .
+                        '/' . $pname['package'] . $vs . $instead);
+                }
+                // download the latest release
+                return $this->_downloader->_getPackageDownloadUrl(
+                    array('package' => $pname['package'],
+                          'channel' => $pname['channel'],
+                          'version' => $info['version']));
+            } else {
+                // construct helpful error message
+                if (isset($pname['version'])) {
+                    $vs = ', version "' . $pname['version'] . '"';
+                } elseif (isset($pname['state'])) {
+                    $vs = ', stability "' . $pname['state'] . '"';
+                } elseif ($param == 'dependency') {
+                    if (!class_exists('PEAR_Common')) {
+                        require_once 'PEAR/Common.php';
+                    }
+                    if (!in_array($info['info']->getState(),
+                          PEAR_Common::betterStates($this->_config->get('preferred_state'), true))) {
+                        if ($optional) {
+                            // don't spit out confusing error message, and don't die on
+                            // optional dep failure!
+                            return $this->_downloader->_getPackageDownloadUrl(
+                                array('package' => $pname['package'],
+                                      'channel' => $pname['channel'],
+                                      'version' => $info['version']));
+                        }
+                        $vs = ' within preferred state "' . $this->_config->get('preferred_state') .
+                            '"';
+                    } else {
+                        if (!class_exists('PEAR_Dependency2')) {
+                            require_once 'PEAR/Dependency2.php';
+                        }
+                        if ($optional) {
+                            // don't spit out confusing error message, and don't die on
+                            // optional dep failure!
+                            return $this->_downloader->_getPackageDownloadUrl(
+                                array('package' => $pname['package'],
+                                      'channel' => $pname['channel'],
+                                      'version' => $info['version']));
+                        }
+                        $vs = PEAR_Dependency2::_getExtraString($pname);
+                    }
+                } else {
+                    $vs = ' within preferred state "' . $this->_downloader->config->get(
+                        'preferred_state') . '"';
+                }
+                $err = PEAR::raiseError(
+                    'Failed to download ' . $this->_registry->parsedPackageNameToString(
+                        array('channel' => $pname['channel'], 'package' => $pname['package']),
+                            true)
+                     . $vs .
+                    ', latest release is version ' . $info['version'] .
+                    ', stability "' . $info['info']->getState() . '", use "' .
+                    $this->_registry->parsedPackageNameToString(
+                        array('channel' => $pname['channel'], 'package' => $pname['package'],
+                        'version' => $info['version'])) . '" to install');
+                return $err;
+            }
+        }
+        return $info;
+    }
+}
+?>
index 9ad94d738cb49015d57937fbf5ba0c5174b42af6..f8dea9d43c0cd7cb237999adb6afe848059d51c5 100644 (file)
@@ -1,24 +1,4 @@
 <?php
-//
-// +----------------------------------------------------------------------+
-// | PHP Version 5                                                        |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2004 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: Gregory Beaver <cellog@php.net>                              |
-// |                                                                      |
-// +----------------------------------------------------------------------+
-//
-// $Id$
-
 /**
  * Error Stack Implementation
  * 
  *
  * Since version PEAR1.3.2, ErrorStack no longer instantiates an exception class.  This can
  * still be done quite handily in an error callback or by manipulating the returned array
- * @author Greg Beaver <cellog@php.net>
- * @version PEAR1.3.2 (beta)
- * @package PEAR_ErrorStack
- * @category Debugging
- * @license http://www.php.net/license/3_0.txt PHP License v3.0
+ * @category   Debugging
+ * @package    PEAR_ErrorStack
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  2004-2005 Greg Beaver
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR_ErrorStack
  */
 
 /**
@@ -149,9 +131,14 @@ define('PEAR_ERRORSTACK_ERR_OBJTOSTRING', 2);
  * // local error stack
  * $local_stack = new PEAR_ErrorStack('MyPackage');
  * </code>
- * @copyright 2004 Gregory Beaver
- * @package PEAR_ErrorStack
- * @license http://www.php.net/license/3_0.txt PHP License
+ * @author     Greg Beaver <cellog@php.net>
+ * @version    @package_version@
+ * @package    PEAR_ErrorStack
+ * @category   Debugging
+ * @copyright  2004-2005 Greg Beaver
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR_ErrorStack
  */
 class PEAR_ErrorStack {
     /**
@@ -281,8 +268,10 @@ class PEAR_ErrorStack {
                 'stack class "%stackclass%" is not a valid class name (should be like PEAR_ErrorStack)',
                 false, $trace);
         }
-        return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package] =
-            &new $stackClass($package, $msgCallback, $contextCallback, $throwPEAR_Error);
+        $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package] =
+            new $stackClass($package, $msgCallback, $contextCallback, $throwPEAR_Error);
+
+        return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package];
     }
 
     /**
@@ -548,7 +537,6 @@ class PEAR_ErrorStack {
                                         array(&$this, $err));
             $err['message'] = $msg;
         }        
-        
         $push = $log = true;
         $die = false;
         // try the overriding callback first
@@ -910,10 +898,8 @@ class PEAR_ErrorStack {
         } else {
             $mainmsg = $stack->getErrorMessageTemplate($err['code']);
         }
-
         $mainmsg = str_replace('%__msg%', $err['message'], $mainmsg);
-
-        if (count($err['params']) && count($err['params'])) {
+        if (is_array($err['params']) && count($err['params'])) {
             foreach ($err['params'] as $name => $val) {
                 if (is_array($val)) {
                     // @ is needed in case $val is a multi-dimensional array
index 1e191f84ea5d6a6853c6e3e687a57d781cee14c1..4fe85d9e3933486b9577471144f05e19dd9ca622 100644 (file)
@@ -1,34 +1,33 @@
 <?php
 /* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
-// +----------------------------------------------------------------------+
-// | PEAR_Exception                                                       |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 2004 The PEAR 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 at through the world-wide-web at                           |
-// | 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: Tomas V.V.Cox <cox@idecnet.com>                             |
-// |          Hans Lellelid <hans@velum.net>                              |
-// |          Bertrand Mansion <bmansion@mamasam.com>                     |
-// |          Greg Beaver <cellog@php.net>                                |
-// +----------------------------------------------------------------------+
-//
-// $Id$
+/**
+ * PEAR_Exception
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Tomas V. V. Cox <cox@idecnet.com>
+ * @author     Hans Lellelid <hans@velum.net>
+ * @author     Bertrand Mansion <bmansion@mamasam.com>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.3.3
+ */
 
 
 /**
  * Base PEAR_Exception Class
  *
- * WARNING: This code should be considered stable, but the API is
- * subject to immediate and drastic change, so API stability is
- * at best alpha
- *
  * 1) Features:
  *
  * - Nestable exceptions (throw new PEAR_Exception($msg, $prev_exception))
  *  }
  * </code>
  *
- * @since PHP 5
- * @package PEAR
- * @version $Revision$
- * @author Tomas V.V.Cox <cox@idecnet.com>
- * @author Hans Lellelid <hans@velum.net>
- * @author Bertrand Mansion <bmansion@mamasam.com>
+ * @category   pear
+ * @package    PEAR
+ * @author     Tomas V.V.Cox <cox@idecnet.com>
+ * @author     Hans Lellelid <hans@velum.net>
+ * @author     Bertrand Mansion <bmansion@mamasam.com>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.3.3
  *
  */
 class PEAR_Exception extends Exception
@@ -128,7 +132,7 @@ class PEAR_Exception extends Exception
             }
             $this->cause = $p2;
         } else {
-        $code = null;
+            $code = null;
             $this->cause = null;
         }
         parent::__construct($message, $code);
@@ -234,13 +238,24 @@ class PEAR_Exception extends Exception
                 $cause['line'] = $trace[0]['line'];
             }
         }
+        $causes[] = $cause;
         if ($this->cause instanceof PEAR_Exception) {
             $this->cause->getCauseMessage($causes);
-        }
-        if (is_array($this->cause)) {
+        } elseif ($this->cause instanceof Exception) {
+            $causes[] = array('class'   => get_class($cause),
+                           'message' => $cause->getMessage(),
+                           'file' => $cause->getFile(),
+                           'line' => $cause->getLine());
+
+        } elseif (is_array($this->cause)) {
             foreach ($this->cause as $cause) {
                 if ($cause instanceof PEAR_Exception) {
                     $cause->getCauseMessage($causes);
+                } elseif ($cause instanceof Exception) {
+                    $causes[] = array('class'   => get_class($cause),
+                                   'message' => $cause->getMessage(),
+                                   'file' => $cause->getFile(),
+                                   'line' => $cause->getLine());
                 } elseif (is_array($cause) && isset($cause['message'])) {
                     // PEAR_ErrorStack warning
                     $causes[] = array(
@@ -288,7 +303,7 @@ class PEAR_Exception extends Exception
             return $this->toHtml();
         }
         return $this->toText();
-        }
+    }
 
     public function toHtml()
     {
@@ -333,7 +348,9 @@ class PEAR_Exception extends Exception
             }
             $html .= '(' . implode(', ',$args) . ')'
                    . '</td>'
-                   . '<td>' . $v['file'] . ':' . $v['line'] . '</td></tr>' . "\n";
+                   . '<td>' . (isset($v['file']) ? $v['file'] : 'unknown')
+                   . ':' . (isset($v['line']) ? $v['line'] : 'unknown')
+                   . '</td></tr>' . "\n";
         }
         $html .= '<tr><td align="center">' . ($k+1) . '</td>'
                . '<td>{main}</td>'
diff --git a/pear/PEAR/Frontend.php b/pear/PEAR/Frontend.php
new file mode 100644 (file)
index 0000000..c9ea58f
--- /dev/null
@@ -0,0 +1,142 @@
+<?php
+/**
+ * PEAR_Frontend, the singleton-based frontend for user input/output
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a1
+ */
+
+/**
+ * Which user interface class is being used.
+ * @var string class name
+ */
+$GLOBALS['_PEAR_FRONTEND_CLASS'] = 'PEAR_Frontend_CLI';
+
+/**
+ * Instance of $_PEAR_Command_uiclass.
+ * @var object
+ */
+$GLOBALS['_PEAR_FRONTEND_SINGLETON'] = null;
+
+/**
+ * Singleton-based frontend for PEAR user input/output
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
+ */
+class PEAR_Frontend extends PEAR
+{
+    /**
+     * Retrieve the frontend object
+     * @return PEAR_Frontend_CLI|PEAR_Frontend_Web|PEAR_Frontend_Gtk
+     * @static
+     */
+    function &singleton($type = null)
+    {
+        if ($type === null) {
+            if (!isset($GLOBALS['_PEAR_FRONTEND_SINGLETON'])) {
+                $a = false;
+                return $a;
+            }
+            return $GLOBALS['_PEAR_FRONTEND_SINGLETON'];
+        } else {
+            $a = PEAR_Frontend::setFrontendClass($type);
+            return $a;
+        }
+    }
+
+    function &setFrontendClass($uiclass)
+    {
+        if (is_object($GLOBALS['_PEAR_FRONTEND_SINGLETON']) &&
+              is_a($GLOBALS['_PEAR_FRONTEND_SINGLETON'], $uiclass)) {
+            return $GLOBALS['_PEAR_FRONTEND_SINGLETON'];
+        }
+        if (!class_exists($uiclass)) {
+            $file = str_replace('_', '/', $uiclass) . '.php';
+            if (PEAR_Frontend::isIncludeable($file)) {
+                include_once $file;
+            }
+        }
+        if (class_exists($uiclass)) {
+            $obj = &new $uiclass;
+            // quick test to see if this class implements a few of the most
+            // important frontend methods
+            if (method_exists($obj, 'userConfirm')) {
+                $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = &$obj;
+                $GLOBALS['_PEAR_FRONTEND_CLASS'] = $uiclass;
+                return $obj;
+            } else {
+                $err = PEAR::raiseError("not a frontend class: $uiclass");
+                return $err;
+            }
+        }
+        $err = PEAR::raiseError("no such class: $uiclass");
+        return $err;
+    }
+
+    /**
+     * @param string $path relative or absolute include path
+     * @return boolean
+     * @static
+     */
+    function isIncludeable($path)
+    {
+        if (file_exists($path) && is_readable($path)) {
+            return true;
+        }
+        $ipath = explode(PATH_SEPARATOR, ini_get('include_path'));
+        foreach ($ipath as $include) {
+            $test = realpath($include . DIRECTORY_SEPARATOR . $path);
+            if (!$test) { // support wrappers like phar (realpath just don't work with them)
+                $test = $include . DIRECTORY_SEPARATOR . $path;
+            }
+            if (file_exists($test) && is_readable($test)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @param PEAR_Config
+     */
+    function setConfig(&$config)
+    {
+    }
+
+    /**
+     * This can be overridden to allow session-based temporary file management
+     *
+     * By default, all files are deleted at the end of a session.  The web installer
+     * needs to be able to sustain a list over many sessions in order to support
+     * user interaction with install scripts
+     */
+    function addTempFile($file)
+    {
+        $GLOBALS['_PEAR_Common_tempfiles'][] = $file;
+    }
+
+    function log($level, $msg, $append_crlf = true)
+    {
+    }
+}
+?>
\ No newline at end of file
index 95067b024fcc6db8caa8f9f127b3e14bc9e7773e..af50657ec113958cba95ffbfbeb7362b630f7bbc 100644 (file)
@@ -1,27 +1,43 @@
 <?php
-/*
-  +----------------------------------------------------------------------+
-  | PHP Version 5                                                        |
-  +----------------------------------------------------------------------+
-  | Copyright (c) 1997-2004 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.php";
-
-class PEAR_Frontend_CLI extends PEAR
+/**
+ * PEAR_Frontend_CLI
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 0.1
+ */
+/**
+ * base class
+ */
+require_once 'PEAR/Frontend.php';
+
+/**
+ * Command-line Frontend for the PEAR Installer
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 0.1
+ */
+class PEAR_Frontend_CLI extends PEAR_Frontend
 {
     // {{{ properties
 
@@ -110,6 +126,28 @@ class PEAR_Frontend_CLI extends PEAR
     function displayFatalError($eobj)
     {
         $this->displayError($eobj);
+        if (class_exists('PEAR_Config')) {
+            $config = &PEAR_Config::singleton();
+            if ($config->get('verbose') > 5) {
+                if (function_exists('debug_print_backtrace')) {
+                    debug_print_backtrace();
+                } elseif (function_exists('debug_backtrace')) {
+                    $trace = debug_backtrace();
+                    $raised = false;
+                    foreach ($trace as $i => $frame) {
+                        if (!$raised) {
+                            if (isset($frame['class']) && strtolower($frame['class']) ==
+                                  'pear' && strtolower($frame['function']) == 'raiseerror') {
+                                $raised = true;
+                            } else {
+                                continue;
+                            }
+                        }
+                        @$this->_displayLine("#$i: $frame[class]$frame[type]$frame[function] $frame[line]");
+                    }
+                }
+            }
+        }
         exit(1);
     }
 
@@ -128,13 +166,186 @@ class PEAR_Frontend_CLI extends PEAR
     }
 
     // }}}
+
+    /**
+     * Instruct the runInstallScript method to skip a paramgroup that matches the
+     * id value passed in.
+     *
+     * This method is useful for dynamically configuring which sections of a post-install script
+     * will be run based on the user's setup, which is very useful for making flexible
+     * post-install scripts without losing the cross-Frontend ability to retrieve user input
+     * @param string
+     */
+    function skipParamgroup($id)
+    {
+        $this->_skipSections[$id] = true;
+    }
+
+    function runPostinstallScripts(&$scripts)
+    {
+        foreach ($scripts as $i => $script) {
+            $this->runInstallScript($scripts[$i]->_params, $scripts[$i]->_obj);
+        }
+    }
+
+    /**
+     * @param array $xml contents of postinstallscript tag
+     * @param object $script post-installation script
+     * @param string install|upgrade
+     */
+    function runInstallScript($xml, &$script)
+    {
+        $this->_skipSections = array();
+        if (!is_array($xml) || !isset($xml['paramgroup'])) {
+            $script->run(array(), '_default');
+        } else {
+            $completedPhases = array();
+            if (!isset($xml['paramgroup'][0])) {
+                $xml['paramgroup'] = array($xml['paramgroup']);
+            }
+            foreach ($xml['paramgroup'] as $group) {
+                if (isset($this->_skipSections[$group['id']])) {
+                    // the post-install script chose to skip this section dynamically
+                    continue;
+                }
+                if (isset($group['name'])) {
+                    $paramname = explode('::', $group['name']);
+                    if ($lastgroup['id'] != $paramname[0]) {
+                        continue;
+                    }
+                    $group['name'] = $paramname[1];
+                    if (isset($answers)) {
+                        if (isset($answers[$group['name']])) {
+                            switch ($group['conditiontype']) {
+                                case '=' :
+                                    if ($answers[$group['name']] != $group['value']) {
+                                        continue 2;
+                                    }
+                                break;
+                                case '!=' :
+                                    if ($answers[$group['name']] == $group['value']) {
+                                        continue 2;
+                                    }
+                                break;
+                                case 'preg_match' :
+                                    if (!@preg_match('/' . $group['value'] . '/',
+                                          $answers[$group['name']])) {
+                                        continue 2;
+                                    }
+                                break;
+                                default :
+                                return;
+                            }
+                        }
+                    } else {
+                        return;
+                    }
+                }
+                $lastgroup = $group;
+                if (isset($group['instructions'])) {
+                    $this->_display($group['instructions']);
+                }
+                if (!isset($group['param'][0])) {
+                    $group['param'] = array($group['param']);
+                }
+                if (isset($group['param'])) {
+                    if (method_exists($script, 'postProcessPrompts')) {
+                        $prompts = $script->postProcessPrompts($group['param'], $group['id']);
+                        if (!is_array($prompts) || count($prompts) != count($group['param'])) {
+                            $this->outputData('postinstall', 'Error: post-install script did not ' .
+                                'return proper post-processed prompts');
+                            $prompts = $group['param'];
+                        } else {
+                            foreach ($prompts as $i => $var) {
+                                if (!is_array($var) || !isset($var['prompt']) ||
+                                      !isset($var['name']) ||
+                                      ($var['name'] != $group['param'][$i]['name']) ||
+                                      ($var['type'] != $group['param'][$i]['type'])) {
+                                    $this->outputData('postinstall', 'Error: post-install script ' .
+                                        'modified the variables or prompts, severe security risk. ' .
+                                        'Will instead use the defaults from the package.xml');
+                                    $prompts = $group['param'];
+                                }
+                            }
+                        }
+                        $answers = $this->confirmDialog($prompts);
+                    } else {
+                        $answers = $this->confirmDialog($group['param']);
+                    }
+                }
+                if ((isset($answers) && $answers) || !isset($group['param'])) {
+                    if (!isset($answers)) {
+                        $answers = array();
+                    }
+                    array_unshift($completedPhases, $group['id']);
+                    if (!$script->run($answers, $group['id'])) {
+                        $script->run($completedPhases, '_undoOnError');
+                        return;
+                    }
+                } else {
+                    $script->run($completedPhases, '_undoOnError');
+                    return;
+                }
+            }
+        }
+    }
+
+    /**
+     * Ask for user input, confirm the answers and continue until the user is satisfied
+     * @param array an array of arrays, format array('name' => 'paramname', 'prompt' =>
+     *              'text to display', 'type' => 'string'[, default => 'default value'])
+     * @return array
+     */
+    function confirmDialog($params)
+    {
+        $answers = array();
+        $prompts = $types = array();
+        foreach ($params as $param) {
+            $prompts[$param['name']] = $param['prompt'];
+            $types[$param['name']] = $param['type'];
+            if (isset($param['default'])) {
+                $answers[$param['name']] = $param['default'];
+            } else {
+                $answers[$param['name']] = '';
+            }
+        }
+        do {
+            $ok = array('yesno' => 'no');
+            do {
+                $answers = $this->userDialog('', $prompts, $types, $answers);
+            } while (count(array_filter($answers)) != count($prompts));
+            $this->outputData('Your choices:');
+            foreach ($prompts as $name => $prompt) {
+                $this->outputData($prompt . ': ' . $answers[$name]);
+            }
+            $ok = $this->userDialog('',
+                array(
+                    'yesno' => 'These Choices OK? (use "abort" to halt)'
+                ),
+                array(
+                    'yesno' => 'string',
+                ),
+                array(
+                    'yesno' => 'yes'
+                )
+            );
+            if ($ok['yesno'] == 'abort') {
+                return false;
+            }
+        } while ($ok['yesno'] != 'yes');
+        return $answers;
+    }
     // {{{ userDialog(prompt, [type], [default])
 
     function userDialog($command, $prompts, $types = array(), $defaults = array())
     {
         $result = array();
         if (is_array($prompts)) {
-            $fp = fopen("php://stdin", "r");
+            // php 5.0.0 inexplicably breaks BC with this behavior
+            // now reading from STDIN is the intended syntax
+            if (version_compare(phpversion(), '5.0.0', '<')) {
+                $fp = fopen("php://stdin", "r");
+            }
             foreach ($prompts as $key => $prompt) {
                 $type = $types[$key];
                 $default = @$defaults[$key];
@@ -146,7 +357,14 @@ class PEAR_Frontend_CLI extends PEAR
                     print "[$default] ";
                 }
                 print ": ";
-                $line = fgets($fp, 2048);
+                if (version_compare(phpversion(), '5.0.0', '<')) {
+                    $line = fgets($fp, 2048);
+                } else {
+                    if (!defined('STDIN')) {
+                        define('STDIN', fopen('php://stdin', 'r'));
+                    }
+                    $line = fgets(STDIN, 2048);
+                }
                 if ($type == 'password') {
                     system('stty echo');
                     print "\n";
@@ -154,10 +372,12 @@ class PEAR_Frontend_CLI extends PEAR
                 if ($default && trim($line) == "") {
                     $result[$key] = $default;
                 } else {
-                    $result[$key] = $line;
+                    $result[$key] = trim($line);
                 }
             }
-            fclose($fp);
+            if (version_compare(phpversion(), '5.0.0', '<')) {
+                fclose($fp);
+            }
         }
         return $result;
     }
@@ -369,6 +589,14 @@ class PEAR_Frontend_CLI extends PEAR
     function outputData($data, $command = '_default')
     {
         switch ($command) {
+            case 'channel-info':
+                foreach ($data as $type => $section) {
+                    if ($type == 'main') {
+                        $section['data'] = array_values($section['data']);
+                    }
+                    $this->outputData($section);
+                }
+                break;
             case 'install':
             case 'upgrade':
             case 'upgrade-all':
@@ -405,8 +633,8 @@ class PEAR_Frontend_CLI extends PEAR
 
                 foreach($data['data'] as $category) {
                     foreach($category as $pkg) {
-                        unset($pkg[3]);
                         unset($pkg[4]);
+                        unset($pkg[5]);
                         $this->_tableRow($pkg, null, array(1 => array('wrap' => 55)));
                     }
                 };
index af4ae5b62e68f1b8d57325fcd94da04f62deba41..1e97b6c57507ba79049dc8e19c4766c01f8a5a06 100644 (file)
@@ -1,41 +1,50 @@
 <?php
-//
-// +----------------------------------------------------------------------+
-// | PHP Version 5                                                        |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2004 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$
+/**
+ * PEAR_Installer
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Tomas V.V. Cox <cox@idecnet.com>
+ * @author     Martin Jansen <mj@php.net>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 0.1
+ */
 
+/**
+ * Used for installation groups in package.xml 2.0 and platform exceptions
+ */
+require_once 'OS/Guess.php';
 require_once 'PEAR/Downloader.php';
 
+define('PEAR_INSTALLER_NOBINARY', -240);
 /**
  * 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>
- * @author Greg Beaver <cellog@php.net>
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Tomas V.V. Cox <cox@idecnet.com>
+ * @author     Martin Jansen <mj@php.net>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 0.1
  */
 class PEAR_Installer extends PEAR_Downloader
 {
@@ -77,11 +86,18 @@ class PEAR_Installer extends PEAR_Downloader
      */
     var $tmpdir;
 
-    /** PEAR_Registry object used by the installer
-     * @var object
+    /**
+     * PEAR_Registry object used by the installer
+     * @var PEAR_Registry
      */
     var $registry;
 
+    /**
+     * array of PEAR_Downloader_Packages
+     * @var array
+     */
+    var $_downloadedPackages;
+
     /** List of file transactions queued for an install/upgrade/uninstall.
      *
      *  Format:
@@ -111,38 +127,77 @@ class PEAR_Installer extends PEAR_Downloader
         parent::PEAR_Common();
         $this->setFrontendObject($ui);
         $this->debug = $this->config->get('verbose');
-        //$this->registry = &new PEAR_Registry($this->config->get('php_dir'));
+    }
+
+    function setOptions($options)
+    {
+        $this->_options = $options;
+    }
+
+    function setConfig(&$config)
+    {
+        $this->config = &$config;
+        $this->_registry = &$config->getRegistry();
     }
 
     // }}}
 
+    function _removeBackups($files)
+    {
+        foreach ($files as $path) {
+            $this->addFileOperation('removebackup', array($path));
+        }
+    }
+
     // {{{ _deletePackageFiles()
 
     /**
      * Delete a package's installed files, does not remove empty directories.
      *
-     * @param string $package package name
-     *
+     * @param string package name
+     * @param string channel name
+     * @param bool if true, then files are backed up first
      * @return bool TRUE on success, or a PEAR error on failure
-     *
-     * @access private
+     * @access protected
      */
-    function _deletePackageFiles($package)
+    function _deletePackageFiles($package, $channel = false, $backup = false)
     {
+        if (!$channel) {
+            $channel = 'pear.php.net';
+        }
         if (!strlen($package)) {
             return $this->raiseError("No package to uninstall given");
         }
-        $filelist = $this->registry->packageInfo($package, 'filelist');
+        if (strtolower($package) == 'pear' && $channel == 'pear.php.net') {
+            // to avoid race conditions, include all possible needed files
+            require_once 'PEAR/Task/Common.php';
+            require_once 'PEAR/Task/Replace.php';
+            require_once 'PEAR/Task/Unixeol.php';
+            require_once 'PEAR/Task/Windowseol.php';
+            require_once 'PEAR/PackageFile/v1.php';
+            require_once 'PEAR/PackageFile/v2.php';
+            require_once 'PEAR/PackageFile/Generator/v1.php';
+            require_once 'PEAR/PackageFile/Generator/v2.php';
+        }
+        $filelist = $this->_registry->packageInfo($package, 'filelist', $channel);
         if ($filelist == null) {
-            return $this->raiseError("$package not installed");
+            return $this->raiseError("$channel/$package not installed");
         }
+        $ret = array();
         foreach ($filelist as $file => $props) {
             if (empty($props['installed_as'])) {
                 continue;
             }
-            $path = $this->_prependPath($props['installed_as'], $this->installroot);
+            $path = $props['installed_as'];
+            if ($backup) {
+                $this->addFileOperation('backup', array($path));
+                $ret[] = $path;
+            }
             $this->addFileOperation('delete', array($path));
         }
+        if ($backup) {
+            return $ret;
+        }
         return true;
     }
 
@@ -160,9 +215,11 @@ class PEAR_Installer extends PEAR_Downloader
     {
         // {{{ return if this file is meant for another platform
         static $os;
+        if (!isset($this->_registry)) {
+            $this->_registry = &$this->config->getRegistry();
+        }
         if (isset($atts['platform'])) {
             if (empty($os)) {
-                include_once "OS/Guess.php";
                 $os = new OS_Guess();
             }
             if (strlen($atts['platform']) && $atts['platform']{0} == '!') {
@@ -179,21 +236,22 @@ class PEAR_Installer extends PEAR_Downloader
         }
         // }}}
 
+        $channel = $this->pkginfo->getChannel();
         // {{{ 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'];
+                $dest_dir = $this->config->get($atts['role'] . '_dir', null, $channel) .
+                            DIRECTORY_SEPARATOR . $this->pkginfo->getPackage();
                 unset($atts['baseinstalldir']);
                 break;
             case 'ext':
             case 'php':
-                $dest_dir = $this->config->get($atts['role'] . '_dir');
+                $dest_dir = $this->config->get($atts['role'] . '_dir', null, $channel);
                 break;
             case 'script':
-                $dest_dir = $this->config->get('bin_dir');
+                $dest_dir = $this->config->get('bin_dir', null, $channel);
                 break;
             case 'src':
             case 'extsrc':
@@ -219,10 +277,11 @@ class PEAR_Installer extends PEAR_Downloader
         // Clean up the DIRECTORY_SEPARATOR mess
         $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR;
         list($dest_file, $orig_file) = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"),
-                                                    DIRECTORY_SEPARATOR,
+                                                    array(DIRECTORY_SEPARATOR,
+                                                          DIRECTORY_SEPARATOR,
+                                                          DIRECTORY_SEPARATOR),
                                                     array($dest_file, $orig_file));
-        $installed_as = $dest_file;
-        $final_dest_file = $this->_prependPath($dest_file, $this->installroot);
+        $final_dest_file = $installed_as = $dest_file;
         $dest_dir = dirname($final_dest_file);
         $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file);
         // }}}
@@ -236,7 +295,7 @@ class PEAR_Installer extends PEAR_Downloader
         }
         if (empty($atts['replacements'])) {
             if (!file_exists($orig_file)) {
-                return $this->raiseError("file does not exist",
+                return $this->raiseError("file $orig_file does not exist",
                                          PEAR_INSTALLER_FAILED);
             }
             if (!@copy($orig_file, $dest_file)) {
@@ -253,9 +312,16 @@ class PEAR_Installer extends PEAR_Downloader
                 return $this->raiseError("file does not exist",
                                          PEAR_INSTALLER_FAILED);
             }
-            $fp = fopen($orig_file, "r");
-            $contents = fread($fp, filesize($orig_file));
-            fclose($fp);
+            if (function_exists('file_get_contents')) {
+                $contents = file_get_contents($orig_file);
+            } else {
+                $fp = fopen($orig_file, "r");
+                $contents = @fread($fp, filesize($orig_file));
+                fclose($fp);
+            }
+            if ($contents === false) {
+                $contents = '';
+            }
             if (isset($atts['md5sum'])) {
                 $md5sum = md5($contents);
             }
@@ -266,20 +332,35 @@ class PEAR_Installer extends PEAR_Downloader
                     if (preg_match('/^[a-z0-9_]+$/i', $a['to'])) {
                         eval("\$to = $a[to];");
                     } else {
-                        $this->log(0, "invalid php-const replacement: $a[to]");
+                        if (!isset($options['soft'])) {
+                            $this->log(0, "invalid php-const replacement: $a[to]");
+                        }
                         continue;
                     }
                 } elseif ($a['type'] == 'pear-config') {
-                    $to = $this->config->get($a['to']);
+                    if ($a['to'] == 'master_server') {
+                        $chan = $this->_registry->getChannel($channel);
+                        if ($chan) {
+                            $to = $chan->getServer();
+                        } else {
+                            $to = $this->config->get($a['to'], null, $channel);
+                        }
+                    } else {
+                        $to = $this->config->get($a['to'], null, $channel);
+                    }
                     if (is_null($to)) {
-                        $this->log(0, "invalid pear-config replacement: $a[to]");
+                        if (!isset($options['soft'])) {
+                            $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']];
+                    if ($t = $this->pkginfo->packageInfo($a['to'])) {
+                        $to = $t;
                     } else {
-                        $this->log(0, "invalid package-info replacement: $a[to]");
+                        if (!isset($options['soft'])) {
+                            $this->log(0, "invalid package-info replacement: $a[to]");
+                        }
                         continue;
                     }
                 }
@@ -297,7 +378,7 @@ class PEAR_Installer extends PEAR_Downloader
                 return $this->raiseError("failed to create $dest_file: $php_errormsg",
                                          PEAR_INSTALLER_FAILED);
             }
-            if (!fwrite($wp, $contents)) {
+            if (fwrite($wp, $contents) === false) {
                 return $this->raiseError("failed writing to $dest_file: $php_errormsg",
                                          PEAR_INSTALLER_FAILED);
             }
@@ -312,10 +393,18 @@ class PEAR_Installer extends PEAR_Downloader
                 if (empty($options['force'])) {
                     // delete the file
                     @unlink($dest_file);
-                    return $this->raiseError("bad md5sum for file $final_dest_file",
+                    if (!isset($options['ignore-errors'])) {
+                        return $this->raiseError("bad md5sum for file $final_dest_file",
                                              PEAR_INSTALLER_FAILED);
+                    } else {
+                        if (!isset($options['soft'])) {
+                            $this->log(0, "warning : bad md5sum for file $final_dest_file");
+                        }
+                    }
                 } else {
-                    $this->log(0, "warning : bad md5sum for file $final_dest_file");
+                    if (!isset($options['soft'])) {
+                        $this->log(0, "warning : bad md5sum for file $final_dest_file");
+                    }
                 }
             }
         }
@@ -330,11 +419,14 @@ class PEAR_Installer extends PEAR_Downloader
             }
             $this->addFileOperation("chmod", array($mode, $dest_file));
             if (!@chmod($dest_file, $mode)) {
-                $this->log(0, "failed to change mode of $dest_file");
+                if (!isset($options['soft'])) {
+                    $this->log(0, "failed to change mode of $dest_file");
+                }
             }
         }
         // }}}
-        $this->addFileOperation("rename", array($dest_file, $final_dest_file));
+        $this->addFileOperation("rename", array($dest_file, $final_dest_file,
+            $atts['role'] == 'ext'));
         // 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)))));
@@ -343,6 +435,165 @@ class PEAR_Installer extends PEAR_Downloader
         return PEAR_INSTALLER_OK;
     }
 
+    // }}}
+    // {{{ _installFile2()
+
+    /**
+     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+     * @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 _installFile2(&$pkg, $file, $atts, $tmp_path, $options)
+    {
+        if (!isset($this->_registry)) {
+            $this->_registry = &$this->config->getRegistry();
+        }
+
+        $channel = $pkg->getChannel();
+        // {{{ assemble the destination paths
+        if (!in_array($atts['attribs']['role'],
+              PEAR_Installer_Role::getValidRoles($pkg->getPackageType()))) {
+            return $this->raiseError('Invalid role `' . $atts['attribs']['role'] .
+                    "' for file $file");
+        }
+        $role = &PEAR_Installer_Role::factory($pkg, $atts['attribs']['role'], $this->config);
+        $err = $role->setup($this, $pkg, $atts['attribs'], $file);
+        if (PEAR::isError($err)) {
+            return $err;
+        }
+        if (!$role->isInstallable()) {
+            return;
+        }
+        $info = $role->processInstallation($pkg, $atts['attribs'], $file, $tmp_path);
+        if (PEAR::isError($info)) {
+            return $info;
+        } else {
+            list($save_destdir, $dest_dir, $dest_file, $orig_file) = $info;
+        }
+        $final_dest_file = $installed_as = $dest_file;
+        $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");
+        }
+        $attribs = $atts['attribs'];
+        unset($atts['attribs']);
+        if (!count($atts)) { // no tasks
+            if (!file_exists($orig_file)) {
+                return $this->raiseError("file $orig_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($attribs['md5sum'])) {
+                $md5sum = md5_file($dest_file);
+            }
+        } else { // file with tasks
+            if (!file_exists($orig_file)) {
+                return $this->raiseError("file $orig_file does not exist",
+                                         PEAR_INSTALLER_FAILED);
+            }
+            if (function_exists('file_get_contents')) {
+                $contents = file_get_contents($orig_file);
+            } else {
+                $fp = fopen($orig_file, "r");
+                $contents = @fread($fp, filesize($orig_file)); // filesize can be 0
+                fclose($fp);
+            }
+            if ($contents === false) {
+                $contents = '';
+            }
+            if (isset($attribs['md5sum'])) {
+                $md5sum = md5($contents);
+            }
+            foreach ($atts as $tag => $raw) {
+                $tag = str_replace($pkg->getTasksNs() . ':', '', $tag);
+                $task = "PEAR_Task_$tag";
+                $task = &new $task($this->config, $this, PEAR_TASK_INSTALL);
+                if (!$task->isScript()) { // scripts are only handled after installation
+                    $task->init($raw, $attribs, $pkg->getLastInstalledVersion());
+                    $res = $task->startSession($pkg, $contents, $final_dest_file);
+                    if ($res === false) {
+                        continue; // skip this file
+                    }
+                    if (PEAR::isError($res)) {
+                        return $res;
+                    }
+                    $contents = $res; // save changes
+                }
+                $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) === false) {
+                    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($attribs['md5sum'])) {
+                $this->log(2, "md5sum ok: $final_dest_file");
+            } else {
+                if (empty($options['force'])) {
+                    // delete the file
+                    @unlink($dest_file);
+                    if (!isset($options['ignore-errors'])) {
+                        return $this->raiseError("bad md5sum for file $final_dest_file",
+                                                 PEAR_INSTALLER_FAILED);
+                    } else {
+                        if (!isset($options['soft'])) {
+                            $this->log(0, "warning : bad md5sum for file $final_dest_file");
+                        }
+                    }
+                } else {
+                    if (!isset($options['soft'])) {
+                        $this->log(0, "warning : bad md5sum for file $final_dest_file");
+                    }
+                }
+            }
+        }
+        // }}}
+        // {{{ set file permissions
+        if (!OS_WINDOWS) {
+            if ($role->isExecutable()) {
+                $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)) {
+                if (!isset($options['soft'])) {
+                    $this->log(0, "failed to change mode of $dest_file");
+                }
+            }
+        }
+        // }}}
+        $this->addFileOperation("rename", array($dest_file, $final_dest_file, $role->isExtension()));
+        // Store the full path where the file was installed for easy uninstall
+        $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()
 
@@ -350,16 +601,18 @@ class PEAR_Installer extends PEAR_Downloader
      * 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)
+     * @param string $type This can be one of:
+     *    - rename:  rename a file ($data has 3 values)
+     *    - backup:  backup an existing file ($data has 1 value)
+     *    - removebackup:  clean up backups created during install ($data has 1 value)
      *    - 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
+     * @param 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 second its new name, the third whether this is a PHP extension.
      *
      *    The installed_as operation contains 4 elements in this order:
      *    1. Filename as listed in the filelist element from package.xml
@@ -426,8 +679,18 @@ class PEAR_Installer extends PEAR_Downloader
                         $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]";
+                    if (file_exists($data[0])) {
+                        if (!is_writable(dirname($data[0]))) {
+                            $errors[] = "permission denied ($type): $data[0]";
+                        } else {
+                            // make sure the file to be deleted can be opened for writing
+                            $fp = false;
+                            if (!is_dir($data[0]) && !($fp = @fopen($data[0], 'a'))) {
+                                $errors[] = "permission denied ($type): $data[0]";
+                            } elseif ($fp) {
+                                fclose($fp);
+                            }
+                        }
                     }
                     break;
             }
@@ -437,16 +700,44 @@ class PEAR_Installer extends PEAR_Downloader
         $m = sizeof($errors);
         if ($m > 0) {
             foreach ($errors as $error) {
-                $this->log(1, $error);
+                if (!isset($this->_options['soft'])) {
+                    $this->log(1, $error);
+                }
+            }
+            if (!isset($this->_options['ignore-errors'])) {
+                return false;
             }
-            return false;
         }
+        $this->_dirtree = array();
         // {{{ really commit the transaction
         foreach ($this->file_operations as $tr) {
             list($type, $data) = $tr;
             switch ($type) {
+                case 'backup':
+                    @copy($data[0], $data[0] . '.bak');
+                    $this->log(3, "+ backup $data[0] to $data[0].bak");
+                    break;
+                case 'removebackup':
+                    @unlink($data[0] . '.bak');
+                    $this->log(3, "+ rm backup of $data[0] ($data[0].bak)");
+                    break;
                 case 'rename':
-                    @unlink($data[1]);
+                    $test = @unlink($data[1]);
+                    if (!$test && file_exists($data[1])) {
+                        if ($data[2]) {
+                            $extra = ', this extension must be installed manually.  Rename to "' .
+                                basename($data[1]) . '"';
+                        } else {
+                            $extra = '';
+                        }
+                        if (!isset($this->_options['soft'])) {
+                            $this->log(1, 'Could not delete ' . $data[1] . ', cannot rename ' .
+                                $data[0] . $extra);
+                        }
+                        if (!isset($this->_options['ignore-errors'])) {
+                            return false;
+                        }
+                    }
                     @rename($data[0], $data[1]);
                     $this->log(3, "+ mv $data[0] $data[1]");
                     break;
@@ -464,13 +755,16 @@ class PEAR_Installer extends PEAR_Downloader
                     $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;
+                    $this->pkginfo->setInstalledAs($data[0], $data[1]);
+                    if (!isset($this->_dirtree[dirname($data[1])])) {
+                        $this->_dirtree[dirname($data[1])] = true;
+                        $this->pkginfo->setDirtree(dirname($data[1]));
+
                         while(!empty($data[3]) && $data[3] != '/' && $data[3] != '\\'
                               && $data[3] != '.') {
-                            $this->pkginfo['filelist']['dirtree']
-                                [$this->_prependPath($data[3], $data[2])] = true;
+                            $this->pkginfo->setDirtree($pp =
+                                $this->_prependPath($data[3], $data[2]));
+                            $this->_dirtree[$pp] = true;
                             $data[3] = dirname($data[3]);
                         }
                     }
@@ -493,6 +787,13 @@ class PEAR_Installer extends PEAR_Downloader
         foreach ($this->file_operations as $tr) {
             list($type, $data) = $tr;
             switch ($type) {
+                case 'backup':
+                    if (file_exists($data[0] . '.bak')) {
+                        @unlink($data[0]);
+                        @copy($data[0] . '.bak', $data[0]);
+                        $this->log(3, "+ restore $data[0] from $data[0].bak");
+                    }
+                    break;
                 case 'rename':
                     @unlink($data[0]);
                     $this->log(3, "+ rm $data[0]");
@@ -506,25 +807,11 @@ class PEAR_Installer extends PEAR_Downloader
                 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']);
-                    }
+                    $this->pkginfo->setInstalledAs($data[0], false);
                     break;
             }
         }
+        $this->pkginfo->resetDirtree();
         $this->file_operations = array();
     }
 
@@ -574,12 +861,82 @@ class PEAR_Installer extends PEAR_Downloader
     }
 
     // }}}
+    // {{{ _parsePackageXml()
+
+    function _parsePackageXml(&$descfile, &$tmpdir)
+    {
+        if (substr($descfile, -4) == '.xml') {
+            $tmpdir = false;
+        } else {
+            // {{{ Decompress pack in tmp dir -------------------------------------
+
+            // To allow relative package file names
+            $descfile = realpath($descfile);
+
+            if (PEAR::isError($tmpdir = System::mktemp('-d'))) {
+                return $tmpdir;
+            }
+            $this->log(3, '+ tmp dir created at ' . $tmpdir);
+            // }}}
+        }
+        // Parse xml file -----------------------------------------------
+        $pkg = new PEAR_PackageFile($this->config, $this->debug, $tmpdir);
+        PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+        $p = &$pkg->fromAnyFile($descfile, PEAR_VALIDATE_INSTALLING);
+        PEAR::staticPopErrorHandling();
+        if (PEAR::isError($p)) {
+            foreach ($pkg->getValidationWarnings(true) as $err) {
+                $loglevel = $err['level'] == 'error' ? 0 : 1;
+                if (!isset($this->_options['soft'])) {
+                    $this->log($loglevel, ucfirst($err['level']) . ': ' . $err['message']);
+                }
+            }
+            return $this->raiseError('Installation failed: invalid package file');
+        } else {
+            $descfile = $p->getPackageFile();
+        }
+        return $p;
+    }
+
+    // }}}
+    /**
+     * Set the list of PEAR_Downloader_Package objects to allow more sane
+     * dependency validation
+     * @param array
+     */
+    function setDownloadedPackages(&$pkgs)
+    {
+        PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+        $err = $this->analyzeDependencies($pkgs);
+        PEAR::popErrorHandling();
+        if (PEAR::isError($err)) {
+            return $err;
+        }
+        $this->_downloadedPackages = &$pkgs;
+    }
+
+    /**
+     * Set the list of PEAR_Downloader_Package objects to allow more sane
+     * dependency validation
+     * @param array
+     */
+    function setUninstallPackages(&$pkgs)
+    {
+        $this->_downloadedPackages = &$pkgs;
+    }
+
+    function getInstallPackages()
+    {
+        return $this->_downloadedPackages;
+    }
+
     // {{{ install()
 
     /**
      * Installs the files within the package file specified.
      *
-     * @param string $pkgfile path to the package file
+     * @param string|PEAR_Downloader_Package $pkgfile path to the package file,
+     *        or a pre-initialized packagefile object
      * @param array $options
      * recognized options:
      * - installroot   : optional prefix directory for installation
@@ -596,118 +953,114 @@ class PEAR_Installer extends PEAR_Downloader
 
     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'];
+        $this->_options = $options;
+        $this->_registry = &$this->config->getRegistry();
+        if (is_object($pkgfile)) {
+            $dlpkg = &$pkgfile;
+            $pkg = $pkgfile->getPackageFile();
+            $pkgfile = $pkg->getArchiveFile();
+            $descfile = $pkg->getPackageFile();
+            $tmpdir = dirname($descfile);
         } 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;
+            $tmpdir = '';
+            if (PEAR::isError($pkg = &$this->_parsePackageXml($descfile, $tmpdir))) {
+                return $pkg;
             }
-            $this->log(3, '+ tmp dir created at ' . $tmpdir);
+        }
 
+        if (realpath($descfile) != realpath($pkgfile)) {
             $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'];
+        $pkgname = $pkg->getName();
+        $channel = $pkg->getChannel();
 
-        // {{{ 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);
-                }
-            }
+        if (isset($options['installroot'])) {
+            $this->config->setInstallRoot($options['installroot']);
+            $this->_registry = &$this->config->getRegistry();
+            $this->installroot = ''; // all done automagically now
+        } else {
+            $this->config->setInstallRoot(false);
+            $this->_registry = &$this->config->getRegistry();
+            $this->installroot = '';
         }
-        // }}}
+        $php_dir = $this->config->get('php_dir', null, $channel);
 
         // {{{ checks to do when not in "force" mode
-        if (empty($options['force'])) {
-            $test = $this->registry->checkFileMap($pkginfo);
+        if (empty($options['force']) && @is_dir($this->config->get('php_dir'))) {
+            $testp = $channel == 'pear.php.net' ? $pkgname : array($channel, $pkgname);
+            $test = $this->_registry->checkFileMap($pkg->getInstallationFileList(true), $testp, '1.1');
+            if (PEAR::isError($test)) {
+                return $test;
+            }
             if (sizeof($test)) {
-                $tmp = $test;
-                foreach ($tmp as $file => $pkg) {
-                    if ($pkg == $pkgname) {
-                        unset($test[$file]);
+                $pkgs = $this->getInstallPackages();
+                $found = false;
+                foreach ($pkgs as $param) {
+                    if ($pkg->isSubpackageOf($param)) {
+                        $found = true;
+                        break;
+                    }
+                }
+                if ($found) {
+                    // subpackages can conflict with earlier versions of parent packages
+                    $parentreg = $this->_registry->packageInfo($param->getPackage(), null, $param->getChannel());
+                    $tmp = $test;
+                    foreach ($tmp as $file => $info) {
+                        if (is_array($info)) {
+                            if (strtolower($info[1]) == strtolower($param->getPackage()) &&
+                                  strtolower($info[0]) == strtolower($param->getChannel())) {
+                                unset($test[$file]);
+                                unset($parentreg['filelist'][$file]);
+                            }
+                        } else {
+                            if (strtolower($param->getChannel()) != 'pear.php.net') {
+                                continue;
+                            }
+                            if (strtolower($info) == strtolower($param->getPackage())) {
+                                unset($test[$file]);
+                                unset($parentreg['filelist'][$file]);
+                            }
+                        }
+                    }
+                    $pfk = &new PEAR_PackageFile($this->config);
+                    $parentpkg = &$pfk->fromArray($parentreg);
+                    $this->_registry->updatePackage2($parentpkg);
+                }
+                if ($param->getChannel() == 'pecl.php.net' && isset($options['upgrade'])) {
+                    $tmp = $test;
+                    foreach ($tmp as $file => $info) {
+                        if (is_string($info)) {
+                            // pear.php.net packages are always stored as strings
+                            if (strtolower($info) == strtolower($param->getPackage())) {
+                                // upgrading existing package
+                                unset($test[$file]);
+                            }
+                        }
                     }
                 }
                 if (sizeof($test)) {
-                    $msg = "$pkgname: conflicting files found:\n";
+                    $msg = "$channel/$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);
+                    foreach ($test as $file => $info) {
+                        if (!is_array($info)) {
+                            $info = array('pear.php.net', $info);
+                        }
+                        $info = $info[0] . '/' . $info[1];
+                        $msg .= sprintf($fmt, $file, $info);
+                    }
+                    if (!isset($options['ignore-errors'])) {
+                        return $this->raiseError($msg);
+                    } else {
+                        if (!isset($options['soft'])) {
+                            $this->log(0, "WARNING: $msg");
+                        }
                     }
-                    return $this->raiseError($msg);
                 }
             }
         }
@@ -715,23 +1068,50 @@ class PEAR_Installer extends PEAR_Downloader
 
         $this->startFileTransaction();
 
-        if (empty($options['upgrade'])) {
+        if (empty($options['upgrade']) && empty($options['soft'])) {
             // checks to do only when installing new packages
-            if (empty($options['force']) && $this->registry->packageExists($pkgname)) {
-                return $this->raiseError("$pkgname already installed");
+            if ($channel == 'pecl.php.net') {
+                $test = $this->_registry->packageExists($pkgname, $channel);
+                if (!$test) {
+                    $test = $this->_registry->packageExists($pkgname, 'pear.php.net');
+                }
+            } else {
+                $test = $this->_registry->packageExists($pkgname, $channel);
+            }
+            if (empty($options['force']) && $test) {
+                return $this->raiseError("$channel/$pkgname is already installed");
             }
         } else {
-            if ($this->registry->packageExists($pkgname)) {
-                $v1 = $this->registry->packageInfo($pkgname, 'version');
-                $v2 = $pkginfo['version'];
+            $usechannel = $channel;
+            if ($channel == 'pecl.php.net') {
+                $test = $this->_registry->packageExists($pkgname, $channel);
+                if (!$test) {
+                    $test = $this->_registry->packageExists($pkgname, 'pear.php.net');
+                    $usechannel = 'pear.php.net';
+                }
+            } else {
+                $test = $this->_registry->packageExists($pkgname, $channel);
+            }
+            if ($test) {
+                $v1 = $this->_registry->packageInfo($pkgname, 'version', $usechannel);
+                $v2 = $pkg->getVersion();
                 $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);
+                    if (PEAR::isError($err = $this->_deletePackageFiles($pkgname, $usechannel,
+                          true))) {
+                        if (!isset($options['ignore-errors'])) {
+                            return $this->raiseError($err);
+                        } else {
+                            if (!isset($options['soft'])) {
+                                $this->log(0, 'WARNING: ' . $err->getMessage());
+                            }
+                        }
+                    } else {
+                        $backedup = $err;
                     }
                 }
             }
@@ -740,32 +1120,47 @@ class PEAR_Installer extends PEAR_Downloader
         // {{{ Copy files to dest dir ---------------------------------------
 
         // info from the package it self we want to access from _installFile
-        $this->pkginfo = &$pkginfo;
+        $this->pkginfo = &$pkg;
         // used to determine whether we should build any C code
         $this->source_files = 0;
 
+        $savechannel = $this->config->get('default_channel');
         if (empty($options['register-only'])) {
             if (!is_dir($php_dir)) {
-                return $this->raiseError("no script destination directory\n",
-                                         null, PEAR_ERROR_DIE);
+                if (PEAR::isError(System::mkdir(array('-p'), $php_dir))) {
+                    return $this->raiseError("no installation destination directory '$php_dir'\n");
+                }
             }
 
             $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);
+                $tmp_path .= DIRECTORY_SEPARATOR . $pkgname . '-' . $pkg->getVersion();
             }
-            // <== XXX This part should be removed later on
 
+            $this->configSet('default_channel', $channel);
             // {{{ install files
-            foreach ($pkginfo['filelist'] as $file => $atts) {
-                $this->expectError(PEAR_INSTALLER_FAILED);
-                $res = $this->_installFile($file, $atts, $tmp_path, $options);
-                $this->popExpect();
+            
+            if ($pkg->getPackagexmlVersion() == '2.0') {
+                $filelist = $pkg->getInstallationFilelist();
+            } else {
+                $filelist = $pkg->getFileList();
+            }
+            if (PEAR::isError($filelist)) {
+                return $filelist;
+            }
+            $pkg->resetFilelist();
+            $pkg->setLastInstalledVersion($this->_registry->packageInfo($pkg->getPackage(),
+                'version', $pkg->getChannel()));
+            foreach ($filelist as $file => $atts) {
+                if ($pkg->getPackagexmlVersion() == '1.0') {
+                    $this->expectError(PEAR_INSTALLER_FAILED);
+                    $res = $this->_installFile($file, $atts, $tmp_path, $options);
+                    $this->popExpect();
+                } else {
+                    $this->expectError(PEAR_INSTALLER_FAILED);
+                    $res = $this->_installFile2($pkg, $file, $atts, $tmp_path, $options);
+                    $this->popExpect();
+                }
                 if (PEAR::isError($res)) {
                     if (empty($options['ignore-errors'])) {
                         $this->rollbackFileTransaction();
@@ -774,106 +1169,181 @@ class PEAR_Installer extends PEAR_Downloader
                         }
                         return $this->raiseError($res);
                     } else {
-                        $this->log(0, "Warning: " . $res->getMessage());
+                        if (!isset($options['soft'])) {
+                            $this->log(0, "Warning: " . $res->getMessage());
+                        }
                     }
                 }
-                if ($res != PEAR_INSTALLER_OK) {
-                    // Do not register files that were not installed
-                    unset($pkginfo['filelist'][$file]);
+                if ($res == PEAR_INSTALLER_OK) {
+                    // Register files that were installed
+                    $pkg->installedFile($file, $atts);
                 }
             }
             // }}}
 
             // {{{ 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, $_ext_suff) = explode('.', $bn);
-                    if ($_ext_suff == '.so' || $_ext_suff == '.dll') {
-                        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');
-                        }
-                        $role = 'ext';
-                    } else {
-                        $role = 'src';
-                    }
-                    $dest = $ext['dest'];
-                    $this->log(1, "Installing '$ext[file]'");
-                    $copyto = $this->_prependPath($dest, $this->installroot);
-                    $copydir = dirname($copyto);
-                    if (!@is_dir($copydir)) {
-                        if (!$this->mkDirHier($copydir)) {
-                            return $this->raiseError("failed to mkdir $copydir",
-                                PEAR_INSTALLER_FAILED);
-                        }
-                        $this->log(3, "+ mkdir $copydir");
-                    }
-                    if (!@copy($ext['file'], $copyto)) {
-                        return $this->raiseError("failed to write $copyto", PEAR_INSTALLER_FAILED);
-                    }
-                    $this->log(3, "+ cp $ext[file] $copyto");
-                    if (!OS_WINDOWS) {
-                        $mode = 0666 & ~(int)octdec($this->config->get('umask'));
-                        $this->addFileOperation('chmod', array($mode, $copyto));
-                        if (!@chmod($copyto, $mode)) {
-                            $this->log(0, "failed to change mode of $copyto");
-                        }
-                    }
-                    $this->addFileOperation('rename', array($ext['file'], $copyto));
-
-                    $pkginfo['filelist'][$bn] = array(
-                        'role' => $role,
-                        'installed_as' => $dest,
-                        'php_api' => $ext['php_api'],
-                        'zend_mod_api' => $ext['zend_mod_api'],
-                        'zend_ext_api' => $ext['zend_ext_api'],
-                        );
+                if (PEAR::isError($err =
+                      $this->_compileSourceFiles($savechannel, $pkg))) {
+                    return $err;
                 }
             }
             // }}}
         }
 
+        if (isset($backedup)) {
+            $this->_removeBackups($backedup);
+        }
         if (!$this->commitFileTransaction()) {
             $this->rollbackFileTransaction();
+            $this->configSet('default_channel', $savechannel);
             return $this->raiseError("commit failed", PEAR_INSTALLER_FAILED);
         }
         // }}}
 
         $ret = false;
+        $installphase = 'install';
+        $oldversion = 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);
+            $usechannel = $channel;
+            if ($channel == 'pecl.php.net') {
+                $test = $this->_registry->packageExists($pkgname, $channel);
+                if (!$test) {
+                    $test = $this->_registry->packageExists($pkgname, 'pear.php.net');
+                    $usechannel = 'pear.php.net';
+                }
+            } else {
+                $test = $this->_registry->packageExists($pkgname, $channel);
             }
-            $ret = $this->registry->addPackage($pkgname, $pkginfo);
+            if (!empty($options['force']) && $test) {
+                $oldversion = $this->_registry->packageInfo($pkgname, 'version', $usechannel);
+                $this->_registry->deletePackage($pkgname, $usechannel);
+            }
+            $ret = $this->_registry->addPackage2($pkg);
         } else {
+            $usechannel = $channel;
+            if ($channel == 'pecl.php.net') {
+                $test = $this->_registry->packageExists($pkgname, $channel);
+                if (!$test) {
+                    $test = $this->_registry->packageExists($pkgname, 'pear.php.net');
+                    $usechannel = 'pear.php.net';
+                }
+            } else {
+                $test = $this->_registry->packageExists($pkgname, $channel);
+            }
             // new: upgrade installs a package if it isn't installed
-            if (!$this->registry->packageExists($pkgname)) {
-                $ret = $this->registry->addPackage($pkgname, $pkginfo);
+            if (!$test) {
+                $ret = $this->_registry->addPackage2($pkg);
             } else {
-                $ret = $this->registry->updatePackage($pkgname, $pkginfo, false);
+                if ($usechannel != $channel) {
+                    $this->_registry->deletePackage($pkgname, $usechannel);
+                    $ret = $this->_registry->addPackage2($pkg);
+                } else {
+                    $ret = $this->_registry->updatePackage2($pkg);
+                }
+                $installphase = 'upgrade';
             }
         }
         if (!$ret) {
-            return $this->raiseError("Adding package $pkgname to registry failed");
+            $this->configSet('default_channel', $savechannel);
+            return $this->raiseError("Adding package $channel/$pkgname to registry failed");
         }
         // }}}
-        return $pkginfo;
+        $this->configSet('default_channel', $savechannel);
+        if (class_exists('PEAR_Task_Common')) { // this is auto-included if any tasks exist
+            if (PEAR_Task_Common::hasPostinstallTasks()) {
+                PEAR_Task_Common::runPostinstallTasks($installphase);
+            }
+        }
+        return $pkg->toArray(true);
+    }
+
+    // }}}
+
+    // {{{ _compileSourceFiles()
+    /**
+     * @param string
+     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+     */
+    function _compileSourceFiles($savechannel, &$filelist)
+    {
+        require_once 'PEAR/Builder.php';
+        $this->log(1, "$this->source_files source files, building");
+        $bob = &new PEAR_Builder($this->ui);
+        $bob->debug = $this->debug;
+        $built = $bob->build($filelist, array(&$this, '_buildCallback'));
+        if (PEAR::isError($built)) {
+            $this->rollbackFileTransaction();
+            $this->configSet('default_channel', $savechannel);
+            return $built;
+        }
+        $this->log(1, "\nBuild process completed successfully");
+        foreach ($built as $ext) {
+            $bn = basename($ext['file']);
+            list($_ext_name, $_ext_suff) = explode('.', $bn);
+            if ($_ext_suff == '.so' || $_ext_suff == '.dll') {
+                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');
+                }
+                $role = 'ext';
+            } else {
+                $role = 'src';
+            }
+            $dest = $ext['dest'];
+            $this->log(1, "Installing '$ext[file]'");
+            $copyto = $this->_prependPath($dest, $this->installroot);
+            $copydir = dirname($copyto);
+            if (!@is_dir($copydir)) {
+                if (!$this->mkDirHier($copydir)) {
+                    return $this->raiseError("failed to mkdir $copydir",
+                        PEAR_INSTALLER_FAILED);
+                }
+                $this->log(3, "+ mkdir $copydir");
+            }
+            if (!@copy($ext['file'], $copyto)) {
+                return $this->raiseError("failed to write $copyto", PEAR_INSTALLER_FAILED);
+            }
+            $this->log(3, "+ cp $ext[file] $copyto");
+            if (!OS_WINDOWS) {
+                $mode = 0666 & ~(int)octdec($this->config->get('umask'));
+                $this->addFileOperation('chmod', array($mode, $copyto));
+                if (!@chmod($copyto, $mode)) {
+                    $this->log(0, "failed to change mode of $copyto");
+                }
+            }
+            $this->addFileOperation('rename', array($ext['file'], $copyto));
+
+            if ($filelist->getPackageXmlVersion() == '1.0') {
+                $filelist->installedFile($bn, array(
+                    'role' => $role,
+                    'name' => $bn,
+                    'installed_as' => $dest,
+                    'php_api' => $ext['php_api'],
+                    'zend_mod_api' => $ext['zend_mod_api'],
+                    'zend_ext_api' => $ext['zend_ext_api'],
+                    ));
+            } else {
+                $filelist->installedFile($bn, array('attribs' => array(
+                    'role' => $role,
+                    'name' => $bn,
+                    'installed_as' => $dest,
+                    'php_api' => $ext['php_api'],
+                    'zend_mod_api' => $ext['zend_mod_api'],
+                    'zend_ext_api' => $ext['zend_ext_api'],
+                    )));
+            }
+        }
     }
 
     // }}}
+    function &getUninstallPackages()
+    {
+        return $this->_downloadedPackages;
+    }
     // {{{ uninstall()
 
     /**
@@ -890,49 +1360,100 @@ class PEAR_Installer extends PEAR_Downloader
      */
     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);
+            $this->config->setInstallRoot($options['installroot']);
+            $this->installroot = '';
         } else {
+            $this->config->setInstallRoot('');
             $this->installroot = '';
         }
-        $this->registry = &new PEAR_Registry($php_dir);
-        $filelist = $this->registry->packageInfo($package, 'filelist');
-        if ($filelist == null) {
-            return $this->raiseError("$package not installed");
+        $this->_registry = &$this->config->getRegistry();
+        if (is_object($package)) {
+            $channel = $package->getChannel();
+            $pkg = $package;
+            $package = $pkg->getPackage();
+        } else {
+            $pkg = false;
+            $info = $this->_registry->parsePackageName($package,
+                $this->config->get('default_channel'));
+            $channel = $info['channel'];
+            $package = $info['package'];
         }
-        if (empty($options['nodeps'])) {
-            $depchecker = &new PEAR_Dependency($this->registry);
-            $error = $depchecker->checkPackageUninstall($errors, $warning, $package);
-            if ($error) {
-                return $this->raiseError($errors . 'uninstall failed');
+        $savechannel = $this->config->get('default_channel');
+        $this->configSet('default_channel', $channel);
+        if (!is_object($pkg)) {
+            $pkg = $this->_registry->getPackage($package, $channel);
+        }
+        if (!$pkg) {
+            $this->configSet('default_channel', $savechannel);
+            return $this->raiseError($this->_registry->parsedPackageNameToString(
+                array(
+                    'channel' => $channel,
+                    'package' => $package
+                ), true) . ' not installed');
+        }
+        if ($pkg->getInstalledBinary()) {
+            // this is just an alias for a binary package
+            return $this->_registry->deletePackage($package, $channel);
+        }
+        $filelist = $pkg->getFilelist();
+        PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+        if (!class_exists('PEAR_Dependency2')) {
+            require_once 'PEAR/Dependency2.php';
+        }
+        $depchecker = &new PEAR_Dependency2($this->config, $options, 
+            array('channel' => $channel, 'package' => $package),
+            PEAR_VALIDATE_UNINSTALLING);
+        $e = $depchecker->validatePackageUninstall($this);
+        PEAR::staticPopErrorHandling();
+        if (PEAR::isError($e)) {
+            if (!isset($options['ignore-errors'])) {
+                return $this->raiseError($e);
+            } else {
+                if (!isset($options['soft'])) {
+                    $this->log(0, 'WARNING: ' . $e->getMessage());
+                }
             }
-            if ($warning) {
-                $this->log(0, $warning);
+        } elseif (is_array($e)) {
+            if (!isset($options['soft'])) {
+                $this->log(0, $e[0]);
             }
         }
         // {{{ Delete the files
         $this->startFileTransaction();
-        if (PEAR::isError($err = $this->_deletePackageFiles($package))) {
+        PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+        if (PEAR::isError($err = $this->_deletePackageFiles($package, $channel))) {
+            PEAR::popErrorHandling();
             $this->rollbackFileTransaction();
-            return $this->raiseError($err);
+            $this->configSet('default_channel', $savechannel);
+            if (!isset($options['ignore-errors'])) {
+                return $this->raiseError($err);
+            } else {
+                if (!isset($options['soft'])) {
+                    $this->log(0, 'WARNING: ' . $err->getMessage());
+                }
+            }
+        } else {
+            PEAR::popErrorHandling();
         }
         if (!$this->commitFileTransaction()) {
             $this->rollbackFileTransaction();
-            return $this->raiseError("uninstall failed");
+            if (!isset($options['ignore-errors'])) {
+                return $this->raiseError("uninstall failed");
+            } elseif (!isset($options['soft'])) {
+                $this->log(0, 'WARNING: 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 ($dirtree = $pkg->getDirTree()) {
+                // attempt to delete empty directories
+                uksort($dirtree, array($this, '_sortDirs'));
+                foreach($dirtree as $dir => $notused) {
+                    $this->addFileOperation('rmdir', array($dir));
+                }
+            } else {
+                $this->configSet('default_channel', $savechannel);
+                return $this->_registry->deletePackage($package, $channel);
             }
             if (!$this->commitFileTransaction()) {
                 $this->rollbackFileTransaction();
@@ -940,8 +1461,46 @@ class PEAR_Installer extends PEAR_Downloader
         }
         // }}}
 
+        $this->configSet('default_channel', $savechannel);
         // Register that the package is no longer installed
-        return $this->registry->deletePackage($package);
+        return $this->_registry->deletePackage($package, $channel);
+    }
+
+    /**
+     * Sort a list of arrays of array(downloaded packagefilename) by dependency.
+     *
+     * It also removes duplicate dependencies
+     * @param array an array of PEAR_PackageFile_v[1/2] objects
+     * @return array|PEAR_Error array of array(packagefilename, package.xml contents)
+     */
+    function sortPackagesForUninstall(&$packages)
+    {
+        $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->config);
+        if (PEAR::isError($this->_dependencyDB)) {
+            return $this->_dependencyDB;
+        }
+        usort($packages, array(&$this, '_sortUninstall'));
+    }
+
+    function _sortUninstall($a, $b)
+    {
+        if (!$a->getDeps() && !$b->getDeps()) {
+            return 0; // neither package has dependencies, order is insignificant
+        }
+        if ($a->getDeps() && !$b->getDeps()) {
+            return -1; // $a must be installed after $b because $a has dependencies
+        }
+        if (!$a->getDeps() && $b->getDeps()) {
+            return 1; // $b must be installed after $a because $b has dependencies
+        }
+        // both packages have dependencies
+        if ($this->_dependencyDB->dependsOn($a, $b)) {
+            return -1;
+        }
+        if ($this->_dependencyDB->dependsOn($b, $a)) {
+            return 1;
+        }
+        return 0;
     }
 
     // }}}
@@ -954,92 +1513,7 @@ class PEAR_Installer extends PEAR_Downloader
     }
 
     // }}}
-    // {{{ 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)
@@ -1058,11 +1532,16 @@ if (!function_exists("md5_file")) {
     function md5_file($filename) {
         $fp = fopen($filename, "r");
         if (!$fp) return null;
-        $contents = fread($fp, filesize($filename));
-        fclose($fp);
+        if (function_exists('file_get_contents')) {
+            fclose($fp);
+            $contents = file_get_contents($filename);
+        } else {
+            $contents = fread($fp, filesize($filename));
+            fclose($fp);
+        }
         return md5($contents);
     }
 }
 // }}}
 
-?>
+?>
\ No newline at end of file
diff --git a/pear/PEAR/Installer/Role.php b/pear/PEAR/Installer/Role.php
new file mode 100644 (file)
index 0000000..177d006
--- /dev/null
@@ -0,0 +1,248 @@
+<?php
+/**
+ * PEAR_Installer_Role
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a1
+ */
+
+/**
+ * base class for installer roles
+ */
+require_once 'PEAR/Installer/Role/Common.php';
+require_once 'PEAR/XMLParser.php';
+//$GLOBALS['_PEAR_INSTALLER_ROLES'] = array();
+/**
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
+ */
+class PEAR_Installer_Role
+{
+    /**
+     * Set up any additional configuration variables that file roles require
+     *
+     * Never call this directly, it is called by the PEAR_Config constructor
+     * @param PEAR_Config
+     * @access private
+     * @static
+     */
+    function initializeConfig(&$config)
+    {
+        if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) {
+            PEAR_Installer_Role::registerRoles();
+        }
+        foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $class => $info) {
+            if (!$info['config_vars']) {
+                continue;
+            }
+            $config->_addConfigVars($info['config_vars']);
+        }
+    }
+
+    /**
+     * @param PEAR_PackageFile_v2
+     * @param string role name
+     * @param PEAR_Config
+     * @return PEAR_Installer_Role_Common
+     * @static
+     */
+    function &factory($pkg, $role, &$config)
+    {
+        if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) {
+            PEAR_Installer_Role::registerRoles();
+        }
+        if (!in_array($role, PEAR_Installer_Role::getValidRoles($pkg->getPackageType()))) {
+            $a = false;
+            return $a;
+        }
+        $a = 'PEAR_Installer_Role_' . ucfirst($role);
+        if (!class_exists($a)) {
+            require_once str_replace('_', '/', $a) . '.php';
+        }
+        $b = new $a($config);
+        return $b;
+    }
+
+    /**
+     * Get a list of file roles that are valid for the particular release type.
+     *
+     * For instance, src files serve no purpose in regular php releases.  php files
+     * serve no purpose in extsrc or extbin releases
+     * @param string
+     * @param bool clear cache
+     * @return array
+     * @static
+     */
+    function getValidRoles($release, $clear = false)
+    {
+        if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) {
+            PEAR_Installer_Role::registerRoles();
+        }
+        static $ret = array();
+        if ($clear) {
+            $ret = array();
+        }
+        if (isset($ret[$release])) {
+            return $ret[$release];
+        }
+        $ret[$release] = array();
+        foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) {
+            if (in_array($release, $okreleases['releasetypes'])) {
+                $ret[$release][] = strtolower(str_replace('PEAR_Installer_Role_', '', $role));
+            }
+        }
+        return $ret[$release];
+    }
+
+    /**
+     * Get a list of roles that require their files to be installed
+     *
+     * Most roles must be installed, but src and package roles, for instance
+     * are pseudo-roles.  src files are compiled into a new extension.  Package
+     * roles are actually fully bundled releases of a package
+     * @param bool clear cache
+     * @return array
+     * @static
+     */
+    function getInstallableRoles($clear = false)
+    {
+        if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) {
+            PEAR_Installer_Role::registerRoles();
+        }
+        static $ret;
+        if ($clear) {
+            unset($ret);
+        }
+        if (!isset($ret)) {
+            foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) {
+                if ($okreleases['installable']) {
+                    $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role));
+                }
+            }
+        }
+        return $ret;
+    }
+
+    /**
+     * Return an array of roles that are affected by the baseinstalldir attribute
+     *
+     * Most roles ignore this attribute, and instead install directly into:
+     * PackageName/filepath
+     * so a tests file tests/file.phpt is installed into PackageName/tests/filepath.php
+     * @param bool clear cache
+     * @return array
+     * @static
+     */
+    function getBaseinstallRoles($clear = false)
+    {
+        if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) {
+            PEAR_Installer_Role::registerRoles();
+        }
+        static $ret;
+        if ($clear) {
+            unset($ret);
+        }
+        if (!isset($ret)) {
+            foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) {
+                if ($okreleases['honorsbaseinstall']) {
+                    $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role));
+                }
+            }
+        }
+        return $ret;
+    }
+
+    /**
+     * Return an array of file roles that should be analyzed for PHP content at package time,
+     * like the "php" role.
+     * @param bool clear cache
+     * @return array
+     * @static
+     */
+    function getPhpRoles($clear = false)
+    {
+        if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) {
+            PEAR_Installer_Role::registerRoles();
+        }
+        static $ret;
+        if ($clear) {
+            unset($ret);
+        }
+        if (!isset($ret)) {
+            foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) {
+                if ($okreleases['phpfile']) {
+                    $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role));
+                }
+            }
+        }
+        return $ret;
+    }
+
+    /**
+     * Scan through the Command directory looking for classes
+     * and see what commands they implement.
+     * @param string which directory to look for classes, defaults to
+     *               the Installer/Roles subdirectory of
+     *               the directory from where this file (__FILE__) is
+     *               included.
+     *
+     * @return bool TRUE on success, a PEAR error on failure
+     * @access public
+     * @static
+     */
+    function registerRoles($dir = null)
+    {
+        $parser = new PEAR_XMLParser;
+        if ($dir === null) {
+            $dir = dirname(__FILE__) . '/Role';
+        }
+        $dp = @opendir($dir);
+        if (empty($dp)) {
+            return PEAR::raiseError("registerRoles: opendir($dir) failed");
+        }
+        while ($entry = readdir($dp)) {
+            if ($entry{0} == '.' || substr($entry, -4) != '.xml') {
+                continue;
+            }
+            $class = "PEAR_Installer_Role_".substr($entry, 0, -4);
+            // List of roles
+            if (empty($GLOBALS['_PEAR_INSTALLER_ROLES'][$class])) {
+                $file = "$dir/$entry";
+                $parser->parse(file_get_contents($file));
+                $data = $parser->getData();
+                if (!is_array($data['releasetypes'])) {
+                    $data['releasetypes'] = array($data['releasetypes']);
+                }
+                $GLOBALS['_PEAR_INSTALLER_ROLES'][$class] = $data;
+            }
+        }
+        @closedir($dp);
+        ksort($GLOBALS['_PEAR_INSTALLER_ROLES']);
+        PEAR_Installer_Role::getBaseinstallRoles(true);
+        PEAR_Installer_Role::getInstallableRoles(true);
+        PEAR_Installer_Role::getPhpRoles(true);
+        PEAR_Installer_Role::getValidRoles('****', true);
+        return true;
+    }
+}
+?>
diff --git a/pear/PEAR/Installer/Role/Common.php b/pear/PEAR/Installer/Role/Common.php
new file mode 100644 (file)
index 0000000..a5fd4b9
--- /dev/null
@@ -0,0 +1,180 @@
+<?php
+/**
+ * Base class for all installation roles.
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a1
+ */
+/**
+ * Base class for all installation roles.
+ *
+ * This class allows extensibility of file roles.  Packages with complex
+ * customization can now provide custom file roles along with the possibility of
+ * adding configuration values to match.
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
+ */
+class PEAR_Installer_Role_Common
+{
+    /**
+     * @var PEAR_Config
+     * @access protected
+     */
+    var $config;
+
+    /**
+     * @param PEAR_Config
+     */
+    function PEAR_Installer_Role_Common(&$config)
+    {
+        $this->config = $config;
+    }
+
+    /**
+     * Retrieve configuration information about a file role from its XML info
+     *
+     * @param string $role Role Classname, as in "PEAR_Installer_Role_Data"
+     * @return array
+     */
+    function getInfo($role)
+    {
+        if (empty($GLOBALS['_PEAR_INSTALLER_ROLES'][$role])) {
+            return PEAR::raiseError('Unknown Role class: "' . $role . '"');
+        }
+        return $GLOBALS['_PEAR_INSTALLER_ROLES'][$role];
+    }
+
+    /**
+     * This is called for each file to set up the directories and files
+     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+     * @param array attributes from the <file> tag
+     * @param string file name
+     * @return array an array consisting of:
+     *
+     *    1 the original, pre-baseinstalldir installation directory
+     *    2 the final installation directory
+     *    3 the full path to the final location of the file
+     *    4 the location of the pre-installation file
+     */
+    function processInstallation($pkg, $atts, $file, $tmp_path, $layer = null)
+    {
+        $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . 
+            ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this)))));
+        if (PEAR::isError($roleInfo)) {
+            return $roleInfo;
+        }
+        if (!$roleInfo['locationconfig']) {
+            return false;
+        }
+        if ($roleInfo['honorsbaseinstall']) {
+            $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'], $layer,
+                $pkg->getChannel());
+            if (!empty($atts['baseinstalldir'])) {
+                $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir'];
+            }
+        } elseif ($roleInfo['unusualbaseinstall']) {
+            $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'],
+                    null, $pkg->getChannel()) . DIRECTORY_SEPARATOR . $pkg->getPackage();
+            if (!empty($atts['baseinstalldir'])) {
+                $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir'];
+            }
+        } else {
+            $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'],
+                    null, $pkg->getChannel()) . DIRECTORY_SEPARATOR . $pkg->getPackage();
+        }
+        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_dir, $dest_file, $orig_file) = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"),
+                                                    array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR,
+                                                          DIRECTORY_SEPARATOR),
+                                                    array($dest_dir, $dest_file, $orig_file));
+        return array($save_destdir, $dest_dir, $dest_file, $orig_file);
+    }
+
+    /**
+     * Get the name of the configuration variable that specifies the location of this file
+     * @return string|false
+     */
+    function getLocationConfig()
+    {
+        $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . 
+            ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this)))));
+        if (PEAR::isError($roleInfo)) {
+            return $roleInfo;
+        }
+        return $roleInfo['locationconfig'];
+    }
+
+    /**
+     * Do any unusual setup here
+     * @param PEAR_Installer
+     * @param PEAR_PackageFile_v2
+     * @param array file attributes
+     * @param string file name
+     */
+    function setup(&$installer, $pkg, $atts, $file)
+    {
+    }
+
+    function isExecutable()
+    {
+        $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . 
+            ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this)))));
+        if (PEAR::isError($roleInfo)) {
+            return $roleInfo;
+        }
+        return $roleInfo['executable'];
+    }
+
+    function isInstallable()
+    {
+        $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . 
+            ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this)))));
+        if (PEAR::isError($roleInfo)) {
+            return $roleInfo;
+        }
+        return $roleInfo['installable'];
+    }
+
+    function isExtension()
+    {
+        $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . 
+            ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this)))));
+        if (PEAR::isError($roleInfo)) {
+            return $roleInfo;
+        }
+        return $roleInfo['phpextension'];
+    }
+}
+?>
\ No newline at end of file
diff --git a/pear/PEAR/Installer/Role/Data.php b/pear/PEAR/Installer/Role/Data.php
new file mode 100644 (file)
index 0000000..1d8f47f
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+/**
+ * PEAR_Installer_Role_Data
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a1
+ */
+
+/**
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
+ */
+class PEAR_Installer_Role_Data extends PEAR_Installer_Role_Common {}
+?>
\ No newline at end of file
diff --git a/pear/PEAR/Installer/Role/Data.xml b/pear/PEAR/Installer/Role/Data.xml
new file mode 100644 (file)
index 0000000..4382b70
--- /dev/null
@@ -0,0 +1,13 @@
+<role version="1.0">
+ <releasetypes>php</releasetypes>
+ <releasetypes>extsrc</releasetypes>
+ <releasetypes>extbin</releasetypes>
+ <installable>1</installable>
+ <locationconfig>data_dir</locationconfig>
+ <honorsbaseinstall />
+ <unusualbaseinstall />
+ <phpfile />
+ <executable />
+ <phpextension />
+ <config_vars />
+</role>
\ No newline at end of file
diff --git a/pear/PEAR/Installer/Role/Doc.php b/pear/PEAR/Installer/Role/Doc.php
new file mode 100644 (file)
index 0000000..c7d318c
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+/**
+ * PEAR_Installer_Role_Doc
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a1
+ */
+
+/**
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
+ */
+class PEAR_Installer_Role_Doc extends PEAR_Installer_Role_Common {}
+?>
\ No newline at end of file
diff --git a/pear/PEAR/Installer/Role/Doc.xml b/pear/PEAR/Installer/Role/Doc.xml
new file mode 100644 (file)
index 0000000..0c593ef
--- /dev/null
@@ -0,0 +1,13 @@
+<role version="1.0">
+ <releasetypes>php</releasetypes>
+ <releasetypes>extsrc</releasetypes>
+ <releasetypes>extbin</releasetypes>
+ <installable>1</installable>
+ <locationconfig>doc_dir</locationconfig>
+ <honorsbaseinstall />
+ <unusualbaseinstall />
+ <phpfile />
+ <executable />
+ <phpextension />
+ <config_vars />
+</role>
\ No newline at end of file
diff --git a/pear/PEAR/Installer/Role/Ext.php b/pear/PEAR/Installer/Role/Ext.php
new file mode 100644 (file)
index 0000000..ddd1a44
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+/**
+ * PEAR_Installer_Role_Ext
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a1
+ */
+
+/**
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
+ */
+class PEAR_Installer_Role_Ext extends PEAR_Installer_Role_Common {}
+?>
\ No newline at end of file
diff --git a/pear/PEAR/Installer/Role/Ext.xml b/pear/PEAR/Installer/Role/Ext.xml
new file mode 100644 (file)
index 0000000..d5c1c48
--- /dev/null
@@ -0,0 +1,11 @@
+<role version="1.0">
+ <releasetypes>extbin</releasetypes>
+ <installable>1</installable>
+ <locationconfig>ext_dir</locationconfig>
+ <honorsbaseinstall>1</honorsbaseinstall>
+ <unusualbaseinstall />
+ <phpfile />
+ <executable />
+ <phpextension>1</phpextension>
+ <config_vars />
+</role>
\ No newline at end of file
diff --git a/pear/PEAR/Installer/Role/Php.php b/pear/PEAR/Installer/Role/Php.php
new file mode 100644 (file)
index 0000000..ae9f97e
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+/**
+ * PEAR_Installer_Role_Php
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a1
+ */
+
+/**
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
+ */
+class PEAR_Installer_Role_Php extends PEAR_Installer_Role_Common {}
+?>
\ No newline at end of file
diff --git a/pear/PEAR/Installer/Role/Php.xml b/pear/PEAR/Installer/Role/Php.xml
new file mode 100644 (file)
index 0000000..037c2a1
--- /dev/null
@@ -0,0 +1,13 @@
+<role version="1.0">
+ <releasetypes>php</releasetypes>
+ <releasetypes>extsrc</releasetypes>
+ <releasetypes>extbin</releasetypes>
+ <installable>1</installable>
+ <locationconfig>php_dir</locationconfig>
+ <honorsbaseinstall>1</honorsbaseinstall>
+ <unusualbaseinstall />
+ <phpfile>1</phpfile>
+ <executable />
+ <phpextension />
+ <config_vars />
+</role>
\ No newline at end of file
diff --git a/pear/PEAR/Installer/Role/Script.php b/pear/PEAR/Installer/Role/Script.php
new file mode 100644 (file)
index 0000000..cfe0a0d
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+/**
+ * PEAR_Installer_Role_Script
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a1
+ */
+
+/**
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
+ */
+class PEAR_Installer_Role_Script extends PEAR_Installer_Role_Common {}
+?>
\ No newline at end of file
diff --git a/pear/PEAR/Installer/Role/Script.xml b/pear/PEAR/Installer/Role/Script.xml
new file mode 100644 (file)
index 0000000..bc2df17
--- /dev/null
@@ -0,0 +1,13 @@
+<role version="1.0">
+ <releasetypes>php</releasetypes>
+ <releasetypes>extsrc</releasetypes>
+ <releasetypes>extbin</releasetypes>
+ <installable>1</installable>
+ <locationconfig>bin_dir</locationconfig>
+ <honorsbaseinstall>1</honorsbaseinstall>
+ <unusualbaseinstall />
+ <phpfile />
+ <executable>1</executable>
+ <phpextension />
+ <config_vars />
+</role>
\ No newline at end of file
diff --git a/pear/PEAR/Installer/Role/Src.php b/pear/PEAR/Installer/Role/Src.php
new file mode 100644 (file)
index 0000000..fed8820
--- /dev/null
@@ -0,0 +1,40 @@
+<?php
+/**
+ * PEAR_Installer_Role_Src
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a1
+ */
+
+/**
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
+ */
+class PEAR_Installer_Role_Src extends PEAR_Installer_Role_Common
+{
+    function setup(&$installer, $pkg, $atts, $file)
+    {
+        $installer->source_files++;
+    }
+}
+?>
\ No newline at end of file
diff --git a/pear/PEAR/Installer/Role/Src.xml b/pear/PEAR/Installer/Role/Src.xml
new file mode 100644 (file)
index 0000000..c2fb4d1
--- /dev/null
@@ -0,0 +1,11 @@
+<role version="1.0">
+ <releasetypes>extsrc</releasetypes>
+ <installable />
+ <locationconfig />
+ <honorsbaseinstall />
+ <unusualbaseinstall />
+ <phpfile />
+ <executable />
+ <phpextension />
+ <config_vars />
+</role>
\ No newline at end of file
diff --git a/pear/PEAR/Installer/Role/Test.php b/pear/PEAR/Installer/Role/Test.php
new file mode 100644 (file)
index 0000000..2ecfd64
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+/**
+ * PEAR_Installer_Role_Test
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a1
+ */
+
+/**
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
+ */
+class PEAR_Installer_Role_Test extends PEAR_Installer_Role_Common {}
+?>
\ No newline at end of file
diff --git a/pear/PEAR/Installer/Role/Test.xml b/pear/PEAR/Installer/Role/Test.xml
new file mode 100644 (file)
index 0000000..dd48642
--- /dev/null
@@ -0,0 +1,13 @@
+<role version="1.0">
+ <releasetypes>php</releasetypes>
+ <releasetypes>extsrc</releasetypes>
+ <releasetypes>extbin</releasetypes>
+ <installable>1</installable>
+ <locationconfig>test_dir</locationconfig>
+ <honorsbaseinstall />
+ <unusualbaseinstall />
+ <phpfile />
+ <executable />
+ <phpextension />
+ <config_vars />
+</role>
\ No newline at end of file
diff --git a/pear/PEAR/PackageFile.php b/pear/PEAR/PackageFile.php
new file mode 100644 (file)
index 0000000..6f677a3
--- /dev/null
@@ -0,0 +1,436 @@
+<?php
+/**
+ * PEAR_PackageFile, package.xml parsing utility class
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a1
+ */
+
+/**
+ * needed for PEAR_VALIDATE_* constants
+ */
+require_once 'PEAR/Validate.php';
+/**
+ * Error code if the package.xml <package> tag does not contain a valid version
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_PACKAGEVERSION', 1);
+/**
+ * Error code if the package.xml <package> tag version is not supported (version 1.0 and 1.1 are the only supported versions,
+ * currently
+ */
+define('PEAR_PACKAGEFILE_ERROR_INVALID_PACKAGEVERSION', 2);
+/**
+ * Abstraction for the package.xml package description file
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @PEAR-VER@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
+ */
+class PEAR_PackageFile
+{
+    /**
+     * @var PEAR_Config
+     */
+    var $_config;
+    var $_debug;
+    /**
+     * Temp directory for uncompressing tgz files.
+     * @var string|false
+     */
+    var $_tmpdir;
+    var $_logger = false;
+    /**
+     * @var boolean
+     */
+    var $_rawReturn = false;
+
+    /**
+     *
+     * @param   PEAR_Config $config
+     * @param   ?   $debug
+     * @param   string @tmpdir Optional temporary directory for uncompressing
+     *          files
+     */
+    function PEAR_PackageFile(&$config, $debug = false, $tmpdir = false)
+    {
+        $this->_config = $config;
+        $this->_debug = $debug;
+        $this->_tmpdir = $tmpdir;
+    }
+
+    /**
+     * Turn off validation - return a parsed package.xml without checking it
+     *
+     * This is used by the package-validate command
+     */
+    function rawReturn()
+    {
+        $this->_rawReturn = true;
+    }
+
+    function setLogger(&$l)
+    {
+        $this->_logger = &$l;
+    }
+
+    /**
+     * Create a PEAR_PackageFile_Parser_v* of a given version.
+     * @param   int $version
+     * @return  PEAR_PackageFile_Parser_v1|PEAR_PackageFile_Parser_v1
+     */
+    function &parserFactory($version)
+    {
+        if (!in_array($version{0}, array('1', '2'))) {
+            $a = false;
+            return $a;
+        }
+        include_once 'PEAR/PackageFile/Parser/v' . $version{0} . '.php';
+        $version = $version{0};
+        $class = "PEAR_PackageFile_Parser_v$version";
+        $a = new $class;
+        return $a;
+    }
+
+    /**
+     * For simpler unit-testing
+     * @return string
+     */
+    function getClassPrefix()
+    {
+        return 'PEAR_PackageFile_v';
+    }
+
+    /**
+     * Create a PEAR_PackageFile_v* of a given version.
+     * @param   int $version
+     * @return  PEAR_PackageFile_v1|PEAR_PackageFile_v1
+     */
+    function &factory($version)
+    {
+        if (!in_array($version{0}, array('1', '2'))) {
+            $a = false;
+            return $a;
+        }
+        include_once 'PEAR/PackageFile/v' . $version{0} . '.php';
+        $version = $version{0};
+        $class = $this->getClassPrefix() . $version;
+        $a = new $class;
+        return $a;
+    }
+
+    /**
+     * Create a PEAR_PackageFile_v* from its toArray() method
+     *
+     * WARNING: no validation is performed, the array is assumed to be valid,
+     * always parse from xml if you want validation.
+     * @param   array $arr
+     * @return PEAR_PackageFileManager_v1|PEAR_PackageFileManager_v2
+     * @uses    factory() to construct the returned object.
+     */
+    function &fromArray($arr)
+    {
+        if (isset($arr['xsdversion'])) {
+            $obj = &$this->factory($arr['xsdversion']);
+            if ($this->_logger) {
+                $obj->setLogger($this->_logger);
+            }
+            $obj->setConfig($this->_config);
+            $obj->fromArray($arr);
+            return $obj;
+        } else {
+            if (isset($arr['package']['attribs']['version'])) {
+                $obj = &$this->factory($arr['package']['attribs']['version']);
+            } else {
+                $obj = &$this->factory('1.0');
+            }
+            if ($this->_logger) {
+                $obj->setLogger($this->_logger);
+            }
+            $obj->setConfig($this->_config);
+            $obj->fromArray($arr);
+            return $obj;
+        }
+    }
+
+    /**
+     * Create a PEAR_PackageFile_v* from an XML string.
+     * @access  public
+     * @param   string $data contents of package.xml file
+     * @param   int $state package state (one of PEAR_VALIDATE_* constants)
+     * @param   string $file full path to the package.xml file (and the files
+     *          it references)
+     * @param   string $archive optional name of the archive that the XML was
+     *          extracted from, if any
+     * @return  PEAR_PackageFile_v1|PEAR_PackageFile_v2
+     * @uses    parserFactory() to construct a parser to load the package.
+     */
+    function &fromXmlString($data, $state, $file, $archive = false)
+    {
+        if (preg_match('/<package[^>]+version="([0-9]+\.[0-9]+)"/', $data, $packageversion)) {
+            if (!in_array($packageversion[1], array('1.0', '2.0'))) {
+                return PEAR::raiseError('package.xml version "' . $packageversion[1] .
+                    '" is not supported, only 1.0 and 2.0 are supported.');
+            }
+            $object = &$this->parserFactory($packageversion[1]);
+            if ($this->_logger) {
+                $object->setLogger($this->_logger);
+            }
+            $object->setConfig($this->_config);
+            $pf = $object->parse($data, $file, $archive);
+            if (PEAR::isError($pf)) {
+                return $pf;
+            }
+            if ($this->_rawReturn) {
+                return $pf;
+            }
+            if ($pf->validate($state)) {
+                if ($this->_logger) {
+                    if ($pf->getValidationWarnings(false)) {
+                        foreach ($pf->getValidationWarnings() as $warning) {
+                            $this->_logger->log(0, 'WARNING: ' . $warning['message']);
+                        }
+                    }
+                }
+                if (method_exists($pf, 'flattenFilelist')) {
+                    $pf->flattenFilelist(); // for v2
+                }
+                return $pf;
+            } else {
+                if ($this->_config->get('verbose') > 0) {
+                    if ($this->_logger) {
+                        if ($pf->getValidationWarnings(false)) {
+                            foreach ($pf->getValidationWarnings(false) as $warning) {
+                                $this->_logger->log(0, 'ERROR: ' . $warning['message']);
+                            }
+                        }
+                    }
+                }
+                $a = PEAR::raiseError('Parsing of package.xml from file "' . $file . '" failed',
+                    2, null, null, $pf->getValidationWarnings());
+                return $a;
+            }
+        } elseif (preg_match('/<package[^>]+version="([^"]+)"/', $data, $packageversion)) {
+            $a = PEAR::raiseError('package.xml file "' . $file .
+                '" has unsupported package.xml <package> version "' . $packageversion[1] . '"');
+            return $a;
+        } else {
+            if (!class_exists('PEAR_ErrorStack')) {
+                require_once 'PEAR/ErrorStack.php';
+            }
+            PEAR_ErrorStack::staticPush('PEAR_PackageFile',
+                PEAR_PACKAGEFILE_ERROR_NO_PACKAGEVERSION,
+                'warning', array('xml' => $data), 'package.xml "' . $file .
+                    '" has no package.xml <package> version');
+            $object = &$this->parserFactory('1.0');
+            $object->setConfig($this->_config);
+            $pf = $object->parse($data, $file, $archive);
+            if (PEAR::isError($pf)) {
+                return $pf;
+            }
+            if ($this->_rawReturn) {
+                return $pf;
+            }
+            if ($pf->validate($state)) {
+                if ($this->_logger) {
+                    if ($pf->getValidationWarnings(false)) {
+                        foreach ($pf->getValidationWarnings() as $warning) {
+                            $this->_logger->log(0, 'WARNING: ' . $warning['message']);
+                        }
+                    }
+                }
+                if (method_exists($pf, 'flattenFilelist')) {
+                    $pf->flattenFilelist(); // for v2
+                }
+                return $pf;
+            } else {
+                $a = PEAR::raiseError('Parsing of package.xml from file "' . $file . '" failed',
+                    2, null, null, $pf->getValidationWarnings());
+                return $a;
+            }
+        }
+    }
+
+    /**
+     * Register a temporary file or directory.  When the destructor is
+     * executed, all registered temporary files and directories are
+     * removed.
+     *
+     * @param string  $file  name of file or directory
+     * @return  void
+     */
+    function addTempFile($file)
+    {
+        $GLOBALS['_PEAR_Common_tempfiles'][] = $file;
+    }
+
+    /**
+     * Create a PEAR_PackageFile_v* from a compresed Tar or Tgz file.
+     * @access  public
+     * @param string contents of package.xml file
+     * @param int package state (one of PEAR_VALIDATE_* constants)
+     * @return  PEAR_PackageFile_v1|PEAR_PackageFile_v2
+     * @using   Archive_Tar to extract the files
+     * @using   fromPackageFile() to load the package after the package.xml
+     *          file is extracted.
+     */
+    function &fromTgzFile($file, $state)
+    {
+        if (!class_exists('Archive_Tar')) {
+            require_once 'Archive/Tar.php';
+        }
+        $tar = new Archive_Tar($file);
+        if ($this->_debug <= 1) {
+            $tar->pushErrorHandling(PEAR_ERROR_RETURN);
+        }
+        $content = $tar->listContent();
+        if ($this->_debug <= 1) {
+            $tar->popErrorHandling();
+        }
+        if (!is_array($content)) {
+            if (is_string($file) && strlen($file < 255) && !@is_file($file)) {
+                $ret = PEAR::raiseError("could not open file \"$file\"");
+                return $ret;
+            }
+            $file = realpath($file);
+            $ret = PEAR::raiseError("Could not get contents of package \"$file\"".
+                                     '. Invalid tgz file.');
+            return $ret;
+        } else {
+            if (!count($content) && !@is_file($file)) {
+                $ret = PEAR::raiseError("could not open file \"$file\"");
+                return $ret;
+            }
+        }
+        $xml = null;
+        $origfile = $file;
+        foreach ($content as $file) {
+            $name = $file['filename'];
+            if ($name == 'package2.xml') { // allow a .tgz to distribute both versions
+                $xml = $name;
+                break;
+            }
+            if ($name == 'package.xml') {
+                $xml = $name;
+                break;
+            } elseif (ereg('package.xml$', $name, $match)) {
+                $xml = $match[0];
+                break;
+            }
+        }
+        if ($this->_tmpdir) {
+            $tmpdir = $this->_tmpdir;
+        } else {
+            $tmpdir = System::mkTemp(array('-d', 'pear'));
+            PEAR_PackageFile::addTempFile($tmpdir);
+        }
+        if (!$xml || !$tar->extractList(array($xml), $tmpdir)) {
+            $ret = PEAR::raiseError('could not extract the package.xml file from "' .
+                $origfile . '"');
+            return $ret;
+        }
+        $ret = &PEAR_PackageFile::fromPackageFile("$tmpdir/$xml", $state, $origfile);
+        return $ret;
+    }
+
+    /**
+     * Create a PEAR_PackageFile_v* from a package.xml file.
+     *
+     * @access public
+     * @param   string  $descfile  name of package xml file
+     * @param   int     $state package state (one of PEAR_VALIDATE_* constants)
+     * @param   string|false $archive name of the archive this package.xml came
+     *          from, if any
+     * @return  PEAR_PackageFile_v1|PEAR_PackageFile_v2
+     * @uses    PEAR_PackageFile::fromXmlString to create the oject after the
+     *          XML is loaded from the package.xml file.
+     */
+    function &fromPackageFile($descfile, $state, $archive = false)
+    {
+        if (is_string($descfile) && strlen($descfile) < 255 &&
+             !@is_file($descfile) || !is_readable($descfile) ||
+             (!$fp = @fopen($descfile, 'r'))) {
+            $a = PEAR::raiseError("Unable to open $descfile");
+            return $a;
+        }
+
+        // read the whole thing so we only get one cdata callback
+        // for each block of cdata
+        if (function_exists('file_get_contents')) {
+            @fclose($fp);
+            $data = file_get_contents($descfile);
+        } else {
+            $data = '';
+            while (!feof($fp)) {
+                $data .= @fread($fp, 8192);
+            }
+            fclose($fp);
+        }
+        $ret = &PEAR_PackageFile::fromXmlString($data, $state, $descfile, $archive);
+        return $ret;
+    }
+
+
+    /**
+     * Create a PEAR_PackageFile_v* from a .tgz archive or package.xml file.
+     *
+     * This method is able to extract information about a package from a .tgz
+     * archive or from a XML package definition file.
+     *
+     * @access public
+     * @param   string  $info file name
+     * @param   int     $state package state (one of PEAR_VALIDATE_* constants)
+     * @return  PEAR_PackageFile_v1|PEAR_PackageFile_v2
+     * @uses    fromPackageFile() if the file appears to be XML
+     * @uses    fromTgzFile() to load all non-XML files
+     */
+    function &fromAnyFile($info, $state)
+    {
+        $fp = false;
+        if (is_string($info) && strlen($info) < 255 &&
+             (file_exists($info) || ($fp = @fopen($info, 'r')))) {
+            if ($fp) {
+                fclose($fp);
+            }
+            $tmp = substr($info, -4);
+            if ($tmp == '.xml') {
+                $info = &PEAR_PackageFile::fromPackageFile($info, $state);
+            } elseif ($tmp == '.tar' || $tmp == '.tgz') {
+                $info = &PEAR_PackageFile::fromTgzFile($info, $state);
+            } else {
+                $fp = fopen($info, "r");
+                $test = fread($fp, 5);
+                fclose($fp);
+                if ($test == "<?xml") {
+                    $info = &PEAR_PackageFile::fromPackageFile($info, $state);
+                } else {
+                    $info = &PEAR_PackageFile::fromTgzFile($info, $state);
+                }
+            }
+        } else {
+            $info = PEAR::raiseError("Cannot open '$info' for parsing");
+            return $info;
+        }
+        return $info;
+    }
+}
+
+?>
\ No newline at end of file
diff --git a/pear/PEAR/PackageFile/Generator/v1.php b/pear/PEAR/PackageFile/Generator/v1.php
new file mode 100644 (file)
index 0000000..688e9b9
--- /dev/null
@@ -0,0 +1,1267 @@
+<?php
+/**
+ * package.xml generation class, package.xml version 1.0
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a1
+ */
+/**
+ * needed for PEAR_VALIDATE_* constants
+ */
+require_once 'PEAR/Validate.php';
+require_once 'System.php';
+require_once 'PEAR/PackageFile/v2.php';
+/**
+ * This class converts a PEAR_PackageFile_v1 object into any output format.
+ *
+ * Supported output formats include array, XML string, and a PEAR_PackageFile_v2
+ * object, for converting package.xml 1.0 into package.xml 2.0 with no sweat.
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @PEAR-VER@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
+ */
+class PEAR_PackageFile_Generator_v1
+{
+    /**
+     * @var PEAR_PackageFile_v1
+     */
+    var $_packagefile;
+    function PEAR_PackageFile_Generator_v1(&$packagefile)
+    {
+        $this->_packagefile = &$packagefile;
+    }
+
+    function getPackagerVersion()
+    {
+        return '@PEAR-VER@';
+    }
+
+    /**
+     * @param PEAR_Packager
+     * @param bool if true, a .tgz is written, otherwise a .tar is written
+     * @param string|null directory in which to save the .tgz
+     * @return string|PEAR_Error location of package or error object
+     */
+    function toTgz(&$packager, $compress = true, $where = null)
+    {
+        require_once 'Archive/Tar.php';
+        if ($where === null) {
+            if (!($where = System::mktemp(array('-d')))) {
+                return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: mktemp failed');
+            }
+        } elseif (!@System::mkDir(array('-p', $where))) {
+            return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: "' . $where . '" could' .
+                ' not be created');
+        }
+        if (file_exists($where . DIRECTORY_SEPARATOR . 'package.xml') &&
+              !is_file($where . DIRECTORY_SEPARATOR . 'package.xml')) {
+            return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: unable to save package.xml as' .
+                ' "' . $where . DIRECTORY_SEPARATOR . 'package.xml"');
+        }
+        if (!$this->_packagefile->validate(PEAR_VALIDATE_PACKAGING)) {
+            return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: invalid package file');
+        }
+        $pkginfo = $this->_packagefile->getArray();
+        $ext = $compress ? '.tgz' : '.tar';
+        $pkgver = $pkginfo['package'] . '-' . $pkginfo['version'];
+        $dest_package = getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext;
+        if (file_exists(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext) &&
+              !is_file(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext)) {
+            return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: cannot create tgz file "' .
+                getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext . '"');
+        }
+        if ($pkgfile = $this->_packagefile->getPackageFile()) {
+            $pkgdir = dirname(realpath($pkgfile));
+            $pkgfile = basename($pkgfile);
+        } else {
+            return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: package file object must ' .
+                'be created from a real file');
+        }
+        // {{{ Create the package file list
+        $filelist = array();
+        $i = 0;
+
+        foreach ($this->_packagefile->getFilelist() as $fname => $atts) {
+            $file = $pkgdir . DIRECTORY_SEPARATOR . $fname;
+            if (!file_exists($file)) {
+                return PEAR::raiseError("File does not exist: $fname");
+            } else {
+                $filelist[$i++] = $file;
+                if (!isset($atts['md5sum'])) {
+                    $this->_packagefile->setFileAttribute($fname, 'md5sum', md5_file($file));
+                }
+                $packager->log(2, "Adding file $fname");
+            }
+        }
+        // }}}
+        $packagexml = $this->toPackageFile($where, PEAR_VALIDATE_PACKAGING, 'package.xml', true);
+        if ($packagexml) {
+            $tar =& new Archive_Tar($dest_package, $compress);
+            $tar->setErrorHandling(PEAR_ERROR_RETURN); // XXX Don't print errors
+            // ----- Creates with the package.xml file
+            $ok = $tar->createModify(array($packagexml), '', $where);
+            if (PEAR::isError($ok)) {
+                return $ok;
+            } elseif (!$ok) {
+                return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: tarball creation failed');
+            }
+            // ----- Add the content of the package
+            if (!$tar->addModify($filelist, $pkgver, $pkgdir)) {
+                return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: tarball creation failed');
+            }
+            return $dest_package;
+        }
+    }
+
+    /**
+     * @param string|null directory to place the package.xml in, or null for a temporary dir
+     * @param int one of the PEAR_VALIDATE_* constants
+     * @param string name of the generated file
+     * @param bool if true, then no analysis will be performed on role="php" files
+     * @return string|PEAR_Error path to the created file on success
+     */
+    function toPackageFile($where = null, $state = PEAR_VALIDATE_NORMAL, $name = 'package.xml',
+                           $nofilechecking = false)
+    {
+        if (!$this->_packagefile->validate($state, $nofilechecking)) {
+            return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: invalid package.xml',
+                null, null, null, $this->_packagefile->getValidationWarnings());
+        }
+        if ($where === null) {
+            if (!($where = System::mktemp(array('-d')))) {
+                return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: mktemp failed');
+            }
+        } elseif (!@System::mkDir(array('-p', $where))) {
+            return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: "' . $where . '" could' .
+                ' not be created');
+        }
+        $newpkgfile = $where . DIRECTORY_SEPARATOR . $name;
+        $np = @fopen($newpkgfile, 'wb');
+        if (!$np) {
+            return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: unable to save ' .
+               "$name as $newpkgfile");
+        }
+        fwrite($np, $this->toXml($state, true));
+        fclose($np);
+        return $newpkgfile;
+    }
+
+    /**
+     * fix both XML encoding to be UTF8, and replace standard XML entities < > " & '
+     *
+     * @param string $string
+     * @return string
+     * @access private
+     */
+    function _fixXmlEncoding($string)
+    {
+        if (version_compare(phpversion(), '5.0.0', 'lt')) {
+            $string = utf8_encode($string);
+        }
+        return strtr($string, array(
+                                          '&'  => '&amp;',
+                                          '>'  => '&gt;',
+                                          '<'  => '&lt;',
+                                          '"'  => '&quot;',
+                                          '\'' => '&apos;' ));
+    }
+
+    /**
+     * Return an XML document based on the package info (as returned
+     * by the PEAR_Common::infoFrom* methods).
+     *
+     * @return string XML data
+     */
+    function toXml($state = PEAR_VALIDATE_NORMAL, $nofilevalidation = false)
+    {
+        $this->_packagefile->setDate(date('Y-m-d'));
+        if (!$this->_packagefile->validate($state, $nofilevalidation)) {
+            return false;
+        }
+        $pkginfo = $this->_packagefile->getArray();
+        static $maint_map = array(
+            "handle" => "user",
+            "name" => "name",
+            "email" => "email",
+            "role" => "role",
+            );
+        $ret = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
+        $ret .= "<!DOCTYPE package SYSTEM \"http://pear.php.net/dtd/package-1.0\">\n";
+        $ret .= "<package version=\"1.0\" packagerversion=\"@PEAR-VER@\">\n" .
+" <name>$pkginfo[package]</name>";
+        if (isset($pkginfo['extends'])) {
+            $ret .= "\n<extends>$pkginfo[extends]</extends>";
+        }
+        $ret .=
+ "\n <summary>".$this->_fixXmlEncoding($pkginfo['summary'])."</summary>\n" .
+" <description>".trim($this->_fixXmlEncoding($pkginfo['description']))."\n </description>\n" .
+" <maintainers>\n";
+        foreach ($pkginfo['maintainers'] as $maint) {
+            $ret .= "  <maintainer>\n";
+            foreach ($maint_map as $idx => $elm) {
+                $ret .= "   <$elm>";
+                $ret .= $this->_fixXmlEncoding($maint[$idx]);
+                $ret .= "</$elm>\n";
+            }
+            $ret .= "  </maintainer>\n";
+        }
+        $ret .= "  </maintainers>\n";
+        $ret .= $this->_makeReleaseXml($pkginfo, false, $state);
+        if (isset($pkginfo['changelog']) && count($pkginfo['changelog']) > 0) {
+            $ret .= " <changelog>\n";
+            foreach ($pkginfo['changelog'] as $oldrelease) {
+                $ret .= $this->_makeReleaseXml($oldrelease, true);
+            }
+            $ret .= " </changelog>\n";
+        }
+        $ret .= "</package>\n";
+        return $ret;
+    }
+
+    // }}}
+    // {{{ _makeReleaseXml()
+
+    /**
+     * Generate part of an XML description with release information.
+     *
+     * @param array  $pkginfo    array with release information
+     * @param bool   $changelog  whether the result will be in a changelog element
+     *
+     * @return string XML data
+     *
+     * @access private
+     */
+    function _makeReleaseXml($pkginfo, $changelog = false, $state = PEAR_VALIDATE_NORMAL)
+    {
+        // XXX QUOTE ENTITIES IN PCDATA, OR EMBED IN CDATA BLOCKS!!
+        $indent = $changelog ? "  " : "";
+        $ret = "$indent <release>\n";
+        if (!empty($pkginfo['version'])) {
+            $ret .= "$indent  <version>$pkginfo[version]</version>\n";
+        }
+        if (!empty($pkginfo['release_date'])) {
+            $ret .= "$indent  <date>$pkginfo[release_date]</date>\n";
+        }
+        if (!empty($pkginfo['release_license'])) {
+            $ret .= "$indent  <license>$pkginfo[release_license]</license>\n";
+        }
+        if (!empty($pkginfo['release_state'])) {
+            $ret .= "$indent  <state>$pkginfo[release_state]</state>\n";
+        }
+        if (!empty($pkginfo['release_notes'])) {
+            $ret .= "$indent  <notes>".trim($this->_fixXmlEncoding($pkginfo['release_notes']))
+            ."\n$indent  </notes>\n";
+        }
+        if (!empty($pkginfo['release_warnings'])) {
+            $ret .= "$indent  <warnings>".$this->_fixXmlEncoding($pkginfo['release_warnings'])."</warnings>\n";
+        }
+        if (isset($pkginfo['release_deps']) && sizeof($pkginfo['release_deps']) > 0) {
+            $ret .= "$indent  <deps>\n";
+            foreach ($pkginfo['release_deps'] as $dep) {
+                $ret .= "$indent   <dep type=\"$dep[type]\" rel=\"$dep[rel]\"";
+                if (isset($dep['version'])) {
+                    $ret .= " version=\"$dep[version]\"";
+                }
+                if (isset($dep['optional'])) {
+                    $ret .= " optional=\"$dep[optional]\"";
+                }
+                if (isset($dep['name'])) {
+                    $ret .= ">$dep[name]</dep>\n";
+                } else {
+                    $ret .= "/>\n";
+                }
+            }
+            $ret .= "$indent  </deps>\n";
+        }
+        if (isset($pkginfo['configure_options'])) {
+            $ret .= "$indent  <configureoptions>\n";
+            foreach ($pkginfo['configure_options'] as $c) {
+                $ret .= "$indent   <configureoption name=\"".
+                    $this->_fixXmlEncoding($c['name']) . "\"";
+                if (isset($c['default'])) {
+                    $ret .= " default=\"" . $this->_fixXmlEncoding($c['default']) . "\"";
+                }
+                $ret .= " prompt=\"" . $this->_fixXmlEncoding($c['prompt']) . "\"";
+                $ret .= "/>\n";
+            }
+            $ret .= "$indent  </configureoptions>\n";
+        }
+        if (isset($pkginfo['provides'])) {
+            foreach ($pkginfo['provides'] as $key => $what) {
+                $ret .= "$indent  <provides type=\"$what[type]\" ";
+                $ret .= "name=\"$what[name]\" ";
+                if (isset($what['extends'])) {
+                    $ret .= "extends=\"$what[extends]\" ";
+                }
+                $ret .= "/>\n";
+            }
+        }
+        if (isset($pkginfo['filelist'])) {
+            $ret .= "$indent  <filelist>\n";
+            if ($state ^ PEAR_VALIDATE_PACKAGING) {
+                $ret .= $this->recursiveXmlFilelist($pkginfo['filelist']);
+            } else {
+                foreach ($pkginfo['filelist'] as $file => $fa) {
+                    @$ret .= "$indent   <file role=\"$fa[role]\"";
+                    if (isset($fa['baseinstalldir'])) {
+                        $ret .= ' baseinstalldir="' .
+                            $this->_fixXmlEncoding($fa['baseinstalldir']) . '"';
+                    }
+                    if (isset($fa['md5sum'])) {
+                        $ret .= " md5sum=\"$fa[md5sum]\"";
+                    }
+                    if (isset($fa['platform'])) {
+                        $ret .= " platform=\"$fa[platform]\"";
+                    }
+                    if (!empty($fa['install-as'])) {
+                        $ret .= ' install-as="' .
+                            $this->_fixXmlEncoding($fa['install-as']) . '"';
+                    }
+                    $ret .= ' name="' . $this->_fixXmlEncoding($file) . '"';
+                    if (empty($fa['replacements'])) {
+                        $ret .= "/>\n";
+                    } else {
+                        $ret .= ">\n";
+                        foreach ($fa['replacements'] as $r) {
+                            $ret .= "$indent    <replace";
+                            foreach ($r as $k => $v) {
+                                $ret .= " $k=\"" . $this->_fixXmlEncoding($v) .'"';
+                            }
+                            $ret .= "/>\n";
+                        }
+                        @$ret .= "$indent   </file>\n";
+                    }
+                }
+            }
+            $ret .= "$indent  </filelist>\n";
+        }
+        $ret .= "$indent </release>\n";
+        return $ret;
+    }
+
+    /**
+     * @param array
+     * @access protected
+     */
+    function recursiveXmlFilelist($list)
+    {
+        $this->_dirs = array();
+        foreach ($list as $file => $attributes) {
+            $this->_addDir($this->_dirs, explode('/', dirname($file)), $file, $attributes);
+        }
+        return $this->_formatDir($this->_dirs);
+    }
+
+    /**
+     * @param array
+     * @param array
+     * @param string|null
+     * @param array|null
+     * @access private
+     */
+    function _addDir(&$dirs, $dir, $file = null, $attributes = null)
+    {
+        if ($dir == array() || $dir == array('.')) {
+            $dirs['files'][basename($file)] = $attributes;
+            return;
+        }
+        $curdir = array_shift($dir);
+        if (!isset($dirs['dirs'][$curdir])) {
+            $dirs['dirs'][$curdir] = array();
+        }
+        $this->_addDir($dirs['dirs'][$curdir], $dir, $file, $attributes);
+    }
+
+    /**
+     * @param array
+     * @param string
+     * @param string
+     * @access private
+     */
+    function _formatDir($dirs, $indent = '', $curdir = '')
+    {
+        $ret = '';
+        if (!count($dirs)) {
+            return '';
+        }
+        if (isset($dirs['dirs'])) {
+            uksort($dirs['dirs'], 'strnatcasecmp');
+            foreach ($dirs['dirs'] as $dir => $contents) {
+                $usedir = "$curdir/$dir";
+                $ret .= "$indent   <dir name=\"$dir\">\n";
+                $ret .= $this->_formatDir($contents, "$indent ", $usedir);
+                $ret .= "$indent   </dir> <!-- $usedir -->\n";
+            }
+        }
+        if (isset($dirs['files'])) {
+            uksort($dirs['files'], 'strnatcasecmp');
+            foreach ($dirs['files'] as $file => $attribs) {
+                $ret .= $this->_formatFile($file, $attribs, $indent);
+            }
+        }
+        return $ret;
+    }
+
+    /**
+     * @param string
+     * @param array
+     * @param string
+     * @access private
+     */
+    function _formatFile($file, $attributes, $indent)
+    {
+        $ret = "$indent   <file role=\"$attributes[role]\"";
+        if (isset($attributes['baseinstalldir'])) {
+            $ret .= ' baseinstalldir="' .
+                $this->_fixXmlEncoding($attributes['baseinstalldir']) . '"';
+        }
+        if (isset($attributes['md5sum'])) {
+            $ret .= " md5sum=\"$attributes[md5sum]\"";
+        }
+        if (isset($attributes['platform'])) {
+            $ret .= " platform=\"$attributes[platform]\"";
+        }
+        if (!empty($attributes['install-as'])) {
+            $ret .= ' install-as="' .
+                $this->_fixXmlEncoding($attributes['install-as']) . '"';
+        }
+        $ret .= ' name="' . $this->_fixXmlEncoding($file) . '"';
+        if (empty($attributes['replacements'])) {
+            $ret .= "/>\n";
+        } else {
+            $ret .= ">\n";
+            foreach ($attributes['replacements'] as $r) {
+                $ret .= "$indent    <replace";
+                foreach ($r as $k => $v) {
+                    $ret .= " $k=\"" . $this->_fixXmlEncoding($v) .'"';
+                }
+                $ret .= "/>\n";
+            }
+            $ret .= "$indent   </file>\n";
+        }
+        return $ret;
+    }
+
+    // {{{ _unIndent()
+
+    /**
+     * Unindent given string (?)
+     *
+     * @param string $str The string that has to be unindented.
+     * @return string
+     * @access private
+     */
+    function _unIndent($str)
+    {
+        // remove leading newlines
+        $str = preg_replace('/^[\r\n]+/', '', $str);
+        // find whitespace at the beginning of the first line
+        $indent_len = strspn($str, " \t");
+        $indent = substr($str, 0, $indent_len);
+        $data = '';
+        // remove the same amount of whitespace from following lines
+        foreach (explode("\n", $str) as $line) {
+            if (substr($line, 0, $indent_len) == $indent) {
+                $data .= substr($line, $indent_len) . "\n";
+            }
+        }
+        return $data;
+    }
+
+    /**
+     * @return array
+     */
+    function dependenciesToV2()
+    {
+        $arr = array();
+        $this->_convertDependencies2_0($arr);
+        return $arr['dependencies'];
+    }
+
+    /**
+     * Convert a package.xml version 1.0 into version 2.0
+     *
+     * Note that this does a basic conversion, to allow more advanced
+     * features like bundles and multiple releases
+     * @param string the classname to instantiate and return.  This must be
+     *               PEAR_PackageFile_v2 or a descendant
+     * @param boolean if true, only valid, deterministic package.xml 1.0 as defined by the
+     *                strictest parameters will be converted
+     * @return PEAR_PackageFile_v2|PEAR_Error
+     */
+    function &toV2($class = 'PEAR_PackageFile_v2', $strict = false)
+    {
+        if ($strict) {
+            if (!$this->_packagefile->validate()) {
+                $a = PEAR::raiseError('invalid package.xml version 1.0 cannot be converted' .
+                    ' to version 2.0', null, null, null,
+                    $this->_packagefile->getValidationWarnings(true));
+                return $a;
+            }
+        }
+        $arr = array(
+            'attribs' => array(
+                             'version' => '2.0',
+                             'xmlns' => 'http://pear.php.net/dtd/package-2.0',
+                             'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0',
+                             'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
+                             'xsi:schemaLocation' => "http://pear.php.net/dtd/tasks-1.0\n" .
+"http://pear.php.net/dtd/tasks-1.0.xsd\n" .
+"http://pear.php.net/dtd/package-2.0\n" .
+'http://pear.php.net/dtd/package-2.0.xsd',
+                         ),
+            'name' => $this->_packagefile->getPackage(),
+            'channel' => 'pear.php.net',
+        );
+        $arr['summary'] = $this->_packagefile->getSummary();
+        $arr['description'] = $this->_packagefile->getDescription();
+        $maintainers = $this->_packagefile->getMaintainers();
+        foreach ($maintainers as $maintainer) {
+            if ($maintainer['role'] != 'lead') {
+                continue;
+            }
+            $new = array(
+                'name' => $maintainer['name'],
+                'user' => $maintainer['handle'],
+                'email' => $maintainer['email'],
+                'active' => 'yes',
+            );
+            $arr['lead'][] = $new;
+        }
+        if (!isset($arr['lead'])) { // some people... you know?
+            $arr['lead'] = array(
+                'name' => 'unknown',
+                'user' => 'unknown',
+                'email' => 'noleadmaintainer@example.com',
+                'active' => 'no',
+            );
+        }
+        if (count($arr['lead']) == 1) {
+            $arr['lead'] = $arr['lead'][0];
+        }
+        foreach ($maintainers as $maintainer) {
+            if ($maintainer['role'] == 'lead') {
+                continue;
+            }
+            $new = array(
+                'name' => $maintainer['name'],
+                'user' => $maintainer['handle'],
+                'email' => $maintainer['email'],
+                'active' => 'yes',
+            );
+            $arr[$maintainer['role']][] = $new;
+        }
+        if (isset($arr['developer']) && count($arr['developer']) == 1) {
+            $arr['developer'] = $arr['developer'][0];
+        }
+        if (isset($arr['contributor']) && count($arr['contributor']) == 1) {
+            $arr['contributor'] = $arr['contributor'][0];
+        }
+        if (isset($arr['helper']) && count($arr['helper']) == 1) {
+            $arr['helper'] = $arr['helper'][0];
+        }
+        $arr['date'] = $this->_packagefile->getDate();
+        $arr['version'] =
+            array(
+                'release' => $this->_packagefile->getVersion(),
+                'api' => $this->_packagefile->getVersion(),
+            );
+        $arr['stability'] =
+            array(
+                'release' => $this->_packagefile->getState(),
+                'api' => $this->_packagefile->getState(),
+            );
+        $licensemap =
+            array(
+                'php' => 'http://www.php.net/license',
+                'php license' => 'http://www.php.net/license',
+                'lgpl' => 'http://www.gnu.org/copyleft/lesser.html',
+                'bsd' => 'http://www.opensource.org/licenses/bsd-license.php',
+                'bsd style' => 'http://www.opensource.org/licenses/bsd-license.php',
+                'bsd-style' => 'http://www.opensource.org/licenses/bsd-license.php',
+                'mit' => 'http://www.opensource.org/licenses/mit-license.php',
+                'gpl' => 'http://www.gnu.org/copyleft/gpl.html',
+                'apache' => 'http://www.opensource.org/licenses/apache2.0.php'
+            );
+        if (isset($licensemap[strtolower($this->_packagefile->getLicense())])) {
+            $arr['license'] = array(
+                'attribs' => array('uri' =>
+                    $licensemap[strtolower($this->_packagefile->getLicense())]),
+                '_content' => $this->_packagefile->getLicense()
+                );
+        } else {
+            // don't use bogus uri
+            $arr['license'] = $this->_packagefile->getLicense();
+        }
+        $arr['notes'] = $this->_packagefile->getNotes();
+        $temp = array();
+        $arr['contents'] = $this->_convertFilelist2_0($temp);
+        $this->_convertDependencies2_0($arr);
+        $release = ($this->_packagefile->getConfigureOptions() || $this->_isExtension) ?
+            'extsrcrelease' : 'phprelease';
+        if ($release == 'extsrcrelease') {
+            $arr['channel'] = 'pecl.php.net';
+            $arr['providesextension'] = $arr['name']; // assumption
+        }
+        $arr[$release] = array();
+        if ($this->_packagefile->getConfigureOptions()) {
+            $arr[$release]['configureoption'] = $this->_packagefile->getConfigureOptions();
+            foreach ($arr[$release]['configureoption'] as $i => $opt) {
+                $arr[$release]['configureoption'][$i] = array('attribs' => $opt);
+            }
+            if (count($arr[$release]['configureoption']) == 1) {
+                $arr[$release]['configureoption'] = $arr[$release]['configureoption'][0];
+            }
+        }
+        $this->_convertRelease2_0($arr[$release], $temp);
+        if ($release == 'extsrcrelease' && count($arr[$release]) > 1) {
+            // multiple extsrcrelease tags added in PEAR 1.4.1
+            $arr['dependencies']['required']['pearinstaller']['min'] = '1.4.1';
+        }
+        if ($cl = $this->_packagefile->getChangelog()) {
+            foreach ($cl as $release) {
+                $rel = array();
+                $rel['version'] =
+                    array(
+                        'release' => $release['version'],
+                        'api' => $release['version'],
+                    );
+                if (!isset($release['release_state'])) {
+                    $release['release_state'] = 'stable';
+                }
+                $rel['stability'] =
+                    array(
+                        'release' => $release['release_state'],
+                        'api' => $release['release_state'],
+                    );
+                if (isset($release['release_date'])) {
+                    $rel['date'] = $release['release_date'];
+                } else {
+                    $rel['date'] = date('Y-m-d');
+                }
+                if (isset($release['release_license'])) {
+                    if (isset($licensemap[strtolower($release['release_license'])])) {
+                        $uri = $licensemap[strtolower($release['release_license'])];
+                    } else {
+                        $uri = 'http://www.example.com';
+                    }
+                    $rel['license'] = array(
+                            'attribs' => array('uri' => $uri),
+                            '_content' => $release['release_license']
+                        );
+                } else {
+                    $rel['license'] = $arr['license'];
+                }
+                if (!isset($release['release_notes'])) {
+                    $release['release_notes'] = 'no release notes';
+                }
+                $rel['notes'] = $release['release_notes'];
+                $arr['changelog']['release'][] = $rel;
+            }
+        }
+        $ret = new $class;
+        $ret->setConfig($this->_packagefile->_config);
+        $ret->setLogger($this->_packagefile->_logger);
+        $ret->fromArray($arr);
+        return $ret;
+    }
+
+    /**
+     * @param array
+     * @param bool
+     * @access private
+     */
+    function _convertDependencies2_0(&$release, $internal = false)
+    {
+        $peardep = array('pearinstaller' =>
+            array('min' => '1.4.0b1')); // this is a lot safer
+        $required = $optional = array();
+        $release['dependencies'] = array();
+        if ($this->_packagefile->hasDeps()) {
+            foreach ($this->_packagefile->getDeps() as $dep) {
+                if (!isset($dep['optional']) || $dep['optional'] == 'no') {
+                    $required[] = $dep;
+                } else {
+                    $optional[] = $dep;
+                }
+            }
+            foreach (array('required', 'optional') as $arr) {
+                $deps = array();
+                foreach ($$arr as $dep) {
+                    // organize deps by dependency type and name
+                    if (!isset($deps[$dep['type']])) {
+                        $deps[$dep['type']] = array();
+                    }
+                    if (isset($dep['name'])) {
+                        $deps[$dep['type']][$dep['name']][] = $dep;
+                    } else {
+                        $deps[$dep['type']][] = $dep;
+                    }
+                }
+                do {
+                    if (isset($deps['php'])) {
+                        $php = array();
+                        if (count($deps['php']) > 1) {
+                            $php = $this->_processPhpDeps($deps['php']);
+                        } else {
+                            if (!isset($deps['php'][0])) {
+                                list($key, $blah) = each ($deps['php']); // stupid buggy versions
+                                $deps['php'] = array($blah[0]);
+                            }
+                            $php = $this->_processDep($deps['php'][0]);
+                            if (!$php) {
+                                break; // poor mans throw
+                            }
+                        }
+                        $release['dependencies'][$arr]['php'] = $php;
+                    }
+                } while (false);
+                do {
+                    if (isset($deps['pkg'])) {
+                        $pkg = array();
+                        $pkg = $this->_processMultipleDepsName($deps['pkg']);
+                        if (!$pkg) {
+                            break; // poor mans throw
+                        }
+                        $release['dependencies'][$arr]['package'] = $pkg;
+                    }
+                } while (false);
+                do {
+                    if (isset($deps['ext'])) {
+                        $pkg = array();
+                        $pkg = $this->_processMultipleDepsName($deps['ext']);
+                        $release['dependencies'][$arr]['extension'] = $pkg;
+                    }
+                } while (false);
+                // skip sapi - it's not supported so nobody will have used it
+                // skip os - it's not supported in 1.0
+            }
+        }
+        if (isset($release['dependencies']['required'])) {
+            $release['dependencies']['required'] =
+                array_merge($peardep, $release['dependencies']['required']);
+        } else {
+            $release['dependencies']['required'] = $peardep;
+        }
+        if (!isset($release['dependencies']['required']['php'])) {
+            $release['dependencies']['required']['php'] =
+                array('min' => '4.0.0');
+        }
+        $order = array();
+        $bewm = $release['dependencies']['required'];
+        $order['php'] = $bewm['php'];
+        $order['pearinstaller'] = $bewm['pearinstaller'];
+        isset($bewm['package']) ? $order['package'] = $bewm['package'] :0;
+        isset($bewm['extension']) ? $order['extension'] = $bewm['extension'] :0;
+        $release['dependencies']['required'] = $order;
+    }
+
+    /**
+     * @param array
+     * @access private
+     */
+    function _convertFilelist2_0(&$package)
+    {
+        $ret = array('dir' =>
+                    array(
+                        'attribs' => array('name' => '/'),
+                        'file' => array()
+                        )
+                    );
+        $package['platform'] =
+        $package['install-as'] = array();
+        $this->_isExtension = false;
+        foreach ($this->_packagefile->getFilelist() as $name => $file) {
+            $file['name'] = $name;
+            if (isset($file['role']) && $file['role'] == 'src') {
+                $this->_isExtension = true;
+            }
+            if (isset($file['replacements'])) {
+                $repl = $file['replacements'];
+                unset($file['replacements']);
+            } else {
+                unset($repl);
+            }
+            if (isset($file['install-as'])) {
+                $package['install-as'][$name] = $file['install-as'];
+                unset($file['install-as']);
+            }
+            if (isset($file['platform'])) {
+                $package['platform'][$name] = $file['platform'];
+                unset($file['platform']);
+            }
+            $file = array('attribs' => $file);
+            if (isset($repl)) {
+                foreach ($repl as $replace ) {
+                    $file['tasks:replace'][] = array('attribs' => $replace);
+                }
+                if (count($repl) == 1) {
+                    $file['tasks:replace'] = $file['tasks:replace'][0];
+                }
+            }
+            $ret['dir']['file'][] = $file;
+        }
+        return $ret;
+    }
+
+    /**
+     * Post-process special files with install-as/platform attributes and
+     * make the release tag.
+     * 
+     * This complex method follows this work-flow to create the release tags:
+     * 
+     * <pre>
+     * - if any install-as/platform exist, create a generic release and fill it with
+     *   o <install as=..> tags for <file name=... install-as=...>
+     *   o <install as=..> tags for <file name=... platform=!... install-as=..>
+     *   o <ignore> tags for <file name=... platform=...>
+     *   o <ignore> tags for <file name=... platform=... install-as=..>
+     * - create a release for each platform encountered and fill with
+     *   o <install as..> tags for <file name=... install-as=...>
+     *   o <install as..> tags for <file name=... platform=this platform install-as=..>
+     *   o <install as..> tags for <file name=... platform=!other platform install-as=..>
+     *   o <ignore> tags for <file name=... platform=!this platform>
+     *   o <ignore> tags for <file name=... platform=other platform>
+     *   o <ignore> tags for <file name=... platform=other platform install-as=..>
+     *   o <ignore> tags for <file name=... platform=!this platform install-as=..>
+     * </pre>
+     * 
+     * It does this by accessing the $package parameter, which contains an array with
+     * indices:
+     * 
+     *  - platform: mapping of file => OS the file should be installed on
+     *  - install-as: mapping of file => installed name
+     *  - osmap: mapping of OS => list of files that should be installed
+     *    on that OS
+     *  - notosmap: mapping of OS => list of files that should not be
+     *    installed on that OS
+     *
+     * @param array
+     * @param array
+     * @access private
+     */
+    function _convertRelease2_0(&$release, $package)
+    {
+        //- if any install-as/platform exist, create a generic release and fill it with 
+        if (count($package['platform']) || count($package['install-as'])) {
+            $generic = array();
+            $genericIgnore = array();
+            foreach ($package['install-as'] as $file => $as) {
+                //o <install as=..> tags for <file name=... install-as=...>
+                if (!isset($package['platform'][$file])) {
+                    $generic[] = $file;
+                    continue;
+                }
+                //o <install as=..> tags for <file name=... platform=!... install-as=..>
+                if (isset($package['platform'][$file]) &&
+                      $package['platform'][$file]{0} == '!') {
+                    $generic[] = $file;
+                    continue;
+                }
+                //o <ignore> tags for <file name=... platform=... install-as=..>
+                if (isset($package['platform'][$file]) &&
+                      $package['platform'][$file]{0} != '!') {
+                    $genericIgnore[] = $file;
+                    continue;
+                }
+            }
+            foreach ($package['platform'] as $file => $platform) {
+                if (isset($package['install-as'][$file])) {
+                    continue;
+                }
+                if ($platform{0} != '!') {
+                    //o <ignore> tags for <file name=... platform=...>
+                    $genericIgnore[] = $file;
+                }
+            }
+            if (count($package['platform'])) {
+                $oses = $notplatform = $platform = array();
+                foreach ($package['platform'] as $file => $os) {
+                    // get a list of oses
+                    if ($os{0} == '!') {
+                        if (isset($oses[substr($os, 1)])) {
+                            continue;
+                        }
+                        $oses[substr($os, 1)] = count($oses);
+                    } else {
+                        if (isset($oses[$os])) {
+                            continue;
+                        }
+                        $oses[$os] = count($oses);
+                    }
+                }
+                //- create a release for each platform encountered and fill with
+                foreach ($oses as $os => $releaseNum) {
+                    $release[$releaseNum]['installconditions']['os']['name'] = $os;
+                    $release[$releaseNum]['filelist'] = array('install' => array(),
+                        'ignore' => array());
+                    foreach ($package['install-as'] as $file => $as) {
+                        //o <install as=..> tags for <file name=... install-as=...>
+                        if (!isset($package['platform'][$file])) {
+                            $release[$releaseNum]['filelist']['install'][] =
+                                array(
+                                    'attribs' => array(
+                                        'name' => $file,
+                                        'as' => $as,
+                                    ),
+                                );
+                            continue;
+                        }
+                        //o <install as..> tags for
+                        //  <file name=... platform=this platform install-as=..>
+                        if (isset($package['platform'][$file]) &&
+                              $package['platform'][$file] == $os) {
+                            $release[$releaseNum]['filelist']['install'][] =
+                                array(
+                                    'attribs' => array(
+                                        'name' => $file,
+                                        'as' => $as,
+                                    ),
+                                );
+                            continue;
+                        }
+                        //o <install as..> tags for
+                        //  <file name=... platform=!other platform install-as=..>
+                        if (isset($package['platform'][$file]) &&
+                              $package['platform'][$file] != "!$os" &&
+                              $package['platform'][$file]{0} == '!') {
+                            $release[$releaseNum]['filelist']['install'][] =
+                                array(
+                                    'attribs' => array(
+                                        'name' => $file,
+                                        'as' => $as,
+                                    ),
+                                );
+                            continue;
+                        }
+                        //o <ignore> tags for
+                        //  <file name=... platform=!this platform install-as=..>
+                        if (isset($package['platform'][$file]) &&
+                              $package['platform'][$file] == "!$os") {
+                            $release[$releaseNum]['filelist']['ignore'][] =
+                                array(
+                                    'attribs' => array(
+                                        'name' => $file,
+                                    ),
+                                );
+                            continue;
+                        }
+                        //o <ignore> tags for
+                        //  <file name=... platform=other platform install-as=..>
+                        if (isset($package['platform'][$file]) &&
+                              $package['platform'][$file]{0} != '!' &&
+                              $package['platform'][$file] != $os) {
+                            $release[$releaseNum]['filelist']['ignore'][] =
+                                array(
+                                    'attribs' => array(
+                                        'name' => $file,
+                                    ),
+                                );
+                            continue;
+                        }
+                    }
+                    foreach ($package['platform'] as $file => $platform) {
+                        if (isset($package['install-as'][$file])) {
+                            continue;
+                        }
+                        //o <ignore> tags for <file name=... platform=!this platform>
+                        if ($platform == "!$os") {
+                            $release[$releaseNum]['filelist']['ignore'][] =
+                                array(
+                                    'attribs' => array(
+                                        'name' => $file,
+                                    ),
+                                );
+                            continue;
+                        }
+                        //o <ignore> tags for <file name=... platform=other platform>
+                        if ($platform{0} != '!' && $platform != $os) {
+                            $release[$releaseNum]['filelist']['ignore'][] =
+                                array(
+                                    'attribs' => array(
+                                        'name' => $file,
+                                    ),
+                                );
+                        }
+                    }
+                    if (!count($release[$releaseNum]['filelist']['install'])) {
+                        unset($release[$releaseNum]['filelist']['install']);
+                    }
+                    if (!count($release[$releaseNum]['filelist']['ignore'])) {
+                        unset($release[$releaseNum]['filelist']['ignore']);
+                    }
+                }
+                if (count($generic) || count($genericIgnore)) {
+                    $release[count($oses)] = array();
+                    if (count($generic)) {
+                        foreach ($generic as $file) {
+                            if (isset($package['install-as'][$file])) {
+                                $installas = $package['install-as'][$file];
+                            } else {
+                                $installas = $file;
+                            }
+                            $release[count($oses)]['filelist']['install'][] =
+                                array(
+                                    'attribs' => array(
+                                        'name' => $file,
+                                        'as' => $installas,
+                                    )
+                                );
+                        }
+                    }
+                    if (count($genericIgnore)) {
+                        foreach ($genericIgnore as $file) {
+                            $release[count($oses)]['filelist']['ignore'][] =
+                                array(
+                                    'attribs' => array(
+                                        'name' => $file,
+                                    )
+                                );
+                        }
+                    }
+                }
+                // cleanup
+                foreach ($release as $i => $rel) {
+                    if (isset($rel['filelist']['install']) &&
+                          count($rel['filelist']['install']) == 1) {
+                        $release[$i]['filelist']['install'] =
+                            $release[$i]['filelist']['install'][0];
+                    }
+                    if (isset($rel['filelist']['ignore']) &&
+                          count($rel['filelist']['ignore']) == 1) {
+                        $release[$i]['filelist']['ignore'] =
+                            $release[$i]['filelist']['ignore'][0];
+                    }
+                }
+                if (count($release) == 1) {
+                    $release = $release[0];
+                }
+            } else {
+                // no platform atts, but some install-as atts
+                foreach ($package['install-as'] as $file => $value) {
+                    $release['filelist']['install'][] =
+                        array(
+                            'attribs' => array(
+                                'name' => $file,
+                                'as' => $value
+                            )
+                        );
+                }
+                if (count($release['filelist']['install']) == 1) {
+                    $release['filelist']['install'] = $release['filelist']['install'][0];
+                }
+            }
+        }
+    }
+
+    /**
+     * @param array
+     * @return array
+     * @access private
+     */
+    function _processDep($dep)
+    {
+        if ($dep['type'] == 'php') {
+            if ($dep['rel'] == 'has') {
+                // come on - everyone has php!
+                return false;
+            }
+        }
+        $php = array();
+        if ($dep['type'] != 'php') {
+            $php['name'] = $dep['name'];
+            if ($dep['type'] == 'pkg') {
+                $php['channel'] = 'pear.php.net';
+            }
+        }
+        switch ($dep['rel']) {
+            case 'gt' :
+                $php['min'] = $dep['version'];
+                $php['exclude'] = $dep['version'];
+            break;
+            case 'ge' :
+                if (!isset($dep['version'])) {
+                    if ($dep['type'] == 'php') {
+                        if (isset($dep['name'])) {
+                            $dep['version'] = $dep['name'];
+                        }
+                    }
+                }
+                $php['min'] = $dep['version'];
+            break;
+            case 'lt' :
+                $php['max'] = $dep['version'];
+                $php['exclude'] = $dep['version'];
+            break;
+            case 'le' :
+                $php['max'] = $dep['version'];
+            break;
+            case 'eq' :
+                $php['min'] = $dep['version'];
+                $php['max'] = $dep['version'];
+            break;
+            case 'ne' :
+                $php['exclude'] = $dep['version'];
+            break;
+            case 'not' :
+                $php['conflicts'] = 'yes';
+            break;
+        }
+        return $php;
+    }
+
+    /**
+     * @param array
+     * @return array
+     */
+    function _processPhpDeps($deps)
+    {
+        $test = array();
+        foreach ($deps as $dep) {
+            $test[] = $this->_processDep($dep);
+        }
+        $min = array();
+        $max = array();
+        foreach ($test as $dep) {
+            if (!$dep) {
+                continue;
+            }
+            if (isset($dep['min'])) {
+                $min[$dep['min']] = count($min);
+            }
+            if (isset($dep['max'])) {
+                $max[$dep['max']] = count($max);
+            }
+        }
+        if (count($min) > 0) {
+            uksort($min, 'version_compare');
+        }
+        if (count($max) > 0) {
+            uksort($max, 'version_compare');
+        }
+        if (count($min)) {
+            // get the highest minimum
+            $min = array_pop($a = array_flip($min));
+        } else {
+            $min = false;
+        }
+        if (count($max)) {
+            // get the lowest maximum
+            $max = array_shift($a = array_flip($max));
+        } else {
+            $max = false;
+        }
+        if ($min) {
+            $php['min'] = $min;
+        }
+        if ($max) {
+            $php['max'] = $max;
+        }
+        $exclude = array();
+        foreach ($test as $dep) {
+            if (!isset($dep['exclude'])) {
+                continue;
+            }
+            $exclude[] = $dep['exclude'];
+        }
+        if (count($exclude)) {
+            $php['exclude'] = $exclude;
+        }
+        return $php;
+    }
+
+    /**
+     * process multiple dependencies that have a name, like package deps
+     * @param array
+     * @return array
+     * @access private
+     */
+    function _processMultipleDepsName($deps)
+    {
+        $tests = array();
+        foreach ($deps as $name => $dep) {
+            foreach ($dep as $d) {
+                $tests[$name][] = $this->_processDep($d);
+            }
+        }
+        foreach ($tests as $name => $test) {
+            $php = array();
+            $min = array();
+            $max = array();
+            $php['name'] = $name;
+            foreach ($test as $dep) {
+                if (!$dep) {
+                    continue;
+                }
+                if (isset($dep['channel'])) {
+                    $php['channel'] = 'pear.php.net';
+                }
+                if (isset($dep['conflicts']) && $dep['conflicts'] == 'yes') {
+                    $php['conflicts'] = 'yes';
+                }
+                if (isset($dep['min'])) {
+                    $min[$dep['min']] = count($min);
+                }
+                if (isset($dep['max'])) {
+                    $max[$dep['max']] = count($max);
+                }
+            }
+            if (count($min) > 0) {
+                uksort($min, 'version_compare');
+            }
+            if (count($max) > 0) {
+                uksort($max, 'version_compare');
+            }
+            if (count($min)) {
+                // get the highest minimum
+                $min = array_pop($a = array_flip($min));
+            } else {
+                $min = false;
+            }
+            if (count($max)) {
+                // get the lowest maximum
+                $max = array_shift($a = array_flip($max));
+            } else {
+                $max = false;
+            }
+            if ($min) {
+                $php['min'] = $min;
+            }
+            if ($max) {
+                $php['max'] = $max;
+            }
+            $exclude = array();
+            foreach ($test as $dep) {
+                if (!isset($dep['exclude'])) {
+                    continue;
+                }
+                $exclude[] = $dep['exclude'];
+            }
+            if (count($exclude)) {
+                $php['exclude'] = $exclude;
+            }
+            $ret[] = $php;
+        }
+        return $ret;
+    }
+}
+?>
\ No newline at end of file
diff --git a/pear/PEAR/PackageFile/Generator/v2.php b/pear/PEAR/PackageFile/Generator/v2.php
new file mode 100644 (file)
index 0000000..be137cb
--- /dev/null
@@ -0,0 +1,1539 @@
+<?php
+/**
+ * package.xml generation class, package.xml version 2.0
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @author     Stephan Schmidt (original XML_Serializer code)
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a1
+ */
+/**
+ * file/dir manipulation routines
+ */
+require_once 'System.php';
+/**
+ * This class converts a PEAR_PackageFile_v2 object into any output format.
+ *
+ * Supported output formats include array, XML string (using S. Schmidt's
+ * XML_Serializer, slightly customized)
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @author     Stephan Schmidt (original XML_Serializer code)
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @PEAR-VER@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
+ */
+class PEAR_PackageFile_Generator_v2
+{
+   /**
+    * default options for the serialization
+    * @access private
+    * @var array $_defaultOptions
+    */
+    var $_defaultOptions = array(
+                         'indent'             => ' ',                    // string used for indentation
+                         'linebreak'          => "\n",                  // string used for newlines
+                         'typeHints'          => false,                 // automatically add type hin attributes
+                         'addDecl'            => true,                 // add an XML declaration
+                         'defaultTagName'     => 'XML_Serializer_Tag',  // tag used for indexed arrays or invalid names
+                         'classAsTagName'     => false,                 // use classname for objects in indexed arrays
+                         'keyAttribute'       => '_originalKey',        // attribute where original key is stored
+                         'typeAttribute'      => '_type',               // attribute for type (only if typeHints => true)
+                         'classAttribute'     => '_class',              // attribute for class of objects (only if typeHints => true)
+                         'scalarAsAttributes' => false,                 // scalar values (strings, ints,..) will be serialized as attribute
+                         'prependAttributes'  => '',                    // prepend string for attributes
+                         'indentAttributes'   => false,                 // indent the attributes, if set to '_auto', it will indent attributes so they all start at the same column
+                         'mode'               => 'simplexml',             // use 'simplexml' to use parent name as tagname if transforming an indexed array
+                         'addDoctype'         => false,                 // add a doctype declaration
+                         'doctype'            => null,                  // supply a string or an array with id and uri ({@see XML_Util::getDoctypeDeclaration()}
+                         'rootName'           => 'package',                  // name of the root tag
+                         'rootAttributes'     => array(
+                             'version' => '2.0',
+                             'xmlns' => 'http://pear.php.net/dtd/package-2.0',
+                             'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0',
+                             'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
+                             'xsi:schemaLocation' => 'http://pear.php.net/dtd/tasks-1.0
+http://pear.php.net/dtd/tasks-1.0.xsd
+http://pear.php.net/dtd/package-2.0
+http://pear.php.net/dtd/package-2.0.xsd',
+                         ),               // attributes of the root tag
+                         'attributesArray'    => 'attribs',                  // all values in this key will be treated as attributes
+                         'contentName'        => '_content',                   // this value will be used directly as content, instead of creating a new tag, may only be used in conjuction with attributesArray
+                         'beautifyFilelist'   => false,
+                         'encoding' => 'UTF-8',
+                        );
+
+   /**
+    * options for the serialization
+    * @access private
+    * @var array $options
+    */
+    var $options = array();
+
+   /**
+    * current tag depth
+    * @var integer $_tagDepth
+    */
+    var $_tagDepth = 0;
+
+   /**
+    * serilialized representation of the data
+    * @var string $_serializedData
+    */
+    var $_serializedData = null;
+    /**
+     * @var PEAR_PackageFile_v2
+     */
+    var $_packagefile;
+    /**
+     * @param PEAR_PackageFile_v2
+     */
+    function PEAR_PackageFile_Generator_v2(&$packagefile)
+    {
+        $this->_packagefile = &$packagefile;
+    }
+
+    /**
+     * @return string
+     */
+    function getPackagerVersion()
+    {
+        return '@PEAR-VER@';
+    }
+
+    /**
+     * @param PEAR_Packager
+     * @param bool generate a .tgz or a .tar
+     * @param string|null temporary directory to package in
+     */
+    function toTgz(&$packager, $compress = true, $where = null)
+    {
+        $a = null;
+        return $this->toTgz2($packager, $a, $compress, $where);
+    }
+
+    /**
+     * Package up both a package.xml and package2.xml for the same release
+     * @param PEAR_Packager
+     * @param PEAR_PackageFile_v1
+     * @param bool generate a .tgz or a .tar
+     * @param string|null temporary directory to package in
+     */
+    function toTgz2(&$packager, &$pf1, $compress = true, $where = null)
+    {
+        require_once 'Archive/Tar.php';
+        if (!$this->_packagefile->isEquivalent($pf1)) {
+            return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: "' .
+                basename($pf1->getPackageFile()) .
+                '" is not equivalent to "' . basename($this->_packagefile->getPackageFile())
+                . '"');
+        }
+        if ($where === null) {
+            if (!($where = System::mktemp(array('-d')))) {
+                return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: mktemp failed');
+            }
+        } elseif (!@System::mkDir(array('-p', $where))) {
+            return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: "' . $where . '" could' .
+                ' not be created');
+        }
+        if (file_exists($where . DIRECTORY_SEPARATOR . 'package.xml') &&
+              !is_file($where . DIRECTORY_SEPARATOR . 'package.xml')) {
+            return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: unable to save package.xml as' .
+                ' "' . $where . DIRECTORY_SEPARATOR . 'package.xml"');
+        }
+        if (!$this->_packagefile->validate(PEAR_VALIDATE_PACKAGING)) {
+            return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: invalid package.xml');
+        }
+        $ext = $compress ? '.tgz' : '.tar';
+        $pkgver = $this->_packagefile->getPackage() . '-' . $this->_packagefile->getVersion();
+        $dest_package = getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext;
+        if (file_exists(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext) &&
+              !is_file(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext)) {
+            return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: cannot create tgz file "' .
+                getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext . '"');
+        }
+        if ($pkgfile = $this->_packagefile->getPackageFile()) {
+            $pkgdir = dirname(realpath($pkgfile));
+            $pkgfile = basename($pkgfile);
+        } else {
+            return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: package file object must ' .
+                'be created from a real file');
+        }
+        // {{{ Create the package file list
+        $filelist = array();
+        $i = 0;
+        $this->_packagefile->flattenFilelist();
+        $contents = $this->_packagefile->getContents();
+        if (isset($contents['bundledpackage'])) { // bundles of packages
+            $contents = $contents['bundledpackage'];
+            if (!isset($contents[0])) {
+                $contents = array($contents);
+            }
+            $packageDir = $where;
+            foreach ($contents as $i => $package) {
+                $fname = $package;
+                $file = $pkgdir . DIRECTORY_SEPARATOR . $fname;
+                if (!file_exists($file)) {
+                    return $packager->raiseError("File does not exist: $fname");
+                }
+                $tfile = $packageDir . DIRECTORY_SEPARATOR . $fname;
+                System::mkdir(array('-p', dirname($tfile)));
+                copy($file, $tfile);
+                $filelist[$i++] = $tfile;
+                $packager->log(2, "Adding package $fname");
+            }
+        } else { // normal packages
+            $contents = $contents['dir']['file'];
+            if (!isset($contents[0])) {
+                $contents = array($contents);
+            }
+    
+            $packageDir = $where;
+            foreach ($contents as $i => $file) {
+                $fname = $file['attribs']['name'];
+                $atts = $file['attribs'];
+                $orig = $file;
+                $file = $pkgdir . DIRECTORY_SEPARATOR . $fname;
+                if (!file_exists($file)) {
+                    return $packager->raiseError("File does not exist: $fname");
+                } else {
+                    $tfile = $packageDir . DIRECTORY_SEPARATOR . $fname;
+                    unset($orig['attribs']);
+                    if (count($orig)) { // file with tasks
+                        // run any package-time tasks
+                        if (function_exists('file_get_contents')) {
+                            $contents = file_get_contents($file);
+                        } else {
+                            $fp = fopen($file, "r");
+                            $contents = @fread($fp, filesize($file));
+                            fclose($fp);
+                        }
+                        foreach ($orig as $tag => $raw) {
+                            $tag = str_replace($this->_packagefile->getTasksNs() . ':', '', $tag);
+                            $task = "PEAR_Task_$tag";
+                            $task = &new $task($this->_packagefile->_config,
+                                $this->_packagefile->_logger,
+                                PEAR_TASK_PACKAGE);
+                            $task->init($raw, $atts, null);
+                            $res = $task->startSession($this->_packagefile, $contents, $tfile);
+                            if (!$res) {
+                                continue; // skip this task
+                            }
+                            if (PEAR::isError($res)) {
+                                return $res;
+                            }
+                            $contents = $res; // save changes
+                            System::mkdir(array('-p', dirname($tfile)));
+                            $wp = fopen($tfile, "wb");
+                            fwrite($wp, $contents);
+                            fclose($wp);
+                        }
+                    }
+                    if (!file_exists($tfile)) {
+                        System::mkdir(array('-p', dirname($tfile)));
+                        copy($file, $tfile);
+                    }
+                    $filelist[$i++] = $tfile;
+                    $this->_packagefile->setFileAttribute($fname, 'md5sum', md5_file($tfile), $i - 1);
+                    $packager->log(2, "Adding file $fname");
+                }
+            }
+        }
+            // }}}
+        if ($pf1 !== null) {
+            $name = 'package2.xml';
+        } else {
+            $name = 'package.xml';
+        }
+        $packagexml = $this->toPackageFile($where, PEAR_VALIDATE_PACKAGING, $name);
+        if ($packagexml) {
+            $tar =& new Archive_Tar($dest_package, $compress);
+            $tar->setErrorHandling(PEAR_ERROR_RETURN); // XXX Don't print errors
+            // ----- Creates with the package.xml file
+            $ok = $tar->createModify(array($packagexml), '', $where);
+            if (PEAR::isError($ok)) {
+                return $packager->raiseError($ok);
+            } elseif (!$ok) {
+                return $packager->raiseError('PEAR_Packagefile_v2::toTgz(): adding ' . $name .
+                    ' failed');
+            }
+            // ----- Add the content of the package
+            if (!$tar->addModify($filelist, $pkgver, $where)) {
+                return $packager->raiseError(
+                    'PEAR_Packagefile_v2::toTgz(): tarball creation failed');
+            }
+            // add the package.xml version 1.0
+            if ($pf1 !== null) {
+                $pfgen = &$pf1->getDefaultGenerator();
+                $packagexml1 = $pfgen->toPackageFile($where, PEAR_VALIDATE_PACKAGING,
+                    'package.xml', true);
+                if (!$tar->addModify(array($packagexml1), '', $where)) {
+                    return $packager->raiseError(
+                        'PEAR_Packagefile_v2::toTgz(): adding package.xml failed');
+                }
+            }
+            return $dest_package;
+        }
+    }
+
+    function toPackageFile($where = null, $state = PEAR_VALIDATE_NORMAL, $name = 'package.xml')
+    {
+        if (!$this->_packagefile->validate($state)) {
+            return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: invalid package.xml',
+                null, null, null, $this->_packagefile->getValidationWarnings());
+        }
+        if ($where === null) {
+            if (!($where = System::mktemp(array('-d')))) {
+                return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: mktemp failed');
+            }
+        } elseif (!@System::mkDir(array('-p', $where))) {
+            return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: "' . $where . '" could' .
+                ' not be created');
+        }
+        $newpkgfile = $where . DIRECTORY_SEPARATOR . $name;
+        $np = @fopen($newpkgfile, 'wb');
+        if (!$np) {
+            return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: unable to save ' .
+               "$name as $newpkgfile");
+        }
+        fwrite($np, $this->toXml($state));
+        fclose($np);
+        return $newpkgfile;
+    }
+
+    function &toV2()
+    {
+        return $this->_packagefile;
+    }
+
+    /**
+     * Return an XML document based on the package info (as returned
+     * by the PEAR_Common::infoFrom* methods).
+     *
+     * @return string XML data
+     */
+    function toXml($state = PEAR_VALIDATE_NORMAL, $options = array())
+    {
+        $this->_packagefile->setDate(date('Y-m-d'));
+        $this->_packagefile->setTime(date('H:i:s'));
+        if (!$this->_packagefile->validate($state)) {
+            return false;
+        }
+        if (is_array($options)) {
+            $this->options = array_merge($this->_defaultOptions, $options);
+        } else {
+            $this->options = $this->_defaultOptions;
+        }
+        $arr = $this->_packagefile->getArray();
+        if (isset($arr['filelist'])) {
+            unset($arr['filelist']);
+        }
+        if (isset($arr['_lastversion'])) {
+            unset($arr['_lastversion']);
+        }
+        if ($state ^ PEAR_VALIDATE_PACKAGING && !isset($arr['bundle'])) {
+            $use = $this->_recursiveXmlFilelist($arr['contents']['dir']['file']);
+            unset($arr['contents']['dir']['file']);
+            if (isset($use['dir'])) {
+                $arr['contents']['dir']['dir'] = $use['dir'];
+            }
+            if (isset($use['file'])) {
+                $arr['contents']['dir']['file'] = $use['file'];
+            }
+            $this->options['beautifyFilelist'] = true;
+        }
+        $arr['attribs']['packagerversion'] = '@PEAR-VER@';
+        if ($this->serialize($arr, $options)) {
+            return $this->_serializedData . "\n";
+        }
+        return false;
+    }
+
+
+    function _recursiveXmlFilelist($list)
+    {
+        $dirs = array();
+        if (isset($list['attribs'])) {
+            $file = $list['attribs']['name'];
+            unset($list['attribs']['name']);
+            $attributes = $list['attribs'];
+            $this->_addDir($dirs, explode('/', dirname($file)), $file, $attributes);
+        } else {
+            foreach ($list as $a) {
+                $file = $a['attribs']['name'];
+                $attributes = $a['attribs'];
+                unset($a['attribs']);
+                $this->_addDir($dirs, explode('/', dirname($file)), $file, $attributes, $a);
+            }
+        }
+        $this->_formatDir($dirs);
+        $this->_deFormat($dirs);
+        return $dirs;
+    }
+
+    function _addDir(&$dirs, $dir, $file = null, $attributes = null, $tasks = null)
+    {
+        if (!$tasks) {
+            $tasks = array();
+        }
+        if ($dir == array() || $dir == array('.')) {
+            $dirs['file'][basename($file)] = $tasks;
+            $attributes['name'] = basename($file);
+            $dirs['file'][basename($file)]['attribs'] = $attributes;
+            return;
+        }
+        $curdir = array_shift($dir);
+        if (!isset($dirs['dir'][$curdir])) {
+            $dirs['dir'][$curdir] = array();
+        }
+        $this->_addDir($dirs['dir'][$curdir], $dir, $file, $attributes, $tasks);
+    }
+
+    function _formatDir(&$dirs)
+    {
+        if (!count($dirs)) {
+            return array();
+        }
+        $newdirs = array();
+        if (isset($dirs['dir'])) {
+            $newdirs['dir'] = $dirs['dir'];
+        }
+        if (isset($dirs['file'])) {
+            $newdirs['file'] = $dirs['file'];
+        }
+        $dirs = $newdirs;
+        if (isset($dirs['dir'])) {
+            uksort($dirs['dir'], 'strnatcasecmp');
+            foreach ($dirs['dir'] as $dir => $contents) {
+                $this->_formatDir($dirs['dir'][$dir]);
+            }
+        }
+        if (isset($dirs['file'])) {
+            uksort($dirs['file'], 'strnatcasecmp');
+        };
+    }
+
+    function _deFormat(&$dirs)
+    {
+        if (!count($dirs)) {
+            return array();
+        }
+        $newdirs = array();
+        if (isset($dirs['dir'])) {
+            foreach ($dirs['dir'] as $dir => $contents) {
+                $newdir = array();
+                $newdir['attribs']['name'] = $dir;
+                $this->_deFormat($contents);
+                foreach ($contents as $tag => $val) {
+                    $newdir[$tag] = $val;
+                }
+                $newdirs['dir'][] = $newdir;
+            }
+            if (count($newdirs['dir']) == 1) {
+                $newdirs['dir'] = $newdirs['dir'][0];
+            }
+        }
+        if (isset($dirs['file'])) {
+            foreach ($dirs['file'] as $name => $file) {
+                $newdirs['file'][] = $file;
+            }
+            if (count($newdirs['file']) == 1) {
+                $newdirs['file'] = $newdirs['file'][0];
+            }
+        }
+        $dirs = $newdirs;
+    }
+
+    /**
+    * reset all options to default options
+    *
+    * @access   public
+    * @see      setOption(), XML_Unserializer()
+    */
+    function resetOptions()
+    {
+        $this->options = $this->_defaultOptions;
+    }
+
+   /**
+    * set an option
+    *
+    * You can use this method if you do not want to set all options in the constructor
+    *
+    * @access   public
+    * @see      resetOption(), XML_Serializer()
+    */
+    function setOption($name, $value)
+    {
+        $this->options[$name] = $value;
+    }
+    
+   /**
+    * sets several options at once
+    *
+    * You can use this method if you do not want to set all options in the constructor
+    *
+    * @access   public
+    * @see      resetOption(), XML_Unserializer(), setOption()
+    */
+    function setOptions($options)
+    {
+        $this->options = array_merge($this->options, $options);
+    }
+
+   /**
+    * serialize data
+    *
+    * @access   public
+    * @param    mixed    $data data to serialize
+    * @return   boolean  true on success, pear error on failure
+    */
+    function serialize($data, $options = null)
+    {
+        // if options have been specified, use them instead
+        // of the previously defined ones
+        if (is_array($options)) {
+            $optionsBak = $this->options;
+            if (isset($options['overrideOptions']) && $options['overrideOptions'] == true) {
+                $this->options = array_merge($this->_defaultOptions, $options);
+            } else {
+                $this->options = array_merge($this->options, $options);
+            }
+        }
+        else {
+            $optionsBak = null;
+        }
+        
+        //  start depth is zero
+        $this->_tagDepth = 0;
+
+        $this->_serializedData = '';
+        // serialize an array
+        if (is_array($data)) {
+            if (isset($this->options['rootName'])) {
+                $tagName = $this->options['rootName'];
+            } else {
+                $tagName = 'array';
+            }
+
+            $this->_serializedData .= $this->_serializeArray($data, $tagName, $this->options['rootAttributes']);
+        }
+        
+        // add doctype declaration
+        if ($this->options['addDoctype'] === true) {
+            $this->_serializedData = XML_Util::getDoctypeDeclaration($tagName, $this->options['doctype'])
+                                   . $this->options['linebreak']
+                                   . $this->_serializedData;
+        }
+
+        //  build xml declaration
+        if ($this->options['addDecl']) {
+            $atts = array();
+            if (isset($this->options['encoding']) ) {
+                $encoding = $this->options['encoding'];
+            } else {
+                $encoding = null;
+            }
+            $this->_serializedData = XML_Util::getXMLDeclaration('1.0', $encoding)
+                                   . $this->options['linebreak']
+                                   . $this->_serializedData;
+        }
+        
+        
+               if ($optionsBak !== null) {
+                       $this->options = $optionsBak;
+               }
+               
+        return  true;
+    }
+
+   /**
+    * get the result of the serialization
+    *
+    * @access public
+    * @return string serialized XML
+    */
+    function getSerializedData()
+    {
+        if ($this->_serializedData == null ) {
+            return  $this->raiseError('No serialized data available. Use XML_Serializer::serialize() first.', XML_SERIALIZER_ERROR_NO_SERIALIZATION);
+        }
+        return $this->_serializedData;
+    }
+    
+   /**
+    * serialize any value
+    *
+    * This method checks for the type of the value and calls the appropriate method
+    *
+    * @access private
+    * @param  mixed     $value
+    * @param  string    $tagName
+    * @param  array     $attributes
+    * @return string
+    */
+    function _serializeValue($value, $tagName = null, $attributes = array())
+    {
+        if (is_array($value)) {
+            $xml = $this->_serializeArray($value, $tagName, $attributes);
+        } elseif (is_object($value)) {
+            $xml = $this->_serializeObject($value, $tagName);
+        } else {
+            $tag = array(
+                          'qname'      => $tagName,
+                          'attributes' => $attributes,
+                          'content'    => $value
+                        );
+            $xml = $this->_createXMLTag($tag);
+        }
+        return $xml;
+    }
+    
+   /**
+    * serialize an array
+    *
+    * @access   private
+    * @param    array   $array       array to serialize
+    * @param    string  $tagName     name of the root tag
+    * @param    array   $attributes  attributes for the root tag
+    * @return   string  $string      serialized data
+    * @uses     XML_Util::isValidName() to check, whether key has to be substituted
+    */
+    function _serializeArray(&$array, $tagName = null, $attributes = array())
+    {
+        $_content = null;
+        
+        /**
+         * check for special attributes
+         */
+        if ($this->options['attributesArray'] !== null) {
+            if (isset($array[$this->options['attributesArray']])) {
+                $attributes = $array[$this->options['attributesArray']];
+                unset($array[$this->options['attributesArray']]);
+            }
+            /**
+             * check for special content
+             */
+            if ($this->options['contentName'] !== null) {
+                if (isset($array[$this->options['contentName']])) {
+                    $_content = $array[$this->options['contentName']];
+                    unset($array[$this->options['contentName']]);
+                }
+            }
+        }
+
+        /*
+        * if mode is set to simpleXML, check whether
+        * the array is associative or indexed
+        */
+        if (is_array($array) && $this->options['mode'] == 'simplexml') {
+            $indexed = true;
+            if (!count($array)) {
+                $indexed = false;
+            }
+            foreach ($array as $key => $val) {
+                if (!is_int($key)) {
+                    $indexed = false;
+                    break;
+                }
+            }
+
+            if ($indexed && $this->options['mode'] == 'simplexml') {
+                $string = '';
+                foreach ($array as $key => $val) {
+                    if ($this->options['beautifyFilelist'] && $tagName == 'dir') {
+                        if (!isset($this->_curdir)) {
+                            $this->_curdir = '';
+                        }
+                        $savedir = $this->_curdir;
+                        if (isset($val['attribs'])) {
+                            if ($val['attribs']['name'] == '/') {
+                                $this->_curdir = '/';
+                            } else {
+                                if ($this->_curdir == '/') {
+                                    $this->_curdir = '';
+                                }
+                                $this->_curdir .= '/' . $val['attribs']['name'];
+                            }
+                        }
+                    }
+                    $string .= $this->_serializeValue( $val, $tagName, $attributes);
+                    if ($this->options['beautifyFilelist'] && $tagName == 'dir') {
+                        $string .= ' <!-- ' . $this->_curdir . ' -->';
+                        if (empty($savedir)) {
+                            unset($this->_curdir);
+                        } else {
+                            $this->_curdir = $savedir;
+                        }
+                    }
+                    
+                    $string .= $this->options['linebreak'];
+                               //      do indentation
+                    if ($this->options['indent']!==null && $this->_tagDepth>0) {
+                        $string .= str_repeat($this->options['indent'], $this->_tagDepth);
+                    }
+                }
+                return rtrim($string);
+            }
+        }
+        
+               if ($this->options['scalarAsAttributes'] === true) {
+               foreach ($array as $key => $value) {
+                               if (is_scalar($value) && (XML_Util::isValidName($key) === true)) {
+                                       unset($array[$key]);
+                                       $attributes[$this->options['prependAttributes'].$key] = $value;
+                               }
+                       }
+               }
+
+        // check for empty array => create empty tag
+        if (empty($array)) {
+            $tag = array(
+                            'qname'      => $tagName,
+                            'content'    => $_content,
+                            'attributes' => $attributes
+                        );
+
+        } else {
+            $this->_tagDepth++;
+            $tmp = $this->options['linebreak'];
+            foreach ($array as $key => $value) {
+                       //      do indentation
+                if ($this->options['indent']!==null && $this->_tagDepth>0) {
+                    $tmp .= str_repeat($this->options['indent'], $this->_tagDepth);
+                }
+    
+                       //      copy key
+                       $origKey        =       $key;
+                       //      key cannot be used as tagname => use default tag
+                $valid = XML_Util::isValidName($key);
+               if (PEAR::isError($valid)) {
+                   if ($this->options['classAsTagName'] && is_object($value)) {
+                       $key = get_class($value);
+                   } else {
+                       $key = $this->options['defaultTagName'];
+                   }
+                       }
+                $atts = array();
+                if ($this->options['typeHints'] === true) {
+                    $atts[$this->options['typeAttribute']] = gettype($value);
+                               if ($key !== $origKey) {
+                                       $atts[$this->options['keyAttribute']] = (string)$origKey;
+                               }
+    
+                }
+                if ($this->options['beautifyFilelist'] && $key == 'dir') {
+                    if (!isset($this->_curdir)) {
+                        $this->_curdir = '';
+                    }
+                    $savedir = $this->_curdir;
+                    if (isset($value['attribs'])) {
+                        if ($value['attribs']['name'] == '/') {
+                            $this->_curdir = '/';
+                        } else {
+                            $this->_curdir .= '/' . $value['attribs']['name'];
+                        }
+                    }
+                }
+
+                if (is_string($value) && $value && ($value{strlen($value) - 1} == "\n")) {
+                    $value .= str_repeat($this->options['indent'], $this->_tagDepth);
+                }
+                $tmp .= $this->_createXMLTag(array(
+                                                    'qname'      => $key,
+                                                    'attributes' => $atts,
+                                                    'content'    => $value )
+                                            );
+                if ($this->options['beautifyFilelist'] && $key == 'dir') {
+                    if (isset($value['attribs'])) {
+                        $tmp .= ' <!-- ' . $this->_curdir . ' -->';
+                        if (empty($savedir)) {
+                            unset($this->_curdir);
+                        } else {
+                            $this->_curdir = $savedir;
+                        }
+                    }
+                }
+                $tmp .= $this->options['linebreak'];
+            }
+            
+            $this->_tagDepth--;
+            if ($this->options['indent']!==null && $this->_tagDepth>0) {
+                $tmp .= str_repeat($this->options['indent'], $this->_tagDepth);
+            }
+    
+               if (trim($tmp) === '') {
+                       $tmp = null;
+               }
+               
+            $tag = array(
+                            'qname'      => $tagName,
+                            'content'    => $tmp,
+                            'attributes' => $attributes
+                        );
+        }
+        if ($this->options['typeHints'] === true) {
+            if (!isset($tag['attributes'][$this->options['typeAttribute']])) {
+                $tag['attributes'][$this->options['typeAttribute']] = 'array';
+            }
+        }
+
+        $string = $this->_createXMLTag($tag, false);
+        return $string;
+    }
+  
+   /**
+    * create a tag from an array
+    * this method awaits an array in the following format
+    * array(
+    *       'qname'        => $tagName,
+    *       'attributes'   => array(),
+    *       'content'      => $content,      // optional
+    *       'namespace'    => $namespace     // optional
+    *       'namespaceUri' => $namespaceUri  // optional
+    *   )
+    *
+    * @access   private
+    * @param    array   $tag tag definition
+    * @param    boolean $replaceEntities whether to replace XML entities in content or not
+    * @return   string  $string XML tag
+    */
+    function _createXMLTag( $tag, $replaceEntities = true )
+    {
+        if ($this->options['indentAttributes'] !== false) {
+            $multiline = true;
+            $indent    = str_repeat($this->options['indent'], $this->_tagDepth);
+
+            if ($this->options['indentAttributes'] == '_auto') {
+                $indent .= str_repeat(' ', (strlen($tag['qname'])+2));
+
+            } else {
+                $indent .= $this->options['indentAttributes'];
+            }
+        } else {
+            $multiline = false;
+            $indent    = false;
+        }
+    
+        if (is_array($tag['content'])) {
+            if (empty($tag['content'])) {
+                $tag['content'] =   '';
+            }
+        } elseif(is_scalar($tag['content']) && (string)$tag['content'] == '') {
+            $tag['content'] =   '';
+        }
+    
+        if (is_scalar($tag['content']) || is_null($tag['content'])) {
+            if ($this->options['encoding'] == 'UTF-8' &&
+                  version_compare(phpversion(), '5.0.0', 'lt')) {
+                $encoding = XML_UTIL_ENTITIES_UTF8_XML;
+            } else {
+                $encoding = XML_UTIL_ENTITIES_XML;
+            }
+            $tag = XML_Util::createTagFromArray($tag, $replaceEntities, $multiline, $indent, $this->options['linebreak'], $encoding);
+        } elseif (is_array($tag['content'])) {
+            $tag    =   $this->_serializeArray($tag['content'], $tag['qname'], $tag['attributes']);
+        } elseif (is_object($tag['content'])) {
+            $tag    =   $this->_serializeObject($tag['content'], $tag['qname'], $tag['attributes']);
+        } elseif (is_resource($tag['content'])) {
+            settype($tag['content'], 'string');
+            $tag    =   XML_Util::createTagFromArray($tag, $replaceEntities);
+        }
+        return  $tag;
+    }
+}
+
+//foreach (explode(PATH_SEPARATOR, ini_get('include_path')) as $path) {
+//    $t = $path . DIRECTORY_SEPARATOR . 'XML' . DIRECTORY_SEPARATOR .
+//          'Util';
+//    if (file_exists($t) && is_readable($t)) {
+//        include_once 'XML/Util';
+//    }
+//}
+//if (!class_exists('XML_Util')) {
+// well, it's one way to do things without extra deps ...
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+// +----------------------------------------------------------------------+
+// | PHP Version 4                                                        |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1997-2002 The PHP Group                                |
+// +----------------------------------------------------------------------+
+// | This source file is subject to version 2.0 of the PHP license,       |
+// | that is bundled with this package in the file LICENSE, and is        |
+// | available at through the world-wide-web at                           |
+// | http://www.php.net/license/2_02.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: Stephan Schmidt <schst@php-tools.net>                       |
+// +----------------------------------------------------------------------+
+//
+//    $Id$
+
+/**
+ * error code for invalid chars in XML name
+ */
+define("XML_UTIL_ERROR_INVALID_CHARS", 51);
+
+/**
+ * error code for invalid chars in XML name
+ */
+define("XML_UTIL_ERROR_INVALID_START", 52);
+
+/**
+ * error code for non-scalar tag content
+ */
+define("XML_UTIL_ERROR_NON_SCALAR_CONTENT", 60);
+    
+/**
+ * error code for missing tag name
+ */
+define("XML_UTIL_ERROR_NO_TAG_NAME", 61);
+    
+/**
+ * replace XML entities
+ */
+define("XML_UTIL_REPLACE_ENTITIES", 1);
+
+/**
+ * embedd content in a CData Section
+ */
+define("XML_UTIL_CDATA_SECTION", 2);
+
+/**
+ * do not replace entitites
+ */
+define("XML_UTIL_ENTITIES_NONE", 0);
+
+/**
+ * replace all XML entitites
+ * This setting will replace <, >, ", ' and &
+ */
+define("XML_UTIL_ENTITIES_XML", 1);
+
+/**
+ * replace only required XML entitites
+ * This setting will replace <, " and &
+ */
+define("XML_UTIL_ENTITIES_XML_REQUIRED", 2);
+
+/**
+ * replace HTML entitites
+ * @link    http://www.php.net/htmlentities
+ */
+define("XML_UTIL_ENTITIES_HTML", 3);
+
+/**
+ * replace all XML entitites, and encode from ISO-8859-1 to UTF-8
+ * This setting will replace <, >, ", ' and &
+ */
+define("XML_UTIL_ENTITIES_UTF8_XML", 4);
+
+/**
+ * utility class for working with XML documents
+ *
+ * @category XML
+ * @package  XML_Util
+ * @version  0.6.0
+ * @author   Stephan Schmidt <schst@php.net>
+ */
+class XML_Util {
+
+   /**
+    * return API version
+    *
+    * @access   public
+    * @static
+    * @return   string  $version API version
+    */
+    function apiVersion()
+    {
+        return "0.6";
+    }
+
+   /**
+    * replace XML entities
+    *
+    * With the optional second parameter, you may select, which
+    * entities should be replaced.
+    *
+    * <code>
+    * require_once 'XML/Util.php';
+    * 
+    * // replace XML entites:
+    * $string = XML_Util::replaceEntities("This string contains < & >.");
+    * </code>
+    *
+    * @access   public
+    * @static
+    * @param    string  string where XML special chars should be replaced
+    * @param    integer setting for entities in attribute values (one of XML_UTIL_ENTITIES_XML, XML_UTIL_ENTITIES_XML_REQUIRED, XML_UTIL_ENTITIES_HTML)
+    * @return   string  string with replaced chars
+    */
+    function replaceEntities($string, $replaceEntities = XML_UTIL_ENTITIES_XML)
+    {
+        switch ($replaceEntities) {
+            case XML_UTIL_ENTITIES_UTF8_XML:
+                return strtr(utf8_encode($string),array(
+                                          '&'  => '&amp;',
+                                          '>'  => '&gt;',
+                                          '<'  => '&lt;',
+                                          '"'  => '&quot;',
+                                          '\'' => '&apos;' ));
+                break;
+            case XML_UTIL_ENTITIES_XML:
+                return strtr($string,array(
+                                          '&'  => '&amp;',
+                                          '>'  => '&gt;',
+                                          '<'  => '&lt;',
+                                          '"'  => '&quot;',
+                                          '\'' => '&apos;' ));
+                break;
+            case XML_UTIL_ENTITIES_XML_REQUIRED:
+                return strtr($string,array(
+                                          '&'  => '&amp;',
+                                          '<'  => '&lt;',
+                                          '"'  => '&quot;' ));
+                break;
+            case XML_UTIL_ENTITIES_HTML:
+                return htmlspecialchars($string);
+                break;
+        }
+        return $string;
+    }
+
+   /**
+    * build an xml declaration
+    *
+    * <code>
+    * require_once 'XML/Util.php';
+    * 
+    * // get an XML declaration:
+    * $xmlDecl = XML_Util::getXMLDeclaration("1.0", "UTF-8", true);
+    * </code>
+    *
+    * @access   public
+    * @static
+    * @param    string  $version     xml version
+    * @param    string  $encoding    character encoding
+    * @param    boolean $standAlone  document is standalone (or not)
+    * @return   string  $decl xml declaration
+    * @uses     XML_Util::attributesToString() to serialize the attributes of the XML declaration
+    */
+    function getXMLDeclaration($version = "1.0", $encoding = null, $standalone = null)
+    {
+        $attributes = array(
+                            "version" => $version,
+                           );
+        // add encoding
+        if ($encoding !== null) {
+            $attributes["encoding"] = $encoding;
+        }
+        // add standalone, if specified
+        if ($standalone !== null) {
+            $attributes["standalone"] = $standalone ? "yes" : "no";
+        }
+        
+        return sprintf("<?xml%s?>", XML_Util::attributesToString($attributes, false));
+    }
+
+   /**
+    * build a document type declaration
+    *
+    * <code>
+    * require_once 'XML/Util.php';
+    * 
+    * // get a doctype declaration:
+    * $xmlDecl = XML_Util::getDocTypeDeclaration("rootTag","myDocType.dtd");
+    * </code>
+    *
+    * @access   public
+    * @static
+    * @param    string  $root         name of the root tag
+    * @param    string  $uri          uri of the doctype definition (or array with uri and public id)
+    * @param    string  $internalDtd  internal dtd entries   
+    * @return   string  $decl         doctype declaration
+    * @since    0.2
+    */
+    function getDocTypeDeclaration($root, $uri = null, $internalDtd = null)
+    {
+        if (is_array($uri)) {
+            $ref = sprintf( ' PUBLIC "%s" "%s"', $uri["id"], $uri["uri"] );
+        } elseif (!empty($uri)) {
+            $ref = sprintf( ' SYSTEM "%s"', $uri );
+        } else {
+            $ref = "";
+        }
+
+        if (empty($internalDtd)) {
+            return sprintf("<!DOCTYPE %s%s>", $root, $ref);
+        } else {
+            return sprintf("<!DOCTYPE %s%s [\n%s\n]>", $root, $ref, $internalDtd);
+        }
+    }
+
+   /**
+    * create string representation of an attribute list
+    *
+    * <code>
+    * require_once 'XML/Util.php';
+    * 
+    * // build an attribute string
+    * $att = array(
+    *              "foo"   =>  "bar",
+    *              "argh"  =>  "tomato"
+    *            );
+    *
+    * $attList = XML_Util::attributesToString($att);    
+    * </code>
+    *
+    * @access   public
+    * @static
+    * @param    array         $attributes        attribute array
+    * @param    boolean|array $sort              sort attribute list alphabetically, may also be an assoc array containing the keys 'sort', 'multiline', 'indent', 'linebreak' and 'entities'
+    * @param    boolean       $multiline         use linebreaks, if more than one attribute is given
+    * @param    string        $indent            string used for indentation of multiline attributes
+    * @param    string        $linebreak         string used for linebreaks of multiline attributes
+    * @param    integer       $entities          setting for entities in attribute values (one of XML_UTIL_ENTITIES_NONE, XML_UTIL_ENTITIES_XML, XML_UTIL_ENTITIES_XML_REQUIRED, XML_UTIL_ENTITIES_HTML)
+    * @return   string                           string representation of the attributes
+    * @uses     XML_Util::replaceEntities() to replace XML entities in attribute values
+    * @todo     allow sort also to be an options array
+    */
+    function attributesToString($attributes, $sort = true, $multiline = false, $indent = '    ', $linebreak = "\n", $entities = XML_UTIL_ENTITIES_XML)
+    {
+        /**
+         * second parameter may be an array
+         */
+        if (is_array($sort)) {
+            if (isset($sort['multiline'])) {
+                $multiline = $sort['multiline'];
+            }
+            if (isset($sort['indent'])) {
+                $indent = $sort['indent'];
+            }
+            if (isset($sort['linebreak'])) {
+                $multiline = $sort['linebreak'];
+            }
+            if (isset($sort['entities'])) {
+                $entities = $sort['entities'];
+            }
+            if (isset($sort['sort'])) {
+                $sort = $sort['sort'];
+            } else {
+                $sort = true;
+            }
+        }
+        $string = '';
+        if (is_array($attributes) && !empty($attributes)) {
+            if ($sort) {
+                ksort($attributes);
+            }
+            if( !$multiline || count($attributes) == 1) {
+                foreach ($attributes as $key => $value) {
+                    if ($entities != XML_UTIL_ENTITIES_NONE) {
+                        $value = XML_Util::replaceEntities($value, $entities);
+                    }
+                    $string .= ' '.$key.'="'.$value.'"';
+                }
+            } else {
+                $first = true;
+                foreach ($attributes as $key => $value) {
+                    if ($entities != XML_UTIL_ENTITIES_NONE) {
+                        $value = XML_Util::replaceEntities($value, $entities);
+                    }
+                    if ($first) {
+                        $string .= " ".$key.'="'.$value.'"';
+                        $first = false;
+                    } else {
+                        $string .= $linebreak.$indent.$key.'="'.$value.'"';
+                    }
+                }
+            }
+        }
+        return $string;
+    }
+
+   /**
+    * create a tag
+    *
+    * This method will call XML_Util::createTagFromArray(), which
+    * is more flexible.
+    *
+    * <code>
+    * require_once 'XML/Util.php';
+    * 
+    * // create an XML tag:
+    * $tag = XML_Util::createTag("myNs:myTag", array("foo" => "bar"), "This is inside the tag", "http://www.w3c.org/myNs#");
+    * </code>
+    *
+    * @access   public
+    * @static
+    * @param    string  $qname             qualified tagname (including namespace)
+    * @param    array   $attributes        array containg attributes
+    * @param    mixed   $content
+    * @param    string  $namespaceUri      URI of the namespace
+    * @param    integer $replaceEntities   whether to replace XML special chars in content, embedd it in a CData section or none of both
+    * @param    boolean $multiline         whether to create a multiline tag where each attribute gets written to a single line
+    * @param    string  $indent            string used to indent attributes (_auto indents attributes so they start at the same column)
+    * @param    string  $linebreak         string used for linebreaks
+    * @param    string  $encoding          encoding that should be used to translate content
+    * @return   string  $string            XML tag
+    * @see      XML_Util::createTagFromArray()
+    * @uses     XML_Util::createTagFromArray() to create the tag
+    */
+    function createTag($qname, $attributes = array(), $content = null, $namespaceUri = null, $replaceEntities = XML_UTIL_REPLACE_ENTITIES, $multiline = false, $indent = "_auto", $linebreak = "\n", $encoding = XML_UTIL_ENTITIES_XML)
+    {
+        $tag = array(
+                     "qname"      => $qname,
+                     "attributes" => $attributes
+                    );
+
+        // add tag content
+        if ($content !== null) {
+            $tag["content"] = $content;
+        }
+        
+        // add namespace Uri
+        if ($namespaceUri !== null) {
+            $tag["namespaceUri"] = $namespaceUri;
+        }
+
+        return XML_Util::createTagFromArray($tag, $replaceEntities, $multiline, $indent, $linebreak, $encoding);
+    }
+
+   /**
+    * create a tag from an array
+    * this method awaits an array in the following format
+    * <pre>
+    * array(
+    *  "qname"        => $qname         // qualified name of the tag
+    *  "namespace"    => $namespace     // namespace prefix (optional, if qname is specified or no namespace)
+    *  "localpart"    => $localpart,    // local part of the tagname (optional, if qname is specified)
+    *  "attributes"   => array(),       // array containing all attributes (optional)
+    *  "content"      => $content,      // tag content (optional)
+    *  "namespaceUri" => $namespaceUri  // namespaceUri for the given namespace (optional)
+    *   )
+    * </pre>
+    *
+    * <code>
+    * require_once 'XML/Util.php';
+    * 
+    * $tag = array(
+    *           "qname"        => "foo:bar",
+    *           "namespaceUri" => "http://foo.com",
+    *           "attributes"   => array( "key" => "value", "argh" => "fruit&vegetable" ),
+    *           "content"      => "I'm inside the tag",
+    *            );
+    * // creating a tag with qualified name and namespaceUri
+    * $string = XML_Util::createTagFromArray($tag);
+    * </code>
+    *
+    * @access   public
+    * @static
+    * @param    array   $tag               tag definition
+    * @param    integer $replaceEntities   whether to replace XML special chars in content, embedd it in a CData section or none of both
+    * @param    boolean $multiline         whether to create a multiline tag where each attribute gets written to a single line
+    * @param    string  $indent            string used to indent attributes (_auto indents attributes so they start at the same column)
+    * @param    string  $linebreak         string used for linebreaks
+    * @return   string  $string            XML tag
+    * @see      XML_Util::createTag()
+    * @uses     XML_Util::attributesToString() to serialize the attributes of the tag
+    * @uses     XML_Util::splitQualifiedName() to get local part and namespace of a qualified name
+    */
+    function createTagFromArray($tag, $replaceEntities = XML_UTIL_REPLACE_ENTITIES, $multiline = false, $indent = "_auto", $linebreak = "\n", $encoding = XML_UTIL_ENTITIES_XML)
+    {
+        if (isset($tag["content"]) && !is_scalar($tag["content"])) {
+            return XML_Util::raiseError( "Supplied non-scalar value as tag content", XML_UTIL_ERROR_NON_SCALAR_CONTENT );
+        }
+
+        if (!isset($tag['qname']) && !isset($tag['localPart'])) {
+            return XML_Util::raiseError( 'You must either supply a qualified name (qname) or local tag name (localPart).', XML_UTIL_ERROR_NO_TAG_NAME );
+        }
+
+        // if no attributes hav been set, use empty attributes
+        if (!isset($tag["attributes"]) || !is_array($tag["attributes"])) {
+            $tag["attributes"] = array();
+        }
+        
+        // qualified name is not given
+        if (!isset($tag["qname"])) {
+            // check for namespace
+            if (isset($tag["namespace"]) && !empty($tag["namespace"])) {
+                $tag["qname"] = $tag["namespace"].":".$tag["localPart"];
+            } else {
+                $tag["qname"] = $tag["localPart"];
+            }
+        // namespace URI is set, but no namespace
+        } elseif (isset($tag["namespaceUri"]) && !isset($tag["namespace"])) {
+            $parts = XML_Util::splitQualifiedName($tag["qname"]);
+            $tag["localPart"] = $parts["localPart"];
+            if (isset($parts["namespace"])) {
+                $tag["namespace"] = $parts["namespace"];
+            }
+        }
+
+        if (isset($tag["namespaceUri"]) && !empty($tag["namespaceUri"])) {
+            // is a namespace given
+            if (isset($tag["namespace"]) && !empty($tag["namespace"])) {
+                $tag["attributes"]["xmlns:".$tag["namespace"]] = $tag["namespaceUri"];
+            } else {
+                // define this Uri as the default namespace
+                $tag["attributes"]["xmlns"] = $tag["namespaceUri"];
+            }
+        }
+
+        // check for multiline attributes
+        if ($multiline === true) {
+            if ($indent === "_auto") {
+                $indent = str_repeat(" ", (strlen($tag["qname"])+2));
+            }
+        }
+        
+        // create attribute list
+        $attList    =   XML_Util::attributesToString($tag["attributes"], true, $multiline, $indent, $linebreak );
+        if (!isset($tag["content"]) || (string)$tag["content"] == '') {
+            $tag    =   sprintf("<%s%s />", $tag["qname"], $attList);
+        } else {
+            if ($replaceEntities == XML_UTIL_REPLACE_ENTITIES) {
+                $tag["content"] = XML_Util::replaceEntities($tag["content"], $encoding);
+            } elseif ($replaceEntities == XML_UTIL_CDATA_SECTION) {
+                $tag["content"] = XML_Util::createCDataSection($tag["content"]);
+            }
+            $tag    =   sprintf("<%s%s>%s</%s>", $tag["qname"], $attList, $tag["content"], $tag["qname"] );
+        }        
+        return  $tag;
+    }
+
+   /**
+    * create a start element
+    *
+    * <code>
+    * require_once 'XML/Util.php';
+    * 
+    * // create an XML start element:
+    * $tag = XML_Util::createStartElement("myNs:myTag", array("foo" => "bar") ,"http://www.w3c.org/myNs#");
+    * </code>
+    *
+    * @access   public
+    * @static
+    * @param    string  $qname             qualified tagname (including namespace)
+    * @param    array   $attributes        array containg attributes
+    * @param    string  $namespaceUri      URI of the namespace
+    * @param    boolean $multiline         whether to create a multiline tag where each attribute gets written to a single line
+    * @param    string  $indent            string used to indent attributes (_auto indents attributes so they start at the same column)
+    * @param    string  $linebreak         string used for linebreaks
+    * @return   string  $string            XML start element
+    * @see      XML_Util::createEndElement(), XML_Util::createTag()
+    */
+    function createStartElement($qname, $attributes = array(), $namespaceUri = null, $multiline = false, $indent = '_auto', $linebreak = "\n")
+    {
+        // if no attributes hav been set, use empty attributes
+        if (!isset($attributes) || !is_array($attributes)) {
+            $attributes = array();
+        }
+        
+        if ($namespaceUri != null) {
+            $parts = XML_Util::splitQualifiedName($qname);
+        }
+
+        // check for multiline attributes
+        if ($multiline === true) {
+            if ($indent === "_auto") {
+                $indent = str_repeat(" ", (strlen($qname)+2));
+            }
+        }
+
+        if ($namespaceUri != null) {
+            // is a namespace given
+            if (isset($parts["namespace"]) && !empty($parts["namespace"])) {
+                $attributes["xmlns:".$parts["namespace"]] = $namespaceUri;
+            } else {
+                // define this Uri as the default namespace
+                $attributes["xmlns"] = $namespaceUri;
+            }
+        }
+
+        // create attribute list
+        $attList    =   XML_Util::attributesToString($attributes, true, $multiline, $indent, $linebreak);
+        $element    =   sprintf("<%s%s>", $qname, $attList);
+        return  $element;
+    }
+
+   /**
+    * create an end element
+    *
+    * <code>
+    * require_once 'XML/Util.php';
+    * 
+    * // create an XML start element:
+    * $tag = XML_Util::createEndElement("myNs:myTag");
+    * </code>
+    *
+    * @access   public
+    * @static
+    * @param    string  $qname             qualified tagname (including namespace)
+    * @return   string  $string            XML end element
+    * @see      XML_Util::createStartElement(), XML_Util::createTag()
+    */
+    function createEndElement($qname)
+    {
+        $element    =   sprintf("</%s>", $qname);
+        return  $element;
+    }
+    
+   /**
+    * create an XML comment
+    *
+    * <code>
+    * require_once 'XML/Util.php';
+    * 
+    * // create an XML start element:
+    * $tag = XML_Util::createComment("I am a comment");
+    * </code>
+    *
+    * @access   public
+    * @static
+    * @param    string  $content           content of the comment
+    * @return   string  $comment           XML comment
+    */
+    function createComment($content)
+    {
+        $comment    =   sprintf("<!-- %s -->", $content);
+        return  $comment;
+    }
+    
+   /**
+    * create a CData section
+    *
+    * <code>
+    * require_once 'XML/Util.php';
+    * 
+    * // create a CData section
+    * $tag = XML_Util::createCDataSection("I am content.");
+    * </code>
+    *
+    * @access   public
+    * @static
+    * @param    string  $data              data of the CData section
+    * @return   string  $string            CData section with content
+    */
+    function createCDataSection($data)
+    {
+        return  sprintf("<![CDATA[%s]]>", $data);
+    }
+
+   /**
+    * split qualified name and return namespace and local part
+    *
+    * <code>
+    * require_once 'XML/Util.php';
+    * 
+    * // split qualified tag
+    * $parts = XML_Util::splitQualifiedName("xslt:stylesheet");
+    * </code>
+    * the returned array will contain two elements:
+    * <pre>
+    * array(
+    *       "namespace" => "xslt",
+    *       "localPart" => "stylesheet"
+    *      );
+    * </pre>
+    *
+    * @access public
+    * @static
+    * @param  string    $qname      qualified tag name
+    * @param  string    $defaultNs  default namespace (optional)
+    * @return array     $parts      array containing namespace and local part
+    */
+    function splitQualifiedName($qname, $defaultNs = null)
+    {
+        if (strstr($qname, ':')) {
+            $tmp = explode(":", $qname);
+            return array(
+                          "namespace" => $tmp[0],
+                          "localPart" => $tmp[1]
+                        );
+        }
+        return array(
+                      "namespace" => $defaultNs,
+                      "localPart" => $qname
+                    );
+    }
+
+   /**
+    * check, whether string is valid XML name
+    *
+    * <p>XML names are used for tagname, attribute names and various
+    * other, lesser known entities.</p>
+    * <p>An XML name may only consist of alphanumeric characters,
+    * dashes, undescores and periods, and has to start with a letter
+    * or an underscore.
+    * </p>
+    *
+    * <code>
+    * require_once 'XML/Util.php';
+    * 
+    * // verify tag name
+    * $result = XML_Util::isValidName("invalidTag?");
+    * if (XML_Util::isError($result)) {
+    *    print "Invalid XML name: " . $result->getMessage();
+    * }
+    * </code>
+    *
+    * @access  public
+    * @static
+    * @param   string  $string string that should be checked
+    * @return  mixed   $valid  true, if string is a valid XML name, PEAR error otherwise
+    * @todo    support for other charsets
+    */
+    function isValidName($string)
+    {
+        // check for invalid chars
+        if (!preg_match("/^[[:alnum:]_\-.]$/", $string{0})) {
+            return XML_Util::raiseError( "XML names may only start with letter or underscore", XML_UTIL_ERROR_INVALID_START );
+        }
+        
+        // check for invalid chars
+        if (!preg_match("/^([a-zA-Z_]([a-zA-Z0-9_\-\.]*)?:)?[a-zA-Z_]([a-zA-Z0-9_\-\.]+)?$/", $string)) {
+            return XML_Util::raiseError( "XML names may only contain alphanumeric chars, period, hyphen, colon and underscores", XML_UTIL_ERROR_INVALID_CHARS );
+         }
+        // XML name is valid
+        return true;
+    }
+
+   /**
+    * replacement for XML_Util::raiseError
+    *
+    * Avoids the necessity to always require
+    * PEAR.php
+    *
+    * @access   public
+    * @param    string      error message
+    * @param    integer     error code
+    * @return   object PEAR_Error
+    */
+    function raiseError($msg, $code)
+    {
+        require_once 'PEAR.php';
+        return PEAR::raiseError($msg, $code);
+    }
+}
+//} // if (!class_exists('XML_Util'))
+?>
\ No newline at end of file
diff --git a/pear/PEAR/PackageFile/Parser/v1.php b/pear/PEAR/PackageFile/Parser/v1.php
new file mode 100644 (file)
index 0000000..692ec70
--- /dev/null
@@ -0,0 +1,461 @@
+<?php
+/**
+ * package.xml parsing class, package.xml version 1.0
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a1
+ */
+/**
+ * package.xml abstraction class
+ */
+require_once 'PEAR/PackageFile/v1.php';
+/**
+ * Parser for package.xml version 1.0
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @PEAR-VER@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
+ */
+class PEAR_PackageFile_Parser_v1
+{
+    var $_registry;
+    var $_config;
+    var $_logger;
+    /**
+     * BC hack to allow PEAR_Common::infoFromString() to sort of
+     * work with the version 2.0 format - there's no filelist though
+     * @param PEAR_PackageFile_v2
+     */
+    function fromV2($packagefile)
+    {
+        $info = $packagefile->getArray(true);
+        $ret = new PEAR_PackageFile_v1;
+        $ret->fromArray($info['old']);
+    }
+
+    function setConfig(&$c)
+    {
+        $this->_config = &$c;
+        $this->_registry = &$c->getRegistry();
+    }
+
+    function setLogger(&$l)
+    {
+        $this->_logger = &$l;
+    }
+
+    /**
+     * @param string contents of package.xml file, version 1.0
+     * @return bool success of parsing
+     */
+    function parse($data, $file, $archive = false)
+    {
+        if (!extension_loaded('xml')) {
+            return PEAR::raiseError('Cannot create xml parser for parsing package.xml, no xml extension');
+        }
+        $xp = @xml_parser_create();
+        if (!$xp) {
+            return PEAR::raiseError('Cannot create xml parser for parsing package.xml');
+        }
+        xml_set_object($xp, $this);
+        xml_set_element_handler($xp, '_element_start_1_0', '_element_end_1_0');
+        xml_set_character_data_handler($xp, '_pkginfo_cdata_1_0');
+        xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, false);
+
+        $this->element_stack = array();
+        $this->_packageInfo = array('provides' => array());
+        $this->current_element = false;
+        unset($this->dir_install);
+        $this->_packageInfo['filelist'] = array();
+        $this->filelist =& $this->_packageInfo['filelist'];
+        $this->dir_names = array();
+        $this->in_changelog = false;
+        $this->d_i = 0;
+        $this->cdata = '';
+        $this->_isValid = true;
+
+        if (!xml_parse($xp, $data, 1)) {
+            $code = xml_get_error_code($xp);
+            $line = xml_get_current_line_number($xp);
+            xml_parser_free($xp);
+            return PEAR::raiseError(sprintf("XML error: %s at line %d",
+                           $str = xml_error_string($code), $line), 2);
+        }
+
+        xml_parser_free($xp);
+
+        $pf = new PEAR_PackageFile_v1;
+        $pf->setConfig($this->_config);
+        if (isset($this->_logger)) {
+            $pf->setLogger($this->_logger);
+        }
+        $pf->setPackagefile($file, $archive);
+        $pf->fromArray($this->_packageInfo);
+        return $pf;
+    }
+    // {{{ _unIndent()
+
+    /**
+     * Unindent given string
+     *
+     * @param string $str The string that has to be unindented.
+     * @return string
+     * @access private
+     */
+    function _unIndent($str)
+    {
+        // remove leading newlines
+        $str = preg_replace('/^[\r\n]+/', '', $str);
+        // find whitespace at the beginning of the first line
+        $indent_len = strspn($str, " \t");
+        $indent = substr($str, 0, $indent_len);
+        $data = '';
+        // remove the same amount of whitespace from following lines
+        foreach (explode("\n", $str) as $line) {
+            if (substr($line, 0, $indent_len) == $indent) {
+                $data .= substr($line, $indent_len) . "\n";
+            }
+        }
+        return $data;
+    }
+
+    // Support for package DTD v1.0:
+    // {{{ _element_start_1_0()
+
+    /**
+     * XML parser callback for ending elements.  Used for version 1.0
+     * packages.
+     *
+     * @param resource  $xp    XML parser resource
+     * @param string    $name  name of ending element
+     *
+     * @return void
+     *
+     * @access private
+     */
+    function _element_start_1_0($xp, $name, $attribs)
+    {
+        array_push($this->element_stack, $name);
+        $this->current_element = $name;
+        $spos = sizeof($this->element_stack) - 2;
+        $this->prev_element = ($spos >= 0) ? $this->element_stack[$spos] : '';
+        $this->current_attributes = $attribs;
+        $this->cdata = '';
+        switch ($name) {
+            case 'dir':
+                if ($this->in_changelog) {
+                    break;
+                }
+                if (array_key_exists('name', $attribs) && $attribs['name'] != '/') {
+                    $attribs['name'] = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'),
+                        $attribs['name']);
+                    if (strrpos($attribs['name'], '/') == strlen($attribs['name']) - 1) {
+                        $attribs['name'] = substr($attribs['name'], 0,
+                            strlen($attribs['name']) - 1);
+                    }
+                    if (strpos($attribs['name'], '/') === 0) {
+                        $attribs['name'] = substr($attribs['name'], 1);
+                    }
+                    $this->dir_names[] = $attribs['name'];
+                }
+                if (isset($attribs['baseinstalldir'])) {
+                    $this->dir_install = $attribs['baseinstalldir'];
+                }
+                if (isset($attribs['role'])) {
+                    $this->dir_role = $attribs['role'];
+                }
+                break;
+            case 'file':
+                if ($this->in_changelog) {
+                    break;
+                }
+                if (isset($attribs['name'])) {
+                    $path = '';
+                    if (count($this->dir_names)) {
+                        foreach ($this->dir_names as $dir) {
+                            $path .= $dir . '/';
+                        }
+                    }
+                    $path .= preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'),
+                        $attribs['name']);
+                    unset($attribs['name']);
+                    $this->current_path = $path;
+                    $this->filelist[$path] = $attribs;
+                    // Set the baseinstalldir only if the file don't have this attrib
+                    if (!isset($this->filelist[$path]['baseinstalldir']) &&
+                        isset($this->dir_install))
+                    {
+                        $this->filelist[$path]['baseinstalldir'] = $this->dir_install;
+                    }
+                    // Set the Role
+                    if (!isset($this->filelist[$path]['role']) && isset($this->dir_role)) {
+                        $this->filelist[$path]['role'] = $this->dir_role;
+                    }
+                }
+                break;
+            case 'replace':
+                if (!$this->in_changelog) {
+                    $this->filelist[$this->current_path]['replacements'][] = $attribs;
+                }
+                break;
+            case 'maintainers':
+                $this->_packageInfo['maintainers'] = array();
+                $this->m_i = 0; // maintainers array index
+                break;
+            case 'maintainer':
+                // compatibility check
+                if (!isset($this->_packageInfo['maintainers'])) {
+                    $this->_packageInfo['maintainers'] = array();
+                    $this->m_i = 0;
+                }
+                $this->_packageInfo['maintainers'][$this->m_i] = array();
+                $this->current_maintainer =& $this->_packageInfo['maintainers'][$this->m_i];
+                break;
+            case 'changelog':
+                $this->_packageInfo['changelog'] = array();
+                $this->c_i = 0; // changelog array index
+                $this->in_changelog = true;
+                break;
+            case 'release':
+                if ($this->in_changelog) {
+                    $this->_packageInfo['changelog'][$this->c_i] = array();
+                    $this->current_release = &$this->_packageInfo['changelog'][$this->c_i];
+                } else {
+                    $this->current_release = &$this->_packageInfo;
+                }
+                break;
+            case 'deps':
+                if (!$this->in_changelog) {
+                    $this->_packageInfo['release_deps'] = array();
+                }
+                break;
+            case 'dep':
+                // dependencies array index
+                if (!$this->in_changelog) {
+                    $this->d_i++;
+                    isset($attribs['type']) ? ($attribs['type'] = strtolower($attribs['type'])) : false;
+                    $this->_packageInfo['release_deps'][$this->d_i] = $attribs;
+                }
+                break;
+            case 'configureoptions':
+                if (!$this->in_changelog) {
+                    $this->_packageInfo['configure_options'] = array();
+                }
+                break;
+            case 'configureoption':
+                if (!$this->in_changelog) {
+                    $this->_packageInfo['configure_options'][] = $attribs;
+                }
+                break;
+            case 'provides':
+                if (empty($attribs['type']) || empty($attribs['name'])) {
+                    break;
+                }
+                $attribs['explicit'] = true;
+                $this->_packageInfo['provides']["$attribs[type];$attribs[name]"] = $attribs;
+                break;
+            case 'package' :
+                if (isset($attribs['version'])) {
+                    $this->_packageInfo['xsdversion'] = trim($attribs['version']);
+                } else {
+                    $this->_packageInfo['xsdversion'] = '1.0';
+                }
+                if (isset($attribs['packagerversion'])) {
+                    $this->_packageInfo['packagerversion'] = $attribs['packagerversion'];
+                }
+                break;
+        }
+    }
+
+    // }}}
+    // {{{ _element_end_1_0()
+
+    /**
+     * XML parser callback for ending elements.  Used for version 1.0
+     * packages.
+     *
+     * @param resource  $xp    XML parser resource
+     * @param string    $name  name of ending element
+     *
+     * @return void
+     *
+     * @access private
+     */
+    function _element_end_1_0($xp, $name)
+    {
+        $data = trim($this->cdata);
+        switch ($name) {
+            case 'name':
+                switch ($this->prev_element) {
+                    case 'package':
+                        $this->_packageInfo['package'] = $data;
+                        break;
+                    case 'maintainer':
+                        $this->current_maintainer['name'] = $data;
+                        break;
+                }
+                break;
+            case 'extends' :
+                $this->_packageInfo['extends'] = $data;
+                break;
+            case 'summary':
+                $this->_packageInfo['summary'] = $data;
+                break;
+            case 'description':
+                $data = $this->_unIndent($this->cdata);
+                $this->_packageInfo['description'] = $data;
+                break;
+            case 'user':
+                $this->current_maintainer['handle'] = $data;
+                break;
+            case 'email':
+                $this->current_maintainer['email'] = $data;
+                break;
+            case 'role':
+                $this->current_maintainer['role'] = $data;
+                break;
+            case 'version':
+                //$data = ereg_replace ('[^a-zA-Z0-9._\-]', '_', $data);
+                if ($this->in_changelog) {
+                    $this->current_release['version'] = $data;
+                } else {
+                    $this->_packageInfo['version'] = $data;
+                }
+                break;
+            case 'date':
+                if ($this->in_changelog) {
+                    $this->current_release['release_date'] = $data;
+                } else {
+                    $this->_packageInfo['release_date'] = $data;
+                }
+                break;
+            case 'notes':
+                // try to "de-indent" release notes in case someone
+                // has been over-indenting their xml ;-)
+                $data = $this->_unIndent($this->cdata);
+                if ($this->in_changelog) {
+                    $this->current_release['release_notes'] = $data;
+                } else {
+                    $this->_packageInfo['release_notes'] = $data;
+                }
+                break;
+            case 'warnings':
+                if ($this->in_changelog) {
+                    $this->current_release['release_warnings'] = $data;
+                } else {
+                    $this->_packageInfo['release_warnings'] = $data;
+                }
+                break;
+            case 'state':
+                if ($this->in_changelog) {
+                    $this->current_release['release_state'] = $data;
+                } else {
+                    $this->_packageInfo['release_state'] = $data;
+                }
+                break;
+            case 'license':
+                if ($this->in_changelog) {
+                    $this->current_release['release_license'] = $data;
+                } else {
+                    $this->_packageInfo['release_license'] = $data;
+                }
+                break;
+            case 'dep':
+                if ($data && !$this->in_changelog) {
+                    $this->_packageInfo['release_deps'][$this->d_i]['name'] = $data;
+                }
+                break;
+            case 'dir':
+                if ($this->in_changelog) {
+                    break;
+                }
+                array_pop($this->dir_names);
+                break;
+            case 'file':
+                if ($this->in_changelog) {
+                    break;
+                }
+                if ($data) {
+                    $path = '';
+                    if (count($this->dir_names)) {
+                        foreach ($this->dir_names as $dir) {
+                            $path .= $dir . '/';
+                        }
+                    }
+                    $path .= $data;
+                    $this->filelist[$path] = $this->current_attributes;
+                    // Set the baseinstalldir only if the file don't have this attrib
+                    if (!isset($this->filelist[$path]['baseinstalldir']) &&
+                        isset($this->dir_install))
+                    {
+                        $this->filelist[$path]['baseinstalldir'] = $this->dir_install;
+                    }
+                    // Set the Role
+                    if (!isset($this->filelist[$path]['role']) && isset($this->dir_role)) {
+                        $this->filelist[$path]['role'] = $this->dir_role;
+                    }
+                }
+                break;
+            case 'maintainer':
+                if (empty($this->_packageInfo['maintainers'][$this->m_i]['role'])) {
+                    $this->_packageInfo['maintainers'][$this->m_i]['role'] = 'lead';
+                }
+                $this->m_i++;
+                break;
+            case 'release':
+                if ($this->in_changelog) {
+                    $this->c_i++;
+                }
+                break;
+            case 'changelog':
+                $this->in_changelog = false;
+                break;
+        }
+        array_pop($this->element_stack);
+        $spos = sizeof($this->element_stack) - 1;
+        $this->current_element = ($spos > 0) ? $this->element_stack[$spos] : '';
+        $this->cdata = '';
+    }
+
+    // }}}
+    // {{{ _pkginfo_cdata_1_0()
+
+    /**
+     * XML parser callback for character data.  Used for version 1.0
+     * packages.
+     *
+     * @param resource  $xp    XML parser resource
+     * @param string    $name  character data
+     *
+     * @return void
+     *
+     * @access private
+     */
+    function _pkginfo_cdata_1_0($xp, $data)
+    {
+        if (isset($this->cdata)) {
+            $this->cdata .= $data;
+        }
+    }
+
+    // }}}
+}
+?>
\ No newline at end of file
diff --git a/pear/PEAR/PackageFile/Parser/v2.php b/pear/PEAR/PackageFile/Parser/v2.php
new file mode 100644 (file)
index 0000000..ac37153
--- /dev/null
@@ -0,0 +1,115 @@
+<?php
+/**
+ * package.xml parsing class, package.xml version 2.0
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a1
+ */
+/**
+ * base xml parser class
+ */
+require_once 'PEAR/XMLParser.php';
+require_once 'PEAR/PackageFile/v2.php';
+/**
+ * Parser for package.xml version 2.0
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @PEAR-VER@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
+ */
+class PEAR_PackageFile_Parser_v2 extends PEAR_XMLParser
+{
+    var $_config;
+    var $_logger;
+    var $_registry;
+
+    function setConfig(&$c)
+    {
+        $this->_config = &$c;
+        $this->_registry = &$c->getRegistry();
+    }
+
+    function setLogger(&$l)
+    {
+        $this->_logger = &$l;
+    }
+    /**
+     * Unindent given string
+     *
+     * @param string $str The string that has to be unindented.
+     * @return string
+     * @access private
+     */
+    function _unIndent($str)
+    {
+        // remove leading newlines
+        $str = preg_replace('/^[\r\n]+/', '', $str);
+        // find whitespace at the beginning of the first line
+        $indent_len = strspn($str, " \t");
+        $indent = substr($str, 0, $indent_len);
+        $data = '';
+        // remove the same amount of whitespace from following lines
+        foreach (explode("\n", $str) as $line) {
+            if (substr($line, 0, $indent_len) == $indent) {
+                $data .= substr($line, $indent_len) . "\n";
+            }
+        }
+        return $data;
+    }
+
+    /**
+     * post-process data
+     *
+     * @param string $data
+     * @param string $element element name
+     */
+    function postProcess($data, $element)
+    {
+        if ($element == 'notes') {
+            return trim($this->_unIndent($data));
+        }
+        return trim($data);
+    }
+
+    /**
+     * @param string
+     * @param string file name of the package.xml
+     * @param string|false name of the archive this package.xml came from, if any
+     * @param string class name to instantiate and return.  This must be PEAR_PackageFile_v2 or
+     *               a subclass
+     * @return PEAR_PackageFile_v2
+     */
+    function parse($data, $file, $archive = false, $class = 'PEAR_PackageFile_v2')
+    {
+        if (PEAR::isError($err = parent::parse($data, $file))) {
+            return $err;
+        }
+        $ret = new $class;
+        $ret->setConfig($this->_config);
+        if (isset($this->_logger)) {
+            $ret->setLogger($this->_logger);
+        }
+        $ret->fromArray($this->_unserializedData);
+        $ret->setPackagefile($file, $archive);
+        return $ret;
+    }
+}
+?>
\ No newline at end of file
diff --git a/pear/PEAR/PackageFile/v1.php b/pear/PEAR/PackageFile/v1.php
new file mode 100644 (file)
index 0000000..eb87c5b
--- /dev/null
@@ -0,0 +1,1596 @@
+<?php
+/**
+ * PEAR_PackageFile_v1, package.xml version 1.0
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a1
+ */
+/**
+ * For error handling
+ */
+require_once 'PEAR/ErrorStack.php';
+
+/**
+ * Error code if parsing is attempted with no xml extension
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_XML_EXT', 3);
+
+/**
+ * Error code if creating the xml parser resource fails
+ */
+define('PEAR_PACKAGEFILE_ERROR_CANT_MAKE_PARSER', 4);
+
+/**
+ * Error code used for all sax xml parsing errors
+ */
+define('PEAR_PACKAGEFILE_ERROR_PARSER_ERROR', 5);
+
+/**
+ * Error code used when there is no name
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_NAME', 6);
+
+/**
+ * Error code when a package name is not valid
+ */
+define('PEAR_PACKAGEFILE_ERROR_INVALID_NAME', 7);
+
+/**
+ * Error code used when no summary is parsed
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_SUMMARY', 8);
+
+/**
+ * Error code for summaries that are more than 1 line
+ */
+define('PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY', 9);
+
+/**
+ * Error code used when no description is present
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION', 10);
+
+/**
+ * Error code used when no license is present
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_LICENSE', 11);
+
+/**
+ * Error code used when a <version> version number is not present
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_VERSION', 12);
+
+/**
+ * Error code used when a <version> version number is invalid
+ */
+define('PEAR_PACKAGEFILE_ERROR_INVALID_VERSION', 13);
+
+/**
+ * Error code when release state is missing
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_STATE', 14);
+
+/**
+ * Error code when release state is invalid
+ */
+define('PEAR_PACKAGEFILE_ERROR_INVALID_STATE', 15);
+
+/**
+ * Error code when release state is missing
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_DATE', 16);
+
+/**
+ * Error code when release state is invalid
+ */
+define('PEAR_PACKAGEFILE_ERROR_INVALID_DATE', 17);
+
+/**
+ * Error code when no release notes are found
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_NOTES', 18);
+
+/**
+ * Error code when no maintainers are found
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS', 19);
+
+/**
+ * Error code when a maintainer has no handle
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE', 20);
+
+/**
+ * Error code when a maintainer has no handle
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE', 21);
+
+/**
+ * Error code when a maintainer has no name
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME', 22);
+
+/**
+ * Error code when a maintainer has no email
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL', 23);
+
+/**
+ * Error code when a maintainer has no handle
+ */
+define('PEAR_PACKAGEFILE_ERROR_INVALID_MAINTROLE', 24);
+
+/**
+ * Error code when a dependency is not a PHP dependency, but has no name
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_DEPNAME', 25);
+
+/**
+ * Error code when a dependency has no type (pkg, php, etc.)
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE', 26);
+
+/**
+ * Error code when a dependency has no relation (lt, ge, has, etc.)
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_DEPREL', 27);
+
+/**
+ * Error code when a dependency is not a 'has' relation, but has no version
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION', 28);
+
+/**
+ * Error code when a dependency has an invalid relation
+ */
+define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPREL', 29);
+
+/**
+ * Error code when a dependency has an invalid type
+ */
+define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPTYPE', 30);
+
+/**
+ * Error code when a dependency has an invalid optional option
+ */
+define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL', 31);
+
+/**
+ * Error code when a dependency is a pkg dependency, and has an invalid package name
+ */
+define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPNAME', 32);
+
+/**
+ * Error code when a dependency has a channel="foo" attribute, and foo is not a registered channel
+ */
+define('PEAR_PACKAGEFILE_ERROR_UNKNOWN_DEPCHANNEL', 33);
+
+/**
+ * Error code when rel="has" and version attribute is present.
+ */
+define('PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED', 34);
+
+/**
+ * Error code when type="php" and dependency name is present
+ */
+define('PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED', 35);
+
+/**
+ * Error code when a configure option has no name
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_CONFNAME', 36);
+
+/**
+ * Error code when a configure option has no name
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT', 37);
+
+/**
+ * Error code when a file in the filelist has an invalid role
+ */
+define('PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE', 38);
+
+/**
+ * Error code when a file in the filelist has no role
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_FILEROLE', 39);
+
+/**
+ * Error code when analyzing a php source file that has parse errors
+ */
+define('PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE', 40);
+
+/**
+ * Error code when analyzing a php source file reveals a source element
+ * without a package name prefix
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX', 41);
+
+/**
+ * Error code when an unknown channel is specified
+ */
+define('PEAR_PACKAGEFILE_ERROR_UNKNOWN_CHANNEL', 42);
+
+/**
+ * Error code when no files are found in the filelist
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_FILES', 43);
+
+/**
+ * Error code when a file is not valid php according to _analyzeSourceCode()
+ */
+define('PEAR_PACKAGEFILE_ERROR_INVALID_FILE', 44);
+
+/**
+ * Error code when the channel validator returns an error or warning
+ */
+define('PEAR_PACKAGEFILE_ERROR_CHANNELVAL', 45);
+
+/**
+ * Error code when a php5 package is packaged in php4 (analysis doesn't work)
+ */
+define('PEAR_PACKAGEFILE_ERROR_PHP5', 46);
+
+/**
+ * Error code when a file is listed in package.xml but does not exist
+ */
+define('PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND', 47);
+
+/**
+ * Error code when a <dep type="php" rel="not"... is encountered (use rel="ne")
+ */
+define('PEAR_PACKAGEFILE_PHP_NO_NOT', 48);
+
+/**
+ * Error code when a package.xml contains non-ISO-8859-1 characters
+ */
+define('PEAR_PACKAGEFILE_ERROR_NON_ISO_CHARS', 49);
+
+/**
+ * Error code when a dependency is not a 'has' relation, but has no version
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION', 50);
+
+/**
+ * Error code when a package has no lead developer
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_LEAD', 51);
+
+/**
+ * Error code when a filename begins with "."
+ */
+define('PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME', 52);
+/**
+ * package.xml encapsulator
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
+ */
+class PEAR_PackageFile_v1
+{
+    /**
+     * @access private
+     * @var PEAR_ErrorStack
+     * @access private
+     */
+    var $_stack;
+
+    /**
+     * A registry object, used to access the package name validation regex for non-standard channels
+     * @var PEAR_Registry
+     * @access private
+     */
+    var $_registry;
+
+    /**
+     * An object that contains a log method that matches PEAR_Common::log's signature
+     * @var object
+     * @access private
+     */
+    var $_logger;
+
+    /**
+     * Parsed package information
+     * @var array
+     * @access private
+     */
+    var $_packageInfo;
+
+    /**
+     * path to package.xml
+     * @var string
+     * @access private
+     */
+    var $_packageFile;
+
+    /**
+     * path to package .tgz or false if this is a local/extracted package.xml
+     * @var string
+     * @access private
+     */
+    var $_archiveFile;
+
+    /**
+     * @var int
+     * @access private
+     */
+    var $_isValid = 0;
+
+    /**
+     * Determines whether this packagefile was initialized only with partial package info
+     *
+     * If this package file was constructed via parsing REST, it will only contain
+     *
+     * - package name
+     * - channel name
+     * - dependencies 
+     * @var boolean
+     * @access private
+     */
+    var $_incomplete = true;
+
+    /**
+     * @param bool determines whether to return a PEAR_Error object, or use the PEAR_ErrorStack
+     * @param string Name of Error Stack class to use.
+     */
+    function PEAR_PackageFile_v1()
+    {
+        $this->_stack = &new PEAR_ErrorStack('PEAR_PackageFile_v1');
+        $this->_stack->setErrorMessageTemplate($this->_getErrorMessage());
+        $this->_isValid = 0;
+    }
+
+    function installBinary($installer)
+    {
+        return false;
+    }
+
+    function isExtension($name)
+    {
+        return false;
+    }
+
+    function setConfig(&$config)
+    {
+        $this->_config = &$config;
+        $this->_registry = &$config->getRegistry();
+    }
+
+    function setRequestedGroup()
+    {
+        // placeholder
+    }
+
+    /**
+     * For saving in the registry.
+     *
+     * Set the last version that was installed
+     * @param string
+     */
+    function setLastInstalledVersion($version)
+    {
+        $this->_packageInfo['_lastversion'] = $version;
+    }
+
+    /**
+     * @return string|false
+     */
+    function getLastInstalledVersion()
+    {
+        if (isset($this->_packageInfo['_lastversion'])) {
+            return $this->_packageInfo['_lastversion'];
+        }
+        return false;
+    }
+
+    function getInstalledBinary()
+    {
+        return false;
+    }
+
+    function listPostinstallScripts()
+    {
+        return false;
+    }
+
+    function initPostinstallScripts()
+    {
+        return false;
+    }
+
+    function setLogger(&$logger)
+    {
+        if ($logger && (!is_object($logger) || !method_exists($logger, 'log'))) {
+            return PEAR::raiseError('Logger must be compatible with PEAR_Common::log');
+        }
+        $this->_logger = &$logger;
+    }
+
+    function setPackagefile($file, $archive = false)
+    {
+        $this->_packageFile = $file;
+        $this->_archiveFile = $archive ? $archive : $file;
+    }
+
+    function getPackageFile()
+    {
+        return isset($this->_packageFile) ? $this->_packageFile : false;
+    }
+
+    function getPackageType()
+    {
+        return 'php';
+    }
+
+    function getArchiveFile()
+    {
+        return $this->_archiveFile;
+    }
+
+    function packageInfo($field)
+    {
+        if (!is_string($field) || empty($field) ||
+            !isset($this->_packageInfo[$field])) {
+            return false;
+        }
+        return $this->_packageInfo[$field];
+    }
+
+    function setDirtree($path)
+    {
+        $this->_packageInfo['dirtree'][$path] = true;
+    }
+
+    function getDirtree()
+    {
+        if (isset($this->_packageInfo['dirtree']) && count($this->_packageInfo['dirtree'])) {
+            return $this->_packageInfo['dirtree'];
+        }
+        return false;
+    }
+
+    function resetDirtree()
+    {
+        unset($this->_packageInfo['dirtree']);
+    }
+
+    function fromArray($pinfo)
+    {
+        $this->_incomplete = false;
+        $this->_packageInfo = $pinfo;
+    }
+
+    function isIncomplete()
+    {
+        return $this->_incomplete;
+    }
+
+    function getChannel()
+    {
+        return 'pear.php.net';
+    }
+
+    function getUri()
+    {
+        return false;
+    }
+
+    function getTime()
+    {
+        return false;
+    }
+
+    function getExtends()
+    {
+        if (isset($this->_packageInfo['extends'])) {
+            return $this->_packageInfo['extends'];
+        }
+        return false;
+    }
+
+    /**
+     * @return array
+     */
+    function toArray()
+    {
+        if (!$this->validate(PEAR_VALIDATE_NORMAL)) {
+            return false;
+        }
+        return $this->getArray();
+    }
+
+    function getArray()
+    {
+        return $this->_packageInfo;
+    }
+
+    function getName()
+    {
+        return $this->getPackage();
+    }
+
+    function getPackage()
+    {
+        if (isset($this->_packageInfo['package'])) {
+            return $this->_packageInfo['package'];
+        }
+        return false;
+    }
+
+    /**
+     * WARNING - don't use this unless you know what you are doing
+     */
+    function setRawPackage($package)
+    {
+        $this->_packageInfo['package'] = $package;
+    }
+
+    function setPackage($package)
+    {
+        $this->_packageInfo['package'] = $package;
+        $this->_isValid = false;
+    }
+
+    function getVersion()
+    {
+        if (isset($this->_packageInfo['version'])) {
+            return $this->_packageInfo['version'];
+        }
+        return false;
+    }
+
+    function setVersion($version)
+    {
+        $this->_packageInfo['version'] = $version;
+        $this->_isValid = false;
+    }
+
+    function clearMaintainers()
+    {
+        unset($this->_packageInfo['maintainers']);
+    }
+
+    function getMaintainers()
+    {
+        if (isset($this->_packageInfo['maintainers'])) {
+            return $this->_packageInfo['maintainers'];
+        }
+        return false;
+    }
+
+    /**
+     * Adds a new maintainer - no checking of duplicates is performed, use
+     * updatemaintainer for that purpose.
+     */
+    function addMaintainer($role, $handle, $name, $email)
+    {
+        $this->_packageInfo['maintainers'][] =
+            array('handle' => $handle, 'role' => $role, 'email' => $email, 'name' => $name);
+        $this->_isValid = false;
+    }
+
+    function updateMaintainer($role, $handle, $name, $email)
+    {
+        $found = false;
+        if (!isset($this->_packageInfo['maintainers']) ||
+              !is_array($this->_packageInfo['maintainers'])) {
+            return $this->addMaintainer($role, $handle, $name, $email);
+        }
+        foreach ($this->_packageInfo['maintainers'] as $i => $maintainer) {
+            if ($maintainer['handle'] == $handle) {
+                $found = $i;
+                break;
+            }
+        }
+        if ($found !== false) {
+            unset($this->_packageInfo['maintainers'][$found]);
+            $this->_packageInfo['maintainers'] =
+                array_values($this->_packageInfo['maintainers']);
+        }
+        $this->addMaintainer($role, $handle, $name, $email);
+    }
+
+    function deleteMaintainer($handle)
+    {
+        $found = false;
+        foreach ($this->_packageInfo['maintainers'] as $i => $maintainer) {
+            if ($maintainer['handle'] == $handle) {
+                $found = $i;
+                break;
+            }
+        }
+        if ($found !== false) {
+            unset($this->_packageInfo['maintainers'][$found]);
+            $this->_packageInfo['maintainers'] =
+                array_values($this->_packageInfo['maintainers']);
+            return true;
+        }
+        return false;
+    }
+
+    function getState()
+    {
+        if (isset($this->_packageInfo['release_state'])) {
+            return $this->_packageInfo['release_state'];
+        }
+        return false;
+    }
+
+    function setRawState($state)
+    {
+        $this->_packageInfo['release_state'] = $state;
+    }
+
+    function setState($state)
+    {
+        $this->_packageInfo['release_state'] = $state;
+        $this->_isValid = false;
+    }
+
+    function getDate()
+    {
+        if (isset($this->_packageInfo['release_date'])) {
+            return $this->_packageInfo['release_date'];
+        }
+        return false;
+    }
+
+    function setDate($date)
+    {
+        $this->_packageInfo['release_date'] = $date;
+        $this->_isValid = false;
+    }
+
+    function getLicense()
+    {
+        if (isset($this->_packageInfo['release_license'])) {
+            return $this->_packageInfo['release_license'];
+        }
+        return false;
+    }
+
+    function setLicense($date)
+    {
+        $this->_packageInfo['release_license'] = $date;
+        $this->_isValid = false;
+    }
+
+    function getSummary()
+    {
+        if (isset($this->_packageInfo['summary'])) {
+            return $this->_packageInfo['summary'];
+        }
+        return false;
+    }
+
+    function setSummary($summary)
+    {
+        $this->_packageInfo['summary'] = $summary;
+        $this->_isValid = false;
+    }
+
+    function getDescription()
+    {
+        if (isset($this->_packageInfo['description'])) {
+            return $this->_packageInfo['description'];
+        }
+        return false;
+    }
+
+    function setDescription($desc)
+    {
+        $this->_packageInfo['description'] = $desc;
+        $this->_isValid = false;
+    }
+
+    function getNotes()
+    {
+        if (isset($this->_packageInfo['release_notes'])) {
+            return $this->_packageInfo['release_notes'];
+        }
+        return false;
+    }
+
+    function setNotes($notes)
+    {
+        $this->_packageInfo['release_notes'] = $notes;
+        $this->_isValid = false;
+    }
+
+    function getDeps()
+    {
+        if (isset($this->_packageInfo['release_deps'])) {
+            return $this->_packageInfo['release_deps'];
+        }
+        return false;
+    }
+
+    /**
+     * Reset dependencies prior to adding new ones
+     */
+    function clearDeps()
+    {
+        unset($this->_packageInfo['release_deps']);
+    }
+
+    function addPhpDep($version, $rel)
+    {
+        $this->_isValid = false;
+        $this->_packageInfo['release_deps'][] =
+            array('type' => 'php',
+                  'rel' => $rel,
+                  'version' => $version);
+    }
+
+    function addPackageDep($name, $version, $rel, $optional = 'no')
+    {
+        $this->_isValid = false;
+        $dep =
+            array('type' => 'pkg',
+                  'name' => $name,
+                  'rel' => $rel,
+                  'optional' => $optional);
+        if ($rel != 'has' && $rel != 'not') {
+            $dep['version'] = $version;
+        }
+        $this->_packageInfo['release_deps'][] = $dep;
+    }
+
+    function addExtensionDep($name, $version, $rel, $optional = 'no')
+    {
+        $this->_isValid = false;
+        $this->_packageInfo['release_deps'][] =
+            array('type' => 'ext',
+                  'name' => $name,
+                  'rel' => $rel,
+                  'version' => $version,
+                  'optional' => $optional);
+    }
+
+    /**
+     * WARNING - do not use this function directly unless you know what you're doing
+     */
+    function setDeps($deps)
+    {
+        $this->_packageInfo['release_deps'] = $deps;
+    }
+
+    function hasDeps()
+    {
+        return isset($this->_packageInfo['release_deps']) &&
+            count($this->_packageInfo['release_deps']);
+    }
+
+    function getDependencyGroup($group)
+    {
+        return false;
+    }
+
+    function isCompatible($pf)
+    {
+        return false;
+    }
+
+    function isSubpackageOf($p)
+    {
+        return $p->isSubpackage($this);
+    }
+
+    function isSubpackage($p)
+    {
+        return false;
+    }
+
+    function dependsOn($package, $channel)
+    {
+        if (strtolower($channel) != 'pear.php.net') {
+            return false;
+        }
+        if (!($deps = $this->getDeps())) {
+            return false;
+        }
+        foreach ($deps as $dep) {
+            if ($dep['type'] != 'pkg') {
+                continue;
+            }
+            if (strtolower($dep['name']) == strtolower($package)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    function getConfigureOptions()
+    {
+        if (isset($this->_packageInfo['configure_options'])) {
+            return $this->_packageInfo['configure_options'];
+        }
+        return false;
+    }
+
+    function hasConfigureOptions()
+    {
+        return isset($this->_packageInfo['configure_options']) &&
+            count($this->_packageInfo['configure_options']);
+    }
+
+    function addConfigureOption($name, $prompt, $default = false)
+    {
+        $o = array('name' => $name, 'prompt' => $prompt);
+        if ($default !== false) {
+            $o['default'] = $default;
+        }
+        if (!isset($this->_packageInfo['configure_options'])) {
+            $this->_packageInfo['configure_options'] = array();
+        }
+        $this->_packageInfo['configure_options'][] = $o;
+    }
+
+    function clearConfigureOptions()
+    {
+        unset($this->_packageInfo['configure_options']);
+    }
+
+    function getProvides()
+    {
+        if (isset($this->_packageInfo['provides'])) {
+            return $this->_packageInfo['provides'];
+        }
+        return false;
+    }
+
+    function addFile($dir, $file, $attrs)
+    {
+        $dir = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), $dir);
+        if ($dir == '/' || $dir == '') {
+            $dir = '';
+        } else {
+            $dir .= '/';
+        }
+        $file = $dir . $file;
+        $file = preg_replace('![\\/]+!', '/', $file);
+        $this->_packageInfo['filelist'][$file] = $attrs;
+    }
+
+    function getInstallationFilelist()
+    {
+        return $this->getFilelist();
+    }
+
+    function getFilelist()
+    {
+        if (isset($this->_packageInfo['filelist'])) {
+            return $this->_packageInfo['filelist'];
+        }
+        return false;
+    }
+
+    function setFileAttribute($file, $attr, $value)
+    {
+        $this->_packageInfo['filelist'][$file][$attr] = $value;
+    }
+
+    function resetFilelist()
+    {
+        $this->_packageInfo['filelist'] = array();
+    }
+
+    function setInstalledAs($file, $path)
+    {
+        if ($path) {
+            return $this->_packageInfo['filelist'][$file]['installed_as'] = $path;
+        }
+        unset($this->_packageInfo['filelist'][$file]['installed_as']);
+    }
+
+    function installedFile($file, $atts)
+    {
+        if (isset($this->_packageInfo['filelist'][$file])) {
+            $this->_packageInfo['filelist'][$file] =
+                array_merge($this->_packageInfo['filelist'][$file], $atts);
+        } else {
+            $this->_packageInfo['filelist'][$file] = $atts;
+        }
+    }
+
+    function getChangelog()
+    {
+        if (isset($this->_packageInfo['changelog'])) {
+            return $this->_packageInfo['changelog'];
+        }
+        return false;
+    }
+
+    function getPackagexmlVersion()
+    {
+        return '1.0';
+    }
+
+    /**
+     * Wrapper to {@link PEAR_ErrorStack::getErrors()}
+     * @param boolean determines whether to purge the error stack after retrieving
+     * @return array
+     */
+    function getValidationWarnings($purge = true)
+    {
+        return $this->_stack->getErrors($purge);
+    }
+
+    // }}}
+    /**
+     * Validation error.  Also marks the object contents as invalid
+     * @param error code
+     * @param array error information
+     * @access private
+     */
+    function _validateError($code, $params = array())
+    {
+        $this->_stack->push($code, 'error', $params, false, false, debug_backtrace());
+        $this->_isValid = false;
+    }
+
+    /**
+     * Validation warning.  Does not mark the object contents invalid.
+     * @param error code
+     * @param array error information
+     * @access private
+     */
+    function _validateWarning($code, $params = array())
+    {
+        $this->_stack->push($code, 'warning', $params, false, false, debug_backtrace());
+    }
+
+    /**
+     * @param integer error code
+     * @access protected
+     */
+    function _getErrorMessage()
+    {
+        return array(
+                PEAR_PACKAGEFILE_ERROR_NO_NAME =>
+                    'Missing Package Name',
+                PEAR_PACKAGEFILE_ERROR_NO_SUMMARY =>
+                    'No summary found',
+                PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY =>
+                    'Summary should be on one line',
+                PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION =>
+                    'Missing description',
+                PEAR_PACKAGEFILE_ERROR_NO_LICENSE =>
+                    'Missing license',
+                PEAR_PACKAGEFILE_ERROR_NO_VERSION =>
+                    'No release version found',
+                PEAR_PACKAGEFILE_ERROR_NO_STATE =>
+                    'No release state found',
+                PEAR_PACKAGEFILE_ERROR_NO_DATE =>
+                    'No release date found',
+                PEAR_PACKAGEFILE_ERROR_NO_NOTES =>
+                    'No release notes found',
+                PEAR_PACKAGEFILE_ERROR_NO_LEAD =>
+                    'Package must have at least one lead maintainer',
+                PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS =>
+                    'No maintainers found, at least one must be defined',
+                PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE =>
+                    'Maintainer %index% has no handle (user ID at channel server)',
+                PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE =>
+                    'Maintainer %index% has no role',
+                PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME =>
+                    'Maintainer %index% has no name',
+                PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL =>
+                    'Maintainer %index% has no email',
+                PEAR_PACKAGEFILE_ERROR_NO_DEPNAME =>
+                    'Dependency %index% is not a php dependency, and has no name',
+                PEAR_PACKAGEFILE_ERROR_NO_DEPREL =>
+                    'Dependency %index% has no relation (rel)',
+                PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE =>
+                    'Dependency %index% has no type',
+                PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED =>
+                    'PHP Dependency %index% has a name attribute of "%name%" which will be' .
+                        ' ignored!',
+                PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION =>
+                    'Dependency %index% is not a rel="has" or rel="not" dependency, ' .
+                        'and has no version',
+                PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION =>
+                    'Dependency %index% is a type="php" dependency, ' .
+                        'and has no version',
+                PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED =>
+                    'Dependency %index% is a rel="%rel%" dependency, versioning is ignored',
+                PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL =>
+                    'Dependency %index% has invalid optional value "%opt%", should be yes or no',
+                PEAR_PACKAGEFILE_PHP_NO_NOT =>
+                    'Dependency %index%: php dependencies cannot use "not" rel, use "ne"' .
+                        ' to exclude specific versions',
+                PEAR_PACKAGEFILE_ERROR_NO_CONFNAME =>
+                    'Configure Option %index% has no name',
+                PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT =>
+                    'Configure Option %index% has no prompt',
+                PEAR_PACKAGEFILE_ERROR_NO_FILES =>
+                    'No files in <filelist> section of package.xml',
+                PEAR_PACKAGEFILE_ERROR_NO_FILEROLE =>
+                    'File "%file%" has no role, expecting one of "%roles%"',
+                PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE =>
+                    'File "%file%" has invalid role "%role%", expecting one of "%roles%"',
+                PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME =>
+                    'File "%file%" cannot start with ".", cannot package or install',
+                PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE =>
+                    'Parser error: invalid PHP found in file "%file%"',
+                PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX =>
+                    'in %file%: %type% "%name%" not prefixed with package name "%package%"',
+                PEAR_PACKAGEFILE_ERROR_INVALID_FILE =>
+                    'Parser error: invalid PHP file "%file%"',
+                PEAR_PACKAGEFILE_ERROR_CHANNELVAL =>
+                    'Channel validator error: field "%field%" - %reason%',
+                PEAR_PACKAGEFILE_ERROR_PHP5 =>
+                    'Error, PHP5 token encountered in %file%, analysis should be in PHP5',
+                PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND =>
+                    'File "%file%" in package.xml does not exist',
+                PEAR_PACKAGEFILE_ERROR_NON_ISO_CHARS =>
+                    'Package.xml contains non-ISO-8859-1 characters, and may not validate',
+            );
+    }
+
+    /**
+     * Validate XML package definition file.
+     *
+     * @access public
+     * @return boolean
+     */
+    function validate($state = PEAR_VALIDATE_NORMAL, $nofilechecking = false)
+    {
+        if (($this->_isValid & $state) == $state) {
+            return true;
+        }
+        $this->_isValid = true;
+        $info = $this->_packageInfo;
+        if (empty($info['package'])) {
+            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NAME);
+            $this->_packageName = $pn = 'unknown';
+        } else {
+            $this->_packageName = $pn = $info['package'];
+        }
+
+        if (empty($info['summary'])) {
+            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_SUMMARY);
+        } elseif (strpos(trim($info['summary']), "\n") !== false) {
+            $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY,
+                array('summary' => $info['summary']));
+        }
+        if (empty($info['description'])) {
+            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION);
+        }
+        if (empty($info['release_license'])) {
+            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LICENSE);
+        }
+        if (empty($info['version'])) {
+            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_VERSION);
+        }
+        if (empty($info['release_state'])) {
+            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_STATE);
+        }
+        if (empty($info['release_date'])) {
+            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DATE);
+        }
+        if (empty($info['release_notes'])) {
+            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NOTES);
+        }
+        if (empty($info['maintainers'])) {
+            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS);
+        } else {
+            $haslead = false;
+            $i = 1;
+            foreach ($info['maintainers'] as $m) {
+                if (empty($m['handle'])) {
+                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE,
+                        array('index' => $i));
+                }
+                if (empty($m['role'])) {
+                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE,
+                        array('index' => $i, 'roles' => PEAR_Common::getUserRoles()));
+                } elseif ($m['role'] == 'lead') {
+                    $haslead = true;
+                }
+                if (empty($m['name'])) {
+                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME,
+                        array('index' => $i));
+                }
+                if (empty($m['email'])) {
+                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL,
+                        array('index' => $i));
+                }
+                $i++;
+            }
+            if (!$haslead) {
+                $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LEAD);
+            }
+        }
+        if (!empty($info['release_deps'])) {
+            $i = 1;
+            foreach ($info['release_deps'] as $d) {
+                if (!isset($d['type']) || empty($d['type'])) {
+                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE,
+                        array('index' => $i, 'types' => PEAR_Common::getDependencyTypes()));
+                    continue;
+                }
+                if (!isset($d['rel']) || empty($d['rel'])) {
+                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPREL,
+                        array('index' => $i, 'rels' => PEAR_Common::getDependencyRelations()));
+                    continue;
+                }
+                if (!empty($d['optional'])) {
+                    if (!in_array($d['optional'], array('yes', 'no'))) {
+                        $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL,
+                            array('index' => $i, 'opt' => $d['optional']));
+                    }
+                }
+                if ($d['rel'] != 'has' && $d['rel'] != 'not' && empty($d['version'])) {
+                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION,
+                        array('index' => $i));
+                } elseif (($d['rel'] == 'has' || $d['rel'] == 'not') && !empty($d['version'])) {
+                    $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED,
+                        array('index' => $i, 'rel' => $d['rel']));
+                }
+                if ($d['type'] == 'php' && !empty($d['name'])) {
+                    $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED,
+                        array('index' => $i, 'name' => $d['name']));
+                } elseif ($d['type'] != 'php' && empty($d['name'])) {
+                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPNAME,
+                        array('index' => $i));
+                }
+                if ($d['type'] == 'php' && empty($d['version'])) {
+                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION,
+                        array('index' => $i));
+                }
+                if (($d['rel'] == 'not') && ($d['type'] == 'php')) {
+                    $this->_validateError(PEAR_PACKAGEFILE_PHP_NO_NOT,
+                        array('index' => $i));
+                }
+                $i++;
+            }
+        }
+        if (!empty($info['configure_options'])) {
+            $i = 1;
+            foreach ($info['configure_options'] as $c) {
+                if (empty($c['name'])) {
+                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFNAME,
+                        array('index' => $i));
+                }
+                if (empty($c['prompt'])) {
+                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT,
+                        array('index' => $i));
+                }
+                $i++;
+            }
+        }
+        if (empty($info['filelist'])) {
+            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILES);
+            $errors[] = 'no files';
+        } else {
+            foreach ($info['filelist'] as $file => $fa) {
+                if (empty($fa['role'])) {
+                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILEROLE,
+                        array('file' => $file, 'roles' => PEAR_Common::getFileRoles()));
+                    continue;
+                } elseif (!in_array($fa['role'], PEAR_Common::getFileRoles())) {
+                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE,
+                        array('file' => $file, 'role' => $fa['role'], 'roles' => PEAR_Common::getFileRoles()));
+                }
+                if ($file{0} == '.' && $file{1} == '/') {
+                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME,
+                        array('file' => $file));
+                }
+            }
+        }
+        if (isset($this->_registry) && $this->_isValid) {
+            $chan = $this->_registry->getChannel('pear.php.net');
+            $validator = $chan->getValidationObject();
+            $validator->setPackageFile($this);
+            $validator->validate($state);
+            $failures = $validator->getFailures();
+            foreach ($failures['errors'] as $error) {
+                $this->_validateError(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $error);
+            }
+            foreach ($failures['warnings'] as $warning) {
+                $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $warning);
+            }
+        }
+        if ($this->_isValid && $state == PEAR_VALIDATE_PACKAGING && !$nofilechecking) {
+            if ($this->_analyzePhpFiles()) {
+                $this->_isValid = true;
+            }
+        }
+        if ($this->_isValid) {
+            return $this->_isValid = $state;
+        }
+        return $this->_isValid = 0;
+    }
+
+    function _analyzePhpFiles()
+    {
+        if (!$this->_isValid) {
+            return false;
+        }
+        if (!isset($this->_packageFile)) {
+            return false;
+        }
+        $dir_prefix = dirname($this->_packageFile);
+        $common = new PEAR_Common;
+        $log = isset($this->_logger) ? array(&$this->_logger, 'log') :
+            array($common, 'log');
+        $info = $this->getFilelist();
+        foreach ($info as $file => $fa) {
+            if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $file)) {
+                $this->_validateError(PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND,
+                    array('file' => realpath($dir_prefix) . DIRECTORY_SEPARATOR . $file));
+                continue;
+            }
+            if ($fa['role'] == 'php' && $dir_prefix) {
+                call_user_func_array($log, array(1, "Analyzing $file"));
+                $srcinfo = $this->_analyzeSourceCode($dir_prefix . DIRECTORY_SEPARATOR . $file);
+                if ($srcinfo) {
+                    $this->_buildProvidesArray($srcinfo);
+                }
+            }
+        }
+        $this->_packageName = $pn = $this->getPackage();
+        $pnl = strlen($pn);
+        if (isset($this->_packageInfo['provides'])) {
+            foreach ((array) $this->_packageInfo['provides'] as $key => $what) {
+                if (isset($what['explicit'])) {
+                    // skip conformance checks if the provides entry is
+                    // specified in the package.xml file
+                    continue;
+                }
+                extract($what);
+                if ($type == 'class') {
+                    if (!strncasecmp($name, $pn, $pnl)) {
+                        continue;
+                    }
+                    $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX,
+                        array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn));
+                } elseif ($type == 'function') {
+                    if (strstr($name, '::') || !strncasecmp($name, $pn, $pnl)) {
+                        continue;
+                    }
+                    $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX,
+                        array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn));
+                }
+            }
+        }
+        return $this->_isValid;
+    }
+
+    /**
+     * Get the default xml generator object
+     *
+     * @return PEAR_PackageFile_Generator_v1
+     */
+    function &getDefaultGenerator()
+    {
+        if (!class_exists('PEAR_PackageFile_Generator_v1')) {
+            require_once 'PEAR/PackageFile/Generator/v1.php';
+        }
+        $a = &new PEAR_PackageFile_Generator_v1($this);
+        return $a;
+    }
+
+    /**
+     * Get the contents of a file listed within the package.xml
+     * @param string
+     * @return string
+     */
+    function getFileContents($file)
+    {
+        if ($this->_archiveFile == $this->_packageFile) { // unpacked
+            $dir = dirname($this->_packageFile);
+            $file = $dir . DIRECTORY_SEPARATOR . $file;
+            $file = str_replace(array('/', '\\'),
+                array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), $file);
+            if (file_exists($file) && is_readable($file)) {
+                return implode('', file($file));
+            }
+        } else { // tgz
+            if (!class_exists('Archive_Tar')) {
+                require_once 'Archive/Tar.php';
+            }
+            $tar = &new Archive_Tar($this->_archiveFile);
+            $tar->pushErrorHandling(PEAR_ERROR_RETURN);
+            if ($file != 'package.xml' && $file != 'package2.xml') {
+                $file = $this->getPackage() . '-' . $this->getVersion() . '/' . $file;
+            }
+            $file = $tar->extractInString($file);
+            $tar->popErrorHandling();
+            if (PEAR::isError($file)) {
+                return PEAR::raiseError("Cannot locate file '$file' in archive");
+            }
+            return $file;
+        }
+    }
+
+    // {{{ analyzeSourceCode()
+    /**
+     * Analyze the source code of the given PHP file
+     *
+     * @param  string Filename of the PHP file
+     * @return mixed
+     * @access private
+     */
+    function _analyzeSourceCode($file)
+    {
+        if (!function_exists("token_get_all")) {
+            return false;
+        }
+        if (!defined('T_DOC_COMMENT')) {
+            define('T_DOC_COMMENT', T_COMMENT);
+        }
+        if (!defined('T_INTERFACE')) {
+            define('T_INTERFACE', -1);
+        }
+        if (!defined('T_IMPLEMENTS')) {
+            define('T_IMPLEMENTS', -1);
+        }
+        if (!$fp = @fopen($file, "r")) {
+            return false;
+        }
+        if (function_exists('file_get_contents')) {
+            fclose($fp);
+            $contents = file_get_contents($file);
+        } else {
+            $contents = @fread($fp, filesize($file));
+            fclose($fp);
+        }
+        $tokens = token_get_all($contents);
+/*
+        for ($i = 0; $i < sizeof($tokens); $i++) {
+            @list($token, $data) = $tokens[$i];
+            if (is_string($token)) {
+                var_dump($token);
+            } else {
+                print token_name($token) . ' ';
+                var_dump(rtrim($data));
+            }
+        }
+*/
+        $look_for = 0;
+        $paren_level = 0;
+        $bracket_level = 0;
+        $brace_level = 0;
+        $lastphpdoc = '';
+        $current_class = '';
+        $current_interface = '';
+        $current_class_level = -1;
+        $current_function = '';
+        $current_function_level = -1;
+        $declared_classes = array();
+        $declared_interfaces = array();
+        $declared_functions = array();
+        $declared_methods = array();
+        $used_classes = array();
+        $used_functions = array();
+        $extends = array();
+        $implements = array();
+        $nodeps = array();
+        $inquote = false;
+        $interface = false;
+        for ($i = 0; $i < sizeof($tokens); $i++) {
+            if (is_array($tokens[$i])) {
+                list($token, $data) = $tokens[$i];
+            } else {
+                $token = $tokens[$i];
+                $data = '';
+            }
+            if ($inquote) {
+                if ($token != '"' && $token != T_END_HEREDOC) {
+                    continue;
+                } else {
+                    $inquote = false;
+                    continue;
+                }
+            }
+            switch ($token) {
+                case T_WHITESPACE :
+                    continue;
+                case ';':
+                    if ($interface) {
+                        $current_function = '';
+                        $current_function_level = -1;
+                    }
+                    break;
+                case '"':
+                case T_START_HEREDOC:
+                    $inquote = true;
+                    break;
+                case T_CURLY_OPEN:
+                case T_DOLLAR_OPEN_CURLY_BRACES:
+                case '{': $brace_level++; continue 2;
+                case '}':
+                    $brace_level--;
+                    if ($current_class_level == $brace_level) {
+                        $current_class = '';
+                        $current_class_level = -1;
+                    }
+                    if ($current_function_level == $brace_level) {
+                        $current_function = '';
+                        $current_function_level = -1;
+                    }
+                    continue 2;
+                case '[': $bracket_level++; continue 2;
+                case ']': $bracket_level--; continue 2;
+                case '(': $paren_level++;   continue 2;
+                case ')': $paren_level--;   continue 2;
+                case T_INTERFACE:
+                    $interface = true;
+                case T_CLASS:
+                    if (($current_class_level != -1) || ($current_function_level != -1)) {
+                        $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE,
+                            array('file' => $file));
+                        return false;
+                    }
+                case T_FUNCTION:
+                case T_NEW:
+                case T_EXTENDS:
+                case T_IMPLEMENTS:
+                    $look_for = $token;
+                    continue 2;
+                case T_STRING:
+                    if (version_compare(zend_version(), '2.0', '<')) {
+                        if (in_array(strtolower($data),
+                            array('public', 'private', 'protected', 'abstract',
+                                  'interface', 'implements', 'throw') 
+                                 )) {
+                            $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_PHP5,
+                                array($file));
+                        }
+                    }
+                    if ($look_for == T_CLASS) {
+                        $current_class = $data;
+                        $current_class_level = $brace_level;
+                        $declared_classes[] = $current_class;
+                    } elseif ($look_for == T_INTERFACE) {
+                        $current_interface = $data;
+                        $current_class_level = $brace_level;
+                        $declared_interfaces[] = $current_interface;
+                    } elseif ($look_for == T_IMPLEMENTS) {
+                        $implements[$current_class] = $data;
+                    } elseif ($look_for == T_EXTENDS) {
+                        $extends[$current_class] = $data;
+                    } elseif ($look_for == T_FUNCTION) {
+                        if ($current_class) {
+                            $current_function = "$current_class::$data";
+                            $declared_methods[$current_class][] = $data;
+                        } elseif ($current_interface) {
+                            $current_function = "$current_interface::$data";
+                            $declared_methods[$current_interface][] = $data;
+                        } else {
+                            $current_function = $data;
+                            $declared_functions[] = $current_function;
+                        }
+                        $current_function_level = $brace_level;
+                        $m = array();
+                    } elseif ($look_for == T_NEW) {
+                        $used_classes[$data] = true;
+                    }
+                    $look_for = 0;
+                    continue 2;
+                case T_VARIABLE:
+                    $look_for = 0;
+                    continue 2;
+                case T_DOC_COMMENT:
+                case T_COMMENT:
+                    if (preg_match('!^/\*\*\s!', $data)) {
+                        $lastphpdoc = $data;
+                        if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) {
+                            $nodeps = array_merge($nodeps, $m[1]);
+                        }
+                    }
+                    continue 2;
+                case T_DOUBLE_COLON:
+                    if (!($tokens[$i - 1][0] == T_WHITESPACE || $tokens[$i - 1][0] == T_STRING)) {
+                        $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE,
+                            array('file' => $file));
+                        return false;
+                    }
+                    $class = $tokens[$i - 1][1];
+                    if (strtolower($class) != 'parent') {
+                        $used_classes[$class] = true;
+                    }
+                    continue 2;
+            }
+        }
+        return array(
+            "source_file" => $file,
+            "declared_classes" => $declared_classes,
+            "declared_interfaces" => $declared_interfaces,
+            "declared_methods" => $declared_methods,
+            "declared_functions" => $declared_functions,
+            "used_classes" => array_diff(array_keys($used_classes), $nodeps),
+            "inheritance" => $extends,
+            "implements" => $implements,
+            );
+    }
+
+    /**
+     * Build a "provides" array from data returned by
+     * analyzeSourceCode().  The format of the built array is like
+     * this:
+     *
+     *  array(
+     *    'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'),
+     *    ...
+     *  )
+     *
+     *
+     * @param array $srcinfo array with information about a source file
+     * as returned by the analyzeSourceCode() method.
+     *
+     * @return void
+     *
+     * @access private
+     *
+     */
+    function _buildProvidesArray($srcinfo)
+    {
+        if (!$this->_isValid) {
+            return false;
+        }
+        $file = basename($srcinfo['source_file']);
+        $pn = $this->getPackage();
+        $pnl = strlen($pn);
+        foreach ($srcinfo['declared_classes'] as $class) {
+            $key = "class;$class";
+            if (isset($this->_packageInfo['provides'][$key])) {
+                continue;
+            }
+            $this->_packageInfo['provides'][$key] =
+                array('file'=> $file, 'type' => 'class', 'name' => $class);
+            if (isset($srcinfo['inheritance'][$class])) {
+                $this->_packageInfo['provides'][$key]['extends'] =
+                    $srcinfo['inheritance'][$class];
+            }
+        }
+        foreach ($srcinfo['declared_methods'] as $class => $methods) {
+            foreach ($methods as $method) {
+                $function = "$class::$method";
+                $key = "function;$function";
+                if ($method{0} == '_' || !strcasecmp($method, $class) ||
+                    isset($this->_packageInfo['provides'][$key])) {
+                    continue;
+                }
+                $this->_packageInfo['provides'][$key] =
+                    array('file'=> $file, 'type' => 'function', 'name' => $function);
+            }
+        }
+
+        foreach ($srcinfo['declared_functions'] as $function) {
+            $key = "function;$function";
+            if ($function{0} == '_' || isset($this->_packageInfo['provides'][$key])) {
+                continue;
+            }
+            if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) {
+                $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\"";
+            }
+            $this->_packageInfo['provides'][$key] =
+                array('file'=> $file, 'type' => 'function', 'name' => $function);
+        }
+    }
+
+    // }}}
+}
+?>
diff --git a/pear/PEAR/PackageFile/v2.php b/pear/PEAR/PackageFile/v2.php
new file mode 100644 (file)
index 0000000..458df73
--- /dev/null
@@ -0,0 +1,1979 @@
+<?php
+/**
+ * PEAR_PackageFile_v2, package.xml version 2.0
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a1
+ */
+/**
+ * For error handling
+ */
+require_once 'PEAR/ErrorStack.php';
+/**
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
+ */
+class PEAR_PackageFile_v2
+{
+
+    /**
+     * Parsed package information
+     * @var array
+     * @access private
+     */
+    var $_packageInfo = array();
+
+    /**
+     * path to package .tgz or false if this is a local/extracted package.xml
+     * @var string|false
+     * @access private
+     */
+    var $_archiveFile;
+
+    /**
+     * path to package .xml or false if this is an abstract parsed-from-string xml
+     * @var string|false
+     * @access private
+     */
+    var $_packageFile;
+
+    /**
+     * This is used by file analysis routines to log progress information
+     * @var PEAR_Common
+     * @access protected
+     */
+    var $_logger;
+
+    /**
+     * This is set to the highest validation level that has been validated
+     *
+     * If the package.xml is invalid or unknown, this is set to 0.  If
+     * normal validation has occurred, this is set to PEAR_VALIDATE_NORMAL.  If
+     * downloading/installation validation has occurred it is set to PEAR_VALIDATE_DOWNLOADING
+     * or INSTALLING, and so on up to PEAR_VALIDATE_PACKAGING.  This allows validation
+     * "caching" to occur, which is particularly important for package validation, so
+     * that PHP files are not validated twice
+     * @var int
+     * @access private
+     */
+    var $_isValid = 0;
+
+    /**
+     * True if the filelist has been validated
+     * @param bool
+     */
+    var $_filesValid = false;
+
+    /**
+     * @var PEAR_Registry
+     * @access protected
+     */
+    var $_registry;
+
+    /**
+     * @var PEAR_Config
+     * @access protected
+     */
+    var $_config;
+
+    /**
+     * Optional Dependency group requested for installation
+     * @var string
+     * @access private
+     */
+    var $_requestedGroup = false;
+
+    /**
+     * @var PEAR_ErrorStack
+     * @access protected
+     */
+    var $_stack;
+
+    /**
+     * Namespace prefix used for tasks in this package.xml - use tasks: whenever possible
+     */
+    var $_tasksNs;
+
+    /**
+     * Determines whether this packagefile was initialized only with partial package info
+     *
+     * If this package file was constructed via parsing REST, it will only contain
+     *
+     * - package name
+     * - channel name
+     * - dependencies 
+     * @var boolean
+     * @access private
+     */
+    var $_incomplete = true;
+
+    /**
+     * The constructor merely sets up the private error stack
+     */
+    function PEAR_PackageFile_v2()
+    {
+        $this->_stack = new PEAR_ErrorStack('PEAR_PackageFile_v2', false, null);
+        $this->_isValid = false;
+    }
+
+    /**
+     * To make unit-testing easier
+     * @param PEAR_Frontend_*
+     * @param array options
+     * @param PEAR_Config
+     * @return PEAR_Downloader
+     * @access protected
+     */
+    function &getPEARDownloader(&$i, $o, &$c)
+    {
+        $z = &new PEAR_Downloader($i, $o, $c);
+        return $z;
+    }
+
+    /**
+     * To make unit-testing easier
+     * @param PEAR_Config
+     * @param array options
+     * @param array package name as returned from {@link PEAR_Registry::parsePackageName()}
+     * @param int PEAR_VALIDATE_* constant
+     * @return PEAR_Dependency2
+     * @access protected
+     */
+    function &getPEARDependency2(&$c, $o, $p, $s = PEAR_VALIDATE_INSTALLING)
+    {
+        if (!class_exists('PEAR_Dependency2')) {
+            require_once 'PEAR/Dependency2.php';
+        }
+        $z = &new PEAR_Dependency2($c, $o, $p, $s);
+        return $z;
+    }
+
+    function getInstalledBinary()
+    {
+        return isset($this->_packageInfo['#binarypackage']) ? $this->_packageInfo['#binarypackage'] :
+            false;
+    }
+
+    /**
+     * Installation of source package has failed, attempt to download and install the
+     * binary version of this package.
+     * @param PEAR_Installer
+     * @return array|false
+     */
+    function installBinary(&$installer)
+    {
+        if (!OS_WINDOWS) {
+            $a = false;
+            return $a;
+        }
+        if ($this->getPackageType() == 'extsrc') {
+            if (!is_array($installer->getInstallPackages())) {
+                $a = false;
+                return $a;
+            }
+            foreach ($installer->getInstallPackages() as $p) {
+                if ($p->isExtension($this->_packageInfo['providesextension'])) {
+                    if ($p->getPackageType() != 'extsrc') {
+                        $a = false;
+                        return $a; // the user probably downloaded it separately
+                    }
+                }
+            }
+            if (isset($this->_packageInfo['extsrcrelease']['binarypackage'])) {
+                $installer->log(0, 'Attempting to download binary version of extension "' .
+                    $this->_packageInfo['providesextension'] . '"');
+                $params = $this->_packageInfo['extsrcrelease']['binarypackage'];
+                if (!is_array($params) || !isset($params[0])) {
+                    $params = array($params);
+                }
+                if (isset($this->_packageInfo['channel'])) {
+                    foreach ($params as $i => $param) {
+                        $params[$i] = array('channel' => $this->_packageInfo['channel'],
+                            'package' => $param, 'version' => $this->getVersion());
+                    }
+                }
+                $dl = &$this->getPEARDownloader($installer->ui, $installer->getOptions(),
+                    $installer->config);
+                $verbose = $dl->config->get('verbose');
+                $dl->config->set('verbose', -1);
+                foreach ($params as $param) {
+                    PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+                    $ret = $dl->download(array($param));
+                    PEAR::popErrorHandling();
+                    if (is_array($ret) && count($ret)) {
+                        break;
+                    }
+                }
+                $dl->config->set('verbose', $verbose);
+                if (is_array($ret)) {
+                    if (count($ret) == 1) {
+                        $pf = $ret[0]->getPackageFile();
+                        PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+                        $err = $installer->install($ret[0]);
+                        PEAR::popErrorHandling();
+                        if (is_array($err)) {
+                            $this->_packageInfo['#binarypackage'] = $ret[0]->getPackage();
+                            // "install" self, so all dependencies will work transparently
+                            $this->_registry->addPackage2($this);
+                            $installer->log(0, 'Download and install of binary extension "' .
+                                $this->_registry->parsedPackageNameToString(
+                                    array('channel' => $pf->getChannel(),
+                                          'package' => $pf->getPackage()), true) . '" successful');
+                            $a = array($ret[0], $err);
+                            return $a;
+                        }
+                        $installer->log(0, 'Download and install of binary extension "' .
+                            $this->_registry->parsedPackageNameToString(
+                                    array('channel' => $pf->getChannel(),
+                                          'package' => $pf->getPackage()), true) . '" failed');
+                    }
+                }
+            }
+        }
+        $a = false;
+        return $a;
+    }
+
+    /**
+     * @return string|false Extension name
+     */
+    function getProvidesExtension()
+    {
+        if (in_array($this->getPackageType(), array('extsrc', 'extbin'))) {
+            if (isset($this->_packageInfo['providesextension'])) {
+                return $this->_packageInfo['providesextension'];
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @param string Extension name
+     * @return bool
+     */
+    function isExtension($extension)
+    {
+        if (in_array($this->getPackageType(), array('extsrc', 'extbin'))) {
+            return $this->_packageInfo['providesextension'] == $extension;
+        }
+        return false;
+    }
+
+    /**
+     * Tests whether every part of the package.xml 1.0 is represented in
+     * this package.xml 2.0
+     * @param PEAR_PackageFile_v1
+     * @return bool
+     */
+    function isEquivalent($pf1)
+    {
+        if (!$pf1) {
+            return true;
+        }
+        if ($this->getPackageType() == 'bundle') {
+            return false;
+        }
+        $this->_stack->getErrors(true);
+        if (!$pf1->validate(PEAR_VALIDATE_NORMAL)) {
+            return false;
+        }
+        $pass = true;
+        if ($pf1->getPackage() != $this->getPackage()) {
+            $this->_differentPackage($pf1->getPackage());
+            $pass = false;
+        }
+        if ($pf1->getVersion() != $this->getVersion()) {
+            $this->_differentVersion($pf1->getVersion());
+            $pass = false;
+        }
+        if (trim($pf1->getSummary()) != $this->getSummary()) {
+            $this->_differentSummary($pf1->getSummary());
+            $pass = false;
+        }
+        if (preg_replace('/\s+/', '', $pf1->getDescription()) !=
+              preg_replace('/\s+/', '', $this->getDescription())) {
+            $this->_differentDescription($pf1->getDescription());
+            $pass = false;
+        }
+        if ($pf1->getState() != $this->getState()) {
+            $this->_differentState($pf1->getState());
+            $pass = false;
+        }
+        if (!strstr(preg_replace('/\s+/', '', $this->getNotes()),
+              preg_replace('/\s+/', '', $pf1->getNotes()))) {
+            $this->_differentNotes($pf1->getNotes());
+            $pass = false;
+        }
+        $mymaintainers = $this->getMaintainers();
+        $yourmaintainers = $pf1->getMaintainers();
+        for ($i1 = 0; $i1 < count($yourmaintainers); $i1++) {
+            $reset = false;
+            for ($i2 = 0; $i2 < count($mymaintainers); $i2++) {
+                if ($mymaintainers[$i2]['handle'] == $yourmaintainers[$i1]['handle']) {
+                    if ($mymaintainers[$i2]['role'] != $yourmaintainers[$i1]['role']) {
+                        $this->_differentRole($mymaintainers[$i2]['handle'],
+                            $yourmaintainers[$i1]['role'], $mymaintainers[$i2]['role']);
+                        $pass = false;
+                    }
+                    if ($mymaintainers[$i2]['email'] != $yourmaintainers[$i1]['email']) {
+                        $this->_differentEmail($mymaintainers[$i2]['handle'],
+                            $yourmaintainers[$i1]['email'], $mymaintainers[$i2]['email']);
+                        $pass = false;
+                    }
+                    if ($mymaintainers[$i2]['name'] != $yourmaintainers[$i1]['name']) {
+                        $this->_differentName($mymaintainers[$i2]['handle'],
+                            $yourmaintainers[$i1]['name'], $mymaintainers[$i2]['name']);
+                        $pass = false;
+                    }
+                    unset($mymaintainers[$i2]);
+                    $mymaintainers = array_values($mymaintainers);
+                    unset($yourmaintainers[$i1]);
+                    $yourmaintainers = array_values($yourmaintainers);
+                    $reset = true;
+                    break;
+                }
+            }
+            if ($reset) {
+                $i1 = -1;
+            }
+        }
+        $this->_unmatchedMaintainers($mymaintainers, $yourmaintainers);
+        $filelist = $this->getFilelist();
+        foreach ($pf1->getFilelist() as $file => $atts) {
+            if (!isset($filelist[$file])) {
+                $this->_missingFile($file);
+                $pass = false;
+            }
+        }
+        return $pass;
+    }
+
+    function _differentPackage($package)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('package' => $package,
+            'self' => $this->getPackage()),
+            'package.xml 1.0 package "%package%" does not match "%self%"');
+    }
+
+    function _differentVersion($version)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('version' => $version,
+            'self' => $this->getVersion()),
+            'package.xml 1.0 version "%version%" does not match "%self%"');
+    }
+
+    function _differentState($state)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('state' => $state,
+            'self' => $this->getState()),
+            'package.xml 1.0 state "%state%" does not match "%self%"');
+    }
+
+    function _differentRole($handle, $role, $selfrole)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle,
+            'role' => $role, 'self' => $selfrole),
+            'package.xml 1.0 maintainer "%handle%" role "%role%" does not match "%self%"');
+    }
+
+    function _differentEmail($handle, $email, $selfemail)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle,
+            'email' => $email, 'self' => $selfemail),
+            'package.xml 1.0 maintainer "%handle%" email "%email%" does not match "%self%"');
+    }
+
+    function _differentName($handle, $name, $selfname)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle,
+            'name' => $name, 'self' => $selfname),
+            'package.xml 1.0 maintainer "%handle%" name "%name%" does not match "%self%"');
+    }
+
+    function _unmatchedMaintainers($my, $yours)
+    {
+        if ($my) {
+            array_walk($my, create_function('&$i, $k', '$i = $i["handle"];'));
+            $this->_stack->push(__FUNCTION__, 'error', array('handles' => $my),
+                'package.xml 2.0 has unmatched extra maintainers "%handles%"');
+        }
+        if ($yours) {
+            array_walk($yours, create_function('&$i, $k', '$i = $i["handle"];'));
+            $this->_stack->push(__FUNCTION__, 'error', array('handles' => $yours),
+                'package.xml 1.0 has unmatched extra maintainers "%handles%"');
+        }
+    }
+
+    function _differentNotes($notes)
+    {
+        $truncnotes = strlen($notes) < 25 ? $notes : substr($notes, 0, 24) . '...';
+        $truncmynotes = strlen($this->getNotes()) < 25 ? $this->getNotes() :
+            substr($this->getNotes(), 0, 24) . '...';
+        $this->_stack->push(__FUNCTION__, 'error', array('notes' => $truncnotes,
+            'self' => $truncmynotes),
+            'package.xml 1.0 release notes "%notes%" do not match "%self%"');
+    }
+
+    function _differentSummary($summary)
+    {
+        $truncsummary = strlen($summary) < 25 ? $summary : substr($summary, 0, 24) . '...';
+        $truncmysummary = strlen($this->getsummary()) < 25 ? $this->getSummary() :
+            substr($this->getsummary(), 0, 24) . '...';
+        $this->_stack->push(__FUNCTION__, 'error', array('summary' => $truncsummary,
+            'self' => $truncmysummary),
+            'package.xml 1.0 summary "%summary%" does not match "%self%"');
+    }
+
+    function _differentDescription($description)
+    {
+        $truncdescription = trim(strlen($description) < 25 ? $description : substr($description, 0, 24) . '...');
+        $truncmydescription = trim(strlen($this->getDescription()) < 25 ? $this->getDescription() :
+            substr($this->getdescription(), 0, 24) . '...');
+        $this->_stack->push(__FUNCTION__, 'error', array('description' => $truncdescription,
+            'self' => $truncmydescription),
+            'package.xml 1.0 description "%description%" does not match "%self%"');
+    }
+
+    function _missingFile($file)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('file' => $file),
+            'package.xml 1.0 file "%file%" is not present in <contents>');
+    }
+
+    /**
+     * WARNING - do not use this function unless you know what you're doing
+     */
+    function setRawState($state)
+    {
+        $this->_packageInfo['stability']['release'] = $state;
+    }
+
+    /**
+     * WARNING - do not use this function unless you know what you're doing
+     */
+    function setRawCompatible($compatible)
+    {
+        $this->_packageInfo['compatible'] = $compatible;
+    }
+
+    /**
+     * WARNING - do not use this function unless you know what you're doing
+     */
+    function setRawPackage($package)
+    {
+        $this->_packageInfo['name'] = $package;
+    }
+
+    /**
+     * WARNING - do not use this function unless you know what you're doing
+     */
+    function setRawChannel($channel)
+    {
+        $this->_packageInfo['channel'] = $channel;
+    }
+
+    function setRequestedGroup($group)
+    {
+        $this->_requestedGroup = $group;
+    }
+
+    function getRequestedGroup()
+    {
+        if (isset($this->_requestedGroup)) {
+            return $this->_requestedGroup;
+        }
+        return false;
+    }
+
+    /**
+     * For saving in the registry.
+     *
+     * Set the last version that was installed
+     * @param string
+     */
+    function setLastInstalledVersion($version)
+    {
+        $this->_packageInfo['_lastversion'] = $version;
+    }
+
+    /**
+     * @return string|false
+     */
+    function getLastInstalledVersion()
+    {
+        if (isset($this->_packageInfo['_lastversion'])) {
+            return $this->_packageInfo['_lastversion'];
+        }
+        return false;
+    }
+
+    /**
+     * Determines whether this package.xml has post-install scripts or not
+     * @return array|false
+     */
+    function listPostinstallScripts()
+    {
+        $filelist = $this->getFilelist();
+        $contents = $this->getContents();
+        $contents = $contents['dir']['file'];
+        if (!is_array($contents) || !isset($contents[0])) {
+            $contents = array($contents);
+        }
+        $taskfiles = array();
+        foreach ($contents as $file) {
+            $atts = $file['attribs'];
+            unset($file['attribs']);
+            if (count($file)) {
+                $taskfiles[$atts['name']] = $file;
+            }
+        }
+        $common = new PEAR_Common;
+        $common->debug = $this->_config->get('verbose');
+        $this->_scripts = array();
+        $ret = array();
+        foreach ($taskfiles as $name => $tasks) {
+            if (!isset($filelist[$name])) {
+                // ignored files will not be in the filelist
+                continue;
+            }
+            $atts = $filelist[$name];
+            foreach ($tasks as $tag => $raw) {
+                $task = $this->getTask($tag);
+                $task = &new $task($this->_config, $common, PEAR_TASK_INSTALL);
+                if ($task->isScript()) {
+                    $ret[] = $filelist[$name]['installed_as'];
+                }
+            }
+        }
+        if (count($ret)) {
+            return $ret;
+        }
+        return false;
+    }
+
+    /**
+     * Initialize post-install scripts for running
+     *
+     * This method can be used to detect post-install scripts, as the return value
+     * indicates whether any exist
+     * @return bool
+     */
+    function initPostinstallScripts()
+    {
+        $filelist = $this->getFilelist();
+        $contents = $this->getContents();
+        $contents = $contents['dir']['file'];
+        if (!is_array($contents) || !isset($contents[0])) {
+            $contents = array($contents);
+        }
+        $taskfiles = array();
+        foreach ($contents as $file) {
+            $atts = $file['attribs'];
+            unset($file['attribs']);
+            if (count($file)) {
+                $taskfiles[$atts['name']] = $file;
+            }
+        }
+        $common = new PEAR_Common;
+        $common->debug = $this->_config->get('verbose');
+        $this->_scripts = array();
+        foreach ($taskfiles as $name => $tasks) {
+            $atts = $filelist[$name];
+            foreach ($tasks as $tag => $raw) {
+                $taskname = $this->getTask($tag);
+                $task = &new $taskname($this->_config, $common, PEAR_TASK_INSTALL);
+                if (!$task->isScript()) {
+                    continue; // scripts are only handled after installation
+                }
+                $lastversion = isset($this->_packageInfo['_lastversion']) ?
+                    $this->_packageInfo['_lastversion'] : null;
+                $task->init($raw, $atts, $lastversion);
+                $res = $task->startSession($this, $atts['installed_as']);
+                if (!$res) {
+                    continue; // skip this file
+                }
+                if (PEAR::isError($res)) {
+                    return $res;
+                }
+                $assign = &$task;
+                $this->_scripts[] = &$assign;
+            }
+        }
+        if (count($this->_scripts)) {
+            return true;
+        }
+        return false;
+    }
+
+    function runPostinstallScripts()
+    {
+        if ($this->initPostinstallScripts()) {
+            $ui = &PEAR_Frontend::singleton();
+            if ($ui) {
+                $ui->runPostinstallScripts($this->_scripts, $this);
+            }
+        }
+    }
+
+
+    /**
+     * Convert a recursive set of <dir> and <file> tags into a single <dir> tag with
+     * <file> tags.
+     */
+    function flattenFilelist()
+    {
+        if (isset($this->_packageInfo['bundle'])) {
+            return;
+        }
+        $filelist = array();
+        if (isset($this->_packageInfo['contents']['dir']['dir'])) {
+            $this->_getFlattenedFilelist($filelist, $this->_packageInfo['contents']['dir']);
+            if (!isset($filelist[1])) {
+                $filelist = $filelist[0];
+            }
+            $this->_packageInfo['contents']['dir']['file'] = $filelist;
+            unset($this->_packageInfo['contents']['dir']['dir']);
+        } else {
+            // else already flattened but check for baseinstalldir propagation
+            if (isset($this->_packageInfo['contents']['dir']['attribs']['baseinstalldir'])) {
+                if (isset($this->_packageInfo['contents']['dir']['file'][0])) {
+                    foreach ($this->_packageInfo['contents']['dir']['file'] as $i => $file) {
+                        $this->_packageInfo['contents']['dir']['file'][$i]['attribs']['baseinstalldir']
+                            = $this->_packageInfo['contents']['dir']['attribs']['baseinstalldir'];
+                    }
+                } else {
+                    $this->_packageInfo['contents']['dir']['file']['attribs']['baseinstalldir']
+                        = $this->_packageInfo['contents']['dir']['attribs']['baseinstalldir'];
+                }
+            }
+        }
+    }
+
+    /**
+     * @param array the final flattened file list
+     * @param array the current directory being processed
+     * @param string|false any recursively inherited baeinstalldir attribute
+     * @param string private recursion variable
+     * @return array
+     * @access protected
+     */
+    function _getFlattenedFilelist(&$files, $dir, $baseinstall = false, $path = '')
+    {
+        if (isset($dir['attribs']) && isset($dir['attribs']['baseinstalldir'])) {
+            $baseinstall = $dir['attribs']['baseinstalldir'];
+        }
+        if (isset($dir['dir'])) {
+            if (!isset($dir['dir'][0])) {
+                $dir['dir'] = array($dir['dir']);
+            }
+            foreach ($dir['dir'] as $subdir) {
+                if (!isset($subdir['attribs']) || !isset($subdir['attribs']['name'])) {
+                    $name = '*unknown*';
+                } else {
+                    $name = $subdir['attribs']['name'];
+                }
+                $newpath = empty($path) ? $name :
+                    $path . '/' . $name;
+                $this->_getFlattenedFilelist($files, $subdir,
+                    $baseinstall, $newpath);
+            }
+        }
+        if (isset($dir['file'])) {
+            if (!isset($dir['file'][0])) {
+                $dir['file'] = array($dir['file']);
+            }
+            foreach ($dir['file'] as $file) {
+                $attrs = $file['attribs'];
+                $name = $attrs['name'];
+                if ($baseinstall) {
+                    $attrs['baseinstalldir'] = $baseinstall;
+                }
+                $attrs['name'] = empty($path) ? $name : $path . '/' . $name;
+                $attrs['name'] = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'),
+                    $attrs['name']);
+                $file['attribs'] = $attrs;
+                $files[] = $file;
+            }
+        }
+    }
+
+    function setConfig(&$config)
+    {
+        $this->_config = &$config;
+        $this->_registry = &$config->getRegistry();
+    }
+
+    function setLogger(&$logger)
+    {
+        if ($logger && (!is_object($logger) || !method_exists($logger, 'log'))) {
+            return PEAR::raiseError('Logger must be compatible with PEAR_Common::log');
+        }
+        $this->_logger = &$logger;
+    }
+
+    /**
+     * WARNING - do not use this function directly unless you know what you're doing
+     */
+    function setDeps($deps)
+    {
+        $this->_packageInfo['dependencies'] = $deps;
+    }
+
+    function setPackagefile($file, $archive = false)
+    {
+        $this->_packageFile = $file;
+        $this->_archiveFile = $archive ? $archive : $file;
+    }
+
+    /**
+     * Wrapper to {@link PEAR_ErrorStack::getErrors()}
+     * @param boolean determines whether to purge the error stack after retrieving
+     * @return array
+     */
+    function getValidationWarnings($purge = true)
+    {
+        return $this->_stack->getErrors($purge);
+    }
+
+    function getPackageFile()
+    {
+        return $this->_packageFile;
+    }
+
+    function getArchiveFile()
+    {
+        return $this->_archiveFile;
+    }
+
+
+    /**
+     * Directly set the array that defines this packagefile
+     *
+     * WARNING: no validation.  This should only be performed by internal methods
+     * inside PEAR or by inputting an array saved from an existing PEAR_PackageFile_v2
+     * @param array
+     */
+    function fromArray($pinfo)
+    {
+        unset($pinfo['old']);
+        unset($pinfo['xsdversion']);
+        $this->_incomplete = false;
+        $this->_packageInfo = $pinfo;
+    }
+
+    function isIncomplete()
+    {
+        return $this->_incomplete;
+    }
+
+    /**
+     * @return array
+     */
+    function toArray($forreg = false)
+    {
+        if (!$this->validate(PEAR_VALIDATE_NORMAL)) {
+            return false;
+        }
+        return $this->getArray($forreg);
+    }
+
+    function getArray($forReg = false)
+    {
+        if ($forReg) {
+            $arr = $this->_packageInfo;
+            $arr['old'] = array();
+            $arr['old']['version'] = $this->getVersion();
+            $arr['old']['release_date'] = $this->getDate();
+            $arr['old']['release_state'] = $this->getState();
+            $arr['old']['release_license'] = $this->getLicense();
+            $arr['old']['release_notes'] = $this->getNotes();
+            $arr['old']['release_deps'] = $this->getDeps();
+            $arr['old']['maintainers'] = $this->getMaintainers();
+            $arr['xsdversion'] = '2.0';
+            return $arr;
+        } else {
+            $info = $this->_packageInfo;
+            unset($info['dirtree']);
+            if (isset($info['_lastversion'])) {
+                unset($info['_lastversion']);
+            }
+            if (isset($info['#binarypackage'])) {
+                unset($info['#binarypackage']);
+            }
+            return $info;
+        }
+    }
+
+    function packageInfo($field)
+    {
+        $arr = $this->getArray(true);
+        if ($field == 'apiversion') {
+            return $arr['version']['api'];
+        }
+        if (isset($arr['old'][$field])) {
+            if (!is_string($arr['old'][$field])) {
+                return null;
+            }
+            return $arr['old'][$field];
+        }
+        if (isset($arr[$field])) {
+            if (!is_string($arr[$field])) {
+                return null;
+            }
+            return $arr[$field];
+        }
+        return null;
+    }
+
+    function getName()
+    {
+        return $this->getPackage();
+    }
+
+    function getPackage()
+    {
+        if (isset($this->_packageInfo['name'])) {
+            return $this->_packageInfo['name'];
+        }
+        return false;
+    }
+
+    function getChannel()
+    {
+        if (isset($this->_packageInfo['uri'])) {
+            return '__uri';
+        }
+        if (isset($this->_packageInfo['channel'])) {
+            return strtolower($this->_packageInfo['channel']);
+        }
+        return false;
+    }
+
+    function getUri()
+    {
+        if (isset($this->_packageInfo['uri'])) {
+            return $this->_packageInfo['uri'];
+        }
+        return false;
+    }
+
+    function getExtends()
+    {
+        if (isset($this->_packageInfo['extends'])) {
+            return $this->_packageInfo['extends'];
+        }
+        return false;
+    }
+
+    function getSummary()
+    {
+        if (isset($this->_packageInfo['summary'])) {
+            return $this->_packageInfo['summary'];
+        }
+        return false;
+    }
+
+    function getDescription()
+    {
+        if (isset($this->_packageInfo['description'])) {
+            return $this->_packageInfo['description'];
+        }
+        return false;
+    }
+
+    function getMaintainers($raw = false)
+    {
+        if (!$this->_isValid && !$this->validate()) {
+            return false;
+        }
+        if ($raw) {
+            $ret = array('lead' => $this->_packageInfo['lead']);
+            (isset($this->_packageInfo['developer'])) ?
+                $ret['developer'] = $this->_packageInfo['developer'] :null;
+            (isset($this->_packageInfo['contributor'])) ?
+                $ret['contributor'] = $this->_packageInfo['contributor'] :null;
+            (isset($this->_packageInfo['helper'])) ?
+                $ret['helper'] = $this->_packageInfo['helper'] :null;
+            return $ret;
+        } else {
+            $ret = array();
+            $leads = isset($this->_packageInfo['lead'][0]) ? $this->_packageInfo['lead'] :
+                array($this->_packageInfo['lead']);
+            foreach ($leads as $lead) {
+                $s = $lead;
+                $s['handle'] = $s['user'];
+                unset($s['user']);
+                $s['role'] = 'lead';
+                $ret[] = $s;
+            }
+            if (isset($this->_packageInfo['developer'])) {
+                $leads = isset($this->_packageInfo['developer'][0]) ?
+                    $this->_packageInfo['developer'] :
+                    array($this->_packageInfo['developer']);
+                foreach ($leads as $maintainer) {
+                    $s = $maintainer;
+                    $s['handle'] = $s['user'];
+                    unset($s['user']);
+                    $s['role'] = 'developer';
+                    $ret[] = $s;
+                }
+            }
+            if (isset($this->_packageInfo['contributor'])) {
+                $leads = isset($this->_packageInfo['contributor'][0]) ?
+                    $this->_packageInfo['contributor'] :
+                    array($this->_packageInfo['contributor']);
+                foreach ($leads as $maintainer) {
+                    $s = $maintainer;
+                    $s['handle'] = $s['user'];
+                    unset($s['user']);
+                    $s['role'] = 'contributor';
+                    $ret[] = $s;
+                }
+            }
+            if (isset($this->_packageInfo['helper'])) {
+                $leads = isset($this->_packageInfo['helper'][0]) ?
+                    $this->_packageInfo['helper'] :
+                    array($this->_packageInfo['helper']);
+                foreach ($leads as $maintainer) {
+                    $s = $maintainer;
+                    $s['handle'] = $s['user'];
+                    unset($s['user']);
+                    $s['role'] = 'helper';
+                    $ret[] = $s;
+                }
+            }
+            return $ret;
+        }
+        return false;
+    }
+
+    function getLeads()
+    {
+        if (isset($this->_packageInfo['lead'])) {
+            return $this->_packageInfo['lead'];
+        }
+        return false;
+    }
+
+    function getDevelopers()
+    {
+        if (isset($this->_packageInfo['developer'])) {
+            return $this->_packageInfo['developer'];
+        }
+        return false;
+    }
+
+    function getContributors()
+    {
+        if (isset($this->_packageInfo['contributor'])) {
+            return $this->_packageInfo['contributor'];
+        }
+        return false;
+    }
+
+    function getHelpers()
+    {
+        if (isset($this->_packageInfo['helper'])) {
+            return $this->_packageInfo['helper'];
+        }
+        return false;
+    }
+
+    function setDate($date)
+    {
+        if (!isset($this->_packageInfo['date'])) {
+            // ensure that the extends tag is set up in the right location
+            $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
+                array('time', 'version',
+                    'stability', 'license', 'notes', 'contents', 'compatible',
+                    'dependencies', 'providesextension', 'srcpackage', 'srcuri',
+                    'phprelease', 'extsrcrelease',
+                    'extbinrelease', 'bundle', 'changelog'), array(), 'date');
+        }
+        $this->_packageInfo['date'] = $date;
+        $this->_isValid = 0;
+    }
+
+    function setTime($time)
+    {
+        $this->_isValid = 0;
+        if (!isset($this->_packageInfo['time'])) {
+            // ensure that the time tag is set up in the right location
+            $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
+                    array('version',
+                    'stability', 'license', 'notes', 'contents', 'compatible',
+                    'dependencies', 'providesextension', 'srcpackage', 'srcuri',
+                    'phprelease', 'extsrcrelease',
+                    'extbinrelease', 'bundle', 'changelog'), $time, 'time');
+        }
+        $this->_packageInfo['time'] = $time;
+    }
+
+    function getDate()
+    {
+        if (isset($this->_packageInfo['date'])) {
+            return $this->_packageInfo['date'];
+        }
+        return false;
+    }
+
+    function getTime()
+    {
+        if (isset($this->_packageInfo['time'])) {
+            return $this->_packageInfo['time'];
+        }
+        return false;
+    }
+
+    /**
+     * @param package|api version category to return
+     */
+    function getVersion($key = 'release')
+    {
+        if (isset($this->_packageInfo['version'][$key])) {
+            return $this->_packageInfo['version'][$key];
+        }
+        return false;
+    }
+
+    function getStability()
+    {
+        if (isset($this->_packageInfo['stability'])) {
+            return $this->_packageInfo['stability'];
+        }
+        return false;
+    }
+
+    function getState($key = 'release')
+    {
+        if (isset($this->_packageInfo['stability'][$key])) {
+            return $this->_packageInfo['stability'][$key];
+        }
+        return false;
+    }
+
+    function getLicense($raw = false)
+    {
+        if (isset($this->_packageInfo['license'])) {
+            if ($raw) {
+                return $this->_packageInfo['license'];
+            }
+            if (is_array($this->_packageInfo['license'])) {
+                return $this->_packageInfo['license']['_content'];
+            } else {
+                return $this->_packageInfo['license'];
+            }
+        }
+        return false;
+    }
+
+    function getLicenseLocation()
+    {
+        if (!isset($this->_packageInfo['license']) || !is_array($this->_packageInfo['license'])) {
+            return false;
+        }
+        return $this->_packageInfo['license']['attribs'];
+    }
+
+    function getNotes()
+    {
+        if (isset($this->_packageInfo['notes'])) {
+            return $this->_packageInfo['notes'];
+        }
+        return false;
+    }
+
+    /**
+     * Return the <usesrole> tag contents, if any
+     * @return array|false
+     */
+    function getUsesrole()
+    {
+        if (isset($this->_packageInfo['usesrole'])) {
+            return $this->_packageInfo['usesrole'];
+        }
+        return false;
+    }
+
+    /**
+     * Return the <usestask> tag contents, if any
+     * @return array|false
+     */
+    function getUsestask()
+    {
+        if (isset($this->_packageInfo['usestask'])) {
+            return $this->_packageInfo['usestask'];
+        }
+        return false;
+    }
+
+    /**
+     * This should only be used to retrieve filenames and install attributes
+     */
+    function getFilelist($preserve = false)
+    {
+        if (isset($this->_packageInfo['filelist']) && !$preserve) {
+            return $this->_packageInfo['filelist'];
+        }
+        $this->flattenFilelist();
+        if ($contents = $this->getContents()) {
+            $ret = array();
+            if (!isset($contents['dir']['file'][0])) {
+                $contents['dir']['file'] = array($contents['dir']['file']);
+            }
+            foreach ($contents['dir']['file'] as $file) {
+                $name = $file['attribs']['name'];
+                if (!$preserve) {
+                    $file = $file['attribs'];
+                }
+                $ret[$name] = $file;
+            }
+            if (!$preserve) {
+                $this->_packageInfo['filelist'] = $ret;
+            }
+            return $ret;
+        }
+        return false;
+    }
+
+    /**
+     * Return configure options array, if any
+     *
+     * @return array|false
+     */
+    function getConfigureOptions()
+    {
+        if ($this->getPackageType() != 'extsrc') {
+            return false;
+        }
+        $releases = $this->getReleases();
+        if (isset($releases[0])) {
+            $releases = $release[0];
+        }
+        if (isset($releases['configureoption'])) {
+            if (!isset($releases['configureoption'][0])) {
+                $releases['configureoption'] = array($releases['configureoption']);
+            }
+            for ($i = 0; $i < count($releases['configureoption']); $i++) {
+                $releases['configureoption'][$i] = $releases['configureoption'][$i]['attribs'];
+            }
+            return $releases['configureoption'];
+        }
+        return false;
+    }
+
+    /**
+     * This is only used at install-time, after all serialization
+     * is over.
+     */
+    function resetFilelist()
+    {
+        $this->_packageInfo['filelist'] = array();
+    }
+
+    /**
+     * Retrieve a list of files that should be installed on this computer
+     * @return array
+     */
+    function getInstallationFilelist($forfilecheck = false)
+    {
+        $contents = $this->getFilelist(true);
+        if (isset($contents['dir']['attribs']['baseinstalldir'])) {
+            $base = $contents['dir']['attribs']['baseinstalldir'];
+        }
+        if (isset($this->_packageInfo['bundle'])) {
+            return PEAR::raiseError(
+                'Exception: bundles should be handled in download code only');
+        }
+        $release = $this->getReleases();
+        if ($release) {
+            if (!isset($release[0])) {
+                if (!isset($release['installconditions']) && !isset($release['filelist'])) {
+                    if ($forfilecheck) {
+                        return $this->getFilelist();
+                    }
+                    return $contents;
+                }
+                $release = array($release);
+            }
+            $depchecker = &$this->getPEARDependency2($this->_config, array(),
+                array('channel' => $this->getChannel(), 'package' => $this->getPackage()),
+                PEAR_VALIDATE_INSTALLING);
+            foreach ($release as $instance) {
+                if (isset($instance['installconditions'])) {
+                    $installconditions = $instance['installconditions'];
+                    if (is_array($installconditions)) {
+                        PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+                        foreach ($installconditions as $type => $conditions) {
+                            if (!isset($conditions[0])) {
+                                $conditions = array($conditions);
+                            }
+                            foreach ($conditions as $condition) {
+                                $ret = $depchecker->{"validate{$type}Dependency"}($condition);
+                                if (PEAR::isError($ret)) {
+                                    PEAR::popErrorHandling();
+                                    continue 3; // skip this release
+                                }
+                            }
+                        }
+                        PEAR::popErrorHandling();
+                    }
+                }
+                // this is the release to use
+                if (isset($instance['filelist'])) {
+                    // ignore files
+                    if (isset($instance['filelist']['ignore'])) {
+                        $ignore = isset($instance['filelist']['ignore'][0]) ?
+                            $instance['filelist']['ignore'] :
+                            array($instance['filelist']['ignore']);
+                        foreach ($ignore as $ig) {
+                            unset ($contents[$ig['attribs']['name']]);
+                        }
+                    }
+                    // install files as this name
+                    if (isset($instance['filelist']['install'])) {
+                        $installas = isset($instance['filelist']['install'][0]) ?
+                            $instance['filelist']['install'] :
+                            array($instance['filelist']['install']);
+                        foreach ($installas as $as) {
+                            $contents[$as['attribs']['name']]['attribs']['install-as'] =
+                                $as['attribs']['as'];
+                        }
+                    }
+                }
+                if ($forfilecheck) {
+                    foreach ($contents as $file => $attrs) {
+                        $contents[$file] = $attrs['attribs'];
+                    }
+                }
+                return $contents;
+            }
+        } else { // simple release - no installconditions or install-as
+            if ($forfilecheck) {
+                return $this->getFilelist();
+            }
+            return $contents;
+        }
+        // no releases matched
+        return PEAR::raiseError('No releases in package.xml matched the existing operating ' .
+            'system, extensions installed, or architecture, cannot install');
+    }
+
+    /**
+     * This is only used at install-time, after all serialization
+     * is over.
+     * @param string file name
+     * @param string installed path
+     */
+    function setInstalledAs($file, $path)
+    {
+        if ($path) {
+            return $this->_packageInfo['filelist'][$file]['installed_as'] = $path;
+        }
+        unset($this->_packageInfo['filelist'][$file]['installed_as']);
+    }
+
+    function getInstalledLocation($file)
+    {
+        if (isset($this->_packageInfo['filelist'][$file]['installed_as'])) {
+            return $this->_packageInfo['filelist'][$file]['installed_as'];
+        }
+        return false;
+    }
+
+    /**
+     * This is only used at install-time, after all serialization
+     * is over.
+     */
+    function installedFile($file, $atts)
+    {
+        if (isset($this->_packageInfo['filelist'][$file])) {
+            $this->_packageInfo['filelist'][$file] =
+                array_merge($this->_packageInfo['filelist'][$file], $atts['attribs']);
+        } else {
+            $this->_packageInfo['filelist'][$file] = $atts['attribs'];
+        }
+    }
+
+    /**
+     * Retrieve the contents tag
+     */
+    function getContents()
+    {
+        if (isset($this->_packageInfo['contents'])) {
+            return $this->_packageInfo['contents'];
+        }
+        return false;
+    }
+
+    /**
+     * @param string full path to file
+     * @param string attribute name
+     * @param string attribute value
+     * @param int risky but fast - use this to choose a file based on its position in the list
+     *            of files.  Index is zero-based like PHP arrays.
+     * @return bool success of operation
+     */
+    function setFileAttribute($filename, $attr, $value, $index = false)
+    {
+        $this->_isValid = 0;
+        if (in_array($attr, array('role', 'name', 'baseinstalldir'))) {
+            $this->_filesValid = false;
+        }
+        if ($index !== false &&
+              isset($this->_packageInfo['contents']['dir']['file'][$index]['attribs'])) {
+            $this->_packageInfo['contents']['dir']['file'][$index]['attribs'][$attr] = $value;
+            return true;
+        }
+        if (!isset($this->_packageInfo['contents']['dir']['file'])) {
+            return false;
+        }
+        $files = $this->_packageInfo['contents']['dir']['file'];
+        if (!isset($files[0])) {
+            $files = array($files);
+            $ind = false;
+        } else {
+            $ind = true;
+        }
+        foreach ($files as $i => $file) {
+            if (isset($file['attribs'])) {
+                if ($file['attribs']['name'] == $filename) {
+                    if ($ind) {
+                        $this->_packageInfo['contents']['dir']['file'][$i]['attribs'][$attr] = $value;
+                    } else {
+                        $this->_packageInfo['contents']['dir']['file']['attribs'][$attr] = $value;
+                    }
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    function setDirtree($path)
+    {
+        $this->_packageInfo['dirtree'][$path] = true;
+    }
+
+    function getDirtree()
+    {
+        if (isset($this->_packageInfo['dirtree']) && count($this->_packageInfo['dirtree'])) {
+            return $this->_packageInfo['dirtree'];
+        }
+        return false;
+    }
+
+    function resetDirtree()
+    {
+        unset($this->_packageInfo['dirtree']);
+    }
+
+    /**
+     * Determines whether this package claims it is compatible with the version of
+     * the package that has a recommended version dependency
+     * @param PEAR_PackageFile_v2|PEAR_PackageFile_v1|PEAR_Downloader_Package
+     * @return boolean
+     */
+    function isCompatible($pf)
+    {
+        if (!isset($this->_packageInfo['compatible'])) {
+            return false;
+        }
+        if (!isset($this->_packageInfo['channel'])) {
+            return false;
+        }
+        $me = $pf->getVersion();
+        $compatible = $this->_packageInfo['compatible'];
+        if (!isset($compatible[0])) {
+            $compatible = array($compatible);
+        }
+        $found = false;
+        foreach ($compatible as $info) {
+            if (strtolower($info['name']) == strtolower($pf->getPackage())) {
+                if (strtolower($info['channel']) == strtolower($pf->getChannel())) {
+                    $found = true;
+                    break;
+                }
+            }
+        }
+        if (!$found) {
+            return false;
+        }
+        if (isset($info['exclude'])) {
+            if (!isset($info['exclude'][0])) {
+                $info['exclude'] = array($info['exclude']);
+            }
+            foreach ($info['exclude'] as $exclude) {
+                if (version_compare($me, $exclude, '==')) {
+                    return false;
+                }
+            }
+        }
+        if (version_compare($me, $info['min'], '>=') && version_compare($me, $info['max'], '<=')) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * @return array|false
+     */
+    function getCompatible()
+    {
+        if (isset($this->_packageInfo['compatible'])) {
+            return $this->_packageInfo['compatible'];
+        }
+        return false;
+    }
+
+    function getDependencies()
+    {
+        if (isset($this->_packageInfo['dependencies'])) {
+            return $this->_packageInfo['dependencies'];
+        }
+        return false;
+    }
+
+    function isSubpackageOf($p)
+    {
+        return $p->isSubpackage($this);
+    }
+
+    /**
+     * Determines whether the passed in package is a subpackage of this package.
+     *
+     * No version checking is done, only name verification.
+     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+     * @return bool
+     */
+    function isSubpackage($p)
+    {
+        $sub = array();
+        if (isset($this->_packageInfo['dependencies']['required']['subpackage'])) {
+            $sub = $this->_packageInfo['dependencies']['required']['subpackage'];
+            if (!isset($sub[0])) {
+                $sub = array($sub);
+            }
+        }
+        if (isset($this->_packageInfo['dependencies']['optional']['subpackage'])) {
+            $sub1 = $this->_packageInfo['dependencies']['optional']['subpackage'];
+            if (!isset($sub1[0])) {
+                $sub1 = array($sub1);
+            }
+            $sub = array_merge($sub, $sub1);
+        }
+        if (isset($this->_packageInfo['dependencies']['group'])) {
+            $group = $this->_packageInfo['dependencies']['group'];
+            if (!isset($group[0])) {
+                $group = array($group);
+            }
+            foreach ($group as $deps) {
+                if (isset($deps['subpackage'])) {
+                    $sub2 = $deps['subpackage'];
+                    if (!isset($sub2[0])) {
+                        $sub2 = array($sub2);
+                    }
+                    $sub = array_merge($sub, $sub2);
+                }
+            }
+        }
+        foreach ($sub as $dep) {
+            if (strtolower($dep['name']) == strtolower($p->getPackage())) {
+                if (isset($dep['channel'])) {
+                    if (strtolower($dep['channel']) == strtolower($p->getChannel())) {
+                        return true;
+                    }
+                } else {
+                    if ($dep['uri'] == $p->getURI()) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    function dependsOn($package, $channel)
+    {
+        if (!($deps = $this->getDependencies())) {
+            return false;
+        }
+        foreach (array('package', 'subpackage') as $type) {
+            foreach (array('required', 'optional') as $needed) {
+                if (isset($deps[$needed][$type])) {
+                    if (!isset($deps[$needed][$type][0])) {
+                        $deps[$needed][$type] = array($deps[$needed][$type]);
+                    }
+                    foreach ($deps[$needed][$type] as $dep) {
+                        $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri';
+                        if (strtolower($dep['name']) == strtolower($package) &&
+                              $depchannel == $channel) {
+                            return true;
+                        }  
+                    }
+                }
+            }
+            if (isset($deps['group'])) {
+                if (!isset($deps['group'][0])) {
+                    $dep['group'] = array($deps['group']);
+                }
+                foreach ($deps['group'] as $group) {
+                    if (isset($group[$type])) {
+                        if (!is_array($group[$type])) {
+                            $group[$type] = array($group[$type]);
+                        }
+                        foreach ($group[$type] as $dep) {
+                            $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri';
+                            if (strtolower($dep['name']) == strtolower($package) &&
+                                  $depchannel == $channel) {
+                                return true;
+                            }  
+                        }
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Get the contents of a dependency group
+     * @param string
+     * @return array|false
+     */
+    function getDependencyGroup($name)
+    {
+        $name = strtolower($name);
+        if (!isset($this->_packageInfo['dependencies']['group'])) {
+            return false;
+        }
+        $groups = $this->_packageInfo['dependencies']['group'];
+        if (!isset($groups[0])) {
+            $groups = array($groups);
+        }
+        foreach ($groups as $group) {
+            if (strtolower($group['attribs']['name']) == $name) {
+                return $group;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Retrieve a partial package.xml 1.0 representation of dependencies
+     *
+     * a very limited representation of dependencies is returned by this method.
+     * The <exclude> tag for excluding certain versions of a dependency is
+     * completely ignored.  In addition, dependency groups are ignored, with the
+     * assumption that all dependencies in dependency groups are also listed in
+     * the optional group that work with all dependency groups
+     * @param boolean return package.xml 2.0 <dependencies> tag
+     * @return array|false
+     */
+    function getDeps($raw = false, $nopearinstaller = false)
+    {
+        if (isset($this->_packageInfo['dependencies'])) {
+            if ($raw) {
+                return $this->_packageInfo['dependencies'];
+            }
+            $ret = array();
+            $map = array(
+                'php' => 'php',
+                'package' => 'pkg',
+                'subpackage' => 'pkg',
+                'extension' => 'ext',
+                'os' => 'os',
+                'pearinstaller' => 'pkg',
+                );
+            foreach (array('required', 'optional') as $type) {
+                $optional = ($type == 'optional') ? 'yes' : 'no';
+                if (!isset($this->_packageInfo['dependencies'][$type])) {
+                    continue;
+                }
+                foreach ($this->_packageInfo['dependencies'][$type] as $dtype => $deps) {
+                    if ($dtype == 'pearinstaller' && $nopearinstaller) {
+                        continue;
+                    }
+                    if (!isset($deps[0])) {
+                        $deps = array($deps);
+                    }
+                    foreach ($deps as $dep) {
+                        if (!isset($map[$dtype])) {
+                            // no support for arch type
+                            continue;
+                        }
+                        if ($dtype == 'pearinstaller') {
+                            $dep['name'] = 'PEAR';
+                            $dep['channel'] = 'pear.php.net';
+                        }
+                        $s = array('type' => $map[$dtype]);
+                        if (isset($dep['channel'])) {
+                            $s['channel'] = $dep['channel'];
+                        }
+                        if (isset($dep['uri'])) {
+                            $s['uri'] = $dep['uri'];
+                        }
+                        if (isset($dep['name'])) {
+                            $s['name'] = $dep['name'];
+                        }
+                        if (isset($dep['conflicts'])) {
+                            $s['rel'] = 'not';
+                        } else {
+                            if (!isset($dep['min']) &&
+                                  !isset($dep['max'])) {
+                                $s['rel'] = 'has';
+                            } elseif (isset($dep['min']) &&
+                                  isset($dep['max'])) {
+                                $s['rel'] = 'ge';
+                                $s1 = $s;
+                                $s1['rel'] = 'le';
+                                $s['version'] = $dep['min'];
+                                $s1['version'] = $dep['max'];
+                                if (isset($dep['channel'])) {
+                                    $s1['channel'] = $dep['channel'];
+                                }
+                                if ($dtype != 'php') {
+                                    $s['name'] = $dep['name'];
+                                    $s1['name'] = $dep['name'];
+                                }
+                                $s['optional'] = $optional;
+                                $s1['optional'] = $optional;
+                                $ret[] = $s1;
+                            } elseif (isset($dep['min'])) {
+                                $s['rel'] = 'ge';
+                                $s['version'] = $dep['min'];
+                                $s['optional'] = $optional;
+                                if ($dtype != 'php') {
+                                    $s['name'] = $dep['name'];
+                                }
+                            } elseif (isset($dep['max'])) {
+                                $s['rel'] = 'le';
+                                $s['version'] = $dep['max'];
+                                $s['optional'] = $optional;
+                                if ($dtype != 'php') {
+                                    $s['name'] = $dep['name'];
+                                }
+                            }
+                        }
+                        $ret[] = $s;
+                    }
+                }
+            }
+            if (count($ret)) {
+                return $ret;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @return php|extsrc|extbin|bundle|false
+     */
+    function getPackageType()
+    {
+        if (isset($this->_packageInfo['phprelease'])) {
+            return 'php';
+        }
+        if (isset($this->_packageInfo['extsrcrelease'])) {
+            return 'extsrc';
+        }
+        if (isset($this->_packageInfo['extbinrelease'])) {
+            return 'extbin';
+        }
+        if (isset($this->_packageInfo['bundle'])) {
+            return 'bundle';
+        }
+        return false;
+    }
+
+    /**
+     * @return array|false
+     */
+    function getReleases()
+    {
+        $type = $this->getPackageType();
+        if ($type != 'bundle') {
+            $type .= 'release';
+        }
+        if ($this->getPackageType() && isset($this->_packageInfo[$type])) {
+            return $this->_packageInfo[$type];
+        }
+        return false;
+    }
+
+    /**
+     * @return array
+     */
+    function getChangelog()
+    {
+        if (isset($this->_packageInfo['changelog'])) {
+            return $this->_packageInfo['changelog'];
+        }
+        return false;
+    }
+
+    function hasDeps()
+    {
+        return isset($this->_packageInfo['dependencies']);
+    }
+
+    function getPackagexmlVersion()
+    {
+        return '2.0';
+    }
+
+    /**
+     * @return array|false
+     */
+    function getSourcePackage()
+    {
+        if (isset($this->_packageInfo['extbinrelease'])) {
+            return array('channel' => $this->_packageInfo['srcchannel'],
+                         'package' => $this->_packageInfo['srcpackage']);
+        }
+        return false;
+    }
+
+    function getBundledPackages()
+    {
+        if (isset($this->_packageInfo['bundle'])) {
+            return $this->_packageInfo['contents']['bundledpackage'];
+        }
+        return false;
+    }
+
+    function getLastModified()
+    {
+        if (isset($this->_packageInfo['_lastmodified'])) {
+            return $this->_packageInfo['_lastmodified'];
+        }
+        return false;
+    }
+
+    /**
+     * Get the contents of a file listed within the package.xml
+     * @param string
+     * @return string
+     */
+    function getFileContents($file)
+    {
+        if ($this->_archiveFile == $this->_packageFile) { // unpacked
+            $dir = dirname($this->_packageFile);
+            $file = $dir . DIRECTORY_SEPARATOR . $file;
+            $file = str_replace(array('/', '\\'),
+                array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), $file);
+            if (file_exists($file) && is_readable($file)) {
+                return implode('', file($file));
+            }
+        } else { // tgz
+            $tar = &new Archive_Tar($this->_archiveFile);
+            $tar->pushErrorHandling(PEAR_ERROR_RETURN);
+            if ($file != 'package.xml' && $file != 'package2.xml') {
+                $file = $this->getPackage() . '-' . $this->getVersion() . '/' . $file;
+            }
+            $file = $tar->extractInString($file);
+            $tar->popErrorHandling();
+            if (PEAR::isError($file)) {
+                return PEAR::raiseError("Cannot locate file '$file' in archive");
+            }
+            return $file;
+        }
+    }
+
+    function &getRW()
+    {
+        if (!class_exists('PEAR_PackageFile_v2_rw')) {
+            require_once 'PEAR/PackageFile/v2/rw.php';
+        }
+        $a = new PEAR_PackageFile_v2_rw;
+        foreach (get_object_vars($this) as $name => $unused) {
+            if (!isset($this->$name)) {
+                continue;
+            }
+            if ($name == '_config' || $name == '_logger'|| $name == '_registry' ||
+                  $name == '_stack') {
+                $a->$name = &$this->$name;
+            } else {
+                $a->$name = $this->$name;
+            }
+        }
+        return $a;
+    }
+
+    function &getDefaultGenerator()
+    {
+        if (!class_exists('PEAR_PackageFile_Generator_v2')) {
+            require_once 'PEAR/PackageFile/Generator/v2.php';
+        }
+        $a = &new PEAR_PackageFile_Generator_v2($this);
+        return $a;
+    }
+
+    function analyzeSourceCode($file, $string = false)
+    {
+        if (!isset($this->_v2Validator)) {
+            if (!class_exists('PEAR_PackageFile_v2_Validator')) {
+                require_once 'PEAR/PackageFile/v2/Validator.php';
+            }
+            $this->_v2Validator = new PEAR_PackageFile_v2_Validator;
+        }
+        return $this->_v2Validator->analyzeSourceCode($file, $string);
+    }
+
+    function validate($state = PEAR_VALIDATE_NORMAL)
+    {
+        if (!isset($this->_packageInfo) || !is_array($this->_packageInfo)) {
+            return false;
+        }
+        if (!isset($this->_v2Validator)) {
+            if (!class_exists('PEAR_PackageFile_v2_Validator')) {
+                require_once 'PEAR/PackageFile/v2/Validator.php';
+            }
+            $this->_v2Validator = new PEAR_PackageFile_v2_Validator;
+        }
+        if (isset($this->_packageInfo['xsdversion'])) {
+            unset($this->_packageInfo['xsdversion']);
+        }
+        return $this->_v2Validator->validate($this, $state);
+    }
+
+    function getTasksNs()
+    {
+        if (!isset($this->_tasksNs)) {
+            if (isset($this->_packageInfo['attribs'])) {
+                foreach ($this->_packageInfo['attribs'] as $name => $value) {
+                    if ($value == 'http://pear.php.net/dtd/tasks-1.0') {
+                        $this->_tasksNs = str_replace('xmlns:', '', $name);
+                        break;
+                    }
+                }
+            }
+        }
+        return $this->_tasksNs;
+    }
+
+    /**
+     * Determine whether a task name is a valid task.  Custom tasks may be defined
+     * using subdirectories by putting a "-" in the name, as in <tasks:mycustom-task>
+     *
+     * Note that this method will auto-load the task class file and test for the existence
+     * of the name with "-" replaced by "_" as in PEAR/Task/mycustom/task.php makes class
+     * PEAR_Task_mycustom_task
+     * @param string
+     * @return boolean
+     */
+    function getTask($task)
+    {
+        $this->getTasksNs();
+        // transform all '-' to '/' and 'tasks:' to '' so tasks:replace becomes replace
+        $task = str_replace(array($this->_tasksNs . ':', '-'), array('', ' '), $task);
+        $task = str_replace(' ', '/', ucwords($task));
+        $ps = (strtolower(substr(PHP_OS, 0, 3)) == 'win') ? ';' : ':';
+        foreach (explode($ps, ini_get('include_path')) as $path) {
+            if (file_exists($path . "/PEAR/Task/$task.php")) {
+                include_once "PEAR/Task/$task.php";
+                $task = str_replace('/', '_', $task);
+                if (class_exists("PEAR_Task_$task")) {
+                    return "PEAR_Task_$task";
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Key-friendly array_splice
+     * @param tagname to splice a value in before
+     * @param mixed the value to splice in
+     * @param string the new tag name
+     */
+    function _ksplice($array, $key, $value, $newkey)
+    {
+        $offset = array_search($key, array_keys($array));
+        $after = array_slice($array, $offset);
+        $before = array_slice($array, 0, $offset);
+        $before[$newkey] = $value;
+        return array_merge($before, $after);
+    }
+
+    /**
+     * @param array a list of possible keys, in the order they may occur
+     * @param mixed contents of the new package.xml tag
+     * @param string tag name
+     * @access private
+     */
+    function _insertBefore($array, $keys, $contents, $newkey)
+    {
+        foreach ($keys as $key) {
+            if (isset($array[$key])) {
+                return $array = $this->_ksplice($array, $key, $contents, $newkey);
+            }
+        }
+        $array[$newkey] = $contents;
+        return $array;
+    }
+
+    /**
+     * @param subsection of {@link $_packageInfo}
+     * @param array|string tag contents
+     * @param array format:
+     * <pre>
+     * array(
+     *   tagname => array(list of tag names that follow this one),
+     *   childtagname => array(list of child tag names that follow this one),
+     * )
+     * </pre>
+     *
+     * This allows construction of nested tags
+     * @access private
+     */
+    function _mergeTag($manip, $contents, $order)
+    {
+        if (count($order)) {
+            foreach ($order as $tag => $curorder) {
+                if (!isset($manip[$tag])) {
+                    // ensure that the tag is set up
+                    $manip = $this->_insertBefore($manip, $curorder, array(), $tag);
+                }
+                if (count($order) > 1) {
+                    $manip[$tag] = $this->_mergeTag($manip[$tag], $contents, array_slice($order, 1));
+                    return $manip;
+                }
+            }
+        } else {
+            return $manip;
+        }
+        if (is_array($manip[$tag]) && !empty($manip[$tag]) && isset($manip[$tag][0])) {
+            $manip[$tag][] = $contents;
+        } else {
+            if (!count($manip[$tag])) {
+                $manip[$tag] = $contents;
+            } else {
+                $manip[$tag] = array($manip[$tag]);
+                $manip[$tag][] = $contents;
+            }
+        }
+        return $manip;
+    }
+}
+?>
diff --git a/pear/PEAR/PackageFile/v2/Validator.php b/pear/PEAR/PackageFile/v2/Validator.php
new file mode 100644 (file)
index 0000000..40fad97
--- /dev/null
@@ -0,0 +1,1976 @@
+<?php
+//
+// +----------------------------------------------------------------------+
+// | PHP Version 5                                                        |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1997-2004 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: Greg Beaver <cellog@php.net>                                 |
+// |                                                                      |
+// +----------------------------------------------------------------------+
+//
+// $Id$
+/**
+ * Private validation class used by PEAR_PackageFile_v2 - do not use directly, its
+ * sole purpose is to split up the PEAR/PackageFile/v2.php file to make it smaller
+ * @author Greg Beaver <cellog@php.net>
+ * @access private
+ */
+class PEAR_PackageFile_v2_Validator
+{
+    /**
+     * @var array
+     */
+    var $_packageInfo;
+    /**
+     * @var PEAR_PackageFile_v2
+     */
+    var $_pf;
+    /**
+     * @var PEAR_ErrorStack
+     */
+    var $_stack;
+    /**
+     * @var int
+     */
+    var $_isValid = 0;
+    /**
+     * @var int
+     */
+    var $_curState = 0;
+    /**
+     * @param PEAR_PackageFile_v2
+     * @param int
+     */
+    function validate(&$pf, $state = PEAR_VALIDATE_NORMAL)
+    {
+        $this->_pf = &$pf;
+        $this->_curState = $state;
+        $this->_packageInfo = $this->_pf->getArray();
+        $this->_isValid = $this->_pf->_isValid;
+        $this->_filesValid = $this->_pf->_filesValid;
+        $this->_stack = &$pf->_stack;
+        $this->_stack->getErrors(true);
+        if (($this->_isValid & $state) == $state) {
+            return true;
+        }
+        if (!isset($this->_packageInfo) || !is_array($this->_packageInfo)) {
+            return false;
+        }
+        if (!isset($this->_packageInfo['attribs']['version']) ||
+              $this->_packageInfo['attribs']['version'] != '2.0') {
+            $this->_noPackageVersion();
+        }
+        $structure =
+        array(
+            'name',
+            'channel|uri',
+            '*extends', // can't be multiple, but this works fine
+            'summary',
+            'description',
+            '+lead', // these all need content checks
+            '*developer',
+            '*contributor',
+            '*helper',
+            'date',
+            '*time',
+            'version',
+            'stability',
+            'license->?uri->?filesource',
+            'notes',
+            'contents', //special validation needed
+            '*compatible',
+            'dependencies', //special validation needed
+            '*usesrole',
+            '*usestask', // reserve these for 1.4.0a1 to implement
+                         // this will allow a package.xml to gracefully say it
+                         // needs a certain package installed in order to implement a role or task
+            '*providesextension',
+            '*srcpackage|*srcuri',
+            '+phprelease|+extsrcrelease|+extbinrelease|bundle', //special validation needed
+            '*changelog',
+        );
+        $test = $this->_packageInfo;
+        // ignore post-installation array fields
+        if (array_key_exists('filelist', $test)) {
+            unset($test['filelist']);
+        }
+        if (array_key_exists('_lastmodified', $test)) {
+            unset($test['_lastmodified']);
+        }
+        if (array_key_exists('#binarypackage', $test)) {
+            unset($test['#binarypackage']);
+        }
+        if (array_key_exists('old', $test)) {
+            unset($test['old']);
+        }
+        if (array_key_exists('_lastversion', $test)) {
+            unset($test['_lastversion']);
+        }
+        if (!$this->_stupidSchemaValidate($structure,
+                                          $test, '<package>')) {
+            return false;
+        }
+        if (empty($this->_packageInfo['name'])) {
+            $this->_tagCannotBeEmpty('name');
+        }
+        if (isset($this->_packageInfo['uri'])) {
+            $test = 'uri';
+        } else {
+            $test = 'channel';
+        }
+        if (empty($this->_packageInfo[$test])) {
+            $this->_tagCannotBeEmpty($test);
+        }
+        if (is_array($this->_packageInfo['license']) &&
+              (!isset($this->_packageInfo['license']['_content']) ||
+              empty($this->_packageInfo['license']['_content']))) {
+            $this->_tagCannotBeEmpty('license');
+        } elseif (empty($this->_packageInfo['license'])) {
+            $this->_tagCannotBeEmpty('license');
+        }
+        if (empty($this->_packageInfo['summary'])) {
+            $this->_tagCannotBeEmpty('summary');
+        }
+        if (empty($this->_packageInfo['description'])) {
+            $this->_tagCannotBeEmpty('description');
+        }
+        if (empty($this->_packageInfo['date'])) {
+            $this->_tagCannotBeEmpty('date');
+        }
+        if (empty($this->_packageInfo['notes'])) {
+            $this->_tagCannotBeEmpty('notes');
+        }
+        if (isset($this->_packageInfo['time']) && empty($this->_packageInfo['time'])) {
+            $this->_tagCannotBeEmpty('time');
+        }
+        if (isset($this->_packageInfo['dependencies'])) {
+            $this->_validateDependencies();
+        }
+        if (isset($this->_packageInfo['compatible'])) {
+            $this->_validateCompatible();
+        }
+        if (!isset($this->_packageInfo['bundle'])) {
+            if (!isset($this->_packageInfo['contents']['dir'])) {
+                $this->_filelistMustContainDir('contents');
+                return false;
+            }
+            if (isset($this->_packageInfo['contents']['file'])) {
+                $this->_filelistCannotContainFile('contents');
+                return false;
+            }
+        }
+        $this->_validateMaintainers();
+        $this->_validateStabilityVersion();
+        $fail = false;
+        if (array_key_exists('usesrole', $this->_packageInfo)) {
+            $roles = $this->_packageInfo['usesrole'];
+            if (!is_array($roles) || !isset($roles[0])) {
+                $roles = array($roles);
+            }
+            foreach ($roles as $role) {
+                if (!isset($role['role'])) {
+                    $this->_usesroletaskMustHaveRoleTask('usesrole', 'role');
+                    $fail = true;
+                } else {
+                    if (!isset($role['channel'])) {
+                        if (!isset($role['uri'])) {
+                            $this->_usesroletaskMustHaveChannelOrUri($role['role'], 'usesrole');
+                            $fail = true;
+                        }
+                    } elseif (!isset($role['package'])) {
+                        $this->_usesroletaskMustHavePackage($role['role'], 'usesrole');
+                        $fail = true;
+                    }
+                }
+            }
+        }
+        if (array_key_exists('usestask', $this->_packageInfo)) {
+            $roles = $this->_packageInfo['usestask'];
+            if (!is_array($roles) || !isset($roles[0])) {
+                $roles = array($roles);
+            }
+            foreach ($roles as $role) {
+                if (!isset($role['task'])) {
+                    $this->_usesroletaskMustHaveRoleTask('usestask', 'task');
+                    $fail = true;
+                } else {
+                    if (!isset($role['channel'])) {
+                        if (!isset($role['uri'])) {
+                            $this->_usesroletaskMustHaveChannelOrUri($role['task'], 'usestask');
+                            $fail = true;
+                        }
+                    } elseif (!isset($role['package'])) {
+                        $this->_usesroletaskMustHavePackage($role['task'], 'usestask');
+                        $fail = true;
+                    }
+                }
+            }
+        }
+        if ($fail) {
+            return false;
+        }
+        $this->_validateFilelist();
+        $this->_validateRelease();
+        if (!$this->_stack->hasErrors()) {
+            $chan = $this->_pf->_registry->getChannel($this->_pf->getChannel(), true);
+            if (!$chan) {
+                $this->_unknownChannel($this->_pf->getChannel());
+            } else {
+                $valpack = $chan->getValidationPackage();
+                // for channel validator packages, always use the default PEAR validator.
+                // otherwise, they can't be installed or packaged
+                $validator = $chan->getValidationObject($this->_pf->getPackage());
+                if (!$validator) {
+                    $this->_stack->push(__FUNCTION__, 'error',
+                        array_merge(
+                            array('channel' => $chan->getName(),
+                                  'package' => $this->_pf->getPackage()),
+                              $valpack
+                            ),
+                        'package "%channel%/%package%" cannot be properly validated without ' .
+                        'validation package "%channel%/%name%-%version%"');
+                    return $this->_isValid = 0;
+                }
+                $validator->setPackageFile($this->_pf);
+                $validator->validate($state);
+                $failures = $validator->getFailures();
+                foreach ($failures['errors'] as $error) {
+                    $this->_stack->push(__FUNCTION__, 'error', $error,
+                        'Channel validator error: field "%field%" - %reason%');
+                }
+                foreach ($failures['warnings'] as $warning) {
+                    $this->_stack->push(__FUNCTION__, 'warning', $warning,
+                        'Channel validator warning: field "%field%" - %reason%');
+                }
+            }
+        }
+        $this->_pf->_isValid = $this->_isValid = !$this->_stack->hasErrors('error');
+        if ($this->_isValid && $state == PEAR_VALIDATE_PACKAGING && !$this->_filesValid) {
+            if ($this->_pf->getPackageType() == 'bundle') {
+                if ($this->_analyzeBundledPackages()) {
+                    $this->_filesValid = $this->_pf->_filesValid = true;
+                } else {
+                    $this->_pf->_isValid = $this->_isValid = 0;
+                }
+            } else {
+                if (!$this->_analyzePhpFiles()) {
+                    $this->_pf->_isValid = $this->_isValid = 0;
+                } else {
+                    $this->_filesValid = $this->_pf->_filesValid = true;
+                }
+            }
+        }
+        if ($this->_isValid) {
+            return $this->_pf->_isValid = $this->_isValid = $state;
+        }
+        return $this->_pf->_isValid = $this->_isValid = 0;
+    }
+
+    function _stupidSchemaValidate($structure, $xml, $root)
+    {
+        if (!is_array($xml)) {
+            $xml = array();
+        }
+        $keys = array_keys($xml);
+        reset($keys);
+        $key = current($keys);
+        while ($key == 'attribs' || $key == '_contents') {
+            $key = next($keys);
+        }
+        $unfoundtags = $optionaltags = array();
+        $ret = true;
+        $mismatch = false;
+        foreach ($structure as $struc) {
+            if ($key) {
+                $tag = $xml[$key];
+            }
+            $test = $this->_processStructure($struc);
+            if (isset($test['choices'])) {
+                $loose = true;
+                foreach ($test['choices'] as $choice) {
+                    if ($key == $choice['tag']) {
+                        $key = next($keys);
+                        while ($key == 'attribs' || $key == '_contents') {
+                            $key = next($keys);
+                        }
+                        $unfoundtags = $optionaltags = array();
+                        $mismatch = false;
+                        if ($key && $key != $choice['tag'] && isset($choice['multiple'])) {
+                            $unfoundtags[] = $choice['tag'];
+                            $optionaltags[] = $choice['tag'];
+                            if ($key) {
+                                $mismatch = true;
+                            }
+                        }
+                        $ret &= $this->_processAttribs($choice, $tag, $root);
+                        continue 2;
+                    } else {
+                        $unfoundtags[] = $choice['tag'];
+                        $mismatch = true;
+                    }
+                    if (!isset($choice['multiple']) || $choice['multiple'] != '*') {
+                        $loose = false;
+                    } else {
+                        $optionaltags[] = $choice['tag'];
+                    }
+                }
+                if (!$loose) {
+                    $this->_invalidTagOrder($unfoundtags, $key, $root);
+                    return false;
+                }
+            } else {
+                if ($key != $test['tag']) {
+                    if (isset($test['multiple']) && $test['multiple'] != '*') {
+                        $unfoundtags[] = $test['tag'];
+                        $this->_invalidTagOrder($unfoundtags, $key, $root);
+                        return false;
+                    } else {
+                        if ($key) {
+                            $mismatch = true;
+                        }
+                        $unfoundtags[] = $test['tag'];
+                        $optionaltags[] = $test['tag'];
+                    }
+                    if (!isset($test['multiple'])) {
+                        $this->_invalidTagOrder($unfoundtags, $key, $root);
+                        return false;
+                    }
+                    continue;
+                } else {
+                    $unfoundtags = $optionaltags = array();
+                    $mismatch = false;
+                }
+                $key = next($keys);
+                while ($key == 'attribs' || $key == '_contents') {
+                    $key = next($keys);
+                }
+                if ($key && $key != $test['tag'] && isset($test['multiple'])) {
+                    $unfoundtags[] = $test['tag'];
+                    $optionaltags[] = $test['tag'];
+                    $mismatch = true;
+                }
+                $ret &= $this->_processAttribs($test, $tag, $root);
+                continue;
+            }
+        }
+        if (!$mismatch && count($optionaltags)) {
+            // don't error out on any optional tags
+            $unfoundtags = array_diff($unfoundtags, $optionaltags);
+        }
+        if (count($unfoundtags)) {
+            $this->_invalidTagOrder($unfoundtags, $key, $root);
+        } elseif ($key) {
+            // unknown tags
+            $this->_invalidTagOrder('*no tags allowed here*', $key, $root);
+            while ($key = next($keys)) {
+                $this->_invalidTagOrder('*no tags allowed here*', $key, $root);
+            }
+        }
+        return $ret;
+    }
+
+    function _processAttribs($choice, $tag, $context)
+    {
+        if (isset($choice['attribs'])) {
+            if (!is_array($tag)) {
+                $tag = array($tag);
+            }
+            $tags = $tag;
+            if (!isset($tags[0])) {
+                $tags = array($tags);
+            }
+            $ret = true;
+            foreach ($tags as $i => $tag) {
+                if (!is_array($tag) || !isset($tag['attribs'])) {
+                    foreach ($choice['attribs'] as $attrib) {
+                        if ($attrib{0} != '?') {
+                            $ret &= $this->_tagHasNoAttribs($choice['tag'],
+                                $context);
+                            continue 2;
+                        }
+                    }
+                }
+                foreach ($choice['attribs'] as $attrib) {
+                    if ($attrib{0} != '?') {
+                        if (!isset($tag['attribs'][$attrib])) {
+                            $ret &= $this->_tagMissingAttribute($choice['tag'],
+                                $attrib, $context);
+                        }
+                    }
+                }
+            }
+            return $ret;
+        }
+        return true;
+    }
+
+    function _processStructure($key)
+    {
+        $ret = array();
+        if (count($pieces = explode('|', $key)) > 1) {
+            foreach ($pieces as $piece) {
+                $ret['choices'][] = $this->_processStructure($piece);
+            }
+            return $ret;
+        }
+        $multi = $key{0};
+        if ($multi == '+' || $multi == '*') {
+            $ret['multiple'] = $key{0};
+            $key = substr($key, 1);
+        }
+        if (count($attrs = explode('->', $key)) > 1) {
+            $ret['tag'] = array_shift($attrs);
+            $ret['attribs'] = $attrs;
+        } else {
+            $ret['tag'] = $key;
+        }
+        return $ret;
+    }
+
+    function _validateStabilityVersion()
+    {
+        $structure = array('release', 'api');
+        $a = $this->_stupidSchemaValidate($structure, $this->_packageInfo['version'], '<version>');
+        $a &= $this->_stupidSchemaValidate($structure, $this->_packageInfo['stability'], '<stability>');
+        if ($a) {
+            if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
+                  $this->_packageInfo['version']['release'])) {
+                $this->_invalidVersion('release', $this->_packageInfo['version']['release']);
+            }
+            if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
+                  $this->_packageInfo['version']['api'])) {
+                $this->_invalidVersion('api', $this->_packageInfo['version']['api']);
+            }
+            if (!in_array($this->_packageInfo['stability']['release'],
+                  array('snapshot', 'devel', 'alpha', 'beta', 'stable'))) {
+                $this->_invalidState('release', $this->_packageinfo['stability']['release']);
+            }
+            if (!in_array($this->_packageInfo['stability']['api'],
+                  array('devel', 'alpha', 'beta', 'stable'))) {
+                $this->_invalidState('api', $this->_packageinfo['stability']['api']);
+            }
+        }
+    }
+
+    function _validateMaintainers()
+    {
+        $structure =
+            array(
+                'name',
+                'user',
+                'email',
+                'active',
+            );
+        foreach (array('lead', 'developer', 'contributor', 'helper') as $type) {
+            if (!isset($this->_packageInfo[$type])) {
+                continue;
+            }
+            if (isset($this->_packageInfo[$type][0])) {
+                foreach ($this->_packageInfo[$type] as $lead) {
+                    $this->_stupidSchemaValidate($structure, $lead, '<' . $type . '>');
+                }
+            } else {
+                $this->_stupidSchemaValidate($structure, $this->_packageInfo[$type],
+                    '<' . $type . '>');
+            }
+        }
+    }
+
+    function _validatePhpDep($dep, $installcondition = false)
+    {
+        $structure = array(
+            'min',
+            '*max',
+            '*exclude',
+        );
+        $type = $installcondition ? '<installcondition><php>' : '<dependencies><required><php>';
+        $this->_stupidSchemaValidate($structure, $dep, $type);
+        if (isset($dep['min'])) {
+            if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?$/',
+                  $dep['min'])) {
+                $this->_invalidVersion($type . '<min>', $dep['min']);
+            }
+        }
+        if (isset($dep['max'])) {
+            if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?$/',
+                  $dep['max'])) {
+                $this->_invalidVersion($type . '<max>', $dep['max']);
+            }
+        }
+    }
+
+    function _validatePearinstallerDep($dep)
+    {
+        $structure = array(
+            'min',
+            '*max',
+            '*recommended',
+            '*exclude',
+        );
+        $this->_stupidSchemaValidate($structure, $dep, '<dependencies><required><pearinstaller>');
+        if (isset($dep['min'])) {
+            if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
+                  $dep['min'])) {
+                $this->_invalidVersion('<dependencies><required><pearinstaller><min>',
+                    $dep['min']);
+            }
+        }
+        if (isset($dep['max'])) {
+            if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
+                  $dep['max'])) {
+                $this->_invalidVersion('<dependencies><required><pearinstaller><max>',
+                    $dep['max']);
+            }
+        }
+        if (isset($dep['recommended'])) {
+            if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
+                  $dep['recommended'])) {
+                $this->_invalidVersion('<dependencies><required><pearinstaller><recommended>',
+                    $dep['recommended']);
+            }
+        }
+        if (isset($dep['exclude'])) {
+            if (!is_array($dep['exclude'])) {
+                $dep['exclude'] = array($dep['exclude']);
+            }
+            foreach ($dep['exclude'] as $exclude) {
+                if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
+                      $exclude)) {
+                    $this->_invalidVersion('<dependencies><required><pearinstaller><exclude>',
+                        $exclude);
+                }
+            }
+        }
+    }
+
+    function _validatePackageDep($dep, $group, $type = '<package>')
+    {
+        if (isset($dep['uri'])) {
+            if (isset($dep['conflicts'])) {
+                $structure = array(
+                    'name',
+                    'uri',
+                    'conflicts',
+                    '*providesextension',
+                );
+            } else {
+                $structure = array(
+                    'name',
+                    'uri',
+                    '*providesextension',
+                );
+            }
+        } else {
+            if (isset($dep['conflicts'])) {
+                $structure = array(
+                    'name',
+                    'channel',
+                    '*min',
+                    '*max',
+                    '*exclude',
+                    'conflicts',
+                    '*providesextension',
+                );
+            } else {
+                $structure = array(
+                    'name',
+                    'channel',
+                    '*min',
+                    '*max',
+                    '*recommended',
+                    '*exclude',
+                    '*nodefault',
+                    '*providesextension',
+                );
+            }
+        }
+        if (isset($dep['name'])) {
+            $type .= '<name>' . $dep['name'] . '</name>';
+        }
+        $this->_stupidSchemaValidate($structure, $dep, '<dependencies>' . $group . $type);
+        if (isset($dep['uri']) && (isset($dep['min']) || isset($dep['max']) ||
+              isset($dep['recommended']) || isset($dep['exclude']))) {
+            $this->_uriDepsCannotHaveVersioning('<dependencies>' . $group . $type);
+        }
+        if (isset($dep['channel']) && strtolower($dep['channel']) == '__uri') {
+            $this->_DepchannelCannotBeUri('<dependencies>' . $group . $type);
+        }
+        if (isset($dep['min'])) {
+            if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
+                  $dep['min'])) {
+                $this->_invalidVersion('<dependencies>' . $group . $type . '<min>', $dep['min']);
+            }
+        }
+        if (isset($dep['max'])) {
+            if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
+                  $dep['max'])) {
+                $this->_invalidVersion('<dependencies>' . $group . $type . '<max>', $dep['max']);
+            }
+        }
+        if (isset($dep['recommended'])) {
+            if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
+                  $dep['recommended'])) {
+                $this->_invalidVersion('<dependencies>' . $group . $type . '<recommended>',
+                    $dep['recommended']);
+            }
+        }
+        if (isset($dep['exclude'])) {
+            if (!is_array($dep['exclude'])) {
+                $dep['exclude'] = array($dep['exclude']);
+            }
+            foreach ($dep['exclude'] as $exclude) {
+                if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
+                      $exclude)) {
+                    $this->_invalidVersion('<dependencies>' . $group . $type . '<exclude>',
+                        $exclude);
+                }
+            }
+        }
+    }
+
+    function _validateSubpackageDep($dep, $group)
+    {
+        $this->_validatePackageDep($dep, $group, '<subpackage>');
+        if (isset($dep['providesextension'])) {
+            $this->_subpackageCannotProvideExtension(@$dep['name']);
+        }
+        if (isset($dep['conflicts'])) {
+            $this->_subpackagesCannotConflict(@$dep['name']);
+        }
+    }
+
+    function _validateExtensionDep($dep, $group = false, $installcondition = false)
+    {
+        if (isset($dep['conflicts'])) {
+            $structure = array(
+                'name',
+                '*min',
+                '*max',
+                '*exclude',
+                'conflicts',
+            );
+        } else {
+            $structure = array(
+                'name',
+                '*min',
+                '*max',
+                '*recommended',
+                '*exclude',
+            );
+        }
+        if ($installcondition) {
+            $type = '<installcondition><extension>';
+        } else {
+            $type = '<dependencies>' . $group . '<extension>';
+        }
+        if (isset($dep['name'])) {
+            $type .= '<name>' . $dep['name'] . '</name>';
+        }
+        $this->_stupidSchemaValidate($structure, $dep, $type);
+        if (isset($dep['min'])) {
+            if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
+                  $dep['min'])) {
+                $this->_invalidVersion(substr($type, 1) . '<min', $dep['min']);
+            }
+        }
+        if (isset($dep['max'])) {
+            if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
+                  $dep['max'])) {
+                $this->_invalidVersion(substr($type, 1) . '<max', $dep['max']);
+            }
+        }
+        if (isset($dep['recommended'])) {
+            if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
+                  $dep['recommended'])) {
+                $this->_invalidVersion(substr($type, 1) . '<recommended', $dep['recommended']);
+            }
+        }
+        if (isset($dep['exclude'])) {
+            if (!is_array($dep['exclude'])) {
+                $dep['exclude'] = array($dep['exclude']);
+            }
+            foreach ($dep['exclude'] as $exclude) {
+                if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
+                      $exclude)) {
+                    $this->_invalidVersion(substr($type, 1) . '<exclude', $exclude);
+                }
+            }
+        }
+    }
+
+    function _validateOsDep($dep, $installcondition = false)
+    {
+        $structure = array(
+            'name',
+            '*conflicts',
+        );
+        $type = $installcondition ? '<installcondition><os>' : '<dependencies><required><os>';
+        if ($this->_stupidSchemaValidate($structure, $dep, $type)) {
+            if ($dep['name'] == '*') {
+                if (array_key_exists('conflicts', $dep)) {
+                    $this->_cannotConflictWithAllOs($type);
+                }
+            }
+        }
+    }
+
+    function _validateArchDep($dep, $installcondition = false)
+    {
+        $structure = array(
+            'pattern',
+            '*conflicts',
+        );
+        $type = $installcondition ? '<installcondition><arch>' : '<dependencies><required><arch>';
+        $this->_stupidSchemaValidate($structure, $dep, $type);
+    }
+
+    function _validateInstallConditions($cond, $release)
+    {
+        $structure = array(
+            '*php',
+            '*extension',
+            '*os',
+            '*arch',
+        );
+        if (!$this->_stupidSchemaValidate($structure,
+              $cond, $release)) {
+            return false;
+        }
+        foreach (array('php', 'extension', 'os', 'arch') as $type) {
+            if (isset($cond[$type])) {
+                $iter = $cond[$type];
+                if (!is_array($iter) || !isset($iter[0])) {
+                    $iter = array($iter);
+                }
+                foreach ($iter as $package) {
+                    if ($type == 'extension') {
+                        $this->{"_validate{$type}Dep"}($package, false, true);
+                    } else {
+                        $this->{"_validate{$type}Dep"}($package, true);
+                    }
+                }
+            }
+        }
+    }
+
+    function _validateDependencies()
+    {
+        $structure = array(
+            'required',
+            '*optional',
+            '*group->name->hint'
+        );
+        if (!$this->_stupidSchemaValidate($structure,
+              $this->_packageInfo['dependencies'], '<dependencies>')) {
+            return false;
+        }
+        foreach (array('required', 'optional') as $simpledep) {
+            if (isset($this->_packageInfo['dependencies'][$simpledep])) {
+                if ($simpledep == 'optional') {
+                    $structure = array(
+                        '*package',
+                        '*subpackage',
+                        '*extension',
+                    );
+                } else {
+                    $structure = array(
+                        'php',
+                        'pearinstaller',
+                        '*package',
+                        '*subpackage',
+                        '*extension',
+                        '*os',
+                        '*arch',
+                    );
+                }
+                if ($this->_stupidSchemaValidate($structure,
+                      $this->_packageInfo['dependencies'][$simpledep],
+                      "<dependencies><$simpledep>")) {
+                    foreach (array('package', 'subpackage', 'extension') as $type) {
+                        if (isset($this->_packageInfo['dependencies'][$simpledep][$type])) {
+                            $iter = $this->_packageInfo['dependencies'][$simpledep][$type];
+                            if (!isset($iter[0])) {
+                                $iter = array($iter);
+                            }
+                            foreach ($iter as $package) {
+                                if ($type != 'extension') {
+                                    if (isset($package['uri'])) {
+                                        if (isset($package['channel'])) {
+                                            $this->_UrlOrChannel($type,
+                                                $package['name']);
+                                        }
+                                    } else {
+                                        if (!isset($package['channel'])) {
+                                            $this->_NoChannel($type, $package['name']);
+                                        }
+                                    }
+                                }
+                                $this->{"_validate{$type}Dep"}($package, "<$simpledep>");
+                            }
+                        }
+                    }
+                    if ($simpledep == 'optional') {
+                        continue;
+                    }
+                    foreach (array('php', 'pearinstaller', 'os', 'arch') as $type) {
+                        if (isset($this->_packageInfo['dependencies'][$simpledep][$type])) {
+                            $iter = $this->_packageInfo['dependencies'][$simpledep][$type];
+                            if (!isset($iter[0])) {
+                                $iter = array($iter);
+                            }
+                            foreach ($iter as $package) {
+                                $this->{"_validate{$type}Dep"}($package);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        if (isset($this->_packageInfo['dependencies']['group'])) {
+            $groups = $this->_packageInfo['dependencies']['group'];
+            if (!isset($groups[0])) {
+                $groups = array($groups);
+            }
+            $structure = array(
+                '*package',
+                '*subpackage',
+                '*extension',
+            );
+            foreach ($groups as $group) {
+                if ($this->_stupidSchemaValidate($structure, $group, '<group>')) {
+                    if (!PEAR_Validate::validGroupName($group['attribs']['name'])) {
+                        $this->_invalidDepGroupName($group['attribs']['name']);
+                    }
+                    foreach (array('package', 'subpackage', 'extension') as $type) {
+                        if (isset($group[$type])) {
+                            $iter = $group[$type];
+                            if (!isset($iter[0])) {
+                                $iter = array($iter);
+                            }
+                            foreach ($iter as $package) {
+                                if ($type != 'extension') {
+                                    if (isset($package['uri'])) {
+                                        if (isset($package['channel'])) {
+                                            $this->_UrlOrChannelGroup($type,
+                                                $package['name'],
+                                                $group['name']);
+                                        }
+                                    } else {
+                                        if (!isset($package['channel'])) {
+                                            $this->_NoChannelGroup($type,
+                                                $package['name'],
+                                                $group['name']);
+                                        }
+                                    }
+                                }
+                                $this->{"_validate{$type}Dep"}($package, '<group name="' .
+                                    $group['attribs']['name'] . '">');
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    function _validateCompatible()
+    {
+        $compat = $this->_packageInfo['compatible'];
+        if (!isset($compat[0])) {
+            $compat = array($compat);
+        }
+        $required = array('name', 'channel', 'min', 'max', '*exclude');
+        foreach ($compat as $package) {
+            $type = '<compatible>';
+            if (is_array($package) && array_key_exists('name', $package)) {
+                $type .= '<name>' . $package['name'] . '</name>';
+            }
+            $this->_stupidSchemaValidate($required, $package, $type);
+            if (is_array($package) && array_key_exists('min', $package)) {
+                if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
+                      $package['min'])) {
+                    $this->_invalidVersion(substr($type, 1) . '<min', $package['min']);
+                }
+            }
+            if (is_array($package) && array_key_exists('max', $package)) {
+                if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
+                      $package['max'])) {
+                    $this->_invalidVersion(substr($type, 1) . '<max', $package['max']);
+                }
+            }
+            if (is_array($package) && array_key_exists('exclude', $package)) {
+                if (!is_array($package['exclude'])) {
+                    $package['exclude'] = array($package['exclude']);
+                }
+                foreach ($package['exclude'] as $exclude) {
+                    if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
+                          $exclude)) {
+                        $this->_invalidVersion(substr($type, 1) . '<exclude', $exclude);
+                    }
+                }
+            }
+        }
+    }
+
+    function _validateBundle($list)
+    {
+        if (!is_array($list) || !isset($list['bundledpackage'])) {
+            return $this->_NoBundledPackages();
+        }
+        if (!is_array($list['bundledpackage']) || !isset($list['bundledpackage'][0])) {
+            return $this->_AtLeast2BundledPackages();
+        }
+        foreach ($list['bundledpackage'] as $package) {
+            if (!is_string($package)) {
+                $this->_bundledPackagesMustBeFilename();
+            }
+        }
+    }
+
+    function _validateFilelist($list = false, $allowignore = false, $dirs = '')
+    {
+        $iscontents = false;
+        if (!$list) {
+            $iscontents = true;
+            $list = $this->_packageInfo['contents'];
+            if (isset($this->_packageInfo['bundle'])) {
+                return $this->_validateBundle($list);
+            }
+        }
+        if ($allowignore) {
+            $struc = array(
+                '*install->name->as',
+                '*ignore->name'
+            );
+        } else {
+            $struc = array(
+                '*dir->name->?baseinstalldir',
+                '*file->name->role->?baseinstalldir->?md5sum'
+            );
+            if (isset($list['dir']) && isset($list['file'])) {
+                // stave off validation errors without requiring a set order.
+                $_old = $list;
+                if (isset($list['attribs'])) {
+                    $list = array('attribs' => $_old['attribs']);
+                }
+                $list['dir'] = $_old['dir'];
+                $list['file'] = $_old['file'];
+            }
+        }
+        if (!isset($list['attribs']) || !isset($list['attribs']['name'])) {
+            $unknown = $allowignore ? '<filelist>' : '<dir name="*unknown*">';
+            $dirname = $iscontents ? '<contents>' : $unknown;
+        } else {
+            $dirname = '<dir name="' . $list['attribs']['name'] . '">';
+        }
+        $res = $this->_stupidSchemaValidate($struc, $list, $dirname);
+        if ($allowignore && $res) {
+            $this->_pf->getFilelist();
+            $fcontents = $this->_pf->getContents();
+            $filelist = array();
+            if (!isset($fcontents['dir']['file'][0])) {
+                $fcontents['dir']['file'] = array($fcontents['dir']['file']);
+            }
+            foreach ($fcontents['dir']['file'] as $file) {
+                $filelist[$file['attribs']['name']] = true;
+            }
+            if (isset($list['install'])) {
+                if (!isset($list['install'][0])) {
+                    $list['install'] = array($list['install']);
+                }
+                foreach ($list['install'] as $file) {
+                    if (!isset($filelist[$file['attribs']['name']])) {
+                        $this->_notInContents($file['attribs']['name'], 'install');
+                    }
+                }
+            }
+            if (isset($list['ignore'])) {
+                if (!isset($list['ignore'][0])) {
+                    $list['ignore'] = array($list['ignore']);
+                }
+                foreach ($list['ignore'] as $file) {
+                    if (!isset($filelist[$file['attribs']['name']])) {
+                        $this->_notInContents($file['attribs']['name'], 'ignore');
+                    }
+                }
+            }
+        }
+        if (!$allowignore && isset($list['file'])) {
+            if (!isset($list['file'][0])) {
+                // single file
+                $list['file'] = array($list['file']);
+            }
+            foreach ($list['file'] as $i => $file)
+            {
+                if (isset($file['attribs']) && isset($file['attribs']['name']) &&
+                      $file['attribs']['name']{0} == '.' &&
+                        $file['attribs']['name']{1} == '/') {
+                    // name is something like "./doc/whatever.txt"
+                    $this->_invalidFileName($file['attribs']['name']);
+                }
+                if (isset($file['attribs']) && isset($file['attribs']['role'])) {
+                    if (!$this->_validateRole($file['attribs']['role'])) {
+                        if (isset($this->_packageInfo['usesrole'])) {
+                            $roles = $this->_packageInfo['usesrole'];
+                            if (!isset($roles[0])) {
+                                $roles = array($roles);
+                            }
+                            foreach ($roles as $role) {
+                                if ($role['role'] = $file['attribs']['role']) {
+                                    $msg = 'This package contains role "%role%" and requires ' .
+                                        'package "%package%" to be used';
+                                    if (isset($role['uri'])) {
+                                        $params = array('role' => $role['role'],
+                                            'package' => $role['uri']);
+                                    } else {
+                                        $params = array('role' => $role['role'],
+                                            'package' => $this->_pf->_registry->
+                                            parsedPackageNameToString(array('package' =>
+                                                $role['package'], 'channel' => $role['channel']),
+                                                true));
+                                    }
+                                    $this->_stack->push('_mustInstallRole', 'error', $params, $msg);
+                                }
+                            }
+                        }
+                        $this->_invalidFileRole($file['attribs']['name'],
+                            $dirname, $file['attribs']['role']);
+                    }
+                }
+                if (!isset($file['attribs'])) {
+                    continue;
+                }
+                $save = $file['attribs'];
+                if ($dirs) {
+                    $save['name'] = $dirs . '/' . $save['name'];
+                }
+                unset($file['attribs']);
+                if (count($file) && $this->_curState != PEAR_VALIDATE_DOWNLOADING) { // has tasks
+                    foreach ($file as $task => $value) {
+                        if ($tagClass = $this->_pf->getTask($task)) {
+                            if (!is_array($value) || !isset($value[0])) {
+                                $value = array($value);
+                            }
+                            foreach ($value as $v) {
+                                $ret = call_user_func(array($tagClass, 'validateXml'),
+                                    $this->_pf, $v, $this->_pf->_config, $save);
+                                if (is_array($ret)) {
+                                    $this->_invalidTask($task, $ret, @$save['name']);
+                                }
+                            }
+                        } else {
+                            if (isset($this->_packageInfo['usestask'])) {
+                                $roles = $this->_packageInfo['usestask'];
+                                if (!isset($roles[0])) {
+                                    $roles = array($roles);
+                                }
+                                foreach ($roles as $role) {
+                                    if ($role['task'] = $task) {
+                                        $msg = 'This package contains task "%task%" and requires ' .
+                                            'package "%package%" to be used';
+                                        if (isset($role['uri'])) {
+                                            $params = array('task' => $role['task'],
+                                                'package' => $role['uri']);
+                                        } else {
+                                            $params = array('task' => $role['task'],
+                                                'package' => $this->_pf->_registry->
+                                                parsedPackageNameToString(array('package' =>
+                                                    $role['package'], 'channel' => $role['channel']),
+                                                    true));
+                                        }
+                                        $this->_stack->push('_mustInstallTask', 'error',
+                                            $params, $msg);
+                                    }
+                                }
+                            }
+                            $this->_unknownTask($task, $save['name']);
+                        }
+                    }
+                }
+            }
+        }
+        if (isset($list['ignore'])) {
+            if (!$allowignore) {
+                $this->_ignoreNotAllowed('ignore');
+            }
+        }
+        if (isset($list['install'])) {
+            if (!$allowignore) {
+                $this->_ignoreNotAllowed('install');
+            }
+        }
+        if (isset($list['file'])) {
+            if ($allowignore) {
+                $this->_fileNotAllowed('file');
+            }
+        }
+        if (isset($list['dir'])) {
+            if ($allowignore) {
+                $this->_fileNotAllowed('dir');
+            } else {
+                if (!isset($list['dir'][0])) {
+                    $list['dir'] = array($list['dir']);
+                }
+                foreach ($list['dir'] as $dir) {
+                    if (isset($dir['attribs']) && isset($dir['attribs']['name'])) {
+                        if ($dir['attribs']['name'] == '/' ||
+                              !isset($this->_packageInfo['contents']['dir']['dir'])) {
+                            // always use nothing if the filelist has already been flattened
+                            $newdirs = '';
+                        } elseif ($dirs == '') {
+                            $newdirs = $dir['attribs']['name'];
+                        } else {
+                            $newdirs = $dirs . '/' . $dir['attribs']['name'];
+                        }
+                    } else {
+                        $newdirs = $dirs;
+                    }
+                    $this->_validateFilelist($dir, $allowignore, $newdirs);
+                }
+            }
+        }
+    }
+
+    function _validateRelease()
+    {
+        if (isset($this->_packageInfo['phprelease'])) {
+            $release = 'phprelease';
+            if (isset($this->_packageInfo['providesextension'])) {
+                $this->_cannotProvideExtension($release);
+            }
+            if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) {
+                $this->_cannotHaveSrcpackage($release);
+            }
+            $releases = $this->_packageInfo['phprelease'];
+            if (!is_array($releases)) {
+                return true;
+            }
+            if (!isset($releases[0])) {
+                $releases = array($releases);
+            }
+            foreach ($releases as $rel) {
+                $this->_stupidSchemaValidate(array(
+                    '*installconditions',
+                    '*filelist',
+                ), $rel, '<phprelease>');
+            }
+        }
+        if (isset($this->_packageInfo['extsrcrelease'])) {
+            $release = 'extsrcrelease';
+            if (!isset($this->_packageInfo['providesextension'])) {
+                $this->_mustProvideExtension($release);
+            }
+            if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) {
+                $this->_cannotHaveSrcpackage($release);
+            }
+            $releases = $this->_packageInfo['extsrcrelease'];
+            if (!is_array($releases)) {
+                return true;
+            }
+            if (!isset($releases[0])) {
+                $releases = array($releases);
+            }
+            foreach ($releases as $rel) {
+                $this->_stupidSchemaValidate(array(
+                    '*installconditions',
+                    '*configureoption->name->prompt->?default',
+                    '*binarypackage',
+                    '*filelist',
+                ), $rel, '<extsrcrelease>');
+                if (isset($rel['binarypackage'])) {
+                    if (!is_array($rel['binarypackage']) || !isset($rel['binarypackage'][0])) {
+                        $rel['binarypackage'] = array($rel['binarypackage']);
+                    }
+                    foreach ($rel['binarypackage'] as $bin) {
+                        if (!is_string($bin)) {
+                            $this->_binaryPackageMustBePackagename();
+                        }
+                    }
+                }
+            }
+        }
+        if (isset($this->_packageInfo['extbinrelease'])) {
+            $release = 'extbinrelease';
+            if (!isset($this->_packageInfo['providesextension'])) {
+                $this->_mustProvideExtension($release);
+            }
+            if (isset($this->_packageInfo['channel']) &&
+                  !isset($this->_packageInfo['srcpackage'])) {
+                $this->_mustSrcPackage($release);
+            }
+            if (isset($this->_packageInfo['uri']) && !isset($this->_packageInfo['srcuri'])) {
+                $this->_mustSrcuri($release);
+            }
+            $releases = $this->_packageInfo['extbinrelease'];
+            if (!is_array($releases)) {
+                return true;
+            }
+            if (!isset($releases[0])) {
+                $releases = array($releases);
+            }
+            foreach ($releases as $rel) {
+                $this->_stupidSchemaValidate(array(
+                    '*installconditions',
+                    '*filelist',
+                ), $rel, '<extbinrelease>');
+            }
+        }
+        if (isset($this->_packageInfo['bundle'])) {
+            $release = 'bundle';
+            if (isset($this->_packageInfo['providesextension'])) {
+                $this->_cannotProvideExtension($release);
+            }
+            if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) {
+                $this->_cannotHaveSrcpackage($release);
+            }
+            $releases = $this->_packageInfo['bundle'];
+            if (!is_array($releases) || !isset($releases[0])) {
+                $releases = array($releases);
+            }
+            foreach ($releases as $rel) {
+                $this->_stupidSchemaValidate(array(
+                    '*installconditions',
+                    '*filelist',
+                ), $rel, '<bundle>');
+            }
+        }
+        foreach ($releases as $rel) {
+            if (is_array($rel) && array_key_exists('installconditions', $rel)) {
+                $this->_validateInstallConditions($rel['installconditions'],
+                    "<$release><installconditions>");
+            }
+            if (is_array($rel) && array_key_exists('filelist', $rel)) {
+                if ($rel['filelist']) {
+                    
+                    $this->_validateFilelist($rel['filelist'], true);
+                }
+            }
+        }
+    }
+
+    /**
+     * This is here to allow role extension through plugins
+     * @param string
+     */
+    function _validateRole($role)
+    {
+        return in_array($role, PEAR_Installer_Role::getValidRoles($this->_pf->getPackageType()));
+    }
+
+    function _invalidTagOrder($oktags, $actual, $root)
+    {
+        $this->_stack->push(__FUNCTION__, 'error',
+            array('oktags' => $oktags, 'actual' => $actual, 'root' => $root),
+            'Invalid tag order in %root%, found <%actual%> expected one of "%oktags%"');
+    }
+
+    function _ignoreNotAllowed($type)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('type' => $type),
+            '<%type%> is not allowed inside global <contents>, only inside ' .
+            '<phprelease>/<extbinrelease>, use <dir> and <file> only');
+    }
+
+    function _fileNotAllowed($type)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('type' => $type),
+            '<%type%> is not allowed inside release <filelist>, only inside ' .
+            '<contents>, use <ignore> and <install> only');
+    }
+
+    function _tagMissingAttribute($tag, $attr, $context)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag,
+            'attribute' => $attr, 'context' => $context),
+            'tag <%tag%> in context "%context%" has no attribute "%attribute%"');
+    }
+
+    function _tagHasNoAttribs($tag, $context)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag,
+            'context' => $context),
+            'tag <%tag%> has no attributes in context "%context%"');
+    }
+
+    function _invalidInternalStructure()
+    {
+        $this->_stack->push(__FUNCTION__, 'exception', array(),
+            'internal array was not generated by compatible parser, or extreme parser error, cannot continue');
+    }
+
+    function _invalidFileRole($file, $dir, $role)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array(
+            'file' => $file, 'dir' => $dir, 'role' => $role,
+            'roles' => PEAR_Installer_Role::getValidRoles($this->_pf->getPackageType())),
+            'File "%file%" in directory "%dir%" has invalid role "%role%", should be one of %roles%');
+    }
+
+    function _invalidFileName($file, $dir)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array(
+            'file' => $file),
+            'File "%file%" cannot begin with "."');
+    }
+
+    function _filelistCannotContainFile($filelist)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('tag' => $filelist),
+            '<%tag%> can only contain <dir>, contains <file>.  Use ' .
+            '<dir name="/"> as the first dir element');
+    }
+
+    function _filelistMustContainDir($filelist)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('tag' => $filelist),
+            '<%tag%> must contain <dir>.  Use <dir name="/"> as the ' .
+            'first dir element');
+    }
+
+    function _tagCannotBeEmpty($tag)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag),
+            '<%tag%> cannot be empty (<%tag%/>)');
+    }
+
+    function _UrlOrChannel($type, $name)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('type' => $type,
+            'name' => $name),
+            'Required dependency <%type%> "%name%" can have either url OR ' .
+            'channel attributes, and not both');
+    }
+
+    function _NoChannel($type, $name)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('type' => $type,
+            'name' => $name),
+            'Required dependency <%type%> "%name%" must have either url OR ' .
+            'channel attributes');
+    }
+
+    function _UrlOrChannelGroup($type, $name, $group)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('type' => $type,
+            'name' => $name, 'group' => $group),
+            'Group "%group%" dependency <%type%> "%name%" can have either url OR ' .
+            'channel attributes, and not both');
+    }
+
+    function _NoChannelGroup($type, $name, $group)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('type' => $type,
+            'name' => $name, 'group' => $group),
+            'Group "%group%" dependency <%type%> "%name%" must have either url OR ' .
+            'channel attributes');
+    }
+
+    function _unknownChannel($channel)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('channel' => $channel),
+            'Unknown channel "%channel%"');
+    }
+
+    function _noPackageVersion()
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array(),
+            'package.xml <package> tag has no version attribute, or version is not 2.0');
+    }
+
+    function _NoBundledPackages()
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array(),
+            'No <bundledpackage> tag was found in <contents>, required for bundle packages');
+    }
+
+    function _AtLeast2BundledPackages()
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array(),
+            'At least 2 packages must be bundled in a bundle package');
+    }
+
+    function _ChannelOrUri($name)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('name' => $name),
+            'Bundled package "%name%" can have either a uri or a channel, not both');
+    }
+
+    function _noChildTag($child, $tag)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('child' => $child, 'tag' => $tag),
+            'Tag <%tag%> is missing child tag <%child%>');
+    }
+
+    function _invalidVersion($type, $value)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, 'value' => $value),
+            'Version type <%type%> is not a valid version (%value%)');
+    }
+
+    function _invalidState($type, $value)
+    {
+        $states = array('stable', 'beta', 'alpha', 'devel');
+        if ($type != 'api') {
+            $states[] = 'snapshot';
+        }
+        if (strtolower($value) == 'rc') {
+            $this->_stack->push(__FUNCTION__, 'error',
+                array('version' => $this->_packageInfo['version']['release']),
+                'RC is not a state, it is a version postfix, try %version%RC1, stability beta');
+        }
+        $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, 'value' => $value,
+            'types' => $states),
+            'Stability type <%type%> is not a valid stability (%value%), must be one of ' .
+            '%types%');
+    }
+
+    function _invalidTask($task, $ret, $file)
+    {
+        switch ($ret[0]) {
+            case PEAR_TASK_ERROR_MISSING_ATTRIB :
+                $info = array('attrib' => $ret[1], 'task' => $task, 'file' => $file);
+                $msg = 'task <%task%> is missing attribute "%attrib%" in file %file%';
+            break;
+            case PEAR_TASK_ERROR_NOATTRIBS :
+                $info = array('task' => $task, 'file' => $file);
+                $msg = 'task <%task%> has no attributes in file %file%';
+            break;
+            case PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE :
+                $info = array('attrib' => $ret[1], 'values' => $ret[3],
+                    'was' => $ret[2], 'task' => $task, 'file' => $file);
+                $msg = 'task <%task%> attribute "%attrib%" has the wrong value "%was%" '.
+                    'in file %file%, expecting one of "%values%"';
+            break;
+            case PEAR_TASK_ERROR_INVALID :
+                $info = array('reason' => $ret[1], 'task' => $task, 'file' => $file);
+                $msg = 'task <%task%> in file %file% is invalid because of "%reason%"';
+            break;
+        }
+        $this->_stack->push(__FUNCTION__, 'error', $info, $msg);
+    }
+
+    function _unknownTask($task, $file)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('task' => $task, 'file' => $file),
+            'Unknown task "%task%" passed in file <file name="%file%">');
+    }
+
+    function _subpackageCannotProvideExtension($name)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('name' => $name),
+            'Subpackage dependency "%name%" cannot use <providesextension>, ' .
+            'only package dependencies can use this tag');
+    }
+
+    function _subpackagesCannotConflict($name)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('name' => $name),
+            'Subpackage dependency "%name%" cannot use <conflicts/>, ' .
+            'only package dependencies can use this tag');
+    }
+
+    function _cannotProvideExtension($release)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('release' => $release),
+            '<%release%> packages cannot use <providesextension>, only extbinrelease and extsrcrelease can provide a PHP extension');
+    }
+
+    function _mustProvideExtension($release)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('release' => $release),
+            '<%release%> packages must use <providesextension> to indicate which PHP extension is provided');
+    }
+
+    function _cannotHaveSrcpackage($release)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('release' => $release),
+            '<%release%> packages cannot specify a source code package, only extension binaries may use the <srcpackage> tag');
+    }
+
+    function _mustSrcPackage($release)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('release' => $release),
+            '<extbinrelease> packages must specify a source code package with <srcpackage>');
+    }
+
+    function _mustSrcuri($release)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('release' => $release),
+            '<extbinrelease> packages must specify a source code package with <srcuri>');
+    }
+
+    function _uriDepsCannotHaveVersioning($type)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('type' => $type),
+            '%type%: dependencies with a <uri> tag cannot have any versioning information');
+    }
+
+    function _conflictingDepsCannotHaveVersioning($type)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('type' => $type),
+            '%type%: conflicting dependencies cannot have versioning info, use <exclude> to ' .
+            'exclude specific versions of a dependency');
+    }
+
+    function _DepchannelCannotBeUri($type)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('type' => $type),
+            '%type%: channel cannot be __uri, this is a pseudo-channel reserved for uri ' .
+            'dependencies only');
+    }
+
+    function _bundledPackagesMustBeFilename()
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array(),
+            '<bundledpackage> tags must contain only the filename of a package release ' .
+            'in the bundle');
+    }
+
+    function _binaryPackageMustBePackagename()
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array(),
+            '<binarypackage> tags must contain the name of a package that is ' .
+            'a compiled version of this extsrc package');
+    }
+
+    function _fileNotFound($file)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('file' => $file),
+            'File "%file%" in package.xml does not exist');
+    }
+
+    function _notInContents($file, $tag)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('file' => $file, 'tag' => $tag),
+            '<%tag% name="%file%"> is invalid, file is not in <contents>');
+    }
+
+    function _cannotValidateNoPathSet()
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array(),
+            'Cannot validate files, no path to package file is set (use setPackageFile())');
+    }
+
+    function _usesroletaskMustHaveChannelOrUri($role, $tag)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('role' => $role, 'tag' => $tag),
+            '<%tag%> must contain either <uri>, or <channel> and <package>');
+    }
+
+    function _usesroletaskMustHavePackage($role, $tag)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('role' => $role, 'tag' => $tag),
+            '<%tag%> must contain <package>');
+    }
+
+    function _usesroletaskMustHaveRoleTask($tag, $type)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag, 'type' => $type),
+            '<%tag%> must contain <%type%> defining the %type% to be used');
+    }
+
+    function _cannotConflictWithAllOs($type)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag),
+            '%tag% cannot conflict with all OSes');
+    }
+
+    function _invalidDepGroupName($name)
+    {
+        $this->_stack->push(__FUNCTION__, 'error', array('group' => $name),
+            'Invalid dependency group name "%name%"');
+    }
+
+    function _analyzeBundledPackages()
+    {
+        if (!$this->_isValid) {
+            return false;
+        }
+        if (!$this->_pf->getPackageType() == 'bundle') {
+            return false;
+        }
+        if (!isset($this->_pf->_packageFile)) {
+            return false;
+        }
+        $dir_prefix = dirname($this->_pf->_packageFile);
+        $log = isset($this->_pf->_logger) ? array(&$this->_pf->_logger, 'log') :
+            array('PEAR_Common', 'log');
+        $info = $this->_pf->getContents();
+        $info = $info['bundledpackage'];
+        if (!is_array($info)) {
+            $info = array($info);
+        }
+        $pkg = &new PEAR_PackageFile($this->_pf->_config);
+        foreach ($info as $package) {
+            if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $package)) {
+                $this->_fileNotFound($dir_prefix . DIRECTORY_SEPARATOR . $package);
+                $this->_isValid = 0;
+                continue;
+            }
+            call_user_func_array($log, array(1, "Analyzing bundled package $package"));
+            PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+            $ret = $pkg->fromAnyFile($dir_prefix . DIRECTORY_SEPARATOR . $package,
+                PEAR_VALIDATE_NORMAL);
+            PEAR::popErrorHandling();
+            if (PEAR::isError($ret)) {
+                call_user_func_array($log, array(0, "ERROR: package $package is not a valid " .
+                    'package'));
+                $inf = $ret->getUserInfo();
+                if (is_array($inf)) {
+                    foreach ($inf as $err) {
+                        call_user_func_array($log, array(1, $err['message']));
+                    }
+                }
+                return false;
+            }
+        }
+        return true;
+    }
+
+    function _analyzePhpFiles()
+    {
+        if (!$this->_isValid) {
+            return false;
+        }
+        if (!isset($this->_pf->_packageFile)) {
+            $this->_cannotValidateNoPathSet();
+            return false;
+        }
+        $dir_prefix = dirname($this->_pf->_packageFile);
+        $common = new PEAR_Common;
+        $log = isset($this->_pf->_logger) ? array(&$this->_pf->_logger, 'log') :
+            array(&$common, 'log');
+        $info = $this->_pf->getContents();
+        $info = $info['dir']['file'];
+        if (isset($info['attribs'])) {
+            $info = array($info);
+        }
+        $provides = array();
+        foreach ($info as $fa) {
+            $fa = $fa['attribs'];
+            $file = $fa['name'];
+            if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $file)) {
+                $this->_fileNotFound($dir_prefix . DIRECTORY_SEPARATOR . $file);
+                $this->_isValid = 0;
+                continue;
+            }
+            if (in_array($fa['role'], PEAR_Installer_Role::getPhpRoles()) && $dir_prefix) {
+                call_user_func_array($log, array(1, "Analyzing $file"));
+                $srcinfo = $this->analyzeSourceCode($dir_prefix . DIRECTORY_SEPARATOR . $file);
+                if ($srcinfo) {
+                    $provides = array_merge($provides, $this->_buildProvidesArray($srcinfo));
+                }
+            }
+        }
+        $this->_packageName = $pn = $this->_pf->getPackage();
+        $pnl = strlen($pn);
+        foreach ($provides as $key => $what) {
+            if (isset($what['explicit']) || !$what) {
+                // skip conformance checks if the provides entry is
+                // specified in the package.xml file
+                continue;
+            }
+            extract($what);
+            if ($type == 'class') {
+                if (!strncasecmp($name, $pn, $pnl)) {
+                    continue;
+                }
+                $this->_stack->push(__FUNCTION__, 'warning',
+                    array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn),
+                    'in %file%: %type% "%name%" not prefixed with package name "%package%"');
+            } elseif ($type == 'function') {
+                if (strstr($name, '::') || !strncasecmp($name, $pn, $pnl)) {
+                    continue;
+                }
+                $this->_stack->push(__FUNCTION__, 'warning',
+                    array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn),
+                    'in %file%: %type% "%name%" not prefixed with package name "%package%"');
+            }
+        }
+        return $this->_isValid;
+    }
+
+    /**
+     * Analyze the source code of the given PHP file
+     *
+     * @param  string Filename of the PHP file
+     * @param  boolean whether to analyze $file as the file contents
+     * @return mixed
+     */
+    function analyzeSourceCode($file, $string = false)
+    {
+        if (!function_exists("token_get_all")) {
+            return false;
+        }
+        if (!defined('T_DOC_COMMENT')) {
+            define('T_DOC_COMMENT', T_COMMENT);
+        }
+        if (!defined('T_INTERFACE')) {
+            define('T_INTERFACE', -1);
+        }
+        if (!defined('T_IMPLEMENTS')) {
+            define('T_IMPLEMENTS', -1);
+        }
+        if ($string) {
+            $contents = $file;
+        } else {
+            if (!$fp = @fopen($file, "r")) {
+                return false;
+            }
+            if (function_exists('file_get_contents')) {
+                fclose($fp);
+                $contents = file_get_contents($file);
+            } else {
+                $contents = @fread($fp, filesize($file));
+                fclose($fp);
+            }
+        }
+        $tokens = token_get_all($contents);
+/*
+        for ($i = 0; $i < sizeof($tokens); $i++) {
+            @list($token, $data) = $tokens[$i];
+            if (is_string($token)) {
+                var_dump($token);
+            } else {
+                print token_name($token) . ' ';
+                var_dump(rtrim($data));
+            }
+        }
+*/
+        $look_for = 0;
+        $paren_level = 0;
+        $bracket_level = 0;
+        $brace_level = 0;
+        $lastphpdoc = '';
+        $current_class = '';
+        $current_interface = '';
+        $current_class_level = -1;
+        $current_function = '';
+        $current_function_level = -1;
+        $declared_classes = array();
+        $declared_interfaces = array();
+        $declared_functions = array();
+        $declared_methods = array();
+        $used_classes = array();
+        $used_functions = array();
+        $extends = array();
+        $implements = array();
+        $nodeps = array();
+        $inquote = false;
+        $interface = false;
+        for ($i = 0; $i < sizeof($tokens); $i++) {
+            if (is_array($tokens[$i])) {
+                list($token, $data) = $tokens[$i];
+            } else {
+                $token = $tokens[$i];
+                $data = '';
+            }
+            if ($inquote) {
+                if ($token != '"' && $token != T_END_HEREDOC) {
+                    continue;
+                } else {
+                    $inquote = false;
+                    continue;
+                }
+            }
+            switch ($token) {
+                case T_WHITESPACE :
+                    continue;
+                case ';':
+                    if ($interface) {
+                        $current_function = '';
+                        $current_function_level = -1;
+                    }
+                    break;
+                case '"':
+                case T_START_HEREDOC:
+                    $inquote = true;
+                    break;
+                case T_CURLY_OPEN:
+                case T_DOLLAR_OPEN_CURLY_BRACES:
+                case '{': $brace_level++; continue 2;
+                case '}':
+                    $brace_level--;
+                    if ($current_class_level == $brace_level) {
+                        $current_class = '';
+                        $current_class_level = -1;
+                    }
+                    if ($current_function_level == $brace_level) {
+                        $current_function = '';
+                        $current_function_level = -1;
+                    }
+                    continue 2;
+                case '[': $bracket_level++; continue 2;
+                case ']': $bracket_level--; continue 2;
+                case '(': $paren_level++;   continue 2;
+                case ')': $paren_level--;   continue 2;
+                case T_INTERFACE:
+                    $interface = true;
+                case T_CLASS:
+                    if (($current_class_level != -1) || ($current_function_level != -1)) {
+                        $this->_stack->push(__FUNCTION__, 'error', array('file' => $file),
+                        'Parser error: invalid PHP found in file "%file%"');
+                        return false;
+                    }
+                case T_FUNCTION:
+                case T_NEW:
+                case T_EXTENDS:
+                case T_IMPLEMENTS:
+                    $look_for = $token;
+                    continue 2;
+                case T_STRING:
+                    if (version_compare(zend_version(), '2.0', '<')) {
+                        if (in_array(strtolower($data),
+                            array('public', 'private', 'protected', 'abstract',
+                                  'interface', 'implements', 'throw') 
+                                 )) {
+                            $this->_stack->push(__FUNCTION__, 'warning', array(
+                                'file' => $file),
+                                'Error, PHP5 token encountered in %file%,' .
+                                ' analysis should be in PHP5');
+                        }
+                    }
+                    if ($look_for == T_CLASS) {
+                        $current_class = $data;
+                        $current_class_level = $brace_level;
+                        $declared_classes[] = $current_class;
+                    } elseif ($look_for == T_INTERFACE) {
+                        $current_interface = $data;
+                        $current_class_level = $brace_level;
+                        $declared_interfaces[] = $current_interface;
+                    } elseif ($look_for == T_IMPLEMENTS) {
+                        $implements[$current_class] = $data;
+                    } elseif ($look_for == T_EXTENDS) {
+                        $extends[$current_class] = $data;
+                    } elseif ($look_for == T_FUNCTION) {
+                        if ($current_class) {
+                            $current_function = "$current_class::$data";
+                            $declared_methods[$current_class][] = $data;
+                        } elseif ($current_interface) {
+                            $current_function = "$current_interface::$data";
+                            $declared_methods[$current_interface][] = $data;
+                        } else {
+                            $current_function = $data;
+                            $declared_functions[] = $current_function;
+                        }
+                        $current_function_level = $brace_level;
+                        $m = array();
+                    } elseif ($look_for == T_NEW) {
+                        $used_classes[$data] = true;
+                    }
+                    $look_for = 0;
+                    continue 2;
+                case T_VARIABLE:
+                    $look_for = 0;
+                    continue 2;
+                case T_DOC_COMMENT:
+                case T_COMMENT:
+                    if (preg_match('!^/\*\*\s!', $data)) {
+                        $lastphpdoc = $data;
+                        if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) {
+                            $nodeps = array_merge($nodeps, $m[1]);
+                        }
+                    }
+                    continue 2;
+                case T_DOUBLE_COLON:
+                    if (!($tokens[$i - 1][0] == T_WHITESPACE || $tokens[$i - 1][0] == T_STRING)) {
+                        $this->_stack->push(__FUNCTION__, 'warning', array('file' => $file),
+                            'Parser error: invalid PHP found in file "%file%"');
+                        return false;
+                    }
+                    $class = $tokens[$i - 1][1];
+                    if (strtolower($class) != 'parent') {
+                        $used_classes[$class] = true;
+                    }
+                    continue 2;
+            }
+        }
+        return array(
+            "source_file" => $file,
+            "declared_classes" => $declared_classes,
+            "declared_interfaces" => $declared_interfaces,
+            "declared_methods" => $declared_methods,
+            "declared_functions" => $declared_functions,
+            "used_classes" => array_diff(array_keys($used_classes), $nodeps),
+            "inheritance" => $extends,
+            "implements" => $implements,
+            );
+    }
+
+    /**
+     * Build a "provides" array from data returned by
+     * analyzeSourceCode().  The format of the built array is like
+     * this:
+     *
+     *  array(
+     *    'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'),
+     *    ...
+     *  )
+     *
+     *
+     * @param array $srcinfo array with information about a source file
+     * as returned by the analyzeSourceCode() method.
+     *
+     * @return void
+     *
+     * @access private
+     *
+     */
+    function _buildProvidesArray($srcinfo)
+    {
+        if (!$this->_isValid) {
+            return array();
+        }
+        $providesret = array();
+        $file = basename($srcinfo['source_file']);
+        $pn = $this->_pf->getPackage();
+        $pnl = strlen($pn);
+        foreach ($srcinfo['declared_classes'] as $class) {
+            $key = "class;$class";
+            if (isset($providesret[$key])) {
+                continue;
+            }
+            $providesret[$key] =
+                array('file'=> $file, 'type' => 'class', 'name' => $class);
+            if (isset($srcinfo['inheritance'][$class])) {
+                $providesret[$key]['extends'] =
+                    $srcinfo['inheritance'][$class];
+            }
+        }
+        foreach ($srcinfo['declared_methods'] as $class => $methods) {
+            foreach ($methods as $method) {
+                $function = "$class::$method";
+                $key = "function;$function";
+                if ($method{0} == '_' || !strcasecmp($method, $class) ||
+                    isset($providesret[$key])) {
+                    continue;
+                }
+                $providesret[$key] =
+                    array('file'=> $file, 'type' => 'function', 'name' => $function);
+            }
+        }
+
+        foreach ($srcinfo['declared_functions'] as $function) {
+            $key = "function;$function";
+            if ($function{0} == '_' || isset($providesret[$key])) {
+                continue;
+            }
+            if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) {
+                $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\"";
+            }
+            $providesret[$key] =
+                array('file'=> $file, 'type' => 'function', 'name' => $function);
+        }
+        return $providesret;
+    }
+}
+?>
\ No newline at end of file
diff --git a/pear/PEAR/PackageFile/v2/rw.php b/pear/PEAR/PackageFile/v2/rw.php
new file mode 100644 (file)
index 0000000..8bb9ed1
--- /dev/null
@@ -0,0 +1,1557 @@
+<?php
+/**
+ * PEAR_PackageFile_v2, package.xml version 2.0, read/write version
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a8
+ */
+/**
+ * For base class
+ */
+require_once 'PEAR/PackageFile/v2.php';
+/**
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a8
+ */
+class PEAR_PackageFile_v2_rw extends PEAR_PackageFile_v2
+{
+    /**
+     * @param string Extension name
+     * @return bool success of operation
+     */
+    function setProvidesExtension($extension)
+    {
+        if (in_array($this->getPackageType(), array('extsrc', 'extbin'))) {
+            if (!isset($this->_packageInfo['providesextension'])) {
+                // ensure that the channel tag is set up in the right location
+                $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
+                    array('usesrole', 'usestask', 'srcpackage', 'srcuri', 'phprelease',
+                    'extsrcrelease', 'extbinrelease', 'bundle', 'changelog'),
+                    $extension, 'providesextension');
+            }
+            $this->_packageInfo['providesextension'] = $extension;
+            return true;
+        }
+        return false;
+    }
+
+    function setPackage($package)
+    {
+        $this->_isValid = 0;
+        if (!isset($this->_packageInfo['attribs'])) {
+            $this->_packageInfo = array_merge(array('attribs' => array(
+                                 'version' => '2.0',
+                                 'xmlns' => 'http://pear.php.net/dtd/package-2.0',
+                                 'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0',
+                                 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
+                                 'xsi:schemaLocation' => 'http://pear.php.net/dtd/tasks-1.0
+    http://pear.php.net/dtd/tasks-1.0.xsd
+    http://pear.php.net/dtd/package-2.0
+    http://pear.php.net/dtd/package-2.0.xsd',
+                             )), $this->_packageInfo);
+        }
+        if (!isset($this->_packageInfo['name'])) {
+            return $this->_packageInfo = array_merge(array('name' => $package),
+                $this->_packageInfo);
+        }
+        $this->_packageInfo['name'] = $package;
+    }
+
+    function setUri($uri)
+    {
+        unset($this->_packageInfo['channel']);
+        $this->_isValid = 0;
+        if (!isset($this->_packageInfo['uri'])) {
+            // ensure that the uri tag is set up in the right location
+            $this->_packageInfo = $this->_insertBefore($this->_packageInfo, 
+                array('extends', 'summary', 'description', 'lead',
+                'developer', 'contributor', 'helper', 'date', 'time', 'version',
+                'stability', 'license', 'notes', 'contents', 'compatible',
+                'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
+                'phprelease', 'extsrcrelease',
+                'extbinrelease', 'bundle', 'changelog'), $uri, 'uri');
+        }
+        $this->_packageInfo['uri'] = $uri;
+    }
+
+    function setChannel($channel)
+    {
+        unset($this->_packageInfo['uri']);
+        $this->_isValid = 0;
+        if (!isset($this->_packageInfo['channel'])) {
+            // ensure that the channel tag is set up in the right location
+            $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
+                array('extends', 'summary', 'description', 'lead',
+                'developer', 'contributor', 'helper', 'date', 'time', 'version',
+                'stability', 'license', 'notes', 'contents', 'compatible',
+                'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
+                'phprelease', 'extsrcrelease',
+                'extbinrelease', 'bundle', 'changelog'), $channel, 'channel');
+        }
+        $this->_packageInfo['channel'] = $channel;
+    }
+
+    function setExtends($extends)
+    {
+        $this->_isValid = 0;
+        if (!isset($this->_packageInfo['extends'])) {
+            // ensure that the extends tag is set up in the right location
+            $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
+                array('summary', 'description', 'lead',
+                'developer', 'contributor', 'helper', 'date', 'time', 'version',
+                'stability', 'license', 'notes', 'contents', 'compatible',
+                'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
+                'phprelease', 'extsrcrelease',
+                'extbinrelease', 'bundle', 'changelog'), $extends, 'extends');
+        }
+        $this->_packageInfo['extends'] = $extends;
+    }
+
+    function setSummary($summary)
+    {
+        $this->_isValid = 0;
+        if (!isset($this->_packageInfo['summary'])) {
+            // ensure that the summary tag is set up in the right location
+            $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
+                array('description', 'lead',
+                'developer', 'contributor', 'helper', 'date', 'time', 'version',
+                'stability', 'license', 'notes', 'contents', 'compatible',
+                'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
+                'phprelease', 'extsrcrelease',
+                'extbinrelease', 'bundle', 'changelog'), $summary, 'summary');
+        }
+        $this->_packageInfo['summary'] = $summary;
+    }
+
+    function setDescription($desc)
+    {
+        $this->_isValid = 0;
+        if (!isset($this->_packageInfo['description'])) {
+            // ensure that the description tag is set up in the right location
+            $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
+                array('lead',
+                'developer', 'contributor', 'helper', 'date', 'time', 'version',
+                'stability', 'license', 'notes', 'contents', 'compatible',
+                'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
+                'phprelease', 'extsrcrelease',
+                'extbinrelease', 'bundle', 'changelog'), $desc, 'description');
+        }
+        $this->_packageInfo['description'] = $desc;
+    }
+
+    /**
+     * Adds a new maintainer - no checking of duplicates is performed, use
+     * updatemaintainer for that purpose.
+     */
+    function addMaintainer($role, $handle, $name, $email, $active = 'yes')
+    {
+        if (!in_array($role, array('lead', 'developer', 'contributor', 'helper'))) {
+            return false;
+        }
+        if (isset($this->_packageInfo[$role])) {
+            if (!isset($this->_packageInfo[$role][0])) {
+                $this->_packageInfo[$role] = array($this->_packageInfo[$role]);
+            }
+            $this->_packageInfo[$role][] =
+                array(
+                    'name' => $name,
+                    'user' => $handle,
+                    'email' => $email,
+                    'active' => $active,
+                );
+        } else {
+            $testarr = array('lead',
+                    'developer', 'contributor', 'helper', 'date', 'time', 'version',
+                    'stability', 'license', 'notes', 'contents', 'compatible',
+                    'dependencies', 'providesextension', 'usesrole', 'usestask',
+                    'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease',
+                    'extbinrelease', 'bundle', 'changelog');
+            foreach (array('lead', 'developer', 'contributor', 'helper') as $testrole) {
+                array_shift($testarr);
+                if ($role == $testrole) {
+                    break;
+                }
+            }
+            if (!isset($this->_packageInfo[$role])) {
+                // ensure that the extends tag is set up in the right location
+                $this->_packageInfo = $this->_insertBefore($this->_packageInfo, $testarr,
+                    array(), $role);
+            }
+            $this->_packageInfo[$role] =
+                array(
+                    'name' => $name,
+                    'user' => $handle,
+                    'email' => $email,
+                    'active' => $active,
+                );
+        }
+        $this->_isValid = 0;
+    }
+
+    function updateMaintainer($newrole, $handle, $name, $email, $active = 'yes')
+    {
+        $found = false;
+        foreach (array('lead', 'developer', 'contributor', 'helper') as $role) {
+            if (!isset($this->_packageInfo[$role])) {
+                continue;
+            }
+            $info = $this->_packageInfo[$role];
+            if (!isset($info[0])) {
+                if ($info['user'] == $handle) {
+                    $found = true;
+                    break;
+                }
+            }
+            foreach ($info as $i => $maintainer) {
+                if ($maintainer['user'] == $handle) {
+                    $found = $i;
+                    break 2;
+                }
+            }
+        }
+        if ($found === false) {
+            return $this->addMaintainer($newrole, $handle, $name, $email, $active);
+        }
+        if ($found !== false) {
+            if ($found === true) {
+                unset($this->_packageInfo[$role]);
+            } else {
+                unset($this->_packageInfo[$role][$found]);
+                $this->_packageInfo[$role] = array_values($this->_packageInfo[$role]);
+            }
+        }
+        $this->addMaintainer($newrole, $handle, $name, $email);
+        $this->_isValid = 0;
+    }
+
+    function deleteMaintainer($handle)
+    {
+        $found = false;
+        foreach (array('lead', 'developer', 'contributor', 'helper') as $role) {
+            if (!isset($this->_packageInfo[$role])) {
+                continue;
+            }
+            if (!isset($this->_packageInfo[$role][0])) {
+                $this->_packageInfo[$role] = array($this->_packageInfo[$role]);
+            }
+            foreach ($this->_packageInfo[$role] as $i => $maintainer) {
+                if ($maintainer['user'] == $handle) {
+                    $found = $i;
+                    break;
+                }
+            }
+            if ($found !== false) {
+                unset($this->_packageInfo[$role][$found]);
+                if (!count($this->_packageInfo[$role]) && $role == 'lead') {
+                    $this->_isValid = 0;
+                }
+                if (!count($this->_packageInfo[$role])) {
+                    unset($this->_packageInfo[$role]);
+                    return true;
+                }
+                $this->_packageInfo[$role] =
+                    array_values($this->_packageInfo[$role]);
+                if (count($this->_packageInfo[$role]) == 1) {
+                    $this->_packageInfo[$role] = $this->_packageInfo[$role][0];
+                }
+                return true;
+            }
+            if (count($this->_packageInfo[$role]) == 1) {
+                $this->_packageInfo[$role] = $this->_packageInfo[$role][0];
+            }
+        }
+        return false;
+    }
+
+    function setReleaseVersion($version)
+    {
+        if (isset($this->_packageInfo['version']) &&
+              isset($this->_packageInfo['version']['release'])) {
+            unset($this->_packageInfo['version']['release']);
+        }
+        $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $version, array(
+            'version' => array('stability', 'license', 'notes', 'contents', 'compatible',
+                'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
+                'phprelease', 'extsrcrelease',
+                'extbinrelease', 'bundle', 'changelog'),
+            'release' => array('api')));
+        $this->_isValid = 0;
+    }
+
+    function setAPIVersion($version)
+    {
+        if (isset($this->_packageInfo['version']) &&
+              isset($this->_packageInfo['version']['api'])) {
+            unset($this->_packageInfo['version']['api']);
+        }
+        $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $version, array(
+            'version' => array('stability', 'license', 'notes', 'contents', 'compatible',
+                'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
+                'phprelease', 'extsrcrelease',
+                'extbinrelease', 'bundle', 'changelog'),
+            'api' => array()));
+        $this->_isValid = 0;
+    }
+
+    /**
+     * snapshot|devel|alpha|beta|stable
+     */
+    function setReleaseStability($state)
+    {
+        if (isset($this->_packageInfo['stability']) &&
+              isset($this->_packageInfo['stability']['release'])) {
+            unset($this->_packageInfo['stability']['release']);
+        }
+        $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $state, array(
+            'stability' => array('license', 'notes', 'contents', 'compatible',
+                'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
+                'phprelease', 'extsrcrelease',
+                'extbinrelease', 'bundle', 'changelog'),
+            'release' => array('api')));
+        $this->_isValid = 0;
+    }
+
+    /**
+     * @param devel|alpha|beta|stable
+     */
+    function setAPIStability($state)
+    {
+        if (isset($this->_packageInfo['stability']) &&
+              isset($this->_packageInfo['stability']['api'])) {
+            unset($this->_packageInfo['stability']['api']);
+        }
+        $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $state, array(
+            'stability' => array('license', 'notes', 'contents', 'compatible',
+                'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
+                'phprelease', 'extsrcrelease',
+                'extbinrelease', 'bundle', 'changelog'),
+            'api' => array()));
+        $this->_isValid = 0;
+    }
+
+    function setLicense($license, $uri = false, $filesource = false)
+    {
+        if (!isset($this->_packageInfo['license'])) {
+            // ensure that the license tag is set up in the right location
+            $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
+                array('notes', 'contents', 'compatible',
+                'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
+                'phprelease', 'extsrcrelease',
+                'extbinrelease', 'bundle', 'changelog'), 0, 'license');
+        }
+        if ($uri || $filesource) {
+            $attribs = array();
+            if ($uri) {
+                $attribs['uri'] = $uri;
+            }
+            $uri = true; // for test below
+            if ($filesource) {
+                $attribs['filesource'] = $filesource;
+            }
+        }
+        $license = $uri ? array('attribs' => $attribs, '_content' => $license) : $license;
+        $this->_packageInfo['license'] = $license;
+        $this->_isValid = 0;
+    }
+
+    function setNotes($notes)
+    {
+        $this->_isValid = 0;
+        if (!isset($this->_packageInfo['notes'])) {
+            // ensure that the notes tag is set up in the right location
+            $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
+                array('contents', 'compatible',
+                'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
+                'phprelease', 'extsrcrelease',
+                'extbinrelease', 'bundle', 'changelog'), $notes, 'notes');
+        }
+        $this->_packageInfo['notes'] = $notes;
+    }
+
+    /**
+     * This is only used at install-time, after all serialization
+     * is over.
+     * @param string file name
+     * @param string installed path
+     */
+    function setInstalledAs($file, $path)
+    {
+        if ($path) {
+            return $this->_packageInfo['filelist'][$file]['installed_as'] = $path;
+        }
+        unset($this->_packageInfo['filelist'][$file]['installed_as']);
+    }
+
+    /**
+     * This is only used at install-time, after all serialization
+     * is over.
+     */
+    function installedFile($file, $atts)
+    {
+        if (isset($this->_packageInfo['filelist'][$file])) {
+            $this->_packageInfo['filelist'][$file] =
+                array_merge($this->_packageInfo['filelist'][$file], $atts['attribs']);
+        } else {
+            $this->_packageInfo['filelist'][$file] = $atts['attribs'];
+        }
+    }
+
+    /**
+     * Reset the listing of package contents
+     * @param string base installation dir for the whole package, if any
+     */
+    function clearContents($baseinstall = false)
+    {
+        $this->_filesValid = false;
+        $this->_isValid = 0;
+        if (!isset($this->_packageInfo['contents'])) {
+            $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
+                array('compatible',
+                    'dependencies', 'providesextension', 'usesrole', 'usestask',
+                    'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease',
+                    'extbinrelease', 'bundle', 'changelog'), array(), 'contents');
+        }
+        if ($this->getPackageType() != 'bundle') {
+            $this->_packageInfo['contents'] = 
+                array('dir' => array('attribs' => array('name' => '/')));
+            if ($baseinstall) {
+                $this->_packageInfo['contents']['dir']['attribs']['baseinstalldir'] = $baseinstall;
+            }
+        }
+    }
+
+    /**
+     * @param string relative path of the bundled package.
+     */
+    function addBundledPackage($path)
+    {
+        if ($this->getPackageType() != 'bundle') {
+            return false;
+        }
+        $this->_filesValid = false;
+        $this->_isValid = 0;
+        $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $path, array(
+                'contents' => array('compatible', 'dependencies', 'providesextension',
+                'usesrole', 'usestask', 'srcpackage', 'srcuri', 'phprelease',
+                'extsrcrelease', 'extbinrelease', 'bundle', 'changelog'),
+                'bundledpackage' => array()));
+    }
+
+    /**
+     * @param string file name
+     * @param PEAR_Task_Common a read/write task
+     */
+    function addTaskToFile($filename, $task)
+    {
+        if (!method_exists($task, 'getXml')) {
+            return false;
+        }
+        if (!method_exists($task, 'getName')) {
+            return false;
+        }
+        if (!method_exists($task, 'validate')) {
+            return false;
+        }
+        if (!$task->validate()) {
+            return false;
+        }
+        if (!isset($this->_packageInfo['contents']['dir']['file'])) {
+            return false;
+        }
+        $this->getTasksNs(); // discover the tasks namespace if not done already
+        $files = $this->_packageInfo['contents']['dir']['file'];
+        if (!isset($files[0])) {
+            $files = array($files);
+            $ind = false;
+        } else {
+            $ind = true;
+        }
+        foreach ($files as $i => $file) {
+            if (isset($file['attribs'])) {
+                if ($file['attribs']['name'] == $filename) {
+                    if ($ind) {
+                        $t = isset($this->_packageInfo['contents']['dir']['file'][$i]
+                              ['attribs'][$this->_tasksNs .
+                              ':' . $task->getName()]) ?
+                              $this->_packageInfo['contents']['dir']['file'][$i]
+                              ['attribs'][$this->_tasksNs .
+                              ':' . $task->getName()] : false;
+                        if ($t && !isset($t[0])) {
+                            $this->_packageInfo['contents']['dir']['file'][$i]
+                                [$this->_tasksNs . ':' . $task->getName()] = array($t);
+                        }
+                        $this->_packageInfo['contents']['dir']['file'][$i][$this->_tasksNs .
+                            ':' . $task->getName()][] = $task->getXml();
+                    } else {
+                        $t = isset($this->_packageInfo['contents']['dir']['file']
+                              ['attribs'][$this->_tasksNs .
+                              ':' . $task->getName()]) ? $this->_packageInfo['contents']['dir']['file']
+                              ['attribs'][$this->_tasksNs .
+                              ':' . $task->getName()] : false;
+                        if ($t && !isset($t[0])) {
+                            $this->_packageInfo['contents']['dir']['file']
+                                [$this->_tasksNs . ':' . $task->getName()] = array($t);
+                        }
+                        $this->_packageInfo['contents']['dir']['file'][$this->_tasksNs .
+                            ':' . $task->getName()][] = $task->getXml();
+                    }
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @param string path to the file
+     * @param string filename
+     * @param array extra attributes
+     */
+    function addFile($dir, $file, $attrs)
+    {
+        if ($this->getPackageType() == 'bundle') {
+            return false;
+        }
+        $this->_filesValid = false;
+        $this->_isValid = 0;
+        $dir = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), $dir);
+        if ($dir == '/' || $dir == '') {
+            $dir = '';
+        } else {
+            $dir .= '/';
+        }
+        $attrs['name'] = $dir . $file;
+        if (!isset($this->_packageInfo['contents'])) {
+            // ensure that the contents tag is set up
+            $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
+                array('compatible', 'dependencies', 'providesextension', 'usesrole', 'usestask',
+                'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease',
+                'extbinrelease', 'bundle', 'changelog'), array(), 'contents');
+        }
+        if (isset($this->_packageInfo['contents']['dir']['file'])) {
+            if (!isset($this->_packageInfo['contents']['dir']['file'][0])) {
+                $this->_packageInfo['contents']['dir']['file'] =
+                    array($this->_packageInfo['contents']['dir']['file']);
+            }
+            $this->_packageInfo['contents']['dir']['file'][]['attribs'] = $attrs;
+        } else {
+            $this->_packageInfo['contents']['dir']['file']['attribs'] = $attrs;
+        }
+    }
+
+    /**
+     * @param string Dependent package name
+     * @param string Dependent package's channel name
+     * @param string minimum version of specified package that this release is guaranteed to be
+     *               compatible with
+     * @param string maximum version of specified package that this release is guaranteed to be
+     *               compatible with
+     * @param string versions of specified package that this release is not compatible with
+     */
+    function addCompatiblePackage($name, $channel, $min, $max, $exclude = false)
+    {
+        $this->_isValid = 0;
+        $set = array(
+            'name' => $name,
+            'channel' => $channel,
+            'min' => $min,
+            'max' => $max,
+        );
+        if ($exclude) {
+            $set['exclude'] = $exclude;
+        }
+        $this->_isValid = 0;
+        $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $set, array(
+                'compatible' => array('dependencies', 'providesextension', 'usesrole', 'usestask',
+                    'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
+                    'bundle', 'changelog')
+            ));
+    }
+
+    /**
+     * Removes the <usesrole> tag entirely
+     */
+    function resetUsesrole()
+    {
+        if (isset($this->_packageInfo['usesrole'])) {
+            unset($this->_packageInfo['usesrole']);
+        }
+    }
+
+    /**
+     * @param string
+     * @param string package name or uri
+     * @param string channel name if non-uri
+     */
+    function addUsesrole($role, $packageOrUri, $channel = false) {
+        $set = array('role' => $role);
+        if ($channel) {
+            $set['package'] = $packageOrUri;
+            $set['channel'] = $channel;
+        } else {
+            $set['uri'] = $packageOrUri;
+        }
+        $this->_isValid = 0;
+        $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $set, array(
+                'usesrole' => array('usestask', 'srcpackage', 'srcuri',
+                    'phprelease', 'extsrcrelease', 'extbinrelease', 'bundle', 'changelog')
+            ));
+    }
+
+    /**
+     * Removes the <usestask> tag entirely
+     */
+    function resetUsestask()
+    {
+        if (isset($this->_packageInfo['usestask'])) {
+            unset($this->_packageInfo['usestask']);
+        }
+    }
+
+
+    /**
+     * @param string
+     * @param string package name or uri
+     * @param string channel name if non-uri
+     */
+    function addUsestask($task, $packageOrUri, $channel = false) {
+        $set = array('task' => $task);
+        if ($channel) {
+            $set['package'] = $packageOrUri;
+            $set['channel'] = $channel;
+        } else {
+            $set['uri'] = $packageOrUri;
+        }
+        $this->_isValid = 0;
+        $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $set, array(
+                'usestask' => array('srcpackage', 'srcuri',
+                    'phprelease', 'extsrcrelease', 'extbinrelease', 'bundle', 'changelog')
+            ));
+    }
+
+    /**
+     * Remove all compatible tags
+     */
+    function clearCompatible()
+    {
+        unset($this->_packageInfo['compatible']);
+    }
+
+    /**
+     * Reset dependencies prior to adding new ones
+     */
+    function clearDeps()
+    {
+        if (!isset($this->_packageInfo['dependencies'])) {
+            $this->_packageInfo = $this->_mergeTag($this->_packageInfo, array(),
+                array(
+                    'dependencies' => array('providesextension', 'usesrole', 'usestask',
+                        'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
+                        'bundle', 'changelog')));
+        }
+        $this->_packageInfo['dependencies'] = array();
+    }
+
+    /**
+     * @param string minimum PHP version allowed
+     * @param string maximum PHP version allowed
+     * @param array $exclude incompatible PHP versions
+     */
+    function setPhpDep($min, $max = false, $exclude = false)
+    {
+        $this->_isValid = 0;
+        $dep =
+            array(
+                'min' => $min,
+            );
+        if ($max) {
+            $dep['max'] = $max;
+        }
+        if ($exclude) {
+            if (count($exclude) == 1) {
+                $exclude = $exclude[0];
+            }
+            $dep['exclude'] = $exclude;
+        }
+        if (isset($this->_packageInfo['dependencies']['required']['php'])) {
+            $this->_stack->push(__FUNCTION__, 'warning', array('dep' =>
+            $this->_packageInfo['dependencies']['required']['php']),
+                'warning: PHP dependency already exists, overwriting');
+            unset($this->_packageInfo['dependencies']['required']['php']);
+        }
+        $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
+            array(
+                'dependencies' => array('providesextension', 'usesrole', 'usestask',
+                    'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
+                    'bundle', 'changelog'),
+                'required' => array('optional', 'group'),
+                'php' => array('pearinstaller', 'package', 'subpackage', 'extension', 'os', 'arch')
+            ));
+        return true;
+    }
+
+    /**
+     * @param string minimum allowed PEAR installer version
+     * @param string maximum allowed PEAR installer version
+     * @param string recommended PEAR installer version
+     * @param array incompatible version of the PEAR installer
+     */
+    function setPearinstallerDep($min, $max = false, $recommended = false, $exclude = false)
+    {
+        $this->_isValid = 0;
+        $dep =
+            array(
+                'min' => $min,
+            );
+        if ($max) {
+            $dep['max'] = $max;
+        }
+        if ($recommended) {
+            $dep['recommended'] = $recommended;
+        }
+        if ($exclude) {
+            if (count($exclude) == 1) {
+                $exclude = $exclude[0];
+            }
+            $dep['exclude'] = $exclude;
+        }
+        if (isset($this->_packageInfo['dependencies']['required']['pearinstaller'])) {
+            $this->_stack->push(__FUNCTION__, 'warning', array('dep' =>
+            $this->_packageInfo['dependencies']['required']['pearinstaller']),
+                'warning: PEAR Installer dependency already exists, overwriting');
+            unset($this->_packageInfo['dependencies']['required']['pearinstaller']);
+        }
+        $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
+            array(
+                'dependencies' => array('providesextension', 'usesrole', 'usestask',
+                    'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
+                    'bundle', 'changelog'),
+                'required' => array('optional', 'group'),
+                'pearinstaller' => array('package', 'subpackage', 'extension', 'os', 'arch')
+            ));
+    }
+
+    /**
+     * Mark a package as conflicting with this package
+     * @param string package name
+     * @param string package channel
+     * @param string extension this package provides, if any
+     */
+    function addConflictingPackageDepWithChannel($name, $channel, $providesextension = false)
+    {
+        $this->_isValid = 0;
+        $dep =
+            array(
+                'name' => $name,
+                'channel' => $channel,
+                'conflicts' => '',
+            );
+        if ($providesextension) {
+            $dep['providesextension'] = $providesextension;
+        }
+        $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
+            array(
+                'dependencies' => array('providesextension', 'usesrole', 'usestask',
+                    'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
+                    'bundle', 'changelog'),
+                'required' => array('optional', 'group'),
+                'package' => array('subpackage', 'extension', 'os', 'arch')
+            ));
+    }
+
+    /**
+     * Mark a package as conflicting with this package
+     * @param string package name
+     * @param string package channel
+     * @param string extension this package provides, if any
+     */
+    function addConflictingPackageDepWithUri($name, $uri, $providesextension = false)
+    {
+        $this->_isValid = 0;
+        $dep =
+            array(
+                'name' => $name,
+                'uri' => $uri,
+                'conflicts' => '',
+            );
+        if ($providesextension) {
+            $dep['providesextension'] = $providesextension;
+        }
+        $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
+            array(
+                'dependencies' => array('providesextension', 'usesrole', 'usestask',
+                    'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
+                    'bundle', 'changelog'),
+                'required' => array('optional', 'group'),
+                'package' => array('subpackage', 'extension', 'os', 'arch')
+            ));
+    }
+
+    function addDependencyGroup($name, $hint)
+    {
+        $this->_isValid = 0;
+        $this->_packageInfo = $this->_mergeTag($this->_packageInfo,
+            array('attribs' => array('name' => $name, 'hint' => $hint)),
+            array(
+                'dependencies' => array('providesextension', 'usesrole', 'usestask',
+                    'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
+                    'bundle', 'changelog'),
+                'group' => array(),
+            ));
+    }
+
+    /**
+     * @param string package name
+     * @param string|false channel name, false if this is a uri
+     * @param string|false uri name, false if this is a channel
+     * @param string|false minimum version required
+     * @param string|false maximum version allowed
+     * @param string|false recommended installation version
+     * @param array|false versions to exclude from installation
+     * @param string extension this package provides, if any
+     * @param bool if true, tells the installer to ignore the default optional dependency group
+     *             when installing this package
+     * @return array
+     * @access private
+     */
+    function _constructDep($name, $channel, $uri, $min, $max, $recommended, $exclude,
+                           $providesextension = false, $nodefault = false)
+    {
+        $dep =
+            array(
+                'name' => $name,
+            );
+        if ($channel) {
+            $dep['channel'] = $channel;
+        } elseif ($uri) {
+            $dep['uri'] = $uri;
+        }
+        if ($min) {
+            $dep['min'] = $min;
+        }
+        if ($max) {
+            $dep['max'] = $max;
+        }
+        if ($recommended) {
+            $dep['recommended'] = $recommended;
+        }
+        if ($exclude) {
+            if (is_array($exclude) && count($exclude) == 1) {
+                $exclude = $exclude[0];
+            }
+            $dep['exclude'] = $exclude;
+        }
+        if ($nodefault) {
+            $dep['nodefault'] = '';
+        }
+        if ($providesextension) {
+            $dep['providesextension'] = $providesextension;
+        }
+        return $dep;
+    }
+
+    /**
+     * @param package|subpackage
+     * @param string group name
+     * @param string package name
+     * @param string package channel
+     * @param string minimum version
+     * @param string maximum version
+     * @param string recommended version
+     * @param array|false optional excluded versions
+     * @param string extension this package provides, if any
+     * @param bool if true, tells the installer to ignore the default optional dependency group
+     *             when installing this package
+     * @return bool false if the dependency group has not been initialized with
+     *              {@link addDependencyGroup()}, or a subpackage is added with
+     *              a providesextension
+     */
+    function addGroupPackageDepWithChannel($type, $groupname, $name, $channel, $min = false,
+                                      $max = false, $recommended = false, $exclude = false,
+                                      $providesextension = false, $nodefault = false)
+    {
+        if ($type == 'subpackage' && $providesextension) {
+            return false; // subpackages must be php packages
+        }
+        $dep = $this->_constructDep($name, $channel, false, $min, $max, $recommended, $exclude,
+            $providesextension, $nodefault);
+        return $this->_addGroupDependency($type, $dep, $groupname);
+    }
+
+    /**
+     * @param package|subpackage
+     * @param string group name
+     * @param string package name
+     * @param string package uri
+     * @param string extension this package provides, if any
+     * @param bool if true, tells the installer to ignore the default optional dependency group
+     *             when installing this package
+     * @return bool false if the dependency group has not been initialized with
+     *              {@link addDependencyGroup()}
+     */
+    function addGroupPackageDepWithURI($type, $groupname, $name, $uri, $providesextension = false,
+                                       $nodefault = false)
+    {
+        if ($type == 'subpackage' && $providesextension) {
+            return false; // subpackages must be php packages
+        }
+        $dep = $this->_constructDep($name, false, $uri, false, false, false, false,
+            $providesextension, $nodefault);
+        return $this->_addGroupDependency($type, $dep, $groupname);
+    }
+
+    /**
+     * @param string group name (must be pre-existing)
+     * @param string extension name
+     * @param string minimum version allowed
+     * @param string maximum version allowed
+     * @param string recommended version
+     * @param array incompatible versions
+     */
+    function addGroupExtensionDep($groupname, $name, $min = false, $max = false,
+                                         $recommended = false, $exclude = false)
+    {
+        $this->_isValid = 0;
+        $dep = $this->_constructDep($name, false, false, $min, $max, $recommended, $exclude);
+        return $this->_addGroupDependency('extension', $dep, $groupname);
+    }
+
+    /**
+     * @param package|subpackage|extension
+     * @param array dependency contents
+     * @param string name of the dependency group to add this to
+     * @return boolean
+     * @access private
+     */
+    function _addGroupDependency($type, $dep, $groupname)
+    {
+        $arr = array('subpackage', 'extension');
+        if ($type != 'package') {
+            array_shift($arr);
+        }
+        if ($type == 'extension') {
+            array_shift($arr);
+        }
+        if (!isset($this->_packageInfo['dependencies']['group'])) {
+            return false;
+        } else {
+            if (!isset($this->_packageInfo['dependencies']['group'][0])) {
+                if ($this->_packageInfo['dependencies']['group']['attribs']['name'] == $groupname) {
+                    $this->_packageInfo['dependencies']['group'] = $this->_mergeTag(
+                        $this->_packageInfo['dependencies']['group'], $dep,
+                        array(
+                            $type => $arr
+                        ));
+                    $this->_isValid = 0;
+                    return true;
+                } else {
+                    return false;
+                }
+            } else {
+                foreach ($this->_packageInfo['dependencies']['group'] as $i => $group) {
+                    if ($group['attribs']['name'] == $groupname) {
+                    $this->_packageInfo['dependencies']['group'][$i] = $this->_mergeTag(
+                        $this->_packageInfo['dependencies']['group'][$i], $dep,
+                        array(
+                            $type => $arr
+                        ));
+                        $this->_isValid = 0;
+                        return true;
+                    }
+                }
+                return false;
+            }
+        }
+    }
+
+    /**
+     * @param optional|required
+     * @param string package name
+     * @param string package channel
+     * @param string minimum version
+     * @param string maximum version
+     * @param string recommended version
+     * @param string extension this package provides, if any
+     * @param bool if true, tells the installer to ignore the default optional dependency group
+     *             when installing this package
+     * @param array|false optional excluded versions
+     */
+    function addPackageDepWithChannel($type, $name, $channel, $min = false, $max = false,
+                                      $recommended = false, $exclude = false,
+                                      $providesextension = false, $nodefault = false)
+    {
+        $this->_isValid = 0;
+        $arr = array('optional', 'group');
+        if ($type != 'required') {
+            array_shift($arr);
+        }
+        $dep = $this->_constructDep($name, $channel, false, $min, $max, $recommended, $exclude,
+            $providesextension, $nodefault);
+        $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
+            array(
+                'dependencies' => array('providesextension', 'usesrole', 'usestask',
+                    'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
+                    'bundle', 'changelog'),
+                $type => $arr,
+                'package' => array('subpackage', 'extension', 'os', 'arch')
+            ));
+    }
+
+    /**
+     * @param optional|required
+     * @param string name of the package
+     * @param string uri of the package
+     * @param string extension this package provides, if any
+     * @param bool if true, tells the installer to ignore the default optional dependency group
+     *             when installing this package
+     */
+    function addPackageDepWithUri($type, $name, $uri, $providesextension = false,
+                                  $nodefault = false)
+    {
+        $this->_isValid = 0;
+        $arr = array('optional', 'group');
+        if ($type != 'required') {
+            array_shift($arr);
+        }
+        $dep = $this->_constructDep($name, false, $uri, false, false, false, false,
+            $providesextension, $nodefault);
+        $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
+            array(
+                'dependencies' => array('providesextension', 'usesrole', 'usestask',
+                    'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
+                    'bundle', 'changelog'),
+                $type => $arr,
+                'package' => array('subpackage', 'extension', 'os', 'arch')
+            ));
+    }
+
+    /**
+     * @param optional|required optional, required
+     * @param string package name
+     * @param string package channel
+     * @param string minimum version
+     * @param string maximum version
+     * @param string recommended version
+     * @param array incompatible versions
+     * @param bool if true, tells the installer to ignore the default optional dependency group
+     *             when installing this package
+     */
+    function addSubpackageDepWithChannel($type, $name, $channel, $min = false, $max = false,
+                                         $recommended = false, $exclude = false,
+                                         $nodefault = false)
+    {
+        $this->_isValid = 0;
+        $arr = array('optional', 'group');
+        if ($type != 'required') {
+            array_shift($arr);
+        }
+        $dep = $this->_constructDep($name, $channel, false, $min, $max, $recommended, $exclude,
+            $nodefault);
+        $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
+            array(
+                'dependencies' => array('providesextension', 'usesrole', 'usestask',
+                    'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
+                    'bundle', 'changelog'),
+                $type => $arr,
+                'subpackage' => array('extension', 'os', 'arch')
+            ));
+    }
+
+    /**
+     * @param optional|required optional, required
+     * @param string package name
+     * @param string package uri for download
+     * @param bool if true, tells the installer to ignore the default optional dependency group
+     *             when installing this package
+     */
+    function addSubpackageDepWithUri($type, $name, $uri, $nodefault = false)
+    {
+        $this->_isValid = 0;
+        $arr = array('optional', 'group');
+        if ($type != 'required') {
+            array_shift($arr);
+        }
+        $dep = $this->_constructDep($name, false, $uri, false, false, false, false, $nodefault);
+        $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
+            array(
+                'dependencies' => array('providesextension', 'usesrole', 'usestask',
+                    'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
+                    'bundle', 'changelog'),
+                $type => $arr,
+                'subpackage' => array('extension', 'os', 'arch')
+            ));
+    }
+
+    /**
+     * @param optional|required optional, required
+     * @param string extension name
+     * @param string minimum version
+     * @param string maximum version
+     * @param string recommended version
+     * @param array incompatible versions
+     */
+    function addExtensionDep($type, $name, $min = false, $max = false, $recommended = false,
+                             $exclude = false)
+    {
+        $this->_isValid = 0;
+        $arr = array('optional', 'group');
+        if ($type != 'required') {
+            array_shift($arr);
+        }
+        $dep = $this->_constructDep($name, false, false, $min, $max, $recommended, $exclude);
+        $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
+            array(
+                'dependencies' => array('providesextension', 'usesrole', 'usestask',
+                    'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
+                    'bundle', 'changelog'),
+                $type => $arr,
+                'extension' => array('os', 'arch')
+            ));
+    }
+
+    /**
+     * @param string Operating system name
+     * @param boolean true if this package cannot be installed on this OS
+     */
+    function addOsDep($name, $conflicts = false)
+    {
+        $this->_isValid = 0;
+        $dep = array('name' => $name);
+        if ($conflicts) {
+            $dep['conflicts'] = '';
+        }
+        $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
+            array(
+                'dependencies' => array('providesextension', 'usesrole', 'usestask',
+                    'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
+                    'bundle', 'changelog'),
+                'required' => array('optional', 'group'),
+                'os' => array('arch')
+            ));
+    }
+
+    /**
+     * @param string Architecture matching pattern
+     * @param boolean true if this package cannot be installed on this architecture
+     */
+    function addArchDep($pattern, $conflicts = false)
+    {
+        $this->_isValid = 0;
+        $dep = array('pattern' => $pattern);
+        if ($conflicts) {
+            $dep['conflicts'] = '';
+        }
+        $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
+            array(
+                'dependencies' => array('providesextension', 'usesrole', 'usestask',
+                    'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
+                    'bundle', 'changelog'),
+                'required' => array('optional', 'group'),
+                'arch' => array()
+            ));
+    }
+
+    /**
+     * Set the kind of package, and erase all release tags
+     *
+     * - a php package is a PEAR-style package
+     * - an extbin package is a PECL-style extension binary
+     * - an extsrc package is a PECL-style source for a binary
+     * - a bundle package is a collection of other pre-packaged packages
+     * @param php|extbin|extsrc|bundle
+     * @return bool success
+     */
+    function setPackageType($type)
+    {
+        $this->_isValid = 0;
+        if (!in_array($type, array('php', 'extbin', 'extsrc', 'bundle'))) {
+            return false;
+        }
+        if ($type != 'bundle') {
+            $type .= 'release';
+        }
+        foreach (array('phprelease', 'extbinrelease', 'extsrcrelease', 'bundle') as $test) {
+            unset($this->_packageInfo[$test]);
+        }
+        if (!isset($this->_packageInfo[$type])) {
+            // ensure that the release tag is set up
+            $this->_packageInfo = $this->_insertBefore($this->_packageInfo, array('changelog'),
+                array(), $type);
+        }
+        $this->_packageInfo[$type] = array();
+        return true;
+    }
+
+    /**
+     * @return bool true if package type is set up
+     */
+    function addRelease()
+    {
+        if ($type = $this->getPackageType()) {
+            if ($type != 'bundle') {
+                $type .= 'release';
+            }
+            $this->_packageInfo = $this->_mergeTag($this->_packageInfo, array(),
+                array($type => array('changelog')));
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Get the current release tag in order to add to it
+     * @param bool returns only releases that have installcondition if true
+     * @return array|null
+     */
+    function &_getCurrentRelease($strict = true)
+    {
+        if ($p = $this->getPackageType()) {
+            if ($strict) {
+                if ($p == 'extsrc') {
+                    $a = null;
+                    return $a;
+                }
+            }
+            if ($p != 'bundle') {
+                $p .= 'release';
+            }
+            if (isset($this->_packageInfo[$p][0])) {
+                return $this->_packageInfo[$p][count($this->_packageInfo[$p]) - 1];
+            } else {
+                return $this->_packageInfo[$p];
+            }
+        } else {
+            $a = null;
+            return $a;
+        }
+    }
+
+    /**
+     * Add a file to the current release that should be installed under a different name
+     * @param string <contents> path to file
+     * @param string name the file should be installed as
+     */
+    function addInstallAs($path, $as)
+    {
+        $r = &$this->_getCurrentRelease();
+        if ($r === null) {
+            return false;
+        }
+        $this->_isValid = 0;
+        $r = $this->_mergeTag($r, array('attribs' => array('name' => $path, 'as' => $as)),
+            array(
+                'filelist' => array(),
+                'install' => array('ignore')
+            ));
+    }
+
+    /**
+     * Add a file to the current release that should be ignored
+     * @param string <contents> path to file
+     * @return bool success of operation
+     */
+    function addIgnore($path)
+    {
+        $r = &$this->_getCurrentRelease();
+        if ($r === null) {
+            return false;
+        }
+        $this->_isValid = 0;
+        $r = $this->_mergeTag($r, array('attribs' => array('name' => $path)),
+            array(
+                'filelist' => array(),
+                'ignore' => array()
+            ));
+    }
+
+    /**
+     * Add an extension binary package for this extension source code release
+     *
+     * Note that the package must be from the same channel as the extension source package
+     * @param string
+     */
+    function addBinarypackage($package)
+    {
+        if ($this->getPackageType() != 'extsrc') {
+            return false;
+        }
+        $r = &$this->_getCurrentRelease(false);
+        if ($r === null) {
+            return false;
+        }
+        $this->_isValid = 0;
+        $r = $this->_mergeTag($r, $package,
+            array(
+                'binarypackage' => array('filelist'),
+            ));
+    }
+
+    /**
+     * Add a configureoption to an extension source package
+     * @param string
+     * @param string
+     * @param string
+     */
+    function addConfigureOption($name, $prompt, $default = null)
+    {
+        if ($this->getPackageType() != 'extsrc') {
+            return false;
+        }
+        $r = &$this->_getCurrentRelease(false);
+        if ($r === null) {
+            return false;
+        }
+        $opt = array('attribs' => array('name' => $name, 'prompt' => $prompt));
+        if ($default !== null) {
+            $opt['default'] = $default;
+        }
+        $this->_isValid = 0;
+        $r = $this->_mergeTag($r, $opt,
+            array(
+                'configureoption' => array('binarypackage', 'filelist'),
+            ));
+    }
+
+    /**
+     * Set an installation condition based on php version for the current release set
+     * @param string minimum version
+     * @param string maximum version
+     * @param false|array incompatible versions of PHP
+     */
+    function setPhpInstallCondition($min, $max, $exclude = false)
+    {
+        $r = &$this->_getCurrentRelease();
+        if ($r === null) {
+            return false;
+        }
+        $this->_isValid = 0;
+        if (isset($r['installconditions']['php'])) {
+            unset($r['installconditions']['php']);
+        }
+        $dep = array('min' => $min, 'max' => $max);
+        if ($exclude) {
+            if (is_array($exclude) && count($exclude) == 1) {
+                $exclude = $exclude[0];
+            }
+            $dep['exclude'] = $exclude;
+        }
+        if ($this->getPackageType() == 'extsrc') {
+            $r = $this->_mergeTag($r, $dep,
+                array(
+                    'installconditions' => array('configureoption', 'binarypackage',
+                        'filelist'),
+                    'php' => array('extension', 'os', 'arch')
+                ));
+        } else {
+            $r = $this->_mergeTag($r, $dep,
+                array(
+                    'installconditions' => array('filelist'),
+                    'php' => array('extension', 'os', 'arch')
+                ));
+        }
+    }
+
+    /**
+     * @param optional|required optional, required
+     * @param string extension name
+     * @param string minimum version
+     * @param string maximum version
+     * @param string recommended version
+     * @param array incompatible versions
+     */
+    function addExtensionInstallCondition($name, $min = false, $max = false, $recommended = false,
+                                          $exclude = false)
+    {
+        $r = &$this->_getCurrentRelease();
+        if ($r === null) {
+            return false;
+        }
+        $this->_isValid = 0;
+        $dep = $this->_constructDep($name, false, false, $min, $max, $recommended, $exclude);
+        if ($this->getPackageType() == 'extsrc') {
+            $r = $this->_mergeTag($r, $dep,
+                array(
+                    'installconditions' => array('configureoption', 'binarypackage',
+                        'filelist'),
+                    'extension' => array('os', 'arch')
+                ));
+        } else {
+            $r = $this->_mergeTag($r, $dep,
+                array(
+                    'installconditions' => array('filelist'),
+                    'extension' => array('os', 'arch')
+                ));
+        }
+    }
+
+    /**
+     * Set an installation condition based on operating system for the current release set
+     * @param string OS name
+     * @param bool whether this OS is incompatible with the current release
+     */
+    function setOsInstallCondition($name, $conflicts = false)
+    {
+        $r = &$this->_getCurrentRelease();
+        if ($r === null) {
+            return false;
+        }
+        $this->_isValid = 0;
+        if (isset($r['installconditions']['os'])) {
+            unset($r['installconditions']['os']);
+        }
+        $dep = array('name' => $name);
+        if ($conflicts) {
+            $dep['conflicts'] = '';
+        }
+        if ($this->getPackageType() == 'extsrc') {
+            $r = $this->_mergeTag($r, $dep,
+                array(
+                    'installconditions' => array('configureoption', 'binarypackage',
+                        'filelist'),
+                    'os' => array('arch')
+                ));
+        } else {
+            $r = $this->_mergeTag($r, $dep,
+                array(
+                    'installconditions' => array('filelist'),
+                    'os' => array('arch')
+                ));
+        }
+    }
+
+    /**
+     * Set an installation condition based on architecture for the current release set
+     * @param string architecture pattern
+     * @param bool whether this arch is incompatible with the current release
+     */
+    function setArchInstallCondition($pattern, $conflicts = false)
+    {
+        $r = &$this->_getCurrentRelease();
+        if ($r === null) {
+            return false;
+        }
+        $this->_isValid = 0;
+        if (isset($r['installconditions']['arch'])) {
+            unset($r['installconditions']['arch']);
+        }
+        $dep = array('pattern' => $pattern);
+        if ($conflicts) {
+            $dep['conflicts'] = '';
+        }
+        if ($this->getPackageType() == 'extsrc') {
+            $r = $this->_mergeTag($r, $dep,
+                array(
+                    'installconditions' => array('configureoption', 'binarypackage',
+                        'filelist'),
+                    'arch' => array()
+                ));
+        } else {
+            $r = $this->_mergeTag($r, $dep,
+                array(
+                    'installconditions' => array('filelist'),
+                    'arch' => array()
+                ));
+        }
+    }
+
+    /**
+     * For extension binary releases, this is used to specify either the
+     * static URI to a source package, or the package name and channel of the extsrc
+     * package it is based on.
+     * @param string Package name, or full URI to source package (extsrc type)
+     */
+    function setSourcePackage($packageOrUri)
+    {
+        $this->_isValid = 0;
+        if (isset($this->_packageInfo['channel'])) {
+            $this->_packageInfo = $this->_insertBefore($this->_packageInfo, array('phprelease',
+                'extsrcrelease', 'extbinrelease', 'bundle', 'changelog'),
+                $packageOrUri, 'srcpackage');
+        } else {
+            $this->_packageInfo = $this->_insertBefore($this->_packageInfo, array('phprelease',
+                'extsrcrelease', 'extbinrelease', 'bundle', 'changelog'), $packageOrUri, 'srcuri');
+        }
+    }
+
+    /**
+     * Generate a valid change log entry from the current package.xml
+     * @param string|false
+     */
+    function generateChangeLogEntry($notes = false)
+    {
+        return array(
+            'version' => 
+                array(
+                    'release' => $this->getVersion('release'),
+                    'api' => $this->getVersion('api'),
+                    ),
+            'stability' =>
+                $this->getStability(),
+            'date' => $this->getDate(),
+            'license' => $this->getLicense(),
+            'notes' => $notes ? $notes : $this->getNotes()
+            );
+    }
+
+    /**
+     * @param string release version to set change log notes for
+     * @param array output of {@link generateChangeLogEntry()}
+     */
+    function setChangelogEntry($releaseversion, $contents)
+    {
+        if (!isset($this->_packageInfo['changelog'])) {
+            $this->_packageInfo['changelog']['release'] = $contents;
+            return;
+        }
+        if (!isset($this->_packageInfo['changelog']['release'][0])) {
+            if ($this->_packageInfo['changelog']['release']['version']['release'] == $releaseversion) {
+                $this->_packageInfo['changelog']['release'] = array(
+                    $this->_packageInfo['changelog']['release']);
+            } else {
+                $this->_packageInfo['changelog']['release'] = array(
+                    $this->_packageInfo['changelog']['release']);
+                return $this->_packageInfo['changelog']['release'][] = $contents;
+            }
+        }
+        foreach($this->_packageInfo['changelog']['release'] as $index => $changelog) {
+            if (isset($changelog['version']) &&
+                  strnatcasecmp($changelog['version']['release'], $releaseversion) == 0) {
+                $curlog = $index;
+            }
+        }
+        if (isset($curlog)) {
+            $this->_packageInfo['changelog']['release'][$curlog] = $contents;
+        } else {
+            $this->_packageInfo['changelog']['release'][] = $contents;
+        }
+    }
+
+    /**
+     * Remove the changelog entirely
+     */
+    function clearChangeLog()
+    {
+        unset($this->_packageInfo['changelog']);
+    }
+}
+?>
\ No newline at end of file
index 3e729fb5fe591a78f72cbd227138a78bec2c4367..2a40dd8617b8c7b0dd873443236ced3ed1635330 100644 (file)
 <?php
-//
-// +----------------------------------------------------------------------+
-// | PHP Version 5                                                        |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2004 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>                             |
-// +----------------------------------------------------------------------+
-//
-// $Id$
+/**
+ * PEAR_Packager for generating releases
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Tomas V. V. Cox <cox@idecnet.com>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 0.1
+ */
 
+/**
+ * base class
+ */
 require_once 'PEAR/Common.php';
+require_once 'PEAR/PackageFile.php';
 require_once 'System.php';
 
 /**
  * Administration class used to make a PEAR release tarball.
  *
- * TODO:
- *  - add an extra param the dir where to place the created package
- *
- * @since PHP 4.0.2
- * @author Stig Bakken <ssb@php.net>
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 0.1
  */
 class PEAR_Packager extends PEAR_Common
 {
-    // {{{ constructor
-
-    function PEAR_Packager()
-    {
-        parent::PEAR_Common();
-    }
-
-    // }}}
-    // {{{ destructor
-
-    function _PEAR_Packager()
-    {
-        parent::_PEAR_Common();
-    }
-
-    // }}}
-
+    /**
+     * @var PEAR_Registry
+     */
+    var $_registry;
     // {{{ package()
 
-    function package($pkgfile = null, $compress = true)
+    function package($pkgfile = null, $compress = true, $pkg2 = null)
     {
         // {{{ validate supplied package.xml file
         if (empty($pkgfile)) {
             $pkgfile = 'package.xml';
         }
-        // $this->pkginfo gets populated inside
-        $pkginfo = $this->infoFromDescriptionFile($pkgfile);
-        if (PEAR::isError($pkginfo)) {
-            return $this->raiseError($pkginfo);
+        PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+        $pkg = &new PEAR_PackageFile($this->config, $this->debug);
+        $pf = &$pkg->fromPackageFile($pkgfile, PEAR_VALIDATE_NORMAL);
+        $main = &$pf;
+        PEAR::staticPopErrorHandling();
+        if (PEAR::isError($pf)) {
+            if (is_array($pf->getUserInfo())) {
+                foreach ($pf->getUserInfo() as $error) {
+                    $this->log(0, 'Error: ' . $error['message']);
+                }
+            }
+            $this->log(0, $pf->getMessage());
+            return $this->raiseError("Cannot package, errors in package file");
+        } else {
+            foreach ($pf->getValidationWarnings() as $warning) {
+                $this->log(1, 'Warning: ' . $warning['message']);
+            }
         }
 
-        $pkgdir = dirname(realpath($pkgfile));
-        $pkgfile = basename($pkgfile);
-
-        $errors = $warnings = array();
-        $this->validatePackageInfo($pkginfo, $errors, $warnings, $pkgdir);
-        foreach ($warnings as $w) {
-            $this->log(1, "Warning: $w");
-        }
-        foreach ($errors as $e) {
-            $this->log(0, "Error: $e");
-        }
-        if (sizeof($errors) > 0) {
-            return $this->raiseError('Errors in package');
-        }
         // }}}
-
-        $pkgver = $pkginfo['package'] . '-' . $pkginfo['version'];
-
-        // {{{ Create the package file list
-        $filelist = array();
-        $i = 0;
-
-        foreach ($pkginfo['filelist'] as $fname => $atts) {
-            $file = $pkgdir . DIRECTORY_SEPARATOR . $fname;
-            if (!file_exists($file)) {
-                return $this->raiseError("File does not exist: $fname");
+        if ($pkg2) {
+            $this->log(0, 'Attempting to process the second package file');
+            PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+            $pf2 = &$pkg->fromPackageFile($pkg2, PEAR_VALIDATE_NORMAL);
+            PEAR::staticPopErrorHandling();
+            if (PEAR::isError($pf2)) {
+                if (is_array($pf2->getUserInfo())) {
+                    foreach ($pf2->getUserInfo() as $error) {
+                        $this->log(0, 'Error: ' . $error['message']);
+                    }
+                }
+                $this->log(0, $pf2->getMessage());
+                return $this->raiseError("Cannot package, errors in second package file");
             } else {
-                $filelist[$i++] = $file;
-                if (empty($pkginfo['filelist'][$fname]['md5sum'])) {
-                    $md5sum = md5_file($file);
-                    $pkginfo['filelist'][$fname]['md5sum'] = $md5sum;
+                foreach ($pf2->getValidationWarnings() as $warning) {
+                    $this->log(1, 'Warning: ' . $warning['message']);
                 }
-                $this->log(2, "Adding file $fname");
+            }
+            if ($pf2->getPackagexmlVersion() == '2.0') {
+                $main = &$pf2;
+                $other = &$pf;
+            } else {
+                $main = &$pf;
+                $other = &$pf2;
+            }
+            if ($main->getPackagexmlVersion() != '2.0') {
+                return PEAR::raiseError('Error: cannot package two package.xml version 1.0, can ' .
+                    'only package together a package.xml 1.0 and package.xml 2.0');
+            }
+            if ($other->getPackagexmlVersion() != '1.0') {
+                return PEAR::raiseError('Error: cannot package two package.xml version 2.0, can ' .
+                    'only package together a package.xml 1.0 and package.xml 2.0');
             }
         }
-        // }}}
-
-        // {{{ regenerate package.xml
-        $new_xml = $this->xmlFromInfo($pkginfo);
-        if (PEAR::isError($new_xml)) {
-            return $this->raiseError($new_xml);
-        }
-        if (!($tmpdir = System::mktemp(array('-d')))) {
-            return $this->raiseError("PEAR_Packager: mktemp failed");
-        }
-        $newpkgfile = $tmpdir . DIRECTORY_SEPARATOR . 'package.xml';
-        $np = @fopen($newpkgfile, 'wb');
-        if (!$np) {
-            return $this->raiseError("PEAR_Packager: unable to rewrite $pkgfile as $newpkgfile");
-        }
-        fwrite($np, $new_xml);
-        fclose($np);
-        // }}}
-
-        // {{{ TAR the Package -------------------------------------------
-        $ext = $compress ? '.tgz' : '.tar';
-        $dest_package = getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext;
-        $tar =& new Archive_Tar($dest_package, $compress);
-        $tar->setErrorHandling(PEAR_ERROR_RETURN); // XXX Don't print errors
-        // ----- Creates with the package.xml file
-        $ok = $tar->createModify(array($newpkgfile), '', $tmpdir);
-        if (PEAR::isError($ok)) {
-            return $this->raiseError($ok);
-        } elseif (!$ok) {
-            return $this->raiseError('PEAR_Packager: tarball creation failed');
-        }
-        // ----- Add the content of the package
-        if (!$tar->addModify($filelist, $pkgver, $pkgdir)) {
-            return $this->raiseError('PEAR_Packager: tarball creation failed');
+        $main->setLogger($this);
+        if (!$main->validate(PEAR_VALIDATE_PACKAGING)) {
+            foreach ($main->getValidationWarnings() as $warning) {
+                $this->log(0, 'Error: ' . $warning['message']);
+            }
+            return $this->raiseError("Cannot package, errors in package");
+        } else {
+            foreach ($main->getValidationWarnings() as $warning) {
+                $this->log(1, 'Warning: ' . $warning['message']);
+            }
         }
-        $this->log(1, "Package $dest_package done");
-        if (file_exists("$pkgdir/CVS/Root")) {
-            $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $pkginfo['version']);
-            $cvstag = "RELEASE_$cvsversion";
-            $this->log(1, "Tag the released code with `pear cvstag $pkgfile'");
-            $this->log(1, "(or set the CVS tag $cvstag by hand)");
+        if ($pkg2) {
+            $other->setLogger($this);
+            $a = false;
+            if (!$other->validate(PEAR_VALIDATE_NORMAL) || $a = !$main->isEquivalent($other)) {
+                foreach ($other->getValidationWarnings() as $warning) {
+                    $this->log(0, 'Error: ' . $warning['message']);
+                }
+                foreach ($main->getValidationWarnings() as $warning) {
+                    $this->log(0, 'Error: ' . $warning['message']);
+                }
+                if ($a) {
+                    return $this->raiseError('The two package.xml files are not equivalent!');
+                }
+                return $this->raiseError("Cannot package, errors in package");
+            } else {
+                foreach ($other->getValidationWarnings() as $warning) {
+                    $this->log(1, 'Warning: ' . $warning['message']);
+                }
+            }
+            $gen = &$main->getDefaultGenerator();
+            $tgzfile = $gen->toTgz2($this, $other, $compress);
+            if (PEAR::isError($tgzfile)) {
+                return $tgzfile;
+            }
+            $dest_package = basename($tgzfile);
+            $pkgdir = dirname($pkgfile);
+    
+            // TAR the Package -------------------------------------------
+            $this->log(1, "Package $dest_package done");
+            if (file_exists("$pkgdir/CVS/Root")) {
+                $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $pf->getVersion());
+                $cvstag = "RELEASE_$cvsversion";
+                $this->log(1, 'Tag the released code with "pear cvstag ' .
+                    $main->getPackageFile() . '"');
+                $this->log(1, "(or set the CVS tag $cvstag by hand)");
+            }
+        } else { // this branch is executed for single packagefile packaging
+            $gen = &$pf->getDefaultGenerator();
+            $tgzfile = $gen->toTgz($this, $compress);
+            if (PEAR::isError($tgzfile)) {
+                $this->log(0, $tgzfile->getMessage());
+                return $this->raiseError("Cannot package, errors in package");
+            }
+            $dest_package = basename($tgzfile);
+            $pkgdir = dirname($pkgfile);
+    
+            // TAR the Package -------------------------------------------
+            $this->log(1, "Package $dest_package done");
+            if (file_exists("$pkgdir/CVS/Root")) {
+                $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $pf->getVersion());
+                $cvstag = "RELEASE_$cvsversion";
+                $this->log(1, "Tag the released code with `pear cvstag $pkgfile'");
+                $this->log(1, "(or set the CVS tag $cvstag by hand)");
+            }
         }
-        // }}}
-
         return $dest_package;
     }
 
@@ -155,8 +187,13 @@ if (!function_exists('md5_file')) {
         if (!$fd = @fopen($file, 'r')) {
             return false;
         }
-        $md5 = md5(fread($fd, filesize($file)));
-        fclose($fd);
+        if (function_exists('file_get_contents')) {
+            fclose($fd);
+            $md5 = md5(file_get_contents($file));
+        } else {
+            $md5 = md5(fread($fd, filesize($file)));
+            fclose($fd);
+        }
         return $md5;
     }
 }
diff --git a/pear/PEAR/REST.php b/pear/PEAR/REST.php
new file mode 100644 (file)
index 0000000..99a739d
--- /dev/null
@@ -0,0 +1,380 @@
+<?php
+/**
+ * PEAR_REST
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a1
+ */
+
+/**
+ * For downloading xml files
+ */
+require_once 'PEAR.php';
+require_once 'PEAR/XMLParser.php';
+
+/**
+ * Intelligently retrieve data, following hyperlinks if necessary, and re-directing
+ * as well
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
+ */
+class PEAR_REST
+{
+    var $config;
+    var $_options;
+    function PEAR_REST(&$config, $options = array())
+    {
+        $this->config = &$config;
+        $this->_options = $options;
+    }
+
+    /**
+     * Retrieve REST data, but always retrieve the local cache if it is available.
+     *
+     * This is useful for elements that should never change, such as information on a particular
+     * release
+     * @param string full URL to this resource
+     * @param array|false contents of the accept-encoding header
+     * @param boolean     if true, xml will be returned as a string, otherwise, xml will be
+     *                    parsed using PEAR_XMLParser
+     * @return string|array
+     */
+    function retrieveCacheFirst($url, $accept = false, $forcestring = false)
+    {
+        $cachefile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR .
+            md5($url) . 'rest.cachefile';
+        if (@file_exists($cachefile)) {
+            return unserialize(implode('', file($cachefile)));
+        }
+        return $this->retrieveData($url, $accept, $forcestring);
+    }
+
+    /**
+     * Retrieve a remote REST resource
+     * @param string full URL to this resource
+     * @param array|false contents of the accept-encoding header
+     * @param boolean     if true, xml will be returned as a string, otherwise, xml will be
+     *                    parsed using PEAR_XMLParser
+     * @return string|array
+     */
+    function retrieveData($url, $accept = false, $forcestring = false)
+    {
+        $cacheId = $this->getCacheId($url);
+        if ($ret = $this->useLocalCache($url, $cacheId)) {
+            return $ret;
+        }
+        if (!isset($this->_options['offline'])) {
+            $trieddownload = true;
+            $file = $this->downloadHttp($url, $cacheId ? $cacheId['lastChange'] : false, $accept);
+        } else {
+            $trieddownload = false;
+            $file = false;
+        }
+        if (PEAR::isError($file)) {
+            if ($file->getCode() == -9276) {
+                $trieddownload = false;
+                $file = false; // use local copy if available on socket connect error
+            } else {
+                return $file;
+            }
+        }
+        if (!$file) {
+            $ret = $this->getCache($url);
+            if (!PEAR::isError($ret) && $trieddownload) {
+                // reset the age of the cache if the server says it was unmodified
+                $this->saveCache($url, $ret, null, true, $cacheId);
+            }
+            return $ret;
+        }
+        $headers = $file[2];
+        $lastmodified = $file[1];
+        $content = $file[0];
+        if ($forcestring) {
+            $this->saveCache($url, $content, $lastmodified, false, $cacheId);
+            return $content;
+        }
+        if (isset($headers['content-type'])) {
+            switch ($headers['content-type']) {
+                case 'text/xml' :
+                case 'application/xml' :
+                    $parser = new PEAR_XMLParser;
+                    PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+                    $err = $parser->parse($content);
+                    PEAR::popErrorHandling();
+                    if (PEAR::isError($err)) {
+                        return PEAR::raiseError('Invalid xml downloaded from "' . $url . '": ' .
+                            $err->getMessage());
+                    }
+                    $content = $parser->getData();
+                case 'text/html' :
+                default :
+                    // use it as a string
+            }
+        } else {
+            // assume XML
+            $parser = new PEAR_XMLParser;
+            $parser->parse($file);
+            $content = $parser->getData();
+        }
+        $this->saveCache($url, $content, $lastmodified, false, $cacheId);
+        return $content;
+    }
+
+    function useLocalCache($url, $cacheid = null)
+    {
+        if ($cacheid === null) {
+            $cacheidfile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR .
+                md5($url) . 'rest.cacheid';
+            if (@file_exists($cacheidfile)) {
+                $cacheid = unserialize(implode('', file($cacheidfile)));
+            } else {
+                return false;
+            }
+        }
+        $cachettl = $this->config->get('cache_ttl');
+        // If cache is newer than $cachettl seconds, we use the cache!
+        if (time() - $cacheid['age'] < $cachettl) {
+            return $this->getCache($url);
+        }
+        return false;
+    }
+
+    function getCacheId($url)
+    {
+        $cacheidfile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR .
+            md5($url) . 'rest.cacheid';
+        if (@file_exists($cacheidfile)) {
+            $ret = unserialize(implode('', file($cacheidfile)));
+            return $ret;
+        } else {
+            return false;
+        }
+    }
+
+    function getCache($url)
+    {
+        $cachefile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR .
+            md5($url) . 'rest.cachefile';
+        if (@file_exists($cachefile)) {
+            return unserialize(implode('', file($cachefile)));
+        } else {
+            return PEAR::raiseError('No cached content available for "' . $url . '"');
+        }
+    }
+
+    /**
+     * @param string full URL to REST resource
+     * @param string original contents of the REST resource
+     * @param array  HTTP Last-Modified and ETag headers
+     * @param bool   if true, then the cache id file should be regenerated to
+     *               trigger a new time-to-live value
+     */
+    function saveCache($url, $contents, $lastmodified, $nochange = false, $cacheid = null)
+    {
+        $cacheidfile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR .
+            md5($url) . 'rest.cacheid';
+        $cachefile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR .
+            md5($url) . 'rest.cachefile';
+        if ($cacheid === null && $nochange) {
+            $cacheid = unserialize(implode('', file($cacheidfile)));
+        }
+        $fp = @fopen($cacheidfile, 'wb');
+        if (!$fp) {
+            return false;
+        }
+        if ($nochange) {
+            fwrite($fp, serialize(array(
+                'age'        => time(),
+                'lastChange' => $cacheid['lastChange'],
+                )));
+            fclose($fp);
+            return true;
+        } else {
+            fwrite($fp, serialize(array(
+                'age'        => time(),
+                'lastChange' => $lastmodified,
+                )));
+        }
+        fclose($fp);
+        $fp = @fopen($cachefile, 'wb');
+        if (!$fp) {
+            @unlink($cacheidfile);
+            return false;
+        }
+        fwrite($fp, serialize($contents));
+        fclose($fp);
+        return true;
+    }
+
+    /**
+     * Efficiently Download a file through HTTP.  Returns downloaded file as a string in-memory
+     * This is best used for small files
+     *
+     * If an HTTP proxy has been configured (http_proxy PEAR_Config
+     * setting), the proxy will be used.
+     *
+     * @param string  $url       the URL to download
+     * @param string  $save_dir  directory to save file in
+     * @param false|string|array $lastmodified header values to check against for caching
+     *                           use false to return the header values from this download
+     * @param false|array $accept Accept headers to send
+     * @return string|array  Returns the contents of the downloaded file or a PEAR
+     *                       error on failure.  If the error is caused by
+     *                       socket-related errors, the error object will
+     *                       have the fsockopen error code available through
+     *                       getCode().  If caching is requested, then return the header
+     *                       values.
+     *
+     * @access public
+     */
+    function downloadHttp($url, $lastmodified = null, $accept = false)
+    {
+        $info = parse_url($url);
+        if (!isset($info['scheme']) || !in_array($info['scheme'], array('http', 'https'))) {
+            return PEAR::raiseError('Cannot download non-http URL "' . $url . '"');
+        }
+        if (!isset($info['host'])) {
+            return PEAR::raiseError('Cannot download from non-URL "' . $url . '"');
+        } else {
+            $host = $info['host'];
+            if (!array_key_exists('port', $info)) {
+                $info['port'] = null;
+            }
+            if (!array_key_exists('path', $info)) {
+                $info['path'] = null;
+            }
+            $port = $info['port'];
+            $path = $info['path'];
+        }
+        $proxy_host = $proxy_port = $proxy_user = $proxy_pass = '';
+        if ($this->config->get('http_proxy')&& 
+              $proxy = parse_url($this->config->get('http_proxy'))) {
+            $proxy_host = @$proxy['host'];
+            if (isset($proxy['scheme']) && $proxy['scheme'] == 'https') {
+                $proxy_host = 'ssl://' . $proxy_host;
+            }
+            $proxy_port = @$proxy['port'];
+            $proxy_user = @$proxy['user'];
+            $proxy_pass = @$proxy['pass'];
+
+            if ($proxy_port == '') {
+                $proxy_port = 8080;
+            }
+        }
+        if (empty($port)) {
+            if (isset($info['scheme']) && $info['scheme'] == 'https') {
+                $port = 443;
+            } else {
+                $port = 80;
+            }
+        }
+        If (isset($proxy['host'])) {
+            $request = "GET $url HTTP/1.1\r\n";
+        } else {
+            $request = "GET $path HTTP/1.1\r\n";
+        }
+
+        $ifmodifiedsince = '';
+        if (is_array($lastmodified)) {
+            if (isset($lastmodified['Last-Modified'])) {
+                $ifmodifiedsince = 'If-Modified-Since: ' . $lastmodified['Last-Modified'] . "\r\n";
+            }
+            if (isset($lastmodified['ETag'])) {
+                $ifmodifiedsince .= "If-None-Match: $lastmodified[ETag]\r\n";
+            }
+        } else {
+            $ifmodifiedsince = ($lastmodified ? "If-Modified-Since: $lastmodified\r\n" : '');
+        }
+        $request .= "Host: $host:$port\r\n" . $ifmodifiedsince .
+            "User-Agent: PEAR/@package_version@/PHP/" . PHP_VERSION . "\r\n";
+        $username = $this->config->get('username');
+        $password = $this->config->get('password');
+        if ($username && $password) {
+            $tmp = base64_encode("$username:$password");
+            $request .= "Authorization: Basic $tmp\r\n";
+        }
+        if ($proxy_host != '' && $proxy_user != '') {
+            $request .= 'Proxy-Authorization: Basic ' .
+                base64_encode($proxy_user . ':' . $proxy_pass) . "\r\n";
+        }
+        if ($accept) {
+            $request .= 'Accept: ' . implode(', ', $accept) . "\r\n";
+        }
+        $request .= "Connection: close\r\n";
+        $request .= "\r\n";
+        if ($proxy_host != '') {
+            $fp = @fsockopen($proxy_host, $proxy_port, $errno, $errstr, 15);
+            if (!$fp) {
+                return PEAR::raiseError("Connection to `$proxy_host:$proxy_port' failed: $errstr",
+                    -9276);
+            }
+        } else {
+            if (isset($info['scheme']) && $info['scheme'] == 'https') {
+                $host = 'ssl://' . $host;
+            }
+            $fp = @fsockopen($host, $port, $errno, $errstr);
+            if (!$fp) {
+                return PEAR::raiseError("Connection to `$host:$port' failed: $errstr", $errno);
+            }
+        }
+        fwrite($fp, $request);
+        $headers = array();
+        while (trim($line = fgets($fp, 1024))) {
+            if (preg_match('/^([^:]+):\s+(.*)\s*$/', $line, $matches)) {
+                $headers[strtolower($matches[1])] = trim($matches[2]);
+            } elseif (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) {
+                if ($matches[1] == 304 && ($lastmodified || ($lastmodified === false))) {
+                    return false;
+                }
+                if ($matches[1] != 200) {
+                    return PEAR::raiseError("File http://$host:$port$path not valid (received: $line)");
+                }
+            }
+        }
+        if (isset($headers['content-length'])) {
+            $length = $headers['content-length'];
+        } else {
+            $length = -1;
+        }
+        $data = '';
+        while ($chunk = @fread($fp, 8192)) {
+            $data .= $chunk;
+        }
+        fclose($fp);
+        if ($lastmodified === false || $lastmodified) {
+            if (isset($headers['etag'])) {
+                $lastmodified = array('ETag' => $headers['etag']);
+            }
+            if (isset($headers['last-modified'])) {
+                if (is_array($lastmodified)) {
+                    $lastmodified['Last-Modified'] = $headers['last-modified'];
+                } else {
+                    $lastmodified = $headers['last-modified'];
+                }
+            }
+            return array($data, $lastmodified, $headers);
+        }
+        return $data;
+    }
+}
+?>
\ No newline at end of file
diff --git a/pear/PEAR/REST/10.php b/pear/PEAR/REST/10.php
new file mode 100644 (file)
index 0000000..f359dac
--- /dev/null
@@ -0,0 +1,621 @@
+<?php
+/**
+ * PEAR_REST_10
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a12
+ */
+
+/**
+ * For downloading REST xml/txt files
+ */
+require_once 'PEAR/REST.php';
+
+/**
+ * Implement REST 1.0
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a12
+ */
+class PEAR_REST_10
+{
+    /**
+     * @var PEAR_REST
+     */
+    var $_rest;
+    function PEAR_REST_10($config, $options = array())
+    {
+        $this->_rest = &new PEAR_REST($config, $options);
+    }
+
+    function getDownloadURL($base, $packageinfo, $prefstate, $installed)
+    {
+        $channel = $packageinfo['channel'];
+        $package = $packageinfo['package'];
+        $states = $this->betterStates($prefstate, true);
+        if (!$states) {
+            return PEAR::raiseError('"' . $prefstate . '" is not a valid state');
+        }
+        $state = $version = null;
+        if (isset($packageinfo['state'])) {
+            $state = $packageinfo['state'];
+        }
+        if (isset($packageinfo['version'])) {
+            $version = $packageinfo['version'];
+        }
+        $info = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . '/allreleases.xml');
+        if (PEAR::isError($info)) {
+            return PEAR::raiseError('No releases available for package "' .
+                $channel . '/' . $package . '"');
+        }
+        if (!isset($info['r'])) {
+            return false;
+        }
+        $found = false;
+        $release = false;
+        if (!is_array($info['r']) || !isset($info['r'][0])) {
+            $info['r'] = array($info['r']);
+        }
+        foreach ($info['r'] as $release) {
+            if (!isset($this->_rest->_options['force']) && ($installed &&
+                  version_compare($release['v'], $installed, '<'))) {
+                continue;
+            }
+            if (isset($state)) {
+                if ($release['s'] == $state) {
+                    $found = true;
+                    break;
+                }
+            } elseif (isset($version)) {
+                if ($release['v'] == $version) {
+                    $found = true;
+                    break;
+                }
+            } else {
+                if (in_array($release['s'], $states)) {
+                    $found = true;
+                    break;
+                }
+            }
+        }
+        return $this->_returnDownloadURL($base, $package, $release, $info, $found);
+    }
+
+    function getDepDownloadURL($base, $xsdversion, $dependency, $deppackage,
+                               $prefstate = 'stable', $installed = false)
+    {
+        $channel = $dependency['channel'];
+        $package = $dependency['name'];
+        $states = $this->betterStates($prefstate, true);
+        if (!$states) {
+            return PEAR::raiseError('"' . $prefstate . '" is not a valid state');
+        }
+        $state = $version = null;
+        if (isset($packageinfo['state'])) {
+            $state = $packageinfo['state'];
+        }
+        if (isset($packageinfo['version'])) {
+            $version = $packageinfo['version'];
+        }
+        $info = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . '/allreleases.xml');
+        if (PEAR::isError($info)) {
+            return PEAR::raiseError('Package "' . $deppackage['channel'] . '/' . $deppackage['package']
+                . '" dependency "' . $channel . '/' . $package . '" has no releases');
+        }
+        if (!is_array($info) || !isset($info['r'])) {
+            return false;
+        }
+        $exclude = array();
+        $min = $max = $recommended = false;
+        if ($xsdversion == '1.0') {
+            $pinfo['package'] = $dependency['name'];
+            $pinfo['channel'] = 'pear.php.net'; // this is always true - don't change this
+            switch ($dependency['rel']) {
+                case 'ge' :
+                    $min = $dependency['version'];
+                break;
+                case 'gt' :
+                    $min = $dependency['version'];
+                    $exclude = array($dependency['version']);
+                break;
+                case 'eq' :
+                    $recommended = $dependency['version'];
+                break;
+                case 'lt' :
+                    $max = $dependency['version'];
+                    $exclude = array($dependency['version']);
+                break;
+                case 'le' :
+                    $max = $dependency['version'];
+                break;
+                case 'ne' :
+                    $exclude = array($dependency['version']);
+                break;
+            }
+        } else {
+            $pinfo['package'] = $dependency['name'];
+            $min = isset($dependency['min']) ? $dependency['min'] : false;
+            $max = isset($dependency['max']) ? $dependency['max'] : false;
+            $recommended = isset($dependency['recommended']) ?
+                $dependency['recommended'] : false;
+            if (isset($dependency['exclude'])) {
+                if (!isset($dependency['exclude'][0])) {
+                    $exclude = array($dependency['exclude']);
+                }
+            }
+        }
+        $found = false;
+        $release = false;
+        if (!is_array($info['r']) || !isset($info['r'][0])) {
+            $info['r'] = array($info['r']);
+        }
+        foreach ($info['r'] as $release) {
+            if (!isset($this->_rest->_options['force']) && ($installed &&
+                  version_compare($release['v'], $installed, '<'))) {
+                continue;
+            }
+            if (in_array($release['v'], $exclude)) { // skip excluded versions
+                continue;
+            }
+            // allow newer releases to say "I'm OK with the dependent package"
+            if ($xsdversion == '2.0' && isset($release['co'])) {
+                if (!is_array($release['co']) || !isset($release['co'][0])) {
+                    $release['co'] = array($release['co']);
+                }
+                foreach ($release['co'] as $entry) {
+                    if (isset($entry['x']) && !is_array($entry['x'])) {
+                        $entry['x'] = array($entry['x']);
+                    } elseif (!isset($entry['x'])) {
+                        $entry['x'] = array();
+                    }
+                    if ($entry['c'] == $deppackage['channel'] &&
+                          strtolower($entry['p']) == strtolower($deppackage['package']) &&
+                          version_compare($deppackage['version'], $entry['min'], '>=') &&
+                          version_compare($deppackage['version'], $entry['max'], '<=') &&
+                          !in_array($release['v'], $entry['x'])) {
+                        $recommended = $release['v'];
+                        break;
+                    }
+                }
+            }
+            if ($recommended) {
+                if ($release['v'] != $recommended) { // if we want a specific
+                    // version, then skip all others
+                    continue;
+                } else {
+                    if (!in_array($release['s'], $states)) {
+                        // the stability is too low, but we must return the
+                        // recommended version if possible
+                        return $this->_returnDownloadURL($base, $package, $release, $info, true);
+                    }
+                }
+            }
+            if ($min && version_compare($release['v'], $min, 'lt')) { // skip too old versions
+                continue;
+            }
+            if ($max && version_compare($release['v'], $max, 'gt')) { // skip too new versions
+                continue;
+            }
+            if ($installed && version_compare($release['v'], $installed, '<')) {
+                continue;
+            }
+            if (in_array($release['s'], $states)) { // if in the preferred state...
+                $found = true; // ... then use it
+                break;
+            }
+        }
+        return $this->_returnDownloadURL($base, $package, $release, $info, $found);
+    }
+
+    function _returnDownloadURL($base, $package, $release, $info, $found)
+    {
+        if (!$found) {
+            $release = $info['r'][0];
+        }
+        $releaseinfo = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/' . 
+            $release['v'] . '.xml');
+        if (PEAR::isError($releaseinfo)) {
+            return PEAR::raiseError('Package "' . $package . '" Version "' . $release['v'] .
+                '" does not have REST xml available');
+        }
+        $packagexml = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/' .
+            'deps.' . $release['v'] . '.txt', false, true);
+        if (PEAR::isError($packagexml)) {
+            return PEAR::raiseError('Package "' . $package . '" Version "' . $release['v'] .
+                '" does not have REST dependency information available');
+        }
+        $packagexml = unserialize($packagexml);
+        if (!$packagexml) {
+            $packagexml = array();
+        }
+        $allinfo = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
+            '/allreleases.xml');
+        if (!is_array($allinfo['r']) || !isset($allinfo['r'][0])) {
+            $allinfo['r'] = array($allinfo['r']);
+        }
+        $compatible = false;
+        foreach ($allinfo['r'] as $release) {
+            if ($release['v'] != $releaseinfo['v']) {
+                continue;
+            }
+            if (!isset($release['co'])) {
+                break;
+            }
+            $compatible = array();
+            if (!is_array($release['co']) || !isset($release['co'][0])) {
+                $release['co'] = array($release['co']);
+            }
+            foreach ($release['co'] as $entry) {
+                $comp = array();
+                $comp['name'] = $entry['p'];
+                $comp['channel'] = $entry['c'];
+                $comp['min'] = $entry['min'];
+                $comp['max'] = $entry['max'];
+                if (isset($entry['x']) && !is_array($entry['x'])) {
+                    $comp['exclude'] = $entry['x'];
+                }
+                $compatible[] = $comp;
+            }
+            if (count($compatible) == 1) {
+                $compatible = $compatible[0];
+            }
+            break;
+        }
+        if ($found) {
+            return 
+                array('version' => $releaseinfo['v'],
+                      'info' => $packagexml,
+                      'package' => $releaseinfo['p']['_content'],
+                      'stability' => $releaseinfo['st'],
+                      'url' => $releaseinfo['g'],
+                      'compatible' => $compatible);
+        } else {
+            return
+                array('version' => $releaseinfo['v'],
+                      'package' => $releaseinfo['p']['_content'],
+                      'stability' => $releaseinfo['st'],
+                      'info' => $packagexml,
+                      'compatible' => $compatible);
+        }
+    }
+
+    function listPackages($base)
+    {
+        $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml');
+        if (PEAR::isError($packagelist)) {
+            return $packagelist;
+        }
+        if (!is_array($packagelist['p'])) {
+            $packagelist['p'] = array($packagelist['p']);
+        }
+        return $packagelist['p'];
+    }
+
+    function listAll($base, $dostable, $basic = true, $searchpackage = false, $searchsummary = false)
+    {
+        $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml');
+        if (PEAR::isError($packagelist)) {
+            return $packagelist;
+        }
+        if ($this->_rest->config->get('verbose') > 0) {
+            $ui = &PEAR_Frontend::singleton();
+            $ui->log('Retrieving data...0%', false);
+        }
+        $ret = array();
+        if (!is_array($packagelist) || !isset($packagelist['p'])) {
+            return $ret;
+        }
+        if (!is_array($packagelist['p'])) {
+            $packagelist['p'] = array($packagelist['p']);
+        }
+        PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+        $next = .1;
+        foreach ($packagelist['p'] as $progress => $package) {
+            if ($this->_rest->config->get('verbose') > 0) {
+                if ($progress / count($packagelist['p']) >= $next) {
+                    if ($next == .5) {
+                        $ui->log('50%', false);
+                    } else {
+                        $ui->log('.', false);
+                    }
+                    $next += .1;
+                }
+            }
+            if ($basic) { // remote-list command
+                if ($dostable) {
+                    $latest = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
+                        '/stable.txt');
+                } else {
+                    $latest = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
+                        '/latest.txt');
+                }
+                if (PEAR::isError($latest)) {
+                    $latest = false;
+                }
+                $info = array('stable' => $latest);
+            } else { // list-all command
+                $inf = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml');
+                if (PEAR::isError($inf)) {
+                    PEAR::popErrorHandling();
+                    return $inf;
+                }
+                if ($searchpackage) {
+                    $found = (!empty($searchpackage) && stristr($package, $searchpackage) !== false);
+                    if (!$found && !(isset($searchsummary) && !empty($searchsummary)
+                        && (stristr($inf['s'], $searchsummary) !== false
+                            || stristr($inf['d'], $searchsummary) !== false)))
+                    {
+                        continue;
+                    };
+                }
+                $releases = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
+                    '/allreleases.xml');
+                if (PEAR::isError($releases)) {
+                    continue;
+                }
+                if (!isset($releases['r'][0])) {
+                    $releases['r'] = array($releases['r']);
+                }
+                unset($latest);
+                unset($unstable);
+                unset($stable);
+                unset($state);
+                foreach ($releases['r'] as $release) {
+                    if (!isset($latest)) {
+                        if ($dostable && $release['s'] == 'stable') {
+                            $latest = $release['v'];
+                            $state = 'stable';
+                        }
+                        if (!$dostable) {
+                            $latest = $release['v'];
+                            $state = $release['s'];
+                        }
+                    }
+                    if (!isset($stable) && $release['s'] == 'stable') {
+                        $stable = $release['v'];
+                        if (!isset($unstable)) {
+                            $unstable = $stable;
+                        }
+                    }
+                    if (!isset($unstable) && $release['s'] != 'stable') {
+                        $latest = $unstable = $release['v'];
+                        $state = $release['s'];
+                    }
+                    if (isset($latest) && !isset($state)) {
+                        $state = $release['s'];
+                    }
+                    if (isset($latest) && isset($stable) && isset($unstable)) {
+                        break;
+                    }
+                }
+                $deps = array();
+                if (!isset($unstable)) {
+                    $unstable = false;
+                    $state = 'stable';
+                    if (isset($stable)) {
+                        $latest = $unstable = $stable;
+                    }
+                } else {
+                    $latest = $unstable;
+                }
+                if (!isset($latest)) {
+                    $latest = false;
+                }
+                if ($latest) {
+                    $d = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/deps.' .
+                        $latest . '.txt');
+                    if (!PEAR::isError($d)) {
+                        $d = unserialize($d);
+                        if ($d) {
+                            if (isset($d['required'])) {
+                                if (!class_exists('PEAR_PackageFile_v2')) {
+                                    require_once 'PEAR/PackageFile/v2.php';
+                                }
+                                if (!isset($pf)) {
+                                    $pf = new PEAR_PackageFile_v2;
+                                }
+                                $pf->setDeps($d);
+                                $tdeps = $pf->getDeps();
+                            } else {
+                                $tdeps = $d;
+                            }
+                            foreach ($tdeps as $dep) {
+                                if ($dep['type'] !== 'pkg') {
+                                    continue;
+                                }
+                                $deps[] = $dep;
+                            }
+                        }
+                    }
+                }
+                if (!isset($stable)) {
+                    $stable = '-n/a-';
+                }
+                if (!$searchpackage) {
+                    $info = array('stable' => $latest, 'summary' => $inf['s'], 'description' =>
+                        $inf['d'], 'deps' => $deps, 'category' => $inf['ca']['_content'],
+                        'unstable' => $unstable, 'state' => $state);
+                } else {
+                    $info = array('stable' => $stable, 'summary' => $inf['s'], 'description' =>
+                        $inf['d'], 'deps' => $deps, 'category' => $inf['ca']['_content'],
+                        'unstable' => $unstable, 'state' => $state);
+                }
+            }
+            $ret[$package] = $info;
+        }
+        PEAR::popErrorHandling();
+        return $ret;
+    }
+
+    function listLatestUpgrades($base, $state, $installed, $channel, &$reg)
+    {
+        $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml');
+        if (PEAR::isError($packagelist)) {
+            return $packagelist;
+        }
+        $ret = array();
+        if (!is_array($packagelist) || !isset($packagelist['p'])) {
+            return $ret;
+        }
+        if (!is_array($packagelist['p'])) {
+            $packagelist['p'] = array($packagelist['p']);
+        }
+        if ($state) {
+            $states = $this->betterStates($state, true);
+        }
+        foreach ($packagelist['p'] as $package) {
+            if (!isset($installed[strtolower($package)])) {
+                continue;
+            }
+            $inst_version = $reg->packageInfo($package, 'version', $channel);
+            PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+            $info = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
+                '/allreleases.xml');
+            PEAR::popErrorHandling();
+            if (PEAR::isError($info)) {
+                continue; // no remote releases
+            }
+            if (!isset($info['r'])) {
+                continue;
+            }
+            $found = false;
+            $release = false;
+            if (!is_array($info['r']) || !isset($info['r'][0])) {
+                $info['r'] = array($info['r']);
+            }
+            foreach ($info['r'] as $release) {
+                if ($inst_version && version_compare($release['v'], $inst_version, '<=')) {
+                    continue;
+                }
+                if ($state) {
+                    if (in_array($release['s'], $states)) {
+                        $found = true;
+                        break;
+                    }
+                } else {
+                    $found = true;
+                    break;
+                }
+            }
+            if (!$found) {
+                continue;
+            }
+            $relinfo = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/' . 
+                $release['v'] . '.xml');
+            if (PEAR::isError($relinfo)) {
+                return $relinfo;
+            }
+            $ret[$package] = array(
+                    'version' => $release['v'],
+                    'state' => $release['s'],
+                    'filesize' => $relinfo['f'],
+                );
+        }
+        return $ret;
+    }
+
+    function packageInfo($base, $package)
+    {
+        PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+        $pinfo = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml');
+        if (PEAR::isError($pinfo)) {
+            PEAR::popErrorHandling();
+            return PEAR::raiseError('Unknown package: "' . $package . '" (Debug: ' .
+                $pinfo->getMessage() . ')');
+        }
+        $releases = array();
+        $allreleases = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
+            '/allreleases.xml');
+        if (!PEAR::isError($allreleases)) {
+            if (!class_exists('PEAR_PackageFile_v2')) {
+                require_once 'PEAR/PackageFile/v2.php';
+            }
+            if (!is_array($allreleases['r'])) {
+                $allreleases['r'] = array($allreleases['r']);
+            }
+            $pf = new PEAR_PackageFile_v2;
+            foreach ($allreleases['r'] as $release) {
+                $ds = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/deps.' .
+                    $release['v'] . '.txt');
+                if (PEAR::isError($ds)) {
+                    continue;
+                }
+                if (!isset($latest)) {
+                    $latest = $release['v'];
+                }
+                $pf->setDeps(unserialize($ds));
+                $ds = $pf->getDeps();
+                $info = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package)
+                    . '/' . $release['v'] . '.xml');
+                if (PEAR::isError($info)) {
+                    continue;
+                }
+                $releases[$release['v']] = array(
+                    'doneby' => $info['m'],
+                    'license' => $info['l'],
+                    'summary' => $info['s'],
+                    'description' => $info['d'],
+                    'releasedate' => $info['da'],
+                    'releasenotes' => $info['n'],
+                    'state' => $release['s'],
+                    'deps' => $ds ? $ds : array(),
+                );
+            }
+        } else {
+            $latest = '';
+        }
+        PEAR::popErrorHandling();
+        return array(
+            'name' => $pinfo['n'],
+            'channel' => $pinfo['c'],
+            'category' => $pinfo['ca']['_content'],
+            'stable' => $latest,
+            'license' => $pinfo['l'],
+            'summary' => $pinfo['s'],
+            'description' => $pinfo['d'],
+            'releases' => $releases,
+            );
+    }
+
+    /**
+     * Return an array containing all of the states that are more stable than
+     * or equal to the passed in state
+     *
+     * @param string Release state
+     * @param boolean Determines whether to include $state in the list
+     * @return false|array False if $state is not a valid release state
+     */
+    function betterStates($state, $include = false)
+    {
+        static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable');
+        $i = array_search($state, $states);
+        if ($i === false) {
+            return false;
+        }
+        if ($include) {
+            $i--;
+        }
+        return array_slice($states, $i + 1);
+    }
+}
+?>
\ No newline at end of file
diff --git a/pear/PEAR/REST/11.php b/pear/PEAR/REST/11.php
new file mode 100644 (file)
index 0000000..44e2b19
--- /dev/null
@@ -0,0 +1,206 @@
+<?php
+/**
+ * PEAR_REST_11 - implement faster list-all/remote-list command
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.3
+ */
+
+/**
+ * For downloading REST xml/txt files
+ */
+require_once 'PEAR/REST.php';
+
+/**
+ * Implement REST 1.1
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.3
+ */
+class PEAR_REST_11
+{
+    /**
+     * @var PEAR_REST
+     */
+    var $_rest;
+
+    function PEAR_REST_11($config, $options = array())
+    {
+        $this->_rest = &new PEAR_REST($config, $options);
+    }
+
+    function listAll($base, $dostable, $basic = true)
+    {
+        $categorylist = $this->_rest->retrieveData($base . 'c/categories.xml');
+        if (PEAR::isError($categorylist)) {
+            return $categorylist;
+        }
+        $ret = array();
+        if (!is_array($categorylist['c'])) {
+            $categorylist['c'] = array($categorylist['c']);
+        }
+        PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+        foreach ($categorylist['c'] as $progress => $category) {
+            $category = $category['_content'];
+            $packagesinfo = $this->_rest->retrieveData($base .
+                'c/' . urlencode($category) . '/packagesinfo.xml');
+            if (PEAR::isError($packagesinfo)) {
+                continue;
+            }
+            if (!is_array($packagesinfo) || !isset($packagesinfo['pi'])) {
+                continue;
+            }
+            if (!is_array($packagesinfo['pi']) || !isset($packagesinfo['pi'][0])) {
+                $packagesinfo['pi'] = array($packagesinfo['pi']);
+            }
+            foreach ($packagesinfo['pi'] as $packageinfo) {
+                $info = $packageinfo['p'];
+                $package = $info['n'];
+                $releases = isset($packageinfo['a']) ? $packageinfo['a'] : false;
+                unset($latest);
+                unset($unstable);
+                unset($stable);
+                unset($state);
+                if ($releases) {
+                    if (!isset($releases['r'][0])) {
+                        $releases['r'] = array($releases['r']);
+                    }
+                    foreach ($releases['r'] as $release) {
+                        if (!isset($latest)) {
+                            if ($dostable && $release['s'] == 'stable') {
+                                $latest = $release['v'];
+                                $state = 'stable';
+                            }
+                            if (!$dostable) {
+                                $latest = $release['v'];
+                                $state = $release['s'];
+                            }
+                        }
+                        if (!isset($stable) && $release['s'] == 'stable') {
+                            $stable = $release['v'];
+                            if (!isset($unstable)) {
+                                $unstable = $stable;
+                            }
+                        }
+                        if (!isset($unstable) && $release['s'] != 'stable') {
+                            $latest = $unstable = $release['v'];
+                            $state = $release['s'];
+                        }
+                        if (isset($latest) && !isset($state)) {
+                            $state = $release['s'];
+                        }
+                        if (isset($latest) && isset($stable) && isset($unstable)) {
+                            break;
+                        }
+                    }
+                }
+                if ($basic) { // remote-list command
+                    if (!isset($latest)) {
+                        $latest = false;
+                    }
+                    $ret[$package] = array('stable' => $latest);
+                    continue;
+                }
+                // list-all command
+                $deps = array();
+                if (!isset($unstable)) {
+                    $unstable = false;
+                    $state = 'stable';
+                    if (isset($stable)) {
+                        $latest = $unstable = $stable;
+                    }
+                } else {
+                    $latest = $unstable;
+                }
+                if (!isset($latest)) {
+                    $latest = false;
+                }
+                if ($latest) {
+                    if (isset($packageinfo['deps'])) {
+                        if (!isset($packageinfo['deps'][0])) {
+                            $packageinfo['deps'] = array($packageinfo['deps']);
+                        }
+                    }
+                    $d = false;
+                    foreach ($packageinfo['deps'] as $dep) {
+                        if ($dep['v'] == $latest) {
+                            $d = unserialize($dep['d']);
+                        }
+                    }
+                    if ($d) {
+                        if (isset($d['required'])) {
+                            if (!class_exists('PEAR_PackageFile_v2')) {
+                                require_once 'PEAR/PackageFile/v2.php';
+                            }
+                            if (!isset($pf)) {
+                                $pf = new PEAR_PackageFile_v2;
+                            }
+                            $pf->setDeps($d);
+                            $tdeps = $pf->getDeps();
+                        } else {
+                            $tdeps = $d;
+                        }
+                        foreach ($tdeps as $dep) {
+                            if ($dep['type'] !== 'pkg') {
+                                continue;
+                            }
+                            $deps[] = $dep;
+                        }
+                    }
+                }
+                if (!isset($stable)) {
+                    $stable = '-n/a-';
+                }
+                $info = array('stable' => $latest, 'summary' => $info['s'],
+                    'description' =>
+                    $info['d'], 'deps' => $deps, 'category' => $info['ca']['_content'],
+                    'unstable' => $unstable, 'state' => $state);
+                $ret[$package] = $info;
+            }
+        }
+        PEAR::popErrorHandling();
+        return $ret;
+    }
+
+    /**
+     * Return an array containing all of the states that are more stable than
+     * or equal to the passed in state
+     *
+     * @param string Release state
+     * @param boolean Determines whether to include $state in the list
+     * @return false|array False if $state is not a valid release state
+     */
+    function betterStates($state, $include = false)
+    {
+        static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable');
+        $i = array_search($state, $states);
+        if ($i === false) {
+            return false;
+        }
+        if ($include) {
+            $i--;
+        }
+        return array_slice($states, $i + 1);
+    }
+}
+?>
\ No newline at end of file
index 631328bea9ded13ce3cda441ae3bb91da5b296eb..cca21cbd0ec181ff55c861c37041c97c757828e8 100644 (file)
@@ -1,45 +1,62 @@
 <?php
-//
-// +----------------------------------------------------------------------+
-// | PHP Version 5                                                        |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2004 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 Bakken <ssb@php.net>                                    |
-// |         Tomas V.V.Cox <cox@idecnet.com>                              |
-// |                                                                      |
-// +----------------------------------------------------------------------+
-//
-// $Id$
-
-/*
-TODO:
-    - Transform into singleton()
-    - Add application level lock (avoid change the registry from the cmdline
-      while using the GTK interface, for ex.)
-*/
-require_once "System.php";
-require_once "PEAR.php";
+/**
+ * PEAR_Registry
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Tomas V. V. Cox <cox@idecnet.com>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 0.1
+ */
+
+/**
+ * for PEAR_Error
+ */
+require_once 'PEAR.php';
+require_once 'PEAR/DependencyDB.php';
 
 define('PEAR_REGISTRY_ERROR_LOCK',   -2);
 define('PEAR_REGISTRY_ERROR_FORMAT', -3);
 define('PEAR_REGISTRY_ERROR_FILE',   -4);
+define('PEAR_REGISTRY_ERROR_CONFLICT', -5);
+define('PEAR_REGISTRY_ERROR_CHANNEL_FILE', -6);
 
 /**
  * Administration class used to maintain the installed package database.
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Tomas V. V. Cox <cox@idecnet.com>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
  */
 class PEAR_Registry extends PEAR
 {
     // {{{ properties
 
+    /**
+     * File containing all channel information.
+     * @var string
+     */
+    var $channels = '';
+
     /** Directory where registry files are stored.
      * @var string
      */
@@ -50,6 +67,11 @@ class PEAR_Registry extends PEAR
      */
     var $filemap = '';
 
+    /** Directory where registry files for channels are stored.
+     * @var string
+     */
+    var $channelsdir = '';
+
     /** Name of file used for locking the registry
      * @var string
      */
@@ -79,6 +101,25 @@ class PEAR_Registry extends PEAR
      */
     var $filemap_cache = array();
 
+    /**
+     * @var false|PEAR_ChannelFile
+     */
+    var $_pearChannel;
+
+    /**
+     * @var false|PEAR_ChannelFile
+     */
+    var $_peclChannel;
+
+    /**
+     * @var PEAR_DependencyDB
+     */
+    var $_dependencyDB;
+
+    /**
+     * @var PEAR_Config
+     */
+    var $_config;
     // }}}
 
     // {{{ constructor
@@ -87,22 +128,130 @@ class PEAR_Registry extends PEAR
      * PEAR_Registry constructor.
      *
      * @param string (optional) PEAR install directory (for .php files)
+     * @param PEAR_ChannelFile PEAR_ChannelFile object representing the PEAR channel, if
+     *        default values are not desired.  Only used the very first time a PEAR
+     *        repository is initialized
+     * @param PEAR_ChannelFile PEAR_ChannelFile object representing the PECL channel, if
+     *        default values are not desired.  Only used the very first time a PEAR
+     *        repository is initialized
      *
      * @access public
      */
-    function PEAR_Registry($pear_install_dir = PEAR_INSTALL_DIR)
+    function PEAR_Registry($pear_install_dir = PEAR_INSTALL_DIR, $pear_channel = false,
+                           $pecl_channel = false)
     {
         parent::PEAR();
         $ds = DIRECTORY_SEPARATOR;
         $this->install_dir = $pear_install_dir;
+        $this->channelsdir = $pear_install_dir.$ds.'.channels';
         $this->statedir = $pear_install_dir.$ds.'.registry';
         $this->filemap  = $pear_install_dir.$ds.'.filemap';
         $this->lockfile = $pear_install_dir.$ds.'.lock';
+        $this->_pearChannel = $pear_channel;
+        $this->_peclChannel = $pecl_channel;
+        $this->_config = false;
+    }
+
+    function hasWriteAccess()
+    {
+        if (!@file_exists($this->install_dir)) {
+            $dir = $this->install_dir;
+            while ($dir && $dir != '.') {
+                $dir = dirname($dir); // cd ..
+                if ($dir != '.' && @file_exists($dir)) {
+                    if (@is_writeable($dir)) {
+                        return true;
+                    } else {
+                        return false;
+                    }
+                }
+            }
+            return false;
+        }
+        return @is_writeable($this->install_dir);
+    }
+
+    function setConfig(&$config)
+    {
+        $this->_config = &$config;
+    }
+
+    function _initializeChannelDirs()
+    {
+        static $running = false;
+        if (!$running) {
+            $running = true;
+            $ds = DIRECTORY_SEPARATOR;
+            if (!is_dir($this->channelsdir) ||
+                  !file_exists($this->channelsdir . $ds . 'pear.php.net.reg') ||
+                  !file_exists($this->channelsdir . $ds . 'pecl.php.net.reg') ||
+                  !file_exists($this->channelsdir . $ds . '__uri.reg')) {
+                if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) {
+                    $pear_channel = $this->_pearChannel;
+                    if (!is_a($pear_channel, 'PEAR_ChannelFile') || !$pear_channel->validate()) {
+                        if (!class_exists('PEAR_ChannelFile')) {
+                            require_once 'PEAR/ChannelFile.php';
+                        }
+                        $pear_channel = new PEAR_ChannelFile;
+                        $pear_channel->setName('pear.php.net');
+                        $pear_channel->setAlias('pear');
+                        $pear_channel->setServer('pear.php.net');
+                        $pear_channel->setSummary('PHP Extension and Application Repository');
+                        $pear_channel->setDefaultPEARProtocols();
+                        $pear_channel->setBaseURL('REST1.0', 'http://pear.php.net/rest/');
+                        $pear_channel->setBaseURL('REST1.1', 'http://pear.php.net/rest/');
+                    } else {
+                        $pear_channel->setName('pear.php.net');
+                        $pear_channel->setAlias('pear');
+                    }
+                    $pear_channel->validate();
+                    $this->_addChannel($pear_channel);
+                }
+                if (!file_exists($this->channelsdir . $ds . 'pecl.php.net.reg')) {
+                    $pecl_channel = $this->_peclChannel;
+                    if (!is_a($pecl_channel, 'PEAR_ChannelFile') || !$pecl_channel->validate()) {
+                        if (!class_exists('PEAR_ChannelFile')) {
+                            require_once 'PEAR/ChannelFile.php';
+                        }
+                        $pecl_channel = new PEAR_ChannelFile;
+                        $pecl_channel->setName('pecl.php.net');
+                        $pecl_channel->setAlias('pecl');
+                        $pecl_channel->setServer('pecl.php.net');
+                        $pecl_channel->setSummary('PHP Extension Community Library');
+                        $pecl_channel->setDefaultPEARProtocols();
+                        $pecl_channel->setBaseURL('REST1.0', 'http://pecl.php.net/rest/');
+                        $pecl_channel->setBaseURL('REST1.1', 'http://pecl.php.net/rest/');
+                        $pecl_channel->setValidationPackage('PEAR_Validator_PECL', '1.0');
+                    } else {
+                        $pecl_channel->setName('pecl.php.net');
+                        $pecl_channel->setAlias('pecl');
+                    }
+                    $pecl_channel->validate();
+                    $this->_addChannel($pecl_channel);
+                }
+                if (!file_exists($this->channelsdir . $ds . '__uri.reg')) {
+                    if (!class_exists('PEAR_ChannelFile')) {
+                        require_once 'PEAR/ChannelFile.php';
+                    }
+                    $private = new PEAR_ChannelFile;
+                    $private->setName('__uri');
+                    $private->addFunction('xmlrpc', '1.0', '****');
+                    $private->setSummary('Pseudo-channel for static packages');
+                    $this->_addChannel($private);
+                }
+                $this->_rebuildFileMap();
+            }
+            $running = false;
+        }
+    }
 
+    function _initializeDirs()
+    {
+        $ds = DIRECTORY_SEPARATOR;
         // XXX Compatibility code should be removed in the future
         // rename all registry files if any to lowercase
         if (!OS_WINDOWS && $handle = @opendir($this->statedir)) {
-            $dest = $this->statedir . DIRECTORY_SEPARATOR;
+            $dest = $this->statedir . $ds;
             while (false !== ($file = readdir($handle))) {
                 if (preg_match('/^.*[A-Z].*\.reg$/', $file)) {
                     rename($dest . $file, $dest . strtolower($file));
@@ -110,11 +259,45 @@ class PEAR_Registry extends PEAR
             }
             closedir($handle);
         }
+        $this->_initializeChannelDirs();
         if (!file_exists($this->filemap)) {
-            $this->rebuildFileMap();
+            $this->_rebuildFileMap();
         }
+        $this->_initializeDepDB();
     }
 
+    function _initializeDepDB()
+    {
+        if (!isset($this->_dependencyDB)) {
+            static $initializing = false;
+            if (!$initializing) {
+                $initializing = true;
+                if (!$this->_config) { // never used?
+                    if (OS_WINDOWS) {
+                        $file = 'pear.ini';
+                    } else {
+                        $file = '.pearrc';
+                    }
+                    $this->_config = &new PEAR_Config($this->statedir . DIRECTORY_SEPARATOR .
+                        $file);
+                    $this->_config->setRegistry($this);
+                    $this->_config->set('php_dir', $this->install_dir);
+                }
+                $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config);
+                if (PEAR::isError($this->_dependencyDB)) {
+                    // attempt to recover by removing the dep db
+                    @unlink($this->_config->get('php_dir', null, 'pear.php.net') .
+                        DIRECTORY_SEPARATOR . '.depdb');
+                    $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config);
+                    if (PEAR::isError($this->_dependencyDB)) {
+                        echo $this->_dependencyDB->getMessage();
+                        die('Unrecoverable error');
+                    }
+                }
+                $initializing = false;
+            }
+        }
+    }
     // }}}
     // {{{ destructor
 
@@ -143,12 +326,112 @@ class PEAR_Registry extends PEAR
      *
      * @access private
      */
-    function _assertStateDir()
+    function _assertStateDir($channel = false)
     {
+        if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') {
+            return $this->_assertChannelStateDir($channel);
+        }
+        static $init = false;
         if (!@is_dir($this->statedir)) {
+            if (!$this->hasWriteAccess()) {
+                return false;
+            }
+            require_once 'System.php';
             if (!System::mkdir(array('-p', $this->statedir))) {
                 return $this->raiseError("could not create directory '{$this->statedir}'");
             }
+            $init = true;
+        }
+        $ds = DIRECTORY_SEPARATOR;
+        if (!@is_dir($this->channelsdir) ||
+              !file_exists($this->channelsdir . $ds . 'pear.php.net.reg') ||
+              !file_exists($this->channelsdir . $ds . 'pecl.php.net.reg') ||
+              !file_exists($this->channelsdir . $ds . '__uri.reg')) {
+            $init = true;
+        }
+        if ($init) {
+            static $running = false;
+            if (!$running) {
+                $running = true;
+                $this->_initializeDirs();
+                $running = false;
+                $init = false;
+            }
+        } else {
+            $this->_initializeDepDB();
+        }
+        return true;
+    }
+
+    // }}}
+    // {{{ _assertChannelStateDir()
+
+    /**
+     * Make sure the directory where we keep registry files exists for a non-standard channel.
+     *
+     * @param string channel name
+     * @return bool TRUE if directory exists, FALSE if it could not be
+     * created
+     *
+     * @access private
+     */
+    function _assertChannelStateDir($channel)
+    {
+        $ds = DIRECTORY_SEPARATOR;
+        if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') {
+            if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) {
+                $this->_initializeChannelDirs();
+            }
+            return $this->_assertStateDir($channel);
+        }
+        $channelDir = $this->_channelDirectoryName($channel);
+        if (!is_dir($this->channelsdir) ||
+              !file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) {
+            $this->_initializeChannelDirs();
+        }
+        if (!@is_dir($channelDir)) {
+            if (!$this->hasWriteAccess()) {
+                return false;
+            }
+            require_once 'System.php';
+            if (!System::mkdir(array('-p', $channelDir))) {
+                return $this->raiseError("could not create directory '" . $channelDir .
+                    "'");
+            }
+        }
+        return true;
+    }
+
+    // }}}
+    // {{{ _assertChannelDir()
+
+    /**
+     * Make sure the directory where we keep registry files for channels exists
+     *
+     * @return bool TRUE if directory exists, FALSE if it could not be
+     * created
+     *
+     * @access private
+     */
+    function _assertChannelDir()
+    {
+        if (!@is_dir($this->channelsdir)) {
+            if (!$this->hasWriteAccess()) {
+                return false;
+            }
+            require_once 'System.php';
+            if (!System::mkdir(array('-p', $this->channelsdir))) {
+                return $this->raiseError("could not create directory '{$this->channelsdir}'");
+            }
+        }
+        if (!@is_dir($this->channelsdir . DIRECTORY_SEPARATOR . '.alias')) {
+            if (!$this->hasWriteAccess()) {
+                return false;
+            }
+            require_once 'System.php';
+            if (!System::mkdir(array('-p', $this->channelsdir . DIRECTORY_SEPARATOR . '.alias'))) {
+                return $this->raiseError("could not create directory '{$this->channelsdir}/.alias'");
+            }
         }
         return true;
     }
@@ -159,24 +442,141 @@ class PEAR_Registry extends PEAR
     /**
      * Get the name of the file where data for a given package is stored.
      *
+     * @param string channel name, or false if this is a PEAR package
      * @param string package name
      *
      * @return string registry file name
      *
      * @access public
      */
-    function _packageFileName($package)
+    function _packageFileName($package, $channel = false)
     {
+        if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') {
+            return $this->_channelDirectoryName($channel) . DIRECTORY_SEPARATOR .
+                strtolower($package) . '.reg';
+        }
         return $this->statedir . DIRECTORY_SEPARATOR . strtolower($package) . '.reg';
     }
 
+    // }}}
+    // {{{ _channelFileName()
+
+    /**
+     * Get the name of the file where data for a given channel is stored.
+     * @param string channel name
+     * @return string registry file name
+     */
+    function _channelFileName($channel, $noaliases = false)
+    {
+        if (!$noaliases) {
+            if (@file_exists($this->_getChannelAliasFileName($channel))) {
+                $channel = implode('', file($this->_getChannelAliasFileName($channel)));
+            }
+        }
+        return $this->channelsdir . DIRECTORY_SEPARATOR . str_replace('/', '_',
+            strtolower($channel)) . '.reg';
+    }
+
+    // }}}
+    // {{{ getChannelAliasFileName()
+
+    /**
+     * @param string
+     * @return string
+     */
+    function _getChannelAliasFileName($alias)
+    {
+        return $this->channelsdir . DIRECTORY_SEPARATOR . '.alias' .
+              DIRECTORY_SEPARATOR . str_replace('/', '_', strtolower($alias)) . '.txt';
+    }
+
+    // }}}
+    // {{{ _getChannelFromAlias()
+
+    /**
+     * Get the name of a channel from its alias
+     */
+    function _getChannelFromAlias($channel)
+    {
+        if (!$this->_channelExists($channel)) {
+            if ($channel == 'pear.php.net') {
+                return 'pear.php.net';
+            }
+            if ($channel == 'pecl.php.net') {
+                return 'pecl.php.net';
+            }
+            if ($channel == '__uri') {
+                return '__uri';
+            }
+            return false;
+        }
+        $channel = strtolower($channel);
+        if (file_exists($this->_getChannelAliasFileName($channel))) {
+            // translate an alias to an actual channel
+            return implode('', file($this->_getChannelAliasFileName($channel)));
+        } else {
+            return $channel;
+        }
+    }    
+    // }}}
+    // {{{ _getChannelFromAlias()
+
+    /**
+     * Get the alias of a channel from its alias or its name
+     */
+    function _getAlias($channel)
+    {
+        if (!$this->_channelExists($channel)) {
+            if ($channel == 'pear.php.net') {
+                return 'pear';
+            }
+            if ($channel == 'pecl.php.net') {
+                return 'pecl';
+            }
+            return false;
+        }
+        $channel = $this->_getChannel($channel);
+        return $channel->getAlias();
+    }    
+    // }}}
+    // {{{ _channelDirectoryName()
+
+    /**
+     * Get the name of the file where data for a given package is stored.
+     *
+     * @param string channel name, or false if this is a PEAR package
+     * @param string package name
+     *
+     * @return string registry file name
+     *
+     * @access public
+     */
+    function _channelDirectoryName($channel)
+    {
+        if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') {
+            return $this->statedir;
+        } else {
+            $ch = $this->_getChannelFromAlias($channel);
+            if (!$ch) {
+                $ch = $channel;
+            }
+            return $this->statedir . DIRECTORY_SEPARATOR . strtolower('.channel.' .
+                str_replace('/', '_', $ch));
+        }
+    }
+
     // }}}
     // {{{ _openPackageFile()
 
-    function _openPackageFile($package, $mode)
+    function _openPackageFile($package, $mode, $channel = false)
     {
-        $this->_assertStateDir();
-        $file = $this->_packageFileName($package);
+        if (!$this->_assertStateDir($channel)) {
+            return null;
+        }
+        if (!in_array($mode, array('r', 'rb')) && !$this->hasWriteAccess()) {
+            return null;
+        }
+        $file = $this->_packageFileName($package, $channel);
         $fp = @fopen($file, $mode);
         if (!$fp) {
             return null;
@@ -193,32 +593,86 @@ class PEAR_Registry extends PEAR
     }
 
     // }}}
-    // {{{ rebuildFileMap()
+    // {{{ _openPackageFile()
+
+    function _openChannelFile($channel, $mode)
+    {
+        if (!$this->_assertChannelDir()) {
+            return null;
+        }
+        if (!in_array($mode, array('r', 'rb')) && !$this->hasWriteAccess()) {
+            return null;
+        }
+        $file = $this->_channelFileName($channel);
+        $fp = @fopen($file, $mode);
+        if (!$fp) {
+            return null;
+        }
+        return $fp;
+    }
+
+    // }}}
+    // {{{ _closePackageFile()
+
+    function _closeChannelFile($fp)
+    {
+        fclose($fp);
+    }
+
+    // }}}
+    // {{{ _rebuildFileMap()
 
-    function rebuildFileMap()
+    function _rebuildFileMap()
     {
-        $packages = $this->listPackages();
+        if (!class_exists('PEAR_Installer_Role')) {
+            require_once 'PEAR/Installer/Role.php';
+        }
+        $channels = $this->_listAllPackages();
         $files = array();
-        foreach ($packages as $package) {
-            $version = $this->packageInfo($package, 'version');
-            $filelist = $this->packageInfo($package, 'filelist');
-            if (!is_array($filelist)) {
-                continue;
-            }
-            foreach ($filelist as $name => $attrs) {
-                if (isset($attrs['role']) && $attrs['role'] != 'php') {
+        foreach ($channels as $channel => $packages) {
+            foreach ($packages as $package) {
+                $version = $this->_packageInfo($package, 'version', $channel);
+                $filelist = $this->_packageInfo($package, 'filelist', $channel);
+                if (!is_array($filelist)) {
                     continue;
                 }
-                if (isset($attrs['baseinstalldir'])) {
-                    $file = $attrs['baseinstalldir'].DIRECTORY_SEPARATOR.$name;
-                } else {
-                    $file = $name;
+                foreach ($filelist as $name => $attrs) {
+                    if (isset($attrs['attribs'])) {
+                        $attrs = $attrs['attribs'];
+                    }
+                    // it is possible for conflicting packages in different channels to
+                    // conflict with data files/doc files
+                    if ($name == 'dirtree') {
+                        continue;
+                    }
+                    if (isset($attrs['role']) && !in_array($attrs['role'],
+                          PEAR_Installer_Role::getInstallableRoles())) {
+                        // these are not installed
+                        continue;
+                    }
+                    if (isset($attrs['role']) && !in_array($attrs['role'],
+                          PEAR_Installer_Role::getBaseinstallRoles())) {
+                        $attrs['baseinstalldir'] = $package;
+                    }
+                    if (isset($attrs['baseinstalldir'])) {
+                        $file = $attrs['baseinstalldir'].DIRECTORY_SEPARATOR.$name;
+                    } else {
+                        $file = $name;
+                    }
+                    $file = preg_replace(',^/+,', '', $file);
+                    if ($channel != 'pear.php.net') {
+                        $files[$attrs['role']][$file] = array(strtolower($channel),
+                            strtolower($package));
+                    } else {
+                        $files[$attrs['role']][$file] = strtolower($package);
+                    }
                 }
-                $file = preg_replace(',^/+,', '', $file);
-                $files[$file] = $package;
             }
         }
         $this->_assertStateDir();
+        if (!$this->hasWriteAccess()) {
+            return false;
+        }
         $fp = @fopen($this->filemap, 'wb');
         if (!$fp) {
             return false;
@@ -230,20 +684,26 @@ class PEAR_Registry extends PEAR
     }
 
     // }}}
-    // {{{ readFileMap()
+    // {{{ _readFileMap()
 
-    function readFileMap()
+    function _readFileMap()
     {
         $fp = @fopen($this->filemap, 'r');
         if (!$fp) {
             return $this->raiseError('PEAR_Registry: could not open filemap', PEAR_REGISTRY_ERROR_FILE, null, null, $php_errormsg);
         }
-        $fsize = filesize($this->filemap);
+        clearstatcache();
         $rt = get_magic_quotes_runtime();
         set_magic_quotes_runtime(0);
-        $data = fread($fp, $fsize);
+        $fsize = filesize($this->filemap);
+        if (function_exists('file_get_contents')) {
+            fclose($fp);
+            $data = file_get_contents($this->filemap);
+        } else {
+            $data = fread($fp, $fsize);
+            fclose($fp);
+        }
         set_magic_quotes_runtime($rt);
-        fclose($fp);
         $tmp = unserialize($data);
         if (!$tmp && $fsize > 7) {
             return $this->raiseError('PEAR_Registry: invalid filemap data', PEAR_REGISTRY_ERROR_FORMAT, null, null, $data);
@@ -274,8 +734,12 @@ class PEAR_Registry extends PEAR
                 // XXX does not check type of lock (LOCK_SH/LOCK_EX)
                 return true;
             }
-            if (PEAR::isError($err = $this->_assertStateDir())) {
-                return $err;
+            if (!$this->_assertStateDir()) {
+                if ($mode == LOCK_EX) {
+                    return $this->raiseError('Registry directory is not writeable by the current user');
+                } else {
+                    return true;
+                }
             }
             $open_mode = 'w';
             // XXX People reported problems with LOCK_SH and 'w'
@@ -324,94 +788,717 @@ class PEAR_Registry extends PEAR
     // }}}
     // {{{ _packageExists()
 
-    function _packageExists($package)
+    function _packageExists($package, $channel = false)
     {
-        return file_exists($this->_packageFileName($package));
+        return file_exists($this->_packageFileName($package, $channel));
     }
 
     // }}}
-    // {{{ _packageInfo()
+    // {{{ _channelExists()
 
-    function _packageInfo($package = null, $key = null)
+    /**
+     * Determine whether a channel exists in the registry
+     * @param string Channel name
+     * @param bool if true, then aliases will be ignored
+     * @return boolean
+     */
+    function _channelExists($channel, $noaliases = false)
     {
-        if ($package === null) {
-            return array_map(array($this, '_packageInfo'),
-                             $this->_listPackages());
-        }
-        $fp = $this->_openPackageFile($package, 'r');
-        if ($fp === null) {
-            return null;
-        }
-        $rt = get_magic_quotes_runtime();
-        set_magic_quotes_runtime(0);
-        $data = fread($fp, filesize($this->_packageFileName($package)));
-        set_magic_quotes_runtime($rt);
-        $this->_closePackageFile($fp);
-        $data = unserialize($data);
-        if ($key === null) {
-            return $data;
+        $a = file_exists($this->_channelFileName($channel, $noaliases));
+        if (!$a && $channel == 'pear.php.net') {
+            return true;
         }
-        if (isset($data[$key])) {
-            return $data[$key];
+        if (!$a && $channel == 'pecl.php.net') {
+            return true;
         }
-        return null;
+        return $a;
     }
 
     // }}}
-    // {{{ _listPackages()
+    // {{{ _addChannel()
 
-    function _listPackages()
+    /**
+     * @param PEAR_ChannelFile Channel object
+     * @param donotuse
+     * @param string Last-Modified HTTP tag from remote request
+     * @return boolean|PEAR_Error True on creation, false if it already exists
+     */
+    function _addChannel($channel, $update = false, $lastmodified = false)
     {
-        $pkglist = array();
-        $dp = @opendir($this->statedir);
-        if (!$dp) {
-            return $pkglist;
+        if (!is_a($channel, 'PEAR_ChannelFile')) {
+            return false;
         }
-        while ($ent = readdir($dp)) {
-            if ($ent{0} == '.' || substr($ent, -4) != '.reg') {
-                continue;
+        if (!$channel->validate()) {
+            return false;
+        }
+        if (file_exists($this->_channelFileName($channel->getName()))) {
+            if (!$update) {
+                return false;
+            }
+            $checker = $this->_getChannel($channel->getName());
+            if ($channel->getAlias() != $checker->getAlias()) {
+                @unlink($this->_getChannelAliasFileName($checker->getAlias()));
+            }
+        } else {
+            if ($update && !in_array($channel->getName(), array('pear.php.net', 'pecl.php.net'))) {
+                return false;
             }
-            $pkglist[] = substr($ent, 0, -4);
         }
-        return $pkglist;
+        $ret = $this->_assertChannelDir();
+        if (PEAR::isError($ret)) {
+            return $ret;
+        }
+        $ret = $this->_assertChannelStateDir($channel->getName());
+        if (PEAR::isError($ret)) {
+            return $ret;
+        }
+        if ($channel->getAlias() != $channel->getName()) {
+            if (file_exists($this->_getChannelAliasFileName($channel->getAlias())) &&
+                  $this->_getChannelFromAlias($channel->getAlias()) != $channel->getName()) {
+                $channel->setAlias($channel->getName());
+            }
+            if (!$this->hasWriteAccess()) {
+                return false;
+            }
+            $fp = @fopen($this->_getChannelAliasFileName($channel->getAlias()), 'w');
+            if (!$fp) {
+                return false;
+            }
+            fwrite($fp, $channel->getName());
+            fclose($fp);
+        }
+        if (!$this->hasWriteAccess()) {
+            return false;
+        }
+        $fp = @fopen($this->_channelFileName($channel->getName()), 'wb');
+        if (!$fp) {
+            return false;
+        }
+        $info = $channel->toArray();
+        if ($lastmodified) {
+            $info['_lastmodified'] = $lastmodified;
+        } else {
+            $info['_lastmodified'] = date('r');
+        }
+        fwrite($fp, serialize($info));
+        fclose($fp);
+        return true;
     }
 
     // }}}
+    // {{{ _deleteChannel()
 
-    // {{{ packageExists()
-
-    function packageExists($package)
+    /**
+     * Deletion fails if there are any packages installed from the channel
+     * @param string|PEAR_ChannelFile channel name
+     * @return boolean|PEAR_Error True on deletion, false if it doesn't exist
+     */
+    function _deleteChannel($channel)
     {
-        if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
-            return $e;
+        if (!is_string($channel)) {
+            if (is_a($channel, 'PEAR_ChannelFile')) {
+                if (!$channel->validate()) {
+                    return false;
+                }
+                $channel = $channel->getName();
+            } else {
+                return false;
+            }
         }
-        $ret = $this->_packageExists($package);
-        $this->_unlock();
-        return $ret;
-    }
+        if ($this->_getChannelFromAlias($channel) == '__uri') {
+            return false;
+        }
+        if ($this->_getChannelFromAlias($channel) == 'pecl.php.net') {
+            return false;
+        }
+        if (!$this->_channelExists($channel)) {
+            return false;
+        }
+        if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') {
+            return false;
+        }
+        $channel = $this->_getChannelFromAlias($channel);
+        if ($channel == 'pear.php.net') {
+            return false;
+        }
+        $test = $this->_listChannelPackages($channel);
+        if (count($test)) {
+            return false;
+        }
+        $test = @rmdir($this->_channelDirectoryName($channel));
+        if (!$test) {
+            return false;
+        }
+        $file = $this->_getChannelAliasFileName($this->_getAlias($channel));
+        if (@file_exists($file)) {
+            $test = @unlink($file);
+            if (!$test) {
+                return false;
+            }
+        }
+        $file = $this->_channelFileName($channel);
+        $ret = @unlink($file);
+        return $ret;
+    }
+
+    // }}}
+    // {{{ _isChannelAlias()
+
+    /**
+     * Determine whether a channel exists in the registry
+     * @param string Channel Alias
+     * @return boolean
+     */
+    function _isChannelAlias($alias)
+    {
+        return file_exists($this->_getChannelAliasFileName($alias));
+    }
+
+    // }}}
+    // {{{ _packageInfo()
+
+    /**
+     * @param string|null
+     * @param string|null
+     * @param string|null
+     * @return array|null
+     * @access private
+     */
+    function _packageInfo($package = null, $key = null, $channel = 'pear.php.net')
+    {
+        if ($package === null) {
+            if ($channel === null) {
+                $channels = $this->_listChannels();
+                $ret = array();
+                foreach ($channels as $channel) {
+                    $channel = strtolower($channel);
+                    $ret[$channel] = array();
+                    $packages = $this->_listPackages($channel);
+                    foreach ($packages as $package) {
+                        $ret[$channel][] = $this->_packageInfo($package, null, $channel);
+                    }
+                }
+                return $ret;
+            }
+            $ps = $this->_listPackages($channel);
+            if (!count($ps)) {
+                return array();
+            }
+            return array_map(array(&$this, '_packageInfo'),
+                             $ps, array_fill(0, count($ps), null),
+                             array_fill(0, count($ps), $channel));
+        }
+        $fp = $this->_openPackageFile($package, 'r', $channel);
+        if ($fp === null) {
+            return null;
+        }
+        $rt = get_magic_quotes_runtime();
+        set_magic_quotes_runtime(0);
+        clearstatcache();
+        if (function_exists('file_get_contents')) {
+            $this->_closePackageFile($fp);
+            $data = file_get_contents($this->_packageFileName($package, $channel));
+        } else {
+            $data = fread($fp, filesize($this->_packageFileName($package, $channel)));
+            $this->_closePackageFile($fp);
+        }
+        set_magic_quotes_runtime($rt);
+        $data = unserialize($data);
+        if ($key === null) {
+            return $data;
+        }
+        // compatibility for package.xml version 2.0
+        if (isset($data['old'][$key])) {
+            return $data['old'][$key];
+        }
+        if (isset($data[$key])) {
+            return $data[$key];
+        }
+        return null;
+    }
+
+    // }}}
+    // {{{ _channelInfo()
+
+    /**
+     * @param string Channel name
+     * @param bool whether to strictly retrieve info of channels, not just aliases
+     * @return array|null
+     */
+    function _channelInfo($channel, $noaliases = false)
+    {
+        if (!$this->_channelExists($channel, $noaliases)) {
+            return null;
+        }
+        $fp = $this->_openChannelFile($channel, 'r');
+        if ($fp === null) {
+            return null;
+        }
+        $rt = get_magic_quotes_runtime();
+        set_magic_quotes_runtime(0);
+        clearstatcache();
+        if (function_exists('file_get_contents')) {
+            $this->_closeChannelFile($fp);
+            $data = file_get_contents($this->_channelFileName($channel));
+        } else {
+            $data = fread($fp, filesize($this->_channelFileName($channel)));
+            $this->_closeChannelFile($fp);
+        }
+        set_magic_quotes_runtime($rt);
+        $data = unserialize($data);
+        return $data;
+    }
+
+    // }}}
+    // {{{ _listChannels()
+
+    function _listChannels()
+    {
+        $channellist = array();
+        $dp = @opendir($this->channelsdir);
+        if (!$dp  || !@is_dir($this->channelsdir)) {
+            return array('pear.php.net', 'pecl.php.net', '__uri');
+        }
+        while ($ent = readdir($dp)) {
+            if ($ent{0} == '.' || substr($ent, -4) != '.reg') {
+                continue;
+            }
+            $channellist[] = substr($ent, 0, -4);
+        }
+        closedir($dp);
+        if (!in_array('pear.php.net', $channellist)) {
+            $channellist[] = 'pear.php.net';
+        }
+        if (!in_array('pecl.php.net', $channellist)) {
+            $channellist[] = 'pecl.php.net';
+        }
+        if (!in_array('__uri', $channellist)) {
+            $channellist[] = '__uri';
+        }
+        return $channellist;
+    }
+
+    // }}}
+    // {{{ _listPackages()
+
+    function _listPackages($channel = false)
+    {
+        if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') {
+            return $this->_listChannelPackages($channel);
+        }
+        $pkglist = array();
+        $dp = @opendir($this->statedir);
+        if (!$dp) {
+            return $pkglist;
+        }
+        while ($ent = readdir($dp)) {
+            if ($ent{0} == '.' || substr($ent, -4) != '.reg') {
+                continue;
+            }
+            $pkglist[] = substr($ent, 0, -4);
+        }
+        closedir($dp);
+        return $pkglist;
+    }
+
+    // }}}
+    // {{{ _listChannelPackages()
+
+    function _listChannelPackages($channel)
+    {
+        $pkglist = array();
+        $dp = @opendir($this->_channelDirectoryName($channel));
+        if (!$dp) {
+            return $pkglist;
+        }
+        while ($ent = readdir($dp)) {
+            if ($ent{0} == '.' || substr($ent, -4) != '.reg') {
+                continue;
+            }
+            $pkglist[] = substr($ent, 0, -4);
+        }
+        closedir($dp);
+        return $pkglist;
+    }
+
+    // }}}
+    
+    function _listAllPackages()
+    {
+        $ret = array();
+        foreach ($this->_listChannels() as $channel) {
+            $ret[$channel] = $this->_listPackages($channel);
+        }
+        return $ret;
+    }
+
+    /**
+     * Add an installed package to the registry
+     * @param string package name
+     * @param array package info (parsed by PEAR_Common::infoFrom*() methods)
+     * @return bool success of saving
+     * @access private
+     */
+    function _addPackage($package, $info)
+    {
+        if ($this->_packageExists($package)) {
+            return false;
+        }
+        $fp = $this->_openPackageFile($package, 'wb');
+        if ($fp === null) {
+            return false;
+        }
+        $info['_lastmodified'] = time();
+        fwrite($fp, serialize($info));
+        $this->_closePackageFile($fp);
+        if (isset($info['filelist'])) {
+            $this->_rebuildFileMap();
+        }
+        return true;
+    }
+
+    /**
+     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+     * @return bool
+     * @access private
+     */
+    function _addPackage2($info)
+    {
+        if (!$info->validate()) {
+            if (class_exists('PEAR_Common')) {
+                $ui = PEAR_Frontend::singleton();
+                if ($ui) {
+                    foreach ($info->getValidationWarnings() as $err) {
+                        $ui->log(2, $err['message']);
+                    }
+                }
+            }
+            return false;
+        }
+        $channel = $info->getChannel();
+        $package = $info->getPackage();
+        $save = $info;
+        if ($this->_packageExists($package, $channel)) {
+            return false;
+        }
+        if (!$this->_channelExists($channel, true)) {
+            return false;
+        }
+        $info = $info->toArray(true);
+        if (!$info) {
+            return false;
+        }
+        $fp = $this->_openPackageFile($package, 'wb', $channel);
+        if ($fp === null) {
+            return false;
+        }
+        $info['_lastmodified'] = time();
+        fwrite($fp, serialize($info));
+        $this->_closePackageFile($fp);
+        $this->_rebuildFileMap();
+        return true;
+    }
+
+    /**
+     * @param string Package name
+     * @param array parsed package.xml 1.0
+     * @param bool this parameter is only here for BC.  Don't use it.
+     * @access private
+     */
+    function _updatePackage($package, $info, $merge = true)
+    {
+        $oldinfo = $this->_packageInfo($package);
+        if (empty($oldinfo)) {
+            return false;
+        }
+        $fp = $this->_openPackageFile($package, 'w');
+        if ($fp === null) {
+            return false;
+        }
+        if (is_object($info)) {
+            $info = $info->toArray();
+        }
+        $info['_lastmodified'] = time();
+        $newinfo = $info;
+        if ($merge) {
+            $info = array_merge($oldinfo, $info);
+        } else {
+            $diff = $info;
+        }
+        fwrite($fp, serialize($info));
+        $this->_closePackageFile($fp);
+        if (isset($newinfo['filelist'])) {
+            $this->_rebuildFileMap();
+        }
+        return true;
+    }
+
+    /**
+     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+     * @return bool
+     * @access private
+     */
+    function _updatePackage2($info)
+    {
+        if (!$this->_packageExists($info->getPackage(), $info->getChannel())) {
+            return false;
+        }
+        $fp = $this->_openPackageFile($info->getPackage(), 'w', $info->getChannel());
+        if ($fp === null) {
+            return false;
+        }
+        $save = $info;
+        $info = $save->getArray(true);
+        $info['_lastmodified'] = time();
+        fwrite($fp, serialize($info));
+        $this->_closePackageFile($fp);
+        $this->_rebuildFileMap();
+        return true;
+    }
+
+    /**
+     * @param string Package name
+     * @param string Channel name
+     * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null
+     * @access private
+     */
+    function &_getPackage($package, $channel = 'pear.php.net')
+    {
+        $info = $this->_packageInfo($package, null, $channel);
+        if ($info === null) {
+            return $info;
+        }
+        $a = $this->_config;
+        if (!$a) {
+            $this->_config = &new PEAR_Config;
+            $this->_config->set('php_dir', $this->statedir);
+        }
+        if (!class_exists('PEAR_PackageFile')) {
+            require_once 'PEAR/PackageFile.php';
+        }
+        $pkg = &new PEAR_PackageFile($this->_config);
+        $pf = &$pkg->fromArray($info);
+        return $pf;
+    }
+
+    /**
+     * @param string channel name
+     * @param bool whether to strictly retrieve channel names
+     * @return PEAR_ChannelFile|false
+     * @access private
+     */
+    function &_getChannel($channel, $noaliases = false)
+    {
+        $ch = false;
+        if ($this->_channelExists($channel, $noaliases)) {
+            if (!class_exists('PEAR_ChannelFile')) {
+                require_once 'PEAR/ChannelFile.php';
+            }
+            $ch = &PEAR_ChannelFile::fromArray($this->_channelInfo($channel, $noaliases));
+        }
+        if ($ch) {
+            return $ch;
+        }
+        if ($this->_getChannelFromAlias($channel) == 'pear.php.net') {
+            // the registry is not properly set up, so use defaults
+            if (!class_exists('PEAR_ChannelFile')) {
+                require_once 'PEAR/ChannelFile.php';
+            }
+            $pear_channel = new PEAR_ChannelFile;
+            $pear_channel->setName('pear.php.net');
+            $pear_channel->setAlias('pear');
+            $pear_channel->setSummary('PHP Extension and Application Repository');
+            $pear_channel->setDefaultPEARProtocols();
+            $pear_channel->setBaseURL('REST1.0', 'http://pear.php.net/rest/');
+            $pear_channel->setBaseURL('REST1.1', 'http://pear.php.net/rest/');
+            return $pear_channel;
+        }
+        if ($this->_getChannelFromAlias($channel) == 'pecl.php.net') {
+            // the registry is not properly set up, so use defaults
+            if (!class_exists('PEAR_ChannelFile')) {
+                require_once 'PEAR/ChannelFile.php';
+            }
+            $pear_channel = new PEAR_ChannelFile;
+            $pear_channel->setName('pecl.php.net');
+            $pear_channel->setAlias('pecl');
+            $pear_channel->setSummary('PHP Extension Community Library');
+            $pear_channel->setDefaultPEARProtocols();
+            $pear_channel->setBaseURL('REST1.0', 'http://pecl.php.net/rest/');
+            $pear_channel->setBaseURL('REST1.1', 'http://pecl.php.net/rest/');
+            $pear_channel->setValidationPackage('PEAR_Validator_PECL', '1.0');
+            return $pear_channel;
+        }
+        if ($this->_getChannelFromAlias($channel) == '__uri') {
+            // the registry is not properly set up, so use defaults
+            if (!class_exists('PEAR_ChannelFile')) {
+                require_once 'PEAR/ChannelFile.php';
+            }
+            $private = new PEAR_ChannelFile;
+            $private->setName('__uri');
+            $private->addFunction('xmlrpc', '1.0', '****');
+            $private->setSummary('Pseudo-channel for static packages');
+            return $private;
+        }
+        return $ch;
+    }
+
+    // {{{ packageExists()
+
+    /**
+     * @param string Package name
+     * @param string Channel name
+     * @return bool
+     */
+    function packageExists($package, $channel = 'pear.php.net')
+    {
+        if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
+            return $e;
+        }
+        $ret = $this->_packageExists($package, $channel);
+        $this->_unlock();
+        return $ret;
+    }
+
+    // }}}
+
+    // {{{ channelExists()
+
+    /**
+     * @param string channel name
+     * @param bool if true, then aliases will be ignored
+     * @return bool
+     */
+    function channelExists($channel, $noaliases = false)
+    {
+        if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
+            return $e;
+        }
+        $ret = $this->_channelExists($channel, $noaliases);
+        $this->_unlock();
+        return $ret;
+    }
+
+    // }}}
+
+    // {{{ isAlias()
+
+    /**
+     * Determines whether the parameter is an alias of a channel
+     * @param string
+     * @return bool
+     */
+    function isAlias($alias)
+    {
+        if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
+            return $e;
+        }
+        $ret = $this->_isChannelAlias($alias);
+        $this->_unlock();
+        return $ret;
+    }
+
+    // }}}
+    // {{{ packageInfo()
+
+    /**
+     * @param string|null
+     * @param string|null
+     * @param string
+     * @return array|null
+     */
+    function packageInfo($package = null, $key = null, $channel = 'pear.php.net')
+    {
+        if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
+            return $e;
+        }
+        $ret = $this->_packageInfo($package, $key, $channel);
+        $this->_unlock();
+        return $ret;
+    }
+
+    // }}}
+    // {{{ channelInfo()
+
+    /**
+     * Retrieve a raw array of channel data.
+     *
+     * Do not use this, instead use {@link getChannel()} for normal
+     * operations.  Array structure is undefined in this method
+     * @param string channel name
+     * @param bool whether to strictly retrieve information only on non-aliases
+     * @return array|null|PEAR_Error
+     */
+    function channelInfo($channel = null, $noaliases = false)
+    {
+        if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
+            return $e;
+        }
+        $ret = $this->_channelInfo($channel, $noaliases);
+        $this->_unlock();
+        return $ret;
+    }
 
     // }}}
-    // {{{ packageInfo()
 
-    function packageInfo($package = null, $key = null)
+    /**
+     * @param string
+     */
+    function channelName($channel)
     {
         if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
             return $e;
         }
-        $ret = $this->_packageInfo($package, $key);
+        $ret = $this->_getChannelFromAlias($channel);
         $this->_unlock();
         return $ret;
     }
 
-    // }}}
+    /**
+     * @param string
+     */
+    function channelAlias($channel)
+    {
+        if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
+            return $e;
+        }
+        $ret = $this->_getAlias($channel);
+        $this->_unlock();
+        return $ret;
+    }
     // {{{ listPackages()
 
-    function listPackages()
+    function listPackages($channel = false)
+    {
+        if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
+            return $e;
+        }
+        $ret = $this->_listPackages($channel);
+        $this->_unlock();
+        return $ret;
+    }
+
+    // }}}
+    // {{{ listAllPackages()
+
+    function listAllPackages()
     {
         if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
             return $e;
         }
-        $ret = $this->_listPackages();
+        $ret = $this->_listAllPackages();
+        $this->_unlock();
+        return $ret;
+    }
+
+    // }}}
+    // {{{ listChannel()
+
+    function listChannels()
+    {
+        if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
+            return $e;
+        }
+        $ret = $this->_listChannels();
         $this->_unlock();
         return $ret;
     }
@@ -419,38 +1506,133 @@ class PEAR_Registry extends PEAR
     // }}}
     // {{{ addPackage()
 
+    /**
+     * Add an installed package to the registry
+     * @param string|PEAR_PackageFile_v1|PEAR_PackageFile_v2 package name or object
+     *               that will be passed to {@link addPackage2()}
+     * @param array package info (parsed by PEAR_Common::infoFrom*() methods)
+     * @return bool success of saving
+     */
     function addPackage($package, $info)
     {
-        if ($this->packageExists($package)) {
+        if (is_object($info)) {
+            return $this->addPackage2($info);
+        }
+        if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
+            return $e;
+        }
+        $ret = $this->_addPackage($package, $info);
+        $this->_unlock();
+        if ($ret) {
+            if (!class_exists('PEAR_PackageFile_v1')) {
+                require_once 'PEAR/PackageFile/v1.php';
+            }
+            $pf = new PEAR_PackageFile_v1;
+            $pf->setConfig($this->_config);
+            $pf->fromArray($info);
+            $this->_dependencyDB->uninstallPackage($pf);
+            $this->_dependencyDB->installPackage($pf);
+        }
+        return $ret;
+    }
+
+    // }}}
+    // {{{ addPackage2()
+
+    function addPackage2($info)
+    {
+        if (!is_object($info)) {
+            return $this->addPackage($info['package'], $info);
+        }
+        if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
+            return $e;
+        }
+        $ret = $this->_addPackage2($info);
+        $this->_unlock();
+        if ($ret) {
+            $this->_dependencyDB->uninstallPackage($info);
+            $this->_dependencyDB->installPackage($info);
+        }
+        return $ret;
+    }
+
+    // }}}
+    // {{{ updateChannel()
+
+    /**
+     * For future expandibility purposes, separate this
+     * @param PEAR_ChannelFile
+     */
+    function updateChannel($channel, $lastmodified = null)
+    {
+        if ($channel->getName() == '__uri') {
             return false;
         }
+        return $this->addChannel($channel, $lastmodified, true);
+    }
+
+    // }}}
+    // {{{ deleteChannel()
+
+    /**
+     * Deletion fails if there are any packages installed from the channel
+     * @param string|PEAR_ChannelFile channel name
+     * @return boolean|PEAR_Error True on deletion, false if it doesn't exist
+     */
+    function deleteChannel($channel)
+    {
         if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
             return $e;
         }
-        $fp = $this->_openPackageFile($package, 'wb');
-        if ($fp === null) {
-            $this->_unlock();
+        $ret = $this->_deleteChannel($channel);
+        $this->_unlock();
+        if ($ret && is_a($this->_config, 'PEAR_Config')) {
+            $this->_config->setChannels($this->listChannels());
+        }
+        return $ret;
+    }
+
+    // }}}
+    // {{{ addChannel()
+
+    /**
+     * @param PEAR_ChannelFile Channel object
+     * @param string Last-Modified header from HTTP for caching
+     * @return boolean|PEAR_Error True on creation, false if it already exists
+     */
+    function addChannel($channel, $lastmodified = false, $update = false)
+    {
+        if (!is_a($channel, 'PEAR_ChannelFile')) {
             return false;
         }
-        $info['_lastmodified'] = time();
-        fwrite($fp, serialize($info));
-        $this->_closePackageFile($fp);
+        if (!$channel->validate()) {
+            return false;
+        }
+        if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
+            return $e;
+        }
+        $ret = $this->_addChannel($channel, $update, $lastmodified);
         $this->_unlock();
-        return true;
+        if (!$update && $ret && is_a($this->_config, 'PEAR_Config')) {
+            $this->_config->setChannels($this->listChannels());
+        }
+        return $ret;
     }
 
     // }}}
     // {{{ deletePackage()
 
-    function deletePackage($package)
+    function deletePackage($package, $channel = 'pear.php.net')
     {
         if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
             return $e;
         }
-        $file = $this->_packageFileName($package);
+        $file = $this->_packageFileName($package, $channel);
         $ret = @unlink($file);
-        $this->rebuildFileMap();
+        $this->_rebuildFileMap();
         $this->_unlock();
+        $p = array('channel' => $channel, 'package' => $package);
+        $this->_dependencyDB->uninstallPackage($p);
         return $ret;
     }
 
@@ -459,80 +1641,491 @@ class PEAR_Registry extends PEAR
 
     function updatePackage($package, $info, $merge = true)
     {
-        $oldinfo = $this->packageInfo($package);
-        if (empty($oldinfo)) {
+        if (is_object($info)) {
+            return $this->updatePackage2($info, $merge);
+        }
+        if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
+            return $e;
+        }
+        $ret = $this->_updatePackage($package, $info, $merge);
+        $this->_unlock();
+        if ($ret) {
+            $pf = new PEAR_PackageFile_v1;
+            $pf->setConfig($this->_config);
+            $pf->fromArray($this->packageInfo($package));
+            $this->_dependencyDB->uninstallPackage($pf);
+            $this->_dependencyDB->installPackage($pf);
+        }
+        return $ret;
+    }
+
+    // }}}
+    // {{{ updatePackage2()
+
+    function updatePackage2($info)
+    {
+        if (!is_object($info)) {
+            return $this->updatePackage($info['package'], $info, $merge);
+        }
+        if (!$info->validate(PEAR_VALIDATE_DOWNLOADING)) {
             return false;
         }
         if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
             return $e;
         }
-        $fp = $this->_openPackageFile($package, 'w');
-        if ($fp === null) {
-            $this->_unlock();
+        $ret = $this->_updatePackage2($info);
+        $this->_unlock();
+        if ($ret) {
+            $this->_dependencyDB->uninstallPackage($info);
+            $this->_dependencyDB->installPackage($info);
+        }
+        return $ret;
+    }
+
+    // }}}
+    // {{{ getChannel()
+    /**
+     * @param string channel name
+     * @param bool whether to strictly return raw channels (no aliases)
+     * @return PEAR_ChannelFile|false
+     */
+    function &getChannel($channel, $noaliases = false)
+    {
+        if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
+            return $e;
+        }
+        $ret = &$this->_getChannel($channel, $noaliases);
+        $this->_unlock();
+        return $ret;
+    }
+
+    // }}}
+    // {{{ getPackage()
+    /**
+     * @param string package name
+     * @param string channel name
+     * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null
+     */
+    function &getPackage($package, $channel = 'pear.php.net')
+    {
+        if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
+            return $e;
+        }
+        $pf = &$this->_getPackage($package, $channel);
+        $this->_unlock();
+        return $pf;
+    }
+
+    // }}}
+
+    /**
+     * Get PEAR_PackageFile_v[1/2] objects representing the contents of
+     * a dependency group that are installed.
+     *
+     * This is used at uninstall-time
+     * @param array
+     * @return array|false
+     */
+    function getInstalledGroup($group)
+    {
+        $ret = array();
+        if (isset($group['package'])) {
+            if (!isset($group['package'][0])) {
+                $group['package'] = array($group['package']);
+            }
+            foreach ($group['package'] as $package) {
+                $depchannel = isset($package['channel']) ? $package['channel'] : '__uri';
+                $p = &$this->getPackage($package['name'], $depchannel);
+                if ($p) {
+                    $save = &$p;
+                    $ret[] = &$save;
+                }
+            }
+        }
+        if (isset($group['subpackage'])) {
+            if (!isset($group['subpackage'][0])) {
+                $group['subpackage'] = array($group['subpackage']);
+            }
+            foreach ($group['subpackage'] as $package) {
+                $depchannel = isset($package['channel']) ? $package['channel'] : '__uri';
+                $p = &$this->getPackage($package['name'], $depchannel);
+                if ($p) {
+                    $save = &$p;
+                    $ret[] = &$save;
+                }
+            }
+        }
+        if (!count($ret)) {
             return false;
         }
-        $info['_lastmodified'] = time();
-        if ($merge) {
-            fwrite($fp, serialize(array_merge($oldinfo, $info)));
-        } else {
-            fwrite($fp, serialize($info));
+        return $ret;
+    }
+
+    // {{{ getChannelValidator()
+    /**
+     * @param string channel name
+     * @return PEAR_Validate|false
+     */
+    function &getChannelValidator($channel)
+    {
+        $chan = $this->getChannel($channel);
+        if (!$chan) {
+            return $chan;
         }
-        $this->_closePackageFile($fp);
-        if (isset($info['filelist'])) {
-            $this->rebuildFileMap();
+        $val = $chan->getValidationObject();
+        return $val;
+    }
+    // }}}
+    // {{{ getChannels()
+    /**
+     * @param string channel name
+     * @return array an array of PEAR_ChannelFile objects representing every installed channel
+     */
+    function &getChannels()
+    {
+        $ret = array();
+        if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
+            return $e;
+        }
+        foreach ($this->_listChannels() as $channel) {
+            $ret[] = &$this->_getChannel($channel);
         }
         $this->_unlock();
-        return true;
+        return $ret;
     }
 
     // }}}
     // {{{ checkFileMap()
 
     /**
-     * Test whether a file belongs to a package.
-     *
-     * @param string $path file path, absolute or relative to the pear
-     * install dir
+     * Test whether a file or set of files belongs to a package.
      *
-     * @return string which package the file belongs to, or an empty
-     * string if the file does not belong to an installed package
-     *
-     * @access public
+     * If an array is passed in
+     * @param string|array file path, absolute or relative to the pear
+     *                     install dir
+     * @param string|array name of PEAR package or array('package' => name, 'channel' =>
+     *                     channel) of a package that will be ignored
+     * @param string API version - 1.1 will exclude any files belonging to a package
+     * @param array private recursion variable
+     * @return array|false which package and channel the file belongs to, or an empty
+     *                     string if the file does not belong to an installed package,
+     *                     or belongs to the second parameter's package
      */
-    function checkFileMap($path)
+    function checkFileMap($path, $package = false, $api = '1.0', $attrs = false)
     {
         if (is_array($path)) {
             static $notempty;
             if (empty($notempty)) {
+                if (!class_exists('PEAR_Installer_Role')) {
+                    require_once 'PEAR/Installer/Role.php';
+                }
                 $notempty = create_function('$a','return !empty($a);');
             }
+            $package = is_array($package) ? array(strtolower($package[0]), strtolower($package[1]))
+                : strtolower($package);
             $pkgs = array();
             foreach ($path as $name => $attrs) {
-                if (is_array($attrs) && isset($attrs['baseinstalldir'])) {
-                    $name = $attrs['baseinstalldir'].DIRECTORY_SEPARATOR.$name;
+                if (is_array($attrs)) {
+                    if (isset($attrs['install-as'])) {
+                        $name = $attrs['install-as'];
+                    }
+                    if (!in_array($attrs['role'], PEAR_Installer_Role::getInstallableRoles())) {
+                        // these are not installed
+                        continue;
+                    }
+                    if (!in_array($attrs['role'], PEAR_Installer_Role::getBaseinstallRoles())) {
+                        $attrs['baseinstalldir'] = is_array($package) ? $package[1] : $package;
+                    }
+                    if (isset($attrs['baseinstalldir'])) {
+                        $name = $attrs['baseinstalldir'] . DIRECTORY_SEPARATOR . $name;
+                    }
+                }
+                $pkgs[$name] = $this->checkFileMap($name, $package, $api, $attrs);
+                if (PEAR::isError($pkgs[$name])) {
+                    return $pkgs[$name];
                 }
-                $pkgs[$name] = $this->checkFileMap($name);
             }
             return array_filter($pkgs, $notempty);
         }
-        if (empty($this->filemap_cache) && PEAR::isError($this->readFileMap())) {
-            return $err;
+        if (empty($this->filemap_cache)) {
+            if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
+                return $e;
+            }
+            $err = $this->_readFileMap();
+            $this->_unlock();
+            if (PEAR::isError($err)) {
+                return $err;
+            }
+        }
+        if (!$attrs) {
+            $attrs = array('role' => 'php'); // any old call would be for PHP role only
         }
-        if (isset($this->filemap_cache[$path])) {
-            return $this->filemap_cache[$path];
+        if (isset($this->filemap_cache[$attrs['role']][$path])) {
+            if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package) {
+                return false;
+            }
+            return $this->filemap_cache[$attrs['role']][$path];
         }
         $l = strlen($this->install_dir);
         if (substr($path, 0, $l) == $this->install_dir) {
             $path = preg_replace('!^'.DIRECTORY_SEPARATOR.'+!', '', substr($path, $l));
         }
-        if (isset($this->filemap_cache[$path])) {
-            return $this->filemap_cache[$path];
+        if (isset($this->filemap_cache[$attrs['role']][$path])) {
+            if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package) {
+                return false;
+            }
+            return $this->filemap_cache[$attrs['role']][$path];
         }
-        return '';
+        return false;
     }
 
     // }}}
+    // {{{ apiVersion()
+    /**
+     * Get the expected API version.  Channels API is version 1.1, as it is backwards
+     * compatible with 1.0
+     * @return string
+     */
+    function apiVersion()
+    {
+        return '1.1';
+    }
+    // }}}
+
+
+    /**
+     * Parse a package name, or validate a parsed package name array
+     * @param string|array pass in an array of format
+     *                     array(
+     *                      'package' => 'pname',
+     *                     ['channel' => 'channame',]
+     *                     ['version' => 'version',]
+     *                     ['state' => 'state',]
+     *                     ['group' => 'groupname'])
+     *                     or a string of format
+     *                     [channel://][channame/]pname[-version|-state][/group=groupname]
+     * @return array|PEAR_Error
+     */
+    function parsePackageName($param, $defaultchannel = 'pear.php.net')
+    {
+        $saveparam = $param;
+        if (is_array($param)) {
+            // convert to string for error messages
+            $saveparam = $this->parsedPackageNameToString($param);
+            // process the array
+            if (!isset($param['package'])) {
+                return PEAR::raiseError('parsePackageName(): array $param ' .
+                    'must contain a valid package name in index "param"',
+                    'package', null, null, $param);
+            }
+            if (!isset($param['uri'])) {
+                if (!isset($param['channel'])) {
+                    $param['channel'] = $defaultchannel;
+                }
+            } else {
+                $param['channel'] = '__uri';
+            }
+        } else {
+            $components = @parse_url($param);
+            if (isset($components['scheme'])) {
+                if ($components['scheme'] == 'http') {
+                    // uri package
+                    $param = array('uri' => $param, 'channel' => '__uri');
+                } elseif($components['scheme'] != 'channel') {
+                    return PEAR::raiseError('parsePackageName(): only channel:// uris may ' .
+                        'be downloaded, not "' . $param . '"', 'invalid', null, null, $param);
+                }
+            }
+            if (!isset($components['path'])) {
+                return PEAR::raiseError('parsePackageName(): array $param ' .
+                    'must contain a valid package name in "' . $param . '"',
+                    'package', null, null, $param);
+            }
+            if (isset($components['host'])) {
+                // remove the leading "/"
+                $components['path'] = substr($components['path'], 1);
+            }
+            if (!isset($components['scheme'])) {
+                if (strpos($components['path'], '/') !== false) {
+                    if ($components['path']{0} == '/') {
+                        return PEAR::raiseError('parsePackageName(): this is not ' .
+                            'a package name, it begins with "/" in "' . $param . '"',
+                            'invalid', null, null, $param);
+                    }
+                    $parts = explode('/', $components['path']);
+                    $components['host'] = array_shift($parts);
+                    if (count($parts) > 1) {
+                        $components['path'] = array_pop($parts);
+                        $components['host'] .= '/' . implode('/', $parts);
+                    } else {
+                        $components['path'] = implode('/', $parts);
+                    }
+                } else {
+                    $components['host'] = $defaultchannel;
+                }
+            } else {
+                if (strpos($components['path'], '/')) {
+                    $parts = explode('/', $components['path']);
+                    $components['path'] = array_pop($parts);
+                    $components['host'] .= '/' . implode('/', $parts);
+                }
+            }
+
+            if (is_array($param)) {
+                $param['package'] = $components['path'];
+            } else {
+                $param = array(
+                    'package' => $components['path']
+                    );
+                if (isset($components['host'])) {
+                    $param['channel'] = $components['host'];
+                }
+            }
+            if (isset($components['fragment'])) {
+                $param['group'] = $components['fragment'];
+            }
+            if (isset($components['user'])) {
+                $param['user'] = $components['user'];
+            }
+            if (isset($components['pass'])) {
+                $param['pass'] = $components['pass'];
+            }
+            if (isset($components['query'])) {
+                parse_str($components['query'], $param['opts']);
+            }
+            // check for extension
+            $pathinfo = pathinfo($param['package']);
+            if (isset($pathinfo['extension']) &&
+                  in_array(strtolower($pathinfo['extension']), array('tgz', 'tar'))) {
+                $param['extension'] = $pathinfo['extension'];
+                $param['package'] = substr($pathinfo['basename'], 0,
+                    strlen($pathinfo['basename']) - 4);
+            }
+            // check for version
+            if (strpos($param['package'], '-')) {
+                $test = explode('-', $param['package']);
+                if (count($test) != 2) {
+                    return PEAR::raiseError('parsePackageName(): only one version/state ' .
+                        'delimiter "-" is allowed in "' . $saveparam . '"',
+                        'version', null, null, $param);
+                }
+                list($param['package'], $param['version']) = $test;
+            }
+        }
+        // validation
+        $info = $this->channelExists($param['channel']);
+        if (PEAR::isError($info)) {
+            return $info;
+        }
+        if (!$info) {
+            return PEAR::raiseError('unknown channel "' . $param['channel'] .
+                '" in "' . $saveparam . '"', 'channel', null, null, $param);
+        }
+        $chan = $this->getChannel($param['channel']);
+        if (PEAR::isError($chan)) {
+            return $chan;
+        }
+        if (!$chan) {
+            return PEAR::raiseError("Exception: corrupt registry, could not " .
+                "retrieve channel " . $param['channel'] . " information",
+                'registry', null, null, $param);
+        }
+        $param['channel'] = $chan->getName();
+        $validate = $chan->getValidationObject();
+        $vpackage = $chan->getValidationPackage();
+        // validate package name
+        if (!$validate->validPackageName($param['package'], $vpackage['_content'])) {
+            return PEAR::raiseError('parsePackageName(): invalid package name "' .
+                $param['package'] . '" in "' . $saveparam . '"',
+                'package', null, null, $param);
+        }
+        if (isset($param['group'])) {
+            if (!PEAR_Validate::validGroupName($param['group'])) {
+                return PEAR::raiseError('parsePackageName(): dependency group "' . $param['group'] .
+                    '" is not a valid group name in "' . $saveparam . '"', 'group', null, null,
+                    $param);
+            }
+        }
+        if (isset($param['state'])) {
+            if (!in_array(strtolower($param['state']), $validate->getValidStates())) {
+                return PEAR::raiseError('parsePackageName(): state "' . $param['state']
+                    . '" is not a valid state in "' . $saveparam . '"',
+                    'state', null, null, $param);
+            }
+        }
+        if (isset($param['version'])) {
+            if (isset($param['state'])) {
+                return PEAR::raiseError('parsePackageName(): cannot contain both ' .
+                    'a version and a stability (state) in "' . $saveparam . '"',
+                    'version/state', null, null, $param);
+            }
+            // check whether version is actually a state
+            if (in_array(strtolower($param['version']), $validate->getValidStates())) {
+                $param['state'] = strtolower($param['version']);
+                unset($param['version']);
+            } else {
+                if (!$validate->validVersion($param['version'])) {
+                    return PEAR::raiseError('parsePackageName(): "' . $param['version'] .
+                        '" is neither a valid version nor a valid state in "' .
+                        $saveparam . '"', 'version/state', null, null, $param);
+                }                    
+            }
+        }
+        return $param;
+    }
 
+    /**
+     * @param array
+     * @return string
+     */
+    function parsedPackageNameToString($parsed, $brief = false)
+    {
+        if (is_string($parsed)) {
+            return $parsed;
+        }
+        if (is_object($parsed)) {
+            $p = $parsed;
+            $parsed = array(
+                'package' => $p->getPackage(),
+                'channel' => $p->getChannel(),
+                'version' => $p->getVersion(),
+            );
+        }
+        if (isset($parsed['uri'])) {
+            return $parsed['uri'];
+        }
+        if ($brief) {
+            if ($channel = $this->channelAlias($parsed['channel'])) {
+                return $channel . '/' . $parsed['package'];
+            }
+        }
+        $upass = '';
+        if (isset($parsed['user'])) {
+            $upass = $parsed['user'];
+            if (isset($parsed['pass'])) {
+                $upass .= ':' . $parsed['pass'];
+            }
+            $upass = "$upass@";
+        }
+        $ret = 'channel://' . $upass . $parsed['channel'] . '/' . $parsed['package'];
+        if (isset($parsed['version']) || isset($parsed['state'])) {
+            $ret .= '-' . @$parsed['version'] . @$parsed['state'];
+        }
+        if (isset($parsed['extension'])) {
+            $ret .= '.' . $parsed['extension'];
+        }
+        if (isset($parsed['opts'])) {
+            $ret .= '?';
+            foreach ($parsed['opts'] as $name => $value) {
+                $parsed['opts'][$name] = "$name=$value";
+            }
+            $ret .= implode('&', $parsed['opts']);
+        }
+        if (isset($parsed['group'])) {
+            $ret .= '#' . $parsed['group'];
+        }
+        return $ret;
+    }
 }
 
 ?>
index 555ec63b6c92407b49fd9e7cf45da952d3de40dd..e653e72909eed753290539ecf9e6e1cb51d9de2d 100644 (file)
@@ -1,23 +1,29 @@
 <?php
-//
-// +----------------------------------------------------------------------+
-// | PHP Version 5                                                        |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2004 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 Bakken <ssb@php.net>                                    |
-// +----------------------------------------------------------------------+
-//
-// $Id$
+/**
+ * PEAR_Remote
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 0.1
+ */
 
+/**
+ * needed for PEAR_Error
+ */
 require_once 'PEAR.php';
 require_once 'PEAR/Config.php';
 
@@ -28,6 +34,15 @@ require_once 'PEAR/Config.php';
  * @nodep XML_RPC_Value
  * @nodep XML_RPC_Message
  * @nodep XML_RPC_Client
+ * @category   pear
+ * @package    PEAR
+ * @author     Stig Bakken <ssb@php.net>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 0.1
  */
 class PEAR_Remote extends PEAR
 {
@@ -35,6 +50,11 @@ class PEAR_Remote extends PEAR
 
     var $config = null;
     var $cache  = null;
+    /**
+     * @var PEAR_Registry
+     * @access private
+     */
+    var $_registry;
 
     // }}}
 
@@ -44,10 +64,17 @@ class PEAR_Remote extends PEAR
     {
         $this->PEAR();
         $this->config = &$config;
+        $this->_registry = &$this->config->getRegistry();
     }
 
     // }}}
-
+    // {{{ setRegistry()
+    
+    function setRegistry(&$reg)
+    {
+        $this->_registry = &$reg;
+    }
+    // }}}
     // {{{ getCache()
 
 
@@ -58,14 +85,19 @@ class PEAR_Remote extends PEAR
         $filename = $cachedir . DIRECTORY_SEPARATOR . 'xmlrpc_cache_' . $id;
         if (!file_exists($filename)) {
             return null;
-        };
+        }
 
         $fp = fopen($filename, 'rb');
         if (!$fp) {
             return null;
         }
-        $content  = fread($fp, filesize($filename));
-        fclose($fp);
+        if (function_exists('file_get_contents')) {
+            fclose($fp);
+            $content = file_get_contents($filename);
+        } else {
+            $content  = fread($fp, filesize($filename));
+            fclose($fp);
+        }
         $result   = array(
             'age'        => time() - filemtime($filename),
             'lastChange' => filemtime($filename),
@@ -91,54 +123,105 @@ class PEAR_Remote extends PEAR
         if ($fp) {
             fwrite($fp, serialize($data));
             fclose($fp);
-        };
+        }
     }
 
     // }}}
 
+    // {{{ clearCache()
+
+    function clearCache($method, $args)
+    {
+        array_unshift($args, $method);
+        array_unshift($args, $this->config->get('default_channel')); // cache by channel
+        $id       = md5(serialize($args));
+        $cachedir = $this->config->get('cache_dir');
+        $filename = $cachedir.'/xmlrpc_cache_'.$id;
+        if (file_exists($filename)) {
+            @unlink($filename);
+        }
+    }
+
+    // }}}
     // {{{ call(method, [args...])
 
     function call($method)
     {
         $_args = $args = func_get_args();
 
-        $this->cache = $this->getCache($args);
+        $server_channel = $this->config->get('default_channel');
+        $channel = $this->_registry->getChannel($server_channel);
+        if ($channel) {
+            $mirror = $this->config->get('preferred_mirror');
+            if ($channel->getMirror($mirror)) {
+                if ($channel->supports('xmlrpc', $method, $mirror)) {
+                    $server_channel = $server_host = $mirror; // use the preferred mirror
+                    $server_port = $channel->getPort($mirror);
+                } elseif (!$channel->supports('xmlrpc', $method)) {
+                    return $this->raiseError("Channel $server_channel does not " .
+                        "support xml-rpc method $method");
+                }
+            }
+            if (!isset($server_host)) {
+                if (!$channel->supports('xmlrpc', $method)) {
+                    return $this->raiseError("Channel $server_channel does not support " .
+                        "xml-rpc method $method");
+                } else {
+                    $server_host = $server_channel;
+                    $server_port = $channel->getPort();
+                }
+            }
+        } else {
+            return $this->raiseError("Unknown channel '$server_channel'");
+        }
+
+        array_unshift($_args, $server_channel); // cache by channel
+        $this->cache = $this->getCache($_args);
         $cachettl = $this->config->get('cache_ttl');
         // If cache is newer than $cachettl seconds, we use the cache!
         if ($this->cache !== null && $this->cache['age'] < $cachettl) {
             return $this->cache['content'];
-        };
-
+        }
         if (extension_loaded("xmlrpc")) {
             $result = call_user_func_array(array(&$this, 'call_epi'), $args);
             if (!PEAR::isError($result)) {
                 $this->saveCache($_args, $result);
-            };
+            }
             return $result;
-        } elseif (!@include_once("XML/RPC.php")) {
-            return $this->raiseError("For this remote PEAR operation you need to install the XML_RPC package");
+        } elseif (!@include_once 'XML/RPC.php') {
+            return $this->raiseError("For this remote PEAR operation you need to load the xmlrpc extension or install XML_RPC");
         }
 
         array_shift($args);
-        $server_host = $this->config->get('master_server');
         $username = $this->config->get('username');
         $password = $this->config->get('password');
         $eargs = array();
-        foreach($args as $arg) $eargs[] = $this->_encode($arg);
+        foreach($args as $arg) {
+            $eargs[] = $this->_encode($arg);
+        }
         $f = new XML_RPC_Message($method, $eargs);
         if ($this->cache !== null) {
             $maxAge = '?maxAge='.$this->cache['lastChange'];
         } else {
             $maxAge = '';
-        };
+        }
         $proxy_host = $proxy_port = $proxy_user = $proxy_pass = '';
         if ($proxy = parse_url($this->config->get('http_proxy'))) {
             $proxy_host = @$proxy['host'];
+            if (isset($proxy['scheme']) && $proxy['scheme'] == 'https') {
+                $proxy_host = 'https://' . $proxy_host;
+            }
             $proxy_port = @$proxy['port'];
             $proxy_user = @urldecode(@$proxy['user']);
             $proxy_pass = @urldecode(@$proxy['pass']);
         }
-        $c = new XML_RPC_Client('/xmlrpc.php'.$maxAge, $server_host, 80, $proxy_host, $proxy_port, $proxy_user, $proxy_pass);
+        $shost = $server_host;
+        if ($channel->getSSL()) {
+            $shost = "https://$shost";
+        }
+        $c = new XML_RPC_Client('/' . $channel->getPath('xmlrpc')
+            . $maxAge, $shost, $server_port, $proxy_host, $proxy_port,
+            $proxy_user, $proxy_pass);
         if ($username && $password) {
             $c->setCredentials($username, $password);
         }
@@ -192,27 +275,57 @@ class PEAR_Remote extends PEAR
             }
             return $this->raiseError("unable to load xmlrpc extension");
         } while (false);
+        $server_channel = $this->config->get('default_channel');
+        $channel = $this->_registry->getChannel($server_channel);
+        if ($channel) {
+            $mirror = $this->config->get('preferred_mirror');
+            if ($channel->getMirror($mirror)) {
+                if ($channel->supports('xmlrpc', $method, $mirror)) {
+                    $server_channel = $server_host = $mirror; // use the preferred mirror
+                    $server_port = $channel->getPort($mirror);
+                } elseif (!$channel->supports('xmlrpc', $method)) {
+                    return $this->raiseError("Channel $server_channel does not " .
+                        "support xml-rpc method $method");
+                }
+            }
+            if (!isset($server_host)) {
+                if (!$channel->supports('xmlrpc', $method)) {
+                    return $this->raiseError("Channel $server_channel does not support " .
+                        "xml-rpc method $method");
+                } else {
+                    $server_host = $server_channel;
+                    $server_port = $channel->getPort();
+                }
+            }
+        } else {
+            return $this->raiseError("Unknown channel '$server_channel'");
+        }
         $params = func_get_args();
         array_shift($params);
         $method = str_replace("_", ".", $method);
         $request = xmlrpc_encode_request($method, $params);
-        $server_host = $this->config->get("master_server");
-        if (empty($server_host)) {
-            return $this->raiseError("PEAR_Remote::call: no master_server configured");
-        }
-        $server_port = 80;
         if ($http_proxy = $this->config->get('http_proxy')) {
             $proxy = parse_url($http_proxy);
             $proxy_host = $proxy_port = $proxy_user = $proxy_pass = '';
             $proxy_host = @$proxy['host'];
+            if (isset($proxy['scheme']) && $proxy['scheme'] == 'https') {
+                $proxy_host = 'ssl://' . $proxy_host;
+            }
             $proxy_port = @$proxy['port'];
             $proxy_user = @urldecode(@$proxy['user']);
             $proxy_pass = @urldecode(@$proxy['pass']);
             $fp = @fsockopen($proxy_host, $proxy_port);
             $use_proxy = true;
+            if ($channel->getSSL()) {
+                $server_host = "https://$server_host";
+            }
         } else {
             $use_proxy = false;
-            $fp = @fsockopen($server_host, $server_port);
+            $ssl = $channel->getSSL();
+            $fp = @fsockopen(($ssl ? 'ssl://' : '') . $server_host, $server_port);
+            if (!$fp) {
+                $server_host = "$ssl$server_host"; // for error-reporting
+            }
         }
         if (!$fp && $http_proxy) {
             return $this->raiseError("PEAR_Remote::call: fsockopen(`$proxy_host', $proxy_port) failed");
@@ -234,7 +347,7 @@ class PEAR_Remote extends PEAR
             $maxAge = '?maxAge='.$this->cache['lastChange'];
         } else {
             $maxAge = '';
-        };
+        }
 
         if ($use_proxy && $proxy_host != '' && $proxy_user != '') {
             $req_headers .= 'Proxy-Authorization: Basic '
@@ -258,7 +371,8 @@ class PEAR_Remote extends PEAR
             $post_string = "POST ";
         }
 
-        fwrite($fp, ($post_string."/xmlrpc.php$maxAge HTTP/1.0\r\n$req_headers\r\n$request"));
+        $path = '/' . $channel->getPath('xmlrpc');
+        fwrite($fp, ($post_string . $path . "$maxAge HTTP/1.0\r\n$req_headers\r\n$request"));
         $response = '';
         $line1 = fgets($fp, 2048);
         if (!preg_match('!^HTTP/[0-9\.]+ (\d+) (.*)!', $line1, $matches)) {
@@ -271,12 +385,16 @@ class PEAR_Remote extends PEAR
                 return $this->cache['content'];
             case "401": // Unauthorized
                 if ($username && $password) {
-                    return $this->raiseError("PEAR_Remote: authorization failed", 401);
+                    return $this->raiseError("PEAR_Remote ($server_host:$server_port) " .
+                        ": authorization failed", 401);
                 } else {
-                    return $this->raiseError("PEAR_Remote: authorization required, please log in first", 401);
+                    return $this->raiseError("PEAR_Remote ($server_host:$server_port) " .
+                        ": authorization required, please log in first", 401);
                 }
             default:
-                return $this->raiseError("PEAR_Remote: unexpected HTTP response", (int)$matches[1], null, null, "$matches[1] $matches[2]");
+                return $this->raiseError("PEAR_Remote ($server_host:$server_port) : " .
+                    "unexpected HTTP response", (int)$matches[1], null, null,
+                    "$matches[1] $matches[2]");
         }
         while (trim(fgets($fp, 2048)) != ''); // skip rest of headers
         while ($chunk = fread($fp, 10240)) {
@@ -315,6 +433,12 @@ class PEAR_Remote extends PEAR
             $faultString = "XML-RPC Server Fault: " .
                  str_replace("\n", " ", $faultString);
             return $this->raiseError($faultString, $faultCode);
+        } elseif (is_array($ret) && sizeof($ret) == 2 && !empty($ret['faultString']) &&
+              !empty($ret['faultCode'])) {
+            extract($ret);
+            $faultString = "XML-RPC Server Fault: " .
+                 str_replace("\n", " ", $faultString);
+            return $this->raiseError($faultString, $faultCode);
         }
         return $ret;
     }
@@ -338,6 +462,7 @@ class PEAR_Remote extends PEAR
                 $firstkey = key($php_val);
                 end($php_val);
                 $lastkey = key($php_val);
+                reset($php_val);
                 if ($firstkey === 0 && is_int($lastkey) &&
                     ($lastkey + 1) == count($php_val)) {
                     $is_continuous = true;
index 707bcdfe303bf6c781a878d880c9103c81b1c4db..3d851c3056699754d14b1d2176c07957f16bf08c 100644 (file)
@@ -1,58 +1,70 @@
 <?php
-//
-// +----------------------------------------------------------------------+
-// | PHP Version 5                                                        |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2004 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: Tomas V.V.Cox <cox@idecnet.com>                             |
-// |          Greg Beaver <cellog@php.net>                                |
-// |                                                                      |
-// +----------------------------------------------------------------------+
-//
-// $Id$
-//
-
 /**
- * Simplified version of PHP's test suite
- * -- EXPERIMENTAL --
-
- Try it with:
-
- $ php -r 'include "../PEAR/RunTest.php"; $t=new PEAR_RunTest; $o=$t->run("./pear_system.phpt");print_r($o);'
-
-
-TODO:
-
-Actually finish the development and testing
-
+ * PEAR_RunTest
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Tomas V.V.Cox <cox@idecnet.com>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.3.3
  */
 
+/**
+ * for error handling
+ */
 require_once 'PEAR.php';
 require_once 'PEAR/Config.php';
 
 define('DETAILED', 1);
 putenv("PHP_PEAR_RUNTESTS=1");
 
+/**
+ * Simplified version of PHP's test suite
+ *
+ * Try it with:
+ *
+ * $ php -r 'include "../PEAR/RunTest.php"; $t=new PEAR_RunTest; $o=$t->run("./pear_system.phpt");print_r($o);'
+ *
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Tomas V.V.Cox <cox@idecnet.com>
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.3.3
+ */
 class PEAR_RunTest
 {
     var $_logger;
+    var $_options;
 
     /**
      * An object that supports the PEAR_Common->log() signature, or null
      * @param PEAR_Common|null
      */
-    function PEAR_RunTest($logger = null)
+    function PEAR_RunTest($logger = null, $options = array())
     {
+        if (is_null($logger)) {
+            require_once 'PEAR/Common.php';
+            $logger = new PEAR_Common;
+        }
         $this->_logger = $logger;
+        $this->_options = $options;
     }
 
     //
@@ -78,6 +90,7 @@ class PEAR_RunTest
             'ARGS'    => '',
         );
 
+        $file = realpath($file);
         if (!is_file($file) || !$fp = fopen($file, "r")) {
             return PEAR::raiseError("Cannot open test file: $file");
         }
@@ -91,15 +104,22 @@ class PEAR_RunTest
                 $section = $r[1];
                 $section_text[$section] = '';
                 continue;
-            }
+            } elseif (empty($section)) {
+                fclose($fp);
+                return PEAR::raiseError("Invalid sections formats in test file: $file");
+                       }
 
             // Add to the section text.
             $section_text[$section] .= $line;
         }
         fclose($fp);
 
-        $shortname = str_replace($cwd.'/', '', $file);
-        $tested = trim($section_text['TEST'])." [$shortname]";
+        $shortname = str_replace($cwd . DIRECTORY_SEPARATOR, '', $file);
+        if (!isset($this->_options['simple'])) {
+            $tested = trim($section_text['TEST']) . "[$shortname]";
+        } else {
+            $tested = trim($section_text['TEST']) . ' ';
+        }
 
         $tmp = realpath(dirname($file));
         $tmp_skipif = $tmp . uniqid('/phpt.');
@@ -134,7 +154,9 @@ class PEAR_RunTest
                     if ($reason) {
                         $skipreason .= " (reason: $reason)";
                     }
-                    $this->_logger->log(0, $skipreason);
+                    if (!isset($this->_options['quiet'])) {
+                        $this->_logger->log(0, $skipreason);
+                    }
                     if (isset($old_php)) {
                         $php = $old_php;
                     }
@@ -209,7 +231,9 @@ class PEAR_RunTest
     */
             if (!$returnfail && preg_match("/^$wanted_re\$/s", $output)) {
                 @unlink($tmp_file);
-                $this->_logger->log(0, "PASS $tested$info");
+                if (!isset($this->_options['quiet'])) {
+                    $this->_logger->log(0, "PASS $tested$info");
+                }
                 if (isset($old_php)) {
                     $php = $old_php;
                 }
@@ -223,7 +247,9 @@ class PEAR_RunTest
             $ok = (0 == strcmp($output,$wanted));
             if (!$returnfail && $ok) {
                 @unlink($tmp_file);
-                $this->_logger->log(0, "PASS $tested$info");
+                if (!isset($this->_options['quiet'])) {
+                    $this->_logger->log(0, "PASS $tested$info");
+                }
                 if (isset($old_php)) {
                     $php = $old_php;
                 }
@@ -360,4 +386,4 @@ $text
     }
 
 }
-?>
\ No newline at end of file
+?>
diff --git a/pear/PEAR/Task/Common.php b/pear/PEAR/Task/Common.php
new file mode 100644 (file)
index 0000000..e63a83d
--- /dev/null
@@ -0,0 +1,208 @@
+<?php
+/**
+ * PEAR_Task_Common, base class for installer tasks
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a1
+ */
+/**#@+
+ * Error codes for task validation routines
+ */
+define('PEAR_TASK_ERROR_NOATTRIBS', 1);
+define('PEAR_TASK_ERROR_MISSING_ATTRIB', 2);
+define('PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE', 3);
+define('PEAR_TASK_ERROR_INVALID', 4);
+/**#@-*/
+define('PEAR_TASK_PACKAGE', 1);
+define('PEAR_TASK_INSTALL', 2);
+define('PEAR_TASK_PACKAGEANDINSTALL', 3);
+/**
+ * A task is an operation that manipulates the contents of a file.
+ *
+ * Simple tasks operate on 1 file.  Multiple tasks are executed after all files have been
+ * processed and installed, and are designed to operate on all files containing the task.
+ * The Post-install script task simply takes advantage of the fact that it will be run
+ * after installation, replace is a simple task.
+ *
+ * Combining tasks is possible, but ordering is significant.
+ *
+ * <file name="test.php" role="php">
+ *  <tasks:replace from="@data-dir@" to="data_dir" type="pear-config"/>
+ *  <tasks:postinstallscript/>
+ * </file>
+ *
+ * This will first replace any instance of @data-dir@ in the test.php file
+ * with the path to the current data directory.  Then, it will include the
+ * test.php file and run the script it contains to configure the package post-installation.
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
+ * @abstract
+ */
+class PEAR_Task_Common
+{
+    /**
+     * Valid types for this version are 'simple' and 'multiple'
+     *
+     * - simple tasks operate on the contents of a file and write out changes to disk
+     * - multiple tasks operate on the contents of many files and write out the
+     *   changes directly to disk
+     *
+     * Child task classes must override this property.
+     * @access protected
+     */
+    var $type = 'simple';
+    /**
+     * Determines which install phase this task is executed under
+     */
+    var $phase = PEAR_TASK_INSTALL;
+    /**
+     * @access protected
+     */
+    var $config;
+    /**
+     * @access protected
+     */
+    var $registry;
+    /**
+     * @access protected
+     */
+    var $logger;
+    /**
+     * @access protected
+     */
+    var $installphase;
+    /**
+     * @param PEAR_Config
+     * @param PEAR_Common
+     */
+    function PEAR_Task_Common(&$config, &$logger, $phase)
+    {
+        $this->config = &$config;
+        $this->registry = &$config->getRegistry();
+        $this->logger = &$logger;
+        $this->installphase = $phase;
+        if ($this->type == 'multiple') {
+            $GLOBALS['_PEAR_TASK_POSTINSTANCES'][get_class($this)][] = &$this;
+        }
+    }
+
+    /**
+     * Validate the basic contents of a task tag.
+     * @param PEAR_PackageFile_v2
+     * @param array
+     * @param PEAR_Config
+     * @param array the entire parsed <file> tag
+     * @return true|array On error, return an array in format:
+     *    array(PEAR_TASK_ERROR_???[, param1][, param2][, ...])
+     *
+     *    For PEAR_TASK_ERROR_MISSING_ATTRIB, pass the attribute name in
+     *    For PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, pass the attribute name and an array
+     *    of legal values in
+     * @static
+     * @abstract
+     */
+    function validXml($pkg, $xml, &$config, $fileXml)
+    {
+    }
+
+    /**
+     * Initialize a task instance with the parameters
+     * @param array raw, parsed xml
+     * @param array attributes from the <file> tag containing this task
+     * @param string|null last installed version of this package
+     * @abstract
+     */
+    function init($xml, $fileAttributes, $lastVersion)
+    {
+    }
+
+    /**
+     * Begin a task processing session.  All multiple tasks will be processed after each file
+     * has been successfully installed, all simple tasks should perform their task here and
+     * return any errors using the custom throwError() method to allow forward compatibility
+     *
+     * This method MUST NOT write out any changes to disk
+     * @param PEAR_PackageFile_v2
+     * @param string file contents
+     * @param string the eventual final file location (informational only)
+     * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail
+     *         (use $this->throwError), otherwise return the new contents
+     * @abstract
+     */
+    function startSession($pkg, $contents, $dest)
+    {
+    }
+
+    /**
+     * This method is used to process each of the tasks for a particular multiple class
+     * type.  Simple tasks need not implement this method.
+     * @param array an array of tasks
+     * @access protected
+     * @static
+     * @abstract
+     */
+    function run($tasks)
+    {
+    }
+
+    /**
+     * @static
+     * @final
+     */
+    function hasPostinstallTasks()
+    {
+        return isset($GLOBALS['_PEAR_TASK_POSTINSTANCES']);
+    }
+
+    /**
+     * @static
+     * @final
+     */
+     function runPostinstallTasks()
+     {
+         foreach ($GLOBALS['_PEAR_TASK_POSTINSTANCES'] as $class => $tasks) {
+             $err = call_user_func(array($class, 'run'),
+                  $GLOBALS['_PEAR_TASK_POSTINSTANCES'][$class]);
+             if ($err) {
+                 return PEAR_Task_Common::throwError($err);
+             }
+         }
+         unset($GLOBALS['_PEAR_TASK_POSTINSTANCES']);
+    }
+
+    /**
+     * Determines whether a role is a script
+     * @return bool
+     */
+    function isScript()
+    {
+        return $this->type == 'script';
+    }
+
+    function throwError($msg, $code = -1)
+    {
+        include_once 'PEAR.php';
+        return PEAR::raiseError($msg, $code);
+    }
+}
+?>
\ No newline at end of file
diff --git a/pear/PEAR/Task/Postinstallscript.php b/pear/PEAR/Task/Postinstallscript.php
new file mode 100644 (file)
index 0000000..6798f2f
--- /dev/null
@@ -0,0 +1,325 @@
+<?php
+/**
+ * <tasks:postinstallscript>
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a1
+ */
+/**
+ * Base class
+ */
+require_once 'PEAR/Task/Common.php';
+/**
+ * Implements the postinstallscript file task.
+ *
+ * Note that post-install scripts are handled separately from installation, by the
+ * "pear run-scripts" command
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
+ */
+class PEAR_Task_Postinstallscript extends PEAR_Task_Common
+{
+    var $type = 'script';
+    var $_class;
+    var $_params;
+    var $_obj;
+    /**
+     *
+     * @var PEAR_PackageFile_v2
+     */
+    var $_pkg;
+    var $_contents;
+    var $phase = PEAR_TASK_INSTALL;
+
+    /**
+     * Validate the raw xml at parsing-time.
+     *
+     * This also attempts to validate the script to make sure it meets the criteria
+     * for a post-install script
+     * @param PEAR_PackageFile_v2
+     * @param array The XML contents of the <postinstallscript> tag
+     * @param PEAR_Config
+     * @param array the entire parsed <file> tag
+     * @static
+     */
+    function validateXml($pkg, $xml, &$config, $fileXml)
+    {
+        if ($fileXml['role'] != 'php') {
+            return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
+            $fileXml['name'] . '" must be role="php"');
+        }
+        PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+        $file = $pkg->getFileContents($fileXml['name']);
+        if (PEAR::isError($file)) {
+            PEAR::popErrorHandling();
+            return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
+                $fileXml['name'] . '" is not valid: ' .
+                $file->getMessage());
+        } elseif ($file === null) {
+            return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
+                $fileXml['name'] . '" could not be retrieved for processing!');
+        } else {
+            $analysis = $pkg->analyzeSourceCode($file, true);
+            if (PEAR::isError($analysis)) {
+                PEAR::popErrorHandling();
+                return array(PEAR_TASK_ERROR_INVALID, 'Analysis of post-install script "' .
+                    $fileXml['name'] . '" failed');
+            }
+            if (count($analysis['declared_classes']) != 1) {
+                PEAR::popErrorHandling();
+                return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
+                    $fileXml['name'] . '" must declare exactly 1 class');
+            }
+            $class = $analysis['declared_classes'][0];
+            if ($class != str_replace(array('/', '.php'), array('_', ''),
+                  $fileXml['name']) . '_postinstall') {
+                PEAR::popErrorHandling();
+                return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
+                    $fileXml['name'] . '" class "' . $class . '" must be named "' .
+                    str_replace(array('/', '.php'), array('_', ''),
+                    $fileXml['name']) . '_postinstall"');
+            }
+            if (!isset($analysis['declared_methods'][$class])) {
+                PEAR::popErrorHandling();
+                return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
+                    $fileXml['name'] . '" must declare methods init() and run()');
+            }
+            $methods = array('init' => 0, 'run' => 1);
+            foreach ($analysis['declared_methods'][$class] as $method) {
+                if (isset($methods[$method])) {
+                    unset($methods[$method]);
+                }
+            }
+            if (count($methods)) {
+                PEAR::popErrorHandling();
+                return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
+                    $fileXml['name'] . '" must declare methods init() and run()');
+            }
+        }
+        PEAR::popErrorHandling();
+        $definedparams = array();
+        $tasksNamespace = $pkg->getTasksNs() . ':';
+        if (!isset($xml[$tasksNamespace . 'paramgroup']) && isset($xml['paramgroup'])) {
+            // in order to support the older betas, which did not expect internal tags
+            // to also use the namespace
+            $tasksNamespace = '';
+        }
+        if (isset($xml[$tasksNamespace . 'paramgroup'])) {
+            $params = $xml[$tasksNamespace . 'paramgroup'];
+            if (!is_array($params) || !isset($params[0])) {
+                $params = array($params);
+            }
+            foreach ($params as $param) {
+                if (!isset($param[$tasksNamespace . 'id'])) {
+                    return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
+                        $fileXml['name'] . '" <paramgroup> must have ' .
+                        'an ' . $tasksNamespace . 'id> tag');
+                }
+                if (isset($param[$tasksNamespace . 'name'])) {
+                    if (!in_array($param[$tasksNamespace . 'name'], $definedparams)) {
+                        return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
+                            $fileXml['name'] . '" ' . $tasksNamespace .
+                            'paramgroup> id "' . $param[$tasksNamespace . 'id'] .
+                            '" parameter "' . $param[$tasksNamespace . 'name'] .
+                            '" has not been previously defined');
+                    }
+                    if (!isset($param[$tasksNamespace . 'conditiontype'])) {
+                        return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
+                            $fileXml['name'] . '" ' . $tasksNamespace .
+                            'paramgroup> id "' . $param[$tasksNamespace . 'id'] .
+                            '" must have a ' . $tasksNamespace . 
+                            'conditiontype> tag containing either "=", ' .
+                            '"!=", or "preg_match"');
+                    }
+                    if (!in_array($param[$tasksNamespace . 'conditiontype'],
+                          array('=', '!=', 'preg_match'))) {
+                        return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
+                            $fileXml['name'] . '" ' . $tasksNamespace .
+                            'paramgroup> id "' . $param[$tasksNamespace . 'id'] .
+                            '" must have a ' . $tasksNamespace .
+                            'conditiontype> tag containing either "=", ' .
+                            '"!=", or "preg_match"');
+                    }
+                    if (!isset($param[$tasksNamespace . 'value'])) {
+                        return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
+                            $fileXml['name'] . '" ' . $tasksNamespace .
+                            'paramgroup> id "' . $param[$tasksNamespace . 'id'] .
+                            '" must have a ' . $tasksNamespace .
+                            'value> tag containing expected parameter value');
+                    }
+                }
+                if (isset($param[$tasksNamespace . 'instructions'])) {
+                    if (!is_string($param[$tasksNamespace . 'instructions'])) {
+                        return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
+                            $fileXml['name'] . '" ' . $tasksNamespace .
+                            'paramgroup> id "' . $param[$tasksNamespace . 'id'] .
+                            '" ' . $tasksNamespace . 'instructions> must be simple text');
+                    }
+                }
+                if (!isset($param[$tasksNamespace . 'param'])) {
+                    continue; // <param> is no longer required
+                }
+                $subparams = $param[$tasksNamespace . 'param'];
+                if (!is_array($subparams) || !isset($subparams[0])) {
+                    $subparams = array($subparams);
+                }
+                foreach ($subparams as $subparam) {
+                    if (!isset($subparam[$tasksNamespace . 'name'])) {
+                        return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
+                            $fileXml['name'] . '" parameter for ' .
+                            $tasksNamespace . 'paramgroup> id "' .
+                            $param[$tasksNamespace . 'id'] . '" must have ' .
+                            'a ' . $tasksNamespace . 'name> tag');
+                    }
+                    if (!preg_match('/[a-zA-Z0-9]+/',
+                          $subparam[$tasksNamespace . 'name'])) {
+                        return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
+                            $fileXml['name'] . '" parameter "' .
+                            $subparam[$tasksNamespace . 'name'] .
+                            '" for ' . $tasksNamespace . 'paramgroup> id "' .
+                            $param[$tasksNamespace . 'id'] .
+                            '" is not a valid name.  Must contain only alphanumeric characters');
+                    }
+                    if (!isset($subparam[$tasksNamespace . 'prompt'])) {
+                        return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
+                            $fileXml['name'] . '" parameter "' .
+                            $subparam[$tasksNamespace . 'name'] .
+                            '" for ' . $tasksNamespace . 'paramgroup> id "' .
+                            $param[$tasksNamespace . 'id'] .
+                            '" must have a ' . $tasksNamespace . 'prompt> tag');
+                    }
+                    if (!isset($subparam[$tasksNamespace . 'type'])) {
+                        return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' .
+                            $fileXml['name'] . '" parameter "' .
+                            $subparam[$tasksNamespace . 'name'] .
+                            '" for ' . $tasksNamespace . 'paramgroup> id "' .
+                            $param[$tasksNamespace . 'id'] .
+                            '" must have a ' . $tasksNamespace . 'type> tag');
+                    }
+                    $definedparams[] = $param[$tasksNamespace . 'id'] . '::' .
+                    $subparam[$tasksNamespace . 'name'];
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Initialize a task instance with the parameters
+     * @param array raw, parsed xml
+     * @param array attributes from the <file> tag containing this task
+     * @param string|null last installed version of this package, if any (useful for upgrades)
+     */
+    function init($xml, $fileattribs, $lastversion)
+    {
+        $this->_class = str_replace('/', '_', $fileattribs['name']);
+        $this->_filename = $fileattribs['name'];
+        $this->_class = str_replace ('.php', '', $this->_class) . '_postinstall';
+        $this->_params = $xml;
+        $this->_lastversion = $lastversion;
+    }
+
+    /**
+     * Strip the tasks: namespace from internal params
+     *
+     * @access private
+     */
+    function _stripNamespace($params = null)
+    {
+        if ($params === null) {
+            $params = array();
+            if (!is_array($this->_params)) {
+                return;
+            }
+            foreach ($this->_params as $i => $param) {
+                if (is_array($param)) {
+                    $param = $this->_stripNamespace($param);
+                }
+                $params[str_replace($this->_pkg->getTasksNs() . ':', '', $i)] = $param;
+            }
+            $this->_params = $params;
+        } else {
+            $newparams = array();
+            foreach ($params as $i => $param) {
+                if (is_array($param)) {
+                    $param = $this->_stripNamespace($param);
+                }
+                $newparams[str_replace($this->_pkg->getTasksNs() . ':', '', $i)] = $param;
+            }
+            return $newparams;
+        }
+    }
+
+    /**
+     * Unlike other tasks, the installed file name is passed in instead of the file contents,
+     * because this task is handled post-installation
+     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+     * @param string file name
+     * @return bool|PEAR_Error false to skip this file, PEAR_Error to fail
+     *         (use $this->throwError)
+     */
+    function startSession($pkg, $contents)
+    {
+        if ($this->installphase != PEAR_TASK_INSTALL) {
+            return false;
+        }
+        // remove the tasks: namespace if present
+        $this->_pkg = $pkg;
+        $this->_stripNamespace();
+        $this->logger->log(0, 'Including external post-installation script "' .
+            $contents . '" - any errors are in this script');
+        include_once $contents;
+        if (class_exists($this->_class)) {
+            $this->logger->log(0, 'Inclusion succeeded');
+        } else {
+            return $this->throwError('init of post-install script class "' . $this->_class
+                . '" failed');
+        }
+        $this->_obj = new $this->_class;
+        $this->logger->log(1, 'running post-install script "' . $this->_class . '->init()"');
+        PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+        $res = $this->_obj->init($this->config, $pkg, $this->_lastversion);
+        PEAR::popErrorHandling();
+        if ($res) {
+            $this->logger->log(0, 'init succeeded');
+        } else {
+            return $this->throwError('init of post-install script "' . $this->_class .
+                '->init()" failed');
+        }
+        $this->_contents = $contents;
+        return true;
+    }
+
+    /**
+     * No longer used
+     * @see PEAR_PackageFile_v2::runPostinstallScripts()
+     * @param array an array of tasks
+     * @param string install or upgrade
+     * @access protected
+     * @static
+     */
+    function run()
+    {
+    }
+}
+?>
\ No newline at end of file
diff --git a/pear/PEAR/Task/Postinstallscript/rw.php b/pear/PEAR/Task/Postinstallscript/rw.php
new file mode 100644 (file)
index 0000000..742583a
--- /dev/null
@@ -0,0 +1,176 @@
+<?php
+/**
+ * <tasks:postinstallscript> - read/write version
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a10
+ */
+/**
+ * Base class
+ */
+require_once 'PEAR/Task/Postinstallscript.php';
+/**
+ * Abstracts the postinstallscript file task xml.
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a10
+ */
+class PEAR_Task_Postinstallscript_rw extends PEAR_Task_Postinstallscript
+{
+    /**
+     * parent package file object
+     *
+     * @var PEAR_PackageFile_v2_rw
+     */
+    var $_pkg;
+    /**
+     * Enter description here...
+     *
+     * @param PEAR_PackageFile_v2_rw $pkg
+     * @param PEAR_Config $config
+     * @param PEAR_Frontend $logger
+     * @param array $fileXml
+     * @return PEAR_Task_Postinstallscript_rw
+     */
+    function PEAR_Task_Postinstallscript_rw(&$pkg, &$config, &$logger, $fileXml)
+    {
+        parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE);
+        $this->_contents = $fileXml;
+        $this->_pkg = &$pkg;
+        $this->_params = array();
+    }
+
+    function validate()
+    {
+        return $this->validateXml($this->_pkg, $this->_params, $this->config, $this->_contents);
+    }
+
+    function getName()
+    {
+        return 'postinstallscript';
+    }
+
+    /**
+     * add a simple <paramgroup> to the post-install script
+     *
+     * Order is significant, so call this method in the same
+     * sequence the users should see the paramgroups.  The $params
+     * parameter should either be the result of a call to {@link getParam()}
+     * or an array of calls to getParam().
+     * 
+     * Use {@link addConditionTypeGroup()} to add a <paramgroup> containing
+     * a <conditiontype> tag
+     * @param string $id <paramgroup> id as seen by the script
+     * @param array|false $params array of getParam() calls, or false for no params
+     * @param string|false $instructions
+     */
+    function addParamGroup($id, $params = false, $instructions = false)
+    {
+        if ($params && isset($params[0]) && !isset($params[1])) {
+            $params = $params[0];
+        }
+        $stuff =
+            array(
+                $this->_pkg->getTasksNs() . ':id' => $id,
+            );
+        if ($instructions) {
+            $stuff[$this->_pkg->getTasksNs() . ':instructions'] = $instructions;
+        }
+        if ($params) {
+            $stuff[$this->_pkg->getTasksNs() . ':param'] = $params;
+        }
+        $this->_params[$this->_pkg->getTasksNs() . ':paramgroup'][] = $stuff;
+    }
+
+    /**
+     * add a complex <paramgroup> to the post-install script with conditions
+     *
+     * This inserts a <paramgroup> with
+     *
+     * Order is significant, so call this method in the same
+     * sequence the users should see the paramgroups.  The $params
+     * parameter should either be the result of a call to {@link getParam()}
+     * or an array of calls to getParam().
+     * 
+     * Use {@link addParamGroup()} to add a simple <paramgroup>
+     *
+     * @param string $id <paramgroup> id as seen by the script
+     * @param string $oldgroup <paramgroup> id of the section referenced by
+     *                         <conditiontype>
+     * @param string $param name of the <param> from the older section referenced
+     *                      by <contitiontype>
+     * @param string $value value to match of the parameter
+     * @param string $conditiontype one of '=', '!=', 'preg_match'
+     * @param array|false $params array of getParam() calls, or false for no params
+     * @param string|false $instructions
+     */
+    function addConditionTypeGroup($id, $oldgroup, $param, $value, $conditiontype = '=',
+                                   $params = false, $instructions = false)
+    {
+        if ($params && isset($params[0]) && !isset($params[1])) {
+            $params = $params[0];
+        }
+        $stuff =
+            array(
+                $this->_pkg->getTasksNs() . ':id' => $id,
+            );
+        if ($instructions) {
+            $stuff[$this->_pkg->getTasksNs() . ':instructions'] = $instructions;
+        }
+        $stuff[$this->_pkg->getTasksNs() . ':name'] = $oldgroup . '::' . $param;
+        $stuff[$this->_pkg->getTasksNs() . ':conditiontype'] = $conditiontype;
+        $stuff[$this->_pkg->getTasksNs() . ':value'] = $value;
+        if ($params) {
+            $stuff[$this->_pkg->getTasksNs() . ':param'] = $params;
+        }
+        $this->_params[$this->_pkg->getTasksNs() . ':paramgroup'][] = $stuff;
+    }
+
+    function getXml()
+    {
+        return $this->_params;
+    }
+
+    /**
+     * Use to set up a param tag for use in creating a paramgroup
+     * @static
+     */
+    function getParam($name, $prompt, $type = 'string', $default = null)
+    {
+        if ($default !== null) {
+            return 
+            array(
+                $this->_pkg->getTasksNs() . ':name' => $name,
+                $this->_pkg->getTasksNs() . ':prompt' => $prompt,
+                $this->_pkg->getTasksNs() . ':type' => $type,
+                $this->_pkg->getTasksNs() . ':default' => $default
+            );
+        }
+        return
+            array(
+                $this->_pkg->getTasksNs() . ':name' => $name,
+                $this->_pkg->getTasksNs() . ':prompt' => $prompt,
+                $this->_pkg->getTasksNs() . ':type' => $type,
+            );
+    }
+}
+?>
\ No newline at end of file
diff --git a/pear/PEAR/Task/Replace.php b/pear/PEAR/Task/Replace.php
new file mode 100644 (file)
index 0000000..4fe7dc4
--- /dev/null
@@ -0,0 +1,182 @@
+<?php
+/**
+ * <tasks:replace>
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a1
+ */
+/**
+ * Base class
+ */
+require_once 'PEAR/Task/Common.php';
+/**
+ * Implements the replace file task.
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
+ */
+class PEAR_Task_Replace extends PEAR_Task_Common
+{
+    var $type = 'simple';
+    var $phase = PEAR_TASK_PACKAGEANDINSTALL;
+    var $_replacements;
+
+    /**
+     * Validate the raw xml at parsing-time.
+     * @param PEAR_PackageFile_v2
+     * @param array raw, parsed xml
+     * @param PEAR_Config
+     * @static
+     */
+    function validateXml($pkg, $xml, &$config, $fileXml)
+    {
+        if (!isset($xml['attribs'])) {
+            return array(PEAR_TASK_ERROR_NOATTRIBS);
+        }
+        if (!isset($xml['attribs']['type'])) {
+            return array(PEAR_TASK_ERROR_MISSING_ATTRIB, 'type');
+        }
+        if (!isset($xml['attribs']['to'])) {
+            return array(PEAR_TASK_ERROR_MISSING_ATTRIB, 'to');
+        }
+        if (!isset($xml['attribs']['from'])) {
+            return array(PEAR_TASK_ERROR_MISSING_ATTRIB, 'from');
+        }
+        if ($xml['attribs']['type'] == 'pear-config') {
+            if (!in_array($xml['attribs']['to'], $config->getKeys())) {
+                return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'to', $xml['attribs']['to'],
+                    $config->getKeys());
+            }
+        } elseif ($xml['attribs']['type'] == 'php-const') {
+            if (defined($xml['attribs']['to'])) {
+                return true;
+            } else {
+                return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'to', $xml['attribs']['to'],
+                    array('valid PHP constant'));
+            }
+        } elseif ($xml['attribs']['type'] == 'package-info') {
+            if (in_array($xml['attribs']['to'],
+                array('name', 'summary', 'channel', 'notes', 'extends', 'description',
+                    'release_notes', 'license', 'release-license', 'license-uri',
+                    'version', 'api-version', 'state', 'api-state', 'release_date',
+                    'date', 'time'))) {
+                return true;
+            } else {
+                return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'to', $xml['attribs']['to'],
+                    array('name', 'summary', 'channel', 'notes', 'extends', 'description',
+                    'release_notes', 'license', 'release-license', 'license-uri',
+                    'version', 'api-version', 'state', 'api-state', 'release_date',
+                    'date', 'time'));
+            }
+        } else {
+            return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'type', $xml['attribs']['type'],
+                array('pear-config', 'package-info'));
+        }
+        return true;
+    }
+
+    /**
+     * Initialize a task instance with the parameters
+     * @param array raw, parsed xml
+     * @param unused
+     */
+    function init($xml, $attribs)
+    {
+        $this->_replacements = isset($xml['attribs']) ? array($xml) : $xml;
+    }
+
+    /**
+     * Do a package.xml 1.0 replacement, with additional package-info fields available
+     *
+     * See validateXml() source for the complete list of allowed fields
+     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+     * @param string file contents
+     * @param string the eventual final file location (informational only)
+     * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail
+     *         (use $this->throwError), otherwise return the new contents
+     */
+    function startSession($pkg, $contents, $dest)
+    {
+        $subst_from = $subst_to = array();
+        foreach ($this->_replacements as $a) {
+            $a = $a['attribs'];
+            $to = '';
+            if ($a['type'] == 'pear-config') {
+                if ($this->installphase == PEAR_TASK_PACKAGE) {
+                    return false;
+                }
+                if ($a['to'] == 'master_server') {
+                    $chan = $this->registry->getChannel($pkg->getChannel());
+                    if ($chan) {
+                        $to = $chan->getServer();
+                    } else {
+                        $this->logger->log(0, "$dest: invalid pear-config replacement: $a[to]");
+                        return false;
+                    }
+                } else {
+                    if ($this->config->isDefinedLayer('ftp')) {
+                        // try the remote config file first
+                        $to = $this->config->get($a['to'], 'ftp', $pkg->getChannel());
+                        if (is_null($to)) {
+                            // then default to local
+                            $to = $this->config->get($a['to'], null, $pkg->getChannel());
+                        }
+                    } else {
+                        $to = $this->config->get($a['to'], null, $pkg->getChannel());
+                    }
+                }
+                if (is_null($to)) {
+                    $this->logger->log(0, "$dest: invalid pear-config replacement: $a[to]");
+                    return false;
+                }
+            } elseif ($a['type'] == 'php-const') {
+                if ($this->installphase == PEAR_TASK_PACKAGE) {
+                    return false;
+                }
+                if (defined($a['to'])) {
+                    $to = constant($a['to']);
+                } else {
+                    $this->logger->log(0, "$dest: invalid php-const replacement: $a[to]");
+                    return false;
+                }
+            } else {
+                if ($t = $pkg->packageInfo($a['to'])) {
+                    $to = $t;
+                } else {
+                    $this->logger->log(0, "$dest: invalid package-info replacement: $a[to]");
+                    return false;
+                }
+            }
+            if (!is_null($to)) {
+                $subst_from[] = $a['from'];
+                $subst_to[] = $to;
+            }
+        }
+        $this->logger->log(3, "doing " . sizeof($subst_from) .
+            " substitution(s) for $dest");
+        if (sizeof($subst_from)) {
+            $contents = str_replace($subst_from, $subst_to, $contents);
+        }
+        return $contents;
+    }
+}
+?>
\ No newline at end of file
diff --git a/pear/PEAR/Task/Replace/rw.php b/pear/PEAR/Task/Replace/rw.php
new file mode 100644 (file)
index 0000000..6972c1a
--- /dev/null
@@ -0,0 +1,67 @@
+<?php
+/**
+ * <tasks:replace> - read/write version
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a10
+ */
+/**
+ * Base class
+ */
+require_once 'PEAR/Task/Replace.php';
+/**
+ * Abstracts the replace task xml.
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a10
+ */
+class PEAR_Task_Replace_rw extends PEAR_Task_Replace
+{
+    function PEAR_Task_Replace_rw(&$pkg, &$config, &$logger, $fileXml)
+    {
+        parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE);
+        $this->_contents = $fileXml;
+        $this->_pkg = &$pkg;
+        $this->_params = array();
+    }
+
+    function validate()
+    {
+        return $this->validateXml($this->_pkg, $this->_params, $this->config, $this->_contents);
+    }
+
+    function setInfo($from, $to, $type)
+    {
+        $this->_params = array('attribs' => array('from' => $from, 'to' => $to, 'type' => $type));
+    }
+
+    function getName()
+    {
+        return 'replace';
+    }
+
+    function getXml()
+    {
+        return $this->_params;
+    }
+}
+?>
\ No newline at end of file
diff --git a/pear/PEAR/Task/Unixeol.php b/pear/PEAR/Task/Unixeol.php
new file mode 100644 (file)
index 0000000..540247e
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+/**
+ * <tasks:unixeol>
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a1
+ */
+/**
+ * Base class
+ */
+require_once 'PEAR/Task/Common.php';
+/**
+ * Implements the unix line endings file task.
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
+ */
+class PEAR_Task_Unixeol extends PEAR_Task_Common
+{
+    var $type = 'simple';
+    var $phase = PEAR_TASK_PACKAGE;
+    var $_replacements;
+
+    /**
+     * Validate the raw xml at parsing-time.
+     * @param PEAR_PackageFile_v2
+     * @param array raw, parsed xml
+     * @param PEAR_Config
+     * @static
+     */
+    function validateXml($pkg, $xml, &$config, $fileXml)
+    {
+        if ($xml != '') {
+            return array(PEAR_TASK_ERROR_INVALID, 'no attributes allowed');
+        }
+        return true;
+    }
+
+    /**
+     * Initialize a task instance with the parameters
+     * @param array raw, parsed xml
+     * @param unused
+     */
+    function init($xml, $attribs)
+    {
+    }
+
+    /**
+     * Replace all line endings with line endings customized for the current OS
+     *
+     * See validateXml() source for the complete list of allowed fields
+     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+     * @param string file contents
+     * @param string the eventual final file location (informational only)
+     * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail
+     *         (use $this->throwError), otherwise return the new contents
+     */
+    function startSession($pkg, $contents, $dest)
+    {
+        $this->logger->log(3, "replacing all line endings with \\n in $dest");
+        return preg_replace("/\r\n|\n\r|\r|\n/", "\n", $contents);
+    }
+}
+?>
\ No newline at end of file
diff --git a/pear/PEAR/Task/Unixeol/rw.php b/pear/PEAR/Task/Unixeol/rw.php
new file mode 100644 (file)
index 0000000..9d5e13d
--- /dev/null
@@ -0,0 +1,62 @@
+<?php
+/**
+ * <tasks:unixeol> - read/write version
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a10
+ */
+/**
+ * Base class
+ */
+require_once 'PEAR/Task/Unixeol.php';
+/**
+ * Abstracts the unixeol task xml.
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a10
+ */
+class PEAR_Task_Unixeol_rw extends PEAR_Task_Unixeol
+{
+    function PEAR_Task_Unixeol_rw(&$pkg, &$config, &$logger, $fileXml)
+    {
+        parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE);
+        $this->_contents = $fileXml;
+        $this->_pkg = &$pkg;
+        $this->_params = array();
+    }
+
+    function validate()
+    {
+        return true;
+    }
+
+    function getName()
+    {
+        return 'unixeol';
+    }
+
+    function getXml()
+    {
+        return '';
+    }
+}
+?>
\ No newline at end of file
diff --git a/pear/PEAR/Task/Windowseol.php b/pear/PEAR/Task/Windowseol.php
new file mode 100644 (file)
index 0000000..54182b8
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+/**
+ * <tasks:windowseol>
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a1
+ */
+/**
+ * Base class
+ */
+require_once 'PEAR/Task/Common.php';
+/**
+ * Implements the windows line endsings file task.
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
+ */
+class PEAR_Task_Windowseol extends PEAR_Task_Common
+{
+    var $type = 'simple';
+    var $phase = PEAR_TASK_PACKAGE;
+    var $_replacements;
+
+    /**
+     * Validate the raw xml at parsing-time.
+     * @param PEAR_PackageFile_v2
+     * @param array raw, parsed xml
+     * @param PEAR_Config
+     * @static
+     */
+    function validateXml($pkg, $xml, &$config, $fileXml)
+    {
+        if ($xml != '') {
+            return array(PEAR_TASK_ERROR_INVALID, 'no attributes allowed');
+        }
+        return true;
+    }
+
+    /**
+     * Initialize a task instance with the parameters
+     * @param array raw, parsed xml
+     * @param unused
+     */
+    function init($xml, $attribs)
+    {
+    }
+
+    /**
+     * Replace all line endings with windows line endings
+     *
+     * See validateXml() source for the complete list of allowed fields
+     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+     * @param string file contents
+     * @param string the eventual final file location (informational only)
+     * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail
+     *         (use $this->throwError), otherwise return the new contents
+     */
+    function startSession($pkg, $contents, $dest)
+    {
+        $this->logger->log(3, "replacing all line endings with \\r\\n in $dest");
+        return preg_replace("/\r\n|\n\r|\r|\n/", "\r\n", $contents);
+    }
+}
+?>
\ No newline at end of file
diff --git a/pear/PEAR/Task/Windowseol/rw.php b/pear/PEAR/Task/Windowseol/rw.php
new file mode 100644 (file)
index 0000000..1320e45
--- /dev/null
@@ -0,0 +1,62 @@
+<?php
+/**
+ * <tasks:windowseol> - read/write version
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a10
+ */
+/**
+ * Base class
+ */
+require_once 'PEAR/Task/Windowseol.php';
+/**
+ * Abstracts the windowseol task xml.
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a10
+ */
+class PEAR_Task_Windowseol_rw extends PEAR_Task_Windowseol
+{
+    function PEAR_Task_Windowseol_rw(&$pkg, &$config, &$logger, $fileXml)
+    {
+        parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE);
+        $this->_contents = $fileXml;
+        $this->_pkg = &$pkg;
+        $this->_params = array();
+    }
+
+    function validate()
+    {
+        return true;
+    }
+
+    function getName()
+    {
+        return 'windowseol';
+    }
+
+    function getXml()
+    {
+        return '';
+    }
+}
+?>
\ No newline at end of file
diff --git a/pear/PEAR/Task/test.dat b/pear/PEAR/Task/test.dat
new file mode 100644 (file)
index 0000000..971b517
--- /dev/null
@@ -0,0 +1,28 @@
+a:15:{s:8:"provides";a:12:{s:17:"class;Archive_Tar";a:3:{s:4:"type";s:5:"class";s:4:"name";s:11:"Archive_Tar";s:8:"explicit";b:1;}s:28:"function;Archive_Tar::create";a:3:{s:4:"type";s:8:"function";s:4:"name";s:19:"Archive_Tar::create";s:8:"explicit";b:1;}s:25:"function;Archive_Tar::add";a:3:{s:4:"type";s:8:"function";s:4:"name";s:16:"Archive_Tar::add";s:8:"explicit";b:1;}s:29:"function;Archive_Tar::extract";a:3:{s:4:"type";s:8:"function";s:4:"name";s:20:"Archive_Tar::extract";s:8:"explicit";b:1;}s:33:"function;Archive_Tar::listContent";a:3:{s:4:"type";s:8:"function";s:4:"name";s:24:"Archive_Tar::listContent";s:8:"explicit";b:1;}s:34:"function;Archive_Tar::createModify";a:3:{s:4:"type";s:8:"function";s:4:"name";s:25:"Archive_Tar::createModify";s:8:"explicit";b:1;}s:31:"function;Archive_Tar::addModify";a:3:{s:4:"type";s:8:"function";s:4:"name";s:22:"Archive_Tar::addModify";s:8:"explicit";b:1;}s:31:"function;Archive_Tar::addString";a:3:{s:4:"type";s:8:"function";s:4:"name";s:22:"Archive_Tar::addString";s:8:"explicit";b:1;}s:35:"function;Archive_Tar::extractModify";a:3:{s:4:"type";s:8:"function";s:4:"name";s:26:"Archive_Tar::extractModify";s:8:"explicit";b:1;}s:37:"function;Archive_Tar::extractInString";a:3:{s:4:"type";s:8:"function";s:4:"name";s:28:"Archive_Tar::extractInString";s:8:"explicit";b:1;}s:33:"function;Archive_Tar::extractList";a:3:{s:4:"type";s:8:"function";s:4:"name";s:24:"Archive_Tar::extractList";s:8:"explicit";b:1;}s:34:"function;Archive_Tar::setAttribute";a:3:{s:4:"type";s:8:"function";s:4:"name";s:25:"Archive_Tar::setAttribute";s:8:"explicit";b:1;}}s:8:"filelist";a:2:{s:15:"Archive/Tar.php";a:4:{s:4:"role";s:3:"php";s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"4b718a4f5943d3b88defb243359b2866";s:12:"installed_as";s:41:"C:\Program Files\php\pear\Archive\Tar.php";}s:20:"docs/Archive_Tar.txt";a:4:{s:4:"role";s:3:"doc";s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"ae640b797078a6542ea0d236f28efffb";s:12:"installed_as";s:58:"C:\devel\Chiara\pear\docs\Archive_Tar\docs\Archive_Tar.txt";}}s:10:"xsdversion";s:3:"1.0";s:7:"package";s:11:"Archive_Tar";s:7:"summary";s:25:"Tar file management class";s:11:"description";s:258:"This class provides handling of tar files in PHP.\r
+It supports creating, listing, extracting and adding to tar files.\r
+Gzip support is available if PHP has the zlib extension built-in or\r
+loaded. Bz2 compression is also supported with the bz2 extension loaded.\r
+";s:11:"maintainers";a:2:{i:0;a:4:{s:6:"handle";s:7:"vblavet";s:4:"name";s:14:"Vincent Blavet";s:5:"email";s:22:"vincent@phpconcept.net";s:4:"role";s:4:"lead";}i:1;a:4:{s:6:"handle";s:3:"ssb";s:4:"name";s:18:"Stig Sæther Bakken";s:5:"email";s:12:"stig@php.net";s:4:"role";s:6:"helper";}}s:7:"version";s:3:"1.2";s:12:"release_date";s:10:"2004-05-08";s:15:"release_license";s:11:"PHP License";s:13:"release_state";s:6:"stable";s:13:"release_notes";s:72:"Add support for other separator than the space char and bug\r
+       correction\r
+";s:9:"changelog";a:7:{i:0;a:4:{s:7:"version";s:3:"1.1";s:12:"release_date";s:10:"2003-05-28";s:13:"release_state";s:6:"stable";s:13:"release_notes";s:143:"* Add support for BZ2 compression\r
+* Add support for add and extract without using temporary files : methods addString() and extractInString()\r
+\r
+";}i:1;a:4:{s:7:"version";s:3:"1.0";s:12:"release_date";s:10:"2003-01-24";s:13:"release_state";s:6:"stable";s:13:"release_notes";s:26:"Change status to stable\r
+\r
+\r
+";}i:2;a:4:{s:7:"version";s:7:"0.10-b1";s:12:"release_date";s:10:"2003-01-08";s:13:"release_state";s:4:"beta";s:13:"release_notes";s:62:"Add support for long filenames (greater than 99 characters)\r
+\r
+\r
+";}i:3;a:4:{s:7:"version";s:3:"0.9";s:12:"release_date";s:10:"2002-05-27";s:13:"release_state";s:6:"stable";s:13:"release_notes";s:28:"Auto-detect gzip'ed files\r
+\r
+\r
+";}i:4;a:4:{s:7:"version";s:3:"0.4";s:12:"release_date";s:10:"2002-05-20";s:13:"release_state";s:6:"stable";s:13:"release_notes";s:54:"Windows bugfix: use forward slashes inside archives\r
+\r
+\r
+";}i:5;a:4:{s:7:"version";s:3:"0.2";s:12:"release_date";s:10:"2002-02-18";s:13:"release_state";s:6:"stable";s:13:"release_notes";s:32:"From initial commit to stable\r
+\r
+\r
+";}i:6;a:4:{s:7:"version";s:3:"0.3";s:12:"release_date";s:10:"2002-04-13";s:13:"release_state";s:6:"stable";s:13:"release_notes";s:50:"Windows bugfix: used wrong directory separators\r
+\r
+\r
+";}}s:7:"dirtree";a:2:{s:33:"C:\Program Files\php\pear\Archive";b:1;s:42:"C:\devel\Chiara\pear\docs\Archive_Tar\docs";b:1;}s:13:"_lastmodified";i:1094797013;}
\ No newline at end of file
diff --git a/pear/PEAR/Task/test.php b/pear/PEAR/Task/test.php
new file mode 100644 (file)
index 0000000..93ec3a8
--- /dev/null
@@ -0,0 +1,11 @@
+<?php
+error_reporting(E_ALL);
+$a = unserialize(file_get_contents('test.dat'));
+var_dump($a);
+$a = unserialize(file_get_contents('C:\\development\\pear-core\\tests\\PEAR_DependencyDB\\tester\\.registry\\archive_tar.reg'));
+$fp = fopen('C:\\development\\pear-core\\tests\\PEAR_DependencyDB\\tester\\.registry\\archive_tar.reg', 'r');
+$a = fread($fp, 4501);
+fclose($fp);
+var_dump(substr($a, 2420));
+var_dump($a);
+?>
\ No newline at end of file
diff --git a/pear/PEAR/Validate.php b/pear/PEAR/Validate.php
new file mode 100644 (file)
index 0000000..167ffed
--- /dev/null
@@ -0,0 +1,624 @@
+<?php
+/**
+ * PEAR_Validate
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a1
+ */
+/**#@+
+ * Constants for install stage
+ */
+define('PEAR_VALIDATE_INSTALLING', 1);
+define('PEAR_VALIDATE_UNINSTALLING', 2); // this is not bit-mapped like the others
+define('PEAR_VALIDATE_NORMAL', 3);
+define('PEAR_VALIDATE_DOWNLOADING', 4); // this is not bit-mapped like the others
+define('PEAR_VALIDATE_PACKAGING', 7);
+/**#@-*/
+require_once 'PEAR/Common.php';
+require_once 'PEAR/Validator/PECL.php';
+
+/**
+ * Validation class for package.xml - channel-level advanced validation
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
+ */
+class PEAR_Validate
+{
+    var $packageregex = _PEAR_COMMON_PACKAGE_NAME_PREG;
+    /**
+     * @var PEAR_PackageFile_v1|PEAR_PackageFile_v2
+     */
+    var $_packagexml;
+    /**
+     * @var int one of the PEAR_VALIDATE_* constants
+     */
+    var $_state = PEAR_VALIDATE_NORMAL;
+    /**
+     * Format: ('error' => array('field' => name, 'reason' => reason), 'warning' => same)
+     * @var array
+     * @access private
+     */
+    var $_failures = array('error' => array(), 'warning' => array());
+
+    /**
+     * Override this method to handle validation of normal package names
+     * @param string
+     * @return bool
+     * @access protected
+     */
+    function _validPackageName($name)
+    {
+        return (bool) preg_match('/^' . $this->packageregex . '$/', $name);
+    }
+
+    /**
+     * @param string package name to validate
+     * @param string name of channel-specific validation package
+     * @final
+     */
+    function validPackageName($name, $validatepackagename = false)
+    {
+        if ($validatepackagename) {
+            if (strtolower($name) == strtolower($validatepackagename)) {
+                return (bool) preg_match('/^[a-zA-Z0-9_]+(?:\.[a-zA-Z0-9_]+)*$/', $name);
+            }
+        }
+        return $this->_validPackageName($name);
+    }
+
+    /**
+     * This validates a bundle name, and bundle names must conform
+     * to the PEAR naming convention, so the method is final and static.
+     * @param string
+     * @final
+     * @static
+     */
+    function validGroupName($name)
+    {
+        return (bool) preg_match('/^' . _PEAR_COMMON_PACKAGE_NAME_PREG . '$/', $name);
+    }
+
+    /**
+     * Determine whether $state represents a valid stability level
+     * @param string
+     * @return bool
+     * @static
+     * @final
+     */
+    function validState($state)
+    {
+        return in_array($state, array('snapshot', 'devel', 'alpha', 'beta', 'stable'));
+    }
+
+    /**
+     * Get a list of valid stability levels
+     * @return array
+     * @static
+     * @final
+     */
+    function getValidStates()
+    {
+        return array('snapshot', 'devel', 'alpha', 'beta', 'stable');
+    }
+
+    /**
+     * Determine whether a version is a properly formatted version number that can be used
+     * by version_compare
+     * @param string
+     * @return bool
+     * @static
+     * @final
+     */
+    function validVersion($ver)
+    {
+        return (bool) preg_match(PEAR_COMMON_PACKAGE_VERSION_PREG, $ver);
+    }
+
+    /**
+     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+     */
+    function setPackageFile(&$pf)
+    {
+        $this->_packagexml = &$pf;
+    }
+
+    /**
+     * @access private
+     */
+    function _addFailure($field, $reason)
+    {
+        $this->_failures['errors'][] = array('field' => $field, 'reason' => $reason);
+    }
+
+    /**
+     * @access private
+     */
+    function _addWarning($field, $reason)
+    {
+        $this->_failures['warnings'][] = array('field' => $field, 'reason' => $reason);
+    }
+
+    function getFailures()
+    {
+        $failures = $this->_failures;
+        $this->_failures = array('warnings' => array(), 'errors' => array());
+        return $failures;
+    }
+
+    /**
+     * @param int one of the PEAR_VALIDATE_* constants
+     */
+    function validate($state = null)
+    {
+        if (!isset($this->_packagexml)) {
+            return false;
+        }
+        if ($state !== null) {
+            $this->_state = $state;
+        }
+        $this->_failures = array('warnings' => array(), 'errors' => array());
+        $this->validatePackageName();
+        $this->validateVersion();
+        $this->validateMaintainers();
+        $this->validateDate();
+        $this->validateSummary();
+        $this->validateDescription();
+        $this->validateLicense();
+        $this->validateNotes();
+        if ($this->_packagexml->getPackagexmlVersion() == '1.0') {
+            $this->validateState();
+            $this->validateFilelist();
+        } elseif ($this->_packagexml->getPackagexmlVersion() == '2.0') {
+            $this->validateTime();
+            $this->validateStability();
+            $this->validateDeps();
+            $this->validateMainFilelist();
+            $this->validateReleaseFilelist();
+            //$this->validateGlobalTasks();
+            $this->validateChangelog();
+        }
+        return !((bool) count($this->_failures['errors']));
+    }
+
+    /**
+     * @access protected
+     */
+    function validatePackageName()
+    {
+        if ($this->_state == PEAR_VALIDATE_PACKAGING ||
+              $this->_state == PEAR_VALIDATE_NORMAL) {
+            if ($this->_packagexml->getPackagexmlVersion() == '2.0' &&
+                  $this->_packagexml->getExtends()) {
+                $version = $this->_packagexml->getVersion() . '';
+                $name = $this->_packagexml->getPackage();
+                $test = array_shift($a = explode('.', $version));
+                if ($test == '0') {
+                    return true;
+                }
+                $vlen = strlen($test);
+                $majver = substr($name, strlen($name) - $vlen);
+                while ($majver && !is_numeric($majver{0})) {
+                    $majver = substr($majver, 1);
+                }
+                if ($majver != $test) {
+                    $this->_addWarning('package', "package $name extends package " .
+                        $this->_packagexml->getExtends() . ' and so the name should ' .
+                        'have a postfix equal to the major version like "' .
+                        $this->_packagexml->getExtends() . $test . '"');
+                    return true;
+                } elseif (substr($name, 0, strlen($name) - $vlen) !=
+                            $this->_packagexml->getExtends()) {
+                    $this->_addWarning('package', "package $name extends package " .
+                        $this->_packagexml->getExtends() . ' and so the name must ' .
+                        'be an extension like "' . $this->_packagexml->getExtends() .
+                        $test . '"');
+                    return true;
+                }
+            }
+        }
+        if (!$this->validPackageName($this->_packagexml->getPackage())) {
+            $this->_addFailure('name', 'package name "' .
+                $this->_packagexml->getPackage() . '" is invalid');
+            return false;
+        }
+    }
+
+    /**
+     * @access protected
+     */
+    function validateVersion()
+    {
+        if ($this->_state != PEAR_VALIDATE_PACKAGING) {
+            if (!$this->validVersion($this->_packagexml->getVersion())) {
+                $this->_addFailure('version',
+                    'Invalid version number "' . $this->_packagexml->getVersion() . '"');
+            }
+            return false;
+        }
+        $version = $this->_packagexml->getVersion();
+        $versioncomponents = explode('.', $version);
+        if (count($versioncomponents) != 3) {
+            $this->_addWarning('version',
+                'A version number should have 3 decimals (x.y.z)');
+            return true;
+        }
+        $name = $this->_packagexml->getPackage();
+        // version must be based upon state
+        switch ($this->_packagexml->getState()) {
+            case 'snapshot' :
+                return true;
+            case 'devel' :
+                if ($versioncomponents[0] . 'a' == '0a') {
+                    return true;
+                }
+                if ($versioncomponents[0] == 0) {
+                    $versioncomponents[0] = '0';
+                    $this->_addWarning('version',
+                        'version "' . $version . '" should be "' .
+                        implode('.' ,$versioncomponents) . '"');
+                } else {
+                    $this->_addWarning('version',
+                        'packages with devel stability must be < version 1.0.0');
+                }
+                return true;
+            break;
+            case 'alpha' :
+            case 'beta' :
+                // check for a package that extends a package,
+                // like Foo and Foo2
+                if (!$this->_packagexml->getExtends()) {
+                    if ($versioncomponents[0] == '1') {
+                        if ($versioncomponents[2]{0} == '0') {
+                            if ($versioncomponents[2] == '0') {
+                                // version 1.*.0000
+                                $this->_addWarning('version',
+                                    'version 1.' . $versioncomponents[1] .
+                                        '.0 probably should not be alpha or beta');
+                                return true;
+                            } elseif (strlen($versioncomponents[2]) > 1) {
+                                // version 1.*.0RC1 or 1.*.0beta24 etc.
+                                return true;
+                            } else {
+                                // version 1.*.0
+                                $this->_addWarning('version',
+                                    'version 1.' . $versioncomponents[1] .
+                                        '.0 probably should not be alpha or beta');
+                                return true;
+                            }
+                        } else {
+                            $this->_addWarning('version',
+                                'bugfix versions (1.3.x where x > 0) probably should ' .
+                                'not be alpha or beta');
+                            return true;
+                        }
+                    } elseif ($versioncomponents[0] != '0') {
+                        $this->_addWarning('version',
+                            'major versions greater than 1 are not allowed for packages ' .
+                            'without an <extends> tag or an identical postfix (foo2 v2.0.0)');
+                        return true;
+                    }
+                    if ($versioncomponents[0] . 'a' == '0a') {
+                        return true;
+                    }
+                    if ($versioncomponents[0] == 0) {
+                        $versioncomponents[0] = '0';
+                        $this->_addWarning('version',
+                            'version "' . $version . '" should be "' .
+                            implode('.' ,$versioncomponents) . '"');
+                    }
+                } else {
+                    $vlen = strlen($versioncomponents[0] . '');
+                    $majver = substr($name, strlen($name) - $vlen);
+                    while ($majver && !is_numeric($majver{0})) {
+                        $majver = substr($majver, 1);
+                    }
+                    if (($versioncomponents[0] != 0) && $majver != $versioncomponents[0]) {
+                        $this->_addWarning('version', 'first version number "' .
+                            $versioncomponents[0] . '" must match the postfix of ' .
+                            'package name "' . $name . '" (' .
+                            $majver . ')');
+                        return true;
+                    }
+                    if ($versioncomponents[0] == $majver) {
+                        if ($versioncomponents[2]{0} == '0') {
+                            if ($versioncomponents[2] == '0') {
+                                // version 2.*.0000
+                                $this->_addWarning('version',
+                                    "version $majver." . $versioncomponents[1] .
+                                        '.0 probably should not be alpha or beta');
+                                return false;
+                            } elseif (strlen($versioncomponents[2]) > 1) {
+                                // version 2.*.0RC1 or 2.*.0beta24 etc.
+                                return true;
+                            } else {
+                                // version 2.*.0
+                                $this->_addWarning('version',
+                                    "version $majver." . $versioncomponents[1] .
+                                        '.0 cannot be alpha or beta');
+                                return true;
+                            }
+                        } else {
+                            $this->_addWarning('version',
+                                "bugfix versions ($majver.x.y where y > 0) should " .
+                                'not be alpha or beta');
+                            return true;
+                        }
+                    } elseif ($versioncomponents[0] != '0') {
+                        $this->_addWarning('version',
+                            "only versions 0.x.y and $majver.x.y are allowed for alpha/beta releases");
+                        return true;
+                    }
+                    if ($versioncomponents[0] . 'a' == '0a') {
+                        return true;
+                    }
+                    if ($versioncomponents[0] == 0) {
+                        $versioncomponents[0] = '0';
+                        $this->_addWarning('version',
+                            'version "' . $version . '" should be "' .
+                            implode('.' ,$versioncomponents) . '"');
+                    }
+                }
+                return true;
+            break;
+            case 'stable' :
+                if ($versioncomponents[0] == '0') {
+                    $this->_addWarning('version', 'versions less than 1.0.0 cannot ' .
+                    'be stable');
+                    return true;
+                }
+                if (!is_numeric($versioncomponents[2])) {
+                    if (preg_match('/\d+(rc|a|alpha|b|beta)\d*/i',
+                          $versioncomponents[2])) {
+                        $this->_addWarning('version', 'version "' . $version . '" or any ' .
+                            'RC/beta/alpha version cannot be stable');
+                        return true;
+                    }
+                }
+                // check for a package that extends a package,
+                // like Foo and Foo2
+                if ($this->_packagexml->getExtends()) {
+                    $vlen = strlen($versioncomponents[0] . '');
+                    $majver = substr($name, strlen($name) - $vlen);
+                    while ($majver && !is_numeric($majver{0})) {
+                        $majver = substr($majver, 1);
+                    }
+                    if (($versioncomponents[0] != 0) && $majver != $versioncomponents[0]) {
+                        $this->_addWarning('version', 'first version number "' .
+                            $versioncomponents[0] . '" must match the postfix of ' .
+                            'package name "' . $name . '" (' .
+                            $majver . ')');
+                        return true;
+                    }
+                } elseif ($versioncomponents[0] > 1) {
+                    $this->_addWarning('version', 'major version x in x.y.z may not be greater than ' .
+                        '1 for any package that does not have an <extends> tag');
+                }
+                return true;
+            break;
+            default :
+                return false;
+            break;
+        }
+    }
+
+    /**
+     * @access protected
+     */
+    function validateMaintainers()
+    {
+        // maintainers can only be truly validated server-side for most channels
+        // but allow this customization for those who wish it
+        return true;
+    }
+
+    /**
+     * @access protected
+     */
+    function validateDate()
+    {
+        if ($this->_state == PEAR_VALIDATE_NORMAL ||
+              $this->_state == PEAR_VALIDATE_PACKAGING) {
+            if (!preg_match('/\d\d\d\d\-\d\d\-\d\d/',
+                  $this->_packagexml->getDate())) {
+                $this->_addFailure('date', 'invalid release date "' .
+                    $this->_packagexml->getDate() . '"');
+                return false;
+            }
+            if (strtotime($this->_packagexml->getDate()) == -1) {
+                $this->_addFailure('date', 'invalid release date "' .
+                    $this->_packagexml->getDate() . '"');
+                return false;
+            }
+            if ($this->_state == PEAR_VALIDATE_PACKAGING &&
+                  $this->_packagexml->getDate() != date('Y-m-d')) {
+                $this->_addWarning('date', 'Release Date "' .
+                    $this->_packagexml->getDate() . '"is not today');
+            }
+        }
+        return true;
+    }
+
+    /**
+     * @access protected
+     */
+    function validateTime()
+    {
+        if (!$this->_packagexml->getTime()) {
+            // default of no time value set
+            return true;
+        }
+        // packager automatically sets time, so only validate if
+        // pear validate is called
+        if ($this->_state = PEAR_VALIDATE_NORMAL) {
+            if (!preg_match('/\d\d:\d\d:\d\d/',
+                  $this->_packagexml->getTime())) {
+                $this->_addFailure('time', 'invalid release time "' .
+                    $this->_packagexml->getTime() . '"');
+                return false;
+            }
+            if (strtotime($this->_packagexml->getTime()) == -1) {
+                $this->_addFailure('time', 'invalid release time "' .
+                    $this->_packagexml->getTime() . '"');
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * @access protected
+     */
+    function validateState()
+    {
+        // this is the closest to "final" php4 can get
+        if (!PEAR_Validate::validState($this->_packagexml->getState())) {
+            if (strtolower($this->_packagexml->getState() == 'rc')) {
+                $this->_addFailure('state', 'RC is not a state, it is a version ' .
+                    'postfix, use ' . $this->_packagexml->getVersion() . 'RC1, state beta');
+            }
+            $this->_addFailure('state', 'invalid release state "' .
+                $this->_packagexml->getState() . '", must be one of: ' .
+                implode(', ', PEAR_Validate::getValidStates()));
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * @access protected
+     */
+    function validateStability()
+    {
+        $ret = true;
+        $packagestability = $this->_packagexml->getState();
+        $apistability = $this->_packagexml->getState('api');
+        if (!PEAR_Validate::validState($packagestability)) {
+            $this->_addFailure('state', 'invalid release stability "' .
+                $this->_packagexml->getState() . '", must be one of: ' .
+                implode(', ', PEAR_Validate::getValidStates()));
+            $ret = false;
+        }
+        $apistates = PEAR_Validate::getValidStates();
+        array_shift($apistates); // snapshot is not allowed
+        if (!in_array($apistability, $apistates)) {
+            $this->_addFailure('state', 'invalid API stability "' .
+                $this->_packagexml->getState('api') . '", must be one of: ' .
+                implode(', ', $apistates));
+            $ret = false;
+        }
+        return $ret;
+    }
+
+    /**
+     * @access protected
+     */
+    function validateSummary()
+    {
+        return true;
+    }
+
+    /**
+     * @access protected
+     */
+    function validateDescription()
+    {
+        return true;
+    }
+
+    /**
+     * @access protected
+     */
+    function validateLicense()
+    {
+        return true;
+    }
+
+    /**
+     * @access protected
+     */
+    function validateNotes()
+    {
+        return true;
+    }
+
+    /**
+     * for package.xml 2.0 only - channels can't use package.xml 1.0
+     * @access protected
+     */
+    function validateDependencies()
+    {
+        return true;
+    }
+
+    /**
+     * for package.xml 1.0 only
+     * @access private
+     */
+    function _validateFilelist()
+    {
+        return true; // placeholder for now
+    }
+
+    /**
+     * for package.xml 2.0 only
+     * @access protected
+     */
+    function validateMainFilelist()
+    {
+        return true; // placeholder for now
+    }
+
+    /**
+     * for package.xml 2.0 only
+     * @access protected
+     */
+    function validateReleaseFilelist()
+    {
+        return true; // placeholder for now
+    }
+
+    /**
+     * @access protected
+     */
+    function validateChangelog()
+    {
+        return true;
+    }
+
+    /**
+     * @access protected
+     */
+    function validateFilelist()
+    {
+        return true;
+    }
+
+    /**
+     * @access protected
+     */
+    function validateDeps()
+    {
+        return true;
+    }
+}
+?>
\ No newline at end of file
diff --git a/pear/PEAR/Validator/PECL.php b/pear/PEAR/Validator/PECL.php
new file mode 100644 (file)
index 0000000..da70a3f
--- /dev/null
@@ -0,0 +1,52 @@
+<?php
+/**
+ * Channel Validator for the pecl.php.net channel
+ *
+ * PHP 4 and PHP 5
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a5
+ */
+/**
+ * This is the parent class for all validators
+ */
+require_once 'PEAR/Validate.php';
+/**
+ * Channel Validator for the pecl.php.net channel
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a5
+ */
+class PEAR_Validator_PECL extends PEAR_Validate
+{
+    function validateVersion()
+    {
+        return true;
+    }
+
+    function validatePackageName()
+    {
+        $ret = parent::validatePackageName();
+        if ($this->_packagexml->getPackageType() == 'extsrc') {
+            if (strtolower($this->_packagexml->getPackage()) !=
+                  strtolower($this->_packagexml->getProvidesExtension())) {
+                $this->_addWarning('providesextension', 'package name "' .
+                    $this->_packagexml->getPackage() . '" is different from extension name "' .
+                    $this->_packagexml->getProvidesExtension() . '"');
+            }
+        }
+        return $ret;
+    }
+}
+?>
\ No newline at end of file
diff --git a/pear/PEAR/XMLParser.php b/pear/PEAR/XMLParser.php
new file mode 100644 (file)
index 0000000..6373761
--- /dev/null
@@ -0,0 +1,261 @@
+<?php
+/**
+ * PEAR_FTP
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @author     Stephan Schmidt (original XML_Unserializer code)
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 1.4.0a1
+ */
+
+/**
+ * Parser for any xml file
+ * @category   pear
+ * @package    PEAR
+ * @author     Greg Beaver <cellog@php.net>
+ * @author     Stephan Schmidt (original XML_Unserializer code)
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/PEAR
+ * @since      Class available since Release 1.4.0a1
+ */
+class PEAR_XMLParser
+{
+    /**
+     * unserilialized data
+     * @var string $_serializedData
+     */
+    var $_unserializedData = null;
+
+    /**
+     * name of the root tag
+     * @var string $_root
+     */
+    var $_root = null;
+
+    /**
+     * stack for all data that is found
+     * @var array    $_dataStack
+     */
+    var $_dataStack  =   array();
+
+    /**
+     * stack for all values that are generated
+     * @var array    $_valStack
+     */
+    var $_valStack  =   array();
+
+    /**
+     * current tag depth
+     * @var int    $_depth
+     */
+    var $_depth = 0;
+
+    /**
+     * @return array
+     */
+    function getData()
+    {
+        return $this->_unserializedData;
+    }
+
+    /**
+     * @param string xml content
+     * @return true|PEAR_Error
+     */
+    function parse($data)
+    {
+        if (!extension_loaded('xml')) {
+            include_once 'PEAR.php';
+            return PEAR::raiseError("XML Extension not found", 1);
+        }
+        $this->_valStack = array();
+        $this->_dataStack = array();
+        $this->_depth = 0;
+
+        if (version_compare(phpversion(), '5.0.0', 'lt')) {
+            if (strpos($data, 'encoding="UTF-8"')) {
+                $data = utf8_decode($data);
+            }
+            $xp = @xml_parser_create('ISO-8859-1');
+        } else {
+            if (strpos($data, 'encoding="UTF-8"')) {
+                $xp = @xml_parser_create('UTF-8');
+            } else {
+                $xp = @xml_parser_create('ISO-8859-1');
+            }
+        }
+        xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, 0);
+        xml_set_object($xp, $this);
+        xml_set_element_handler($xp, 'startHandler', 'endHandler');
+        xml_set_character_data_handler($xp, 'cdataHandler');
+        if (!xml_parse($xp, $data)) {
+            $msg = xml_error_string(xml_get_error_code($xp));
+            $line = xml_get_current_line_number($xp);
+            xml_parser_free($xp);
+            include_once 'PEAR.php';
+            return PEAR::raiseError("XML Error: '$msg' on line '$line'", 2);
+        }
+        xml_parser_free($xp);
+        return true;
+    }
+
+    /**
+     * Start element handler for XML parser
+     *
+     * @access private
+     * @param  object $parser  XML parser object
+     * @param  string $element XML element
+     * @param  array  $attribs attributes of XML tag
+     * @return void
+     */
+    function startHandler($parser, $element, $attribs)
+    {
+        $type = 'string';
+
+        $this->_depth++;
+        $this->_dataStack[$this->_depth] = null;
+
+        $val = array(
+                     'name'         => $element,
+                     'value'        => null,
+                     'type'         => $type,
+                     'childrenKeys' => array(),
+                     'aggregKeys'   => array()
+                    );
+
+        if (count($attribs) > 0) {
+            $val['children'] = array();
+            $val['type'] = 'array';
+
+            $val['children']['attribs'] = $attribs;
+
+        }
+
+        array_push($this->_valStack, $val);
+    }
+
+    /**
+     * post-process data
+     *
+     * @param string $data
+     * @param string $element element name
+     */
+    function postProcess($data, $element)
+    {
+        return trim($data);
+    }
+
+    /**
+     * End element handler for XML parser
+     *
+     * @access private
+     * @param  object XML parser object
+     * @param  string
+     * @return void
+     */
+    function endHandler($parser, $element)
+    {
+        $value = array_pop($this->_valStack);
+        $data  = $this->postProcess($this->_dataStack[$this->_depth], $element);
+
+        // adjust type of the value
+        switch(strtolower($value['type'])) {
+
+            /*
+             * unserialize an array
+             */
+            case 'array':
+                if ($data !== '') {
+                    $value['children']['_content'] = $data;
+                }
+                if (isset($value['children'])) {
+                    $value['value'] = $value['children'];
+                } else {
+                    $value['value'] = array();
+                }
+                break;
+
+            /*
+             * unserialize a null value
+             */
+            case 'null':
+                $data = null;
+                break;
+
+            /*
+             * unserialize any scalar value
+             */
+            default:
+                settype($data, $value['type']);
+                $value['value'] = $data;
+                break;
+        }
+        $parent = array_pop($this->_valStack);
+        if ($parent === null) {
+            $this->_unserializedData = &$value['value'];
+            $this->_root = &$value['name'];
+            return true;
+        } else {
+            // parent has to be an array
+            if (!isset($parent['children']) || !is_array($parent['children'])) {
+                $parent['children'] = array();
+                if ($parent['type'] != 'array') {
+                    $parent['type'] = 'array';
+                }
+            }
+
+            if (!empty($value['name'])) {
+                // there already has been a tag with this name
+                if (in_array($value['name'], $parent['childrenKeys'])) {
+                    // no aggregate has been created for this tag
+                    if (!in_array($value['name'], $parent['aggregKeys'])) {
+                        if (isset($parent['children'][$value['name']])) {
+                            $parent['children'][$value['name']] = array($parent['children'][$value['name']]);
+                        } else {
+                            $parent['children'][$value['name']] = array();
+                        }
+                        array_push($parent['aggregKeys'], $value['name']);
+                    }
+                    array_push($parent['children'][$value['name']], $value['value']);
+                } else {
+                    $parent['children'][$value['name']] = &$value['value'];
+                    array_push($parent['childrenKeys'], $value['name']);
+                }
+            } else {
+                array_push($parent['children'],$value['value']);
+            }
+            array_push($this->_valStack, $parent);
+        }
+
+        $this->_depth--;
+    }
+
+    /**
+     * Handler for character data
+     *
+     * @access private
+     * @param  object XML parser object
+     * @param  string CDATA
+     * @return void
+     */
+    function cdataHandler($parser, $cdata)
+    {
+        $this->_dataStack[$this->_depth] .= $cdata;
+    }
+}
+?>
\ No newline at end of file
index 7289016da52a66ba4a5c2b081963fb84de0ed82c..6f32140ec660727dc37715c6236c0838d7ac6160 100644 (file)
@@ -1,24 +1,28 @@
 <?php
-//
-// +----------------------------------------------------------------------+
-// | PHP Version 5                                                        |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2004 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: Tomas V.V.Cox <cox@idecnet.com>                             |
-// +----------------------------------------------------------------------+
-//
-// $Id$
-//
+/**
+ * File/Directory manipulation
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * 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 web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   pear
+ * @package    System
+ * @author     Tomas V.V.Cox <cox@idecnet.com>
+ * @copyright  1997-2005 The PHP Group
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id$
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 0.1
+ */
 
+/**
+ * base class
+ */
 require_once 'PEAR.php';
 require_once 'Console/Getopt.php';
 
@@ -46,11 +50,14 @@ $GLOBALS['_System_temp_files'] = array();
 *
 * System::rm(array('-r', $file1, $dir1));
 *
-* @package  System
-* @author   Tomas V.V.Cox <cox@idecnet.com>
-* @version  $Revision$
-* @access   public
-* @see      http://pear.php.net/manual/
+* @category   pear
+* @package    System
+* @author     Tomas V.V. Cox <cox@idecnet.com>
+* @copyright  1997-2005 The PHP Group
+* @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+* @version    Release: @package_version@
+* @link       http://pear.php.net/package/PEAR
+* @since      Class available since Release 0.1
 */
 class System
 {
@@ -66,7 +73,7 @@ class System
     function _parseArgs($argv, $short_options, $long_options = null)
     {
         if (!is_array($argv) && $argv !== null) {
-            $argv = preg_split('/\s+/', $argv);
+            $argv = preg_split('/\s+/', $argv, -1, PREG_SPLIT_NO_EMPTY);
         }
         return Console_Getopt::getopt2($argv, $short_options);
     }
@@ -119,9 +126,9 @@ class System
             System::raiseError("Could not open dir $sPath");
             return $struct; // XXX could not open error
         }
-        $struct['dirs'][] = $sPath; // XXX don't add if '.' or '..' ?
+        $struct['dirs'][] = $sPath = realpath($sPath); // XXX don't add if '.' or '..' ?
         $list = array();
-        while ($file = readdir($dir)) {
+        while (false !== ($file = readdir($dir))) {
             if ($file != '.' && $file != '..') {
                 $list[] = $file;
             }
@@ -131,7 +138,7 @@ class System
         if ($aktinst < $maxinst || $maxinst == 0) {
             foreach($list as $val) {
                 $path = $sPath . DIRECTORY_SEPARATOR . $val;
-                if (is_dir($path)) {
+                if (is_dir($path) && !is_link($path)) {
                     $tmp = System::_dirToStruct($path, $maxinst, $aktinst+1);
                     $struct = array_merge_recursive($tmp, $struct);
                 } else {
@@ -154,7 +161,7 @@ class System
         $struct = array('dirs' => array(), 'files' => array());
         settype($files, 'array');
         foreach ($files as $file) {
-            if (is_dir($file)) {
+            if (is_dir($file) && !is_link($file)) {
                 $tmp = System::_dirToStruct($file, 0);
                 $struct = array_merge_recursive($tmp, $struct);
             } else {
@@ -208,9 +215,9 @@ class System
     }
 
     /**
-    * Make directories. Note that we use call_user_func('mkdir') to avoid
-    * a problem with ZE2 calling System::mkDir instead of the native PHP func.
+    * Make directories.
     *
+    * The -p option will create parent directories
     * @param    string  $args    the name of the director(y|ies) to create
     * @return   bool    True for success
     * @access   public
@@ -246,14 +253,18 @@ class System
                     $dir = dirname($dir);
                 }
                 while ($newdir = array_shift($dirstack)) {
-                    if (!call_user_func('mkdir', $newdir, $mode)) {
+                    if (!is_writeable(dirname($newdir))) {
+                        $ret = false;
+                        break;
+                    }
+                    if (!mkdir($newdir, $mode)) {
                         $ret = false;
                     }
                 }
             }
         } else {
             foreach($opts[1] as $dir) {
-                if (!@is_dir($dir) && !call_user_func('mkdir', $dir, $mode)) {
+                if (!@is_dir($dir) && !mkdir($dir, $mode)) {
                     $ret = false;
                 }
             }
@@ -280,7 +291,7 @@ class System
         $ret = null;
         $files = array();
         if (!is_array($args)) {
-            $args = preg_split('/\s+/', $args);
+            $args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY);
         }
         for($i=0; $i < count($args); $i++) {
             if ($args[$i] == '>') {
@@ -363,13 +374,13 @@ class System
         if (!isset($tmpdir)) {
             $tmpdir = System::tmpdir();
         }
-        if (!System::mkDir("-p $tmpdir")) {
+        if (!System::mkDir(array('-p', $tmpdir))) {
             return false;
         }
         $tmp = tempnam($tmpdir, $prefix);
         if (isset($tmp_is_dir)) {
             unlink($tmp); // be careful possible race condition here
-            if (!call_user_func('mkdir', $tmp, 0700)) {
+            if (!mkdir($tmp, 0700)) {
                 return System::raiseError("Unable to create temporary directory $tmpdir");
             }
         }
@@ -393,6 +404,7 @@ class System
             $delete = $GLOBALS['_System_temp_files'];
             array_unshift($delete, '-r');
             System::rm($delete);
+            $GLOBALS['_System_temp_files'] = array();
         }
     }
 
@@ -428,31 +440,53 @@ class System
     * The "which" command (show the full path of a command)
     *
     * @param string $program The command to search for
+    * @param mixed  $fallback Value to return if $program is not found
+    *
     * @return mixed A string with the full path or false if not found
     * @author Stig Bakken <ssb@php.net>
     */
     function which($program, $fallback = false)
     {
-        // is_executable() is not available on windows
-        if (OS_WINDOWS) {
-            $pear_is_executable = 'is_file';
+        // avaible since 4.3.0RC2
+        if (defined('PATH_SEPARATOR')) {
+            $path_delim = PATH_SEPARATOR;
         } else {
-            $pear_is_executable = 'is_executable';
+            $path_delim = OS_WINDOWS ? ';' : ':';
         }
-
         // full path given
         if (basename($program) != $program) {
-            return (@$pear_is_executable($program)) ? $program : $fallback;
+            $path_elements[] = dirname($program);
+            $program = basename($program);
+        } else {
+            // Honor safe mode
+            if (!ini_get('safe_mode') || !$path = ini_get('safe_mode_exec_dir')) {
+                $path = getenv('PATH');
+                if (!$path) {
+                    $path = getenv('Path'); // some OSes are just stupid enough to do this
+                }
+            }
+            $path_elements = explode($path_delim, $path);
+        }
+
+        if (OS_WINDOWS) {
+            $exe_suffixes = getenv('PATHEXT')
+                                ? explode($path_delim, getenv('PATHEXT'))
+                                : array('.exe','.bat','.cmd','.com');
+            // allow passing a command.exe param
+            if (strpos($program, '.') !== false) {
+                array_unshift($exe_suffixes, '');
+            }
+            // is_executable() is not available on windows for PHP4
+            $pear_is_executable = (function_exists('is_executable')) ? 'is_executable' : 'is_file';
+        } else {
+            $exe_suffixes = array('');
+            $pear_is_executable = 'is_executable';
         }
 
-        // XXX FIXME honor safe mode
-        $path_delim = OS_WINDOWS ? ';' : ':';
-        $exe_suffixes = OS_WINDOWS ? array('.exe','.bat','.cmd','.com') : array('');
-        $path_elements = explode($path_delim, getenv('PATH'));
         foreach ($exe_suffixes as $suff) {
             foreach ($path_elements as $dir) {
                 $file = $dir . DIRECTORY_SEPARATOR . $program . $suff;
-                if (@is_file($file) && @$pear_is_executable($file)) {
+                if ($pear_is_executable($file)) {
                     return $file;
                 }
             }
@@ -497,7 +531,7 @@ class System
                 case '-type':
                     if (in_array($args[$i+1], array('d', 'f'))) {
                         if ($args[$i+1] == 'd') {
-                             $do_files = false;
+                            $do_files = false;
                         } else {
                             $do_dirs = false;
                         }
@@ -505,8 +539,14 @@ class System
                     $i++;
                     break;
                 case '-name':
+                    if (OS_WINDOWS) {
+                        if ($args[$i+1]{0} == '\\') {
+                            // prepend drive
+                            $args[$i+1] = addslashes(substr(getcwd(), 0, 2) . $args[$i + 1]);
+                        }
+                    }
                     $patterns[] = "(" . preg_replace(array('/\./', '/\*/'),
-                                                     array('\.', '.*'),
+                                                     array('\.', '.*'),
                                                      $args[$i+1])
                                       . ")";
                     $i++;
index 68a43cb30ccb1be5906d3c318227d5b6229cfb53..ddce382c025a4bf19941fc7b4dc5d6580b3b1b8f 100644 (file)
@@ -2,13 +2,16 @@
 
 /* $Id$ */
 
+error_reporting(E_ALL);
 $pear_dir = dirname(__FILE__);
 ini_set('include_path', $pear_dir);
+set_time_limit(0);
 include_once 'PEAR.php';
 include_once 'PEAR/Installer.php';
 include_once 'PEAR/Registry.php';
-include_once 'PEAR/Frontend/CLI.php';
-
+include_once 'PEAR/PackageFile.php';
+include_once 'PEAR/Downloader/Package.php';
+include_once 'PEAR/Frontend.php';
 $a = true;
 if (!PEAR::loadExtension('xml')) {
     $a = false;
@@ -25,6 +28,7 @@ if (!$a) {
 $force = false;
 $install_files = array();
 array_shift($argv);
+$debug = false;
 for ($i = 0; $i < sizeof($argv); $i++) {
     $arg = $argv[$i];
     $bn = basename($arg);
@@ -39,6 +43,10 @@ for ($i = 0; $i < sizeof($argv); $i++) {
     } elseif ($arg == '-b') {
         $bin_dir = $argv[$i+1];
         $i++;
+    } elseif ($arg == '--debug') {
+        $debug = 1;
+    } elseif ($arg == '--extremedebug') {
+        $debug = 2;
     }
 }
 
@@ -51,7 +59,11 @@ foreach ($config_layers as $layer) {
     $config->removeLayer($layer);
 }
 $keys = $config->getKeys();
-$config->set('verbose', 0, 'default');
+if ($debug) {
+    $config->set('verbose', 5, 'default');
+} else {
+    $config->set('verbose', 0, 'default');
+}
 // PEAR executables
 if (!empty($bin_dir)) {
     $config->set('bin_dir', $bin_dir, 'default');
@@ -63,43 +75,64 @@ if (!empty($with_dir)) {
     $config->set('doc_dir', $with_dir . $ds . 'doc', 'default');
     $config->set('data_dir', $with_dir . $ds . 'data', 'default');
     $config->set('test_dir', $with_dir . $ds . 'test', 'default');
+    if (!is_writable($config->get('cache_dir'))) {
+        include_once 'System.php';
+        $cdir = System::mktemp(array('-d', 'pear'));
+        if (PEAR::isError($cdir)) {
+            $ui->outputData("[PEAR] cannot make new temporary directory: " . $cdir);
+            die(1);
+        }
+        $oldcachedir = $config->get('cache_dir');
+        $config->set('cache_dir', $cdir);
+    }
 }
-/* Print PEAR Conf (useful for debuging do NOT REMOVE)
-sort($keys);
-foreach ($keys as $key) {
-    echo $config->getPrompt($key) . ": " . $config->get($key) . "\n";
+/* Print PEAR Conf (useful for debuging do NOT REMOVE) */
+if ($debug) {
+    sort($keys);
+    foreach ($keys as $key) {
+        echo $key . '    ' .
+            $config->getPrompt($key) . ": " . $config->get($key, null, 'default') . "\n";
+    }
+    if ($debug == 2) { // extreme debugging
+        exit;
+    }
 }
-exit;
 // end print
-//*/
 
 $php_dir = $config->get('php_dir');
 $options = array();
+$options['upgrade'] = true;
 $install_root = getenv('INSTALL_ROOT');
 if (!empty($install_root)) {
     $options['installroot'] = $install_root;
-    $reg_dir = $install_root . $php_dir;
-} else {
-    $reg_dir = $php_dir;
+    $config->setInstallRoot($install_root);
 }
 
-$reg = &new PEAR_Registry($reg_dir);
-$ui = &new PEAR_Frontend_CLI();
+$reg = $config->getRegistry('default');
+$ui = &PEAR_Frontend::singleton('PEAR_Frontend_CLI');
 $installer = &new PEAR_Installer($ui);
-//$installer->registry = &$reg; // This should be changed in Installer/Registry
+$pkg = &new PEAR_PackageFile($config, $debug);
 
 foreach ($install_files as $package => $instfile) {
+    $info = &$pkg->fromAnyFile($instfile, PEAR_VALIDATE_INSTALLING);
+    $new_ver = $info->getVersion();
+    if (PEAR::isError($info)) {
+        $ui->outputData(sprintf("[PEAR] %s: %s", $package, $info->getMessage()));
+        continue;
+    }
+    $downloaderpackage = &new PEAR_Downloader_Package($installer);
+    $err = $downloaderpackage->initialize($instfile);
+    if (PEAR::isError($err)) {
+        $ui->outputData(sprintf("[PEAR] %s: %s", $package, $err->getMessage()));
+        continue;
+    }
     if ($reg->packageExists($package)) {
-        $info = $installer->infoFromAny($instfile);
-        if (PEAR::isError($info)) {
-            $ui->outputData(sprintf("[PEAR] %s: %s", $package, $info->getMessage()));
-            continue;
-        }
-        $new_ver = $info['version'];
         $old_ver = $reg->packageInfo($package, 'version');
         if (version_compare($new_ver, $old_ver, 'gt')) {
-            $options['upgrade'] = true;
-            $err = $installer->install($instfile, $options);
+            $installer->setOptions($options);
+            $dp = array(&$downloaderpackage);
+            $installer->setDownloadedPackages($dp);
+            $err = $installer->install($downloaderpackage, $options);
             if (PEAR::isError($err)) {
                 $ui->outputData(sprintf("[PEAR] %s: %s", $package, $err->getMessage()));
                 continue;
@@ -108,7 +141,10 @@ foreach ($install_files as $package => $instfile) {
         } else {
             if ($force) {
                 $options['force'] = true;
-                $err = $installer->install($instfile, $options);
+                $installer->setOptions($options);
+                $dp = array(&$downloaderpackage);
+                $installer->setDownloadedPackages($dp);
+                $err = $installer->install($downloaderpackage, $options);
                 if (PEAR::isError($err)) {
                     $ui->outputData(sprintf("[PEAR] %s: %s", $package, $err->getMessage()));
                     continue;
@@ -120,12 +156,14 @@ foreach ($install_files as $package => $instfile) {
         }
     } else {
         $options['nodeps'] = true;
-        $err = $installer->install($instfile, $options);
+        $installer->setOptions($options);
+        $dp = array(&$downloaderpackage);
+        $installer->setDownloadedPackages($dp);
+        $err = $installer->install($downloaderpackage, $options);
         if (PEAR::isError($err)) {
             $ui->outputData(sprintf("[PEAR] %s: %s", $package, $err->getMessage()));
             continue;
         }
-        $new_ver = $reg->packageInfo($package, 'version');
         $ui->outputData(sprintf("[PEAR] %-15s- installed: %s", $package, $new_ver));
     }
     if ($package == 'PEAR') {
@@ -135,6 +173,9 @@ foreach ($install_files as $package => $instfile) {
                             "'$ufile'. You may probably want to remove it.");
         }
         $config->set('verbose', 1, 'default');
+        if (isset($oldcachedir)) {
+            $config->set('cache_dir', $oldcachedir);
+        }
         foreach ($config->getKeys() as $key) {
             $data[$key] = $config->get($key);
         }
index 9a134fdd4c52369bd0a99ad125c1a8e1a7d41a7b..85a2a96cbaaf6ae44d9d299ed14ee9d72908b30f 100644 (file)
-<?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:
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--DOCTYPE package SYSTEM "http://pear.php.net/dtd/package-1.0"-->
+<package version="1.0" xmlns="http://pear.php.net/dtd/package-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/package-1.0
+http://pear.php.net/dtd/package-1.0.xsd">
+ <name>PEAR</name>
+ <summary>PEAR Base System</summary>
+ <description>The PEAR package contains:
  * the PEAR installer, for creating, distributing
    and installing packages
- * the alpha-quality PEAR_Exception php5-only exception class
+ * the beta-quality PEAR_Exception PHP5 error handling mechanism
  * the beta-quality PEAR_ErrorStack advanced error handling mechanism
  * the PEAR_Error error handling mechanism
  * the OS_Guess class for retrieving info about the OS
    where PHP is running on
- * the System class for quick handling common operations
+ * the System class for quick handling of common operations
    with files and directories
  * the PEAR base class
-</description>
-  <maintainers>
-    <maintainer>
-      <user>ssb</user>
-      <role>lead</role>
-      <name>Stig 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>cellog</user>
-      <role>lead</role>
-      <name>Greg Beaver</name>
-      <email>cellog@php.net</email>
-    </maintainer>
-    <maintainer>
-      <user>pajoye</user>
-      <role>lead</role>
-      <name>Pierre-Alain Joye</name>
-      <email>pajoye@pearfr.org</email>
-    </maintainer>
-    <maintainer>
-      <user>mj</user>
-      <role>developer</role>
-      <name>Martin Jansen</name>
-      <email>mj@php.net</email>
-    </maintainer>
-  </maintainers>
-  <release>
-    <version>1.3.6</version>
-    <date>2005-08-18</date>
-    <state>stable</state>
-    <license>PHP License</license>
-    <notes>
- * Bump XML_RPC dependency to 1.4.0
- * return by reference from PEAR::raiseError()
-    </notes>
-    <provides type="class" name="OS_Guess" />
-    <provides type="class" name="System" />
-    <provides type="function" name="md5_file" />
-    <filelist>
-      <dir name="OS">
-        <file role="php" name="Guess.php"/>
-      </dir>
-      <dir name="PEAR">
-        <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.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>
-        <dir name="Frontend">
-          <file role="php" name="CLI.php"/>
-        </dir>
-        <file role="php" name="Autoloader.php"/>
-        <file role="php" name="Command.php"/>
-        <file role="php" name="Common.php"/>
-        <file role="php" name="Config.php"/>
-        <file role="php" name="Dependency.php"/>
-        <file role="php" name="Downloader.php"/>
-        <file role="php" name="Exception.php"/>
-        <file role="php" name="ErrorStack.php"/>
-        <file role="php" name="Builder.php">
-         <replace from="@PEAR-VER@" to="version" type="package-info"/>
-        </file>
-        <file role="php" name="Installer.php"/>
-        <file role="php" name="Packager.php"/>
-        <file role="php" name="Registry.php"/>
-        <file role="php" name="Remote.php"/>
-        <file role="php" name="RunTest.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>
-      <file role="data" name="package.dtd"/>
-      <file role="data" name="template.spec"/>
-      <file role="php" name="PEAR.php"/>
-      <file role="php" name="System.php"/>
-    </filelist>
-    <deps>
-      <dep type="php" rel="ge" version="4.2"/>
-      <dep type="pkg" rel="ge" version="1.1">Archive_Tar</dep>
-      <dep type="pkg" rel="ge" version="1.2">Console_Getopt</dep>
-      <dep type="pkg" rel="ge" version="1.4.0">XML_RPC</dep>
-      <dep type="ext" rel="has">xml</dep>
-      <dep type="ext" rel="has">pcre</dep>
-      <dep type="ext" rel="has" optional="yes">xmlrpc</dep>
-    </deps>
-  </release>
-  <changelog>
-  <release>
-    <version>1.3.5</version>
-    <date>2005-02-18</date>
-    <state>stable</state>
-    <license>PHP License</license>
-    <notes>
- * fix Bug #3505: pecl can't install PDO
- * enhance pear run-tests dramatically
- * fix Bug #3506: pear install should export the pear version into the environment
-    </notes>
-  </release>
-  <release>
-    <version>1.3.1</version>
-    <date>2004-04-06</date>
-    <state>stable</state>
-    <notes>
-PEAR Installer:
 
- * Bug #534  pear search doesn't list unstable releases
- * Bug #933  CMD Usability Patch 
- * Bug #937  throwError() treats every call as static 
- * Bug #964 PEAR_ERROR_EXCEPTION causes fatal error 
- * Bug #1008 safe mode raises warning
+  New features in a nutshell:
+  * full support for channels
+  * pre-download dependency validation
+  * new package.xml 2.0 format allows tremendous flexibility while maintaining BC
+  * support for optional dependency groups and limited support for sub-packaging
+  * robust dependency support
+  * full dependency validation on uninstall
+  * remote install for hosts with only ftp access - no more problems with
+    restricted host installation
+  * full support for mirroring
+  * support for bundling several packages into a single tarball
+  * support for static dependencies on a url-based package
+  * support for custom file roles and installation tasks
 
-PEAR_ErrorStack:
+  NOTE: users of PEAR_Frontend_Web/PEAR_Frontend_Gtk must upgrade their installations
+  to the latest version, or PEAR will not upgrade properly
+ </description>
+ <maintainers>
+  <maintainer>
+   <user>cellog</user>
+   <role>lead</role>
+   <name>Greg Beaver</name>
+   <email>cellog@php.net</email>
+  </maintainer>
+  <maintainer>
+   <user>ssb</user>
+   <role>lead</role>
+   <name>Stig 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>pajoye</user>
+   <role>lead</role>
+   <name>Pierre-Alain Joye</name>
+   <email>pajoye@pearfr.org</email>
+  </maintainer>
+  <maintainer>
+   <user>mj</user>
+   <role>helper</role>
+   <name>Martin Jansen</name>
+   <email>mj@php.net</email>
+  </maintainer>
+ </maintainers>
+ <release>
+  <version>1.4.3</version>
+  <date>2005-11-03</date>
+  <license>PHP License</license>
+  <state>stable</state>
+  <notes>
+  MINOR SECURITY FIX release
 
- * Added experimental error handling, designed to eventually replace
-   PEAR_Error.  It should be considered experimental until explicitly marked
-   stable.  require_once 'PEAR/ErrorStack.php' to use.
+  A security vulnerability has been discovered in all
+  PEAR versions (1.0 to 1.4.2).  This vulnerability has been fixed, 
+  and this is a recommended upgrade for all users.
 
-    </notes>
-  </release>
+  Run "pear channel-update" after upgrading for exponentially
+  faster list-all/remote-list!!
+
+  * fix installation of files named like &quot;.test&quot;
+  * fix base class for writeable unixeol/windowseol classes
+  * fix running of post-install scripts with empty or no paramgroup
+    in CLI frontend
+  * fix validation of &lt;postinstallscript&gt;
+  * fix writeable PEAR_Task_Postinstallscript_rw class
+  * fix error in REST-based search command if searching through description
+    as well
+  * silence warning on list-upgrades/upgrade-all if no releases exist at a channel
+  * add checks for updated channel.xml in all remote commands
+  * fix pecl script if safe_mode is enabled by default
+  * implement SERIOUS improvement in list-all/remote-list speed.  From 6 minutes
+    down to about 16-30 seconds
+  * implement --loose option to avoid recommended version validation
+  * implement Request #5527: alternative approach to determining glibc version
+  * fix Bug #5717: analyzeSourceCode() fails to process certain
+    quote situations properly
+  * fix Bug #5736: if registry can't lock registry or open filemap,
+    checkFileMap(), no error
+  * fix Bug #5676: pear config-create broken
+  * fix Bug #5683: Deadlock with (almost) circular dependency
+  * fix Bug #5725: PHP5 warnings need improvement
+  * fix Bug #5789: small typo
+  * fix Bug #5810: internet should not be contacted on install if dependencies are installed
+  </notes>
+  <provides type="class" name="OS_Guess"/>
+  <provides type="class" name="System"/>
+  <provides type="function" name="md5_file"/>
+  <deps>
+   <dep type="php" rel="ge" version="4.2"/>
+   <dep type="pkg" rel="ge" version="1.3.3">PEAR</dep>
+   <dep type="pkg" rel="ge" version="1.3.1">Archive_Tar</dep>
+   <dep type="pkg" rel="ge" version="1.2">Console_Getopt</dep>
+   <dep type="pkg" rel="ge" version="1.4.0" optional="yes">XML_RPC</dep>
+   <dep type="pkg" rel="ge" version="0.5.0" optional="yes">PEAR_Frontend_Web</dep>
+   <dep type="pkg" rel="ge" version="0.4.0" optional="yes">PEAR_Frontend_Gtk</dep>
+   <dep type="ext" rel="has">xml</dep>
+   <dep type="ext" rel="has">pcre</dep>
+  </deps>
+  <filelist>
+   <dir name="OS">
+    <file role="php" name="Guess.php">
+     <replace from="@package_version@" to="version" type="package-info"/>
+    </file>
+   </dir>
+   <dir name="PEAR">
+    <dir name="ChannelFile">
+     <file name="Parser.php" role="php">
+      <replace from="@package_version@" to="version" type="package-info"/>
+     </file>
+    </dir>
+    <dir name="Command">
+     <file role="php" name="Auth.xml"/>
+     <file role="php" name="Auth.php">
+      <replace from="@package_version@" to="version" type="package-info"/>
+     </file>
+     <file role="php" name="Build.xml"/>
+     <file role="php" name="Build.php">
+      <replace from="@package_version@" to="version" type="package-info"/>
+     </file>
+     <file role="php" name="Channels.xml"/>
+     <file role="php" name="Channels.php">
+      <replace from="@package_version@" to="version" type="package-info"/>
+     </file>
+     <file role="php" name="Common.php">
+      <replace from="@package_version@" to="version" type="package-info"/>
+     </file>
+     <file role="php" name="Config.xml"/>
+     <file role="php" name="Config.php">
+      <replace from="@package_version@" to="version" type="package-info"/>
+     </file>
+     <file role="php" name="Install.xml"/>
+     <file role="php" name="Install.php">
+      <replace from="@package_version@" to="version" type="package-info"/>
+     </file>
+     <file role="php" name="Package.xml"/>
+     <file role="php" name="Package.php">
+      <replace from="@DATA-DIR@" to="data_dir" type="pear-config"/>
+      <replace from="@package_version@" to="version" type="package-info"/>
+     </file>
+     <file role="php" name="Pickle.xml"/>
+     <file role="php" name="Pickle.php">
+      <replace from="@package_version@" to="version" type="package-info"/>
+     </file>
+     <file role="php" name="Registry.xml"/>
+     <file role="php" name="Registry.php">
+      <replace from="@package_version@" to="version" type="package-info"/>
+     </file>
+     <file role="php" name="Remote.xml"/>
+     <file role="php" name="Remote.php">
+      <replace from="@package_version@" to="version" type="package-info"/>
+     </file>
+     <file role="php" name="Mirror.xml"/>
+     <file role="php" name="Mirror.php">
+      <replace from="@package_version@" to="version" type="package-info"/>
+     </file>
+     <file role="php" name="Test.xml"/>
+     <file role="php" name="Test.php">
+      <replace from="@package_version@" to="version" type="package-info"/>
+     </file>
+    </dir>
+    <dir name="Downloader">
+     <file role="php" name="Package.php">
+      <replace from="@PEAR-VER@" to="version" type="package-info"/>
+     </file>
+    </dir>
+    <dir name="Frontend">
+     <file role="php" name="CLI.php">
+      <replace from="@package_version@" to="version" type="package-info"/>
+     </file>
+    </dir>
+    <dir name="Installer">
+     <dir name="Role">
+      <file role="php" name="Common.php">
+       <replace from="@package_version@" to="version" type="package-info"/>
+      </file>
+      <file role="php" name="Data.xml"/>
+      <file role="php" name="Data.php">
+       <replace from="@package_version@" to="version" type="package-info"/>
+      </file>
+      <file role="php" name="Doc.xml"/>
+      <file role="php" name="Doc.php">
+       <replace from="@package_version@" to="version" type="package-info"/>
+      </file>
+      <file role="php" name="Ext.xml"/>
+      <file role="php" name="Ext.php">
+       <replace from="@package_version@" to="version" type="package-info"/>
+      </file>
+      <file role="php" name="Php.xml"/>
+      <file role="php" name="Php.php">
+       <replace from="@package_version@" to="version" type="package-info"/>
+      </file>
+      <file role="php" name="Script.xml"/>
+      <file role="php" name="Script.php">
+       <replace from="@package_version@" to="version" type="package-info"/>
+      </file>
+      <file role="php" name="Src.xml"/>
+      <file role="php" name="Src.php">
+       <replace from="@package_version@" to="version" type="package-info"/>
+      </file>
+      <file role="php" name="Test.xml"/>
+      <file role="php" name="Test.php">
+       <replace from="@package_version@" to="version" type="package-info"/>
+      </file>
+     </dir>
+     <file role="php" name="Role.php">
+      <replace from="@package_version@" to="version" type="package-info"/>
+     </file>
+    </dir>
+    <dir name="PackageFile">
+     <dir name="Generator">
+      <file role="php" name="v1.php">
+       <replace from="@PEAR-VER@" to="version" type="package-info"/>
+      </file>
+      <file role="php" name="v2.php">
+       <replace from="@PEAR-VER@" to="version" type="package-info"/>
+      </file>
+     </dir>
+     <dir name="Parser">
+      <file role="php" name="v1.php">
+       <replace from="@package_version@" to="version" type="package-info"/>
+      </file>
+      <file role="php" name="v2.php">
+       <replace from="@package_version@" to="version" type="package-info"/>
+      </file>
+     </dir>
+     <dir name="v2">
+      <file role="php" name="rw.php">
+       <replace from="@package_version@" to="version" type="package-info"/>
+      </file>
+      <file role="php" name="Validator.php">
+       <replace from="@package_version@" to="version" type="package-info"/>
+      </file>
+     </dir>
+     <file role="php" name="v1.php">
+      <replace from="@package_version@" to="version" type="package-info"/>
+     </file>
+     <file role="php" name="v2.php">
+      <replace from="@package_version@" to="version" type="package-info"/>
+     </file>
+    </dir>
+    <dir name="REST">
+     <file role="php" name="10.php">
+      <replace from="@package_version@" to="version" type="package-info"/>
+     </file>
+     <file role="php" name="11.php">
+      <replace from="@package_version@" to="version" type="package-info"/>
+     </file>
+    </dir>
+    <dir name="Task">
+     <dir name="Postinstallscript">
+      <file role="php" name="rw.php">
+       <replace from="@package_version@" to="version" type="package-info"/>
+      </file>
+     </dir>
+     <dir name="Replace">
+      <file role="php" name="rw.php">
+       <replace from="@package_version@" to="version" type="package-info"/>
+      </file>
+     </dir>
+     <dir name="Unixeol">
+      <file role="php" name="rw.php">
+       <replace from="@package_version@" to="version" type="package-info"/>
+      </file>
+     </dir>
+     <dir name="Windowseol">
+      <file role="php" name="rw.php">
+       <replace from="@package_version@" to="version" type="package-info"/>
+      </file>
+     </dir>
+     <file role="php" name="Common.php">
+      <replace from="@package_version@" to="version" type="package-info"/>
+     </file>
+     <file role="php" name="Postinstallscript.php">
+      <replace from="@package_version@" to="version" type="package-info"/>
+     </file>
+     <file role="php" name="Replace.php">
+      <replace from="@package_version@" to="version" type="package-info"/>
+     </file>
+     <file role="php" name="Unixeol.php">
+      <replace from="@package_version@" to="version" type="package-info"/>
+     </file>
+     <file role="php" name="Windowseol.php">
+      <replace from="@package_version@" to="version" type="package-info"/>
+     </file>
+    </dir>
+    <dir name="Validator">
+     <file role="php" name="PECL.php">
+      <replace from="@package_version@" to="version" type="package-info"/>
+     </file>
+    </dir>
+    <file role="php" name="Autoloader.php">
+     <replace from="@package_version@" to="version" type="package-info"/>
+    </file>
+    <file role="php" name="Builder.php">
+     <replace from="@PEAR-VER@" to="version" type="package-info"/>
+    </file>
+    <file role="php" name="ChannelFile.php">
+     <replace from="@package_version@" to="version" type="package-info"/>
+    </file>
+    <file role="php" name="Command.php">
+     <replace from="@package_version@" to="version" type="package-info"/>
+    </file>
+    <file role="php" name="Common.php">
+     <replace from="@package_version@" to="version" type="package-info"/>
+    </file>
+    <file role="php" name="Config.php">
+     <replace from="@package_version@" to="version" type="package-info"/>
+    </file>
+    <file role="php" name="Dependency.php"/>
+    <file role="php" name="DependencyDB.php">
+     <replace from="@package_version@" to="version" type="package-info"/>
+    </file>
+    <file role="php" name="Dependency2.php">
+     <replace from="@PEAR-VER@" to="version" type="package-info"/>
+    </file>
+    <file role="php" name="Downloader.php">
+     <replace from="@package_version@" to="version" type="package-info"/>
+    </file>
+    <file role="php" name="ErrorStack.php">
+     <replace from="@package_version@" to="version" type="package-info"/>
+    </file>
+    <file role="php" name="Exception.php">
+     <replace from="@package_version@" to="version" type="package-info"/>
+    </file>
+    <file role="php" name="Frontend.php">
+     <replace from="@package_version@" to="version" type="package-info"/>
+    </file>
+    <file role="php" name="Installer.php">
+     <replace from="@package_version@" to="version" type="package-info"/>
+    </file>
+    <file role="php" name="Packager.php">
+     <replace from="@package_version@" to="version" type="package-info"/>
+    </file>
+    <file role="php" name="PackageFile.php">
+     <replace from="@PEAR-VER@" to="version" type="package-info"/>
+    </file>
+    <file role="php" name="Registry.php">
+     <replace from="@package_version@" to="version" type="package-info"/>
+    </file>
+    <file role="php" name="Remote.php">
+     <replace from="@package_version@" to="version" type="package-info"/>
+    </file>
+    <file role="php" name="REST.php">
+     <replace from="@package_version@" to="version" type="package-info"/>
+    </file>
+    <file role="php" name="RunTest.php">
+     <replace from="@package_version@" to="version" type="package-info"/>
+    </file>
+    <file role="php" name="Validate.php">
+     <replace from="@package_version@" to="version" type="package-info"/>
+    </file>
+    <file role="php" name="XMLParser.php">
+     <replace from="@package_version@" to="version" type="package-info"/>
+    </file>
+   </dir>
+   <dir name="scripts" baseinstalldir="/">
+    <file role="script" install-as="pear" name="pear.sh" platform="!windows">
+     <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" install-as="peardev" name="peardev.sh" platform="!windows">
+     <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" install-as="pecl" name="pecl.sh" platform="!windows">
+     <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="peardev.bat" name="peardev.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="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="script" platform="windows" install-as="pecl.bat" name="pecl.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>
+    <file role="php" install-as="peclcmd.php" name="peclcmd.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>
+   <file role="data" name="package.dtd"/>
+   <file role="data" name="template.spec"/>
+   <file role="php" name="PEAR.php">
+    <replace from="@package_version@" to="version" type="package-info"/>
+   </file>
+   <file role="php" name="System.php">
+    <replace from="@package_version@" to="version" type="package-info"/>
+   </file>
+  </filelist>
+ </release>
+ <changelog>
   <release>
-    <version>1.3.3</version>
-    <date>2004-10-28</date>
-    <state>stable</state>
-    <notes>
-Installer:
- * fix Bug #1186 raise a notice error on PEAR::Common $_packageName
- * fix Bug #1249 display the right state when using --force option
- * fix Bug #2189 upgrade-all stops if dependancy fails
- * fix Bug #1637 The use of interface causes warnings when packaging with PEAR
- * fix Bug #1420 Parser bug for T_DOUBLE_COLON
- * fix Request #2220 pear5 build fails on dual php4/php5 system
- * fix Bug #1163  pear makerpm fails with packages that supply role="doc"
+   <version>1.4.0</version>
+   <date>2005-09-18</date>
+   <license>PHP License</license>
+   <state>stable</state>
+   <notes>
+  This is a major milestone release for PEAR.  In addition to several killer features,
+  every single element of PEAR has a regression test, and so stability is much higher
+  than any previous PEAR release.
 
-Other:
- * add PEAR_Exception class for PHP5 users
- * fix critical problem in package.xml for linux in 1.3.2
- * fix staticPopCallback() in PEAR_ErrorStack
- * fix warning in PEAR_Registry for windows 98 users
-    </notes>
-   </release>
+  New features in a nutshell:
+  * full support for channels
+  * pre-download dependency validation
+  * new package.xml 2.0 format allows tremendous flexibility while maintaining BC
+  * support for optional dependency groups and limited support for sub-packaging
+  * robust dependency support
+  * full dependency validation on uninstall
+  * remote install for hosts with only ftp access - no more problems with
+    restricted host installation
+  * full support for mirroring
+  * support for bundling several packages into a single tarball
+  * support for static dependencies on a url-based package
+  * support for custom file roles and installation tasks
+
+  NOTE: users of PEAR_Frontend_Web/PEAR_Frontend_Gtk must upgrade their installations
+  to the latest version, or PEAR will not upgrade properly
+   </notes>
+  </release>
   <release>
-    <version>1.3.3.1</version>
-    <date>2004-11-08</date>
-    <state>stable</state>
-    <notes>
-     add RunTest.php to package.xml, make run-tests display failed tests, and use ui
-    </notes>
-   </release>
+   <version>1.4.1</version>
+   <date>2005-09-25</date>
+   <license>PHP License</license>
+   <state>stable</state>
+   <notes>
+  Major bugfix release.  This is a recommended download for ALL PEAR users
+  
+  UPGRADING FROM 1.4.0 WILL CAUSE A SERIES OF NOTICES.  IGNORE THEM.
+  THIS IS CAUSED BY A BUG IN 1.4.0 THAT IS FIXED IN 1.4.1
+
+  * fix prompt processing in post-install scripts
+  * make dual package.xml equivalency stricter when using package.xml/package2.xml
+  * fix critical error in validating bogus php dependencies of package.xml 1.0
+    This error has existed for every PEAR version, and allows dependencies like:
+    &lt;dep type=&quot;php&quot; rel=&quot;has&quot;&gt;4.3.0&lt;/dep&gt; to
+    slip through unnoticed
+  * re-enable php-const replacements
+  * PEAR_PackageFile_v2::getConfigureOptions() was missing!!
+  * fix cvsdiff command
+  * fix xml encoding issues finally
+  * clean up package.xml 1.0 dir/file parsing
+  * fix invalid PEAR_Config generation
+  * change the user agent from PHP/phpversion to PEAR/pearversion/PHP/phpversion
+  * don't use a bogus uri for licenses on running convert command
+  * add &quot;pickle&quot; command for PECL packaging
+  * add validation warning if the release date in package.xml is not today when packaging
+  * implement progress bar for list-all/remote-list
+  * fix Bug #5323: pear search returns odd version numbers
+  * fix Bug #5428: pear cvstag package2.xml does not include the package.xml
+  * fix Bug #5449: pear makerpm completely broken for package.xml 2.0
+  * fix Bug #5462: raiseError method does not return by ref anymore
+  * fix Bug #5465: pear install --offline fails to display error
+  * fix Bug #5477: Bug in Downloader.php and Dependency2.php
+  * fix Bug #5481: &quot;pear install PECLextension&quot; should display warning to use pecl command
+  * fix Bug #5482: installation of PECL packages should say add extensions to php.ini
+  * fix Bug #5483: pecl uninstall crack fatal error
+  * fix Bug #5487: PECL: compiled files are not uninstalled via the uninstall command
+  * fix Bug #5488: pecl uninstall package fails if package has a package.xml 1.0
+  * fix Bug #5501: the commands list mentions XML-RPC
+  * fix Bug #5509: addDependecyGroup does not validate group name
+  * fix Bug #5513: PEAR 1.4 does not install non-pear.php.net packages
+   </notes>
+  </release>
   <release>
-    <version>1.3.4</version>
-    <date>2005-01-01</date>
-    <state>stable</state>
-    <notes>
- * fix a serious problem caused by a bug in all versions of PHP that caused multiple registration
-   of the shutdown function of PEAR.php
- * fix Bug #2861: package.dtd does not define NUMBER
- * fix Bug #2946: ini_set warning errors
- * fix Bug #3026: Dependency type &quot;ne&quot; is needed, &quot;not&quot; is not handled
-   properly
- * fix Bug #3061: potential warnings in PEAR_Exception
- * implement Request #2848: PEAR_ErrorStack logger extends, PEAR_ERRORSTACK_DIE
- * implement Request #2914: Dynamic Include Path for run-tests command
- * make pear help listing more useful (put how-to-use info at the bottom of the listing)
-    </notes>
-   </release>
-  </changelog>
+   <version>1.4.2</version>
+   <date>2005-10-08</date>
+   <license>PHP License</license>
+   <state>stable</state>
+   <notes>
+  Minor bugfix release
+
+  * fix issues with API for adding tasks to package2.xml
+  * fix Bug #5520: pecl pickle fails on pecl pickle fails on extension/package deps
+  * fix Bug #5523: pecl pickle misses to put configureoptions into package.xml v1
+  * fix Bug #5527: No need for cpp
+  * fix Bug #5529: configure options in package.xml 2.0 will be ignored
+  * fix Bug #5530: PEAR_PackageFile_v2->getConfigureOptions() API incompatible with v1
+  * fix Bug #5531: adding of installconditions/binarypackage/configure options
+                   to extsrc may fail
+  * fix Bug #5550: PHP notices/warnings/errors are 1 file off in trace
+  * fix Bug #5580: pear makerpm XML_sql2xml-0.3.2.tgz error
+  * fix Bug #5619: pear makerpm produces invalid .spec dependancy code
+  * fix Bug #5629: pear install http_download dies with bad error message
+   </notes>
+  </release>
+ </changelog>
 </package>
index 0181ad8762a76a3778ec61fe08480f708de61e96..c7a285d35a3b3b6158e2b4fe863bf22a6171f20d 100644 (file)
@@ -1,14 +1,14 @@
 <!--
-     $Id: package.dtd,v 1.27.4.12 2005-03-28 16:56:58 cellog Exp $
+     $Id: package.dtd,v 1.27.4.12.2.1 2005-11-02 16:57:19 cellog Exp $
 
      This is the PEAR package description, version 1.0.
      It should be used with the informal public identifier:
 
          "-//PHP Group//DTD PEAR Package 1.0//EN//XML"
 
-     Copyright (c) 1997-2004 The PHP Group
+     Copyright (c) 1997-2005 The PHP Group             
 
-     This source file is subject to version 3.0 of the PHP license, 
+     This source file is subject to version 3.00 of the PHP license,
      that is bundled with this package in the file LICENSE, and is
      available at through the world-wide-web at
      http://www.php.net/license/3_0.txt. 
      license@php.net so we can mail you a copy immediately.
 
      Authors:
-         Stig S. Bakken <ssb@php.net>
+         Stig S. Bakken <ssb@fast.no>
+         Gregory Beaver <cellog@php.net>
 
   -->
 <!ENTITY % NUMBER "CDATA">
-<!ELEMENT package (name|summary|description|license|maintainers|release|changelog)+>
+<!ELEMENT package (name,summary,description,license?,maintainers,release,changelog?)>
 <!ATTLIST package type    (source|binary|empty) "empty"
-                  version CDATA                 #REQUIRED>
+                  version CDATA                 #REQUIRED
+                  packagerversion CDATA         #IMPLIED>
 
 <!ELEMENT name (#PCDATA)>
 
 <!ELEMENT summary (#PCDATA)>
 
-<!ELEMENT description (#PCDATA)>
-
 <!ELEMENT license (#PCDATA)>
 
+<!ELEMENT description (#PCDATA)>
+
 <!ELEMENT maintainers (maintainer)+>
 
 <!ELEMENT maintainer (user|role|name|email)+>
 
 <!ELEMENT changelog (release)+>
 
-<!ELEMENT release (version|license|state|date|notes|filelist|deps|provides|script|configureoptions)+>
+<!ELEMENT release (version,date,license,state,notes,warnings?,provides*,deps?,configureoptions?,filelist)>
 
 <!ELEMENT version (#PCDATA)>
 
-<!ELEMENT state (#PCDATA)>
-
 <!ELEMENT date (#PCDATA)>
 
+<!ELEMENT state (#PCDATA)>
+
 <!ELEMENT notes (#PCDATA)>
 
+<!ELEMENT warnings (#PCDATA)>
+
+<!ELEMENT deps (dep*)>
+
+<!ELEMENT dep (#PCDATA)>
+<!ATTLIST dep type    (pkg|ext|php) #REQUIRED
+                              rel     (has|eq|lt|le|gt|ge)                          #IMPLIED
+                              version CDATA                                     #IMPLIED
+                              optional (yes|no)     'no'>
+
+<!ELEMENT configureoptions (configureoption)+>
+
+<!ELEMENT configureoption EMPTY>
+<!ATTLIST configureoption name CDATA #REQUIRED
+                                           default CDATA #IMPLIED
+                                           prompt CDATA #REQUIRED>
+
+<!ELEMENT provides EMPTY>
+<!ATTLIST provides type (ext|prog|class|function|feature|api) #REQUIRED
+                                name CDATA #REQUIRED
+                                extends CDATA #IMPLIED>
 <!ELEMENT filelist (dir|file)+>
 
 <!ELEMENT dir (dir|file)+>
 <!ATTLIST dir name           CDATA #REQUIRED
+              role           (php|ext|src|test|doc|data|script) 'php'
               baseinstalldir CDATA #IMPLIED>
 
 <!ELEMENT file (replace*)>
 <!ATTLIST file role           (php|ext|src|test|doc|data|script) 'php'
                debug          (na|on|off)        'na'
-               zts            (na|on|off)        'na'
-               phpapi         %NUMBER;           #IMPLIED
-               zendapi        %NUMBER;           #IMPLIED
                format         CDATA              #IMPLIED
                baseinstalldir CDATA              #IMPLIED
                platform       CDATA              #IMPLIED
                install-as     CDATA              #IMPLIED>
 
 <!ELEMENT replace EMPTY>
-<!ATTLIST replace from        CDATA              #REQUIRED
-                  to          CDATA              #REQUIRED
-                  type        CDATA              #REQUIRED>
-
-<!ELEMENT deps (dep)+>
+<!ATTLIST replace type (php-const|pear-config|package-info) #REQUIRED
+                              from CDATA #REQUIRED
+                              to CDATA #REQUIRED>
 
-<!ELEMENT dep (#PCDATA)>
-<!ATTLIST dep
-       optional    (yes|no)    'no'
-       type        (pkg|ext|php|prog|ldlib|rtlib|os|websrv|sapi|zend) #REQUIRED
-       rel         (has|eq|lt|le|gt|ge) 'has'
-       version     CDATA                #IMPLIED>
-
-<!ELEMENT provides (#PCDATA)>
-<!ATTLIST provides
-       type    (ext|prog|class|function|feature|api)  #REQUIRED
-       name    CDATA                                  #REQUIRED
-       extends CDATA                                  #IMPLIED>
-
-<!ELEMENT script (#PCDATA)>
-<!ATTLIST script
-        phase   (pre-install  |post-install  |
-                 pre-uninstall|post-uninstall|
-                 pre-build    |post-build    |
-                 pre-setup    |post-setup    )         #REQUIRED>
-
-<!ELEMENT configureoptions (configureoption*)>
 
-<!ELEMENT configureoption EMPTY>
-<!ATTLIST configureoption
-        name     CDATA      #REQUIRED
-        default  CDATA      #IMPLIED
-        prompt   CDATA      #REQUIRED>
diff --git a/pear/package2.xml b/pear/package2.xml
new file mode 100644 (file)
index 0000000..ff3e791
--- /dev/null
@@ -0,0 +1,649 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<package version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
+http://pear.php.net/dtd/tasks-1.0.xsd
+http://pear.php.net/dtd/package-2.0
+http://pear.php.net/dtd/package-2.0.xsd">
+ <name>PEAR</name>
+ <channel>pear.php.net</channel>
+ <summary>PEAR Base System</summary>
+ <description>The PEAR package contains:
+ * the PEAR installer, for creating, distributing
+   and installing packages
+ * the beta-quality PEAR_Exception PHP5 error handling mechanism
+ * the beta-quality PEAR_ErrorStack advanced error handling mechanism
+ * the PEAR_Error error handling mechanism
+ * the OS_Guess class for retrieving info about the OS
+   where PHP is running on
+ * the System class for quick handling of common operations
+   with files and directories
+ * the PEAR base class
+
+  New features in a nutshell:
+  * full support for channels
+  * pre-download dependency validation
+  * new package.xml 2.0 format allows tremendous flexibility while maintaining BC
+  * support for optional dependency groups and limited support for sub-packaging
+  * robust dependency support
+  * full dependency validation on uninstall
+  * remote install for hosts with only ftp access - no more problems with
+    restricted host installation
+  * full support for mirroring
+  * support for bundling several packages into a single tarball
+  * support for static dependencies on a url-based package
+  * support for custom file roles and installation tasks
+
+  NOTE: users of PEAR_Frontend_Web/PEAR_Frontend_Gtk must upgrade their installations
+  to the latest version, or PEAR will not upgrade properly
+ </description>
+ <lead>
+  <name>Greg Beaver</name>
+  <user>cellog</user>
+  <email>cellog@php.net</email>
+  <active>yes</active>
+ </lead>
+ <lead>
+  <name>Stig Bakken</name>
+  <user>ssb</user>
+  <email>stig@php.net</email>
+  <active>yes</active>
+ </lead>
+ <lead>
+  <name>Tomas V.V.Cox</name>
+  <user>cox</user>
+  <email>cox@idecnet.com</email>
+  <active>yes</active>
+ </lead>
+ <lead>
+  <name>Pierre-Alain Joye</name>
+  <user>pajoye</user>
+  <email>pajoye@pearfr.org</email>
+  <active>yes</active>
+ </lead>
+ <helper>
+  <name>Martin Jansen</name>
+  <user>mj</user>
+  <email>mj@php.net</email>
+  <active>no</active>
+ </helper>
+ <date>2005-11-03</date>
+ <version>
+  <release>1.4.3</release>
+  <api>1.4.0</api>
+ </version>
+ <stability>
+  <release>stable</release>
+  <api>stable</api>
+ </stability>
+ <license uri="http://www.php.net/license">PHP License</license>
+ <notes>
+  MINOR SECURITY FIX release
+
+  A security vulnerability has been discovered in all
+  PEAR versions (1.0 to 1.4.2).  This vulnerability has been fixed, 
+  and this is a recommended upgrade for all users.
+
+  Run "pear channel-update" after upgrading for exponentially
+  faster list-all/remote-list!!
+
+  * fix installation of files named like &quot;.test&quot;
+  * fix base class for writeable unixeol/windowseol classes
+  * fix running of post-install scripts with empty or no paramgroup
+    in CLI frontend
+  * fix validation of &lt;postinstallscript&gt;
+  * fix writeable PEAR_Task_Postinstallscript_rw class
+  * fix error in REST-based search command if searching through description
+    as well
+  * silence warning on list-upgrades/upgrade-all if no releases exist at a channel
+  * add checks for updated channel.xml in all remote commands
+  * fix pecl script if safe_mode is enabled by default
+  * implement SERIOUS improvement in list-all/remote-list speed.  From 6 minutes
+    down to about 16-30 seconds
+  * implement --loose option to avoid recommended version validation
+  * implement Request #5527: alternative approach to determining glibc version
+  * fix Bug #5717: analyzeSourceCode() fails to process certain
+    quote situations properly
+  * fix Bug #5736: if registry can't lock registry or open filemap,
+    checkFileMap(), no error
+  * fix Bug #5676: pear config-create broken
+  * fix Bug #5683: Deadlock with (almost) circular dependency
+  * fix Bug #5725: PHP5 warnings need improvement
+  * fix Bug #5789: small typo
+  * fix Bug #5810: internet should not be contacted on install if dependencies are installed
+ </notes>
+ <contents>
+  <dir name="/">
+   <dir name="OS">
+    <file name="Guess.php" role="php">
+     <tasks:replace from="@package_version@" to="version" type="package-info" />
+    </file>
+   </dir> <!-- /OS -->
+   <dir name="PEAR">
+    <dir name="ChannelFile">
+     <file name="Parser.php" role="php">
+      <tasks:replace from="@package_version@" to="version" type="package-info" />
+     </file>
+    </dir> <!-- /PEAR/ChannelFile -->
+    <dir name="Command">
+     <file name="Auth.xml" role="php"/>
+     <file name="Auth.php" role="php">
+      <tasks:replace from="@package_version@" to="version" type="package-info" />
+     </file>
+     <file name="Build.xml" role="php"/>
+     <file name="Build.php" role="php">
+      <tasks:replace from="@package_version@" to="version" type="package-info" />
+     </file>
+     <file name="Channels.xml" role="php"/>
+     <file name="Channels.php" role="php">
+      <tasks:replace from="@package_version@" to="version" type="package-info" />
+     </file>
+     <file name="Common.php" role="php">
+      <tasks:replace from="@package_version@" to="version" type="package-info" />
+     </file>
+     <file name="Config.xml" role="php"/>
+     <file name="Config.php" role="php">
+      <tasks:replace from="@package_version@" to="version" type="package-info" />
+     </file>
+     <file name="Install.xml" role="php"/>
+     <file name="Install.php" role="php">
+      <tasks:replace from="@package_version@" to="version" type="package-info" />
+     </file>
+     <file name="Mirror.xml" role="php"/>
+     <file name="Mirror.php" role="php">
+      <tasks:replace from="@package_version@" to="version" type="package-info" />
+     </file>
+     <file name="Package.xml" role="php"/>
+     <file name="Package.php" role="php">
+      <tasks:replace from="@DATA-DIR@" to="data_dir" type="pear-config" />
+      <tasks:replace from="@package_version@" to="version" type="package-info" />
+     </file>
+     <file name="Pickle.xml" role="php"/>
+     <file name="Pickle.php" role="php">
+      <tasks:replace from="@package_version@" to="version" type="package-info" />
+     </file>
+     <file name="Registry.xml" role="php"/>
+     <file name="Registry.php" role="php">
+      <tasks:replace from="@package_version@" to="version" type="package-info" />
+     </file>
+     <file name="Remote.xml" role="php"/>
+     <file name="Remote.php" role="php">
+      <tasks:replace from="@package_version@" to="version" type="package-info" />
+     </file>
+     <file name="Test.xml" role="php"/>
+     <file name="Test.php" role="php">
+      <tasks:replace from="@package_version@" to="version" type="package-info" />
+     </file>
+    </dir> <!-- /PEAR/Command -->
+    <dir name="Downloader">
+     <file name="Package.php" role="php">
+      <tasks:replace from="@PEAR-VER@" to="version" type="package-info" />
+     </file>
+    </dir> <!-- /PEAR/Downloader -->
+    <dir name="Frontend">
+     <file name="CLI.php" role="php">
+      <tasks:replace from="@package_version@" to="version" type="package-info" />
+     </file>
+    </dir> <!-- /PEAR/Frontend -->
+    <dir name="Installer">
+     <dir name="Role">
+      <file name="Common.php" role="php">
+       <tasks:replace from="@package_version@" to="version" type="package-info" />
+      </file>
+      <file name="Data.xml" role="php"/>
+      <file name="Data.php" role="php">
+       <tasks:replace from="@package_version@" to="version" type="package-info" />
+      </file>
+      <file name="Doc.xml" role="php"/>
+      <file name="Doc.php" role="php">
+       <tasks:replace from="@package_version@" to="version" type="package-info" />
+      </file>
+      <file name="Ext.xml" role="php"/>
+      <file name="Ext.php" role="php">
+       <tasks:replace from="@package_version@" to="version" type="package-info" />
+      </file>
+      <file name="Php.xml" role="php"/>
+      <file name="Php.php" role="php">
+       <tasks:replace from="@package_version@" to="version" type="package-info" />
+      </file>
+      <file name="Script.xml" role="php"/>
+      <file name="Script.php" role="php">
+       <tasks:replace from="@package_version@" to="version" type="package-info" />
+      </file>
+      <file name="Src.xml" role="php"/>
+      <file name="Src.php" role="php">
+       <tasks:replace from="@package_version@" to="version" type="package-info" />
+      </file>
+      <file name="Test.xml" role="php"/>
+      <file name="Test.php" role="php">
+       <tasks:replace from="@package_version@" to="version" type="package-info" />
+      </file>
+     </dir> <!-- /PEAR/Installer/Role -->
+     <file name="Role.php" role="php">
+      <tasks:replace from="@package_version@" to="version" type="package-info" />
+     </file>
+    </dir> <!-- /PEAR/Installer -->
+    <dir name="PackageFile">
+     <dir name="Generator">
+      <file name="v1.php" role="php">
+       <tasks:replace from="@PEAR-VER@" to="version" type="package-info" />
+      </file>
+      <file name="v2.php" role="php">
+       <tasks:replace from="@PEAR-VER@" to="version" type="package-info" />
+      </file>
+     </dir> <!-- /PEAR/PackageFile/Generator -->
+     <dir name="Parser">
+      <file name="v1.php" role="php">
+       <tasks:replace from="@package_version@" to="version" type="package-info" />
+      </file>
+      <file name="v2.php" role="php">
+       <tasks:replace from="@package_version@" to="version" type="package-info" />
+      </file>
+     </dir> <!-- /PEAR/PackageFile/Parser -->
+     <dir name="v2">
+      <file role="php" name="rw.php">
+       <tasks:replace from="@package_version@" to="version" type="package-info" />
+      </file>
+      <file role="php" name="Validator.php">
+       <tasks:replace from="@package_version@" to="version" type="package-info" />
+      </file>
+     </dir> <!-- /PEAR/PackageFile/v2 -->
+     <file name="v1.php" role="php">
+      <tasks:replace from="@package_version@" to="version" type="package-info" />
+     </file>
+     <file name="v2.php" role="php">
+      <tasks:replace from="@package_version@" to="version" type="package-info" />
+     </file>
+    </dir> <!-- /PEAR/PackageFile -->
+    <dir name="REST">
+     <file name="10.php" role="php">
+      <tasks:replace from="@package_version@" to="version" type="package-info" />
+     </file>
+     <file name="11.php" role="php">
+      <tasks:replace from="@package_version@" to="version" type="package-info" />
+     </file>
+    </dir> <!-- /PEAR/REST -->
+    <dir name="Task">
+     <dir name="Postinstallscript">
+      <file name="rw.php" role="php">
+       <tasks:replace from="@package_version@" to="version" type="package-info" />
+      </file>
+     </dir> <!-- /PEAR/Task/Postinstallscript -->
+     <dir name="Replace">
+      <file name="rw.php" role="php">
+       <tasks:replace from="@package_version@" to="version" type="package-info" />
+      </file>
+     </dir> <!-- /PEAR/Task/Replace -->
+     <dir name="Unixeol">
+      <file name="rw.php" role="php">
+       <tasks:replace from="@package_version@" to="version" type="package-info" />
+      </file>
+     </dir> <!-- /PEAR/Task/Unixeol -->
+     <dir name="Windowseol">
+      <file name="rw.php" role="php">
+       <tasks:replace from="@package_version@" to="version" type="package-info" />
+      </file>
+     </dir> <!-- /PEAR/Task/Windowseol -->
+     <file name="Common.php" role="php">
+      <tasks:replace from="@package_version@" to="version" type="package-info" />
+     </file>
+     <file name="Postinstallscript.php" role="php">
+      <tasks:replace from="@package_version@" to="version" type="package-info" />
+     </file>
+     <file name="Replace.php" role="php">
+      <tasks:replace from="@package_version@" to="version" type="package-info" />
+     </file>
+     <file name="Unixeol.php" role="php">
+      <tasks:replace from="@package_version@" to="version" type="package-info" />
+     </file>
+     <file name="Windowseol.php" role="php">
+      <tasks:replace from="@package_version@" to="version" type="package-info" />
+     </file>
+    </dir> <!-- /PEAR/Task -->
+    <dir name="Validator">
+     <file name="PECL.php" role="php">
+      <tasks:replace from="@package_version@" to="version" type="package-info" />
+     </file>
+    </dir> <!-- /PEAR/Validator -->
+    <file name="Autoloader.php" role="php">
+     <tasks:replace from="@package_version@" to="version" type="package-info" />
+    </file>
+    <file name="Builder.php" role="php">
+     <tasks:replace from="@PEAR-VER@" to="version" type="package-info"/>
+    </file>
+    <file name="ChannelFile.php" role="php">
+     <tasks:replace from="@package_version@" to="version" type="package-info" />
+    </file>
+    <file name="Command.php" role="php">
+     <tasks:replace from="@package_version@" to="version" type="package-info" />
+    </file>
+    <file name="Common.php" role="php">
+     <tasks:replace from="@package_version@" to="version" type="package-info" />
+    </file>
+    <file name="Config.php" role="php">
+     <tasks:replace from="@package_version@" to="version" type="package-info" />
+    </file>
+    <file name="Dependency.php" role="php" />
+    <file name="DependencyDB.php" role="php">
+     <tasks:replace from="@package_version@" to="version" type="package-info" />
+    </file>
+    <file name="Dependency2.php" role="php">
+     <tasks:replace from="@PEAR-VER@" to="version" type="package-info"/>
+    </file>
+    <file name="Downloader.php" role="php">
+     <tasks:replace from="@package_version@" to="version" type="package-info" />
+    </file>
+    <file name="ErrorStack.php" role="php">
+     <tasks:replace from="@package_version@" to="version" type="package-info" />
+    </file>
+    <file name="Exception.php" role="php">
+     <tasks:replace from="@package_version@" to="version" type="package-info" />
+    </file>
+    <file name="Frontend.php" role="php">
+     <tasks:replace from="@package_version@" to="version" type="package-info" />
+    </file>
+    <file name="Installer.php" role="php">
+     <tasks:replace from="@package_version@" to="version" type="package-info" />
+    </file>
+    <file name="PackageFile.php" role="php">
+     <tasks:replace from="@PEAR-VER@" to="version" type="package-info" />
+    </file>
+    <file name="Packager.php" role="php">
+     <tasks:replace from="@package_version@" to="version" type="package-info" />
+    </file>
+    <file name="Registry.php" role="php">
+     <tasks:replace from="@package_version@" to="version" type="package-info" />
+    </file>
+    <file name="Remote.php" role="php">
+     <tasks:replace from="@package_version@" to="version" type="package-info" />
+    </file>
+    <file name="REST.php" role="php">
+     <tasks:replace from="@package_version@" to="version" type="package-info" />
+    </file>
+    <file name="RunTest.php" role="php">
+     <tasks:replace from="@package_version@" to="version" type="package-info" />
+    </file>
+    <file name="Validate.php" role="php">
+     <tasks:replace from="@package_version@" to="version" type="package-info" />
+    </file>
+    <file name="XMLParser.php" role="php">
+     <tasks:replace from="@package_version@" to="version" type="package-info" />
+    </file>
+   </dir> <!-- /PEAR -->
+   <dir name="scripts" baseinstalldir="/">
+    <file name="pear.bat" role="script">
+     <tasks:replace from="@bin_dir@" to="bin_dir" type="pear-config" />
+     <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
+     <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
+     <tasks:windowseol/>
+    </file>
+    <file name="peardev.bat" role="script">
+     <tasks:replace from="@bin_dir@" to="bin_dir" type="pear-config" />
+     <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
+     <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
+     <tasks:windowseol/>
+    </file>
+    <file name="pecl.bat" role="script">
+     <tasks:replace from="@bin_dir@" to="bin_dir" type="pear-config" />
+     <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
+     <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
+     <tasks:windowseol/>
+    </file>
+    <file name="pear.sh" role="script">
+     <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
+     <tasks:replace from="@php_dir@" to="php_dir" type="pear-config" />
+     <tasks:replace from="@pear_version@" to="version" type="package-info" />
+     <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
+     <tasks:unixeol/>
+    </file>
+    <file name="peardev.sh" role="script">
+     <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
+     <tasks:replace from="@php_dir@" to="php_dir" type="pear-config" />
+     <tasks:replace from="@pear_version@" to="version" type="package-info" />
+     <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
+     <tasks:unixeol/>
+    </file>
+    <file name="pecl.sh" role="script">
+     <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
+     <tasks:replace from="@php_dir@" to="php_dir" type="pear-config" />
+     <tasks:replace from="@pear_version@" to="version" type="package-info" />
+     <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
+     <tasks:unixeol/>
+    </file>
+    <file name="pearcmd.php" role="php">
+     <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
+     <tasks:replace from="@php_dir@" to="php_dir" type="pear-config" />
+     <tasks:replace from="@pear_version@" to="version" type="package-info" />
+     <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
+    </file>
+    <file name="peclcmd.php" role="php">
+     <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
+     <tasks:replace from="@php_dir@" to="php_dir" type="pear-config" />
+     <tasks:replace from="@pear_version@" to="version" type="package-info" />
+     <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
+    </file>
+   </dir> <!-- /scripts -->
+   <file name="package.dtd" role="data" />
+   <file name="PEAR.php" role="php">
+    <tasks:replace from="@package_version@" to="version" type="package-info" />
+   </file>
+   <file name="System.php" role="php">
+    <tasks:replace from="@package_version@" to="version" type="package-info" />
+   </file>
+   <file name="template.spec" role="data" />
+  </dir> <!-- / -->
+ </contents>
+ <dependencies>
+  <required>
+   <php>
+    <min>4.2</min>
+   </php>
+   <pearinstaller>
+    <min>1.4.0a12</min>
+   </pearinstaller>
+   <package>
+    <name>Archive_Tar</name>
+    <channel>pear.php.net</channel>
+    <min>1.1</min>
+    <recommended>1.3.1</recommended>
+    <exclude>1.3.0</exclude>
+   </package>
+   <package>
+    <name>Console_Getopt</name>
+    <channel>pear.php.net</channel>
+    <min>1.2</min>
+    <recommended>1.2</recommended>
+   </package>
+   <package>
+    <name>PEAR_Frontend_Web</name>
+    <channel>pear.php.net</channel>
+    <max>0.5.0</max>
+    <exclude>0.5.0</exclude>
+    <conflicts/>
+   </package>
+   <package>
+    <name>PEAR_Frontend_Gtk</name>
+    <channel>pear.php.net</channel>
+    <max>0.4.0</max>
+    <exclude>0.4.0</exclude>
+    <conflicts/>
+   </package>
+   <extension>
+    <name>xml</name>
+   </extension>
+   <extension>
+    <name>pcre</name>
+   </extension>
+  </required>
+  <optional>
+   <package>
+    <name>XML_RPC</name>
+    <channel>pear.php.net</channel>
+    <min>1.4.0</min>
+   </package>
+  </optional>
+<!--  <group name="remoteinstall" hint="adds the ability to install packages to a remote ftp server">
+   <subpackage>
+    <name>PEAR_RemoteInstaller</name>
+    <channel>pear.php.net</channel>
+    <min>0.1.0</min>
+    <recommended>0.1.0</recommended>
+   </subpackage>
+  </group> -->
+  <group name="webinstaller" hint="PEAR's web-based installer">
+   <package>
+    <name>PEAR_Frontend_Web</name>
+    <channel>pear.php.net</channel>
+    <min>0.5.0</min>
+   </package>
+  </group>
+  <group name="gtkinstaller" hint="PEAR's PHP-GTK-based installer">
+   <package>
+    <name>PEAR_Frontend_Gtk</name>
+    <channel>pear.php.net</channel>
+    <min>0.4.0</min>
+   </package>
+  </group>
+ </dependencies>
+ <phprelease>
+  <installconditions>
+   <os>
+    <name>windows</name>
+   </os>
+  </installconditions>
+  <filelist>
+   <install as="pear.bat" name="scripts/pear.bat" />
+   <install as="peardev.bat" name="scripts/peardev.bat" />
+   <install as="pecl.bat" name="scripts/pecl.bat" />
+   <install as="pearcmd.php" name="scripts/pearcmd.php" />
+   <install as="peclcmd.php" name="scripts/peclcmd.php" />
+   <ignore name="scripts/peardev.sh" />
+   <ignore name="scripts/pear.sh" />
+   <ignore name="scripts/pecl.sh" />
+  </filelist>
+ </phprelease>
+ <phprelease>
+  <filelist>
+   <install as="pear" name="scripts/pear.sh" />
+   <install as="peardev" name="scripts/peardev.sh" />
+   <install as="pecl" name="scripts/pecl.sh" />
+   <install as="pearcmd.php" name="scripts/pearcmd.php" />
+   <install as="peclcmd.php" name="scripts/peclcmd.php" />
+   <ignore name="scripts/pear.bat" />
+   <ignore name="scripts/peardev.bat" />
+   <ignore name="scripts/pecl.bat" />
+  </filelist>
+ </phprelease>
+ <changelog>
+  <release>
+   <version>
+    <release>1.4.0</release>
+    <api>1.4.0</api>
+   </version>
+   <stability>
+    <release>stable</release>
+    <api>stable</api>
+   </stability>
+   <date>2005-09-18</date>
+   <license uri="http://www.php.net/license/3_0.txt">PHP License</license>
+   <notes>
+  This is a major milestone release for PEAR.  In addition to several killer features,
+  every single element of PEAR has a regression test, and so stability is much higher
+  than any previous PEAR release.
+
+  New features in a nutshell:
+  * full support for channels
+  * pre-download dependency validation
+  * new package.xml 2.0 format allows tremendous flexibility while maintaining BC
+  * support for optional dependency groups and limited support for sub-packaging
+  * robust dependency support
+  * full dependency validation on uninstall
+  * remote install for hosts with only ftp access - no more problems with
+    restricted host installation [through PEAR_RemoteInstaller package]
+  * full support for mirroring
+  * support for bundling several packages into a single tarball
+  * support for static dependencies on a uri-based package
+  * support for custom file roles and installation tasks
+
+  NOTE: users of PEAR_Frontend_Web/PEAR_Frontend_Gtk must upgrade their installations
+  to the latest version, or PEAR will not upgrade properly
+   </notes>
+  </release>
+  <release>
+   <version>
+    <release>1.4.1</release>
+    <api>1.4.0</api>
+   </version>
+   <stability>
+    <release>stable</release>
+    <api>stable</api>
+   </stability>
+   <date>2005-09-25</date>
+   <license uri="http://www.php.net/license/3_0.txt">PHP License</license>
+   <notes>
+  Major bugfix release.  This is a recommended download for ALL PEAR users
+  
+  UPGRADING FROM 1.4.0 WILL CAUSE A SERIES OF NOTICES.  IGNORE THEM.
+  THIS IS CAUSED BY A BUG IN 1.4.0 THAT IS FIXED IN 1.4.1
+
+  * fix prompt processing in post-install scripts
+  * make dual package.xml equivalency stricter when using package.xml/package2.xml
+  * fix critical error in validating bogus php dependencies of package.xml 1.0
+    This error has existed for every PEAR version, and allows dependencies like:
+    &lt;dep type=&quot;php&quot; rel=&quot;has&quot;&gt;4.3.0&lt;/dep&gt; to
+    slip through unnoticed
+  * re-enable php-const replacements
+  * PEAR_PackageFile_v2::getConfigureOptions() was missing!!
+  * fix cvsdiff command
+  * fix xml encoding issues finally
+  * clean up package.xml 1.0 dir/file parsing
+  * fix invalid PEAR_Config generation
+  * change the user agent from PHP/phpversion to PEAR/pearversion/PHP/phpversion
+  * don't use a bogus uri for licenses on running convert command
+  * add &quot;pickle&quot; command for PECL packaging
+  * add validation warning if the release date in package.xml is not today when packaging
+  * implement progress bar for list-all/remote-list
+  * fix Bug #5323: pear search returns odd version numbers
+  * fix Bug #5428: pear cvstag package2.xml does not include the package.xml
+  * fix Bug #5449: pear makerpm completely broken for package.xml 2.0
+  * fix Bug #5462: raiseError method does not return by ref anymore
+  * fix Bug #5465: pear install --offline fails to display error
+  * fix Bug #5477: Bug in Downloader.php and Dependency2.php
+  * fix Bug #5481: &quot;pear install PECLextension&quot; should display warning to use pecl command
+  * fix Bug #5482: installation of PECL packages should say add extensions to php.ini
+  * fix Bug #5483: pecl uninstall crack fatal error
+  * fix Bug #5487: PECL: compiled files are not uninstalled via the uninstall command
+  * fix Bug #5488: pecl uninstall package fails if package has a package.xml 1.0
+  * fix Bug #5501: the commands list mentions XML-RPC
+  * fix Bug #5509: addDependecyGroup does not validate group name
+  * fix Bug #5513: PEAR 1.4 does not install non-pear.php.net packages
+   </notes>
+  </release>
+  <release>
+   <version>
+    <release>1.4.2</release>
+    <api>1.4.0</api>
+   </version>
+   <stability>
+    <release>stable</release>
+    <api>stable</api>
+   </stability>
+   <date>2005-10-08</date>
+   <license uri="http://www.php.net/license/3_0.txt">PHP License</license>
+   <notes>
+  Minor bugfix release
+
+  * fix issues with API for adding tasks to package2.xml
+  * fix Bug #5520: pecl pickle fails on pecl pickle fails on extension/package deps
+  * fix Bug #5523: pecl pickle misses to put configureoptions into package.xml v1
+  * fix Bug #5527: No need for cpp
+  * fix Bug #5529: configure options in package.xml 2.0 will be ignored
+  * fix Bug #5530: PEAR_PackageFile_v2->getConfigureOptions() API incompatible with v1
+  * fix Bug #5531: adding of installconditions/binarypackage/configure options
+                   to extsrc may fail
+  * fix Bug #5550: PHP notices/warnings/errors are 1 file off in trace
+  * fix Bug #5580: pear makerpm XML_sql2xml-0.3.2.tgz error
+  * fix Bug #5619: pear makerpm produces invalid .spec dependancy code
+  * fix Bug #5629: pear install http_download dies with bad error message
+   </notes>
+  </release>
+ </changelog>
+</package>
index 2b30f8162a985b38ffef8df322287f60c4db6e33..1aefa94b7068e14a8f406a55f1d97f63c8e75bae 100755 (executable)
@@ -16,23 +16,69 @@ REM ----------------------------------------------------------------------
 REM  Authors:     Alexander Merz (alexmerz@php.net)\r
 REM ----------------------------------------------------------------------\r
 REM\r
-REM  Last updated 3/13/2004 ($Id$ is not replaced if the file is binary)\r
+REM  Last updated 12/29/2004 ($Id$ is not replaced if the file is binary)\r
 \r
 REM change this lines to match the paths of your system\r
 REM -------------------\r
 \r
-@ECHO OFF\r
-:: Check PEAR global ENV, set them if they do not exist\r
+\r
+REM Test to see if this is a raw pear.bat (uninstalled version)\r
+SET TMPTMPTMPTMPT=@includ\r
+SET PMTPMTPMT=%TMPTMPTMPTMPT%e_path@\r
+FOR %%x IN ("@include_path@") DO (if %%x=="%PMTPMTPMT%" GOTO :NOTINSTALLED)\r
+\r
+REM Check PEAR global ENV, set them if they do not exist\r
 IF "%PHP_PEAR_INSTALL_DIR%"=="" SET "PHP_PEAR_INSTALL_DIR=@include_path@"\r
 IF "%PHP_PEAR_BIN_DIR%"=="" SET "PHP_PEAR_BIN_DIR=@bin_dir@"\r
 IF "%PHP_PEAR_PHP_BIN%"=="" SET "PHP_PEAR_PHP_BIN=@php_bin@"\r
\r
-:: Check Folders and files\r
+GOTO :INSTALLED\r
+\r
+:NOTINSTALLED\r
+ECHO WARNING: This is a raw, uninstalled pear.bat\r
+\r
+REM Check to see if we can grab the directory of this file (Windows NT+)\r
+IF %~n0 == pear (\r
+FOR %%x IN (cli\php.exe php.exe) DO (if "%%~$PATH:x" NEQ "" (\r
+SET "PHP_PEAR_PHP_BIN=%%~$PATH:x"\r
+echo Using PHP Executable "%PHP_PEAR_PHP_BIN%"\r
+"%PHP_PEAR_PHP_BIN%" -v\r
+GOTO :NEXTTEST\r
+))\r
+GOTO :FAILAUTODETECT\r
+:NEXTTEST\r
+IF "%PHP_PEAR_PHP_BIN%" NEQ "" (\r
+\r
+REM We can use this PHP to run a temporary php file to get the dirname of pear\r
+\r
+echo ^<?php $s=getcwd^(^);chdir^($a=dirname^(__FILE__^).'\\'^);if^(stristr^($a,'\\scripts'^)^)$a=dirname^(dirname^($a^)^).'\\';$f=fopen^($s.'\\~a.a','wb'^);echo$s.'\\~a.a';fwrite^($f,$a^);fclose^($f^);chdir^($s^);?^> > ~~getloc.php\r
+"%PHP_PEAR_PHP_BIN%" ~~getloc.php\r
+set /p PHP_PEAR_BIN_DIR=fakeprompt < ~a.a\r
+DEL ~a.a\r
+DEL ~~getloc.php\r
+set "PHP_PEAR_INSTALL_DIR=%PHP_PEAR_BIN_DIR%pear"\r
+\r
+REM Make sure there is a pearcmd.php at our disposal\r
+\r
+IF NOT EXIST %PHP_PEAR_INSTALL_DIR%\pearcmd.php (\r
+IF EXIST %PHP_PEAR_INSTALL_DIR%\scripts\pearcmd.php COPY %PHP_PEAR_INSTALL_DIR%\scripts\pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php\r
+IF EXIST pearcmd.php COPY pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php\r
+IF EXIST %~dp0\scripts\pearcmd.php COPY %~dp0\scripts\pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php\r
+)\r
+)\r
+GOTO :INSTALLED\r
+) ELSE (\r
+REM Windows Me/98 cannot succeed, so allow the batch to fail\r
+)\r
+:FAILAUTODETECT\r
+echo WARNING: failed to auto-detect pear information\r
+:INSTALLED\r
+\r
+REM Check Folders and files\r
 IF NOT EXIST "%PHP_PEAR_INSTALL_DIR%" GOTO PEAR_INSTALL_ERROR\r
 IF NOT EXIST "%PHP_PEAR_INSTALL_DIR%\pearcmd.php" GOTO PEAR_INSTALL_ERROR2\r
 IF NOT EXIST "%PHP_PEAR_BIN_DIR%" GOTO PEAR_BIN_ERROR\r
 IF NOT EXIST "%PHP_PEAR_PHP_BIN%" GOTO PEAR_PHPBIN_ERROR\r
-:: launch pearcmd\r
+REM launch pearcmd\r
 GOTO RUN\r
 :PEAR_INSTALL_ERROR\r
 ECHO PHP_PEAR_INSTALL_DIR is not set correctly.\r
@@ -66,4 +112,4 @@ GOTO END
 :RUN\r
 "%PHP_PEAR_PHP_BIN%" -C -d output_buffering=1 -d include_path="%PHP_PEAR_INSTALL_DIR%" -f "%PHP_PEAR_INSTALL_DIR%\pearcmd.php" -- %1 %2 %3 %4 %5 %6 %7 %8 %9\r
 :END\r
-@ECHO ON\r
+@ECHO ON
\ No newline at end of file
index ff9366142ef78357111304973a6b1e31044276e1..5a3418f2db7aae3dfd71df37a698dfede3265c2c 100644 (file)
 // $Id$
 
 ob_end_clean();
+if (!defined('PEAR_RUNTYPE')) {
+    // this is defined in peclcmd.php as 'pecl'
+    define('PEAR_RUNTYPE', 'pear');
+}
+define('PEAR_IGNORE_BACKTRACE', 1);
 /**
  * @nodep Gtk
  */
 if ('@include_path@' != '@'.'include_path'.'@') {
     ini_set('include_path', '@include_path@');
+    $raw = false;
+} else {
+    // this is a raw, uninstalled pear, either a cvs checkout, or php distro
+    $raw = true;
 }
-ini_set('allow_url_fopen', true);
+@ini_set('allow_url_fopen', true);
 if (!ini_get('safe_mode')) {
     @set_time_limit(0);
 }
 ob_implicit_flush(true);
-ini_set('track_errors', true);
-ini_set('html_errors', false);
-ini_set('magic_quotes_runtime', false);
+@ini_set('track_errors', true);
+@ini_set('html_errors', false);
+@ini_set('magic_quotes_runtime', false);
+$_PEAR_PHPDIR = '#$%^&*';
 set_error_handler('error_handler');
 
 $pear_package_version = "@pear_version@";
 
 require_once 'PEAR.php';
+require_once 'PEAR/Frontend.php';
 require_once 'PEAR/Config.php';
 require_once 'PEAR/Command.php';
 require_once 'Console/Getopt.php';
 
+
 PEAR_Command::setFrontendType('CLI');
 $all_commands = PEAR_Command::getCommands();
 
 $argv = Console_Getopt::readPHPArgv();
-/* $progname = basename($argv[0]); */
-$progname = 'pear';
+$progname = PEAR_RUNTYPE;
 if (in_array('getopt2', get_class_methods('Console_Getopt'))) {
     array_shift($argv);
     $options = Console_Getopt::getopt2($argv, "c:C:d:D:Gh?sSqu:vV");
@@ -72,15 +83,6 @@ if ($progname == 'gpear' || $progname == 'pear-gtk') {
         }
     }
 }
-PEAR_Command::setFrontendType($fetype);
-$ui = &PEAR_Command::getFrontendObject();
-PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, array($ui, "displayFatalError"));
-if (ini_get('safe_mode')) {
-    $ui->outputData('WARNING: running in safe mode requires that all files created ' .
-        'be the same uid as the current script.  PHP reports this script is uid: ' .
-        @getmyuid() . ', and current user is: ' . @get_current_user());
-}
-
 $pear_user_config = '';
 $pear_system_config = '';
 $store_user_config = false;
@@ -98,10 +100,75 @@ foreach ($opts as $opt) {
     }
 }
 
+PEAR_Command::setFrontendType($fetype);
+$ui = &PEAR_Command::getFrontendObject();
 $config = &PEAR_Config::singleton($pear_user_config, $pear_system_config);
+
+if (PEAR::isError($config)) {
+    $_file = '';
+    if ($pear_user_config !== false) {
+       $_file .= $pear_user_config;
+    }
+    if ($pear_system_config !== false) {
+       $_file .= '/' . $pear_system_config;
+    }
+    if ($_file == '/') {
+        $_file = 'The default config file';
+    }
+    $config->getMessage();
+    $ui->outputData("ERROR: $_file is not a valid config file or is corrupted.");
+    // We stop, we have no idea where we are :)
+    exit();    
+}
+
+// this is used in the error handler to retrieve a relative path
+$_PEAR_PHPDIR = $config->get('php_dir');
+$ui->setConfig($config);
+PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, array($ui, "displayFatalError"));
+if (ini_get('safe_mode')) {
+    $ui->outputData('WARNING: running in safe mode requires that all files created ' .
+        'be the same uid as the current script.  PHP reports this script is uid: ' .
+        @getmyuid() . ', and current user is: ' . @get_current_user());
+}
+
 $verbose = $config->get("verbose");
 $cmdopts = array();
 
+if ($raw) {
+    if (!$config->isDefinedLayer('user') && !$config->isDefinedLayer('system')) {
+        $found = false;
+        foreach ($opts as $opt) {
+            if ($opt[0] == 'd' || $opt[0] == 'D') {
+                $found = true; // the user knows what they are doing, and are setting config values
+            }
+        }
+        if (!$found) {
+            // no prior runs, try to install PEAR
+            if (strpos(dirname(__FILE__), 'scripts')) {
+                $packagexml = dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'package2.xml';
+                $pearbase = dirname(dirname(__FILE__));
+            } else {
+                $packagexml = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'package2.xml';
+                $pearbase = dirname(__FILE__);
+            }
+            if (file_exists($packagexml)) {
+                $options[1] = array(
+                    'install',
+                    $packagexml
+                );
+                $config->set('php_dir', $pearbase . DIRECTORY_SEPARATOR . 'php');
+                $config->set('data_dir', $pearbase . DIRECTORY_SEPARATOR . 'data');
+                $config->set('doc_dir', $pearbase . DIRECTORY_SEPARATOR . 'docs');
+                $config->set('test_dir', $pearbase . DIRECTORY_SEPARATOR . 'tests');
+                $config->set('ext_dir', $pearbase . DIRECTORY_SEPARATOR . 'extensions');
+                $config->set('bin_dir', $pearbase);
+                $config->mergeConfigFile($pearbase . 'pear.ini', false);
+                $config->store();
+                $config->set('auto_discover', 1);
+            }
+        }
+    }
+}
 foreach ($opts as $opt) {
     $param = !empty($opt[1]) ? $opt[1] : true;
     switch ($opt[0]) {
@@ -130,6 +197,9 @@ foreach ($opts as $opt) {
             break;
         case 'V':
             usage(null, 'version');
+        case 'c':
+        case 'C':
+            break;
         default:
             // all non pear params goes to the command
             $cmdopts[$opt[0]] = $param;
@@ -152,17 +222,27 @@ if (empty($command) && ($store_user_config || $store_system_config)) {
 }
 
 if ($fetype == 'Gtk') {
+    if (!$config->validConfiguration()) {
+        PEAR::raiseError('CRITICAL ERROR: no existing valid configuration files found in files ' .
+            "'$pear_user_config' or '$pear_system_config', please copy an existing configuration" .
+            'file to one of these locations, or use the -c and -s options to create one');
+    }
     Gtk::main();
 } else do {
     if ($command == 'help') {
         usage(null, @$options[1][1]);
     }
+    if (!$config->validConfiguration()) {
+        PEAR::raiseError('CRITICAL ERROR: no existing valid configuration files found in files ' .
+            "'$pear_user_config' or '$pear_system_config', please copy an existing configuration" .
+            'file to one of these locations, or use the -c and -s options to create one');
+    }
 
     PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
     $cmd = PEAR_Command::factory($command, $config);
     PEAR::popErrorHandling();
     if (PEAR::isError($cmd)) {
-        usage(null, @$options[1][1]);
+        usage(null, @$options[1][0]);
     }
 
     $short_args = $long_args = null;
@@ -200,6 +280,10 @@ if ($fetype == 'Gtk') {
     if ($ok === false) {
         PEAR::raiseError("unknown command `$command'");
     }
+    if (PEAR::isError($ok)) {
+        PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, array($ui, "displayFatalError"));
+        PEAR::raiseError($ok);
+    }
 } while (false);
 
 // {{{ usage()
@@ -284,7 +368,12 @@ function cmdHelp($command)
 
 function error_handler($errno, $errmsg, $file, $line, $vars) {
     if ((defined('E_STRICT') && $errno & E_STRICT) || !error_reporting()) {
-        return; // @silenced error
+        if (defined('E_STRICT') && $errno & E_STRICT) {
+            return; // E_STRICT
+        }
+        if ($GLOBALS['config']->get('verbose') < 4) {
+            return; // @silenced error, show all if debug is high enough
+        }
     }
     $errortype = array (
         E_ERROR   =>  "Error",
@@ -300,7 +389,12 @@ function error_handler($errno, $errmsg, $file, $line, $vars) {
         E_USER_NOTICE =>  "User Notice"
     );
     $prefix = $errortype[$errno];
-    $file = basename($file);
+    global $_PEAR_PHPDIR;
+    if (stristr($file, $_PEAR_PHPDIR)) {
+        $file = substr($file, strlen($_PEAR_PHPDIR) + 1);
+    } else {
+        $file = basename($file);
+    }
     print "\n$prefix: $errmsg in $file on line $line\n";
 }
 
diff --git a/pear/scripts/peardev.bat b/pear/scripts/peardev.bat
new file mode 100644 (file)
index 0000000..9e82b96
--- /dev/null
@@ -0,0 +1,115 @@
+@ECHO OFF\r
+\r
+REM ----------------------------------------------------------------------\r
+REM PHP version 5\r
+REM ----------------------------------------------------------------------\r
+REM Copyright (c) 1997-2004 The PHP Group\r
+REM ----------------------------------------------------------------------\r
+REM  This source file is subject to version 3.0 of the PHP license, \r
+REM  that is bundled with this package in the file LICENSE, and is\r
+REM  available at through the world-wide-web at\r
+REM  http://www.php.net/license/3_0.txt. \r
+REM  If you did not receive a copy of the PHP license and are unable to\r
+REM  obtain it through the world-wide-web, please send a note to\r
+REM  license@php.net so we can mail you a copy immediately.\r
+REM ----------------------------------------------------------------------\r
+REM  Authors:     Alexander Merz (alexmerz@php.net)\r
+REM ----------------------------------------------------------------------\r
+REM\r
+REM  $Id: peardev.bat,v 1.1.2.1 2005-11-02 16:57:24 cellog Exp $\r
+\r
+REM change this lines to match the paths of your system\r
+REM -------------------\r
+\r
+\r
+REM Test to see if this is a raw pear.bat (uninstalled version)\r
+SET TMPTMPTMPTMPT=@includ\r
+SET PMTPMTPMT=%TMPTMPTMPTMPT%e_path@\r
+FOR %%x IN ("@include_path@") DO (if %%x=="%PMTPMTPMT%" GOTO :NOTINSTALLED)\r
+\r
+REM Check PEAR global ENV, set them if they do not exist\r
+IF "%PHP_PEAR_INSTALL_DIR%"=="" SET "PHP_PEAR_INSTALL_DIR=@include_path@"\r
+IF "%PHP_PEAR_BIN_DIR%"=="" SET "PHP_PEAR_BIN_DIR=@bin_dir@"\r
+IF "%PHP_PEAR_PHP_BIN%"=="" SET "PHP_PEAR_PHP_BIN=@php_bin@"\r
+GOTO :INSTALLED\r
+\r
+:NOTINSTALLED\r
+ECHO WARNING: This is a raw, uninstalled pear.bat\r
+\r
+REM Check to see if we can grab the directory of this file (Windows NT+)\r
+IF %~n0 == pear (\r
+FOR %%x IN (cli\php.exe php.exe) DO (if "%%~$PATH:x" NEQ "" (\r
+SET "PHP_PEAR_PHP_BIN=%%~$PATH:x"\r
+echo Using PHP Executable "%PHP_PEAR_PHP_BIN%"\r
+"%PHP_PEAR_PHP_BIN%" -v\r
+GOTO :NEXTTEST\r
+))\r
+GOTO :FAILAUTODETECT\r
+:NEXTTEST\r
+IF "%PHP_PEAR_PHP_BIN%" NEQ "" (\r
+\r
+REM We can use this PHP to run a temporary php file to get the dirname of pear\r
+\r
+echo ^<?php $s=getcwd^(^);chdir^($a=dirname^(__FILE__^).'\\'^);if^(stristr^($a,'\\scripts'^)^)$a=dirname^(dirname^($a^)^).'\\';$f=fopen^($s.'\\~a.a','wb'^);echo$s.'\\~a.a';fwrite^($f,$a^);fclose^($f^);chdir^($s^);?^> > ~~getloc.php\r
+"%PHP_PEAR_PHP_BIN%" ~~getloc.php\r
+set /p PHP_PEAR_BIN_DIR=fakeprompt < ~a.a\r
+DEL ~a.a\r
+DEL ~~getloc.php\r
+set "PHP_PEAR_INSTALL_DIR=%PHP_PEAR_BIN_DIR%pear"\r
+\r
+REM Make sure there is a pearcmd.php at our disposal\r
+\r
+IF NOT EXIST %PHP_PEAR_INSTALL_DIR%\pearcmd.php (\r
+IF EXIST %PHP_PEAR_INSTALL_DIR%\scripts\pearcmd.php COPY %PHP_PEAR_INSTALL_DIR%\scripts\pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php\r
+IF EXIST pearcmd.php COPY pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php\r
+IF EXIST %~dp0\scripts\pearcmd.php COPY %~dp0\scripts\pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php\r
+)\r
+)\r
+GOTO :INSTALLED\r
+) ELSE (\r
+REM Windows Me/98 cannot succeed, so allow the batch to fail\r
+)\r
+:FAILAUTODETECT\r
+echo WARNING: failed to auto-detect pear information\r
+:INSTALLED\r
+\r
+REM Check Folders and files\r
+IF NOT EXIST "%PHP_PEAR_INSTALL_DIR%" GOTO PEAR_INSTALL_ERROR\r
+IF NOT EXIST "%PHP_PEAR_INSTALL_DIR%\pearcmd.php" GOTO PEAR_INSTALL_ERROR2\r
+IF NOT EXIST "%PHP_PEAR_BIN_DIR%" GOTO PEAR_BIN_ERROR\r
+IF NOT EXIST "%PHP_PEAR_PHP_BIN%" GOTO PEAR_PHPBIN_ERROR\r
+REM launch pearcmd\r
+GOTO RUN\r
+:PEAR_INSTALL_ERROR\r
+ECHO PHP_PEAR_INSTALL_DIR is not set correctly.\r
+ECHO Please fix it using your environment variable or modify\r
+ECHO the default value in pear.bat\r
+ECHO The current value is:\r
+ECHO %PHP_PEAR_INSTALL_DIR%\r
+GOTO END\r
+:PEAR_INSTALL_ERROR2\r
+ECHO PHP_PEAR_INSTALL_DIR is not set correctly.\r
+ECHO pearcmd.php could not be found there.\r
+ECHO Please fix it using your environment variable or modify\r
+ECHO the default value in pear.bat\r
+ECHO The current value is:\r
+ECHO %PHP_PEAR_INSTALL_DIR%\r
+GOTO END\r
+:PEAR_BIN_ERROR\r
+ECHO PHP_PEAR_BIN_DIR is not set correctly.\r
+ECHO Please fix it using your environment variable or modify\r
+ECHO the default value in pear.bat\r
+ECHO The current value is:\r
+ECHO %PHP_PEAR_BIN_DIR%\r
+GOTO END\r
+:PEAR_PHPBIN_ERROR\r
+ECHO PHP_PEAR_PHP_BIN is not set correctly.\r
+ECHO Please fix it using your environment variable or modify\r
+ECHO the default value in pear.bat\r
+ECHO The current value is:\r
+ECHO %PHP_PEAR_PHP_BIN%\r
+GOTO END\r
+:RUN\r
+"%PHP_PEAR_PHP_BIN%" -C -d memory_limit="-1" -d output_buffering=1 -d include_path="%PHP_PEAR_INSTALL_DIR%" -f "%PHP_PEAR_INSTALL_DIR%\pearcmd.php" -- %1 %2 %3 %4 %5 %6 %7 %8 %9\r
+:END\r
+@ECHO ON
\ No newline at end of file
diff --git a/pear/scripts/peardev.sh b/pear/scripts/peardev.sh
new file mode 100644 (file)
index 0000000..7f1383e
--- /dev/null
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+# first find which PHP binary to use
+if test "x$PHP_PEAR_PHP_BIN" != "x"; then
+  PHP="$PHP_PEAR_PHP_BIN"
+else
+  if test "@php_bin@" = '@'php_bin'@'; then
+    PHP=php 
+  else
+    PHP="@php_bin@"
+  fi
+fi
+
+# then look for the right pear include dir
+if test "x$PHP_PEAR_INSTALL_DIR" != "x"; then
+  INCDIR=$PHP_PEAR_INSTALL_DIR
+  INCARG="-d include_path=$PHP_PEAR_INSTALL_DIR"
+else
+  if test "@php_dir@" = '@'php_dir'@'; then
+    INCDIR=`dirname $0`
+    INCARG=""  
+  else
+    INCDIR="@php_dir@"
+    INCARG="-d include_path=@php_dir@"
+  fi
+fi
+
+exec $PHP -d memory_limit="-1" -C -q $INCARG -d output_buffering=1 $INCDIR/pearcmd.php "$@"
diff --git a/pear/scripts/pearwin.php b/pear/scripts/pearwin.php
deleted file mode 100644 (file)
index 5b0623e..0000000
+++ /dev/null
@@ -1,233 +0,0 @@
-<?php
-//
-// +----------------------------------------------------------------------+
-// | PHP Version 4                                                        |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2004 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>                             |
-// +----------------------------------------------------------------------+
-//
-// $Id$
-
-require_once 'PEAR.php';
-require_once 'PEAR/Common.php';
-require_once 'PEAR/Config.php';
-require_once 'PEAR/Remote.php';
-require_once 'PEAR/Registry.php';
-require_once 'Console/Getopt.php';
-
-error_reporting(E_ALL ^ E_NOTICE);
-
-$progname = basename($argv[0]);
-
-PEAR::setErrorHandling(PEAR_ERROR_PRINT, "$progname: %s\n");
-
-$argv = Console_Getopt::readPHPArgv();
-if (PEAR::isError($argv)) {
-    die($argv->getMessage());
-}
-$options = Console_Getopt::getopt($argv, "c:C:d:D:h?sSqu:v");
-if (PEAR::isError($options)) {
-    usage($options);
-}
-
-
-$php_sysconfdir = getenv('PHP_SYSCONFDIR');
-if (!empty($php_sysconfdir)) {
-    $pear_default_config = $php_sysconfdir.DIRECTORY_SEPARATOR.'pearsys.ini';
-    $pear_user_config    = $php_sysconfdir.DIRECTORY_SEPARATOR.'pear.ini';
-} else {
-    $pear_default_config = PHP_SYSCONFDIR.DIRECTORY_SEPARATOR.'pearsys.ini';
-    $pear_user_config    = PHP_SYSCONFDIR.DIRECTORY_SEPARATOR.'pear.ini';
-}
-
-$opts = $options[0];
-
-//echo "ini_get : ".ini_get("pear_install_dir")."\n";
-//echo "get_cfg_var : ".get_cfg_var("pear_install_dir")."\n";
-
-foreach ($opts as $opt) {
-    switch ($opt[0]) {
-        case 'c':
-            $pear_user_config = $opt[1];
-            break;
-        case 'C':
-            $pear_default_config = $opt[1];
-            break;
-    }
-}
-
-$config = new PEAR_Config($pear_user_config, $pear_default_config);
-$store_user_config = false;
-$store_default_config = false;
-$verbose = 1;
-
-foreach ($opts as $opt) {
-    $param = $opt[1];
-    switch ($opt[0]) {
-        case 'd':
-            list($key, $value) = explode('=', $param);
-            $config->set($key, $value);
-            break;
-        case 'D':
-            list($key, $value) = explode('=', $param);
-            $config->set($key, $value, true);
-            break;
-        case 's':
-            $store_user_config = true;
-            break;
-        case 'S':
-            $store_default_config = true;
-            break;
-        case 'u':
-            $config->toDefault($param);
-            break;
-        case 'v':
-            $verbose++;
-            break;
-        case 'q':
-            $verbose--;
-            break;
-    }
-}
-
-if ($store_default_config) {
-    if (@is_writeable($pear_default_config)) {
-        $config->writeConfigFile($pear_default_config, 'default');
-    } else {
-        die("You don't have write access to $pear_default_config, exiting!\n");
-    }
-}
-
-if ($store_user_config) {
-    $config->writeConfigFile($pear_user_config, 'userdefined');
-}
-
-$fallback_config = array(
-    'master_server' => 'pear.php.net',
-    'php_dir'       => getenv('PEAR_INSTALL_DIR'),
-    'ext_dir'       => getenv('PEAR_EXTENSION_DIR'),
-    'doc_dir'       => getenv('PHP_DATADIR') . DIRECTORY_SEPARATOR . 'pear' .
-                       DIRECTORY_SEPARATOR . 'doc',
-    'verbose'       => true,
-);
-$fallback_done = array();
-
-foreach ($fallback_config as $key => $value) {
-    if (!$config->isDefined($key)) {
-        $config->set($key, $value);
-        $fallback_done[$key] = true;
-    }
-}
-
-//$verbose    = $config->get("verbose");
-$script_dir = $config->get("php_dir");
-$ext_dir    = $config->get("ext_dir");
-$doc_dir    = $config->get("doc_dir");
-
-PEAR::setErrorHandling(PEAR_ERROR_PRINT);
-
-$command = (isset($options[1][1])) ? $options[1][1] : null;
-$rest = array_slice($options[1], 2);
-
-if (isset($command_options[$command])) {
-    $tmp = Console_Getopt::getopt($rest, $command_options[$command]);
-    if (PEAR::isError($tmp)) {
-        usage($tmp);
-    }
-    $cmdopts = $tmp[0];
-    $cmdargs = $tmp[1];
-} else {
-    $cmdopts = array();
-    $cmdargs = $rest;
-}
-
-
-/* Extracted from pearcmd-common.php */
-function heading($text)
-{
-    $l = strlen(trim($text));
-    print rtrim($text) . "\n" . str_repeat("=", $l) . "\n";
-}
-
-switch ($command) {
-    case 'install':
-        include 'pearcmd-install.php';
-        break;
-    case 'uninstall':
-        include 'pearcmd-uninstall.php';
-        break;
-    case 'list':
-        include 'pearcmd-list.php';
-        break;
-    case 'package':
-        include 'pearcmd-package.php';
-        break;
-    case 'remote-list':
-        include 'pearcmd-remote-list.php';
-        break;
-    case 'show-config':
-        $keys = $config->getKeys();
-        foreach ($keys as $key) {
-            $value = $config->get($key);
-            $xi = "";
-            if ($config->isDefaulted($key)) {
-                $xi .= " (default)";
-            }
-            if (isset($fallback_done[$key])) {
-                $xi .= " (built-in)";
-            }
-            printf("%s = %s%s\n", $key, $value, $xi);
-        }
-        break;
-    default: {
-        if (!$store_default_config && !$store_user_config) {
-            usage();
-        }
-        break;
-    }
-}
-
-function usage($obj = null)
-{
-    $stderr = fopen('php://stderr', 'w');
-    if ($obj !== null) {
-        fputs($stderr, $obj->getMessage());
-    }
-    fputs($stderr,
-          "Usage: pear [options] command [command-options] <parameters>\n".
-          "Options:\n".
-          "     -v             increase verbosity level (default 1)\n".
-          "     -q             be quiet, decrease verbosity level\n".
-          "     -c file        find user configuration in `file'\n".
-          "     -C file        find system configuration in `file'\n".
-          "     -d \"foo=bar\" set user config variable `foo' to `bar'\n".
-          "     -D \"foo=bar\" set system config variable `foo' to `bar'\n".
-          "     -s             store user configuration\n".
-          "     -S             store system configuration\n".
-          "     -u foo         unset `foo' in the user configuration\n".
-          "     -h, -?         display help/usage (this message)\n".
-          "Commands:\n".
-          "   help [command]\n".
-          "   install [-r] <package file>\n".
-          "   uninstall [-r] <package name>\n".
-          "   package [package info file]\n".
-          "   list\n".
-          "   remote-list\n".
-          "   show-config\n".
-          "\n");
-    fclose($stderr);
-    exit;
-}
-
-?>
diff --git a/pear/scripts/pecl.bat b/pear/scripts/pecl.bat
new file mode 100644 (file)
index 0000000..6a29186
--- /dev/null
@@ -0,0 +1,115 @@
+@ECHO OFF
+
+REM ----------------------------------------------------------------------
+REM PHP version 5
+REM ----------------------------------------------------------------------
+REM Copyright (c) 1997-2004 The PHP Group
+REM ----------------------------------------------------------------------
+REM  This source file is subject to version 3.0 of the PHP license, 
+REM  that is bundled with this package in the file LICENSE, and is
+REM  available at through the world-wide-web at
+REM  http://www.php.net/license/3_0.txt. 
+REM  If you did not receive a copy of the PHP license and are unable to
+REM  obtain it through the world-wide-web, please send a note to
+REM  license@php.net so we can mail you a copy immediately.
+REM ----------------------------------------------------------------------
+REM  Authors:     Alexander Merz (alexmerz@php.net)
+REM ----------------------------------------------------------------------
+REM
+REM  Last updated 02/08/2004 ($Id: pecl.bat,v 1.1.2.1 2005-11-02 16:57:24 cellog Exp $ is not replaced if the file is binary)
+
+REM change this lines to match the paths of your system
+REM -------------------
+
+
+REM Test to see if this is a raw pear.bat (uninstalled version)
+SET TMPTMPTMPTMPT=@includ
+SET PMTPMTPMT=%TMPTMPTMPTMPT%e_path@
+FOR %%x IN ("@include_path@") DO (if %%x=="%PMTPMTPMT%" GOTO :NOTINSTALLED)
+
+REM Check PEAR global ENV, set them if they do not exist
+IF "%PHP_PEAR_INSTALL_DIR%"=="" SET "PHP_PEAR_INSTALL_DIR=@include_path@"
+IF "%PHP_PEAR_BIN_DIR%"=="" SET "PHP_PEAR_BIN_DIR=@bin_dir@"
+IF "%PHP_PEAR_PHP_BIN%"=="" SET "PHP_PEAR_PHP_BIN=@php_bin@"
+GOTO :INSTALLED
+
+:NOTINSTALLED
+ECHO WARNING: This is a raw, uninstalled pear.bat
+
+REM Check to see if we can grab the directory of this file (Windows NT+)
+IF %~n0 == pear (
+FOR %%x IN (cli\php.exe php.exe) DO (if "%%~$PATH:x" NEQ "" (
+SET "PHP_PEAR_PHP_BIN=%%~$PATH:x"
+echo Using PHP Executable "%PHP_PEAR_PHP_BIN%"
+"%PHP_PEAR_PHP_BIN%" -v
+GOTO :NEXTTEST
+))
+GOTO :FAILAUTODETECT
+:NEXTTEST
+IF "%PHP_PEAR_PHP_BIN%" NEQ "" (
+
+REM We can use this PHP to run a temporary php file to get the dirname of pear
+
+echo ^<?php $s=getcwd^(^);chdir^($a=dirname^(__FILE__^).'\\'^);if^(stristr^($a,'\\scripts'^)^)$a=dirname^(dirname^($a^)^).'\\';$f=fopen^($s.'\\~a.a','wb'^);echo$s.'\\~a.a';fwrite^($f,$a^);fclose^($f^);chdir^($s^);?^> > ~~getloc.php
+"%PHP_PEAR_PHP_BIN%" ~~getloc.php
+set /p PHP_PEAR_BIN_DIR=fakeprompt < ~a.a
+DEL ~a.a
+DEL ~~getloc.php
+set "PHP_PEAR_INSTALL_DIR=%PHP_PEAR_BIN_DIR%pear"
+
+REM Make sure there is a pearcmd.php at our disposal
+
+IF NOT EXIST %PHP_PEAR_INSTALL_DIR%\pearcmd.php (
+IF EXIST %PHP_PEAR_INSTALL_DIR%\scripts\pearcmd.php COPY %PHP_PEAR_INSTALL_DIR%\scripts\pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php
+IF EXIST pearcmd.php COPY pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php
+IF EXIST %~dp0\scripts\pearcmd.php COPY %~dp0\scripts\pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php
+)
+)
+GOTO :INSTALLED
+) ELSE (
+REM Windows Me/98 cannot succeed, so allow the batch to fail
+)
+:FAILAUTODETECT
+echo WARNING: failed to auto-detect pear information
+:INSTALLED
+
+REM Check Folders and files
+IF NOT EXIST "%PHP_PEAR_INSTALL_DIR%" GOTO PEAR_INSTALL_ERROR
+IF NOT EXIST "%PHP_PEAR_INSTALL_DIR%\pearcmd.php" GOTO PEAR_INSTALL_ERROR2
+IF NOT EXIST "%PHP_PEAR_BIN_DIR%" GOTO PEAR_BIN_ERROR
+IF NOT EXIST "%PHP_PEAR_PHP_BIN%" GOTO PEAR_PHPBIN_ERROR
+REM launch pearcmd
+GOTO RUN
+:PEAR_INSTALL_ERROR
+ECHO PHP_PEAR_INSTALL_DIR is not set correctly.
+ECHO Please fix it using your environment variable or modify
+ECHO the default value in pear.bat
+ECHO The current value is:
+ECHO %PHP_PEAR_INSTALL_DIR%
+GOTO END
+:PEAR_INSTALL_ERROR2
+ECHO PHP_PEAR_INSTALL_DIR is not set correctly.
+ECHO pearcmd.php could not be found there.
+ECHO Please fix it using your environment variable or modify
+ECHO the default value in pear.bat
+ECHO The current value is:
+ECHO %PHP_PEAR_INSTALL_DIR%
+GOTO END
+:PEAR_BIN_ERROR
+ECHO PHP_PEAR_BIN_DIR is not set correctly.
+ECHO Please fix it using your environment variable or modify
+ECHO the default value in pear.bat
+ECHO The current value is:
+ECHO %PHP_PEAR_BIN_DIR%
+GOTO END
+:PEAR_PHPBIN_ERROR
+ECHO PHP_PEAR_PHP_BIN is not set correctly.
+ECHO Please fix it using your environment variable or modify
+ECHO the default value in pear.bat
+ECHO The current value is:
+ECHO %PHP_PEAR_PHP_BIN%
+GOTO END
+:RUN
+"%PHP_PEAR_PHP_BIN%" -C -n -d output_buffering=1 -d safe_mode=0 -d include_path="%PHP_PEAR_INSTALL_DIR%" -f "%PHP_PEAR_INSTALL_DIR%\peclcmd.php" -- %1 %2 %3 %4 %5 %6 %7 %8 %9
+:END
+@ECHO ON
\ No newline at end of file
diff --git a/pear/scripts/pecl.sh b/pear/scripts/pecl.sh
new file mode 100644 (file)
index 0000000..0ad593e
--- /dev/null
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+# first find which PHP binary to use
+if test "x$PHP_PEAR_PHP_BIN" != "x"; then
+  PHP="$PHP_PEAR_PHP_BIN"
+else
+  if test "@php_bin@" = '@'php_bin'@'; then
+    PHP=php 
+  else
+    PHP="@php_bin@"
+  fi
+fi
+
+# then look for the right pear include dir
+if test "x$PHP_PEAR_INSTALL_DIR" != "x"; then
+  INCDIR=$PHP_PEAR_INSTALL_DIR
+  INCARG="-d include_path=$PHP_PEAR_INSTALL_DIR"
+else
+  if test "@php_dir@" = '@'php_dir'@'; then
+    INCDIR=`dirname $0`
+    INCARG=""  
+  else
+    INCDIR="@php_dir@"
+    INCARG="-d include_path=@php_dir@"
+  fi
+fi
+
+exec $PHP -C -n -q $INCARG -d output_buffering=1 -d safe_mode=0 $INCDIR/peclcmd.php "$@"
diff --git a/pear/scripts/peclcmd.php b/pear/scripts/peclcmd.php
new file mode 100644 (file)
index 0000000..eeca1dd
--- /dev/null
@@ -0,0 +1,45 @@
+<?php
+//
+// +----------------------------------------------------------------------+
+// | PHP Version 5                                                        |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1997-2004 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>                             |
+// |                                                                      |
+// +----------------------------------------------------------------------+
+//
+// $Id$
+
+/**
+ * @nodep Gtk
+ */
+if ('@include_path@' != '@'.'include_path'.'@') {
+    ini_set('include_path', '@include_path@');
+    $raw = false;
+} else {
+    // this is a raw, uninstalled pear, either a cvs checkout, or php distro
+    $raw = true;
+}
+define('PEAR_RUNTYPE', 'pecl');
+require_once 'pearcmd.php';
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * mode: php
+ * End:
+ */
+// vim600:syn=php
+
+?>
index f6f91a524ec7cabad4c072736f2cd8576490c1ce..9fd57af695f32142b5243acb7ae468d342d73d9c 100644 (file)
@@ -6,7 +6,7 @@ License: @release_license@
 Group: Development/Libraries
 Source: http://@master_server@/get/@package@-%{version}.tgz
 BuildRoot: %{_tmppath}/%{name}-root
-URL: http://@master_server@/
+URL: http://@master_server@/package/@package@
 Prefix: %{_prefix}
 #Docdir: @doc_dir@/@package@
 BuildArchitectures: @arch@
@@ -24,43 +24,39 @@ pear -v -c %{buildroot}/pearrc \
         -d bin_dir=%{_bindir} \
         -d data_dir=%{_libdir}/php/pear/data \
         -d test_dir=%{_libdir}/php/pear/tests \
-        -d ext_dir=%{_libdir} \
+        -d ext_dir=%{_libdir} \@extra_config@
         -s
 
 %build
 echo BuildRoot=%{buildroot}
 
-%clean
-[ -n "%{buildroot}" -a "%{buildroot}" != / ] && rm -rf %{buildroot}
-
 %postun
-pear uninstall --nodeps -r @package@
+pear uninstall --nodeps -r @possible_channel@@package@
+rm @rpm_xml_dir@/@package@.xml
 
 %post
 pear install --nodeps -r @rpm_xml_dir@/@package@.xml
 
 %install
-pear -c "%{buildroot}/pearrc" install --nodeps -R "%{buildroot}" \
-        "$RPM_SOURCE_DIR/@package@-%{version}.tgz"
+pear -c %{buildroot}/pearrc install --nodeps -R %{buildroot} \
+        $RPM_SOURCE_DIR/@package@-%{version}.tgz
 rm %{buildroot}/pearrc
 rm %{buildroot}/%{_libdir}/php/pear/.filemap
 rm %{buildroot}/%{_libdir}/php/pear/.lock
 rm -rf %{buildroot}/%{_libdir}/php/pear/.registry
-for DOCDIR in docs doc examples; do
-    if [ -d "%{buildroot}/docs/@package@/$DOCDIR" ]; then
-        rm -rf $RPM_BUILD_DIR/$DOCDIR
-        mv %{buildroot}/docs/@package@/$DOCDIR $RPM_BUILD_DIR
-        rm -rf %{buildroot}/docs
-    fi
-done
+if [ -d "%{buildroot}/docs/@package@/doc" ]; then
+    rm -rf $RPM_BUILD_DIR/doc
+    mv %{buildroot}/docs/@package@/doc $RPM_BUILD_DIR
+    rm -rf %{buildroot}/docs
+fi
 mkdir -p %{buildroot}@rpm_xml_dir@
-tar -xzf $RPM_SOURCE_DIR/@package@-%{version}.tgz package.xml
-cp -p package.xml %{buildroot}@rpm_xml_dir@/@package@.xml
+tar -xzf $RPM_SOURCE_DIR/@package@-%{version}.tgz package@package2xml@.xml
+cp -p package@package2xml@.xml %{buildroot}@rpm_xml_dir@/@package@.xml
 
 #rm -rf %{buildroot}/*
-#pear -q install -R %{buildroot} -n package.xml
+#pear -q install -R %{buildroot} -n package@package2xml@.xml
 #mkdir -p %{buildroot}@rpm_xml_dir@
-#cp -p package.xml %{buildroot}@rpm_xml_dir@/@package@.xml
+#cp -p package@package2xml@.xml %{buildroot}@rpm_xml_dir@/@package@.xml
 
 %files
     %defattr(-,root,root)
diff --git a/pear/tests/PEAR_ErrorStack/Error_Stack_TestCase_getErrorMessage.php b/pear/tests/PEAR_ErrorStack/Error_Stack_TestCase_getErrorMessage.php
deleted file mode 100644 (file)
index 2f46b19..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-<?php
-
-/**
- * API Unit tests for PEAR_ErrorStack package.
- * 
- * @version    $Id$
- * @author     Laurent Laville <pear@laurent-laville.org> portions from HTML_CSS
- * @author     Greg Beaver
- * @package    PEAR_ErrorStack
- */
-
-class testgemessage 
-{
-    function __toString()
-    {
-        return '__toString() called';
-    }
-}
-class testgemessage1 {} 
-/**
- * @package PEAR_ErrorStack
- */
-
-class PEAR_ErrorStack_TestCase_getErrorMessage extends PHPUnit_TestCase
-{
-
-    function PEAR_ErrorStack_TestCase_getErrorMessage($name)
-    {
-        $this->PHPUnit_TestCase($name);
-    }
-
-    function setUp()
-    {
-        error_reporting(E_ALL);
-        $this->errorOccured = false;
-        set_error_handler(array(&$this, 'errorHandler'));
-        $this->stack = new PEAR_ErrorStack('test');
-        $s = &PEAR_ErrorStack::singleton('PEAR_ErrorStack');
-        $s->pushCallback(array('PEAR_ErrorStack', '_handleError'));
-    }
-
-    function tearDown()
-    {
-        unset($this->stack);
-        unset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON']);
-    }
-
-
-    function _stripWhitespace($str)
-    {
-        return preg_replace('/\\s+/', '', $str);
-    }
-
-    function _methodExists($name) 
-    {
-        if (in_array(strtolower($name), get_class_methods($this->stack))) {
-            return true;
-        }
-        $this->assertTrue(false, 'method '. $name . ' not implemented in ' . get_class($this->stack));
-        return false;
-    }
-
-    function errorHandler($errno, $errstr, $errfile, $errline) {
-        //die("$errstr in $errfile at line $errline: $errstr");
-        $this->errorOccured = true;
-        $this->assertTrue(false, "$errstr at line $errline, $errfile");
-    }
-    
-    function returnsignore($err)
-    {
-        $this->wasCalled = true;
-        return PEAR_ERRORSTACK_IGNORE;
-    }
-    
-    function test_basic()
-    {
-        if (!$this->_methodExists('getErrorMessage')) {
-            return;
-        }
-        $msg = PEAR_ErrorStack::getErrorMessage($this->stack,
-            array('message' => 'boo', 'params' => array(), 'code' => 6));
-        $this->assertEquals('boo', $msg);
-    }
-    
-    function test_basic_template()
-    {
-        if (!$this->_methodExists('getErrorMessage')) {
-            return;
-        }
-        $msg = PEAR_ErrorStack::getErrorMessage($this->stack,
-            array('message' => 'boo', 'params' => array()), 'far%__msg%');
-        $this->assertEquals('farboo', $msg);
-    }
-    
-    function test_basic_params()
-    {
-        if (!$this->_methodExists('getErrorMessage')) {
-            return;
-        }
-        $msg = PEAR_ErrorStack::getErrorMessage($this->stack, array('message' => '',
-            'params' => array('bar' => 'hello')), '%bar% foo');
-        $this->assertEquals('hello foo', $msg, 'string');
-        $msg = PEAR_ErrorStack::getErrorMessage($this->stack, array('message' => '',
-            'params' => array('bar' => array('hello', 'there'))), '%bar% foo');
-        $this->assertEquals('hello, there foo', $msg, 'array');
-        $msg = PEAR_ErrorStack::getErrorMessage($this->stack, array('message' => '',
-            'params' => array('bar' => new testgemessage)), '%bar% foo');
-        $this->assertEquals('__toString() called foo', $msg, 'first object, __toString()');
-        $msg = PEAR_ErrorStack::getErrorMessage($this->stack, array('message' => '',
-            'params' => array('bar' => new testgemessage1)), '%bar% foo');
-        $this->assertEquals('Object foo', $msg, 'second object, no __toString()');
-        $errs = PEAR_ErrorStack::staticGetErrors();
-        unset($errs['PEAR_ErrorStack'][0]['context']);
-        unset($errs['PEAR_ErrorStack'][0]['time']);
-        $this->assertEquals(
-            array('PEAR_ErrorStack' =>
-            array(
-                array(
-                    'code' => PEAR_ERRORSTACK_ERR_OBJTOSTRING,
-                    'params' => array('obj' => 'testgemessage1'),
-                    'package' => 'PEAR_ErrorStack',
-                    'level' => 'warning',
-                    'message' => 'object testgemessage1 passed into getErrorMessage, but has no __toString() method',
-                ))), $errs, 'warning not raised');
-    }
-    
-    function test_basic_params_with_template()
-    {
-        if (!$this->_methodExists('getErrorMessage')) {
-            return;
-        }
-        $this->stack->setErrorMessageTemplate(array(6 => '%bar% foo'));
-        $msg = PEAR_ErrorStack::getErrorMessage($this->stack, array('message' => '',
-            'params' => array('bar' => 'hello'), 'code' => 6));
-        $this->assertEquals('hello foo', $msg, 'string');
-        $msg = PEAR_ErrorStack::getErrorMessage($this->stack, array('message' => '',
-            'params' => array('bar' => 'hello'), 'code' => 7));
-        $this->assertEquals('', $msg, 'string');
-    }
-}
-
-?>
diff --git a/pear/tests/PEAR_ErrorStack/Error_Stack_TestCase_getErrorMessageTemplate.php b/pear/tests/PEAR_ErrorStack/Error_Stack_TestCase_getErrorMessageTemplate.php
deleted file mode 100644 (file)
index 36270d6..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-<?php
-
-/**
- * API Unit tests for PEAR_ErrorStack package.
- * 
- * @version    $Id$
- * @author     Laurent Laville <pear@laurent-laville.org> portions from HTML_CSS
- * @author     Greg Beaver
- * @package    PEAR_ErrorStack
- */
-
-/**
- * @package PEAR_ErrorStack
- */
-
-class PEAR_ErrorStack_TestCase_getErrorMessageTemplate extends PHPUnit_TestCase
-{
-
-    function PEAR_ErrorStack_TestCase_getErrorMessageTemplate($name)
-    {
-        $this->PHPUnit_TestCase($name);
-    }
-
-    function setUp()
-    {
-        error_reporting(E_ALL);
-        $this->errorOccured = false;
-        set_error_handler(array(&$this, 'errorHandler'));
-        $this->stack = new PEAR_ErrorStack('test');
-        $s = &PEAR_ErrorStack::singleton('PEAR_ErrorStack');
-        $s->pushCallback(array('PEAR_ErrorStack', '_handleError'));
-    }
-
-    function tearDown()
-    {
-        unset($this->stack);
-        unset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON']);
-    }
-
-
-    function _stripWhitespace($str)
-    {
-        return preg_replace('/\\s+/', '', $str);
-    }
-
-    function _methodExists($name) 
-    {
-        if (in_array(strtolower($name), get_class_methods($this->stack))) {
-            return true;
-        }
-        $this->assertTrue(false, 'method '. $name . ' not implemented in ' . get_class($this->stack));
-        return false;
-    }
-
-    function errorHandler($errno, $errstr, $errfile, $errline) {
-        //die("$errstr in $errfile at line $errline: $errstr");
-        $this->errorOccured = true;
-        $this->assertTrue(false, "$errstr at line $errline, $errfile");
-    }
-    
-    function returnsignore($err)
-    {
-        $this->wasCalled = true;
-        return PEAR_ERRORSTACK_IGNORE;
-    }
-    
-    function test_normal()
-    {
-        if (!$this->_methodExists('getErrorMessageTemplate')) {
-            return;
-        }
-        $this->assertEquals('%__msg%', $this->stack->getErrorMessageTemplate(23));
-    }
-    
-    function test_normal_hascode()
-    {
-        if (!$this->_methodExists('getErrorMessageTemplate')) {
-            return;
-        }
-        if (!$this->_methodExists('setErrorMessageTemplate')) {
-            return;
-        }
-        $this->stack->setErrorMessageTemplate(array(23 => '%foo% has %__msg%'));
-        $this->assertEquals('%foo% has %__msg%', $this->stack->getErrorMessageTemplate(23));
-    }
-}
-
-?>
diff --git a/pear/tests/PEAR_ErrorStack/Error_Stack_TestCase_getErrors.php b/pear/tests/PEAR_ErrorStack/Error_Stack_TestCase_getErrors.php
deleted file mode 100644 (file)
index e2a986e..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-<?php
-
-/**
- * API Unit tests for PEAR_ErrorStack package.
- * 
- * @version    $Id$
- * @author     Laurent Laville <pear@laurent-laville.org> portions from HTML_CSS
- * @author     Greg Beaver
- * @package    PEAR_ErrorStack
- */
-
-/**
- * @package PEAR_ErrorStack
- */
-
-class PEAR_ErrorStack_TestCase_getErrors extends PHPUnit_TestCase
-{
-
-    function PEAR_ErrorStack_TestCase_getErrors($name)
-    {
-        $this->PHPUnit_TestCase($name);
-    }
-
-    function setUp()
-    {
-        error_reporting(E_ALL);
-        $this->errorOccured = false;
-        set_error_handler(array(&$this, 'errorHandler'));
-        $this->stack = new PEAR_ErrorStack('test');
-        $s = &PEAR_ErrorStack::singleton('PEAR_ErrorStack');
-        $s->pushCallback(array('PEAR_ErrorStack', '_handleError'));
-    }
-
-    function tearDown()
-    {
-        unset($this->stack);
-        unset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON']);
-    }
-
-
-    function _stripWhitespace($str)
-    {
-        return preg_replace('/\\s+/', '', $str);
-    }
-
-    function _methodExists($name) 
-    {
-        if (in_array(strtolower($name), get_class_methods($this->stack))) {
-            return true;
-        }
-        $this->assertTrue(false, 'method '. $name . ' not implemented in ' . get_class($this->stack));
-        return false;
-    }
-
-    function errorHandler($errno, $errstr, $errfile, $errline) {
-        //die("$errstr in $errfile at line $errline: $errstr");
-        $this->errorOccured = true;
-        $this->assertTrue(false, "$errstr at line $errline, $errfile");
-    }
-    
-    function returnsignore($err)
-    {
-        $this->wasCalled = true;
-        return PEAR_ERRORSTACK_IGNORE;
-    }
-    
-    function test_none()
-    {
-        if (!$this->_methodExists('getErrors')) {
-            return;
-        }
-        $this->assertEquals(array(), $this->stack->getErrors());
-        $this->assertEquals(array(), $this->stack->getErrors(true));
-    }
-    
-    function test_normal()
-    {
-        if (!$this->_methodExists('getErrors')) {
-            return;
-        }
-        $this->assertEquals(array(), $this->stack->getErrors());
-        $this->stack->push(1);
-        $this->stack->push(2, 'warning');
-        $this->stack->push(3, 'foo');
-        $ret = $this->stack->getErrors();
-        for ($i= 0; $i < 3; $i++) {
-            unset($ret[$i]['time']);
-            unset($ret[$i]['context']);
-        }
-        $this->assertEquals(
-            array(
-                array('code' => 3,
-                'params' => array(),
-                'package' => 'test',
-                'level' => 'foo',
-                'message' => ''),
-                array('code' => 2,
-                'params' => array(),
-                'package' => 'test',
-                'level' => 'warning',
-                'message' => ''),
-                array('code' => 1,
-                'params' => array(),
-                'package' => 'test',
-                'level' => 'error',
-                'message' => ''),
-                ), $ret, 'incorrect errors, non-purge');
-        $ret = $this->stack->getErrors(true);
-        for ($i= 0; $i < 3; $i++) {
-            unset($ret[$i]['time']);
-            unset($ret[$i]['context']);
-        }
-        $this->assertEquals(
-            array(
-                array('code' => 3,
-                'params' => array(),
-                'package' => 'test',
-                'level' => 'foo',
-                'message' => ''),
-                array('code' => 2,
-                'params' => array(),
-                'package' => 'test',
-                'level' => 'warning',
-                'message' => ''),
-                array('code' => 1,
-                'params' => array(),
-                'package' => 'test',
-                'level' => 'error',
-                'message' => ''),
-                ), $ret, 'incorrect errors, purge');
-        $this->assertEquals(array(), $this->stack->getErrors());
-    }
-}
-
-?>
diff --git a/pear/tests/PEAR_ErrorStack/Error_Stack_TestCase_pushpop.php b/pear/tests/PEAR_ErrorStack/Error_Stack_TestCase_pushpop.php
deleted file mode 100644 (file)
index ec7eb83..0000000
+++ /dev/null
@@ -1,367 +0,0 @@
-<?php
-
-/**
- * API Unit tests for PEAR_ErrorStack package.
- * 
- * @version    $Id$
- * @author     Laurent Laville <pear@laurent-laville.org> portions from HTML_CSS
- * @author     Greg Beaver
- * @package    PEAR_ErrorStack
- */
-
-/**
- * @package PEAR_ErrorStack
- */
-
-class PEAR_ErrorStack_TestCase_pushpop extends PHPUnit_TestCase
-{
-    /**
-     * A PEAR_PackageFileManager object
-     * @var        object
-     */
-    var $packagexml;
-
-    function PEAR_ErrorStack_TestCase_pushpop($name)
-    {
-        $this->PHPUnit_TestCase($name);
-    }
-
-    function setUp()
-    {
-        error_reporting(E_ALL);
-        $this->errorOccured = false;
-        set_error_handler(array(&$this, 'errorHandler'));
-        $this->stack = new PEAR_ErrorStack('test');
-        $s = &PEAR_ErrorStack::singleton('PEAR_ErrorStack');
-        $s->pushCallback(array('PEAR_ErrorStack', '_handleError'));
-    }
-
-    function tearDown()
-    {
-        unset($this->stack);
-        unset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON']);
-    }
-
-
-    function _stripWhitespace($str)
-    {
-        return preg_replace('/\\s+/', '', $str);
-    }
-
-    function _methodExists($name) 
-    {
-        if (in_array(strtolower($name), get_class_methods($this->stack))) {
-            return true;
-        }
-        $this->assertTrue(false, 'method '. $name . ' not implemented in ' . get_class($this->stack));
-        return false;
-    }
-
-    function errorHandler($errno, $errstr, $errfile, $errline) {
-        //die("$errstr in $errfile at line $errline: $errstr");
-        $this->errorOccured = true;
-        $this->assertTrue(false, "$errstr at line $errline, $errfile");
-    }
-    
-    function test_valid_basic()
-    {
-        if (!$this->_methodExists('push')) {
-            return;
-        }
-        if (!$this->_methodExists('pop')) {
-            return;
-        }
-        $this->stack->push(1);
-        $err = $this->stack->pop();
-        unset($err['context']);
-        unset($err['time']);
-        $this->assertEquals(
-            array(
-                'code' => 1,
-                'params' => array(),
-                'package' => 'test',
-                'message' => '',
-                'level' => 'error',
-            ),
-            $err, 'popped something else'
-        );
-        $err = $this->stack->pop();
-        $this->assertFalse($err, 'stack not empty!');
-    }
-    
-    function test_valid_params()
-    {
-        if (!$this->_methodExists('push')) {
-            return;
-        }
-        if (!$this->_methodExists('pop')) {
-            return;
-        }
-        $z = $this->stack->push(2, 'exception', array('my' => 'param'), 'hello',
-            array('test'), array(array('file' => 'boof', 'line' => 34)));
-        $err = $this->stack->pop('exception');
-        $this->assertEquals($z, $err, 'popped different error');
-        unset($err['time']);
-        $this->assertEquals(
-            array(
-                'code' => 2,
-                'params' => array('my' => 'param'),
-                'package' => 'test',
-                'message' => 'hello',
-                'level' => 'exception',
-                'context' =>
-                    array(
-                        'file' => 'boof',
-                        'line' => 34,
-                    ),
-                'repackage' => array('test'),
-            ),
-            $err, 'popped something else'
-        );
-        $err = $this->stack->pop();
-        $this->assertFalse($err, 'stack not empty!');
-    }
-    
-    function test_valid_paramscompat()
-    {
-        if (!$this->_methodExists('push')) {
-            return;
-        }
-        if (!$this->_methodExists('pop')) {
-            return;
-        }
-        $this->stack = new PEAR_ErrorStack('test', false, null, true);
-        $z = $this->stack->push(2, 'exception', array('my' => 'param'), 'hello',
-            array('test'), array(array('file' => 'boof', 'line' => 34)));
-        $this->assertEquals('pear_error', strtolower(get_class($z)), 'not pear_error');
-        $err = $this->stack->pop('exception');
-        if (is_a($z, 'PEAR_Error')) {
-            $this->assertEquals($err, $z->getUserInfo(), 'userinfo wrong');
-        }
-        unset($err['time']);
-        $this->assertEquals(
-            array(
-                'code' => 2,
-                'params' => array('my' => 'param'),
-                'package' => 'test',
-                'message' => 'hello',
-                'level' => 'exception',
-                'context' =>
-                    array(
-                        'file' => 'boof',
-                        'line' => 34,
-                    ),
-                'repackage' => array('test'),
-            ),
-            $err, 'popped something else'
-        );
-        $err = $this->stack->pop();
-        $this->assertFalse($err, 'stack not empty!');
-    }
-    
-    function contextcallback($code, $params, $trace)
-    {
-        $this->assertEquals(4, $code, 'wrong context code');
-        $this->assertEquals(array('hello' => 6), $params, 'wrong context params');
-        $this->wasCalled = true;
-        return array('hi' => 'there', 'you' => 'fool');
-    }
-    
-    function test_valid_contextconstructor()
-    {
-        if (!$this->_methodExists('push')) {
-            return;
-        }
-        if (!$this->_methodExists('pop')) {
-            return;
-        }
-        $this->stack = new PEAR_ErrorStack('test', false, array(&$this, 'contextcallback'));
-        $this->wasCalled = false;
-        $this->stack->push(4, 'error', array('hello' => 6));
-        $this->assertTrue($this->wasCalled, 'context callback was not called!');
-        $err = $this->stack->pop();
-        unset($err['time']);
-        $this->assertEquals(
-            array(
-                'code' => 4,
-                'params' => array('hello' => 6),
-                'package' => 'test',
-                'message' => '',
-                'level' => 'error',
-                'context' => array('hi' => 'there', 'you' => 'fool'),
-            ),
-            $err, 'popped something else'
-        );
-        $err = $this->stack->pop();
-        $this->assertFalse($err, 'stack not empty!');
-    }
-    
-    function test_valid_contextsingleton()
-    {
-        if (!$this->_methodExists('push')) {
-            return;
-        }
-        if (!$this->_methodExists('pop')) {
-            return;
-        }
-        if (!$this->_methodExists('singleton')) {
-            return;
-        }
-        $this->stack = &PEAR_ErrorStack::singleton('test', false, array(&$this, 'contextcallback'));
-        $this->wasCalled = false;
-        $this->stack->push(4, 'error', array('hello' => 6));
-        $this->assertTrue($this->wasCalled, 'context callback was not called!');
-        $err = $this->stack->pop();
-        unset($err['time']);
-        $this->assertEquals(
-            array(
-                'code' => 4,
-                'params' => array('hello' => 6),
-                'package' => 'test',
-                'message' => '',
-                'level' => 'error',
-                'context' => array('hi' => 'there', 'you' => 'fool'),
-            ),
-            $err, 'popped something else'
-        );
-        $err = $this->stack->pop();
-        $this->assertFalse($err, 'stack not empty!');
-    }
-    
-    function test_valid_context_setcontext()
-    {
-        if (!$this->_methodExists('push')) {
-            return;
-        }
-        if (!$this->_methodExists('pop')) {
-            return;
-        }
-        if (!$this->_methodExists('setContextCallback')) {
-            return;
-        }
-        $this->stack->setContextCallback(array(&$this, 'contextcallback'));
-        $this->wasCalled = false;
-        $this->stack->push(4, 'error', array('hello' => 6));
-        $this->assertTrue($this->wasCalled, 'context callback was not called!');
-        $err = $this->stack->pop();
-        unset($err['time']);
-        $this->assertEquals(
-            array(
-                'code' => 4,
-                'params' => array('hello' => 6),
-                'package' => 'test',
-                'message' => '',
-                'level' => 'error',
-                'context' => array('hi' => 'there', 'you' => 'fool'),
-            ),
-            $err, 'popped something else'
-        );
-        $err = $this->stack->pop();
-        $this->assertFalse($err, 'stack not empty!');
-    }
-    
-    function messagecallback(&$stack, $err)
-    {
-        $this->assertEquals(4, $err['code'], 'wrong message code');
-        $this->assertEquals(array('hello' => 6), $err['params'], 'wrong message params');
-        $this->assertEquals('test1', $err['package'], 'wrong error stack');
-        $this->wasCalled = true;
-        return 'my silly message';
-    }
-    
-    function test_valid_msgcallbackconstructor()
-    {
-        if (!$this->_methodExists('push')) {
-            return;
-        }
-        if (!$this->_methodExists('pop')) {
-            return;
-        }
-        $this->stack = new PEAR_ErrorStack('test1', array(&$this, 'messagecallback'));
-        $this->wasCalled = false;
-        $this->stack->push(4, 'error', array('hello' => 6));
-        $this->assertTrue($this->wasCalled, 'message callback was not called!');
-        $err = $this->stack->pop();
-        unset($err['time']);
-        unset($err['context']);
-        $this->assertEquals(
-            array(
-                'code' => 4,
-                'params' => array('hello' => 6),
-                'package' => 'test1',
-                'message' => 'my silly message',
-                'level' => 'error',
-            ),
-            $err, 'popped something else'
-        );
-        $err = $this->stack->pop();
-        $this->assertFalse($err, 'stack not empty!');
-    }
-    
-    function test_valid_msgcallbacksingleton()
-    {
-        if (!$this->_methodExists('push')) {
-            return;
-        }
-        if (!$this->_methodExists('pop')) {
-            return;
-        }
-        if (!$this->_methodExists('singleton')) {
-            return;
-        }
-        $this->stack = &PEAR_ErrorStack::singleton('test1', array(&$this, 'messagecallback'));
-        $this->wasCalled = false;
-        $this->stack->push(4, 'error', array('hello' => 6));
-        $this->assertTrue($this->wasCalled, 'message callback was not called!');
-        $err = $this->stack->pop();
-        unset($err['time']);
-        unset($err['context']);
-        $this->assertEquals(
-            array(
-                'code' => 4,
-                'params' => array('hello' => 6),
-                'package' => 'test1',
-                'message' => 'my silly message',
-                'level' => 'error',
-            ),
-            $err, 'popped something else'
-        );
-        $err = $this->stack->pop();
-        $this->assertFalse($err, 'stack not empty!');
-    }
-    
-    function test_valid_msgcallback_setmsgcallback()
-    {
-        if (!$this->_methodExists('push')) {
-            return;
-        }
-        if (!$this->_methodExists('pop')) {
-            return;
-        }
-        if (!$this->_methodExists('setContextCallback')) {
-            return;
-        }
-        $this->stack = new PEAR_ErrorStack('test1');
-        $this->stack->setMessageCallback(array(&$this, 'messagecallback'));
-        $this->wasCalled = false;
-        $this->stack->push(4, 'error', array('hello' => 6));
-        $this->assertTrue($this->wasCalled, 'message callback was not called!');
-        $err = $this->stack->pop();
-        unset($err['time']);
-        unset($err['context']);
-        $this->assertEquals(
-            array(
-                'code' => 4,
-                'params' => array('hello' => 6),
-                'package' => 'test1',
-                'message' => 'my silly message',
-                'level' => 'error',
-            ),
-            $err, 'popped something else'
-        );
-        $err = $this->stack->pop();
-        $this->assertFalse($err, 'stack not empty!');
-    }
-}
-
-?>
diff --git a/pear/tests/PEAR_ErrorStack/Error_Stack_TestCase_pushpopcallback.php b/pear/tests/PEAR_ErrorStack/Error_Stack_TestCase_pushpopcallback.php
deleted file mode 100644 (file)
index 3838ae3..0000000
+++ /dev/null
@@ -1,320 +0,0 @@
-<?php
-
-/**
- * API Unit tests for PEAR_ErrorStack package.
- * 
- * @version    $Id$
- * @author     Laurent Laville <pear@laurent-laville.org> portions from HTML_CSS
- * @author     Greg Beaver
- * @package    PEAR_ErrorStack
- */
-
-/**
- * @package PEAR_ErrorStack
- */
-
-class PEAR_ErrorStack_TestCase_pushpopcallback extends PHPUnit_TestCase
-{
-    /**
-     * A PEAR_PackageFileManager object
-     * @var        object
-     */
-    var $packagexml;
-
-    function PEAR_ErrorStack_TestCase_pushpopcallback($name)
-    {
-        $this->PHPUnit_TestCase($name);
-    }
-
-    function setUp()
-    {
-        error_reporting(E_ALL);
-        $this->errorOccured = false;
-        set_error_handler(array(&$this, 'errorHandler'));
-        $this->stack = new PEAR_ErrorStack('test');
-    }
-
-    function tearDown()
-    {
-        unset($this->stack);
-        unset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON']);
-    }
-
-
-    function _stripWhitespace($str)
-    {
-        return preg_replace('/\\s+/', '', $str);
-    }
-
-    function _methodExists($name) 
-    {
-        if (in_array(strtolower($name), get_class_methods($this->stack))) {
-            return true;
-        }
-        $this->assertTrue(false, 'method '. $name . ' not implemented in ' . get_class($this->stack));
-        return false;
-    }
-
-    function errorHandler($errno, $errstr, $errfile, $errline) {
-        //die("$errstr in $errfile at line $errline: $errstr");
-        $this->errorOccured = true;
-        $this->assertTrue(false, "$errstr at line $errline, $errfile");
-    }
-    
-    function returnsignore($err)
-    {
-        $this->wasCalled = true;
-        return PEAR_ERRORSTACK_IGNORE;
-    }
-    
-    function test_return_ignore()
-    {
-        if (!$this->_methodExists('push')) {
-            return;
-        }
-        if (!$this->_methodExists('pop')) {
-            return;
-        }
-        if (!$this->_methodExists('pushCallback')) {
-            return;
-        }
-        if (!$this->_methodExists('popCallback')) {
-            return;
-        }
-        $this->stack->pushCallback(array(&$this, 'returnsignore'));
-        $this->wasCalled = false;
-        $this->stack->push(1);
-        $this->assertTrue($this->wasCalled, 'returnsignore not called');
-        $err = $this->stack->pop();
-        $this->assertFalse($err, 'error was not ignored!');
-        $this->stack->popCallback();
-        $this->wasCalled = false;
-        $this->stack->push(1);
-        $this->assertFalse($this->wasCalled, 'returnsignore called');
-        $err = $this->stack->pop();
-        unset($err['context']);
-        unset($err['time']);
-        $this->assertEquals(
-            array(
-                'code' => 1,
-                'params' => array(),
-                'package' => 'test',
-                'message' => '',
-                'level' => 'error',
-            ),
-            $err, 'popped something else'
-        );
-        
-        $err = $this->stack->pop();
-        $this->assertFalse($err, 'stack not empty!');
-    }
-    
-    function returnsnothing($err)
-    {
-        $this->wasCalled = true;
-    }
-    
-    function test_return_nothing()
-    {
-        if (!$this->_methodExists('push')) {
-            return;
-        }
-        if (!$this->_methodExists('pop')) {
-            return;
-        }
-        if (!$this->_methodExists('pushCallback')) {
-            return;
-        }
-        if (!$this->_methodExists('popCallback')) {
-            return;
-        }
-        $this->stack->pushCallback(array(&$this, 'returnsnothing'));
-        $this->wasCalled = false;
-        $this->stack->push(1);
-        $this->assertTrue($this->wasCalled, 'returnsnothing not called');
-        $err = $this->stack->pop();
-        unset($err['context']);
-        unset($err['time']);
-        $this->assertEquals(
-            array(
-                'code' => 1,
-                'params' => array(),
-                'package' => 'test',
-                'message' => '',
-                'level' => 'error',
-            ),
-            $err, 'popped something else'
-        );
-        $this->stack->popCallback();
-        $this->wasCalled = false;
-        $this->stack->push(1);
-        $this->assertFalse($this->wasCalled, 'returnsnothing called');
-        $err = $this->stack->pop();
-        unset($err['context']);
-        unset($err['time']);
-        $this->assertEquals(
-            array(
-                'code' => 1,
-                'params' => array(),
-                'package' => 'test',
-                'message' => '',
-                'level' => 'error',
-            ),
-            $err, 'popped something else'
-        );
-        
-        $err = $this->stack->pop();
-        $this->assertFalse($err, 'stack not empty!');
-    }
-    
-    function returnspush($err)
-    {
-        $this->wasCalled = true;
-        return PEAR_ERRORSTACK_PUSH;
-    }
-    
-    function test_return_push()
-    {
-        if (!$this->_methodExists('push')) {
-            return;
-        }
-        if (!$this->_methodExists('pop')) {
-            return;
-        }
-        if (!$this->_methodExists('pushCallback')) {
-            return;
-        }
-        if (!$this->_methodExists('popCallback')) {
-            return;
-        }
-        if (!$this->_methodExists('setLogger')) {
-            return;
-        }
-        $this->stack->pushCallback(array(&$this, 'returnspush'));
-        $log = new BurfLog;
-        $log->setTestCase($this);
-        $log->curMethod(__FUNCTION__);
-        $this->stack->setLogger($log);
-        $this->wasCalled = false;
-        $this->stack->push(1);
-        $this->assertTrue($this->wasCalled, 'returnspush not called');
-        $err = $this->stack->pop();
-        unset($err['context']);
-        unset($err['time']);
-        $this->assertEquals(
-            array(
-                'code' => 1,
-                'params' => array(),
-                'package' => 'test',
-                'message' => '',
-                'level' => 'error',
-            ),
-            $err, 'popped something else 1'
-        );
-        $this->stack->popCallback();
-        $log->pushExpect('', PEAR_LOG_ERR, array(
-                'code' => 1,
-                'params' => array(),
-                'package' => 'test',
-                'message' => '',
-                'level' => 'error',
-            ));
-        $this->wasCalled = false;
-        $this->wasLogged = false;
-        $this->stack->push(1);
-        $this->assertFalse($this->wasCalled, 'returnspush called');
-        $this->assertTrue($this->wasLogged, 'was not logged!');
-        $err = $this->stack->pop();
-        unset($err['context']);
-        unset($err['time']);
-        $this->assertEquals(
-            array(
-                'code' => 1,
-                'params' => array(),
-                'package' => 'test',
-                'message' => '',
-                'level' => 'error',
-            ),
-            $err, 'popped something else 2'
-        );
-        
-        $err = $this->stack->pop();
-        $this->assertFalse($err, 'stack not empty!');
-    }
-    
-    function returnslog($err)
-    {
-        $this->wasCalled = true;
-        return PEAR_ERRORSTACK_LOG;
-    }
-    
-    function test_return_log()
-    {
-        if (!$this->_methodExists('push')) {
-            return;
-        }
-        if (!$this->_methodExists('pop')) {
-            return;
-        }
-        if (!$this->_methodExists('pushCallback')) {
-            return;
-        }
-        if (!$this->_methodExists('popCallback')) {
-            return;
-        }
-        if (!$this->_methodExists('setLogger')) {
-            return;
-        }
-        $this->stack->pushCallback(array(&$this, 'returnslog'));
-        $log = new BurfLog;
-        $log->setTestCase($this);
-        $log->curMethod(__FUNCTION__);
-        $this->stack->setLogger($log);
-        $this->wasCalled = false;
-        $this->wasLogged = false;
-        $log->pushExpect('', PEAR_LOG_ERR, array(
-                'code' => 1,
-                'params' => array(),
-                'package' => 'test',
-                'message' => '',
-                'level' => 'error',
-            ));
-        $this->stack->push(1);
-        $this->assertTrue($this->wasCalled, 'returnslog not called');
-        $this->assertTrue($this->wasLogged, 'was not logged!');
-        $err = $this->stack->pop();
-        $this->assertFalse($err, 'an error was pushed!');
-        $this->stack->popCallback();
-        $log->clearExpect();
-        $log->pushExpect('', PEAR_LOG_ERR, array(
-                'code' => 1,
-                'params' => array(),
-                'package' => 'test',
-                'message' => '',
-                'level' => 'error',
-            ));
-        $this->wasCalled = false;
-        $this->wasLogged = false;
-        $this->stack->push(1);
-        $this->assertFalse($this->wasCalled, 'returnspush called');
-        $this->assertTrue($this->wasLogged, 'was not logged!');
-        $err = $this->stack->pop();
-        unset($err['context']);
-        unset($err['time']);
-        $this->assertEquals(
-            array(
-                'code' => 1,
-                'params' => array(),
-                'package' => 'test',
-                'message' => '',
-                'level' => 'error',
-            ),
-            $err, 'popped something else 2'
-        );
-        
-        $err = $this->stack->pop();
-        $this->assertFalse($err, 'stack not empty!');
-    }
-}
-
-?>
diff --git a/pear/tests/PEAR_ErrorStack/Error_Stack_TestCase_pushpopstatic.php b/pear/tests/PEAR_ErrorStack/Error_Stack_TestCase_pushpopstatic.php
deleted file mode 100644 (file)
index 1af66d7..0000000
+++ /dev/null
@@ -1,327 +0,0 @@
-<?php
-
-/**
- * API Unit tests for PEAR_ErrorStack package.
- * 
- * @version    $Id$
- * @author     Laurent Laville <pear@laurent-laville.org> portions from HTML_CSS
- * @author     Greg Beaver
- * @package    PEAR_ErrorStack
- */
-
-/**
- * @package PEAR_ErrorStack
- */
-
-class PEAR_ErrorStack_TestCase_pushpopstatic extends PHPUnit_TestCase
-{
-    /**
-     * A PEAR_PackageFileManager object
-     * @var        object
-     */
-    var $packagexml;
-
-    function PEAR_ErrorStack_TestCase_pushpopstatic($name)
-    {
-        $this->PHPUnit_TestCase($name);
-    }
-
-    function setUp()
-    {
-        error_reporting(E_ALL);
-        $this->errorOccured = false;
-        set_error_handler(array(&$this, 'errorHandler'));
-        $this->stack = new PEAR_ErrorStack('');
-        $s = &PEAR_ErrorStack::singleton('PEAR_ErrorStack');
-        $s->pushCallback(array('PEAR_ErrorStack', '_handleError'));
-    }
-
-    function tearDown()
-    {
-        unset($this->stack);
-        unset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON']);
-    }
-
-
-    function _stripWhitespace($str)
-    {
-        return preg_replace('/\\s+/', '', $str);
-    }
-
-    function _methodExists($name) 
-    {
-        if (in_array(strtolower($name), get_class_methods($this->stack))) {
-            return true;
-        }
-        $this->assertTrue(false, 'method '. $name . ' not implemented in ' . get_class($this->stack));
-        return false;
-    }
-
-    function errorHandler($errno, $errstr, $errfile, $errline) {
-        //die("$errstr in $errfile at line $errline: $errstr");
-        $this->errorOccured = true;
-        $this->assertTrue(false, "$errstr at line $errline, $errfile");
-    }
-    
-    function test_valid_basic()
-    {
-        if (!$this->_methodExists('staticPush')) {
-            return;
-        }
-        if (!$this->_methodExists('singleton')) {
-            return;
-        }
-        if (!$this->_methodExists('pop')) {
-            return;
-        }
-        $this->stack = &PEAR_ErrorStack::singleton('test');
-        PEAR_ErrorStack::staticPush('test', 1);
-        $err = $this->stack->pop();
-        unset($err['context']);
-        unset($err['time']);
-        $this->assertEquals(
-            array(
-                'code' => 1,
-                'params' => array(),
-                'package' => 'test',
-                'message' => '',
-                'level' => 'error',
-            ),
-            $err, 'popped something else'
-        );
-        $err = $this->stack->pop();
-        $this->assertFalse($err, 'stack not empty!');
-    }
-    
-    function test_valid_params()
-    {
-        if (!$this->_methodExists('staticPush')) {
-            return;
-        }
-        if (!$this->_methodExists('singleton')) {
-            return;
-        }
-        if (!$this->_methodExists('pop')) {
-            return;
-        }
-        $this->stack = &PEAR_ErrorStack::singleton('test');
-        $z = PEAR_ErrorStack::staticPush('test', 2, 'exception', array('my' => 'param'), 'hello',
-            array('test'), array(array('file' => 'boof', 'line' => 34)));
-        $err = $this->stack->pop('exception');
-        $this->assertEquals($z, $err, 'popped different error');
-        unset($err['time']);
-        $this->assertEquals(
-            array(
-                'code' => 2,
-                'params' => array('my' => 'param'),
-                'package' => 'test',
-                'message' => 'hello',
-                'level' => 'exception',
-                'context' =>
-                    array(
-                        'file' => 'boof',
-                        'line' => 34,
-                    ),
-                'repackage' => array('test'),
-            ),
-            $err, 'popped something else'
-        );
-        $err = $this->stack->pop();
-        $this->assertFalse($err, 'stack not empty!');
-    }
-    
-    function test_valid_paramscompat()
-    {
-        if (!$this->_methodExists('staticPush')) {
-            return;
-        }
-        if (!$this->_methodExists('singleton')) {
-            return;
-        }
-        if (!$this->_methodExists('pop')) {
-            return;
-        }
-        $this->stack = &PEAR_ErrorStack::singleton('test', false, null, 'PEAR_ErrorStack', true);
-        $z = PEAR_ErrorStack::staticPush('test', 2, 'exception', array('my' => 'param'), 'hello',
-            array('test'), array(array('file' => 'boof', 'line' => 34)));
-        $this->assertEquals('pear_error', strtolower(get_class($z)), 'not pear_error');
-        $err = $this->stack->pop('exception');
-        if (is_a($z, 'PEAR_Error')) {
-            $this->assertEquals($err, $z->getUserInfo(), 'userinfo wrong');
-        }
-        unset($err['time']);
-        $this->assertEquals(
-            array(
-                'code' => 2,
-                'params' => array('my' => 'param'),
-                'package' => 'test',
-                'message' => 'hello',
-                'level' => 'exception',
-                'context' =>
-                    array(
-                        'file' => 'boof',
-                        'line' => 34,
-                    ),
-                'repackage' => array('test'),
-            ),
-            $err, 'popped something else'
-        );
-        $err = $this->stack->pop();
-        $this->assertFalse($err, 'stack not empty!');
-    }
-    
-    function contextcallback($code, $params, $trace)
-    {
-        $this->assertEquals(4, $code, 'wrong context code');
-        $this->assertEquals(array('hello' => 6), $params, 'wrong context params');
-        $this->wasCalled = true;
-        return array('hi' => 'there', 'you' => 'fool');
-    }
-    
-    function test_valid_contextsingleton()
-    {
-        if (!$this->_methodExists('staticPush')) {
-            return;
-        }
-        if (!$this->_methodExists('singleton')) {
-            return;
-        }
-        if (!$this->_methodExists('pop')) {
-            return;
-        }
-        $this->stack = &PEAR_ErrorStack::singleton('test', false, array(&$this, 'contextcallback'));
-        $this->wasCalled = false;
-        PEAR_ErrorStack::staticPush('test', 4, 'error', array('hello' => 6));
-        $this->assertTrue($this->wasCalled, 'context callback was not called!');
-        $err = $this->stack->pop();
-        unset($err['time']);
-        $this->assertEquals(
-            array(
-                'code' => 4,
-                'params' => array('hello' => 6),
-                'package' => 'test',
-                'message' => '',
-                'level' => 'error',
-                'context' => array('hi' => 'there', 'you' => 'fool'),
-            ),
-            $err, 'popped something else'
-        );
-        $err = $this->stack->pop();
-        $this->assertFalse($err, 'stack not empty!');
-    }
-    
-    function test_valid_context_setcontext()
-    {
-        if (!$this->_methodExists('staticPush')) {
-            return;
-        }
-        if (!$this->_methodExists('singleton')) {
-            return;
-        }
-        if (!$this->_methodExists('pop')) {
-            return;
-        }
-        if (!$this->_methodExists('setContextCallback')) {
-            return;
-        }
-        $this->stack = &PEAR_ErrorStack::singleton('test');
-        $this->stack->setContextCallback(array(&$this, 'contextcallback'));
-        $this->wasCalled = false;
-        PEAR_ErrorStack::staticPush('test', 4, 'error', array('hello' => 6));
-        $this->assertTrue($this->wasCalled, 'context callback was not called!');
-        $err = $this->stack->pop();
-        unset($err['time']);
-        $this->assertEquals(
-            array(
-                'code' => 4,
-                'params' => array('hello' => 6),
-                'package' => 'test',
-                'message' => '',
-                'level' => 'error',
-                'context' => array('hi' => 'there', 'you' => 'fool'),
-            ),
-            $err, 'popped something else'
-        );
-        $err = $this->stack->pop();
-        $this->assertFalse($err, 'stack not empty!');
-    }
-    
-    function messagecallback(&$stack, $err)
-    {
-        $this->assertEquals(4, $err['code'], 'wrong message code');
-        $this->assertEquals(array('hello' => 6), $err['params'], 'wrong message params');
-        $this->assertEquals('test1', $err['package'], 'wrong error stack');
-        $this->wasCalled = true;
-        return 'my silly message';
-    }
-    
-    function test_valid_msgcallbacksingleton()
-    {
-        if (!$this->_methodExists('staticPush')) {
-            return;
-        }
-        if (!$this->_methodExists('singleton')) {
-            return;
-        }
-        if (!$this->_methodExists('pop')) {
-            return;
-        }
-        $this->stack = &PEAR_ErrorStack::singleton('test1', array(&$this, 'messagecallback'));
-        $this->wasCalled = false;
-        PEAR_ErrorStack::staticPush('test1', 4, 'error', array('hello' => 6));
-        $this->assertTrue($this->wasCalled, 'message callback was not called!');
-        $err = $this->stack->pop();
-        unset($err['time']);
-        unset($err['context']);
-        $this->assertEquals(
-            array(
-                'code' => 4,
-                'params' => array('hello' => 6),
-                'package' => 'test1',
-                'message' => 'my silly message',
-                'level' => 'error',
-            ),
-            $err, 'popped something else'
-        );
-        $err = $this->stack->pop();
-        $this->assertFalse($err, 'stack not empty!');
-    }
-    
-    function test_valid_msgcallback_setmsgcallback()
-    {
-        if (!$this->_methodExists('staticPush')) {
-            return;
-        }
-        if (!$this->_methodExists('singleton')) {
-            return;
-        }
-        if (!$this->_methodExists('pop')) {
-            return;
-        }
-        if (!$this->_methodExists('setContextCallback')) {
-            return;
-        }
-        $this->stack = &PEAR_ErrorStack::singleton('test1');
-        $this->stack->setMessageCallback(array(&$this, 'messagecallback'));
-        $this->wasCalled = false;
-        PEAR_ErrorStack::staticPush('test1', 4, 'error', array('hello' => 6));
-        $this->assertTrue($this->wasCalled, 'message callback was not called!');
-        $err = $this->stack->pop();
-        unset($err['time']);
-        unset($err['context']);
-        $this->assertEquals(
-            array(
-                'code' => 4,
-                'params' => array('hello' => 6),
-                'package' => 'test1',
-                'message' => 'my silly message',
-                'level' => 'error',
-            ),
-            $err, 'popped something else'
-        );
-        $err = $this->stack->pop();
-        $this->assertFalse($err, 'stack not empty!');
-    }
-}
-
-?>
diff --git a/pear/tests/PEAR_ErrorStack/Error_Stack_TestCase_singleton.php b/pear/tests/PEAR_ErrorStack/Error_Stack_TestCase_singleton.php
deleted file mode 100644 (file)
index 0a052f1..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-<?php
-
-/**
- * API Unit tests for PEAR_ErrorStack package.
- * 
- * @version    $Id$
- * @author     Laurent Laville <pear@laurent-laville.org> portions from HTML_CSS
- * @author     Greg Beaver
- * @package    PEAR_ErrorStack
- */
-
-/**
- * @package PEAR_ErrorStack
- */
-
-class PEAR_ErrorStack_TestCase_singleton extends PHPUnit_TestCase
-{
-    /**
-     * A PEAR_PackageFileManager object
-     * @var        object
-     */
-    var $packagexml;
-
-    function PEAR_ErrorStack_TestCase_singleton($name)
-    {
-        $this->PHPUnit_TestCase($name);
-    }
-
-    function setUp()
-    {
-        error_reporting(E_ALL);
-        $this->errorOccured = false;
-        set_error_handler(array(&$this, 'errorHandler'));
-        $this->stack = new PEAR_ErrorStack('');
-        $s = &PEAR_ErrorStack::singleton('PEAR_ErrorStack');
-        $s->pushCallback(array('PEAR_ErrorStack', '_handleError'));
-    }
-
-    function tearDown()
-    {
-    }
-
-
-    function _stripWhitespace($str)
-    {
-        return preg_replace('/\\s+/', '', $str);
-    }
-
-    function _methodExists($name) 
-    {
-        if (in_array(strtolower($name), get_class_methods($this->stack))) {
-            return true;
-        }
-        $this->assertTrue(false, 'method '. $name . ' not implemented in ' . get_class($this->stack));
-        return false;
-    }
-
-    function errorHandler($errno, $errstr, $errfile, $errline) {
-        //die("$errstr in $errfile at line $errline: $errstr");
-        $this->errorOccured = true;
-        $this->assertTrue(false, "$errstr at line $errline, $errfile");
-    }
-    
-    function test_valid_singleton()
-    {
-        if (!$this->_methodExists('singleton')) {
-            return;
-        }
-        $one = &PEAR_ErrorStack::singleton('first');
-        $two = &PEAR_ErrorStack::singleton('first');
-        $two->testme = 2;
-        $this->assertEquals(2, $two->testme, 'duh test');
-        $one->testme = 4;
-        $this->assertEquals(4, $one->testme, 'duh test 2');
-        $this->assertEquals(4, $two->testme, 'same object test');
-    }
-    
-    function test_invalid_singleton()
-    {
-        if (!$this->_methodExists('singleton')) {
-            return;
-        }
-        $one = &PEAR_ErrorStack::singleton('first');
-        $two = &PEAR_ErrorStack::singleton('second');
-        $two->testme = 2;
-        $this->assertEquals(2, $two->testme, 'duh test');
-        $one->testme = 4;
-        $this->assertEquals(4, $one->testme, 'duh test 2');
-        $this->assertEquals(2, $two->testme, 'not same object test');
-    }
-}
-
-?>
diff --git a/pear/tests/PEAR_ErrorStack/Error_Stack_TestCase_staticGetErrors.php b/pear/tests/PEAR_ErrorStack/Error_Stack_TestCase_staticGetErrors.php
deleted file mode 100644 (file)
index d96480d..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-<?php
-
-/**
- * API Unit tests for PEAR_ErrorStack package.
- * 
- * @version    $Id$
- * @author     Laurent Laville <pear@laurent-laville.org> portions from HTML_CSS
- * @author     Greg Beaver
- * @package    PEAR_ErrorStack
- */
-
-/**
- * @package PEAR_ErrorStack
- */
-
-class PEAR_ErrorStack_TestCase_staticGetErrors extends PHPUnit_TestCase
-{
-
-    function PEAR_ErrorStack_TestCase_staticGetErrors($name)
-    {
-        $this->PHPUnit_TestCase($name);
-    }
-
-    function setUp()
-    {
-        error_reporting(E_ALL);
-        $this->errorOccured = false;
-        set_error_handler(array(&$this, 'errorHandler'));
-        $this->stack = &PEAR_ErrorStack::singleton('test');
-        $s = &PEAR_ErrorStack::singleton('PEAR_ErrorStack');
-        $s->pushCallback(array('PEAR_ErrorStack', '_handleError'));
-    }
-
-    function tearDown()
-    {
-        unset($this->stack);
-        unset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON']);
-    }
-
-
-    function _stripWhitespace($str)
-    {
-        return preg_replace('/\\s+/', '', $str);
-    }
-
-    function _methodExists($name) 
-    {
-        if (in_array(strtolower($name), get_class_methods($this->stack))) {
-            return true;
-        }
-        $this->assertTrue(false, 'method '. $name . ' not implemented in ' . get_class($this->stack));
-        return false;
-    }
-
-    function errorHandler($errno, $errstr, $errfile, $errline) {
-        //die("$errstr in $errfile at line $errline: $errstr");
-        $this->errorOccured = true;
-        $this->assertTrue(false, "$errstr at line $errline, $errfile");
-    }
-    
-    function returnsignore($err)
-    {
-        $this->wasCalled = true;
-        return PEAR_ERRORSTACK_IGNORE;
-    }
-    
-    function test_none()
-    {
-        if (!$this->_methodExists('staticGetErrors')) {
-            return;
-        }
-        $this->assertEquals(array(), PEAR_ErrorStack::staticGetErrors());
-        $this->assertEquals(array(), PEAR_ErrorStack::staticGetErrors(true));
-    }
-    
-    function test_normal()
-    {
-        if (!$this->_methodExists('staticGetErrors')) {
-            return;
-        }
-        $this->assertEquals(array(), PEAR_ErrorStack::staticGetErrors());
-        $this->stack->push(1);
-        $this->stack->push(2, 'warning');
-        $this->stack->push(3, 'foo');
-        $ret = PEAR_ErrorStack::staticGetErrors();
-        for ($i= 0; $i < 3; $i++) {
-            unset($ret['test'][$i]['time']);
-            unset($ret['test'][$i]['context']);
-        }
-        $this->assertEquals(
-            array( 'test' => array(
-                array('code' => 3,
-                'params' => array(),
-                'package' => 'test',
-                'level' => 'foo',
-                'message' => ''),
-                array('code' => 2,
-                'params' => array(),
-                'package' => 'test',
-                'level' => 'warning',
-                'message' => ''),
-                array('code' => 1,
-                'params' => array(),
-                'package' => 'test',
-                'level' => 'error',
-                'message' => ''),
-                )), $ret, 'incorrect errors, non-purge');
-        $ret = PEAR_ErrorStack::staticGetErrors(true);
-        for ($i= 0; $i < 3; $i++) {
-            unset($ret['test'][$i]['time']);
-            unset($ret['test'][$i]['context']);
-        }
-        $this->assertEquals(
-            array( 'test' => array(
-                array('code' => 3,
-                'params' => array(),
-                'package' => 'test',
-                'level' => 'foo',
-                'message' => ''),
-                array('code' => 2,
-                'params' => array(),
-                'package' => 'test',
-                'level' => 'warning',
-                'message' => ''),
-                array('code' => 1,
-                'params' => array(),
-                'package' => 'test',
-                'level' => 'error',
-                'message' => ''),
-                )), $ret, 'incorrect errors, purge');
-        $this->assertEquals(array(), PEAR_ErrorStack::staticGetErrors());
-    }
-    
-    function test_merge()
-    {
-        if (!$this->_methodExists('staticGetErrors')) {
-            return;
-        }
-        $this->assertEquals(array(), PEAR_ErrorStack::staticGetErrors());
-        $this->stack->push(1);
-        for($i=0;$i<10000;$i++);
-        $this->stack->push(2, 'warning');
-        for($i=0;$i<10000;$i++);
-        PEAR_ErrorStack::staticPush('fronk', 3, 'foo');
-        $ret = PEAR_ErrorStack::staticGetErrors(true, true);
-        for ($i= 0; $i < 3; $i++) {
-            unset($ret[$i]['time']);
-            unset($ret[$i]['context']);
-        }
-        $this->assertEquals(
-            array(
-                array('code' => 3,
-                'params' => array(),
-                'package' => 'fronk',
-                'level' => 'foo',
-                'message' => ''),
-                array('code' => 2,
-                'params' => array(),
-                'package' => 'test',
-                'level' => 'warning',
-                'message' => ''),
-                array('code' => 1,
-                'params' => array(),
-                'package' => 'test',
-                'level' => 'error',
-                'message' => ''),
-                ), $ret, 'incorrect errors, non-purge');
-        $test = PEAR_ErrorStack::staticGetErrors();
-        $this->assertEquals(array(), $test, 'normal array');
-    }
-
-    function _sortErrorsRev($a, $b)
-    {
-        $this->wasCalled = true;
-        if ($a['time'] == $b['time']) {
-            return 0;
-        }
-        if ($a['time'] < $b['time']) {
-            return -1;
-        }
-        return 1;
-    }
-    
-    function test_merge_sortfunc()
-    {
-        if (!$this->_methodExists('staticGetErrors')) {
-            return;
-        }
-        $this->assertEquals(array(), PEAR_ErrorStack::staticGetErrors());
-        $this->stack->push(1);
-        for($i=0;$i<10000;$i++);
-        $this->stack->push(2, 'warning');
-        for($i=0;$i<10000;$i++);
-        PEAR_ErrorStack::staticPush('fronk', 3, 'foo');
-        $this->wasCalled = false;
-        $ret = PEAR_ErrorStack::staticGetErrors(true, true, array(&$this, '_sortErrorsRev'));
-        $this->assertTrue($this->wasCalled, '_sortErrorsRev not called!');
-        for ($i= 0; $i < 3; $i++) {
-            unset($ret[$i]['time']);
-            unset($ret[$i]['context']);
-        }
-        $this->assertEquals(
-            array(
-                array('code' => 1,
-                'params' => array(),
-                'package' => 'test',
-                'level' => 'error',
-                'message' => ''),
-                array('code' => 2,
-                'params' => array(),
-                'package' => 'test',
-                'level' => 'warning',
-                'message' => ''),
-                array('code' => 3,
-                'params' => array(),
-                'package' => 'fronk',
-                'level' => 'foo',
-                'message' => ''),
-                ), $ret, 'incorrect errors, non-purge');
-        $test = PEAR_ErrorStack::staticGetErrors();
-        $this->assertEquals(array(), $test, 'normal array');
-    }
-}
-
-?>
diff --git a/pear/tests/PEAR_ErrorStack/HTML_TestListener.php b/pear/tests/PEAR_ErrorStack/HTML_TestListener.php
deleted file mode 100644 (file)
index a6b3ca6..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-<?php
-
-/**
- * Provides a nice HTML output for PHPUnit suite tests.
- * 
- * @version    $Id$
- * @author     Laurent Laville <pear@laurent-laville.org>
- * @package    HTML_CSS
- */
-
-class HTML_TestListener extends PHPUnit_TestListener {
-
-    function HTML_TestListener() {
-
-$report = <<<EOS
-<table cellspacing="1" cellpadding="1" border="0" width="90%" align="center" class="details">
-<tr><th>Class</th><th>Function</th><th>Success</th><th>Meta-result</th></tr>
-EOS;
-        echo $report;
-    }
-
-    function addError(&$test, &$t) {
-        $this->_errors += 1;
-    }
-
-    function addFailure(&$test, &$t) {
-        $this->_fails += 1;
-    }
-
-    function endTest(&$test) {
-       /* Report both the test result and, for this special situation
-          where some tests are expected to fail, a "meta" test result
-          which indicates whether the test result matches the
-          expected result. 
-        */
-       $expect_failure = preg_match('/fail/i', $test->getName());
-       $test_passed = ($this->_fails == 0 && $this->_errors == 0);
-
-       if ($this->_errors > 0) {
-           $outcome = "<span class=\"Error\">ERROR</span>";
-       } else if ($this->_fails > 0) {
-           $outcome = "<span class=\"Failure\">FAIL</span>";
-       } else {
-           $outcome = "<span class=\"Pass\">OK</span>";
-        }
-       if ($this->_errors > 0) {
-           $meta_outcome = '<span class="Unknown">unknown</span>';
-       } else {
-           $meta_outcome = ($expect_failure xor $test_passed)
-               ? '<span class="Expected">as expected</span>'
-               : '<span class="Unexpected">UNEXPECTED</span>';
-        }
-       printf("<td>$outcome</td><td>$meta_outcome</td></tr>");
-    }
-
-    function startTest(&$test) {
-        $this->_fails = 0;
-        $this->_errors = 0;
-        printf("<tr><td>%s </td><td>%s </td>", get_class($test), $test->getName());
-    }
-
-
-}
-?>
\ No newline at end of file
diff --git a/pear/tests/PEAR_ErrorStack/TestUnit.php b/pear/tests/PEAR_ErrorStack/TestUnit.php
deleted file mode 100644 (file)
index 1fe703f..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-<?php
-
-/**
- * TestUnit runs a TestSuite and returns a TestResult object.
- * And more than PHPUnit attach a listener to TestResult. 
- *
- * @version    $Id$
- * @author     Laurent Laville <pear@laurent-laville.org>
- * @package    HTML_CSS
- */
-
-require_once 'PHPUnit.php';
-
-class TestUnit extends PHPUnit {
-
-    function &run(&$suite, $listener) {
-        $result = new TestResult();
-       $result->addListener($listener);
-        $suite->run($result);
-
-        return $result;
-    }
-}
-
-class TestResult extends PHPUnit_TestResult {
-
-    /* report result of test run */
-    function report() {
-       echo "</TABLE>";
-
-       $nRun = $this->runCount();
-       $nErrors = $this->errorCount();
-       $nFailures = $this->failureCount();
-       echo "<h2>Summary</h2>";
-
-       printf("<p>%s test%s run.<br>", $nRun, ($nRun > 1) ? 's' : '');
-       printf("%s error%s.<br>\n", $nErrors, ($nErrors > 1) ? 's' : '');
-       printf("%s failure%s.<br>\n", $nFailures, ($nFailures > 1) ? 's' : '');
-       if ($nFailures > 0) {
-           echo "<h2>Failure Details</h2>";
-            print("<ol>\n");
-            $failures = $this->failures();
-            while (list($i, $failure) = each($failures)) {
-                $failedTest = $failure->failedTest();
-                printf("<li>%s\n", $failedTest->getName() );
-                print("<ul>");
-                printf("<li>%s\n", $failure->thrownException() );
-                print("</ul>");
-            }
-            print("</ol>\n");
-       }
-    }
-
-}
-?>
diff --git a/pear/tests/PEAR_ErrorStack/base_regression.php b/pear/tests/PEAR_ErrorStack/base_regression.php
deleted file mode 100644 (file)
index 16e9eeb..0000000
+++ /dev/null
@@ -1,550 +0,0 @@
-<?php
-// $Revision$
-/**
- * Basic regression test for PEAR_ErrorStack::getFileLine()
- * 
- * phpUnit can't test global code properly because of its design, so I designed
- * this instead
- * @package PEAR_ErrorStack
- * @subpackage tests
- * @author Greg Beaver <cellog@php.net>
- */
-require_once 'PEAR/ErrorStack.php';
-$result = array(
-'passed' => array(),
-'failed' => array()
-);
-$stack = &PEAR_ErrorStack::singleton('test');
-$testNumber = 1;
-// test basic global file/line
-$stack->push(3);
-$testline = __LINE__ - 1;
-
-$ret = $stack->pop();
-$diff = array_diff_assoc($ret['context'],
-array('file' => __FILE__,
-      'function' => 'include_once',
-      'line' => $testline));
-
-if ($diff !== array()) {
-    $result['failed'][$testNumber] = $diff;
-} else {
-    $result['passed'][$testNumber] = true;
-}
-
-$testNumber++;
-// test basic in-function file/line #2
-function testfunc() { global $stack, $testline;
-$stack->push(3);
-$testline = __LINE__ - 1;
-}
-testfunc();
-
-$ret = $stack->pop();
-$diff = array_diff_assoc($ret['context'],
-array('file' => __FILE__,
-      'line' => $testline,
-      'function' => 'testfunc'));
-
-if ($diff !== array()) {
-    $result['failed'][$testNumber] = $diff;
-} else {
-    $result['passed'][$testNumber] = true;
-}
-
-$testNumber++;
-// test basic in-static method file/line #3
-class stclass {
-function stfunc() { global $stack, $testline;
-$stack->push(3);
-$testline = __LINE__ - 1;
-}
-}
-stclass::stfunc();
-
-$ret = $stack->pop();
-$diff = array_diff_assoc($ret['context'],
-array('file' => __FILE__,
-      'line' => $testline,
-      'function' => 'stfunc',
-      'class' => 'stclass'));
-
-if ($diff !== array()) {
-    $result['failed'][$testNumber] = $diff;
-} else {
-    $result['passed'][$testNumber] = true;
-}
-
-$testNumber++;
-// test basic in-method file/line #4
-class normalclass {
-function normalfunc() { global $stack, $testline;
-$stack->push(3);
-$testline = __LINE__ - 1;
-}
-}
-$z = new normalclass;
-$z->normalfunc();
-
-$ret = $stack->pop();
-$diff = array_diff_assoc($ret['context'],
-array('file' => __FILE__,
-      'line' => $testline,
-      'function' => 'normalfunc',
-      'class' => 'normalclass'));
-
-if ($diff !== array()) {
-    $result['failed'][$testNumber] = $diff;
-} else {
-    $result['passed'][$testNumber] = true;
-}
-
-$testNumber++;
-// test global eval file/line #5
-eval('$stack->push(3);');
-$testline = __LINE__ - 1;
-
-$ret = $stack->pop();
-$diff = array_diff_assoc($ret['context'],
-array('file' => __FILE__,
-      'function' => 'include_once',
-      'line' => $testline));
-
-if ($diff !== array()) {
-    $result['failed'][$testNumber] = $diff;
-} else {
-    $result['passed'][$testNumber] = true;
-}
-
-$testNumber++;
-// test in-function eval file/line #6
-function test2() {
-    global $testline, $stack;
-eval('$stack->push(3);');
-$testline = __LINE__ - 1;
-}
-test2();
-
-$ret = $stack->pop();
-$diff = array_diff_assoc($ret['context'],
-array('file' => __FILE__,
-      'line' => $testline,
-      'function' => 'test2'));
-
-if ($diff !== array()) {
-    $result['failed'][$testNumber] = $diff;
-} else {
-    $result['passed'][$testNumber] = true;
-}
-
-$testNumber++;
-// test in-static method eval file/line #7
-class test3 {
-function test3() {
-    global $testline, $stack;
-eval('$stack->push(3);');
-$testline = __LINE__ - 1;
-}
-}
-test3::test3();
-
-$ret = $stack->pop();
-$diff = array_diff_assoc($ret['context'],
-array('file' => __FILE__,
-      'line' => $testline,
-      'function' => 'test3',
-      'class' => 'test3'));
-
-if ($diff !== array()) {
-    $result['failed'][$testNumber] = $diff;
-} else {
-    $result['passed'][$testNumber] = true;
-}
-
-$testNumber++;
-// test in-method eval file/line #8
-class test4 {
-function test4() {
-    global $testline, $stack;
-eval('$stack->push(3);');
-$testline = __LINE__ - 1;
-}
-}
-$z = new test4;
-$z->test4();
-
-$ret = $stack->pop();
-$diff = array_diff_assoc($ret['context'],
-array('file' => __FILE__,
-      'line' => $testline,
-      'function' => 'test4',
-      'class' => 'test4'));
-
-if ($diff !== array()) {
-    $result['failed'][$testNumber] = $diff;
-} else {
-    $result['passed'][$testNumber] = true;
-}
-
-$testNumber++;
-// test global create_function file/line #9
-$a = create_function('', '$GLOBALS["stack"]->push(3);');
-$testline = __LINE__ - 1;
-$a();
-
-$ret = $stack->pop();
-$diff = array_diff_assoc($ret['context'],
-array('file' => __FILE__,
-      'line' => $testline,
-      'function' => 'create_function() code'));
-
-if ($diff !== array()) {
-    $result['failed'][$testNumber] = $diff;
-} else {
-    $result['passed'][$testNumber] = true;
-}
-
-$testNumber++;
-// test in-function create_function file/line #10
-function test7() { global $a;
-$a();
-}
-test7();
-
-$ret = $stack->pop();
-$diff = array_diff_assoc($ret['context'],
-array('file' => __FILE__,
-      'line' => $testline,
-      'function' => 'create_function() code'));
-
-if ($diff !== array()) {
-    $result['failed'][$testNumber] = $diff;
-} else {
-    $result['passed'][$testNumber] = true;
-}
-
-$testNumber++;
-// test in-static method create_function file/line #11
-class test8 {
-function test8() { global $a;
-$a();
-}
-}
-test8::test8();
-
-$ret = $stack->pop();
-$diff = array_diff_assoc($ret['context'],
-array('file' => __FILE__,
-      'line' => $testline,
-      'function' => 'create_function() code'));
-
-if ($diff !== array()) {
-    $result['failed'][$testNumber] = $diff;
-} else {
-    $result['passed'][$testNumber] = true;
-}
-
-$testNumber++;
-// test in-method create_function file/line #12
-class test9 {
-function test9() { global $a;
-$a();
-}
-}
-$z = new test9;
-$z->test9();
-
-$ret = $stack->pop();
-$diff = array_diff_assoc($ret['context'],
-array('file' => __FILE__,
-      'line' => $testline,
-      'function' => 'create_function() code'));
-
-if ($diff !== array()) {
-    $result['failed'][$testNumber] = $diff;
-} else {
-    $result['passed'][$testNumber] = true;
-}
-
-$result['number'] = $testNumber;
-
-$testNumber++;
-// test static basic global file/line #13
-PEAR_ErrorStack::staticPush('test', 3);
-$testline = __LINE__ - 1;
-
-$ret = $stack->pop();
-$diff = array_diff_assoc($ret['context'],
-array('file' => __FILE__,
-      'function' => 'include_once',
-      'line' => $testline));
-
-if ($diff !== array()) {
-    $result['failed'][$testNumber] = $diff;
-} else {
-    $result['passed'][$testNumber] = true;
-}
-
-$testNumber++;
-// test static basic in-function file/line #14
-function testfunc2() { global $stack, $testline;
-PEAR_ErrorStack::staticPush('test', 3);
-$testline = __LINE__ - 1;
-}
-testfunc2();
-
-$ret = $stack->pop();
-$diff = array_diff_assoc($ret['context'],
-array('file' => __FILE__,
-      'line' => $testline,
-      'function' => 'testfunc2'));
-
-if ($diff !== array()) {
-    $result['failed'][$testNumber] = $diff;
-} else {
-    $result['passed'][$testNumber] = true;
-}
-
-$testNumber++;
-// test static basic in-static method file/line #15
-class stclass2 {
-function stfunc() { global $stack, $testline;
-PEAR_ErrorStack::staticPush('test', 3);
-$testline = __LINE__ - 1;
-}
-}
-stclass2::stfunc();
-
-$ret = $stack->pop();
-$diff = array_diff_assoc($ret['context'],
-array('file' => __FILE__,
-      'line' => $testline,
-      'function' => 'stfunc',
-      'class' => 'stclass2'));
-
-if ($diff !== array()) {
-    $result['failed'][$testNumber] = $diff;
-} else {
-    $result['passed'][$testNumber] = true;
-}
-
-$testNumber++;
-// test static basic in-method file/line #16
-class normalclass2 {
-function normalfunc() { global $stack, $testline;
-PEAR_ErrorStack::staticPush('test', 3);
-$testline = __LINE__ - 1;
-}
-}
-$z = new normalclass2;
-$z->normalfunc();
-
-$ret = $stack->pop();
-$diff = array_diff_assoc($ret['context'],
-array('file' => __FILE__,
-      'line' => $testline,
-      'function' => 'normalfunc',
-      'class' => 'normalclass2'));
-
-if ($diff !== array()) {
-    $result['failed'][$testNumber] = $diff;
-} else {
-    $result['passed'][$testNumber] = true;
-}
-
-$testNumber++;
-// test static global eval file/line #17
-eval('PEAR_ErrorStack::staticPush(\'test\', 3);');
-$testline = __LINE__ - 1;
-
-$ret = $stack->pop();
-$diff = array_diff_assoc($ret['context'],
-array('file' => __FILE__,
-      'function' => 'include_once',
-      'line' => $testline));
-
-if ($diff !== array()) {
-    $result['failed'][$testNumber] = $diff;
-} else {
-    $result['passed'][$testNumber] = true;
-}
-
-$testNumber++;
-// test static in-function eval file/line #18
-function test22() {
-    global $testline, $stack;
-eval('PEAR_ErrorStack::staticPush("test", 3);');
-$testline = __LINE__ - 1;
-}
-test22();
-
-$ret = $stack->pop();
-$diff = array_diff_assoc($ret['context'],
-array('file' => __FILE__,
-      'line' => $testline,
-      'function' => 'test22'));
-
-if ($diff !== array()) {
-    $result['failed'][$testNumber] = $diff;
-} else {
-    $result['passed'][$testNumber] = true;
-}
-
-$testNumber++;
-// test static in-static method eval file/line #19
-class test32 {
-function test3() {
-    global $testline, $stack;
-eval('PEAR_ErrorStack::staticPush(\'test\',3);');
-$testline = __LINE__ - 1;
-}
-}
-test32::test3();
-
-$ret = $stack->pop();
-$diff = array_diff_assoc($ret['context'],
-array('file' => __FILE__,
-      'line' => $testline,
-      'function' => 'test3',
-      'class' => 'test32'));
-
-if ($diff !== array()) {
-    $result['failed'][$testNumber] = $diff;
-} else {
-    $result['passed'][$testNumber] = true;
-}
-
-$testNumber++;
-// test static in-method eval file/line #20
-class test42 {
-function test4() {
-    global $testline, $stack;
-eval('PEAR_ErrorStack::staticPush(\'test\',3);');
-$testline = __LINE__ - 1;
-}
-}
-$z = new test42;
-$z->test4();
-
-$ret = $stack->pop();
-$diff = array_diff_assoc($ret['context'],
-array('file' => __FILE__,
-      'line' => $testline,
-      'function' => 'test4',
-      'class' => 'test42'));
-
-if ($diff !== array()) {
-    $result['failed'][$testNumber] = $diff;
-} else {
-    $result['passed'][$testNumber] = true;
-}
-
-$testNumber++;
-// test static global create_function file/line #21
-$a = create_function('', 'PEAR_ErrorStack::staticPush("test",3);');
-$testline = __LINE__ - 1;
-$a();
-
-$ret = $stack->pop();
-$diff = array_diff_assoc($ret['context'],
-array('file' => __FILE__,
-      'line' => $testline,
-      'function' => 'create_function() code'));
-
-if ($diff !== array()) {
-    $result['failed'][$testNumber] = $diff;
-} else {
-    $result['passed'][$testNumber] = true;
-}
-
-$testNumber++;
-// test static in-function create_function file/line #22
-function test72() { global $a;
-$a();
-}
-test72();
-
-$ret = $stack->pop();
-$diff = array_diff_assoc($ret['context'],
-array('file' => __FILE__,
-      'line' => $testline,
-      'function' => 'create_function() code'));
-
-if ($diff !== array()) {
-    $result['failed'][$testNumber] = $diff;
-} else {
-    $result['passed'][$testNumber] = true;
-}
-
-$testNumber++;
-// test static in-static method create_function file/line #23
-class test82 {
-function test8() { global $a;
-$a();
-}
-}
-test82::test8();
-
-$ret = $stack->pop();
-$diff = array_diff_assoc($ret['context'],
-array('file' => __FILE__,
-      'line' => $testline,
-      'function' => 'create_function() code'));
-
-if ($diff !== array()) {
-    $result['failed'][$testNumber] = $diff;
-} else {
-    $result['passed'][$testNumber] = true;
-}
-
-$testNumber++;
-// test static in-method create_function file/line #24
-class test92 {
-function test9() { global $a;
-$a();
-}
-}
-$z = new test92;
-$z->test9();
-
-$ret = $stack->pop();
-$diff = array_diff_assoc($ret['context'],
-array('file' => __FILE__,
-      'line' => $testline,
-      'function' => 'create_function() code'));
-
-if ($diff !== array()) {
-    $result['failed'][$testNumber] = $diff;
-} else {
-    $result['passed'][$testNumber] = true;
-}
-
-$result['number'] = $testNumber;
-
-return $result;
-/**
- * Utility function
- */
-function isIncludeable($path)
-{
-    if (file_exists(realpath($path)) && is_readable(realpath($path))) {
-        return true;
-    }
-    foreach (explode(PATH_SEPARATOR, get_include_path()) as $prepend) {
-       $test = realpath($prepend . DIRECTORY_SEPARATOR . $path);
-        if (file_exists($test) && is_readable($test)) {
-            return true;
-        }
-    }
-}
-/**
- * Mock PHPUnit object
- */
-class Mock_PHPUnit {
-    var $name;
-    function getName()
-    {
-        return 'base regression test ' . $this->name;
-    }
-}
-?>
\ No newline at end of file
diff --git a/pear/tests/PEAR_ErrorStack/stylesheet.css b/pear/tests/PEAR_ErrorStack/stylesheet.css
deleted file mode 100644 (file)
index 47b9f92..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/* $Id$ */
-
-body {
-       font:normal 68% verdana,arial,helvetica;
-       color:#000000;
-}
-table tr td, table tr th {
-    font-size: 68%;
-}
-table.details tr th{
-       font-weight: bold;
-       text-align:left;
-       background:#a6caf0;
-}
-table.details tr{
-       background:#eeeee0;
-}
-
-p {
-       line-height:1.5em;
-       margin-top:0.5em; margin-bottom:1.0em;
-}
-h1 {
-       margin: 0px 0px 5px; font: 165% verdana,arial,helvetica
-}
-h2 {
-       margin-top: 1em; margin-bottom: 0.5em; font: bold 125% verdana,arial,helvetica
-}
-h3 {
-       margin-bottom: 0.5em; font: bold 115% verdana,arial,helvetica
-}
-h4 {
-       margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica
-}
-h5 {
-       margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica
-}
-h6 {
-       margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica
-}
-.Error {
-       font-weight:bold; color:red;
-}
-.Failure, .Unexpected {
-       background:#ff0000; font-weight:bold; color:black;
-}
-.Unknown {
-       background:#ffff00; font-weight:bold; color:black;
-}
-.Pass, .Expected {
-       background:#00ff00; font-weight:bold; color:black;
-}
-.Properties {
-       text-align:right;
-}
-
-CODE.expected {
-       color: green; background: none; font-weight: normal;
-}
-CODE.actual {
-       color: red; background: none; font-weight: normal;
-}
-.typeinfo {
-       color: gray;
-}
diff --git a/pear/tests/PEAR_ErrorStack/testsuite.php b/pear/tests/PEAR_ErrorStack/testsuite.php
deleted file mode 100644 (file)
index 1899142..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-<?php
-
-/**
- * HTML output for PHPUnit suite tests.
- *
- * Copied for PEAR_PackageFileManager from HTML_CSS
- * @version    $Id$
- * @author     Laurent Laville <pear@laurent-laville.org>
- * @package    HTML_CSS
- */
-
-require_once 'TestUnit.php';
-require_once 'HTML_TestListener.php';
-require_once 'PEAR/ErrorStack.php';
-
-$title = 'PhpUnit test run, PEAR_ErrorStack package';
-?>
-<html>
-<head>
-<title><?php echo $title; ?></title>
-<link rel="stylesheet" href="stylesheet.css" type="text/css" />
-</head>
-<body>
-<h1><?php echo $title; ?></h1>
-      <p>
-       This page runs all the phpUnit self-tests, and produces nice HTML output.
-      </p>
-      <p>
-       Unlike typical test run, <strong>expect many test cases to
-         fail</strong>.  Exactly those with <code>pass</code> in their name
-       should succeed.
-      </p>
-      <p>
-      For each test we display both the test result -- <span
-      class="Pass">ok</span>, <span class="Failure">FAIL</span>, or
-      <span class="Error">ERROR</span> -- and also a meta-result --
-      <span class="Expected">as expected</span>, <span
-      class="Unexpected">UNEXPECTED</span>, or <span
-      class="Unknown">unknown</span> -- that indicates whether the
-      expected test result occurred.  Although many test results will
-      be 'FAIL' here, all meta-results should be 'as expected', except
-      for a few 'unknown' meta-results (because of errors) when running
-      in PHP3.
-      </p>
-      
-<h2>Tests</h2>
-       <?php
-       $testcases = array(
-           'PEAR_ErrorStack_TestCase_singleton',
-           'PEAR_ErrorStack_TestCase_pushpop',
-           'PEAR_ErrorStack_TestCase_pushpopstatic',
-           'PEAR_ErrorStack_TestCase_pushpopcallback',
-           'PEAR_ErrorStack_TestCase_getErrorMessage',
-           'PEAR_ErrorStack_TestCase_getErrorMessageTemplate',
-           'PEAR_ErrorStack_TestCase_getErrors',
-           'PEAR_ErrorStack_TestCase_staticGetErrors',
-       );
-define('PEAR_LOG_EMERG',    0);     /** System is unusable */
-define('PEAR_LOG_ALERT',    1);     /** Immediate action required */
-define('PEAR_LOG_CRIT',     2);     /** Critical conditions */
-define('PEAR_LOG_ERR',      3);     /** Error conditions */
-define('PEAR_LOG_WARNING',  4);     /** Warning conditions */
-define('PEAR_LOG_NOTICE',   5);     /** Normal but significant */
-define('PEAR_LOG_INFO',     6);     /** Informational */
-define('PEAR_LOG_DEBUG',    7);     /** Debug-level messages */
-/**
-* Mock Log object
-*/
-class BurfLog {
-    var $testcase;
-    var $method;
-    var $expect = array();
-    function setTestCase(&$testcase)
-    {
-        $this->testcase = &$testcase;
-    }
-    
-    function curMethod($method)
-    {
-        $this->method = $method;
-    }
-    
-    function pushExpect($message, $priority, $errarray)
-    {
-        unset($errarray['time']);
-        unset($errarray['context']);
-        array_push($this->expect, array($message, $priority, $errarray));
-    }
-    
-    function clearExpect()
-    {
-        $this->expect = array();
-    }
-
-    function log($message, $priority, $errarray)
-    {
-        $this->testcase->wasLogged = true;
-        if (!is_a($this->testcase, 'PHPUnit_TestCase')) {
-            trigger_error('ERROR: burflog never set up', E_USER_ERROR);
-            return;
-        }
-        if (!isset($this->method)) {
-            $this->testcase->assertFalse(true, 'ERROR: burflog never set up');
-            return;
-        }
-        if (!count($this->expect)) {
-            $this->testcase->assertFalse(true, "method $this->method: logged, but no log expected");
-            $this->testcase->assertFalse(true, "method $this->method: log message = $message");
-            $this->testcase->assertFalse(true, "method $this->method: log priority = $priority");
-            return;
-        }
-        unset($errarray['time']);
-        unset($errarray['context']);
-        $expect = array_pop($this->expect);
-        $this->testcase->assertEquals($expect[0], $message, "method $this->method: wrong message");
-        $this->testcase->assertEquals($expect[1], $priority, "method $this->method: wrong priority");
-        $this->testcase->assertEquals($expect[2], $errarray, "method $this->method: wrong errarray");
-    }
-}
-       
-       $suite = new PHPUnit_TestSuite();
-
-       foreach ($testcases as $testcase) {
-           include_once $testcase . '.php';
-            $suite->addTestSuite($testcase);
-       }
-
-       $listener = new HTML_TestListener();
-    $finalresult = TestUnit::run($suite, $listener);
-    $results = include_once dirname(__FILE__) . '/base_regression.php';
-    $num = $results['number'];
-    $failed = $results['failed'];
-    $passed = $results['passed'];
-    for ($i = 1; $i <= $num; $i++) {
-        $bla = new Mock_PHPUnit;
-        $bla->name = $i;
-        $listener->startTest($bla);
-       if (isset($failed[$i])) {
-           $listener->addFailure($bla, $failed[$i]);
-            $finalresult->addFailure($bla, $a = 'context had additional ' . serialize($failed[$i]));
-        }
-        $listener->endTest($bla);
-    }
-
-       $finalresult->removeListener($listener);
-    // hack in the base regression test count
-    $finalresult->_runTests += count($results['failed']) + count($results['passed']);
-       $finalresult->report();
-
-       ?>
-</body>
-</html>
diff --git a/pear/tests/common_sortPkgDeps1_package.xml b/pear/tests/common_sortPkgDeps1_package.xml
deleted file mode 100644 (file)
index a103b10..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1" ?>
-    <!DOCTYPE package SYSTEM "http://pear.php.net/dtd/package-1.0">
-    <package version="1.0">
-      <name>pkg1</name>
-      <summary>required test for PEAR_Installer</summary>
-      <description>
-        fake package
-      </description>
-      <license>PHP License</license>
-      <maintainers>
-        <maintainer>
-          <user>fakeuser</user>
-          <name>Joe Shmoe</name>
-          <email>nobody@example.com</email>
-          <role>lead</role>
-        </maintainer>
-      </maintainers>
-      <release>
-        <version>1.1</version>
-        <date>2003-09-09</date>
-        <state>stable</state>
-        <notes>
-                       required dependency test
-        </notes>
-               <deps>
-                <dep type="pkg" version="1.0" rel="ge">pkg2</dep>
-               </deps>
-        <filelist>
-          <dir name="/" baseinstalldir="grob" role="php">
-            <file>zoorb.php</file>
-            <dir name="goompness" role="php">
-              <file>oggbrzitzkee.php</file>
-              <file>Mopreeb.php</file>
-            </dir>
-          </dir>
-        </filelist>
-      </release>
-   </package>
diff --git a/pear/tests/common_sortPkgDeps2_package.xml b/pear/tests/common_sortPkgDeps2_package.xml
deleted file mode 100644 (file)
index 3e7c038..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1" ?>
-    <!DOCTYPE package SYSTEM "http://pear.php.net/dtd/package-1.0">
-    <package version="1.0">
-      <name>pkg2</name>
-      <summary>required test for PEAR_Installer</summary>
-      <description>
-        fake package
-      </description>
-      <license>PHP License</license>
-      <maintainers>
-        <maintainer>
-          <user>fakeuser</user>
-          <name>Joe Shmoe</name>
-          <email>nobody@example.com</email>
-          <role>lead</role>
-        </maintainer>
-      </maintainers>
-      <release>
-        <version>1.1</version>
-        <date>2003-09-09</date>
-        <state>stable</state>
-        <notes>
-                       required dependency test
-        </notes>
-               <deps>
-                <dep type="pkg" version="1.0" rel="ge">pkg3</dep>
-                <dep type="php" version="1.0" rel="ge" />
-               </deps>
-        <filelist>
-          <dir name="/" baseinstalldir="grob" role="php">
-            <file>zoorb.php</file>
-            <dir name="goompness" role="php">
-              <file>oggbrzitzkee.php</file>
-              <file>Mopreeb.php</file>
-            </dir>
-          </dir>
-        </filelist>
-      </release>
-   </package>
diff --git a/pear/tests/common_sortPkgDeps3_package.xml b/pear/tests/common_sortPkgDeps3_package.xml
deleted file mode 100644 (file)
index 830a94c..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1" ?>
-    <!DOCTYPE package SYSTEM "http://pear.php.net/dtd/package-1.0">
-    <package version="1.0">
-      <name>pkg3</name>
-      <summary>required test for PEAR_Installer</summary>
-      <description>
-        fake package
-      </description>
-      <license>PHP License</license>
-      <maintainers>
-        <maintainer>
-          <user>fakeuser</user>
-          <name>Joe Shmoe</name>
-          <email>nobody@example.com</email>
-          <role>lead</role>
-        </maintainer>
-      </maintainers>
-      <release>
-        <version>1.1</version>
-        <date>2003-09-09</date>
-        <state>stable</state>
-        <notes>
-                       required dependency test
-        </notes>
-               <deps>
-                <dep type="pkg" version="1.0" rel="ge">pkg4</dep>
-                <dep type="pkg" version="1.0" rel="ge">pkg5</dep>
-               </deps>
-        <filelist>
-          <dir name="/" baseinstalldir="grob" role="php">
-            <file>zoorb.php</file>
-            <dir name="goompness" role="php">
-              <file>oggbrzitzkee.php</file>
-              <file>Mopreeb.php</file>
-            </dir>
-          </dir>
-        </filelist>
-      </release>
-   </package>
diff --git a/pear/tests/common_sortPkgDeps4_package.xml b/pear/tests/common_sortPkgDeps4_package.xml
deleted file mode 100644 (file)
index ff3394e..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1" ?>
-    <!DOCTYPE package SYSTEM "http://pear.php.net/dtd/package-1.0">
-    <package version="1.0">
-      <name>pkg4</name>
-      <summary>required test for PEAR_Installer</summary>
-      <description>
-        fake package
-      </description>
-      <license>PHP License</license>
-      <maintainers>
-        <maintainer>
-          <user>fakeuser</user>
-          <name>Joe Shmoe</name>
-          <email>nobody@example.com</email>
-          <role>lead</role>
-        </maintainer>
-      </maintainers>
-      <release>
-        <version>1.1</version>
-        <date>2003-09-09</date>
-        <state>stable</state>
-        <notes>
-                       required dependency test
-        </notes>
-               <deps>
-                <dep type="pkg" version="1.0" rel="ge">pkg6</dep>
-               </deps>
-        <filelist>
-          <dir name="/" baseinstalldir="grob" role="php">
-            <file>zoorb.php</file>
-            <dir name="goompness" role="php">
-              <file>oggbrzitzkee.php</file>
-              <file>Mopreeb.php</file>
-            </dir>
-          </dir>
-        </filelist>
-      </release>
-   </package>
diff --git a/pear/tests/common_sortPkgDeps5_package.xml b/pear/tests/common_sortPkgDeps5_package.xml
deleted file mode 100644 (file)
index 6dea22f..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1" ?>
-    <!DOCTYPE package SYSTEM "http://pear.php.net/dtd/package-1.0">
-    <package version="1.0">
-      <name>pkg5</name>
-      <summary>required test for PEAR_Installer</summary>
-      <description>
-        fake package
-      </description>
-      <license>PHP License</license>
-      <maintainers>
-        <maintainer>
-          <user>fakeuser</user>
-          <name>Joe Shmoe</name>
-          <email>nobody@example.com</email>
-          <role>lead</role>
-        </maintainer>
-      </maintainers>
-      <release>
-        <version>1.1</version>
-        <date>2003-09-09</date>
-        <state>stable</state>
-        <notes>
-                       required dependency test
-        </notes>
-               <deps>
-                <dep type="pkg" version="1.0" rel="ge">pkg6</dep>
-               </deps>
-        <filelist>
-          <dir name="/" baseinstalldir="grob" role="php">
-            <file>zoorb.php</file>
-            <dir name="goompness" role="php">
-              <file>oggbrzitzkee.php</file>
-              <file>Mopreeb.php</file>
-            </dir>
-          </dir>
-        </filelist>
-      </release>
-   </package>
diff --git a/pear/tests/common_sortPkgDeps6_package.xml b/pear/tests/common_sortPkgDeps6_package.xml
deleted file mode 100644 (file)
index a196e70..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1" ?>
-    <!DOCTYPE package SYSTEM "http://pear.php.net/dtd/package-1.0">
-    <package version="1.0">
-      <name>pkg6</name>
-      <summary>required test for PEAR_Installer</summary>
-      <description>
-        fake package
-      </description>
-      <license>PHP License</license>
-      <maintainers>
-        <maintainer>
-          <user>fakeuser</user>
-          <name>Joe Shmoe</name>
-          <email>nobody@example.com</email>
-          <role>lead</role>
-        </maintainer>
-      </maintainers>
-      <release>
-        <version>1.1</version>
-        <date>2003-09-09</date>
-        <state>stable</state>
-        <notes>
-                       required dependency test
-        </notes>
-        <filelist>
-          <dir name="/" baseinstalldir="grob" role="php">
-            <file>zoorb.php</file>
-            <dir name="goompness" role="php">
-              <file>oggbrzitzkee.php</file>
-              <file>Mopreeb.php</file>
-            </dir>
-          </dir>
-        </filelist>
-      </release>
-   </package>
diff --git a/pear/tests/dirtree/multiplepackages/pkg1file.php b/pear/tests/dirtree/multiplepackages/pkg1file.php
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/pear/tests/dirtree/multiplepackages/pkg2file.php b/pear/tests/dirtree/multiplepackages/pkg2file.php
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/pear/tests/dirtree/nestedroot/emptydir/fakefile1.php b/pear/tests/dirtree/nestedroot/emptydir/fakefile1.php
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/pear/tests/dirtree/nestedroot/emptydir/nesteddir/nestedfile.php b/pear/tests/dirtree/nestedroot/emptydir/nesteddir/nestedfile.php
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/pear/tests/dirtree/nestedroot/rootfile.php b/pear/tests/dirtree/nestedroot/rootfile.php
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/pear/tests/dirtree/package-fail.xml b/pear/tests/dirtree/package-fail.xml
deleted file mode 100644 (file)
index f2bf6f1..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1" ?>
-    <!DOCTYPE package SYSTEM "http://pear.php.net/dtd/package-1.0">
-    <package version="1.0">
-      <name>pkg2</name>
-      <summary>required test for PEAR_Installer</summary>
-      <description>
-        fake package
-      </description>
-      <license>PHP License</license>
-      <maintainers>
-        <maintainer>
-          <user>fakeuser</user>
-          <name>Joe Shmoe</name>
-          <email>nobody@example.com</email>
-          <role>lead</role>
-        </maintainer>
-      </maintainers>
-      <release>
-        <version>1.0</version>
-        <date>2003-12-11</date>
-        <state>stable</state>
-        <notes>
-                       second package
-        </notes>
-        <filelist>
-          <dir name="/" baseinstalldir="test" role="php">
-                  <dir name="multiplepackages" role="php">
-            <file>pkg2file.php</file>
-                  </dir>
-                  <dir name="nestedroot" role="php">
-            <file>rootfile.php</file>
-                       <dir name="emptydir" role="php">
-                        <dir name="nesteddir" role="php">
-                         <file>nestedfile.php</file>
-                         <file>doesntexist.php</file>
-                        </dir>
-                       </dir>
-                  </dir>
-          </dir>
-        </filelist>
-      </release>
-   </package>
diff --git a/pear/tests/dirtree/package.xml b/pear/tests/dirtree/package.xml
deleted file mode 100644 (file)
index 8ba556e..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1" ?>
-    <!DOCTYPE package SYSTEM "http://pear.php.net/dtd/package-1.0">
-    <package version="1.0">
-      <name>pkg1</name>
-      <summary>required test for PEAR_Installer</summary>
-      <description>
-        fake package
-      </description>
-      <license>PHP License</license>
-      <maintainers>
-        <maintainer>
-          <user>fakeuser</user>
-          <name>Joe Shmoe</name>
-          <email>nobody@example.com</email>
-          <role>lead</role>
-        </maintainer>
-      </maintainers>
-      <release>
-        <version>1.0</version>
-        <date>2003-12-11</date>
-        <state>stable</state>
-        <notes>
-                       first package
-        </notes>
-        <filelist>
-          <dir name="/" baseinstalldir="test" role="php">
-                  <dir name="multiplepackages" role="php">
-            <file>pkg1file.php</file>
-                  </dir>
-                  <dir name="pkg1" role="php">
-            <file>randomfile.php</file>
-                  </dir>
-          </dir>
-        </filelist>
-      </release>
-   </package>
diff --git a/pear/tests/dirtree/package2.xml b/pear/tests/dirtree/package2.xml
deleted file mode 100644 (file)
index c0bde59..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1" ?>
-    <!DOCTYPE package SYSTEM "http://pear.php.net/dtd/package-1.0">
-    <package version="1.0">
-      <name>pkg2</name>
-      <summary>required test for PEAR_Installer</summary>
-      <description>
-        fake package
-      </description>
-      <license>PHP License</license>
-      <maintainers>
-        <maintainer>
-          <user>fakeuser</user>
-          <name>Joe Shmoe</name>
-          <email>nobody@example.com</email>
-          <role>lead</role>
-        </maintainer>
-      </maintainers>
-      <release>
-        <version>1.0</version>
-        <date>2003-12-11</date>
-        <state>stable</state>
-        <notes>
-                       second package
-        </notes>
-        <filelist>
-          <dir name="/" baseinstalldir="test" role="php">
-                  <dir name="multiplepackages" role="php">
-            <file>pkg2file.php</file>
-                  </dir>
-                  <dir name="nestedroot" role="php">
-            <file>rootfile.php</file>
-                       <dir name="emptydir" role="php">
-                        <dir name="nesteddir" role="php">
-                         <file>nestedfile.php</file>
-                        </dir>
-                       </dir>
-                  </dir>
-          </dir>
-        </filelist>
-      </release>
-   </package>
diff --git a/pear/tests/dirtree/pkg1-1.0.tgz b/pear/tests/dirtree/pkg1-1.0.tgz
deleted file mode 100644 (file)
index ab305f7..0000000
Binary files a/pear/tests/dirtree/pkg1-1.0.tgz and /dev/null differ
diff --git a/pear/tests/dirtree/pkg2-1.0.tgz b/pear/tests/dirtree/pkg2-1.0.tgz
deleted file mode 100644 (file)
index 18bc9d2..0000000
Binary files a/pear/tests/dirtree/pkg2-1.0.tgz and /dev/null differ
diff --git a/pear/tests/merge.input b/pear/tests/merge.input
deleted file mode 100644 (file)
index 440106e..0000000
+++ /dev/null
@@ -1 +0,0 @@
-a:1:{s:7:"verbose";i:100;}
\ No newline at end of file
diff --git a/pear/tests/pear1.phpt b/pear/tests/pear1.phpt
deleted file mode 100644 (file)
index 400a97e..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
---TEST--
-PEAR constructor/destructor test
---SKIPIF--
-<?php
-if (!getenv('PHP_PEAR_RUNTESTS')) {
-    echo 'skip';
-}
-?>
---FILE--
-<?php
-
-require_once "PEAR.php";
-
-class TestPEAR extends PEAR {
-    function TestPEAR($name) {
-        $this->_debug = true;
-        $this->name = $name;
-        $this->PEAR();
-    }
-    function _TestPEAR() {
-        print "This is the TestPEAR($this->name) destructor\n";
-        $this->_PEAR();
-    }
-}
-
-class Test2 extends PEAR {
-    function _Test2() {
-        print "This is the Test2 destructor\n";
-        $this->_PEAR();
-    }
-}
-
-class Test3 extends Test2 {
-}
-
-// test for bug http://bugs.php.net/bug.php?id=14744
-class Other extends Pear {
-
-    var $a = 'default value';
-
-    function Other() {
-        $this->PEAR();
-    }
-
-    function _Other() {
-        // $a was modified but here misteriously returns to be
-        // the original value. That makes the destructor useless
-        // The correct value for $a in the destructor shoud be "new value"
-        echo "#bug 14744# Other class destructor: other->a == '" . $this->a ."'\n";
-    }
-}
-
-print "testing plain destructors\n";
-$o = new TestPEAR("test1");
-$p = new TestPEAR("test2");
-print "..\n";
-print "testing inherited destructors\n";
-$q = new Test3;
-
-echo "...\ntesting bug #14744\n";
-$other =& new Other;
-echo "#bug 14744# Other class constructor: other->a == '" . $other->a ."'\n";
-// Modify $a
-$other->a = 'new value';
-echo "#bug 14744# Other class modified: other->a == '" . $other->a ."'\n";
-
-print "..\n";
-print "script exiting...\n";
-print "..\n";
-
-?>
---GET--
---POST--
---EXPECT--
-testing plain destructors
-PEAR constructor called, class=testpear
-PEAR constructor called, class=testpear
-..
-testing inherited destructors
-...
-testing bug #14744
-#bug 14744# Other class constructor: other->a == 'default value'
-#bug 14744# Other class modified: other->a == 'new value'
-..
-script exiting...
-..
-This is the TestPEAR(test1) destructor
-PEAR destructor called, class=testpear
-This is the TestPEAR(test2) destructor
-PEAR destructor called, class=testpear
-This is the Test2 destructor
-#bug 14744# Other class destructor: other->a == 'new value'
diff --git a/pear/tests/pear2.phpt b/pear/tests/pear2.phpt
deleted file mode 100644 (file)
index a0174a1..0000000
+++ /dev/null
@@ -1,852 +0,0 @@
---TEST--
-PEAR complete set/push/pop error-handling test (run from pear/tests dir)
---SKIPIF--
-<?php
-if (!getenv('PHP_PEAR_RUNTESTS')) {
-    echo 'skip';
-}
-?>
---FILE--
-<?php
-
-require_once "PEAR.php";
-
-class testErrorHandlingStatic {
-    function doSetErrorHandlingFunction()
-    {
-        print "testing in class setErrorHandling\n";
-        PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'get_error_mode');
-        echoPEARVars('_PEAR_default_error_mode', $GLOBALS['_PEAR_default_error_mode'],
-                     '_PEAR_default_error_options', $GLOBALS['_PEAR_default_error_options']);
-    }
-    
-    function doSetErrorHandlingStatic()
-    {
-        print "testing in class setErrorHandling array(obj, method)\n";
-        $obj = new testErrorHandlingPEAR;
-        PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, array(&$obj, 'fakeHandleError'));
-        echoPEARVars('_PEAR_default_error_mode', $GLOBALS['_PEAR_default_error_mode'],
-                     '_PEAR_default_error_options', $GLOBALS['_PEAR_default_error_options']);
-    }
-    
-    function doSetErrorHandlingObject()
-    {
-        print "testing in class setErrorHandling array(class, method)\n";
-        PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, array('testErrorHandlingStatic', 'fakeHandleError'));
-        echoPEARVars('_PEAR_default_error_mode', $GLOBALS['_PEAR_default_error_mode'],
-                     '_PEAR_default_error_options', $GLOBALS['_PEAR_default_error_options']);
-    }
-
-    function doPushErrorHandlingFunction()
-    {
-        print "testing in class pushErrorHandling\n";
-        PEAR::pushErrorHandling(PEAR_ERROR_CALLBACK, 'get_error_mode');
-        echoPEARStack('_PEAR_error_handler_stack', $GLOBALS['_PEAR_error_handler_stack']);
-    }
-    
-    function doPushErrorHandlingObject()
-    {
-        print "testing in class pushErrorHandling array(obj, method)\n";
-        $obj = new testErrorHandlingPEAR;
-        PEAR::pushErrorHandling(PEAR_ERROR_CALLBACK, array(&$obj, 'fakeHandleError'));
-        echoPEARStack('_PEAR_error_handler_stack', $GLOBALS['_PEAR_error_handler_stack']);
-    }
-    
-    function doPushErrorHandlingStatic()
-    {
-        print "testing in class pushErrorHandling array(class, method)\n";
-        PEAR::pushErrorHandling(PEAR_ERROR_CALLBACK, array('testErrorHandlingStatic', 'fakeHandleError'));
-        echoPEARStack('_PEAR_error_handler_stack', $GLOBALS['_PEAR_error_handler_stack']);
-    }
-    
-    function doPopErrorHandling()
-    {
-        print "testing in class popErrorHandling\n";
-        PEAR::popErrorHandling();
-        echoPEARStack('_PEAR_error_handler_stack', $GLOBALS['_PEAR_error_handler_stack']);
-    }
-    
-    function fakeHandleError($err)
-    {
-    }
-}
-
-class testErrorHandlingPEAR extends PEAR {
-    
-    function fakeHandleError($err)
-    {
-    }
-
-    function doSetErrorHandlingFunction()
-    {
-        print "testing in PEAR setErrorHandling\n";
-        PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'get_error_mode');
-        echoPEARVars('_PEAR_default_error_mode', $GLOBALS['_PEAR_default_error_mode'],
-                     '_PEAR_default_error_options', $GLOBALS['_PEAR_default_error_options']);
-        echoPEARVars('$this->_default_error_mode', $this->_default_error_mode,
-                     '$this->_default_error_options', $this->_default_error_options);
-    }
-    
-    function doSetErrorHandlingStatic()
-    {
-        print "testing in PEAR setErrorHandling array(obj, method)\n";
-        $obj = new testErrorHandlingPEAR;
-        PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, array(&$obj, 'fakeHandleError'));
-        echoPEARVars('_PEAR_default_error_mode', $GLOBALS['_PEAR_default_error_mode'],
-                     '_PEAR_default_error_options', $GLOBALS['_PEAR_default_error_options']);
-        echoPEARVars('$this->_default_error_mode', $this->_default_error_mode,
-                     '$this->_default_error_options', $this->_default_error_options);
-    }
-    
-    function doSetErrorHandlingObject()
-    {
-        print "testing in PEAR setErrorHandling array(class, method)\n";
-        PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, array('testErrorHandlingStatic', 'fakeHandleError'));
-        echoPEARVars('_PEAR_default_error_mode', $GLOBALS['_PEAR_default_error_mode'],
-                     '_PEAR_default_error_options', $GLOBALS['_PEAR_default_error_options']);
-        echoPEARVars('$this->_default_error_mode', $this->_default_error_mode,
-                     '$this->_default_error_options', $this->_default_error_options);
-    }
-
-    function doPushErrorHandlingFunction()
-    {
-        print "testing in PEAR pushErrorHandling\n";
-        PEAR::pushErrorHandling(PEAR_ERROR_CALLBACK, 'get_error_mode');
-        echoPEARStack('_PEAR_error_handler_stack', $GLOBALS['_PEAR_error_handler_stack']);
-    }
-    
-    function doPushErrorHandlingObject()
-    {
-        print "testing in PEAR pushErrorHandling array(obj, method)\n";
-        $obj = new testErrorHandlingPEAR;
-        PEAR::pushErrorHandling(PEAR_ERROR_CALLBACK, array(&$obj, 'fakeHandleError'));
-        echoPEARStack('_PEAR_error_handler_stack', $GLOBALS['_PEAR_error_handler_stack']);
-    }
-    
-    function doPushErrorHandlingStatic()
-    {
-        print "testing in PEAR pushErrorHandling array(class, method)\n";
-        PEAR::pushErrorHandling(PEAR_ERROR_CALLBACK, array('testErrorHandlingStatic', 'fakeHandleError'));
-        echoPEARStack('_PEAR_error_handler_stack', $GLOBALS['_PEAR_error_handler_stack']);
-    }
-    
-    function doPopErrorHandling()
-    {
-        print "testing in PEAR popErrorHandling\n";
-        PEAR::popErrorHandling();
-        echoPEARStack('_PEAR_error_handler_stack', $GLOBALS['_PEAR_error_handler_stack']);
-    }
-}
-
-function echoPEARVars($name1, $mode, $name2, $options, $indent = '')
-{
-    $levelMap = 
-        array(
-            E_USER_NOTICE => 'E_USER_NOTICE',
-            E_USER_WARNING => 'E_USER_WARNING',
-            E_USER_ERROR => 'E_USER_ERROR',
-        );
-    $pearLevelMap =
-        array(
-            PEAR_ERROR_RETURN =>'PEAR_ERROR_RETURN',
-            PEAR_ERROR_PRINT =>'PEAR_ERROR_PRINT',
-            PEAR_ERROR_TRIGGER =>'PEAR_ERROR_TRIGGER',
-            PEAR_ERROR_DIE =>'PEAR_ERROR_DIE',
-            PEAR_ERROR_CALLBACK =>'PEAR_ERROR_CALLBACK',
-            PEAR_ERROR_EXCEPTION =>'PEAR_ERROR_EXCEPTION',
-        );
-    print $indent . "echoing PEAR error-handling Variables:\n";
-    print "$indent--------------------------------------\n";
-    print $indent . "$name1:\n";
-    $levels = get_error_mode($mode);
-    print $indent;
-    foreach($levels as $level) {
-        print $pearLevelMap[$level] . ',';
-    }
-    print "\n";
-    print $indent . "$name2:\n";
-    if (is_string($options)) {
-        print $indent . 'Callback: ' . $options. "()\n";
-    } elseif (is_array($options)) {
-        print $indent . 'Callback: ';
-        if (is_string($options[0])) {
-            print '(static) ' . $options[0] . '::';
-        } else {
-            print get_class($options[0]) . '->';
-        }
-        print $options[1] . "()\n";
-    } else {
-        print $indent . $levelMap[$options] . "\n";
-    }
-    print "$indent--------------------------------------\n";
-}
-
-function echoPEARStack($name, $stack)
-{
-    print "stack $name:\n";
-    foreach ($stack as $i =>  $item) {
-        print "Index $i:\n";
-        echoPEARVars('mode', $item[0], 'options', $item[1], '    ');
-    }
-}
-
-function get_error_mode($err)
-{
-    $ret = array();
-    $level = 0;
-    while($level < 7) {
-        $a = ($err >> $level++) & 1;
-        if ($a) {
-            $ret[] = 1 << ($level - 1);
-        }
-    }
-    return $ret;
-}
-print "testing static error-handling global code\n";
-echoPEARVars('_PEAR_default_error_mode', $GLOBALS['_PEAR_default_error_mode'],
-             '_PEAR_default_error_options', $GLOBALS['_PEAR_default_error_options']);
-print "testing setErrorHandling\n";
-PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'get_error_mode');
-echoPEARVars('_PEAR_default_error_mode', $GLOBALS['_PEAR_default_error_mode'],
-             '_PEAR_default_error_options', $GLOBALS['_PEAR_default_error_options']);
-print "testing setErrorHandling array(obj, method)\n";
-$obj = new testErrorHandlingPEAR;
-PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, array(&$obj, 'fakeHandleError'));
-echoPEARVars('_PEAR_default_error_mode', $GLOBALS['_PEAR_default_error_mode'],
-             '_PEAR_default_error_options', $GLOBALS['_PEAR_default_error_options']);
-print "testing setErrorHandling array(class, method)\n";
-PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, array('testErrorHandlingStatic', 'fakeHandleError'));
-echoPEARVars('_PEAR_default_error_mode', $GLOBALS['_PEAR_default_error_mode'],
-             '_PEAR_default_error_options', $GLOBALS['_PEAR_default_error_options']);
-
-
-print "testing pushErrorHandling\n";
-PEAR::pushErrorHandling(PEAR_ERROR_CALLBACK, 'get_error_mode');
-echoPEARStack('_PEAR_error_handler_stack', $GLOBALS['_PEAR_error_handler_stack']);
-print "testing pushErrorHandling array(obj, method)\n";
-$obj = new testErrorHandlingPEAR;
-PEAR::pushErrorHandling(PEAR_ERROR_CALLBACK, array(&$obj, 'fakeHandleError'));
-echoPEARStack('_PEAR_error_handler_stack', $GLOBALS['_PEAR_error_handler_stack']);
-print "testing pushErrorHandling array(class, method)\n";
-PEAR::pushErrorHandling(PEAR_ERROR_CALLBACK, array('testErrorHandlingStatic', 'fakeHandleError'));
-echoPEARStack('_PEAR_error_handler_stack', $GLOBALS['_PEAR_error_handler_stack']);
-
-
-print "testing popErrorHandling\n";
-PEAR::popErrorHandling();
-echoPEARStack('_PEAR_error_handler_stack', $GLOBALS['_PEAR_error_handler_stack']);
-print "testing popErrorHandling\n";
-$obj = new testErrorHandlingPEAR;
-PEAR::popErrorHandling();
-echoPEARStack('_PEAR_error_handler_stack', $GLOBALS['_PEAR_error_handler_stack']);
-print "testing popErrorHandling\n";
-PEAR::popErrorHandling();
-echoPEARStack('_PEAR_error_handler_stack', $GLOBALS['_PEAR_error_handler_stack']);
-print "*******************************************\n";
-print "testing static error-handling in-class code\n";
-print "*******************************************\n";
-PEAR::setErrorHandling(PEAR_ERROR_RETURN, E_USER_NOTICE);
-$obj = new testErrorHandlingStatic;
-$obj->doSetErrorHandlingFunction();
-$obj->doSetErrorHandlingStatic();
-$obj->doSetErrorHandlingObject();
-$obj->doPushErrorHandlingFunction();
-$obj->doPushErrorHandlingStatic();
-$obj->doPushErrorHandlingObject();
-$obj->doPopErrorHandling();
-$obj->doPopErrorHandling();
-$obj->doPopErrorHandling();
-print "*******************************************\n";
-print "testing non-static error-handling in-class code\n";
-print "*******************************************\n";
-PEAR::setErrorHandling(PEAR_ERROR_RETURN, E_USER_NOTICE);
-$obj = new testErrorHandlingPEAR;
-$obj->doSetErrorHandlingFunction();
-$obj->doSetErrorHandlingStatic();
-$obj->doSetErrorHandlingObject();
-$obj->doPushErrorHandlingFunction();
-$obj->doPushErrorHandlingStatic();
-$obj->doPushErrorHandlingObject();
-$obj->doPopErrorHandling();
-$obj->doPopErrorHandling();
-$obj->doPopErrorHandling();
-
-?>
---GET--
---POST--
---EXPECT--
-testing static error-handling global code
-echoing PEAR error-handling Variables:
---------------------------------------
-_PEAR_default_error_mode:
-PEAR_ERROR_RETURN,
-_PEAR_default_error_options:
-E_USER_NOTICE
---------------------------------------
-testing setErrorHandling
-echoing PEAR error-handling Variables:
---------------------------------------
-_PEAR_default_error_mode:
-PEAR_ERROR_CALLBACK,
-_PEAR_default_error_options:
-Callback: get_error_mode()
---------------------------------------
-testing setErrorHandling array(obj, method)
-echoing PEAR error-handling Variables:
---------------------------------------
-_PEAR_default_error_mode:
-PEAR_ERROR_CALLBACK,
-_PEAR_default_error_options:
-Callback: testerrorhandlingpear->fakeHandleError()
---------------------------------------
-testing setErrorHandling array(class, method)
-echoing PEAR error-handling Variables:
---------------------------------------
-_PEAR_default_error_mode:
-PEAR_ERROR_CALLBACK,
-_PEAR_default_error_options:
-Callback: (static) testErrorHandlingStatic::fakeHandleError()
---------------------------------------
-testing pushErrorHandling
-stack _PEAR_error_handler_stack:
-Index 0:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: (static) testErrorHandlingStatic::fakeHandleError()
-    --------------------------------------
-Index 1:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: get_error_mode()
-    --------------------------------------
-testing pushErrorHandling array(obj, method)
-stack _PEAR_error_handler_stack:
-Index 0:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: (static) testErrorHandlingStatic::fakeHandleError()
-    --------------------------------------
-Index 1:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: get_error_mode()
-    --------------------------------------
-Index 2:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: get_error_mode()
-    --------------------------------------
-Index 3:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: testerrorhandlingpear->fakeHandleError()
-    --------------------------------------
-testing pushErrorHandling array(class, method)
-stack _PEAR_error_handler_stack:
-Index 0:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: (static) testErrorHandlingStatic::fakeHandleError()
-    --------------------------------------
-Index 1:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: get_error_mode()
-    --------------------------------------
-Index 2:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: get_error_mode()
-    --------------------------------------
-Index 3:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: testerrorhandlingpear->fakeHandleError()
-    --------------------------------------
-Index 4:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: testerrorhandlingpear->fakeHandleError()
-    --------------------------------------
-Index 5:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: (static) testErrorHandlingStatic::fakeHandleError()
-    --------------------------------------
-testing popErrorHandling
-stack _PEAR_error_handler_stack:
-Index 0:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: (static) testErrorHandlingStatic::fakeHandleError()
-    --------------------------------------
-Index 1:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: get_error_mode()
-    --------------------------------------
-Index 2:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: get_error_mode()
-    --------------------------------------
-Index 3:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: testerrorhandlingpear->fakeHandleError()
-    --------------------------------------
-testing popErrorHandling
-stack _PEAR_error_handler_stack:
-Index 0:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: (static) testErrorHandlingStatic::fakeHandleError()
-    --------------------------------------
-Index 1:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: get_error_mode()
-    --------------------------------------
-testing popErrorHandling
-stack _PEAR_error_handler_stack:
-*******************************************
-testing static error-handling in-class code
-*******************************************
-testing in class setErrorHandling
-echoing PEAR error-handling Variables:
---------------------------------------
-_PEAR_default_error_mode:
-PEAR_ERROR_CALLBACK,
-_PEAR_default_error_options:
-Callback: get_error_mode()
---------------------------------------
-testing in class setErrorHandling array(obj, method)
-echoing PEAR error-handling Variables:
---------------------------------------
-_PEAR_default_error_mode:
-PEAR_ERROR_CALLBACK,
-_PEAR_default_error_options:
-Callback: testerrorhandlingpear->fakeHandleError()
---------------------------------------
-testing in class setErrorHandling array(class, method)
-echoing PEAR error-handling Variables:
---------------------------------------
-_PEAR_default_error_mode:
-PEAR_ERROR_CALLBACK,
-_PEAR_default_error_options:
-Callback: (static) testErrorHandlingStatic::fakeHandleError()
---------------------------------------
-testing in class pushErrorHandling
-stack _PEAR_error_handler_stack:
-Index 0:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: (static) testErrorHandlingStatic::fakeHandleError()
-    --------------------------------------
-Index 1:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: get_error_mode()
-    --------------------------------------
-testing in class pushErrorHandling array(class, method)
-stack _PEAR_error_handler_stack:
-Index 0:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: (static) testErrorHandlingStatic::fakeHandleError()
-    --------------------------------------
-Index 1:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: get_error_mode()
-    --------------------------------------
-Index 2:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: get_error_mode()
-    --------------------------------------
-Index 3:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: (static) testErrorHandlingStatic::fakeHandleError()
-    --------------------------------------
-testing in class pushErrorHandling array(obj, method)
-stack _PEAR_error_handler_stack:
-Index 0:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: (static) testErrorHandlingStatic::fakeHandleError()
-    --------------------------------------
-Index 1:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: get_error_mode()
-    --------------------------------------
-Index 2:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: get_error_mode()
-    --------------------------------------
-Index 3:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: (static) testErrorHandlingStatic::fakeHandleError()
-    --------------------------------------
-Index 4:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: (static) testErrorHandlingStatic::fakeHandleError()
-    --------------------------------------
-Index 5:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: testerrorhandlingpear->fakeHandleError()
-    --------------------------------------
-testing in class popErrorHandling
-stack _PEAR_error_handler_stack:
-Index 0:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: (static) testErrorHandlingStatic::fakeHandleError()
-    --------------------------------------
-Index 1:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: get_error_mode()
-    --------------------------------------
-Index 2:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: get_error_mode()
-    --------------------------------------
-Index 3:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: (static) testErrorHandlingStatic::fakeHandleError()
-    --------------------------------------
-testing in class popErrorHandling
-stack _PEAR_error_handler_stack:
-Index 0:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: (static) testErrorHandlingStatic::fakeHandleError()
-    --------------------------------------
-Index 1:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: get_error_mode()
-    --------------------------------------
-testing in class popErrorHandling
-stack _PEAR_error_handler_stack:
-*******************************************
-testing non-static error-handling in-class code
-*******************************************
-testing in PEAR setErrorHandling
-echoing PEAR error-handling Variables:
---------------------------------------
-_PEAR_default_error_mode:
-PEAR_ERROR_RETURN,
-_PEAR_default_error_options:
-E_USER_NOTICE
---------------------------------------
-echoing PEAR error-handling Variables:
---------------------------------------
-$this->_default_error_mode:
-PEAR_ERROR_CALLBACK,
-$this->_default_error_options:
-Callback: get_error_mode()
---------------------------------------
-testing in PEAR setErrorHandling array(obj, method)
-echoing PEAR error-handling Variables:
---------------------------------------
-_PEAR_default_error_mode:
-PEAR_ERROR_RETURN,
-_PEAR_default_error_options:
-E_USER_NOTICE
---------------------------------------
-echoing PEAR error-handling Variables:
---------------------------------------
-$this->_default_error_mode:
-PEAR_ERROR_CALLBACK,
-$this->_default_error_options:
-Callback: testerrorhandlingpear->fakeHandleError()
---------------------------------------
-testing in PEAR setErrorHandling array(class, method)
-echoing PEAR error-handling Variables:
---------------------------------------
-_PEAR_default_error_mode:
-PEAR_ERROR_RETURN,
-_PEAR_default_error_options:
-E_USER_NOTICE
---------------------------------------
-echoing PEAR error-handling Variables:
---------------------------------------
-$this->_default_error_mode:
-PEAR_ERROR_CALLBACK,
-$this->_default_error_options:
-Callback: (static) testErrorHandlingStatic::fakeHandleError()
---------------------------------------
-testing in PEAR pushErrorHandling
-stack _PEAR_error_handler_stack:
-Index 0:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: (static) testErrorHandlingStatic::fakeHandleError()
-    --------------------------------------
-Index 1:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: get_error_mode()
-    --------------------------------------
-testing in PEAR pushErrorHandling array(class, method)
-stack _PEAR_error_handler_stack:
-Index 0:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: (static) testErrorHandlingStatic::fakeHandleError()
-    --------------------------------------
-Index 1:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: get_error_mode()
-    --------------------------------------
-Index 2:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: get_error_mode()
-    --------------------------------------
-Index 3:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: (static) testErrorHandlingStatic::fakeHandleError()
-    --------------------------------------
-testing in PEAR pushErrorHandling array(obj, method)
-stack _PEAR_error_handler_stack:
-Index 0:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: (static) testErrorHandlingStatic::fakeHandleError()
-    --------------------------------------
-Index 1:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: get_error_mode()
-    --------------------------------------
-Index 2:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: get_error_mode()
-    --------------------------------------
-Index 3:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: (static) testErrorHandlingStatic::fakeHandleError()
-    --------------------------------------
-Index 4:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: (static) testErrorHandlingStatic::fakeHandleError()
-    --------------------------------------
-Index 5:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: testerrorhandlingpear->fakeHandleError()
-    --------------------------------------
-testing in PEAR popErrorHandling
-stack _PEAR_error_handler_stack:
-Index 0:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: (static) testErrorHandlingStatic::fakeHandleError()
-    --------------------------------------
-Index 1:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: get_error_mode()
-    --------------------------------------
-Index 2:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: get_error_mode()
-    --------------------------------------
-Index 3:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: (static) testErrorHandlingStatic::fakeHandleError()
-    --------------------------------------
-testing in PEAR popErrorHandling
-stack _PEAR_error_handler_stack:
-Index 0:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: (static) testErrorHandlingStatic::fakeHandleError()
-    --------------------------------------
-Index 1:
-    echoing PEAR error-handling Variables:
-    --------------------------------------
-    mode:
-    PEAR_ERROR_CALLBACK,
-    options:
-    Callback: get_error_mode()
-    --------------------------------------
-testing in PEAR popErrorHandling
-stack _PEAR_error_handler_stack:
diff --git a/pear/tests/pear_autoloader.phpt b/pear/tests/pear_autoloader.phpt
deleted file mode 100644 (file)
index f25f4a4..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
---TEST--
-PEAR_Autoloader
---SKIPIF--
-skip
-<?php /*if (!extension_loaded("overload")) die("skip\n"); */ ?>
---FILE--
-<?php
-
-include dirname(__FILE__)."/../PEAR/Autoloader.php";
-
-class test1 extends PEAR_Autoloader {
-    function test1() {
-       $this->addAutoload(array(
-           'testfunc1' => 'testclass1',
-           'testfunca' => 'testclass1',
-           'testfunc2' => 'testclass2',
-           'testfuncb' => 'testclass2',
-       ));
-    }
-}
-
-class testclass1 {
-    function testfunc1($a) {
-       print "testfunc1 arg=";var_dump($a);
-       return 1;
-    }
-    function testfunca($a) {
-       print "testfunca arg=";var_dump($a);
-       return 2;
-    }
-}
-
-class testclass2 {
-    function testfunc2($b) {
-       print "testfunc2 arg=";var_dump($b);
-       return 3;
-    }
-    function testfuncb($b) {
-       print "testfuncb arg=";var_dump($b);
-       return 4;
-    }
-}
-
-function dump($obj) {
-    print "mapped methods:";
-    foreach ($obj->_method_map as $method => $object) {
-       print " $method";
-    }
-    print "\n";
-}
-
-function call($msg, $retval) {
-    print "calling $msg returned $retval\n";
-}
-
-$obj = new test1;
-dump($obj);
-call("testfunc1", $obj->testfunc1(2));
-dump($obj);
-call("testfunca", $obj->testfunca(2));
-dump($obj);
-call("testfunc2", $obj->testfunc2(2));
-dump($obj);
-call("testfuncb", $obj->testfuncb(2));
-dump($obj);
-
-?>
---EXPECT--
-mapped methods:
-testfunc1 arg=int(2)
-calling testfunc1 returned 1
-mapped methods: testfunc1 testfunca
-testfunca arg=int(2)
-calling testfunca returned 2
-mapped methods: testfunc1 testfunca
-testfunc2 arg=int(2)
-calling testfunc2 returned 3
-mapped methods: testfunc1 testfunca testfunc2 testfuncb
-testfuncb arg=int(2)
-calling testfuncb returned 4
-mapped methods: testfunc1 testfunca testfunc2 testfuncb
diff --git a/pear/tests/pear_common_analyzeSC.phpt b/pear/tests/pear_common_analyzeSC.phpt
deleted file mode 100644 (file)
index 720c1a6..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
---TEST--
-PEAR_Common::analyzeSourceCode test
---SKIPIF--
-<?php
-if (!getenv('PHP_PEAR_RUNTESTS')) {
-    echo 'skip';
-}
-if (!function_exists('token_get_all')) {
-    echo 'skip';
-}
-?>
---FILE--
-<?php
-
-require_once "PEAR/Common.php";
-
-$x = PEAR_Common::analyzeSourceCode('=+"\\//452');
-echo "first test: returns false with non-existing filename? ";
-echo $x ? "no\n" : "yes\n";
-
-$testdir = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'pear_common_analyzeSCtest';
-mkdir($testdir);
-
-$test1 = '
-<?php
-::error();
-?>
-';
-$fp = fopen($testdir . DIRECTORY_SEPARATOR . 'test1.php', 'w');
-fwrite($fp, $test1);
-fclose($fp);
-
-$ret = PEAR_Common::analyzeSourceCode($testdir . DIRECTORY_SEPARATOR . 'test1.php');
-echo "second test: returns false with invalid PHP? ";
-echo $ret ? "no\n" : "yes\n";
-unlink($testdir . DIRECTORY_SEPARATOR . 'test1.php');
-
-$test3 = '
-<?php
-class test
-{
-    class test2 {
-    }
-}
-?>
-';
-$fp = fopen($testdir . DIRECTORY_SEPARATOR . 'test3.php', 'w');
-fwrite($fp, $test3);
-fclose($fp);
-
-$ret = PEAR_Common::analyzeSourceCode($testdir . DIRECTORY_SEPARATOR . 'test3.php');
-echo "fourth test: returns false with invalid PHP? ";
-echo $ret ? "no\n" : "yes\n";
-unlink($testdir . DIRECTORY_SEPARATOR . 'test3.php');
-
-$test4 = '
-<?php
-function test()
-{
-    class test2 {
-    }
-}
-?>
-';
-$fp = fopen($testdir . DIRECTORY_SEPARATOR . 'test4.php', 'w');
-fwrite($fp, $test4);
-fclose($fp);
-
-$ret = PEAR_Common::analyzeSourceCode($testdir . DIRECTORY_SEPARATOR . 'test4.php');
-echo "fifth test: returns false with invalid PHP? ";
-echo $ret ? "no\n" : "yes\n";
-unlink($testdir . DIRECTORY_SEPARATOR . 'test4.php');
-
-$test5 = '
-<?php
-function test()
-{
-}
-
-if (trytofool) {
-    function fool()
-    {
-    }
-}
-class test2 {
-    function test2() {
-        parent::unused();
-        Greg::classes();
-        $a = new Pierre;
-    }
-}
-
-class blah extends test2 {
-    /**
-     * @nodep Stig
-     */
-    function blah() 
-    {
-        Stig::rules();
-    }
-}
-?>
-';
-$fp = fopen($testdir . DIRECTORY_SEPARATOR . 'test5.php', 'w');
-fwrite($fp, $test5);
-fclose($fp);
-
-$ret = PEAR_Common::analyzeSourceCode($testdir . DIRECTORY_SEPARATOR . 'test5.php');
-echo "sixth test: returns false with valid PHP? ";
-echo $ret ? "no\n" : "yes\n";
-var_dump($ret);
-unlink($testdir . DIRECTORY_SEPARATOR . 'test5.php');
-
-rmdir($testdir);
-?>
---GET--
---POST--
---EXPECT--
-first test: returns false with non-existing filename? yes
-second test: returns false with invalid PHP? yes
-fourth test: returns false with invalid PHP? yes
-fifth test: returns false with invalid PHP? yes
-sixth test: returns false with valid PHP? no
-array(5) {
-  ["declared_classes"]=>
-  array(2) {
-    [0]=>
-    string(5) "test2"
-    [1]=>
-    string(4) "blah"
-  }
-  ["declared_methods"]=>
-  array(2) {
-    ["test2"]=>
-    array(1) {
-      [0]=>
-      string(5) "test2"
-    }
-    ["blah"]=>
-    array(1) {
-      [0]=>
-      string(4) "blah"
-    }
-  }
-  ["declared_functions"]=>
-  array(2) {
-    [0]=>
-    string(4) "test"
-    [1]=>
-    string(4) "fool"
-  }
-  ["used_classes"]=>
-  array(2) {
-    [0]=>
-    string(4) "Greg"
-    [1]=>
-    string(6) "Pierre"
-  }
-  ["inheritance"]=>
-  array(1) {
-    ["blah"]=>
-    string(5) "test2"
-  }
-}
\ No newline at end of file
diff --git a/pear/tests/pear_common_buildProvidesArray.phpt b/pear/tests/pear_common_buildProvidesArray.phpt
deleted file mode 100644 (file)
index d76c350..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
---TEST--
-PEAR_Common::buildProvidesArray test
---SKIPIF--
-<?php
-if (!getenv('PHP_PEAR_RUNTESTS')) {
-    echo 'skip';
-}
-if (!function_exists('token_get_all')) {
-    echo 'skip';
-}
-?>
---FILE--
-<?php
-
-require_once "PEAR/Common.php";
-
-$testdir = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'pear_common_buildProvidesArraytest';
-mkdir($testdir);
-
-$test5 = '
-<?php
-function test()
-{
-}
-
-if (trytofool) {
-    function fool()
-    {
-    }
-}
-class test2 {
-    function test2() {
-        parent::unused();
-        Greg::classes();
-        $a = new Pierre;
-    }
-}
-
-class blah extends test2 {
-    /**
-     * @nodep Stig
-     */
-    function blah() 
-    {
-        Stig::rules();
-    }
-}
-?>
-';
-$fp = fopen($testdir . DIRECTORY_SEPARATOR . 'test5.php', 'w');
-fwrite($fp, $test5);
-fclose($fp);
-
-$ret = PEAR_Common::analyzeSourceCode($testdir . DIRECTORY_SEPARATOR . 'test5.php');
-echo "pre-test: returns false with valid PHP? ";
-echo $ret ? "no\n" : "yes\n";
-var_dump($ret);
-unlink($testdir . DIRECTORY_SEPARATOR . 'test5.php');
-$common = new PEAR_Common;
-$common->buildProvidesArray($ret);
-var_dump($common->pkginfo);
-rmdir($testdir);
-?>
---GET--
---POST--
---EXPECT--
-pre-test: returns false with valid PHP? no
-array(5) {
-  ["declared_classes"]=>
-  array(2) {
-    [0]=>
-    string(5) "test2"
-    [1]=>
-    string(4) "blah"
-  }
-  ["declared_methods"]=>
-  array(2) {
-    ["test2"]=>
-    array(1) {
-      [0]=>
-      string(5) "test2"
-    }
-    ["blah"]=>
-    array(1) {
-      [0]=>
-      string(4) "blah"
-    }
-  }
-  ["declared_functions"]=>
-  array(2) {
-    [0]=>
-    string(4) "test"
-    [1]=>
-    string(4) "fool"
-  }
-  ["used_classes"]=>
-  array(2) {
-    [0]=>
-    string(4) "Greg"
-    [1]=>
-    string(6) "Pierre"
-  }
-  ["inheritance"]=>
-  array(1) {
-    ["blah"]=>
-    string(5) "test2"
-  }
-}
-array(1) {
-  ["provides"]=>
-  array(4) {
-    ["class;test2"]=>
-    array(2) {
-      ["type"]=>
-      string(5) "class"
-      ["name"]=>
-      string(5) "test2"
-    }
-    ["class;blah"]=>
-    array(3) {
-      ["type"]=>
-      string(5) "class"
-      ["name"]=>
-      string(4) "blah"
-      ["extends"]=>
-      string(5) "test2"
-    }
-    ["function;test"]=>
-    array(2) {
-      ["type"]=>
-      string(8) "function"
-      ["name"]=>
-      string(4) "test"
-    }
-    ["function;fool"]=>
-    array(2) {
-      ["type"]=>
-      string(8) "function"
-      ["name"]=>
-      string(4) "fool"
-    }
-  }
-}
\ No newline at end of file
diff --git a/pear/tests/pear_common_downloadHttp.phpt b/pear/tests/pear_common_downloadHttp.phpt
deleted file mode 100644 (file)
index b11d904..0000000
+++ /dev/null
@@ -1,216 +0,0 @@
---TEST--
-PEAR_Common::downloadHttp test
---SKIPIF--
-<?php
-if (!getenv('PHP_PEAR_RUNTESTS')) {
-    echo 'skip';
-}
-$fp = @fsockopen('pear.php.net', 80);
-if (!$fp) {
-    echo 'skip';
-} else {
-    fclose($fp);
-}
-?>
---FILE--
-<?php
-mkdir($temp_path = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'testDownloadHttp');
-// make the fake configuration - we'll use one of these and it should work
-$config = serialize(array('master_server' => 'pear.php.net',
-    'php_dir' => $temp_path . DIRECTORY_SEPARATOR . 'php',
-    'ext_dir' => $temp_path . DIRECTORY_SEPARATOR . 'ext',
-    'data_dir' => $temp_path . DIRECTORY_SEPARATOR . 'data',
-    'doc_dir' => $temp_path . DIRECTORY_SEPARATOR . 'doc',
-    'test_dir' => $temp_path . DIRECTORY_SEPARATOR . 'test',
-    'bin_dir' => $temp_path . DIRECTORY_SEPARATOR . 'bin',));
-touch($temp_path . DIRECTORY_SEPARATOR . 'pear.conf');
-$fp = fopen($temp_path . DIRECTORY_SEPARATOR . 'pear.conf', 'w');
-fwrite($fp, $config);
-fclose($fp);
-touch($temp_path . DIRECTORY_SEPARATOR . 'pear.ini');
-$fp = fopen($temp_path . DIRECTORY_SEPARATOR . 'pear.ini', 'w');
-fwrite($fp, $config);
-fclose($fp);
-
-putenv('PHP_PEAR_SYSCONF_DIR=' . $temp_path);
-$home = getenv('HOME');
-if (!empty($home)) {
-    // for PEAR_Config initialization
-    putenv('HOME="'.$temp_path);
-}
-
-require_once "PEAR/Common.php";
-
-$common = &new PEAR_Common;
-
-PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'catchit');
-
-function catchit($err)
-{
-    echo "Caught error: " . $err->getMessage() . "\n";
-}
-
-echo "Test static:\n";
-
-echo "Simple: ";
-PEAR_Common::downloadHttp('http://test.pear.php.net/testdownload.tgz', $ui, $temp_path);
-$firstone = implode('', file(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'testdownload.tgz'));
-$secondone = implode('', file($temp_path . DIRECTORY_SEPARATOR . 'testdownload.tgz'));
-echo ($firstone == $secondone) ? "passed\n" : "failed\n";
-
-echo "Simple fail:\n";
-PEAR_Common::downloadHttp('http://test.poop.php.net/stuff.tgz', $ui, $temp_path);
-
-echo "Test callback:\n";
-
-$ui = 'My UI';
-
-PEAR_Common::downloadHttp('http://test.pear.php.net/testdownload.tgz', $ui, $temp_path, 'myCallback');
-$firstone = implode('', file(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'testdownload.tgz'));
-$secondone = implode('', file($temp_path . DIRECTORY_SEPARATOR . 'testdownload.tgz'));
-echo "Working Callback: ";
-echo ($firstone == $secondone) ? "passed\n" : "failed\n";
-
-
-function myCallback($message, $payload)
-{
-    $stuff = serialize($payload);
-    echo "Callback Message: $message\n";
-    echo "Callback Payload: $stuff\n";
-}
-
-echo "Callback fail:\n";
-PEAR_Common::downloadHttp('http://test.poop.php.net/stuff.tgz', $ui, $temp_path, 'myCallback');
-
-cleanall($temp_path);
-
-// ------------------------------------------------------------------------- //
-
-function cleanall($dir)
-{
-    $dp = opendir($dir);
-    while ($ent = readdir($dp)) {
-        if ($ent == '.' || $ent == '..') {
-            continue;
-        }
-        if (is_dir($dir . DIRECTORY_SEPARATOR . $ent)) {
-            cleanall($dir . DIRECTORY_SEPARATOR . $ent);
-        } else {
-            unlink($dir . DIRECTORY_SEPARATOR . $ent);
-        }
-    }
-    closedir($dp);
-    rmdir($dir);
-}
-?>
---GET--
---POST--
---EXPECT--
-Test static:
-Simple: passed
-Simple fail:
-Caught error: Connection to `test.poop.php.net:80' failed: The operation completed successfully.
-
-Test callback:
-Callback Message: setup
-Callback Payload: a:1:{i:0;s:5:"My UI";}
-Callback Message: message
-Callback Payload: s:35:"Using HTTP proxy test.pear.php.net:";
-Callback Message: saveas
-Callback Payload: s:16:"testdownload.tgz";
-Callback Message: start
-Callback Payload: a:2:{i:0;s:16:"testdownload.tgz";i:1;s:5:"41655";}
-Callback Message: bytesread
-Callback Payload: i:1024;
-Callback Message: bytesread
-Callback Payload: i:2048;
-Callback Message: bytesread
-Callback Payload: i:3072;
-Callback Message: bytesread
-Callback Payload: i:4096;
-Callback Message: bytesread
-Callback Payload: i:5120;
-Callback Message: bytesread
-Callback Payload: i:6144;
-Callback Message: bytesread
-Callback Payload: i:7168;
-Callback Message: bytesread
-Callback Payload: i:8192;
-Callback Message: bytesread
-Callback Payload: i:9216;
-Callback Message: bytesread
-Callback Payload: i:10240;
-Callback Message: bytesread
-Callback Payload: i:11264;
-Callback Message: bytesread
-Callback Payload: i:12288;
-Callback Message: bytesread
-Callback Payload: i:13312;
-Callback Message: bytesread
-Callback Payload: i:14336;
-Callback Message: bytesread
-Callback Payload: i:15360;
-Callback Message: bytesread
-Callback Payload: i:16384;
-Callback Message: bytesread
-Callback Payload: i:17408;
-Callback Message: bytesread
-Callback Payload: i:18432;
-Callback Message: bytesread
-Callback Payload: i:19456;
-Callback Message: bytesread
-Callback Payload: i:20480;
-Callback Message: bytesread
-Callback Payload: i:21504;
-Callback Message: bytesread
-Callback Payload: i:22528;
-Callback Message: bytesread
-Callback Payload: i:23552;
-Callback Message: bytesread
-Callback Payload: i:24576;
-Callback Message: bytesread
-Callback Payload: i:25600;
-Callback Message: bytesread
-Callback Payload: i:26624;
-Callback Message: bytesread
-Callback Payload: i:27648;
-Callback Message: bytesread
-Callback Payload: i:28672;
-Callback Message: bytesread
-Callback Payload: i:29696;
-Callback Message: bytesread
-Callback Payload: i:30720;
-Callback Message: bytesread
-Callback Payload: i:31744;
-Callback Message: bytesread
-Callback Payload: i:32768;
-Callback Message: bytesread
-Callback Payload: i:33792;
-Callback Message: bytesread
-Callback Payload: i:34816;
-Callback Message: bytesread
-Callback Payload: i:35840;
-Callback Message: bytesread
-Callback Payload: i:36864;
-Callback Message: bytesread
-Callback Payload: i:37888;
-Callback Message: bytesread
-Callback Payload: i:38912;
-Callback Message: bytesread
-Callback Payload: i:39936;
-Callback Message: bytesread
-Callback Payload: i:40960;
-Callback Message: bytesread
-Callback Payload: i:41655;
-Callback Message: done
-Callback Payload: i:41655;
-Working Callback: passed
-Callback fail:
-Callback Message: setup
-Callback Payload: a:1:{i:0;s:5:"My UI";}
-Callback Message: message
-Callback Payload: s:35:"Using HTTP proxy test.poop.php.net:";
-Callback Message: connfailed
-Callback Payload: a:4:{i:0;s:17:"test.poop.php.net";i:1;i:80;i:2;i:0;i:3;s:39:"The operation completed successfully.
-";}
-Caught error: Connection to `test.poop.php.net:80' failed: The operation completed successfully.
\ No newline at end of file
diff --git a/pear/tests/pear_common_infoFromString.phpt b/pear/tests/pear_common_infoFromString.phpt
deleted file mode 100644 (file)
index fa45390..0000000
+++ /dev/null
@@ -1,1754 +0,0 @@
---TEST--
-PEAR_Common::infoFromString test
---SKIPIF--
-<?php
-if (!getenv('PHP_PEAR_RUNTESTS')) {
-    echo 'skip';
-}
-if (!function_exists('token_get_all')) {
-    echo 'skip';
-}
-?>
---FILE--
-<?php
-putenv('PHP_PEAR_SYSCONF_DIR=' . dirname(__FILE__));
-
-require_once "PEAR/Common.php";
-
-$common = &new PEAR_Common;
-
-PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'catchit');
-
-function catchit($err)
-{
-    echo "Caught error: " . $err->getMessage() . "\n";
-}
-
-echo "Test invalid XML\n";
-
-$common->infoFromString('\\goober');
-
-echo "Test valid XML, not a package.xml\n";
-
-$common->infoFromString('<?xml version="1.0" encoding="ISO-8859-1" ?>' .
-    "\n<grobbage></grobbage>");
-
-echo "Test valid package.xml, invalid version number\n";
-
-$common->infoFromString('<?xml version="1.0" encoding="ISO-8859-1" ?>' .
-    '<package version="10000000"></package>');
-
-echo "Test empty package.xml\n";
-
-$ret = $common->infoFromString('<?xml version="1.0" encoding="ISO-8859-1" ?>' .
-    '<package version="1.0"></package>');
-
-var_dump($ret);
-
-echo "Test 1\n";
-
-$ret = $common->infoFromString('<?xml version="1.0" encoding="ISO-8859-1" ?>' .
-    '<package version="1.0"><name>test</name></package>');
-
-var_dump($ret);
-
-echo "Test 2\n";
-
-$ret = $common->infoFromString('<?xml version="1.0" encoding="ISO-8859-1" ?>' .
-    '<package version="1.0"><name>test</name><summary>PEAR test</summary>' . 
-    '</package>');
-
-var_dump($ret);
-
-echo "Test 3\n";
-
-$ret = $common->infoFromString('<?xml version="1.0" encoding="ISO-8859-1" ?>' .
-    '<package version="1.0"><name>test</name><summary>PEAR test</summary>' . 
-    '<description>The test</description></package>');
-
-var_dump($ret);
-
-echo "Test 4\n";
-
-$ret = $common->infoFromString('<?xml version="1.0" encoding="ISO-8859-1" ?>' .
-    '<package version="1.0"><name>test</name><summary>PEAR test</summary>' . 
-    '<description>The test</description><license>PHP License</license></package>');
-
-var_dump($ret);
-
-echo "Test 5\n";
-
-$ret = $common->infoFromString('<?xml version="1.0" encoding="ISO-8859-1" ?>' .
-    '<package version="1.0"><name>test</name><summary>PEAR test</summary>' . 
-    '<description>The test</description><license>PHP License</license>  <maintainers>
-    <maintainer>
-      <user>test</user>
-      <role>lead</role>
-      <name>test tester</name>
-      <email>test@php.net</email>
-    </maintainer></maintainers>
-</package>');
-
-var_dump($ret);
-
-echo "Test 6\n";
-
-$ret = $common->infoFromString('<?xml version="1.0" encoding="ISO-8859-1" ?>' .
-    '<package version="1.0"><name>test</name><summary>PEAR test</summary>' . 
-    '<description>The test</description><license>PHP License</license>  <maintainers>
-    <maintainer>
-      <user>test</user>
-      <role>lead</role>
-      <name>test tester</name>
-      <email>test@php.net</email>
-    </maintainer></maintainers><release>
-    <version>1.3b4</version></release>
-</package>');
-
-var_dump($ret);
-
-echo "Test 7\n";
-
-$ret = $common->infoFromString('<?xml version="1.0" encoding="ISO-8859-1" ?>' .
-    '<package version="1.0"><name>test</name><summary>PEAR test</summary>' . 
-    '<description>The test</description><license>PHP License</license>  <maintainers>
-    <maintainer>
-      <user>test</user>
-      <role>lead</role>
-      <name>test tester</name>
-      <email>test@php.net</email>
-    </maintainer></maintainers><release>
-    <version>1.3b4</version>
-    <date>2003-11-17</date>
-    <state>beta</state>
-    <notes>test</notes></release>
-</package>');
-
-var_dump($ret);
-
-echo "Test 8\n";
-
-$ret = $common->infoFromString('<?xml version="1.0" encoding="ISO-8859-1" ?>' .
-    '<package version="1.0"><name>test</name><summary>PEAR test</summary>' . 
-    '<description>The test</description><license>PHP License</license>  <maintainers>
-    <maintainer>
-      <user>test</user>
-      <role>lead</role>
-      <name>test tester</name>
-      <email>test@php.net</email>
-    </maintainer></maintainers><release>
-    <version>1.3b4</version>
-    <date>2003-11-17</date>
-    <state>beta</state>
-    <notes>test</notes>
-    <provides type="class" name="furngy" /></release>
-</package>');
-
-var_dump($ret);
-
-echo "Test 9\n";
-
-$ret = $common->infoFromString('<?xml version="1.0" encoding="ISO-8859-1" ?>' .
-    '<package version="1.0"><name>test</name><summary>PEAR test</summary>' . 
-    '<description>The test</description><license>PHP License</license>  <maintainers>
-    <maintainer>
-      <user>test</user>
-      <role>lead</role>
-      <name>test tester</name>
-      <email>test@php.net</email>
-    </maintainer></maintainers><release>
-    <version>1.3b4</version>
-    <date>2003-11-17</date>
-    <state>beta</state>
-    <notes>test</notes>
-    <provides type="class" name="furngy" />
-    <deps>
-          <dep type="ext" rel="has" optional="yes">xmlrpc</dep>
-    </deps>
-</release>
-</package>');
-
-var_dump($ret);
-
-echo "Test 10\n";
-
-$ret = $common->infoFromString('<?xml version="1.0" encoding="ISO-8859-1" ?>' .
-    '<package version="1.0"><name>test</name><summary>PEAR test</summary>' . 
-    '<description>The test</description><license>PHP License</license>  <maintainers>
-    <maintainer>
-      <user>test</user>
-      <role>lead</role>
-      <name>test tester</name>
-      <email>test@php.net</email>
-    </maintainer></maintainers><release>
-    <version>1.3b4</version>
-    <date>2003-11-17</date>
-    <state>beta</state>
-    <notes>test</notes>
-    <provides type="class" name="furngy" />
-    <deps>
-          <dep type="ext" rel="has" optional="yes">xmlrpc</dep>
-    </deps>
-        <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.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.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>
-
-</release>
-</package>');
-
-var_dump($ret);
-
-echo "Test 11\n";
-
-$ret = $common->infoFromString('<?xml version="1.0" encoding="ISO-8859-1" ?>' .
-    '<package version="1.0"><name>test</name><summary>PEAR test</summary>' . 
-    '<description>The test</description><license>PHP License</license>  <maintainers>
-    <maintainer>
-      <user>test</user>
-      <role>lead</role>
-      <name>test tester</name>
-      <email>test@php.net</email>
-    </maintainer></maintainers><release>
-    <version>1.3b4</version>
-    <date>2003-11-17</date>
-    <state>beta</state>
-    <notes>test</notes>
-    <provides type="class" name="furngy" />
-    <deps>
-          <dep type="ext" rel="has" optional="yes">xmlrpc</dep>
-    </deps>
-        <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.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.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>
-    <configureoptions>
-     <configureoption name="test" prompt="The prompt test" default="foo" />
-    </configureoptions>
-</release>
-</package>');
-
-var_dump($ret);
-
-echo "Test 12\n";
-
-$ret = $common->infoFromString('<?xml version="1.0" encoding="ISO-8859-1" ?>' .
-    '<package version="1.0"><name>test</name><summary>PEAR test</summary>' . 
-    '<description>The test</description><license>PHP License</license>  <maintainers>
-    <maintainer>
-      <user>test</user>
-      <role>lead</role>
-      <name>test tester</name>
-      <email>test@php.net</email>
-    </maintainer></maintainers><release>
-    <version>1.3b4</version>
-    <date>2003-11-17</date>
-    <state>beta</state>
-    <notes>test</notes>
-    <provides type="class" name="furngy" />
-    <deps>
-          <dep type="ext" rel="has" optional="yes">xmlrpc</dep>
-    </deps>
-        <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.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.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>
-    <configureoptions>
-     <configureoption name="test" prompt="The prompt test" default="foo" />
-    </configureoptions>
-</release>
-  <changelog>
-    <release>
-      <version>0.1</version>
-      <date>2003-07-21</date>
-      <license>PHP License</license>
-      <state>alpha</state>
-      <notes>First release of test</notes>
-    </release>
-    <release>
-      <version>0.2</version>
-      <date>2003-07-21</date>
-      <license>PHP License</license>
-      <state>alpha</state>
-      <notes>Generation of package.xml from scratch is now supported.  In addition,
-generation of &lt;provides&gt; is supported and so is addition of
-maintainers and configure options
-
-- Fixed a bug in &lt;release&gt; generation
-- Added _addProvides() to generate a &lt;provides&gt; section</notes>
-    </release>
-   </changelog>
-</package>');
-
-var_dump($ret);
-
-?>
---GET--
---POST--
---EXPECT--
-Test invalid XML
-Caught error: XML error: not well-formed (invalid token) at line 1
-Test valid XML, not a package.xml
-Caught error: Invalid Package File, no <package> tag
-Test valid package.xml, invalid version number
-Caught error: No handlers for package.xml version 10000000
-Test empty package.xml
-array(2) {
-  ["provides"]=>
-  array(0) {
-  }
-  ["filelist"]=>
-  &array(0) {
-  }
-}
-Test 1
-array(3) {
-  ["provides"]=>
-  array(0) {
-  }
-  ["filelist"]=>
-  &array(0) {
-  }
-  ["package"]=>
-  string(4) "test"
-}
-Test 2
-array(4) {
-  ["provides"]=>
-  array(0) {
-  }
-  ["filelist"]=>
-  &array(0) {
-  }
-  ["package"]=>
-  string(4) "test"
-  ["summary"]=>
-  string(9) "PEAR test"
-}
-Test 3
-array(5) {
-  ["provides"]=>
-  array(0) {
-  }
-  ["filelist"]=>
-  &array(0) {
-  }
-  ["package"]=>
-  string(4) "test"
-  ["summary"]=>
-  string(9) "PEAR test"
-  ["description"]=>
-  string(8) "The test"
-}
-Test 4
-array(6) {
-  ["provides"]=>
-  array(0) {
-  }
-  ["filelist"]=>
-  &array(0) {
-  }
-  ["package"]=>
-  string(4) "test"
-  ["summary"]=>
-  string(9) "PEAR test"
-  ["description"]=>
-  string(8) "The test"
-  ["release_license"]=>
-  string(11) "PHP License"
-}
-Test 5
-array(7) {
-  ["provides"]=>
-  array(0) {
-  }
-  ["filelist"]=>
-  &array(0) {
-  }
-  ["package"]=>
-  string(4) "test"
-  ["summary"]=>
-  string(9) "PEAR test"
-  ["description"]=>
-  string(8) "The test"
-  ["release_license"]=>
-  string(11) "PHP License"
-  ["maintainers"]=>
-  array(1) {
-    [0]=>
-    &array(4) {
-      ["handle"]=>
-      string(4) "test"
-      ["role"]=>
-      string(4) "lead"
-      ["name"]=>
-      string(11) "test tester"
-      ["email"]=>
-      string(12) "test@php.net"
-    }
-  }
-}
-Test 6
-array(8) {
-  ["provides"]=>
-  array(0) {
-  }
-  ["filelist"]=>
-  &array(0) {
-  }
-  ["package"]=>
-  string(4) "test"
-  ["summary"]=>
-  string(9) "PEAR test"
-  ["description"]=>
-  string(8) "The test"
-  ["release_license"]=>
-  string(11) "PHP License"
-  ["maintainers"]=>
-  array(1) {
-    [0]=>
-    &array(4) {
-      ["handle"]=>
-      string(4) "test"
-      ["role"]=>
-      string(4) "lead"
-      ["name"]=>
-      string(11) "test tester"
-      ["email"]=>
-      string(12) "test@php.net"
-    }
-  }
-  ["version"]=>
-  string(5) "1.3b4"
-}
-Test 7
-array(11) {
-  ["provides"]=>
-  array(0) {
-  }
-  ["filelist"]=>
-  &array(0) {
-  }
-  ["package"]=>
-  string(4) "test"
-  ["summary"]=>
-  string(9) "PEAR test"
-  ["description"]=>
-  string(8) "The test"
-  ["release_license"]=>
-  string(11) "PHP License"
-  ["maintainers"]=>
-  array(1) {
-    [0]=>
-    &array(4) {
-      ["handle"]=>
-      string(4) "test"
-      ["role"]=>
-      string(4) "lead"
-      ["name"]=>
-      string(11) "test tester"
-      ["email"]=>
-      string(12) "test@php.net"
-    }
-  }
-  ["version"]=>
-  string(5) "1.3b4"
-  ["release_date"]=>
-  string(10) "2003-11-17"
-  ["release_state"]=>
-  string(4) "beta"
-  ["release_notes"]=>
-  string(4) "test"
-}
-Test 8
-array(11) {
-  ["provides"]=>
-  array(1) {
-    ["class;furngy"]=>
-    array(3) {
-      ["type"]=>
-      string(5) "class"
-      ["name"]=>
-      string(6) "furngy"
-      ["explicit"]=>
-      bool(true)
-    }
-  }
-  ["filelist"]=>
-  &array(0) {
-  }
-  ["package"]=>
-  string(4) "test"
-  ["summary"]=>
-  string(9) "PEAR test"
-  ["description"]=>
-  string(8) "The test"
-  ["release_license"]=>
-  string(11) "PHP License"
-  ["maintainers"]=>
-  array(1) {
-    [0]=>
-    &array(4) {
-      ["handle"]=>
-      string(4) "test"
-      ["role"]=>
-      string(4) "lead"
-      ["name"]=>
-      string(11) "test tester"
-      ["email"]=>
-      string(12) "test@php.net"
-    }
-  }
-  ["version"]=>
-  string(5) "1.3b4"
-  ["release_date"]=>
-  string(10) "2003-11-17"
-  ["release_state"]=>
-  string(4) "beta"
-  ["release_notes"]=>
-  string(4) "test"
-}
-Test 9
-array(12) {
-  ["provides"]=>
-  array(1) {
-    ["class;furngy"]=>
-    array(3) {
-      ["type"]=>
-      string(5) "class"
-      ["name"]=>
-      string(6) "furngy"
-      ["explicit"]=>
-      bool(true)
-    }
-  }
-  ["filelist"]=>
-  &array(0) {
-  }
-  ["package"]=>
-  string(4) "test"
-  ["summary"]=>
-  string(9) "PEAR test"
-  ["description"]=>
-  string(8) "The test"
-  ["release_license"]=>
-  string(11) "PHP License"
-  ["maintainers"]=>
-  array(1) {
-    [0]=>
-    &array(4) {
-      ["handle"]=>
-      string(4) "test"
-      ["role"]=>
-      string(4) "lead"
-      ["name"]=>
-      string(11) "test tester"
-      ["email"]=>
-      string(12) "test@php.net"
-    }
-  }
-  ["version"]=>
-  string(5) "1.3b4"
-  ["release_date"]=>
-  string(10) "2003-11-17"
-  ["release_state"]=>
-  string(4) "beta"
-  ["release_notes"]=>
-  string(4) "test"
-  ["release_deps"]=>
-  array(1) {
-    [1]=>
-    array(4) {
-      ["type"]=>
-      string(3) "ext"
-      ["rel"]=>
-      string(3) "has"
-      ["optional"]=>
-      string(3) "yes"
-      ["name"]=>
-      string(6) "xmlrpc"
-    }
-  }
-}
-Test 10
-array(12) {
-  ["provides"]=>
-  array(1) {
-    ["class;furngy"]=>
-    array(3) {
-      ["type"]=>
-      string(5) "class"
-      ["name"]=>
-      string(6) "furngy"
-      ["explicit"]=>
-      bool(true)
-    }
-  }
-  ["filelist"]=>
-  &array(28) {
-    ["package.dtd"]=>
-    array(1) {
-      ["role"]=>
-      string(4) "data"
-    }
-    ["template.spec"]=>
-    array(1) {
-      ["role"]=>
-      string(4) "data"
-    }
-    ["PEAR.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["System.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Autoloader.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Command.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Command\Auth.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Command\Build.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Command\Common.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Command\Config.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Command\Install.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Command\Package.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Command\Registry.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Command\Remote.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Command\Mirror.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Common.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Config.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Dependency.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Frontend\CLI.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Builder.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Installer.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Packager.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Registry.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Remote.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["OS\Guess.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["scripts\pear.sh"]=>
-    array(4) {
-      ["role"]=>
-      string(6) "script"
-      ["install-as"]=>
-      string(4) "pear"
-      ["baseinstalldir"]=>
-      string(1) "/"
-      ["replacements"]=>
-      array(4) {
-        [0]=>
-        array(3) {
-          ["from"]=>
-          string(9) "@php_bin@"
-          ["to"]=>
-          string(7) "php_bin"
-          ["type"]=>
-          string(11) "pear-config"
-        }
-        [1]=>
-        array(3) {
-          ["from"]=>
-          string(9) "@php_dir@"
-          ["to"]=>
-          string(7) "php_dir"
-          ["type"]=>
-          string(11) "pear-config"
-        }
-        [2]=>
-        array(3) {
-          ["from"]=>
-          string(14) "@pear_version@"
-          ["to"]=>
-          string(7) "version"
-          ["type"]=>
-          string(12) "package-info"
-        }
-        [3]=>
-        array(3) {
-          ["from"]=>
-          string(14) "@include_path@"
-          ["to"]=>
-          string(7) "php_dir"
-          ["type"]=>
-          string(11) "pear-config"
-        }
-      }
-    }
-    ["scripts\pear.bat"]=>
-    array(5) {
-      ["role"]=>
-      string(6) "script"
-      ["platform"]=>
-      string(7) "windows"
-      ["install-as"]=>
-      string(8) "pear.bat"
-      ["baseinstalldir"]=>
-      string(1) "/"
-      ["replacements"]=>
-      array(3) {
-        [0]=>
-        array(3) {
-          ["from"]=>
-          string(9) "@bin_dir@"
-          ["to"]=>
-          string(7) "bin_dir"
-          ["type"]=>
-          string(11) "pear-config"
-        }
-        [1]=>
-        array(3) {
-          ["from"]=>
-          string(9) "@php_bin@"
-          ["to"]=>
-          string(7) "php_bin"
-          ["type"]=>
-          string(11) "pear-config"
-        }
-        [2]=>
-        array(3) {
-          ["from"]=>
-          string(14) "@include_path@"
-          ["to"]=>
-          string(7) "php_dir"
-          ["type"]=>
-          string(11) "pear-config"
-        }
-      }
-    }
-    ["scripts\pearcmd.php"]=>
-    array(4) {
-      ["role"]=>
-      string(3) "php"
-      ["install-as"]=>
-      string(11) "pearcmd.php"
-      ["baseinstalldir"]=>
-      string(1) "/"
-      ["replacements"]=>
-      array(4) {
-        [0]=>
-        array(3) {
-          ["from"]=>
-          string(9) "@php_bin@"
-          ["to"]=>
-          string(7) "php_bin"
-          ["type"]=>
-          string(11) "pear-config"
-        }
-        [1]=>
-        array(3) {
-          ["from"]=>
-          string(9) "@php_dir@"
-          ["to"]=>
-          string(7) "php_dir"
-          ["type"]=>
-          string(11) "pear-config"
-        }
-        [2]=>
-        array(3) {
-          ["from"]=>
-          string(14) "@pear_version@"
-          ["to"]=>
-          string(7) "version"
-          ["type"]=>
-          string(12) "package-info"
-        }
-        [3]=>
-        array(3) {
-          ["from"]=>
-          string(14) "@include_path@"
-          ["to"]=>
-          string(7) "php_dir"
-          ["type"]=>
-          string(11) "pear-config"
-        }
-      }
-    }
-  }
-  ["package"]=>
-  string(4) "test"
-  ["summary"]=>
-  string(9) "PEAR test"
-  ["description"]=>
-  string(8) "The test"
-  ["release_license"]=>
-  string(11) "PHP License"
-  ["maintainers"]=>
-  array(1) {
-    [0]=>
-    &array(4) {
-      ["handle"]=>
-      string(4) "test"
-      ["role"]=>
-      string(4) "lead"
-      ["name"]=>
-      string(11) "test tester"
-      ["email"]=>
-      string(12) "test@php.net"
-    }
-  }
-  ["version"]=>
-  string(5) "1.3b4"
-  ["release_date"]=>
-  string(10) "2003-11-17"
-  ["release_state"]=>
-  string(4) "beta"
-  ["release_notes"]=>
-  string(4) "test"
-  ["release_deps"]=>
-  array(1) {
-    [1]=>
-    array(4) {
-      ["type"]=>
-      string(3) "ext"
-      ["rel"]=>
-      string(3) "has"
-      ["optional"]=>
-      string(3) "yes"
-      ["name"]=>
-      string(6) "xmlrpc"
-    }
-  }
-}
-Test 11
-array(13) {
-  ["provides"]=>
-  array(1) {
-    ["class;furngy"]=>
-    array(3) {
-      ["type"]=>
-      string(5) "class"
-      ["name"]=>
-      string(6) "furngy"
-      ["explicit"]=>
-      bool(true)
-    }
-  }
-  ["filelist"]=>
-  &array(28) {
-    ["package.dtd"]=>
-    array(1) {
-      ["role"]=>
-      string(4) "data"
-    }
-    ["template.spec"]=>
-    array(1) {
-      ["role"]=>
-      string(4) "data"
-    }
-    ["PEAR.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["System.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Autoloader.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Command.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Command\Auth.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Command\Build.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Command\Common.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Command\Config.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Command\Install.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Command\Package.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Command\Registry.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Command\Remote.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Command\Mirror.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Common.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Config.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Dependency.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Frontend\CLI.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Builder.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Installer.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Packager.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Registry.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Remote.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["OS\Guess.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["scripts\pear.sh"]=>
-    array(4) {
-      ["role"]=>
-      string(6) "script"
-      ["install-as"]=>
-      string(4) "pear"
-      ["baseinstalldir"]=>
-      string(1) "/"
-      ["replacements"]=>
-      array(4) {
-        [0]=>
-        array(3) {
-          ["from"]=>
-          string(9) "@php_bin@"
-          ["to"]=>
-          string(7) "php_bin"
-          ["type"]=>
-          string(11) "pear-config"
-        }
-        [1]=>
-        array(3) {
-          ["from"]=>
-          string(9) "@php_dir@"
-          ["to"]=>
-          string(7) "php_dir"
-          ["type"]=>
-          string(11) "pear-config"
-        }
-        [2]=>
-        array(3) {
-          ["from"]=>
-          string(14) "@pear_version@"
-          ["to"]=>
-          string(7) "version"
-          ["type"]=>
-          string(12) "package-info"
-        }
-        [3]=>
-        array(3) {
-          ["from"]=>
-          string(14) "@include_path@"
-          ["to"]=>
-          string(7) "php_dir"
-          ["type"]=>
-          string(11) "pear-config"
-        }
-      }
-    }
-    ["scripts\pear.bat"]=>
-    array(5) {
-      ["role"]=>
-      string(6) "script"
-      ["platform"]=>
-      string(7) "windows"
-      ["install-as"]=>
-      string(8) "pear.bat"
-      ["baseinstalldir"]=>
-      string(1) "/"
-      ["replacements"]=>
-      array(3) {
-        [0]=>
-        array(3) {
-          ["from"]=>
-          string(9) "@bin_dir@"
-          ["to"]=>
-          string(7) "bin_dir"
-          ["type"]=>
-          string(11) "pear-config"
-        }
-        [1]=>
-        array(3) {
-          ["from"]=>
-          string(9) "@php_bin@"
-          ["to"]=>
-          string(7) "php_bin"
-          ["type"]=>
-          string(11) "pear-config"
-        }
-        [2]=>
-        array(3) {
-          ["from"]=>
-          string(14) "@include_path@"
-          ["to"]=>
-          string(7) "php_dir"
-          ["type"]=>
-          string(11) "pear-config"
-        }
-      }
-    }
-    ["scripts\pearcmd.php"]=>
-    array(4) {
-      ["role"]=>
-      string(3) "php"
-      ["install-as"]=>
-      string(11) "pearcmd.php"
-      ["baseinstalldir"]=>
-      string(1) "/"
-      ["replacements"]=>
-      array(4) {
-        [0]=>
-        array(3) {
-          ["from"]=>
-          string(9) "@php_bin@"
-          ["to"]=>
-          string(7) "php_bin"
-          ["type"]=>
-          string(11) "pear-config"
-        }
-        [1]=>
-        array(3) {
-          ["from"]=>
-          string(9) "@php_dir@"
-          ["to"]=>
-          string(7) "php_dir"
-          ["type"]=>
-          string(11) "pear-config"
-        }
-        [2]=>
-        array(3) {
-          ["from"]=>
-          string(14) "@pear_version@"
-          ["to"]=>
-          string(7) "version"
-          ["type"]=>
-          string(12) "package-info"
-        }
-        [3]=>
-        array(3) {
-          ["from"]=>
-          string(14) "@include_path@"
-          ["to"]=>
-          string(7) "php_dir"
-          ["type"]=>
-          string(11) "pear-config"
-        }
-      }
-    }
-  }
-  ["package"]=>
-  string(4) "test"
-  ["summary"]=>
-  string(9) "PEAR test"
-  ["description"]=>
-  string(8) "The test"
-  ["release_license"]=>
-  string(11) "PHP License"
-  ["maintainers"]=>
-  array(1) {
-    [0]=>
-    &array(4) {
-      ["handle"]=>
-      string(4) "test"
-      ["role"]=>
-      string(4) "lead"
-      ["name"]=>
-      string(11) "test tester"
-      ["email"]=>
-      string(12) "test@php.net"
-    }
-  }
-  ["version"]=>
-  string(5) "1.3b4"
-  ["release_date"]=>
-  string(10) "2003-11-17"
-  ["release_state"]=>
-  string(4) "beta"
-  ["release_notes"]=>
-  string(4) "test"
-  ["release_deps"]=>
-  array(1) {
-    [1]=>
-    array(4) {
-      ["type"]=>
-      string(3) "ext"
-      ["rel"]=>
-      string(3) "has"
-      ["optional"]=>
-      string(3) "yes"
-      ["name"]=>
-      string(6) "xmlrpc"
-    }
-  }
-  ["configure_options"]=>
-  array(1) {
-    [0]=>
-    array(3) {
-      ["name"]=>
-      string(4) "test"
-      ["prompt"]=>
-      string(15) "The prompt test"
-      ["default"]=>
-      string(3) "foo"
-    }
-  }
-}
-Test 12
-array(14) {
-  ["provides"]=>
-  array(1) {
-    ["class;furngy"]=>
-    array(3) {
-      ["type"]=>
-      string(5) "class"
-      ["name"]=>
-      string(6) "furngy"
-      ["explicit"]=>
-      bool(true)
-    }
-  }
-  ["filelist"]=>
-  &array(28) {
-    ["package.dtd"]=>
-    array(1) {
-      ["role"]=>
-      string(4) "data"
-    }
-    ["template.spec"]=>
-    array(1) {
-      ["role"]=>
-      string(4) "data"
-    }
-    ["PEAR.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["System.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Autoloader.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Command.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Command\Auth.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Command\Build.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Command\Common.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Command\Config.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Command\Install.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Command\Package.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Command\Registry.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Command\Remote.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Command\Mirror.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Common.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Config.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Dependency.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Frontend\CLI.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Builder.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Installer.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Packager.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Registry.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["PEAR\Remote.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["OS\Guess.php"]=>
-    array(1) {
-      ["role"]=>
-      string(3) "php"
-    }
-    ["scripts\pear.sh"]=>
-    array(4) {
-      ["role"]=>
-      string(6) "script"
-      ["install-as"]=>
-      string(4) "pear"
-      ["baseinstalldir"]=>
-      string(1) "/"
-      ["replacements"]=>
-      array(4) {
-        [0]=>
-        array(3) {
-          ["from"]=>
-          string(9) "@php_bin@"
-          ["to"]=>
-          string(7) "php_bin"
-          ["type"]=>
-          string(11) "pear-config"
-        }
-        [1]=>
-        array(3) {
-          ["from"]=>
-          string(9) "@php_dir@"
-          ["to"]=>
-          string(7) "php_dir"
-          ["type"]=>
-          string(11) "pear-config"
-        }
-        [2]=>
-        array(3) {
-          ["from"]=>
-          string(14) "@pear_version@"
-          ["to"]=>
-          string(7) "version"
-          ["type"]=>
-          string(12) "package-info"
-        }
-        [3]=>
-        array(3) {
-          ["from"]=>
-          string(14) "@include_path@"
-          ["to"]=>
-          string(7) "php_dir"
-          ["type"]=>
-          string(11) "pear-config"
-        }
-      }
-    }
-    ["scripts\pear.bat"]=>
-    array(5) {
-      ["role"]=>
-      string(6) "script"
-      ["platform"]=>
-      string(7) "windows"
-      ["install-as"]=>
-      string(8) "pear.bat"
-      ["baseinstalldir"]=>
-      string(1) "/"
-      ["replacements"]=>
-      array(3) {
-        [0]=>
-        array(3) {
-          ["from"]=>
-          string(9) "@bin_dir@"
-          ["to"]=>
-          string(7) "bin_dir"
-          ["type"]=>
-          string(11) "pear-config"
-        }
-        [1]=>
-        array(3) {
-          ["from"]=>
-          string(9) "@php_bin@"
-          ["to"]=>
-          string(7) "php_bin"
-          ["type"]=>
-          string(11) "pear-config"
-        }
-        [2]=>
-        array(3) {
-          ["from"]=>
-          string(14) "@include_path@"
-          ["to"]=>
-          string(7) "php_dir"
-          ["type"]=>
-          string(11) "pear-config"
-        }
-      }
-    }
-    ["scripts\pearcmd.php"]=>
-    array(4) {
-      ["role"]=>
-      string(3) "php"
-      ["install-as"]=>
-      string(11) "pearcmd.php"
-      ["baseinstalldir"]=>
-      string(1) "/"
-      ["replacements"]=>
-      array(4) {
-        [0]=>
-        array(3) {
-          ["from"]=>
-          string(9) "@php_bin@"
-          ["to"]=>
-          string(7) "php_bin"
-          ["type"]=>
-          string(11) "pear-config"
-        }
-        [1]=>
-        array(3) {
-          ["from"]=>
-          string(9) "@php_dir@"
-          ["to"]=>
-          string(7) "php_dir"
-          ["type"]=>
-          string(11) "pear-config"
-        }
-        [2]=>
-        array(3) {
-          ["from"]=>
-          string(14) "@pear_version@"
-          ["to"]=>
-          string(7) "version"
-          ["type"]=>
-          string(12) "package-info"
-        }
-        [3]=>
-        array(3) {
-          ["from"]=>
-          string(14) "@include_path@"
-          ["to"]=>
-          string(7) "php_dir"
-          ["type"]=>
-          string(11) "pear-config"
-        }
-      }
-    }
-  }
-  ["package"]=>
-  string(4) "test"
-  ["summary"]=>
-  string(9) "PEAR test"
-  ["description"]=>
-  string(8) "The test"
-  ["release_license"]=>
-  string(11) "PHP License"
-  ["maintainers"]=>
-  array(1) {
-    [0]=>
-    &array(4) {
-      ["handle"]=>
-      string(4) "test"
-      ["role"]=>
-      string(4) "lead"
-      ["name"]=>
-      string(11) "test tester"
-      ["email"]=>
-      string(12) "test@php.net"
-    }
-  }
-  ["version"]=>
-  string(5) "1.3b4"
-  ["release_date"]=>
-  string(10) "2003-11-17"
-  ["release_state"]=>
-  string(4) "beta"
-  ["release_notes"]=>
-  string(4) "test"
-  ["release_deps"]=>
-  array(1) {
-    [1]=>
-    array(4) {
-      ["type"]=>
-      string(3) "ext"
-      ["rel"]=>
-      string(3) "has"
-      ["optional"]=>
-      string(3) "yes"
-      ["name"]=>
-      string(6) "xmlrpc"
-    }
-  }
-  ["configure_options"]=>
-  array(1) {
-    [0]=>
-    array(3) {
-      ["name"]=>
-      string(4) "test"
-      ["prompt"]=>
-      string(15) "The prompt test"
-      ["default"]=>
-      string(3) "foo"
-    }
-  }
-  ["changelog"]=>
-  array(2) {
-    [0]=>
-    &array(5) {
-      ["version"]=>
-      string(3) "0.1"
-      ["release_date"]=>
-      string(10) "2003-07-21"
-      ["release_license"]=>
-      string(11) "PHP License"
-      ["release_state"]=>
-      string(5) "alpha"
-      ["release_notes"]=>
-      string(22) "First release of test
-"
-    }
-    [1]=>
-    &array(5) {
-      ["version"]=>
-      string(3) "0.2"
-      ["release_date"]=>
-      string(10) "2003-07-21"
-      ["release_license"]=>
-      string(11) "PHP License"
-      ["release_state"]=>
-      string(5) "alpha"
-      ["release_notes"]=>
-      string(260) "Generation of package.xml from scratch is now supported.  In addition,
-generation of <provides> is supported and so is addition of
-maintainers and configure options
-
-- Fixed a bug in <release> generation
-- Added _addProvides() to generate a <provides> section
-"
-    }
-  }
-}
\ No newline at end of file
diff --git a/pear/tests/pear_common_sortPkgDeps.phpt b/pear/tests/pear_common_sortPkgDeps.phpt
deleted file mode 100644 (file)
index e05cbc6..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
---TEST--
-PEAR_Common::sortPkgDeps test
---SKIPIF--
-<?php
-if (!getenv('PHP_PEAR_RUNTESTS')) {
-    echo 'skip';
-}
-?>
---FILE--
-<?php
-$dir = getcwd();
-chdir(dirname(__FILE__));
-
-require_once 'PEAR/Common.php';
-
-$c = new PEAR_Common();
-
-$packages = array(
-'common_sortPkgDeps6_package.xml',
-'common_sortPkgDeps2_package.xml',
-'common_sortPkgDeps1_package.xml',
-'common_sortPkgDeps4_package.xml',
-'common_sortPkgDeps5_package.xml',
-'common_sortPkgDeps3_package.xml',
-);
-
-$uninstallpackages = array(
-$c->infoFromAny('common_sortPkgDeps6_package.xml'),
-$c->infoFromAny('common_sortPkgDeps2_package.xml'),
-$c->infoFromAny('common_sortPkgDeps1_package.xml'),
-$c->infoFromAny('common_sortPkgDeps4_package.xml'),
-$c->infoFromAny('common_sortPkgDeps5_package.xml'),
-$c->infoFromAny('common_sortPkgDeps3_package.xml'),
-);
-
-echo "Test Install Sort:\n";
-$c->sortPkgDeps($packages);
-dumpPacks($packages);
-
-echo "Test Uninstall Sort:\n";
-$c->sortPkgDeps($uninstallpackages, true);
-dumpPacks($uninstallpackages);
-
-chdir($dir);
-
-function dumpPacks($p)
-{
-    echo "Packages(\n";
-    foreach ($p as $inf) {
-        echo $inf['info']['package'] . ",\n";
-    }
-    echo ")\n";
-}
-?>
---GET--
---POST--
---EXPECT--
-Test Install Sort:
-Packages(
-pkg6,
-pkg5,
-pkg4,
-pkg3,
-pkg2,
-pkg1,
-)
-Test Uninstall Sort:
-Packages(
-pkg1,
-pkg2,
-pkg3,
-pkg5,
-pkg4,
-pkg6,
-)
\ No newline at end of file
diff --git a/pear/tests/pear_common_validPackageVersion.phpt b/pear/tests/pear_common_validPackageVersion.phpt
deleted file mode 100644 (file)
index a23477a..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
---TEST--
-PEAR_Common::validPackageVersion test
---SKIPIF--
-<?php
-if (!getenv('PHP_PEAR_RUNTESTS')) {
-    echo 'skip';
-}
-?>
---FILE--
-<?php
-
-require_once 'PEAR/Common.php';
-
-// '\d+(?:\.\d+)*(?:[a-z]+\d*)?'
-
-echo "==Valid Tests==\n";
-$a = '1';
-echo "$a ";
-echo (PEAR_Common::validPackageVersion($a)) ? "valid\n" : "invalid\n";
-
-$a = '1.1';
-echo "$a ";
-echo (PEAR_Common::validPackageVersion($a)) ? "valid\n" : "invalid\n";
-
-$a = '1.1.1';
-echo "$a ";
-echo (PEAR_Common::validPackageVersion($a)) ? "valid\n" : "invalid\n";
-
-$a = '1.1.1.1';
-echo "$a ";
-echo (PEAR_Common::validPackageVersion($a)) ? "valid\n" : "invalid\n";
-
-$a = '1.1.1abc3';
-echo "$a ";
-echo (PEAR_Common::validPackageVersion($a)) ? "valid\n" : "invalid\n";
-
-$a = '1.234beta4';
-echo "$a ";
-echo (PEAR_Common::validPackageVersion($a)) ? "valid\n" : "invalid\n";
-
-$a = '1alpha3';
-echo "$a ";
-echo (PEAR_Common::validPackageVersion($a)) ? "valid\n" : "invalid\n";
-
-$a = '1alpha';
-echo "$a ";
-echo (PEAR_Common::validPackageVersion($a)) ? "valid\n" : "invalid\n";
-
-$a = '1.1a';
-echo "$a ";
-echo (PEAR_Common::validPackageVersion($a)) ? "valid\n" : "invalid\n";
-
-echo "==Invalid Tests==\n";
-
-$a = '1.0.0-alpha2';
-echo "$a ";
-echo (PEAR_Common::validPackageVersion($a)) ? "valid\n" : "invalid\n";
-
-$a = '1alpha.4';
-echo "$a ";
-echo (PEAR_Common::validPackageVersion($a)) ? "valid\n" : "invalid\n";
-
-$a = '1.1alpha.4';
-echo "$a ";
-echo (PEAR_Common::validPackageVersion($a)) ? "valid\n" : "invalid\n";
-?>
---GET--
---POST--
---EXPECT--
-==Valid Tests==
-1 valid
-1.1 valid
-1.1.1 valid
-1.1.1.1 valid
-1.1.1abc3 valid
-1.234beta4 valid
-1alpha3 valid
-1alpha valid
-1.1a valid
-==Invalid Tests==
-1.0.0-alpha2 invalid
-1alpha.4 invalid
-1.1alpha.4 invalid
diff --git a/pear/tests/pear_config.phpt b/pear/tests/pear_config.phpt
deleted file mode 100644 (file)
index 5bc0016..0000000
+++ /dev/null
@@ -1,297 +0,0 @@
---TEST--
-PEAR_Config
---SKIPIF--
-<?php
-if (!getenv('PHP_PEAR_RUNTESTS')) {
-    echo 'skip';
-}
-?>
---FILE--
-<?php
-
-error_reporting(E_ALL);
-chdir(dirname(__FILE__));
-include "PEAR/Config.php";
-copy("system.input", "system.conf");
-copy("user.input", "user.conf");
-copy("user2.input", "user2.conf");
-copy("merge.input", "merge.conf");
-PEAR::setErrorHandling(PEAR_ERROR_PRINT, "%s\n");
-
-print "\n#0 starting up\n";
-dump_files();
-
-print "\n#1 testing: constructor\n";
-$config = new PEAR_Config("user.conf", "system.conf");
-dump_array("files", $config->files);
-
-print "\n#2 testing: singleton\n";
-$o1 = &PEAR_Config::singleton();
-$o1->blah = 'blah';
-$o2 = &PEAR_Config::singleton();
-var_dump($o1->blah);
-@var_dump($o2->blah);
-
-print "\n#3 testing: readConfigFile\n";
-$config->readConfigFile("user2.conf", "user");
-dump_config($config);
-$config->readConfigFile("user.conf");
-dump_config($config);
-
-print "\n#4 testing: mergeConfigFile\n";
-$config->readConfigFile("user2.conf");
-dump_config($config, "user");
-$config->mergeConfigFile("merge.conf", true);
-dump_config($config, "user");
-$config->readConfigFile("user2.conf");
-$config->mergeConfigFile("merge.conf", false);
-dump_config($config, "user");
-$config->readConfigFile("user.conf");
-dump_config($config, "user");
-$config->mergeConfigFile("merge.conf", true, "xyzzy");
-
-print "\n#5 testing: config file version detection\n";
-$config->readConfigFile("user.conf", "user");
-$config->readConfigFile("toonew.conf", "user");
-
-print "\n#6 testing: get/set/remove\n";
-var_dump($config->get("verbose"));
-$config->set("verbose", 100, "system");
-var_dump($config->get("verbose"));
-$config->set("verbose", 2, "user");
-var_dump($config->get("verbose"));
-$config->set("verbose", 2, "system");
-$config->set("verbose", 50, "user");
-var_dump($config->get("verbose"));
-$config->remove("verbose", "user");
-var_dump($config->get("verbose"));
-$config->remove("verbose", "system");
-var_dump($config->get("verbose"));
-
-print "\n#7 testing: getType\n";
-var_dump($config->getType("__unknown__"));
-var_dump($config->getType("verbose"));
-var_dump($config->getType("master_server"));
-var_dump($config->getType("ext_dir"));
-
-print "\n#8 testing: getDocs\n";
-print "master_server: " . $config->getDocs("master_server") . "\n";
-
-print "\n#9 testing: getKeys\n";
-$keys = $config->getKeys();
-sort($keys);
-print implode(" ", $keys) . "\n";
-
-print "\n#10 testing: definedBy\n";
-var_dump($config->definedBy("verbose"));
-$config->set("verbose", 6, "system");
-$config->set("verbose", 3, "user");
-var_dump($config->definedBy("verbose"));
-$config->remove("verbose", "system");
-var_dump($config->definedBy("verbose"));
-$config->set("verbose", 6, "system");
-$config->remove("verbose", "user");
-var_dump($config->definedBy("verbose"));
-$config->remove("verbose", "system");
-var_dump($config->definedBy("verbose"));
-
-print "\n#11 testing: isDefined\n";
-var_dump($config->isDefined("php_dir"));
-var_dump($config->isDefined("verbose"));
-var_dump($config->isDefined("HTTP_GET_VARS"));
-var_dump($config->isDefined("query"));
-
-print "\n#12 testing: getGroup\n";
-foreach ($keys as $key) {
-    print "$key: ".$config->getGroup($key)."\n";
-}
-
-print "\n#13 testing: getGroups\n";
-$groups = $config->getGroups();
-sort($groups);
-print implode(", ", $groups) . "\n";
-
-print "\n#14 testing: getGroupKeys\n";
-foreach ($groups as $group) {
-    $gk = $config->getGroupKeys($group);
-    sort($gk);
-    print "$group: " . implode(", ", $gk) . "\n";
-}
-
-print "\n#15 testing: getPrompt\n";
-foreach ($keys as $key) {
-    print "$key: ".$config->getPrompt($key)."\n";
-}
-
-
-//
-
-print "done\n";
-
-unlink("user.conf");
-unlink("user2.conf");
-unlink("system.conf");
-unlink("merge.conf");
-
-// ------------------------------------------------------------------------- //
-
-function dump_file($file)
-{
-       print "..$file:";
-        $data = PEAR_Config::_readConfigDataFrom($file);
-       if (empty($data)) {
-               print " <empty>\n";
-               return;
-       }
-       foreach ($data as $k => $v) {
-               print " $k=\"$v\"";
-       }
-       print "\n";
-}
-
-function dump_files() {
-       dump_file("system.conf");
-       dump_file("user.conf");
-}
-
-function dump_array($name, $arr) {
-       print "$name:";
-       if (empty($arr)) {
-               print " <empty>";
-       } else {
-               foreach ($arr as $k => $v) {
-                       print " $k=\"$v\"";
-               }
-       }
-       print "\n";
-}
-
-function dump_config(&$obj, $layer = null) {
-       if ($layer !== null) {
-               dump_array($layer, $obj->configuration[$layer]);
-               return;
-       }
-       foreach ($obj->configuration as $layer => $data) {
-               if ($layer == "default") {
-                       continue;
-               }
-               dump_array($layer, $data);
-       }
-}
-
-?>
---EXPECT--
-#0 starting up
-..system.conf: master_server="pear.php.net"
-..user.conf: <empty>
-
-#1 testing: constructor
-files: system="system.conf" user="user.conf"
-
-#2 testing: singleton
-string(4) "blah"
-string(4) "blah"
-
-#3 testing: readConfigFile
-user: verbose="2"
-system: master_server="pear.php.net"
-user: <empty>
-system: master_server="pear.php.net"
-
-#4 testing: mergeConfigFile
-user: verbose="2"
-user: verbose="100"
-user: verbose="2"
-user: <empty>
-unknown config file type `xyzzy'
-
-#5 testing: config file version detection
-toonew.conf: unknown version `2.0'
-
-#6 testing: get/set/remove
-int(1)
-int(100)
-int(2)
-int(50)
-int(2)
-int(1)
-
-#7 testing: getType
-bool(false)
-string(7) "integer"
-string(6) "string"
-string(9) "directory"
-
-#8 testing: getDocs
-master_server: name of the main PEAR server
-
-#9 testing: getKeys
-bin_dir cache_dir cache_ttl data_dir doc_dir ext_dir http_proxy master_server password php_bin php_dir preferred_state sig_bin sig_keydir sig_keyid sig_type test_dir umask username verbose
-
-#10 testing: definedBy
-string(7) "default"
-string(4) "user"
-string(4) "user"
-string(6) "system"
-string(7) "default"
-
-#11 testing: isDefined
-bool(true)
-bool(true)
-bool(false)
-bool(false)
-
-#12 testing: getGroup
-bin_dir: File Locations
-cache_dir: File Locations (Advanced)
-cache_ttl: Advanced
-data_dir: File Locations (Advanced)
-doc_dir: File Locations
-ext_dir: File Locations
-http_proxy: Internet Access
-master_server: Internet Access
-password: Maintainers
-php_bin: File Locations (Advanced)
-php_dir: File Locations
-preferred_state: Advanced
-sig_bin: Maintainers
-sig_keydir: Maintainers
-sig_keyid: Maintainers
-sig_type: Maintainers
-test_dir: File Locations (Advanced)
-umask: Advanced
-username: Maintainers
-verbose: Advanced
-
-#13 testing: getGroups
-Advanced, File Locations, File Locations (Advanced), Internet Access, Maintainers
-
-#14 testing: getGroupKeys
-Advanced: cache_ttl, preferred_state, umask, verbose
-File Locations: bin_dir, doc_dir, ext_dir, php_dir
-File Locations (Advanced): cache_dir, data_dir, php_bin, test_dir
-Internet Access: http_proxy, master_server
-Maintainers: password, sig_bin, sig_keydir, sig_keyid, sig_type, username
-
-#15 testing: getPrompt
-bin_dir: PEAR executables directory
-cache_dir: PEAR Installer cache directory
-cache_ttl: Cache TimeToLive
-data_dir: PEAR data directory
-doc_dir: PEAR documentation directory
-ext_dir: PHP extension directory
-http_proxy: HTTP Proxy Server Address
-master_server: PEAR server
-password: PEAR password (for maintainers)
-php_bin: PHP CLI/CGI binary
-php_dir: PEAR directory
-preferred_state: Preferred Package State
-sig_bin: Signature Handling Program
-sig_keydir: Signature Key Directory
-sig_keyid: Signature Key Id
-sig_type: Package Signature Type
-test_dir: PEAR test directory
-umask: Unix file mask
-username: PEAR username (for maintainers)
-verbose: Debug Log Level
-done
\ No newline at end of file
diff --git a/pear/tests/pear_dependency_checkExtension.phpt b/pear/tests/pear_dependency_checkExtension.phpt
deleted file mode 100644 (file)
index 37d808e..0000000
+++ /dev/null
@@ -1,262 +0,0 @@
---TEST--
-PEAR_Dependency::checkExtension() test
---SKIPIF--
-<?php
-if (!getenv('PHP_PEAR_RUNTESTS')) {
-    echo 'skip';
-}
-if (!ini_get('enable_dl') || ini_get('safe_mode')) {
-    echo 'skip';
-}
-
-$dir = ini_get('extension_dir');
-if (OS_WINDOWS) {
-    $suffix = '.dll';
-} elseif (PHP_OS == 'HP-UX') {
-    $suffix = '.sl';
-} elseif (PHP_OS == 'AIX') {
-    $suffix = '.a';
-} elseif (PHP_OS == 'OSX') {
-    $suffix = '.bundle';
-} else {
-    $suffix = '.so';
-}
-
-// get a list of possible extensions
-$extensions = array();
-if ($handle = opendir($dir)) {
-    while (false !== ($file = readdir($handle))) { 
-        if (strpos($file, $suffix) && substr($file, 0, 4) == 'php_') {
-            $extensions[] = $file;
-        }
-    }
-    closedir($handle); 
-}
-
-$loaded = false;
-$notloaded = false;
-// choose an extension for this test
-foreach ($extensions as $ext) {
-    $ext = substr(substr($ext, 0, strlen($ext) - strlen($suffix)), 4);
-    if (!$loaded && extension_loaded($ext)) {
-        $loaded = $ext;
-    }
-    if (!$notloaded && !extension_loaded($ext)) {
-        // safe list for testing
-        if (in_array($ext, array('zip', 'bz2', 'sqlite', 'dbx'))) {
-            $notloaded = $ext;
-        }
-    }
-}
-if (!$notloaded || !$loaded) {
-    echo 'skip';
-}
-?>
---FILE--
-<?php
-
-@mkdir(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'checkPackagetmp');
-require_once "PEAR/Registry.php";
-require_once "PEAR/Dependency.php";
-
-$dir = ini_get('extension_dir');
-if (OS_WINDOWS) {
-    $suffix = '.dll';
-} elseif (PHP_OS == 'HP-UX') {
-    $suffix = '.sl';
-} elseif (PHP_OS == 'AIX') {
-    $suffix = '.a';
-} elseif (PHP_OS == 'OSX') {
-    $suffix = '.bundle';
-} else {
-    $suffix = '.so';
-}
-
-// get a list of possible extensions
-$extensions = array();
-if ($handle = opendir($dir)) {
-    while (false !== ($file = readdir($handle))) { 
-        if (strpos($file, $suffix) && substr($file, 0, 4) == 'php_') {
-            $extensions[] = $file;
-        }
-    }
-    closedir($handle); 
-}
-
-$loaded = false;
-$notloaded = false;
-// choose an extension for this test
-foreach ($extensions as $ext) {
-    $ext = substr(substr($ext, 0, strlen($ext) - strlen($suffix)), 4);
-    if (!$loaded && extension_loaded($ext)) {
-        $loaded = $ext;
-    }
-    if (!$notloaded && !extension_loaded($ext)) {
-        // safe list for testing
-        if (in_array($ext, array('zip', 'bz2', 'sqlite', 'dbx'))) {
-            $notloaded = $ext;
-        }
-    }
-}
-
-$reg = new PEAR_Registry;
-$reg->statedir = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'checkPackagetmp';
-$dep = new PEAR_Dependency($reg);
-
-$msg = 'no error';
-$ret = $dep->checkExtension($msg, $loaded, null, 'has');
-echo 'extension 1 ok? ';
-echo $ret ? "no\n" : "yes\n";
-echo $msg . "\n";
-
-$msg = 'no error';
-$ret = $dep->checkExtension($msg, $notloaded, null, 'not');
-echo 'extension 2 ok? ';
-echo $ret ? "no\n" : "yes\n";
-echo $msg . "\n";
-
-$loadedver = phpversion($loaded);
-
-$msg = 'no error';
-$ret = $dep->checkExtension($msg, $loaded, $loadedver + 1, 'ge');
-echo 'extension 3 ok? ';
-echo $ret ? "no\n" : "yes\n";
-echo 'message : ' . ($msg == "'$loaded' PHP extension version >= " . ($loadedver + 1) .
-    " is required" ? "match\n" : "$msg\n" );
-
-$msg = 'no error';
-$ret = $dep->checkExtension($msg, $loaded, $loadedver + 1, 'ge', true);
-echo 'extension 3 optional ok? ';
-echo $ret ? "no\n" : "yes\n";
-echo 'message : ' . ($msg == "'$loaded' PHP extension version >= " . ($loadedver + 1) .
-    " is recommended to utilize some features" ? "match\n" : "$msg\n" );
-
-$msg = 'no error';
-$ret = $dep->checkExtension($msg, $loaded, $loadedver, 'ne');
-echo 'extension 4 ok? ';
-echo $ret ? "no\n" : "yes\n";
-echo 'message : ' . ($msg == "'$loaded' PHP extension version != " . $loadedver .
-    " is required" ? "match\n" : "$msg\n" );
-
-$msg = 'no error';
-$ret = $dep->checkExtension($msg, $loaded, $loadedver, 'gt');
-echo 'extension 5 ok? ';
-echo $ret ? "no\n" : "yes\n";
-echo 'message : ' . ($msg == "'$loaded' PHP extension version > " . $loadedver .
-    " is required" ? "match\n" : "$msg\n" );
-
-$msg = 'no error';
-$ret = $dep->checkExtension($msg, $loaded, $loadedver, 'gt', true);
-echo 'extension 5 optional ok? ';
-echo $ret ? "no\n" : "yes\n";
-echo 'message : ' . ($msg == "'$loaded' PHP extension version > " . $loadedver .
-    " is recommended to utilize some features" ? "match\n" : "$msg\n" );
-
-$msg = 'no error';
-$ret = $dep->checkExtension($msg, $loaded, $loadedver, 'lt');
-echo 'extension 6 ok? ';
-echo $ret ? "no\n" : "yes\n";
-echo 'message : ' . ($msg == "'$loaded' PHP extension version < " . $loadedver .
-    " is required" ? "match\n" : "$msg\n" );
-
-$msg = 'no error';
-$ret = $dep->checkExtension($msg, $loaded, $loadedver, 'lt', true);
-echo 'extension 6 optional ok? ';
-echo $ret ? "no\n" : "yes\n";
-echo 'message : ' . ($msg == "'$loaded' PHP extension version < " . $loadedver .
-    " is recommended to utilize some features" ? "match\n" : "$msg\n" );
-
-if ($loadedver == 0) {
-    echo "extension 7 ok? no\nmessage : match\n";
-    echo "extension 7 optional ok? no\nmessage : match\n";
-} else {
-    $msg = 'no error';
-    $ret = $dep->checkExtension($msg, $loaded, $loadedver - 1, 'le');
-    echo 'extension 7 ok? ';
-    echo $ret ? "no\n" : "yes\n";
-    echo 'message : ' . ($msg == "'$loaded' PHP extension version <= " . ($loadedver - 1).
-        " is required" ? "match\n" : "$msg\n");
-
-    $msg = 'no error';
-    $ret = $dep->checkExtension($msg, $loaded, $loadedver - 1, 'le', true);
-    echo 'extension 7 ok? ';
-    echo $ret ? "no\n" : "yes\n";
-    echo 'message : ' . ($msg == "'$loaded' PHP extension version <= " . ($loadedver - 1).
-        " is recommended to utilize some features" ? "match\n" : "$msg\n");
-}
-
-$msg = 'no error';
-$ret = $dep->checkExtension($msg, $loaded, $loadedver, 'eq');
-echo 'extension 8 ok? ';
-echo $ret ? "no\n" : "yes\n";
-echo $msg . "\n";
-
-$msg = 'no error';
-$ret = $dep->checkExtension($msg, $notloaded, $loadedver, 'ne');
-echo 'extension 9 ok? ';
-echo $ret ? "no\n" : "yes\n";
-echo $msg . "\n";
-
-$msg = 'no error';
-$ret = $dep->checkExtension($msg, $loaded, $loadedver + 1, 'eq');
-echo 'extension 10 ok? ';
-echo $ret ? "no\n" : "yes\n";
-echo 'message : ' . ($msg == "'$loaded' PHP extension version == " . ($loadedver + 1).
-        " is required" ? "match\n" : "$msg\n");
-
-$msg = 'no error';
-$ret = $dep->checkExtension($msg, $loaded, $loadedver + 1, 'eq', true);
-echo 'extension 10 optional ok? ';
-echo $ret ? "no\n" : "yes\n";
-echo 'message : ' . ($msg == "'$loaded' PHP extension version == " . ($loadedver + 1).
-        " is recommended to utilize some features" ? "match\n" : "$msg\n");
-
-cleanall();
-// ------------------------------------------------------------------------- //
-
-function cleanall()
-{
-    $dp = opendir(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'checkPackagetmp');
-    while ($ent = readdir($dp)) {
-        if (substr($ent, -4) == ".reg") {
-            unlink(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'checkPackagetmp' . DIRECTORY_SEPARATOR . $ent);
-        }
-    }
-    closedir($dp);
-    rmdir(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'checkPackagetmp');
-}
-
-?>
---GET--
---POST--
---EXPECT--
-extension 1 ok? yes
-no error
-extension 2 ok? yes
-no error
-extension 3 ok? no
-message : match
-extension 3 optional ok? no
-message : match
-extension 4 ok? no
-message : match
-extension 5 ok? no
-message : match
-extension 5 optional ok? no
-message : match
-extension 6 ok? no
-message : match
-extension 6 optional ok? no
-message : match
-extension 7 ok? no
-message : match
-extension 7 optional ok? no
-message : match
-extension 8 ok? yes
-no error
-extension 9 ok? yes
-no error
-extension 10 ok? no
-message : match
-extension 10 optional ok? no
-message : match
diff --git a/pear/tests/pear_dependency_checkPackage.phpt b/pear/tests/pear_dependency_checkPackage.phpt
deleted file mode 100644 (file)
index 1bb2120..0000000
+++ /dev/null
@@ -1,269 +0,0 @@
---TEST--
-PEAR_Dependency::checkPackage() test
---SKIPIF--
-<?php
-if (!getenv('PHP_PEAR_RUNTESTS')) {
-    echo 'skip';
-}
-?>
---FILE--
-<?php
-require_once "PEAR/Registry.php";
-require_once "PEAR/Dependency.php";
-
-mkdir(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'checkPackagetmp');
-// snarfed from pear_registry.phpt
-$reg = new PEAR_Registry;
-$reg->statedir = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'checkPackagetmp';
-
-$files1 = array(
-    "pkg1-1.php" => array(
-        "role" => "php",
-        ),
-    "pkg1-2.php" => array(
-        "role" => "php",
-        "baseinstalldir" => "pkg1",
-        ),
-    );
-$reg->addPackage("pkg1", array("name" => "pkg1", "version" => "1.0", "filelist" => $files1));
-
-$dep = new PEAR_Dependency($reg);
-$msg = 'no error';
-$ret = $dep->checkPackage($msg, 'pkg1');
-echo 'has works? ';
-echo $ret ? "no\n" : "yes\n";
-echo $msg . "\n";
-
-$msg = 'no error';
-$ret = $dep->checkPackage($msg, 'pkg1', '1.0', 'eq');
-echo 'eq 1.0 works? ';
-echo $ret ? "no\n" : "yes\n";
-echo $msg . "\n";
-
-$msg = 'no error';
-$ret = $dep->checkPackage($msg, 'pkg1', '1.0', 'le');
-echo 'le 1.0 works? ';
-echo $ret ? "no\n" : "yes\n";
-echo $msg . "\n";
-
-$msg = 'no error';
-$ret = $dep->checkPackage($msg, 'pkg1', '1.1', 'lt');
-echo 'lt 1.1 works? ';
-echo $ret ? "no\n" : "yes\n";
-echo $msg . "\n";
-
-$msg = 'no error';
-$ret = $dep->checkPackage($msg, 'pkg1', '1.1', 'ne');
-echo 'ne 1.1 works? ';
-echo $ret ? "no\n" : "yes\n";
-echo $msg . "\n";
-
-$msg = 'no error';
-$ret = $dep->checkPackage($msg, 'pkg1', '1.0', 'ge');
-echo 'ge 1.0 works? ';
-echo $ret ? "no\n" : "yes\n";
-echo $msg . "\n";
-
-$msg = 'no error';
-$ret = $dep->checkPackage($msg, 'pkg1', '0.9', 'gt');
-echo 'ge 0.9 works? ';
-echo $ret ? "no\n" : "yes\n";
-echo $msg . "\n";
-
-$msg = 'no error';
-$ret = $dep->checkPackage($msg, 'pkg2', null, 'not');
-echo 'not pkg2 works? ';
-echo $ret ? "no\n" : "yes\n";
-echo $msg . "\n";
-
-// error conditions
-
-$msg = 'no error';
-$ret = $dep->checkPackage($msg, 'pkg2', null, 'has');
-echo 'has pkg2 works? ';
-echo $ret ? "no\n" : "yes\n";
-echo '$ret is PEAR_DEPENDENCY_MISSING? ';
-echo ($ret == PEAR_DEPENDENCY_MISSING) ? "yes\n" : "no\n";
-echo $msg . "\n";
-
-$msg = 'no error';
-$ret = $dep->checkPackage($msg, 'pkg2', null, 'has', true);
-echo 'has optional pkg2 works? ';
-echo $ret ? "no\n" : "yes\n";
-echo '$ret is PEAR_DEPENDENCY_MISSING_OPTIONAL? ';
-echo ($ret == PEAR_DEPENDENCY_MISSING_OPTIONAL) ? "yes\n" : "no\n";
-echo $msg . "\n";
-
-$msg = 'no error';
-$ret = $dep->checkPackage($msg, 'pkg1', '0.9', 'le');
-echo 'le 0.9 works? ';
-echo $ret ? "no\n" : "yes\n";
-echo '$ret is PEAR_DEPENDENCY_CONFLICT? ';
-echo ($ret == PEAR_DEPENDENCY_CONFLICT) ? "yes\n" : "no\n";
-echo $msg . "\n";
-
-$msg = 'no error';
-$ret = $dep->checkPackage($msg, 'pkg1', '0.9', 'le', true);
-echo 'optional le 0.9 works? ';
-echo $ret ? "no\n" : "yes\n";
-echo '$ret is PEAR_DEPENDENCY_CONFLICT_OPTIONAL? ';
-echo ($ret == PEAR_DEPENDENCY_CONFLICT_OPTIONAL) ? "yes\n" : "no\n";
-echo $msg . "\n";
-
-$msg = 'no error';
-$ret = $dep->checkPackage($msg, 'pkg1', '1.0', 'ne');
-echo 'ne 1.0 works? ';
-echo $ret ? "no\n" : "yes\n";
-echo '$ret is PEAR_DEPENDENCY_CONFLICT? ';
-echo ($ret == PEAR_DEPENDENCY_CONFLICT) ? "yes\n" : "no\n";
-echo $msg . "\n";
-
-$msg = 'no error';
-$ret = $dep->checkPackage($msg, 'pkg1', '1.0', 'ne', true);
-echo 'optional ne 1.0 works? ';
-echo $ret ? "no\n" : "yes\n";
-echo '$ret is PEAR_DEPENDENCY_CONFLICT_OPTIONAL? ';
-echo ($ret == PEAR_DEPENDENCY_CONFLICT_OPTIONAL) ? "yes\n" : "no\n";
-echo $msg . "\n";
-
-$msg = 'no error';
-$ret = $dep->checkPackage($msg, 'pkg1', '1.1', 'ge');
-echo 'ge 1.1 works? ';
-echo $ret ? "no\n" : "yes\n";
-echo '$ret is PEAR_DEPENDENCY_UPGRADE_MINOR? ';
-echo ($ret == PEAR_DEPENDENCY_UPGRADE_MINOR) ? "yes\n" : "no\n";
-echo $msg . "\n";
-
-$msg = 'no error';
-$ret = $dep->checkPackage($msg, 'pkg1', '1.1', 'ge', true);
-echo 'optional ge 1.1 works? ';
-echo $ret ? "no\n" : "yes\n";
-echo '$ret is PEAR_DEPENDENCY_UPGRADE_MINOR_OPTIONAL? ';
-echo ($ret == PEAR_DEPENDENCY_UPGRADE_MINOR_OPTIONAL) ? "yes\n" : "no\n";
-echo $msg . "\n";
-
-$msg = 'no error';
-$ret = $dep->checkPackage($msg, 'pkg1', '2.0', 'ge');
-echo 'ge 2.0 works? ';
-echo $ret ? "no\n" : "yes\n";
-echo '$ret is PEAR_DEPENDENCY_UPGRADE_MAJOR? ';
-echo ($ret == PEAR_DEPENDENCY_UPGRADE_MAJOR) ? "yes\n" : "no\n";
-echo $msg . "\n";
-
-$msg = 'no error';
-$ret = $dep->checkPackage($msg, 'pkg1', '2.0', 'ge', true);
-echo 'optional ge 2.0 works? ';
-echo $ret ? "no\n" : "yes\n";
-echo '$ret is PEAR_DEPENDENCY_UPGRADE_MAJOR_OPTIONAL? ';
-echo ($ret == PEAR_DEPENDENCY_UPGRADE_MAJOR_OPTIONAL) ? "yes\n" : "no\n";
-echo $msg . "\n";
-
-$msg = 'no error';
-$ret = $dep->checkPackage($msg, 'pkg1', '1.0', 'gt');
-echo 'gt 1.0 works? ';
-echo $ret ? "no\n" : "yes\n";
-echo '$ret is PEAR_DEPENDENCY_UPGRADE_MINOR? ';
-echo ($ret == PEAR_DEPENDENCY_UPGRADE_MINOR) ? "yes\n" : "no\n";
-echo $msg . "\n";
-
-$msg = 'no error';
-$ret = $dep->checkPackage($msg, 'pkg1', '1.0', 'gt', true);
-echo 'optional gt 1.0 works? ';
-echo $ret ? "no\n" : "yes\n";
-echo '$ret is PEAR_DEPENDENCY_UPGRADE_MINOR_OPTIONAL? ';
-echo ($ret == PEAR_DEPENDENCY_UPGRADE_MINOR_OPTIONAL) ? "yes\n" : "no\n";
-echo $msg . "\n";
-
-$msg = 'no error';
-$ret = $dep->checkPackage($msg, 'pkg1', null, 'not');
-echo 'not pkg1 works? ';
-echo $ret ? "no\n" : "yes\n";
-echo '$ret is PEAR_DEPENDENCY_CONFLICT? ';
-echo ($ret == PEAR_DEPENDENCY_CONFLICT) ? "yes\n" : "no\n";
-echo $msg . "\n";
-
-$msg = 'no error';
-$ret = $dep->checkPackage($msg, 'pkg1', null, 'foobar');
-echo 'foobar pkg1 works? ';
-echo $ret ? "no\n" : "yes\n";
-echo '$ret is PEAR_DEPENDENCY_BAD_DEPENDENCY? ';
-echo ($ret == PEAR_DEPENDENCY_BAD_DEPENDENCY) ? "yes\n" : "no\n";
-echo $msg . "\n";
-cleanall();
-
-// ------------------------------------------------------------------------- //
-
-function cleanall()
-{
-    $dp = opendir(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'checkPackagetmp');
-    while ($ent = readdir($dp)) {
-        if (substr($ent, -4) == ".reg") {
-            unlink(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'checkPackagetmp' . DIRECTORY_SEPARATOR . $ent);
-        }
-    }
-    closedir($dp);
-    rmdir(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'checkPackagetmp');
-}
-
-?>
---GET--
---POST--
---EXPECT--
-has works? yes
-no error
-eq 1.0 works? yes
-no error
-le 1.0 works? yes
-no error
-lt 1.1 works? yes
-no error
-ne 1.1 works? yes
-no error
-ge 1.0 works? yes
-no error
-ge 0.9 works? yes
-no error
-not pkg2 works? yes
-no error
-has pkg2 works? no
-$ret is PEAR_DEPENDENCY_MISSING? yes
-requires package `pkg2'
-has optional pkg2 works? no
-$ret is PEAR_DEPENDENCY_MISSING_OPTIONAL? yes
-package `pkg2' is recommended to utilize some features.
-le 0.9 works? no
-$ret is PEAR_DEPENDENCY_CONFLICT? yes
-requires package `pkg1' <= 0.9
-optional le 0.9 works? no
-$ret is PEAR_DEPENDENCY_CONFLICT_OPTIONAL? yes
-package `pkg1' version <= 0.9 is recommended to utilize some features.  Installed version is 1.0
-ne 1.0 works? no
-$ret is PEAR_DEPENDENCY_CONFLICT? yes
-requires package `pkg1' != 1.0
-optional ne 1.0 works? no
-$ret is PEAR_DEPENDENCY_CONFLICT_OPTIONAL? yes
-package `pkg1' version != 1.0 is recommended to utilize some features.  Installed version is 1.0
-ge 1.1 works? no
-$ret is PEAR_DEPENDENCY_UPGRADE_MINOR? yes
-requires package `pkg1' >= 1.1
-optional ge 1.1 works? no
-$ret is PEAR_DEPENDENCY_UPGRADE_MINOR_OPTIONAL? yes
-package `pkg1' version >= 1.1 is recommended to utilize some features.  Installed version is 1.0
-ge 2.0 works? no
-$ret is PEAR_DEPENDENCY_UPGRADE_MAJOR? yes
-requires package `pkg1' >= 2.0
-optional ge 2.0 works? no
-$ret is PEAR_DEPENDENCY_UPGRADE_MAJOR_OPTIONAL? yes
-package `pkg1' version >= 2.0 is recommended to utilize some features.  Installed version is 1.0
-gt 1.0 works? no
-$ret is PEAR_DEPENDENCY_UPGRADE_MINOR? yes
-requires package `pkg1' > 1.0
-optional gt 1.0 works? no
-$ret is PEAR_DEPENDENCY_UPGRADE_MINOR_OPTIONAL? yes
-package `pkg1' version > 1.0 is recommended to utilize some features.  Installed version is 1.0
-not pkg1 works? no
-$ret is PEAR_DEPENDENCY_CONFLICT? yes
-conflicts with package `pkg1'
-foobar pkg1 works? no
-$ret is PEAR_DEPENDENCY_BAD_DEPENDENCY? yes
-relation 'foobar' with requirement '' is not supported (name=pkg1)
diff --git a/pear/tests/pear_dependency_checkPackageUninstall.phpt b/pear/tests/pear_dependency_checkPackageUninstall.phpt
deleted file mode 100644 (file)
index 0206733..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
---TEST--
-PEAR_Dependency::checkPackageUninstall() test
---SKIPIF--
-<?php
-if (!getenv('PHP_PEAR_RUNTESTS')) {
-    echo 'skip';
-}
-?>
---FILE--
-<?php
-
-require_once "PEAR/Registry.php";
-require_once "PEAR/Dependency.php";
-
-// snarfed from pear_registry.phpt
-$reg = new PEAR_Registry;
-@mkdir(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'checkPackagetmp');
-$reg->statedir = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'checkPackagetmp';
-
-$files1 = array(
-    "pkg1-1.php" => array(
-        "role" => "php",
-        ),
-    "pkg1-2.php" => array(
-        "role" => "php",
-        "baseinstalldir" => "pkg1",
-        ),
-    );
-$files2 = array(
-    "pkg2-1.php" => array(
-        "role" => "php",
-        ),
-    "pkg2-2.php" => array(
-        "role" => "php",
-        "baseinstalldir" => "pkg2",
-        ),
-    );
-$files3 = array(
-    "pkg3-1.php" => array(
-        "role" => "php",
-        ),
-    "pkg3-2.php" => array(
-        "role" => "php",
-        "baseinstalldir" => "pkg3",
-        ),
-    );
-
-$reg->addPackage("pkg2", array("name" => "pkg2", "version" => "2.0", "filelist" => $files2));
-$reg->addPackage("pkg3", array("name" => "pkg3", "version" => "3.0", "filelist" => $files3));
-
-$reg->addPackage("pkg1", array("name" => "pkg1", "version" => "1.0", "filelist" => $files1,
-    'release_deps' => array(
-        array('type' => 'pkg', 'name' => 'pkg3', 'rel' => 'not')
-        )));
-
-$dep = new PEAR_Dependency($reg);
-$msg = '';
-$warn = '';
-$ret = $dep->checkPackageUninstall($msg, $warn, 'pkg1');
-echo 'uninstall ok? ';
-echo $ret ? "no\n" : "yes\n";
-echo $msg . "\n";
-echo $warn . "\n";
-
-cleanall();
-
-$reg->addPackage("pkg2", array("name" => "pkg2", "version" => "2.0", "filelist" => $files2));
-$reg->addPackage("pkg3", array("name" => "pkg3", "version" => "3.0", "filelist" => $files3));
-
-$reg->addPackage("pkg1", array("name" => "pkg1", "version" => "1.0", "filelist" => $files1,
-    'release_deps' => array(
-        array('type' => 'pkg', 'name' => 'pkg2', 'rel' => 'ne', 'version' => '6.0')
-        )));
-
-$dep = new PEAR_Dependency($reg);
-$msg = '';
-$warn = '';
-$ret = $dep->checkPackageUninstall($msg, $warn, 'pkg2');
-echo 'uninstall ok? ';
-echo $ret ? "no\n" : "yes\n";
-echo $msg . "\n";
-echo $warn . "\n";
-
-cleanall();
-
-$reg->addPackage("pkg2", array("name" => "pkg2", "version" => "2.0", "filelist" => $files2));
-$reg->addPackage("pkg3", array("name" => "pkg3", "version" => "3.0", "filelist" => $files3));
-
-$reg->addPackage("pkg1", array("name" => "pkg1", "version" => "1.0", "filelist" => $files1,
-    'release_deps' => array(
-        array('type' => 'pkg', 'name' => 'pkg2', 'rel' => 'has')
-        )));
-
-$dep = new PEAR_Dependency($reg);
-$msg = '';
-$warn = '';
-$ret = $dep->checkPackageUninstall($msg, $warn, 'pkg2');
-echo 'uninstall ok? ';
-echo $ret ? "no\n" : "yes\n";
-echo $msg . "\n";
-echo $warn . "\n";
-
-cleanall();
-
-$reg->addPackage("pkg2", array("name" => "pkg2", "version" => "2.0", "filelist" => $files2));
-$reg->addPackage("pkg3", array("name" => "pkg3", "version" => "3.0", "filelist" => $files3));
-
-$reg->addPackage("pkg1", array("name" => "pkg1", "version" => "1.0", "filelist" => $files1,
-    'release_deps' => array(
-        array('type' => 'pkg', 'name' => 'pkg2', 'rel' => 'has', 'optional' => 'no')
-        )));
-
-$dep = new PEAR_Dependency($reg);
-$msg = '';
-$warn = '';
-$ret = $dep->checkPackageUninstall($msg, $warn, 'pkg2');
-echo 'uninstall ok? ';
-echo $ret ? "no\n" : "yes\n";
-echo $msg . "\n";
-echo $warn . "\n";
-
-cleanall();
-
-$reg->addPackage("pkg2", array("name" => "pkg2", "version" => "2.0", "filelist" => $files2));
-$reg->addPackage("pkg3", array("name" => "pkg3", "version" => "3.0", "filelist" => $files3));
-
-$reg->addPackage("pkg1", array("name" => "pkg1", "version" => "1.0", "filelist" => $files1,
-    'release_deps' => array(
-        array('type' => 'pkg', 'name' => 'pkg2', 'rel' => 'has', 'optional' => 'yes')
-        )));
-
-$dep = new PEAR_Dependency($reg);
-$msg = '';
-$warn = '';
-$ret = $dep->checkPackageUninstall($msg, $warn, 'pkg2');
-echo 'uninstall ok? ';
-echo $ret ? "no\n" : "yes\n";
-echo $msg . "\n";
-echo $warn . "\n";
-
-cleanall();
-
-// ------------------------------------------------------------------------- //
-
-function cleanall()
-{
-    $dp = opendir(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'checkPackagetmp');
-    while ($ent = readdir($dp)) {
-        if (substr($ent, -4) == ".reg") {
-            unlink(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'checkPackagetmp' . DIRECTORY_SEPARATOR . $ent);
-        }
-    }
-    closedir($dp);
-    rmdir(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'checkPackagetmp');
-}
-
-?>
---GET--
---POST--
---EXPECT--
-uninstall ok? yes
-
-
-uninstall ok? yes
-
-
-uninstall ok? no
-Package 'pkg1' depends on 'pkg2'
-
-
-uninstall ok? no
-Package 'pkg1' depends on 'pkg2'
-
-
-uninstall ok? yes
-
-
-Warning: Package 'pkg1' optionally depends on 'pkg2'
\ No newline at end of file
diff --git a/pear/tests/pear_downloader_invalid.phpt b/pear/tests/pear_downloader_invalid.phpt
deleted file mode 100644 (file)
index 04e41c0..0000000
+++ /dev/null
@@ -1,366 +0,0 @@
---TEST--
-PEAR_Downloader::download() invalid values test
---SKIPIF--
-<?php
-if (!getenv('PHP_PEAR_RUNTESTS')) {
-    echo 'skip';
-}
-?>
---FILE--
-<?php
-
-$server = 'pear.Chiara';
-//$server = 'test.pear.php.net';
-$temp_path = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'testinstallertemp';
-if (!is_dir($temp_path)) {
-    mkdir($temp_path);
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'php')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'php');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'data')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'data');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'doc')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'doc');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'test')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'test');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'ext')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'ext');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'script')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'script');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'tmp')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'tmp');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'bin')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'bin');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'cache')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'cache');
-}
-// make the fake configuration - we'll use one of these and it should work
-$config = serialize(array('master_server' => $server,
-    'preferred_state' => 'stable',
-    'cache_dir' => $temp_path . DIRECTORY_SEPARATOR . 'cache',
-    'php_dir' => $temp_path . DIRECTORY_SEPARATOR . 'php',
-    'ext_dir' => $temp_path . DIRECTORY_SEPARATOR . 'ext',
-    'data_dir' => $temp_path . DIRECTORY_SEPARATOR . 'data',
-    'doc_dir' => $temp_path . DIRECTORY_SEPARATOR . 'doc',
-    'test_dir' => $temp_path . DIRECTORY_SEPARATOR . 'test',
-    'bin_dir' => $temp_path . DIRECTORY_SEPARATOR . 'bin',));
-touch($temp_path . DIRECTORY_SEPARATOR . 'pear.conf');
-$fp = fopen($temp_path . DIRECTORY_SEPARATOR . 'pear.conf', 'w');
-fwrite($fp, $config);
-fclose($fp);
-touch($temp_path . DIRECTORY_SEPARATOR . 'pear.ini');
-$fp = fopen($temp_path . DIRECTORY_SEPARATOR . 'pear.ini', 'w');
-fwrite($fp, $config);
-fclose($fp);
-
-putenv('PHP_PEAR_SYSCONF_DIR='.$temp_path);
-$home = getenv('HOME');
-if (!empty($home)) {
-    // for PEAR_Config initialization
-    putenv('HOME="'.$temp_path);
-}
-require_once "PEAR/Downloader.php";
-
-// no UI is needed for these tests
-$ui = false;
-$curdir = getcwd();
-chdir(dirname(__FILE__));
-
-PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'catchit');
-$error_to_catch = false;
-function catchit($err)
-{
-    global $error_to_catch;
-    if ($error_to_catch) {
-        if ($err->getMessage() == $error_to_catch) {
-            $error_to_catch = false;
-            echo "Caught expected error\n";
-            return;
-        }
-    }
-    echo "Caught error: " . $err->getMessage() . "\n";
-}
-
-$config = &PEAR_Config::singleton();
-$options = array();
-$installer = &new PEAR_Downloader($ui, $options, $config);
-
-echo "-=-=-=-=-=-=-=-=- Failure Tests -=-=-=-=-=-=-=-=-=-=-\n";
-
-echo "Test invalid package name:\n";
-$packages = array("/invalid+packagename");
-$a = $installer->download($packages);
-$installpackages = $installer->getDownloadedPackages();
-var_dump(get_class($a), $installer->getErrorMsgs(), $installpackages);
-
-echo "Test download of a package with no releases:\n";
-$packages = array("noreleases");
-$a = $installer->download($packages);
-$installpackages = $installer->getDownloadedPackages();
-var_dump(get_class($a), $installer->getErrorMsgs(), $installpackages);
-
-echo "Test download of a non-existing package version:\n";
-$packages = array("pkg1-1976.9.2");
-$a = $installer->download($packages);
-$installpackages = $installer->getDownloadedPackages();
-var_dump(get_class($a), $installer->getErrorMsgs(), $installpackages);
-
-echo "Test download of a non-existing package release state:\n";
-$packages = array("pkg1-snapshot");
-$a = $installer->download($packages);
-$installpackages = $installer->getDownloadedPackages();
-var_dump(get_class($a), $installer->getErrorMsgs(), $installpackages);
-
-echo "Test download of invalid release state:\n";
-$packages = array("pkg1-burgerking");
-$a = $installer->download($packages);
-$installpackages = $installer->getDownloadedPackages();
-var_dump(get_class($a), $installer->getErrorMsgs(), $installpackages);
-
-$installer->configSet('preferred_state', 'stable');
-
-echo "Test automatic version resolution (stable):\n";
-$packages = array("stabilitytoolow");
-$a = $installer->download($packages);
-$installpackages = $installer->getDownloadedPackages();
-var_dump(get_class($a), $installer->getErrorMsgs(), $installpackages);
-
-echo "Test automatic version resolution (stable) with --force:\n";
-$packages = array("stabilitytoolow");
-$installer->setOptions(array('force' => true));
-$a = $installer->download($packages);
-$installpackages = $installer->getDownloadedPackages();
-var_dump(get_class($a), $installer->getErrorMsgs(), $installpackages[0]['info']['version']);
-
-$installer->configSet('preferred_state', 'beta');
-
-echo "Test automatic version resolution (beta):\n";
-$packages = array("stabilitytoolow");
-$a = $installer->download($packages);
-$installpackages = $installer->getDownloadedPackages();
-var_dump(get_class($a), $installer->getErrorMsgs(), $installpackages[0]['info']['version']);
-
-$installer->configSet('preferred_state', 'alpha');
-
-echo "Test automatic version resolution (alpha):\n";
-$packages = array("stabilitytoolow");
-$a = $installer->download($packages);
-$installpackages = $installer->getDownloadedPackages();
-var_dump(get_class($a), $installer->getErrorMsgs(), $installpackages[0]['info']['version']);
-
-$installer->configSet('preferred_state', 'devel');
-
-echo "Test automatic version resolution (devel):\n";
-$packages = array("stabilitytoolow");
-$a = $installer->download($packages);
-$installpackages = $installer->getDownloadedPackages();
-var_dump(get_class($a), $installer->getErrorMsgs(), $installpackages[0]['info']['version']);
-
-echo "Test download attempt if a version is already installed:\n";
-
-require_once 'PEAR/Installer.php';
-$install = &new PEAR_Installer($ui);
-$installer->setOptions(array());
-
-$installer->download(array('pkg6'));
-$pkgs = $installer->getDownloadedPackages();
-$install->install($pkgs[0]['file']);
-$installer->download(array('pkg6'));
-var_dump(get_class($a), $installer->getErrorMsgs());
-
-echo "Test download attempt if a version is already installed with --force:\n";
-
-$installer->setOptions(array('force' => true));
-
-$installer->download(array('pkg6'));
-$pkgs = $installer->getDownloadedPackages();
-var_dump(get_class($a), $installer->getErrorMsgs(), $pkgs[0]['info']['version']);
-
-echo "Test download attempt if a version is already installed with upgrade, same version:\n";
-
-$installer->setOptions(array('upgrade' => true));
-
-$installer->download(array('pkg6'));
-$pkgs = $installer->getDownloadedPackages();
-var_dump(get_class($a), $installer->getErrorMsgs());
-
-echo "Test download attempt if a version is already installed with upgrade, lesser version:\n";
-
-$installer->setOptions(array('upgrade' => true));
-
-$installer->download(array('pkg6-1.1'));
-$pkgs = $installer->getDownloadedPackages();
-var_dump(get_class($a), $installer->getErrorMsgs());
-
-echo "Test download attempt with --alldeps, but dependency has no releases:\n";
-
-$installer->setOptions(array('alldeps' => true));
-
-$installer->download(array('depnoreleases'));
-$pkgs = $installer->getDownloadedPackages();
-var_dump(get_class($a), $installer->getErrorMsgs());
-
-echo "Test download attempt with --onlyreqdeps, but dependency has no releases:\n";
-
-$installer->setOptions(array('onlyreqdeps' => true));
-
-$installer->download(array('depnoreleases'));
-$pkgs = $installer->getDownloadedPackages();
-var_dump(get_class($a), $installer->getErrorMsgs());
-
-$installer->configSet('preferred_state', 'stable');
-echo "Test download attempt with --alldeps, but dependency is too unstable:\n";
-$installer->setOptions(array('alldeps' => true));
-
-$installer->download(array('depunstable'));
-$pkgs = $installer->getDownloadedPackages();
-var_dump(get_class($a), $installer->getErrorMsgs());
-
-echo "Test download attempt with --onlyreqdeps, but dependency is too unstable:\n";
-
-$installer->setOptions(array('onlyreqdeps' => true));
-
-$installer->download(array('depunstable'));
-$pkgs = $installer->getDownloadedPackages();
-var_dump(get_class($a), $installer->getErrorMsgs());
-
-chdir($curdir);
-cleanall($temp_path);
-// ------------------------------------------------------------------------- //
-
-function cleanall($dir)
-{
-    $dp = opendir($dir);
-    while ($ent = readdir($dp)) {
-        if ($ent == '.' || $ent == '..') {
-            continue;
-        }
-        if (is_dir($dir . DIRECTORY_SEPARATOR . $ent)) {
-            cleanall($dir . DIRECTORY_SEPARATOR . $ent);
-        } else {
-            unlink($dir . DIRECTORY_SEPARATOR . $ent);
-        }
-    }
-    closedir($dp);
-    rmdir($dir);
-}
-?>
---GET--
---POST--
---EXPECT--
--=-=-=-=-=-=-=-=- Failure Tests -=-=-=-=-=-=-=-=-=-=-
-Test invalid package name:
-Caught error: Package name '/invalid+packagename' not valid
-string(10) "pear_error"
-array(0) {
-}
-array(0) {
-}
-Test download of a package with no releases:
-Caught error: No releases found for package 'noreleases'
-string(10) "pear_error"
-array(0) {
-}
-array(0) {
-}
-Test download of a non-existing package version:
-Caught error: No release with version '1976.9.2' found for 'pkg1'
-string(10) "pear_error"
-array(0) {
-}
-array(0) {
-}
-Test download of a non-existing package release state:
-Caught error: No release with state 'snapshot' found for 'pkg1'
-string(10) "pear_error"
-array(0) {
-}
-array(0) {
-}
-Test download of invalid release state:
-Caught error: Invalid postfix '-burgerking', be sure to pass a valid PEAR version number or release state
-string(10) "pear_error"
-array(0) {
-}
-array(0) {
-}
-Test automatic version resolution (stable):
-Caught error: No release with state equal to: 'stable' found for 'stabilitytoolow'
-string(10) "pear_error"
-array(0) {
-}
-array(0) {
-}
-Test automatic version resolution (stable) with --force:
-Warning: stabilitytoolow is state 'devel' which is less stable than state 'stable'
-bool(false)
-array(0) {
-}
-string(6) "3.0dev"
-Test automatic version resolution (beta):
-bool(false)
-array(0) {
-}
-string(5) "1.0b1"
-Test automatic version resolution (alpha):
-bool(false)
-array(0) {
-}
-string(5) "2.0a1"
-Test automatic version resolution (devel):
-bool(false)
-array(0) {
-}
-string(6) "3.0dev"
-Test download attempt if a version is already installed:
-Package 'pkg6' already installed, skipping
-bool(false)
-array(0) {
-}
-Test download attempt if a version is already installed with --force:
-bool(false)
-array(0) {
-}
-string(5) "2.0b1"
-Test download attempt if a version is already installed with upgrade, same version:
-Package 'pkg6-2.0b1' already installed, skipping
-bool(false)
-array(0) {
-}
-Test download attempt if a version is already installed with upgrade, lesser version:
-Package 'pkg6' version '2.0b1'  is installed and 2.0b1 is > requested '1.1', skipping
-bool(false)
-array(0) {
-}
-Test download attempt with --alldeps, but dependency has no releases:
-bool(false)
-array(1) {
-  [0]=>
-  string(63) "Package 'depnoreleases' dependency 'noreleases' has no releases"
-}
-Test download attempt with --onlyreqdeps, but dependency has no releases:
-bool(false)
-array(1) {
-  [0]=>
-  string(63) "Package 'depnoreleases' dependency 'noreleases' has no releases"
-}
-Test download attempt with --alldeps, but dependency is too unstable:
-bool(false)
-array(1) {
-  [0]=>
-  string(91) "Release for 'depunstable' dependency 'stabilitytoolow' has state 'devel', requires 'stable'"
-}
-Test download attempt with --onlyreqdeps, but dependency is too unstable:
-bool(false)
-array(1) {
-  [0]=>
-  string(91) "Release for 'depunstable' dependency 'stabilitytoolow' has state 'devel', requires 'stable'"
-}
\ No newline at end of file
diff --git a/pear/tests/pear_downloader_new.phpt b/pear/tests/pear_downloader_new.phpt
deleted file mode 100644 (file)
index 4d6e8c7..0000000
+++ /dev/null
@@ -1,570 +0,0 @@
---TEST--
-PEAR_Downloader::download() test
---SKIPIF--
-<?php
-if (!getenv('PHP_PEAR_RUNTESTS')) {
-    echo 'skip';
-}
-?>
---FILE--
-<?php
-
-$server = 'pear.Chiara';
-//$server = 'test.pear.php.net';
-$temp_path = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'testinstallertemp';
-if (!is_dir($temp_path)) {
-    mkdir($temp_path);
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'php')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'php');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'data')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'data');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'doc')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'doc');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'test')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'test');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'ext')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'ext');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'script')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'script');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'tmp')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'tmp');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'bin')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'bin');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'cache')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'cache');
-}
-// make the fake configuration - we'll use one of these and it should work
-$config = serialize(array('master_server' => $server,
-    'preferred_state' => 'stable',
-    'cache_dir' => $temp_path . DIRECTORY_SEPARATOR . 'cache',
-    'php_dir' => $temp_path . DIRECTORY_SEPARATOR . 'php',
-    'ext_dir' => $temp_path . DIRECTORY_SEPARATOR . 'ext',
-    'data_dir' => $temp_path . DIRECTORY_SEPARATOR . 'data',
-    'doc_dir' => $temp_path . DIRECTORY_SEPARATOR . 'doc',
-    'test_dir' => $temp_path . DIRECTORY_SEPARATOR . 'test',
-    'bin_dir' => $temp_path . DIRECTORY_SEPARATOR . 'bin',));
-touch($temp_path . DIRECTORY_SEPARATOR . 'pear.conf');
-$fp = fopen($temp_path . DIRECTORY_SEPARATOR . 'pear.conf', 'w');
-fwrite($fp, $config);
-fclose($fp);
-touch($temp_path . DIRECTORY_SEPARATOR . 'pear.ini');
-$fp = fopen($temp_path . DIRECTORY_SEPARATOR . 'pear.ini', 'w');
-fwrite($fp, $config);
-fclose($fp);
-
-putenv('PHP_PEAR_SYSCONF_DIR='.$temp_path);
-$home = getenv('HOME');
-if (!empty($home)) {
-    // for PEAR_Config initialization
-    putenv('HOME="'.$temp_path);
-}
-require_once "PEAR/Downloader.php";
-
-// no UI is needed for these tests
-$ui = false;
-$curdir = getcwd();
-chdir(dirname(__FILE__));
-
-PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'catchit');
-$error_to_catch = false;
-function catchit($err)
-{
-    global $error_to_catch;
-    if ($error_to_catch) {
-        if ($err->getMessage() == $error_to_catch) {
-            $error_to_catch = false;
-            echo "Caught expected error\n";
-            return;
-        }
-    }
-    echo "Caught error: " . $err->getMessage() . "\n";
-}
-
-echo "Test simple direct url download:\n";
-
-$config = &PEAR_Config::singleton();
-$packages = array("http://$server/get/pkg6-1.1.tgz");
-$options = array();
-$installer = &new PEAR_Downloader($ui, $options, $config);
-$a = $installer->download($packages);
-$installpackages = $installer->getDownloadedPackages();
-var_dump($a, $installer->getErrorMsgs());
-
-echo "File exists? ";
-echo (is_file($installpackages[0]['file'])) ? "yes\n" : "no\n";
-echo "File is the same? ";
-$good = implode('', file(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'test-pkg6' . DIRECTORY_SEPARATOR . 'pkg6-1.1.tgz'));
-$dled = implode('', file($installpackages[0]['file']));
-echo ($good == $dled) ? "yes\n" : "no\n";
-unlink($installpackages[0]['file']);
-unset($installpackages[0]['file']);
-var_dump($installpackages);
-
-echo "Test simple package name download:\n";
-$installpackages = $errors = array();
-$packages = array('pkg6');
-$a = $installer->download($packages);
-$installpackages = $installer->getDownloadedPackages();
-var_dump($a, $installer->getErrorMsgs());
-
-echo "File exists? ";
-echo (is_file($installpackages[0]['file'])) ? "yes\n" : "no\n";
-echo "File is the same? ";
-$good = implode('', file(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'test-pkg6' . DIRECTORY_SEPARATOR . 'pkg6-1.1.tgz'));
-$dled = implode('', file($installpackages[0]['file']));
-echo ($good == $dled) ? "yes\n" : "no\n";
-unlink($installpackages[0]['file']);
-unset($installpackages[0]['file']);
-var_dump($installpackages);
-
-echo "Test package name with version download:\n";
-$installpackages = $errors = array();
-$packages = array('pkg6-1.1');
-$a = $installer->download($packages);
-$installpackages = $installer->getDownloadedPackages();
-var_dump($a, $installer->getErrorMsgs());
-
-echo "File exists? ";
-echo (is_file($installpackages[0]['file'])) ? "yes\n" : "no\n";
-echo "File is the same? ";
-$good = implode('', file(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'test-pkg6' . DIRECTORY_SEPARATOR . 'pkg6-1.1.tgz'));
-$dled = implode('', file($installpackages[0]['file']));
-echo ($good == $dled) ? "yes\n" : "no\n";
-unlink($installpackages[0]['file']);
-
-echo "Test package name with state stable download:\n";
-$installpackages = $errors = array();
-$packages = array('pkg6-stable');
-$a = $installer->download($packages);
-$installpackages = $installer->getDownloadedPackages();
-var_dump($a, $installer->getErrorMsgs());
-
-echo "File exists? ";
-echo (is_file($installpackages[0]['file'])) ? "yes\n" : "no\n";
-echo "File is the same? ";
-$good = implode('', file(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'test-pkg6' . DIRECTORY_SEPARATOR . 'pkg6-1.1.tgz'));
-$dled = implode('', file($installpackages[0]['file']));
-echo ($good == $dled) ? "yes\n" : "no\n";
-unlink($installpackages[0]['file']);
-
-echo "Test package name with state beta download:\n";
-$installpackages = $errors = array();
-$packages = array('pkg6-beta');
-$a = $installer->download($packages);
-$installpackages = $installer->getDownloadedPackages();
-var_dump($a, $installer->getErrorMsgs());
-
-echo "File exists? ";
-echo (is_file($installpackages[0]['file'])) ? "yes\n" : "no\n";
-echo "File is the same? ";
-$good = implode('', file(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'test-pkg6' . DIRECTORY_SEPARATOR . 'pkg6-2.0b1.tgz'));
-$dled = implode('', file($installpackages[0]['file']));
-echo ($good == $dled) ? "yes\n" : "no\n";
-unlink($installpackages[0]['file']);
-
-echo "================\nTest preferred_state = beta\n";
-$installer->configSet('preferred_state', 'beta');
-
-echo "Test simple package name download:\n";
-$installpackages = $errors = array();
-$packages = array('pkg6');
-$a = $installer->download($packages);
-$installpackages = $installer->getDownloadedPackages();
-var_dump($a, $installer->getErrorMsgs());
-
-echo "File exists? ";
-echo (is_file($installpackages[0]['file'])) ? "yes\n" : "no\n";
-echo "File is the same? ";
-$good = implode('', file(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'test-pkg6' . DIRECTORY_SEPARATOR . 'pkg6-2.0b1.tgz'));
-$dled = implode('', file($installpackages[0]['file']));
-echo ($good == $dled) ? "yes\n" : "no\n";
-unlink($installpackages[0]['file']);
-unset($installpackages[0]['file']);
-
-echo "\n================Test --alldeps\nTest preferred_state = stable\n";
-$installer->configSet('preferred_state', 'stable');
-
-$installer = &new PEAR_Downloader($ui, array('alldeps' => true), $config);
-$packages = array("http://$server/get/pkg1-1.1.tgz");
-$a = $installer->download($packages);
-$installpackages = $installer->getDownloadedPackages();
-var_dump($a, $installer->getErrorMsgs());
-echo "Packages downloaded and version:\n";
-foreach ($installpackages as $package) {
-    echo $package['pkg'] . '-' . $package['info']['version'] . "\n";
-}
-$packages = array("pkg1");
-$a = $installer->download($packages);
-$installpackages = $installer->getDownloadedPackages();
-var_dump($a, $installer->getErrorMsgs());
-echo "Packages downloaded and version:\n";
-foreach ($installpackages as $package) {
-    echo $package['pkg'] . '-' . $package['info']['version'] . "\n";
-}
-
-echo "Test preferred_state = beta:\n";
-$installer->configSet('preferred_state', 'beta');
-
-$packages = array("pkg1");
-$a = $installer->download($packages);
-$installpackages = $installer->getDownloadedPackages();
-var_dump($a, $installer->getErrorMsgs());
-echo "Packages downloaded and version:\n";
-foreach ($installpackages as $package) {
-    echo $package['pkg'] . '-' . $package['info']['version'] . "\n";
-}
-
-echo "Test preferred_state = alpha:\n";
-$installer->configSet('preferred_state', 'alpha');
-
-$packages = array("pkg1");
-$a = $installer->download($packages);
-$installpackages = $installer->getDownloadedPackages();
-var_dump($a, $installer->getErrorMsgs());
-echo "Packages downloaded and version:\n";
-foreach ($installpackages as $package) {
-    echo $package['pkg'] . '-' . $package['info']['version'] . "\n";
-}
-echo "\n================Test --onlyreqdeps\nTest preferred_state = stable\n";
-$config->set('preferred_state', 'stable');
-
-$installer = &new PEAR_Downloader($ui, array('onlyreqdeps' => true), $config);
-$packages = array("http://$server/get/pkg1-1.1.tgz");
-$a = $installer->download($packages);
-$installpackages = $installer->getDownloadedPackages();
-var_dump($a, $installer->getErrorMsgs());
-echo "Packages downloaded and version:\n";
-foreach ($installpackages as $package) {
-    echo $package['pkg'] . '-' . $package['info']['version'] . "\n";
-}
-$packages = array("pkg1");
-$a = $installer->download($packages);
-$installpackages = $installer->getDownloadedPackages();
-var_dump($a, $installer->getErrorMsgs());
-echo "Packages downloaded and version:\n";
-foreach ($installpackages as $package) {
-    echo $package['pkg'] . '-' . $package['info']['version'] . "\n";
-}
-
-echo "Test preferred_state = beta:\n";
-$installer->configSet('preferred_state', 'beta');
-
-$packages = array("pkg1");
-$a = $installer->download($packages);
-$installpackages = $installer->getDownloadedPackages();
-var_dump($a, $installer->getErrorMsgs());
-echo "Packages downloaded and version:\n";
-foreach ($installpackages as $package) {
-    echo $package['pkg'] . '-' . $package['info']['version'] . "\n";
-}
-
-echo "Test preferred_state = alpha:\n";
-$installer->configSet('preferred_state', 'alpha');
-
-$packages = array("pkg1");
-$a = $installer->download($packages);
-$installpackages = $installer->getDownloadedPackages();
-var_dump($a, $installer->getErrorMsgs());
-echo "Packages downloaded and version:\n";
-foreach ($installpackages as $package) {
-    echo $package['pkg'] . '-' . $package['info']['version'] . "\n";
-}
-
-
-chdir($curdir);
-cleanall($temp_path);
-// ------------------------------------------------------------------------- //
-
-function cleanall($dir)
-{
-    $dp = opendir($dir);
-    while ($ent = readdir($dp)) {
-        if ($ent == '.' || $ent == '..') {
-            continue;
-        }
-        if (is_dir($dir . DIRECTORY_SEPARATOR . $ent)) {
-            cleanall($dir . DIRECTORY_SEPARATOR . $ent);
-        } else {
-            unlink($dir . DIRECTORY_SEPARATOR . $ent);
-        }
-    }
-    closedir($dp);
-    rmdir($dir);
-}
-?>
---GET--
---POST--
---EXPECT--
-Test simple direct url download:
-NULL
-array(0) {
-}
-File exists? yes
-File is the same? yes
-array(1) {
-  [0]=>
-  array(2) {
-    ["pkg"]=>
-    string(4) "pkg6"
-    ["info"]=>
-    array(11) {
-      ["provides"]=>
-      array(0) {
-      }
-      ["filelist"]=>
-      &array(3) {
-        ["zoorb.php"]=>
-        array(2) {
-          ["role"]=>
-          string(3) "php"
-          ["baseinstalldir"]=>
-          string(5) "groob"
-        }
-        ["goompness\oggbrzitzkee.php"]=>
-        array(2) {
-          ["role"]=>
-          string(3) "php"
-          ["baseinstalldir"]=>
-          string(5) "groob"
-        }
-        ["goompness\Mopreeb.php"]=>
-        array(2) {
-          ["role"]=>
-          string(3) "php"
-          ["baseinstalldir"]=>
-          string(5) "groob"
-        }
-      }
-      ["package"]=>
-      string(4) "pkg6"
-      ["summary"]=>
-      string(32) "required test for PEAR_Installer"
-      ["description"]=>
-      string(12) "fake package"
-      ["maintainers"]=>
-      array(1) {
-        [0]=>
-        &array(4) {
-          ["handle"]=>
-          string(8) "fakeuser"
-          ["name"]=>
-          string(9) "Joe Shmoe"
-          ["email"]=>
-          string(18) "nobody@example.com"
-          ["role"]=>
-          string(4) "lead"
-        }
-      }
-      ["version"]=>
-      string(3) "1.1"
-      ["release_date"]=>
-      string(10) "2003-09-09"
-      ["release_license"]=>
-      string(11) "PHP License"
-      ["release_state"]=>
-      string(6) "stable"
-      ["release_notes"]=>
-      string(24) "required dependency test"
-    }
-  }
-}
-Test simple package name download:
-NULL
-array(0) {
-}
-File exists? yes
-File is the same? yes
-array(1) {
-  [0]=>
-  array(2) {
-    ["pkg"]=>
-    string(4) "pkg6"
-    ["info"]=>
-    array(11) {
-      ["provides"]=>
-      array(0) {
-      }
-      ["filelist"]=>
-      &array(3) {
-        ["zoorb.php"]=>
-        array(2) {
-          ["role"]=>
-          string(3) "php"
-          ["baseinstalldir"]=>
-          string(5) "groob"
-        }
-        ["goompness\oggbrzitzkee.php"]=>
-        array(2) {
-          ["role"]=>
-          string(3) "php"
-          ["baseinstalldir"]=>
-          string(5) "groob"
-        }
-        ["goompness\Mopreeb.php"]=>
-        array(2) {
-          ["role"]=>
-          string(3) "php"
-          ["baseinstalldir"]=>
-          string(5) "groob"
-        }
-      }
-      ["package"]=>
-      string(4) "pkg6"
-      ["summary"]=>
-      string(32) "required test for PEAR_Installer"
-      ["description"]=>
-      string(12) "fake package"
-      ["maintainers"]=>
-      array(1) {
-        [0]=>
-        &array(4) {
-          ["handle"]=>
-          string(8) "fakeuser"
-          ["name"]=>
-          string(9) "Joe Shmoe"
-          ["email"]=>
-          string(18) "nobody@example.com"
-          ["role"]=>
-          string(4) "lead"
-        }
-      }
-      ["version"]=>
-      string(3) "1.1"
-      ["release_date"]=>
-      string(10) "2003-09-09"
-      ["release_license"]=>
-      string(11) "PHP License"
-      ["release_state"]=>
-      string(6) "stable"
-      ["release_notes"]=>
-      string(24) "required dependency test"
-    }
-  }
-}
-Test package name with version download:
-NULL
-array(0) {
-}
-File exists? yes
-File is the same? yes
-Test package name with state stable download:
-NULL
-array(0) {
-}
-File exists? yes
-File is the same? yes
-Test package name with state beta download:
-NULL
-array(0) {
-}
-File exists? yes
-File is the same? yes
-================
-Test preferred_state = beta
-Test simple package name download:
-NULL
-array(0) {
-}
-File exists? yes
-File is the same? yes
-
-================Test --alldeps
-Test preferred_state = stable
-NULL
-array(0) {
-}
-Packages downloaded and version:
-pkg1-1.1
-pkg2-1.1
-pkg3-1.1
-pkg4-1.1
-pkg5-1.1
-pkg6-1.1
-NULL
-array(0) {
-}
-Packages downloaded and version:
-pkg1-1.1
-pkg2-1.1
-pkg3-1.1
-pkg4-1.1
-pkg5-1.1
-pkg6-1.1
-Test preferred_state = beta:
-NULL
-array(0) {
-}
-Packages downloaded and version:
-pkg1-2.0b1
-pkg2-1.1
-pkg3-1.1
-pkg4-1.1
-pkg5-1.1
-pkg6-2.0b1
-Test preferred_state = alpha:
-NULL
-array(0) {
-}
-Packages downloaded and version:
-pkg1-2.0b1
-pkg2-1.1
-pkg3-1.4
-pkg4AndAHalf-1.3
-pkg4-1.1
-pkg5-1.1
-pkg6-2.0b1
-
-================Test --onlyreqdeps
-Test preferred_state = stable
-NULL
-array(0) {
-}
-Packages downloaded and version:
-pkg1-1.1
-pkg2-1.1
-pkg3-1.1
-pkg4-1.1
-pkg5-1.1
-pkg6-1.1
-NULL
-array(0) {
-}
-Packages downloaded and version:
-pkg1-1.1
-pkg2-1.1
-pkg3-1.1
-pkg4-1.1
-pkg5-1.1
-pkg6-1.1
-Test preferred_state = beta:
-NULL
-array(0) {
-}
-Packages downloaded and version:
-pkg1-2.0b1
-pkg2-1.1
-pkg3-1.1
-pkg4-1.1
-pkg5-1.1
-pkg6-2.0b1
-Test preferred_state = alpha:
-skipping Package 'pkg3' optional dependency 'pkg4AndAHalf'
-NULL
-array(0) {
-}
-Packages downloaded and version:
-pkg1-2.0b1
-pkg2-1.1
-pkg3-1.4
-pkg4-1.1
-pkg5-1.1
-pkg6-2.0b1
\ No newline at end of file
diff --git a/pear/tests/pear_downloader_old.phpt b/pear/tests/pear_downloader_old.phpt
deleted file mode 100644 (file)
index 381dfca..0000000
+++ /dev/null
@@ -1,598 +0,0 @@
---TEST--
-PEAR_Installer test: PEAR_Installer::download() (deprecated)
---SKIPIF--
-<?php
-if (!getenv('PHP_PEAR_RUNTESTS')) {
-    echo 'skip';
-}
-?>
---FILE--
-<?php
-
-$server = 'pear.Chiara';
-//$server = 'test.pear.php.net';
-$temp_path = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'testinstallertemp';
-if (!is_dir($temp_path)) {
-    mkdir($temp_path);
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'php')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'php');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'data')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'data');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'doc')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'doc');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'test')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'test');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'ext')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'ext');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'script')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'script');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'tmp')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'tmp');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'bin')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'bin');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'cache')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'cache');
-}
-// make the fake configuration - we'll use one of these and it should work
-$config = serialize(array('master_server' => $server,
-    'preferred_state' => 'stable',
-    'cache_dir' => $temp_path . DIRECTORY_SEPARATOR . 'cache',
-    'php_dir' => $temp_path . DIRECTORY_SEPARATOR . 'php',
-    'ext_dir' => $temp_path . DIRECTORY_SEPARATOR . 'ext',
-    'data_dir' => $temp_path . DIRECTORY_SEPARATOR . 'data',
-    'doc_dir' => $temp_path . DIRECTORY_SEPARATOR . 'doc',
-    'test_dir' => $temp_path . DIRECTORY_SEPARATOR . 'test',
-    'bin_dir' => $temp_path . DIRECTORY_SEPARATOR . 'bin',));
-touch($temp_path . DIRECTORY_SEPARATOR . 'pear.conf');
-$fp = fopen($temp_path . DIRECTORY_SEPARATOR . 'pear.conf', 'w');
-fwrite($fp, $config);
-fclose($fp);
-touch($temp_path . DIRECTORY_SEPARATOR . 'pear.ini');
-$fp = fopen($temp_path . DIRECTORY_SEPARATOR . 'pear.ini', 'w');
-fwrite($fp, $config);
-fclose($fp);
-
-putenv('PHP_PEAR_SYSCONF_DIR='.$temp_path);
-$home = getenv('HOME');
-if (!empty($home)) {
-    // for PEAR_Config initialization
-    putenv('HOME="'.$temp_path);
-}
-require_once "PEAR/Installer.php";
-
-// no UI is needed for these tests
-$ui = false;
-$installer = new PEAR_Installer($ui);
-$curdir = getcwd();
-chdir(dirname(__FILE__));
-
-PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'catchit');
-set_error_handler('catchphp');
-
-function catchphp($errno, $errmsg)
-{
-    if (error_reporting() == 0) {
-        return;
-    }
-    $errlevel = array(
-        E_USER_NOTICE => 'Notice',
-        E_USER_WARNING => 'Warning',
-        E_USER_ERROR => 'Error',
-        E_WARNING => 'Warning',
-        E_NOTICE => 'Notice'
-    );
-    echo $errlevel[$errno] . ': ' . $errmsg . "\n";
-}
-$error_to_catch = false;
-function catchit($err)
-{
-    global $error_to_catch;
-    if ($error_to_catch) {
-        if ($err->getMessage() == $error_to_catch) {
-            $error_to_catch = false;
-            echo "Caught expected error\n";
-            return;
-        }
-    }
-    echo "Caught error: " . $err->getMessage() . "\n";
-}
-
-echo "Test simple direct url download:\n";
-
-$config = &PEAR_Config::singleton();
-$packages = array("http://$server/get/pkg6-1.1.tgz");
-$a = $installer->download($packages, array(), &$config, &$installpackages, &$errors);
-var_dump($a, $errors);
-
-echo "File exists? ";
-echo (is_file($installpackages[0]['file'])) ? "yes\n" : "no\n";
-echo "File is the same? ";
-$good = implode('', file(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'test-pkg6' . DIRECTORY_SEPARATOR . 'pkg6-1.1.tgz'));
-$dled = implode('', file($installpackages[0]['file']));
-echo ($good == $dled) ? "yes\n" : "no\n";
-unlink($installpackages[0]['file']);
-unset($installpackages[0]['file']);
-var_dump($installpackages);
-
-echo "Test simple package name download:\n";
-$installpackages = $errors = array();
-$packages = array('pkg6');
-$a = $installer->download($packages, array(), &$config, &$installpackages, &$errors);
-var_dump($a, $errors);
-
-echo "File exists? ";
-echo (is_file($installpackages[0]['file'])) ? "yes\n" : "no\n";
-echo "File is the same? ";
-$good = implode('', file(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'test-pkg6' . DIRECTORY_SEPARATOR . 'pkg6-1.1.tgz'));
-$dled = implode('', file($installpackages[0]['file']));
-echo ($good == $dled) ? "yes\n" : "no\n";
-unlink($installpackages[0]['file']);
-unset($installpackages[0]['file']);
-var_dump($installpackages);
-
-echo "Test package name with version download:\n";
-$installpackages = $errors = array();
-$packages = array('pkg6-1.1');
-$a = $installer->download($packages, array(), &$config, &$installpackages, &$errors);
-var_dump($a, $errors);
-
-echo "File exists? ";
-echo (is_file($installpackages[0]['file'])) ? "yes\n" : "no\n";
-echo "File is the same? ";
-$good = implode('', file(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'test-pkg6' . DIRECTORY_SEPARATOR . 'pkg6-1.1.tgz'));
-$dled = implode('', file($installpackages[0]['file']));
-echo ($good == $dled) ? "yes\n" : "no\n";
-unlink($installpackages[0]['file']);
-
-echo "Test package name with state stable download:\n";
-$installpackages = $errors = array();
-$packages = array('pkg6-stable');
-$a = $installer->download($packages, array(), &$config, &$installpackages, &$errors);
-var_dump($a, $errors);
-
-echo "File exists? ";
-echo (is_file($installpackages[0]['file'])) ? "yes\n" : "no\n";
-echo "File is the same? ";
-$good = implode('', file(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'test-pkg6' . DIRECTORY_SEPARATOR . 'pkg6-1.1.tgz'));
-$dled = implode('', file($installpackages[0]['file']));
-echo ($good == $dled) ? "yes\n" : "no\n";
-unlink($installpackages[0]['file']);
-
-echo "Test package name with state beta download:\n";
-$installpackages = $errors = array();
-$packages = array('pkg6-beta');
-$a = $installer->download($packages, array(), &$config, &$installpackages, &$errors);
-var_dump($a, $errors);
-
-echo "File exists? ";
-echo (is_file($installpackages[0]['file'])) ? "yes\n" : "no\n";
-echo "File is the same? ";
-$good = implode('', file(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'test-pkg6' . DIRECTORY_SEPARATOR . 'pkg6-2.0b1.tgz'));
-$dled = implode('', file($installpackages[0]['file']));
-echo ($good == $dled) ? "yes\n" : "no\n";
-unlink($installpackages[0]['file']);
-
-echo "================\nTest preferred_state = beta\n";
-$config->set('preferred_state', 'beta');
-
-echo "Test simple package name download:\n";
-$installpackages = $errors = array();
-$packages = array('pkg6');
-$a = $installer->download($packages, array(), &$config, &$installpackages, &$errors);
-var_dump($a, $errors);
-
-echo "File exists? ";
-echo (is_file($installpackages[0]['file'])) ? "yes\n" : "no\n";
-echo "File is the same? ";
-$good = implode('', file(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'test-pkg6' . DIRECTORY_SEPARATOR . 'pkg6-2.0b1.tgz'));
-$dled = implode('', file($installpackages[0]['file']));
-echo ($good == $dled) ? "yes\n" : "no\n";
-unlink($installpackages[0]['file']);
-unset($installpackages[0]['file']);
-
-echo "\n================Test --alldeps\nTest preferred_state = stable\n";
-$config->set('preferred_state', 'stable');
-
-$config = &PEAR_Config::singleton();
-$packages = array("http://$server/get/pkg1-1.1.tgz");
-$a = $installer->download($packages, array('alldeps' => true), &$config, &$installpackages, &$errors);
-var_dump($a, $errors);
-echo "Packages downloaded and version:\n";
-foreach ($installpackages as $package) {
-    echo $package['pkg'] . '-' . $package['info']['version'] . "\n";
-}
-$packages = array("pkg1");
-$a = $installer->download($packages, array('alldeps' => true), &$config, &$installpackages, &$errors);
-var_dump($a, $errors);
-echo "Packages downloaded and version:\n";
-foreach ($installpackages as $package) {
-    echo $package['pkg'] . '-' . $package['info']['version'] . "\n";
-}
-
-echo "Test preferred_state = beta:\n";
-$config->set('preferred_state', 'beta');
-
-$config = &PEAR_Config::singleton();
-$packages = array("pkg1");
-$a = $installer->download($packages, array('alldeps' => true), &$config, &$installpackages, &$errors);
-var_dump($a, $errors);
-echo "Packages downloaded and version:\n";
-foreach ($installpackages as $package) {
-    echo $package['pkg'] . '-' . $package['info']['version'] . "\n";
-}
-
-echo "Test preferred_state = alpha:\n";
-$config->set('preferred_state', 'alpha');
-
-$config = &PEAR_Config::singleton();
-$packages = array("pkg1");
-$a = $installer->download($packages, array('alldeps' => true), &$config, &$installpackages, &$errors);
-var_dump($a, $errors);
-echo "Packages downloaded and version:\n";
-foreach ($installpackages as $package) {
-    echo $package['pkg'] . '-' . $package['info']['version'] . "\n";
-}
-echo "\n================Test --onlyreqdeps\nTest preferred_state = stable\n";
-$config->set('preferred_state', 'stable');
-
-$config = &PEAR_Config::singleton();
-$packages = array("http://$server/get/pkg1-1.1.tgz");
-$a = $installer->download($packages, array('onlyreqdeps' => true), &$config, &$installpackages, &$errors);
-var_dump($a, $errors);
-echo "Packages downloaded and version:\n";
-foreach ($installpackages as $package) {
-    echo $package['pkg'] . '-' . $package['info']['version'] . "\n";
-}
-$packages = array("pkg1");
-$a = $installer->download($packages, array('onlyreqdeps' => true), &$config, &$installpackages, &$errors);
-var_dump($a, $errors);
-echo "Packages downloaded and version:\n";
-foreach ($installpackages as $package) {
-    echo $package['pkg'] . '-' . $package['info']['version'] . "\n";
-}
-
-echo "Test preferred_state = beta:\n";
-$config->set('preferred_state', 'beta');
-
-$config = &PEAR_Config::singleton();
-$packages = array("pkg1");
-$a = $installer->download($packages, array('onlyreqdeps' => true), &$config, &$installpackages, &$errors);
-var_dump($a, $errors);
-echo "Packages downloaded and version:\n";
-foreach ($installpackages as $package) {
-    echo $package['pkg'] . '-' . $package['info']['version'] . "\n";
-}
-
-echo "Test preferred_state = alpha:\n";
-$config->set('preferred_state', 'alpha');
-
-$config = &PEAR_Config::singleton();
-$packages = array("pkg1");
-$a = $installer->download($packages, array('onlyreqdeps' => true), &$config, &$installpackages, &$errors);
-var_dump($a, $errors);
-echo "Packages downloaded and version:\n";
-foreach ($installpackages as $package) {
-    echo $package['pkg'] . '-' . $package['info']['version'] . "\n";
-}
-
-
-chdir($curdir);
-cleanall($temp_path);
-/*
-echo "File exists? ";
-echo (is_file($installpackages[0]['file'])) ? "yes\n" : "no\n";
-echo "File is the same? ";
-$good = implode('', file(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'test-pkg6' . DIRECTORY_SEPARATOR . 'pkg6-1.1.tgz'));
-$dled = implode('', file($installpackages[0]['file']));
-echo ($good == $dled) ? "yes\n" : "no\n";
-unlink($installpackages[0]['file']);
-unset($installpackages[0]['file']);*/
-// ------------------------------------------------------------------------- //
-
-function cleanall($dir)
-{
-    $dp = opendir($dir);
-    while ($ent = readdir($dp)) {
-        if ($ent == '.' || $ent == '..') {
-            continue;
-        }
-        if (is_dir($dir . DIRECTORY_SEPARATOR . $ent)) {
-            cleanall($dir . DIRECTORY_SEPARATOR . $ent);
-        } else {
-            unlink($dir . DIRECTORY_SEPARATOR . $ent);
-        }
-    }
-    closedir($dp);
-    rmdir($dir);
-}
-?>
---GET--
---POST--
---EXPECT--
-Test simple direct url download:
-Warning: PEAR Warning: PEAR_Installer::download() is deprecated in favor of PEAR_Downloader class
-NULL
-array(0) {
-}
-File exists? yes
-File is the same? yes
-array(1) {
-  [0]=>
-  array(2) {
-    ["pkg"]=>
-    string(4) "pkg6"
-    ["info"]=>
-    array(11) {
-      ["provides"]=>
-      array(0) {
-      }
-      ["filelist"]=>
-      &array(3) {
-        ["zoorb.php"]=>
-        array(2) {
-          ["role"]=>
-          string(3) "php"
-          ["baseinstalldir"]=>
-          string(5) "groob"
-        }
-        ["goompness\oggbrzitzkee.php"]=>
-        array(2) {
-          ["role"]=>
-          string(3) "php"
-          ["baseinstalldir"]=>
-          string(5) "groob"
-        }
-        ["goompness\Mopreeb.php"]=>
-        array(2) {
-          ["role"]=>
-          string(3) "php"
-          ["baseinstalldir"]=>
-          string(5) "groob"
-        }
-      }
-      ["package"]=>
-      string(4) "pkg6"
-      ["summary"]=>
-      string(32) "required test for PEAR_Installer"
-      ["description"]=>
-      string(12) "fake package"
-      ["maintainers"]=>
-      array(1) {
-        [0]=>
-        &array(4) {
-          ["handle"]=>
-          string(8) "fakeuser"
-          ["name"]=>
-          string(9) "Joe Shmoe"
-          ["email"]=>
-          string(18) "nobody@example.com"
-          ["role"]=>
-          string(4) "lead"
-        }
-      }
-      ["version"]=>
-      string(3) "1.1"
-      ["release_date"]=>
-      string(10) "2003-09-09"
-      ["release_license"]=>
-      string(11) "PHP License"
-      ["release_state"]=>
-      string(6) "stable"
-      ["release_notes"]=>
-      string(24) "required dependency test"
-    }
-  }
-}
-Test simple package name download:
-Warning: PEAR Warning: PEAR_Installer::download() is deprecated in favor of PEAR_Downloader class
-NULL
-array(0) {
-}
-File exists? yes
-File is the same? yes
-array(1) {
-  [0]=>
-  array(2) {
-    ["pkg"]=>
-    string(4) "pkg6"
-    ["info"]=>
-    array(11) {
-      ["provides"]=>
-      array(0) {
-      }
-      ["filelist"]=>
-      &array(3) {
-        ["zoorb.php"]=>
-        array(2) {
-          ["role"]=>
-          string(3) "php"
-          ["baseinstalldir"]=>
-          string(5) "groob"
-        }
-        ["goompness\oggbrzitzkee.php"]=>
-        array(2) {
-          ["role"]=>
-          string(3) "php"
-          ["baseinstalldir"]=>
-          string(5) "groob"
-        }
-        ["goompness\Mopreeb.php"]=>
-        array(2) {
-          ["role"]=>
-          string(3) "php"
-          ["baseinstalldir"]=>
-          string(5) "groob"
-        }
-      }
-      ["package"]=>
-      string(4) "pkg6"
-      ["summary"]=>
-      string(32) "required test for PEAR_Installer"
-      ["description"]=>
-      string(12) "fake package"
-      ["maintainers"]=>
-      array(1) {
-        [0]=>
-        &array(4) {
-          ["handle"]=>
-          string(8) "fakeuser"
-          ["name"]=>
-          string(9) "Joe Shmoe"
-          ["email"]=>
-          string(18) "nobody@example.com"
-          ["role"]=>
-          string(4) "lead"
-        }
-      }
-      ["version"]=>
-      string(3) "1.1"
-      ["release_date"]=>
-      string(10) "2003-09-09"
-      ["release_license"]=>
-      string(11) "PHP License"
-      ["release_state"]=>
-      string(6) "stable"
-      ["release_notes"]=>
-      string(24) "required dependency test"
-    }
-  }
-}
-Test package name with version download:
-Warning: PEAR Warning: PEAR_Installer::download() is deprecated in favor of PEAR_Downloader class
-NULL
-array(0) {
-}
-File exists? yes
-File is the same? yes
-Test package name with state stable download:
-Warning: PEAR Warning: PEAR_Installer::download() is deprecated in favor of PEAR_Downloader class
-NULL
-array(0) {
-}
-File exists? yes
-File is the same? yes
-Test package name with state beta download:
-Warning: PEAR Warning: PEAR_Installer::download() is deprecated in favor of PEAR_Downloader class
-NULL
-array(0) {
-}
-File exists? yes
-File is the same? yes
-================
-Test preferred_state = beta
-Test simple package name download:
-Warning: PEAR Warning: PEAR_Installer::download() is deprecated in favor of PEAR_Downloader class
-NULL
-array(0) {
-}
-File exists? yes
-File is the same? yes
-
-================Test --alldeps
-Test preferred_state = stable
-Warning: PEAR Warning: PEAR_Installer::download() is deprecated in favor of PEAR_Downloader class
-NULL
-array(0) {
-}
-Packages downloaded and version:
-pkg1-1.1
-pkg2-1.1
-pkg3-1.1
-pkg4-1.1
-pkg5-1.1
-pkg6-1.1
-Warning: PEAR Warning: PEAR_Installer::download() is deprecated in favor of PEAR_Downloader class
-NULL
-array(0) {
-}
-Packages downloaded and version:
-pkg1-1.1
-pkg2-1.1
-pkg3-1.1
-pkg4-1.1
-pkg5-1.1
-pkg6-1.1
-Test preferred_state = beta:
-Warning: PEAR Warning: PEAR_Installer::download() is deprecated in favor of PEAR_Downloader class
-NULL
-array(0) {
-}
-Packages downloaded and version:
-pkg1-2.0b1
-pkg2-1.1
-pkg3-1.1
-pkg4-1.1
-pkg5-1.1
-pkg6-2.0b1
-Test preferred_state = alpha:
-Warning: PEAR Warning: PEAR_Installer::download() is deprecated in favor of PEAR_Downloader class
-NULL
-array(0) {
-}
-Packages downloaded and version:
-pkg1-2.0b1
-pkg2-1.1
-pkg3-1.4
-pkg4AndAHalf-1.3
-pkg4-1.1
-pkg5-1.1
-pkg6-2.0b1
-
-================Test --onlyreqdeps
-Test preferred_state = stable
-Warning: PEAR Warning: PEAR_Installer::download() is deprecated in favor of PEAR_Downloader class
-NULL
-array(0) {
-}
-Packages downloaded and version:
-pkg1-1.1
-pkg2-1.1
-pkg3-1.1
-pkg4-1.1
-pkg5-1.1
-pkg6-1.1
-Warning: PEAR Warning: PEAR_Installer::download() is deprecated in favor of PEAR_Downloader class
-NULL
-array(0) {
-}
-Packages downloaded and version:
-pkg1-1.1
-pkg2-1.1
-pkg3-1.1
-pkg4-1.1
-pkg5-1.1
-pkg6-1.1
-Test preferred_state = beta:
-Warning: PEAR Warning: PEAR_Installer::download() is deprecated in favor of PEAR_Downloader class
-NULL
-array(0) {
-}
-Packages downloaded and version:
-pkg1-2.0b1
-pkg2-1.1
-pkg3-1.1
-pkg4-1.1
-pkg5-1.1
-pkg6-2.0b1
-Test preferred_state = alpha:
-skipping Package 'pkg3' optional dependency 'pkg4AndAHalf'
-Warning: PEAR Warning: PEAR_Installer::download() is deprecated in favor of PEAR_Downloader class
-NULL
-array(0) {
-}
-Packages downloaded and version:
-pkg1-2.0b1
-pkg2-1.1
-pkg3-1.4
-pkg4-1.1
-pkg5-1.1
-pkg6-2.0b1
\ No newline at end of file
diff --git a/pear/tests/pear_error.phpt b/pear/tests/pear_error.phpt
deleted file mode 100644 (file)
index e65cd56..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
---TEST--
-PEAR_Error: basic test
---SKIPIF--
-<?php
-if (!getenv('PHP_PEAR_RUNTESTS')) {
-    echo 'skip';
-}
-?>
---FILE--
-<?php // -*- PHP -*-
-
-// Test for: PEAR.php
-// Parts tested: - PEAR_Error class
-//               - PEAR::isError static method
-
-include dirname(__FILE__)."/../PEAR.php";
-
-function test_error_handler($errno, $errmsg, $file, $line, $vars) {
-       $errortype = array (
-               1   =>  "Error",
-               2   =>  "Warning",
-               4   =>  "Parsing Error",
-               8   =>  "Notice",
-               16  =>  "Core Error",
-               32  =>  "Core Warning",
-               64  =>  "Compile Error",
-               128 =>  "Compile Warning",
-               256 =>  "User Error",
-               512 =>  "User Warning",
-               1024=>  "User Notice"
-       );
-       if (preg_match('/^The call_user_method.. function is deprecated/',
-           $errmsg)) {
-           return;
-       }
-       $prefix = $errortype[$errno];
-       $file = basename($file);
-       print "\n$prefix: $errmsg in $file on line XXX\n";
-}
-
-error_reporting(E_ALL);
-set_error_handler("test_error_handler");
-
-class Foo_Error extends PEAR_Error
-{
-    function Foo_Error($message = "unknown error", $code = null,
-                       $mode = null, $options = null, $userinfo = null)
-    {
-        $this->PEAR_Error($message, $code, $mode, $options, $userinfo);
-        $this->error_message_prefix = 'Foo_Error prefix';
-    }
-}
-
-class Test1 extends PEAR {
-    function Test1() {
-        $this->PEAR("Foo_Error");
-    }
-    function runtest() {
-        return $this->raiseError("test error");
-    }
-}
-
-function errorhandler(&$obj) {
-    print "errorhandler function called, obj=".$obj->toString()."\n";
-}
-
-class errorclass {
-    function errorhandler(&$obj) {
-               print "errorhandler method called, obj=".$obj->toString()."\n";
-    }
-}
-
-print "specify error class: ";
-$obj = new Test1;
-$err = $obj->runtest();
-print $err->toString() . "\n";
-
-$eo = new errorclass;
-
-print "default PEAR_Error: ";
-$err = new PEAR_Error;
-print $err->toString() . "\n";
-print "Testing it: ";
-var_dump(PEAR::isError($err));
-print "This is not an error: ";
-$str = "not an error";
-var_dump(PEAR::isError($str));
-
-print "Now trying a bunch of variations...\n";
-
-print "different message: ";
-$err = new PEAR_Error("test error");
-print $err->toString() . "\n";
-
-print "different message,code: ";
-$err = new PEAR_Error("test error", -42);
-print $err->toString() . "\n";
-
-print "mode=print: ";
-$err = new PEAR_Error("test error", -42, PEAR_ERROR_PRINT);
-print $err->toString() . "\n";
-
-print "mode=callback(function): ";
-$err = new PEAR_Error("test error", -42, PEAR_ERROR_CALLBACK, "errorhandler");
-
-print "mode=callback(method): ";
-$err = new PEAR_Error("test error", -42, PEAR_ERROR_CALLBACK,
-                      array(&$eo, "errorhandler"));
-
-print "mode=print&trigger: ";
-$err = new PEAR_Error("test error", -42, PEAR_ERROR_PRINT|PEAR_ERROR_TRIGGER);
-print $err->toString() . "\n";
-
-print "mode=trigger:";
-$err = new PEAR_Error("test error", -42, PEAR_ERROR_TRIGGER);
-print $err->toString() . "\n";
-
-print "mode=trigger,level=notice:";
-$err = new PEAR_Error("test error", -42, PEAR_ERROR_TRIGGER, E_USER_NOTICE);
-print $err->toString() . "\n";
-
-print "mode=trigger,level=warning:";
-$err = new PEAR_Error("test error", -42, PEAR_ERROR_TRIGGER, E_USER_WARNING);
-print $err->toString() . "\n";
-
-print "mode=trigger,level=error:";
-$err = new PEAR_Error("test error", -42, PEAR_ERROR_TRIGGER, E_USER_ERROR);
-print $err->toString() . "\n";
-
-?>
---GET--
---POST--
---EXPECT--
-specify error class: [foo_error: message="test error" code=0 mode=return level=notice prefix="Foo_Error prefix" info=""]
-default PEAR_Error: [pear_error: message="unknown error" code=0 mode=return level=notice prefix="" info=""]
-Testing it: bool(true)
-This is not an error: bool(false)
-Now trying a bunch of variations...
-different message: [pear_error: message="test error" code=0 mode=return level=notice prefix="" info=""]
-different message,code: [pear_error: message="test error" code=-42 mode=return level=notice prefix="" info=""]
-mode=print: test error[pear_error: message="test error" code=-42 mode=print level=notice prefix="" info=""]
-mode=callback(function): errorhandler function called, obj=[pear_error: message="test error" code=-42 mode=callback callback=errorhandler prefix="" info=""]
-mode=callback(method): errorhandler method called, obj=[pear_error: message="test error" code=-42 mode=callback callback=errorclass::errorhandler prefix="" info=""]
-mode=print&trigger: test error
-User Notice: test error in PEAR.php on line XXX
-[pear_error: message="test error" code=-42 mode=print|trigger level=notice prefix="" info=""]
-mode=trigger:
-User Notice: test error in PEAR.php on line XXX
-[pear_error: message="test error" code=-42 mode=trigger level=notice prefix="" info=""]
-mode=trigger,level=notice:
-User Notice: test error in PEAR.php on line XXX
-[pear_error: message="test error" code=-42 mode=trigger level=notice prefix="" info=""]
-mode=trigger,level=warning:
-User Warning: test error in PEAR.php on line XXX
-[pear_error: message="test error" code=-42 mode=trigger level=warning prefix="" info=""]
-mode=trigger,level=error:
-User Error: test error in PEAR.php on line XXX
-[pear_error: message="test error" code=-42 mode=trigger level=error prefix="" info=""]
diff --git a/pear/tests/pear_error2.phpt b/pear/tests/pear_error2.phpt
deleted file mode 100644 (file)
index 17d3208..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
---TEST--
-PEAR_Error: die mode
---SKIPIF--
-<?php
-if (!getenv('PHP_PEAR_RUNTESTS')) {
-    echo 'skip';
-}
-?>
---FILE--
-<?php // -*- C++ -*-
-
-// Test for: PEAR.php
-// Parts tested: - PEAR_Error class
-//               - PEAR::isError static method
-// testing PEAR_Error
-
-include dirname(__FILE__)."/../PEAR.php";
-
-error_reporting(E_ALL);
-
-print "mode=die: ";
-$err = new PEAR_Error("test error!!\n", -42, PEAR_ERROR_DIE);
-print $err->toString() . "\n";
-
-?>
---GET--
---POST--
---EXPECT--
-mode=die: test error!!
diff --git a/pear/tests/pear_error3.phpt b/pear/tests/pear_error3.phpt
deleted file mode 100644 (file)
index 63378a4..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
---TEST--
-PEAR_Error: default error handling
---SKIPIF--
-<?php
-if (!getenv('PHP_PEAR_RUNTESTS')) {
-    echo 'skip';
-}
-?>
---FILE--
-<?php // -*- PHP -*-
-
-// Test for: PEAR.php
-// Parts tested: - PEAR_Error class
-//               - PEAR::setErrorHandling
-//               - PEAR::raiseError method
-
-include dirname(__FILE__)."/../PEAR.php";
-
-error_reporting(E_ALL);
-
-function errorhandler($eobj)
-{
-    if (PEAR::isError($eobj)) {
-        print "errorhandler called with an error object.\n";
-        print "error message: ".$eobj->getMessage()."\n";
-    } else {
-        print "errorhandler called, but without an error object.\n";
-    }
-}
-
-// Test 1
-PEAR::setErrorHandling(PEAR_ERROR_PRINT, "OOPS: %s\n");
-$tmp = new PEAR;
-$tmp->raiseError("error happens");
-
-// Return PEAR to its original state
-$GLOBALS['_PEAR_default_error_mode']     = PEAR_ERROR_RETURN;
-$GLOBALS['_PEAR_default_error_options']  = E_USER_NOTICE;
-$GLOBALS['_PEAR_default_error_callback'] = '';
-
-// Test 2
-$obj = new PEAR;
-$obj->setErrorHandling(PEAR_ERROR_PRINT);
-$obj->raiseError("error 1\n");
-$obj->setErrorHandling(null);
-$obj->raiseError("error 2\n");
-PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, "errorhandler");
-$obj->raiseError("error 3");
-$obj->setErrorHandling(PEAR_ERROR_PRINT);
-$obj->raiseError("error 4\n");
-
-?>
---EXPECT--
-OOPS: error happens
-error 1
-errorhandler called with an error object.
-error message: error 3
-error 4
\ No newline at end of file
diff --git a/pear/tests/pear_error4.phpt b/pear/tests/pear_error4.phpt
deleted file mode 100644 (file)
index b34dbce..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
---TEST--
-PEAR_Error: expected errors
---SKIPIF--
-<?php
-if (!getenv('PHP_PEAR_RUNTESTS')) {
-    echo 'skip';
-}
-?>
---FILE--
-<?php // -*- PHP -*-
-
-// Test for: PEAR.php
-// Parts tested: - PEAR_Error class
-//               - PEAR::expectError
-//               - PEAR::popExpect
-
-include dirname(__FILE__)."/../PEAR.php";
-
-error_reporting(E_ALL);
-
-function errorhandler($eobj)
-{
-    if (PEAR::isError($eobj)) {
-        print "error: ".$eobj->getMessage()."\n";
-    } else {
-        print "errorhandler called without error object\n";
-    }
-}
-
-$obj = new PEAR;
-$obj->setErrorHandling(PEAR_ERROR_CALLBACK, "errorhandler");
-
-print "subtest 1\n";
-$obj->expectError(1);
-$obj->raiseError("1", 1);
-$obj->popExpect();
-$obj->raiseError("2", 2);
-
-print "subtest 2\n";
-$obj->expectError(3);
-$obj->expectError(2);
-$obj->raiseError("3", 3);
-
-print "subtest 3\n";
-$obj->popExpect();
-$obj->raiseError("3", 3);
-$obj->popExpect();
-
-print "subtest 4\n";
-$obj->expectError(array(1,2,3,4,5));
-$obj->raiseError("0", 0);
-$obj->raiseError("1", 1);
-$obj->raiseError("2", 2);
-$obj->raiseError("3", 3);
-$obj->raiseError("4", 4);
-$obj->raiseError("5", 5);
-$obj->raiseError("6", 6);
-$obj->raiseError("error");
-$obj->popExpect();
-
-print "subtest 5\n";
-$obj->expectError("*");
-$obj->raiseError("42", 42);
-$obj->raiseError("75", 75);
-$obj->raiseError("13", 13);
-$obj->popExpect();
-
-print "subtest 6\n";
-$obj->expectError();
-$obj->raiseError("123", 123);
-$obj->raiseError("456", 456);
-$obj->raiseError("789", 789);
-$obj->popExpect();
-
-print "subtest 7\n";
-$obj->expectError("syntax error");
-$obj->raiseError("type mismatch");
-$obj->raiseError("syntax error");
-$obj->popExpect();
-
-print "subtest 8\n";
-$obj->expectError(array(1, 2, 3));
-$obj->expectError(array(3, 4, 5));
-$obj->raiseError(4);
-$obj->delExpect(2);
-$obj->raiseError(3);
-$obj->delExpect(1, 3, 4, 5);
-$err = $obj->delExpect(2);
-
-?>
---EXPECT--
-subtest 1
-error: 2
-subtest 2
-error: 3
-subtest 3
-subtest 4
-error: 0
-error: 6
-error: error
-subtest 5
-subtest 6
-subtest 7
-error: type mismatch
-subtest 8
-error: 4
-error: 3
-error: The expected error you submitted does not exist
diff --git a/pear/tests/pear_installer1.phpt b/pear/tests/pear_installer1.phpt
deleted file mode 100644 (file)
index 90c710c..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
---TEST--
-PEAR_Installer test #1
---SKIPIF--
-<?php
-if (!getenv('PHP_PEAR_RUNTESTS')) {
-    echo 'skip';
-}
-?>
---FILE--
-<?php
-
-require_once "PEAR/Installer.php";
-
-$temp_path = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'testinstallertemp';
-if (!is_dir($temp_path)) {
-    mkdir($temp_path);
-}
-touch($temp_path . DIRECTORY_SEPARATOR . 'user.conf');
-// no UI is needed for these tests
-$ui = false;
-$installer = new PEAR_Installer($ui);
-echo "test extractDownloadFileName:\n";
-echo 'existing file: ';
-echo ($temp_path . DIRECTORY_SEPARATOR . 'user.conf' ==
-     $installer->extractDownloadFileName($temp_path . DIRECTORY_SEPARATOR . 'user.conf',
-    $ui)) ? "yes\n" : "no\n";
-var_dump($ui);
-echo 'invalid match: ';
-echo $installer->extractDownloadFileName('27',
-    $ui);
-echo "\n";
-var_dump($ui);
-echo 'valid match, no version: ';
-echo $installer->extractDownloadFileName('Testpackage', $ui);
-echo "\n";
-var_dump($ui);
-echo 'invalid match, has invalid version: ';
-echo $installer->extractDownloadFileName('Testpackage-##', $ui);
-echo "\n";
-var_dump($ui);
-echo 'valid match, has version: ';
-echo $installer->extractDownloadFileName('Testpackage-1.2', $ui);
-echo "\n";
-var_dump($ui);
-
-echo "\ntest checkDeps 1:\n";
-$fakerel = array('release_deps' =>
-array(
-    array(
-        'type' => 'pkg',
-        'rel '=> 'has',
-        'name' => 'foo',
-        'optional' => 'yes'
-    ),
-    array(
-        'type' => 'pkg',
-        'rel '=> 'ge',
-        'version' => '1.6',
-        'name' => 'bar',
-    ),
-));
-$res = '';
-var_dump($installer->checkDeps($fakerel, $res));
-var_dump($res);
-$fakerel = array('release_deps' =>
-array(
-    array(
-        'type' => 'pkg',
-        'rel '=> 'has',
-        'name' => 'foo',
-        'optional' => 'yes'
-    ),
-));
-echo "\ntest checkDeps 2:\n";
-$res = '';
-var_dump($installer->checkDeps($fakerel, $res));
-var_dump($res);
-unlink($temp_path . DIRECTORY_SEPARATOR . 'user.conf');
-rmdir($temp_path);
-?>
---GET--
---POST--
---EXPECT--
-test extractDownloadFileName:
-existing file: yes
-bool(false)
-invalid match: 27
-NULL
-valid match, no version: Testpackage
-NULL
-invalid match, has invalid version: Testpackage-##
-NULL
-valid match, has version: Testpackage
-string(3) "1.2"
-
-test checkDeps 1:
-bool(true)
-string(23) "
-requires package `bar'"
-
-test checkDeps 2:
-bool(false)
-string(77) "Optional dependencies:
-package `foo' is recommended to utilize some features."
diff --git a/pear/tests/pear_installer2.phpt b/pear/tests/pear_installer2.phpt
deleted file mode 100644 (file)
index daee603..0000000
+++ /dev/null
@@ -1,399 +0,0 @@
---TEST--
-PEAR_Installer test #2
---SKIPIF--
-<?php
-if (!getenv('PHP_PEAR_RUNTESTS')) {
-    echo 'skip';
-}
-?>
---FILE--
-<?php
-$temp_path = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'testinstallertemp';
-if (!is_dir($temp_path)) {
-    mkdir($temp_path);
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'php')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'php');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'data')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'data');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'doc')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'doc');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'test')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'test');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'ext')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'ext');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'script')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'script');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'tmp')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'tmp');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'bin')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'bin');
-}
-// make the fake configuration - we'll use one of these and it should work
-$config = serialize(array('master_server' => 'pear.php.net',
-    'php_dir' => $temp_path . DIRECTORY_SEPARATOR . 'php',
-    'ext_dir' => $temp_path . DIRECTORY_SEPARATOR . 'ext',
-    'data_dir' => $temp_path . DIRECTORY_SEPARATOR . 'data',
-    'doc_dir' => $temp_path . DIRECTORY_SEPARATOR . 'doc',
-    'test_dir' => $temp_path . DIRECTORY_SEPARATOR . 'test',
-    'bin_dir' => $temp_path . DIRECTORY_SEPARATOR . 'bin',));
-touch($temp_path . DIRECTORY_SEPARATOR . 'pear.conf');
-$fp = fopen($temp_path . DIRECTORY_SEPARATOR . 'pear.conf', 'w');
-fwrite($fp, $config);
-fclose($fp);
-touch($temp_path . DIRECTORY_SEPARATOR . 'pear.ini');
-$fp = fopen($temp_path . DIRECTORY_SEPARATOR . 'pear.ini', 'w');
-fwrite($fp, $config);
-fclose($fp);
-
-putenv('PHP_PEAR_SYSCONF_DIR='.$temp_path);
-$home = getenv('HOME');
-if (!empty($home)) {
-    // for PEAR_Config initialization
-    putenv('HOME="'.$temp_path);
-}
-require_once "PEAR/Installer.php";
-
-// no UI is needed for these tests
-$ui = false;
-$installer = new PEAR_Installer($ui);
-$curdir = getcwd();
-chdir(dirname(__FILE__));
-
-echo "test _installFile():\n";
-$fp = fopen($temp_path . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR . 'installer2.phpt.testfile.php', 'w');
-fwrite($fp, 'a');
-fclose($fp);
-// pretend we just parsed a package.xml
-$installer->pkginfo = array('package' => 'Foo');
-
-echo "install as role=\"php\":\n";
-var_dump($installer->_installFile('installer2.phpt.testfile.php', array('role' => 'php'),
-    $temp_path . DIRECTORY_SEPARATOR . 'tmp', array()));
-echo 'file ext/.tmpinstaller2.phpt.testfile.php exists? => ';
-echo (file_exists($temp_path . DIRECTORY_SEPARATOR . 'php' . DIRECTORY_SEPARATOR .
-    '.tmpinstaller2.phpt.testfile.php') ? "yes\n" : "no\n");
-
-echo "install as role=\"ext\":\n";
-var_dump($installer->_installFile('installer2.phpt.testfile.php', array('role' => 'ext'),
-    $temp_path . DIRECTORY_SEPARATOR . 'tmp', array()));
-echo 'file php/.tmpinstaller2.phpt.testfile.php exists? => ';
-echo (file_exists($temp_path . DIRECTORY_SEPARATOR . 'ext' . DIRECTORY_SEPARATOR .
-    '.tmpinstaller2.phpt.testfile.php') ? "yes\n" : "no\n");
-
-echo "install as role=\"data\":\n";
-var_dump($installer->_installFile('installer2.phpt.testfile.php', array('role' => 'data'),
-    $temp_path . DIRECTORY_SEPARATOR . 'tmp', array()));
-echo 'file data/.tmpinstaller2.phpt.testfile.php exists? => ';
-echo (file_exists($temp_path . DIRECTORY_SEPARATOR . 'data' . DIRECTORY_SEPARATOR .
-    'Foo' . DIRECTORY_SEPARATOR . '.tmpinstaller2.phpt.testfile.php') ? "yes\n" : "no\n");
-
-echo "install as role=\"doc\":\n";
-var_dump($installer->_installFile('installer2.phpt.testfile.php', array('role' => 'doc'),
-    $temp_path . DIRECTORY_SEPARATOR . 'tmp', array()));
-echo 'file doc/.tmpinstaller2.phpt.testfile.php exists? => ';
-echo (file_exists($temp_path . DIRECTORY_SEPARATOR . 'doc' . DIRECTORY_SEPARATOR .
-    'Foo' . DIRECTORY_SEPARATOR . '.tmpinstaller2.phpt.testfile.php') ? "yes\n" : "no\n");
-
-echo "install as role=\"test\":\n";
-var_dump($installer->_installFile('installer2.phpt.testfile.php', array('role' => 'test'),
-    $temp_path . DIRECTORY_SEPARATOR . 'tmp', array()));
-echo 'file test/.tmpinstaller2.phpt.testfile.php exists? => ';
-echo (file_exists($temp_path . DIRECTORY_SEPARATOR . 'test' . DIRECTORY_SEPARATOR .
-    'Foo' . DIRECTORY_SEPARATOR . '.tmpinstaller2.phpt.testfile.php') ? "yes\n" : "no\n");
-
-echo "install as role=\"script\":\n";
-var_dump($installer->_installFile('installer2.phpt.testfile.php', array('role' => 'script'),
-    $temp_path . DIRECTORY_SEPARATOR . 'tmp', array()));
-echo 'file bin/.tmpinstaller2.phpt.testfile.php exists? => ';
-echo (file_exists($temp_path . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR .
-    '.tmpinstaller2.phpt.testfile.php') ? "yes\n" : "no\n");
-
-$installer->rollbackFileTransaction();
-
-echo "install as invalid role=\"klingon\":\n";
-$err = $installer->_installFile('installer2.phpt.testfile.php', array('role' => 'klingon'),
-    $temp_path . DIRECTORY_SEPARATOR . 'tmp', array());
-echo 'returned PEAR_Error: ' . (get_class($err) == 'pear_error' ? "yes\n" : "no\n");
-if (is_object($err)) {
-    echo 'message: ' . $err->getMessage() . "\n\n";
-}
-echo 'file bin/.tmpinstaller2.phpt.testfile.php exists? => ';
-echo (file_exists($temp_path . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR .
-    '.tmpinstaller2.phpt.testfile.php') ? "yes\n" : "no\n");
-
-echo "install non-existent file:\n";
-$err = $installer->_installFile('....php', array('role' => 'php'),
-    $temp_path . DIRECTORY_SEPARATOR . 'tmp', array());
-echo 'returned PEAR_Error: ' . (get_class($err) == 'pear_error' ? "yes\n" : "no\n");
-if (is_object($err)) {
-    echo 'message: ' . $err->getMessage() . "\n";
-}
-echo 'file bin/.tmp....php exists? => ';
-echo (file_exists($temp_path . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR .
-    '.tmp....php') ? "yes\n" : "no\n");
-
-$fp = fopen($temp_path . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR . 'installer2.phpt.testfile.php', 'w');
-fwrite($fp, '@TEST@ stuff');
-fclose($fp);
-
-echo "\ntest valid md5sum:\n";
-var_dump($installer->_installFile('installer2.phpt.testfile.php', array('role' => 'script', 'md5sum' => md5('@TEST@ stuff')),
-    $temp_path . DIRECTORY_SEPARATOR . 'tmp', array()));
-echo 'file bin/.tmpinstaller2.phpt.testfile.php exists? => ';
-echo (file_exists($temp_path . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR .
-    '.tmpinstaller2.phpt.testfile.php') ? "yes\n" : "no\n");
-
-$installer->rollbackFileTransaction();
-
-echo "test invalid md5sum:\n";
-$err = $installer->_installFile('installer2.phpt.testfile.php', array('role' => 'script', 'md5sum' => md5('oops stuff')),
-    $temp_path . DIRECTORY_SEPARATOR . 'tmp', array());
-echo 'returned PEAR_Error: ' . (get_class($err) == 'pear_error' ? "yes\n" : "no\n");
-if (is_object($err)) {
-    echo 'message: ' . ($err->getMessage() == 'bad md5sum for file ' . $temp_path . DIRECTORY_SEPARATOR . 'bin' .
-    DIRECTORY_SEPARATOR . 'installer2.phpt.testfile.php' ? 'match' : 'no match') . "\n";
-}
-echo 'file bin/.tmpinstaller2.phpt.testfile.php exists? => ';
-echo (file_exists($temp_path . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR .
-    '.tmpinstaller2.phpt.testfile.php') ? "yes\n" : "no\n");
-
-echo "test invalid md5sum with --force:\n";
-ob_start();
-$err = $installer->_installFile('installer2.phpt.testfile.php', array('role' => 'script', 'md5sum' => md5('oops stuff')),
-    $temp_path . DIRECTORY_SEPARATOR . 'tmp', array('force' => true));
-$warning = ob_get_contents();
-ob_end_clean();
-echo 'warning : ';
-echo ($warning == 'warning : bad md5sum for file ' . $temp_path . DIRECTORY_SEPARATOR . 'bin' .
-    DIRECTORY_SEPARATOR . "installer2.phpt.testfile.php\n" ? "match\n" : "no match\n");
-echo 'returned PEAR_Error: ' . (get_class($err) == 'pear_error' ? "yes\n" : "no\n");
-if (is_object($err)) {
-    echo 'message: ' . ($err->getMessage() == 'bad md5sum for file ' . $temp_path . DIRECTORY_SEPARATOR . 'bin' .
-    DIRECTORY_SEPARATOR . 'installer2.phpt.testfile.php' ? 'match' : 'no match') . "\n";
-}
-echo 'file bin/.tmpinstaller2.phpt.testfile.php exists? => ';
-echo (file_exists($temp_path . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR .
-    '.tmpinstaller2.phpt.testfile.php') ? "yes\n" : "no\n");
-
-define('PEARINSTALLERTEST2_FAKE_FOO_CONST', 'good');
-echo "\ntest replacements:\n";
-var_dump($installer->_installFile('installer2.phpt.testfile.php', array('role' => 'script',
-    'replacements' => array(array('type' => 'php-const', 'from' => '@TEST@', 'to' => 'PEARINSTALLERTEST2_FAKE_FOO_CONST'))),
-    $temp_path . DIRECTORY_SEPARATOR . 'tmp', array()));
-echo "==>test php-const replacement: equals 'good stuff'? => ";
-if (file_exists($temp_path . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR .
-    '.tmpinstaller2.phpt.testfile.php'))
-{
-    $a = implode(file($temp_path . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR .
-    '.tmpinstaller2.phpt.testfile.php'), '');
-    echo "$a\n";
-} else {
-    echo "no! file installation failed\n";
-}
-$installer->rollbackFileTransaction();
-
-echo "==>test invalid php-const replacement:\n";
-$err = $installer->_installFile('installer2.phpt.testfile.php', array('role' => 'script',
-    'replacements' => array(array('type' => 'php-const', 'from' => '@TEST@', 'to' => '%PEARINSTALLERTEST2_FAKE_FOO_CONST'))),
-    $temp_path . DIRECTORY_SEPARATOR . 'tmp', array());
-if (file_exists($temp_path . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR .
-    '.tmpinstaller2.phpt.testfile.php'))
-{
-    $a = implode(file($temp_path . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR .
-    '.tmpinstaller2.phpt.testfile.php'), '');
-    echo "$a\n";
-} else {
-    echo "no! file installation failed\n";
-}
-
-$installer->rollbackFileTransaction();
-
-var_dump($installer->_installFile('installer2.phpt.testfile.php', array('role' => 'script',
-    'replacements' => array(array('type' => 'pear-config', 'from' => '@TEST@', 'to' => 'master_server'))),
-    $temp_path . DIRECTORY_SEPARATOR . 'tmp', array()));
-echo "==>test pear-config replacement: equals 'pear.php.net stuff'? => ";
-if (file_exists($temp_path . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR .
-    '.tmpinstaller2.phpt.testfile.php'))
-{
-    $a = implode(file($temp_path . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR .
-    '.tmpinstaller2.phpt.testfile.php'), '');
-    echo "$a\n";
-} else {
-    echo "no! file installation failed\n";
-}
-$installer->rollbackFileTransaction();
-
-echo "==>test invalid pear-config replacement\n";
-var_dump($installer->_installFile('installer2.phpt.testfile.php', array('role' => 'script',
-    'replacements' => array(array('type' => 'pear-config', 'from' => '@TEST@', 'to' => 'blahblahblah'))),
-    $temp_path . DIRECTORY_SEPARATOR . 'tmp', array()));
-if (file_exists($temp_path . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR .
-    '.tmpinstaller2.phpt.testfile.php'))
-{
-    $a = implode(file($temp_path . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR .
-    '.tmpinstaller2.phpt.testfile.php'), '');
-    echo "$a\n";
-} else {
-    echo "no! file installation failed\n";
-}
-$installer->rollbackFileTransaction();
-
-var_dump($installer->_installFile('installer2.phpt.testfile.php', array('role' => 'script',
-    'replacements' => array(array('type' => 'package-info', 'from' => '@TEST@', 'to' => 'package'))),
-    $temp_path . DIRECTORY_SEPARATOR . 'tmp', array()));
-echo "==>test package-info replacement: equals 'Foo stuff'? => ";
-if (file_exists($temp_path . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR .
-    '.tmpinstaller2.phpt.testfile.php'))
-{
-    $a = implode(file($temp_path . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR .
-    '.tmpinstaller2.phpt.testfile.php'), '');
-    echo "$a\n";
-} else {
-    echo "no! file installation failed\n";
-}
-$installer->rollbackFileTransaction();
-
-echo "==>test invalid package-info replacement:\n";
-var_dump($installer->_installFile('installer2.phpt.testfile.php', array('role' => 'script',
-    'replacements' => array(array('type' => 'package-info', 'from' => '@TEST@', 'to' => 'gronk'))),
-    $temp_path . DIRECTORY_SEPARATOR . 'tmp', array()));
-if (file_exists($temp_path . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR .
-    '.tmpinstaller2.phpt.testfile.php'))
-{
-    $a = implode(file($temp_path . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR .
-    '.tmpinstaller2.phpt.testfile.php'), '');
-    echo "$a\n";
-} else {
-    echo "no! file installation failed\n";
-}
-$installer->rollbackFileTransaction();
-
-echo "\ntest install-as:\n";
-var_dump($installer->_installFile('installer2.phpt.testfile.php', array('role' => 'script',
-    'install-as' => 'foobar.php'),
-    $temp_path . DIRECTORY_SEPARATOR . 'tmp', array()));
-echo "==>test install as 'foobar.php'.  file exists? ";
-if (file_exists($temp_path . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR .
-    '.tmpfoobar.php'))
-{
-    echo "yes\n";
-} else {
-    echo "no\n";
-}
-$installer->rollbackFileTransaction();
-
-echo "\ntest baseinstalldir:\n";
-var_dump($installer->_installFile('installer2.phpt.testfile.php', array('role' => 'script',
-    'baseinstalldir' => 'Foo/Mine'),
-    $temp_path . DIRECTORY_SEPARATOR . 'tmp', array()));
-echo "==>test baseinstalldir = 'Foo/Mine'.  file exists? ";
-if (file_exists($temp_path . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR .
-    'Foo' . DIRECTORY_SEPARATOR . 'Mine' . DIRECTORY_SEPARATOR . '.tmpinstaller2.phpt.testfile.php'))
-{
-    echo "yes\n";
-} else {
-    echo "no\n";
-}
-$installer->rollbackFileTransaction();
-
-rmdir($temp_path . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR .
-    'Foo' . DIRECTORY_SEPARATOR . 'Mine');
-rmdir($temp_path . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR .
-    'Foo');
-unlink($temp_path . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR . 'installer2.phpt.testfile.php');
-//cleanup
-chdir($curdir);
-unlink ($temp_path . DIRECTORY_SEPARATOR . 'pear.conf');
-unlink ($temp_path . DIRECTORY_SEPARATOR . 'pear.ini');
-rmdir($temp_path . DIRECTORY_SEPARATOR . 'php');
-rmdir($temp_path . DIRECTORY_SEPARATOR . 'data' . DIRECTORY_SEPARATOR . 'Foo');
-rmdir($temp_path . DIRECTORY_SEPARATOR . 'data');
-rmdir($temp_path . DIRECTORY_SEPARATOR . 'doc' . DIRECTORY_SEPARATOR . 'Foo');
-rmdir($temp_path . DIRECTORY_SEPARATOR . 'doc');
-rmdir($temp_path . DIRECTORY_SEPARATOR . 'test' . DIRECTORY_SEPARATOR . 'Foo');
-rmdir($temp_path . DIRECTORY_SEPARATOR . 'test');
-rmdir($temp_path . DIRECTORY_SEPARATOR . 'script');
-rmdir($temp_path . DIRECTORY_SEPARATOR . 'ext');
-rmdir($temp_path . DIRECTORY_SEPARATOR . 'tmp');
-rmdir($temp_path . DIRECTORY_SEPARATOR . 'bin');
-rmdir($temp_path);
-?>
---GET--
---POST--
---EXPECT--
-test _installFile():
-install as role="php":
-int(1)
-file ext/.tmpinstaller2.phpt.testfile.php exists? => yes
-install as role="ext":
-int(1)
-file php/.tmpinstaller2.phpt.testfile.php exists? => yes
-install as role="data":
-int(1)
-file data/.tmpinstaller2.phpt.testfile.php exists? => yes
-install as role="doc":
-int(1)
-file doc/.tmpinstaller2.phpt.testfile.php exists? => yes
-install as role="test":
-int(1)
-file test/.tmpinstaller2.phpt.testfile.php exists? => yes
-install as role="script":
-int(1)
-file bin/.tmpinstaller2.phpt.testfile.php exists? => yes
-install as invalid role="klingon":
-returned PEAR_Error: yes
-message: Invalid role `klingon' for file installer2.phpt.testfile.php
-
-file bin/.tmpinstaller2.phpt.testfile.php exists? => no
-install non-existent file:
-returned PEAR_Error: yes
-message: file does not exist
-file bin/.tmp....php exists? => no
-
-test valid md5sum:
-int(1)
-file bin/.tmpinstaller2.phpt.testfile.php exists? => yes
-test invalid md5sum:
-returned PEAR_Error: yes
-message: match
-file bin/.tmpinstaller2.phpt.testfile.php exists? => no
-test invalid md5sum with --force:
-warning : match
-returned PEAR_Error: no
-file bin/.tmpinstaller2.phpt.testfile.php exists? => yes
-
-test replacements:
-int(1)
-==>test php-const replacement: equals 'good stuff'? => good stuff
-==>test invalid php-const replacement:
-invalid php-const replacement: %PEARINSTALLERTEST2_FAKE_FOO_CONST
-@TEST@ stuff
-int(1)
-==>test pear-config replacement: equals 'pear.php.net stuff'? => pear.php.net stuff
-==>test invalid pear-config replacement
-invalid pear-config replacement: blahblahblah
-int(1)
-@TEST@ stuff
-int(1)
-==>test package-info replacement: equals 'Foo stuff'? => Foo stuff
-==>test invalid package-info replacement:
-invalid package-info replacement: gronk
-int(1)
-@TEST@ stuff
-
-test install-as:
-int(1)
-==>test install as 'foobar.php'.  file exists? yes
-
-test baseinstalldir:
-int(1)
-==>test baseinstalldir = 'Foo/Mine'.  file exists? yes
-
diff --git a/pear/tests/pear_installer3.phpt b/pear/tests/pear_installer3.phpt
deleted file mode 100644 (file)
index d40f1fd..0000000
+++ /dev/null
@@ -1,417 +0,0 @@
---TEST--
-PEAR_Installer test #3 File Transactions
---SKIPIF--
-<?php
-if (!getenv('PHP_PEAR_RUNTESTS')) {
-    echo 'skip';
-}
-?>
---FILE--
-<?php
-$temp_path = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'testinstallertemp';
-if (!is_dir($temp_path)) {
-    mkdir($temp_path);
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'php')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'php');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'data')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'data');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'doc')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'doc');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'test')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'test');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'ext')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'ext');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'script')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'script');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'tmp')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'tmp');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'bin')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'bin');
-}
-// make the fake configuration - we'll use one of these and it should work
-$config = serialize(array('master_server' => 'pear.php.net',
-    'php_dir' => $temp_path . DIRECTORY_SEPARATOR . 'php',
-    'ext_dir' => $temp_path . DIRECTORY_SEPARATOR . 'ext',
-    'data_dir' => $temp_path . DIRECTORY_SEPARATOR . 'data',
-    'doc_dir' => $temp_path . DIRECTORY_SEPARATOR . 'doc',
-    'test_dir' => $temp_path . DIRECTORY_SEPARATOR . 'test',
-    'bin_dir' => $temp_path . DIRECTORY_SEPARATOR . 'bin',));
-touch($temp_path . DIRECTORY_SEPARATOR . 'pear.conf');
-$fp = fopen($temp_path . DIRECTORY_SEPARATOR . 'pear.conf', 'w');
-fwrite($fp, $config);
-fclose($fp);
-touch($temp_path . DIRECTORY_SEPARATOR . 'pear.ini');
-$fp = fopen($temp_path . DIRECTORY_SEPARATOR . 'pear.ini', 'w');
-fwrite($fp, $config);
-fclose($fp);
-
-putenv('PHP_PEAR_SYSCONF_DIR='.$temp_path);
-$home = getenv('HOME');
-if (!empty($home)) {
-    // for PEAR_Config initialization
-    putenv('HOME="'.$temp_path);
-}
-require_once "PEAR/Installer.php";
-
-// no UI is needed for these tests
-$ui = false;
-$installer = new PEAR_Installer($ui);
-$installer->debug = 2; // hack debugging in
-$curdir = getcwd();
-chdir(dirname(__FILE__));
-
-echo "test addFileOperation():\n";
-echo "invalid input to addFileOperation():\n";
-$err = $installer->addFileOperation('rename', 2);
-echo 'Returned PEAR_Error?';
-echo (get_class($err) == 'pear_error' ? " yes\n" : " no\n");
-if (get_class($err) == 'pear_error') {
-    echo $err->getMessage() . "\n";
-}
-echo 'count($installer->file_operations) = ';
-var_dump(count($installer->file_operations));
-echo "Do valid addFileOperation() delete\n";
-touch($temp_path . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR . 'installertestfooblah.phpt');
-$installer->addFileOperation('delete', array($temp_path . DIRECTORY_SEPARATOR .
-    'tmp' . DIRECTORY_SEPARATOR . 'installertestfooblah.phpt'));
-echo 'count($installer->file_operations) = ';
-var_dump(count($installer->file_operations));
-
-echo "test valid commitFileTransaction():\n";
-if ($installer->commitFileTransaction()) {
-    echo "worked\n";
-} else {
-    echo "didn't work!\n";
-}
-
-echo "Do valid addFileOperation() rename\n";
-touch($temp_path . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR . 'installertestfooblah.phpt');
-$installer->addFileOperation('rename', array($temp_path . DIRECTORY_SEPARATOR .
-    'tmp' . DIRECTORY_SEPARATOR . 'installertestfooblah.phpt', $temp_path .
-    DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR . 'renamed.phpt'));
-
-echo 'file renamed.phpt exists?';
-clearstatcache();
-echo (file_exists($temp_path . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR
-    . 'renamed.phpt') ? " yes\n" : " no\n");
-echo "test valid commitFileTransaction():\n";
-if ($installer->commitFileTransaction()) {
-    echo "worked\n";
-} else {
-    echo "didn't work!\n";
-}
-echo 'file renamed.phpt exists?';
-clearstatcache();
-echo (file_exists($temp_path . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR
-    . 'renamed.phpt') ? " yes\n" : " no\n");
-unlink($temp_path . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR
-    . 'renamed.phpt');
-
-echo "Do valid addFileOperation() chmod\n";
-touch($temp_path . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR . 'installertestfooblah.phpt');
-clearstatcache();
-$perms = fileperms($temp_path . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR . 'installertestfooblah.phpt');
-// check to see if chmod works on this OS
-chmod($temp_path . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR . 'installertestfooblah.phpt', 0776);
-clearstatcache();
-if (fileperms($temp_path . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR . 'installertestfooblah.phpt')
-      == $perms && substr(PHP_OS, 0, 3) == 'WIN') {
-    // we are on windows, so skip this test, but simulate success
-echo <<<EOF
-file permissions are: 776
-test valid commitFileTransaction():
-about to commit 1 file operations
-successfully committed 1 file operations
-worked
-file permissions are: 640
-
-EOF;
-} else {
-    $installer->addFileOperation('chmod', array(0640, $temp_path . DIRECTORY_SEPARATOR .
-        'tmp' . DIRECTORY_SEPARATOR . 'installertestfooblah.phpt'));
-    
-    echo 'file permissions are: ' . decoct(fileperms($temp_path . DIRECTORY_SEPARATOR .
-        'tmp' . DIRECTORY_SEPARATOR . 'installertestfooblah.phpt')) . "\n";
-    echo "test valid commitFileTransaction():\n";
-    if ($installer->commitFileTransaction()) {
-        echo "worked\n";
-    } else {
-        echo "didn't work!\n";
-    }
-    echo 'file permissions are: ' . decoct(fileperms($temp_path . DIRECTORY_SEPARATOR .
-        'tmp' . DIRECTORY_SEPARATOR . 'installertestfooblah.phpt')) . "\n";
-}
-unlink($temp_path . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR
-    . 'installertestfooblah.phpt');
-
-mkdir($temp_path . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR
-    . 'installertestfooblah');
-echo "Do valid addFileOperation() rmdir\n";
-echo 'directory exists?';
-clearstatcache();
-echo (is_dir($temp_path . DIRECTORY_SEPARATOR .
-    'tmp' . DIRECTORY_SEPARATOR . 'installertestfooblah') ? " yes\n" : " no\n");
-$installer->addFileOperation('rmdir', array($temp_path . DIRECTORY_SEPARATOR .
-    'tmp' . DIRECTORY_SEPARATOR . 'installertestfooblah'));
-
-echo "test valid commitFileTransaction():\n";
-if ($installer->commitFileTransaction()) {
-    echo "worked\n";
-} else {
-    echo "didn't work!\n";
-}
-echo 'directory exists?';
-
-clearstatcache();
-echo (is_dir($temp_path . DIRECTORY_SEPARATOR .
-    'tmp' . DIRECTORY_SEPARATOR . 'installertestfooblah') ? " yes\n" : " no\n");
-
-echo "Do valid addFileOperation() installed_as\n";
-$installer->addFileOperation('installed_as', array('test.php',
-    $temp_path . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR .
-    'glomp' . DIRECTORY_SEPARATOR . 'fromp' . DIRECTORY_SEPARATOR
-    . 'installertestfooblah.phpt',
-    $temp_path . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR,
-    'glomp' . DIRECTORY_SEPARATOR . 'fromp'));
-echo "test valid commitFileTransaction():\n";
-if ($installer->commitFileTransaction()) {
-    echo "worked\n";
-} else {
-    echo "didn't work!\n";
-}
-if (isset($installer->pkginfo['filelist'])) {
-    echo "filelist created\n";
-} else {
-    echo "filelist not created!\n";
-}
-if (isset($installer->pkginfo['filelist']['test.php'])) {
-    echo "filelist test.php created\n";
-} else {
-    echo "filelist test.php not created!\n";
-}
-if (isset($installer->pkginfo['filelist']['test.php']['installed_as'])) {
-    echo "filelist test.php installed_as created\n";
-} else {
-    echo "filelist test.php installed_as not created!\n";
-}
-$p = $temp_path . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR .
-    'glomp' . DIRECTORY_SEPARATOR . 'fromp' . DIRECTORY_SEPARATOR
-    . 'installertestfooblah.phpt';
-if (@$installer->pkginfo['filelist']['test.php']['installed_as'] == $p) {
-    echo "filelist test.php installed_as is correct\n";
-} else {
-    echo "filelist test.php installed_as is not correct!\n";
-}
-if (isset($installer->pkginfo['filelist']['dirtree'])) {
-    echo "filelist dirtree created\n";
-} else {
-    echo "filelist dirtree not created!\n";
-}
-$p = $temp_path . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR .
-    'glomp';
-if (isset($installer->pkginfo['filelist']['dirtree'][$p])) {
-    echo "filelist dirtree glomp created\n";
-} else {
-    echo "filelist dirtree glomp not created!\n";
-}
-$p .= DIRECTORY_SEPARATOR . 'fromp';
-if (isset($installer->pkginfo['filelist']['dirtree'][$p])) {
-    echo "filelist dirtree fromp created\n";
-} else {
-    echo "filelist dirtree fromp not created!\n";
-}
-
-echo "Do valid addFileOperation() installed_as\n";
-$installer->addFileOperation('installed_as', array('test.php',
-    $temp_path . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR .
-    'glomp' . DIRECTORY_SEPARATOR . 'fromp' . DIRECTORY_SEPARATOR
-    . 'installertestfooblah.phpt',
-    $temp_path . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR,
-    'glomp' . DIRECTORY_SEPARATOR . 'fromp'));
-echo "test valid rollbackFileTransaction():\n";
-$installer->rollbackFileTransaction();
-if (isset($installer->pkginfo['filelist'])) {
-    echo "filelist created\n";
-} else {
-    echo "filelist not created!\n";
-}
-if (isset($installer->pkginfo['filelist']['test.php'])) {
-    echo "filelist test.php created\n";
-} else {
-    echo "filelist test.php not created!\n";
-}
-if (isset($installer->pkginfo['filelist']['test.php']['installed_as'])) {
-    echo "filelist test.php installed_as created\n";
-} else {
-    echo "filelist test.php installed_as not created!\n";
-}
-$p = $temp_path . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR .
-    'glomp' . DIRECTORY_SEPARATOR . 'fromp' . DIRECTORY_SEPARATOR
-    . 'installertestfooblah.phpt';
-if (@$installer->pkginfo['filelist']['test.php']['installed_as'] == $p) {
-    echo "filelist test.php installed_as is correct\n";
-} else {
-    echo "filelist test.php installed_as is not correct!\n";
-}
-if (isset($installer->pkginfo['filelist']['dirtree'])) {
-    echo "filelist dirtree created\n";
-} else {
-    echo "filelist dirtree not created!\n";
-}
-$p = $temp_path . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR .
-    'glomp';
-if (isset($installer->pkginfo['filelist']['dirtree'][$p])) {
-    echo "filelist dirtree glomp created\n";
-} else {
-    echo "filelist dirtree glomp not created!\n";
-}
-$p .= DIRECTORY_SEPARATOR . 'fromp';
-if (isset($installer->pkginfo['filelist']['dirtree'][$p])) {
-    echo "filelist dirtree fromp created\n";
-} else {
-    echo "filelist dirtree fromp not created!\n";
-}
-
-// invalid tests
-echo "\n==>Invalid tests\n";
-echo "Do valid addFileOperation() delete with non-existing file\n";
-$installer->addFileOperation('delete', array('gloober62456.phpt'));
-echo 'count($installer->file_operations) = ';
-var_dump(count($installer->file_operations));
-
-echo "test invalid commitFileTransaction():\n";
-if ($installer->commitFileTransaction()) {
-    echo "worked\n";
-} else {
-    echo "didn't work!\n";
-    $installer->rollbackFileTransaction();
-}
-
-echo "Do valid addFileOperation() rename with non-existing file\n";
-$installer->addFileOperation('rename', array('gloober62456.phpt', 'faber.com'));
-echo 'count($installer->file_operations) = ';
-var_dump(count($installer->file_operations));
-
-echo "test invalid commitFileTransaction():\n";
-if ($installer->commitFileTransaction()) {
-    echo "worked\n";
-} else {
-    echo "didn't work!\n";
-    $installer->rollbackFileTransaction();
-}
-
-echo "Do valid addFileOperation() chmod with non-existing file\n";
-$installer->addFileOperation('chmod', array(0640, 'faber.com'));
-echo 'count($installer->file_operations) = ';
-var_dump(count($installer->file_operations));
-
-echo "test invalid commitFileTransaction():\n";
-if ($installer->commitFileTransaction()) {
-    echo "worked\n";
-} else {
-    echo "didn't work!\n";
-    $installer->rollbackFileTransaction();
-}
-
-//cleanup
-chdir($curdir);
-unlink ($temp_path . DIRECTORY_SEPARATOR . 'pear.conf');
-unlink ($temp_path . DIRECTORY_SEPARATOR . 'pear.ini');
-rmdir($temp_path . DIRECTORY_SEPARATOR . 'php');
-rmdir($temp_path . DIRECTORY_SEPARATOR . 'data');
-rmdir($temp_path . DIRECTORY_SEPARATOR . 'doc');
-rmdir($temp_path . DIRECTORY_SEPARATOR . 'test');
-rmdir($temp_path . DIRECTORY_SEPARATOR . 'script');
-rmdir($temp_path . DIRECTORY_SEPARATOR . 'ext');
-rmdir($temp_path . DIRECTORY_SEPARATOR . 'tmp');
-rmdir($temp_path . DIRECTORY_SEPARATOR . 'bin');
-rmdir($temp_path);
-?>
---GET--
---POST--
---EXPECT--
-test addFileOperation():
-invalid input to addFileOperation():
-Returned PEAR_Error? yes
-Internal Error: $data in addFileOperation must be an array, was integer
-count($installer->file_operations) = int(0)
-Do valid addFileOperation() delete
-count($installer->file_operations) = int(1)
-test valid commitFileTransaction():
-about to commit 1 file operations
-successfully committed 1 file operations
-worked
-Do valid addFileOperation() rename
-file renamed.phpt exists? no
-test valid commitFileTransaction():
-about to commit 1 file operations
-successfully committed 1 file operations
-worked
-file renamed.phpt exists? yes
-Do valid addFileOperation() chmod
-file permissions are: 776
-test valid commitFileTransaction():
-about to commit 1 file operations
-successfully committed 1 file operations
-worked
-file permissions are: 640
-Do valid addFileOperation() rmdir
-directory exists? yes
-test valid commitFileTransaction():
-about to commit 1 file operations
-successfully committed 1 file operations
-worked
-directory exists? no
-Do valid addFileOperation() installed_as
-test valid commitFileTransaction():
-about to commit 1 file operations
-successfully committed 1 file operations
-worked
-filelist created
-filelist test.php created
-filelist test.php installed_as created
-filelist test.php installed_as is correct
-filelist dirtree created
-filelist dirtree glomp created
-filelist dirtree fromp created
-Do valid addFileOperation() installed_as
-test valid rollbackFileTransaction():
-rolling back 1 file operations
-filelist created
-filelist test.php created
-filelist test.php installed_as not created!
-filelist test.php installed_as is not correct!
-filelist dirtree not created!
-filelist dirtree glomp not created!
-filelist dirtree fromp not created!
-
-==>Invalid tests
-Do valid addFileOperation() delete with non-existing file
-count($installer->file_operations) = int(1)
-test invalid commitFileTransaction():
-about to commit 1 file operations
-warning: file gloober62456.phpt doesn't exist, can't be deleted
-successfully committed 1 file operations
-worked
-Do valid addFileOperation() rename with non-existing file
-count($installer->file_operations) = int(1)
-test invalid commitFileTransaction():
-about to commit 1 file operations
-cannot rename file gloober62456.phpt, doesn't exist
-didn't work!
-rolling back 1 file operations
-Do valid addFileOperation() chmod with non-existing file
-count($installer->file_operations) = int(1)
-test invalid commitFileTransaction():
-about to commit 1 file operations
-permission denied (chmod): faber.com 640
-didn't work!
-rolling back 1 file operations
diff --git a/pear/tests/pear_installer4.phpt b/pear/tests/pear_installer4.phpt
deleted file mode 100644 (file)
index c9af6c4..0000000
+++ /dev/null
@@ -1,259 +0,0 @@
---TEST--
-PEAR_Installer test #4: PEAR_Installer::install()
---SKIPIF--
-<?php
-if (!getenv('PHP_PEAR_RUNTESTS')) {
-    echo 'skip';
-}
-?>
---FILE--
-<?php
-$temp_path = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'testinstallertemp';
-if (!is_dir($temp_path)) {
-    mkdir($temp_path);
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'php')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'php');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'data')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'data');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'doc')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'doc');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'test')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'test');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'ext')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'ext');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'script')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'script');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'tmp')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'tmp');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'bin')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'bin');
-}
-// make the fake configuration - we'll use one of these and it should work
-$config = serialize(array('master_server' => 'pear.php.net',
-    'php_dir' => $temp_path . DIRECTORY_SEPARATOR . 'php',
-    'ext_dir' => $temp_path . DIRECTORY_SEPARATOR . 'ext',
-    'data_dir' => $temp_path . DIRECTORY_SEPARATOR . 'data',
-    'doc_dir' => $temp_path . DIRECTORY_SEPARATOR . 'doc',
-    'test_dir' => $temp_path . DIRECTORY_SEPARATOR . 'test',
-    'bin_dir' => $temp_path . DIRECTORY_SEPARATOR . 'bin',));
-touch($temp_path . DIRECTORY_SEPARATOR . 'pear.conf');
-$fp = fopen($temp_path . DIRECTORY_SEPARATOR . 'pear.conf', 'w');
-fwrite($fp, $config);
-fclose($fp);
-touch($temp_path . DIRECTORY_SEPARATOR . 'pear.ini');
-$fp = fopen($temp_path . DIRECTORY_SEPARATOR . 'pear.ini', 'w');
-fwrite($fp, $config);
-fclose($fp);
-
-putenv('PHP_PEAR_SYSCONF_DIR='.$temp_path);
-$home = getenv('HOME');
-if (!empty($home)) {
-    // for PEAR_Config initialization
-    putenv('HOME="'.$temp_path);
-}
-require_once "PEAR/Installer.php";
-
-// no UI is needed for these tests
-$ui = false;
-$installer = new PEAR_Installer($ui);
-$curdir = getcwd();
-chdir(dirname(__FILE__));
-
-PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'catchit');
-
-$error_to_catch = false;
-function catchit($err)
-{
-    global $error_to_catch;
-    if ($error_to_catch) {
-        if ($err->getMessage() == $error_to_catch) {
-            $error_to_catch = false;
-            echo "Caught expected error\n";
-            return;
-        }
-    }
-    echo "Caught error: " . $err->getMessage() . "\n";
-}
-
-echo "Test package.xml direct install:\n";
-$installer->install(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'test-pkg6' . DIRECTORY_SEPARATOR . 'package.xml');
-$reg = &new PEAR_Registry($temp_path . DIRECTORY_SEPARATOR . 'php');
-var_dump($reg->listPackages());
-echo "zoorb.php exists? ";
-echo (file_exists($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'groob' . DIRECTORY_SEPARATOR . 'zoorb.php')) ? "yes\n" : "no\n";
-echo "goompness/Mopreeb.php exists? ";
-echo (file_exists($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'groob' . DIRECTORY_SEPARATOR . 'goompness'
-    . DIRECTORY_SEPARATOR . 'Mopreeb.php')) ? "yes\n" : "no\n";
-echo "goompness/oggbrzitzkee.php exists? ";
-echo (file_exists($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'groob' . DIRECTORY_SEPARATOR . 'goompness'
-    . DIRECTORY_SEPARATOR . 'oggbrzitzkee.php')) ? "yes\n" : "no\n";
-echo "After uninstall:\n";
-$installer->uninstall('pkg6');
-var_dump($reg->listPackages());
-echo "zoorb.php exists? ";
-echo (file_exists($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'groob' . DIRECTORY_SEPARATOR . 'zoorb.php')) ? "yes\n" : "no\n";
-echo "goompness/Mopreeb.php exists? ";
-echo (file_exists($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'groob' . DIRECTORY_SEPARATOR . 'goompness'
-    . DIRECTORY_SEPARATOR . 'Mopreeb.php')) ? "yes\n" : "no\n";
-echo "goompness/oggbrzitzkee.php exists? ";
-echo (file_exists($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'groob' . DIRECTORY_SEPARATOR . 'goompness'
-    . DIRECTORY_SEPARATOR . 'oggbrzitzkee.php')) ? "yes\n" : "no\n";
-echo "goompness exists? ";
-echo (is_dir($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'groob' . DIRECTORY_SEPARATOR . 'goompness'))
-    ? "yes\n" : "no\n";
-
-echo "Test .tgz install:\n";
-$installer->install(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'test-pkg6' . DIRECTORY_SEPARATOR . 'pkg6-1.1.tgz');
-$reg = &new PEAR_Registry($temp_path . DIRECTORY_SEPARATOR . 'php');
-var_dump($reg->listPackages());
-echo "zoorb.php exists? ";
-echo (file_exists($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'groob' . DIRECTORY_SEPARATOR . 'zoorb.php')) ? "yes\n" : "no\n";
-echo "goompness/Mopreeb.php exists? ";
-echo (file_exists($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'groob' . DIRECTORY_SEPARATOR . 'goompness'
-    . DIRECTORY_SEPARATOR . 'Mopreeb.php')) ? "yes\n" : "no\n";
-echo "goompness/oggbrzitzkee.php exists? ";
-echo (file_exists($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'groob' . DIRECTORY_SEPARATOR . 'goompness'
-    . DIRECTORY_SEPARATOR . 'oggbrzitzkee.php')) ? "yes\n" : "no\n";
-echo "After uninstall:\n";
-$installer->uninstall('pkg6');
-var_dump($reg->listPackages());
-echo "zoorb.php exists? ";
-echo (file_exists($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'groob' . DIRECTORY_SEPARATOR . 'zoorb.php')) ? "yes\n" : "no\n";
-echo "goompness/Mopreeb.php exists? ";
-echo (file_exists($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'groob' . DIRECTORY_SEPARATOR . 'goompness'
-    . DIRECTORY_SEPARATOR . 'Mopreeb.php')) ? "yes\n" : "no\n";
-echo "goompness/oggbrzitzkee.php exists? ";
-echo (file_exists($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'groob' . DIRECTORY_SEPARATOR . 'goompness'
-    . DIRECTORY_SEPARATOR . 'oggbrzitzkee.php')) ? "yes\n" : "no\n";
-echo "goompness exists? ";
-echo (is_dir($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'groob' . DIRECTORY_SEPARATOR . 'goompness'))
-    ? "yes\n" : "no\n";
-
-echo "Test invalid .tgz install:\n";
-$error_to_catch = 'unable to unpack ' . dirname(__FILE__) . DIRECTORY_SEPARATOR .
-    'test-pkg6' . DIRECTORY_SEPARATOR . 'invalidtgz.tgz';
-$installer->install(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'test-pkg6' . DIRECTORY_SEPARATOR . 'invalidtgz.tgz');
-$reg = &new PEAR_Registry($temp_path . DIRECTORY_SEPARATOR . 'php');
-var_dump($reg->listPackages());
-echo "zoorb.php exists? ";
-echo (file_exists($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'groob' . DIRECTORY_SEPARATOR . 'zoorb.php')) ? "yes\n" : "no\n";
-echo "goompness/Mopreeb.php exists? ";
-echo (file_exists($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'groob' . DIRECTORY_SEPARATOR . 'goompness'
-    . DIRECTORY_SEPARATOR . 'Mopreeb.php')) ? "yes\n" : "no\n";
-echo "goompness/oggbrzitzkee.php exists? ";
-echo (file_exists($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'groob' . DIRECTORY_SEPARATOR . 'goompness'
-    . DIRECTORY_SEPARATOR . 'oggbrzitzkee.php')) ? "yes\n" : "no\n";
-
-echo "Test missing package.xml in .tgz install:\n";
-$installer->install(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'test-pkg6' . DIRECTORY_SEPARATOR . 'nopackagexml.tgz');
-$reg = &new PEAR_Registry($temp_path . DIRECTORY_SEPARATOR . 'php');
-var_dump($reg->listPackages());
-echo "zoorb.php exists? ";
-echo (file_exists($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'groob' . DIRECTORY_SEPARATOR . 'zoorb.php')) ? "yes\n" : "no\n";
-echo "goompness/Mopreeb.php exists? ";
-echo (file_exists($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'groob' . DIRECTORY_SEPARATOR . 'goompness'
-    . DIRECTORY_SEPARATOR . 'Mopreeb.php')) ? "yes\n" : "no\n";
-echo "goompness/oggbrzitzkee.php exists? ";
-echo (file_exists($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'groob' . DIRECTORY_SEPARATOR . 'goompness'
-    . DIRECTORY_SEPARATOR . 'oggbrzitzkee.php')) ? "yes\n" : "no\n";
-
-chdir($curdir);
-cleanall($temp_path);
-
-// ------------------------------------------------------------------------- //
-
-function cleanall($dir)
-{
-    $dp = opendir($dir);
-    while ($ent = readdir($dp)) {
-        if ($ent == '.' || $ent == '..') {
-            continue;
-        }
-        if (is_dir($dir . DIRECTORY_SEPARATOR . $ent)) {
-            cleanall($dir . DIRECTORY_SEPARATOR . $ent);
-        } else {
-            unlink($dir . DIRECTORY_SEPARATOR . $ent);
-        }
-    }
-    closedir($dp);
-    rmdir($dir);
-}
-?>
---GET--
---POST--
---EXPECT--
-Test package.xml direct install:
-array(1) {
-  [0]=>
-  string(4) "pkg6"
-}
-zoorb.php exists? yes
-goompness/Mopreeb.php exists? yes
-goompness/oggbrzitzkee.php exists? yes
-After uninstall:
-array(0) {
-}
-zoorb.php exists? no
-goompness/Mopreeb.php exists? no
-goompness/oggbrzitzkee.php exists? no
-goompness exists? no
-Test .tgz install:
-array(1) {
-  [0]=>
-  string(4) "pkg6"
-}
-zoorb.php exists? yes
-goompness/Mopreeb.php exists? yes
-goompness/oggbrzitzkee.php exists? yes
-After uninstall:
-array(0) {
-}
-zoorb.php exists? no
-goompness/Mopreeb.php exists? no
-goompness/oggbrzitzkee.php exists? no
-goompness exists? no
-Test invalid .tgz install:
-Caught error: Invalid checksum for file "<?xml version="1.0" encoding="ISO-8859-1" ?>
-    <!DOCTYPE package SYSTEM "http://pear.php.net/dtd/" : 37649 calculated, 0 expected
-Caught expected error
-array(0) {
-}
-zoorb.php exists? no
-goompness/Mopreeb.php exists? no
-goompness/oggbrzitzkee.php exists? no
-Test missing package.xml in .tgz install:
-warning : you are using an archive with an old format
-Caught error: no package.xml file after extracting the archive
-array(0) {
-}
-zoorb.php exists? no
-goompness/Mopreeb.php exists? no
-goompness/oggbrzitzkee.php exists? no
diff --git a/pear/tests/pear_installer5.phpt b/pear/tests/pear_installer5.phpt
deleted file mode 100644 (file)
index 77415b9..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
---TEST--
-PEAR_Installer test #5: test directory tracking/deletion of installation
---SKIPIF--
-<?php
-if (!getenv('PHP_PEAR_RUNTESTS')) {
-    echo 'skip';
-}
-?>
---FILE--
-<?php
-$temp_path = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'testinstallertemp';
-if (!is_dir($temp_path)) {
-    mkdir($temp_path);
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'php')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'php');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'data')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'data');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'doc')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'doc');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'test')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'test');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'ext')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'ext');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'script')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'script');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'tmp')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'tmp');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'bin')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'bin');
-}
-// make the fake configuration - we'll use one of these and it should work
-$config = serialize(array('master_server' => 'pear.php.net',
-    'php_dir' => $temp_path . DIRECTORY_SEPARATOR . 'php',
-    'ext_dir' => $temp_path . DIRECTORY_SEPARATOR . 'ext',
-    'data_dir' => $temp_path . DIRECTORY_SEPARATOR . 'data',
-    'doc_dir' => $temp_path . DIRECTORY_SEPARATOR . 'doc',
-    'test_dir' => $temp_path . DIRECTORY_SEPARATOR . 'test',
-    'bin_dir' => $temp_path . DIRECTORY_SEPARATOR . 'bin',));
-touch($temp_path . DIRECTORY_SEPARATOR . 'pear.conf');
-$fp = fopen($temp_path . DIRECTORY_SEPARATOR . 'pear.conf', 'w');
-fwrite($fp, $config);
-fclose($fp);
-touch($temp_path . DIRECTORY_SEPARATOR . 'pear.ini');
-$fp = fopen($temp_path . DIRECTORY_SEPARATOR . 'pear.ini', 'w');
-fwrite($fp, $config);
-fclose($fp);
-
-putenv('PHP_PEAR_SYSCONF_DIR='.$temp_path);
-$home = getenv('HOME');
-if (!empty($home)) {
-    // for PEAR_Config initialization
-    putenv('HOME="'.$temp_path);
-}
-require_once "PEAR/Installer.php";
-
-// no UI is needed for these tests
-$ui = false;
-$installer = new PEAR_Installer($ui);
-$curdir = getcwd();
-chdir(dirname(__FILE__));
-
-PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'catchit');
-
-$error_to_catch = false;
-function catchit($err)
-{
-    global $error_to_catch;
-    if ($error_to_catch) {
-        if ($err->getMessage() == $error_to_catch) {
-            $error_to_catch = false;
-            echo "Caught expected error\n";
-            return;
-        }
-    }
-    echo "Caught error: " . $err->getMessage() . "\n";
-}
-
-$installer->install(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'dirtree' . DIRECTORY_SEPARATOR . 'package.xml');
-$installer->install(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'dirtree' . DIRECTORY_SEPARATOR . 'package2.xml');
-$reg = &new PEAR_Registry($temp_path . DIRECTORY_SEPARATOR . 'php');
-var_dump($reg->listPackages());
-$info = $reg->packageInfo('pkg1');
-echo "pkg1 dir tree contains test/? ";
-echo (isset($info['filelist']['dirtree'][$temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'test'])) ? "yes\n" : "no\n";
-echo "pkg1 dir tree contains test/multiplepackages? ";
-echo (isset($info['filelist']['dirtree'][$temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'test' . DIRECTORY_SEPARATOR . 'multiplepackages'])) ? "yes\n" : "no\n";
-echo "pkg1 dir tree contains test/pkg1? ";
-echo (isset($info['filelist']['dirtree'][$temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'test' . DIRECTORY_SEPARATOR . 'pkg1'])) ? "yes\n" : "no\n";
-
-$info = $reg->packageInfo('pkg2');
-echo "pkg2 dir tree contains test/? ";
-echo (isset($info['filelist']['dirtree'][$temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'test'])) ? "yes\n" : "no\n";
-echo "pkg2 dir tree contains test/multiplepackages? ";
-echo (isset($info['filelist']['dirtree'][$temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'test' . DIRECTORY_SEPARATOR . 'multiplepackages'])) ? "yes\n" : "no\n";
-echo "pkg2 dir tree contains test/nestedroot? ";
-echo (isset($info['filelist']['dirtree'][$temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'test' . DIRECTORY_SEPARATOR . 'nestedroot'])) ? "yes\n" : "no\n";
-echo "pkg2 dir tree contains test/nestedroot/emptydir? ";
-echo (isset($info['filelist']['dirtree'][$temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'test' . DIRECTORY_SEPARATOR . 'nestedroot'
-    . DIRECTORY_SEPARATOR . 'emptydir'])) ? "yes\n" : "no\n";
-echo "pkg2 dir tree contains test/nestedroot/emptydir/nesteddir? ";
-echo (isset($info['filelist']['dirtree'][$temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'test' . DIRECTORY_SEPARATOR . 'nestedroot'
-    . DIRECTORY_SEPARATOR . 'emptydir' . DIRECTORY_SEPARATOR . 'nesteddir'])) ? "yes\n" : "no\n";
-
-echo "After uninstall of pkg1:\n";
-$installer->uninstall('pkg1');
-echo "test/ exists? ";
-echo (is_dir($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'test')) ? "yes\n" : "no\n";
-echo "test/multiplepackages exists? ";
-echo (is_dir($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'test' . DIRECTORY_SEPARATOR . 'multiplepackages')) ? "yes\n" : "no\n";
-echo "test/pkg1 exists? ";
-echo (is_dir($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'test' . DIRECTORY_SEPARATOR . 'pkg1')) ? "yes\n" : "no\n";
-echo "test/nestedroot exists? ";
-echo (is_dir($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'test' . DIRECTORY_SEPARATOR . 'nestedroot')) ? "yes\n" : "no\n";
-echo "test/nestedroot/emptydir exists? ";
-echo (is_dir($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'test' . DIRECTORY_SEPARATOR . 'nestedroot'
-    . DIRECTORY_SEPARATOR . 'emptydir')) ? "yes\n" : "no\n";
-echo "test/nestedroot/emptydir/nesteddir exists? ";
-echo (is_dir($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'test' . DIRECTORY_SEPARATOR . 'nestedroot'
-    . DIRECTORY_SEPARATOR . 'emptydir'. DIRECTORY_SEPARATOR . 'nesteddir')) ? "yes\n" : "no\n";
-var_dump($reg->listPackages());
-
-echo "After uninstall of pkg2:\n";
-$installer->uninstall('pkg2');
-echo "test/ exists? ";
-echo (is_dir($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'test')) ? "yes\n" : "no\n";
-echo "test/multiplepackages exists? ";
-echo (is_dir($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'test' . DIRECTORY_SEPARATOR . 'multiplepackages')) ? "yes\n" : "no\n";
-echo "test/pkg1 exists? ";
-echo (is_dir($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'test' . DIRECTORY_SEPARATOR . 'pkg1')) ? "yes\n" : "no\n";
-echo "test/nestedroot exists? ";
-echo (is_dir($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'test' . DIRECTORY_SEPARATOR . 'nestedroot')) ? "yes\n" : "no\n";
-echo "test/nestedroot/emptydir exists? ";
-echo (is_dir($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'test' . DIRECTORY_SEPARATOR . 'nestedroot'
-    . DIRECTORY_SEPARATOR . 'emptydir')) ? "yes\n" : "no\n";
-echo "test/nestedroot/emptydir/nesteddir exists? ";
-echo (is_dir($temp_path . DIRECTORY_SEPARATOR . 'php'
-    . DIRECTORY_SEPARATOR . 'test' . DIRECTORY_SEPARATOR . 'nestedroot'
-    . DIRECTORY_SEPARATOR . 'emptydir'. DIRECTORY_SEPARATOR . 'nesteddir')) ? "yes\n" : "no\n";
-var_dump($reg->listPackages());
-
-chdir($curdir);
-cleanall($temp_path);
-
-// ------------------------------------------------------------------------- //
-
-function cleanall($dir)
-{
-    $dp = opendir($dir);
-    while ($ent = readdir($dp)) {
-        if ($ent == '.' || $ent == '..') {
-            continue;
-        }
-        if (is_dir($dir . DIRECTORY_SEPARATOR . $ent)) {
-            cleanall($dir . DIRECTORY_SEPARATOR . $ent);
-        } else {
-            unlink($dir . DIRECTORY_SEPARATOR . $ent);
-        }
-    }
-    closedir($dp);
-    rmdir($dir);
-}
-?>
---GET--
---POST--
---EXPECT--
-array(2) {
-  [0]=>
-  string(4) "pkg1"
-  [1]=>
-  string(4) "pkg2"
-}
-pkg1 dir tree contains test/? yes
-pkg1 dir tree contains test/multiplepackages? yes
-pkg1 dir tree contains test/pkg1? yes
-pkg2 dir tree contains test/? yes
-pkg2 dir tree contains test/multiplepackages? yes
-pkg2 dir tree contains test/nestedroot? yes
-pkg2 dir tree contains test/nestedroot/emptydir? yes
-pkg2 dir tree contains test/nestedroot/emptydir/nesteddir? yes
-After uninstall of pkg1:
-test/ exists? yes
-test/multiplepackages exists? yes
-test/pkg1 exists? no
-test/nestedroot exists? yes
-test/nestedroot/emptydir exists? yes
-test/nestedroot/emptydir/nesteddir exists? yes
-array(1) {
-  [0]=>
-  string(4) "pkg2"
-}
-After uninstall of pkg2:
-test/ exists? no
-test/multiplepackages exists? no
-test/pkg1 exists? no
-test/nestedroot exists? no
-test/nestedroot/emptydir exists? no
-test/nestedroot/emptydir/nesteddir exists? no
-array(0) {
-}
\ No newline at end of file
diff --git a/pear/tests/pear_packager.phpt b/pear/tests/pear_packager.phpt
deleted file mode 100644 (file)
index 9d584b2..0000000
+++ /dev/null
@@ -1,432 +0,0 @@
---TEST--
-PEAR_Packager test
---SKIPIF--
-<?php
-if (!getenv('PHP_PEAR_RUNTESTS')) {
-    echo 'skip';
-}
-?>
---FILE--
-<?php
-$temp_path = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'testinstallertemp';
-if (!is_dir($temp_path)) {
-    mkdir($temp_path);
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'php')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'php');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'data')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'data');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'doc')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'doc');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'test')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'test');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'ext')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'ext');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'script')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'script');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'tmp')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'tmp');
-}
-if (!is_dir($temp_path . DIRECTORY_SEPARATOR . 'bin')) {
-    mkdir($temp_path . DIRECTORY_SEPARATOR . 'bin');
-}
-// make the fake configuration - we'll use one of these and it should work
-$config = serialize(array('master_server' => 'pear.php.net',
-    'php_dir' => $temp_path . DIRECTORY_SEPARATOR . 'php',
-    'ext_dir' => $temp_path . DIRECTORY_SEPARATOR . 'ext',
-    'data_dir' => $temp_path . DIRECTORY_SEPARATOR . 'data',
-    'doc_dir' => $temp_path . DIRECTORY_SEPARATOR . 'doc',
-    'test_dir' => $temp_path . DIRECTORY_SEPARATOR . 'test',
-    'bin_dir' => $temp_path . DIRECTORY_SEPARATOR . 'bin',));
-touch($temp_path . DIRECTORY_SEPARATOR . 'pear.conf');
-$fp = fopen($temp_path . DIRECTORY_SEPARATOR . 'pear.conf', 'w');
-fwrite($fp, $config);
-fclose($fp);
-touch($temp_path . DIRECTORY_SEPARATOR . 'pear.ini');
-$fp = fopen($temp_path . DIRECTORY_SEPARATOR . 'pear.ini', 'w');
-fwrite($fp, $config);
-fclose($fp);
-
-putenv('PHP_PEAR_SYSCONF_DIR='.$temp_path);
-$home = getenv('HOME');
-if (!empty($home)) {
-    // for PEAR_Config initialization
-    putenv('HOME="'.$temp_path);
-}
-require_once "PEAR/Packager.php";
-
-$packager = new PEAR_Packager();
-$curdir = getcwd();
-chdir(dirname(__FILE__));
-
-PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'catchit');
-
-$error_to_catch = false;
-function catchit($err)
-{
-    global $error_to_catch;
-    if ($error_to_catch) {
-        if ($err->getMessage() == $error_to_catch) {
-            $error_to_catch = false;
-            echo "Caught expected error\n";
-            return;
-        }
-    }
-    echo "Caught error: " . $err->getMessage() . "\n";
-}
-ob_start();
-$packager->package(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'dirtree' . DIRECTORY_SEPARATOR . 'package.xml');
-$packager->package(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'dirtree' . DIRECTORY_SEPARATOR . 'package2.xml');
-$stuff = str_replace(array(dirname(__FILE__) . DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), array('', '/'),
-    ob_get_contents());
-ob_end_clean();
-echo $stuff;
-
-$archive1 = &new Archive_Tar(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'pkg1-1.0.tgz');
-$archive1c = &new Archive_Tar(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'dirtree' .
-    DIRECTORY_SEPARATOR . 'pkg1-1.0.tgz');
-$x1 = $archive1->listContent();
-$x2 = $archive1c->listContent();
-for($i=0;$i<count($x1); $i++) {
-    if ($x1[$i]['filename'] == 'package.xml') {
-        unset($x1[$i]['mtime']);
-        unset($x1[$i]['checksum']);
-    }
-}
-for($i=0;$i<count($x2); $i++) {
-    if ($x2[$i]['filename'] == 'package.xml') {
-        unset($x2[$i]['mtime']);
-        unset($x2[$i]['checksum']);
-    }
-}
-var_dump($x1, $x2);
-$archive1 = &new Archive_Tar(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'pkg2-1.0.tgz');
-$archive1c = &new Archive_Tar(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'dirtree' .
-    DIRECTORY_SEPARATOR . 'pkg2-1.0.tgz');
-$x1 = $archive1->listContent();
-$x2 = $archive1c->listContent();
-for($i=0;$i<count($x1); $i++) {
-    if ($x1[$i]['filename'] == 'package.xml') {
-        unset($x1[$i]['mtime']);
-        unset($x1[$i]['checksum']);
-    }
-}
-for($i=0;$i<count($x2); $i++) {
-    if ($x2[$i]['filename'] == 'package.xml') {
-        unset($x2[$i]['mtime']);
-        unset($x2[$i]['checksum']);
-    }
-}
-var_dump($x1, $x2);
-
-echo "test failure:\n";
-$packager->package(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'dirtree' . DIRECTORY_SEPARATOR . 'package-fail.xml');
-
-unlink(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'pkg1-1.0.tgz');
-unlink(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'pkg2-1.0.tgz');
-chdir($curdir);
-cleanall($temp_path);
-
-// ------------------------------------------------------------------------- //
-
-function cleanall($dir)
-{
-    $dp = opendir($dir);
-    while ($ent = readdir($dp)) {
-        if ($ent == '.' || $ent == '..') {
-            continue;
-        }
-        if (is_dir($dir . DIRECTORY_SEPARATOR . $ent)) {
-            cleanall($dir . DIRECTORY_SEPARATOR . $ent);
-        } else {
-            unlink($dir . DIRECTORY_SEPARATOR . $ent);
-        }
-    }
-    closedir($dp);
-    rmdir($dir);
-}
-?>
---GET--
---POST--
---EXPECT--
-Analyzing multiplepackages/pkg1file.php
-Analyzing pkg1/randomfile.php
-Package pkg1-1.0.tgz done
-Tag the released code with `pear cvstag package.xml'
-(or set the CVS tag RELEASE_1_0 by hand)
-Analyzing multiplepackages/pkg2file.php
-Analyzing nestedroot/rootfile.php
-Analyzing nestedroot/emptydir/nesteddir/nestedfile.php
-Package pkg2-1.0.tgz done
-Tag the released code with `pear cvstag package2.xml'
-(or set the CVS tag RELEASE_1_0 by hand)
-array(3) {
-  [0]=>
-  array(6) {
-    ["filename"]=>
-    string(11) "package.xml"
-    ["mode"]=>
-    int(33206)
-    ["uid"]=>
-    int(0)
-    ["gid"]=>
-    int(0)
-    ["size"]=>
-    int(817)
-    ["typeflag"]=>
-    string(0) ""
-  }
-  [1]=>
-  array(8) {
-    ["checksum"]=>
-    int(5592)
-    ["filename"]=>
-    string(38) "pkg1-1.0/multiplepackages/pkg1file.php"
-    ["mode"]=>
-    int(33206)
-    ["uid"]=>
-    int(0)
-    ["gid"]=>
-    int(0)
-    ["size"]=>
-    int(0)
-    ["mtime"]=>
-    int(1071119017)
-    ["typeflag"]=>
-    string(0) ""
-  }
-  [2]=>
-  array(8) {
-    ["checksum"]=>
-    int(4534)
-    ["filename"]=>
-    string(28) "pkg1-1.0/pkg1/randomfile.php"
-    ["mode"]=>
-    int(33206)
-    ["uid"]=>
-    int(0)
-    ["gid"]=>
-    int(0)
-    ["size"]=>
-    int(0)
-    ["mtime"]=>
-    int(1071120110)
-    ["typeflag"]=>
-    string(0) ""
-  }
-}
-array(3) {
-  [0]=>
-  array(6) {
-    ["filename"]=>
-    string(11) "package.xml"
-    ["mode"]=>
-    int(33206)
-    ["uid"]=>
-    int(0)
-    ["gid"]=>
-    int(0)
-    ["size"]=>
-    int(817)
-    ["typeflag"]=>
-    string(0) ""
-  }
-  [1]=>
-  array(8) {
-    ["checksum"]=>
-    int(5592)
-    ["filename"]=>
-    string(38) "pkg1-1.0/multiplepackages/pkg1file.php"
-    ["mode"]=>
-    int(33206)
-    ["uid"]=>
-    int(0)
-    ["gid"]=>
-    int(0)
-    ["size"]=>
-    int(0)
-    ["mtime"]=>
-    int(1071119017)
-    ["typeflag"]=>
-    string(0) ""
-  }
-  [2]=>
-  array(8) {
-    ["checksum"]=>
-    int(4534)
-    ["filename"]=>
-    string(28) "pkg1-1.0/pkg1/randomfile.php"
-    ["mode"]=>
-    int(33206)
-    ["uid"]=>
-    int(0)
-    ["gid"]=>
-    int(0)
-    ["size"]=>
-    int(0)
-    ["mtime"]=>
-    int(1071120110)
-    ["typeflag"]=>
-    string(0) ""
-  }
-}
-array(4) {
-  [0]=>
-  array(6) {
-    ["filename"]=>
-    string(11) "package.xml"
-    ["mode"]=>
-    int(33206)
-    ["uid"]=>
-    int(0)
-    ["gid"]=>
-    int(0)
-    ["size"]=>
-    int(921)
-    ["typeflag"]=>
-    string(0) ""
-  }
-  [1]=>
-  array(8) {
-    ["checksum"]=>
-    int(5600)
-    ["filename"]=>
-    string(38) "pkg2-1.0/multiplepackages/pkg2file.php"
-    ["mode"]=>
-    int(33206)
-    ["uid"]=>
-    int(0)
-    ["gid"]=>
-    int(0)
-    ["size"]=>
-    int(0)
-    ["mtime"]=>
-    int(1071119030)
-    ["typeflag"]=>
-    string(0) ""
-  }
-  [2]=>
-  array(8) {
-    ["checksum"]=>
-    int(5066)
-    ["filename"]=>
-    string(32) "pkg2-1.0/nestedroot/rootfile.php"
-    ["mode"]=>
-    int(33206)
-    ["uid"]=>
-    int(0)
-    ["gid"]=>
-    int(0)
-    ["size"]=>
-    int(0)
-    ["mtime"]=>
-    int(1071119266)
-    ["typeflag"]=>
-    string(0) ""
-  }
-  [3]=>
-  array(8) {
-    ["checksum"]=>
-    int(7193)
-    ["filename"]=>
-    string(53) "pkg2-1.0/nestedroot/emptydir/nesteddir/nestedfile.php"
-    ["mode"]=>
-    int(33206)
-    ["uid"]=>
-    int(0)
-    ["gid"]=>
-    int(0)
-    ["size"]=>
-    int(0)
-    ["mtime"]=>
-    int(1071119310)
-    ["typeflag"]=>
-    string(0) ""
-  }
-}
-array(4) {
-  [0]=>
-  array(6) {
-    ["filename"]=>
-    string(11) "package.xml"
-    ["mode"]=>
-    int(33206)
-    ["uid"]=>
-    int(0)
-    ["gid"]=>
-    int(0)
-    ["size"]=>
-    int(921)
-    ["typeflag"]=>
-    string(0) ""
-  }
-  [1]=>
-  array(8) {
-    ["checksum"]=>
-    int(5600)
-    ["filename"]=>
-    string(38) "pkg2-1.0/multiplepackages/pkg2file.php"
-    ["mode"]=>
-    int(33206)
-    ["uid"]=>
-    int(0)
-    ["gid"]=>
-    int(0)
-    ["size"]=>
-    int(0)
-    ["mtime"]=>
-    int(1071119030)
-    ["typeflag"]=>
-    string(0) ""
-  }
-  [2]=>
-  array(8) {
-    ["checksum"]=>
-    int(5066)
-    ["filename"]=>
-    string(32) "pkg2-1.0/nestedroot/rootfile.php"
-    ["mode"]=>
-    int(33206)
-    ["uid"]=>
-    int(0)
-    ["gid"]=>
-    int(0)
-    ["size"]=>
-    int(0)
-    ["mtime"]=>
-    int(1071119266)
-    ["typeflag"]=>
-    string(0) ""
-  }
-  [3]=>
-  array(8) {
-    ["checksum"]=>
-    int(7193)
-    ["filename"]=>
-    string(53) "pkg2-1.0/nestedroot/emptydir/nesteddir/nestedfile.php"
-    ["mode"]=>
-    int(33206)
-    ["uid"]=>
-    int(0)
-    ["gid"]=>
-    int(0)
-    ["size"]=>
-    int(0)
-    ["mtime"]=>
-    int(1071119310)
-    ["typeflag"]=>
-    string(0) ""
-  }
-}
-test failure:
-Analyzing multiplepackages\pkg2file.php
-Analyzing nestedroot\rootfile.php
-Analyzing nestedroot\emptydir\nesteddir\nestedfile.php
-Analyzing nestedroot\emptydir\nesteddir\doesntexist.php
-Caught error: File does not exist: nestedroot\emptydir\nesteddir\doesntexist.php
\ No newline at end of file
diff --git a/pear/tests/pear_registry.phpt b/pear/tests/pear_registry.phpt
deleted file mode 100644 (file)
index ebec176..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
---TEST--
-PEAR_Registry
---SKIPIF--
-<?php
-if (!getenv('PHP_PEAR_RUNTESTS')) {
-    echo 'skip';
-}
-?>
---FILE--
-<?php
-
-error_reporting(E_ALL);
-include dirname(__FILE__)."/../PEAR/Registry.php";
-PEAR::setErrorHandling(PEAR_ERROR_DIE, "%s\n");
-cleanall();
-
-$files1 = array(
-    "pkg1-1.php" => array(
-        "role" => "php",
-        ),
-    "pkg1-2.php" => array(
-        "role" => "php",
-        "baseinstalldir" => "pkg1",
-        ),
-    );
-$files2 = array(
-    "pkg2-1.php" => array(
-        "role" => "php",
-        ),
-    "pkg2-2.php" => array(
-        "role" => "php",
-        "baseinstalldir" => "pkg2",
-        ),
-    );
-$files3 = array(
-    "pkg3-1.php" => array(
-        "role" => "php",
-        ),
-    "pkg3-2.php" => array(
-        "role" => "php",
-        "baseinstalldir" => "pkg3",
-        ),
-    );
-$files3_new = array(
-    "pkg3-3.php" => array(
-        "role" => "php",
-        "baseinstalldir" => "pkg3",
-        ),
-    "pkg3-4.php" => array(
-        "role" => "php",
-        ),
-    );
-
-print "creating registry object\n";
-$reg = new PEAR_Registry;
-$reg->statedir = getcwd();
-dumpall($reg);
-
-$reg->addPackage("pkg1", array("name" => "pkg1", "version" => "1.0", "filelist" => $files1));
-dumpall($reg);
-
-$reg->addPackage("pkg2", array("name" => "pkg2", "version" => "2.0", "filelist" => $files2));
-$reg->addPackage("pkg3", array("name" => "pkg3", "version" => "3.0", "filelist" => $files3));
-dumpall($reg);
-
-$reg->updatePackage("pkg2", array("version" => "2.1"));
-dumpall($reg);
-
-var_dump($reg->deletePackage("pkg2"));
-dumpall($reg);
-
-var_dump($reg->deletePackage("pkg2"));
-dumpall($reg);
-
-$reg->updatePackage("pkg3", array("version" => "3.1b1", "status" => "beta"));
-dumpall($reg);
-
-$testing = $reg->checkFilemap(array_merge($files3, $files2));
-$ok = ($testing == array('pkg3-1.php' => 'pkg3', 'pkg3' . DIRECTORY_SEPARATOR . 'pkg3-2.php' => 'pkg3'));
-echo 'filemap OK? ' . ($ok ? "yes\n" : "no\n");
-
-$reg->updatePackage("pkg3", array("filelist" => $files3_new));
-dumpall($reg);
-
-print "tests done\n";
-
-cleanall();
-
-// ------------------------------------------------------------------------- //
-
-function cleanall()
-{
-    $dp = opendir(".");
-    while ($ent = readdir($dp)) {
-        if (substr($ent, -4) == ".reg") {
-            unlink($ent);
-        }
-    }
-}
-
-function dumpall(&$reg)
-{
-    print "dumping registry...\n";
-    $info = $reg->packageInfo();
-    foreach ($info as $pkg) {
-        print $pkg["name"] . ":";
-        unset($pkg["name"]);
-        foreach ($pkg as $k => $v) {
-            if ($k == '_lastmodified') continue;
-            if (is_array($v) && $k == 'filelist') {
-                print " $k=array(";
-                $i = 0;
-                foreach ($v as $k2 => $v2) {
-                    if ($i++ > 0) print ",";
-                    print "{$k2}[";
-                    $j = 0;
-                    foreach ($v2 as $k3 => $v3) {
-                        if ($j++ > 0) print ",";
-                        print "$k3=$v3";
-                    }
-                    print "]";
-                }
-                print ")";
-            } else {
-                print " $k=\"$v\"";
-            }
-        }
-        print "\n";
-    }
-    print "dump done\n";
-}
-
-?>
---EXPECT--
-creating registry object
-dumping registry...
-dump done
-dumping registry...
-pkg1: version="1.0" filelist=array(pkg1-1.php[role=php],pkg1-2.php[role=php,baseinstalldir=pkg1])
-dump done
-dumping registry...
-pkg1: version="1.0" filelist=array(pkg1-1.php[role=php],pkg1-2.php[role=php,baseinstalldir=pkg1])
-pkg2: version="2.0" filelist=array(pkg2-1.php[role=php],pkg2-2.php[role=php,baseinstalldir=pkg2])
-pkg3: version="3.0" filelist=array(pkg3-1.php[role=php],pkg3-2.php[role=php,baseinstalldir=pkg3])
-dump done
-dumping registry...
-pkg1: version="1.0" filelist=array(pkg1-1.php[role=php],pkg1-2.php[role=php,baseinstalldir=pkg1])
-pkg2: version="2.1" filelist=array(pkg2-1.php[role=php],pkg2-2.php[role=php,baseinstalldir=pkg2])
-pkg3: version="3.0" filelist=array(pkg3-1.php[role=php],pkg3-2.php[role=php,baseinstalldir=pkg3])
-dump done
-bool(true)
-dumping registry...
-pkg1: version="1.0" filelist=array(pkg1-1.php[role=php],pkg1-2.php[role=php,baseinstalldir=pkg1])
-pkg3: version="3.0" filelist=array(pkg3-1.php[role=php],pkg3-2.php[role=php,baseinstalldir=pkg3])
-dump done
-bool(false)
-dumping registry...
-pkg1: version="1.0" filelist=array(pkg1-1.php[role=php],pkg1-2.php[role=php,baseinstalldir=pkg1])
-pkg3: version="3.0" filelist=array(pkg3-1.php[role=php],pkg3-2.php[role=php,baseinstalldir=pkg3])
-dump done
-dumping registry...
-pkg1: version="1.0" filelist=array(pkg1-1.php[role=php],pkg1-2.php[role=php,baseinstalldir=pkg1])
-pkg3: version="3.1b1" filelist=array(pkg3-1.php[role=php],pkg3-2.php[role=php,baseinstalldir=pkg3]) status="beta"
-dump done
-filemap OK? yes
-dumping registry...
-pkg1: version="1.0" filelist=array(pkg1-1.php[role=php],pkg1-2.php[role=php,baseinstalldir=pkg1])
-pkg3: version="3.1b1" filelist=array(pkg3-3.php[role=php,baseinstalldir=pkg3],pkg3-4.php[role=php]) status="beta"
-dump done
-tests done
diff --git a/pear/tests/pear_system.phpt b/pear/tests/pear_system.phpt
deleted file mode 100644 (file)
index 591b3b6..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
---TEST--
-System commands tests
---SKIPIF--
-<?php
-if (!getenv('PHP_PEAR_RUNTESTS')) {
-    echo 'skip';
-}
-?>
---FILE--
-<?php
-error_reporting(E_ALL);
-require_once 'System.php';
-
-$sep = DIRECTORY_SEPARATOR;
-$ereg_sep = $sep;
-if (OS_WINDOWS) {
-    $ereg_sep .= $sep;
-}
-/*******************
-        mkDir
-********************/
-// Single directory creation
-System::mkDir('singledir');
-if( !is_dir('singledir') ){
-    print "System::mkDir('singledir'); failed\n";
-}
-System::rm('singledir');
-
-// Multiple directory creation
-System::mkDir('dir1 dir2 dir3');
-if (!@is_dir('dir1') || !@is_dir('dir2') || !@is_dir('dir3')) {
-    print "System::mkDir('dir1 dir2 dir3'); failed\n";
-}
-
-// Parent creation without "-p" fail
-if (@System::mkDir("dir4{$sep}dir3")) {
-    print "System::mkDir(\"dir4{$sep}dir3\") did not failed\n";
-}
-
-// Create a directory which is a file already fail
-touch('file4');
-$res = @System::mkDir('file4 dir5');
-if ($res) {
-    print "System::mkDir('file4 dir5') did not failed\n";
-}
-if (!@is_dir('dir5')) {
-    print "System::mkDir('file4 dir5') failed\n";
-}
-
-// Parent directory creation
-System::mkDir("-p dir2{$sep}dir21 dir6{$sep}dir61{$sep}dir611");
-if (!@is_dir("dir2{$sep}dir21") || !@is_dir("dir6{$sep}dir61{$sep}dir611")) {
-    print "System::mkDir(\"-p dir2{$sep}dir21 dir6{$sep}dir61{$sep}dir611\")); failed\n";
-}
-
-/*******************
-        mkTemp
-********************/
-
-// Create a temporal file with "tst" as filename prefix
-$tmpfile = System::mkTemp('tst');
-$tmpenv = str_replace($sep, $ereg_sep, System::tmpDir());
-if (!@is_file($tmpfile) || !ereg("^$tmpenv{$ereg_sep}tst", $tmpfile)) {
-    print "System::mkTemp('tst') failed\n";
-    var_dump(is_file($tmpfile), $tmpfile, "^$tmpenv{$ereg_sep}tst", !ereg("^$tmpenv{$ereg_sep}tst", $tmpfile));
-}
-
-// Create a temporal dir in "dir1" with default prefix "tmp"
-$tmpdir  = System::mkTemp('-d -t dir1');
-if (!@is_dir($tmpdir) || !ereg("^dir1{$ereg_sep}tmp", $tmpdir)) {
-    print "System::mkTemp('-d -t dir1') failed\n";
-}
-
-/*******************
-        rm
-********************/
-
-// Try to delete a dir without "-r" option
-if (@System::rm('dir1')) {
-    print "System::rm('dir1') did not fail\n";
-}
-
-// Multiple and recursive delete
-$del = "dir1 dir2 dir3 file4 dir5 dir6";
-if (!@System::rm("-r $del")) {
-    print "System::rm(\"-r $del\") failed\n";
-}
-
-/*******************
-        which
-********************/
-
-if (OS_UNIX) {
-    if (System::which('ls') != '/bin/ls') {
-        print "System::which('ls') failed\n";
-    }
-    if (System::which('i_am_not_a_command')) {
-        print "System::which('i_am_not_a_command') did not failed\n";
-    }
-} // XXX Windows test
-
-/*******************
-        cat
-********************/
-// Missing tests yet
-
-print "end\n";
-?>
---EXPECT--
-end
diff --git a/pear/tests/php.ini b/pear/tests/php.ini
deleted file mode 100644 (file)
index c75c9b4..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-; php.ini for PEAR tests
-include_path=..
diff --git a/pear/tests/system.input b/pear/tests/system.input
deleted file mode 100644 (file)
index 9c6bece..0000000
+++ /dev/null
@@ -1 +0,0 @@
-a:1:{s:13:"master_server";s:12:"pear.php.net";}
\ No newline at end of file
diff --git a/pear/tests/test-pkg6/goompness/Mopreeb.php b/pear/tests/test-pkg6/goompness/Mopreeb.php
deleted file mode 100644 (file)
index 5422435..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-<?php
-
-/**
- * 
- *
- * @version $Id$
- * @copyright 2003 
- **/
-class test1{}
-
-?>
\ No newline at end of file
diff --git a/pear/tests/test-pkg6/goompness/oggbrzitzkee.php b/pear/tests/test-pkg6/goompness/oggbrzitzkee.php
deleted file mode 100644 (file)
index 5422435..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-<?php
-
-/**
- * 
- *
- * @version $Id$
- * @copyright 2003 
- **/
-class test1{}
-
-?>
\ No newline at end of file
diff --git a/pear/tests/test-pkg6/invalidtgz.tgz b/pear/tests/test-pkg6/invalidtgz.tgz
deleted file mode 100644 (file)
index 909d507..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1" ?>\r
-    <!DOCTYPE package SYSTEM "http://pear.php.net/dtd/package-1.0">\r
-    <package version="1.0">\r
-      <name>pkg6</name>\r
-      <summary>required test for PEAR_Installer</summary>\r
-      <description>\r
-        fake package\r
-      </description>\r
-      <license>PHP License</license>\r
-      <maintainers>\r
-        <maintainer>\r
-          <user>fakeuser</user>\r
-          <name>Joe Shmoe</name>\r
-          <email>nobody@example.com</email>\r
-          <role>lead</role>\r
-        </maintainer>\r
-      </maintainers>\r
-      <release>\r
-        <version>1.1</version>\r
-        <date>2003-09-09</date>\r
-        <state>stable</state>\r
-        <notes>\r
-                       required dependency test\r
-        </notes>\r
-        <filelist>\r
-          <dir name="/" baseinstalldir="groob" role="php">\r
-            <file>zoorb.php</file>\r
-            <dir name="goompness" role="php">\r
-              <file>oggbrzitzkee.php</file>\r
-              <file>Mopreeb.php</file>\r
-            </dir>\r
-          </dir>\r
-        </filelist>\r
-      </release>\r
-   </package>\r
diff --git a/pear/tests/test-pkg6/nopackagexml.tgz b/pear/tests/test-pkg6/nopackagexml.tgz
deleted file mode 100644 (file)
index 8b9d9aa..0000000
Binary files a/pear/tests/test-pkg6/nopackagexml.tgz and /dev/null differ
diff --git a/pear/tests/test-pkg6/package.xml b/pear/tests/test-pkg6/package.xml
deleted file mode 100644 (file)
index 102f972..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1" ?>
-    <!DOCTYPE package SYSTEM "http://pear.php.net/dtd/package-1.0">
-    <package version="1.0">
-      <name>pkg6</name>
-      <summary>required test for PEAR_Installer</summary>
-      <description>
-        fake package
-      </description>
-      <license>PHP License</license>
-      <maintainers>
-        <maintainer>
-          <user>fakeuser</user>
-          <name>Joe Shmoe</name>
-          <email>nobody@example.com</email>
-          <role>lead</role>
-        </maintainer>
-      </maintainers>
-      <release>
-        <version>1.1</version>
-        <date>2003-09-09</date>
-        <state>stable</state>
-        <notes>
-                       required dependency test
-        </notes>
-        <filelist>
-          <dir name="/" baseinstalldir="groob" role="php">
-            <file>zoorb.php</file>
-            <dir name="goompness" role="php">
-              <file>oggbrzitzkee.php</file>
-              <file>Mopreeb.php</file>
-            </dir>
-          </dir>
-        </filelist>
-      </release>
-   </package>
diff --git a/pear/tests/test-pkg6/pkg6-1.1.tgz b/pear/tests/test-pkg6/pkg6-1.1.tgz
deleted file mode 100644 (file)
index 09868ca..0000000
Binary files a/pear/tests/test-pkg6/pkg6-1.1.tgz and /dev/null differ
diff --git a/pear/tests/test-pkg6/pkg6-2.0b1.tgz b/pear/tests/test-pkg6/pkg6-2.0b1.tgz
deleted file mode 100644 (file)
index 45e8877..0000000
Binary files a/pear/tests/test-pkg6/pkg6-2.0b1.tgz and /dev/null differ
diff --git a/pear/tests/test-pkg6/zoorb.php b/pear/tests/test-pkg6/zoorb.php
deleted file mode 100644 (file)
index 5422435..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-<?php
-
-/**
- * 
- *
- * @version $Id$
- * @copyright 2003 
- **/
-class test1{}
-
-?>
\ No newline at end of file
diff --git a/pear/tests/testdownload.tgz b/pear/tests/testdownload.tgz
deleted file mode 100644 (file)
index 0ddc3df..0000000
Binary files a/pear/tests/testdownload.tgz and /dev/null differ
diff --git a/pear/tests/toonew.conf b/pear/tests/toonew.conf
deleted file mode 100644 (file)
index 6f0c72f..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-#PEAR_Config 2.0
-master_server = pear.php.net
diff --git a/pear/tests/user.input b/pear/tests/user.input
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/pear/tests/user2.input b/pear/tests/user2.input
deleted file mode 100644 (file)
index ac9a8af..0000000
+++ /dev/null
@@ -1 +0,0 @@
-a:1:{s:7:"verbose";i:2;}
\ No newline at end of file