/** * Rebuild the dependency DB by reading registry entries. * @return true|PEAR_Error */ function rebuildDB() { $depdb = array('_version' => $this->_version); if (!$this->hasWriteAccess()) { // allow startup for read-only with older Registry return $depdb; } $packages = $this->_registry->listAllPackages(); if (PEAR::isError($packages)) { return $packages; } foreach ($packages as $channel => $ps) { foreach ($ps as $package) { $package = $this->_registry->getPackage($package, $channel); if (PEAR::isError($package)) { return $package; } $this->_setPackageDeps($depdb, $package); } } $error = $this->_writeDepDB($depdb); if (PEAR::isError($error)) { return $error; } $this->_cache = $depdb; return true; }
/** * Sets up the fixture. * This method is called before a test is executed. * * @return void */ protected function setUp() { $reg = new PEAR_Registry(); if ($reg->getPackage("PEAR_Size") == null) { $this->markTestSkipped("PEAR_Size is not installed."); } $this->cli = new PEAR_Size_CLI(); $this->genericResponse = "Usage: pearsize [OPTIONS] [PACKAGE]\nDisplay information on how much space an installed PEAR package required.\n\n -a, --all display information for all installed packages\n -A, --allchannels list packages from all channels, not just the default one\n -c, --channel specify which channel\n -C, --csv output results in CSV format (sizes are measured in bytes).\n -h, --human-readable print sizes in human readable format (for example: 492 B 1KB 7MB)\n -H, --si likewise, but use powers of 1000 not 1024\n -t, --type specify what type of files are required for the report\n by default all types are assumed\n -s, --summarise display channel summary view\n -S, --fsort sort by file size\n -v, --verbose display more detailed information\n --help display this help and exit\n -V, --version output version information and exit\n -X, --xml output results in XML format\n -0, --killzero do not output zero values in verbose mode\n\nTypes:\nYou can specify a subset of roles/file-types to be listed in the report.\nThese roles are those as supported by the PEAR installer.\nThese are: data, doc, ext, php, script, src, test\n\nExamples:\n \$ pearsize --all\n \$ pearsize Console_Table\n \$ pearsize -ttest,doc Console_Table\n \$ pearsize --type=test,doc,php -h Console_Table Date_Holidays\n"; $this->genericIntegratedResponse = "Usage: pear size [OPTIONS] [PACKAGE]\nDisplay information on how much space an installed PEAR package required.\n\n -a, --all display information for all installed packages\n -A, --allchannels list packages from all channels, not just the default one\n -c, --channel specify which channel\n -C, --csv output results in CSV format (sizes are measured in bytes).\n -h, --human-readable print sizes in human readable format (for example: 492 B 1KB 7MB)\n -H, --si likewise, but use powers of 1000 not 1024\n -t, --type specify what type of files are required for the report\n by default all types are assumed\n -s, --summarise display channel summary view\n -S, --fsort sort by file size\n -v, --verbose display more detailed information\n --help display this help and exit\n -V, --version output version information and exit\n -X, --xml output results in XML format\n -0, --killzero do not output zero values in verbose mode\n\nTypes:\nYou can specify a subset of roles/file-types to be listed in the report.\nThese roles are those as supported by the PEAR installer.\nThese are: data, doc, ext, php, script, src, test\n\nExamples:\n \$ pear size --all\n \$ pear size Console_Table\n \$ pear size -ttest,doc Console_Table\n \$ pear size --type=test,doc,php -h Console_Table Date_Holidays\n"; }
/** * Return PEAR packages, versions, etc. * * @see PEAR_Registry, PEAR_Registry::listPackages() * @return array */ public function packages() { $reg = new PEAR_Registry(); $packages = $reg->listPackages(); $p = array(); foreach ($packages as $package) { $pkg = $reg->getPackage($package); $p[] = array('package' => $pkg->getName(), 'released' => $pkg->getDate(), 'version' => $pkg->getVersion(), 'state' => $pkg->getState()); } return array('packages' => $p); }
/** * Rebuild the dependency DB by reading registry entries. * @return true|PEAR_Error */ function rebuildDB() { $depdb = array('_version' => $this->_version); $packages = $this->_registry->listAllPackages(); foreach ($packages as $channel => $ps) { foreach ($ps as $package) { $package = $this->_registry->getPackage($package, $channel); $this->_setPackageDeps($depdb, $package); } } $error = $this->_writeDepDB($depdb); if (PEAR::isError($error)) { return $error; } $this->_cache = $depdb; return true; }
function doInstall($command, $options, $params) { if (!class_exists('PEAR_PackageFile')) { require_once 'PEAR/PackageFile.php'; } if (empty($this->installer)) { $this->installer =& $this->getInstaller($this->ui); } if ($command == 'upgrade' || $command == 'upgrade-all') { $options['upgrade'] = true; } else { $packages = $params; } if (isset($options['installroot']) && isset($options['packagingroot'])) { return $this->raiseError('ERROR: cannot use both --installroot and --packagingroot'); } $reg =& $this->config->getRegistry(); $instreg =& $reg; // instreg used to check if package is installed if (isset($options['packagingroot']) && !isset($options['upgrade'])) { $packrootphp_dir = $this->installer->_prependPath($this->config->get('php_dir', null, 'pear.php.net'), $options['packagingroot']); $instreg = new PEAR_Registry($packrootphp_dir); // other instreg! if ($this->config->get('verbose') > 2) { $this->ui->outputData('using package root: ' . $options['packagingroot']); } } $abstractpackages = array(); $otherpackages = array(); // parse params PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); foreach ($params as $param) { if (strpos($param, 'http://') === 0) { $otherpackages[] = $param; continue; } if (strpos($param, 'channel://') === false && @file_exists($param)) { if (isset($options['force'])) { $otherpackages[] = $param; continue; } $pkg = new PEAR_PackageFile($this->config); $pf = $pkg->fromAnyFile($param, PEAR_VALIDATE_DOWNLOADING); if (PEAR::isError($pf)) { $otherpackages[] = $param; continue; } if ($reg->packageExists($pf->getPackage(), $pf->getChannel()) && version_compare($pf->getVersion(), $reg->packageInfo($pf->getPackage(), 'version', $pf->getChannel()), '<=')) { if ($this->config->get('verbose')) { $this->ui->outputData('Ignoring installed package ' . $reg->parsedPackageNameToString(array('package' => $pf->getPackage(), 'channel' => $pf->getChannel()), true)); } continue; } $otherpackages[] = $param; continue; } $e = $reg->parsePackageName($param, $this->config->get('default_channel')); if (PEAR::isError($e)) { $otherpackages[] = $param; } else { $abstractpackages[] = $e; } } PEAR::staticPopErrorHandling(); // if there are any local package .tgz or remote static url, we can't // filter. The filter only works for abstract packages if (count($abstractpackages) && !isset($options['force'])) { // when not being forced, only do necessary upgrades/installs if (isset($options['upgrade'])) { $abstractpackages = $this->_filterUptodatePackages($abstractpackages, $command); } else { foreach ($abstractpackages as $i => $package) { if (isset($package['group'])) { // do not filter out install groups continue; } if ($instreg->packageExists($package['package'], $package['channel'])) { if ($this->config->get('verbose')) { $this->ui->outputData('Ignoring installed package ' . $reg->parsedPackageNameToString($package, true)); } unset($abstractpackages[$i]); } } } $abstractpackages = array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages); } elseif (count($abstractpackages)) { $abstractpackages = array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages); } $packages = array_merge($abstractpackages, $otherpackages); if (!count($packages)) { $this->ui->outputData('Nothing to ' . $command); return true; } $this->downloader =& $this->getDownloader($this->ui, $options, $this->config); $errors = array(); $binaries = array(); $downloaded = array(); $downloaded =& $this->downloader->download($packages); if (PEAR::isError($downloaded)) { return $this->raiseError($downloaded); } $errors = $this->downloader->getErrorMsgs(); if (count($errors)) { $err = array(); $err['data'] = array(); foreach ($errors as $error) { $err['data'][] = array($error); } $err['headline'] = 'Install Errors'; $this->ui->outputData($err); if (!count($downloaded)) { return $this->raiseError("{$command} failed"); } } $data = array('headline' => 'Packages that would be Installed'); if (isset($options['pretend'])) { foreach ($downloaded as $package) { $data['data'][] = array($reg->parsedPackageNameToString($package->getParsedPackage())); } $this->ui->outputData($data, 'pretend'); return true; } $this->installer->setOptions($options); $this->installer->sortPackagesForInstall($downloaded); if (PEAR::isError($err = $this->installer->setDownloadedPackages($downloaded))) { $this->raiseError($err->getMessage()); return true; } $extrainfo = array(); $binaries = array(); foreach ($downloaded as $param) { PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); $info = $this->installer->install($param, $options); PEAR::staticPopErrorHandling(); if (PEAR::isError($info)) { $oldinfo = $info; $pkg =& $param->getPackageFile(); if ($info->getCode() != PEAR_INSTALLER_NOBINARY) { if (!($info = $pkg->installBinary($this->installer))) { $this->ui->outputData('ERROR: ' . $oldinfo->getMessage()); continue; } // we just installed a different package than requested, // let's change the param and info so that the rest of this works $param = $info[0]; $info = $info[1]; } } if (is_array($info)) { if ($param->getPackageType() == 'extsrc' || $param->getPackageType() == 'extbin' || $param->getPackageType() == 'zendextsrc' || $param->getPackageType() == 'zendextbin') { $pkg =& $param->getPackageFile(); if ($instbin = $pkg->getInstalledBinary()) { $instpkg =& $instreg->getPackage($instbin, $pkg->getChannel()); } else { $instpkg =& $instreg->getPackage($pkg->getPackage(), $pkg->getChannel()); } foreach ($instpkg->getFilelist() as $name => $atts) { $pinfo = pathinfo($atts['installed_as']); if (!isset($pinfo['extension']) || in_array($pinfo['extension'], array('c', 'h'))) { continue; // make sure we don't match php_blah.h } if (strpos($pinfo['basename'], 'php_') === 0 && $pinfo['extension'] == 'dll' || $pinfo['extension'] == 'so' || $pinfo['extension'] == 'sl') { $binaries[] = array($atts['installed_as'], $pinfo); break; } } if (count($binaries)) { foreach ($binaries as $pinfo) { PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); $ret = $this->enableExtension(array($pinfo[0]), $param->getPackageType()); PEAR::staticPopErrorHandling(); if (PEAR::isError($ret)) { $extrainfo[] = $ret->getMessage(); if ($param->getPackageType() == 'extsrc' || $param->getPackageType() == 'extbin') { $exttype = 'extension'; } else { ob_start(); phpinfo(INFO_GENERAL); $info = ob_get_contents(); ob_end_clean(); $debug = function_exists('leak') ? '_debug' : ''; $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : ''; $exttype = 'zend_extension' . $debug . $ts; } $extrainfo[] = 'You should add "' . $exttype . '=' . $pinfo[1]['basename'] . '" to php.ini'; } else { $extrainfo[] = 'Extension ' . $instpkg->getProvidesExtension() . ' enabled in php.ini'; } } } } if ($this->config->get('verbose') > 0) { $channel = $param->getChannel(); $label = $reg->parsedPackageNameToString(array('channel' => $channel, 'package' => $param->getPackage(), 'version' => $param->getVersion())); $out = array('data' => "{$command} ok: {$label}"); if (isset($info['release_warnings'])) { $out['release_warnings'] = $info['release_warnings']; } $this->ui->outputData($out, $command); if (!isset($options['register-only']) && !isset($options['offline'])) { if ($this->config->isDefinedLayer('ftp')) { PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); $info = $this->installer->ftpInstall($param); PEAR::staticPopErrorHandling(); if (PEAR::isError($info)) { $this->ui->outputData($info->getMessage()); $this->ui->outputData("remote install failed: {$label}"); } else { $this->ui->outputData("remote install ok: {$label}"); } } } } $deps = $param->getDeps(); if ($deps) { if (isset($deps['group'])) { $groups = $deps['group']; if (!isset($groups[0])) { $groups = array($groups); } foreach ($groups as $group) { if ($group['attribs']['name'] == 'default') { // default group is always installed, unless the user // explicitly chooses to install another group continue; } $extrainfo[] = $param->getPackage() . ': Optional feature ' . $group['attribs']['name'] . ' available (' . $group['attribs']['hint'] . ')'; } $extrainfo[] = $param->getPackage() . ': To install optional features use "pear install ' . $reg->parsedPackageNameToString(array('package' => $param->getPackage(), 'channel' => $param->getChannel()), true) . '#featurename"'; } } $pkg =& $instreg->getPackage($param->getPackage(), $param->getChannel()); // $pkg may be NULL if install is a 'fake' install via --packagingroot if (is_object($pkg)) { $pkg->setConfig($this->config); if ($list = $pkg->listPostinstallScripts()) { $pn = $reg->parsedPackageNameToString(array('channel' => $param->getChannel(), 'package' => $param->getPackage()), true); $extrainfo[] = $pn . ' has post-install scripts:'; foreach ($list as $file) { $extrainfo[] = $file; } $extrainfo[] = $param->getPackage() . ': Use "pear run-scripts ' . $pn . '" to finish setup.'; $extrainfo[] = 'DO NOT RUN SCRIPTS FROM UNTRUSTED SOURCES'; } } } else { return $this->raiseError("{$command} failed"); } } if (count($extrainfo)) { foreach ($extrainfo as $info) { $this->ui->outputData($info); } } return true; }
function _detect1($deps, $pname, $options, $params) { $this->_downloadDeps = array(); $skipnames = array(); foreach ($deps as $dep) { $nodownload = false; if ($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->_registry->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()); } if (@$skipnames[count($skipnames) - 1] == $this->_registry->parsedPackageNameToString($dep, true)) { array_pop($skipnames); } continue; } else { if (isset($dep['optional']) && $dep['optional'] == 'yes') { $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group . ' 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->_registry->packageInfo($newdep['name'], 'version', $newdep['channel']); } else { $version = $this->_registry->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); } if (@$skipnames[count($skipnames) - 1] == $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'])); 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'); } } }
/** * Verify that uninstalling packages passed in to command line is OK. * * @param PEAR_Installer $dl * @return PEAR_Error|true */ function validatePackageUninstall(&$dl) { if (PEAR::isError($this->_dependencydb)) { return $this->_dependencydb; } $params = array(); // construct an array of "downloaded" packages to fool the package dependency checker // into using these to validate uninstalls of circular dependencies $downloaded =& $dl->getUninstallPackages(); foreach ($downloaded as $i => $pf) { if (!class_exists('PEAR_Downloader_Package')) { require_once 'PEAR/Downloader/Package.php'; } $dp =& new PEAR_Downloader_Package($dl); $dp->setPackageFile($downloaded[$i]); $params[$i] =& $dp; } // check cache $memyselfandI = strtolower($this->_currentPackage['channel']) . '/' . strtolower($this->_currentPackage['package']); if (isset($dl->___uninstall_package_cache)) { $badpackages = $dl->___uninstall_package_cache; if (isset($badpackages[$memyselfandI]['warnings'])) { foreach ($badpackages[$memyselfandI]['warnings'] as $warning) { $dl->log(0, $warning[0]); } } if (isset($badpackages[$memyselfandI]['errors'])) { foreach ($badpackages[$memyselfandI]['errors'] as $error) { if (is_array($error)) { $dl->log(0, $error[0]); } else { $dl->log(0, $error->getMessage()); } } if (isset($this->_options['nodeps']) || isset($this->_options['force'])) { return $this->warning('warning: %s should not be uninstalled, other installed packages depend ' . 'on this package'); } return $this->raiseError('%s cannot be uninstalled, other installed packages depend on this package'); } return true; } // first, list the immediate parents of each package to be uninstalled $perpackagelist = array(); $allparents = array(); foreach ($params as $i => $param) { $a = array('channel' => strtolower($param->getChannel()), 'package' => strtolower($param->getPackage())); $deps = $this->_dependencydb->getDependentPackages($a); if ($deps) { foreach ($deps as $d) { $pardeps = $this->_dependencydb->getDependencies($d); foreach ($pardeps as $dep) { if (strtolower($dep['dep']['channel']) == $a['channel'] && strtolower($dep['dep']['name']) == $a['package']) { if (!isset($perpackagelist[$a['channel'] . '/' . $a['package']])) { $perpackagelist[$a['channel'] . '/' . $a['package']] = array(); } $perpackagelist[$a['channel'] . '/' . $a['package']][] = array($d['channel'] . '/' . $d['package'], $dep); if (!isset($allparents[$d['channel'] . '/' . $d['package']])) { $allparents[$d['channel'] . '/' . $d['package']] = array(); } if (!isset($allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']])) { $allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']] = array(); } $allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']][] = array($d, $dep); } } } } } // next, remove any packages from the parents list that are not installed $remove = array(); foreach ($allparents as $parent => $d1) { foreach ($d1 as $d) { if ($this->_registry->packageExists($d[0][0]['package'], $d[0][0]['channel'])) { continue; } $remove[$parent] = true; } } // next remove any packages from the parents list that are not passed in for // uninstallation foreach ($allparents as $parent => $d1) { foreach ($d1 as $d) { foreach ($params as $param) { if (strtolower($param->getChannel()) == $d[0][0]['channel'] && strtolower($param->getPackage()) == $d[0][0]['package']) { // found it continue 3; } } $remove[$parent] = true; } } // remove all packages whose dependencies fail // save which ones failed for error reporting $badchildren = array(); do { $fail = false; foreach ($remove as $package => $unused) { if (!isset($allparents[$package])) { continue; } foreach ($allparents[$package] as $kid => $d1) { foreach ($d1 as $depinfo) { if ($depinfo[1]['type'] != 'optional') { if (isset($badchildren[$kid])) { continue; } $badchildren[$kid] = true; $remove[$kid] = true; $fail = true; continue 2; } } } if ($fail) { // start over, we removed some children continue 2; } } } while ($fail); // next, construct the list of packages that can't be uninstalled $badpackages = array(); $save = $this->_currentPackage; foreach ($perpackagelist as $package => $packagedeps) { foreach ($packagedeps as $parent) { if (!isset($remove[$parent[0]])) { continue; } $packagename = $this->_registry->parsePackageName($parent[0]); $packagename['channel'] = $this->_registry->channelAlias($packagename['channel']); $pa = $this->_registry->getPackage($packagename['package'], $packagename['channel']); $packagename['package'] = $pa->getPackage(); $this->_currentPackage = $packagename; // parent is not present in uninstall list, make sure we can actually // uninstall it (parent dep is optional) $parentname['channel'] = $this->_registry->channelAlias($parent[1]['dep']['channel']); $pa = $this->_registry->getPackage($parent[1]['dep']['name'], $parent[1]['dep']['channel']); $parentname['package'] = $pa->getPackage(); $parent[1]['dep']['package'] = $parentname['package']; $parent[1]['dep']['channel'] = $parentname['channel']; if ($parent[1]['type'] == 'optional') { $test = $this->_validatePackageUninstall($parent[1]['dep'], false, $dl); if ($test !== true) { $badpackages[$package]['warnings'][] = $test; } } else { $test = $this->_validatePackageUninstall($parent[1]['dep'], true, $dl); if ($test !== true) { $badpackages[$package]['errors'][] = $test; } } } } $this->_currentPackage = $save; $dl->___uninstall_package_cache = $badpackages; if (isset($badpackages[$memyselfandI])) { if (isset($badpackages[$memyselfandI]['warnings'])) { foreach ($badpackages[$memyselfandI]['warnings'] as $warning) { $dl->log(0, $warning[0]); } } if (isset($badpackages[$memyselfandI]['errors'])) { foreach ($badpackages[$memyselfandI]['errors'] as $error) { if (is_array($error)) { $dl->log(0, $error[0]); } else { $dl->log(0, $error->getMessage()); } } if (isset($this->_options['nodeps']) || isset($this->_options['force'])) { return $this->warning('warning: %s should not be uninstalled, other installed packages depend ' . 'on this package'); } return $this->raiseError('%s cannot be uninstalled, other installed packages depend on this package'); } } return true; }
function _validatePackageDownload($dep, $required, $params, $depv1 = false) { $dep['package'] = $dep['name']; if (isset($dep['uri'])) { $dep['channel'] = '__uri'; } $depname = $this->_registry->parsedPackageNameToString($dep, true); $found = false; foreach ($params as $param) { if ($param->isEqual(array('package' => $dep['name'], 'channel' => $dep['channel']))) { $found = true; break; } if ($depv1 && $dep['channel'] == 'pear.php.net') { if ($param->isEqual(array('package' => $dep['name'], 'channel' => 'pecl.php.net'))) { $found = true; break; } } } if (!$found && isset($dep['providesextension'])) { foreach ($params as $param) { if ($param->isExtension($dep['providesextension'])) { $found = true; break; } } } if ($found) { $version = $param->getVersion(); $installed = false; $downloaded = true; } else { if ($this->_registry->packageExists($dep['name'], $dep['channel'])) { $installed = true; $downloaded = false; $version = $this->_registry->packageinfo($dep['name'], 'version', $dep['channel']); } else { if ($dep['channel'] == 'pecl.php.net' && $this->_registry->packageExists($dep['name'], 'pear.php.net')) { $installed = true; $downloaded = false; $version = $this->_registry->packageinfo($dep['name'], 'version', 'pear.php.net'); } else { $version = 'not installed or downloaded'; $installed = false; $downloaded = false; } } } $extra = $this->_getExtraString($dep); if (isset($dep['exclude'])) { if (!is_array($dep['exclude'])) { $dep['exclude'] = array($dep['exclude']); } } if (!isset($dep['min']) && !isset($dep['max']) && !isset($dep['recommended']) && !isset($dep['exclude'])) { if ($installed || $downloaded) { $installed = $installed ? 'installed' : 'downloaded'; if (isset($dep['conflicts'])) { if ($version) { $rest = ", {$installed} version is " . $version; } else { $rest = ''; } if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { return $this->raiseError('%s conflicts with package "' . $depname . '"' . $extra . $rest); } else { return $this->warning('warning: %s conflicts with package "' . $depname . '"' . $extra . $rest); } } return true; } else { if (isset($dep['conflicts'])) { return true; } if ($required) { if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { return $this->raiseError('%s requires package "' . $depname . '"' . $extra); } else { return $this->warning('warning: %s requires package "' . $depname . '"' . $extra); } } else { return $this->warning('%s can optionally use package "' . $depname . '"' . $extra); } } } if (!$installed && !$downloaded) { if (isset($dep['conflicts'])) { return true; } if ($required) { if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { return $this->raiseError('%s requires package "' . $depname . '"' . $extra); } else { return $this->warning('warning: %s requires package "' . $depname . '"' . $extra); } } else { return $this->warning('%s can optionally use package "' . $depname . '"' . $extra); } } $fail = false; if (isset($dep['min'])) { if (version_compare($version, $dep['min'], '<')) { $fail = true; } } if (isset($dep['max'])) { if (version_compare($version, $dep['max'], '>')) { $fail = true; } } if ($fail && !isset($dep['conflicts'])) { $installed = $installed ? 'installed' : 'downloaded'; $dep['package'] = $dep['name']; $dep = $this->_registry->parsedPackageNameToString($dep, true); if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { return $this->raiseError('%s requires package "' . $depname . '"' . $extra . ", {$installed} version is " . $version); } else { return $this->warning('warning: %s requires package "' . $depname . '"' . $extra . ", {$installed} version is " . $version); } } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail && isset($dep['conflicts']) && !isset($dep['exclude'])) { $installed = $installed ? 'installed' : 'downloaded'; if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { return $this->raiseError('%s conflicts with package "' . $depname . '"' . $extra . ", {$installed} version is " . $version); } else { return $this->warning('warning: %s conflicts with package "' . $depname . '"' . $extra . ", {$installed} version is " . $version); } } if (isset($dep['exclude'])) { $installed = $installed ? 'installed' : 'downloaded'; foreach ($dep['exclude'] as $exclude) { if (version_compare($version, $exclude, '==') && !isset($dep['conflicts'])) { if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { return $this->raiseError('%s is not compatible with ' . $installed . ' package "' . $depname . '" version ' . $exclude); } else { return $this->warning('warning: %s is not compatible with ' . $installed . ' package "' . $depname . '" version ' . $exclude); } } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) { $installed = $installed ? 'installed' : 'downloaded'; if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { return $this->raiseError('%s conflicts with package "' . $depname . '"' . $extra . ", {$installed} version is " . $version); } else { return $this->warning('warning: %s conflicts with package "' . $depname . '"' . $extra . ", {$installed} version is " . $version); } } } } if (isset($dep['recommended'])) { $installed = $installed ? 'installed' : 'downloaded'; if (version_compare($version, $dep['recommended'], '==')) { return true; } else { if (!$found && $installed) { $param = $this->_registry->getPackage($dep['name'], $dep['channel']); } if ($param) { $found = false; foreach ($params as $parent) { if ($parent->isEqual($this->_currentPackage)) { $found = true; break; } } if ($found) { if ($param->isCompatible($parent)) { return true; } } else { // this is for validPackage() calls $parent = $this->_registry->getPackage($this->_currentPackage['package'], $this->_currentPackage['channel']); if ($parent !== null) { if ($param->isCompatible($parent)) { return true; } } } } if (!isset($this->_options['nodeps']) && !isset($this->_options['force']) && !isset($this->_options['loose'])) { return $this->raiseError('%s dependency package "' . $depname . '" ' . $installed . ' version ' . $version . ' is not the recommended version ' . $dep['recommended'] . ', but may be compatible, use --force to install'); } else { return $this->warning('warning: %s dependency package "' . $depname . '" ' . $installed . ' version ' . $version . ' is not the recommended version ' . $dep['recommended']); } } } return true; }
/** * Installs the files within the package file specified. * * @param string|PEAR_Downloader_Package $pkgfile path to the package file, * or a pre-initialized packagefile object * @param array $options * recognized options: * - installroot : optional prefix directory for installation * - force : force installation * - register-only : update registry but don't install files * - upgrade : upgrade existing install * - soft : fail silently * - nodeps : ignore dependency conflicts/missing dependencies * - alldeps : install all dependencies * - onlyreqdeps : install only required dependencies * * @return array|PEAR_Error package info if successful */ function install($pkgfile, $options = array()) { $this->_options = $options; $this->_registry =& $this->config->getRegistry(); if (is_object($pkgfile)) { $dlpkg =& $pkgfile; $pkg = $pkgfile->getPackageFile(); $pkgfile = $pkg->getArchiveFile(); $descfile = $pkg->getPackageFile(); } else { $descfile = $pkgfile; $pkg = $this->_parsePackageXml($descfile); if (PEAR::isError($pkg)) { return $pkg; } } $tmpdir = dirname($descfile); if (realpath($descfile) != realpath($pkgfile)) { // Use the temp_dir since $descfile can contain the download dir path $tmpdir = $this->config->get('temp_dir', null, 'pear.php.net'); $tmpdir = System::mktemp('-d -t "' . $tmpdir . '"'); $tar = new Archive_Tar($pkgfile); if (!$tar->extract($tmpdir)) { return $this->raiseError("unable to unpack {$pkgfile}"); } } $pkgname = $pkg->getName(); $channel = $pkg->getChannel(); if (isset($this->_options['packagingroot'])) { $regdir = $this->_prependPath($this->config->get('php_dir', null, 'pear.php.net'), $this->_options['packagingroot']); $packrootphp_dir = $this->_prependPath($this->config->get('php_dir', null, $channel), $this->_options['packagingroot']); } if (isset($options['installroot'])) { $this->config->setInstallRoot($options['installroot']); $this->_registry =& $this->config->getRegistry(); $installregistry =& $this->_registry; $this->installroot = ''; // all done automagically now $php_dir = $this->config->get('php_dir', null, $channel); } else { $this->config->setInstallRoot(false); $this->_registry =& $this->config->getRegistry(); if (isset($this->_options['packagingroot'])) { $installregistry = new PEAR_Registry($regdir); if (!$installregistry->channelExists($channel, true)) { // we need to fake a channel-discover of this channel $chanobj = $this->_registry->getChannel($channel, true); $installregistry->addChannel($chanobj); } $php_dir = $packrootphp_dir; } else { $installregistry =& $this->_registry; $php_dir = $this->config->get('php_dir', null, $channel); } $this->installroot = ''; } // {{{ checks to do when not in "force" mode if (empty($options['force']) && (file_exists($this->config->get('php_dir')) && is_dir($this->config->get('php_dir')))) { $testp = $channel == 'pear.php.net' ? $pkgname : array($channel, $pkgname); $instfilelist = $pkg->getInstallationFileList(true); if (PEAR::isError($instfilelist)) { return $instfilelist; } // ensure we have the most accurate registry $installregistry->flushFileMap(); $test = $installregistry->checkFileMap($instfilelist, $testp, '1.1'); if (PEAR::isError($test)) { return $test; } if (sizeof($test)) { $pkgs = $this->getInstallPackages(); $found = false; foreach ($pkgs as $param) { if ($pkg->isSubpackageOf($param)) { $found = true; break; } } if ($found) { // subpackages can conflict with earlier versions of parent packages $parentreg = $installregistry->packageInfo($param->getPackage(), null, $param->getChannel()); $tmp = $test; foreach ($tmp as $file => $info) { if (is_array($info)) { if (strtolower($info[1]) == strtolower($param->getPackage()) && strtolower($info[0]) == strtolower($param->getChannel())) { if (isset($parentreg['filelist'][$file])) { unset($parentreg['filelist'][$file]); } else { $pos = strpos($file, '/'); $basedir = substr($file, 0, $pos); $file2 = substr($file, $pos + 1); if (isset($parentreg['filelist'][$file2]['baseinstalldir']) && $parentreg['filelist'][$file2]['baseinstalldir'] === $basedir) { unset($parentreg['filelist'][$file2]); } } unset($test[$file]); } } else { if (strtolower($param->getChannel()) != 'pear.php.net') { continue; } if (strtolower($info) == strtolower($param->getPackage())) { if (isset($parentreg['filelist'][$file])) { unset($parentreg['filelist'][$file]); } else { $pos = strpos($file, '/'); $basedir = substr($file, 0, $pos); $file2 = substr($file, $pos + 1); if (isset($parentreg['filelist'][$file2]['baseinstalldir']) && $parentreg['filelist'][$file2]['baseinstalldir'] === $basedir) { unset($parentreg['filelist'][$file2]); } } unset($test[$file]); } } } $pfk = new PEAR_PackageFile($this->config); $parentpkg =& $pfk->fromArray($parentreg); $installregistry->updatePackage2($parentpkg); } if ($param->getChannel() == 'pecl.php.net' && isset($options['upgrade'])) { $tmp = $test; foreach ($tmp as $file => $info) { if (is_string($info)) { // pear.php.net packages are always stored as strings if (strtolower($info) == strtolower($param->getPackage())) { // upgrading existing package unset($test[$file]); } } } } if (count($test)) { $msg = "{$channel}/{$pkgname}: conflicting files found:\n"; $longest = max(array_map("strlen", array_keys($test))); $fmt = "%{$longest}s (%s)\n"; foreach ($test as $file => $info) { if (!is_array($info)) { $info = array('pear.php.net', $info); } $info = $info[0] . '/' . $info[1]; $msg .= sprintf($fmt, $file, $info); } if (!isset($options['ignore-errors'])) { return $this->raiseError($msg); } if (!isset($options['soft'])) { $this->log(0, "WARNING: {$msg}"); } } } } // }}} $this->startFileTransaction(); $usechannel = $channel; if ($channel == 'pecl.php.net') { $test = $installregistry->packageExists($pkgname, $channel); if (!$test) { $test = $installregistry->packageExists($pkgname, 'pear.php.net'); $usechannel = 'pear.php.net'; } } else { $test = $installregistry->packageExists($pkgname, $channel); } if (empty($options['upgrade']) && empty($options['soft'])) { // checks to do only when installing new packages if (empty($options['force']) && $test) { return $this->raiseError("{$channel}/{$pkgname} is already installed"); } } else { // Upgrade if ($test) { $v1 = $installregistry->packageInfo($pkgname, 'version', $usechannel); $v2 = $pkg->getVersion(); $cmp = version_compare("{$v1}", "{$v2}", 'gt'); if (empty($options['force']) && !version_compare("{$v2}", "{$v1}", 'gt')) { return $this->raiseError("upgrade to a newer version ({$v2} is not newer than {$v1})"); } } } // Do cleanups for upgrade and install, remove old release's files first if ($test && empty($options['register-only'])) { // when upgrading, remove old release's files first: if (PEAR::isError($err = $this->_deletePackageFiles($pkgname, $usechannel, true))) { if (!isset($options['ignore-errors'])) { return $this->raiseError($err); } if (!isset($options['soft'])) { $this->log(0, 'WARNING: ' . $err->getMessage()); } } else { $backedup = $err; } } // {{{ Copy files to dest dir --------------------------------------- // info from the package it self we want to access from _installFile $this->pkginfo =& $pkg; // used to determine whether we should build any C code $this->source_files = 0; $savechannel = $this->config->get('default_channel'); if (empty($options['register-only']) && !is_dir($php_dir)) { if (PEAR::isError(System::mkdir(array('-p'), $php_dir))) { return $this->raiseError("no installation destination directory '{$php_dir}'\n"); } } if (substr($pkgfile, -4) != '.xml') { $tmpdir .= DIRECTORY_SEPARATOR . $pkgname . '-' . $pkg->getVersion(); } $this->configSet('default_channel', $channel); // {{{ install files $ver = $pkg->getPackagexmlVersion(); if (version_compare($ver, '2.0', '>=')) { $filelist = $pkg->getInstallationFilelist(); } else { $filelist = $pkg->getFileList(); } if (PEAR::isError($filelist)) { return $filelist; } $p =& $installregistry->getPackage($pkgname, $channel); $dirtree = empty($options['register-only']) && $p ? $p->getDirTree() : false; $pkg->resetFilelist(); $pkg->setLastInstalledVersion($installregistry->packageInfo($pkg->getPackage(), 'version', $pkg->getChannel())); foreach ($filelist as $file => $atts) { $this->expectError(PEAR_INSTALLER_FAILED); if ($pkg->getPackagexmlVersion() == '1.0') { $res = $this->_installFile($file, $atts, $tmpdir, $options); } else { $res = $this->_installFile2($pkg, $file, $atts, $tmpdir, $options); } $this->popExpect(); if (PEAR::isError($res)) { if (empty($options['ignore-errors'])) { $this->rollbackFileTransaction(); if ($res->getMessage() == "file does not exist") { $this->raiseError("file {$file} in package.xml does not exist"); } return $this->raiseError($res); } if (!isset($options['soft'])) { $this->log(0, "Warning: " . $res->getMessage()); } } $real = isset($atts['attribs']) ? $atts['attribs'] : $atts; if ($res == PEAR_INSTALLER_OK && $real['role'] != 'src') { // Register files that were installed $pkg->installedFile($file, $atts); } } // }}} // {{{ compile and install source files if ($this->source_files > 0 && empty($options['nobuild'])) { if (PEAR::isError($err = $this->_compileSourceFiles($savechannel, $pkg))) { return $err; } } // }}} if (isset($backedup)) { $this->_removeBackups($backedup); } if (!$this->commitFileTransaction()) { $this->rollbackFileTransaction(); $this->configSet('default_channel', $savechannel); return $this->raiseError("commit failed", PEAR_INSTALLER_FAILED); } // }}} $ret = false; $installphase = 'install'; $oldversion = false; // {{{ Register that the package is installed ----------------------- if (empty($options['upgrade'])) { // if 'force' is used, replace the info in registry $usechannel = $channel; if ($channel == 'pecl.php.net') { $test = $installregistry->packageExists($pkgname, $channel); if (!$test) { $test = $installregistry->packageExists($pkgname, 'pear.php.net'); $usechannel = 'pear.php.net'; } } else { $test = $installregistry->packageExists($pkgname, $channel); } if (!empty($options['force']) && $test) { $oldversion = $installregistry->packageInfo($pkgname, 'version', $usechannel); $installregistry->deletePackage($pkgname, $usechannel); } $ret = $installregistry->addPackage2($pkg); } else { if ($dirtree) { $this->startFileTransaction(); // attempt to delete empty directories uksort($dirtree, array($this, '_sortDirs')); foreach ($dirtree as $dir => $notused) { $this->addFileOperation('rmdir', array($dir)); } $this->commitFileTransaction(); } $usechannel = $channel; if ($channel == 'pecl.php.net') { $test = $installregistry->packageExists($pkgname, $channel); if (!$test) { $test = $installregistry->packageExists($pkgname, 'pear.php.net'); $usechannel = 'pear.php.net'; } } else { $test = $installregistry->packageExists($pkgname, $channel); } // new: upgrade installs a package if it isn't installed if (!$test) { $ret = $installregistry->addPackage2($pkg); } else { if ($usechannel != $channel) { $installregistry->deletePackage($pkgname, $usechannel); $ret = $installregistry->addPackage2($pkg); } else { $ret = $installregistry->updatePackage2($pkg); } $installphase = 'upgrade'; } } if (!$ret) { $this->configSet('default_channel', $savechannel); return $this->raiseError("Adding package {$channel}/{$pkgname} to registry failed"); } // }}} $this->configSet('default_channel', $savechannel); if (class_exists('PEAR_Task_Common')) { // this is auto-included if any tasks exist if (PEAR_Task_Common::hasPostinstallTasks()) { PEAR_Task_Common::runPostinstallTasks($installphase); } } return $pkg->toArray(true); }
/** * Assert results of pear size script as integrated with the pear command. * * @param string $args Arguments list that will be pass to the 'pear size' command * @param array $exp pear size output results expected * * @return void */ private function assertIntegratedExec($args, $exp, $status = 0) { $reg = new PEAR_Registry(); if ($reg->getPackage("PEAR_Size") == null) { $this->markTestSkipped("PEAR_Size is not installed."); } if ('@PEAR-DIR@' == '@' . 'PEAR-DIR' . '@') { // Run from source code checkout. $bin = 'pear'; } else { // Run from installation. $bin = '@BIN-DIR@/pear'; } $command = "'{$bin}' size "; $return = 0; ob_start(); passthru("{$command} {$args}", $return); $output = ob_get_contents(); ob_end_clean(); $this->assertEquals($exp, $output); $this->assertEquals($status, $return); }