]> granicus.if.org Git - php/commitdiff
sync with PEAR_1_3 branch of pear-core
authorGreg Beaver <cellog@php.net>
Mon, 25 Oct 2004 17:14:34 +0000 (17:14 +0000)
committerGreg Beaver <cellog@php.net>
Mon, 25 Oct 2004 17:14:34 +0000 (17:14 +0000)
pear/PEAR/Builder.php
pear/PEAR/Command/Install.php
pear/PEAR/Command/Package.php
pear/PEAR/Common.php
pear/PEAR/Downloader.php
pear/PEAR/ErrorStack.php
pear/PEAR/Exception.php
pear/PEAR/Installer.php
pear/PEAR/Registry.php

index 4806155ef5940eac907d535dc51c9bf3941972c0..c6b4a4f248a6c8caff550e3d4b4b9da545ea47d6 100644 (file)
@@ -198,7 +198,7 @@ class PEAR_Builder extends PEAR_Common
         $dir = getcwd();
         $this->log(2, "building in $dir");
         $this->current_callback = $callback;
-        putenv('PATH=' . getenv('PATH') . ':' . $this->config->get('bin_dir'));
+        putenv('PATH=' . $this->config->get('bin_dir') . ':' . getenv('PATH'));
         $err = $this->_runCommand("phpize", array(&$this, 'phpizeCallback'));
         if (PEAR::isError($err)) {
             return $err;
index f804a838e3aa2c6855dd67f635072e090f965bea..7a89c7cddd62df5edc5ced4432fdf480cbe3ee4e 100644 (file)
@@ -303,7 +303,13 @@ package if needed.
         $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();
+            if (PEAR::isError($info)) {
+                $this->ui->outputData('ERROR: ' .$info->getMessage());
+                continue;
+            }
             if (is_array($info)) {
                 if ($this->config->get('verbose') > 0) {
                     $label = "$info[package] $info[version]";
index dcdc86bd1a4e6cc92f503db30f797312d8cccea1..d0aca3f8e56370323c3ccb599bda419a2bf8e5c5 100644 (file)
@@ -155,7 +155,12 @@ use the "slide" option to move the release tag.
             'summary' => 'Run Regression Tests',
             'function' => 'doRunTests',
             'shortcut' => 'rt',
-            'options' => array(),
+            'options' => array(
+                'recur' => array(
+                    'shortopt' => 'r',
+                    'doc' => 'Run tests in child directories, recursively.  4 dirs deep maximum',
+                )
+            ),
             'doc' => '[testfile|dir ...]
 Run regression tests with PHP\'s regression testing script (run-tests.php).',
             ),
@@ -250,6 +255,9 @@ Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
     {
         $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();
@@ -264,12 +272,6 @@ Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
         if (isset($options['showname'])) {
             $this->output = $result;
         }
-        /* (cox) What is supposed to do that code?
-        $lines = explode("\n", $this->output);
-        foreach ($lines as $line) {
-            $this->output .= $line."n";
-        }
-        */
         if (PEAR::isError($result)) {
             $this->output .= "Package failed: ".$result->getMessage();
         }
@@ -434,6 +436,31 @@ Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
 
     function doRunTests($command, $options, $params)
     {
+        include_once 'PEAR/RunTest.php';
+        $log = new PEAR_Common;
+        $run = new PEAR_RunTest($log);
+        $tests = array();
+        if (isset($options['recur'])) {
+            $depth = 4;
+        } else {
+            $depth = 1;
+        }
+        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 {
+                $tests[] = $p;
+            }
+        }
+        foreach ($tests as $t) {
+            $run->run($t);
+        }
+
+        return true;
+        /*
         $cwd = getcwd();
         $php = $this->config->get('php_bin');
         putenv("TEST_PHP_EXECUTABLE=$php");
@@ -463,6 +490,7 @@ Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
             system($cmd);
         }
         return true;
+        */
     }
 
     // }}}
@@ -642,6 +670,7 @@ Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
             if (!isset($attr['role'])) {
                 continue;
             }
+            $name = preg_replace('![/:\\\\]!', '/', $name);
             if ($attr['role'] == 'doc') {
                 $info['doc_files'] .= " $name";
 
index 2f9c6118234cdec41bd39cba83afdcf188c9fda8..3449ffaac3042c2c2622f091d1dc0d6f08c51fd6 100644 (file)
@@ -34,7 +34,7 @@ define('_PEAR_COMMON_PACKAGE_NAME_PREG', '[A-Za-z][a-zA-Z0-9_]+');
 define('PEAR_COMMON_PACKAGE_NAME_PREG', '/^' . _PEAR_COMMON_PACKAGE_NAME_PREG . '$/');
 
 // this should allow: 1, 1.0, 1.0RC1, 1.0dev, 1.0dev123234234234, 1.0a1, 1.0b1, 1.0pl1
-define('_PEAR_COMMON_PACKAGE_VERSION_PREG', '\d+(?:\.\d+)*(?:[a-z]+\d*)?');
+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 :-)
@@ -98,7 +98,9 @@ $GLOBALS['_PEAR_Common_script_phases'] = array('pre-install', 'post-install', 'p
 // }}}
 
 /**
- * Class providing common functionality for PEAR adminsitration classes.
+ * Class providing common functionality for PEAR administration classes.
+ * @deprecated This class will disappear, and its components will be spread
+ *             into smaller classes, like the AT&T breakup
  */
 class PEAR_Common extends PEAR
 {
@@ -142,12 +144,6 @@ class PEAR_Common extends PEAR
      * @access private
      */
     var $_validPackageFile;
-    /**
-     * Temporary variable used in sorting packages by dependency in {@link sortPkgDeps()}
-     * @var array
-     * @access private
-     */
-    var $_packageSortTree;
 
     // }}}
 
@@ -1293,6 +1289,15 @@ class PEAR_Common extends PEAR
         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;
         }
@@ -1315,17 +1320,21 @@ class PEAR_Common extends PEAR
         $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];
@@ -1341,6 +1350,14 @@ class PEAR_Common extends PEAR
                 }
             }
             switch ($token) {
+                case T_WHITESPACE:
+                    continue;
+                case ';':
+                    if ($interface) {
+                        $current_function = '';
+                        $current_function_level = -1;
+                    }
+                    break;
                 case '"':
                     $inquote = true;
                     break;
@@ -1362,6 +1379,8 @@ class PEAR_Common extends PEAR
                 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)) {
                         PEAR::raiseError("Parser error: Invalid PHP file $file",
@@ -1371,19 +1390,38 @@ class PEAR_Common extends PEAR
                 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', 'clone', 'throw') 
+                                 )) {
+                            PEAR::raiseError('Error: PHP5 packages must be packaged by php 5 PEAR');
+                            return false;
+                        }
+                    }
                     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;
