From 5252f3faa9a9f4d7dd5f56513d6414b0c5c4fba6 Mon Sep 17 00:00:00 2001 From: Greg Beaver Date: Thu, 4 Dec 2003 02:11:40 +0000 Subject: [PATCH] merge downloader code into HEAD - it works fix bug found in uninstall --- pear/PEAR/Command/Install.php | 20 +- pear/PEAR/Installer.php | 422 +--------------------------------- pear/package-PEAR.xml | 3 + 3 files changed, 25 insertions(+), 420 deletions(-) diff --git a/pear/PEAR/Command/Install.php b/pear/PEAR/Command/Install.php index 9cac11a0585..38443ce855e 100644 --- a/pear/PEAR/Command/Install.php +++ b/pear/PEAR/Command/Install.php @@ -251,6 +251,7 @@ package if needed. function doInstall($command, $options, $params) { + require_once 'PEAR/Downloader.php'; if (empty($this->installer)) { $this->installer = &new PEAR_Installer($this->ui); } @@ -260,7 +261,7 @@ package if needed. if ($command == 'upgrade-all') { include_once "PEAR/Remote.php"; $options['upgrade'] = true; - $remote = new PEAR_Remote($this->config); + $remote = &new PEAR_Remote($this->config); $state = $this->config->get('preferred_state'); if (empty($state) || $state == 'any') { $latest = $remote->call("package.listLatestReleases"); @@ -288,21 +289,18 @@ package if needed. $this->ui->outputData(array('data' => "Will upgrade $package"), $command); } } + $this->downloader = &new PEAR_Downloader($this->ui, $options, $this->config); $errors = array(); $downloaded = array(); - $this->installer->download($params, $options, $this->config, $downloaded, - $errors); - if ($command != 'upgrade-all') { - for ($i = 0; $i < count($params); $i++) { - $params[$i] = $this->installer->extractDownloadFileName($params[$i], $_tmp); - } - } + $this->downloader->download($params); + $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']); @@ -346,7 +344,7 @@ package if needed. $newparams[] = $info; } } - PEAR_Common::sortPkgDeps($newparams, true); + $this->installer->sortPkgDeps($newparams, true); $params = array(); foreach($newparams as $info) { $params[] = $info['info']['package']; @@ -377,7 +375,7 @@ package if needed. function doBundle($command, $options, $params) { if (empty($this->installer)) { - $this->installer = &new PEAR_Installer($this->ui); + $this->installer = &new PEAR_Downloader($this->ui); } $installer = &$this->installer; if (sizeof($params) < 1) { @@ -461,5 +459,7 @@ package if needed. // }}} } + // }}} + } ?> diff --git a/pear/PEAR/Installer.php b/pear/PEAR/Installer.php index 1b7f5e4d747..4e22964e640 100644 --- a/pear/PEAR/Installer.php +++ b/pear/PEAR/Installer.php @@ -23,6 +23,7 @@ require_once 'PEAR/Common.php'; require_once 'PEAR/Registry.php'; require_once 'PEAR/Dependency.php'; +require_once 'PEAR/Downloader.php'; require_once 'System.php'; define('PEAR_INSTALLER_OK', 1); @@ -43,8 +44,9 @@ define('PEAR_INSTALLER_ERROR_NO_PREF_STATE', 2); * @since PHP 4.0.2 * @author Stig Bakken * @author Martin Jansen + * @author Greg Beaver */ -class PEAR_Installer extends PEAR_Common +class PEAR_Installer extends PEAR_Downloader { // {{{ properties @@ -528,26 +530,6 @@ class PEAR_Installer extends PEAR_Common $this->file_operations = array(); } - // }}} - // {{{ 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; - } - // }}} // {{{ mkDirHier($dir) @@ -572,106 +554,6 @@ class PEAR_Installer extends PEAR_Common return $path; } - // }}} - // {{{ 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; - } - - // }}} - // {{{ _downloadFile() - /** - * @param string filename to download - * @param PEAR_Config Configuration object - * @param array options returned from Console_GetOpt - * @param array empty array to populate with error messages, if any - * @param string version/state - * @param string original value passed to command-line - * @param string preferred state (snapshot/devel/alpha/beta/stable) - * @return null|PEAR_Error|string - * @access private - */ - function _downloadFile($pkgfile, &$config, $options, &$errors, $version, - $origpkgfile, $state) - { - // {{{ 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($options['upgrade']) && empty($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 = $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)) { - include_once 'PEAR/Remote.php'; - $remote = new PEAR_Remote($config); - if (!PEAR::isError($info = $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; - } - // }}} // {{{ download() @@ -693,269 +575,19 @@ class PEAR_Installer extends PEAR_Common * @param false private recursion variable * @param false private recursion variable * @param false private recursion variable + * @deprecated in favor of PEAR_Downloader */ function download($packages, $options, &$config, &$installpackages, &$errors, $installed = false, $willinstall = false, $state = false) { - // recognized options: - // - onlyreqdeps : install all required dependencies as well - // - alldeps : install all dependencies, including optional - // - // {{{ determine preferred state, installroot, etc - if (!$willinstall) { - $willinstall = array(); - } - if (!$state) { - $state = $config->get('preferred_state'); - if (!$state) { - // don't inadvertantly use a non-set preferred_state - $state = null; - } - } - $mywillinstall = array(); - $php_dir = $config->get('php_dir'); - if (isset($options['installroot'])) { - if (substr($options['installroot'], -1) == DIRECTORY_SEPARATOR) { - $options['installroot'] = substr($options['installroot'], 0, -1); - } - $php_dir = $this->_prependPath($php_dir, $options['installroot']); - $this->installroot = $options['installroot']; - } else { - $this->installroot = ''; - } - // }}} - $this->registry = &new PEAR_Registry($php_dir); - - // {{{ download files in this list if necessary - foreach($packages as $pkgfile) { - if (!is_file($pkgfile)) { - $origpkgfile = $pkgfile; - $pkgfile = $this->extractDownloadFileName($pkgfile, $version); - if (preg_match('#^(http|ftp)://#', $pkgfile)) { - $pkgfile = $this->_downloadFile($pkgfile, $config, $options, - $errors, $version, $origpkgfile, - $state); - if (PEAR::isError($pkgfile)) { - return $pkgfile; - } - $tempinfo = $this->infoFromAny($pkgfile); - if (isset($options['alldeps']) || isset($options['onlyreqdeps'])) { - // ignore dependencies if there are any errors - if (!PEAR::isError($tempinfo)) { - $mywillinstall[strtolower($tempinfo['package'])] = @$tempinfo['release_deps']; - } - } - $installpackages[] = array('pkg' => $tempinfo['package'], - 'file' => $pkgfile, 'info' => $tempinfo); - continue; - } - 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($options['upgrade']) && empty($options['force'])) { - $this->log(0, "Package '{$curinfo['package']}' already installed, skipping"); - continue; - } - // Retrieve remote release list - include_once 'PEAR/Remote.php'; - $curver = $curinfo['version']; - $remote = &new PEAR_Remote($config); - $releases = $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($state, 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($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($options['force'])) { - if ($curinfo['version'] == $version) { - $this->log(0, "Package '{$curinfo['package']}-{$curinfo['version']}' already installed, skipping"); - continue; - } elseif (version_compare("$version", "{$curinfo['version']}") < 0) { - $this->log(0, "Already got '{$curinfo['package']}-{$curinfo['version']}' greater than requested '$version', skipping"); - continue; - } - } - $pkgfile = $this->_downloadFile($pkgfile, $config, $options, - $errors, $version, $origpkgfile, - $state); - if (PEAR::isError($pkgfile)) { - return $pkgfile; - } - } // end is_file() - $tempinfo = $this->infoFromAny($pkgfile); - if (isset($options['alldeps']) || isset($options['onlyreqdeps'])) { - // ignore dependencies if there are any errors - if (!PEAR::isError($tempinfo)) { - $mywillinstall[strtolower($tempinfo['package'])] = @$tempinfo['release_deps']; - } - } - $installpackages[] = array('pkg' => $tempinfo['package'], - 'file' => $pkgfile, 'info' => $tempinfo); - } // end foreach($packages) - // }}} - - // {{{ extract dependencies from downloaded files and then download - // them if necessary - if (isset($options['alldeps']) || isset($options['onlyreqdeps'])) { - include_once "PEAR/Remote.php"; - $remote = new PEAR_Remote($config); - if (!$installed) { - $installed = $this->registry->listPackages(); - array_walk($installed, create_function('&$v,$k','$v = strtolower($v);')); - $installed = array_flip($installed); - } - $deppackages = array(); - // {{{ construct the list of dependencies for each file - foreach ($mywillinstall as $package => $alldeps) { - if (!is_array($alldeps)) { - continue; - } - foreach($alldeps as $info) { - if ($info['type'] != 'pkg') { - continue; - } - if (!isset($options['alldeps']) && isset($info['optional']) && - $info['optional'] == 'yes') { - // skip optional deps - $this->log(0, "skipping Package $package optional dependency $info[name]"); - continue; - } - // {{{ get releases - $releases = $remote->call('package.info', $info['name'], 'releases'); - if (PEAR::isError($releases)) { - return $releases; - } - if (!count($releases)) { - if (!isset($installed[strtolower($info['name'])])) { - $errors[] = "Package $package dependency $info[name] ". - "has no releases"; - } - continue; - } - $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); - $errors[] = "Release for $package dependency $info[name] " . - "has state '$savestate', requires $state"; - continue; - } - if (in_array(strtolower($info['name']), $willinstall) || - isset($mywillinstall[strtolower($info['name'])])) { - // skip upgrade check for packages we will install - continue; - } - if (!isset($installed[strtolower($info['name'])])) { - // check to see if we can install the specific version required - if ($info['rel'] == 'eq') { - $deppackages[] = $info['name'] . '-' . $info['version']; - continue; - } - // skip upgrade check for packages we don't have installed - $deppackages[] = $info['name']; - continue; - } - // }}} - - // {{{ 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')) { - continue; - } else { - $deppackages[] = $info['name']; - continue; - } - } - if (version_compare($info['version'], $inst_version, 'le')) { - // installed version is up-to-date - continue; - } - $deppackages[] = $info['name']; - // }}} - } // foreach($alldeps - } - // }}} foreach($willinstall - - if (count($deppackages)) { - // check dependencies' dependencies - // combine the list of packages to install - $temppack = array(); - foreach($installpackages as $p) { - $temppack[] = strtolower($p['info']['package']); - } - foreach($deppackages as $pack) { - $temppack[] = strtolower($pack); - } - $willinstall = array_merge($willinstall, $temppack); - $this->download($deppackages, $options, $config, $installpackages, - $errors, $installed, $willinstall, $state); - } - } // }}} if --alldeps or --onlyreqdeps + // trickiness: initialize here + parent::PEAR_Downloader($this->ui, $options, $config); + $ret = parent::download($packages); + $errors = $this->getErrorMsgs(); + $installpackages = $this->getDownloadedPackages(); + trigger_error("PEAR Warning: PEAR_Installer::download() is deprecated " . + "in favor of PEAR_Downloader class", E_USER_WARNING); + return $ret; } // }}} @@ -1400,36 +1032,6 @@ class PEAR_Installer extends PEAR_Common return false; } - // }}} - // {{{ _downloadCallback() - - function _downloadCallback($msg, $params = null) - { - switch ($msg) { - case 'saveas': - $this->log(1, "downloading $params ..."); - break; - case 'done': - $this->log(1, '...done: ' . number_format($params, 0, '', ',') . ' bytes'); - break; - case 'bytesread': - static $bytes; - if (empty($bytes)) { - $bytes = 0; - } - if (!($bytes % 10240)) { - $this->log(1, '.', false); - } - $bytes += $params; - break; - case 'start': - $this->log(1, "Starting to download {$params[0]} (".number_format($params[1], 0, '', ',')." bytes)"); - break; - } - if (method_exists($this->ui, '_downloadCallback')) - $this->ui->_downloadCallback($msg, $params); - } - // }}} // {{{ _buildCallback() diff --git a/pear/package-PEAR.xml b/pear/package-PEAR.xml index 59fccc5a17b..0e044db31d6 100644 --- a/pear/package-PEAR.xml +++ b/pear/package-PEAR.xml @@ -58,6 +58,8 @@ PEAR Installer: * 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) +* Moved download code into its own class +* Fully unit tested the installer and downloader, plus PEAR_Common @@ -85,6 +87,7 @@ PEAR Installer: +