Input can come from three sources: - local files (archives or package.xml) - remote files (downloadable urls) - abstract package names The first two elements are handled cleanly by PEAR_PackageFile, but the third requires accessing pearweb's xml-rpc interface to determine necessary dependencies, and the format returned of dependencies is slightly different from that used in package.xml. This class hides the differences between these elements, and makes automatic dependency resolution a piece of cake. It also manages conflicts when two classes depend on incompatible dependencies, or differing versions of the same package dependency. In addition, download will not be attempted if the php version is not supported, PEAR installer version is not supported, or non-PECL extensions are not installed.
 function doMakeRPM($command, $options, $params)
 {
     require_once 'System.php';
     require_once 'Archive/Tar.php';
     if (sizeof($params) != 1) {
         return $this->raiseError("bad parameter(s), try \"help {$command}\"");
     }
     if (!file_exists($params[0])) {
         return $this->raiseError("file does not exist: {$params['0']}");
     }
     $reg =& $this->config->getRegistry();
     $pkg =& $this->getPackageFile($this->config, $this->_debug);
     $pf =& $pkg->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
     if (PEAR::isError($pf)) {
         $u = $pf->getUserinfo();
         if (is_array($u)) {
             foreach ($u as $err) {
                 if (is_array($err)) {
                     $err = $err['message'];
                 }
                 $this->ui->outputData($err);
             }
         }
         return $this->raiseError("{$params['0']} is not a valid package");
     }
     $tmpdir = System::mktemp(array('-d', 'pear2rpm'));
     $instroot = System::mktemp(array('-d', 'pear2rpm'));
     $tmp = $this->config->get('verbose');
     $this->config->set('verbose', 0);
     $installer = $this->getInstaller($this->ui);
     require_once 'PEAR/Downloader/Package.php';
     $pack = new PEAR_Downloader_Package($installer);
     $pack->setPackageFile($pf);
     $params[0] =& $pack;
     $installer->setOptions(array('installroot' => $instroot, 'nodeps' => true, 'soft' => true));
     $installer->setDownloadedPackages($params);
     $info = $installer->install($params[0], array('installroot' => $instroot, 'nodeps' => true, 'soft' => true));
     $pkgdir = $pf->getPackage() . '-' . $pf->getVersion();
     $info['rpm_xml_dir'] = '/var/lib/pear';
     $this->config->set('verbose', $tmp);
     if (isset($options['spec-template'])) {
         $spec_template = $options['spec-template'];
     } else {
         $spec_template = '@DATA-DIR@/PEAR/template.spec';
     }
     $info['possible_channel'] = '';
     $info['extra_config'] = '';
     if (isset($options['rpm-pkgname'])) {
         $rpm_pkgname_format = $options['rpm-pkgname'];
     } else {
         if ($pf->getChannel() == 'pear.php.net' || $pf->getChannel() == 'pecl.php.net') {
             $alias = 'PEAR';
         } else {
             $chan =& $reg->getChannel($pf->getChannel());
             $alias = $chan->getAlias();
             $alias = strtoupper($alias);
             $info['possible_channel'] = $pf->getChannel() . '/';
         }
         $rpm_pkgname_format = $alias . '::%s';
     }
     $info['extra_headers'] = '';
     $info['doc_files'] = '';
     $info['files'] = '';
     $info['package2xml'] = '';
     $info['rpm_package'] = sprintf($rpm_pkgname_format, $pf->getPackage());
     $srcfiles = 0;
     foreach ($info['filelist'] as $name => $attr) {
         if (!isset($attr['role'])) {
             continue;
         }
         $name = preg_replace('![/:\\\\]!', '/', $name);
         if ($attr['role'] == 'doc') {
             $info['doc_files'] .= " {$name}";
             // Map role to the rpm vars
         } else {
             $c_prefix = '%{_libdir}/php/pear';
             switch ($attr['role']) {
                 case 'php':
                     $prefix = $c_prefix;
                     break;
                 case 'ext':
                     $prefix = '%{_libdir}/php';
                     break;
                     // XXX good place?
                 // XXX good place?
                 case 'src':
                     $srcfiles++;
                     $prefix = '%{_includedir}/php';
                     break;
                     // XXX good place?
                 // XXX good place?
                 case 'test':
                     $prefix = "{$c_prefix}/tests/" . $pf->getPackage();
                     break;
                 case 'data':
                     $prefix = "{$c_prefix}/data/" . $pf->getPackage();
                     break;
                 case 'script':
                     $prefix = '%{_bindir}';
                     break;
                 default:
                     // non-standard roles
                     $prefix = "{$c_prefix}/{$attr['role']}/" . $pf->getPackage();
                     $info['extra_config'] .= "\n        -d {$attr[role]}_dir={$c_prefix}/{$attr[role]} \\";
                     $this->ui->outputData('WARNING: role "' . $attr['role'] . '" used, ' . 'and will be installed in "' . $c_prefix . '/' . $attr['role'] . '/' . $pf->getPackage() . ' - hand-edit the final .spec if this is wrong', $command);
                     break;
             }
             $name = str_replace('\\', '/', $name);
             $info['files'] .= "{$prefix}/{$name}\n";
         }
     }
     if ($srcfiles > 0) {
         require_once 'OS/Guess.php';
         $os = new OS_Guess();
         $arch = $os->getCpu();
     } else {
         $arch = 'noarch';
     }
     $cfg = array('master_server', 'php_dir', 'ext_dir', 'doc_dir', 'bin_dir', 'data_dir', 'test_dir');
     foreach ($cfg as $k) {
         if ($k == 'master_server') {
             $chan = $reg->getChannel($pf->getChannel());
             $info[$k] = $chan->getServer();
             continue;
         }
         $info[$k] = $this->config->get($k);
     }
     $info['arch'] = $arch;
     $fp = @fopen($spec_template, "r");
     if (!$fp) {
         return $this->raiseError("could not open RPM spec file template {$spec_template}: {$php_errormsg}");
     }
     $info['package'] = $pf->getPackage();
     $info['version'] = $pf->getVersion();
     $info['release_license'] = $pf->getLicense();
     if ($pf->getDeps()) {
         if ($pf->getPackagexmlVersion() == '1.0') {
             $requires = $conflicts = array();
             foreach ($pf->getDeps() as $dep) {
                 if (isset($dep['optional']) && $dep['optional'] == 'yes') {
                     continue;
                 }
                 if ($dep['type'] != 'pkg') {
                     continue;
                 }
                 if (isset($dep['channel']) && $dep['channel'] != 'pear.php.net' && $dep['channel'] != 'pecl.php.net') {
                     $chan =& $reg->getChannel($dep['channel']);
                     $package = strtoupper($chan->getAlias()) . '::' . $dep['name'];
                 } else {
                     $package = 'PEAR::' . $dep['name'];
                 }
                 $trans = array('>' => '>', '<' => '<', '>=' => '>=', '<=' => '<=', '=' => '=', 'gt' => '>', 'lt' => '<', 'ge' => '>=', 'le' => '<=', 'eq' => '=');
                 if ($dep['rel'] == 'has') {
                     $requires[] = $package;
                 } elseif ($dep['rel'] == 'not') {
                     $conflicts[] = $package;
                 } elseif ($dep['rel'] == 'ne') {
                     $conflicts[] = $package . ' = ' . $dep['version'];
                 } elseif (isset($trans[$dep['rel']])) {
                     $requires[] = $package . ' ' . $trans[$dep['rel']] . ' ' . $dep['version'];
                 }
             }
             if (count($requires)) {
                 $info['extra_headers'] .= 'Requires: ' . implode(', ', $requires) . "\n";
             }
             if (count($conflicts)) {
                 $info['extra_headers'] .= 'Conflicts: ' . implode(', ', $conflicts) . "\n";
             }
         } else {
             $info['package2xml'] = '2';
             // tell the spec to use package2.xml
             $requires = $conflicts = array();
             $deps = $pf->getDeps(true);
             if (isset($deps['required']['package'])) {
                 if (!isset($deps['required']['package'][0])) {
                     $deps['required']['package'] = array($deps['required']['package']);
                 }
                 foreach ($deps['required']['package'] as $dep) {
                     if ($dep['channel'] != 'pear.php.net' && $dep['channel'] != 'pecl.php.net') {
                         $chan =& $reg->getChannel($dep['channel']);
                         $package = strtoupper($chan->getAlias()) . '::' . $dep['name'];
                     } else {
                         $package = 'PEAR::' . $dep['name'];
                     }
                     if (isset($dep['conflicts']) && (isset($dep['min']) || isset($dep['max']))) {
                         $deprange = array();
                         if (isset($dep['min'])) {
                             $deprange[] = array($dep['min'], '>=');
                         }
                         if (isset($dep['max'])) {
                             $deprange[] = array($dep['max'], '<=');
                         }
                         if (isset($dep['exclude'])) {
                             if (!is_array($dep['exclude']) || !isset($dep['exclude'][0])) {
                                 $dep['exclude'] = array($dep['exclude']);
                             }
                             if (count($deprange)) {
                                 $excl = $dep['exclude'];
                                 // change >= to > if excluding the min version
                                 // change <= to < if excluding the max version
                                 for ($i = 0; $i < count($excl); $i++) {
                                     if (isset($deprange[0]) && $excl[$i] == $deprange[0][0]) {
                                         $deprange[0][1] = '<';
                                         unset($dep['exclude'][$i]);
                                     }
                                     if (isset($deprange[1]) && $excl[$i] == $deprange[1][0]) {
                                         $deprange[1][1] = '>';
                                         unset($dep['exclude'][$i]);
                                     }
                                 }
                             }
                             if (count($dep['exclude'])) {
                                 $dep['exclude'] = array_values($dep['exclude']);
                                 $newdeprange = array();
                                 // remove excludes that are outside the existing range
                                 for ($i = 0; $i < count($dep['exclude']); $i++) {
                                     if ($dep['exclude'][$i] < $dep['min'] || $dep['exclude'][$i] > $dep['max']) {
                                         unset($dep['exclude'][$i]);
                                     }
                                 }
                                 $dep['exclude'] = array_values($dep['exclude']);
                                 usort($dep['exclude'], 'version_compare');
                                 // take the remaining excludes and
                                 // split the dependency into sub-ranges
                                 $lastmin = $deprange[0];
                                 for ($i = 0; $i < count($dep['exclude']) - 1; $i++) {
                                     $newdeprange[] = '(' . $package . " {$lastmin[1]} {$lastmin[0]} and " . $package . ' < ' . $dep['exclude'][$i] . ')';
                                     $lastmin = array($dep['exclude'][$i], '>');
                                 }
                                 if (isset($dep['max'])) {
                                     $newdeprange[] = '(' . $package . " {$lastmin[1]} {$lastmin[0]} and " . $package . ' < ' . $dep['max'] . ')';
                                 }
                                 $conflicts[] = implode(' or ', $deprange);
                             } else {
                                 $conflicts[] = $package . " {$deprange[0][1]} {$deprange[0][0]}" . (isset($deprange[1]) ? " and {$package} {$deprange[1][1]} {$deprange[1][0]}" : '');
                             }
                         }
                         continue;
                     }
                     if (!isset($dep['min']) && !isset($dep['max']) && !isset($dep['exclude'])) {
                         if (isset($dep['conflicts'])) {
                             $conflicts[] = $package;
                         } else {
                             $requires[] = $package;
                         }
                     } else {
                         if (isset($dep['min'])) {
                             $requires[] = $package . ' >= ' . $dep['min'];
                         }
                         if (isset($dep['max'])) {
                             $requires[] = $package . ' <= ' . $dep['max'];
                         }
                         if (isset($dep['exclude'])) {
                             $ex = $dep['exclude'];
                             if (!is_array($ex)) {
                                 $ex = array($ex);
                             }
                             foreach ($ex as $ver) {
                                 $conflicts[] = $package . ' = ' . $ver;
                             }
                         }
                     }
                 }
                 require_once 'Archive/Tar.php';
                 $tar = new Archive_Tar($pf->getArchiveFile());
                 $tar->pushErrorHandling(PEAR_ERROR_RETURN);
                 $a = $tar->extractInString('package2.xml');
                 $tar->popErrorHandling();
                 if ($a === null || PEAR::isError($a)) {
                     $info['package2xml'] = '';
                     // this doesn't have a package.xml version 1.0
                     $requires[] = 'PEAR::PEAR >= ' . $deps['required']['pearinstaller']['min'];
                 }
                 if (count($requires)) {
                     $info['extra_headers'] .= 'Requires: ' . implode(', ', $requires) . "\n";
                 }
                 if (count($conflicts)) {
                     $info['extra_headers'] .= 'Conflicts: ' . implode(', ', $conflicts) . "\n";
                 }
             }
         }
     }
     // remove the trailing newline
     $info['extra_headers'] = trim($info['extra_headers']);
     if (function_exists('file_get_contents')) {
         fclose($fp);
         $spec_contents = preg_replace('/@([a-z0-9_-]+)@/e', '$info["\\1"]', file_get_contents($spec_template));
     } else {
         $spec_contents = preg_replace('/@([a-z0-9_-]+)@/e', '$info["\\1"]', fread($fp, filesize($spec_template)));
         fclose($fp);
     }
     $spec_file = "{$info['rpm_package']}-{$info['version']}.spec";
     $wp = fopen($spec_file, "wb");
     if (!$wp) {
         return $this->raiseError("could not write RPM spec file {$spec_file}: {$php_errormsg}");
     }
     fwrite($wp, $spec_contents);
     fclose($wp);
     $this->ui->outputData("Wrote RPM spec file {$spec_file}", $command);
     return true;
 }