@@ -1398,6 +1436,7 @@ class PEAR_Common extends PEAR
                 case T_VARIABLE:
                     $look_for = 0;
                     continue 2;
+                case T_DOC_COMMENT:
                 case T_COMMENT:
                     if (preg_match('!^/\*\*\s!', $data)) {
                         $lastphpdoc = $data;
@@ -1422,10 +1461,12 @@ class PEAR_Common extends PEAR
         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,
             );
     }
 
index 17ad4566a10c87a6791c6c481049471c9f88a1ae..793cc0410e7f155829b2227bc2d0f9a2d900e3cb 100644 (file)
@@ -381,7 +381,8 @@ class PEAR_Downloader extends PEAR_Common
                     // there are no dependencies
                     continue;
                 }
-                foreach($alldeps as $info) {
+                $fail = false;
+                foreach ($alldeps as $info) {
                     if ($info['type'] != 'pkg') {
                         continue;
                     }
@@ -389,11 +390,18 @@ class PEAR_Downloader extends PEAR_Common
                     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)) {
@@ -561,7 +569,7 @@ class PEAR_Downloader extends PEAR_Common
             $savestate = array_shift($get);
             $this->pushError( "Release for '$package' dependency '$info[name]' " .
                 "has state '$savestate', requires '$state'");
-            return false;
+            return 0;
         }
         if (in_array(strtolower($info['name']), $this->_toDownload) ||
               isset($mywillinstall[strtolower($info['name'])])) {
index 6f44f4d686e774cfadd99cae96341362d307ebb0..329e076a6e91894aa05d340ca6bbb78e4200fa70 100644 (file)
  * 
  * Since version 0.3alpha, it is possible to specify the exception class
  * returned from {@link push()}
+ *
+ * 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 0.6alpha
+ * @version PEAR1.3.2 (beta)
  * @package PEAR_ErrorStack
  * @category Debugging
  * @license http://www.php.net/license/3_0.txt PHP License v3.0
@@ -220,13 +223,6 @@ class PEAR_ErrorStack {
      */
     var $_logger = false;
     
-    /**
-     * Class name to use for a PHP 5 exception that will be returned
-     * @var string
-     * @access protected
-     */
-    var $_exceptionClass = 'Exception';
-    
     /**
      * Error messages - designed to be overridden
      * @var array
@@ -242,20 +238,14 @@ class PEAR_ErrorStack {
      * @param callback $contextCallback callback used for context generation,
      *                 defaults to {@link getFileLine()}
      * @param boolean  $throwPEAR_Error
-     * @param string   $exceptionClass exception class to instantiate if
-     *                 in PHP 5
      */
     function PEAR_ErrorStack($package, $msgCallback = false, $contextCallback = false,
-                         $throwPEAR_Error = false, $exceptionClass = null)
+                         $throwPEAR_Error = false)
     {
         $this->_package = $package;
         $this->setMessageCallback($msgCallback);
         $this->setContextCallback($contextCallback);
         $this->_compat = $throwPEAR_Error;
-        // this allows child classes to simply redefine $this->_exceptionClass
-        if (!is_null($exceptionClass)) {
-            $this->_exceptionClass = $exceptionClass;
-        }
     }
     
     /**
@@ -268,29 +258,27 @@ class PEAR_ErrorStack {
      * @param callback $contextCallback callback used for context generation,
      *                 defaults to {@link getFileLine()}
      * @param boolean  $throwPEAR_Error
-     * @param string   $exceptionClass exception class to instantiate if
-     *                 in PHP 5
      * @param string   $stackClass class to instantiate
      * @static
      * @return PEAR_ErrorStack
      */
     function &singleton($package, $msgCallback = false, $contextCallback = false,
-                         $throwPEAR_Error = false, $exceptionClass = null,
-                         $stackClass = 'PEAR_ErrorStack')
+                         $throwPEAR_Error = false, $stackClass = 'PEAR_ErrorStack')
     {
         if (isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
             return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package];
         }
         if (!class_exists($stackClass)) {
-            $trace = debug_backtrace();
+            if (function_exists('debug_backtrace')) {
+                $trace = debug_backtrace();
+            }
             PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_NONCLASS,
                 'exception', array('stackclass' => $stackClass),
                 '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,
-                             $exceptionClass);
+            &new $stackClass($package, $msgCallback, $contextCallback, $throwPEAR_Error);
     }
 
     /**
@@ -383,12 +371,16 @@ class PEAR_ErrorStack {
     /**
      * Set an error code => error message mapping callback
      * 
-     * This method sets the callback that can be used to generate error
-     * messages for any PEAR_ErrorStack instance
-     * @param array|string Callback function/method
+     * This method sets the callback that can be used to generate context
+     * information for an error.  Passing in NULL will disable context generation
+     * and remove the expensive call to debug_backtrace()
+     * @param array|string|null Callback function/method
      */
     function setContextCallback($contextCallback)
     {
+        if ($contextCallback === null) {
+            return $this->_contextCallback = false;
+        }
         if (!$contextCallback) {
             $this->_contextCallback = array(&$this, 'getFileLine');
         } else {
@@ -504,7 +496,7 @@ class PEAR_ErrorStack {
      *    'time' => time(),
      *    'context' => $context,
      *    'message' => $msg,
-     * //['repackage' => $err] repackaged error array
+     * //['repackage' => $err] repackaged error array/Exception class
      * );
      * </code>
      */
@@ -538,8 +530,7 @@ class PEAR_ErrorStack {
             $msg = call_user_func_array($this->_msgCallback,
                                         array(&$this, $err));
             $err['message'] = $msg;
-        }
-        
+        }        
         
         if ($repackage) {
             $err['repackage'] = $repackage;
@@ -588,15 +579,6 @@ class PEAR_ErrorStack {
         if ($this->_compat && $push) {
             return $this->raiseError($msg, $code, null, null, $err);
         }
-        if (class_exists($this->_exceptionClass)) {
-            $exception = $this->_exceptionClass;
-            if (is_string($msg) && is_numeric($code)) {
-                $code = $code + 0;
-            }
-            $ret = new $exception($msg, $code);
-            $ret->errorData = $err;
-            return $ret;
-        }
         return $err;
     }
     
@@ -630,7 +612,9 @@ class PEAR_ErrorStack {
         $s = &PEAR_ErrorStack::singleton($package);
         if ($s->_contextCallback) {
             if (!$backtrace) {
-                $backtrace = debug_backtrace();
+                if (function_exists('debug_backtrace')) {
+                    $backtrace = debug_backtrace();
+                }
             }
         }
         return $s->push($code, $level, $params, $msg, $repackage, $backtrace);
@@ -757,7 +741,7 @@ class PEAR_ErrorStack {
     /**
      * Get a list of all errors since last purge, organized by package
      * @since PEAR 1.4.0dev BC break! $level is now in the place $merge used to be
-     * @param boolean $clearStack Set to purge the error stack of existing errors
+     * @param boolean $purge Set to purge the error stack of existing errors
      * @param string  $level Set to a level name in order to retrieve only errors of a particular level
      * @param boolean $merge Set to return a flat array, not organized by package
      * @param array   $sortfunc Function used to sort a merged array - default
index 8322fd034a2cc6837c23957932357290daea3df4..a5be021a974e1b837853538730a3ffd2930f7661 100644 (file)
 // +----------------------------------------------------------------------+
 // | Authors: Tomas V.V.Cox <cox@idecnet.com>                             |
 // |          Hans Lellelid <hans@velum.net>                              |
-// |                                                                      |
+// |          Bertrand Mansion <bmansion@mamasam.com>                     |
+// |          Greg Beaver <cellog@php.net>                                |
 // +----------------------------------------------------------------------+
 //
 // $Id$
 
-define('PEAR_OBSERVER_PRINT',      -2);
-define('PEAR_OBSERVER_TRIGGER',    -4);
-define('PEAR_OBSERVER_DIE',        -8);
 
 /**
  * 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))
  * - Definable triggers, shot when exceptions occur
  * - Pretty and informative error messages
- * - Added more context info avaible (like class, method or cause)
+ * - Added more context info available (like class, method or cause)
+ * - cause can be a PEAR_Exception or an array of mixed
+ *   PEAR_Exceptions/PEAR_ErrorStack warnings
+ * - callbacks for specific exception classes and their children
  *
  * 2) Ideas:
  *
@@ -54,8 +59,8 @@ define('PEAR_OBSERVER_DIE',        -8);
  * getCode
  * getFile
  * getLine
- * getTrace
- * getTraceAsString
+ * getTraceSafe
+ * getTraceSafeAsString
  * __toString
  *
  * 5) Usage example
@@ -88,16 +93,18 @@ define('PEAR_OBSERVER_DIE',        -8);
  * @version $Revision$
  * @author Tomas V.V.Cox <cox@idecnet.com>
  * @author Hans Lellelid <hans@velum.net>
+ * @author Bertrand Mansion <bmansion@mamasam.com>
  *
  */
 class PEAR_Exception extends Exception
 {
+    const OBSERVER_PRINT = -2;
+    const OBSERVER_TRIGGER = -4;
+    const OBSERVER_DIE = -8;
     protected $cause;
-    protected $error_class;
-    protected $error_method;
-
-    private $_method;
     private static $_observers = array();
+    private static $_uniqueid = 0;
+    private $_trace;
 
     /**
      * Supported signatures:
@@ -105,49 +112,56 @@ class PEAR_Exception extends Exception
      * PEAR_Exception(string $message, int $code);
      * PEAR_Exception(string $message, Exception $cause);
      * PEAR_Exception(string $message, Exception $cause, int $code);
+     * PEAR_Exception(string $message, array $causes);
+     * PEAR_Exception(string $message, array $causes, int $code);
      */
     public function __construct($message, $p2 = null, $p3 = null)
     {
-        $code = null;
-        $cause = null;
-        if (is_int($p3) && $p2 instanceof Exception) {
-            $code = $p3;
-            $cause = $p2;
-        } elseif (is_int($p2)) {
+        if (is_int($p2)) {
             $code = $p2;
-        } elseif ($p2 instanceof Exception) {
-            $cause = $p2;
+            $this->cause = null;
+        } elseif ($p2 instanceof Exception || is_array($p2)) {
+            $code = $p3;
+            if (is_array($p2) && isset($p2['message'])) {
+                // fix potential problem of passing in a single warning
+                $p2 = array($p2);
+            }
+            $this->cause = $p2;
+        } else {
+        $code = null;
+            $this->cause = null;
         }
-        $this->cause = $cause;
-        $trace       = parent::getTrace();
-        $this->error_class  = $trace[0]['class'];
-        $this->error_method = $trace[0]['function'];
-        $this->_method = $this->error_class . '::' . $this->error_method . '()';
         parent::__construct($message, $code);
-
-        $this->_signal();
+        $this->signal();
     }
 
     /**
      * @param mixed $callback  - A valid php callback, see php func is_callable()
-     *                         - A PEAR_OBSERVER_* constant
-     *                         - An array(const PEAR_OBSERVER_*, mixed $options)
-     *
-     * @param string $label    The name of the observer. Use this if you want
-     *                           to remove it later with delObserver()
+     *                         - A PEAR_Exception::OBSERVER_* constant
+     *                         - An array(const PEAR_Exception::OBSERVER_*,
+     *                           mixed $options)
+     * @param string $label    The name of the observer. Use this if you want
+     *                         to remove it later with removeObserver()
      */
-
     public static function addObserver($callback, $label = 'default')
     {
         self::$_observers[$label] = $callback;
     }
 
-    public static function delObserver($label = 'default')
+    public static function removeObserver($label = 'default')
     {
         unset(self::$_observers[$label]);
     }
 
-    private function _signal()
+    /**
+     * @return int unique identifier for an observer
+     */
+    public static function getUniqueId()
+    {
+        return self::$_uniqueid++;
+    }
+
+    private function signal()
     {
         foreach (self::$_observers as $func) {
             if (is_callable($func)) {
@@ -156,15 +170,15 @@ class PEAR_Exception extends Exception
             }
             settype($func, 'array');
             switch ($func[0]) {
-                case PEAR_OBSERVER_PRINT:
+                case self::OBSERVER_PRINT :
                     $f = (isset($func[1])) ? $func[1] : '%s';
                     printf($f, $this->getMessage());
                     break;
-                case PEAR_OBSERVER_TRIGGER:
+                case self::OBSERVER_TRIGGER :
                     $f = (isset($func[1])) ? $func[1] : E_USER_NOTICE;
                     trigger_error($this->getMessage(), $f);
                     break;
-                case PEAR_OBSERVER_DIE:
+                case self::OBSERVER_DIE :
                     $f = (isset($func[1])) ? $func[1] : '%s';
                     die(printf($f, $this->getMessage()));
                     break;
@@ -174,48 +188,165 @@ class PEAR_Exception extends Exception
         }
     }
 
-    private function _getCauseMessage()
+    /**
+     * Return specific error information that can be used for more detailed
+     * error messages or translation.
+     *
+     * This method may be overridden in child exception classes in order
+     * to add functionality not present in PEAR_Exception and is a placeholder
+     * to define API
+     *
+     * The returned array must be an associative array of parameter => value like so:
+     * <pre>
+     * array('name' => $name, 'context' => array(...))
+     * </pre>
+     * @return array
+     */
+    public function getErrorData()
     {
-        $msg = "    #{$this->_method} at {$this->file} ({$this->line})\n" .
-               "     {$this->message}\n";
-        if ($this->cause instanceof Exception) {
-            return $this->cause->_getCauseMessage() . $msg;
-        }
-        return $msg;
+        return array();
     }
 
     /**
-     * @return Exception_object The context of the exception
+     * Returns the exception that caused this exception to be thrown
+     * @access public
+     * @return Exception|array The context of the exception
      */
     public function getCause()
     {
         return $this->cause;
     }
 
+    /**
+     * Function must be public to call on caused exceptions
+     * @param array
+     */
+    public function getCauseMessage(&$causes)
+    {
+        $trace = $this->getTraceSafe();
+        $causes[] = array('class'   => get_class($this),
+                          'message' => $this->message,
+                          'file'    => $trace[0]['file'],
+                          'line'    => $trace[0]['line']);
+        if ($this->cause instanceof PEAR_Exception) {
+            $this->cause->getCauseMessage($causes);
+        }
+        if (is_array($this->cause)) {
+            foreach ($this->cause as $cause) {
+                if ($cause instanceof PEAR_Exception) {
+                    $cause->getCauseMessage($causes);
+                } elseif (is_array($cause) && isset($cause['message'])) {
+                    // PEAR_ErrorStack warning
+                    $causes[] = array(
+                        'class' => $cause['package'],
+                        'message' => $cause['message'],
+                        'file' => isset($cause['context']['file']) ?
+                                            $cause['context']['file'] :
+                                            'unknown',
+                        'line' => isset($cause['context']['line']) ?
+                                            $cause['context']['line'] :
+                                            'unknown',
+                    );
+                }
+            }
+        }
+    }
+
+    public function getTraceSafe()
+    {   
+        if (!isset($this->_trace)) {
+            $this->_trace = $this->getTrace();
+            if (empty($this->_trace)) {
+                $backtrace = debug_backtrace();
+                $this->_trace = array($backtrace[count($backtrace)-1]);
+            }
+        }
+        return $this->_trace;
+    }
+
     public function getErrorClass()
     {
-        return $this->error_class;
+        $trace = $this->getTraceSafe();
+        return $trace[0]['class'];
     }
 
     public function getErrorMethod()
     {
-        return $this->error_method;
+        $trace = $this->getTraceSafe();
+        return $trace[0]['function'];
     }
 
     public function __toString()
     {
-        $str = get_class($this) . " occurred: \n" .
-               "  Error message: {$this->message}\n" .
-               "  Error code   : {$this->code}\n" .
-               "  File (Line)  : {$this->file} ({$this->line})\n" .
-               "  Method       : {$this->_method}\n";
-        if ($this->cause instanceof Exception) {
-            $str .= "  Nested Error :\n" . $this->_getCauseMessage();
-        }
         if (isset($_SERVER['REQUEST_URI'])) {
-            return nl2br('<pre>'.htmlentities($str).'</pre>');
+            return $this->toHtml();
+        }
+        return $this->toText();
+        }
+
+    public function toHtml()
+    {
+        $trace = $this->getTraceSafe();
+        $causes = array();
+        $this->getCauseMessage($causes);
+        $html =  '<table border="1" cellspacing="0">' . "\n";
+        foreach ($causes as $i => $cause) {
+            $html .= '<tr><td colspan="3" bgcolor="#ff9999">'
+               . str_repeat('-', $i) . ' <b>' . $cause['class'] . '</b>: '
+               . htmlspecialchars($cause['message']) . ' in <b>' . $cause['file'] . '</b> '
+               . 'on line <b>' . $cause['line'] . '</b>'
+               . "</td></tr>\n";
+        }
+        $html .= '<tr><td colspan="3" bgcolor="#aaaaaa" align="center"><b>Exception trace</b></td></tr>' . "\n"
+               . '<tr><td align="center" bgcolor="#cccccc" width="20"><b>#</b></td>'
+               . '<td align="center" bgcolor="#cccccc"><b>Function</b></td>'
+               . '<td align="center" bgcolor="#cccccc"><b>Location</b></td></tr>' . "\n";
+
+        foreach ($trace as $k => $v) {
+            $html .= '<tr><td align="center">' . $k . '</td>'
+                   . '<td>';
+            if (!empty($v['class'])) {
+                $html .= $v['class'] . $v['type'];
+            }
+            $html .= $v['function'];
+            $args = array();
+            if (!empty($v['args'])) {
+                foreach ($v['args'] as $arg) {
+                    if (is_null($arg)) $args[] = 'null';
+                    elseif (is_array($arg)) $args[] = 'Array';
+                    elseif (is_object($arg)) $args[] = 'Object('.get_class($arg).')';
+                    elseif (is_bool($arg)) $args[] = $arg ? 'true' : 'false';
+                    elseif (is_int($arg) || is_double($arg)) $args[] = $arg;
+                    else {
+                        $arg = (string)$arg;
+                        $str = htmlspecialchars(substr($arg, 0, 16));
+                        if (strlen($arg) > 16) $str .= '&hellip;';
+                        $args[] = "'" . $str . "'";
+                    }
+                }
+            }
+            $html .= '(' . implode(', ',$args) . ')'
+                   . '</td>'
+                   . '<td>' . $v['file'] . ':' . $v['line'] . '</td></tr>' . "\n";
+        }
+        $html .= '<tr><td align="center">' . ($k+1) . '</td>'
+               . '<td>{main}</td>'
+               . '<td>&nbsp;</td></tr>' . "\n"
+               . '</table>';
+        return $html;
+    }
+
+    public function toText()
+    {
+        $causes = array();
+        $this->getCauseMessage($causes);
+        $causeMsg = '';
+        foreach ($causes as $i => $cause) {
+            $causeMsg .= str_repeat(' ', $i) . $cause['class'] . ': '
+                   . $cause['message'] . ' in ' . $cause['file']
+                   . ' on line ' . $cause['line'] . "\n";
         }
-        return $str;
+        return $causeMsg . $this->getTraceAsString();
     }
 }
 
index 5b178267813ce877079df3c0acdf1c0eeaec204e..2dc91c5d9755ba5a8c028c0af2e3fefd7af67cdd 100644 (file)
@@ -165,7 +165,14 @@ class PEAR_Installer extends PEAR_Downloader
                 include_once "OS/Guess.php";
                 $os = new OS_Guess();
             }
-            if (!$os->matchSignature($atts['platform'])) {
+            if (strlen($atts['platform']) && $atts['platform']{0} == '!') {
+                $negate = true;
+                $platform = substr($atts['platform'], 1);
+            } else {
+                $negate = false;
+                $platform = $atts['platform'];
+            }
+            if ((bool) $os->matchSignature($platform) === $negate) {
                 $this->log(3, "skipped $file (meant for $atts[platform], we are ".$os->getSignature().")");
                 return PEAR_INSTALLER_SKIPPED;
             }
index f85bbfdd5644d3a6de8ee778ee70cfc20d43ca41..c3b21bbaf13da02abd525d2bfa2ef3ce90400d61 100644 (file)
@@ -286,7 +286,9 @@ class PEAR_Registry extends PEAR
                 $open_mode = 'r';
             }
 
-            $this->lock_fp = @fopen($this->lockfile, $open_mode);
+            if (!is_resource($this->lock_fp)) {
+                $this->lock_fp = @fopen($this->lockfile, $open_mode);
+            }
 
             if (!is_resource($this->lock_fp)) {
                 return $this->raiseError("could not create lock file" .
@@ -312,6 +314,7 @@ class PEAR_Registry extends PEAR
     function _unlock()
     {
         $ret = $this->_lock(LOCK_UN);
+        fclose($this->lock_fp);
         $this->lock_fp = null;
         return $ret;
     }