New file |
0,0 → 1,1291 |
<?php |
/** |
* PEAR_Dependency2, advanced dependency validation |
* |
* PHP versions 4 and 5 |
* |
* LICENSE: This source file is subject to version 3.0 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_0.txt. If you did not receive a copy of |
* the PHP License and are unable to obtain it through the web, please |
* send a note to license@php.net so we can mail you a copy immediately. |
* |
* @category pear |
* @package PEAR |
* @author Greg Beaver <cellog@php.net> |
* @copyright 1997-2006 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: Dependency2.php,v 1.54 2007/02/13 04:16:25 cellog Exp $ |
* @link http://pear.php.net/package/PEAR |
* @since File available since Release 1.4.0a1 |
*/ |
|
/** |
* Required for the PEAR_VALIDATE_* constants |
*/ |
require_once 'PEAR/Validate.php'; |
|
/** |
* Dependency check for PEAR packages |
* |
* This class handles both version 1.0 and 2.0 dependencies |
* WARNING: *any* changes to this class must be duplicated in the |
* test_PEAR_Dependency2 class found in tests/PEAR_Dependency2/setup.php.inc, |
* or unit tests will not actually validate the changes |
* @category pear |
* @package PEAR |
* @author Greg Beaver <cellog@php.net> |
* @copyright 1997-2006 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version Release: 1.5.1 |
* @link http://pear.php.net/package/PEAR |
* @since Class available since Release 1.4.0a1 |
*/ |
class PEAR_Dependency2 |
{ |
/** |
* One of the PEAR_VALIDATE_* states |
* @see PEAR_VALIDATE_NORMAL |
* @var integer |
*/ |
var $_state; |
/** |
* Command-line options to install/upgrade/uninstall commands |
* @param array |
*/ |
var $_options; |
/** |
* @var OS_Guess |
*/ |
var $_os; |
/** |
* @var PEAR_Registry |
*/ |
var $_registry; |
/** |
* @var PEAR_Config |
*/ |
var $_config; |
/** |
* @var PEAR_DependencyDB |
*/ |
var $_dependencydb; |
/** |
* Output of PEAR_Registry::parsedPackageName() |
* @var array |
*/ |
var $_currentPackage; |
/** |
* @param PEAR_Config |
* @param array installation options |
* @param array format of PEAR_Registry::parsedPackageName() |
* @param int installation state (one of PEAR_VALIDATE_*) |
*/ |
function PEAR_Dependency2(&$config, $installoptions, $package, |
$state = PEAR_VALIDATE_INSTALLING) |
{ |
$this->_config = &$config; |
if (!class_exists('PEAR_DependencyDB')) { |
require_once 'PEAR/DependencyDB.php'; |
} |
if (isset($installoptions['packagingroot'])) { |
// make sure depdb is in the right location |
$config->setInstallRoot($installoptions['packagingroot']); |
} |
$this->_registry = &$config->getRegistry(); |
$this->_dependencydb = &PEAR_DependencyDB::singleton($config); |
if (isset($installoptions['packagingroot'])) { |
$config->setInstallRoot(false); |
} |
$this->_options = $installoptions; |
$this->_state = $state; |
if (!class_exists('OS_Guess')) { |
require_once 'OS/Guess.php'; |
} |
$this->_os = new OS_Guess; |
$this->_currentPackage = $package; |
} |
|
function _getExtraString($dep) |
{ |
$extra = ' ('; |
if (isset($dep['uri'])) { |
return ''; |
} |
if (isset($dep['recommended'])) { |
$extra .= 'recommended version ' . $dep['recommended']; |
} else { |
if (isset($dep['min'])) { |
$extra .= 'version >= ' . $dep['min']; |
} |
if (isset($dep['max'])) { |
if ($extra != ' (') { |
$extra .= ', '; |
} |
$extra .= 'version <= ' . $dep['max']; |
} |
if (isset($dep['exclude'])) { |
if (!is_array($dep['exclude'])) { |
$dep['exclude'] = array($dep['exclude']); |
} |
if ($extra != ' (') { |
$extra .= ', '; |
} |
$extra .= 'excluded versions: '; |
foreach ($dep['exclude'] as $i => $exclude) { |
if ($i) { |
$extra .= ', '; |
} |
$extra .= $exclude; |
} |
} |
} |
$extra .= ')'; |
if ($extra == ' ()') { |
$extra = ''; |
} |
return $extra; |
} |
|
/** |
* This makes unit-testing a heck of a lot easier |
*/ |
function getPHP_OS() |
{ |
return PHP_OS; |
} |
|
/** |
* This makes unit-testing a heck of a lot easier |
*/ |
function getsysname() |
{ |
return $this->_os->getSysname(); |
} |
|
/** |
* Specify a dependency on an OS. Use arch for detailed os/processor information |
* |
* There are two generic OS dependencies that will be the most common, unix and windows. |
* Other options are linux, freebsd, darwin (OS X), sunos, irix, hpux, aix |
*/ |
function validateOsDependency($dep) |
{ |
if ($this->_state != PEAR_VALIDATE_INSTALLING && |
$this->_state != PEAR_VALIDATE_DOWNLOADING) { |
return true; |
} |
if (isset($dep['conflicts'])) { |
$not = true; |
} else { |
$not = false; |
} |
if ($dep['name'] == '*') { |
return true; |
} |
switch (strtolower($dep['name'])) { |
case 'windows' : |
if ($not) { |
if (strtolower(substr($this->getPHP_OS(), 0, 3)) == 'win') { |
if (!isset($this->_options['nodeps']) && |
!isset($this->_options['force'])) { |
return $this->raiseError("Cannot install %s on Windows"); |
} else { |
return $this->warning("warning: Cannot install %s on Windows"); |
} |
} |
} else { |
if (strtolower(substr($this->getPHP_OS(), 0, 3)) != 'win') { |
if (!isset($this->_options['nodeps']) && |
!isset($this->_options['force'])) { |
return $this->raiseError("Can only install %s on Windows"); |
} else { |
return $this->warning("warning: Can only install %s on Windows"); |
} |
} |
} |
break; |
case 'unix' : |
$unices = array('linux', 'freebsd', 'darwin', 'sunos', 'irix', 'hpux', 'aix'); |
if ($not) { |
if (in_array($this->getSysname(), $unices)) { |
if (!isset($this->_options['nodeps']) && |
!isset($this->_options['force'])) { |
return $this->raiseError("Cannot install %s on any Unix system"); |
} else { |
return $this->warning( |
"warning: Cannot install %s on any Unix system"); |
} |
} |
} else { |
if (!in_array($this->getSysname(), $unices)) { |
if (!isset($this->_options['nodeps']) && |
!isset($this->_options['force'])) { |
return $this->raiseError("Can only install %s on a Unix system"); |
} else { |
return $this->warning( |
"warning: Can only install %s on a Unix system"); |
} |
} |
} |
break; |
default : |
if ($not) { |
if (strtolower($dep['name']) == strtolower($this->getSysname())) { |
if (!isset($this->_options['nodeps']) && |
!isset($this->_options['force'])) { |
return $this->raiseError('Cannot install %s on ' . $dep['name'] . |
' operating system'); |
} else { |
return $this->warning('warning: Cannot install %s on ' . |
$dep['name'] . ' operating system'); |
} |
} |
} else { |
if (strtolower($dep['name']) != strtolower($this->getSysname())) { |
if (!isset($this->_options['nodeps']) && |
!isset($this->_options['force'])) { |
return $this->raiseError('Cannot install %s on ' . |
$this->getSysname() . |
' operating system, can only install on ' . $dep['name']); |
} else { |
return $this->warning('warning: Cannot install %s on ' . |
$this->getSysname() . |
' operating system, can only install on ' . $dep['name']); |
} |
} |
} |
} |
return true; |
} |
|
/** |
* This makes unit-testing a heck of a lot easier |
*/ |
function matchSignature($pattern) |
{ |
return $this->_os->matchSignature($pattern); |
} |
|
/** |
* Specify a complex dependency on an OS/processor/kernel version, |
* Use OS for simple operating system dependency. |
* |
* This is the only dependency that accepts an eregable pattern. The pattern |
* will be matched against the php_uname() output parsed by OS_Guess |
*/ |
function validateArchDependency($dep) |
{ |
if ($this->_state != PEAR_VALIDATE_INSTALLING) { |
return true; |
} |
if (isset($dep['conflicts'])) { |
$not = true; |
} else { |
$not = false; |
} |
if (!$this->matchSignature($dep['pattern'])) { |
if (!$not) { |
if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { |
return $this->raiseError('%s Architecture dependency failed, does not ' . |
'match "' . $dep['pattern'] . '"'); |
} else { |
return $this->warning('warning: %s Architecture dependency failed, does ' . |
'not match "' . $dep['pattern'] . '"'); |
} |
} |
return true; |
} else { |
if ($not) { |
if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { |
return $this->raiseError('%s Architecture dependency failed, required "' . |
$dep['pattern'] . '"'); |
} else { |
return $this->warning('warning: %s Architecture dependency failed, ' . |
'required "' . $dep['pattern'] . '"'); |
} |
} |
return true; |
} |
} |
|
/** |
* This makes unit-testing a heck of a lot easier |
*/ |
function extension_loaded($name) |
{ |
return extension_loaded($name); |
} |
|
/** |
* This makes unit-testing a heck of a lot easier |
*/ |
function phpversion($name = null) |
{ |
if ($name !== null) { |
return phpversion($name); |
} else { |
return phpversion(); |
} |
} |
|
function validateExtensionDependency($dep, $required = true) |
{ |
if ($this->_state != PEAR_VALIDATE_INSTALLING && |
$this->_state != PEAR_VALIDATE_DOWNLOADING) { |
return true; |
} |
$loaded = $this->extension_loaded($dep['name']); |
$extra = $this->_getExtraString($dep); |
if (isset($dep['exclude'])) { |
if (!is_array($dep['exclude'])) { |
$dep['exclude'] = array($dep['exclude']); |
} |
} |
if (!isset($dep['min']) && !isset($dep['max']) && |
!isset($dep['recommended']) && !isset($dep['exclude'])) { |
if ($loaded) { |
if (isset($dep['conflicts'])) { |
if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { |
return $this->raiseError('%s conflicts with PHP extension "' . |
$dep['name'] . '"' . $extra); |
} else { |
return $this->warning('warning: %s conflicts with PHP extension "' . |
$dep['name'] . '"' . $extra); |
} |
} |
return true; |
} else { |
if (isset($dep['conflicts'])) { |
return true; |
} |
if ($required) { |
if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { |
return $this->raiseError('%s requires PHP extension "' . |
$dep['name'] . '"' . $extra); |
} else { |
return $this->warning('warning: %s requires PHP extension "' . |
$dep['name'] . '"' . $extra); |
} |
} else { |
return $this->warning('%s can optionally use PHP extension "' . |
$dep['name'] . '"' . $extra); |
} |
} |
} |
if (!$loaded) { |
if (isset($dep['conflicts'])) { |
return true; |
} |
if (!$required) { |
return $this->warning('%s can optionally use PHP extension "' . |
$dep['name'] . '"' . $extra); |
} else { |
if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { |
return $this->raiseError('%s requires PHP extension "' . $dep['name'] . |
'"' . $extra); |
} |
return $this->warning('warning: %s requires PHP extension "' . $dep['name'] . |
'"' . $extra); |
} |
} |
$version = (string) $this->phpversion($dep['name']); |
if (empty($version)) { |
$version = '0'; |
} |
$fail = false; |
if (isset($dep['min'])) { |
if (!version_compare($version, $dep['min'], '>=')) { |
$fail = true; |
} |
} |
if (isset($dep['max'])) { |
if (!version_compare($version, $dep['max'], '<=')) { |
$fail = true; |
} |
} |
if ($fail && !isset($dep['conflicts'])) { |
if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { |
return $this->raiseError('%s requires PHP extension "' . $dep['name'] . |
'"' . $extra . ', installed version is ' . $version); |
} else { |
return $this->warning('warning: %s requires PHP extension "' . $dep['name'] . |
'"' . $extra . ', installed version is ' . $version); |
} |
} elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail && isset($dep['conflicts'])) { |
if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { |
return $this->raiseError('%s conflicts with PHP extension "' . |
$dep['name'] . '"' . $extra . ', installed version is ' . $version); |
} else { |
return $this->warning('warning: %s conflicts with PHP extension "' . |
$dep['name'] . '"' . $extra . ', installed version is ' . $version); |
} |
} |
if (isset($dep['exclude'])) { |
foreach ($dep['exclude'] as $exclude) { |
if (version_compare($version, $exclude, '==')) { |
if (isset($dep['conflicts'])) { |
continue; |
} |
if (!isset($this->_options['nodeps']) && |
!isset($this->_options['force'])) { |
return $this->raiseError('%s is not compatible with PHP extension "' . |
$dep['name'] . '" version ' . |
$exclude); |
} else { |
return $this->warning('warning: %s is not compatible with PHP extension "' . |
$dep['name'] . '" version ' . |
$exclude); |
} |
} elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) { |
if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { |
return $this->raiseError('%s conflicts with PHP extension "' . |
$dep['name'] . '"' . $extra . ', installed version is ' . $version); |
} else { |
return $this->warning('warning: %s conflicts with PHP extension "' . |
$dep['name'] . '"' . $extra . ', installed version is ' . $version); |
} |
} |
} |
} |
if (isset($dep['recommended'])) { |
if (version_compare($version, $dep['recommended'], '==')) { |
return true; |
} else { |
if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { |
return $this->raiseError('%s dependency: PHP extension ' . $dep['name'] . |
' version "' . $version . '"' . |
' is not the recommended version "' . $dep['recommended'] . |
'", but may be compatible, use --force to install'); |
} else { |
return $this->warning('warning: %s dependency: PHP extension ' . |
$dep['name'] . ' version "' . $version . '"' . |
' is not the recommended version "' . $dep['recommended'].'"'); |
} |
} |
} |
return true; |
} |
|
function validatePhpDependency($dep) |
{ |
if ($this->_state != PEAR_VALIDATE_INSTALLING && |
$this->_state != PEAR_VALIDATE_DOWNLOADING) { |
return true; |
} |
$version = $this->phpversion(); |
$extra = $this->_getExtraString($dep); |
if (isset($dep['exclude'])) { |
if (!is_array($dep['exclude'])) { |
$dep['exclude'] = array($dep['exclude']); |
} |
} |
if (isset($dep['min'])) { |
if (!version_compare($version, $dep['min'], '>=')) { |
if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { |
return $this->raiseError('%s requires PHP' . |
$extra . ', installed version is ' . $version); |
} else { |
return $this->warning('warning: %s requires PHP' . |
$extra . ', installed version is ' . $version); |
} |
} |
} |
if (isset($dep['max'])) { |
if (!version_compare($version, $dep['max'], '<=')) { |
if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { |
return $this->raiseError('%s requires PHP' . |
$extra . ', installed version is ' . $version); |
} else { |
return $this->warning('warning: %s requires PHP' . |
$extra . ', installed version is ' . $version); |
} |
} |
} |
if (isset($dep['exclude'])) { |
foreach ($dep['exclude'] as $exclude) { |
if (version_compare($version, $exclude, '==')) { |
if (!isset($this->_options['nodeps']) && |
!isset($this->_options['force'])) { |
return $this->raiseError('%s is not compatible with PHP version ' . |
$exclude); |
} else { |
return $this->warning( |
'warning: %s is not compatible with PHP version ' . |
$exclude); |
} |
} |
} |
} |
return true; |
} |
|
/** |
* This makes unit-testing a heck of a lot easier |
*/ |
function getPEARVersion() |
{ |
return '1.5.1'; |
} |
|
function validatePearinstallerDependency($dep) |
{ |
$pearversion = $this->getPEARVersion(); |
$extra = $this->_getExtraString($dep); |
if (isset($dep['exclude'])) { |
if (!is_array($dep['exclude'])) { |
$dep['exclude'] = array($dep['exclude']); |
} |
} |
if (version_compare($pearversion, $dep['min'], '<')) { |
if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { |
return $this->raiseError('%s requires PEAR Installer' . $extra . |
', installed version is ' . $pearversion); |
} else { |
return $this->warning('warning: %s requires PEAR Installer' . $extra . |
', installed version is ' . $pearversion); |
} |
} |
if (isset($dep['max'])) { |
if (version_compare($pearversion, $dep['max'], '>')) { |
if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { |
return $this->raiseError('%s requires PEAR Installer' . $extra . |
', installed version is ' . $pearversion); |
} else { |
return $this->warning('warning: %s requires PEAR Installer' . $extra . |
', installed version is ' . $pearversion); |
} |
} |
} |
if (isset($dep['exclude'])) { |
if (!isset($dep['exclude'][0])) { |
$dep['exclude'] = array($dep['exclude']); |
} |
foreach ($dep['exclude'] as $exclude) { |
if (version_compare($exclude, $pearversion, '==')) { |
if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { |
return $this->raiseError('%s is not compatible with PEAR Installer ' . |
'version ' . $exclude); |
} else { |
return $this->warning('warning: %s is not compatible with PEAR ' . |
'Installer version ' . $exclude); |
} |
} |
} |
} |
return true; |
} |
|
function validateSubpackageDependency($dep, $required, $params) |
{ |
return $this->validatePackageDependency($dep, $required, $params); |
} |
|
/** |
* @param array dependency information (2.0 format) |
* @param boolean whether this is a required dependency |
* @param array a list of downloaded packages to be installed, if any |
* @param boolean if true, then deps on pear.php.net that fail will also check |
* against pecl.php.net packages to accomodate extensions that have |
* moved to pecl.php.net from pear.php.net |
*/ |
function validatePackageDependency($dep, $required, $params, $depv1 = false) |
{ |
if ($this->_state != PEAR_VALIDATE_INSTALLING && |
$this->_state != PEAR_VALIDATE_DOWNLOADING) { |
return true; |
} |
if (isset($dep['providesextension'])) { |
if ($this->extension_loaded($dep['providesextension'])) { |
$save = $dep; |
$subdep = $dep; |
$subdep['name'] = $subdep['providesextension']; |
PEAR::pushErrorHandling(PEAR_ERROR_RETURN); |
$ret = $this->validateExtensionDependency($subdep, $required); |
PEAR::popErrorHandling(); |
if (!PEAR::isError($ret)) { |
return true; |
} |
} |
} |
if ($this->_state == PEAR_VALIDATE_INSTALLING) { |
return $this->_validatePackageInstall($dep, $required, $depv1); |
} |
if ($this->_state == PEAR_VALIDATE_DOWNLOADING) { |
return $this->_validatePackageDownload($dep, $required, $params, $depv1); |
} |
} |
|
function _validatePackageDownload($dep, $required, $params, $depv1 = false) |
{ |
$dep['package'] = $dep['name']; |
if (isset($dep['uri'])) { |
$dep['channel'] = '__uri'; |
} |
$depname = $this->_registry->parsedPackageNameToString($dep, true); |
$found = false; |
foreach ($params as $param) { |
if ($param->isEqual( |
array('package' => $dep['name'], |
'channel' => $dep['channel']))) { |
$found = true; |
break; |
} |
if ($depv1 && $dep['channel'] == 'pear.php.net') { |
if ($param->isEqual( |
array('package' => $dep['name'], |
'channel' => 'pecl.php.net'))) { |
$found = true; |
break; |
} |
} |
} |
if (!$found && isset($dep['providesextension'])) { |
foreach ($params as $param) { |
if ($param->isExtension($dep['providesextension'])) { |
$found = true; |
break; |
} |
} |
} |
if ($found) { |
$version = $param->getVersion(); |
$installed = false; |
$downloaded = true; |
} else { |
if ($this->_registry->packageExists($dep['name'], $dep['channel'])) { |
$installed = true; |
$downloaded = false; |
$version = $this->_registry->packageinfo($dep['name'], 'version', |
$dep['channel']); |
} else { |
if ($dep['channel'] == 'pecl.php.net' && $this->_registry->packageExists($dep['name'], |
'pear.php.net')) { |
$installed = true; |
$downloaded = false; |
$version = $this->_registry->packageinfo($dep['name'], 'version', |
'pear.php.net'); |
} else { |
$version = 'not installed or downloaded'; |
$installed = false; |
$downloaded = false; |
} |
} |
} |
$extra = $this->_getExtraString($dep); |
if (isset($dep['exclude'])) { |
if (!is_array($dep['exclude'])) { |
$dep['exclude'] = array($dep['exclude']); |
} |
} |
if (!isset($dep['min']) && !isset($dep['max']) && |
!isset($dep['recommended']) && !isset($dep['exclude'])) { |
if ($installed || $downloaded) { |
$installed = $installed ? 'installed' : 'downloaded'; |
if (isset($dep['conflicts'])) { |
if ($version) { |
$rest = ", $installed version is " . $version; |
} else { |
$rest = ''; |
} |
if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { |
return $this->raiseError('%s conflicts with package "' . $depname . '"' . |
$extra . $rest); |
} else { |
return $this->warning('warning: %s conflicts with package "' . $depname . '"' . |
$extra . $rest); |
} |
} |
return true; |
} else { |
if (isset($dep['conflicts'])) { |
return true; |
} |
if ($required) { |
if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { |
return $this->raiseError('%s requires package "' . $depname . '"' . |
$extra); |
} else { |
return $this->warning('warning: %s requires package "' . $depname . '"' . |
$extra); |
} |
} else { |
return $this->warning('%s can optionally use package "' . $depname . '"' . |
$extra); |
} |
} |
} |
if (!$installed && !$downloaded) { |
if (isset($dep['conflicts'])) { |
return true; |
} |
if ($required) { |
if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { |
return $this->raiseError('%s requires package "' . $depname . '"' . |
$extra); |
} else { |
return $this->warning('warning: %s requires package "' . $depname . '"' . |
$extra); |
} |
} else { |
return $this->warning('%s can optionally use package "' . $depname . '"' . |
$extra); |
} |
} |
$fail = false; |
if (isset($dep['min'])) { |
if (version_compare($version, $dep['min'], '<')) { |
$fail = true; |
} |
} |
if (isset($dep['max'])) { |
if (version_compare($version, $dep['max'], '>')) { |
$fail = true; |
} |
} |
if ($fail && !isset($dep['conflicts'])) { |
$installed = $installed ? 'installed' : 'downloaded'; |
$dep['package'] = $dep['name']; |
$dep = $this->_registry->parsedPackageNameToString($dep, true); |
if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { |
return $this->raiseError('%s requires package "' . $depname . '"' . |
$extra . ", $installed version is " . $version); |
} else { |
return $this->warning('warning: %s requires package "' . $depname . '"' . |
$extra . ", $installed version is " . $version); |
} |
} elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail && |
isset($dep['conflicts']) && !isset($dep['exclude'])) { |
$installed = $installed ? 'installed' : 'downloaded'; |
if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { |
return $this->raiseError('%s conflicts with package "' . $depname . '"' . $extra . |
", $installed version is " . $version); |
} else { |
return $this->warning('warning: %s conflicts with package "' . $depname . '"' . |
$extra . ", $installed version is " . $version); |
} |
} |
if (isset($dep['exclude'])) { |
$installed = $installed ? 'installed' : 'downloaded'; |
foreach ($dep['exclude'] as $exclude) { |
if (version_compare($version, $exclude, '==') && !isset($dep['conflicts'])) { |
if (!isset($this->_options['nodeps']) && |
!isset($this->_options['force'])) { |
return $this->raiseError('%s is not compatible with ' . |
$installed . ' package "' . |
$depname . '" version ' . |
$exclude); |
} else { |
return $this->warning('warning: %s is not compatible with ' . |
$installed . ' package "' . |
$depname . '" version ' . |
$exclude); |
} |
} elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) { |
$installed = $installed ? 'installed' : 'downloaded'; |
if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { |
return $this->raiseError('%s conflicts with package "' . $depname . '"' . |
$extra . ", $installed version is " . $version); |
} else { |
return $this->warning('warning: %s conflicts with package "' . $depname . '"' . |
$extra . ", $installed version is " . $version); |
} |
} |
} |
} |
if (isset($dep['recommended'])) { |
$installed = $installed ? 'installed' : 'downloaded'; |
if (version_compare($version, $dep['recommended'], '==')) { |
return true; |
} else { |
if (!$found && $installed) { |
$param = $this->_registry->getPackage($dep['name'], $dep['channel']); |
} |
if ($param) { |
$found = false; |
foreach ($params as $parent) { |
if ($parent->isEqual($this->_currentPackage)) { |
$found = true; |
break; |
} |
} |
if ($found) { |
if ($param->isCompatible($parent)) { |
return true; |
} |
} else { // this is for validPackage() calls |
$parent = $this->_registry->getPackage($this->_currentPackage['package'], |
$this->_currentPackage['channel']); |
if ($parent !== null) { |
if ($param->isCompatible($parent)) { |
return true; |
} |
} |
} |
} |
if (!isset($this->_options['nodeps']) && !isset($this->_options['force']) && |
!isset($this->_options['loose'])) { |
return $this->raiseError('%s dependency package "' . $depname . |
'" ' . $installed . ' version ' . $version . |
' is not the recommended version ' . $dep['recommended'] . |
', but may be compatible, use --force to install'); |
} else { |
return $this->warning('warning: %s dependency package "' . $depname . |
'" ' . $installed . ' version ' . $version . |
' is not the recommended version ' . $dep['recommended']); |
} |
} |
} |
return true; |
} |
|
function _validatePackageInstall($dep, $required, $depv1 = false) |
{ |
return $this->_validatePackageDownload($dep, $required, array(), $depv1); |
} |
|
/** |
* Verify that uninstalling packages passed in to command line is OK. |
* |
* @param PEAR_Installer $dl |
* @return PEAR_Error|true |
*/ |
function validatePackageUninstall(&$dl) |
{ |
if (PEAR::isError($this->_dependencydb)) { |
return $this->_dependencydb; |
} |
$params = array(); |
// construct an array of "downloaded" packages to fool the package dependency checker |
// into using these to validate uninstalls of circular dependencies |
$downloaded = &$dl->getUninstallPackages(); |
foreach ($downloaded as $i => $pf) { |
if (!class_exists('PEAR_Downloader_Package')) { |
require_once 'PEAR/Downloader/Package.php'; |
} |
$dp = &new PEAR_Downloader_Package($dl); |
$dp->setPackageFile($downloaded[$i]); |
$params[$i] = &$dp; |
} |
// check cache |
$memyselfandI = strtolower($this->_currentPackage['channel']) . '/' . |
strtolower($this->_currentPackage['package']); |
if (isset($dl->___uninstall_package_cache)) { |
$badpackages = $dl->___uninstall_package_cache; |
if (isset($badpackages[$memyselfandI]['warnings'])) { |
foreach ($badpackages[$memyselfandI]['warnings'] as $warning) { |
$dl->log(0, $warning[0]); |
} |
} |
if (isset($badpackages[$memyselfandI]['errors'])) { |
foreach ($badpackages[$memyselfandI]['errors'] as $error) { |
$dl->log(0, $error->getMessage()); |
} |
if (isset($this->_options['nodeps']) || isset($this->_options['force'])) { |
return $this->warning( |
'warning: %s should not be uninstalled, other installed packages depend ' . |
'on this package'); |
} else { |
return $this->raiseError( |
'%s cannot be uninstalled, other installed packages depend on this package'); |
} |
} |
return true; |
} |
// first, list the immediate parents of each package to be uninstalled |
$perpackagelist = array(); |
$allparents = array(); |
foreach ($params as $i => $param) { |
$a = array('channel' => strtolower($param->getChannel()), |
'package' => strtolower($param->getPackage())); |
$deps = $this->_dependencydb->getDependentPackages($a); |
if ($deps) { |
foreach ($deps as $d) { |
$pardeps = $this->_dependencydb->getDependencies($d); |
foreach ($pardeps as $dep) { |
if (strtolower($dep['dep']['channel']) == $a['channel'] && |
strtolower($dep['dep']['name']) == $a['package']) { |
if (!isset($perpackagelist[$a['channel'] . '/' . $a['package']])) { |
$perpackagelist[$a['channel'] . '/' . $a['package']] = array(); |
} |
$perpackagelist[$a['channel'] . '/' . $a['package']][] |
= array($d['channel'] . '/' . $d['package'], $dep); |
if (!isset($allparents[$d['channel'] . '/' . $d['package']])) { |
$allparents[$d['channel'] . '/' . $d['package']] = array(); |
} |
if (!isset($allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']])) { |
$allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']] = array(); |
} |
$allparents[$d['channel'] . '/' . $d['package']] |
[$a['channel'] . '/' . $a['package']][] |
= array($d, $dep); |
} |
} |
} |
} |
} |
// next, remove any packages from the parents list that are not installed |
$remove = array(); |
foreach ($allparents as $parent => $d1) { |
foreach ($d1 as $d) { |
if ($this->_registry->packageExists($d[0][0]['package'], $d[0][0]['channel'])) { |
continue; |
} |
$remove[$parent] = true; |
} |
} |
// next remove any packages from the parents list that are not passed in for |
// uninstallation |
foreach ($allparents as $parent => $d1) { |
foreach ($d1 as $d) { |
foreach ($params as $param) { |
if (strtolower($param->getChannel()) == $d[0][0]['channel'] && |
strtolower($param->getPackage()) == $d[0][0]['package']) { |
// found it |
continue 3; |
} |
} |
$remove[$parent] = true; |
} |
} |
// remove all packages whose dependencies fail |
// save which ones failed for error reporting |
$badchildren = array(); |
do { |
$fail = false; |
foreach ($remove as $package => $unused) { |
if (!isset($allparents[$package])) { |
continue; |
} |
foreach ($allparents[$package] as $kid => $d1) { |
foreach ($d1 as $depinfo) { |
if ($depinfo[1]['type'] != 'optional') { |
if (isset($badchildren[$kid])) { |
continue; |
} |
$badchildren[$kid] = true; |
$remove[$kid] = true; |
$fail = true; |
continue 2; |
} |
} |
} |
if ($fail) { |
// start over, we removed some children |
continue 2; |
} |
} |
} while ($fail); |
// next, construct the list of packages that can't be uninstalled |
$badpackages = array(); |
$save = $this->_currentPackage; |
foreach ($perpackagelist as $package => $packagedeps) { |
foreach ($packagedeps as $parent) { |
if (!isset($remove[$parent[0]])) { |
continue; |
} |
$packagename = $this->_registry->parsePackageName($parent[0]); |
$packagename['channel'] = $this->_registry->channelAlias($packagename['channel']); |
$pa = $this->_registry->getPackage($packagename['package'], $packagename['channel']); |
$packagename['package'] = $pa->getPackage(); |
$this->_currentPackage = $packagename; |
// parent is not present in uninstall list, make sure we can actually |
// uninstall it (parent dep is optional) |
$parentname['channel'] = $this->_registry->channelAlias($parent[1]['dep']['channel']); |
$pa = $this->_registry->getPackage($parent[1]['dep']['name'], $parent[1]['dep']['channel']); |
$parentname['package'] = $pa->getPackage(); |
$parent[1]['dep']['package'] = $parentname['package']; |
$parent[1]['dep']['channel'] = $parentname['channel']; |
if ($parent[1]['type'] == 'optional') { |
$test = $this->_validatePackageUninstall($parent[1]['dep'], false, $dl); |
if ($test !== true) { |
$badpackages[$package]['warnings'][] = $test; |
} |
} else { |
$test = $this->_validatePackageUninstall($parent[1]['dep'], true, $dl); |
if ($test !== true) { |
$badpackages[$package]['errors'][] = $test; |
} |
} |
} |
} |
$this->_currentPackage = $save; |
$dl->___uninstall_package_cache = $badpackages; |
if (isset($badpackages[$memyselfandI])) { |
if (isset($badpackages[$memyselfandI]['warnings'])) { |
foreach ($badpackages[$memyselfandI]['warnings'] as $warning) { |
$dl->log(0, $warning[0]); |
} |
} |
if (isset($badpackages[$memyselfandI]['errors'])) { |
foreach ($badpackages[$memyselfandI]['errors'] as $error) { |
$dl->log(0, $error->getMessage()); |
} |
if (isset($this->_options['nodeps']) || isset($this->_options['force'])) { |
return $this->warning( |
'warning: %s should not be uninstalled, other installed packages depend ' . |
'on this package'); |
} else { |
return $this->raiseError( |
'%s cannot be uninstalled, other installed packages depend on this package'); |
} |
} |
} |
return true; |
} |
|
function _validatePackageUninstall($dep, $required, $dl) |
{ |
$depname = $this->_registry->parsedPackageNameToString($dep, true); |
$version = $this->_registry->packageinfo($dep['package'], 'version', |
$dep['channel']); |
if (!$version) { |
return true; |
} |
$extra = $this->_getExtraString($dep); |
if (isset($dep['exclude'])) { |
if (!is_array($dep['exclude'])) { |
$dep['exclude'] = array($dep['exclude']); |
} |
} |
if (isset($dep['conflicts'])) { |
return true; // uninstall OK - these packages conflict (probably installed with --force) |
} |
if (!isset($dep['min']) && !isset($dep['max'])) { |
if ($required) { |
if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { |
return $this->raiseError('"' . $depname . '" is required by ' . |
'installed package %s' . $extra); |
} else { |
return $this->warning('warning: "' . $depname . '" is required by ' . |
'installed package %s' . $extra); |
} |
} else { |
return $this->warning('"' . $depname . '" can be optionally used by ' . |
'installed package %s' . $extra); |
} |
} |
$fail = false; |
if (isset($dep['min'])) { |
if (version_compare($version, $dep['min'], '>=')) { |
$fail = true; |
} |
} |
if (isset($dep['max'])) { |
if (version_compare($version, $dep['max'], '<=')) { |
$fail = true; |
} |
} |
// we re-use this variable, preserve the original value |
$saverequired = $required; |
if ($required) { |
if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { |
return $this->raiseError($depname . $extra . ' is required by installed package' . |
' "%s"'); |
} else { |
return $this->raiseError('warning: ' . $depname . $extra . |
' is required by installed package "%s"'); |
} |
} else { |
return $this->warning($depname . $extra . ' can be optionally used by installed package' . |
' "%s"'); |
} |
return true; |
} |
|
/** |
* validate a downloaded package against installed packages |
* |
* As of PEAR 1.4.3, this will only validate |
* |
* @param array|PEAR_Downloader_Package|PEAR_PackageFile_v1|PEAR_PackageFile_v2 |
* $pkg package identifier (either |
* array('package' => blah, 'channel' => blah) or an array with |
* index 'info' referencing an object) |
* @param PEAR_Downloader $dl |
* @param array $params full list of packages to install |
* @return true|PEAR_Error |
*/ |
function validatePackage($pkg, &$dl, $params = array()) |
{ |
if (is_array($pkg) && isset($pkg['info'])) { |
$deps = $this->_dependencydb->getDependentPackageDependencies($pkg['info']); |
} else { |
$deps = $this->_dependencydb->getDependentPackageDependencies($pkg); |
} |
$fail = false; |
if ($deps) { |
if (!class_exists('PEAR_Downloader_Package')) { |
require_once 'PEAR/Downloader/Package.php'; |
} |
$dp = &new PEAR_Downloader_Package($dl); |
if (is_object($pkg)) { |
$dp->setPackageFile($pkg); |
} else { |
$dp->setDownloadURL($pkg); |
} |
PEAR::pushErrorHandling(PEAR_ERROR_RETURN); |
foreach ($deps as $channel => $info) { |
foreach ($info as $package => $ds) { |
foreach ($params as $packd) { |
if (strtolower($packd->getPackage()) == strtolower($package) && |
$packd->getChannel() == $channel) { |
$dl->log(3, 'skipping installed package check of "' . |
$this->_registry->parsedPackageNameToString( |
array('channel' => $channel, 'package' => $package), |
true) . |
'", version "' . $packd->getVersion() . '" will be ' . |
'downloaded and installed'); |
continue 2; // jump to next package |
} |
} |
foreach ($ds as $d) { |
$checker = &new PEAR_Dependency2($this->_config, $this->_options, |
array('channel' => $channel, 'package' => $package), $this->_state); |
$dep = $d['dep']; |
$required = $d['type'] == 'required'; |
$ret = $checker->_validatePackageDownload($dep, $required, array(&$dp)); |
if (is_array($ret)) { |
$dl->log(0, $ret[0]); |
} elseif (PEAR::isError($ret)) { |
$dl->log(0, $ret->getMessage()); |
$fail = true; |
} |
} |
} |
} |
PEAR::popErrorHandling(); |
} |
if ($fail) { |
return $this->raiseError( |
'%s cannot be installed, conflicts with installed packages'); |
} |
return true; |
} |
|
/** |
* validate a package.xml 1.0 dependency |
*/ |
function validateDependency1($dep, $params = array()) |
{ |
if (!isset($dep['optional'])) { |
$dep['optional'] = 'no'; |
} |
list($newdep, $type) = $this->normalizeDep($dep); |
if (!$newdep) { |
return $this->raiseError("Invalid Dependency"); |
} |
if (method_exists($this, "validate{$type}Dependency")) { |
return $this->{"validate{$type}Dependency"}($newdep, $dep['optional'] == 'no', |
$params, true); |
} |
} |
|
/** |
* Convert a 1.0 dep into a 2.0 dep |
*/ |
function normalizeDep($dep) |
{ |
$types = array( |
'pkg' => 'Package', |
'ext' => 'Extension', |
'os' => 'Os', |
'php' => 'Php' |
); |
if (isset($types[$dep['type']])) { |
$type = $types[$dep['type']]; |
} else { |
return array(false, false); |
} |
$newdep = array(); |
switch ($type) { |
case 'Package' : |
$newdep['channel'] = 'pear.php.net'; |
case 'Extension' : |
case 'Os' : |
$newdep['name'] = $dep['name']; |
break; |
} |
$dep['rel'] = PEAR_Dependency2::signOperator($dep['rel']); |
switch ($dep['rel']) { |
case 'has' : |
return array($newdep, $type); |
break; |
case 'not' : |
$newdep['conflicts'] = true; |
break; |
case '>=' : |
case '>' : |
$newdep['min'] = $dep['version']; |
if ($dep['rel'] == '>') { |
$newdep['exclude'] = $dep['version']; |
} |
break; |
case '<=' : |
case '<' : |
$newdep['max'] = $dep['version']; |
if ($dep['rel'] == '<') { |
$newdep['exclude'] = $dep['version']; |
} |
break; |
case 'ne' : |
case '!=' : |
$newdep['min'] = '0'; |
$newdep['max'] = '100000'; |
$newdep['exclude'] = $dep['version']; |
break; |
case '==' : |
$newdep['min'] = $dep['version']; |
$newdep['max'] = $dep['version']; |
break; |
} |
if ($type == 'Php') { |
if (!isset($newdep['min'])) { |
$newdep['min'] = '4.2.0'; |
} |
if (!isset($newdep['max'])) { |
$newdep['max'] = '6.0.0'; |
} |
} |
return array($newdep, $type); |
} |
|
/** |
* Converts text comparing operators to them sign equivalents |
* |
* Example: 'ge' to '>=' |
* |
* @access public |
* @param string Operator |
* @return string Sign equivalent |
*/ |
function signOperator($operator) |
{ |
switch($operator) { |
case 'lt': return '<'; |
case 'le': return '<='; |
case 'gt': return '>'; |
case 'ge': return '>='; |
case 'eq': return '=='; |
case 'ne': return '!='; |
default: |
return $operator; |
} |
} |
|
function raiseError($msg) |
{ |
if (isset($this->_options['ignore-errors'])) { |
return $this->warning($msg); |
} |
return PEAR::raiseError(sprintf($msg, $this->_registry->parsedPackageNameToString( |
$this->_currentPackage, true))); |
} |
|
function warning($msg) |
{ |
return array(sprintf($msg, $this->_registry->parsedPackageNameToString( |
$this->_currentPackage, true))); |
} |
} |
?> |