[ Index ]
 

Code source de SPIP Agora 1.4

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

title

Body

[fermer]

/Pear/PEAR/ -> Installer.php (source)

   1  <?php
   2  //
   3  // +----------------------------------------------------------------------+
   4  // | PHP Version 5                                                        |
   5  // +----------------------------------------------------------------------+
   6  // | Copyright (c) 1997-2004 The PHP Group                                |
   7  // +----------------------------------------------------------------------+
   8  // | This source file is subject to version 3.0 of the PHP license,       |
   9  // | that is bundled with this package in the file LICENSE, and is        |
  10  // | available through the world-wide-web at the following url:           |
  11  // | http://www.php.net/license/3_0.txt.                                  |
  12  // | If you did not receive a copy of the PHP license and are unable to   |
  13  // | obtain it through the world-wide-web, please send a note to          |
  14  // | license@php.net so we can mail you a copy immediately.               |
  15  // +----------------------------------------------------------------------+
  16  // | Authors: Stig Bakken <ssb@php.net>                                   |
  17  // |          Tomas V.V.Cox <cox@idecnet.com>                             |
  18  // |          Martin Jansen <mj@php.net>                                  |
  19  // +----------------------------------------------------------------------+
  20  //
  21  // $Id: Installer.php,v 1.150.2.2 2005/02/17 17:47:55 cellog Exp $
  22  
  23  require_once 'PEAR/Downloader.php';
  24  
  25  /**
  26   * Administration class used to install PEAR packages and maintain the
  27   * installed package database.
  28   *
  29   * TODO:
  30   *   - Check dependencies break on package uninstall (when no force given)
  31   *   - add a guessInstallDest() method with the code from _installFile() and
  32   *     use that method in Registry::_rebuildFileMap() & Command_Registry::doList(),
  33   *     others..
  34   *
  35   * @since PHP 4.0.2
  36   * @author Stig Bakken <ssb@php.net>
  37   * @author Martin Jansen <mj@php.net>
  38   * @author Greg Beaver <cellog@php.net>
  39   */
  40  class PEAR_Installer extends PEAR_Downloader
  41  {
  42      // {{{ properties
  43  
  44      /** name of the package directory, for example Foo-1.0
  45       * @var string
  46       */
  47      var $pkgdir;
  48  
  49      /** directory where PHP code files go
  50       * @var string
  51       */
  52      var $phpdir;
  53  
  54      /** directory where PHP extension files go
  55       * @var string
  56       */
  57      var $extdir;
  58  
  59      /** directory where documentation goes
  60       * @var string
  61       */
  62      var $docdir;
  63  
  64      /** installation root directory (ala PHP's INSTALL_ROOT or
  65       * automake's DESTDIR
  66       * @var string
  67       */
  68      var $installroot = '';
  69  
  70      /** debug level
  71       * @var int
  72       */
  73      var $debug = 1;
  74  
  75      /** temporary directory
  76       * @var string
  77       */
  78      var $tmpdir;
  79  
  80      /** PEAR_Registry object used by the installer
  81       * @var object
  82       */
  83      var $registry;
  84  
  85      /** List of file transactions queued for an install/upgrade/uninstall.
  86       *
  87       *  Format:
  88       *    array(
  89       *      0 => array("rename => array("from-file", "to-file")),
  90       *      1 => array("delete" => array("file-to-delete")),
  91       *      ...
  92       *    )
  93       *
  94       * @var array
  95       */
  96      var $file_operations = array();
  97  
  98      // }}}
  99  
 100      // {{{ constructor
 101  
 102      /**
 103       * PEAR_Installer constructor.
 104       *
 105       * @param object $ui user interface object (instance of PEAR_Frontend_*)
 106       *
 107       * @access public
 108       */
 109      function PEAR_Installer(&$ui)
 110      {
 111          parent::PEAR_Common();
 112          $this->setFrontendObject($ui);
 113          $this->debug = $this->config->get('verbose');
 114          //$this->registry = &new PEAR_Registry($this->config->get('php_dir'));
 115      }
 116  
 117      // }}}
 118  
 119      // {{{ _deletePackageFiles()
 120  
 121      /**
 122       * Delete a package's installed files, does not remove empty directories.
 123       *
 124       * @param string $package package name
 125       *
 126       * @return bool TRUE on success, or a PEAR error on failure
 127       *
 128       * @access private
 129       */
 130      function _deletePackageFiles($package)
 131      {
 132          if (!strlen($package)) {
 133              return $this->raiseError("No package to uninstall given");
 134          }
 135          $filelist = $this->registry->packageInfo($package, 'filelist');
 136          if ($filelist == null) {
 137              return $this->raiseError("$package not installed");
 138          }
 139          foreach ($filelist as $file => $props) {
 140              if (empty($props['installed_as'])) {
 141                  continue;
 142              }
 143              $path = $this->_prependPath($props['installed_as'], $this->installroot);
 144              $this->addFileOperation('delete', array($path));
 145          }
 146          return true;
 147      }
 148  
 149      // }}}
 150      // {{{ _installFile()
 151  
 152      /**
 153       * @param string filename
 154       * @param array attributes from <file> tag in package.xml
 155       * @param string path to install the file in
 156       * @param array options from command-line
 157       * @access private
 158       */
 159      function _installFile($file, $atts, $tmp_path, $options)
 160      {
 161          // {{{ return if this file is meant for another platform
 162          static $os;
 163          if (isset($atts['platform'])) {
 164              if (empty($os)) {
 165                  include_once "OS/Guess.php";
 166                  $os = new OS_Guess();
 167              }
 168              if (strlen($atts['platform']) && $atts['platform']{0} == '!') {
 169                  $negate = true;
 170                  $platform = substr($atts['platform'], 1);
 171              } else {
 172                  $negate = false;
 173                  $platform = $atts['platform'];
 174              }
 175              if ((bool) $os->matchSignature($platform) === $negate) {
 176                  $this->log(3, "skipped $file (meant for $atts[platform], we are ".$os->getSignature().")");
 177                  return PEAR_INSTALLER_SKIPPED;
 178              }
 179          }
 180          // }}}
 181  
 182          // {{{ assemble the destination paths
 183          switch ($atts['role']) {
 184              case 'doc':
 185              case 'data':
 186              case 'test':
 187                  $dest_dir = $this->config->get($atts['role'] . '_dir') .
 188                              DIRECTORY_SEPARATOR . $this->pkginfo['package'];
 189                  unset($atts['baseinstalldir']);
 190                  break;
 191              case 'ext':
 192              case 'php':
 193                  $dest_dir = $this->config->get($atts['role'] . '_dir');
 194                  break;
 195              case 'script':
 196                  $dest_dir = $this->config->get('bin_dir');
 197                  break;
 198              case 'src':
 199              case 'extsrc':
 200                  $this->source_files++;
 201                  return;
 202              default:
 203                  return $this->raiseError("Invalid role `$atts[role]' for file $file");
 204          }
 205          $save_destdir = $dest_dir;
 206          if (!empty($atts['baseinstalldir'])) {
 207              $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir'];
 208          }
 209          if (dirname($file) != '.' && empty($atts['install-as'])) {
 210              $dest_dir .= DIRECTORY_SEPARATOR . dirname($file);
 211          }
 212          if (empty($atts['install-as'])) {
 213              $dest_file = $dest_dir . DIRECTORY_SEPARATOR . basename($file);
 214          } else {
 215              $dest_file = $dest_dir . DIRECTORY_SEPARATOR . $atts['install-as'];
 216          }
 217          $orig_file = $tmp_path . DIRECTORY_SEPARATOR . $file;
 218  
 219          // Clean up the DIRECTORY_SEPARATOR mess
 220          $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR;
 221          list($dest_file, $orig_file) = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"),
 222                                                      DIRECTORY_SEPARATOR,
 223                                                      array($dest_file, $orig_file));
 224          $installed_as = $dest_file;
 225          $final_dest_file = $this->_prependPath($dest_file, $this->installroot);
 226          $dest_dir = dirname($final_dest_file);
 227          $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file);
 228          // }}}
 229  
 230          if (!@is_dir($dest_dir)) {
 231              if (!$this->mkDirHier($dest_dir)) {
 232                  return $this->raiseError("failed to mkdir $dest_dir",
 233                                           PEAR_INSTALLER_FAILED);
 234              }
 235              $this->log(3, "+ mkdir $dest_dir");
 236          }
 237          if (empty($atts['replacements'])) {
 238              if (!file_exists($orig_file)) {
 239                  return $this->raiseError("file does not exist",
 240                                           PEAR_INSTALLER_FAILED);
 241              }
 242              if (!@copy($orig_file, $dest_file)) {
 243                  return $this->raiseError("failed to write $dest_file",
 244                                           PEAR_INSTALLER_FAILED);
 245              }
 246              $this->log(3, "+ cp $orig_file $dest_file");
 247              if (isset($atts['md5sum'])) {
 248                  $md5sum = md5_file($dest_file);
 249              }
 250          } else {
 251              // {{{ file with replacements
 252              if (!file_exists($orig_file)) {
 253                  return $this->raiseError("file does not exist",
 254                                           PEAR_INSTALLER_FAILED);
 255              }
 256              $fp = fopen($orig_file, "r");
 257              $contents = fread($fp, filesize($orig_file));
 258              fclose($fp);
 259              if (isset($atts['md5sum'])) {
 260                  $md5sum = md5($contents);
 261              }
 262              $subst_from = $subst_to = array();
 263              foreach ($atts['replacements'] as $a) {
 264                  $to = '';
 265                  if ($a['type'] == 'php-const') {
 266                      if (preg_match('/^[a-z0-9_]+$/i', $a['to'])) {
 267                          eval("\$to = $a[to];");
 268                      } else {
 269                          $this->log(0, "invalid php-const replacement: $a[to]");
 270                          continue;
 271                      }
 272                  } elseif ($a['type'] == 'pear-config') {
 273                      $to = $this->config->get($a['to']);
 274                      if (is_null($to)) {
 275                          $this->log(0, "invalid pear-config replacement: $a[to]");
 276                          continue;
 277                      }
 278                  } elseif ($a['type'] == 'package-info') {
 279                      if (isset($this->pkginfo[$a['to']]) && is_string($this->pkginfo[$a['to']])) {
 280                          $to = $this->pkginfo[$a['to']];
 281                      } else {
 282                          $this->log(0, "invalid package-info replacement: $a[to]");
 283                          continue;
 284                      }
 285                  }
 286                  if (!is_null($to)) {
 287                      $subst_from[] = $a['from'];
 288                      $subst_to[] = $to;
 289                  }
 290              }
 291              $this->log(3, "doing ".sizeof($subst_from)." substitution(s) for $final_dest_file");
 292              if (sizeof($subst_from)) {
 293                  $contents = str_replace($subst_from, $subst_to, $contents);
 294              }
 295              $wp = @fopen($dest_file, "wb");
 296              if (!is_resource($wp)) {
 297                  return $this->raiseError("failed to create $dest_file: $php_errormsg",
 298                                           PEAR_INSTALLER_FAILED);
 299              }
 300              if (!fwrite($wp, $contents)) {
 301                  return $this->raiseError("failed writing to $dest_file: $php_errormsg",
 302                                           PEAR_INSTALLER_FAILED);
 303              }
 304              fclose($wp);
 305              // }}}
 306          }
 307          // {{{ check the md5
 308          if (isset($md5sum)) {
 309              if (strtolower($md5sum) == strtolower($atts['md5sum'])) {
 310                  $this->log(2, "md5sum ok: $final_dest_file");
 311              } else {
 312                  if (empty($options['force'])) {
 313                      // delete the file
 314                      @unlink($dest_file);
 315                      return $this->raiseError("bad md5sum for file $final_dest_file",
 316                                               PEAR_INSTALLER_FAILED);
 317                  } else {
 318                      $this->log(0, "warning : bad md5sum for file $final_dest_file");
 319                  }
 320              }
 321          }
 322          // }}}
 323          // {{{ set file permissions
 324          if (!OS_WINDOWS) {
 325              if ($atts['role'] == 'script') {
 326                  $mode = 0777 & ~(int)octdec($this->config->get('umask'));
 327                  $this->log(3, "+ chmod +x $dest_file");
 328              } else {
 329                  $mode = 0666 & ~(int)octdec($this->config->get('umask'));
 330              }
 331              $this->addFileOperation("chmod", array($mode, $dest_file));
 332              if (!@chmod($dest_file, $mode)) {
 333                  $this->log(0, "failed to change mode of $dest_file");
 334              }
 335          }
 336          // }}}
 337          $this->addFileOperation("rename", array($dest_file, $final_dest_file));
 338          // Store the full path where the file was installed for easy unistall
 339          $this->addFileOperation("installed_as", array($file, $installed_as,
 340                                  $save_destdir, dirname(substr($dest_file, strlen($save_destdir)))));
 341  
 342          //$this->log(2, "installed: $dest_file");
 343          return PEAR_INSTALLER_OK;
 344      }
 345  
 346      // }}}
 347      // {{{ addFileOperation()
 348  
 349      /**
 350       * Add a file operation to the current file transaction.
 351       *
 352       * @see startFileTransaction()
 353       * @var string $type This can be one of:
 354       *    - rename:  rename a file ($data has 2 values)
 355       *    - chmod:   change permissions on a file ($data has 2 values)
 356       *    - delete:  delete a file ($data has 1 value)
 357       *    - rmdir:   delete a directory if empty ($data has 1 value)
 358       *    - installed_as: mark a file as installed ($data has 4 values).
 359       * @var array $data For all file operations, this array must contain the
 360       *    full path to the file or directory that is being operated on.  For
 361       *    the rename command, the first parameter must be the file to rename,
 362       *    the second its new name.
 363       *
 364       *    The installed_as operation contains 4 elements in this order:
 365       *    1. Filename as listed in the filelist element from package.xml
 366       *    2. Full path to the installed file
 367       *    3. Full path from the php_dir configuration variable used in this
 368       *       installation
 369       *    4. Relative path from the php_dir that this file is installed in
 370       */
 371      function addFileOperation($type, $data)
 372      {
 373          if (!is_array($data)) {
 374              return $this->raiseError('Internal Error: $data in addFileOperation'
 375                  . ' must be an array, was ' . gettype($data));
 376          }
 377          if ($type == 'chmod') {
 378              $octmode = decoct($data[0]);
 379              $this->log(3, "adding to transaction: $type $octmode $data[1]");
 380          } else {
 381              $this->log(3, "adding to transaction: $type " . implode(" ", $data));
 382          }
 383          $this->file_operations[] = array($type, $data);
 384      }
 385  
 386      // }}}
 387      // {{{ startFileTransaction()
 388  
 389      function startFileTransaction($rollback_in_case = false)
 390      {
 391          if (count($this->file_operations) && $rollback_in_case) {
 392              $this->rollbackFileTransaction();
 393          }
 394          $this->file_operations = array();
 395      }
 396  
 397      // }}}
 398      // {{{ commitFileTransaction()
 399  
 400      function commitFileTransaction()
 401      {
 402          $n = count($this->file_operations);
 403          $this->log(2, "about to commit $n file operations");
 404          // {{{ first, check permissions and such manually
 405          $errors = array();
 406          foreach ($this->file_operations as $tr) {
 407              list($type, $data) = $tr;
 408              switch ($type) {
 409                  case 'rename':
 410                      if (!file_exists($data[0])) {
 411                          $errors[] = "cannot rename file $data[0], doesn't exist";
 412                      }
 413                      // check that dest dir. is writable
 414                      if (!is_writable(dirname($data[1]))) {
 415                          $errors[] = "permission denied ($type): $data[1]";
 416                      }
 417                      break;
 418                  case 'chmod':
 419                      // check that file is writable
 420                      if (!is_writable($data[1])) {
 421                          $errors[] = "permission denied ($type): $data[1] " . decoct($data[0]);
 422                      }
 423                      break;
 424                  case 'delete':
 425                      if (!file_exists($data[0])) {
 426                          $this->log(2, "warning: file $data[0] doesn't exist, can't be deleted");
 427                      }
 428                      // check that directory is writable
 429                      if (file_exists($data[0]) && !is_writable(dirname($data[0]))) {
 430                          $errors[] = "permission denied ($type): $data[0]";
 431                      }
 432                      break;
 433              }
 434  
 435          }
 436          // }}}
 437          $m = sizeof($errors);
 438          if ($m > 0) {
 439              foreach ($errors as $error) {
 440                  $this->log(1, $error);
 441              }
 442              return false;
 443          }
 444          // {{{ really commit the transaction
 445          foreach ($this->file_operations as $tr) {
 446              list($type, $data) = $tr;
 447              switch ($type) {
 448                  case 'rename':
 449                      @unlink($data[1]);
 450                      @rename($data[0], $data[1]);
 451                      $this->log(3, "+ mv $data[0] $data[1]");
 452                      break;
 453                  case 'chmod':
 454                      @chmod($data[1], $data[0]);
 455                      $octmode = decoct($data[0]);
 456                      $this->log(3, "+ chmod $octmode $data[1]");
 457                      break;
 458                  case 'delete':
 459                      @unlink($data[0]);
 460                      $this->log(3, "+ rm $data[0]");
 461                      break;
 462                  case 'rmdir':
 463                      @rmdir($data[0]);
 464                      $this->log(3, "+ rmdir $data[0]");
 465                      break;
 466                  case 'installed_as':
 467                      $this->pkginfo['filelist'][$data[0]]['installed_as'] = $data[1];
 468                      if (!isset($this->pkginfo['filelist']['dirtree'][dirname($data[1])])) {
 469                          $this->pkginfo['filelist']['dirtree'][dirname($data[1])] = true;
 470                          while(!empty($data[3]) && $data[3] != '/' && $data[3] != '\\'
 471                                && $data[3] != '.') {
 472                              $this->pkginfo['filelist']['dirtree']
 473                                  [$this->_prependPath($data[3], $data[2])] = true;
 474                              $data[3] = dirname($data[3]);
 475                          }
 476                      }
 477                      break;
 478              }
 479          }
 480          // }}}
 481          $this->log(2, "successfully committed $n file operations");
 482          $this->file_operations = array();
 483          return true;
 484      }
 485  
 486      // }}}
 487      // {{{ rollbackFileTransaction()
 488  
 489      function rollbackFileTransaction()
 490      {
 491          $n = count($this->file_operations);
 492          $this->log(2, "rolling back $n file operations");
 493          foreach ($this->file_operations as $tr) {
 494              list($type, $data) = $tr;
 495              switch ($type) {
 496                  case 'rename':
 497                      @unlink($data[0]);
 498                      $this->log(3, "+ rm $data[0]");
 499                      break;
 500                  case 'mkdir':
 501                      @rmdir($data[0]);
 502                      $this->log(3, "+ rmdir $data[0]");
 503                      break;
 504                  case 'chmod':
 505                      break;
 506                  case 'delete':
 507                      break;
 508                  case 'installed_as':
 509                      if (isset($this->pkginfo['filelist'])) {
 510                          unset($this->pkginfo['filelist'][$data[0]]['installed_as']);
 511                      }
 512                      if (isset($this->pkginfo['filelist']['dirtree'][dirname($data[1])])) {
 513                          unset($this->pkginfo['filelist']['dirtree'][dirname($data[1])]);
 514                          while(!empty($data[3]) && $data[3] != '/' && $data[3] != '\\'
 515                                && $data[3] != '.') {
 516                              unset($this->pkginfo['filelist']['dirtree']
 517                                  [$this->_prependPath($data[3], $data[2])]);
 518                              $data[3] = dirname($data[3]);
 519                          }
 520                      }
 521                      if (isset($this->pkginfo['filelist']['dirtree'])
 522                            && !count($this->pkginfo['filelist']['dirtree'])) {
 523                          unset($this->pkginfo['filelist']['dirtree']);
 524                      }
 525                      break;
 526              }
 527          }
 528          $this->file_operations = array();
 529      }
 530  
 531      // }}}
 532      // {{{ mkDirHier($dir)
 533  
 534      function mkDirHier($dir)
 535      {
 536          $this->addFileOperation('mkdir', array($dir));
 537          return parent::mkDirHier($dir);
 538      }
 539  
 540      // }}}
 541      // {{{ download()
 542  
 543      /**
 544       * Download any files and their dependencies, if necessary
 545       *
 546       * @param array a mixed list of package names, local files, or package.xml
 547       * @param PEAR_Config
 548       * @param array options from the command line
 549       * @param array this is the array that will be populated with packages to
 550       *              install.  Format of each entry:
 551       *
 552       * <code>
 553       * array('pkg' => 'package_name', 'file' => '/path/to/local/file',
 554       *    'info' => array() // parsed package.xml
 555       * );
 556       * </code>
 557       * @param array this will be populated with any error messages
 558       * @param false private recursion variable
 559       * @param false private recursion variable
 560       * @param false private recursion variable
 561       * @deprecated in favor of PEAR_Downloader
 562       */
 563      function download($packages, $options, &$config, &$installpackages,
 564                        &$errors, $installed = false, $willinstall = false, $state = false)
 565      {
 566          // trickiness: initialize here
 567          parent::PEAR_Downloader($this->ui, $options, $config);
 568          $ret = parent::download($packages);
 569          $errors = $this->getErrorMsgs();
 570          $installpackages = $this->getDownloadedPackages();
 571          trigger_error("PEAR Warning: PEAR_Installer::download() is deprecated " .
 572                        "in favor of PEAR_Downloader class", E_USER_WARNING);
 573          return $ret;
 574      }
 575  
 576      // }}}
 577      // {{{ install()
 578  
 579      /**
 580       * Installs the files within the package file specified.
 581       *
 582       * @param string $pkgfile path to the package file
 583       * @param array $options
 584       * recognized options:
 585       * - installroot   : optional prefix directory for installation
 586       * - force         : force installation
 587       * - register-only : update registry but don't install files
 588       * - upgrade       : upgrade existing install
 589       * - soft          : fail silently
 590       * - nodeps        : ignore dependency conflicts/missing dependencies
 591       * - alldeps       : install all dependencies
 592       * - onlyreqdeps   : install only required dependencies
 593       *
 594       * @return array|PEAR_Error package info if successful
 595       */
 596  
 597      function install($pkgfile, $options = array())
 598      {
 599          $php_dir = $this->config->get('php_dir');
 600          if (isset($options['installroot'])) {
 601              if (substr($options['installroot'], -1) == DIRECTORY_SEPARATOR) {
 602                  $options['installroot'] = substr($options['installroot'], 0, -1);
 603              }
 604              $php_dir = $this->_prependPath($php_dir, $options['installroot']);
 605              $this->installroot = $options['installroot'];
 606          } else {
 607              $this->installroot = '';
 608          }
 609          $this->registry = &new PEAR_Registry($php_dir);
 610          //  ==> XXX should be removed later on
 611          $flag_old_format = false;
 612  
 613          if (substr($pkgfile, -4) == '.xml') {
 614              $descfile = $pkgfile;
 615          } else {
 616              // {{{ Decompress pack in tmp dir -------------------------------------
 617  
 618              // To allow relative package file names
 619              $pkgfile = realpath($pkgfile);
 620  
 621              if (PEAR::isError($tmpdir = System::mktemp('-d'))) {
 622                  return $tmpdir;
 623              }
 624              $this->log(3, '+ tmp dir created at ' . $tmpdir);
 625  
 626              $tar = new Archive_Tar($pkgfile);
 627              if (!@$tar->extract($tmpdir)) {
 628                  return $this->raiseError("unable to unpack $pkgfile");
 629              }
 630  
 631              // {{{ Look for existing package file
 632              $descfile = $tmpdir . DIRECTORY_SEPARATOR . 'package.xml';
 633  
 634              if (!is_file($descfile)) {
 635                  // ----- Look for old package archive format
 636                  // In this format the package.xml file was inside the
 637                  // Package-n.n directory
 638                  $dp = opendir($tmpdir);
 639                  do {
 640                      $pkgdir = readdir($dp);
 641                  } while ($pkgdir{0} == '.');
 642  
 643                  $descfile = $tmpdir . DIRECTORY_SEPARATOR . $pkgdir . DIRECTORY_SEPARATOR . 'package.xml';
 644                  $flag_old_format = true;
 645                  $this->log(0, "warning : you are using an archive with an old format");
 646              }
 647              // }}}
 648              // <== XXX This part should be removed later on
 649              // }}}
 650          }
 651  
 652          if (!is_file($descfile)) {
 653              return $this->raiseError("no package.xml file after extracting the archive");
 654          }
 655  
 656          // Parse xml file -----------------------------------------------
 657          $pkginfo = $this->infoFromDescriptionFile($descfile);
 658          if (PEAR::isError($pkginfo)) {
 659              return $pkginfo;
 660          }
 661          $this->validatePackageInfo($pkginfo, $errors, $warnings);
 662          // XXX We allow warnings, do we have to do it?
 663          if (count($errors)) {
 664              if (empty($options['force'])) {
 665                  return $this->raiseError("The following errors where found (use force option to install anyway):\n".
 666                                           implode("\n", $errors));
 667              } else {
 668                  $this->log(0, "warning : the following errors were found:\n".
 669                             implode("\n", $errors));
 670              }
 671          }
 672  
 673          $pkgname = $pkginfo['package'];
 674  
 675          // {{{ Check dependencies -------------------------------------------
 676          if (isset($pkginfo['release_deps']) && empty($options['nodeps'])) {
 677              $dep_errors = '';
 678              $error = $this->checkDeps($pkginfo, $dep_errors);
 679              if ($error == true) {
 680                  if (empty($options['soft'])) {
 681                      $this->log(0, substr($dep_errors, 1));
 682                  }
 683                  return $this->raiseError("$pkgname: Dependencies failed");
 684              } else if (!empty($dep_errors)) {
 685                  // Print optional dependencies
 686                  if (empty($options['soft'])) {
 687                      $this->log(0, $dep_errors);
 688                  }
 689              }
 690          }
 691          // }}}
 692  
 693          // {{{ checks to do when not in "force" mode
 694          if (empty($options['force'])) {
 695              $test = $this->registry->checkFileMap($pkginfo);
 696              if (sizeof($test)) {
 697                  $tmp = $test;
 698                  foreach ($tmp as $file => $pkg) {
 699                      if ($pkg == $pkgname) {
 700                          unset($test[$file]);
 701                      }
 702                  }
 703                  if (sizeof($test)) {
 704                      $msg = "$pkgname: conflicting files found:\n";
 705                      $longest = max(array_map("strlen", array_keys($test)));
 706                      $fmt = "%$longest}s (%s)\n";
 707                      foreach ($test as $file => $pkg) {
 708                          $msg .= sprintf($fmt, $file, $pkg);
 709                      }
 710                      return $this->raiseError($msg);
 711                  }
 712              }
 713          }
 714          // }}}
 715  
 716          $this->startFileTransaction();
 717  
 718          if (empty($options['upgrade'])) {
 719              // checks to do only when installing new packages
 720              if (empty($options['force']) && $this->registry->packageExists($pkgname)) {
 721                  return $this->raiseError("$pkgname already installed");
 722              }
 723          } else {
 724              if ($this->registry->packageExists($pkgname)) {
 725                  $v1 = $this->registry->packageInfo($pkgname, 'version');
 726                  $v2 = $pkginfo['version'];
 727                  $cmp = version_compare("$v1", "$v2", 'gt');
 728                  if (empty($options['force']) && !version_compare("$v2", "$v1", 'gt')) {
 729                      return $this->raiseError("upgrade to a newer version ($v2 is not newer than $v1)");
 730                  }
 731                  if (empty($options['register-only'])) {
 732                      // when upgrading, remove old release's files first:
 733                      if (PEAR::isError($err = $this->_deletePackageFiles($pkgname))) {
 734                          return $this->raiseError($err);
 735                      }
 736                  }
 737              }
 738          }
 739  
 740          // {{{ Copy files to dest dir ---------------------------------------
 741  
 742          // info from the package it self we want to access from _installFile
 743          $this->pkginfo = &$pkginfo;
 744          // used to determine whether we should build any C code
 745          $this->source_files = 0;
 746  
 747          if (empty($options['register-only'])) {
 748              if (!is_dir($php_dir)) {
 749                  return $this->raiseError("no script destination directory\n",
 750                                           null, PEAR_ERROR_DIE);
 751              }
 752  
 753              $tmp_path = dirname($descfile);
 754              if (substr($pkgfile, -4) != '.xml') {
 755                  $tmp_path .= DIRECTORY_SEPARATOR . $pkgname . '-' . $pkginfo['version'];
 756              }
 757  
 758              //  ==> XXX This part should be removed later on
 759              if ($flag_old_format) {
 760                  $tmp_path = dirname($descfile);
 761              }
 762              // <== XXX This part should be removed later on
 763  
 764              // {{{ install files
 765              foreach ($pkginfo['filelist'] as $file => $atts) {
 766                  $this->expectError(PEAR_INSTALLER_FAILED);
 767                  $res = $this->_installFile($file, $atts, $tmp_path, $options);
 768                  $this->popExpect();
 769                  if (PEAR::isError($res)) {
 770                      if (empty($options['ignore-errors'])) {
 771                          $this->rollbackFileTransaction();
 772                          if ($res->getMessage() == "file does not exist") {
 773                              $this->raiseError("file $file in package.xml does not exist");
 774                          }
 775                          return $this->raiseError($res);
 776                      } else {
 777                          $this->log(0, "Warning: " . $res->getMessage());
 778                      }
 779                  }
 780                  if ($res != PEAR_INSTALLER_OK) {
 781                      // Do not register files that were not installed
 782                      unset($pkginfo['filelist'][$file]);
 783                  }
 784              }
 785              // }}}
 786  
 787              // {{{ compile and install source files
 788              if ($this->source_files > 0 && empty($options['nobuild'])) {
 789                  $this->log(1, "$this->source_files source files, building");
 790                  $bob = &new PEAR_Builder($this->ui);
 791                  $bob->debug = $this->debug;
 792                  $built = $bob->build($descfile, array(&$this, '_buildCallback'));
 793                  if (PEAR::isError($built)) {
 794                      $this->rollbackFileTransaction();
 795                      return $built;
 796                  }
 797                  $this->log(1, "\nBuild process completed successfully");
 798                  foreach ($built as $ext) {
 799                      $bn = basename($ext['file']);
 800                      list($_ext_name, $_ext_suff) = explode('.', $bn);
 801                      if ($_ext_suff == '.so' || $_ext_suff == '.dll') {
 802                          if (extension_loaded($_ext_name)) {
 803                              $this->raiseError("Extension '$_ext_name' already loaded. " .
 804                                                'Please unload it in your php.ini file ' .
 805                                                'prior to install or upgrade');
 806                          }
 807                          $role = 'ext';
 808                      } else {
 809                          $role = 'src';
 810                      }
 811                      $dest = $ext['dest'];
 812                      $this->log(1, "Installing '$ext[file]'");
 813                      $copyto = $this->_prependPath($dest, $this->installroot);
 814                      $copydir = dirname($copyto);
 815                      if (!@is_dir($copydir)) {
 816                          if (!$this->mkDirHier($copydir)) {
 817                              return $this->raiseError("failed to mkdir $copydir",
 818                                  PEAR_INSTALLER_FAILED);
 819                          }
 820                          $this->log(3, "+ mkdir $copydir");
 821                      }
 822                      if (!@copy($ext['file'], $copyto)) {
 823                          return $this->raiseError("failed to write $copyto", PEAR_INSTALLER_FAILED);
 824                      }
 825                      $this->log(3, "+ cp $ext[file] $copyto");
 826                      if (!OS_WINDOWS) {
 827                          $mode = 0666 & ~(int)octdec($this->config->get('umask'));
 828                          $this->addFileOperation('chmod', array($mode, $copyto));
 829                          if (!@chmod($copyto, $mode)) {
 830                              $this->log(0, "failed to change mode of $copyto");
 831                          }
 832                      }
 833                      $this->addFileOperation('rename', array($ext['file'], $copyto));
 834  
 835                      $pkginfo['filelist'][$bn] = array(
 836                          'role' => $role,
 837                          'installed_as' => $dest,
 838                          'php_api' => $ext['php_api'],
 839                          'zend_mod_api' => $ext['zend_mod_api'],
 840                          'zend_ext_api' => $ext['zend_ext_api'],
 841                          );
 842                  }
 843              }
 844              // }}}
 845          }
 846  
 847          if (!$this->commitFileTransaction()) {
 848              $this->rollbackFileTransaction();
 849              return $this->raiseError("commit failed", PEAR_INSTALLER_FAILED);
 850          }
 851          // }}}
 852  
 853          $ret = false;
 854          // {{{ Register that the package is installed -----------------------
 855          if (empty($options['upgrade'])) {
 856              // if 'force' is used, replace the info in registry
 857              if (!empty($options['force']) && $this->registry->packageExists($pkgname)) {
 858                  $this->registry->deletePackage($pkgname);
 859              }
 860              $ret = $this->registry->addPackage($pkgname, $pkginfo);
 861          } else {
 862              // new: upgrade installs a package if it isn't installed
 863              if (!$this->registry->packageExists($pkgname)) {
 864                  $ret = $this->registry->addPackage($pkgname, $pkginfo);
 865              } else {
 866                  $ret = $this->registry->updatePackage($pkgname, $pkginfo, false);
 867              }
 868          }
 869          if (!$ret) {
 870              return $this->raiseError("Adding package $pkgname to registry failed");
 871          }
 872          // }}}
 873          return $pkginfo;
 874      }
 875  
 876      // }}}
 877      // {{{ uninstall()
 878  
 879      /**
 880       * Uninstall a package
 881       *
 882       * This method removes all files installed by the application, and then
 883       * removes any empty directories.
 884       * @param string package name
 885       * @param array Command-line options.  Possibilities include:
 886       *
 887       *              - installroot: base installation dir, if not the default
 888       *              - nodeps: do not process dependencies of other packages to ensure
 889       *                        uninstallation does not break things
 890       */
 891      function uninstall($package, $options = array())
 892      {
 893          $php_dir = $this->config->get('php_dir');
 894          if (isset($options['installroot'])) {
 895              if (substr($options['installroot'], -1) == DIRECTORY_SEPARATOR) {
 896                  $options['installroot'] = substr($options['installroot'], 0, -1);
 897              }
 898              $this->installroot = $options['installroot'];
 899              $php_dir = $this->_prependPath($php_dir, $this->installroot);
 900          } else {
 901              $this->installroot = '';
 902          }
 903          $this->registry = &new PEAR_Registry($php_dir);
 904          $filelist = $this->registry->packageInfo($package, 'filelist');
 905          if ($filelist == null) {
 906              return $this->raiseError("$package not installed");
 907          }
 908          if (empty($options['nodeps'])) {
 909              $depchecker = &new PEAR_Dependency($this->registry);
 910              $error = $depchecker->checkPackageUninstall($errors, $warning, $package);
 911              if ($error) {
 912                  return $this->raiseError($errors . 'uninstall failed');
 913              }
 914              if ($warning) {
 915                  $this->log(0, $warning);
 916              }
 917          }
 918          // {{{ Delete the files
 919          $this->startFileTransaction();
 920          if (PEAR::isError($err = $this->_deletePackageFiles($package))) {
 921              $this->rollbackFileTransaction();
 922              return $this->raiseError($err);
 923          }
 924          if (!$this->commitFileTransaction()) {
 925              $this->rollbackFileTransaction();
 926              return $this->raiseError("uninstall failed");
 927          } else {
 928              $this->startFileTransaction();
 929              if (!isset($filelist['dirtree']) || !count($filelist['dirtree'])) {
 930                  return $this->registry->deletePackage($package);
 931              }
 932              // attempt to delete empty directories
 933              uksort($filelist['dirtree'], array($this, '_sortDirs'));
 934              foreach($filelist['dirtree'] as $dir => $notused) {
 935                  $this->addFileOperation('rmdir', array($dir));
 936              }
 937              if (!$this->commitFileTransaction()) {
 938                  $this->rollbackFileTransaction();
 939              }
 940          }
 941          // }}}
 942  
 943          // Register that the package is no longer installed
 944          return $this->registry->deletePackage($package);
 945      }
 946  
 947      // }}}
 948      // {{{ _sortDirs()
 949      function _sortDirs($a, $b)
 950      {
 951          if (strnatcmp($a, $b) == -1) return 1;
 952          if (strnatcmp($a, $b) == 1) return -1;
 953          return 0;
 954      }
 955  
 956      // }}}
 957      // {{{ checkDeps()
 958  
 959      /**
 960       * Check if the package meets all dependencies
 961       *
 962       * @param  array   Package information (passed by reference)
 963       * @param  string  Error message (passed by reference)
 964       * @return boolean False when no error occured, otherwise true
 965       */
 966      function checkDeps(&$pkginfo, &$errors)
 967      {
 968          if (empty($this->registry)) {
 969              $this->registry = &new PEAR_Registry($this->config->get('php_dir'));
 970          }
 971          $depchecker = &new PEAR_Dependency($this->registry);
 972          $error = $errors = '';
 973          $failed_deps = $optional_deps = array();
 974          if (is_array($pkginfo['release_deps'])) {
 975              foreach($pkginfo['release_deps'] as $dep) {
 976                  $code = $depchecker->callCheckMethod($error, $dep);
 977                  if ($code) {
 978                      if (isset($dep['optional']) && $dep['optional'] == 'yes') {
 979                          $optional_deps[] = array($dep, $code, $error);
 980                      } else {
 981                          $failed_deps[] = array($dep, $code, $error);
 982                      }
 983                  }
 984              }
 985              // {{{ failed dependencies
 986              $n = count($failed_deps);
 987              if ($n > 0) {
 988                  for ($i = 0; $i < $n; $i++) {
 989                      if (isset($failed_deps[$i]['type'])) {
 990                          $type = $failed_deps[$i]['type'];
 991                      } else {
 992                          $type = 'pkg';
 993                      }
 994                      switch ($failed_deps[$i][1]) {
 995                          case PEAR_DEPENDENCY_MISSING:
 996                              if ($type == 'pkg') {
 997                                  // install
 998                              }
 999                              $errors .= "\n" . $failed_deps[$i][2];
1000                              break;
1001                          case PEAR_DEPENDENCY_UPGRADE_MINOR:
1002                              if ($type == 'pkg') {
1003                                  // upgrade
1004                              }
1005                              $errors .= "\n" . $failed_deps[$i][2];
1006                              break;
1007                          default:
1008                              $errors .= "\n" . $failed_deps[$i][2];
1009                              break;
1010                      }
1011                  }
1012                  return true;
1013              }
1014              // }}}
1015  
1016              // {{{ optional dependencies
1017              $count_optional = count($optional_deps);
1018              if ($count_optional > 0) {
1019                  $errors = "Optional dependencies:";
1020  
1021                  for ($i = 0; $i < $count_optional; $i++) {
1022                      if (isset($optional_deps[$i]['type'])) {
1023                          $type = $optional_deps[$i]['type'];
1024                      } else {
1025                          $type = 'pkg';
1026                      }
1027                      switch ($optional_deps[$i][1]) {
1028                          case PEAR_DEPENDENCY_MISSING:
1029                          case PEAR_DEPENDENCY_UPGRADE_MINOR:
1030                          default:
1031                              $errors .= "\n" . $optional_deps[$i][2];
1032                              break;
1033                      }
1034                  }
1035                  return false;
1036              }
1037              // }}}
1038          }
1039          return false;
1040      }
1041  
1042      // }}}
1043      // {{{ _buildCallback()
1044  
1045      function _buildCallback($what, $data)
1046      {
1047          if (($what == 'cmdoutput' && $this->debug > 1) ||
1048              ($what == 'output' && $this->debug > 0)) {
1049              $this->ui->outputData(rtrim($data), 'build');
1050          }
1051      }
1052  
1053      // }}}
1054  }
1055  
1056  // {{{ md5_file() utility function
1057  if (!function_exists("md5_file")) {
1058      function md5_file($filename) {
1059          $fp = fopen($filename, "r");
1060          if (!$fp) return null;
1061          $contents = fread($fp, filesize($filename));
1062          fclose($fp);
1063          return md5($contents);
1064      }
1065  }
1066  // }}}
1067  
1068  ?>


Généré le : Sat Feb 24 14:40:03 2007 par Balluche grâce à PHPXref 0.7