sean Sun Feb 4 19:31:45 2007 UTC
Modified files: /phpdoc/scripts functable.php Log: first stab at PECL support
http://cvs.php.net/viewvc.cgi/phpdoc/scripts/functable.php?r1=1.7&r2=1.8&diff_format=u Index: phpdoc/scripts/functable.php diff -u phpdoc/scripts/functable.php:1.7 phpdoc/scripts/functable.php:1.8 --- phpdoc/scripts/functable.php:1.7 Sat Feb 3 14:22:25 2007 +++ phpdoc/scripts/functable.php Sun Feb 4 19:31:45 2007 @@ -15,7 +15,7 @@ +----------------------------------------------------------------------+ | Authors: Sean Coates <[EMAIL PROTECTED]> | +----------------------------------------------------------------------+ -$Id: functable.php,v 1.7 2007/02/03 14:22:25 sean Exp $ +$Id: functable.php,v 1.8 2007/02/04 19:31:45 sean Exp $ */ // direct the output of this file into phpdoc/phpbook/phpbook-xsl/version.xml @@ -23,12 +23,16 @@ // To do: // - TEST, please -// - PECL support +// - someone should really make this code parse the source and not just look +// at the protos // You'll need to set up an SQLite DB (see PATH_DB, below) with the following: // CREATE TABLE func_tag (func_name VARCHAR(50), tag_name VARCHAR(50), // has_proto INT, is_alias INT, unicode_safe INT, source VARCHAR(255)); +// set $_ENV['DO_CVS'] to use php-src +// set $_ENV['DO_PECL'] to use PECL + // set up config: // set $_ENV['PATH_TMP'] to change the temporary directory @@ -47,6 +51,9 @@ function rm_recursive($path) { + if (!is_dir($path)) { + return; + } $dir = new DirectoryIterator($path); while($dir->valid()) { if(!$dir->isDot()) { @@ -61,7 +68,7 @@ rmdir($path); } -function get_release_tags() +function get_php_release_tags() { rm_recursive(PATH_TMP); mkdir(PATH_TMP); @@ -96,6 +103,51 @@ return array_reverse($tags); } +function get_pecl_packages() +{ + $packages = array(); + $XE = @new SimpleXMLElement('http://pecl.php.net/rest/p/packages.xml', NULL, true); //@ sucks, but the XML doesn't like me + foreach ($XE as $Element) { + if ($Element->getName() == 'p') { + $packages[] = strtolower((string) $Element); + } + } + return $packages; +} + +function get_pecl_releases($package) +{ + $releases = array(); + try { + $XE = @new SimpleXMLElement("http://pecl.php.net/rest/r/$package/allreleases.xml", NULL, true); //@ sucks, but the XML doesn't like me + foreach ($XE as $Element) { + if ($Element->getName() == 'r') { + if (preg_match('/[0-9]+\.[0-9]+(\.[0-9]+)?$/i', (string) $Element->v)) { + $releases[] = (string) $Element->v; + } + } + } + sort($releases); + return $releases; + } catch (Exception $e) { + fwrite(STDERR, " WARN: NO RELEASES\n"); + return false; + } +} + +function grab_pecl_release($package, $release) +{ + rm_recursive(PATH_TMP); + mkdir(PATH_TMP); + chdir(PATH_TMP); + + $remoteTarball = 'http://pecl.php.net/get/'. urlencode($package) . '-' . urlencode($release); + file_put_contents(PATH_TMP . '/pecl_tarball.tgz', file_get_contents($remoteTarball)); + + // should probably do this as natively as possible.. @@@fixme + exec('/bin/tar zxf pecl_tarball.tgz'); +} + function checkout_tag($tag) { rm_recursive(PATH_TMP); @@ -170,34 +222,34 @@ return $funcs; } -function convert_array_to_words($func) +function convert_array_to_words($func, $tags4, $tags5, $tagsPECL) { - // globals suck )-: - global $tags4, $tags5; + // this functions should be refactored - static $regex = '/PHP_([45])_([0-9])_([0-9])/'; + static $phpRegex = '/PHP_([45])_([0-9])_([0-9])/'; static $rep = '$1.$2.$3'; + // function exists in PHP 4? $text4 = ''; $ft4 = array(); foreach ($tags4 as $t) { if (isset($func[$t])) { $ft4[] = $t; } - } - + } if (!$ft4) { $text4 = ''; } elseif ($ft4 == $tags4) { $text4 = "PHP 4"; } else { if ($ft4[0] == $tags4[0]) { - $text4 = "PHP 4 <= " . preg_replace($regex, $rep, $ft4[count($ft4) - 1]); + $text4 = "PHP 4 <= " . preg_replace($phpRegex, $rep, $ft4[count($ft4) - 1]); } else { - $text4 = "PHP 4 >= " . preg_replace($regex, $rep, $ft4[0]); + $text4 = "PHP 4 >= " . preg_replace($phpRegex, $rep, $ft4[0]); } } + // function exists in PHP 5? $text5 = ''; $ft5 = array(); foreach ($tags5 as $t) { @@ -205,65 +257,157 @@ $ft5[] = $t; } } - if (!$ft5) { $text5 = ''; } elseif ($ft5 == $tags5) { $text5 = "PHP 5"; } else { if ($ft5[0] == $tags5[0]) { - $text5 = "PHP 5 <= " . preg_replace($regex, $rep, $ft5[count($ft5) - 1]); + $text5 = "PHP 5 <= " . preg_replace($phpRegex, $rep, $ft5[count($ft5) - 1]); } else { - $text5 = "PHP 5 >= " . preg_replace($regex, $rep, $ft5[0]); + $text5 = "PHP 5 >= " . preg_replace($phpRegex, $rep, $ft5[0]); + } + } + + // function exists in PECL? + $textPECL = ''; + if ($tagsPECL) { + $pkgPECL = array(); + // determine pacakges + foreach ($tagsPECL as $tag) { + list($pkg, $ver) = explode('-', $tag); + if (isset($func[$tag])) { + if (!isset($pkgPECL[$pkg])) { + $pkgPECL[$pkg] = array(); + } + $pkgPECL[$pkg][] = $ver; + } + } + foreach ($pkgPECL as $pkg => $vers) { + if ($textPECL) { + $textPECL .= ' '; // if there's something in the text, prepend a space + } + $textPECL .= strtolower($pkg) .':'. $vers[0]; + if (count($vers) > 1) { + $textPECL .= '-'. $vers[count($vers) - 1]; + } + } + if ($textPECL) { + $textPECL = 'PECL ' . $textPECL; // prepend PECL } } - if ($text4 && $text5) { - return "$text4, $text5"; - } elseif ($text4) { - return "$text4"; - } elseif ($text5) { - return "$text5"; - } else { - die("Error."); + // output + $texts = array_filter(array($text4, $text5, $textPECL)); // ignore empty classes + return implode(', ', $texts); +} + +function store_protos($tag, $protos, $source = 'php-src') +{ + $dbh = new PDO('sqlite:' . PATH_DB); + + $s = $dbh->prepare('DELETE FROM func_tag WHERE tag_name = ?'); + $s->bindParam(1, $tag); + $s->execute(); + + foreach ($protos as $p) { + $s = $dbh->prepare("INSERT INTO " + . "func_tag (func_name, tag_name, has_proto, unicode_safe, source) " + . "VALUES (?, ?, 1, ?, ?)"); + $s->bindParam(1, $p['func']); + $s->bindParam(2, $tag); + $s->bindParam(3, $p['unicode']); + $s->bindParam(4, $source); + $s->execute(); } } /////////////// /////////////// -if (getenv('SKIP_CVS')) { +if (!getenv('DO_CVS')) { fwrite(STDERR, "Skipping CVS\n"); } else { - fwrite(STDERR, "Using CVS\n"); - + fwrite(STDERR, "Using CVS\n"); if (getenv('FUNCTABLE_TAGS')) { $tags = explode(' ', getenv('FUNCTABLE_TAGS')); } else { - $tags = get_release_tags(); + $tags = get_php_release_tags(); } - fwrite(STDERR, "Tags: " . implode(' ', $tags) ."\n"); + fwrite(STDERR, "PHP Tags: " . implode(' ', $tags) ."\n"); foreach ($tags as $tag) { fwrite(STDERR, "Getting tag: $tag\n"); checkout_tag($tag); + $protos = parse_protos(PATH_TMP . DIRECTORY_SEPARATOR . 'php-src'); + store_protos($tag, $protos); + } +} + +if (getenv('DO_PECL')) { + fwrite(STDERR, "Skipping PECL\n"); +} else { + fwrite(STDERR, "Using PECL\n"); + $releases = array(); + if ($envReleases = getenv('PECL_RELEASES')) { + $envReleases = explode(' ', $envReleases); + sort($envReleases); + foreach ($envReleases as $envR) { + list($pkg, $ver) = explode('-', $envR); + if (isset($ver)) { // (allow for "runkit" instead of "runkit-0.8" + $vers = array($ver); + } else { + $vers = get_pecl_releases($pkg); + } + if ($vers) { + foreach ($vers as $ver) { + if (!isset($releases[$pkg])) { + $releases[$pkg] = array(); + } + if (!in_array($ver, $releases[$pkg])) { + $releases[$pkg][] = $ver; + } + } + } + } + } else { + foreach (get_pecl_packages() as $pkg) { + fwrite(STDERR, "Fetching releases for: $pkg\n"); + if ($peclReleases = get_pecl_releases($pkg)) { + foreach ($peclReleases as $ver) { + if (!isset($releases[$pkg])) { + $releases[$pkg] = array(); + } + $releases[$pkg][] = $ver; + } + } + } + } - $dbh = new PDO('sqlite:' . PATH_DB); - - $s = $dbh->prepare('DELETE FROM func_tag WHERE tag_name = ?'); - $s->bindParam(1, $tag); - $s->execute(); - - foreach ($protos as $p) { - $s = $dbh->prepare("INSERT INTO " - . "func_tag (func_name, tag_name, has_proto, unicode_safe, source) " - . "VALUES (?, ?, 1, ?, 'php-src')"); - $s->bindParam(1, $p['func']); - $s->bindParam(2, $tag); - $s->bindParam(3, $p['unicode']); - $s->execute(); + foreach ($releases as $pkg => $versions) { + foreach ($versions as $ver) { + $pkgName = $pkg . '-' . $ver; + fwrite(STDERR, "Grabbing PECL Release: " . $pkgName ."\n"); + grab_pecl_release($pkg, $ver); + fwrite(STDERR, "Parsing protos ...\n"); + // sometimes PECL package name case is broken: + $dirName = false; + if (is_dir(PATH_TMP . DIRECTORY_SEPARATOR . $pkgName)) { + $dirName = PATH_TMP . DIRECTORY_SEPARATOR . $pkgName; + } elseif (is_dir(PATH_TMP . DIRECTORY_SEPARATOR . strtolower($pkgName))) { + $dirName = PATH_TMP . DIRECTORY_SEPARATOR . strtolower($pkgName); + } elseif (is_dir(PATH_TMP . DIRECTORY_SEPARATOR . strtoupper($pkgName))) { + $dirName = PATH_TMP . DIRECTORY_SEPARATOR . strtoupper($pkgName); + } else { + fwrite(STDERR, "ERROR: unable to determine package directory.\n"); + } + if ($dirName) { + $protos = parse_protos($dirName); + fwrite(STDERR, "Storing protos ...\n"); + store_protos($pkgName, $protos, 'PECL'); + } } } } @@ -301,27 +445,36 @@ func_tag WHERE UPPER(tag_name) = ? + AND + source = ? ORDER BY tag_name "); $tq = $dbh->query(" SELECT - DISTINCT UPPER(tag_name) AS tag_name + DISTINCT UPPER(tag_name) AS tag_name, + source FROM func_tag WHERE - tag_name LIKE 'PHP\\__\\__\\__' ESCAPE '\\' + ( + tag_name LIKE 'PHP\\__\\__\\__' ESCAPE '\\' + AND + source = 'php-src' + ) + OR + source = 'PECL' ORDER BY UPPER(tag_name) "); foreach ($tq as $tr) { $tags[] = $tr['tag_name']; - if ($s->execute(array($tr['tag_name']))) { + if ($s->execute(array($tr['tag_name'], $tr['source']))) { while ($fr = $s->fetch()) { if ($fr['func_name']) { - $funcs[$fr['func_name']][$tr['tag_name']] = 1; + $funcs[$fr['func_name']][$tr['tag_name']] = 1; } } } @@ -330,18 +483,19 @@ $tags4 = array(); $tags5 = array(); +$tagsPECL = array(); foreach ($tags as $t) { if (substr($t,0,5) == 'PHP_4') { $tags4[] = $t; } elseif (substr($t,0,5) == 'PHP_5') { $tags5[] = $t; - } else { - die('ERROR: '. $t); + } else { // must be PECL + $tagsPECL[] = $t; } } foreach ($funcs as $funcname => $func) { - $text = htmlspecialchars(convert_array_to_words($func)); + $text = htmlspecialchars(convert_array_to_words($func, $tags4, $tags5, $tagsPECL)); echo " <function name='{$funcname}' from='{$text}'/>\n"; } ?>