summaryrefslogtreecommitdiff
path: root/buildscripts/phing/classes/phing/Phing.php
diff options
context:
space:
mode:
Diffstat (limited to 'buildscripts/phing/classes/phing/Phing.php')
-rwxr-xr-x[-rw-r--r--]buildscripts/phing/classes/phing/Phing.php1155
1 files changed, 704 insertions, 451 deletions
diff --git a/buildscripts/phing/classes/phing/Phing.php b/buildscripts/phing/classes/phing/Phing.php
index bb8d67f6..d663ee42 100644..100755
--- a/buildscripts/phing/classes/phing/Phing.php
+++ b/buildscripts/phing/classes/phing/Phing.php
@@ -1,6 +1,6 @@
<?php
/*
- * $Id: Phing.php,v 1.51 2006/01/06 15:12:33 hlellelid Exp $
+ * $Id: 1ad418f51ac07c9afaadf1c1f4befd5535f5b390 $
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
@@ -18,13 +18,14 @@
* and is licensed under the LGPL. For more information please see
* <http://phing.info>.
*/
-
+
require_once 'phing/Project.php';
require_once 'phing/ProjectComponent.php';
require_once 'phing/Target.php';
require_once 'phing/Task.php';
include_once 'phing/BuildException.php';
+include_once 'phing/ConfigurationException.php';
include_once 'phing/BuildEvent.php';
include_once 'phing/parser/Location.php';
@@ -41,11 +42,13 @@ include_once 'phing/parser/NestedElementHandler.php';
include_once 'phing/system/util/Properties.php';
include_once 'phing/util/StringHelper.php';
include_once 'phing/system/io/PhingFile.php';
+include_once 'phing/system/io/OutputStream.php';
+include_once 'phing/system/io/FileOutputStream.php';
include_once 'phing/system/io/FileReader.php';
include_once 'phing/system/util/Register.php';
/**
- * Entry point into Phing. This class handles the full lifecycle of a build -- from
+ * Entry point into Phing. This class handles the full lifecycle of a build -- from
* parsing & handling commandline arguments to assembling the project to shutting down
* and cleaning up in the end.
*
@@ -55,7 +58,7 @@ include_once 'phing/system/util/Register.php';
*
* @author Andreas Aderhold <andi@binarycloud.com>
* @author Hans Lellelid <hans@xmpl.org>
- * @version $Revision: 1.51 $
+ * @version $Id: 1ad418f51ac07c9afaadf1c1f4befd5535f5b390 $
* @package phing
*/
class Phing {
@@ -63,8 +66,8 @@ class Phing {
/** The default build file name */
const DEFAULT_BUILD_FILENAME = "build.xml";
- /** Our current message output status. Follows PROJECT_MSG_XXX */
- private static $msgOutputLevel = PROJECT_MSG_INFO;
+ /** Our current message output status. Follows Project::MSG_XXX */
+ private static $msgOutputLevel = Project::MSG_INFO;
/** PhingFile that we are using for configuration */
private $buildFile = null;
@@ -85,90 +88,166 @@ class Phing {
/** The class to handle input (can be only one). */
private $inputHandlerClassname;
-
+
/** Indicates if this phing should be run */
private $readyToRun = false;
/** Indicates we should only parse and display the project help information */
private $projectHelp = false;
-
+
/** Used by utility function getResourcePath() */
private static $importPaths;
-
+
/** System-wide static properties (moved from System) */
private static $properties = array();
-
+
/** Static system timer. */
private static $timer;
-
- /** The current Project */
- private static $currentProject;
-
- /** Whether to capture PHP errors to buffer. */
- private static $phpErrorCapture = false;
-
- /** Array of captured PHP errors */
- private static $capturedPhpErrors = array();
-
+
+ /** The current Project */
+ private static $currentProject;
+
+ /** Whether to capture PHP errors to buffer. */
+ private static $phpErrorCapture = false;
+
+ /** Array of captured PHP errors */
+ private static $capturedPhpErrors = array();
+
/**
- * Prints the message of the Exception if it's not null.
+ * @var OUtputStream Stream for standard output.
*/
- function printMessage(Exception $t) {
- print($t->getMessage() . "\n");
- if (self::getMsgOutputLevel() === PROJECT_MSG_DEBUG) {
- print($t->getTraceAsString()."\n");
- if ($t instanceof Exception) {
- $c = $t->getCause();
- if ($c !== null) {
- print("Wrapped exception trace:\n");
- print($c->getTraceAsString() . "\n");
- }
- }
- } // if output level is DEBUG
- }
+ private static $out;
- /**
+ /**
+ * @var OutputStream Stream for error output.
+ */
+ private static $err;
+
+ /**
+ * @var boolean Whether we are using a logfile.
+ */
+ private static $isLogFileUsed = false;
+
+ /**
+ * Array to hold original ini settings that Phing changes (and needs
+ * to restore in restoreIni() method).
+ *
+ * @var array Struct of array(setting-name => setting-value)
+ * @see restoreIni()
+ */
+ private static $origIniSettings = array();
+
+ /**
* Entry point allowing for more options from other front ends.
- *
+ *
* This method encapsulates the complete build lifecycle.
- *
- * @param array &$args The commandline args passed to phing shell script.
+ *
+ * @param array $args The commandline args passed to phing shell script.
* @param array $additionalUserProperties Any additional properties to be passed to Phing (alternative front-end might implement this).
* These additional properties will be available using the getDefinedProperty() method and will
- * be added to the project's "user" properties.
- * @return void
+ * be added to the project's "user" properties
* @see execute()
* @see runBuild()
+ * @throws Exception - if there is an error during build
*/
- public static function start(&$args, $additionalUserProperties = null) {
+ public static function start($args, array $additionalUserProperties = null) {
try {
$m = new Phing();
$m->execute($args);
} catch (Exception $exc) {
- $m->printMessage($exc);
- self::halt(-1); // Parameter error
+ self::handleLogfile();
+ throw $exc;
}
if ($additionalUserProperties !== null) {
- $keys = $m->additionalUserProperties->keys();
- while(count($keys)) {
- $key = array_shift($keys);
- $property = $m->additionalUserProperties->getProperty($key);
- $m->setDefinedProperty($key, $property);
+ foreach($additionalUserProperties as $key => $value) {
+ $m->setDefinedProperty($key, $value);
}
}
try {
$m->runBuild();
} catch(Exception $exc) {
- self::halt(1); // Errors occured
+ self::handleLogfile();
+ throw $exc;
}
-
+
// everything fine, shutdown
- self::halt(0); // no errors, everything is cake
+ self::handleLogfile();
}
-
+
+ /**
+ * Prints the message of the Exception if it's not null.
+ * @param Exception $t
+ */
+ public static function printMessage(Exception $t) {
+ if (self::$err === null) { // Make sure our error output is initialized
+ self::initializeOutputStreams();
+ }
+ if (self::getMsgOutputLevel() >= Project::MSG_VERBOSE) {
+ self::$err->write($t->__toString() . PHP_EOL);
+ } else {
+ self::$err->write($t->getMessage() . PHP_EOL);
+ }
+ }
+
+ /**
+ * Sets the stdout and stderr streams if they are not already set.
+ */
+ private static function initializeOutputStreams() {
+ if (self::$out === null) {
+ self::$out = new OutputStream(fopen("php://stdout", "w"));
+ }
+ if (self::$err === null) {
+ self::$err = new OutputStream(fopen("php://stderr", "w"));
+ }
+ }
+
+ /**
+ * Sets the stream to use for standard (non-error) output.
+ * @param OutputStream $stream The stream to use for standard output.
+ */
+ public static function setOutputStream(OutputStream $stream) {
+ self::$out = $stream;
+ }
+
+ /**
+ * Gets the stream to use for standard (non-error) output.
+ * @return OutputStream
+ */
+ public static function getOutputStream() {
+ return self::$out;
+ }
+
+ /**
+ * Sets the stream to use for error output.
+ * @param OutputStream $stream The stream to use for error output.
+ */
+ public static function setErrorStream(OutputStream $stream) {
+ self::$err = $stream;
+ }
+
+ /**
+ * Gets the stream to use for error output.
+ * @return OutputStream
+ */
+ public static function getErrorStream() {
+ return self::$err;
+ }
+
+ /**
+ * Close logfiles, if we have been writing to them.
+ *
+ * @since Phing 2.3.0
+ */
+ private static function handleLogfile() {
+ if (self::$isLogFileUsed) {
+ self::$err->close();
+ self::$out->close();
+ }
+ }
+
/**
* Making output level a static property so that this property
* can be accessed by other parts of the system, enabling
@@ -177,8 +256,8 @@ class Phing {
*/
public static function getMsgOutputLevel() {
return self::$msgOutputLevel;
- }
-
+ }
+
/**
* Command line entry point. This method kicks off the building
* of a project object and executes a build using either a given
@@ -190,65 +269,92 @@ class Phing {
public static function fire($args) {
self::start($args, null);
}
-
+
/**
* Setup/initialize Phing environment from commandline args.
* @param array $args commandline args passed to phing shell.
* @return void
*/
public function execute($args) {
-
+
self::$definedProps = new Properties();
$this->searchForThis = null;
- // cycle through given args
- for ($i = 0, $argcount = count($args); $i < $argcount; ++$i) {
- // ++$i intentional here, as first param is script name
+ // 1) First handle any options which should always
+ // Note: The order in which these are executed is important (if multiple of these options are specified)
+
+ if (in_array('-help', $args) || in_array('-h', $args)) {
+ $this->printUsage();
+ return;
+ }
+
+ if (in_array('-version', $args) || in_array('-v', $args)) {
+ $this->printVersion();
+ return;
+ }
+
+ // 2) Next pull out stand-alone args.
+ // Note: The order in which these are executed is important (if multiple of these options are specified)
+
+ if (false !== ($key = array_search('-quiet', $args, true)) || false !== ($key = array_search('-q', $args, true))) {
+ self::$msgOutputLevel = Project::MSG_WARN;
+ unset($args[$key]);
+ }
+
+ if (false !== ($key = array_search('-verbose', $args, true))) {
+ self::$msgOutputLevel = Project::MSG_VERBOSE;
+ unset($args[$key]);
+ }
+
+ if (false !== ($key = array_search('-debug', $args, true))) {
+ self::$msgOutputLevel = Project::MSG_DEBUG;
+ unset($args[$key]);
+ }
+
+ // 3) Finally, cycle through to parse remaining args
+ //
+ $keys = array_keys($args); // Use keys and iterate to max(keys) since there may be some gaps
+ $max = $keys ? max($keys) : -1;
+ for($i=0; $i <= $max; $i++) {
+
+ if (!array_key_exists($i, $args)) {
+ // skip this argument, since it must have been removed above.
+ continue;
+ }
+
$arg = $args[$i];
- if ($arg == "-help" || $arg == "-h") {
- $this->printUsage();
- return;
- } elseif ($arg == "-version" || $arg == "-v") {
- $this->printVersion();
- return;
- } elseif ($arg == "-quiet" || $arg == "-q") {
- self::$msgOutputLevel = PROJECT_MSG_WARN;
- } elseif ($arg == "-verbose") {
- $this->printVersion();
- self::$msgOutputLevel = PROJECT_MSG_VERBOSE;
- } elseif ($arg == "-debug") {
- $this->printVersion();
- self::$msgOutputLevel = PROJECT_MSG_DEBUG;
- } elseif ($arg == "-logfile") {
- try { // try to set logfile
+ if ($arg == "-logfile") {
+ try {
+ // see: http://phing.info/trac/ticket/65
if (!isset($args[$i+1])) {
- print("You must specify a log file when using the -logfile argument\n");
- return;
+ $msg = "You must specify a log file when using the -logfile argument\n";
+ throw new ConfigurationException($msg);
} else {
$logFile = new PhingFile($args[++$i]);
- $this->loggerClassname = 'phing.listener.PearLogger';
- $this->setDefinedProperty('pear.log.name', $logFile->getAbsolutePath());
+ $out = new FileOutputStream($logFile); // overwrite
+ self::setOutputStream($out);
+ self::setErrorStream($out);
+ self::$isLogFileUsed = true;
}
} catch (IOException $ioe) {
- print("Cannot write on the specified log file. Make sure the path exists and you have write permissions.\n");
- throw $ioe;
+ $msg = "Cannot write on the specified log file. Make sure the path exists and you have write permissions.";
+ throw new ConfigurationException($msg, $ioe);
}
} elseif ($arg == "-buildfile" || $arg == "-file" || $arg == "-f") {
if (!isset($args[$i+1])) {
- print("You must specify a buildfile when using the -buildfile argument\n");
- return;
+ $msg = "You must specify a buildfile when using the -buildfile argument.";
+ throw new ConfigurationException($msg);
} else {
$this->buildFile = new PhingFile($args[++$i]);
}
} elseif ($arg == "-listener") {
if (!isset($args[$i+1])) {
- print("You must specify a listener class when using the -listener argument\n");
- return;
+ $msg = "You must specify a listener class when using the -listener argument";
+ throw new ConfigurationException($msg);
} else {
$this->listeners[] = $args[++$i];
}
-
} elseif (StringHelper::startsWith("-D", $arg)) {
$name = substr($arg, 2);
$value = null;
@@ -256,28 +362,41 @@ class Phing {
if ($posEq !== false) {
$value = substr($name, $posEq+1);
$name = substr($name, 0, $posEq);
- } elseif ($i < count($args)-1) {
+ } elseif ($i < count($args)-1 && !StringHelper::startsWith("-D", $args[$i + 1])) {
$value = $args[++$i];
}
self::$definedProps->setProperty($name, $value);
} elseif ($arg == "-logger") {
if (!isset($args[$i+1])) {
- print("You must specify a classname when using the -logger argument\n");
- return;
+ $msg = "You must specify a classname when using the -logger argument";
+ throw new ConfigurationException($msg);
} else {
$this->loggerClassname = $args[++$i];
}
} elseif ($arg == "-inputhandler") {
if ($this->inputHandlerClassname !== null) {
- throw new BuildException("Only one input handler class may be specified.");
+ throw new ConfigurationException("Only one input handler class may be specified.");
}
if (!isset($args[$i+1])) {
- print("You must specify a classname when using the -inputhandler argument\n");
- return;
+ $msg = "You must specify a classname when using the -inputhandler argument";
+ throw new ConfigurationException($msg);
} else {
$this->inputHandlerClassname = $args[++$i];
}
- } elseif ($arg == "-projecthelp" || $arg == "-targets" || $arg == "-list" || $arg == "-l") {
+ } elseif ($arg == "-propertyfile") {
+ if (!isset($args[$i+1])) {
+ $msg = "You must specify a filename when using the -propertyfile argument";
+ throw new ConfigurationException($msg);
+ } else {
+ $p = new Properties();
+ $p->load(new PhingFile($args[++$i]));
+ foreach ($p->getProperties() as $prop => $value) {
+ $this->setProperty($prop, $value);
+ }
+ }
+ } elseif ($arg == "-longtargets") {
+ self::$definedProps->setProperty('phing.showlongtargets', 1);
+ } elseif ($arg == "-projecthelp" || $arg == "-targets" || $arg == "-list" || $arg == "-l" || $arg == "-p") {
// set the flag to display the targets and quit
$this->projectHelp = true;
} elseif ($arg == "-find") {
@@ -289,8 +408,8 @@ class Phing {
}
} elseif (substr($arg,0,1) == "-") {
// we don't have any more args
- print("Unknown argument: $arg\n");
- $this->printUsage();
+ self::$err->write("Unknown argument: $arg" . PHP_EOL);
+ self::printUsage();
return;
} else {
// if it's no other arg, it may be the target
@@ -309,12 +428,12 @@ class Phing {
}
// make sure buildfile exists
if (!$this->buildFile->exists()) {
- throw new BuildException("Buildfile: " . $this->buildFile->__toString() . " does not exist!");
+ throw new ConfigurationException("Buildfile: " . $this->buildFile->__toString() . " does not exist!");
}
// make sure it's not a directory
- if ($this->buildFile->isDirectory()) {
- throw new BuildException("Buildfile: " . $this->buildFile->__toString() . " is a dir!");
+ if ($this->buildFile->isDirectory()) {
+ throw new ConfigurationException("Buildfile: " . $this->buildFile->__toString() . " is a dir!");
}
$this->readyToRun = true;
@@ -326,15 +445,10 @@ class Phing {
* @param PhingFile $file
* @return PhingFile Parent file or null if none
*/
- function _getParentFile(PhingFile $file) {
+ private function _getParentFile(PhingFile $file) {
$filename = $file->getAbsolutePath();
$file = new PhingFile($filename);
$filename = $file->getParent();
-
- if ($filename !== null && self::$msgOutputLevel >= PROJECT_MSG_VERBOSE) {
- print("Searching in $filename\n");
- }
-
return ($filename === null) ? null : new PhingFile($filename);
}
@@ -345,17 +459,14 @@ class Phing {
* parent directory in search of a build file. Once the
* root of the file-system has been reached an exception
* is thrown.
- *
+ *
* @param string $start Start file path.
* @param string $suffix Suffix filename to look for in parents.
* @return PhingFile A handle to the build file
*
* @throws BuildException Failed to locate a build file
*/
- function _findBuildFile($start, $suffix) {
- if (self::$msgOutputLevel >= PROJECT_MSG_INFO) {
- print("Searching for $suffix ...\n");
- }
+ private function _findBuildFile($start, $suffix) {
$startf = new PhingFile($start);
$parent = new PhingFile($startf->getAbsolutePath());
$file = new PhingFile($parent, $suffix);
@@ -368,7 +479,7 @@ class Phing {
// if parent is null, then we are at the root of the fs,
// complain that we can't find the build file.
if ($parent === null) {
- throw new BuildException("Could not locate a build file!");
+ throw new ConfigurationException("Could not locate a build file!");
}
// refresh our file handle
$file = new PhingFile($parent, $suffix);
@@ -385,17 +496,17 @@ class Phing {
if (!$this->readyToRun) {
return;
}
-
+
$project = new Project();
-
- self::setCurrentProject($project);
- set_error_handler(array('Phing', 'handlePhpError'));
-
+
+ self::setCurrentProject($project);
+ set_error_handler(array('Phing', 'handlePhpError'));
+
$error = null;
$this->addBuildListeners($project);
$this->addInputHandler($project);
-
+
// set this right away, so that it can be used in logging.
$project->setUserProperty("phing.file", $this->buildFile->getAbsolutePath());
@@ -404,7 +515,7 @@ class Phing {
$project->init();
} catch (Exception $exc) {
$project->fireBuildFinished($exc);
- throw $exc;
+ throw $exc;
}
$project->setUserProperty("phing.version", $this->getPhingVersion());
@@ -421,30 +532,40 @@ class Phing {
// first use the Configurator to create the project object
// from the given build file.
-
+
try {
ProjectConfigurator::configureProject($project, $this->buildFile);
} catch (Exception $exc) {
$project->fireBuildFinished($exc);
- restore_error_handler();
- self::unsetCurrentProject();
+ restore_error_handler();
+ self::unsetCurrentProject();
throw $exc;
- }
+ }
// make sure that we have a target to execute
if (count($this->targets) === 0) {
$this->targets[] = $project->getDefaultTarget();
}
+ // make sure that minimum required phing version is satisfied
+ try {
+ $this->comparePhingVersion($project->getPhingVersion());
+ } catch(Exception $exc) {
+ $project->fireBuildFinished($exc);
+ restore_error_handler();
+ self::unsetCurrentProject();
+ throw $exc;
+ }
+
// execute targets if help param was not given
if (!$this->projectHelp) {
-
- try {
+
+ try {
$project->executeTargets($this->targets);
} catch (Exception $exc) {
$project->fireBuildFinished($exc);
- restore_error_handler();
- self::unsetCurrentProject();
+ restore_error_handler();
+ self::unsetCurrentProject();
throw $exc;
}
}
@@ -455,32 +576,68 @@ class Phing {
$this->printTargets($project);
} catch (Exception $exc) {
$project->fireBuildFinished($exc);
- restore_error_handler();
- self::unsetCurrentProject();
+ restore_error_handler();
+ self::unsetCurrentProject();
throw $exc;
}
}
-
+
// finally {
if (!$this->projectHelp) {
$project->fireBuildFinished(null);
}
-
- restore_error_handler();
- self::unsetCurrentProject();
+
+ restore_error_handler();
+ self::unsetCurrentProject();
}
-
+
+ private function comparePhingVersion($version) {
+ $current = strtolower(self::getPhingVersion());
+ $current = trim(str_replace('phing', '', $current));
+
+ // make sure that version checks are not applied to trunk
+ if('dev' === $current) {
+ return 1;
+ }
+
+ if(-1 == version_compare($current, $version)) {
+ throw new BuildException(
+ sprintf('Incompatible Phing version (%s). Version "%s" required.', $current, $version));
+ }
+ }
+
/**
- * Bind any default build listeners to this project.
- * Currently this means adding the logger.
+ * Bind any registered build listeners to this project.
+ *
+ * This means adding the logger and any build listeners that were specified
+ * with -listener arg.
+ *
* @param Project $project
* @return void
*/
private function addBuildListeners(Project $project) {
// Add the default listener
$project->addBuildListener($this->createLogger());
+
+ foreach($this->listeners as $listenerClassname) {
+ try {
+ $clz = Phing::import($listenerClassname);
+ } catch (Exception $x) {
+ $msg = "Unable to instantiate specified listener "
+ . "class " . $listenerClassname . " : "
+ . $e->getMessage();
+ throw new ConfigurationException($msg);
+ }
+
+ $listener = new $clz();
+
+ if ($listener instanceof StreamRequiredBuildLogger) {
+ throw new ConfigurationException("Unable to add " . $listenerClassname . " as a listener, since it requires explicit error/output streams. (You can specify it as a -logger.)");
+ }
+ $project->addBuildListener($listener);
+ }
}
-
+
/**
* Creates the InputHandler and adds it to the project.
*
@@ -498,12 +655,12 @@ class Phing {
$handler = new $clz();
if ($project !== null && method_exists($handler, 'setProject')) {
$handler->setProject($project);
- }
+ }
} catch (Exception $e) {
$msg = "Unable to instantiate specified input handler "
- . "class " . $this->inputHandlerClassname . " : "
- . $e->getMessage();
- throw new BuildException($msg);
+ . "class " . $this->inputHandlerClassname . " : "
+ . $e->getMessage();
+ throw new ConfigurationException($msg);
}
}
$project->setInputHandler($handler);
@@ -511,165 +668,185 @@ class Phing {
/**
* Creates the default build logger for sending build events to the log.
- * @return BuildListener The created Logger
+ * @return BuildLogger The created Logger
*/
private function createLogger() {
if ($this->loggerClassname !== null) {
self::import($this->loggerClassname);
- // get class name part
+ // get class name part
$classname = self::import($this->loggerClassname);
$logger = new $classname;
+ if (!($logger instanceof BuildLogger)) {
+ throw new BuildException($classname . ' does not implement the BuildLogger interface.');
+ }
} else {
require_once 'phing/listener/DefaultLogger.php';
$logger = new DefaultLogger();
}
$logger->setMessageOutputLevel(self::$msgOutputLevel);
+ $logger->setOutputStream(self::$out);
+ $logger->setErrorStream(self::$err);
return $logger;
}
-
- /**
- * Sets the current Project
- * @param Project $p
- */
- public static function setCurrentProject($p) {
- self::$currentProject = $p;
- }
-
- /**
- * Unsets the current Project
- */
- public static function unsetCurrentProject() {
- self::$currentProject = null;
- }
-
- /**
- * Gets the current Project.
- * @return Project Current Project or NULL if none is set yet/still.
- */
- public static function getCurrentProject() {
- return self::$currentProject;
- }
-
- /**
- * A static convenience method to send a log to the current (last-setup) Project.
- * If there is no currently-configured Project, then this will do nothing.
- * @param string $message
- * @param int $priority PROJECT_MSG_INFO, etc.
- */
- public static function log($message, $priority = PROJECT_MSG_INFO) {
- $p = self::getCurrentProject();
- if ($p) {
- $p->log($message, $priority);
- }
- }
-
- /**
- * Error handler for PHP errors encountered during the build.
- * This uses the logging for the currently configured project.
- */
- public static function handlePhpError($level, $message, $file, $line) {
-
+
+ /**
+ * Sets the current Project
+ * @param Project $p
+ */
+ public static function setCurrentProject($p) {
+ self::$currentProject = $p;
+ }
+
+ /**
+ * Unsets the current Project
+ */
+ public static function unsetCurrentProject() {
+ self::$currentProject = null;
+ }
+
+ /**
+ * Gets the current Project.
+ * @return Project Current Project or NULL if none is set yet/still.
+ */
+ public static function getCurrentProject() {
+ return self::$currentProject;
+ }
+
+ /**
+ * A static convenience method to send a log to the current (last-setup) Project.
+ * If there is no currently-configured Project, then this will do nothing.
+ * @param string $message
+ * @param int $priority Project::MSG_INFO, etc.
+ */
+ public static function log($message, $priority = Project::MSG_INFO) {
+ $p = self::getCurrentProject();
+ if ($p) {
+ $p->log($message, $priority);
+ }
+ }
+
+ /**
+ * Error handler for PHP errors encountered during the build.
+ * This uses the logging for the currently configured project.
+ */
+ public static function handlePhpError($level, $message, $file, $line) {
+
// don't want to print supressed errors
if (error_reporting() > 0) {
-
- if (self::$phpErrorCapture) {
-
- self::$capturedPhpErrors[] = array('message' => $message, 'level' => $level, 'line' => $line, 'file' => $file);
-
- } else {
-
- $message = '[PHP Error] ' . $message;
- $message .= ' [line ' . $line . ' of ' . $file . ']';
-
- switch ($level) {
-
- case E_STRICT:
- case E_NOTICE:
- case E_USER_NOTICE:
- self::log($message, PROJECT_MSG_VERBOSE);
- break;
- case E_WARNING:
- case E_USER_WARNING:
- self::log($message, PROJECT_MSG_WARN);
- break;
- case E_ERROR:
- case E_USER_ERROR:
- default:
- self::log($message, PROJECT_MSG_ERR);
-
- } // switch
-
- } // if phpErrorCapture
-
+
+ if (self::$phpErrorCapture) {
+
+ self::$capturedPhpErrors[] = array('message' => $message, 'level' => $level, 'line' => $line, 'file' => $file);
+
+ } else {
+
+ $message = '[PHP Error] ' . $message;
+ $message .= ' [line ' . $line . ' of ' . $file . ']';
+
+ switch ($level) {
+ case 16384: // E_USER_DEPRECATED
+ case 8192: // E_DEPRECATED
+ case E_STRICT:
+ case E_NOTICE:
+ case E_USER_NOTICE:
+ self::log($message, Project::MSG_VERBOSE);
+ break;
+ case E_WARNING:
+ case E_USER_WARNING:
+ self::log($message, Project::MSG_WARN);
+ break;
+ case E_ERROR:
+ case E_USER_ERROR:
+ default:
+ self::log($message, Project::MSG_ERR);
+
+ } // switch
+
+ } // if phpErrorCapture
+
} // if not @
-
- }
-
- /**
- * Begins capturing PHP errors to a buffer.
- * While errors are being captured, they are not logged.
- */
- public static function startPhpErrorCapture() {
- self::$phpErrorCapture = true;
- self::$capturedPhpErrors = array();
- }
-
- /**
- * Stops capturing PHP errors to a buffer.
- * The errors will once again be logged after calling this method.
- */
- public static function stopPhpErrorCapture() {
- self::$phpErrorCapture = false;
- }
-
- /**
- * Clears the captured errors without affecting the starting/stopping of the capture.
- */
- public static function clearCapturedPhpErrors() {
- self::$capturedPhpErrors = array();
- }
-
- /**
- * Gets any PHP errors that were captured to buffer.
- * @return array array('message' => message, 'line' => line number, 'file' => file name, 'level' => error level)
- */
- public static function getCapturedPhpErrors() {
- return self::$capturedPhpErrors;
- }
-
+
+ }
+
+ /**
+ * Begins capturing PHP errors to a buffer.
+ * While errors are being captured, they are not logged.
+ */
+ public static function startPhpErrorCapture() {
+ self::$phpErrorCapture = true;
+ self::$capturedPhpErrors = array();
+ }
+
+ /**
+ * Stops capturing PHP errors to a buffer.
+ * The errors will once again be logged after calling this method.
+ */
+ public static function stopPhpErrorCapture() {
+ self::$phpErrorCapture = false;
+ }
+
+ /**
+ * Clears the captured errors without affecting the starting/stopping of the capture.
+ */
+ public static function clearCapturedPhpErrors() {
+ self::$capturedPhpErrors = array();
+ }
+
+ /**
+ * Gets any PHP errors that were captured to buffer.
+ * @return array array('message' => message, 'line' => line number, 'file' => file name, 'level' => error level)
+ */
+ public static function getCapturedPhpErrors() {
+ return self::$capturedPhpErrors;
+ }
+
/** Prints the usage of how to use this class */
- function printUsage() {
- $lSep = self::getProperty("line.separator");
+ public static function printUsage() {
+
$msg = "";
- $msg .= "phing [options] [target [target2 [target3] ...]]" . $lSep;
- $msg .= "Options: " . $lSep;
- $msg .= " -h -help print this message" . $lSep;
- $msg .= " -l -list list available targets in this project" . $lSep;
- $msg .= " -v -version print the version information and exit" . $lSep;
- $msg .= " -q -quiet be extra quiet" . $lSep;
- $msg .= " -verbose be extra verbose" . $lSep;
- $msg .= " -debug print debugging information" . $lSep;
- $msg .= " -logfile <file> use given file for log" . $lSep;
- $msg .= " -logger <classname> the class which is to perform logging" . $lSep;
- $msg .= " -f -buildfile <file> use given buildfile" . $lSep;
- $msg .= " -D<property>=<value> use value for given property" . $lSep;
- $msg .= " -find <file> search for buildfile towards the root of the" . $lSep;
- $msg .= " filesystem and use it" . $lSep;
- //$msg .= " -recursive <file> search for buildfile downwards and use it" . $lSep;
- $msg .= $lSep;
- $msg .= "Report bugs to <dev@phing.tigris.org>".$lSep;
- print($msg);
+ $msg .= "phing [options] [target [target2 [target3] ...]]" . PHP_EOL;
+ $msg .= "Options: " . PHP_EOL;
+ $msg .= " -h -help print this message" . PHP_EOL;
+ $msg .= " -l -list list available targets in this project" . PHP_EOL;
+ $msg .= " -v -version print the version information and exit" . PHP_EOL;
+ $msg .= " -q -quiet be extra quiet" . PHP_EOL;
+ $msg .= " -verbose be extra verbose" . PHP_EOL;
+ $msg .= " -debug print debugging information" . PHP_EOL;
+ $msg .= " -longtargets show target descriptions during build" . PHP_EOL;
+ $msg .= " -logfile <file> use given file for log" . PHP_EOL;
+ $msg .= " -logger <classname> the class which is to perform logging" . PHP_EOL;
+ $msg .= " -f -buildfile <file> use given buildfile" . PHP_EOL;
+ $msg .= " -D<property>=<value> use value for given property" . PHP_EOL;
+ $msg .= " -propertyfile <file> load all properties from file" . PHP_EOL;
+ $msg .= " -find <file> search for buildfile towards the root of the" . PHP_EOL;
+ $msg .= " filesystem and use it" . PHP_EOL;
+ $msg .= " -inputhandler <file> the class to use to handle user input" . PHP_EOL;
+ //$msg .= " -recursive <file> search for buildfile downwards and use it" . PHP_EOL;
+ $msg .= PHP_EOL;
+ $msg .= "Report bugs to <dev@phing.tigris.org>".PHP_EOL;
+ self::$err->write($msg);
}
- function printVersion() {
- print(self::getPhingVersion()."\n");
+ /**
+ * Prints the current Phing version.
+ */
+ public static function printVersion() {
+ self::$out->write(self::getPhingVersion().PHP_EOL);
}
- function getPhingVersion() {
+ /**
+ * Gets the current Phing version based on VERSION.TXT file.
+ * @return string
+ * @throws BuildException - if unable to find version file.
+ */
+ public static function getPhingVersion() {
$versionPath = self::getResourcePath("phing/etc/VERSION.TXT");
- if ($versionPath === null) {
- $versionPath = self::getResourcePath("etc/VERSION.TXT");
- }
+ if ($versionPath === null) {
+ $versionPath = self::getResourcePath("etc/VERSION.TXT");
+ }
+ if ($versionPath === null) {
+ throw new ConfigurationException("No VERSION.TXT file found; try setting phing.home environment variable.");
+ }
try { // try to read file
$buffer = null;
$file = new PhingFile($versionPath);
@@ -679,16 +856,17 @@ class Phing {
//$buffer = "PHING version 1.0, Released 2002-??-??";
$phingVersion = $buffer;
} catch (IOException $iox) {
- print("Can't read version information file\n");
- throw new BuildException("Build failed");
- }
+ throw new ConfigurationException("Can't read version information file");
+ }
return $phingVersion;
}
- /** Print the project description, if any */
- function printDescription(Project $project) {
+ /**
+ * Print the project description, if any
+ */
+ public static function printDescription(Project $project) {
if ($project->getDescription() !== null) {
- print($project->getDescription()."\n");
+ self::$out->write($project->getDescription() . PHP_EOL);
}
}
@@ -704,31 +882,34 @@ class Phing {
// split the targets in top-level and sub-targets depending
// on the presence of a description
-
+
$subNames = array();
$topNameDescMap = array();
-
- foreach($targets as $currentTarget) {
+
+ foreach($targets as $currentTarget) {
$targetName = $currentTarget->getName();
- $targetDescription = $currentTarget->getDescription();
-
+ $targetDescription = $currentTarget->getDescription();
+ if ($currentTarget->isHidden()) {
+ continue;
+ }
+
// subtargets are targets w/o descriptions
if ($targetDescription === null) {
$subNames[] = $targetName;
} else {
// topNames and topDescriptions are handled later
// here we store in hash map (for sorting purposes)
- $topNameDescMap[$targetName] = $targetDescription;
+ $topNameDescMap[$targetName] = $targetDescription;
if (strlen($targetName) > $maxLength) {
$maxLength = strlen($targetName);
}
}
}
-
+
// Sort the arrays
- sort($subNames); // sort array values, resetting keys (which are numeric)
+ sort($subNames); // sort array values, resetting keys (which are numeric)
ksort($topNameDescMap); // sort the keys (targetName) keeping key=>val associations
-
+
$topNames = array_keys($topNameDescMap);
$topDescriptions = array_values($topNameDescMap);
@@ -750,7 +931,7 @@ class Phing {
}
$this->_printTargets($topNames, $topDescriptions, "Main targets:", $maxLength);
$this->_printTargets($subNames, null, "Subtargets:", 0);
- }
+ }
/**
* Writes a formatted list of target names with an optional description.
@@ -770,14 +951,14 @@ class Phing {
* <i>are</i> shorter than this).
*/
private function _printTargets($names, $descriptions, $heading, $maxlen) {
- $lSep = self::getProperty("line.separator");
+
$spaces = ' ';
while (strlen($spaces) < $maxlen) {
$spaces .= $spaces;
}
$msg = "";
- $msg .= $heading . $lSep;
- $msg .= str_repeat("-",79) . $lSep;
+ $msg .= $heading . PHP_EOL;
+ $msg .= str_repeat("-",79) . PHP_EOL;
$total = count($names);
for($i=0; $i < $total; $i++) {
@@ -787,58 +968,74 @@ class Phing {
$msg .= substr($spaces, 0, $maxlen - strlen($names[$i]) + 2);
$msg .= $descriptions[$i];
}
- $msg .= $lSep;
+ $msg .= PHP_EOL;
}
if ($total > 0) {
- print $msg . $lSep;
- }
- }
-
- /**
- * Import a dot-path notation class path.
- * @param string $dotPath
- * @param mixed $classpath String or object supporting __toString()
- * @return string The unqualified classname (which can be instantiated).
- * @throws BuildException - if cannot find the specified file
- */
- public static function import($dotPath, $classpath = null) {
+ self::$out->write($msg . PHP_EOL);
+ }
+ }
+
+ /**
+ * Import a dot-path notation class path.
+ * @param string $dotPath
+ * @param mixed $classpath String or object supporting __toString()
+ * @return string The unqualified classname (which can be instantiated).
+ * @throws BuildException - if cannot find the specified file
+ */
+ public static function import($dotPath, $classpath = null) {
+
+ /// check if this is a PEAR-style path (@link http://pear.php.net/manual/en/standards.naming.php)
+ if (strpos($dotPath, '.') === false && strpos($dotPath, '_') !== false) {
+ $classname = $dotPath;
+ $dotPath = str_replace('_', '.', $dotPath);
+ } else {
+ $classname = StringHelper::unqualify($dotPath);
+ }
// first check to see that the class specified hasn't already been included.
// (this also handles case where this method is called w/ a classname rather than dotpath)
- $classname = StringHelper::unqualify($dotPath);
- if (class_exists($classname, false)) {
+ if (class_exists($classname)) {
return $classname;
}
-
+
$dotClassname = basename($dotPath);
$dotClassnamePos = strlen($dotPath) - strlen($dotClassname);
- $classFile = strtr($dotClassname, '.', DIRECTORY_SEPARATOR) . ".php";
+
+ // 1- temporarily replace escaped '.' with another illegal char (#)
+ $tmp = str_replace('\.', '##', $dotClassname);
+ // 2- swap out the remaining '.' with DIR_SEP
+ $tmp = strtr($tmp, '.', DIRECTORY_SEPARATOR);
+ // 3- swap back the escaped '.'
+ $tmp = str_replace('##', '.', $tmp);
+
+ $classFile = $tmp . ".php";
+
$path = substr_replace($dotPath, $classFile, $dotClassnamePos);
-
+
Phing::__import($path, $classpath);
-
+
return $classname;
- }
-
- /**
- * Import a PHP file
- * @param string $path Path to the PHP file
- * @param mixed $classpath String or object supporting __toString()
- * @throws BuildException - if cannot find the specified file
- */
- public static function __import($path, $classpath = null) {
-
+ }
+
+ /**
+ * Import a PHP file
+ * @param string $path Path to the PHP file
+ * @param mixed $classpath String or object supporting __toString()
+ * @throws BuildException - if cannot find the specified file
+ */
+ public static function __import($path, $classpath = null) {
+
if ($classpath) {
-
+
// Apparently casting to (string) no longer invokes __toString() automatically.
if (is_object($classpath)) {
$classpath = $classpath->__toString();
}
-
+
// classpaths are currently additive, but we also don't want to just
// indiscriminantly prepand/append stuff to the include_path. This means
// we need to parse current incldue_path, and prepend any
- // specified classpath locations that are not already in the include_path.
+ // specified classpath locations that are not already in the include_path.
//
// NOTE: the reason why we do it this way instead of just changing include_path
// and then changing it back, is that in many cases applications (e.g. Propel) will
@@ -848,88 +1045,89 @@ class Phing {
// be more expensive than switching & switching back (not sure, but maybe), it makes it
// possible to write far less expensive run-time applications (e.g. using Propel), which is
// really where speed matters more.
-
- $curr_parts = explode(PATH_SEPARATOR, ini_get('include_path'));
+
+ $curr_parts = explode(PATH_SEPARATOR, get_include_path());
$add_parts = explode(PATH_SEPARATOR, $classpath);
$new_parts = array_diff($add_parts, $curr_parts);
if ($new_parts) {
- if (self::getMsgOutputLevel() === PROJECT_MSG_DEBUG) {
- print("Phing::import() prepending new include_path components: " . implode(PATH_SEPARATOR, $new_parts) . "\n");
- }
- ini_set('include_path', implode(PATH_SEPARATOR, array_merge($new_parts, $curr_parts)));
+ set_include_path(implode(PATH_SEPARATOR, array_merge($new_parts, $curr_parts)));
}
}
- $ret = include_once($path);
-
+ $ret = include_once($path);
+
if ($ret === false) {
- $e = new BuildException("Error importing $path");
- if (self::getMsgOutputLevel() === PROJECT_MSG_DEBUG) {
- // We can't log this because listeners belong
- // to projects. We'll just print it -- of course
- // that isn't very compatible w/ other frontends (but
- // there aren't any right now, so I'm not stressing)
- print("Error importing $path\n");
- print($e->getTraceAsString()."\n");
- }
- throw $e;
+ $msg = "Error importing $path";
+ if (self::getMsgOutputLevel() >= Project::MSG_DEBUG) {
+ $x = new Exception("for-path-trace-only");
+ $msg .= $x->getTraceAsString();
+ }
+ throw new ConfigurationException($msg);
}
-
- return;
- }
-
- /**
- * Looks on include path for specified file.
- * @return string File found (null if no file found).
- */
- public static function getResourcePath($path) {
-
+ }
+
+ /**
+ * Looks on include path for specified file.
+ * @return string File found (null if no file found).
+ */
+ public static function getResourcePath($path) {
+
if (self::$importPaths === null) {
- $paths = ini_get("include_path");
+ $paths = get_include_path();
self::$importPaths = explode(PATH_SEPARATOR, ini_get("include_path"));
}
-
+
$path = str_replace('\\', DIRECTORY_SEPARATOR, $path);
$path = str_replace('/', DIRECTORY_SEPARATOR, $path);
foreach (self::$importPaths as $prefix) {
- $foo_path = $prefix . DIRECTORY_SEPARATOR . $path;
- if (file_exists($foo_path)) {
- return $foo_path;
+ $testPath = $prefix . DIRECTORY_SEPARATOR . $path;
+ if (file_exists($testPath)) {
+ return $testPath;
}
}
-
+
// Check for the property phing.home
- $home_dir = self::getProperty('phing.home');
-
- if ($home_dir)
- {
- $home_path = $home_dir . DIRECTORY_SEPARATOR . $path;
-
- if (file_exists($home_path))
- {
- return $home_path;
- }
- }
-
+ $homeDir = self::getProperty('phing.home');
+ if ($homeDir) {
+ $testPath = $homeDir . DIRECTORY_SEPARATOR . $path;
+ if (file_exists($testPath)) {
+ return $testPath;
+ }
+ }
+
// If we are using this via PEAR then check for the file in the data dir
// This is a bit of a hack, but works better than previous solution of assuming
// data_dir is on the include_path.
- $data_dir = '@DATA-DIR@';
- if ($data_dir{0} != '@') { // if we're using PEAR then the @ DATA-DIR @ token will have been substituted.
- $data_path = $data_dir . DIRECTORY_SEPARATOR . $path;
- if (file_exists($data_path)) {
- return $data_path;
- }
+ $dataDir = '@DATA-DIR@';
+ if ($dataDir{0} != '@') { // if we're using PEAR then the @ DATA-DIR @ token will have been substituted.
+ if (!file_exists($dataDir)) {
+ self::log("The PEAR data_dir setting is incorrect: {$dataDir}.", Project::MSG_ERR);
+ self::log("Please edit using 'pear config-set data_dir ...' and re-install Phing.", Project::MSG_ERR);
+ return null;
+ }
+
+ $testPath = $dataDir . DIRECTORY_SEPARATOR . $path;
+ if (file_exists($testPath)) {
+ return $testPath;
+ }
+ } else {
+ // We're not using PEAR, so do one additional check based on path of
+ // current file (Phing.php)
+ $maybeHomeDir = realpath(dirname(__FILE__) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..');
+ $testPath = $maybeHomeDir . DIRECTORY_SEPARATOR . $path;
+ if (file_exists($testPath)) {
+ return $testPath;
+ }
}
-
+
return null;
- }
-
- // -------------------------------------------------------------------------------------------
- // System-wide methods (moved from System class, which had namespace conflicts w/ PEAR System)
- // -------------------------------------------------------------------------------------------
-
+ }
+
+ // -------------------------------------------------------------------------------------------
+ // System-wide methods (moved from System class, which had namespace conflicts w/ PEAR System)
+ // -------------------------------------------------------------------------------------------
+
/**
* Set System constants which can be retrieved by calling Phing::getProperty($propName).
* @return void
@@ -944,20 +1142,20 @@ class Phing {
* Windows 98SE => WIN32
* FreeBSD 4.5p7 => FreeBSD
* Redhat Linux => Linux
- * Mac OS X => Darwin
+ * Mac OS X => Darwin
*/
self::setProperty('host.os', PHP_OS);
-
- // this is used by some tasks too
+
+ // this is used by some tasks too
self::setProperty('os.name', PHP_OS);
-
+
// it's still possible this won't be defined,
// e.g. if Phing is being included in another app w/o
// using the phing.php script.
if (!defined('PHP_CLASSPATH')) {
define('PHP_CLASSPATH', get_include_path());
}
-
+
self::setProperty('php.classpath', PHP_CLASSPATH);
// try to determine the host filesystem and set system property
@@ -976,24 +1174,26 @@ class Phing {
break;
}
+ self::setProperty('php.interpreter', getenv('PHP_COMMAND'));
+ self::setProperty('line.separator', PHP_EOL);
self::setProperty('php.version', PHP_VERSION);
self::setProperty('user.home', getenv('HOME'));
self::setProperty('application.startdir', getcwd());
- self::setProperty('line.separator', "\n");
+ self::setProperty('phing.startTime', gmdate('D, d M Y H:i:s', time()) . ' GMT');
// try to detect machine dependent information
$sysInfo = array();
if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN' && function_exists("posix_uname")) {
- $sysInfo = posix_uname();
+ $sysInfo = posix_uname();
} else {
- $sysInfo['nodename'] = php_uname('n');
- $sysInfo['machine']= php_uname('m') ;
- //this is a not so ideal substition, but maybe better than nothing
- $sysInfo['domain'] = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : "unknown";
- $sysInfo['release'] = php_uname('r');
- $sysInfo['version'] = php_uname('v');
- }
-
+ $sysInfo['nodename'] = php_uname('n');
+ $sysInfo['machine']= php_uname('m') ;
+ //this is a not so ideal substition, but maybe better than nothing
+ $sysInfo['domain'] = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : "unknown";
+ $sysInfo['release'] = php_uname('r');
+ $sysInfo['version'] = php_uname('v');
+ }
+
self::setProperty("host.name", isset($sysInfo['nodename']) ? $sysInfo['nodename'] : "unknown");
self::setProperty("host.arch", isset($sysInfo['machine']) ? $sysInfo['machine'] : "unknown");
@@ -1002,55 +1202,55 @@ class Phing {
self::setProperty("host.os.version", isset($sysInfo['version']) ? $sysInfo['version'] : "unknown");
unset($sysInfo);
}
-
+
/**
* This gets a property that was set via command line or otherwise passed into Phing.
* "Defined" in this case means "externally defined". The reason this method exists is to
- * provide a public means of accessing commandline properties for (e.g.) logger or listener
+ * provide a public means of accessing commandline properties for (e.g.) logger or listener
* scripts. E.g. to specify which logfile to use, PearLogger needs to be able to access
* the pear.log.name property.
- *
+ *
* @param string $name
* @return string value of found property (or null, if none found).
*/
public static function getDefinedProperty($name) {
return self::$definedProps->getProperty($name);
}
-
+
/**
* This sets a property that was set via command line or otherwise passed into Phing.
- *
+ *
* @param string $name
* @return string value of found property (or null, if none found).
*/
public static function setDefinedProperty($name, $value) {
return self::$definedProps->setProperty($name, $value);
}
-
+
/**
* Returns property value for a System property.
- * System properties are "global" properties like line.separator,
+ * System properties are "global" properties like application.startdir,
* and user.dir. Many of these correspond to similar properties in Java
* or Ant.
- *
+ *
* @param string $paramName
* @return string Value of found property (or null, if none found).
*/
public static function getProperty($propName) {
-
+
// some properties are detemined on each access
// some are cached, see below
// default is the cached value:
$val = isset(self::$properties[$propName]) ? self::$properties[$propName] : null;
-
- // special exceptions
+
+ // special exceptions
switch($propName) {
case 'user.dir':
$val = getcwd();
- break;
+ break;
}
-
+
return $val;
}
@@ -1059,56 +1259,106 @@ class Phing {
return self::$properties;
}
- public static function setProperty($propName, $propValue) {
+ public static function setProperty($propName, $propValue) {
$propName = (string) $propName;
$oldValue = self::getProperty($propName);
self::$properties[$propName] = $propValue;
return $oldValue;
}
-
+
public static function currentTimeMillis() {
list($usec, $sec) = explode(" ",microtime());
return ((float)$usec + (float)$sec);
}
-
+
/**
- * Sets the include path based on PHP_CLASSPATH constant (set in phing.php).
+ * Sets the include path to PHP_CLASSPATH constant (if this has been defined).
* @return void
+ * @throws ConfigurationException - if the include_path could not be set (for some bizarre reason)
*/
private static function setIncludePaths() {
- $success = false;
-
if (defined('PHP_CLASSPATH')) {
- $success = ini_set('include_path', PHP_CLASSPATH);
- } else {
- // don't do anything, just assume that include_path has been properly set.
- $success = true;
+ $result = set_include_path(PHP_CLASSPATH);
+ if ($result === false) {
+ throw new ConfigurationException("Could not set PHP include_path.");
+ }
+ self::$origIniSettings['include_path'] = $result; // save original value for setting back later
}
+ }
+
+ /**
+ * Converts shorthand notation values as returned by ini_get()
+ * @see http://www.php.net/ini_get
+ * @param string $val
+ */
+ private static function convertShorthand($val)
+ {
+ $val = trim($val);
+ $last = strtolower($val[strlen($val) - 1]);
- if ($success === false) {
- print("SYSTEM FAILURE: Could not set PHP include path\n");
- self::halt(-1);
+ switch($last) {
+ // The 'G' modifier is available since PHP 5.1.0
+ case 'g':
+ $val *= 1024;
+ case 'm':
+ $val *= 1024;
+ case 'k':
+ $val *= 1024;
}
- }
+ return $val;
+ }
+
/**
* Sets PHP INI values that Phing needs.
* @return void
*/
private static function setIni() {
- error_reporting(E_ALL);
+
+ self::$origIniSettings['error_reporting'] = error_reporting(E_ALL);
+
+ // We won't bother storing original max_execution_time, since 1) the value in
+ // php.ini may be wrong (and there's no way to get the current value) and
+ // 2) it would mean something very strange to set it to a value less than time script
+ // has already been running, which would be the likely change.
+
set_time_limit(0);
- ini_set('magic_quotes_gpc', 'off');
- ini_set('short_open_tag', 'off');
- ini_set('default_charset', 'iso-8859-1');
- ini_set('register_globals', 'off');
- ini_set('allow_call_time_pass_reference', 'on');
-
- // should return memory limit in MB
- $mem_limit = (int) ini_get('memory_limit');
- if ($mem_limit < 32) {
+
+ self::$origIniSettings['magic_quotes_gpc'] = ini_set('magic_quotes_gpc', 'off');
+ self::$origIniSettings['short_open_tag'] = ini_set('short_open_tag', 'off');
+ self::$origIniSettings['default_charset'] = ini_set('default_charset', 'iso-8859-1');
+ self::$origIniSettings['register_globals'] = ini_set('register_globals', 'off');
+ self::$origIniSettings['allow_call_time_pass_reference'] = ini_set('allow_call_time_pass_reference', 'on');
+ self::$origIniSettings['track_errors'] = ini_set('track_errors', 1);
+
+ $mem_limit = (int) self::convertShorthand(ini_get('memory_limit'));
+ if ($mem_limit < (32 * 1024 * 1024) && $mem_limit > -1) {
+ // We do *not* need to save the original value here, since we don't plan to restore
+ // this after shutdown (we don't trust the effectiveness of PHP's garbage collection).
ini_set('memory_limit', '32M'); // nore: this may need to be higher for many projects
- }
+ }
+ }
+
+ /**
+ * Restores [most] PHP INI values to their pre-Phing state.
+ *
+ * Currently the following settings are not restored:
+ * - max_execution_time (because getting current time limit is not possible)
+ * - memory_limit (which may have been increased by Phing)
+ *
+ * @return void
+ */
+ private static function restoreIni()
+ {
+ foreach(self::$origIniSettings as $settingName => $settingValue) {
+ switch($settingName) {
+ case 'error_reporting':
+ error_reporting($settingValue);
+ break;
+ default:
+ ini_set($settingName, $settingValue);
+ }
+ }
}
/**
@@ -1122,15 +1372,17 @@ class Phing {
}
return self::$timer;
}
-
- /**
+
+ /**
* Start up Phing.
- * Sets up the Phing environment -- does NOT initiate the build process.
+ * Sets up the Phing environment but does not initiate the build process.
* @return void
+ * @throws Exception - If the Phing environment cannot be initialized.
*/
public static function startup() {
-
- register_shutdown_function(array('Phing', 'shutdown'));
+
+ // setup STDOUT and STDERR defaults
+ self::initializeOutputStreams();
// some init stuff
self::getTimer()->start();
@@ -1139,23 +1391,24 @@ class Phing {
self::setIncludePaths();
self::setIni();
}
-
+
/**
* Halts the system.
+ * @deprecated This method is deprecated and is no longer called by Phing internally. Any
+ * normal shutdown routines are handled by the shutdown() method.
* @see shutdown()
*/
- public static function halt($code=0) {
- self::shutdown($code);
+ public static function halt() {
+ self::shutdown();
}
/**
- * Stops timers & exits.
+ * Performs any shutdown routines, such as stopping timers.
* @return void
*/
- public static function shutdown($exitcode = 0) {
- //print("[AUTOMATIC SYSTEM SHUTDOWN]\n");
+ public static function shutdown() {
+ self::restoreIni();
self::getTimer()->stop();
- exit($exitcode); // final point where everything stops
}
-
+
}