Esempio n. 2
0
 /**
  * @param array all packages to be installed
  */
 function analyzeDependencies(&$params, $force = false)
 {
     if (isset($this->_options['downloadonly'])) {
         return;
     }
     PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
     $redo = true;
     $reset = $hasfailed = $failed = false;
     while ($redo) {
         $redo = false;
         foreach ($params as $i => $param) {
             $deps = $param->getDeps();
             if (!$deps) {
                 $depchecker =& $this->getDependency2Object($this->config, $this->getOptions(), $param->getParsedPackage(), PEAR_VALIDATE_DOWNLOADING);
                 $send = $param->getPackageFile();
                 $installcheck = $depchecker->validatePackage($send, $this, $params);
                 if (PEAR::isError($installcheck)) {
                     if (!isset($this->_options['soft'])) {
                         $this->log(0, $installcheck->getMessage());
                     }
                     $hasfailed = true;
                     $params[$i] = false;
                     $reset = true;
                     $redo = true;
                     $failed = false;
                     PEAR_Downloader_Package::removeDuplicates($params);
                     continue 2;
                 }
                 continue;
             }
             if (!$reset && $param->alreadyValidated() && !$force) {
                 continue;
             }
             if (count($deps)) {
                 $depchecker =& $this->getDependency2Object($this->config, $this->getOptions(), $param->getParsedPackage(), PEAR_VALIDATE_DOWNLOADING);
                 $send = $param->getPackageFile();
                 if ($send === null) {
                     $send = $param->getDownloadURL();
                 }
                 $installcheck = $depchecker->validatePackage($send, $this, $params);
                 if (PEAR::isError($installcheck)) {
                     if (!isset($this->_options['soft'])) {
                         $this->log(0, $installcheck->getMessage());
                     }
                     $hasfailed = true;
                     $params[$i] = false;
                     $reset = true;
                     $redo = true;
                     $failed = false;
                     PEAR_Downloader_Package::removeDuplicates($params);
                     continue 2;
                 }
                 $failed = false;
                 if (isset($deps['required']) && is_array($deps['required'])) {
                     foreach ($deps['required'] as $type => $dep) {
                         // note: Dependency2 will never return a PEAR_Error if ignore-errors
                         // is specified, so soft is needed to turn off logging
                         if (!isset($dep[0])) {
                             if (PEAR::isError($e = $depchecker->{"validate{$type}Dependency"}($dep, true, $params))) {
                                 $failed = true;
                                 if (!isset($this->_options['soft'])) {
                                     $this->log(0, $e->getMessage());
                                 }
                             } elseif (is_array($e) && !$param->alreadyValidated()) {
                                 if (!isset($this->_options['soft'])) {
                                     $this->log(0, $e[0]);
                                 }
                             }
                         } else {
                             foreach ($dep as $d) {
                                 if (PEAR::isError($e = $depchecker->{"validate{$type}Dependency"}($d, true, $params))) {
                                     $failed = true;
                                     if (!isset($this->_options['soft'])) {
                                         $this->log(0, $e->getMessage());
                                     }
                                 } elseif (is_array($e) && !$param->alreadyValidated()) {
                                     if (!isset($this->_options['soft'])) {
                                         $this->log(0, $e[0]);
                                     }
                                 }
                             }
                         }
                     }
                     if (isset($deps['optional']) && is_array($deps['optional'])) {
                         foreach ($deps['optional'] as $type => $dep) {
                             if (!isset($dep[0])) {
                                 if (PEAR::isError($e = $depchecker->{"validate{$type}Dependency"}($dep, false, $params))) {
                                     $failed = true;
                                     if (!isset($this->_options['soft'])) {
                                         $this->log(0, $e->getMessage());
                                     }
                                 } elseif (is_array($e) && !$param->alreadyValidated()) {
                                     if (!isset($this->_options['soft'])) {
                                         $this->log(0, $e[0]);
                                     }
                                 }
                             } else {
                                 foreach ($dep as $d) {
                                     if (PEAR::isError($e = $depchecker->{"validate{$type}Dependency"}($d, false, $params))) {
                                         $failed = true;
                                         if (!isset($this->_options['soft'])) {
                                             $this->log(0, $e->getMessage());
                                         }
                                     } elseif (is_array($e) && !$param->alreadyValidated()) {
                                         if (!isset($this->_options['soft'])) {
                                             $this->log(0, $e[0]);
                                         }
                                     }
                                 }
                             }
                         }
                     }
                     $groupname = $param->getGroup();
                     if (isset($deps['group']) && $groupname) {
                         if (!isset($deps['group'][0])) {
                             $deps['group'] = array($deps['group']);
                         }
                         $found = false;
                         foreach ($deps['group'] as $group) {
                             if ($group['attribs']['name'] == $groupname) {
                                 $found = true;
                                 break;
                             }
                         }
                         if ($found) {
                             unset($group['attribs']);
                             foreach ($group as $type => $dep) {
                                 if (!isset($dep[0])) {
                                     if (PEAR::isError($e = $depchecker->{"validate{$type}Dependency"}($dep, false, $params))) {
                                         $failed = true;
                                         if (!isset($this->_options['soft'])) {
                                             $this->log(0, $e->getMessage());
                                         }
                                     } elseif (is_array($e) && !$param->alreadyValidated()) {
                                         if (!isset($this->_options['soft'])) {
                                             $this->log(0, $e[0]);
                                         }
                                     }
                                 } else {
                                     foreach ($dep as $d) {
                                         if (PEAR::isError($e = $depchecker->{"validate{$type}Dependency"}($d, false, $params))) {
                                             $failed = true;
                                             if (!isset($this->_options['soft'])) {
                                                 $this->log(0, $e->getMessage());
                                             }
                                         } elseif (is_array($e) && !$param->alreadyValidated()) {
                                             if (!isset($this->_options['soft'])) {
                                                 $this->log(0, $e[0]);
                                             }
                                         }
                                     }
                                 }
                             }
                         }
                     }
                 } else {
                     foreach ($deps as $dep) {
                         if (PEAR::isError($e = $depchecker->validateDependency1($dep, $params))) {
                             $failed = true;
                             if (!isset($this->_options['soft'])) {
                                 $this->log(0, $e->getMessage());
                             }
                         } elseif (is_array($e) && !$param->alreadyValidated()) {
                             if (!isset($this->_options['soft'])) {
                                 $this->log(0, $e[0]);
                             }
                         }
                     }
                 }
                 $params[$i]->setValidated();
             }
             if ($failed) {
                 $hasfailed = true;
                 $params[$i] = false;
                 $reset = true;
                 $redo = true;
                 $failed = false;
                 PEAR_Downloader_Package::removeDuplicates($params);
                 continue 2;
             }
         }
     }
     PEAR::staticPopErrorHandling();
     if ($hasfailed && (isset($this->_options['ignore-errors']) || isset($this->_options['nodeps']))) {
         // this is probably not needed, but just in case
         if (!isset($this->_options['soft'])) {
             $this->log(0, 'WARNING: dependencies failed');
         }
     }
 }
