summaryrefslogtreecommitdiffstats
path: root/3rdparty/PEAR/Installer.php
diff options
context:
space:
mode:
authorRobin Appelman <icewind@owncloud.com>2012-05-11 17:57:55 +0200
committerRobin Appelman <icewind@owncloud.com>2012-05-11 17:57:55 +0200
commit9c2f1051646f1dfb2615065d79d9a76410152b1a (patch)
treeaeb2812f7f37fb58bc6920cd2b3ccdf08d9c1eec /3rdparty/PEAR/Installer.php
parent347ce2aafada161849dad8593100c40e14c641ce (diff)
downloadnextcloud-server-9c2f1051646f1dfb2615065d79d9a76410152b1a.tar.gz
nextcloud-server-9c2f1051646f1dfb2615065d79d9a76410152b1a.zip
update PEAR to 1.9.4
Diffstat (limited to '3rdparty/PEAR/Installer.php')
-rw-r--r--3rdparty/PEAR/Installer.php1805
1 files changed, 1280 insertions, 525 deletions
diff --git a/3rdparty/PEAR/Installer.php b/3rdparty/PEAR/Installer.php
index 31e2cff81ee..eb17ca7914d 100644
--- a/3rdparty/PEAR/Installer.php
+++ b/3rdparty/PEAR/Installer.php
@@ -1,41 +1,44 @@
<?php
-//
-// +----------------------------------------------------------------------+
-// | PHP Version 5 |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2004 The PHP Group |
-// +----------------------------------------------------------------------+
-// | This source file is subject to version 3.0 of the PHP license, |
-// | that is bundled with this package in the file LICENSE, and is |
-// | available through the world-wide-web at the following url: |
-// | http://www.php.net/license/3_0.txt. |
-// | If you did not receive a copy of the PHP license and are unable to |
-// | obtain it through the world-wide-web, please send a note to |
-// | license@php.net so we can mail you a copy immediately. |
-// +----------------------------------------------------------------------+
-// | Authors: Stig Bakken <ssb@php.net> |
-// | Tomas V.V.Cox <cox@idecnet.com> |
-// | Martin Jansen <mj@php.net> |
-// +----------------------------------------------------------------------+
-//
-// $Id: Installer.php,v 1.150.2.2 2005/02/17 17:47:55 cellog Exp $
+/**
+ * PEAR_Installer
+ *
+ * PHP versions 4 and 5
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken <ssb@php.net>
+ * @author Tomas V.V. Cox <cox@idecnet.com>
+ * @author Martin Jansen <mj@php.net>
+ * @author Greg Beaver <cellog@php.net>
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version CVS: $Id: Installer.php 313024 2011-07-06 19:51:24Z dufuz $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ */
+/**
+ * Used for installation groups in package.xml 2.0 and platform exceptions
+ */
+require_once 'OS/Guess.php';
require_once 'PEAR/Downloader.php';
+define('PEAR_INSTALLER_NOBINARY', -240);
/**
* Administration class used to install PEAR packages and maintain the
* installed package database.
*
- * TODO:
- * - Check dependencies break on package uninstall (when no force given)
- * - add a guessInstallDest() method with the code from _installFile() and
- * use that method in Registry::_rebuildFileMap() & Command_Registry::doList(),
- * others..
- *
- * @since PHP 4.0.2
- * @author Stig Bakken <ssb@php.net>
- * @author Martin Jansen <mj@php.net>
- * @author Greg Beaver <cellog@php.net>
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken <ssb@php.net>
+ * @author Tomas V.V. Cox <cox@idecnet.com>
+ * @author Martin Jansen <mj@php.net>
+ * @author Greg Beaver <cellog@php.net>
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.9.4
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 0.1
*/
class PEAR_Installer extends PEAR_Downloader
{
@@ -77,11 +80,18 @@ class PEAR_Installer extends PEAR_Downloader
*/
var $tmpdir;
- /** PEAR_Registry object used by the installer
- * @var object
+ /**
+ * PEAR_Registry object used by the installer
+ * @var PEAR_Registry
*/
var $registry;
+ /**
+ * array of PEAR_Downloader_Packages
+ * @var array
+ */
+ var $_downloadedPackages;
+
/** List of file transactions queued for an install/upgrade/uninstall.
*
* Format:
@@ -111,38 +121,85 @@ class PEAR_Installer extends PEAR_Downloader
parent::PEAR_Common();
$this->setFrontendObject($ui);
$this->debug = $this->config->get('verbose');
- //$this->registry = &new PEAR_Registry($this->config->get('php_dir'));
+ }
+
+ function setOptions($options)
+ {
+ $this->_options = $options;
+ }
+
+ function setConfig(&$config)
+ {
+ $this->config = &$config;
+ $this->_registry = &$config->getRegistry();
}
// }}}
+ function _removeBackups($files)
+ {
+ foreach ($files as $path) {
+ $this->addFileOperation('removebackup', array($path));
+ }
+ }
+
// {{{ _deletePackageFiles()
/**
* Delete a package's installed files, does not remove empty directories.
*
- * @param string $package package name
- *
+ * @param string package name
+ * @param string channel name
+ * @param bool if true, then files are backed up first
* @return bool TRUE on success, or a PEAR error on failure
- *
- * @access private
+ * @access protected
*/
- function _deletePackageFiles($package)
+ function _deletePackageFiles($package, $channel = false, $backup = false)
{
+ if (!$channel) {
+ $channel = 'pear.php.net';
+ }
+
if (!strlen($package)) {
return $this->raiseError("No package to uninstall given");
}
- $filelist = $this->registry->packageInfo($package, 'filelist');
+
+ if (strtolower($package) == 'pear' && $channel == 'pear.php.net') {
+ // to avoid race conditions, include all possible needed files
+ require_once 'PEAR/Task/Common.php';
+ require_once 'PEAR/Task/Replace.php';
+ require_once 'PEAR/Task/Unixeol.php';
+ require_once 'PEAR/Task/Windowseol.php';
+ require_once 'PEAR/PackageFile/v1.php';
+ require_once 'PEAR/PackageFile/v2.php';
+ require_once 'PEAR/PackageFile/Generator/v1.php';
+ require_once 'PEAR/PackageFile/Generator/v2.php';
+ }
+
+ $filelist = $this->_registry->packageInfo($package, 'filelist', $channel);
if ($filelist == null) {
- return $this->raiseError("$package not installed");
+ return $this->raiseError("$channel/$package not installed");
}
+
+ $ret = array();
foreach ($filelist as $file => $props) {
if (empty($props['installed_as'])) {
continue;
}
- $path = $this->_prependPath($props['installed_as'], $this->installroot);
+
+ $path = $props['installed_as'];
+ if ($backup) {
+ $this->addFileOperation('backup', array($path));
+ $ret[] = $path;
+ }
+
$this->addFileOperation('delete', array($path));
}
+
+ if ($backup) {
+ return $ret;
+ }
+
return true;
}
@@ -160,18 +217,23 @@ class PEAR_Installer extends PEAR_Downloader
{
// {{{ return if this file is meant for another platform
static $os;
+ if (!isset($this->_registry)) {
+ $this->_registry = &$this->config->getRegistry();
+ }
+
if (isset($atts['platform'])) {
if (empty($os)) {
- include_once "OS/Guess.php";
$os = new OS_Guess();
}
+
if (strlen($atts['platform']) && $atts['platform']{0} == '!') {
- $negate = true;
+ $negate = true;
$platform = substr($atts['platform'], 1);
} else {
- $negate = false;
+ $negate = false;
$platform = $atts['platform'];
}
+
if ((bool) $os->matchSignature($platform) === $negate) {
$this->log(3, "skipped $file (meant for $atts[platform], we are ".$os->getSignature().")");
return PEAR_INSTALLER_SKIPPED;
@@ -179,36 +241,40 @@ class PEAR_Installer extends PEAR_Downloader
}
// }}}
+ $channel = $this->pkginfo->getChannel();
// {{{ assemble the destination paths
switch ($atts['role']) {
+ case 'src':
+ case 'extsrc':
+ $this->source_files++;
+ return;
case 'doc':
case 'data':
case 'test':
- $dest_dir = $this->config->get($atts['role'] . '_dir') .
- DIRECTORY_SEPARATOR . $this->pkginfo['package'];
+ $dest_dir = $this->config->get($atts['role'] . '_dir', null, $channel) .
+ DIRECTORY_SEPARATOR . $this->pkginfo->getPackage();
unset($atts['baseinstalldir']);
break;
case 'ext':
case 'php':
- $dest_dir = $this->config->get($atts['role'] . '_dir');
+ $dest_dir = $this->config->get($atts['role'] . '_dir', null, $channel);
break;
case 'script':
- $dest_dir = $this->config->get('bin_dir');
+ $dest_dir = $this->config->get('bin_dir', null, $channel);
break;
- case 'src':
- case 'extsrc':
- $this->source_files++;
- return;
default:
return $this->raiseError("Invalid role `$atts[role]' for file $file");
}
+
$save_destdir = $dest_dir;
if (!empty($atts['baseinstalldir'])) {
$dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir'];
}
+
if (dirname($file) != '.' && empty($atts['install-as'])) {
$dest_dir .= DIRECTORY_SEPARATOR . dirname($file);
}
+
if (empty($atts['install-as'])) {
$dest_file = $dest_dir . DIRECTORY_SEPARATOR . basename($file);
} else {
@@ -219,125 +285,411 @@ class PEAR_Installer extends PEAR_Downloader
// Clean up the DIRECTORY_SEPARATOR mess
$ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR;
list($dest_file, $orig_file) = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"),
- DIRECTORY_SEPARATOR,
+ array(DIRECTORY_SEPARATOR,
+ DIRECTORY_SEPARATOR,
+ DIRECTORY_SEPARATOR),
array($dest_file, $orig_file));
- $installed_as = $dest_file;
- $final_dest_file = $this->_prependPath($dest_file, $this->installroot);
- $dest_dir = dirname($final_dest_file);
+ $final_dest_file = $installed_as = $dest_file;
+ if (isset($this->_options['packagingroot'])) {
+ $installedas_dest_dir = dirname($final_dest_file);
+ $installedas_dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file);
+ $final_dest_file = $this->_prependPath($final_dest_file, $this->_options['packagingroot']);
+ } else {
+ $installedas_dest_dir = dirname($final_dest_file);
+ $installedas_dest_file = $installedas_dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file);
+ }
+
+ $dest_dir = dirname($final_dest_file);
$dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file);
+ if (preg_match('~/\.\.(/|\\z)|^\.\./~', str_replace('\\', '/', $dest_file))) {
+ return $this->raiseError("SECURITY ERROR: file $file (installed to $dest_file) contains parent directory reference ..", PEAR_INSTALLER_FAILED);
+ }
// }}}
- if (!@is_dir($dest_dir)) {
+ if (empty($this->_options['register-only']) &&
+ (!file_exists($dest_dir) || !is_dir($dest_dir))) {
if (!$this->mkDirHier($dest_dir)) {
return $this->raiseError("failed to mkdir $dest_dir",
PEAR_INSTALLER_FAILED);
}
$this->log(3, "+ mkdir $dest_dir");
}
- if (empty($atts['replacements'])) {
- if (!file_exists($orig_file)) {
- return $this->raiseError("file does not exist",
- PEAR_INSTALLER_FAILED);
+
+ // pretty much nothing happens if we are only registering the install
+ if (empty($this->_options['register-only'])) {
+ if (empty($atts['replacements'])) {
+ if (!file_exists($orig_file)) {
+ return $this->raiseError("file $orig_file does not exist",
+ PEAR_INSTALLER_FAILED);
+ }
+
+ if (!@copy($orig_file, $dest_file)) {
+ return $this->raiseError("failed to write $dest_file: $php_errormsg",
+ PEAR_INSTALLER_FAILED);
+ }
+
+ $this->log(3, "+ cp $orig_file $dest_file");
+ if (isset($atts['md5sum'])) {
+ $md5sum = md5_file($dest_file);
+ }
+ } else {
+ // {{{ file with replacements
+ if (!file_exists($orig_file)) {
+ return $this->raiseError("file does not exist",
+ PEAR_INSTALLER_FAILED);
+ }
+
+ $contents = file_get_contents($orig_file);
+ if ($contents === false) {
+ $contents = '';
+ }
+
+ if (isset($atts['md5sum'])) {
+ $md5sum = md5($contents);
+ }
+
+ $subst_from = $subst_to = array();
+ foreach ($atts['replacements'] as $a) {
+ $to = '';
+ if ($a['type'] == 'php-const') {
+ if (preg_match('/^[a-z0-9_]+\\z/i', $a['to'])) {
+ eval("\$to = $a[to];");
+ } else {
+ if (!isset($options['soft'])) {
+ $this->log(0, "invalid php-const replacement: $a[to]");
+ }
+ continue;
+ }
+ } elseif ($a['type'] == 'pear-config') {
+ if ($a['to'] == 'master_server') {
+ $chan = $this->_registry->getChannel($channel);
+ if (!PEAR::isError($chan)) {
+ $to = $chan->getServer();
+ } else {
+ $to = $this->config->get($a['to'], null, $channel);
+ }
+ } else {
+ $to = $this->config->get($a['to'], null, $channel);
+ }
+ if (is_null($to)) {
+ if (!isset($options['soft'])) {
+ $this->log(0, "invalid pear-config replacement: $a[to]");
+ }
+ continue;
+ }
+ } elseif ($a['type'] == 'package-info') {
+ if ($t = $this->pkginfo->packageInfo($a['to'])) {
+ $to = $t;
+ } else {
+ if (!isset($options['soft'])) {
+ $this->log(0, "invalid package-info replacement: $a[to]");
+ }
+ continue;
+ }
+ }
+ if (!is_null($to)) {
+ $subst_from[] = $a['from'];
+ $subst_to[] = $to;
+ }
+ }
+
+ $this->log(3, "doing ".sizeof($subst_from)." substitution(s) for $final_dest_file");
+ if (sizeof($subst_from)) {
+ $contents = str_replace($subst_from, $subst_to, $contents);
+ }
+
+ $wp = @fopen($dest_file, "wb");
+ if (!is_resource($wp)) {
+ return $this->raiseError("failed to create $dest_file: $php_errormsg",
+ PEAR_INSTALLER_FAILED);
+ }
+
+ if (@fwrite($wp, $contents) === false) {
+ return $this->raiseError("failed writing to $dest_file: $php_errormsg",
+ PEAR_INSTALLER_FAILED);
+ }
+
+ fclose($wp);
+ // }}}
}
- if (!@copy($orig_file, $dest_file)) {
- return $this->raiseError("failed to write $dest_file",
- PEAR_INSTALLER_FAILED);
+
+ // {{{ check the md5
+ if (isset($md5sum)) {
+ if (strtolower($md5sum) === strtolower($atts['md5sum'])) {
+ $this->log(2, "md5sum ok: $final_dest_file");
+ } else {
+ if (empty($options['force'])) {
+ // delete the file
+ if (file_exists($dest_file)) {
+ unlink($dest_file);
+ }
+
+ if (!isset($options['ignore-errors'])) {
+ return $this->raiseError("bad md5sum for file $final_dest_file",
+ PEAR_INSTALLER_FAILED);
+ }
+
+ if (!isset($options['soft'])) {
+ $this->log(0, "warning : bad md5sum for file $final_dest_file");
+ }
+ } else {
+ if (!isset($options['soft'])) {
+ $this->log(0, "warning : bad md5sum for file $final_dest_file");
+ }
+ }
+ }
}
- $this->log(3, "+ cp $orig_file $dest_file");
- if (isset($atts['md5sum'])) {
- $md5sum = md5_file($dest_file);
+ // }}}
+ // {{{ set file permissions
+ if (!OS_WINDOWS) {
+ if ($atts['role'] == 'script') {
+ $mode = 0777 & ~(int)octdec($this->config->get('umask'));
+ $this->log(3, "+ chmod +x $dest_file");
+ } else {
+ $mode = 0666 & ~(int)octdec($this->config->get('umask'));
+ }
+
+ if ($atts['role'] != 'src') {
+ $this->addFileOperation("chmod", array($mode, $dest_file));
+ if (!@chmod($dest_file, $mode)) {
+ if (!isset($options['soft'])) {
+ $this->log(0, "failed to change mode of $dest_file: $php_errormsg");
+ }
+ }
+ }
}
- } else {
- // {{{ file with replacements
- if (!file_exists($orig_file)) {
- return $this->raiseError("file does not exist",
- PEAR_INSTALLER_FAILED);
+ // }}}
+
+ if ($atts['role'] == 'src') {
+ rename($dest_file, $final_dest_file);
+ $this->log(2, "renamed source file $dest_file to $final_dest_file");
+ } else {
+ $this->addFileOperation("rename", array($dest_file, $final_dest_file,
+ $atts['role'] == 'ext'));
}
- $fp = fopen($orig_file, "r");
- $contents = fread($fp, filesize($orig_file));
- fclose($fp);
- if (isset($atts['md5sum'])) {
- $md5sum = md5($contents);
+ }
+
+ // Store the full path where the file was installed for easy unistall
+ if ($atts['role'] != 'script') {
+ $loc = $this->config->get($atts['role'] . '_dir');
+ } else {
+ $loc = $this->config->get('bin_dir');
+ }
+
+ if ($atts['role'] != 'src') {
+ $this->addFileOperation("installed_as", array($file, $installed_as,
+ $loc,
+ dirname(substr($installedas_dest_file, strlen($loc)))));
+ }
+
+ //$this->log(2, "installed: $dest_file");
+ return PEAR_INSTALLER_OK;
+ }
+
+ // }}}
+ // {{{ _installFile2()
+
+ /**
+ * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+ * @param string filename
+ * @param array attributes from <file> tag in package.xml
+ * @param string path to install the file in
+ * @param array options from command-line
+ * @access private
+ */
+ function _installFile2(&$pkg, $file, &$real_atts, $tmp_path, $options)
+ {
+ $atts = $real_atts;
+ if (!isset($this->_registry)) {
+ $this->_registry = &$this->config->getRegistry();
+ }
+
+ $channel = $pkg->getChannel();
+ // {{{ assemble the destination paths
+ if (!in_array($atts['attribs']['role'],
+ PEAR_Installer_Role::getValidRoles($pkg->getPackageType()))) {
+ return $this->raiseError('Invalid role `' . $atts['attribs']['role'] .
+ "' for file $file");
+ }
+
+ $role = &PEAR_Installer_Role::factory($pkg, $atts['attribs']['role'], $this->config);
+ $err = $role->setup($this, $pkg, $atts['attribs'], $file);
+ if (PEAR::isError($err)) {
+ return $err;
+ }
+
+ if (!$role->isInstallable()) {
+ return;
+ }
+
+ $info = $role->processInstallation($pkg, $atts['attribs'], $file, $tmp_path);
+ if (PEAR::isError($info)) {
+ return $info;
+ }
+
+ list($save_destdir, $dest_dir, $dest_file, $orig_file) = $info;
+ if (preg_match('~/\.\.(/|\\z)|^\.\./~', str_replace('\\', '/', $dest_file))) {
+ return $this->raiseError("SECURITY ERROR: file $file (installed to $dest_file) contains parent directory reference ..", PEAR_INSTALLER_FAILED);
+ }
+
+ $final_dest_file = $installed_as = $dest_file;
+ if (isset($this->_options['packagingroot'])) {
+ $final_dest_file = $this->_prependPath($final_dest_file,
+ $this->_options['packagingroot']);
+ }
+
+ $dest_dir = dirname($final_dest_file);
+ $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file);
+ // }}}
+
+ if (empty($this->_options['register-only'])) {
+ if (!file_exists($dest_dir) || !is_dir($dest_dir)) {
+ if (!$this->mkDirHier($dest_dir)) {
+ return $this->raiseError("failed to mkdir $dest_dir",
+ PEAR_INSTALLER_FAILED);
+ }
+ $this->log(3, "+ mkdir $dest_dir");
}
- $subst_from = $subst_to = array();
- foreach ($atts['replacements'] as $a) {
- $to = '';
- if ($a['type'] == 'php-const') {
- if (preg_match('/^[a-z0-9_]+$/i', $a['to'])) {
- eval("\$to = $a[to];");
- } else {
- $this->log(0, "invalid php-const replacement: $a[to]");
- continue;
+ }
+
+ $attribs = $atts['attribs'];
+ unset($atts['attribs']);
+ // pretty much nothing happens if we are only registering the install
+ if (empty($this->_options['register-only'])) {
+ if (!count($atts)) { // no tasks
+ if (!file_exists($orig_file)) {
+ return $this->raiseError("file $orig_file does not exist",
+ PEAR_INSTALLER_FAILED);
+ }
+
+ if (!@copy($orig_file, $dest_file)) {
+ return $this->raiseError("failed to write $dest_file: $php_errormsg",
+ PEAR_INSTALLER_FAILED);
+ }
+
+ $this->log(3, "+ cp $orig_file $dest_file");
+ if (isset($attribs['md5sum'])) {
+ $md5sum = md5_file($dest_file);
+ }
+ } else { // file with tasks
+ if (!file_exists($orig_file)) {
+ return $this->raiseError("file $orig_file does not exist",
+ PEAR_INSTALLER_FAILED);
+ }
+
+ $contents = file_get_contents($orig_file);
+ if ($contents === false) {
+ $contents = '';
+ }
+
+ if (isset($attribs['md5sum'])) {
+ $md5sum = md5($contents);
+ }
+
+ foreach ($atts as $tag => $raw) {
+ $tag = str_replace(array($pkg->getTasksNs() . ':', '-'), array('', '_'), $tag);
+ $task = "PEAR_Task_$tag";
+ $task = &new $task($this->config, $this, PEAR_TASK_INSTALL);
+ if (!$task->isScript()) { // scripts are only handled after installation
+ $task->init($raw, $attribs, $pkg->getLastInstalledVersion());
+ $res = $task->startSession($pkg, $contents, $final_dest_file);
+ if ($res === false) {
+ continue; // skip this file
+ }
+
+ if (PEAR::isError($res)) {
+ return $res;
+ }
+
+ $contents = $res; // save changes
}
- } elseif ($a['type'] == 'pear-config') {
- $to = $this->config->get($a['to']);
- if (is_null($to)) {
- $this->log(0, "invalid pear-config replacement: $a[to]");
- continue;
+
+ $wp = @fopen($dest_file, "wb");
+ if (!is_resource($wp)) {
+ return $this->raiseError("failed to create $dest_file: $php_errormsg",
+ PEAR_INSTALLER_FAILED);
}
- } elseif ($a['type'] == 'package-info') {
- if (isset($this->pkginfo[$a['to']]) && is_string($this->pkginfo[$a['to']])) {
- $to = $this->pkginfo[$a['to']];
- } else {
- $this->log(0, "invalid package-info replacement: $a[to]");
- continue;
+
+ if (fwrite($wp, $contents) === false) {
+ return $this->raiseError("failed writing to $dest_file: $php_errormsg",
+ PEAR_INSTALLER_FAILED);
}
+
+ fclose($wp);
}
- if (!is_null($to)) {
- $subst_from[] = $a['from'];
- $subst_to[] = $to;
- }
- }
- $this->log(3, "doing ".sizeof($subst_from)." substitution(s) for $final_dest_file");
- if (sizeof($subst_from)) {
- $contents = str_replace($subst_from, $subst_to, $contents);
- }
- $wp = @fopen($dest_file, "wb");
- if (!is_resource($wp)) {
- return $this->raiseError("failed to create $dest_file: $php_errormsg",
- PEAR_INSTALLER_FAILED);
}
- if (!fwrite($wp, $contents)) {
- return $this->raiseError("failed writing to $dest_file: $php_errormsg",
- PEAR_INSTALLER_FAILED);
+
+ // {{{ check the md5
+ if (isset($md5sum)) {
+ // Make sure the original md5 sum matches with expected
+ if (strtolower($md5sum) === strtolower($attribs['md5sum'])) {
+ $this->log(2, "md5sum ok: $final_dest_file");
+
+ if (isset($contents)) {
+ // set md5 sum based on $content in case any tasks were run.
+ $real_atts['attribs']['md5sum'] = md5($contents);
+ }
+ } else {
+ if (empty($options['force'])) {
+ // delete the file
+ if (file_exists($dest_file)) {
+ unlink($dest_file);
+ }
+
+ if (!isset($options['ignore-errors'])) {
+ return $this->raiseError("bad md5sum for file $final_dest_file",
+ PEAR_INSTALLER_FAILED);
+ }
+
+ if (!isset($options['soft'])) {
+ $this->log(0, "warning : bad md5sum for file $final_dest_file");
+ }
+ } else {
+ if (!isset($options['soft'])) {
+ $this->log(0, "warning : bad md5sum for file $final_dest_file");
+ }
+ }
+ }
+ } else {
+ $real_atts['attribs']['md5sum'] = md5_file($dest_file);
}
- fclose($wp);
+
// }}}
- }
- // {{{ check the md5
- if (isset($md5sum)) {
- if (strtolower($md5sum) == strtolower($atts['md5sum'])) {
- $this->log(2, "md5sum ok: $final_dest_file");
- } else {
- if (empty($options['force'])) {
- // delete the file
- @unlink($dest_file);
- return $this->raiseError("bad md5sum for file $final_dest_file",
- PEAR_INSTALLER_FAILED);
+ // {{{ set file permissions
+ if (!OS_WINDOWS) {
+ if ($role->isExecutable()) {
+ $mode = 0777 & ~(int)octdec($this->config->get('umask'));
+ $this->log(3, "+ chmod +x $dest_file");
} else {
- $this->log(0, "warning : bad md5sum for file $final_dest_file");
+ $mode = 0666 & ~(int)octdec($this->config->get('umask'));
+ }
+
+ if ($attribs['role'] != 'src') {
+ $this->addFileOperation("chmod", array($mode, $dest_file));
+ if (!@chmod($dest_file, $mode)) {
+ if (!isset($options['soft'])) {
+ $this->log(0, "failed to change mode of $dest_file: $php_errormsg");
+ }
+ }
}
}
- }
- // }}}
- // {{{ set file permissions
- if (!OS_WINDOWS) {
- if ($atts['role'] == 'script') {
- $mode = 0777 & ~(int)octdec($this->config->get('umask'));
- $this->log(3, "+ chmod +x $dest_file");
+ // }}}
+
+ if ($attribs['role'] == 'src') {
+ rename($dest_file, $final_dest_file);
+ $this->log(2, "renamed source file $dest_file to $final_dest_file");
} else {
- $mode = 0666 & ~(int)octdec($this->config->get('umask'));
- }
- $this->addFileOperation("chmod", array($mode, $dest_file));
- if (!@chmod($dest_file, $mode)) {
- $this->log(0, "failed to change mode of $dest_file");
+ $this->addFileOperation("rename", array($dest_file, $final_dest_file, $role->isExtension()));
}
}
- // }}}
- $this->addFileOperation("rename", array($dest_file, $final_dest_file));
- // Store the full path where the file was installed for easy unistall
- $this->addFileOperation("installed_as", array($file, $installed_as,
- $save_destdir, dirname(substr($dest_file, strlen($save_destdir)))));
+
+ // Store the full path where the file was installed for easy uninstall
+ if ($attribs['role'] != 'src') {
+ $loc = $this->config->get($role->getLocationConfig(), null, $channel);
+ $this->addFileOperation('installed_as', array($file, $installed_as,
+ $loc,
+ dirname(substr($installed_as, strlen($loc)))));
+ }
//$this->log(2, "installed: $dest_file");
return PEAR_INSTALLER_OK;
@@ -350,16 +702,18 @@ class PEAR_Installer extends PEAR_Downloader
* Add a file operation to the current file transaction.
*
* @see startFileTransaction()
- * @var string $type This can be one of:
- * - rename: rename a file ($data has 2 values)
+ * @param string $type This can be one of:
+ * - rename: rename a file ($data has 3 values)
+ * - backup: backup an existing file ($data has 1 value)
+ * - removebackup: clean up backups created during install ($data has 1 value)
* - chmod: change permissions on a file ($data has 2 values)
* - delete: delete a file ($data has 1 value)
* - rmdir: delete a directory if empty ($data has 1 value)
* - installed_as: mark a file as installed ($data has 4 values).
- * @var array $data For all file operations, this array must contain the
+ * @param array $data For all file operations, this array must contain the
* full path to the file or directory that is being operated on. For
* the rename command, the first parameter must be the file to rename,
- * the second its new name.
+ * the second its new name, the third whether this is a PHP extension.
*
* The installed_as operation contains 4 elements in this order:
* 1. Filename as listed in the filelist element from package.xml
@@ -374,6 +728,7 @@ class PEAR_Installer extends PEAR_Downloader
return $this->raiseError('Internal Error: $data in addFileOperation'
. ' must be an array, was ' . gettype($data));
}
+
if ($type == 'chmod') {
$octmode = decoct($data[0]);
$this->log(3, "adding to transaction: $type $octmode $data[1]");
@@ -399,17 +754,16 @@ class PEAR_Installer extends PEAR_Downloader
function commitFileTransaction()
{
- $n = count($this->file_operations);
- $this->log(2, "about to commit $n file operations");
// {{{ first, check permissions and such manually
$errors = array();
- foreach ($this->file_operations as $tr) {
+ foreach ($this->file_operations as $key => $tr) {
list($type, $data) = $tr;
switch ($type) {
case 'rename':
if (!file_exists($data[0])) {
$errors[] = "cannot rename file $data[0], doesn't exist";
}
+
// check that dest dir. is writable
if (!is_writable(dirname($data[1]))) {
$errors[] = "permission denied ($type): $data[1]";
@@ -426,51 +780,176 @@ class PEAR_Installer extends PEAR_Downloader
$this->log(2, "warning: file $data[0] doesn't exist, can't be deleted");
}
// check that directory is writable
- if (file_exists($data[0]) && !is_writable(dirname($data[0]))) {
- $errors[] = "permission denied ($type): $data[0]";
+ if (file_exists($data[0])) {
+ if (!is_writable(dirname($data[0]))) {
+ $errors[] = "permission denied ($type): $data[0]";
+ } else {
+ // make sure the file to be deleted can be opened for writing
+ $fp = false;
+ if (!is_dir($data[0]) &&
+ (!is_writable($data[0]) || !($fp = @fopen($data[0], 'a')))) {
+ $errors[] = "permission denied ($type): $data[0]";
+ } elseif ($fp) {
+ fclose($fp);
+ }
+ }
+
+ /* Verify we are not deleting a file owned by another package
+ * This can happen when a file moves from package A to B in
+ * an upgrade ala http://pear.php.net/17986
+ */
+ $info = array(
+ 'package' => strtolower($this->pkginfo->getName()),
+ 'channel' => strtolower($this->pkginfo->getChannel()),
+ );
+ $result = $this->_registry->checkFileMap($data[0], $info, '1.1');
+ if (is_array($result)) {
+ $res = array_diff($result, $info);
+ if (!empty($res)) {
+ $new = $this->_registry->getPackage($result[1], $result[0]);
+ $this->file_operations[$key] = false;
+ $this->log(3, "file $data[0] was scheduled for removal from {$this->pkginfo->getName()} but is owned by {$new->getChannel()}/{$new->getName()}, removal has been cancelled.");
+ }
+ }
}
break;
}
}
// }}}
- $m = sizeof($errors);
+
+ $n = count($this->file_operations);
+ $this->log(2, "about to commit $n file operations for " . $this->pkginfo->getName());
+
+ $m = count($errors);
if ($m > 0) {
foreach ($errors as $error) {
- $this->log(1, $error);
+ if (!isset($this->_options['soft'])) {
+ $this->log(1, $error);
+ }
+ }
+
+ if (!isset($this->_options['ignore-errors'])) {
+ return false;
}
- return false;
}
+
+ $this->_dirtree = array();
// {{{ really commit the transaction
- foreach ($this->file_operations as $tr) {
+ foreach ($this->file_operations as $i => $tr) {
+ if (!$tr) {
+ // support removal of non-existing backups
+ continue;
+ }
+
list($type, $data) = $tr;
switch ($type) {
+ case 'backup':
+ if (!file_exists($data[0])) {
+ $this->file_operations[$i] = false;
+ break;
+ }
+
+ if (!@copy($data[0], $data[0] . '.bak')) {
+ $this->log(1, 'Could not copy ' . $data[0] . ' to ' . $data[0] .
+ '.bak ' . $php_errormsg);
+ return false;
+ }
+ $this->log(3, "+ backup $data[0] to $data[0].bak");
+ break;
+ case 'removebackup':
+ if (file_exists($data[0] . '.bak') && is_writable($data[0] . '.bak')) {
+ unlink($data[0] . '.bak');
+ $this->log(3, "+ rm backup of $data[0] ($data[0].bak)");
+ }
+ break;
case 'rename':
- @unlink($data[1]);
- @rename($data[0], $data[1]);
+ $test = file_exists($data[1]) ? @unlink($data[1]) : null;
+ if (!$test && file_exists($data[1])) {
+ if ($data[2]) {
+ $extra = ', this extension must be installed manually. Rename to "' .
+ basename($data[1]) . '"';
+ } else {
+ $extra = '';
+ }
+
+ if (!isset($this->_options['soft'])) {
+ $this->log(1, 'Could not delete ' . $data[1] . ', cannot rename ' .
+ $data[0] . $extra);
+ }
+
+ if (!isset($this->_options['ignore-errors'])) {
+ return false;
+ }
+ }
+
+ // permissions issues with rename - copy() is far superior
+ $perms = @fileperms($data[0]);
+ if (!@copy($data[0], $data[1])) {
+ $this->log(1, 'Could not rename ' . $data[0] . ' to ' . $data[1] .
+ ' ' . $php_errormsg);
+ return false;
+ }
+
+ // copy over permissions, otherwise they are lost
+ @chmod($data[1], $perms);
+ @unlink($data[0]);
$this->log(3, "+ mv $data[0] $data[1]");
break;
case 'chmod':
- @chmod($data[1], $data[0]);
+ if (!@chmod($data[1], $data[0])) {
+ $this->log(1, 'Could not chmod ' . $data[1] . ' to ' .
+ decoct($data[0]) . ' ' . $php_errormsg);
+ return false;
+ }
+
$octmode = decoct($data[0]);
$this->log(3, "+ chmod $octmode $data[1]");
break;
case 'delete':
- @unlink($data[0]);
- $this->log(3, "+ rm $data[0]");
+ if (file_exists($data[0])) {
+ if (!@unlink($data[0])) {
+ $this->log(1, 'Could not delete ' . $data[0] . ' ' .
+ $php_errormsg);
+ return false;
+ }
+ $this->log(3, "+ rm $data[0]");
+ }
break;
case 'rmdir':
- @rmdir($data[0]);
- $this->log(3, "+ rmdir $data[0]");
+ if (file_exists($data[0])) {
+ do {
+ $testme = opendir($data[0]);
+ while (false !== ($entry = readdir($testme))) {
+ if ($entry == '.' || $entry == '..') {
+ continue;
+ }
+ closedir($testme);
+ break 2; // this directory is not empty and can't be
+ // deleted
+ }
+
+ closedir($testme);
+ if (!@rmdir($data[0])) {
+ $this->log(1, 'Could not rmdir ' . $data[0] . ' ' .
+ $php_errormsg);
+ return false;
+ }
+ $this->log(3, "+ rmdir $data[0]");
+ } while (false);
+ }
break;
case 'installed_as':
- $this->pkginfo['filelist'][$data[0]]['installed_as'] = $data[1];
- if (!isset($this->pkginfo['filelist']['dirtree'][dirname($data[1])])) {
- $this->pkginfo['filelist']['dirtree'][dirname($data[1])] = true;
- while(!empty($data[3]) && $data[3] != '/' && $data[3] != '\\'
- && $data[3] != '.') {
- $this->pkginfo['filelist']['dirtree']
- [$this->_prependPath($data[3], $data[2])] = true;
+ $this->pkginfo->setInstalledAs($data[0], $data[1]);
+ if (!isset($this->_dirtree[dirname($data[1])])) {
+ $this->_dirtree[dirname($data[1])] = true;
+ $this->pkginfo->setDirtree(dirname($data[1]));
+
+ while(!empty($data[3]) && dirname($data[3]) != $data[3] &&
+ $data[3] != '/' && $data[3] != '\\') {
+ $this->pkginfo->setDirtree($pp =
+ $this->_prependPath($data[3], $data[2]));
+ $this->_dirtree[$pp] = true;
$data[3] = dirname($data[3]);
}
}
@@ -493,6 +972,21 @@ class PEAR_Installer extends PEAR_Downloader
foreach ($this->file_operations as $tr) {
list($type, $data) = $tr;
switch ($type) {
+ case 'backup':
+ if (file_exists($data[0] . '.bak')) {
+ if (file_exists($data[0] && is_writable($data[0]))) {
+ unlink($data[0]);
+ }
+ @copy($data[0] . '.bak', $data[0]);
+ $this->log(3, "+ restore $data[0] from $data[0].bak");
+ }
+ break;
+ case 'removebackup':
+ if (file_exists($data[0] . '.bak') && is_writable($data[0] . '.bak')) {
+ unlink($data[0] . '.bak');
+ $this->log(3, "+ rm backup of $data[0] ($data[0].bak)");
+ }
+ break;
case 'rename':
@unlink($data[0]);
$this->log(3, "+ rm $data[0]");
@@ -506,25 +1000,11 @@ class PEAR_Installer extends PEAR_Downloader
case 'delete':
break;
case 'installed_as':
- if (isset($this->pkginfo['filelist'])) {
- unset($this->pkginfo['filelist'][$data[0]]['installed_as']);
- }
- if (isset($this->pkginfo['filelist']['dirtree'][dirname($data[1])])) {
- unset($this->pkginfo['filelist']['dirtree'][dirname($data[1])]);
- while(!empty($data[3]) && $data[3] != '/' && $data[3] != '\\'
- && $data[3] != '.') {
- unset($this->pkginfo['filelist']['dirtree']
- [$this->_prependPath($data[3], $data[2])]);
- $data[3] = dirname($data[3]);
- }
- }
- if (isset($this->pkginfo['filelist']['dirtree'])
- && !count($this->pkginfo['filelist']['dirtree'])) {
- unset($this->pkginfo['filelist']['dirtree']);
- }
+ $this->pkginfo->setInstalledAs($data[0], false);
break;
}
}
+ $this->pkginfo->resetDirtree();
$this->file_operations = array();
}
@@ -565,8 +1045,8 @@ class PEAR_Installer extends PEAR_Downloader
{
// trickiness: initialize here
parent::PEAR_Downloader($this->ui, $options, $config);
- $ret = parent::download($packages);
- $errors = $this->getErrorMsgs();
+ $ret = parent::download($packages);
+ $errors = $this->getErrorMsgs();
$installpackages = $this->getDownloadedPackages();
trigger_error("PEAR Warning: PEAR_Installer::download() is deprecated " .
"in favor of PEAR_Downloader class", E_USER_WARNING);
@@ -574,12 +1054,70 @@ class PEAR_Installer extends PEAR_Downloader
}
// }}}
+ // {{{ _parsePackageXml()
+
+ function _parsePackageXml(&$descfile)
+ {
+ // Parse xml file -----------------------------------------------
+ $pkg = new PEAR_PackageFile($this->config, $this->debug);
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $p = &$pkg->fromAnyFile($descfile, PEAR_VALIDATE_INSTALLING);
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($p)) {
+ if (is_array($p->getUserInfo())) {
+ foreach ($p->getUserInfo() as $err) {
+ $loglevel = $err['level'] == 'error' ? 0 : 1;
+ if (!isset($this->_options['soft'])) {
+ $this->log($loglevel, ucfirst($err['level']) . ': ' . $err['message']);
+ }
+ }
+ }
+ return $this->raiseError('Installation failed: invalid package file');
+ }
+
+ $descfile = $p->getPackageFile();
+ return $p;
+ }
+
+ // }}}
+ /**
+ * Set the list of PEAR_Downloader_Package objects to allow more sane
+ * dependency validation
+ * @param array
+ */
+ function setDownloadedPackages(&$pkgs)
+ {
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ $err = $this->analyzeDependencies($pkgs);
+ PEAR::popErrorHandling();
+ if (PEAR::isError($err)) {
+ return $err;
+ }
+ $this->_downloadedPackages = &$pkgs;
+ }
+
+ /**
+ * Set the list of PEAR_Downloader_Package objects to allow more sane
+ * dependency validation
+ * @param array
+ */
+ function setUninstallPackages(&$pkgs)
+ {
+ $this->_downloadedPackages = &$pkgs;
+ }
+
+ function getInstallPackages()
+ {
+ return $this->_downloadedPackages;
+ }
+
// {{{ install()
/**
* Installs the files within the package file specified.
*
- * @param string $pkgfile path to the package file
+ * @param string|PEAR_Downloader_Package $pkgfile path to the package file,
+ * or a pre-initialized packagefile object
* @param array $options
* recognized options:
* - installroot : optional prefix directory for installation
@@ -593,121 +1131,183 @@ class PEAR_Installer extends PEAR_Downloader
*
* @return array|PEAR_Error package info if successful
*/
-
function install($pkgfile, $options = array())
{
- $php_dir = $this->config->get('php_dir');
- if (isset($options['installroot'])) {
- if (substr($options['installroot'], -1) == DIRECTORY_SEPARATOR) {
- $options['installroot'] = substr($options['installroot'], 0, -1);
- }
- $php_dir = $this->_prependPath($php_dir, $options['installroot']);
- $this->installroot = $options['installroot'];
+ $this->_options = $options;
+ $this->_registry = &$this->config->getRegistry();
+ if (is_object($pkgfile)) {
+ $dlpkg = &$pkgfile;
+ $pkg = $pkgfile->getPackageFile();
+ $pkgfile = $pkg->getArchiveFile();
+ $descfile = $pkg->getPackageFile();
} else {
- $this->installroot = '';
- }
- $this->registry = &new PEAR_Registry($php_dir);
- // ==> XXX should be removed later on
- $flag_old_format = false;
-
- if (substr($pkgfile, -4) == '.xml') {
$descfile = $pkgfile;
- } else {
- // {{{ Decompress pack in tmp dir -------------------------------------
-
- // To allow relative package file names
- $pkgfile = realpath($pkgfile);
-
- if (PEAR::isError($tmpdir = System::mktemp('-d'))) {
- return $tmpdir;
+ $pkg = $this->_parsePackageXml($descfile);
+ if (PEAR::isError($pkg)) {
+ return $pkg;
}
- $this->log(3, '+ tmp dir created at ' . $tmpdir);
+ }
+
+ $tmpdir = dirname($descfile);
+ if (realpath($descfile) != realpath($pkgfile)) {
+ // Use the temp_dir since $descfile can contain the download dir path
+ $tmpdir = $this->config->get('temp_dir', null, 'pear.php.net');
+ $tmpdir = System::mktemp('-d -t "' . $tmpdir . '"');
$tar = new Archive_Tar($pkgfile);
- if (!@$tar->extract($tmpdir)) {
+ if (!$tar->extract($tmpdir)) {
return $this->raiseError("unable to unpack $pkgfile");
}
-
- // {{{ Look for existing package file
- $descfile = $tmpdir . DIRECTORY_SEPARATOR . 'package.xml';
-
- if (!is_file($descfile)) {
- // ----- Look for old package archive format
- // In this format the package.xml file was inside the
- // Package-n.n directory
- $dp = opendir($tmpdir);
- do {
- $pkgdir = readdir($dp);
- } while ($pkgdir{0} == '.');
-
- $descfile = $tmpdir . DIRECTORY_SEPARATOR . $pkgdir . DIRECTORY_SEPARATOR . 'package.xml';
- $flag_old_format = true;
- $this->log(0, "warning : you are using an archive with an old format");
- }
- // }}}
- // <== XXX This part should be removed later on
- // }}}
}
- if (!is_file($descfile)) {
- return $this->raiseError("no package.xml file after extracting the archive");
+ $pkgname = $pkg->getName();
+ $channel = $pkg->getChannel();
+ if (isset($this->_options['packagingroot'])) {
+ $regdir = $this->_prependPath(
+ $this->config->get('php_dir', null, 'pear.php.net'),
+ $this->_options['packagingroot']);
+
+ $packrootphp_dir = $this->_prependPath(
+ $this->config->get('php_dir', null, $channel),
+ $this->_options['packagingroot']);
}
- // Parse xml file -----------------------------------------------
- $pkginfo = $this->infoFromDescriptionFile($descfile);
- if (PEAR::isError($pkginfo)) {
- return $pkginfo;
- }
- $this->validatePackageInfo($pkginfo, $errors, $warnings);
- // XXX We allow warnings, do we have to do it?
- if (count($errors)) {
- if (empty($options['force'])) {
- return $this->raiseError("The following errors where found (use force option to install anyway):\n".
- implode("\n", $errors));
+ if (isset($options['installroot'])) {
+ $this->config->setInstallRoot($options['installroot']);
+ $this->_registry = &$this->config->getRegistry();
+ $installregistry = &$this->_registry;
+ $this->installroot = ''; // all done automagically now
+ $php_dir = $this->config->get('php_dir', null, $channel);
+ } else {
+ $this->config->setInstallRoot(false);
+ $this->_registry = &$this->config->getRegistry();
+ if (isset($this->_options['packagingroot'])) {
+ $installregistry = &new PEAR_Registry($regdir);
+ if (!$installregistry->channelExists($channel, true)) {
+ // we need to fake a channel-discover of this channel
+ $chanobj = $this->_registry->getChannel($channel, true);
+ $installregistry->addChannel($chanobj);
+ }
+ $php_dir = $packrootphp_dir;
} else {
- $this->log(0, "warning : the following errors were found:\n".
- implode("\n", $errors));
+ $installregistry = &$this->_registry;
+ $php_dir = $this->config->get('php_dir', null, $channel);
}
+ $this->installroot = '';
}
- $pkgname = $pkginfo['package'];
+ // {{{ checks to do when not in "force" mode
+ if (empty($options['force']) &&
+ (file_exists($this->config->get('php_dir')) &&
+ is_dir($this->config->get('php_dir')))) {
+ $testp = $channel == 'pear.php.net' ? $pkgname : array($channel, $pkgname);
+ $instfilelist = $pkg->getInstallationFileList(true);
+ if (PEAR::isError($instfilelist)) {
+ return $instfilelist;
+ }
- // {{{ Check dependencies -------------------------------------------
- if (isset($pkginfo['release_deps']) && empty($options['nodeps'])) {
- $dep_errors = '';
- $error = $this->checkDeps($pkginfo, $dep_errors);
- if ($error == true) {
- if (empty($options['soft'])) {
- $this->log(0, substr($dep_errors, 1));
- }
- return $this->raiseError("$pkgname: Dependencies failed");
- } else if (!empty($dep_errors)) {
- // Print optional dependencies
- if (empty($options['soft'])) {
- $this->log(0, $dep_errors);
- }
+ // ensure we have the most accurate registry
+ $installregistry->flushFileMap();
+ $test = $installregistry->checkFileMap($instfilelist, $testp, '1.1');
+ if (PEAR::isError($test)) {
+ return $test;
}
- }
- // }}}
- // {{{ checks to do when not in "force" mode
- if (empty($options['force'])) {
- $test = $this->registry->checkFileMap($pkginfo);
if (sizeof($test)) {
- $tmp = $test;
- foreach ($tmp as $file => $pkg) {
- if ($pkg == $pkgname) {
- unset($test[$file]);
+ $pkgs = $this->getInstallPackages();
+ $found = false;
+ foreach ($pkgs as $param) {
+ if ($pkg->isSubpackageOf($param)) {
+ $found = true;
+ break;
}
}
- if (sizeof($test)) {
- $msg = "$pkgname: conflicting files found:\n";
+
+ if ($found) {
+ // subpackages can conflict with earlier versions of parent packages
+ $parentreg = $installregistry->packageInfo($param->getPackage(), null, $param->getChannel());
+ $tmp = $test;
+ foreach ($tmp as $file => $info) {
+ if (is_array($info)) {
+ if (strtolower($info[1]) == strtolower($param->getPackage()) &&
+ strtolower($info[0]) == strtolower($param->getChannel())
+ ) {
+ if (isset($parentreg['filelist'][$file])) {
+ unset($parentreg['filelist'][$file]);
+ } else{
+ $pos = strpos($file, '/');
+ $basedir = substr($file, 0, $pos);
+ $file2 = substr($file, $pos + 1);
+ if (isset($parentreg['filelist'][$file2]['baseinstalldir'])
+ && $parentreg['filelist'][$file2]['baseinstalldir'] === $basedir
+ ) {
+ unset($parentreg['filelist'][$file2]);
+ }
+ }
+
+ unset($test[$file]);
+ }
+ } else {
+ if (strtolower($param->getChannel()) != 'pear.php.net') {
+ continue;
+ }
+
+ if (strtolower($info) == strtolower($param->getPackage())) {
+ if (isset($parentreg['filelist'][$file])) {
+ unset($parentreg['filelist'][$file]);
+ } else{
+ $pos = strpos($file, '/');
+ $basedir = substr($file, 0, $pos);
+ $file2 = substr($file, $pos + 1);
+ if (isset($parentreg['filelist'][$file2]['baseinstalldir'])
+ && $parentreg['filelist'][$file2]['baseinstalldir'] === $basedir
+ ) {
+ unset($parentreg['filelist'][$file2]);
+ }
+ }
+
+ unset($test[$file]);
+ }
+ }
+ }
+
+ $pfk = &new PEAR_PackageFile($this->config);
+ $parentpkg = &$pfk->fromArray($parentreg);
+ $installregistry->updatePackage2($parentpkg);
+ }
+
+ if ($param->getChannel() == 'pecl.php.net' && isset($options['upgrade'])) {
+ $tmp = $test;
+ foreach ($tmp as $file => $info) {
+ if (is_string($info)) {
+ // pear.php.net packages are always stored as strings
+ if (strtolower($info) == strtolower($param->getPackage())) {
+ // upgrading existing package
+ unset($test[$file]);
+ }
+ }
+ }
+ }
+
+ if (count($test)) {
+ $msg = "$channel/$pkgname: conflicting files found:\n";
$longest = max(array_map("strlen", array_keys($test)));
$fmt = "%${longest}s (%s)\n";
- foreach ($test as $file => $pkg) {
- $msg .= sprintf($fmt, $file, $pkg);
+ foreach ($test as $file => $info) {
+ if (!is_array($info)) {
+ $info = array('pear.php.net', $info);
+ }
+ $info = $info[0] . '/' . $info[1];
+ $msg .= sprintf($fmt, $file, $info);
+ }
+
+ if (!isset($options['ignore-errors'])) {
+ return $this->raiseError($msg);
+ }
+
+ if (!isset($options['soft'])) {
+ $this->log(0, "WARNING: $msg");
}
- return $this->raiseError($msg);
}
}
}
@@ -715,165 +1315,310 @@ class PEAR_Installer extends PEAR_Downloader
$this->startFileTransaction();
- if (empty($options['upgrade'])) {
+ $usechannel = $channel;
+ if ($channel == 'pecl.php.net') {
+ $test = $installregistry->packageExists($pkgname, $channel);
+ if (!$test) {
+ $test = $installregistry->packageExists($pkgname, 'pear.php.net');
+ $usechannel = 'pear.php.net';
+ }
+ } else {
+ $test = $installregistry->packageExists($pkgname, $channel);
+ }
+
+ if (empty($options['upgrade']) && empty($options['soft'])) {
// checks to do only when installing new packages
- if (empty($options['force']) && $this->registry->packageExists($pkgname)) {
- return $this->raiseError("$pkgname already installed");
+ if (empty($options['force']) && $test) {
+ return $this->raiseError("$channel/$pkgname is already installed");
}
} else {
- if ($this->registry->packageExists($pkgname)) {
- $v1 = $this->registry->packageInfo($pkgname, 'version');
- $v2 = $pkginfo['version'];
+ // Upgrade
+ if ($test) {
+ $v1 = $installregistry->packageInfo($pkgname, 'version', $usechannel);
+ $v2 = $pkg->getVersion();
$cmp = version_compare("$v1", "$v2", 'gt');
if (empty($options['force']) && !version_compare("$v2", "$v1", 'gt')) {
return $this->raiseError("upgrade to a newer version ($v2 is not newer than $v1)");
}
- if (empty($options['register-only'])) {
- // when upgrading, remove old release's files first:
- if (PEAR::isError($err = $this->_deletePackageFiles($pkgname))) {
- return $this->raiseError($err);
- }
+ }
+ }
+
+ // Do cleanups for upgrade and install, remove old release's files first
+ if ($test && empty($options['register-only'])) {
+ // when upgrading, remove old release's files first:
+ if (PEAR::isError($err = $this->_deletePackageFiles($pkgname, $usechannel,
+ true))) {
+ if (!isset($options['ignore-errors'])) {
+ return $this->raiseError($err);
}
+
+ if (!isset($options['soft'])) {
+ $this->log(0, 'WARNING: ' . $err->getMessage());
+ }
+ } else {
+ $backedup = $err;
}
}
// {{{ Copy files to dest dir ---------------------------------------
// info from the package it self we want to access from _installFile
- $this->pkginfo = &$pkginfo;
+ $this->pkginfo = &$pkg;
// used to determine whether we should build any C code
$this->source_files = 0;
- if (empty($options['register-only'])) {
- if (!is_dir($php_dir)) {
- return $this->raiseError("no script destination directory\n",
- null, PEAR_ERROR_DIE);
+ $savechannel = $this->config->get('default_channel');
+ if (empty($options['register-only']) && !is_dir($php_dir)) {
+ if (PEAR::isError(System::mkdir(array('-p'), $php_dir))) {
+ return $this->raiseError("no installation destination directory '$php_dir'\n");
}
+ }
- $tmp_path = dirname($descfile);
- if (substr($pkgfile, -4) != '.xml') {
- $tmp_path .= DIRECTORY_SEPARATOR . $pkgname . '-' . $pkginfo['version'];
- }
+ if (substr($pkgfile, -4) != '.xml') {
+ $tmpdir .= DIRECTORY_SEPARATOR . $pkgname . '-' . $pkg->getVersion();
+ }
+
+ $this->configSet('default_channel', $channel);
+ // {{{ install files
+
+ $ver = $pkg->getPackagexmlVersion();
+ if (version_compare($ver, '2.0', '>=')) {
+ $filelist = $pkg->getInstallationFilelist();
+ } else {
+ $filelist = $pkg->getFileList();
+ }
+
+ if (PEAR::isError($filelist)) {
+ return $filelist;
+ }
- // ==> XXX This part should be removed later on
- if ($flag_old_format) {
- $tmp_path = dirname($descfile);
+ $p = &$installregistry->getPackage($pkgname, $channel);
+ $dirtree = (empty($options['register-only']) && $p) ? $p->getDirTree() : false;
+
+ $pkg->resetFilelist();
+ $pkg->setLastInstalledVersion($installregistry->packageInfo($pkg->getPackage(),
+ 'version', $pkg->getChannel()));
+ foreach ($filelist as $file => $atts) {
+ $this->expectError(PEAR_INSTALLER_FAILED);
+ if ($pkg->getPackagexmlVersion() == '1.0') {
+ $res = $this->_installFile($file, $atts, $tmpdir, $options);
+ } else {
+ $res = $this->_installFile2($pkg, $file, $atts, $tmpdir, $options);
}
- // <== XXX This part should be removed later on
-
- // {{{ install files
- foreach ($pkginfo['filelist'] as $file => $atts) {
- $this->expectError(PEAR_INSTALLER_FAILED);
- $res = $this->_installFile($file, $atts, $tmp_path, $options);
- $this->popExpect();
- if (PEAR::isError($res)) {
- if (empty($options['ignore-errors'])) {
- $this->rollbackFileTransaction();
- if ($res->getMessage() == "file does not exist") {
- $this->raiseError("file $file in package.xml does not exist");
- }
- return $this->raiseError($res);
- } else {
- $this->log(0, "Warning: " . $res->getMessage());
+ $this->popExpect();
+
+ if (PEAR::isError($res)) {
+ if (empty($options['ignore-errors'])) {
+ $this->rollbackFileTransaction();
+ if ($res->getMessage() == "file does not exist") {
+ $this->raiseError("file $file in package.xml does not exist");
}
+
+ return $this->raiseError($res);
}
- if ($res != PEAR_INSTALLER_OK) {
- // Do not register files that were not installed
- unset($pkginfo['filelist'][$file]);
+
+ if (!isset($options['soft'])) {
+ $this->log(0, "Warning: " . $res->getMessage());
}
}
- // }}}
- // {{{ compile and install source files
- if ($this->source_files > 0 && empty($options['nobuild'])) {
- $this->log(1, "$this->source_files source files, building");
- $bob = &new PEAR_Builder($this->ui);
- $bob->debug = $this->debug;
- $built = $bob->build($descfile, array(&$this, '_buildCallback'));
- if (PEAR::isError($built)) {
- $this->rollbackFileTransaction();
- return $built;
- }
- $this->log(1, "\nBuild process completed successfully");
- foreach ($built as $ext) {
- $bn = basename($ext['file']);
- list($_ext_name, $_ext_suff) = explode('.', $bn);
- if ($_ext_suff == '.so' || $_ext_suff == '.dll') {
- if (extension_loaded($_ext_name)) {
- $this->raiseError("Extension '$_ext_name' already loaded. " .
- 'Please unload it in your php.ini file ' .
- 'prior to install or upgrade');
- }
- $role = 'ext';
- } else {
- $role = 'src';
- }
- $dest = $ext['dest'];
- $this->log(1, "Installing '$ext[file]'");
- $copyto = $this->_prependPath($dest, $this->installroot);
- $copydir = dirname($copyto);
- if (!@is_dir($copydir)) {
- if (!$this->mkDirHier($copydir)) {
- return $this->raiseError("failed to mkdir $copydir",
- PEAR_INSTALLER_FAILED);
- }
- $this->log(3, "+ mkdir $copydir");
- }
- if (!@copy($ext['file'], $copyto)) {
- return $this->raiseError("failed to write $copyto", PEAR_INSTALLER_FAILED);
- }
- $this->log(3, "+ cp $ext[file] $copyto");
- if (!OS_WINDOWS) {
- $mode = 0666 & ~(int)octdec($this->config->get('umask'));
- $this->addFileOperation('chmod', array($mode, $copyto));
- if (!@chmod($copyto, $mode)) {
- $this->log(0, "failed to change mode of $copyto");
- }
- }
- $this->addFileOperation('rename', array($ext['file'], $copyto));
-
- $pkginfo['filelist'][$bn] = array(
- 'role' => $role,
- 'installed_as' => $dest,
- 'php_api' => $ext['php_api'],
- 'zend_mod_api' => $ext['zend_mod_api'],
- 'zend_ext_api' => $ext['zend_ext_api'],
- );
- }
+ $real = isset($atts['attribs']) ? $atts['attribs'] : $atts;
+ if ($res == PEAR_INSTALLER_OK && $real['role'] != 'src') {
+ // Register files that were installed
+ $pkg->installedFile($file, $atts);
}
- // }}}
+ }
+ // }}}
+
+ // {{{ compile and install source files
+ if ($this->source_files > 0 && empty($options['nobuild'])) {
+ if (PEAR::isError($err =
+ $this->_compileSourceFiles($savechannel, $pkg))) {
+ return $err;
+ }
+ }
+ // }}}
+
+ if (isset($backedup)) {
+ $this->_removeBackups($backedup);
}
if (!$this->commitFileTransaction()) {
$this->rollbackFileTransaction();
+ $this->configSet('default_channel', $savechannel);
return $this->raiseError("commit failed", PEAR_INSTALLER_FAILED);
}
// }}}
- $ret = false;
+ $ret = false;
+ $installphase = 'install';
+ $oldversion = false;
// {{{ Register that the package is installed -----------------------
if (empty($options['upgrade'])) {
// if 'force' is used, replace the info in registry
- if (!empty($options['force']) && $this->registry->packageExists($pkgname)) {
- $this->registry->deletePackage($pkgname);
+ $usechannel = $channel;
+ if ($channel == 'pecl.php.net') {
+ $test = $installregistry->packageExists($pkgname, $channel);
+ if (!$test) {
+ $test = $installregistry->packageExists($pkgname, 'pear.php.net');
+ $usechannel = 'pear.php.net';
+ }
+ } else {
+ $test = $installregistry->packageExists($pkgname, $channel);
+ }
+
+ if (!empty($options['force']) && $test) {
+ $oldversion = $installregistry->packageInfo($pkgname, 'version', $usechannel);
+ $installregistry->deletePackage($pkgname, $usechannel);
}
- $ret = $this->registry->addPackage($pkgname, $pkginfo);
+ $ret = $installregistry->addPackage2($pkg);
} else {
+ if ($dirtree) {
+ $this->startFileTransaction();
+ // attempt to delete empty directories
+ uksort($dirtree, array($this, '_sortDirs'));
+ foreach($dirtree as $dir => $notused) {
+ $this->addFileOperation('rmdir', array($dir));
+ }
+ $this->commitFileTransaction();
+ }
+
+ $usechannel = $channel;
+ if ($channel == 'pecl.php.net') {
+ $test = $installregistry->packageExists($pkgname, $channel);
+ if (!$test) {
+ $test = $installregistry->packageExists($pkgname, 'pear.php.net');
+ $usechannel = 'pear.php.net';
+ }
+ } else {
+ $test = $installregistry->packageExists($pkgname, $channel);
+ }
+
// new: upgrade installs a package if it isn't installed
- if (!$this->registry->packageExists($pkgname)) {
- $ret = $this->registry->addPackage($pkgname, $pkginfo);
+ if (!$test) {
+ $ret = $installregistry->addPackage2($pkg);
} else {
- $ret = $this->registry->updatePackage($pkgname, $pkginfo, false);
+ if ($usechannel != $channel) {
+ $installregistry->deletePackage($pkgname, $usechannel);
+ $ret = $installregistry->addPackage2($pkg);
+ } else {
+ $ret = $installregistry->updatePackage2($pkg);
+ }
+ $installphase = 'upgrade';
}
}
+
if (!$ret) {
- return $this->raiseError("Adding package $pkgname to registry failed");
+ $this->configSet('default_channel', $savechannel);
+ return $this->raiseError("Adding package $channel/$pkgname to registry failed");
}
// }}}
- return $pkginfo;
+
+ $this->configSet('default_channel', $savechannel);
+ if (class_exists('PEAR_Task_Common')) { // this is auto-included if any tasks exist
+ if (PEAR_Task_Common::hasPostinstallTasks()) {
+ PEAR_Task_Common::runPostinstallTasks($installphase);
+ }
+ }
+
+ return $pkg->toArray(true);
}
// }}}
+
+ // {{{ _compileSourceFiles()
+ /**
+ * @param string
+ * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+ */
+ function _compileSourceFiles($savechannel, &$filelist)
+ {
+ require_once 'PEAR/Builder.php';
+ $this->log(1, "$this->source_files source files, building");
+ $bob = &new PEAR_Builder($this->ui);
+ $bob->debug = $this->debug;
+ $built = $bob->build($filelist, array(&$this, '_buildCallback'));
+ if (PEAR::isError($built)) {
+ $this->rollbackFileTransaction();
+ $this->configSet('default_channel', $savechannel);
+ return $built;
+ }
+
+ $this->log(1, "\nBuild process completed successfully");
+ foreach ($built as $ext) {
+ $bn = basename($ext['file']);
+ list($_ext_name, $_ext_suff) = explode('.', $bn);
+ if ($_ext_suff == '.so' || $_ext_suff == '.dll') {
+ if (extension_loaded($_ext_name)) {
+ $this->raiseError("Extension '$_ext_name' already loaded. " .
+ 'Please unload it in your php.ini file ' .
+ 'prior to install or upgrade');
+ }
+ $role = 'ext';
+ } else {
+ $role = 'src';
+ }
+
+ $dest = $ext['dest'];
+ $packagingroot = '';
+ if (isset($this->_options['packagingroot'])) {
+ $packagingroot = $this->_options['packagingroot'];
+ }
+
+ $copyto = $this->_prependPath($dest, $packagingroot);
+ $extra = $copyto != $dest ? " as '$copyto'" : '';
+ $this->log(1, "Installing '$dest'$extra");
+
+ $copydir = dirname($copyto);
+ // pretty much nothing happens if we are only registering the install
+ if (empty($this->_options['register-only'])) {
+ if (!file_exists($copydir) || !is_dir($copydir)) {
+ if (!$this->mkDirHier($copydir)) {
+ return $this->raiseError("failed to mkdir $copydir",
+ PEAR_INSTALLER_FAILED);
+ }
+
+ $this->log(3, "+ mkdir $copydir");
+ }
+
+ if (!@copy($ext['file'], $copyto)) {
+ return $this->raiseError("failed to write $copyto ($php_errormsg)", PEAR_INSTALLER_FAILED);
+ }
+
+ $this->log(3, "+ cp $ext[file] $copyto");
+ $this->addFileOperation('rename', array($ext['file'], $copyto));
+ if (!OS_WINDOWS) {
+ $mode = 0666 & ~(int)octdec($this->config->get('umask'));
+ $this->addFileOperation('chmod', array($mode, $copyto));
+ if (!@chmod($copyto, $mode)) {
+ $this->log(0, "failed to change mode of $copyto ($php_errormsg)");
+ }
+ }
+ }
+
+
+ $data = array(
+ 'role' => $role,
+ 'name' => $bn,
+ 'installed_as' => $dest,
+ 'php_api' => $ext['php_api'],
+ 'zend_mod_api' => $ext['zend_mod_api'],
+ 'zend_ext_api' => $ext['zend_ext_api'],
+ );
+
+ if ($filelist->getPackageXmlVersion() == '1.0') {
+ $filelist->installedFile($bn, $data);
+ } else {
+ $filelist->installedFile($bn, array('attribs' => $data));
+ }
+ }
+ }
+
+ // }}}
+ function &getUninstallPackages()
+ {
+ return $this->_downloadedPackages;
+ }
// {{{ uninstall()
/**
@@ -885,63 +1630,172 @@ class PEAR_Installer extends PEAR_Downloader
* @param array Command-line options. Possibilities include:
*
* - installroot: base installation dir, if not the default
+ * - register-only : update registry but don't remove files
* - nodeps: do not process dependencies of other packages to ensure
* uninstallation does not break things
*/
function uninstall($package, $options = array())
{
- $php_dir = $this->config->get('php_dir');
- if (isset($options['installroot'])) {
- if (substr($options['installroot'], -1) == DIRECTORY_SEPARATOR) {
- $options['installroot'] = substr($options['installroot'], 0, -1);
- }
- $this->installroot = $options['installroot'];
- $php_dir = $this->_prependPath($php_dir, $this->installroot);
+ $installRoot = isset($options['installroot']) ? $options['installroot'] : '';
+ $this->config->setInstallRoot($installRoot);
+
+ $this->installroot = '';
+ $this->_registry = &$this->config->getRegistry();
+ if (is_object($package)) {
+ $channel = $package->getChannel();
+ $pkg = $package;
+ $package = $pkg->getPackage();
} else {
- $this->installroot = '';
+ $pkg = false;
+ $info = $this->_registry->parsePackageName($package,
+ $this->config->get('default_channel'));
+ $channel = $info['channel'];
+ $package = $info['package'];
}
- $this->registry = &new PEAR_Registry($php_dir);
- $filelist = $this->registry->packageInfo($package, 'filelist');
- if ($filelist == null) {
- return $this->raiseError("$package not installed");
+
+ $savechannel = $this->config->get('default_channel');
+ $this->configSet('default_channel', $channel);
+ if (!is_object($pkg)) {
+ $pkg = $this->_registry->getPackage($package, $channel);
+ }
+
+ if (!$pkg) {
+ $this->configSet('default_channel', $savechannel);
+ return $this->raiseError($this->_registry->parsedPackageNameToString(
+ array(
+ 'channel' => $channel,
+ 'package' => $package
+ ), true) . ' not installed');
+ }
+
+ if ($pkg->getInstalledBinary()) {
+ // this is just an alias for a binary package
+ return $this->_registry->deletePackage($package, $channel);
+ }
+
+ $filelist = $pkg->getFilelist();
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ if (!class_exists('PEAR_Dependency2')) {
+ require_once 'PEAR/Dependency2.php';
}
- if (empty($options['nodeps'])) {
- $depchecker = &new PEAR_Dependency($this->registry);
- $error = $depchecker->checkPackageUninstall($errors, $warning, $package);
- if ($error) {
- return $this->raiseError($errors . 'uninstall failed');
+
+ $depchecker = &new PEAR_Dependency2($this->config, $options,
+ array('channel' => $channel, 'package' => $package),
+ PEAR_VALIDATE_UNINSTALLING);
+ $e = $depchecker->validatePackageUninstall($this);
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($e)) {
+ if (!isset($options['ignore-errors'])) {
+ return $this->raiseError($e);
}
- if ($warning) {
- $this->log(0, $warning);
+
+ if (!isset($options['soft'])) {
+ $this->log(0, 'WARNING: ' . $e->getMessage());
+ }
+ } elseif (is_array($e)) {
+ if (!isset($options['soft'])) {
+ $this->log(0, $e[0]);
}
}
- // {{{ Delete the files
- $this->startFileTransaction();
- if (PEAR::isError($err = $this->_deletePackageFiles($package))) {
- $this->rollbackFileTransaction();
- return $this->raiseError($err);
- }
- if (!$this->commitFileTransaction()) {
- $this->rollbackFileTransaction();
- return $this->raiseError("uninstall failed");
- } else {
+
+ $this->pkginfo = &$pkg;
+ // pretty much nothing happens if we are only registering the uninstall
+ if (empty($options['register-only'])) {
+ // {{{ Delete the files
$this->startFileTransaction();
- if (!isset($filelist['dirtree']) || !count($filelist['dirtree'])) {
- return $this->registry->deletePackage($package);
- }
- // attempt to delete empty directories
- uksort($filelist['dirtree'], array($this, '_sortDirs'));
- foreach($filelist['dirtree'] as $dir => $notused) {
- $this->addFileOperation('rmdir', array($dir));
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ if (PEAR::isError($err = $this->_deletePackageFiles($package, $channel))) {
+ PEAR::popErrorHandling();
+ $this->rollbackFileTransaction();
+ $this->configSet('default_channel', $savechannel);
+ if (!isset($options['ignore-errors'])) {
+ return $this->raiseError($err);
+ }
+
+ if (!isset($options['soft'])) {
+ $this->log(0, 'WARNING: ' . $err->getMessage());
+ }
+ } else {
+ PEAR::popErrorHandling();
}
+
if (!$this->commitFileTransaction()) {
$this->rollbackFileTransaction();
+ if (!isset($options['ignore-errors'])) {
+ return $this->raiseError("uninstall failed");
+ }
+
+ if (!isset($options['soft'])) {
+ $this->log(0, 'WARNING: uninstall failed');
+ }
+ } else {
+ $this->startFileTransaction();
+ $dirtree = $pkg->getDirTree();
+ if ($dirtree === false) {
+ $this->configSet('default_channel', $savechannel);
+ return $this->_registry->deletePackage($package, $channel);
+ }
+
+ // attempt to delete empty directories
+ uksort($dirtree, array($this, '_sortDirs'));
+ foreach($dirtree as $dir => $notused) {
+ $this->addFileOperation('rmdir', array($dir));
+ }
+
+ if (!$this->commitFileTransaction()) {
+ $this->rollbackFileTransaction();
+ if (!isset($options['ignore-errors'])) {
+ return $this->raiseError("uninstall failed");
+ }
+
+ if (!isset($options['soft'])) {
+ $this->log(0, 'WARNING: uninstall failed');
+ }
+ }
}
+ // }}}
}
- // }}}
+ $this->configSet('default_channel', $savechannel);
// Register that the package is no longer installed
- return $this->registry->deletePackage($package);
+ return $this->_registry->deletePackage($package, $channel);
+ }
+
+ /**
+ * Sort a list of arrays of array(downloaded packagefilename) by dependency.
+ *
+ * It also removes duplicate dependencies
+ * @param array an array of PEAR_PackageFile_v[1/2] objects
+ * @return array|PEAR_Error array of array(packagefilename, package.xml contents)
+ */
+ function sortPackagesForUninstall(&$packages)
+ {
+ $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->config);
+ if (PEAR::isError($this->_dependencyDB)) {
+ return $this->_dependencyDB;
+ }
+ usort($packages, array(&$this, '_sortUninstall'));
+ }
+
+ function _sortUninstall($a, $b)
+ {
+ if (!$a->getDeps() && !$b->getDeps()) {
+ return 0; // neither package has dependencies, order is insignificant
+ }
+ if ($a->getDeps() && !$b->getDeps()) {
+ return -1; // $a must be installed after $b because $a has dependencies
+ }
+ if (!$a->getDeps() && $b->getDeps()) {
+ return 1; // $b must be installed after $a because $b has dependencies
+ }
+ // both packages have dependencies
+ if ($this->_dependencyDB->dependsOn($a, $b)) {
+ return -1;
+ }
+ if ($this->_dependencyDB->dependsOn($b, $a)) {
+ return 1;
+ }
+ return 0;
}
// }}}
@@ -954,92 +1808,7 @@ class PEAR_Installer extends PEAR_Downloader
}
// }}}
- // {{{ checkDeps()
-
- /**
- * Check if the package meets all dependencies
- *
- * @param array Package information (passed by reference)
- * @param string Error message (passed by reference)
- * @return boolean False when no error occured, otherwise true
- */
- function checkDeps(&$pkginfo, &$errors)
- {
- if (empty($this->registry)) {
- $this->registry = &new PEAR_Registry($this->config->get('php_dir'));
- }
- $depchecker = &new PEAR_Dependency($this->registry);
- $error = $errors = '';
- $failed_deps = $optional_deps = array();
- if (is_array($pkginfo['release_deps'])) {
- foreach($pkginfo['release_deps'] as $dep) {
- $code = $depchecker->callCheckMethod($error, $dep);
- if ($code) {
- if (isset($dep['optional']) && $dep['optional'] == 'yes') {
- $optional_deps[] = array($dep, $code, $error);
- } else {
- $failed_deps[] = array($dep, $code, $error);
- }
- }
- }
- // {{{ failed dependencies
- $n = count($failed_deps);
- if ($n > 0) {
- for ($i = 0; $i < $n; $i++) {
- if (isset($failed_deps[$i]['type'])) {
- $type = $failed_deps[$i]['type'];
- } else {
- $type = 'pkg';
- }
- switch ($failed_deps[$i][1]) {
- case PEAR_DEPENDENCY_MISSING:
- if ($type == 'pkg') {
- // install
- }
- $errors .= "\n" . $failed_deps[$i][2];
- break;
- case PEAR_DEPENDENCY_UPGRADE_MINOR:
- if ($type == 'pkg') {
- // upgrade
- }
- $errors .= "\n" . $failed_deps[$i][2];
- break;
- default:
- $errors .= "\n" . $failed_deps[$i][2];
- break;
- }
- }
- return true;
- }
- // }}}
- // {{{ optional dependencies
- $count_optional = count($optional_deps);
- if ($count_optional > 0) {
- $errors = "Optional dependencies:";
-
- for ($i = 0; $i < $count_optional; $i++) {
- if (isset($optional_deps[$i]['type'])) {
- $type = $optional_deps[$i]['type'];
- } else {
- $type = 'pkg';
- }
- switch ($optional_deps[$i][1]) {
- case PEAR_DEPENDENCY_MISSING:
- case PEAR_DEPENDENCY_UPGRADE_MINOR:
- default:
- $errors .= "\n" . $optional_deps[$i][2];
- break;
- }
- }
- return false;
- }
- // }}}
- }
- return false;
- }
-
- // }}}
// {{{ _buildCallback()
function _buildCallback($what, $data)
@@ -1051,18 +1820,4 @@ class PEAR_Installer extends PEAR_Downloader
}
// }}}
-}
-
-// {{{ md5_file() utility function
-if (!function_exists("md5_file")) {
- function md5_file($filename) {
- $fp = fopen($filename, "r");
- if (!$fp) return null;
- $contents = fread($fp, filesize($filename));
- fclose($fp);
- return md5($contents);
- }
-}
-// }}}
-
-?>
+} \ No newline at end of file