[ Index ]
 

Code source de PHP PEAR 1.4.5

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/PEAR/Downloader/ -> Package.php (source)

   1  <?php
   2  /**
   3   * PEAR_Downloader_Package
   4   *
   5   * PHP versions 4 and 5
   6   *
   7   * LICENSE: This source file is subject to version 3.0 of the PHP license
   8   * that is available through the world-wide-web at the following URI:
   9   * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  10   * the PHP License and are unable to obtain it through the web, please
  11   * send a note to license@php.net so we can mail you a copy immediately.
  12   *
  13   * @category   pear
  14   * @package    PEAR
  15   * @author     Greg Beaver <cellog@php.net>
  16   * @copyright  1997-2006 The PHP Group
  17   * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  18   * @version    CVS: $Id: Package.php,v 1.104 2007/01/14 21:11:54 cellog Exp $
  19   * @link       http://pear.php.net/package/PEAR
  20   * @since      File available since Release 1.4.0a1
  21   */
  22  /**
  23   * Error code when parameter initialization fails because no releases
  24   * exist within preferred_state, but releases do exist
  25   */
  26  define('PEAR_DOWNLOADER_PACKAGE_STATE', -1003);
  27  /**
  28   * Coordinates download parameters and manages their dependencies
  29   * prior to downloading them.
  30   *
  31   * Input can come from three sources:
  32   *
  33   * - local files (archives or package.xml)
  34   * - remote files (downloadable urls)
  35   * - abstract package names
  36   *
  37   * The first two elements are handled cleanly by PEAR_PackageFile, but the third requires
  38   * accessing pearweb's xml-rpc interface to determine necessary dependencies, and the
  39   * format returned of dependencies is slightly different from that used in package.xml.
  40   *
  41   * This class hides the differences between these elements, and makes automatic
  42   * dependency resolution a piece of cake.  It also manages conflicts when
  43   * two classes depend on incompatible dependencies, or differing versions of the same
  44   * package dependency.  In addition, download will not be attempted if the php version is
  45   * not supported, PEAR installer version is not supported, or non-PECL extensions are not
  46   * installed.
  47   * @category   pear
  48   * @package    PEAR
  49   * @author     Greg Beaver <cellog@php.net>
  50   * @copyright  1997-2006 The PHP Group
  51   * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  52   * @version    Release: 1.5.0
  53   * @link       http://pear.php.net/package/PEAR
  54   * @since      Class available since Release 1.4.0a1
  55   */
  56  class PEAR_Downloader_Package
  57  {
  58      /**
  59       * @var PEAR_Downloader
  60       */
  61      var $_downloader;
  62      /**
  63       * @var PEAR_Config
  64       */
  65      var $_config;
  66      /**
  67       * @var PEAR_Registry
  68       */
  69      var $_registry;
  70      /**
  71       * Used to implement packagingroot properly
  72       * @var PEAR_Registry
  73       */
  74      var $_installRegistry;
  75      /**
  76       * @var PEAR_PackageFile_v1|PEAR_PackageFile|v2
  77       */
  78      var $_packagefile;
  79      /**
  80       * @var array
  81       */
  82      var $_parsedname;
  83      /**
  84       * @var array
  85       */
  86      var $_downloadURL;
  87      /**
  88       * @var array
  89       */
  90      var $_downloadDeps = array();
  91      /**
  92       * @var boolean
  93       */
  94      var $_valid = false;
  95      /**
  96       * @var boolean
  97       */
  98      var $_analyzed = false;
  99      /**
 100       * if this or a parent package was invoked with Package-state, this is set to the
 101       * state variable.
 102       *
 103       * This allows temporary reassignment of preferred_state for a parent package and all of
 104       * its dependencies.
 105       * @var string|false
 106       */
 107      var $_explicitState = false;
 108      /**
 109       * If this package is invoked with Package#group, this variable will be true
 110       */
 111      var $_explicitGroup = false;
 112      /**
 113       * Package type local|url|xmlrpc
 114       * @var string
 115       */
 116      var $_type;
 117      /**
 118       * Contents of package.xml, if downloaded from a remote channel
 119       * @var string|false
 120       * @access private
 121       */
 122      var $_rawpackagefile;
 123      /**
 124       * @var boolean
 125       * @access private
 126       */
 127      var $_validated = false;
 128  
 129      /**
 130       * @param PEAR_Downloader
 131       */
 132      function PEAR_Downloader_Package(&$downloader)
 133      {
 134          $this->_downloader = &$downloader;
 135          $this->_config = &$this->_downloader->config;
 136          $this->_registry = &$this->_config->getRegistry();
 137          $options = $downloader->getOptions();
 138          if (isset($options['packagingroot'])) {
 139              $this->_config->setInstallRoot($options['packagingroot']);
 140              $this->_installRegistry = &$this->_config->getRegistry();
 141              $this->_config->setInstallRoot(false);
 142          } else {
 143              $this->_installRegistry = &$this->_registry;
 144          }
 145          $this->_valid = $this->_analyzed = false;
 146      }
 147  
 148      /**
 149       * Parse the input and determine whether this is a local file, a remote uri, or an
 150       * abstract package name.
 151       *
 152       * This is the heart of the PEAR_Downloader_Package(), and is used in
 153       * {@link PEAR_Downloader::download()}
 154       * @param string
 155       * @return bool|PEAR_Error
 156       */
 157      function initialize($param)
 158      {
 159          $origErr = $this->_fromFile($param);
 160          if (!$this->_valid) {
 161              $options = $this->_downloader->getOptions();
 162              if (isset($options['offline'])) {
 163                  if (PEAR::isError($origErr)) {
 164                      if (!isset($options['soft'])) {
 165                          $this->_downloader->log(0, $origErr->getMessage());
 166                      }
 167                  }
 168                  return PEAR::raiseError('Cannot download non-local package "' . $param . '"');
 169              }
 170              $err = $this->_fromUrl($param);
 171              if (PEAR::isError($err) || !$this->_valid) {
 172                  if ($this->_type == 'url') {
 173                      if (PEAR::isError($err)) {
 174                          if (!isset($options['soft'])) {
 175                              $this->_downloader->log(0, $err->getMessage());
 176                          }
 177                      }
 178                      return PEAR::raiseError("Invalid or missing remote package file");
 179                  }
 180                  $err = $this->_fromString($param);
 181                  if (PEAR::isError($err) || !$this->_valid) {
 182                      if (PEAR::isError($err) &&
 183                            $err->getCode() == PEAR_DOWNLOADER_PACKAGE_STATE) {
 184                          return false; // instruct the downloader to silently skip
 185                      }
 186                      if (isset($this->_type) && $this->_type == 'local' &&
 187                            PEAR::isError($origErr)) {
 188                          if (is_array($origErr->getUserInfo())) {
 189                              foreach ($origErr->getUserInfo() as $err) {
 190                                  if (is_array($err)) {
 191                                      $err = $err['message'];
 192                                  }
 193                                  if (!isset($options['soft'])) {
 194                                      $this->_downloader->log(0, $err);
 195                                  }
 196                              }
 197                          }
 198                          if (!isset($options['soft'])) {
 199                              $this->_downloader->log(0, $origErr->getMessage());
 200                          }
 201                          if (is_array($param)) {
 202                              $param = $this->_registry->parsedPackageNameToString($param,
 203                                  true);
 204                          }
 205                          return PEAR::raiseError(
 206                              "Cannot initialize '$param', invalid or missing package file");
 207                      }
 208                      if (PEAR::isError($err)) {
 209                          if (!isset($options['soft'])) {
 210                              $this->_downloader->log(0, $err->getMessage());
 211                          }
 212                      }
 213                      if (is_array($param)) {
 214                          $param = $this->_registry->parsedPackageNameToString($param, true);
 215                      }
 216                      return PEAR::raiseError(
 217                          "Cannot initialize '$param', invalid or missing package file");
 218                  }
 219              }
 220          }
 221          return true;
 222      }
 223  
 224      /**
 225       * Retrieve any non-local packages
 226       * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|PEAR_Error
 227       */
 228      function &download()
 229      {
 230          if (isset($this->_packagefile)) {
 231              return $this->_packagefile;
 232          }
 233          if (isset($this->_downloadURL['url'])) {
 234              $this->_isvalid = false;
 235              $info = $this->getParsedPackage();
 236              foreach ($info as $i => $p) {
 237                  $info[$i] = strtolower($p);
 238              }
 239              $err = $this->_fromUrl($this->_downloadURL['url'],
 240                  $this->_registry->parsedPackageNameToString($this->_parsedname, true));
 241              $newinfo = $this->getParsedPackage();
 242              foreach ($newinfo as $i => $p) {
 243                  $newinfo[$i] = strtolower($p);
 244              }
 245              if ($info != $newinfo) {
 246                  do {
 247                      if ($info['package'] == 'pecl.php.net' && $newinfo['package'] == 'pear.php.net') {
 248                          $info['package'] = 'pear.php.net';
 249                          if ($info == $newinfo) {
 250                              // skip the channel check if a pecl package says it's a PEAR package
 251                              break;
 252                          }
 253                      }
 254                      return PEAR::raiseError('CRITICAL ERROR: We are ' .
 255                          $this->_registry->parsedPackageNameToString($info) . ', but the file ' .
 256                          'downloaded claims to be ' .
 257                          $this->_registry->parsedPackageNameToString($this->getParsedPackage()));
 258                  } while (false);
 259              }
 260              if (PEAR::isError($err) || !$this->_valid) {
 261                  return $err;
 262              }
 263          }
 264          $this->_type = 'local';
 265          return $this->_packagefile;
 266      }
 267  
 268      function &getPackageFile()
 269      {
 270          return $this->_packagefile;
 271      }
 272  
 273      function &getDownloader()
 274      {
 275          return $this->_downloader;
 276      }
 277  
 278      function getType() 
 279      {
 280          return $this->_type;
 281      }
 282  
 283      /**
 284       * Like {@link initialize()}, but operates on a dependency
 285       */
 286      function fromDepURL($dep)
 287      {
 288          $this->_downloadURL = $dep;
 289          if (isset($dep['uri'])) {
 290              $options = $this->_downloader->getOptions();
 291              if (!extension_loaded("zlib") || isset($options['nocompress'])) {
 292                  $ext = '.tar';
 293              } else {
 294                  $ext = '.tgz';
 295              }
 296              PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
 297              $err = $this->_fromUrl($dep['uri'] . $ext);
 298              PEAR::popErrorHandling();
 299              if (PEAR::isError($err)) {
 300                  if (!isset($options['soft'])) {
 301                      $this->_downloader->log(0, $err->getMessage());
 302                  }
 303                  return PEAR::raiseError('Invalid uri dependency "' . $dep['uri'] . $ext . '", ' .
 304                      'cannot download');
 305              }
 306          } else {
 307              $this->_parsedname =
 308                  array(
 309                      'package' => $dep['info']->getPackage(),
 310                      'channel' => $dep['info']->getChannel(),
 311                      'version' => $dep['version']
 312                  );
 313              if (!isset($dep['nodefault'])) {
 314                  $this->_parsedname['group'] = 'default'; // download the default dependency group
 315                  $this->_explicitGroup = false;
 316              }
 317              $this->_rawpackagefile = $dep['raw'];
 318          }
 319      }
 320  
 321      function detectDependencies($params)
 322      {
 323          $options = $this->_downloader->getOptions();
 324          if (isset($options['downloadonly'])) {
 325              return;
 326          }
 327          if (isset($options['offline'])) {
 328              $this->_downloader->log(3, 'Skipping dependency download check, --offline specified');
 329              return;
 330          }
 331          $pname = $this->getParsedPackage();
 332          if (!$pname) {
 333              return;
 334          }
 335          $deps = $this->getDeps();
 336          if (!$deps) {
 337              return;
 338          }
 339          if (isset($deps['required'])) { // package.xml 2.0
 340              return $this->_detect2($deps, $pname, $options, $params);
 341          } else {
 342              return $this->_detect1($deps, $pname, $options, $params);
 343          }
 344      }
 345  
 346      function setValidated()
 347      {
 348          $this->_validated = true;
 349      }
 350  
 351      function alreadyValidated()
 352      {
 353          return $this->_validated;
 354      }
 355  
 356      /**
 357       * Remove packages to be downloaded that are already installed
 358       * @param array of PEAR_Downloader_Package objects
 359       * @static
 360       */
 361      function removeInstalled(&$params)
 362      {
 363          if (!isset($params[0])) {
 364              return;
 365          }
 366          $options = $params[0]->_downloader->getOptions();
 367          if (!isset($options['downloadonly'])) {
 368              foreach ($params as $i => $param) {
 369                  // remove self if already installed with this version
 370                  // this does not need any pecl magic - we only remove exact matches
 371                  if ($param->_installRegistry->packageExists($param->getPackage(), $param->getChannel())) {
 372                      if (version_compare($param->_installRegistry->packageInfo($param->getPackage(), 'version',
 373                            $param->getChannel()), $param->getVersion(), '==')) {
 374                          if (!isset($options['force'])) {
 375                              $info = $param->getParsedPackage();
 376                              unset($info['version']);
 377                              unset($info['state']);
 378                              if (!isset($options['soft'])) {
 379                                  $param->_downloader->log(1, 'Skipping package "' .
 380                                      $param->getShortName() .
 381                                      '", already installed as version ' .
 382                                      $param->_installRegistry->packageInfo($param->getPackage(),
 383                                          'version', $param->getChannel()));
 384                              }
 385                              $params[$i] = false;
 386                          }
 387                      } elseif (!isset($options['force']) && !isset($options['upgrade']) &&
 388                            !isset($options['soft'])) {
 389                          $info = $param->getParsedPackage();
 390                          $param->_downloader->log(1, 'Skipping package "' .
 391                              $param->getShortName() .
 392                              '", already installed as version ' .
 393                              $param->_installRegistry->packageInfo($param->getPackage(), 'version',
 394                                  $param->getChannel()));
 395                          $params[$i] = false;
 396                      }
 397                  }
 398              }
 399          }
 400          PEAR_Downloader_Package::removeDuplicates($params);
 401      }
 402  
 403      function _detect2($deps, $pname, $options, $params)
 404      {
 405          $this->_downloadDeps = array();
 406          $groupnotfound = false;
 407          foreach (array('package', 'subpackage') as $packagetype) {
 408              // get required dependency group
 409              if (isset($deps['required'][$packagetype])) {
 410                  if (isset($deps['required'][$packagetype][0])) {
 411                      foreach ($deps['required'][$packagetype] as $dep) {
 412                          if (isset($dep['conflicts'])) {
 413                              // skip any package that this package conflicts with
 414                              continue;
 415                          }
 416                          $ret = $this->_detect2Dep($dep, $pname, 'required', $params);
 417                          if (is_array($ret)) {
 418                              $this->_downloadDeps[] = $ret;
 419                          }
 420                      }
 421                  } else {
 422                      $dep = $deps['required'][$packagetype];
 423                      if (!isset($dep['conflicts'])) {
 424                          // skip any package that this package conflicts with
 425                          $ret = $this->_detect2Dep($dep, $pname, 'required', $params);
 426                          if (is_array($ret)) {
 427                              $this->_downloadDeps[] = $ret;
 428                          }
 429                      }
 430                  }
 431              }
 432              // get optional dependency group, if any
 433              if (isset($deps['optional'][$packagetype])) {
 434                  $skipnames = array();
 435                  if (!isset($deps['optional'][$packagetype][0])) {
 436                      $deps['optional'][$packagetype] = array($deps['optional'][$packagetype]);
 437                  }
 438                  foreach ($deps['optional'][$packagetype] as $dep) {
 439                      $skip = false;
 440                      if (!isset($options['alldeps'])) {
 441                          $dep['package'] = $dep['name'];
 442                          if (!isset($options['soft'])) {
 443                              $this->_downloader->log(3, 'Notice: package "' .
 444                                $this->_registry->parsedPackageNameToString($this->getParsedPackage(),
 445                                      true) . '" optional dependency "' .
 446                                  $this->_registry->parsedPackageNameToString(array('package' =>
 447                                      $dep['name'], 'channel' => 'pear.php.net'), true) .
 448                                  '" will not be automatically downloaded');
 449                          }
 450                          $skipnames[] = $this->_registry->parsedPackageNameToString($dep, true);
 451                          $skip = true;
 452                          unset($dep['package']);
 453                      }
 454                      if (!($ret = $this->_detect2Dep($dep, $pname, 'optional', $params))) {
 455                          $dep['package'] = $dep['name'];
 456                          $skip = count($skipnames) ?
 457                              $skipnames[count($skipnames) - 1] : '';
 458                          if ($skip ==
 459                                $this->_registry->parsedPackageNameToString($dep, true)) {
 460                              array_pop($skipnames);
 461                          }
 462                      }
 463                      if (!$skip && is_array($ret)) {
 464                          $this->_downloadDeps[] = $ret;
 465                      }
 466                  }
 467                  if (count($skipnames)) {
 468                      if (!isset($options['soft'])) {
 469                          $this->_downloader->log(1, 'Did not download optional dependencies: ' .
 470                              implode(', ', $skipnames) .
 471                              ', use --alldeps to download automatically');
 472                      }
 473                  }
 474              }
 475              // get requested dependency group, if any
 476              $groupname = $this->getGroup();
 477              $explicit = $this->_explicitGroup;
 478              if (!$groupname) {
 479                  if ($this->canDefault()) {
 480                      $groupname = 'default'; // try the default dependency group
 481                  } else {
 482                      continue;
 483                  }
 484              }
 485              if ($groupnotfound) {
 486                  continue;
 487              }
 488              if (isset($deps['group'])) {
 489                  if (isset($deps['group']['attribs'])) {
 490                      if (strtolower($deps['group']['attribs']['name']) == strtolower($groupname)) {
 491                          $group = $deps['group'];
 492                      } elseif ($explicit) {
 493                          if (!isset($options['soft'])) {
 494                              $this->_downloader->log(0, 'Warning: package "' .
 495                                  $this->_registry->parsedPackageNameToString($pname, true) .
 496                                  '" has no dependency ' . 'group named "' . $groupname . '"');
 497                          }
 498                          $groupnotfound = true;
 499                          continue;
 500                      }
 501                  } else {
 502                      $found = false;
 503                      foreach ($deps['group'] as $group) {
 504                          if (strtolower($group['attribs']['name']) == strtolower($groupname)) {
 505                              $found = true;
 506                              break;
 507                          }
 508                      }
 509                      if (!$found) {
 510                          if ($explicit) {
 511                              if (!isset($options['soft'])) {
 512                                  $this->_downloader->log(0, 'Warning: package "' .
 513                                      $this->_registry->parsedPackageNameToString($pname, true) .
 514                                      '" has no dependency ' . 'group named "' . $groupname . '"');
 515                              }
 516                          }
 517                          $groupnotfound = true;
 518                          continue;
 519                      }
 520                  }
 521              }
 522              if (isset($group)) {
 523                  if (isset($group[$packagetype])) {
 524                      if (isset($group[$packagetype][0])) {
 525                          foreach ($group[$packagetype] as $dep) {
 526                              $ret = $this->_detect2Dep($dep, $pname, 'dependency group "' .
 527                                  $group['attribs']['name'] . '"', $params);
 528                              if (is_array($ret)) {
 529                                  $this->_downloadDeps[] = $ret;
 530                              }
 531                          }
 532                      } else {
 533                          $ret = $this->_detect2Dep($group[$packagetype], $pname,
 534                              'dependency group "' .
 535                              $group['attribs']['name'] . '"', $params);
 536                          if (is_array($ret)) {
 537                              $this->_downloadDeps[] = $ret;
 538                          }
 539                      }
 540                  }
 541              }
 542          }
 543      }
 544  
 545      function _detect2Dep($dep, $pname, $group, $params)
 546      {
 547          if (isset($dep['conflicts'])) {
 548              return true;
 549          }
 550          $options = $this->_downloader->getOptions();
 551          if (isset($dep['uri'])) {
 552              return array('uri' => $dep['uri'], 'dep' => $dep);;
 553          }
 554          $testdep = $dep;
 555          $testdep['package'] = $dep['name'];
 556          if (PEAR_Downloader_Package::willDownload($testdep, $params)) {
 557              $dep['package'] = $dep['name'];
 558              if (!isset($options['soft'])) {
 559                  $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group .
 560                      ' dependency "' .
 561                      $this->_registry->parsedPackageNameToString($dep, true) .
 562                      '", will be installed');
 563              }
 564              return false;
 565          }
 566          $options = $this->_downloader->getOptions();
 567          PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
 568          if ($this->_explicitState) {
 569              $pname['state'] = $this->_explicitState;
 570          }
 571          $url =
 572              $this->_downloader->_getDepPackageDownloadUrl($dep, $pname);
 573          if (PEAR::isError($url)) {
 574              PEAR::popErrorHandling();
 575              return $url;
 576          }
 577          $dep['package'] = $dep['name'];
 578          $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params, $group == 'optional' &&
 579              !isset($options['alldeps']), true);
 580          PEAR::popErrorHandling();
 581          if (PEAR::isError($ret)) {
 582              if (!isset($options['soft'])) {
 583                  $this->_downloader->log(0, $ret->getMessage());
 584              }
 585              return false;
 586          } else {
 587              // check to see if a dep is already installed and is the same or newer
 588              if (!isset($dep['min']) && !isset($dep['max']) && !isset($dep['recommended'])) {
 589                  $oper = 'has';
 590              } else {
 591                  $oper = 'gt';
 592              }
 593              // do not try to move this before getDepPackageDownloadURL
 594              // we can't determine whether upgrade is necessary until we know what
 595              // version would be downloaded
 596              if (!isset($options['force']) && $this->isInstalled($ret, $oper)) {
 597                  $version = $this->_installRegistry->packageInfo($dep['name'], 'version',
 598                      $dep['channel']);
 599                  $dep['package'] = $dep['name'];
 600                  if (!isset($options['soft'])) {
 601                      $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group .
 602                          ' dependency "' .
 603                      $this->_registry->parsedPackageNameToString($dep, true) .
 604                          '" version ' . $url['version'] . ', already installed as version ' .
 605                          $version);
 606                  }
 607                  return false;
 608              }
 609          }
 610          if (isset($dep['nodefault'])) {
 611              $ret['nodefault'] = true;
 612          }
 613          return $ret;
 614      }
 615  
 616      function _detect1($deps, $pname, $options, $params)
 617      {
 618          $this->_downloadDeps = array();
 619          $skipnames = array();
 620          foreach ($deps as $dep) {
 621              $nodownload = false;
 622              if ($dep['type'] == 'pkg') {
 623                  $dep['channel'] = 'pear.php.net';
 624                  $dep['package'] = $dep['name'];
 625                  switch ($dep['rel']) {
 626                      case 'not' :
 627                          continue 2;
 628                      case 'ge' :
 629                      case 'eq' :
 630                      case 'gt' :
 631                      case 'has' :
 632                          $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
 633                              'required' :
 634                              'optional';
 635                          if (PEAR_Downloader_Package::willDownload($dep, $params)) {
 636                              $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group
 637                                  . ' dependency "' .
 638                                  $this->_registry->parsedPackageNameToString($dep, true) .
 639                                  '", will be installed');
 640                              continue 2;
 641                          }
 642                          $fakedp = new PEAR_PackageFile_v1;
 643                          $fakedp->setPackage($dep['name']);
 644                          // skip internet check if we are not upgrading (bug #5810)
 645                          if (!isset($options['upgrade']) && $this->isInstalled(
 646                                $fakedp, $dep['rel'])) {
 647                              $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group
 648                                  . ' dependency "' .
 649                                  $this->_registry->parsedPackageNameToString($dep, true) .
 650                                  '", is already installed');
 651                              continue 2;
 652                          }
 653                  }
 654                  PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
 655                  if ($this->_explicitState) {
 656                      $pname['state'] = $this->_explicitState;
 657                  }
 658                  $url =
 659                      $this->_downloader->_getDepPackageDownloadUrl($dep, $pname);
 660                  $chan = 'pear.php.net';
 661                  if (PEAR::isError($url)) {
 662                      // check to see if this is a pecl package that has jumped
 663                      // from pear.php.net to pecl.php.net channel
 664                      if (!class_exists('PEAR_Dependency2')) {
 665                          require_once  'PEAR/Dependency2.php';
 666                      }
 667                      $newdep = PEAR_Dependency2::normalizeDep($dep);
 668                      $newdep = $newdep[0];
 669                      $newdep['channel'] = 'pecl.php.net';
 670                      $chan = 'pecl.php.net';
 671                      $url =
 672                          $this->_downloader->_getDepPackageDownloadUrl($newdep, $pname);
 673                      $obj = &$this->_installRegistry->getPackage($dep['name']);
 674                      if (PEAR::isError($url)) {
 675                          PEAR::popErrorHandling();
 676                          if ($obj !== null && $this->isInstalled($obj, $dep['rel'])) {
 677                              $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
 678                                  'required' :
 679                                  'optional';
 680                              $dep['package'] = $dep['name'];
 681                              if (!isset($options['soft'])) {
 682                                  $this->_downloader->log(3, $this->getShortName() .
 683                                      ': Skipping ' . $group . ' dependency "' .
 684                                      $this->_registry->parsedPackageNameToString($dep, true) .
 685                                      '", already installed as version ' . $obj->getVersion());
 686                              }
 687                              $skip = count($skipnames) ?
 688                                  $skipnames[count($skipnames) - 1] : '';
 689                              if ($skip ==
 690                                    $this->_registry->parsedPackageNameToString($dep, true)) {
 691                                  array_pop($skipnames);
 692                              }
 693                              continue;
 694                          } else {
 695                              if (isset($dep['optional']) && $dep['optional'] == 'yes') {
 696                                  $this->_downloader->log(2, $this->getShortName() .
 697                                      ': Skipping ' . $group
 698                                      . ' dependency "' .
 699                                      $this->_registry->parsedPackageNameToString($dep, true) .
 700                                      '", no releases exist');
 701                                  continue;
 702                              } else {
 703                                  return $url;
 704                              }
 705                          }
 706                      }
 707                  }
 708                  PEAR::popErrorHandling();
 709                  if (!isset($options['alldeps'])) {
 710                      if (isset($dep['optional']) && $dep['optional'] == 'yes') {
 711                          if (!isset($options['soft'])) {
 712                              $this->_downloader->log(3, 'Notice: package "' .
 713                                  $this->getShortName() .
 714                                  '" optional dependency "' .
 715                                  $this->_registry->parsedPackageNameToString(
 716                                      array('channel' => $chan, 'package' =>
 717                                      $dep['name']), true) .
 718                                  '" will not be automatically downloaded');
 719                          }
 720                          $skipnames[] = $this->_registry->parsedPackageNameToString(
 721                                  array('channel' => $chan, 'package' =>
 722                                  $dep['name']), true);
 723                          $nodownload = true;
 724                      }
 725                  }
 726                  if (!isset($options['alldeps']) && !isset($options['onlyreqdeps'])) {
 727                      if (!isset($dep['optional']) || $dep['optional'] == 'no') {
 728                          if (!isset($options['soft'])) {
 729                              $this->_downloader->log(3, 'Notice: package "' .
 730                                  $this->getShortName() .
 731                                  '" required dependency "' .
 732                                  $this->_registry->parsedPackageNameToString(
 733                                      array('channel' => $chan, 'package' =>
 734                                      $dep['name']), true) .
 735                                  '" will not be automatically downloaded');
 736                          }
 737                          $skipnames[] = $this->_registry->parsedPackageNameToString(
 738                                  array('channel' => $chan, 'package' =>
 739                                  $dep['name']), true);
 740                          $nodownload = true;
 741                      }
 742                  }
 743                  // check to see if a dep is already installed
 744                  // do not try to move this before getDepPackageDownloadURL
 745                  // we can't determine whether upgrade is necessary until we know what
 746                  // version would be downloaded
 747                  if (!isset($options['force']) && $this->isInstalled(
 748                          $url, $dep['rel'])) {
 749                      $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
 750                          'required' :
 751                          'optional';
 752                      $dep['package'] = $dep['name'];
 753                      if (isset($newdep)) {
 754                          $version = $this->_installRegistry->packageInfo($newdep['name'], 'version',
 755                              $newdep['channel']);
 756                      } else {
 757                          $version = $this->_installRegistry->packageInfo($dep['name'], 'version');
 758                      }
 759                      $dep['version'] = $url['version'];
 760                      if (!isset($options['soft'])) {
 761                          $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group .
 762                              ' dependency "' .
 763                              $this->_registry->parsedPackageNameToString($dep, true) .
 764                              '", already installed as version ' . $version);
 765                      }
 766                      $skip = count($skipnames) ?
 767                          $skipnames[count($skipnames) - 1] : '';
 768                      if ($skip ==
 769                            $this->_registry->parsedPackageNameToString($dep, true)) {
 770                          array_pop($skipnames);
 771                      }
 772                      continue;
 773                  }
 774                  if ($nodownload) {
 775                      continue;
 776                  }
 777                  PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
 778                  if (isset($newdep)) {
 779                      $dep = $newdep;
 780                  }
 781                  $dep['package'] = $dep['name'];
 782                  $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params,
 783                      isset($dep['optional']) && $dep['optional'] == 'yes' &&
 784                      !isset($options['alldeps']), true);
 785                  PEAR::popErrorHandling();
 786                  if (PEAR::isError($ret)) {
 787                      if (!isset($options['soft'])) {
 788                          $this->_downloader->log(0, $ret->getMessage());
 789                      }
 790                      continue;
 791                  }
 792                  $this->_downloadDeps[] = $ret;
 793              }
 794          }
 795          if (count($skipnames)) {
 796              if (!isset($options['soft'])) {
 797                  $this->_downloader->log(1, 'Did not download dependencies: ' .
 798                      implode(', ', $skipnames) .
 799                      ', use --alldeps or --onlyreqdeps to download automatically');
 800              }
 801          }
 802      }
 803  
 804      function setDownloadURL($pkg)
 805      {
 806          $this->_downloadURL = $pkg;
 807      }
 808  
 809      /**
 810       * Set the package.xml object for this downloaded package
 811       *
 812       * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 $pkg
 813       */
 814      function setPackageFile(&$pkg)
 815      {
 816          $this->_packagefile = &$pkg;
 817      }
 818  
 819      function getShortName()
 820      {
 821          return $this->_registry->parsedPackageNameToString(array('channel' => $this->getChannel(),
 822              'package' => $this->getPackage()), true);
 823      }
 824  
 825      function getParsedPackage()
 826      {   
 827          if (isset($this->_packagefile) || isset($this->_parsedname)) {
 828              return array('channel' => $this->getChannel(),
 829                  'package' => $this->getPackage(),
 830                  'version' => $this->getVersion());
 831          }
 832          return false;
 833      }
 834  
 835      function getDownloadURL()
 836      {
 837          return $this->_downloadURL;
 838      }
 839  
 840      function canDefault()
 841      {
 842          if (isset($this->_downloadURL)) {
 843              if (isset($this->_downloadURL['nodefault'])) {
 844                  return false;
 845              }
 846          }
 847          return true;
 848      }
 849  
 850      function getPackage()
 851      {
 852          if (isset($this->_packagefile)) {
 853              return $this->_packagefile->getPackage();
 854          } elseif (isset($this->_downloadURL['info'])) {
 855              return $this->_downloadURL['info']->getPackage();
 856          } else {
 857              return false;
 858          }
 859      }
 860  
 861      /**
 862       * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
 863       */
 864      function isSubpackage(&$pf)
 865      {
 866          if (isset($this->_packagefile)) {
 867              return $this->_packagefile->isSubpackage($pf);
 868          } elseif (isset($this->_downloadURL['info'])) {
 869              return $this->_downloadURL['info']->isSubpackage($pf);
 870          } else {
 871              return false;
 872          }
 873      }
 874  
 875      function getPackageType()
 876      {
 877          if (isset($this->_packagefile)) {
 878              return $this->_packagefile->getPackageType();
 879          } elseif (isset($this->_downloadURL['info'])) {
 880              return $this->_downloadURL['info']->getPackageType();
 881          } else {
 882              return false;
 883          }
 884      }
 885  
 886      function isBundle()
 887      {
 888          if (isset($this->_packagefile)) {
 889              return $this->_packagefile->getPackageType() == 'bundle';
 890          } else {
 891              return false;
 892          }
 893      }
 894  
 895      function getPackageXmlVersion()
 896      {
 897          if (isset($this->_packagefile)) {
 898              return $this->_packagefile->getPackagexmlVersion();
 899          } elseif (isset($this->_downloadURL['info'])) {
 900              return $this->_downloadURL['info']->getPackagexmlVersion();
 901          } else {
 902              return '1.0';
 903          }
 904      }
 905  
 906      function getChannel()
 907      {
 908          if (isset($this->_packagefile)) {
 909              return $this->_packagefile->getChannel();
 910          } elseif (isset($this->_downloadURL['info'])) {
 911              return $this->_downloadURL['info']->getChannel();
 912          } else {
 913              return false;
 914          }
 915      }
 916  
 917      function getURI()
 918      {
 919          if (isset($this->_packagefile)) {
 920              return $this->_packagefile->getURI();
 921          } elseif (isset($this->_downloadURL['info'])) {
 922              return $this->_downloadURL['info']->getURI();
 923          } else {
 924              return false;
 925          }
 926      }
 927  
 928      function getVersion()
 929      {
 930          if (isset($this->_packagefile)) {
 931              return $this->_packagefile->getVersion();
 932          } elseif (isset($this->_downloadURL['version'])) {
 933              return $this->_downloadURL['version'];
 934          } else {
 935              return false;
 936          }
 937      }
 938  
 939      function isCompatible($pf)
 940      {
 941          if (isset($this->_packagefile)) {
 942              return $this->_packagefile->isCompatible($pf);
 943          } elseif (isset($this->_downloadURL['info'])) {
 944              return $this->_downloadURL['info']->isCompatible($pf);
 945          } else {
 946              return true;
 947          }
 948      }
 949  
 950      function setGroup($group)
 951      {
 952          $this->_parsedname['group'] = $group;
 953      }
 954  
 955      function getGroup()
 956      {
 957          if (isset($this->_parsedname['group'])) {
 958              return $this->_parsedname['group'];
 959          } else {
 960              return '';
 961          }
 962      }
 963  
 964      function isExtension($name)
 965      {
 966          if (isset($this->_packagefile)) {
 967              return $this->_packagefile->isExtension($name);
 968          } elseif (isset($this->_downloadURL['info'])) {
 969              if ($this->_downloadURL['info']->getPackagexmlVersion() == '2.0') {
 970                  return $this->_downloadURL['info']->getProvidesExtension() == $name;
 971              } else {
 972                  return false;
 973              }
 974          } else {
 975              return false;
 976          }
 977      }
 978  
 979      function getDeps()
 980      {
 981          if (isset($this->_packagefile)) {
 982              $ver = $this->_packagefile->getPackagexmlVersion();
 983              if (version_compare($ver, '2.0', '>=')) {
 984                  return $this->_packagefile->getDeps(true);
 985              } else {
 986                  return $this->_packagefile->getDeps();
 987              }
 988          } elseif (isset($this->_downloadURL['info'])) {
 989              $ver = $this->_downloadURL['info']->getPackagexmlVersion();
 990              if (version_compare($ver, '2.0', '>=')) {
 991                  return $this->_downloadURL['info']->getDeps(true);
 992              } else {
 993                  return $this->_downloadURL['info']->getDeps();
 994              }
 995          } else {
 996              return array();
 997          }
 998      }
 999  
