New file |
0,0 → 1,1981 |
<?php |
/** |
* PEAR_Downloader_Package |
* |
* PHP versions 4 and 5 |
* |
* @category pear |
* @package PEAR |
* @author Greg Beaver <cellog@php.net> |
* @copyright 1997-2009 The Authors |
* @license http://opensource.org/licenses/bsd-license.php New BSD License |
* @link http://pear.php.net/package/PEAR |
* @since File available since Release 1.4.0a1 |
*/ |
|
/** |
* Error code when parameter initialization fails because no releases |
* exist within preferred_state, but releases do exist |
*/ |
define('PEAR_DOWNLOADER_PACKAGE_STATE', -1003); |
/** |
* Error code when parameter initialization fails because no releases |
* exist that will work with the existing PHP version |
*/ |
define('PEAR_DOWNLOADER_PACKAGE_PHPVERSION', -1004); |
|
/** |
* Coordinates download parameters and manages their dependencies |
* prior to downloading them. |
* |
* Input can come from three sources: |
* |
* - local files (archives or package.xml) |
* - remote files (downloadable urls) |
* - abstract package names |
* |
* The first two elements are handled cleanly by PEAR_PackageFile, but the third requires |
* accessing pearweb's xml-rpc interface to determine necessary dependencies, and the |
* format returned of dependencies is slightly different from that used in package.xml. |
* |
* This class hides the differences between these elements, and makes automatic |
* dependency resolution a piece of cake. It also manages conflicts when |
* two classes depend on incompatible dependencies, or differing versions of the same |
* package dependency. In addition, download will not be attempted if the php version is |
* not supported, PEAR installer version is not supported, or non-PECL extensions are not |
* installed. |
* @category pear |
* @package PEAR |
* @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.10.1 |
* @link http://pear.php.net/package/PEAR |
* @since Class available since Release 1.4.0a1 |
*/ |
class PEAR_Downloader_Package |
{ |
/** |
* @var PEAR_Downloader |
*/ |
var $_downloader; |
/** |
* @var PEAR_Config |
*/ |
var $_config; |
/** |
* @var PEAR_Registry |
*/ |
var $_registry; |
/** |
* Used to implement packagingroot properly |
* @var PEAR_Registry |
*/ |
var $_installRegistry; |
/** |
* @var PEAR_PackageFile_v1|PEAR_PackageFile|v2 |
*/ |
var $_packagefile; |
/** |
* @var array |
*/ |
var $_parsedname; |
/** |
* @var array |
*/ |
var $_downloadURL; |
/** |
* @var array |
*/ |
var $_downloadDeps = array(); |
/** |
* @var boolean |
*/ |
var $_valid = false; |
/** |
* @var boolean |
*/ |
var $_analyzed = false; |
/** |
* if this or a parent package was invoked with Package-state, this is set to the |
* state variable. |
* |
* This allows temporary reassignment of preferred_state for a parent package and all of |
* its dependencies. |
* @var string|false |
*/ |
var $_explicitState = false; |
/** |
* If this package is invoked with Package#group, this variable will be true |
*/ |
var $_explicitGroup = false; |
/** |
* Package type local|url |
* @var string |
*/ |
var $_type; |
/** |
* Contents of package.xml, if downloaded from a remote channel |
* @var string|false |
* @access private |
*/ |
var $_rawpackagefile; |
/** |
* @var boolean |
* @access private |
*/ |
var $_validated = false; |
|
/** |
* @param PEAR_Downloader |
*/ |
function __construct(&$downloader) |
{ |
$this->_downloader = &$downloader; |
$this->_config = &$this->_downloader->config; |
$this->_registry = &$this->_config->getRegistry(); |
$options = $downloader->getOptions(); |
if (isset($options['packagingroot'])) { |
$this->_config->setInstallRoot($options['packagingroot']); |
$this->_installRegistry = &$this->_config->getRegistry(); |
$this->_config->setInstallRoot(false); |
} else { |
$this->_installRegistry = &$this->_registry; |
} |
$this->_valid = $this->_analyzed = false; |
} |
|
/** |
* Parse the input and determine whether this is a local file, a remote uri, or an |
* abstract package name. |
* |
* This is the heart of the PEAR_Downloader_Package(), and is used in |
* {@link PEAR_Downloader::download()} |
* @param string |
* @return bool|PEAR_Error |
*/ |
function initialize($param) |
{ |
$origErr = $this->_fromFile($param); |
if ($this->_valid) { |
return true; |
} |
|
$options = $this->_downloader->getOptions(); |
if (isset($options['offline'])) { |
if (PEAR::isError($origErr) && !isset($options['soft'])) { |
foreach ($origErr->getUserInfo() as $userInfo) { |
if (isset($userInfo['message'])) { |
$this->_downloader->log(0, $userInfo['message']); |
} |
} |
|
$this->_downloader->log(0, $origErr->getMessage()); |
} |
|
return PEAR::raiseError('Cannot download non-local package "' . $param . '"'); |
} |
|
$err = $this->_fromUrl($param); |
if (PEAR::isError($err) || !$this->_valid) { |
if ($this->_type == 'url') { |
if (PEAR::isError($err) && !isset($options['soft'])) { |
$this->_downloader->log(0, $err->getMessage()); |
} |
|
return PEAR::raiseError("Invalid or missing remote package file"); |
} |
|
$err = $this->_fromString($param); |
if (PEAR::isError($err) || !$this->_valid) { |
if (PEAR::isError($err) && $err->getCode() == PEAR_DOWNLOADER_PACKAGE_STATE) { |
return false; // instruct the downloader to silently skip |
} |
|
if (isset($this->_type) && $this->_type == 'local' && PEAR::isError($origErr)) { |
if (is_array($origErr->getUserInfo())) { |
foreach ($origErr->getUserInfo() as $err) { |
if (is_array($err)) { |
$err = $err['message']; |
} |
|
if (!isset($options['soft'])) { |
$this->_downloader->log(0, $err); |
} |
} |
} |
|
if (!isset($options['soft'])) { |
$this->_downloader->log(0, $origErr->getMessage()); |
} |
|
if (is_array($param)) { |
$param = $this->_registry->parsedPackageNameToString($param, true); |
} |
|
if (!isset($options['soft'])) { |
$this->_downloader->log(2, "Cannot initialize '$param', invalid or missing package file"); |
} |
|
// Passing no message back - already logged above |
return PEAR::raiseError(); |
} |
|
if (PEAR::isError($err) && !isset($options['soft'])) { |
$this->_downloader->log(0, $err->getMessage()); |
} |
|
if (is_array($param)) { |
$param = $this->_registry->parsedPackageNameToString($param, true); |
} |
|
if (!isset($options['soft'])) { |
$this->_downloader->log(2, "Cannot initialize '$param', invalid or missing package file"); |
} |
|
// Passing no message back - already logged above |
return PEAR::raiseError(); |
} |
} |
|
return true; |
} |
|
/** |
* Retrieve any non-local packages |
* @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|PEAR_Error |
*/ |
function &download() |
{ |
if (isset($this->_packagefile)) { |
return $this->_packagefile; |
} |
|
if (isset($this->_downloadURL['url'])) { |
$this->_isvalid = false; |
$info = $this->getParsedPackage(); |
foreach ($info as $i => $p) { |
$info[$i] = strtolower($p); |
} |
|
$err = $this->_fromUrl($this->_downloadURL['url'], |
$this->_registry->parsedPackageNameToString($this->_parsedname, true)); |
$newinfo = $this->getParsedPackage(); |
foreach ($newinfo as $i => $p) { |
$newinfo[$i] = strtolower($p); |
} |
|
if ($info != $newinfo) { |
do { |
if ($info['channel'] == 'pecl.php.net' && $newinfo['channel'] == 'pear.php.net') { |
$info['channel'] = 'pear.php.net'; |
if ($info == $newinfo) { |
// skip the channel check if a pecl package says it's a PEAR package |
break; |
} |
} |
if ($info['channel'] == 'pear.php.net' && $newinfo['channel'] == 'pecl.php.net') { |
$info['channel'] = 'pecl.php.net'; |
if ($info == $newinfo) { |
// skip the channel check if a pecl package says it's a PEAR package |
break; |
} |
} |
|
return PEAR::raiseError('CRITICAL ERROR: We are ' . |
$this->_registry->parsedPackageNameToString($info) . ', but the file ' . |
'downloaded claims to be ' . |
$this->_registry->parsedPackageNameToString($this->getParsedPackage())); |
} while (false); |
} |
|
if (PEAR::isError($err) || !$this->_valid) { |
return $err; |
} |
} |
|
$this->_type = 'local'; |
return $this->_packagefile; |
} |
|
function &getPackageFile() |
{ |
return $this->_packagefile; |
} |
|
function &getDownloader() |
{ |
return $this->_downloader; |
} |
|
function getType() |
{ |
return $this->_type; |
} |
|
/** |
* Like {@link initialize()}, but operates on a dependency |
*/ |
function fromDepURL($dep) |
{ |
$this->_downloadURL = $dep; |
if (isset($dep['uri'])) { |
$options = $this->_downloader->getOptions(); |
if (!extension_loaded("zlib") || isset($options['nocompress'])) { |
$ext = '.tar'; |
} else { |
$ext = '.tgz'; |
} |
|
PEAR::pushErrorHandling(PEAR_ERROR_RETURN); |
$err = $this->_fromUrl($dep['uri'] . $ext); |
PEAR::popErrorHandling(); |
if (PEAR::isError($err)) { |
if (!isset($options['soft'])) { |
$this->_downloader->log(0, $err->getMessage()); |
} |
|
return PEAR::raiseError('Invalid uri dependency "' . $dep['uri'] . $ext . '", ' . |
'cannot download'); |
} |
} else { |
$this->_parsedname = |
array( |
'package' => $dep['info']->getPackage(), |
'channel' => $dep['info']->getChannel(), |
'version' => $dep['version'] |
); |
if (!isset($dep['nodefault'])) { |
$this->_parsedname['group'] = 'default'; // download the default dependency group |
$this->_explicitGroup = false; |
} |
|
$this->_rawpackagefile = $dep['raw']; |
} |
} |
|
function detectDependencies($params) |
{ |
$options = $this->_downloader->getOptions(); |
if (isset($options['downloadonly'])) { |
return; |
} |
|
if (isset($options['offline'])) { |
$this->_downloader->log(3, 'Skipping dependency download check, --offline specified'); |
return; |
} |
|
$pname = $this->getParsedPackage(); |
if (!$pname) { |
return; |
} |
|
$deps = $this->getDeps(); |
if (!$deps) { |
return; |
} |
|
if (isset($deps['required'])) { // package.xml 2.0 |
return $this->_detect2($deps, $pname, $options, $params); |
} |
|
return $this->_detect1($deps, $pname, $options, $params); |
} |
|
function setValidated() |
{ |
$this->_validated = true; |
} |
|
function alreadyValidated() |
{ |
return $this->_validated; |
} |
|
/** |
* Remove packages to be downloaded that are already installed |
* @param array of PEAR_Downloader_Package objects |
*/ |
public static function removeInstalled(&$params) |
{ |
if (!isset($params[0])) { |
return; |
} |
|
$options = $params[0]->_downloader->getOptions(); |
if (!isset($options['downloadonly'])) { |
foreach ($params as $i => $param) { |
$package = $param->getPackage(); |
$channel = $param->getChannel(); |
// remove self if already installed with this version |
// this does not need any pecl magic - we only remove exact matches |
if ($param->_installRegistry->packageExists($package, $channel)) { |
$packageVersion = $param->_installRegistry->packageInfo($package, 'version', $channel); |
if (version_compare($packageVersion, $param->getVersion(), '==')) { |
if (!isset($options['force']) && !isset($options['packagingroot'])) { |
$info = $param->getParsedPackage(); |
unset($info['version']); |
unset($info['state']); |
if (!isset($options['soft'])) { |
$param->_downloader->log(1, 'Skipping package "' . |
$param->getShortName() . |
'", already installed as version ' . $packageVersion); |
} |
$params[$i] = false; |
} |
} elseif (!isset($options['force']) && !isset($options['upgrade']) && |
!isset($options['soft']) && !isset($options['packagingroot'])) { |
$info = $param->getParsedPackage(); |
$param->_downloader->log(1, 'Skipping package "' . |
$param->getShortName() . |
'", already installed as version ' . $packageVersion); |
$params[$i] = false; |
} |
} |
} |
} |
|
PEAR_Downloader_Package::removeDuplicates($params); |
} |
|
function _detect2($deps, $pname, $options, $params) |
{ |
$this->_downloadDeps = array(); |
$groupnotfound = false; |
foreach (array('package', 'subpackage') as $packagetype) { |
// get required dependency group |
if (isset($deps['required'][$packagetype])) { |
if (isset($deps['required'][$packagetype][0])) { |
foreach ($deps['required'][$packagetype] as $dep) { |
if (isset($dep['conflicts'])) { |
// skip any package that this package conflicts with |
continue; |
} |
$ret = $this->_detect2Dep($dep, $pname, 'required', $params); |
if (is_array($ret)) { |
$this->_downloadDeps[] = $ret; |
} elseif (PEAR::isError($ret) && !isset($options['soft'])) { |
$this->_downloader->log(0, $ret->getMessage()); |
} |
} |
} else { |
$dep = $deps['required'][$packagetype]; |
if (!isset($dep['conflicts'])) { |
// skip any package that this package conflicts with |
$ret = $this->_detect2Dep($dep, $pname, 'required', $params); |
if (is_array($ret)) { |
$this->_downloadDeps[] = $ret; |
} elseif (PEAR::isError($ret) && !isset($options['soft'])) { |
$this->_downloader->log(0, $ret->getMessage()); |
} |
} |
} |
} |
|
// get optional dependency group, if any |
if (isset($deps['optional'][$packagetype])) { |
$skipnames = array(); |
if (!isset($deps['optional'][$packagetype][0])) { |
$deps['optional'][$packagetype] = array($deps['optional'][$packagetype]); |
} |
|
foreach ($deps['optional'][$packagetype] as $dep) { |
$skip = false; |
if (!isset($options['alldeps'])) { |
$dep['package'] = $dep['name']; |
if (!isset($options['soft'])) { |
$this->_downloader->log(3, 'Notice: package "' . |
$this->_registry->parsedPackageNameToString($this->getParsedPackage(), |
true) . '" optional dependency "' . |
$this->_registry->parsedPackageNameToString(array('package' => |
$dep['name'], 'channel' => 'pear.php.net'), true) . |
'" will not be automatically downloaded'); |
} |
$skipnames[] = $this->_registry->parsedPackageNameToString($dep, true); |
$skip = true; |
unset($dep['package']); |
} |
|
$ret = $this->_detect2Dep($dep, $pname, 'optional', $params); |
if (PEAR::isError($ret) && !isset($options['soft'])) { |
$this->_downloader->log(0, $ret->getMessage()); |
} |
|
if (!$ret) { |
$dep['package'] = $dep['name']; |
$skip = count($skipnames) ? |
$skipnames[count($skipnames) - 1] : ''; |
if ($skip == |
$this->_registry->parsedPackageNameToString($dep, true)) { |
array_pop($skipnames); |
} |
} |
|
if (!$skip && is_array($ret)) { |
$this->_downloadDeps[] = $ret; |
} |
} |
|
if (count($skipnames)) { |
if (!isset($options['soft'])) { |
$this->_downloader->log(1, 'Did not download optional dependencies: ' . |
implode(', ', $skipnames) . |
', use --alldeps to download automatically'); |
} |
} |
} |
|
// get requested dependency group, if any |
$groupname = $this->getGroup(); |
$explicit = $this->_explicitGroup; |
if (!$groupname) { |
if (!$this->canDefault()) { |
continue; |
} |
|
$groupname = 'default'; // try the default dependency group |
} |
|
if ($groupnotfound) { |
continue; |
} |
|
if (isset($deps['group'])) { |
if (isset($deps['group']['attribs'])) { |
if (strtolower($deps['group']['attribs']['name']) == strtolower($groupname)) { |
$group = $deps['group']; |
} elseif ($explicit) { |
if (!isset($options['soft'])) { |
$this->_downloader->log(0, 'Warning: package "' . |
$this->_registry->parsedPackageNameToString($pname, true) . |
'" has no dependency ' . 'group named "' . $groupname . '"'); |
} |
|
$groupnotfound = true; |
continue; |
} |
} else { |
$found = false; |
foreach ($deps['group'] as $group) { |
if (strtolower($group['attribs']['name']) == strtolower($groupname)) { |
$found = true; |
break; |
} |
} |
|
if (!$found) { |
if ($explicit) { |
if (!isset($options['soft'])) { |
$this->_downloader->log(0, 'Warning: package "' . |
$this->_registry->parsedPackageNameToString($pname, true) . |
'" has no dependency ' . 'group named "' . $groupname . '"'); |
} |
} |
|
$groupnotfound = true; |
continue; |
} |
} |
} |
|
if (isset($group) && isset($group[$packagetype])) { |
if (isset($group[$packagetype][0])) { |
foreach ($group[$packagetype] as $dep) { |
$ret = $this->_detect2Dep($dep, $pname, 'dependency group "' . |
$group['attribs']['name'] . '"', $params); |
if (is_array($ret)) { |
$this->_downloadDeps[] = $ret; |
} elseif (PEAR::isError($ret) && !isset($options['soft'])) { |
$this->_downloader->log(0, $ret->getMessage()); |
} |
} |
} else { |
$ret = $this->_detect2Dep($group[$packagetype], $pname, |
'dependency group "' . |
$group['attribs']['name'] . '"', $params); |
if (is_array($ret)) { |
$this->_downloadDeps[] = $ret; |
} elseif (PEAR::isError($ret) && !isset($options['soft'])) { |
$this->_downloader->log(0, $ret->getMessage()); |
} |
} |
} |
} |
} |
|
function _detect2Dep($dep, $pname, $group, $params) |
{ |
if (isset($dep['conflicts'])) { |
return true; |
} |
|
$options = $this->_downloader->getOptions(); |
if (isset($dep['uri'])) { |
return array('uri' => $dep['uri'], 'dep' => $dep);; |
} |
|
$testdep = $dep; |
$testdep['package'] = $dep['name']; |
if (PEAR_Downloader_Package::willDownload($testdep, $params)) { |
$dep['package'] = $dep['name']; |
if (!isset($options['soft'])) { |
$this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group . |
' dependency "' . |
$this->_registry->parsedPackageNameToString($dep, true) . |
'", will be installed'); |
} |
return false; |
} |
|
$options = $this->_downloader->getOptions(); |
PEAR::pushErrorHandling(PEAR_ERROR_RETURN); |
if ($this->_explicitState) { |
$pname['state'] = $this->_explicitState; |
} |
|
$url = $this->_downloader->_getDepPackageDownloadUrl($dep, $pname); |
if (PEAR::isError($url)) { |
PEAR::popErrorHandling(); |
return $url; |
} |
|
$dep['package'] = $dep['name']; |
$ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params, $group == 'optional' && |
!isset($options['alldeps']), true); |
PEAR::popErrorHandling(); |
if (PEAR::isError($ret)) { |
if (!isset($options['soft'])) { |
$this->_downloader->log(0, $ret->getMessage()); |
} |
|
return false; |
} |
|
// check to see if a dep is already installed and is the same or newer |
if (!isset($dep['min']) && !isset($dep['max']) && !isset($dep['recommended'])) { |
$oper = 'has'; |
} else { |
$oper = 'gt'; |
} |
|
// do not try to move this before getDepPackageDownloadURL |
// we can't determine whether upgrade is necessary until we know what |
// version would be downloaded |
if (!isset($options['force']) && $this->isInstalled($ret, $oper)) { |
$version = $this->_installRegistry->packageInfo($dep['name'], 'version', $dep['channel']); |
$dep['package'] = $dep['name']; |
if (!isset($options['soft'])) { |
$this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group . |
' dependency "' . |
$this->_registry->parsedPackageNameToString($dep, true) . |
'" version ' . $url['version'] . ', already installed as version ' . |
$version); |
} |
|
return false; |
} |
|
if (isset($dep['nodefault'])) { |
$ret['nodefault'] = true; |
} |
|
return $ret; |
} |
|
function _detect1($deps, $pname, $options, $params) |
{ |
$this->_downloadDeps = array(); |
$skipnames = array(); |
foreach ($deps as $dep) { |
$nodownload = false; |
if (isset ($dep['type']) && $dep['type'] === 'pkg') { |
$dep['channel'] = 'pear.php.net'; |
$dep['package'] = $dep['name']; |
switch ($dep['rel']) { |
case 'not' : |
continue 2; |
case 'ge' : |
case 'eq' : |
case 'gt' : |
case 'has' : |
$group = (!isset($dep['optional']) || $dep['optional'] == 'no') ? |
'required' : |
'optional'; |
if (PEAR_Downloader_Package::willDownload($dep, $params)) { |
$this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group |
. ' dependency "' . |
$this->_registry->parsedPackageNameToString($dep, true) . |
'", will be installed'); |
continue 2; |
} |
$fakedp = new PEAR_PackageFile_v1; |
$fakedp->setPackage($dep['name']); |
// skip internet check if we are not upgrading (bug #5810) |
if (!isset($options['upgrade']) && $this->isInstalled( |
$fakedp, $dep['rel'])) { |
$this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group |
. ' dependency "' . |
$this->_registry->parsedPackageNameToString($dep, true) . |
'", is already installed'); |
continue 2; |
} |
} |
|
PEAR::pushErrorHandling(PEAR_ERROR_RETURN); |
if ($this->_explicitState) { |
$pname['state'] = $this->_explicitState; |
} |
|
$url = $this->_downloader->_getDepPackageDownloadUrl($dep, $pname); |
$chan = 'pear.php.net'; |
if (PEAR::isError($url)) { |
// check to see if this is a pecl package that has jumped |
// from pear.php.net to pecl.php.net channel |
if (!class_exists('PEAR_Dependency2')) { |
require_once 'PEAR/Dependency2.php'; |
} |
|
$newdep = PEAR_Dependency2::normalizeDep($dep); |
$newdep = $newdep[0]; |
$newdep['channel'] = 'pecl.php.net'; |
$chan = 'pecl.php.net'; |
$url = $this->_downloader->_getDepPackageDownloadUrl($newdep, $pname); |
$obj = &$this->_installRegistry->getPackage($dep['name']); |
if (PEAR::isError($url)) { |
PEAR::popErrorHandling(); |
if ($obj !== null && $this->isInstalled($obj, $dep['rel'])) { |
$group = (!isset($dep['optional']) || $dep['optional'] == 'no') ? |
'required' : |
'optional'; |
$dep['package'] = $dep['name']; |
if (!isset($options['soft'])) { |
$this->_downloader->log(3, $this->getShortName() . |
': Skipping ' . $group . ' dependency "' . |
$this->_registry->parsedPackageNameToString($dep, true) . |
'", already installed as version ' . $obj->getVersion()); |
} |
$skip = count($skipnames) ? |
$skipnames[count($skipnames) - 1] : ''; |
if ($skip == |
$this->_registry->parsedPackageNameToString($dep, true)) { |
array_pop($skipnames); |
} |
continue; |
} else { |
if (isset($dep['optional']) && $dep['optional'] == 'yes') { |
$this->_downloader->log(2, $this->getShortName() . |
': Skipping optional dependency "' . |
$this->_registry->parsedPackageNameToString($dep, true) . |
'", no releases exist'); |
continue; |
} else { |
return $url; |
} |
} |
} |
} |
|
PEAR::popErrorHandling(); |
if (!isset($options['alldeps'])) { |
if (isset($dep['optional']) && $dep['optional'] == 'yes') { |
if (!isset($options['soft'])) { |
$this->_downloader->log(3, 'Notice: package "' . |
$this->getShortName() . |
'" optional dependency "' . |
$this->_registry->parsedPackageNameToString( |
array('channel' => $chan, 'package' => |
$dep['name']), true) . |
'" will not be automatically downloaded'); |
} |
$skipnames[] = $this->_registry->parsedPackageNameToString( |
array('channel' => $chan, 'package' => |
$dep['name']), true); |
$nodownload = true; |
} |
} |
|
if (!isset($options['alldeps']) && !isset($options['onlyreqdeps'])) { |
if (!isset($dep['optional']) || $dep['optional'] == 'no') { |
if (!isset($options['soft'])) { |
$this->_downloader->log(3, 'Notice: package "' . |
$this->getShortName() . |
'" required dependency "' . |
$this->_registry->parsedPackageNameToString( |
array('channel' => $chan, 'package' => |
$dep['name']), true) . |
'" will not be automatically downloaded'); |
} |
$skipnames[] = $this->_registry->parsedPackageNameToString( |
array('channel' => $chan, 'package' => |
$dep['name']), true); |
$nodownload = true; |
} |
} |
|
// check to see if a dep is already installed |
// do not try to move this before getDepPackageDownloadURL |
// we can't determine whether upgrade is necessary until we know what |
// version would be downloaded |
if (!isset($options['force']) && $this->isInstalled( |
$url, $dep['rel'])) { |
$group = (!isset($dep['optional']) || $dep['optional'] == 'no') ? |
'required' : |
'optional'; |
$dep['package'] = $dep['name']; |
if (isset($newdep)) { |
$version = $this->_installRegistry->packageInfo($newdep['name'], 'version', $newdep['channel']); |
} else { |
$version = $this->_installRegistry->packageInfo($dep['name'], 'version'); |
} |
|
$dep['version'] = $url['version']; |
if (!isset($options['soft'])) { |
$this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group . |
' dependency "' . |
$this->_registry->parsedPackageNameToString($dep, true) . |
'", already installed as version ' . $version); |
} |
|
$skip = count($skipnames) ? |
$skipnames[count($skipnames) - 1] : ''; |
if ($skip == |
$this->_registry->parsedPackageNameToString($dep, true)) { |
array_pop($skipnames); |
} |
|
continue; |
} |
|
if ($nodownload) { |
continue; |
} |
|
PEAR::pushErrorHandling(PEAR_ERROR_RETURN); |
if (isset($newdep)) { |
$dep = $newdep; |
} |
|
$dep['package'] = $dep['name']; |
$ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params, |
isset($dep['optional']) && $dep['optional'] == 'yes' && |
!isset($options['alldeps']), true); |
PEAR::popErrorHandling(); |
if (PEAR::isError($ret)) { |
if (!isset($options['soft'])) { |
$this->_downloader->log(0, $ret->getMessage()); |
} |
continue; |
} |
|
$this->_downloadDeps[] = $ret; |
} |
} |
|
if (count($skipnames)) { |
if (!isset($options['soft'])) { |
$this->_downloader->log(1, 'Did not download dependencies: ' . |
implode(', ', $skipnames) . |
', use --alldeps or --onlyreqdeps to download automatically'); |
} |
} |
} |
|
function setDownloadURL($pkg) |
{ |
$this->_downloadURL = $pkg; |
} |
|
/** |
* Set the package.xml object for this downloaded package |
* |
* @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 $pkg |
*/ |
function setPackageFile(&$pkg) |
{ |
$this->_packagefile = &$pkg; |
} |
|
function getShortName() |
{ |
return $this->_registry->parsedPackageNameToString(array('channel' => $this->getChannel(), |
'package' => $this->getPackage()), true); |
} |
|
function getParsedPackage() |
{ |
if (isset($this->_packagefile) || isset($this->_parsedname)) { |
return array('channel' => $this->getChannel(), |
'package' => $this->getPackage(), |
'version' => $this->getVersion()); |
} |
|
return false; |
} |
|
function getDownloadURL() |
{ |
return $this->_downloadURL; |
} |
|
function canDefault() |
{ |
if (isset($this->_downloadURL) && isset($this->_downloadURL['nodefault'])) { |
return false; |
} |
|
return true; |
} |
|
function getPackage() |
{ |
if (isset($this->_packagefile)) { |
return $this->_packagefile->getPackage(); |
} elseif (isset($this->_downloadURL['info'])) { |
return $this->_downloadURL['info']->getPackage(); |
} |
|
return false; |
} |
|
/** |
* @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 |
*/ |
function isSubpackage(&$pf) |
{ |
if (isset($this->_packagefile)) { |
return $this->_packagefile->isSubpackage($pf); |
} elseif (isset($this->_downloadURL['info'])) { |
return $this->_downloadURL['info']->isSubpackage($pf); |
} |
|
return false; |
} |
|
function getPackageType() |
{ |
if (isset($this->_packagefile)) { |
return $this->_packagefile->getPackageType(); |
} elseif (isset($this->_downloadURL['info'])) { |
return $this->_downloadURL['info']->getPackageType(); |
} |
|
return false; |
} |
|
function isBundle() |
{ |
if (isset($this->_packagefile)) { |
return $this->_packagefile->getPackageType() == 'bundle'; |
} |
|
return false; |
} |
|
function getPackageXmlVersion() |
{ |
if (isset($this->_packagefile)) { |
return $this->_packagefile->getPackagexmlVersion(); |
} elseif (isset($this->_downloadURL['info'])) { |
return $this->_downloadURL['info']->getPackagexmlVersion(); |
} |
|
return '1.0'; |
} |
|
function getChannel() |
{ |
if (isset($this->_packagefile)) { |
return $this->_packagefile->getChannel(); |
} elseif (isset($this->_downloadURL['info'])) { |
return $this->_downloadURL['info']->getChannel(); |
} |
|
return false; |
} |
|
function getURI() |
{ |
if (isset($this->_packagefile)) { |
return $this->_packagefile->getURI(); |
} elseif (isset($this->_downloadURL['info'])) { |
return $this->_downloadURL['info']->getURI(); |
} |
|
return false; |
} |
|
function getVersion() |
{ |
if (isset($this->_packagefile)) { |
return $this->_packagefile->getVersion(); |
} elseif (isset($this->_downloadURL['version'])) { |
return $this->_downloadURL['version']; |
} |
|
return false; |
} |
|
function isCompatible($pf) |
{ |
if (isset($this->_packagefile)) { |
return $this->_packagefile->isCompatible($pf); |
} elseif (isset($this->_downloadURL['info'])) { |
return $this->_downloadURL['info']->isCompatible($pf); |
} |
|
return true; |
} |
|
function setGroup($group) |
{ |
$this->_parsedname['group'] = $group; |
} |
|
function getGroup() |
{ |
if (isset($this->_parsedname['group'])) { |
return $this->_parsedname['group']; |
} |
|
return ''; |
} |
|
function isExtension($name) |
{ |
if (isset($this->_packagefile)) { |
return $this->_packagefile->isExtension($name); |
} elseif (isset($this->_downloadURL['info'])) { |
if ($this->_downloadURL['info']->getPackagexmlVersion() == '2.0') { |
return $this->_downloadURL['info']->getProvidesExtension() == $name; |
} |
|
return false; |
} |
|
return false; |
} |
|
function getDeps() |
{ |
if (isset($this->_packagefile)) { |
$ver = $this->_packagefile->getPackagexmlVersion(); |
if (version_compare($ver, '2.0', '>=')) { |
return $this->_packagefile->getDeps(true); |
} |
|
return $this->_packagefile->getDeps(); |
} elseif (isset($this->_downloadURL['info'])) { |
$ver = $this->_downloadURL['info']->getPackagexmlVersion(); |
if (version_compare($ver, '2.0', '>=')) { |
return $this->_downloadURL['info']->getDeps(true); |
} |
|
return $this->_downloadURL['info']->getDeps(); |
} |
|
return array(); |
} |
|
/** |
* @param array Parsed array from {@link PEAR_Registry::parsePackageName()} or a dependency |
* returned from getDepDownloadURL() |
*/ |
function isEqual($param) |
{ |
if (is_object($param)) { |
$channel = $param->getChannel(); |
$package = $param->getPackage(); |
if ($param->getURI()) { |
$param = array( |
'channel' => $param->getChannel(), |
'package' => $param->getPackage(), |
'version' => $param->getVersion(), |
'uri' => $param->getURI(), |
); |
} else { |
$param = array( |
'channel' => $param->getChannel(), |
'package' => $param->getPackage(), |
'version' => $param->getVersion(), |
); |
} |
} else { |
if (isset($param['uri'])) { |
if ($this->getChannel() != '__uri') { |
return false; |
} |
return $param['uri'] == $this->getURI(); |
} |
|
$package = isset($param['package']) ? $param['package'] : $param['info']->getPackage(); |
$channel = isset($param['channel']) ? $param['channel'] : $param['info']->getChannel(); |
if (isset($param['rel'])) { |
if (!class_exists('PEAR_Dependency2')) { |
require_once 'PEAR/Dependency2.php'; |
} |
|
$newdep = PEAR_Dependency2::normalizeDep($param); |
$newdep = $newdep[0]; |
} elseif (isset($param['min'])) { |
$newdep = $param; |
} |
} |
|
if (isset($newdep)) { |
if (!isset($newdep['min'])) { |
$newdep['min'] = '0'; |
} |
|
if (!isset($newdep['max'])) { |
$newdep['max'] = '100000000000000000000'; |
} |
|
// use magic to support pecl packages suddenly jumping to the pecl channel |
// we need to support both dependency possibilities |
if ($channel == 'pear.php.net' && $this->getChannel() == 'pecl.php.net') { |
if ($package == $this->getPackage()) { |
$channel = 'pecl.php.net'; |
} |
} |
if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') { |
if ($package == $this->getPackage()) { |
$channel = 'pear.php.net'; |
} |
} |
|
return (strtolower($package) == strtolower($this->getPackage()) && |
$channel == $this->getChannel() && |
version_compare($newdep['min'], $this->getVersion(), '<=') && |
version_compare($newdep['max'], $this->getVersion(), '>=')); |
} |
|
// use magic to support pecl packages suddenly jumping to the pecl channel |
if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') { |
if (strtolower($package) == strtolower($this->getPackage())) { |
$channel = 'pear.php.net'; |
} |
} |
|
if (isset($param['version'])) { |
return (strtolower($package) == strtolower($this->getPackage()) && |
$channel == $this->getChannel() && |
$param['version'] == $this->getVersion()); |
} |
|
return strtolower($package) == strtolower($this->getPackage()) && |
$channel == $this->getChannel(); |
} |
|
function isInstalled($dep, $oper = '==') |
{ |
if (!$dep) { |
return false; |
} |
|
if ($oper != 'ge' && $oper != 'gt' && $oper != 'has' && $oper != '==') { |
return false; |
} |
|
if (is_object($dep)) { |
$package = $dep->getPackage(); |
$channel = $dep->getChannel(); |
if ($dep->getURI()) { |
$dep = array( |
'uri' => $dep->getURI(), |
'version' => $dep->getVersion(), |
); |
} else { |
$dep = array( |
'version' => $dep->getVersion(), |
); |
} |
} else { |
if (isset($dep['uri'])) { |
$channel = '__uri'; |
$package = $dep['dep']['name']; |
} else { |
$channel = $dep['info']->getChannel(); |
$package = $dep['info']->getPackage(); |
} |
} |
|
$options = $this->_downloader->getOptions(); |
$test = $this->_installRegistry->packageExists($package, $channel); |
if (!$test && $channel == 'pecl.php.net') { |
// do magic to allow upgrading from old pecl packages to new ones |
$test = $this->_installRegistry->packageExists($package, 'pear.php.net'); |
$channel = 'pear.php.net'; |
} |
|
if ($test) { |
if (isset($dep['uri'])) { |
if ($this->_installRegistry->packageInfo($package, 'uri', '__uri') == $dep['uri']) { |
return true; |
} |
} |
|
if (isset($options['upgrade'])) { |
$packageVersion = $this->_installRegistry->packageInfo($package, 'version', $channel); |
if (version_compare($packageVersion, $dep['version'], '>=')) { |
return true; |
} |
|
return false; |
} |
|
return true; |
} |
|
return false; |
} |
|
/** |
* Detect duplicate package names with differing versions |
* |
* If a user requests to install Date 1.4.6 and Date 1.4.7, |
* for instance, this is a logic error. This method |
* detects this situation. |
* |
* @param array $params array of PEAR_Downloader_Package objects |
* @param array $errorparams empty array |
* @return array array of stupid duplicated packages in PEAR_Downloader_Package obejcts |
*/ |
public static function detectStupidDuplicates($params, &$errorparams) |
{ |
$existing = array(); |
foreach ($params as $i => $param) { |
$package = $param->getPackage(); |
$channel = $param->getChannel(); |
$group = $param->getGroup(); |
if (!isset($existing[$channel . '/' . $package])) { |
$existing[$channel . '/' . $package] = array(); |
} |
|
if (!isset($existing[$channel . '/' . $package][$group])) { |
$existing[$channel . '/' . $package][$group] = array(); |
} |
|
$existing[$channel . '/' . $package][$group][] = $i; |
} |
|
$indices = array(); |
foreach ($existing as $package => $groups) { |
foreach ($groups as $group => $dupes) { |
if (count($dupes) > 1) { |
$indices = $indices + $dupes; |
} |
} |
} |
|
$indices = array_unique($indices); |
foreach ($indices as $index) { |
$errorparams[] = $params[$index]; |
} |
|
return count($errorparams); |
} |
|
/** |
* @param array |
* @param bool ignore install groups - for final removal of dupe packages |
*/ |
public static function removeDuplicates(&$params, $ignoreGroups = false) |
{ |
$pnames = array(); |
foreach ($params as $i => $param) { |
if (!$param) { |
continue; |
} |
|
if ($param->getPackage()) { |
$group = $ignoreGroups ? '' : $param->getGroup(); |
$pnames[$i] = $param->getChannel() . '/' . |
$param->getPackage() . '-' . $param->getVersion() . '#' . $group; |
} |
} |
|
$pnames = array_unique($pnames); |
$unset = array_diff(array_keys($params), array_keys($pnames)); |
$testp = array_flip($pnames); |
foreach ($params as $i => $param) { |
if (!$param) { |
$unset[] = $i; |
continue; |
} |
|
if (!is_a($param, 'PEAR_Downloader_Package')) { |
$unset[] = $i; |
continue; |
} |
|
$group = $ignoreGroups ? '' : $param->getGroup(); |
if (!isset($testp[$param->getChannel() . '/' . $param->getPackage() . '-' . |
$param->getVersion() . '#' . $group])) { |
$unset[] = $i; |
} |
} |
|
foreach ($unset as $i) { |
unset($params[$i]); |
} |
|
$ret = array(); |
foreach ($params as $i => $param) { |
$ret[] = &$params[$i]; |
} |
|
$params = array(); |
foreach ($ret as $i => $param) { |
$params[] = &$ret[$i]; |
} |
} |
|
function explicitState() |
{ |
return $this->_explicitState; |
} |
|
function setExplicitState($s) |
{ |
$this->_explicitState = $s; |
} |
|
/** |
*/ |
public static function mergeDependencies(&$params) |
{ |
$bundles = $newparams = array(); |
foreach ($params as $i => $param) { |
if (!$param->isBundle()) { |
continue; |
} |
|
$bundles[] = $i; |
$pf = &$param->getPackageFile(); |
$newdeps = array(); |
$contents = $pf->getBundledPackages(); |
if (!is_array($contents)) { |
$contents = array($contents); |
} |
|
foreach ($contents as $file) { |
$filecontents = $pf->getFileContents($file); |
$dl = &$param->getDownloader(); |
$options = $dl->getOptions(); |
if (PEAR::isError($dir = $dl->getDownloadDir())) { |
return $dir; |
} |
|
$fp = @fopen($dir . DIRECTORY_SEPARATOR . $file, 'wb'); |
if (!$fp) { |
continue; |
} |
|
// FIXME do symlink check |
|
fwrite($fp, $filecontents, strlen($filecontents)); |
fclose($fp); |
if ($s = $params[$i]->explicitState()) { |
$obj->setExplicitState($s); |
} |
|
$obj = new PEAR_Downloader_Package($params[$i]->getDownloader()); |
PEAR::pushErrorHandling(PEAR_ERROR_RETURN); |
if (PEAR::isError($dir = $dl->getDownloadDir())) { |
PEAR::popErrorHandling(); |
return $dir; |
} |
$a = $dir . DIRECTORY_SEPARATOR . $file; |
$e = $obj->_fromFile($a); |
PEAR::popErrorHandling(); |
if (PEAR::isError($e)) { |
if (!isset($options['soft'])) { |
$dl->log(0, $e->getMessage()); |
} |
continue; |
} |
|
if (!PEAR_Downloader_Package::willDownload($obj, |
array_merge($params, $newparams)) && !$param->isInstalled($obj)) { |
$newparams[] = $obj; |
} |
} |
} |
|
foreach ($bundles as $i) { |
unset($params[$i]); // remove bundles - only their contents matter for installation |
} |
|
PEAR_Downloader_Package::removeDuplicates($params); // strip any unset indices |
if (count($newparams)) { // add in bundled packages for install |
foreach ($newparams as $i => $unused) { |
$params[] = &$newparams[$i]; |
} |
$newparams = array(); |
} |
|
foreach ($params as $i => $param) { |
$newdeps = array(); |
foreach ($param->_downloadDeps as $dep) { |
$merge = array_merge($params, $newparams); |
if (!PEAR_Downloader_Package::willDownload($dep, $merge) |
&& !$param->isInstalled($dep) |
) { |
$newdeps[] = $dep; |
} else { |
//var_dump($dep); |
// detect versioning conflicts here |
} |
} |
|
// convert the dependencies into PEAR_Downloader_Package objects for the next time around |
$params[$i]->_downloadDeps = array(); |
foreach ($newdeps as $dep) { |
$obj = new PEAR_Downloader_Package($params[$i]->getDownloader()); |
if ($s = $params[$i]->explicitState()) { |
$obj->setExplicitState($s); |
} |
|
PEAR::pushErrorHandling(PEAR_ERROR_RETURN); |
$e = $obj->fromDepURL($dep); |
PEAR::popErrorHandling(); |
if (PEAR::isError($e)) { |
if (!isset($options['soft'])) { |
$obj->_downloader->log(0, $e->getMessage()); |
} |
continue; |
} |
|
$e = $obj->detectDependencies($params); |
if (PEAR::isError($e)) { |
if (!isset($options['soft'])) { |
$obj->_downloader->log(0, $e->getMessage()); |
} |
} |
|
$newparams[] = $obj; |
} |
} |
|
if (count($newparams)) { |
foreach ($newparams as $i => $unused) { |
$params[] = &$newparams[$i]; |
} |
return true; |
} |
|
return false; |
} |
|
|
/** |
*/ |
public static function willDownload($param, $params) |
{ |
if (!is_array($params)) { |
return false; |
} |
|
foreach ($params as $obj) { |
if ($obj->isEqual($param)) { |
return true; |
} |
} |
|
return false; |
} |
|
/** |
* For simpler unit-testing |
* @param PEAR_Config |
* @param int |
* @param string |
*/ |
function &getPackagefileObject(&$c, $d) |
{ |
$a = new PEAR_PackageFile($c, $d); |
return $a; |
} |
|
/** |
* This will retrieve from a local file if possible, and parse out |
* a group name as well. The original parameter will be modified to reflect this. |
* @param string|array can be a parsed package name as well |
* @access private |
*/ |
function _fromFile(&$param) |
{ |
$saveparam = $param; |
if (is_string($param)) { |
if (!@file_exists($param)) { |
$test = explode('#', $param); |
$group = array_pop($test); |
if (@file_exists(implode('#', $test))) { |
$this->setGroup($group); |
$param = implode('#', $test); |
$this->_explicitGroup = true; |
} |
} |
|
if (@is_file($param)) { |
$this->_type = 'local'; |
$options = $this->_downloader->getOptions(); |
$pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->_debug); |
PEAR::pushErrorHandling(PEAR_ERROR_RETURN); |
$pf = &$pkg->fromAnyFile($param, PEAR_VALIDATE_INSTALLING); |
PEAR::popErrorHandling(); |
if (PEAR::isError($pf)) { |
$this->_valid = false; |
$param = $saveparam; |
return $pf; |
} |
$this->_packagefile = &$pf; |
if (!$this->getGroup()) { |
$this->setGroup('default'); // install the default dependency group |
} |
return $this->_valid = true; |
} |
} |
$param = $saveparam; |
return $this->_valid = false; |
} |
|
function _fromUrl($param, $saveparam = '') |
{ |
if (!is_array($param) && (preg_match('#^(http|https|ftp)://#', $param))) { |
$options = $this->_downloader->getOptions(); |
$this->_type = 'url'; |
$callback = $this->_downloader->ui ? |
array(&$this->_downloader, '_downloadCallback') : null; |
$this->_downloader->pushErrorHandling(PEAR_ERROR_RETURN); |
if (PEAR::isError($dir = $this->_downloader->getDownloadDir())) { |
$this->_downloader->popErrorHandling(); |
return $dir; |
} |
|
$this->_downloader->log(3, 'Downloading "' . $param . '"'); |
$file = $this->_downloader->downloadHttp($param, $this->_downloader->ui, |
$dir, $callback, null, false, $this->getChannel()); |
$this->_downloader->popErrorHandling(); |
if (PEAR::isError($file)) { |
if (!empty($saveparam)) { |
$saveparam = ", cannot download \"$saveparam\""; |
} |
$err = PEAR::raiseError('Could not download from "' . $param . |
'"' . $saveparam . ' (' . $file->getMessage() . ')'); |
return $err; |
} |
|
if ($this->_rawpackagefile) { |
require_once 'Archive/Tar.php'; |
$tar = new Archive_Tar($file); |
$packagexml = $tar->extractInString('package2.xml'); |
if (!$packagexml) { |
$packagexml = $tar->extractInString('package.xml'); |
} |
|
if (str_replace(array("\n", "\r"), array('',''), $packagexml) != |
str_replace(array("\n", "\r"), array('',''), $this->_rawpackagefile)) { |
if ($this->getChannel() != 'pear.php.net') { |
return PEAR::raiseError('CRITICAL ERROR: package.xml downloaded does ' . |
'not match value returned from xml-rpc'); |
} |
|
// be more lax for the existing PEAR packages that have not-ok |
// characters in their package.xml |
$this->_downloader->log(0, 'CRITICAL WARNING: The "' . |
$this->getPackage() . '" package has invalid characters in its ' . |
'package.xml. The next version of PEAR may not be able to install ' . |
'this package for security reasons. Please open a bug report at ' . |
'http://pear.php.net/package/' . $this->getPackage() . '/bugs'); |
} |
} |
|
// whew, download worked! |
$pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->debug); |
|
PEAR::pushErrorHandling(PEAR_ERROR_RETURN); |
$pf = &$pkg->fromAnyFile($file, PEAR_VALIDATE_INSTALLING); |
PEAR::popErrorHandling(); |
if (PEAR::isError($pf)) { |
if (is_array($pf->getUserInfo())) { |
foreach ($pf->getUserInfo() as $err) { |
if (is_array($err)) { |
$err = $err['message']; |
} |
|
if (!isset($options['soft'])) { |
$this->_downloader->log(0, "Validation Error: $err"); |
} |
} |
} |
|
if (!isset($options['soft'])) { |
$this->_downloader->log(0, $pf->getMessage()); |
} |
|
///FIXME need to pass back some error code that we can use to match with to cancel all further operations |
/// At least stop all deps of this package from being installed |
$out = $saveparam ? $saveparam : $param; |
$err = PEAR::raiseError('Download of "' . $out . '" succeeded, but it is not a valid package archive'); |
$this->_valid = false; |
return $err; |
} |
|
$this->_packagefile = &$pf; |
$this->setGroup('default'); // install the default dependency group |
return $this->_valid = true; |
} |
|
return $this->_valid = false; |
} |
|
/** |
* |
* @param string|array pass in an array of format |
* array( |
* 'package' => 'pname', |
* ['channel' => 'channame',] |
* ['version' => 'version',] |
* ['state' => 'state',]) |
* or a string of format [channame/]pname[-version|-state] |
*/ |
function _fromString($param) |
{ |
$options = $this->_downloader->getOptions(); |
$channel = $this->_config->get('default_channel'); |
PEAR::pushErrorHandling(PEAR_ERROR_RETURN); |
$pname = $this->_registry->parsePackageName($param, $channel); |
PEAR::popErrorHandling(); |
if (PEAR::isError($pname)) { |
if ($pname->getCode() == 'invalid') { |
$this->_valid = false; |
return false; |
} |
|
if ($pname->getCode() == 'channel') { |
$parsed = $pname->getUserInfo(); |
if ($this->_downloader->discover($parsed['channel'])) { |
if ($this->_config->get('auto_discover')) { |
PEAR::pushErrorHandling(PEAR_ERROR_RETURN); |
$pname = $this->_registry->parsePackageName($param, $channel); |
PEAR::popErrorHandling(); |
} else { |
if (!isset($options['soft'])) { |
$this->_downloader->log(0, 'Channel "' . $parsed['channel'] . |
'" is not initialized, use ' . |
'"pear channel-discover ' . $parsed['channel'] . '" to initialize' . |
'or pear config-set auto_discover 1'); |
} |
} |
} |
|
if (PEAR::isError($pname)) { |
if (!isset($options['soft'])) { |
$this->_downloader->log(0, $pname->getMessage()); |
} |
|
if (is_array($param)) { |
$param = $this->_registry->parsedPackageNameToString($param); |
} |
|
$err = PEAR::raiseError('invalid package name/package file "' . $param . '"'); |
$this->_valid = false; |
return $err; |
} |
} else { |
if (!isset($options['soft'])) { |
$this->_downloader->log(0, $pname->getMessage()); |
} |
|
$err = PEAR::raiseError('invalid package name/package file "' . $param . '"'); |
$this->_valid = false; |
return $err; |
} |
} |
|
if (!isset($this->_type)) { |
$this->_type = 'rest'; |
} |
|
$this->_parsedname = $pname; |
$this->_explicitState = isset($pname['state']) ? $pname['state'] : false; |
$this->_explicitGroup = isset($pname['group']) ? true : false; |
|
$info = $this->_downloader->_getPackageDownloadUrl($pname); |
if (PEAR::isError($info)) { |
if ($info->getCode() != -976 && $pname['channel'] == 'pear.php.net') { |
// try pecl |
$pname['channel'] = 'pecl.php.net'; |
if ($test = $this->_downloader->_getPackageDownloadUrl($pname)) { |
if (!PEAR::isError($test)) { |
$info = PEAR::raiseError($info->getMessage() . ' - package ' . |
$this->_registry->parsedPackageNameToString($pname, true) . |
' can be installed with "pecl install ' . $pname['package'] . |
'"'); |
} else { |
$pname['channel'] = 'pear.php.net'; |
} |
} else { |
$pname['channel'] = 'pear.php.net'; |
} |
} |
|
return $info; |
} |
|
$this->_rawpackagefile = $info['raw']; |
$ret = $this->_analyzeDownloadURL($info, $param, $pname); |
if (PEAR::isError($ret)) { |
return $ret; |
} |
|
if ($ret) { |
$this->_downloadURL = $ret; |
return $this->_valid = (bool) $ret; |
} |
} |
|
/** |
* @param array output of package.getDownloadURL |
* @param string|array|object information for detecting packages to be downloaded, and |
* for errors |
* @param array name information of the package |
* @param array|null packages to be downloaded |
* @param bool is this an optional dependency? |
* @param bool is this any kind of dependency? |
* @access private |
*/ |
function _analyzeDownloadURL($info, $param, $pname, $params = null, $optional = false, |
$isdependency = false) |
{ |
if (!is_string($param) && PEAR_Downloader_Package::willDownload($param, $params)) { |
return false; |
} |
|
if ($info === false) { |
$saveparam = !is_string($param) ? ", cannot download \"$param\"" : ''; |
|
// no releases exist |
return PEAR::raiseError('No releases for package "' . |
$this->_registry->parsedPackageNameToString($pname, true) . '" exist' . $saveparam); |
} |
|
if (strtolower($info['info']->getChannel()) != strtolower($pname['channel'])) { |
$err = false; |
if ($pname['channel'] == 'pecl.php.net') { |
if ($info['info']->getChannel() != 'pear.php.net') { |
$err = true; |
} |
} elseif ($info['info']->getChannel() == 'pecl.php.net') { |
if ($pname['channel'] != 'pear.php.net') { |
$err = true; |
} |
} else { |
$err = true; |
} |
|
if ($err) { |
return PEAR::raiseError('SECURITY ERROR: package in channel "' . $pname['channel'] . |
'" retrieved another channel\'s name for download! ("' . |
$info['info']->getChannel() . '")'); |
} |
} |
|
$preferred_state = $this->_config->get('preferred_state'); |
if (!isset($info['url'])) { |
$package_version = $this->_registry->packageInfo($info['info']->getPackage(), |
'version', $info['info']->getChannel()); |
if ($this->isInstalled($info)) { |
if ($isdependency && version_compare($info['version'], $package_version, '<=')) { |
// ignore bogus errors of "failed to download dependency" |
// if it is already installed and the one that would be |
// downloaded is older or the same version (Bug #7219) |
return false; |
} |
} |
|
if ($info['version'] === $package_version) { |
if (!isset($options['soft'])) { |
$this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] . |
'/' . $pname['package'] . '-' . $package_version. ', additionally the suggested version' . |
' (' . $package_version . ') is the same as the locally installed one.'); |
} |
|
return false; |
} |
|
if (version_compare($info['version'], $package_version, '<=')) { |
if (!isset($options['soft'])) { |
$this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] . |
'/' . $pname['package'] . '-' . $package_version . ', additionally the suggested version' . |
' (' . $info['version'] . ') is a lower version than the locally installed one (' . $package_version . ').'); |
} |
|
return false; |
} |
|
$instead = ', will instead download version ' . $info['version'] . |
', stability "' . $info['info']->getState() . '"'; |
// releases exist, but we failed to get any |
if (isset($this->_downloader->_options['force'])) { |
if (isset($pname['version'])) { |
$vs = ', version "' . $pname['version'] . '"'; |
} elseif (isset($pname['state'])) { |
$vs = ', stability "' . $pname['state'] . '"'; |
} elseif ($param == 'dependency') { |
if (!class_exists('PEAR_Common')) { |
require_once 'PEAR/Common.php'; |
} |
|
if (!in_array($info['info']->getState(), |
PEAR_Common::betterStates($preferred_state, true))) { |
if ($optional) { |
// don't spit out confusing error message |
return $this->_downloader->_getPackageDownloadUrl( |
array('package' => $pname['package'], |
'channel' => $pname['channel'], |
'version' => $info['version'])); |
} |
$vs = ' within preferred state "' . $preferred_state . |
'"'; |
} else { |
if (!class_exists('PEAR_Dependency2')) { |
require_once 'PEAR/Dependency2.php'; |
} |
|
if ($optional) { |
// don't spit out confusing error message |
return $this->_downloader->_getPackageDownloadUrl( |
array('package' => $pname['package'], |
'channel' => $pname['channel'], |
'version' => $info['version'])); |
} |
$vs = PEAR_Dependency2::_getExtraString($pname); |
$instead = ''; |
} |
} else { |
$vs = ' within preferred state "' . $preferred_state . '"'; |
} |
|
if (!isset($options['soft'])) { |
$this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] . |
'/' . $pname['package'] . $vs . $instead); |
} |
|
// download the latest release |
return $this->_downloader->_getPackageDownloadUrl( |
array('package' => $pname['package'], |
'channel' => $pname['channel'], |
'version' => $info['version'])); |
} else { |
if (isset($info['php']) && $info['php']) { |
$err = PEAR::raiseError('Failed to download ' . |
$this->_registry->parsedPackageNameToString( |
array('channel' => $pname['channel'], |
'package' => $pname['package']), |
true) . |
', latest release is version ' . $info['php']['v'] . |
', but it requires PHP version "' . |
$info['php']['m'] . '", use "' . |
$this->_registry->parsedPackageNameToString( |
array('channel' => $pname['channel'], 'package' => $pname['package'], |
'version' => $info['php']['v'])) . '" to install', |
PEAR_DOWNLOADER_PACKAGE_PHPVERSION); |
return $err; |
} |
|
// construct helpful error message |
if (isset($pname['version'])) { |
$vs = ', version "' . $pname['version'] . '"'; |
} elseif (isset($pname['state'])) { |
$vs = ', stability "' . $pname['state'] . '"'; |
} elseif ($param == 'dependency') { |
if (!class_exists('PEAR_Common')) { |
require_once 'PEAR/Common.php'; |
} |
|
if (!in_array($info['info']->getState(), |
PEAR_Common::betterStates($preferred_state, true))) { |
if ($optional) { |
// don't spit out confusing error message, and don't die on |
// optional dep failure! |
return $this->_downloader->_getPackageDownloadUrl( |
array('package' => $pname['package'], |
'channel' => $pname['channel'], |
'version' => $info['version'])); |
} |
$vs = ' within preferred state "' . $preferred_state . '"'; |
} else { |
if (!class_exists('PEAR_Dependency2')) { |
require_once 'PEAR/Dependency2.php'; |
} |
|
if ($optional) { |
// don't spit out confusing error message, and don't die on |
// optional dep failure! |
return $this->_downloader->_getPackageDownloadUrl( |
array('package' => $pname['package'], |
'channel' => $pname['channel'], |
'version' => $info['version'])); |
} |
$vs = PEAR_Dependency2::_getExtraString($pname); |
} |
} else { |
$vs = ' within preferred state "' . $this->_downloader->config->get('preferred_state') . '"'; |
} |
|
$options = $this->_downloader->getOptions(); |
// this is only set by the "download-all" command |
if (isset($options['ignorepreferred_state'])) { |
$err = PEAR::raiseError( |
'Failed to download ' . $this->_registry->parsedPackageNameToString( |
array('channel' => $pname['channel'], 'package' => $pname['package']), |
true) |
. $vs . |
', latest release is version ' . $info['version'] . |
', stability "' . $info['info']->getState() . '", use "' . |
$this->_registry->parsedPackageNameToString( |
array('channel' => $pname['channel'], 'package' => $pname['package'], |
'version' => $info['version'])) . '" to install', |
PEAR_DOWNLOADER_PACKAGE_STATE); |
return $err; |
} |
|
// Checks if the user has a package installed already and checks the release against |
// the state against the installed package, this allows upgrades for packages |
// with lower stability than the preferred_state |
$stability = $this->_registry->packageInfo($pname['package'], 'stability', $pname['channel']); |
if (!$this->isInstalled($info) |
|| !in_array($info['info']->getState(), PEAR_Common::betterStates($stability['release'], true)) |
) { |
$err = PEAR::raiseError( |
'Failed to download ' . $this->_registry->parsedPackageNameToString( |
array('channel' => $pname['channel'], 'package' => $pname['package']), |
true) |
. $vs . |
', latest release is version ' . $info['version'] . |
', stability "' . $info['info']->getState() . '", use "' . |
$this->_registry->parsedPackageNameToString( |
array('channel' => $pname['channel'], 'package' => $pname['package'], |
'version' => $info['version'])) . '" to install'); |
return $err; |
} |
} |
} |
|
if (isset($info['deprecated']) && $info['deprecated']) { |
$this->_downloader->log(0, |
'WARNING: "' . |
$this->_registry->parsedPackageNameToString( |
array('channel' => $info['info']->getChannel(), |
'package' => $info['info']->getPackage()), true) . |
'" is deprecated in favor of "' . |
$this->_registry->parsedPackageNameToString($info['deprecated'], true) . |
'"'); |
} |
|
return $info; |
} |
} |