require_once 'Archive/Tar.php';
require_once 'System.php';
-/**
+/*
* TODO:
* - check in inforFromDescFile that the minimal data needed is present
* (pack name, version, files, others?)
* - inherance of dir attribs to files may fail under certain circumstances
*/
+
+/**
+ * Class providing common functionality for PEAR adminsitration classes.
+ */
class PEAR_Common extends PEAR
{
// {{{ properties
* Permitted release states
* @var array
*/
- var $releases_states = array('alpha','beta','stable','snapshot');
+ var $releases_states = array('alpha','beta','stable','snapshot','devel');
// }}}
// {{{ constructor
+ /**
+ * PEAR_Common constructor
+ *
+ * @access public
+ */
function PEAR_Common()
{
$GLOBALS['_PEAR_Common_tempfiles'] = array();
// }}}
// {{{ destructor
+ /**
+ * PEAR_Common destructor
+ *
+ * @access private
+ */
function _PEAR_Common()
{
// doesn't work due to bug #14744
// }}}
// {{{ addTempFile()
+ /**
+ * Register a temporary file or directory. When the destructor is
+ * executed, all registered temporary files and directories are
+ * removed.
+ *
+ * @param string name of file or directory
+ *
+ * @return void
+ *
+ * @access public
+ */
function addTempFile($file)
{
$this->_tempfiles[] = $file;
// }}}
// {{{ mkDirHier()
+ /**
+ * Wrapper to System::mkDir(), creates a directory as well as
+ * any necessary parent directories.
+ *
+ * @param string directory name
+ *
+ * @return bool TRUE on success, or a PEAR error
+ *
+ * @access public
+ */
function mkDirHier($dir)
{
$this->log(2, "+ create dir $dir");
// }}}
// {{{ log()
+ /**
+ * Logging method.
+ *
+ * @param int log level (0 is quiet, higher is noisier)
+ *
+ * @param string message to write to the log
+ *
+ * @return void
+ *
+ * @access public
+ */
function log($level, $msg)
{
if ($this->debug >= $level) {
// }}}
// {{{ mkTempDir()
+ /**
+ * Create and register a temporary directory.
+ *
+ * @return string name of created directory
+ *
+ * @access public
+ */
function mkTempDir()
{
if (!$tmpdir = System::mktemp('-d pear')) {
// }}}
// {{{ _element_start()
+ /**
+ * XML parser callback for starting elements. Used while package
+ * format version is not yet known.
+ *
+ * @param resource XML parser resource
+ * @param string name of starting element
+ * @param array element attributes, name => value
+ *
+ * @return void
+ *
+ * @access private
+ */
function _element_start($xp, $name, $attribs)
+ {
+ array_push($this->element_stack, $name);
+ $this->current_element = $name;
+ $spos = sizeof($this->element_stack) - 2;
+ $this->prev_element = ($spos >= 0) ? $this->element_stack[$spos] : '';
+ $this->current_attributes = $attribs;
+ switch ($name) {
+ case 'package': {
+ if (isset($attribs['version'])) {
+ $vs = preg_replace('/[^0-9a-z]/', '_', $attribs['version']);
+ } else {
+ $vs = '1_0';
+ }
+ $elem_start = '_element_start_'. $vs;
+ $elem_end = '_element_end_'. $vs;
+ $cdata = '_pkginfo_cdata_'. $vs;
+ xml_set_element_handler($xp, $elem_start, $elem_end);
+ xml_set_character_data_handler($xp, $cdata);
+ break;
+ }
+ }
+ }
+
+ // }}}
+ // {{{ _element_end()
+
+ /**
+ * XML parser callback for ending elements. Used while package
+ * format version is not yet known.
+ *
+ * @param resource XML parser resource
+ * @param string name of ending element
+ *
+ * @return void
+ *
+ * @access private
+ */
+ function _element_end($xp, $name)
+ {
+ }
+
+ // }}}
+
+ // Support for package DTD v1.0:
+ // {{{ _element_start_1_0()
+
+ /**
+ * XML parser callback for ending elements. Used for version 1.0
+ * packages.
+ *
+ * @param resource XML parser resource
+ * @param string name of ending element
+ *
+ * @return void
+ *
+ * @access private
+ */
+ function _element_start_1_0($xp, $name, $attribs)
{
array_push($this->element_stack, $name);
$this->current_element = $name;
break;
case 'libfile':
$this->lib_atts = $attribs;
- $this->lib_atts['role'] = 'extension';
+ $this->lib_atts['role'] = 'extsrc';
break;
case 'maintainers':
$this->pkginfo['maintainers'] = array();
}
break;
case 'deps':
- $this->pkginfo['release_deps'] = array();
+ if (!$this->in_changelog) {
+ $this->pkginfo['release_deps'] = array();
+ }
break;
case 'dep':
// dependencies array index
- $this->d_i = (isset($this->d_i)) ? $this->d_i + 1 : 0;
- $this->pkginfo['release_deps'][$this->d_i] = $attribs;
+ if (!$this->in_changelog) {
+ $this->d_i = (isset($this->d_i)) ? $this->d_i + 1 : 0;
+ $this->pkginfo['release_deps'][$this->d_i] = $attribs;
+ }
break;
}
}
// }}}
- // {{{ _element_end()
+ // {{{ _element_end_1_0()
- function _element_end($xp, $name)
+ /**
+ * XML parser callback for ending elements. Used for version 1.0
+ * packages.
+ *
+ * @param resource XML parser resource
+ * @param string name of ending element
+ *
+ * @return void
+ *
+ * @access private
+ */
+ function _element_end_1_0($xp, $name)
{
$data = trim($this->cdata);
switch ($name) {
}
break;
case 'libfile':
- $this->lib_name = $data;
$path = '';
if (!empty($this->dir_names)) {
foreach ($this->dir_names as $dir) {
$this->filelist[$path]['baseinstalldir'] = $this->dir_install;
}
if (isset($this->lib_sources)) {
- $this->filelist[$path]['sources'] = $this->lib_sources;
+ $this->filelist[$path]['sources'] = implode(' ', $this->lib_sources);
}
unset($this->lib_atts);
unset($this->lib_sources);
+ unset($this->lib_name);
+ break;
+ case 'libname':
+ $this->lib_name = $data;
break;
case 'maintainer':
+ if (empty($this->pkginfo['maintainers'][$this->m_i]['role'])) {
+ $this->pkginfo['maintainers'][$this->m_i]['role'] = 'lead';
+ }
$this->m_i++;
break;
case 'release':
}
// }}}
- // {{{ _pkginfo_cdata()
+ // {{{ _pkginfo_cdata_1_0()
- function _pkginfo_cdata($xp, $data)
+ /**
+ * XML parser callback for character data. Used for version 1.0
+ * packages.
+ *
+ * @param resource XML parser resource
+ * @param string character data
+ *
+ * @return void
+ *
+ * @access private
+ */
+ function _pkginfo_cdata_1_0($xp, $data)
{
$this->cdata .= $data;
}
+ // }}}
+
+ // {{{ infoFromTgzFile()
+
+ /**
+ * Returns information about a package file. Expects the name of
+ * a gzipped tar file as input.
+ *
+ * @param string name of .tgz file
+ *
+ * @return array array with package information
+ *
+ * @access public
+ *
+ */
+ function infoFromTgzFile($file)
+ {
+ if (!@is_file($file)) {
+ return $this->raiseError('tgz :: could not open file');
+ }
+ $tar = new Archive_Tar($file, true);
+ $content = $tar->listContent();
+ if (!is_array($content)) {
+ return $this->raiseError('tgz :: could not get contents of package');
+ }
+ $xml = null;
+ foreach ($content as $file) {
+ $name = $file['filename'];
+ if ($name == 'package.xml') {
+ $xml = $name;
+ } elseif (ereg('^.*/package.xml$', $name, $match)) {
+ $xml = $match[0];
+ }
+ }
+ $tmpdir = System::mkTemp('-d pear');
+ $this->addTempFile($tmpdir);
+ if (!$xml || !$tar->extractList($xml, $tmpdir)) {
+ return $this->raiseError('tgz :: could not extract the package.xml file');
+ }
+ return $this->infoFromDescriptionFile("$tmpdir/$xml");
+ }
+
// }}}
// {{{ infoFromDescriptionFile()
+ /**
+ * Returns information about a package file. Expects the name of
+ * a package xml file as input.
+ *
+ * @param string name of package xml file
+ *
+ * @return array array with package information
+ *
+ * @access public
+ *
+ */
function infoFromDescriptionFile($descfile)
{
if (!@is_file($descfile) || !is_readable($descfile) ||
(!$fp = @fopen($descfile, 'r'))) {
return $this->raiseError("Unable to open $descfile");
}
+
+ // read the whole thing so we only get one cdata callback
+ // for each block of cdata
+ $data = fread($fp, filesize($descfile));
+ return $this->infoFromString($data);
+ }
+
+ // }}}
+ // {{{ infoFromString()
+
+ /**
+ * Returns information about a package file. Expects the contents
+ * of a package xml file as input.
+ *
+ * @param string name of package xml file
+ *
+ * @return array array with package information
+ *
+ * @access public
+ *
+ */
+ function infoFromString($data)
+ {
$xp = @xml_parser_create();
if (!$xp) {
return $this->raiseError('Unable to create XML parser');
$this->dir_names = array();
$this->in_changelog = false;
- // read the whole thing so we only get one cdata callback
- // for each block of cdata
- $data = fread($fp, filesize($descfile));
if (!xml_parse($xp, $data, 1)) {
+ $code = xml_get_error_code($xp);
$msg = sprintf("XML error: %s at line %d",
- xml_error_string(xml_get_error_code($xp)),
+ xml_error_string($code),
xml_get_current_line_number($xp));
xml_parser_free($xp);
- return $this->raiseError($msg);
+ return $this->raiseError($msg, $code);
}
xml_parser_free($xp);
return $this->pkginfo;
}
// }}}
- // {{{ infoFromTgzFile()
+ // {{{ xmlFromInfo()
/**
- * Returns info from a tgz pear package
- */
- function infoFromTgzFile($file)
+ * Return an XML document based on the package info (as returned
+ * by the PEAR_Common::infoFrom* methods).
+ *
+ * @param array package info
+ *
+ * @return string XML data
+ *
+ * @access public
+ */
+ function xmlFromInfo($pkginfo)
{
- if (!@is_file($file)) {
- return $this->raiseError('tgz :: could not open file');
+ static $maint_map = array(
+ "handle" => "user",
+ "name" => "name",
+ "email" => "email",
+ "role" => "role",
+ );
+ $ret = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n";
+ //$ret .= "<!DOCTYPE package SYSTEM \"http://pear.php.net/package10.dtd\">\n";
+ $ret .= "<package version=\"1.0\">
+ <name>$pkginfo[package]</name>
+ <summary>".htmlspecialchars($pkginfo['summary'])."</summary>
+ <description>".htmlspecialchars($pkginfo['description'])."</description>
+ <maintainers>
+";
+ foreach ($pkginfo['maintainers'] as $maint) {
+ $ret .= " <maintainer>\n";
+ foreach ($maint_map as $idx => $elm) {
+ $ret .= " <$elm>";
+ $ret .= htmlspecialchars($maint[$idx]);
+ $ret .= "</$elm>\n";
+ }
+ $ret .= " </maintainer>\n";
}
- $tar = new Archive_Tar($file, true);
- $content = $tar->listContent();
- if (!is_array($content)) {
- return $this->raiseError('tgz :: could not get contents of package');
+ $ret .= " </maintainers>\n";
+ $ret .= $this->_makeReleaseXml($pkginfo);
+ if (@sizeof($pkginfo['changelog']) > 0) {
+ $ret .= " <changelog>\n";
+ foreach ($pkginfo['changelog'] as $oldrelease) {
+ var_dump($oldrelease);
+ $ret .= $this->_makeReleaseXml($oldrelease, true);
+ }
+ $ret .= " </changelog>\n";
}
- $xml = null;
- foreach ($content as $file) {
- $name = $file['filename'];
- if ($name == 'package.xml') {
- $xml = $name;
- } elseif (ereg('^.*/package.xml$', $name, $match)) {
- $xml = $match[0];
+ $ret .= "</package>\n";
+ return $ret;
+ }
+
+ // }}}
+ // {{{ _makeReleaseXml()
+
+ /**
+ * Generate part of an XML description with release information.
+ *
+ * @param array array with release information
+ * @param bool whether the result will be in a changelog element
+ *
+ * @return string XML data
+ *
+ * @access private
+ */
+ function _makeReleaseXml($pkginfo, $changelog = false)
+ {
+ $indent = $changelog ? " " : "";
+ $ret = "$indent <release>\n";
+ if (!empty($pkginfo['version'])) {
+ $ret .= "$indent <version>$pkginfo[version]</version>\n";
+ }
+ if (!empty($pkginfo['release_date'])) {
+ $ret .= "$indent <date>$pkginfo[release_date]</date>\n";
+ }
+ if (!empty($pkginfo['release_license'])) {
+ $ret .= "$indent <license>$pkginfo[release_license]</license>\n";
+ }
+ if (!empty($pkginfo['release_state'])) {
+ $ret .= "$indent <state>$pkginfo[release_state]</state>\n";
+ }
+ if (!empty($pkginfo['release_notes'])) {
+ $ret .= "$indent <notes>$pkginfo[release_notes]</notes>\n";
+ }
+ if (sizeof($pkginfo['release_deps']) > 0) {
+ $ret .= "$indent <deps>\n";
+ foreach ($pkginfo['release_deps'] as $dep) {
+ $ret .= "$indent <dep type=\"$dep[type]\" rel=\"$dep[rel]\"";
+ if (isset($dep['version'])) {
+ $ret .= " version=\"$dep[version]\"";
+ }
+ if (isset($dep['name'])) {
+ $ret .= ">$dep[name]</dep>\n";
+ } else {
+ $ret .= "/>\n";
+ }
}
+ $ret .= "$indent </deps>\n";
}
- $tmpdir = System::mkTemp('-d pear');
- $this->addTempFile($tmpdir);
- if (!$xml || !$tar->extractList($xml, $tmpdir)) {
- return $this->raiseError('tgz :: could not extract the package.xml file');
+ $ret .= "$indent <filelist>\n";
+/*
+ ob_start();
+ var_dump($pkginfo['filelist']);
+ $tmp = ob_get_contents();
+ ob_end_clean();
+ $ret .= $tmp;
+*/
+ foreach ($pkginfo['filelist'] as $file => $fa) {
+ if ($fa['role'] == 'extsrc') {
+ $ret .= "$indent <libfile>\n";
+ $ret .= "$indent <libname>$file</libname>\n";
+ $ret .= "$indent <sources>$fa[sources]</sources>\n";
+ $ret .= "$indent </libfile>\n";
+ } else {
+ $ret .= "$indent <file role=\"$fa[role]\"";
+ if (isset($fa['baseinstalldir'])) {
+ $ret .= " baseinstalldir=\"$fa[baseinstalldir]\"";
+ }
+ $ret .= ">$file</file>\n";
+ }
}
- return $this->infoFromDescriptionFile("$tmpdir/$xml");
+ $ret .= "$indent </filelist>\n";
+ $ret .= "$indent </release>\n";
+ return $ret;
+ }
// }}}
- }
}
?>
\ No newline at end of file