1000      /**
1001       * @param array Parsed array from {@link PEAR_Registry::parsePackageName()} or a dependency
1002       *                     returned from getDepDownloadURL()
1003       */
1004      function isEqual($param)
1005      {
1006          if (is_object($param)) {
1007              $channel = $param->getChannel();
1008              $package = $param->getPackage();
1009              if ($param->getURI()) {
1010                  $param = array(
1011                      'channel' => $param->getChannel(),
1012                      'package' => $param->getPackage(),
1013                      'version' => $param->getVersion(),
1014                      'uri' => $param->getURI(),
1015                  );
1016              } else {
1017                  $param = array(
1018                      'channel' => $param->getChannel(),
1019                      'package' => $param->getPackage(),
1020                      'version' => $param->getVersion(),
1021                  );
1022              }
1023          } else {
1024              if (isset($param['uri'])) {
1025                  if ($this->getChannel() != '__uri') {
1026                      return false;
1027                  }
1028                  return $param['uri'] == $this->getURI();
1029              }
1030              $package = isset($param['package']) ? $param['package'] :
1031                  $param['info']->getPackage();
1032              $channel = isset($param['channel']) ? $param['channel'] :
1033                  $param['info']->getChannel();
1034              if (isset($param['rel'])) {
1035                  if (!class_exists('PEAR_Dependency2')) {
1036                      require_once  'PEAR/Dependency2.php';
1037                  }
1038                  $newdep = PEAR_Dependency2::normalizeDep($param);
1039                  $newdep = $newdep[0];
1040              } elseif (isset($param['min'])) {
1041                  $newdep = $param;
1042              }
1043          }
1044          if (isset($newdep)) {
1045              if (!isset($newdep['min'])) {
1046                  $newdep['min'] = '0';
1047              }
1048              if (!isset($newdep['max'])) {
1049                  $newdep['max'] = '100000000000000000000';
1050              }
1051              // use magic to support pecl packages suddenly jumping to the pecl channel
1052              // we need to support both dependency possibilities
1053              if ($channel == 'pear.php.net' && $this->getChannel() == 'pecl.php.net') {
1054                  if ($package == $this->getPackage()) {
1055                      $channel = 'pecl.php.net';
1056                  }
1057              }
1058              if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') {
1059                  if ($package == $this->getPackage()) {
1060                      $channel = 'pear.php.net';
1061                  }
1062              }
1063              return (strtolower($package) == strtolower($this->getPackage()) &&
1064                  $channel == $this->getChannel() &&
1065                  version_compare($newdep['min'], $this->getVersion(), '<=') &&
1066                  version_compare($newdep['max'], $this->getVersion(), '>='));
1067          }
1068          // use magic to support pecl packages suddenly jumping to the pecl channel
1069          if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') {
1070              if (strtolower($package) == strtolower($this->getPackage())) {
1071                  $channel = 'pear.php.net';
1072              }
1073          }
1074          if (isset($param['version'])) {
1075              return (strtolower($package) == strtolower($this->getPackage()) &&
1076                  $channel == $this->getChannel() &&
1077                  $param['version'] == $this->getVersion());
1078          } else {
1079              return strtolower($package) == strtolower($this->getPackage()) &&
1080                  $channel == $this->getChannel();
1081          }
1082      }
1083  
1084      function isInstalled($dep, $oper = '==')
1085      {
1086          if (!$dep) {
1087              return false;
1088          }
1089          if ($oper != 'ge' && $oper != 'gt' && $oper != 'has' && $oper != '==') {
1090              return false;
1091          }
1092          if (is_object($dep)) {
1093              $package = $dep->getPackage();
1094              $channel = $dep->getChannel();
1095              if ($dep->getURI()) {
1096                  $dep = array(
1097                      'uri' => $dep->getURI(),
1098                      'version' => $dep->getVersion(),
1099                  );
1100              } else {
1101                  $dep = array(
1102                      'version' => $dep->getVersion(),
1103                  );
1104              }
1105          } else {
1106              if (isset($dep['uri'])) {
1107                  $channel = '__uri';
1108                  $package = $dep['dep']['name'];
1109              } else {
1110                  $channel = $dep['info']->getChannel();
1111                  $package = $dep['info']->getPackage();
1112              }
1113          }
1114          $options = $this->_downloader->getOptions();
1115          $test = $this->_installRegistry->packageExists($package, $channel);
1116          if (!$test && $channel == 'pecl.php.net') {
1117              // do magic to allow upgrading from old pecl packages to new ones
1118              $test = $this->_installRegistry->packageExists($package, 'pear.php.net');
1119              $channel = 'pear.php.net';
1120          }
1121          if ($test) {
1122              if (isset($dep['uri'])) {
1123                  if ($this->_installRegistry->packageInfo($package, 'uri', '__uri') == $dep['uri']) {
1124                      return true;
1125                  }
1126              }
1127              if (isset($options['upgrade'])) {
1128                  if ($oper == 'has') {
1129                      if (version_compare($this->_installRegistry->packageInfo(
1130                            $package, 'version', $channel),
1131                            $dep['version'], '>=')) {
1132                          return true;
1133                      } else {
1134                          return false;
1135                      }
1136                  } else {
1137                      if (version_compare($this->_installRegistry->packageInfo(
1138                            $package, 'version', $channel),
1139                            $dep['version'], '>=')) {
1140                          return true;
1141                      }
1142                      return false;
1143                  }
1144              }
1145              return true;
1146          }
1147          return false;
1148      }
1149  
1150      /**
1151       * @param array
1152       * @param bool ignore install groups - for final removal of dupe packages
1153       * @static
1154       */
1155      function removeDuplicates(&$params, $ignoreGroups = false)
1156      {
1157          $pnames = array();
1158          foreach ($params as $i => $param) {
1159              if (!$param) {
1160                  continue;
1161              }
1162              if ($param->getPackage()) {
1163                  if ($ignoreGroups) {
1164                      $group = '';
1165                  } else {
1166                      $group = $param->getGroup();
1167                  }
1168                  $pnames[$i] = $param->getChannel() . '/' .
1169                      $param->getPackage() . '-' . $param->getVersion() . '#' . $group;
1170              }
1171          }
1172          $pnames = array_unique($pnames);
1173          $unset = array_diff(array_keys($params), array_keys($pnames));
1174          $testp = array_flip($pnames);
1175          foreach ($params as $i => $param) {
1176              if (!$param) {
1177                  $unset[] = $i;
1178                  continue;
1179              }
1180              if (!is_a($param, 'PEAR_Downloader_Package')) {
1181                  $unset[] = $i;
1182                  continue;
1183              }
1184              if ($ignoreGroups) {
1185                  $group = '';
1186              } else {
1187                  $group = $param->getGroup();
1188              }
1189              if (!isset($testp[$param->getChannel() . '/' . $param->getPackage() . '-' .
1190                    $param->getVersion() . '#' . $group])) {
1191                  $unset[] = $i;
1192              }
1193          }
1194          foreach ($unset as $i) {
1195              unset($params[$i]);
1196          }
1197          $ret = array();
1198          foreach ($params as $i => $param) {
1199              $ret[] = &$params[$i];
1200          }
1201          $params = array();
1202          foreach ($ret as $i => $param) {
1203              $params[] = &$ret[$i];
1204          }
1205      }
1206  
1207      function explicitState()
1208      {
1209          return $this->_explicitState;
1210      }
1211  
1212      function setExplicitState($s)
1213      {
1214          $this->_explicitState = $s;
1215      }
1216  
1217      /**
1218       * @static
1219       */
1220      function mergeDependencies(&$params)
1221      {
1222          $newparams = array();
1223          $bundles = array();
1224          foreach ($params as $i => $param) {
1225              if (!$param->isBundle()) {
1226                  continue;
1227              }
1228              $bundles[] = $i;
1229              $pf = &$param->getPackageFile();
1230              $newdeps = array();
1231              $contents = $pf->getBundledPackages();
1232              if (!is_array($contents)) {
1233                  $contents = array($contents);
1234              }
1235              foreach ($contents as $file) {
1236                  $filecontents = $pf->getFileContents($file);
1237                  $dl = &$param->getDownloader();
1238                  $options = $dl->getOptions();
1239                  if (PEAR::isError($dir = $dl->getDownloadDir())) {
1240                      return $dir;
1241                  }
1242                  $fp = @fopen($dir . DIRECTORY_SEPARATOR . $file, 'wb');
1243                  if (!$fp) {
1244                      continue;
1245                  }
1246                  fwrite($fp, $filecontents, strlen($filecontents));
1247                  fclose($fp);
1248                  if ($s = $params[$i]->explicitState()) {
1249                      $obj->setExplicitState($s);
1250                  }
1251                  $obj = &new PEAR_Downloader_Package($params[$i]->getDownloader());
1252                  PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
1253                  if (PEAR::isError($dir = $dl->getDownloadDir())) {
1254                      PEAR::popErrorHandling();
1255                      return $dir;
1256                  }
1257                  $e = $obj->_fromFile($a = $dir . DIRECTORY_SEPARATOR . $file);
1258                  PEAR::popErrorHandling();
1259                  if (PEAR::isError($e)) {
1260                      if (!isset($options['soft'])) {
1261                          $dl->log(0, $e->getMessage());
1262                      }
1263                      continue;
1264                  }
1265                  $j = &$obj;
1266                  if (!PEAR_Downloader_Package::willDownload($j,
1267                        array_merge($params, $newparams)) && !$param->isInstalled($j)) {
1268                      $newparams[] = &$j;
1269                  }
1270              }
1271          }
1272          foreach ($bundles as $i) {
1273              unset($params[$i]); // remove bundles - only their contents matter for installation
1274          }
1275          PEAR_Downloader_Package::removeDuplicates($params); // strip any unset indices
1276          if (count($newparams)) { // add in bundled packages for install
1277              foreach ($newparams as $i => $unused) {
1278                  $params[] = &$newparams[$i];
1279              }
1280              $newparams = array();
1281          }
1282          foreach ($params as $i => $param) {
1283              $newdeps = array();
1284              foreach ($param->_downloadDeps as $dep) {
1285                  if (!PEAR_Downloader_Package::willDownload($dep,
1286                        array_merge($params, $newparams)) && !$param->isInstalled($dep)) {
1287                      $newdeps[] = $dep;
1288                  } else {
1289                      // detect versioning conflicts here
1290                  }
1291              }
1292              // convert the dependencies into PEAR_Downloader_Package objects for the next time
1293              // around
1294              $params[$i]->_downloadDeps = array();
1295              foreach ($newdeps as $dep) {
1296                  $obj = &new PEAR_Downloader_Package($params[$i]->getDownloader());
1297                  if ($s = $params[$i]->explicitState()) {
1298                      $obj->setExplicitState($s);
1299                  }
1300                  PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
1301                  $e = $obj->fromDepURL($dep);
1302                  PEAR::popErrorHandling();
1303                  if (PEAR::isError($e)) {
1304                      if (!isset($options['soft'])) {
1305                          $obj->_downloader->log(0, $e->getMessage());
1306                      }
1307                      continue;
1308                  }
1309                  $e = $obj->detectDependencies($params);
1310                  if (PEAR::isError($e)) {
1311                      if (!isset($options['soft'])) {
1312                          $obj->_downloader->log(0, $e->getMessage());
1313                      }
1314                  }
1315                  $j = &$obj;
1316                  $newparams[] = &$j;
1317              }
1318          }
1319          if (count($newparams)) {
1320              foreach ($newparams as $i => $unused) {
1321                  $params[] = &$newparams[$i];
1322              }
1323              return true;
1324          } else {
1325              return false;
1326          }
1327      }
1328  
1329  
1330      /**
1331       * @static
1332       */
1333      function willDownload($param, $params)
1334      {
1335          if (!is_array($params)) {
1336              return false;
1337          }
1338          foreach ($params as $obj) {
1339              if ($obj->isEqual($param)) {
1340                  return true;
1341              }
1342          }
1343          return false;
1344      }
1345  
1346      /**
1347       * For simpler unit-testing
1348       * @param PEAR_Config
1349       * @param int
1350       * @param string
1351       */
1352      function &getPackagefileObject(&$c, $d, $t = false)
1353      {
1354          $a = &new PEAR_PackageFile($c, $d, $t);
1355          return $a;
1356      }
1357  
1358  
1359      /**
1360       * This will retrieve from a local file if possible, and parse out
1361       * a group name as well.  The original parameter will be modified to reflect this.
1362       * @param string|array can be a parsed package name as well
1363       * @access private
1364       */
1365      function _fromFile(&$param)
1366      {
1367          $saveparam = $param;
1368          if (is_string($param)) {
1369              if (!@file_exists($param)) {
1370                  $test = explode('#', $param);
1371                  $group = array_pop($test);
1372                  if (file_exists(implode('#', $test))) {
1373                      $this->setGroup($group);
1374                      $param = implode('#', $test);
1375                      $this->_explicitGroup = true;
1376                  }
1377              }
1378              if (@is_file($param)) {
1379                  $this->_type = 'local';
1380                  $options = $this->_downloader->getOptions();
1381                  if (isset($options['downloadonly'])) {
1382                      $pkg = &$this->getPackagefileObject($this->_config,
1383                          $this->_downloader->_debug);
1384                  } else {
1385                      if (PEAR::isError($dir = $this->_downloader->getDownloadDir())) {
1386                          return $dir;
1387                      }
1388                      $pkg = &$this->getPackagefileObject($this->_config,
1389                          $this->_downloader->_debug, $dir);
1390                  }
1391                  PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
1392                  $pf = &$pkg->fromAnyFile($param, PEAR_VALIDATE_INSTALLING);
1393                  PEAR::popErrorHandling();
1394                  if (PEAR::isError($pf)) {
1395                      $this->_valid = false;
1396                      $param = $saveparam;
1397                      return $pf;
1398                  }
1399                  $this->_packagefile = &$pf;
1400                  if (!$this->getGroup()) {
1401                      $this->setGroup('default'); // install the default dependency group
1402                  }
1403                  return $this->_valid = true;
1404              }
1405          }
1406          $param = $saveparam;
1407          return $this->_valid = false;
1408      }
1409  
1410      function _fromUrl($param, $saveparam = '')
1411      {
1412          if (!is_array($param) &&
1413                (preg_match('#^(http|ftp)://#', $param))) {
1414              $options = $this->_downloader->getOptions();
1415              $this->_type = 'url';
1416              $callback = $this->_downloader->ui ?
1417                  array(&$this->_downloader, '_downloadCallback') : null;
1418              $this->_downloader->pushErrorHandling(PEAR_ERROR_RETURN);
1419              if (PEAR::isError($dir = $this->_downloader->getDownloadDir())) {
1420                  $this->_downloader->popErrorHandling();
1421                  return $dir;
1422              }
1423              $file = $this->_downloader->downloadHttp($param, $this->_downloader->ui,
1424                  $dir, $callback);
1425              $this->_downloader->popErrorHandling();
1426              if (PEAR::isError($file)) {
1427                  if (!empty($saveparam)) {
1428                      $saveparam = ", cannot download \"$saveparam\"";
1429                  }
1430                  $err = PEAR::raiseError('Could not download from "' . $param .
1431                      '"' . $saveparam . ' (' . $file->getMessage() . ')');
1432                      return $err;
1433              }
1434              if ($this->_rawpackagefile) {
1435                  require_once  'Archive/Tar.php';
1436                  $tar = &new Archive_Tar($file);
1437                  $packagexml = $tar->extractInString('package2.xml');
1438                  if (!$packagexml) {
1439                      $packagexml = $tar->extractInString('package.xml');
1440                  }
1441                  if (str_replace(array("\n", "\r"), array('',''), $packagexml) !=
1442                        str_replace(array("\n", "\r"), array('',''), $this->_rawpackagefile)) {
1443                      if ($this->getChannel() == 'pear.php.net') {
1444                          // be more lax for the existing PEAR packages that have not-ok
1445                          // characters in their package.xml
1446                          $this->_downloader->log(0, 'CRITICAL WARNING: The "' .
1447                              $this->getPackage() . '" package has invalid characters in its ' .
1448                              'package.xml.  The next version of PEAR may not be able to install ' .
1449                              'this package for security reasons.  Please open a bug report at ' .
1450                              'http://pear.php.net/package/' . $this->getPackage() . '/bugs');
1451                      } else {
1452                          return PEAR::raiseError('CRITICAL ERROR: package.xml downloaded does ' .
1453                              'not match value returned from xml-rpc');
1454                      }
1455                  }
1456              }
1457              // whew, download worked!
1458              if (isset($options['downloadonly'])) {
1459                  $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->debug);
1460              } else {
1461                  if (PEAR::isError($dir = $this->_downloader->getDownloadDir())) {
1462                      return $dir;
1463                  }
1464                  $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->debug,
1465                      $dir);
1466              }
1467              PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
1468              $pf = &$pkg->fromAnyFile($file, PEAR_VALIDATE_INSTALLING);
1469              PEAR::popErrorHandling();
1470              if (PEAR::isError($pf)) {
1471                  if (is_array($pf->getUserInfo())) {
1472                      foreach ($pf->getUserInfo() as $err) {
1473                          if (is_array($err)) {
1474                              $err = $err['message'];
1475                          }
1476                          if (!isset($options['soft'])) {
1477                              $this->_downloader->log(0, "Validation Error: $err");
1478                          }
1479                      }
1480                  }
1481                  if (!isset($options['soft'])) {
1482                      $this->_downloader->log(0, $pf->getMessage());
1483                  }
1484                  $err = PEAR::raiseError('Download of "' . ($saveparam ? $saveparam :
1485                      $param) . '" succeeded, but it is not a valid package archive');
1486                  $this->_valid = false;
1487                  return $err;
1488              }
1489              $this->_packagefile = &$pf;
1490              $this->setGroup('default'); // install the default dependency group
1491              return $this->_valid = true;
1492          }
1493          return $this->_valid = false;
1494      }
1495  
1496      /**
1497       *
1498       * @param string|array pass in an array of format
1499       *                     array(
1500       *                      'package' => 'pname',
1501       *                     ['channel' => 'channame',]
1502       *                     ['version' => 'version',]
1503       *                     ['state' => 'state',])
1504       *                     or a string of format [channame/]pname[-version|-state]
1505       */
1506      function _fromString($param)
1507      {
1508          $options = $this->_downloader->getOptions();
1509          PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
1510          $pname = $this->_registry->parsePackageName($param,
1511              $this->_config->get('default_channel'));
1512          PEAR::popErrorHandling();
1513          if (PEAR::isError($pname)) {
1514              if ($pname->getCode() == 'invalid') {
1515                  $this->_valid = false;
1516                  return false;
1517              }
1518              if ($pname->getCode() == 'channel') {
1519                  $parsed = $pname->getUserInfo();
1520                  if ($this->_downloader->discover($parsed['channel'])) {
1521                      if ($this->_config->get('auto_discover')) {
1522                          PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
1523                          $pname = $this->_registry->parsePackageName($param,
1524                              $this->_config->get('default_channel'));
1525                          PEAR::popErrorHandling();
1526                      } else {
1527                          if (!isset($options['soft'])) {
1528                              $this->_downloader->log(0, 'Channel "' . $parsed['channel'] .
1529                                  '" is not initialized, use ' .
1530                                  '"pear channel-discover ' . $parsed['channel'] . '" to initialize' .
1531                                  'or pear config-set auto_discover 1');
1532                          }
1533                      }
1534                  }
1535                  if (PEAR::isError($pname)) {
1536                      if (!isset($options['soft'])) {
1537                          $this->_downloader->log(0, $pname->getMessage());
1538                      }
1539                      if (is_array($param)) {
1540                          $param = $this->_registry->parsedPackageNameToString($param);
1541                      }
1542                      $err = PEAR::raiseError('invalid package name/package file "' .
1543                          $param . '"');
1544                      $this->_valid = false;
1545                      return $err;
1546                  }
1547              } else {
1548                  if (!isset($options['soft'])) {
1549                      $this->_downloader->log(0, $pname->getMessage());
1550                  }
1551                  $err = PEAR::raiseError('invalid package name/package file "' .
1552                      $param . '"');
1553                  $this->_valid = false;
1554                  return $err;
1555              }
1556          }
1557          if (!isset($this->_type)) {
1558              $this->_type = 'xmlrpc';
1559          }
1560          $this->_parsedname = $pname;
1561          if (isset($pname['state'])) {
1562              $this->_explicitState = $pname['state'];
1563          } else {
1564              $this->_explicitState = false;
1565          }
1566          if (isset($pname['group'])) {
1567              $this->_explicitGroup = true;
1568          } else {
1569              $this->_explicitGroup = false;
1570          }
1571          $info = $this->_downloader->_getPackageDownloadUrl($pname);
1572          if (PEAR::isError($info)) {
1573              if ($info->getCode() != -976 && $pname['channel'] == 'pear.php.net') {
1574                  // try pecl
1575                  $pname['channel'] = 'pecl.php.net';
1576                  if ($test = $this->_downloader->_getPackageDownloadUrl($pname)) {
1577                      if (!PEAR::isError($test)) {
1578                          $info = PEAR::raiseError($info->getMessage() . ' - package ' .
1579                              $this->_registry->parsedPackageNameToString($pname, true) .
1580                              ' can be installed with "pecl install ' . $pname['package'] .
1581                              '"');
1582                      } else {
1583                          $pname['channel'] = 'pear.php.net';
1584                      }
1585                  } else {
1586                      $pname['channel'] = 'pear.php.net';
1587                  }
1588              }
1589              return $info;
1590          }
1591          $this->_rawpackagefile = $info['raw'];
1592          $ret = $this->_analyzeDownloadURL($info, $param, $pname);
1593          if (PEAR::isError($ret)) {
1594              return $ret;
1595          }
1596          if ($ret) {
1597              $this->_downloadURL = $ret;
1598              return $this->_valid = (bool) $ret;
1599          }
1600      }
1601  
1602      /**
1603       * @param array output of package.getDownloadURL
1604       * @param string|array|object information for detecting packages to be downloaded, and
1605       *                            for errors
1606       * @param array name information of the package
1607       * @param array|null packages to be downloaded
1608       * @param bool is this an optional dependency?
1609       * @param bool is this any kind of dependency?
1610       * @access private
1611       */
1612      function _analyzeDownloadURL($info, $param, $pname, $params = null, $optional = false,
1613                                   $isdependency = false)
1614      {
1615          if (!is_string($param) && PEAR_Downloader_Package::willDownload($param, $params)) {
1616              return false;
1617          }
1618          if (!$info) {
1619              if (!is_string($param)) {
1620                  $saveparam = ", cannot download \"$param\"";
1621              } else {
1622                  $saveparam = '';
1623              }
1624              // no releases exist
1625              return PEAR::raiseError('No releases for package "' .
1626                  $this->_registry->parsedPackageNameToString($pname, true) . '" exist' . $saveparam);
1627          }
1628          if (strtolower($info['info']->getChannel()) != strtolower($pname['channel'])) {
1629              $err = false;
1630              if ($pname['channel'] == 'pecl.php.net') {
1631                  if ($info['info']->getChannel() != 'pear.php.net') {
1632                      $err = true;
1633                  }
1634              } elseif ($info['info']->getChannel() == 'pecl.php.net') {
1635                  if ($pname['channel'] != 'pear.php.net') {
1636                      $err = true;
1637                  }
1638              } else {
1639                  $err = true;
1640              }
1641              if ($err) {
1642                  return PEAR::raiseError('SECURITY ERROR: package in channel "' . $pname['channel'] .
1643                      '" retrieved another channel\'s name for download! ("' .
1644                      $info['info']->getChannel() . '")');
1645              }
1646          }
1647          if (!isset($info['url'])) {
1648              if ($this->isInstalled($info)) {
1649                  if ($isdependency && version_compare($info['version'],
1650                        $this->_registry->packageInfo($info['info']->getPackage(),
1651                              'version', $info['info']->getChannel()), '<=')) {
1652                      // ignore bogus errors of "failed to download dependency"
1653                      // if it is already installed and the one that would be
1654                      // downloaded is older or the same version (Bug #7219)
1655                      return false;
1656                  }
1657              }
1658              $instead =  ', will instead download version ' . $info['version'] .
1659                          ', stability "' . $info['info']->getState() . '"';
1660              // releases exist, but we failed to get any
1661              if (isset($this->_downloader->_options['force'])) {
1662                  if (isset($pname['version'])) {
1663                      $vs = ', version "' . $pname['version'] . '"';
1664                  } elseif (isset($pname['state'])) {
1665                      $vs = ', stability "' . $pname['state'] . '"';
1666                  } elseif ($param == 'dependency') {
1667                      if (!class_exists('PEAR_Common')) {
1668                          require_once  'PEAR/Common.php';
1669                      }
1670                      if (!in_array($info['info']->getState(),
1671                            PEAR_Common::betterStates($this->_config->get('preferred_state'), true))) {
1672                          if ($optional) {
1673                              // don't spit out confusing error message
1674                              return $this->_downloader->_getPackageDownloadUrl(
1675                                  array('package' => $pname['package'],
1676                                        'channel' => $pname['channel'],
1677                                        'version' => $info['version']));
1678                          }
1679                          $vs = ' within preferred state "' . $this->_config->get('preferred_state') .
1680                              '"';
1681                      } else {
1682                          if (!class_exists('PEAR_Dependency2')) {
1683                              require_once  'PEAR/Dependency2.php';
1684                          }
1685                          if ($optional) {
1686                              // don't spit out confusing error message
1687                              return $this->_downloader->_getPackageDownloadUrl(
1688                                  array('package' => $pname['package'],
1689                                        'channel' => $pname['channel'],
1690                                        'version' => $info['version']));
1691                          }
1692                          $vs = PEAR_Dependency2::_getExtraString($pname);
1693                          $instead = '';
1694                      }
1695                  } else {
1696                      $vs = ' within preferred state "' . $this->_config->get(
1697                          'preferred_state') . '"';
1698                  }
1699                  if (!isset($options['soft'])) {
1700                      $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] .
1701                          '/' . $pname['package'] . $vs . $instead);
1702                  }
1703                  // download the latest release
1704                  return $this->_downloader->_getPackageDownloadUrl(
1705                      array('package' => $pname['package'],
1706                            'channel' => $pname['channel'],
1707                            'version' => $info['version']));
1708              } else {
1709                  // construct helpful error message
1710                  if (isset($pname['version'])) {
1711                      $vs = ', version "' . $pname['version'] . '"';
1712                  } elseif (isset($pname['state'])) {
1713                      $vs = ', stability "' . $pname['state'] . '"';
1714                  } elseif ($param == 'dependency') {
1715                      if (!class_exists('PEAR_Common')) {
1716                          require_once  'PEAR/Common.php';
1717                      }
1718                      if (!in_array($info['info']->getState(),
1719                            PEAR_Common::betterStates($this->_config->get('preferred_state'), true))) {
1720                          if ($optional) {
1721                              // don't spit out confusing error message, and don't die on
1722                              // optional dep failure!
1723                              return $this->_downloader->_getPackageDownloadUrl(
1724                                  array('package' => $pname['package'],
1725                                        'channel' => $pname['channel'],
1726                                        'version' => $info['version']));
1727                          }
1728                          $vs = ' within preferred state "' . $this->_config->get('preferred_state') .
1729                              '"';
1730                      } else {
1731                          if (!class_exists('PEAR_Dependency2')) {
1732                              require_once  'PEAR/Dependency2.php';
1733                          }
1734                          if ($optional) {
1735                              // don't spit out confusing error message, and don't die on
1736                              // optional dep failure!
1737                              return $this->_downloader->_getPackageDownloadUrl(
1738                                  array('package' => $pname['package'],
1739                                        'channel' => $pname['channel'],
1740                                        'version' => $info['version']));
1741                          }
1742                          $vs = PEAR_Dependency2::_getExtraString($pname);
1743                      }
1744                  } else {
1745                      $vs = ' within preferred state "' . $this->_downloader->config->get(
1746                          'preferred_state') . '"';
1747                  }
1748                  $options = $this->_downloader->getOptions();
1749                  // this is only set by the "download-all" command
1750                  if (isset($options['ignorepreferred_state'])) {
1751                      $err = PEAR::raiseError(
1752                          'Failed to download ' . $this->_registry->parsedPackageNameToString(
1753                              array('channel' => $pname['channel'], 'package' => $pname['package']),
1754                                  true)
1755                           . $vs .
1756                          ', latest release is version ' . $info['version'] .
1757                          ', stability "' . $info['info']->getState() . '", use "' .
1758                          $this->_registry->parsedPackageNameToString(
1759                              array('channel' => $pname['channel'], 'package' => $pname['package'],
1760                              'version' => $info['version'])) . '" to install',
1761                              PEAR_DOWNLOADER_PACKAGE_STATE);
1762                      return $err;
1763                  }
1764                  $err = PEAR::raiseError(
1765                      'Failed to download ' . $this->_registry->parsedPackageNameToString(
1766                          array('channel' => $pname['channel'], 'package' => $pname['package']),
1767                              true)
1768                       . $vs .
1769                      ', latest release is version ' . $info['version'] .
1770                      ', stability "' . $info['info']->getState() . '", use "' .
1771                      $this->_registry->parsedPackageNameToString(
1772                          array('channel' => $pname['channel'], 'package' => $pname['package'],
1773                          'version' => $info['version'])) . '" to install');
1774                  return $err;
1775              }
1776          }
1777          if (isset($info['deprecated']) && $info['deprecated']) {
1778              $this->_downloader->log(0,
1779                  'WARNING: "' . 
1780                      $this->_registry->parsedPackageNameToString(
1781                              array('channel' => $info['info']->getChannel(),
1782                                    'package' => $info['info']->getPackage()), true) .
1783                  '" is deprecated in favor of "' .
1784                      $this->_registry->parsedPackageNameToString($info['deprecated'], true) .
1785                  '"');
1786          }
1787          return $info;
1788      }
1789  }
1790  ?>


Généré le : Sun Feb 25 14:08:00 2007 par Balluche grâce à PHPXref 0.7