experimental code shuffling, moved download() into a new class, PEAR_Downloader.

Reasons:
- 7 parameters for a method with lots of pass by reference
  implies the need to save state, i.e. use an object
- cleaner code.  download() can be easily split into 4 separate but related methods
- Installer.php is now exclusively used for installation
- future extensibility: switching to channels or local package repositories from
  using PEAR_Remote is easy.  Simply extend the API for PEAR_Downloader:
  no changes needed to the installer at all

to install for testing purposes, use

pear upgrade --force package-PEAR-new-Downloader.xml

to uninstall, use

pear upgrade --force package-PEAR.xml
This commit is contained in:
Greg Beaver 2003-11-30 05:39:02 +00:00
parent 6dd2f536a4
commit c7c5d7689d
4 changed files with 2276 additions and 0 deletions

View File

@ -0,0 +1,535 @@
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 3.0 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available through the world-wide-web at the following url: |
// | http://www.php.net/license/3_0.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Author: Stig Sæther Bakken <ssb@php.net> |
// +----------------------------------------------------------------------+
//
// $Id$
require_once "PEAR/Command/Common.php";
require_once "PEAR/Installer.php";
/**
* PEAR commands for installation or deinstallation/upgrading of
* packages.
*
*/
class PEAR_Command_Install extends PEAR_Command_Common
{
// {{{ properties
var $commands = array(
'install' => array(
'summary' => 'Install Package',
'function' => 'doInstall',
'shortcut' => 'i',
'options' => array(
'force' => array(
'shortopt' => 'f',
'doc' => 'will overwrite newer installed packages',
),
'nodeps' => array(
'shortopt' => 'n',
'doc' => 'ignore dependencies, install anyway',
),
'register-only' => array(
'shortopt' => 'r',
'doc' => 'do not install files, only register the package as installed',
),
'soft' => array(
'shortopt' => 's',
'doc' => 'soft install, fail silently, or upgrade if already installed',
),
'nobuild' => array(
'shortopt' => 'B',
'doc' => 'don\'t build C extensions',
),
'nocompress' => array(
'shortopt' => 'Z',
'doc' => 'request uncompressed files when downloading',
),
'installroot' => array(
'shortopt' => 'R',
'arg' => 'DIR',
'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
),
'ignore-errors' => array(
'doc' => 'force install even if there were errors',
),
'alldeps' => array(
'shortopt' => 'a',
'doc' => 'install all required and optional dependencies',
),
'onlyreqdeps' => array(
'shortopt' => 'o',
'doc' => 'install all required dependencies',
),
),
'doc' => '<package> ...
Installs one or more PEAR packages. You can specify a package to
install in four ways:
"Package-1.0.tgz" : installs from a local file
"http://example.com/Package-1.0.tgz" : installs from
anywhere on the net.
"package.xml" : installs the package described in
package.xml. Useful for testing, or for wrapping a PEAR package in
another package manager such as RPM.
"Package" : queries your configured server
({config master_server}) and downloads the newest package with
the preferred quality/state ({config preferred_state}).
More than one package may be specified at once. It is ok to mix these
four ways of specifying packages.
'),
'upgrade' => array(
'summary' => 'Upgrade Package',
'function' => 'doInstall',
'shortcut' => 'up',
'options' => array(
'force' => array(
'shortopt' => 'f',
'doc' => 'overwrite newer installed packages',
),
'nodeps' => array(
'shortopt' => 'n',
'doc' => 'ignore dependencies, upgrade anyway',
),
'register-only' => array(
'shortopt' => 'r',
'doc' => 'do not install files, only register the package as upgraded',
),
'nobuild' => array(
'shortopt' => 'B',
'doc' => 'don\'t build C extensions',
),
'nocompress' => array(
'shortopt' => 'Z',
'doc' => 'request uncompressed files when downloading',
),
'installroot' => array(
'shortopt' => 'R',
'arg' => 'DIR',
'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
),
'ignore-errors' => array(
'doc' => 'force install even if there were errors',
),
'alldeps' => array(
'shortopt' => 'a',
'doc' => 'install all required and optional dependencies',
),
'onlyreqdeps' => array(
'shortopt' => 'o',
'doc' => 'install all required dependencies',
),
),
'doc' => '<package> ...
Upgrades one or more PEAR packages. See documentation for the
"install" command for ways to specify a package.
When upgrading, your package will be updated if the provided new
package has a higher version number (use the -f option if you need to
upgrade anyway).
More than one package may be specified at once.
'),
'upgrade-all' => array(
'summary' => 'Upgrade All Packages',
'function' => 'doInstall',
'shortcut' => 'ua',
'options' => array(
'nodeps' => array(
'shortopt' => 'n',
'doc' => 'ignore dependencies, upgrade anyway',
),
'register-only' => array(
'shortopt' => 'r',
'doc' => 'do not install files, only register the package as upgraded',
),
'nobuild' => array(
'shortopt' => 'B',
'doc' => 'don\'t build C extensions',
),
'nocompress' => array(
'shortopt' => 'Z',
'doc' => 'request uncompressed files when downloading',
),
'installroot' => array(
'shortopt' => 'R',
'arg' => 'DIR',
'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
),
'ignore-errors' => array(
'doc' => 'force install even if there were errors',
),
),
'doc' => '
Upgrades all packages that have a newer release available. Upgrades are
done only if there is a release available of the state specified in
"preferred_state" (currently {config preferred_state}), or a state considered
more stable.
'),
'uninstall' => array(
'summary' => 'Un-install Package',
'function' => 'doUninstall',
'shortcut' => 'un',
'options' => array(
'nodeps' => array(
'shortopt' => 'n',
'doc' => 'ignore dependencies, uninstall anyway',
),
'register-only' => array(
'shortopt' => 'r',
'doc' => 'do not remove files, only register the packages as not installed',
),
'installroot' => array(
'shortopt' => 'R',
'arg' => 'DIR',
'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
),
'ignore-errors' => array(
'doc' => 'force install even if there were errors',
),
),
'doc' => '<package> ...
Uninstalls one or more PEAR packages. More than one package may be
specified at once.
'),
'bundle' => array(
'summary' => 'Unpacks a Pecl Package',
'function' => 'doBundle',
'shortcut' => 'bun',
'options' => array(
'destination' => array(
'shortopt' => 'd',
'arg' => 'DIR',
'doc' => 'Optional destination directory for unpacking (defaults to current path or "ext" if exists)',
),
'force' => array(
'shortopt' => 'f',
'doc' => 'Force the unpacking even if there were errors in the package',
),
),
'doc' => '<package>
Unpacks a Pecl Package into the selected location. It will download the
package if needed.
'),
'revert' => array(
'summary' => 'Revert the Most Recent Upgrade of a Package',
'function' => 'doRevert',
'shortcut' => 'r',
'options' => array(
'force' => array(
'shortopt' => 'f',
'doc' => 'Force the revert even if there were errors',
),
'installroot' => array(
'shortopt' => 'R',
'arg' => 'DIR',
'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
),
'deps' => array(
'shortopt' => 'd',
'doc' => 'revert any dependencies that are incompatible with earlier versions',
),
),
'doc' => '<package> ...
This command may only be used after a pear upgrade <package> has
been executed. pear revert will revert a package to the previously
installed version number. This command will only work once, and will
fail if any packages depend on the newer version.'),
);
// }}}
// {{{ constructor
/**
* PEAR_Command_Install constructor.
*
* @access public
*/
function PEAR_Command_Install(&$ui, &$config)
{
parent::PEAR_Command_Common($ui, $config);
}
// }}}
// {{{ doInstall()
function doInstall($command, $options, $params)
{
require_once 'PEAR/Downloader.php';
if (empty($this->installer)) {
$this->installer = &new PEAR_Installer($this->ui);
}
if ($command == 'upgrade') {
$options['upgrade'] = true;
}
if ($command == 'upgrade-all') {
include_once "PEAR/Remote.php";
$options['upgrade'] = true;
$remote = &new PEAR_Remote($this->config);
$state = $this->config->get('preferred_state');
if (empty($state) || $state == 'any') {
$latest = $remote->call("package.listLatestReleases");
} else {
$latest = $remote->call("package.listLatestReleases", $state);
}
if (PEAR::isError($latest)) {
return $latest;
}
$reg = new PEAR_Registry($this->config->get('php_dir'));
$installed = array_flip($reg->listPackages());
$params = array();
foreach ($latest as $package => $info) {
$package = strtolower($package);
if (!isset($installed[$package])) {
// skip packages we don't have installed
continue;
}
$inst_version = $reg->packageInfo($package, 'version');
if (version_compare("$info[version]", "$inst_version", "le")) {
// installed version is up-to-date
continue;
}
$params[] = $package;
$this->ui->outputData(array('data' => "Will upgrade $package"), $command);
}
}
$this->downloader = &new PEAR_Downloader($this->ui, $options, $this->config);
$errors = array();
$downloaded = array();
$this->downloader->download($params);
if ($command != 'upgrade-all') {
for ($i = 0; $i < count($params); $i++) {
$params[$i] = $this->downloader->extractDownloadFileName($params[$i], $_tmp);
}
}
$errors = $this->downloader->getErrorMsgs();
if (count($errors)) {
$err['data'] = array($errors);
$err['headline'] = 'Install Errors';
$this->ui->outputData($err);
return $this->raiseError("$command failed");
}
$downloaded = $this->downloader->getDownloadedPackages();
$this->installer->sortPkgDeps($downloaded);
foreach ($downloaded as $pkg) {
$bn = basename($pkg['file']);
$info = $this->installer->install($pkg['file'], $options, $this->config);
if (is_array($info)) {
if ($this->config->get('verbose') > 0) {
$label = "$info[package] $info[version]";
$out = array('data' => "$command ok: $label");
if (isset($info['release_warnings'])) {
$out['release_warnings'] = $info['release_warnings'];
}
$this->ui->outputData($out, $command);
}
} else {
return $this->raiseError("$command failed");
}
}
return true;
}
// }}}
// {{{ doUninstall()
function doUninstall($command, $options, $params)
{
if (empty($this->installer)) {
$this->installer = &new PEAR_Installer($this->ui);
}
if (sizeof($params) < 1) {
return $this->raiseError("Please supply the package(s) you want to uninstall");
}
include_once 'PEAR/Registry.php';
$reg = new PEAR_Registry($this->config->get('php_dir'));
$newparams = array();
$badparams = array();
foreach ($params as $pkg) {
$info = $reg->packageInfo($pkg);
if ($info === null) {
$badparams[] = $pkg;
} else {
$newparams[] = $info;
}
}
PEAR_Common::sortPkgDeps($newparams, true);
$params = array();
foreach($newparams as $info) {
$params[] = $info['info']['package'];
}
$params = array_merge($params, $badparams);
foreach ($params as $pkg) {
if ($this->installer->uninstall($pkg, $options)) {
if ($this->config->get('verbose') > 0) {
$this->ui->outputData("uninstall ok: $pkg", $command);
}
} else {
return $this->raiseError("uninstall failed: $pkg");
}
}
return true;
}
// }}}
// }}}
// {{{ doBundle()
/*
(cox) It just downloads and untars the package, does not do
any check that the PEAR_Installer::_installFile() does.
*/
function doBundle($command, $options, $params)
{
if (empty($this->installer)) {
$this->installer = &new PEAR_Downloader($this->ui);
}
$installer = &$this->installer;
if (sizeof($params) < 1) {
return $this->raiseError("Please supply the package you want to bundle");
}
$pkgfile = $params[0];
$need_download = false;
if (preg_match('#^(http|ftp)://#', $pkgfile)) {
$need_download = true;
} elseif (!@is_file($pkgfile)) {
if ($installer->validPackageName($pkgfile)) {
$pkgfile = $installer->getPackageDownloadUrl($pkgfile);
$need_download = true;
} else {
if (strlen($pkgfile)) {
return $this->raiseError("Could not open the package file: $pkgfile");
} else {
return $this->raiseError("No package file given");
}
}
}
// Download package -----------------------------------------------
if ($need_download) {
$downloaddir = $installer->config->get('download_dir');
if (empty($downloaddir)) {
if (PEAR::isError($downloaddir = System::mktemp('-d'))) {
return $downloaddir;
}
$installer->log(2, '+ tmp dir created at ' . $downloaddir);
}
$callback = $this->ui ? array(&$installer, '_downloadCallback') : null;
$file = $installer->downloadHttp($pkgfile, $this->ui, $downloaddir, $callback);
if (PEAR::isError($file)) {
return $this->raiseError($file);
}
$pkgfile = $file;
}
// Parse xml file -----------------------------------------------
$pkginfo = $installer->infoFromTgzFile($pkgfile);
if (PEAR::isError($pkginfo)) {
return $this->raiseError($pkginfo);
}
$installer->validatePackageInfo($pkginfo, $errors, $warnings);
// XXX We allow warnings, do we have to do it?
if (count($errors)) {
if (empty($options['force'])) {
return $this->raiseError("The following errors where found:\n".
implode("\n", $errors));
} else {
$this->log(0, "warning : the following errors were found:\n".
implode("\n", $errors));
}
}
$pkgname = $pkginfo['package'];
// Unpacking -------------------------------------------------
if (isset($options['destination'])) {
if (!is_dir($options['destination'])) {
System::mkdir('-p ' . $options['destination']);
}
$dest = realpath($options['destination']);
} else {
$pwd = getcwd();
if (is_dir($pwd . DIRECTORY_SEPARATOR . 'ext')) {
$dest = $pwd . DIRECTORY_SEPARATOR . 'ext';
} else {
$dest = $pwd;
}
}
$dest .= DIRECTORY_SEPARATOR . $pkgname;
$orig = $pkgname . '-' . $pkginfo['version'];
$tar = new Archive_Tar($pkgfile);
if (!@$tar->extractModify($dest, $orig)) {
return $this->raiseError("unable to unpack $pkgfile");
}
$this->ui->outputData("Package ready at '$dest'");
// }}}
}
// }}}
// {{{ doRevert()
function doRevert($command, $options, $params)
{
if (empty($this->installer)) {
$this->installer = &new PEAR_Installer($this->ui);
}
if (sizeof($params) < 1) {
return $this->raiseError("Please supply the package(s) you want to revert");
}
include_once 'PEAR/Registry.php';
$reg = new PEAR_Registry($this->config->get('php_dir'));
$newparams = array();
$badparams = array();
foreach ($params as $pkg) {
$info = $reg->packageInfo($pkg);
if ($info === null) {
$badparams[]['info']['package'] = $pkg;
} else {
$newparams = array_merge($newparams,
$this->installer->processRevertDeps($info, $options, $config, $reg));
$newparams[] = $info;
}
}
PEAR_Common::sortPkgDeps($newparams, true);
$params = array();
$params = array_merge($newparams, $badparams);
foreach ($params as $pkg) {
if (!PEAR::isError($this->installer->revert($pkg['info']['package'],
$options, $this->config))) {
if ($this->config->get('verbose') > 0) {
$this->ui->outputData('revert ok: ' . $pkg['info']['package'], $command);
}
} else {
$this->ui->outputData('revert failed: ');
return $this->raiseError($pkg);
}
}
return true;
}
// }}}
}
?>

588
pear/PEAR/Downloader.php Normal file
View File

@ -0,0 +1,588 @@
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 3.0 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available through the world-wide-web at the following url: |
// | http://www.php.net/license/3_0.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Stig Bakken <ssb@php.net> |
// | Tomas V.V.Cox <cox@idecnet.com> |
// | Martin Jansen <mj@php.net> |
// +----------------------------------------------------------------------+
//
// $Id$
require_once 'PEAR/Common.php';
require_once 'PEAR/Registry.php';
require_once 'PEAR/Dependency.php';
require_once 'PEAR/Remote.php';
require_once 'System.php';
/**
* Administration class used to download PEAR packages and maintain the
* installed package database.
*
* @since PEAR 1.4
* @author Greg Beaver <cellog@php.net>
*/
class PEAR_Downloader extends PEAR_Common
{
/**
* @var PEAR_Config
* @access private
*/
var $_config;
/**
* @var PEAR_Registry
* @access private
*/
var $_registry;
/**
* @var PEAR_Remote
* @access private
*/
var $_remote;
/**
* Preferred Installation State (snapshot, devel, alpha, beta, stable)
* @var string|null
* @access private
*/
var $_preferredState;
/**
* Options from command-line passed to Install.
*
* Recognized options:<br />
* - onlyreqdeps : install all required dependencies as well
* - alldeps : install all dependencies, including optional
* - installroot : base relative path to install files in
* - force : force a download even if warnings would prevent it
* @see PEAR_Command_Install
* @access private
* @var array
*/
var $_options;
/**
* Downloaded Packages after a call to download().
*
* Format of each entry:
*
* <code>
* array('pkg' => 'package_name', 'file' => '/path/to/local/file',
* 'info' => array() // parsed package.xml
* );
* </code>
* @access private
* @var array
*/
var $_downloadedPackages = array();
/**
* Packages slated for download.
*
* This is used to prevent downloading a package more than once should it be a dependency
* for two packages to be installed.
* Format of each entry:
*
* <pre>
* array('package_name1' => parsed package.xml, 'package_name2' => parsed package.xml,
* );
* </pre>
* @access private
* @var array
*/
var $_toDownload = array();
/**
* Array of every package installed, with names lower-cased.
*
* Format:
* <code>
* array('package1' => 0, 'package2' => 1, );
* </code>
* @var array
*/
var $_installed = array();
/**
* @var array
* @access private
*/
var $_errorStack = array();
// {{{ PEAR_Downloader()
function PEAR_Downloader(&$ui, $options, &$config)
{
$this->_options = $options;
$this->_config = &$config;
$this->_preferredState = $this->_config->get('preferred_state');
if (!$this->_preferredState) {
// don't inadvertantly use a non-set preferred_state
$this->_preferredState = null;
}
$php_dir = $this->_config->get('php_dir');
if (isset($this->_options['installroot'])) {
if (substr($this->_options['installroot'], -1) == DIRECTORY_SEPARATOR) {
$this->_options['installroot'] = substr($this->_options['installroot'], 0, -1);
}
$php_dir = $this->_prependPath($php_dir, $this->_options['installroot']);
}
$this->_registry = &new PEAR_Registry($php_dir);
$this->_remote = &new PEAR_Remote($config);
if (isset($this->_options['alldeps']) || isset($this->_options['onlyreqdeps'])) {
$this->_installed = $this->_registry->listPackages();
array_walk($this->_installed, create_function('&$v,$k','$v = strtolower($v);'));
$this->_installed = array_flip($this->_installed);
}
parent::PEAR_Common($ui);
}
// }}}
// {{{ _downloadFile()
/**
* @param string filename to download
* @param string version/state
* @param string original value passed to command-line
* @param string|null preferred state (snapshot/devel/alpha/beta/stable)
* Defaults to configuration preferred state
* @return null|PEAR_Error|string
* @access private
*/
function _downloadFile($pkgfile, $version, $origpkgfile, $state = null)
{
if (is_null($state)) {
$state = $this->_preferredState;
}
// {{{ check the package filename, and whether it's already installed
$need_download = false;
if (preg_match('#^(http|ftp)://#', $pkgfile)) {
$need_download = true;
} elseif (!@is_file($pkgfile)) {
if ($this->validPackageName($pkgfile)) {
if ($this->_registry->packageExists($pkgfile)) {
if (empty($this->_options['upgrade']) && empty($this->_options['force'])) {
$errors[] = "$pkgfile already installed";
return;
}
}
$pkgfile = $this->getPackageDownloadUrl($pkgfile, $version);
$need_download = true;
} else {
if (strlen($pkgfile)) {
$errors[] = "Could not open the package file: $pkgfile";
} else {
$errors[] = "No package file given";
}
return;
}
}
// }}}
// {{{ Download package -----------------------------------------------
if ($need_download) {
$downloaddir = $this->_config->get('download_dir');
if (empty($downloaddir)) {
if (PEAR::isError($downloaddir = System::mktemp('-d'))) {
return $downloaddir;
}
$this->log(3, '+ tmp dir created at ' . $downloaddir);
}
$callback = $this->ui ? array(&$this, '_downloadCallback') : null;
$this->pushErrorHandling(PEAR_ERROR_RETURN);
$file = $this->downloadHttp($pkgfile, $this->ui, $downloaddir, $callback);
$this->popErrorHandling();
if (PEAR::isError($file)) {
if ($this->validPackageName($origpkgfile)) {
if (!PEAR::isError($info = $this->_remote->call('package.info',
$origpkgfile))) {
if (!count($info['releases'])) {
return $this->raiseError('Package ' . $origpkgfile .
' has no releases');
} else {
return $this->raiseError('No releases of preferred state "'
. $state . '" exist for package ' . $origpkgfile .
'. Use ' . $origpkgfile . '-state to install another' .
' state (like ' . $origpkgfile .'-beta)',
PEAR_INSTALLER_ERROR_NO_PREF_STATE);
}
} else {
return $pkgfile;
}
} else {
return $this->raiseError($file);
}
}
$pkgfile = $file;
}
// }}}
return $pkgfile;
}
// }}}
// {{{ getPackageDownloadUrl()
function getPackageDownloadUrl($package, $version = null)
{
if ($version) {
$package .= "-$version";
}
if ($this === null || $this->_config === null) {
$package = "http://pear.php.net/get/$package";
} else {
$package = "http://" . $this->_config->get('master_server') .
"/get/$package";
}
if (!extension_loaded("zlib")) {
$package .= '?uncompress=yes';
}
return $package;
}
// }}}
// {{{ extractDownloadFileName($pkgfile, &$version)
function extractDownloadFileName($pkgfile, &$version)
{
if (@is_file($pkgfile)) {
return $pkgfile;
}
// regex defined in Common.php
if (preg_match(PEAR_COMMON_PACKAGE_DOWNLOAD_PREG, $pkgfile, $m)) {
$version = (isset($m[3])) ? $m[3] : null;
return $m[1];
}
$version = null;
return $pkgfile;
}
// }}}
// }}}
// {{{ getDownloadedPackages()
/**
* Retrieve a list of downloaded packages after a call to {@link download()}.
*
* Also resets the list of downloaded packages.
* @return array
*/
function getDownloadedPackages()
{
$ret = $this->_downloadedPackages;
$this->_downloadedPackages = array();
$this->_toDownload = array();
return $ret;
}
// }}}
// {{{ download()
/**
* Download any files and their dependencies, if necessary
*
* @param array a mixed list of package names, local files, or package.xml
*/
function download($packages)
{
$mywillinstall = array();
$state = $this->_preferredState;
// {{{ download files in this list if necessary
foreach($packages as $pkgfile) {
if (!is_file($pkgfile)) {
$pkgfile = $this->_downloadNonFile($pkgfile);
if (PEAR::isError($pkgfile)) {
return $pkgfile;
}
if ($pkgfile === false) {
continue;
}
} // end is_file()
$tempinfo = $this->infoFromAny($pkgfile);
if (isset($this->_options['alldeps']) || isset($this->_options['onlyreqdeps'])) {
// ignore dependencies if there are any errors
if (!PEAR::isError($tempinfo)) {
$mywillinstall[strtolower($tempinfo['package'])] = @$tempinfo['release_deps'];
}
}
$this->_downloadedPackages[] = array('pkg' => $tempinfo['package'],
'file' => $pkgfile, 'info' => $tempinfo);
} // end foreach($packages)
// }}}
// {{{ extract dependencies from downloaded files and then download
// them if necessary
if (isset($this->_options['alldeps']) || isset($this->_options['onlyreqdeps'])) {
$deppackages = array();
foreach ($mywillinstall as $package => $alldeps) {
if (!is_array($alldeps)) {
// there are no dependencies
continue;
}
foreach($alldeps as $info) {
if ($info['type'] != 'pkg') {
continue;
}
$ret = $this->_processDependency($info, $mywillinstall);
if ($ret === false) {
continue;
}
if (PEAR::isError($ret)) {
return $ret;
}
$deppackages[] = $ret;
} // foreach($alldeps
}
if (count($deppackages)) {
// check dependencies' dependencies
// combine the list of packages to install
$temppack = array();
foreach($this->_downloadedPackages as $p) {
$temppack[] = strtolower($p['info']['package']);
}
foreach($deppackages as $pack) {
$temppack[] = strtolower($pack);
}
$this->_toDownload = array_merge($this->_toDownload, $temppack);
$this->download($deppackages);
}
} // }}} if --alldeps or --onlyreqdeps
}
// }}}
// {{{ _downloadNonFile($pkgfile)
/**
* @return false|PEAR_Error|string false if loop should be broken out of,
* string if the file was downloaded,
* PEAR_Error on exception
* @access private
*/
function _downloadNonFile($pkgfile)
{
$origpkgfile = $pkgfile;
$state = null;
$pkgfile = $this->extractDownloadFileName($pkgfile, $version);
if (preg_match('#^(http|ftp)://#', $pkgfile)) {
$pkgfile = $this->_downloadFile($pkgfile, $version, $origpkgfile);
if (PEAR::isError($pkgfile)) {
return $pkgfile;
}
$tempinfo = $this->infoFromAny($pkgfile);
if (isset($this->_options['alldeps']) || isset($this->_options['onlyreqdeps'])) {
// ignore dependencies if there are any errors
if (!PEAR::isError($tempinfo)) {
$mywillinstall[strtolower($tempinfo['package'])] = @$tempinfo['release_deps'];
}
}
$this->_downloadedPackages[] = array('pkg' => $tempinfo['package'],
'file' => $pkgfile, 'info' => $tempinfo);
return false;
}
if (!$this->validPackageName($pkgfile)) {
return $this->raiseError("Package name '$pkgfile' not valid");
}
// ignore packages that are installed unless we are upgrading
$curinfo = $this->_registry->packageInfo($pkgfile);
if ($this->_registry->packageExists($pkgfile)
&& empty($this->_options['upgrade']) && empty($this->_options['force'])) {
$this->log(0, "Package '{$curinfo['package']}' already installed, skipping");
return false;
}
$curver = $curinfo['version'];
$releases = $this->_remote->call('package.info', $pkgfile, 'releases');
if (!count($releases)) {
return $this->raiseError("No releases found for package '$pkgfile'");
}
// Want a specific version/state
if ($version !== null) {
// Passed Foo-1.2
if ($this->validPackageVersion($version)) {
if (!isset($releases[$version])) {
return $this->raiseError("No release with version '$version' found for '$pkgfile'");
}
// Passed Foo-alpha
} elseif (in_array($version, $this->getReleaseStates())) {
$state = $version;
$version = 0;
foreach ($releases as $ver => $inf) {
if ($inf['state'] == $state && version_compare("$version", "$ver") < 0) {
$version = $ver;
}
}
if ($version == 0) {
return $this->raiseError("No release with state '$state' found for '$pkgfile'");
}
// invalid postfix passed
} else {
return $this->raiseError("Invalid postfix '-$version', be sure to pass a valid PEAR ".
"version number or release state");
}
// Guess what to download
} else {
$states = $this->betterStates($this->_preferredState, true);
$possible = false;
$version = 0;
foreach ($releases as $ver => $inf) {
if (in_array($inf['state'], $states) && version_compare("$version", "$ver") < 0) {
$version = $ver;
}
}
if ($version == 0 && !isset($this->_options['force'])) {
return $this->raiseError('No release with state equal to: \'' . implode(', ', $states) .
"' found for '$pkgfile'");
} elseif ($version == 0) {
$this->log(0, "Warning: $pkgfile is state '$inf[state]' which is less stable " .
"than state '$state'");
}
}
// Check if we haven't already the version
if (empty($this->_options['force'])) {
if ($curinfo['version'] == $version) {
$this->log(0, "Package '{$curinfo['package']}-{$curinfo['version']}' already installed, skipping");
return false;
} elseif (version_compare("$version", "{$curinfo['version']}") < 0) {
$this->log(0, "Already got '{$curinfo['package']}-{$curinfo['version']}' greater than requested '$version', skipping");
return false;
}
}
return $this->_downloadFile($pkgfile, $version, $origpkgfile, $state);
}
// }}}
// {{{ _processDependency($info)
/**
* Process a dependency, download if necessary
* @param array dependency information from PEAR_Remote call
* @param array packages that will be installed in this iteration
* @return false|string|PEAR_Error
* @access private
*/
function _processDependency($info, $mywillinstall)
{
$state = $this->_preferredState;
if (!isset($this->_options['alldeps']) && isset($info['optional']) &&
$info['optional'] == 'yes') {
// skip optional deps
$this->log(0, "skipping Package $package optional dependency $info[name]");
return false;
}
// {{{ get releases
$releases = $this->_remote->call('package.info', $info['name'], 'releases');
if (PEAR::isError($releases)) {
return $releases;
}
if (!count($releases)) {
if (!isset($this->_installed[strtolower($info['name'])])) {
$this->pushError("Package $package dependency $info[name] ".
"has no releases");
}
return false;
}
$found = false;
$save = $releases;
while(count($releases) && !$found) {
if (!empty($state) && $state != 'any') {
list($release_version, $release) = each($releases);
if ($state != $release['state'] &&
!in_array($release['state'], $this->betterStates($state)))
{
// drop this release - it ain't stable enough
array_shift($releases);
} else {
$found = true;
}
} else {
$found = true;
}
}
if (!count($releases) && !$found) {
$get = array();
foreach($save as $release) {
$get = array_merge($get,
$this->betterStates($release['state'], true));
}
$savestate = array_shift($get);
$this->pushError( "Release for $package dependency $info[name] " .
"has state '$savestate', requires $state");
continue;
}
if (in_array(strtolower($info['name']), $this->_toDownload) ||
isset($mywillinstall[strtolower($info['name'])])) {
// skip upgrade check for packages we will install
continue;
}
if (!isset($this->_installed[strtolower($info['name'])])) {
// check to see if we can install the specific version required
if ($info['rel'] == 'eq') {
return $info['name'] . '-' . $info['version'];
}
// skip upgrade check for packages we don't have installed
return $info['name'];
}
// }}}
// {{{ see if a dependency must be upgraded
$inst_version = $this->_registry->packageInfo($info['name'], 'version');
if (!isset($info['version'])) {
// this is a rel='has' dependency, check against latest
if (version_compare($release_version, $inst_version, 'le')) {
return false;
} else {
return $info['name'];
}
}
if (version_compare($info['version'], $inst_version, 'le')) {
// installed version is up-to-date
return false;
}
return $info['name'];
}
// }}}
// {{{ pushError($errmsg, $code)
/**
* @param string
* @param integer
*/
function pushError($errmsg, $code = -1)
{
array_push($this->_errorStack, array($errmsg, $code));
}
// }}}
// {{{ getErrorMsgs()
function getErrorMsgs()
{
$msgs = array();
$errs = $this->_errorStack;
foreach ($errs as $err) {
$msgs[] = $err[0];
}
$this->_errorStack = array();
return $msgs;
}
// }}}
}
// }}}
?>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,130 @@
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE package SYSTEM "package.dtd">
<package version="1.0">
<name>PEAR</name>
<summary>PEAR Base System</summary>
<description>The PEAR package contains:
* the PEAR base class
* the PEAR_Error error handling mechanism
* the PEAR installer, for creating, distributing
and installing packages
* the OS_Guess class for retrieving info about the OS
where PHP is running on
* the System class for quick handling common operations
with files and directories
</description>
<license>PHP License</license>
<maintainers>
<maintainer>
<user>ssb</user>
<role>lead</role>
<name>Stig Sæther Bakken</name>
<email>stig@php.net</email>
</maintainer>
<maintainer>
<user>cox</user>
<role>lead</role>
<name>Tomas V.V.Cox</name>
<email>cox@idecnet.com</email>
</maintainer>
<maintainer>
<user>mj</user>
<role>developer</role>
<name>Martin Jansen</name>
<email>mj@php.net</email>
</maintainer>
<maintainer>
<user>pajoye</user>
<role>developer</role>
<name>Pierre-Alain Joye</name>
<email>pajoye@pearfr.org</email>
</maintainer>
<maintainer>
<user>cellog</user>
<role>developer</role>
<name>Greg Beaver</name>
<email>cellog@php.net</email>
</maintainer>
</maintainers>
<release>
<version>1.4a1</version>
<date>2003-11-17</date>
<state>alpha</state>
<notes>
PEAR Installer:
* Bug #171 --alldeps with a rel=&quot;eq&quot; should install the required version, if possible
* Bug #249 installing from an url doesnt work
* Bug #248 --force command does not work as expected
* Bug #293 [Patch] PEAR_Error not calling static method callbacks for error-handler
* Bug #324 pear -G gives Fatal Error (PHP-GTK not installed, but error is at engine level)
</notes>
<provides type="class" name="OS_Guess" />
<provides type="class" name="System" />
<provides type="function" name="md5_file" />
<filelist>
<file role="data" name="package.dtd"/>
<file role="data" name="template.spec"/>
<file role="php" name="PEAR.php"/>
<file role="php" name="System.php"/>
<dir name="PEAR">
<file role="php" name="Autoloader.php"/>
<file role="php" name="Command.php"/>
<dir name="Command">
<file role="php" name="Auth.php"/>
<file role="php" name="Build.php"/>
<file role="php" name="Common.php"/>
<file role="php" name="Config.php"/>
<file role="php" name="Install-using-downloader.php" install-as="PEAR/Command/Install.php"/>
<file role="php" name="Package.php"/>
<file role="php" name="Registry.php"/>
<file role="php" name="Remote.php"/>
<file role="php" name="Mirror.php"/>
</dir>
<file role="php" name="Common.php"/>
<file role="php" name="Config.php"/>
<file role="php" name="Dependency.php"/>
<dir name="Frontend">
<file role="php" name="CLI.php"/>
</dir>
<file role="php" name="Builder.php"/>
<file role="php" name="Installer-minus-download.php" install-as="PEAR/Installer.php" />
<file role="php" name="Downloader.php"/>
<file role="php" name="Packager.php"/>
<file role="php" name="Registry.php"/>
<file role="php" name="Remote.php"/>
</dir>
<dir name="OS">
<file role="php" name="Guess.php"/>
</dir>
<dir name="scripts" baseinstalldir="/">
<file role="script" install-as="pear" name="pear.sh">
<replace from="@php_bin@" to="php_bin" type="pear-config"/>
<replace from="@php_dir@" to="php_dir" type="pear-config"/>
<replace from="@pear_version@" to="version" type="package-info"/>
<replace from="@include_path@" to="php_dir" type="pear-config"/>
</file>
<file role="script" platform="windows" install-as="pear.bat" name="pear.bat">
<replace from="@bin_dir@" to="bin_dir" type="pear-config"/>
<replace from="@php_bin@" to="php_bin" type="pear-config"/>
<replace from="@include_path@" to="php_dir" type="pear-config"/>
</file>
<file role="php" install-as="pearcmd.php" name="pearcmd.php">
<replace from="@php_bin@" to="php_bin" type="pear-config"/>
<replace from="@php_dir@" to="php_dir" type="pear-config"/>
<replace from="@pear_version@" to="version" type="package-info"/>
<replace from="@include_path@" to="php_dir" type="pear-config"/>
</file>
</dir>
</filelist>
<deps>
<dep type="php" rel="ge" version="4.1"/>
<dep type="pkg" rel="ge" version="1.1">Archive_Tar</dep>
<dep type="pkg" rel="ge" version="1.0">Console_Getopt</dep>
<dep type="pkg" rel="ge" version="1.0.4">XML_RPC</dep>
<dep type="ext" rel="has" optional="yes">xmlrpc</dep>
<dep type="ext" rel="has">xml</dep>
</deps>
</release>
</package>