/** * retrieves a list of avaible Packages from master server * and downloads them * * @access public * @param string $command the command * @param array $options the command options before the command * @param array $params the stuff after the command name * @return bool true if succesful * @throw PEAR_Error */ function doDownloadAll($command, $options, $params) { $this->config->set("php_dir", "."); $remote = new PEAR_Remote($this->config); $remoteInfo = $remote->call("package.listAll"); if (PEAR::isError($remoteInfo)) { return $remoteInfo; } $cmd =& PEAR_Command::factory("download", $this->config); if (PEAR::isError($cmd)) { return $cmd; } foreach ($remoteInfo as $pkgn => $pkg) { /** * Error handling not neccesary, because already done by * the download command */ $cmd->run("download", array(), array($pkgn)); } return true; }
/** * Execute the 'login' command. * * @param string $command command name * * @param array $options option_name => value * * @param array $params list of additional parameters * * @return bool TRUE on success, FALSE for unknown commands, or * a PEAR error on failure * * @access public */ function doLogin($command, $options, $params) { $server = $this->config->get('master_server'); $remote = new PEAR_Remote($this->config); $username = $this->config->get('username'); if (empty($username)) { $username = @$_ENV['USER']; } $this->ui->outputData("Logging in to {$server}.", $command); list($username, $password) = $this->ui->userDialog($command, array('Username', 'Password'), array('text', 'password'), array($username, '')); $username = trim($username); $password = trim($password); $this->config->set('username', $username); $this->config->set('password', $password); $remote->expectError(401); $ok = $remote->call('logintest'); $remote->popExpect(); if ($ok === true) { $this->ui->outputData("Logged in.", $command); $this->config->store(); } else { return $this->raiseError("Login failed!"); } }
/** * @param array dependency array * @access private */ function _getDepPackageDownloadUrl($dep, $parr) { $xsdversion = isset($dep['rel']) ? '1.0' : '2.0'; $curchannel = $this->config->get('default_channel'); if (isset($dep['channel'])) { $remotechannel = $dep['channel']; } else { $remotechannel = 'pear.php.net'; } if (!$this->_registry->channelExists($remotechannel)) { do { if ($this->config->get('auto_discover')) { if ($this->discover($remotechannel)) { break; } } return PEAR::raiseError('Unknown remote channel: ' . $remotechannel); } while (false); } $this->configSet('default_channel', $remotechannel); $state = isset($parr['state']) ? $parr['state'] : $this->config->get('preferred_state'); if (isset($parr['state']) && isset($parr['version'])) { unset($parr['state']); } $chan =& $this->_registry->getChannel($remotechannel); if (PEAR::isError($chan)) { return $chan; } $version = $this->_registry->packageInfo($dep['name'], 'version', $remotechannel); if ($chan->supportsREST($this->config->get('preferred_mirror')) && ($base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror')))) { $rest =& $this->config->getREST('1.0', $this->_options); $url = $rest->getDepDownloadURL($base, $xsdversion, $dep, $parr, $state, $version); if (PEAR::isError($url)) { return $url; } if ($parr['channel'] != $curchannel) { $this->configSet('default_channel', $curchannel); } if (!is_array($url)) { return $url; } $url['raw'] = false; // no checking is necessary for REST if (!is_array($url['info'])) { return PEAR::raiseError('Invalid remote dependencies retrieved from REST - ' . 'this should never happen'); } if (isset($url['info']['required'])) { if (!class_exists('PEAR_PackageFile_v2')) { require_once 'PEAR/PackageFile/v2.php'; } $pf = new PEAR_PackageFile_v2(); $pf->setRawChannel($remotechannel); } else { if (!class_exists('PEAR_PackageFile_v1')) { require_once 'PEAR/PackageFile/v1.php'; } $pf = new PEAR_PackageFile_v1(); } $pf->setRawPackage($url['package']); $pf->setDeps($url['info']); $pf->setRawState($url['stability']); $url['info'] =& $pf; if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) { $ext = '.tar'; } else { $ext = '.tgz'; } if (is_array($url)) { if (isset($url['url'])) { $url['url'] .= $ext; } } return $url; } elseif ($chan->supports('xmlrpc', 'package.getDepDownloadURL', false, '1.1')) { if ($version) { $url = $this->_remote->call('package.getDepDownloadURL', $xsdversion, $dep, $parr, $state, $version); } else { $url = $this->_remote->call('package.getDepDownloadURL', $xsdversion, $dep, $parr, $state); } } else { $url = $this->_remote->call('package.getDepDownloadURL', $xsdversion, $dep, $parr, $state); } if ($parr['channel'] != $curchannel) { $this->configSet('default_channel', $curchannel); } if (!is_array($url)) { return $url; } if (isset($url['__PEAR_ERROR_CLASS__'])) { return PEAR::raiseError($url['message']); } $url['raw'] = $url['info']; $pkg =& $this->getPackagefileObject($this->config, $this->debug); PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); $pinfo =& $pkg->fromXmlString($url['info'], PEAR_VALIDATE_DOWNLOADING, 'remote'); PEAR::staticPopErrorHandling(); if (PEAR::isError($pinfo)) { if (!isset($this->_options['soft'])) { $this->log(0, $pinfo->getMessage()); } return PEAR::raiseError('Remote package.xml is not valid - this should never happen'); } $url['info'] =& $pinfo; if (is_array($url)) { if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) { $ext = '.tar'; } else { $ext = '.tgz'; } if (isset($url['url'])) { $url['url'] .= $ext; } } return $url; }
function doListUpgrades($command, $options, $params) { include_once "PEAR/Registry.php"; $remote = new PEAR_Remote($this->config); if (empty($params[0])) { $state = $this->config->get('preferred_state'); } else { $state = $params[0]; } $caption = 'Available Upgrades'; if (empty($state) || $state == 'any') { $latest = $remote->call("package.listLatestReleases"); } else { $latest = $remote->call("package.listLatestReleases", $state); $caption .= ' (' . $state . ')'; } $caption .= ':'; if (PEAR::isError($latest)) { return $latest; } $reg = new PEAR_Registry($this->config->get('php_dir')); $inst = array_flip($reg->listPackages()); $data = array('caption' => $caption, 'border' => 1, 'headline' => array('Package', 'Version', 'Size')); foreach ($latest as $package => $info) { if (!isset($inst[$package])) { // skip packages we don't have installed continue; } extract($info); $inst_version = $reg->packageInfo($package, 'version'); if (version_compare("{$version}", "{$inst_version}", "le")) { // installed version is up-to-date continue; } if ($filesize >= 20480) { $filesize += 1024 - $filesize % 1024; $fs = sprintf("%dkB", $filesize / 1024); } elseif ($filesize > 0) { $filesize += 103 - $filesize % 103; $fs = sprintf("%.1fkB", $filesize / 1024.0); } else { $fs = " -"; // XXX center instead } $data['data'][] = array($package, $version, $fs); } if (empty($data['data'])) { $this->ui->outputData('No upgrades available'); } else { $this->ui->outputData($data, $command); } return true; }
function doInstall($command, $options, $params) { if (empty($this->installer)) { $this->installer =& new PEAR_Installer($this->ui); } if ($command == 'upgrade') { $options[$command] = 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) { 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("will upgrade {$package}", $command); } } foreach ($params as $pkg) { $bn = basename($pkg); $info = $this->installer->install($pkg, $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; }
function doInstall($command, $options, $params) { 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); } } $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); } } if (count($errors)) { $err['data'] = array($errors); $err['headline'] = 'Install Errors'; $this->ui->outputData($err); return $this->raiseError("{$command} failed"); } $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; }
/** * 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 * @todo Add test for relation 'lt'/'le' -> make sure that the dependency requested is * in fact lower than the required value. This will be very important for BC dependencies */ function _processDependency($package, $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', true); 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}'"); return false; } if (in_array(strtolower($info['name']), $this->_toDownload) || isset($mywillinstall[strtolower($info['name'])])) { // skip upgrade check for packages we will install return false; } 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']; }
/** * Download any files and their dependencies, if necessary * * @param array a mixed list of package names, local files, or package.xml * @param PEAR_Config * @param array options from the command line * @param array this is the array that will be populated with packages to * install. Format of each entry: * * <code> * array('pkg' => 'package_name', 'file' => '/path/to/local/file', * 'info' => array() // parsed package.xml * ); * </code> * @param array this will be populated with any error messages * @param false private recursion variable * @param false private recursion variable * @param false private recursion variable */ 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 (!$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) { return $this->raiseError('No release with state equal to: \'' . implode(', ', $states) . "' found for '{$pkgfile}'"); } } // 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'])])) { // 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 }