Esempio n. 3
0
 /**
  * @param array output of package.getDownloadURL
  * @param string|array|object information for detecting packages to be downloaded, and
  *                            for errors
  * @param array name information of the package
  * @param array|null packages to be downloaded
  * @param bool is this an optional dependency?
  * @access private
  */
 function _analyzeDownloadURL($info, $param, $pname, $params = null, $optional = false)
 {
     if (!is_string($param) && PEAR_Downloader_Package::willDownload($param, $params)) {
         return false;
     }
     if (!$info) {
         if (!is_string($param)) {
             $saveparam = ", cannot download \"{$param}\"";
         } else {
             $saveparam = '';
         }
         // no releases exist
         return PEAR::raiseError('No releases for package "' . $this->_registry->parsedPackageNameToString($pname, true) . '" exist' . $saveparam);
     }
     if (strtolower($info['info']->getChannel()) != strtolower($pname['channel'])) {
         $err = false;
         if ($pname['channel'] == 'pecl.php.net') {
             if ($info['info']->getChannel() != 'pear.php.net') {
                 $err = true;
             }
         } elseif ($info['info']->getChannel() == 'pecl.php.net') {
             if ($pname['channel'] != 'pear.php.net') {
                 $err = true;
             }
         } else {
             $err = true;
         }
         if ($err) {
             return PEAR::raiseError('SECURITY ERROR: package in channel "' . $pname['channel'] . '" retrieved another channel\'s name for download! ("' . $info['info']->getChannel() . '")');
         }
     }
     if (!isset($info['url'])) {
         $instead = ', will instead download version ' . $info['version'] . ', stability "' . $info['info']->getState() . '"';
         // releases exist, but we failed to get any
         if (isset($this->_downloader->_options['force'])) {
             if (isset($pname['version'])) {
                 $vs = ', version "' . $pname['version'] . '"';
             } elseif (isset($pname['state'])) {
                 $vs = ', stability "' . $pname['state'] . '"';
             } elseif ($param == 'dependency') {
                 if (!class_exists('PEAR_Common')) {
                     require_once 'PEAR/Common.php';
                 }
                 if (!in_array($info['info']->getState(), PEAR_Common::betterStates($this->_config->get('preferred_state'), true))) {
                     if ($optional) {
                         // don't spit out confusing error message
                         return $this->_downloader->_getPackageDownloadUrl(array('package' => $pname['package'], 'channel' => $pname['channel'], 'version' => $info['version']));
                     }
                     $vs = ' within preferred state "' . $this->_config->get('preferred_state') . '"';
                 } else {
                     if (!class_exists('PEAR_Dependency2')) {
                         require_once 'PEAR/Dependency2.php';
                     }
                     if ($optional) {
                         // don't spit out confusing error message
                         return $this->_downloader->_getPackageDownloadUrl(array('package' => $pname['package'], 'channel' => $pname['channel'], 'version' => $info['version']));
                     }
                     $vs = PEAR_Dependency2::_getExtraString($pname);
                     $instead = '';
                 }
             } else {
                 $vs = ' within preferred state "' . $this->_config->get('preferred_state') . '"';
             }
             if (!isset($options['soft'])) {
                 $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] . '/' . $pname['package'] . $vs . $instead);
             }
             // download the latest release
             return $this->_downloader->_getPackageDownloadUrl(array('package' => $pname['package'], 'channel' => $pname['channel'], 'version' => $info['version']));
         } else {
             // construct helpful error message
             if (isset($pname['version'])) {
                 $vs = ', version "' . $pname['version'] . '"';
             } elseif (isset($pname['state'])) {
                 $vs = ', stability "' . $pname['state'] . '"';
             } elseif ($param == 'dependency') {
                 if (!class_exists('PEAR_Common')) {
                     require_once 'PEAR/Common.php';
                 }
                 if (!in_array($info['info']->getState(), PEAR_Common::betterStates($this->_config->get('preferred_state'), true))) {
                     if ($optional) {
                         // don't spit out confusing error message, and don't die on
                         // optional dep failure!
                         return $this->_downloader->_getPackageDownloadUrl(array('package' => $pname['package'], 'channel' => $pname['channel'], 'version' => $info['version']));
                     }
                     $vs = ' within preferred state "' . $this->_config->get('preferred_state') . '"';
                 } else {
                     if (!class_exists('PEAR_Dependency2')) {
                         require_once 'PEAR/Dependency2.php';
                     }
                     if ($optional) {
                         // don't spit out confusing error message, and don't die on
                         // optional dep failure!
                         return $this->_downloader->_getPackageDownloadUrl(array('package' => $pname['package'], 'channel' => $pname['channel'], 'version' => $info['version']));
                     }
                     $vs = PEAR_Dependency2::_getExtraString($pname);
                 }
             } else {
                 $vs = ' within preferred state "' . $this->_downloader->config->get('preferred_state') . '"';
             }
             $err = PEAR::raiseError('Failed to download ' . $this->_registry->parsedPackageNameToString(array('channel' => $pname['channel'], 'package' => $pname['package']), true) . $vs . ', latest release is version ' . $info['version'] . ', stability "' . $info['info']->getState() . '", use "' . $this->_registry->parsedPackageNameToString(array('channel' => $pname['channel'], 'package' => $pname['package'], 'version' => $info['version'])) . '" to install');
             return $err;
         }
     }
     return $info;
 }
