/** * Get the contents of a file listed within the package.xml * @param string * @return string */ function getFileContents($file) { if ($this->_archiveFile == $this->_packageFile) { // unpacked $dir = dirname($this->_packageFile); $file = $dir . DIRECTORY_SEPARATOR . $file; $file = str_replace(array('/', '\\'), array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), $file); if (file_exists($file) && is_readable($file)) { return implode('', file($file)); } } else { // tgz if (!class_exists('Archive_Tar')) { require_once 'Archive/Tar.php'; } $tar = new Archive_Tar($this->_archiveFile); $tar->pushErrorHandling(PEAR_ERROR_RETURN); if ($file != 'package.xml' && $file != 'package2.xml') { $file = $this->getPackage() . '-' . $this->getVersion() . '/' . $file; } $file = $tar->extractInString($file); $tar->popErrorHandling(); if (PEAR::isError($file)) { return PEAR::raiseError("Cannot locate file '{$file}' in archive"); } return $file; } }
/** * Create a PEAR_PackageFile_v* from a compresed Tar or Tgz file. * @access public * @param string contents of package.xml file * @param int package state (one of PEAR_VALIDATE_* constants) * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 * @using Archive_Tar to extract the files * @using fromPackageFile() to load the package after the package.xml * file is extracted. */ function &fromTgzFile($file, $state) { if (!class_exists('Archive_Tar')) { require_once 'Archive/Tar.php'; } $tar = new Archive_Tar($file); if ($this->_debug <= 1) { $tar->pushErrorHandling(PEAR_ERROR_RETURN); } $content = $tar->listContent(); if ($this->_debug <= 1) { $tar->popErrorHandling(); } if (!is_array($content)) { if (is_string($file) && strlen($file < 255) && (!file_exists($file) || !@is_file($file))) { $ret = PEAR::raiseError("could not open file \"{$file}\""); return $ret; } $file = realpath($file); $ret = PEAR::raiseError("Could not get contents of package \"{$file}\"" . '. Invalid tgz file.'); return $ret; } else { if (!count($content) && !@is_file($file)) { $ret = PEAR::raiseError("could not open file \"{$file}\""); return $ret; } } $xml = null; $origfile = $file; foreach ($content as $file) { $name = $file['filename']; if ($name == 'package2.xml') { // allow a .tgz to distribute both versions $xml = $name; break; } if ($name == 'package.xml') { $xml = $name; break; } elseif (ereg('package.xml$', $name, $match)) { $xml = $name; break; } } if ($this->_tmpdir) { $tmpdir = $this->_tmpdir; } else { $tmpdir = System::mkTemp(array('-d', 'pear')); PEAR_PackageFile::addTempFile($tmpdir); } $this->_extractErrors(); PEAR::staticPushErrorHandling(PEAR_ERROR_CALLBACK, array($this, '_extractErrors')); if (!$xml || !$tar->extractList(array($xml), $tmpdir)) { $extra = implode("\n", $this->_extractErrors()); if ($extra) { $extra = ' ' . $extra; } PEAR::staticPopErrorHandling(); $ret = PEAR::raiseError('could not extract the package.xml file from "' . $origfile . '"' . $extra); return $ret; } PEAR::staticPopErrorHandling(); $ret =& PEAR_PackageFile::fromPackageFile("{$tmpdir}/{$xml}", $state, $origfile); return $ret; }
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; }
/** * Returns information about a package file. Expects the name of * a gzipped tar file as input. * * @param string $file name of .tgz file * * @return array array with package information * * @access public * */ function infoFromTgzFile($file) { if (!@is_file($file)) { return $this->raiseError("could not open file \"{$file}\""); } $tar = new Archive_Tar($file); if ($this->debug <= 1) { $tar->pushErrorHandling(PEAR_ERROR_RETURN); } $content = $tar->listContent(); if ($this->debug <= 1) { $tar->popErrorHandling(); } if (!is_array($content)) { $file = realpath($file); return $this->raiseError("Could not get contents of package \"{$file}\"" . '. Invalid tgz file.'); } $xml = null; foreach ($content as $file) { $name = $file['filename']; if ($name == 'package.xml') { $xml = $name; break; } elseif (ereg('package.xml$', $name, $match)) { $xml = $match[0]; break; } } $tmpdir = System::mkTemp(array('-d', 'pear')); $this->addTempFile($tmpdir); if (!$xml || !$tar->extractList(array($xml), $tmpdir)) { return $this->raiseError('could not extract the package.xml file'); } return $this->infoFromDescriptionFile("{$tmpdir}/{$xml}"); }
function _generatePackageDeps($pf) { $requires = $conflicts = array(); if ($pf->getPackagexmlVersion() == '1.0') { foreach ($pf->getDeps() as $dep) { if (isset($dep['optional']) && $dep['optional'] == 'yes') { continue; } if (!isset($dep['type']) || $dep['type'] == 'pkg') { $type = 'pkgdep'; } else { $type = $dep['type']; } if (!isset($dep['channel'])) { $dep['channel'] = null; } if (!isset($dep['name'])) { $dep['name'] = ''; } //e.g. "php" dep // $package contains the *dependency name* here, which may or may // not be the same as the package name $package = $this->_getRPMName($dep['name'], $dep['channel'], null, $type); // If we could not find an RPM namespace equivalent, don't add the dependency if (empty($package)) { continue; } $trans = array('>' => '>', '<' => '<', '>=' => '>=', '<=' => '<=', '=' => '=', 'gt' => '>', 'lt' => '<', 'ge' => '>=', 'le' => '<=', 'eq' => '='); if ($dep['rel'] == 'has') { // We use $package as the index to the $requires array to de-duplicate deps. // Note that in the case of duplicate deps, versioned deps will "win" - see several lines down. $requires[$package] = $package; } elseif ($dep['rel'] == 'not') { $conflicts[] = $package; } elseif ($dep['rel'] == 'ne') { $conflicts[] = $package . ' = ' . $dep['version']; } elseif (isset($trans[$dep['rel']])) { $requires[$package] = $package . ' ' . $trans[$dep['rel']] . ' ' . $dep['version']; } } if (count($requires)) { $this->_output['extra_headers'] .= $this->_formatRpmHeader('Requires', implode(', ', $requires)) . "\n"; } if (count($conflicts)) { $this->_output['extra_headers'] .= $this->_formatRpmHeader('Conflicts', implode(', ', $conflicts)) . "\n"; } } else { $this->_output['package2xml'] = '2'; // tell the spec to use package2.xml $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 (!isset($dep['type']) || $dep['type'] == 'pkg') { $type = 'pkgdep'; } else { $type = $dep['type']; } if (!isset($dep['channel'])) { $dep['channel'] = null; } // $package contains the *dependency name* here, which may or may // not be the same as the package name $package = $this->_getRPMName($dep['name'], $dep['channel'], null, $type); if (empty($package)) { continue; } 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] = $package; } } else { if (isset($dep['min'])) { $requires[$package] = $package . ' >= ' . $dep['min']; } if (isset($dep['max'])) { $requires[$package] = $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)) { $this->_output['package2xml'] = ''; // this doesn't have a package.xml version 1.0 $requires[$this->_output['pear_rpm_name']] = $this->_output['pear_rpm_name'] . ' >= ' . $deps['required']['pearinstaller']['min']; } if (count($requires)) { $this->_output['extra_headers'] .= $this->_formatRpmHeader('Requires', implode(', ', $requires)) . "\n"; } if (count($conflicts)) { $this->_output['extra_headers'] .= $this->_formatRpmHeader('Conflicts', implode(', ', $conflicts)) . "\n"; } } } }
/** * Create a PEAR_PackageFile_v* from a compresed Tar or Tgz file. * @access public * @param string contents of package.xml file * @param int package state (one of PEAR_VALIDATE_* constants) * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 * @using Archive_Tar to extract the files * @using fromPackageFile() to load the package after the package.xml * file is extracted. */ function &fromTgzFile($file, $state) { if (!class_exists('Archive_Tar')) { require_once 'Archive/Tar.php'; } $tar = new Archive_Tar($file); if ($this->_debug <= 1) { $tar->pushErrorHandling(PEAR_ERROR_RETURN); } $content = $tar->listContent(); if ($this->_debug <= 1) { $tar->popErrorHandling(); } if (!is_array($content)) { if (is_string($file) && strlen($file < 255) && (!file_exists($file) || !@is_file($file))) { $ret = PEAR::raiseError("could not open file \"{$file}\""); return $ret; } $file = realpath($file); $ret = PEAR::raiseError("Could not get contents of package \"{$file}\"" . '. Invalid tgz file.'); return $ret; } if (!count($content) && !@is_file($file)) { $ret = PEAR::raiseError("could not open file \"{$file}\""); return $ret; } $sig = null; $xml = null; $origfile = $file; foreach ($content as $file) { $name = $file['filename']; if (is_null($xml) && ($name == 'package2.xml' || $name == 'package.xml' || preg_match('/package.xml$/', $name, $match))) { // allow a .tgz to distribute both versions $xml = $name; } if (is_null($sig) && $name == 'package.sig') { $sig = $name; } if (!is_null($sig) && !is_null($xml)) { break; } } $tmpdir = System::mktemp('-t "' . $this->_config->get('temp_dir') . '" -d pear'); if ($tmpdir === false) { $ret = PEAR::raiseError("there was a problem with getting the configured temp directory"); return $ret; } PEAR_PackageFile::addTempFile($tmpdir); $this->_extractErrors(); PEAR::staticPushErrorHandling(PEAR_ERROR_CALLBACK, array($this, '_extractErrors')); if (!$xml || !$tar->extractList(array_values(array_filter(array($sig, $xml))), $tmpdir)) { $extra = implode("\n", $this->_extractErrors()); if ($extra) { $extra = ' ' . $extra; } PEAR::staticPopErrorHandling(); $ret = PEAR::raiseError('could not extract the package.xml file from "' . $origfile . '"' . $extra); return $ret; } PEAR::staticPopErrorHandling(); // Check sig, if it exists. if (!is_null($sig)) { require_once 'PEAR/Gnupg.php'; $gnupg = new PEAR_Gnupg($this->_config); $result = $gnupg->validateSig("{$tmpdir}/{$xml}", "{$tmpdir}/{$sig}"); if (PEAR::isError($result)) { return $result; } } $ret =& PEAR_PackageFile::fromPackageFile("{$tmpdir}/{$xml}", $state, $origfile); return $ret; }