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)) {
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 <ssb@fast.no>
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
/** 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");
}
// }}}
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);
}
// }}}
- // {{{ 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);
}
// }}}
- // {{{ 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;
}
*/
}
* @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)) {
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) {
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)");
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)) {
$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;
}
//
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 {
$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) {
$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;
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()
// }}}
}
-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);
- }
- }
- }
-}
-
?>
--- /dev/null
+<?php
+//
+// +----------------------------------------------------------------------+
+// | PHP version 4.0 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1997-2001 The PHP Group |
+// +----------------------------------------------------------------------+
+// | This source file is subject to version 2.02 of the PHP license, |
+// | that is bundled with this package in the file LICENSE, and is |
+// | available at through the world-wide-web at |
+// | http://www.php.net/license/2_02.txt. |
+// | If you did not receive a copy of the PHP license and are unable to |
+// | obtain it through the world-wide-web, please send a note to |
+// | license@php.net so we can mail you a copy immediately. |
+// +----------------------------------------------------------------------+
+// | Authors: Stig Bakken <ssb@fast.no> |
+// | |
+// +----------------------------------------------------------------------+
+//
+
+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 <ssb@fast.no>
+ */
+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, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n".
+ "<!DOCTYPE Package PUBLIC \"-//PHP Group//DTD PEAR Package 1.0//EN//XML\" \"http://php.net/pear/package.dtd\">\n".
+ "<Package Type=\"Source\">\n".
+ " <Name>".$this->pkginfo["Package,Name"]."</Name>\n".
+ " <Summary>".$this->pkginfo["Package,Summary"]."</Summary>\n".
+ " <Maintainer>\n".
+ " <Initials>".$this->pkginfo["Maintainer,Initials"]."</Initials>\n".
+ " <Name>".$this->pkginfo["Maintainer,Name"]."</Initials>\n".
+ " <Email>".$this->pkginfo["Maintainer,Email"]."</Email>\n".
+ " </Maintainer>\n".
+ " <Release>\n".
+ " <Version>".$this->pkginfo["Release,Version"]."</Version>\n".
+ " <Date>".$this->pkginfo["Release,Date"]."</Date>\n".
+ " <Notes>".$this->pkginfo["Release,Notes"]."</Notes>\n".
+ " </Release>\n".
+ " <FileList>\n".
+ "$this->filelist\n".
+ " </FileList>\n".
+ "</Package>\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 .= "</$name>";
+ }
+ }
+
+ // }}}
+ // {{{ 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;
+ }
+ }
+
+ // }}}
+}
+
+?>
-#!@prefix@/bin/php -q
+#!@prefix@/bin/php -Cq
<?php // -*- C++ -*-
require_once "PEAR.php";
require_once "PEAR/Installer.php";
+require_once "PEAR/Packager.php";
+require_once "Console/Getopt.php";
error_reporting(7);
$stderr = fopen("php://stderr", "w");
-$debug = 1;
-$optind = 1;
-
-while ($optind < $argc && $argv[$optind][0] == "-") {
- switch (substr($argv[$optind], 1)) {
- case "v":
- $debug = (int)$argv[++$optind];
- break;
- case "-":
- $optind++;
- break 2;
- default:
- fputs($stderr, "Unknown option: $argv[$optind]\n");
- /* fall through */
- case "?":
- case "h":
- usage();
- break;
- }
-
- $optind++;
-}
-
-$pkgfile = $argv[$optind];
+PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, "usage");
-if (!$pkgfile) {
- usage();
+$options = Console_Getopt::getopt($argv, "hv:?");
+if (PEAR::isError($options)) {
+ usage($options);
}
-$p = new PEAR_Installer();
-$p->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] <package>\n".
+ "Usage: pear [-v n] [-h] command <parameters>\n".
"Options:\n".
" -v set verbosity level to <n> (0-2, default 1)\n".
- " -h display help/usage (this message)\n");
- fclose($stderr);
+ " -h display help/usage (this message)\n".
+ "Commands:\n".
+ " install <package file>\n".
+ " package [package info file]\n".
+ "\n");
exit;
}