Esempio n. 4
0
 /**
  * @param array output of package.getDownloadURL
  * @param string|array|object information for detecting packages to be downloaded, and
  *                            for errors
  * @param array name information of the package
  * @param array|null packages to be downloaded
  * @param bool is this an optional dependency?
  * @param bool is this any kind of dependency?
  * @access private
  */
 function _analyzeDownloadURL($info, $param, $pname, $params = null, $optional = false, $isdependency = false)
 {
     if (!is_string($param) && PEAR_Downloader_Package::willDownload($param, $params)) {
         return false;
     }
     if ($info === false) {
         $saveparam = !is_string($param) ? ", cannot download \"{$param}\"" : '';
         // no releases exist
         return PEAR::raiseError('No releases for package "' . $this->_registry->parsedPackageNameToString($pname, true) . '" exist' . $saveparam);
     }
     if (strtolower($info['info']->getChannel()) != strtolower($pname['channel'])) {
         $err = false;
         if ($pname['channel'] == 'pecl.php.net') {
             if ($info['info']->getChannel() != 'pear.php.net') {
                 $err = true;
             }
         } elseif ($info['info']->getChannel() == 'pecl.php.net') {
             if ($pname['channel'] != 'pear.php.net') {
                 $err = true;
             }
         } else {
             $err = true;
         }
         if ($err) {
             return PEAR::raiseError('SECURITY ERROR: package in channel "' . $pname['channel'] . '" retrieved another channel\'s name for download! ("' . $info['info']->getChannel() . '")');
         }
     }
     $preferred_state = $this->_config->get('preferred_state');
     if (!isset($info['url'])) {
         $package_version = $this->_registry->packageInfo($info['info']->getPackage(), 'version', $info['info']->getChannel());
         if ($this->isInstalled($info)) {
             if ($isdependency && version_compare($info['version'], $package_version, '<=')) {
                 // ignore bogus errors of "failed to download dependency"
                 // if it is already installed and the one that would be
                 // downloaded is older or the same version (Bug #7219)
                 return false;
             }
         }
         if ($info['version'] === $package_version) {
             if (!isset($options['soft'])) {
                 $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] . '/' . $pname['package'] . '-' . $package_version . ', additionally the suggested version' . ' (' . $package_version . ') is the same as the locally installed one.');
             }
             return false;
         }
         if (version_compare($info['version'], $package_version, '<=')) {
             if (!isset($options['soft'])) {
                 $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] . '/' . $pname['package'] . '-' . $package_version . ', additionally the suggested version' . ' (' . $info['version'] . ') is a lower version than the locally installed one (' . $package_version . ').');
             }
             return false;
         }
         $instead = ', will instead download version ' . $info['version'] . ', stability "' . $info['info']->getState() . '"';
         // releases exist, but we failed to get any
         if (isset($this->_downloader->_options['force'])) {
             if (isset($pname['version'])) {
                 $vs = ', version "' . $pname['version'] . '"';
             } elseif (isset($pname['state'])) {
                 $vs = ', stability "' . $pname['state'] . '"';
             } elseif ($param == 'dependency') {
                 if (!class_exists('PEAR_Common')) {
                     require_once 'PEAR/Common.php';
                 }
                 if (!in_array($info['info']->getState(), PEAR_Common::betterStates($preferred_state, true))) {
                     if ($optional) {
                         // don't spit out confusing error message
                         return $this->_downloader->_getPackageDownloadUrl(array('package' => $pname['package'], 'channel' => $pname['channel'], 'version' => $info['version']));
                     }
                     $vs = ' within preferred state "' . $preferred_state . '"';
                 } else {
                     if (!class_exists('PEAR_Dependency2')) {
                         require_once 'PEAR/Dependency2.php';
                     }
                     if ($optional) {
                         // don't spit out confusing error message
                         return $this->_downloader->_getPackageDownloadUrl(array('package' => $pname['package'], 'channel' => $pname['channel'], 'version' => $info['version']));
                     }
                     $vs = PEAR_Dependency2::_getExtraString($pname);
                     $instead = '';
                 }
             } else {
                 $vs = ' within preferred state "' . $preferred_state . '"';
             }
             if (!isset($options['soft'])) {
                 $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] . '/' . $pname['package'] . $vs . $instead);
             }
             // download the latest release
             return $this->_downloader->_getPackageDownloadUrl(array('package' => $pname['package'], 'channel' => $pname['channel'], 'version' => $info['version']));
         } else {
             if (isset($info['php']) && $info['php']) {
                 $err = PEAR::raiseError('Failed to download ' . $this->_registry->parsedPackageNameToString(array('channel' => $pname['channel'], 'package' => $pname['package']), true) . ', latest release is version ' . $info['php']['v'] . ', but it requires PHP version "' . $info['php']['m'] . '", use "' . $this->_registry->parsedPackageNameToString(array('channel' => $pname['channel'], 'package' => $pname['package'], 'version' => $info['php']['v'])) . '" to install', PEAR_DOWNLOADER_PACKAGE_PHPVERSION);
                 return $err;
             }
             // construct helpful error message
             if (isset($pname['version'])) {
                 $vs = ', version "' . $pname['version'] . '"';
             } elseif (isset($pname['state'])) {
                 $vs = ', stability "' . $pname['state'] . '"';
             } elseif ($param == 'dependency') {
                 if (!class_exists('PEAR_Common')) {
                     require_once 'PEAR/Common.php';
                 }
                 if (!in_array($info['info']->getState(), PEAR_Common::betterStates($preferred_state, true))) {
                     if ($optional) {
                         // don't spit out confusing error message, and don't die on
                         // optional dep failure!
                         return $this->_downloader->_getPackageDownloadUrl(array('package' => $pname['package'], 'channel' => $pname['channel'], 'version' => $info['version']));
                     }
                     $vs = ' within preferred state "' . $preferred_state . '"';
                 } else {
                     if (!class_exists('PEAR_Dependency2')) {
                         require_once 'PEAR/Dependency2.php';
                     }
                     if ($optional) {
                         // don't spit out confusing error message, and don't die on
                         // optional dep failure!
                         return $this->_downloader->_getPackageDownloadUrl(array('package' => $pname['package'], 'channel' => $pname['channel'], 'version' => $info['version']));
                     }
                     $vs = PEAR_Dependency2::_getExtraString($pname);
                 }
             } else {
                 $vs = ' within preferred state "' . $this->_downloader->config->get('preferred_state') . '"';
             }
             $options = $this->_downloader->getOptions();
             // this is only set by the "download-all" command
             if (isset($options['ignorepreferred_state'])) {
                 $err = PEAR::raiseError('Failed to download ' . $this->_registry->parsedPackageNameToString(array('channel' => $pname['channel'], 'package' => $pname['package']), true) . $vs . ', latest release is version ' . $info['version'] . ', stability "' . $info['info']->getState() . '", use "' . $this->_registry->parsedPackageNameToString(array('channel' => $pname['channel'], 'package' => $pname['package'], 'version' => $info['version'])) . '" to install', PEAR_DOWNLOADER_PACKAGE_STATE);
                 return $err;
             }
             // Checks if the user has a package installed already and checks the release against
             // the state against the installed package, this allows upgrades for packages
             // with lower stability than the preferred_state
             $stability = $this->_registry->packageInfo($pname['package'], 'stability', $pname['channel']);
             if (!$this->isInstalled($info) || !in_array($info['info']->getState(), PEAR_Common::betterStates($stability['release'], true))) {
                 $err = PEAR::raiseError('Failed to download ' . $this->_registry->parsedPackageNameToString(array('channel' => $pname['channel'], 'package' => $pname['package']), true) . $vs . ', latest release is version ' . $info['version'] . ', stability "' . $info['info']->getState() . '", use "' . $this->_registry->parsedPackageNameToString(array('channel' => $pname['channel'], 'package' => $pname['package'], 'version' => $info['version'])) . '" to install');
                 return $err;
             }
         }
     }
     if (isset($info['deprecated']) && $info['deprecated']) {
         $this->_downloader->log(0, 'WARNING: "' . $this->_registry->parsedPackageNameToString(array('channel' => $info['info']->getChannel(), 'package' => $info['info']->getPackage()), true) . '" is deprecated in favor of "' . $this->_registry->parsedPackageNameToString($info['deprecated'], true) . '"');
     }
     return $info;
 }
