From: Stig Bakken Date: Tue, 17 Apr 2001 01:17:59 +0000 (+0000) Subject: * implemented PEAR_Packager to make distribution packages. Currently only X-Git-Tag: php-4.0.6RC1~395 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=457333c1fdd4be021f82477d1a2b8e98be760f78;p=php * implemented PEAR_Packager to make distribution packages. Currently only runs on platforms with GNU tar installed * the "pear" script now requires a command parameter (similar to cvs), for example "pear package Cache.xml" * broke PEAR_Installer :-) --- diff --git a/pear/PEAR.php.in b/pear/PEAR.php.in index 763162686a..490add5deb 100644 --- a/pear/PEAR.php.in +++ b/pear/PEAR.php.in @@ -399,7 +399,11 @@ class PEAR_Error trigger_error($this->getMessage(), $this->level); } if ($this->mode & PEAR_ERROR_DIE) { - die($this->getMessage()); + $msg = $this->getMessage(); + if (substr($msg, -1) != "\n") { + $msg .= "\n"; + } + die($msg); } if ($this->mode & PEAR_ERROR_CALLBACK) { if (is_string($this->callback) && strlen($this->callback)) { diff --git a/pear/PEAR/Installer.php b/pear/PEAR/Installer.php index e5f1faec4a..2cb212b208 100644 --- a/pear/PEAR/Installer.php +++ b/pear/PEAR/Installer.php @@ -20,11 +20,9 @@ require_once "PEAR.php"; -register_shutdown_function("__PEAR_Installer_cleanup"); - /** * Administration class used to install PEAR packages and maintain the - * class definition cache. + * installed package database. * * @since PHP 4.0.2 * @author Stig Bakken @@ -49,13 +47,16 @@ class PEAR_Installer extends PEAR var $pkgdir; /** directory where PHP code files go */ - var $pear_phpdir = PEAR_INSTALL_DIR; + var $phpdir; /** directory where PHP extension files go */ - var $pear_extdir = PEAR_EXTENSION_DIR; + var $extdir; /** directory where documentation goes */ - var $pear_docdir = ''; + var $docdir; + + /** directory where system state information goes */ + var $statedir; /** directory where the package wants to put files, relative * to one of the three previous dirs @@ -65,22 +66,32 @@ class PEAR_Installer extends PEAR /** debug mode (boolean) */ var $debug = false; - /** class loading cache */ - var $cache = array(); + /** list of installed packages */ + var $pkglist = array(); /** temporary directory */ var $tmpdir; - /** file pointer for cache file if open */ - var $cache_fp; + /** file pointer for package list file if open */ + var $pkglist_fp; + + /** list of temporary files created by this object */ + var $_tempfiles = array(); // }}} // {{{ constructor - function PEAR_Installer() { + function PEAR_Installer($phpdir = PEAR_INSTALL_DIR, + $extdir = PEAR_EXTENSION_DIR, + $docdir = '') + { $this->PEAR(); - $this->cacheLoad("$this->pear_phpdir/.cache"); + $this->phpdir = $phpdir; + $this->extdir = $extdir; + $this->docdir = $docdir; + $this->statedir = "/var/lib/php"; // XXX FIXME Windows + $this->loadPackageList("$this->statedir/packagelist.xml"); } // }}} @@ -89,33 +100,33 @@ class PEAR_Installer extends PEAR function _PEAR_Installer() { $this->_PEAR(); if ($this->tmpdir && is_dir($this->tmpdir)) { - system("rm -rf $this->tmpdir"); + system("rm -rf $this->tmpdir"); // XXX FIXME Windows } - if ($this->cache_fp && is_resource($this->cache_fp)) { - flock($this->cache_fp, LOCK_UN); - fclose($this->cache_fp); + if ($this->pkglist_fp && is_resource($this->pkglist_fp)) { + flock($this->pkglist_fp, LOCK_UN); + fclose($this->pkglist_fp); } $this->tmpdir = null; - $this->cache_fp = null; + $this->pkglist_fp = null; + while (is_array($this->_tempfiles) && + $file = array_shift($this->_tempfiles)) + { + if (is_dir($file)) { + system("rm -rf $file"); // XXX FIXME Windows + } else { + unlink($file); + } + } } // }}} - // {{{ raiseError() - - function raiseError($msg) - { - return new PEAR_Error("$msg\n", 0, PEAR_ERROR_DIE); - } - - // }}} // {{{ mkDirHier() function mkDirHier($dir) { $dirstack = array(); - // XXX FIXME this does not work on Windows! - while (!is_dir($dir) && $dir != "/") { + while (!is_dir($dir) && $dir != DIRECTORY_SEPARATOR) { array_unshift($dirstack, $dir); $dir = dirname($dir); } @@ -140,23 +151,23 @@ class PEAR_Installer extends PEAR // }}} - // {{{ cacheLock() + // {{{ lockPackageList() - function cacheLock() { - $fp = $this->cache_fp; + function lockPackageList() { + $fp = $this->pkglist_fp; if (!is_resource($fp)) { - $this->cache_fp = $fp = fopen($this->cache_file, "r"); + $this->pkglist_fp = $fp = fopen($this->pkglist_file, "r"); } return flock($fp, LOCK_EX); } // }}} - // {{{ cacheUnlock() + // {{{ unlockPackageList() - function cacheUnlock() { - $fp = $this->cache_fp; + function unlockPackageList() { + $fp = $this->pkglist_fp; if (!is_resource($fp)) { - $this->cache_fp = $fp = fopen($this->cache_file, "r"); + $this->pkglist_fp = $fp = fopen($this->pkglist_file, "r"); $doclose = true; } $ret = flock($fp, LOCK_EX); @@ -167,54 +178,54 @@ class PEAR_Installer extends PEAR } // }}} - // {{{ cacheLoad() + // {{{ loadPackageList() - function cacheLoad($file) { - $this->cache_file = $file; + function loadPackageList($file) { + $this->pkglist_file = $file; if (!file_exists($file)) { touch($file); } - $fp = $this->cache_fp = fopen($file, "r"); - $this->cacheLock(); + $fp = $this->pkglist_fp = fopen($file, "r"); + $this->lockPackageList(); while ($line = fgets($fp, 2048)) { list($type, $name, $file) = explode(" ", trim($line)); - $this->cache[$type][$name] = $file; + $this->pkglist[$type][$name] = $file; } } // }}} - // {{{ cacheSave() + // {{{ savePackageList() - function cacheSave() { - $fp = $this->cache_fp; - $wfp = fopen($this->cache_file, "w"); + function savePackageList() { + $fp = $this->pkglist_fp; + $wfp = fopen($this->pkglist_file, "w"); if (!$wfp) { return false; } if (is_resource($fp)) { fclose($fp); } - $this->cache_fp = $fp = $wfp; - reset($this->cache); - while (list($type, $entry) = each($this->cache)) { + $this->pkglist_fp = $fp = $wfp; + reset($this->pkglist); + while (list($type, $entry) = each($this->pkglist)) { reset($entry); while (list($name, $file) = each($entry)) { fwrite($fp, "$type $name $file\n"); } } fclose($fp); - $this->cache_fp = $fp = null; + $this->pkglist_fp = $fp = null; } // }}} - // {{{ cacheUpdateFrom() + // {{{ updatePackageListFrom() - function cacheUpdateFrom($file) { + function updatePackageListFrom($file) { /* $new = $this->classesDeclaredBy($file); reset($new); while (list($i, $name) = each($new)) { - $this->cache['class'][$name] = $file; + $this->pkglist['class'][$name] = $file; } */ } @@ -231,7 +242,6 @@ class PEAR_Installer extends PEAR * @return bool true if successful, false if not */ function install($pkgfile) { - global $_PEAR_Installer_tempfiles; if (preg_match('#^(http|ftp)://#', $pkgfile)) { $need_download = true; } elseif (!file_exists($pkgfile)) { @@ -240,9 +250,10 @@ class PEAR_Installer extends PEAR if ($need_download) { $file = basename($pkgfile); + // XXX FIXME Windows $downloaddir = "/tmp/pearinstall"; $this->mkDirHier($downloaddir); - $downloadfile = "$downloaddir/$file"; + $downloadfile = $downloaddir.DIRECTORY_SEPARATOR.$file; $this->log(1, "downloading $pkgfile..."); $fp = @fopen($pkgfile, "r"); if (!$fp) { @@ -263,8 +274,9 @@ class PEAR_Installer extends PEAR fclose($fp); fclose($wp); $this->log(1, "...done, $bytes bytes"); - $_PEAR_Installer_tempfiles[] = $downloadfile; + $this->tempfiles[] = $downloadfile; } + // XXX FIXME need internal support for gzip+tar $fp = popen("gzip -dc $pkgfile | tar -tf -", "r"); if (!$fp) { return $this->raiseError("Unable to examine $pkgfile (gzip or tar failed)"); @@ -284,18 +296,19 @@ class PEAR_Installer extends PEAR return $this->raiseError("Invalid package: no package.xml file found!"); } + // XXX FIXME Windows $this->tmpdir = tempnam("/tmp", "pear"); unlink($this->tmpdir); if (!mkdir($this->tmpdir, 0755)) { return $this->raiseError("Unable to create temporary directory $this->tmpdir."); } - $_PEAR_Installer_tempfiles[] = $this->tmpdir; - $pwd = trim(`pwd`); + $this->tempfiles[] = $this->tmpdir; + $pwd = getcwd(); - if (substr($pkgfile, 0, 1) == "/") { + if (substr($pkgfile, 0, 1) == DIRECTORY_SEPARATOR) { $pkgfilepath = $pkgfile; } else { - $pkgfilepath = $pwd.'/'.$pkgfile; + $pkgfilepath = $pwd.DIRECTORY_SEPARATOR.$pkgfile; } if (!chdir($this->tmpdir)) { @@ -323,13 +336,13 @@ class PEAR_Installer extends PEAR $this->element_stack = array(); $this->pkginfo = array(); $this->current_element = false; - $destdir = ''; + $this->destdir = ''; while ($data = fread($fp, 2048)) { if (!xml_parse($xp, $data, feof($fp))) { $err = $this->raiseError(sprintf("XML error: %s at line %d", - xml_error_string(xml_get_error_code($xp)), - xml_get_current_line_number($xp))); + xml_error_string(xml_get_error_code($xp)), + xml_get_current_line_number($xp))); xml_parser_free($xp); return $err; } @@ -374,12 +387,12 @@ class PEAR_Installer extends PEAR // switch ($this->current_element) { case "Dir": - if (!$this->pear_phpdir) { + if (!$this->phpdir) { break; } $type = $this->current_attributes["Type"]; $dir = trim($data); - $d = "$this->pear_phpdir/$this->destdir/$dir"; + $d = "$this->phpdir/$this->destdir/$dir"; if (substr($dir, 0, 1) == "/") { $this->destdir = substr($dir, 1); } else { @@ -399,23 +412,23 @@ class PEAR_Installer extends PEAR $this->log(1, "created dir $d"); break; case "File": - if (!$this->pear_phpdir) { + if (!$this->phpdir) { break; } $type = strtolower($this->current_attributes["Role"]); $file = trim($data); - $updatecache = false; + $updatepkglist = false; switch ($type) { case "test": $d = ""; // don't install test files for now break; default: if ($this->destdir) { - $d = "$this->pear_phpdir/$this->destdir"; + $d = "$this->phpdir/$this->destdir"; } else { - $d = $this->pear_phpdir; + $d = $this->phpdir; } - $updatecache = true; + $updatepkglist = true; break; } if (!$d) { @@ -429,8 +442,8 @@ class PEAR_Installer extends PEAR $this->log(0, "failed to copy $this->pkgdir/$file to $d"); break; } - if ($updatecache) { - $this->cacheUpdateFrom("$d/$file"); + if ($updatepkglist) { + $this->updatePackageListFrom("$d/$file"); } $this->log(1, "installed $d/$bfile"); break; @@ -459,7 +472,36 @@ class PEAR_Installer extends PEAR return $diff; } -// }}} + // }}} + + // {{{ declaredWhenIncluding() + + /** + * Find out which new classes are defined by a file. + * + * @param $file file name passed to "include" + * + * @return array classes that were defined + */ + function &declaredWhenIncluding($file) { + $classes_before = get_declared_classes(); + $funcs_before = get_defined_functions(); +// $vars_before = $GLOBALS; + ob_start(); + include($file); + ob_end_clean(); + $classes_after = get_declared_classes(); + $funcs_after = get_defined_functions(); +// $vars_after = $GLOBALS; + // using array_slice to renumber array + return array( + "classes" => array_slice(array_diff($classes_after, $classes_before), 0), + "functions" => array_slice(array_diff($funcs_after, $funcs_before), 0), +// "globals" => array_slice(array_diff($vars_after, $vars_before), 0) + ); + } + + // }}} // {{{ lockDir() @@ -490,18 +532,4 @@ class PEAR_Installer extends PEAR // }}} } -function __PEAR_Installer_cleanup() -{ - global $_PEAR_Installer_tempfiles; - if (is_array($_PEAR_Installer_tempfiles)) { - while ($file = array_shift($_PEAR_Installer_tempfiles)) { - if (is_dir($file)) { - system("rm -rf $file"); // XXX FIXME Windows - } else { - unlink($file); - } - } - } -} - ?> diff --git a/pear/PEAR/Packager.php b/pear/PEAR/Packager.php new file mode 100644 index 0000000000..2d67da771c --- /dev/null +++ b/pear/PEAR/Packager.php @@ -0,0 +1,309 @@ + | +// | | +// +----------------------------------------------------------------------+ +// + +require_once "PEAR.php"; + +/** + * Administration class used to install PEAR packages and maintain the + * installed package database. + * + * @since PHP 4.0.2 + * @author Stig Bakken + */ +class PEAR_Packager extends PEAR +{ + // {{{ properties + + /** XML_Parser object */ + var $parser; + + /** stack of elements, gives some sort of XML context */ + var $element_stack; + + /** name of currently parsed XML element */ + var $current_element; + + /** array of attributes of the currently parsed XML element */ + var $current_attributes = array(); + + /** assoc with information about the package */ + var $pkginfo = array(); + + /** name of the package directory, for example Foo-1.0 */ + var $pkgdir; + + /** directory where PHP code files go */ + var $phpdir; + + /** directory where PHP extension files go */ + var $extdir; + + /** directory where documentation goes */ + var $docdir; + + /** directory where system state information goes */ + var $statedir; + + /** debug mode (integer) */ + var $debug = 0; + + /** temporary directory */ + var $tmpdir; + + /** whether file list is currently being copied */ + var $recordfilelist; + + /** temporary space for copying file list */ + var $filelist; + + /** package name and version, for example "HTTP-1.0" */ + var $pkgver; + + // }}} + + // {{{ constructor + + function PEAR_Packager($phpdir = PEAR_INSTALL_DIR, + $extdir = PEAR_EXTENSION_DIR, + $docdir = '') + { + $this->PEAR(); + $this->phpdir = $phpdir; + $this->extdir = $extdir; + $this->docdir = $docdir; + } + + // }}} + // {{{ destructor + + function _PEAR_Packager() { + $this->_PEAR(); + while (is_array($this->_tempfiles) && + $file = array_shift($this->_tempfiles)) + { + if (is_dir($file)) { + system("rm -rf $file"); // XXX FIXME Windows + } else { + unlink($file); + } + } + } + + // }}} + + function Package($pkgfile = "package.xml") + { + $pwd = getcwd(); + $fp = @fopen($pkgfile, "r"); + if (!is_resource($fp)) { + return $this->raiseError($php_errormsg); + } + + $xp = xml_parser_create(); + if (!$xp) { + return $this->raiseError("Unable to create XML parser."); + } + xml_set_object($xp, $this); + xml_set_element_handler($xp, "startHandler", "endHandler"); + xml_set_character_data_handler($xp, "charHandler"); + xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, false); + xml_parser_set_option($xp, XML_OPTION_TARGET_ENCODING, "UTF-8"); + + $this->element_stack = array(); + $this->pkginfo = array(); + $this->current_element = false; + + $data = fread($fp, filesize($pkgfile)); + fclose($fp); + if (!xml_parse($xp, $data, true)) { + $msg = sprintf("XML error: %s at line %d", + xml_error_string(xml_get_error_code($xp)), + xml_get_current_line_number($xp)); + xml_parser_free($xp); + return $this->raiseError($msg); + } + xml_parser_free($xp); + + $pkginfofile = $this->tmpdir . DIRECTORY_SEPARATOR . "package.xml"; + $fp = fopen($pkginfofile, "w"); + if (!is_resource($fp)) { + return $this->raiseError("Could not create $pkginfofile: $php_errormsg"); + } + + $this->filelist = preg_replace('/^[\r\n]+\s+/', ' ', $this->filelist); + $this->filelist = preg_replace('/\n\s+/', "\n ", $this->filelist); + $this->filelist = preg_replace('/\n\s+$/', "", $this->filelist); + + fputs($fp, "\n". + "\n". + "\n". + " ".$this->pkginfo["Package,Name"]."\n". + " ".$this->pkginfo["Package,Summary"]."\n". + " \n". + " ".$this->pkginfo["Maintainer,Initials"]."\n". + " ".$this->pkginfo["Maintainer,Name"]."\n". + " ".$this->pkginfo["Maintainer,Email"]."\n". + " \n". + " \n". + " ".$this->pkginfo["Release,Version"]."\n". + " ".$this->pkginfo["Release,Date"]."\n". + " ".$this->pkginfo["Release,Notes"]."\n". + " \n". + " \n". + "$this->filelist\n". + " \n". + "\n"); + fclose($fp); + chdir(dirname($this->tmpdir)); + // XXX FIXME Windows and non-GNU tar + $pkgver = quotemeta($this->pkgver); + system("tar -cvzf $pwd/${pkgver}.tgz $pkgver"); + } + + // {{{ mkDirHier() + + function mkDirHier($dir) + { + $dirstack = array(); + while (!is_dir($dir) && $dir != DIRECTORY_SEPARATOR) { + array_unshift($dirstack, $dir); + $dir = dirname($dir); + } + while ($newdir = array_shift($dirstack)) { + if (mkdir($newdir, 0777)) { + $this->log(1, "created dir $newdir"); + } else { + return $this->raiseError("mkdir($newdir) failed"); + } + } + } + + // }}} + // {{{ log() + + function log($level, $msg) + { + if ($this->debug >= $level) { + print "$msg\n"; + } + } + + // }}} + + // {{{ startHandler() + + function startHandler($xp, $name, $attribs) + { + array_push($this->element_stack, $name); + $this->current_element = $name; + $this->current_attributes = $attribs; + $this->tmpdata = ''; + if ($this->recordfilelist) { + $this->filelist .= "<$name"; + foreach ($attribs as $k => $v) { + $this->filelist .= " $k=\"$v\""; + } + $this->filelist .= ">"; + } + switch ($name) { + case "Package": + if ($attribs["Type"]) { + // warning + } + break; + case "FileList": + // XXX FIXME Windows + $this->recordfilelist = true; + $pwd = getcwd(); + $this->pkgver = $this->pkginfo["Package,Name"] . "-" . + $this->pkginfo["Release,Version"]; + $this->tmpdir = $pwd . DIRECTORY_SEPARATOR . $this->pkgver; + if (file_exists($this->tmpdir)) { + xml_parser_free($xp); + $this->raiseError("$this->tmpdir already exists", + null, PEAR_ERROR_TRIGGER, + E_USER_ERROR); + } + if (!mkdir($this->tmpdir, 0755)) { + xml_parser_free($xp); + $this->raiseError("Unable to create temporary directory $this->tmpdir.", + null, PEAR_ERROR_TRIGGER, + E_USER_ERROR); + } + $this->_tempfiles[] = $this->tmpdir; + break; + } + } + + // }}} + // {{{ endHandler() + + function endHandler($xp, $name) + { + array_pop($this->element_stack); + $this->current_element = $this->element_stack[sizeof($this->element_stack)-1]; + switch ($name) { + case "FileList": + $this->recordfilelist = false; + break; + } + if ($this->recordfilelist) { + $this->filelist .= ""; + } + } + + // }}} + // {{{ charHandler() + + function charHandler($xp, $data) + { + if ($this->recordfilelist) { + $this->filelist .= $data; + } + switch ($this->current_element) { + case "Dir": + break; + case "File": + $file = "$this->tmpdir/$data"; + $dir = dirname($file); + if (!is_dir($dir)) { + if (!$this->mkDirHier($dir)) { + $this->log(0, "could not mkdir $dir"); + break; + } + } + if (!@copy($data, $file)) { + $this->log(0, "could not copy $data to $file"); + } + // fall through + default: + $data = trim($data); + if ($data) { + $id = implode(",", array_slice($this->element_stack, -2)); + $this->pkginfo[$id] = $data; + } + break; + } + } + + // }}} +} + +?> diff --git a/pear/scripts/pear.in b/pear/scripts/pear.in index 7025befba1..7ae61dbe2a 100644 --- a/pear/scripts/pear.in +++ b/pear/scripts/pear.in @@ -1,55 +1,58 @@ -#!@prefix@/bin/php -q +#!@prefix@/bin/php -Cq debug = $debug; -$p->install($pkgfile); +PEAR::setErrorHandling(PEAR_ERROR_PRINT); + +$command = $options[1][1]; +switch ($command) { + case "install": + $package = $options[1][2]; + $installer =& new PEAR_Installer(); + $installer->Install($package); + print "install ok\n"; + break; + case "package": + $pkginfofile = $options[1][2]; + $packager =& new PEAR_Packager(); + $packager->Package($pkginfofile); + print "package ok\n"; + break; + default: + usage(); + break; +} -function usage() +function usage($obj = null) { global $stderr; + if ($obj !== null) { + fputs($stderr, $obj->getMessage()); + } fputs($stderr, - "Usage: pear [-v n] [-h] \n". + "Usage: pear [-v n] [-h] command \n". "Options:\n". " -v set verbosity level to (0-2, default 1)\n". - " -h display help/usage (this message)\n"); - fclose($stderr); + " -h display help/usage (this message)\n". + "Commands:\n". + " install \n". + " package [package info file]\n". + "\n"); exit; }