Esempio n. 5
0
}
$installer = new PEAR_Installer($ui);
$pkg = new PEAR_PackageFile($config, $debug);
foreach ($install_files as $package => $instfile) {
    $info = $pkg->fromAnyFile($instfile, PEAR_VALIDATE_INSTALLING);
    if (PEAR::isError($info)) {
        if (is_array($info->getUserInfo())) {
            foreach ($info->getUserInfo() as $err) {
                $ui->outputData(sprintf("[PEAR] %s: %s", $package, $err['message']));
            }
        }
        $ui->outputData(sprintf("[PEAR] %s: %s", $package, $info->getMessage()));
        continue;
    }
    $new_ver = $info->getVersion();
    $downloaderpackage = new PEAR_Downloader_Package($installer);
    $err = $downloaderpackage->initialize($instfile);
    if (PEAR::isError($err)) {
        $ui->outputData(sprintf("[PEAR] %s: %s", $package, $err->getMessage()));
        continue;
    }
    if ($reg->packageExists($package)) {
        $old_ver = $reg->packageInfo($package, 'version');
        if (version_compare($new_ver, $old_ver, 'gt')) {
            $installer->setOptions($options);
            $dp = array($downloaderpackage);
            $installer->setDownloadedPackages($dp);
            $err = $installer->install($downloaderpackage, $options);
            if (PEAR::isError($err)) {
                $ui->outputData(sprintf("[PEAR] %s: %s", $package, $err->getMessage()));
                continue;
Esempio n. 6
0
 /**
  * validate a downloaded package against installed packages
  * 
  * As of PEAR 1.4.3, this will only validate
  *
  * @param array|PEAR_Downloader_Package|PEAR_PackageFile_v1|PEAR_PackageFile_v2
  *              $pkg package identifier (either
  *                   array('package' => blah, 'channel' => blah) or an array with
  *                   index 'info' referencing an object)
  * @param PEAR_Downloader $dl
  * @param array $params full list of packages to install
  * @return true|PEAR_Error
  */
 function validatePackage($pkg, &$dl, $params = array())
 {
     if (is_array($pkg) && isset($pkg['info'])) {
         $deps = $this->_dependencydb->getDependentPackageDependencies($pkg['info']);
     } else {
         $deps = $this->_dependencydb->getDependentPackageDependencies($pkg);
     }
     $fail = false;
     if ($deps) {
         if (!class_exists('PEAR_Downloader_Package')) {
             require_once 'PEAR/Downloader/Package.php';
         }
         $dp = new PEAR_Downloader_Package($dl);
         if (is_object($pkg)) {
             $dp->setPackageFile($pkg);
         } else {
             $dp->setDownloadURL($pkg);
         }
         PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
         foreach ($deps as $channel => $info) {
             foreach ($info as $package => $ds) {
                 foreach ($params as $packd) {
                     if (strtolower($packd->getPackage()) == strtolower($package) && $packd->getChannel() == $channel) {
                         $dl->log(3, 'skipping installed package check of "' . $this->_registry->parsedPackageNameToString(array('channel' => $channel, 'package' => $package), true) . '", version "' . $packd->getVersion() . '" will be ' . 'downloaded and installed');
                         continue 2;
                         // jump to next package
                     }
                 }
                 foreach ($ds as $d) {
                     $checker = new PEAR_Dependency2($this->_config, $this->_options, array('channel' => $channel, 'package' => $package), $this->_state);
                     $dep = $d['dep'];
                     $required = $d['type'] == 'required';
                     $ret = $checker->_validatePackageDownload($dep, $required, array(&$dp));
                     if (is_array($ret)) {
                         $dl->log(0, $ret[0]);
                     } elseif (PEAR::isError($ret)) {
                         $dl->log(0, $ret->getMessage());
                         $fail = true;
                     }
                 }
             }
         }
         PEAR::popErrorHandling();
     }
     if ($fail) {
         return $this->raiseError('%s cannot be installed, conflicts with installed packages');
     }
     return true;
 }
Esempio n. 7
0
 /**
  * Set the output macros based on a package source
  */
 function _doMakeRPMFromPackage($source_file, $command, $options, $params)
 {
     // Merge the "core" output macros with those for packages only
     $this->_output += $this->_output_package;
     // Set the name of the template spec file to use by default
     $this->_template_spec_name = 'template.spec';
     // Create a PEAR_PackageFile object and fill it with info from the
     // source package
     $reg =& $this->config->getRegistry();
     $pkg =& $this->getPackageFile($this->config, $this->_debug);
     $pf =& $pkg->fromAnyFile($source_file, PEAR_VALIDATE_NORMAL);
     if (PEAR::isError($pf)) {
         $u = $pf->getUserinfo();
         if (is_array($u)) {
             foreach ($u as $err) {
                 if (is_array($err)) {
                     $err = $err['message'];
                 }
                 $this->ui->outputData($err);
             }
         }
         return $this->raiseError("{$source_file} is not a valid package");
     }
     // Install the package into a temporary directory
     $tmpdir = $this->makeTempDir();
     $instroot = $this->makeTempDir();
     // Save a channel object for the channel our package is part of
     // We will need this later to stick back into the temporary
     // installation directory
     $chan = $reg->getChannel($pf->getChannel(), true);
     if (PEAR::isError($chan)) {
         $this->ui->outputData($chan->getMessage());
         return $this->raiseError("Could not find channel data for channel '" . $pf->getChannel() . " - you need to channel-discover or channel-add " . "the channel before building packages based on it.");
     }
     // Set the role prefixes - package won't actually be installed here
     // but we can pull the final install paths back out later to put into
     // our spec
     foreach ($this->_file_prefixes as $role => $prefix) {
         // if role is 'script' the corresponding option is bin_dir
         if ($role == 'script') {
             $role = 'bin';
         }
         // save the original config options to restore later
         $orig_config_options["{$role}_dir"] = $this->config->get("{$role}_dir");
         // Substitute the package name into the file prefix
         $prefix = str_replace('%s', $pf->getPackage(), $prefix);
         // Set the temporary role prefix for installation
         $this->config->set("{$role}_dir", $prefix);
     }
     // Construct a fake registry inside the ultimate destination
     // temporary directory, and load the necessary channel into it
     $regdir = $instroot . $this->config->get('php_dir');
     $fakereg = new PEAR_Registry($regdir);
     $fakereg->addChannel($chan);
     $tmp = $this->config->get('verbose');
     $this->config->set('verbose', 0);
     $installer = $this->getInstaller($this->ui);
     $installer->setConfig($this->config);
     require_once 'PEAR/Downloader/Package.php';
     $pack = new PEAR_Downloader_Package($installer);
     $pack->setPackageFile($pf);
     $params[0] =& $pack;
     $installer->setOptions(array('packagingroot' => $instroot, 'nodeps' => true, 'soft' => true));
     $installer->setDownloadedPackages($params);
     // Don't change $params[0] below to $source_file - it's not the same
     // any more (see $params[0] a few lines above here)
     $package_info = $installer->install($params[0], array('packagingroot' => $instroot, 'nodeps' => true, 'soft' => true));
     if (PEAR::isError($package_info)) {
         $this->ui->outputData($package_info->getMessage());
         return $this->raiseError('Failed to do a temporary installation of the package');
     }
     // Restore the original config options
     foreach ($orig_config_options as $key => $val) {
         $this->config->set($key, $val);
     }
     // Restore the original config verbosity
     $this->config->set('verbose', $tmp);
     // Set up some of the basic macros
     $this->_output['rpm_package'] = $this->_getRPMName($pf->getPackage(), $pf->getChannel(), null, 'pkg');
     $this->_output['description'] = wordwrap($package_info['description']);
     $this->_output['summary'] = trim($package_info['summary']);
     $this->_output['possible_channel'] = $pf->getChannel();
     $this->_output['channel_alias'] = $this->_getChannelAlias($pf->getPackage(), $pf->getChannel());
     $this->_output['package'] = $pf->getPackage();
     $this->_output['version'] = $pf->getVersion();
     $this->_output['release_license'] = $pf->getLicense();
     $this->_output['release_state'] = $pf->getState();
     // Remove trailing dots from summaries
     if (substr($this->_output['summary'], -1) == '.') {
         $this->_output['summary'] = substr($this->_output['summary'], 0, -1);
     }
     // Figure out the master server for the package's channel
     $chan = $reg->getChannel($pf->getChannel());
     $this->_output['master_server'] = $chan->getServer();
     // Put some standard PEAR config options into the output macros. These
     // will probably be deprecated in future
     $cfg = array('php_dir', 'ext_dir', 'doc_dir', 'bin_dir', 'data_dir', 'test_dir');
     foreach ($cfg as $k) {
         $this->_output[$k] = $this->config->get($k);
     }
     // Generate the Requires and Conflicts for the RPM
     if ($pf->getDeps()) {
         $this->_generatePackageDeps($pf);
     }
     // Hook to support virtual Provides, where the dependency name differs
     // from the package name
     $rpmdep = $this->_getRPMName($pf->getPackage(), $pf->getChannel(), null, 'pkgdep');
     if (!empty($rpmdep) && $rpmdep != $this->_output['rpm_package']) {
         $this->_output['extra_headers'] .= $this->_formatRpmHeader('Provides', "{$rpmdep} = %{version}") . "\n";
     }
     // Create the list of files in the package
     foreach ($package_info['filelist'] as $filename => $attr) {
         // Ignore files with no role set or that didn't get installed
         if (!isset($attr['role']) || !isset($attr['installed_as'])) {
             continue;
         }
         $installed_filename = $attr['installed_as'];
         $role = $attr['role'];
         // Handle custom roles; set prefix
         // TODO: This is not tested and probably doesn't work, because:
         // a) package probably needs a custom file role package to build
         // b) [role]_dir wasn't set earlier before we did the test install
         if (!isset($this->_file_prefixes[$role])) {
             $this->_file_prefixes[$role] = $this->_file_prefixes['php'] . "/{$role}/%s";
             $this->_output['extra_config'] .= "\n        -d {$role}_dir=" . $this->_file_prefixes[$role] . "\\";
             $this->ui->outputData("WARNING: role '{$role}' used, " . 'and will be installed in "' . str_replace('%s', $pf->getPackage(), $this->_file_prefixes[$role]) . ' - hand-edit the final .spec if this is wrong', $command);
         }
         // Add to master file list
         $file_list[$role][] = $installed_filename;
     }
     // Build the master file lists
     foreach ($file_list as $role => $files) {
         // Docs are handled separately below; 'src' shouldn't be in RPM
         if ($role == 'doc' || $role == 'src') {
             continue;
         }
         // Master file list @files@ - recommended not to use
         $this->_output['files'] .= implode("\n", $files) . "\n";
         // Handle other roles specially: if the role puts files in a subdir
         // dedicated to the package in question (i.e. the prefix ends with
         // %s) we don't need to specify all the individual files
         if (in_array($role, array('php', 'test', 'data', 'script', 'cfg', 'www'))) {
             $macro_name = "{$role}_files_statement";
         } else {
             $macro_name = 'customrole_files_statement';
         }
         if (substr($this->_file_prefixes[$role], -2) == '%s') {
             $this->_output[$macro_name] = str_replace('%s', $pf->getPackage(), $this->_file_prefixes[$role]);
         } else {
             if ($role == 'cfg') {
                 $this->_output[$macro_name] = '%config(noreplace) ' . implode("\n%config(noreplace) ", $files);
             } else {
                 $this->_output[$macro_name] = implode("\n", $files);
             }
         }
     }
     $this->_output['files'] = trim($this->_output['files']);
     // Handle doc files
     if (isset($file_list['doc'])) {
         $this->_output['doc_files'] = 'docs/' . $pf->getPackage() . '/*';
         $this->_output['doc_files_statement'] = '%doc ' . $this->_output['doc_files'];
         $this->_output['doc_files_relocation_script'] = "mv %{buildroot}/docs .\n";
     }
     // Work out architecture
     // If there are 1 or more files with role="src", something needs compiling
     // and this is not a noarch package
     if (!isset($file_list['src'])) {
         $this->_output['arch_statement'] = $this->_formatRpmHeader('BuildArch', 'noarch') . "\n";
     }
     // If package is not from pear.php.net or pecl.php.net, we will need
     // to BuildRequire/Require a channel RPM
     if (!empty($this->_output['possible_channel']) && !in_array($this->_output['possible_channel'], $this->_standard_channels)) {
         $channel_dep = $this->_getRPMName($this->_output['package'], $this->_output['possible_channel'], null, 'chandep');
         $this->_output['extra_headers'] .= $this->_formatRpmHeader('BuildRequires', $channel_dep) . "\n";
         $this->_output['extra_headers'] .= $this->_formatRpmHeader('Requires', $channel_dep) . "\n";
     }
     // Remove any trailing newline from extra_headers
     $this->_output['extra_headers'] = trim($this->_output['extra_headers']);
 }