summaryrefslogtreecommitdiff
path: root/buildscripts/phing/classes/phing/Phing.php
diff options
context:
space:
mode:
Diffstat (limited to 'buildscripts/phing/classes/phing/Phing.php')
-rw-r--r--buildscripts/phing/classes/phing/Phing.php1161
1 files changed, 1161 insertions, 0 deletions
diff --git a/buildscripts/phing/classes/phing/Phing.php b/buildscripts/phing/classes/phing/Phing.php
new file mode 100644
index 00000000..bb8d67f6
--- /dev/null
+++ b/buildscripts/phing/classes/phing/Phing.php
@@ -0,0 +1,1161 @@
+<?php
+/*
+ * $Id: Phing.php,v 1.51 2006/01/06 15:12:33 hlellelid Exp $
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * 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/BuildEvent.php';
+
+include_once 'phing/parser/Location.php';
+include_once 'phing/parser/ExpatParser.php';
+include_once 'phing/parser/AbstractHandler.php';
+include_once 'phing/parser/ProjectConfigurator.php';
+include_once 'phing/parser/RootHandler.php';
+include_once 'phing/parser/ProjectHandler.php';
+include_once 'phing/parser/TaskHandler.php';
+include_once 'phing/parser/TargetHandler.php';
+include_once 'phing/parser/DataTypeHandler.php';
+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/FileReader.php';
+include_once 'phing/system/util/Register.php';
+
+/**
+ * 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.
+ *
+ * If you are invoking Phing from an external application, this is still
+ * the class to use. Your applicaiton can invoke the start() method, passing
+ * any commandline arguments or additional properties.
+ *
+ * @author Andreas Aderhold <andi@binarycloud.com>
+ * @author Hans Lellelid <hans@xmpl.org>
+ * @version $Revision: 1.51 $
+ * @package phing
+ */
+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;
+
+ /** PhingFile that we are using for configuration */
+ private $buildFile = null;
+
+ /** The build targets */
+ private $targets = array();
+
+ /**
+ * Set of properties that are passed in from commandline or invoking code.
+ * @var Properties
+ */
+ private static $definedProps;
+
+ /** Names of classes to add as listeners to project */
+ private $listeners = array();
+
+ private $loggerClassname = null;
+
+ /** 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();
+
+ /**
+ * Prints the message of the Exception if it's not null.
+ */
+ 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
+ }
+
+ /**
+ * 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 $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
+ * @see execute()
+ * @see runBuild()
+ */
+ public static function start(&$args, $additionalUserProperties = null) {
+
+ try {
+ $m = new Phing();
+ $m->execute($args);
+ } catch (Exception $exc) {
+ $m->printMessage($exc);
+ self::halt(-1); // Parameter error
+ }
+
+ if ($additionalUserProperties !== null) {
+ $keys = $m->additionalUserProperties->keys();
+ while(count($keys)) {
+ $key = array_shift($keys);
+ $property = $m->additionalUserProperties->getProperty($key);
+ $m->setDefinedProperty($key, $property);
+ }
+ }
+
+ try {
+ $m->runBuild();
+ } catch(Exception $exc) {
+ self::halt(1); // Errors occured
+ }
+
+ // everything fine, shutdown
+ self::halt(0); // no errors, everything is cake
+ }
+
+ /**
+ * Making output level a static property so that this property
+ * can be accessed by other parts of the system, enabling
+ * us to display more information -- e.g. backtraces -- for "debug" level.
+ * @return int
+ */
+ 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
+ * target or the default target.
+ *
+ * @param array $args Command line args.
+ * @return void
+ */
+ 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
+ $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 (!isset($args[$i+1])) {
+ print("You must specify a log file when using the -logfile argument\n");
+ return;
+ } else {
+ $logFile = new PhingFile($args[++$i]);
+ $this->loggerClassname = 'phing.listener.PearLogger';
+ $this->setDefinedProperty('pear.log.name', $logFile->getAbsolutePath());
+ }
+ } catch (IOException $ioe) {
+ print("Cannot write on the specified log file. Make sure the path exists and you have write permissions.\n");
+ throw $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;
+ } 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;
+ } else {
+ $this->listeners[] = $args[++$i];
+ }
+
+ } elseif (StringHelper::startsWith("-D", $arg)) {
+ $name = substr($arg, 2);
+ $value = null;
+ $posEq = strpos($name, "=");
+ if ($posEq !== false) {
+ $value = substr($name, $posEq+1);
+ $name = substr($name, 0, $posEq);
+ } elseif ($i < count($args)-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;
+ } else {
+ $this->loggerClassname = $args[++$i];
+ }
+ } elseif ($arg == "-inputhandler") {
+ if ($this->inputHandlerClassname !== null) {
+ throw new BuildException("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;
+ } else {
+ $this->inputHandlerClassname = $args[++$i];
+ }
+ } elseif ($arg == "-projecthelp" || $arg == "-targets" || $arg == "-list" || $arg == "-l") {
+ // set the flag to display the targets and quit
+ $this->projectHelp = true;
+ } elseif ($arg == "-find") {
+ // eat up next arg if present, default to build.xml
+ if ($i < count($args)-1) {
+ $this->searchForThis = $args[++$i];
+ } else {
+ $this->searchForThis = self::DEFAULT_BUILD_FILENAME;
+ }
+ } elseif (substr($arg,0,1) == "-") {
+ // we don't have any more args
+ print("Unknown argument: $arg\n");
+ $this->printUsage();
+ return;
+ } else {
+ // if it's no other arg, it may be the target
+ array_push($this->targets, $arg);
+ }
+ }
+
+ // if buildFile was not specified on the command line,
+ if ($this->buildFile === null) {
+ // but -find then search for it
+ if ($this->searchForThis !== null) {
+ $this->buildFile = $this->_findBuildFile(self::getProperty("user.dir"), $this->searchForThis);
+ } else {
+ $this->buildFile = new PhingFile(self::DEFAULT_BUILD_FILENAME);
+ }
+ }
+ // make sure buildfile exists
+ if (!$this->buildFile->exists()) {
+ throw new BuildException("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!");
+ }
+
+ $this->readyToRun = true;
+ }
+
+ /**
+ * Helper to get the parent file for a given file.
+ *
+ * @param PhingFile $file
+ * @return PhingFile Parent file or null if none
+ */
+ 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);
+ }
+
+ /**
+ * Search parent directories for the build file.
+ *
+ * Takes the given target as a suffix to append to each
+ * 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");
+ }
+ $startf = new PhingFile($start);
+ $parent = new PhingFile($startf->getAbsolutePath());
+ $file = new PhingFile($parent, $suffix);
+
+ // check if the target file exists in the current directory
+ while (!$file->exists()) {
+ // change to parent directory
+ $parent = $this->_getParentFile($parent);
+
+ // 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!");
+ }
+ // refresh our file handle
+ $file = new PhingFile($parent, $suffix);
+ }
+ return $file;
+ }
+
+ /**
+ * Executes the build.
+ * @return void
+ */
+ function runBuild() {
+
+ if (!$this->readyToRun) {
+ return;
+ }
+
+ $project = new Project();
+
+ 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());
+
+ try {
+ $project->fireBuildStarted();
+ $project->init();
+ } catch (Exception $exc) {
+ $project->fireBuildFinished($exc);
+ throw $exc;
+ }
+
+ $project->setUserProperty("phing.version", $this->getPhingVersion());
+
+ $e = self::$definedProps->keys();
+ while (count($e)) {
+ $arg = (string) array_shift($e);
+ $value = (string) self::$definedProps->getProperty($arg);
+ $project->setUserProperty($arg, $value);
+ }
+ unset($e);
+
+ $project->setUserProperty("phing.file", $this->buildFile->getAbsolutePath());
+
+ // 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();
+ throw $exc;
+ }
+
+ // make sure that we have a target to execute
+ if (count($this->targets) === 0) {
+ $this->targets[] = $project->getDefaultTarget();
+ }
+
+ // execute targets if help param was not given
+ if (!$this->projectHelp) {
+
+ try {
+ $project->executeTargets($this->targets);
+ } catch (Exception $exc) {
+ $project->fireBuildFinished($exc);
+ restore_error_handler();
+ self::unsetCurrentProject();
+ throw $exc;
+ }
+ }
+ // if help is requested print it
+ if ($this->projectHelp) {
+ try {
+ $this->printDescription($project);
+ $this->printTargets($project);
+ } catch (Exception $exc) {
+ $project->fireBuildFinished($exc);
+ restore_error_handler();
+ self::unsetCurrentProject();
+ throw $exc;
+ }
+ }
+
+ // finally {
+ if (!$this->projectHelp) {
+ $project->fireBuildFinished(null);
+ }
+
+ restore_error_handler();
+ self::unsetCurrentProject();
+ }
+
+ /**
+ * Bind any default build listeners to this project.
+ * Currently this means adding the logger.
+ * @param Project $project
+ * @return void
+ */
+ private function addBuildListeners(Project $project) {
+ // Add the default listener
+ $project->addBuildListener($this->createLogger());
+ }
+
+ /**
+ * Creates the InputHandler and adds it to the project.
+ *
+ * @param Project $project the project instance.
+ *
+ * @throws BuildException if a specified InputHandler
+ * class could not be loaded.
+ */
+ private function addInputHandler(Project $project) {
+ if ($this->inputHandlerClassname === null) {
+ $handler = new DefaultInputHandler();
+ } else {
+ try {
+ $clz = Phing::import($this->inputHandlerClassname);
+ $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);
+ }
+ }
+ $project->setInputHandler($handler);
+ }
+
+ /**
+ * Creates the default build logger for sending build events to the log.
+ * @return BuildListener The created Logger
+ */
+ private function createLogger() {
+ if ($this->loggerClassname !== null) {
+ self::import($this->loggerClassname);
+ // get class name part
+ $classname = self::import($this->loggerClassname);
+ $logger = new $classname;
+ } else {
+ require_once 'phing/listener/DefaultLogger.php';
+ $logger = new DefaultLogger();
+ }
+ $logger->setMessageOutputLevel(self::$msgOutputLevel);
+ 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) {
+
+ // 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 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;
+ }
+
+ /** Prints the usage of how to use this class */
+ function printUsage() {
+ $lSep = self::getProperty("line.separator");
+ $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);
+ }
+
+ function printVersion() {
+ print(self::getPhingVersion()."\n");
+ }
+
+ function getPhingVersion() {
+ $versionPath = self::getResourcePath("phing/etc/VERSION.TXT");
+ if ($versionPath === null) {
+ $versionPath = self::getResourcePath("etc/VERSION.TXT");
+ }
+ try { // try to read file
+ $buffer = null;
+ $file = new PhingFile($versionPath);
+ $reader = new FileReader($file);
+ $reader->readInto($buffer);
+ $buffer = trim($buffer);
+ //$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");
+ }
+ return $phingVersion;
+ }
+
+ /** Print the project description, if any */
+ function printDescription(Project $project) {
+ if ($project->getDescription() !== null) {
+ print($project->getDescription()."\n");
+ }
+ }
+
+ /** Print out a list of all targets in the current buildfile */
+ function printTargets($project) {
+ // find the target with the longest name
+ $maxLength = 0;
+ $targets = $project->getTargets();
+ $targetNames = array_keys($targets);
+ $targetName = null;
+ $targetDescription = null;
+ $currentTarget = null;
+
+ // split the targets in top-level and sub-targets depending
+ // on the presence of a description
+
+ $subNames = array();
+ $topNameDescMap = array();
+
+ foreach($targets as $currentTarget) {
+ $targetName = $currentTarget->getName();
+ $targetDescription = $currentTarget->getDescription();
+
+ // 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;
+ if (strlen($targetName) > $maxLength) {
+ $maxLength = strlen($targetName);
+ }
+ }
+ }
+
+ // Sort the arrays
+ 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);
+
+ $defaultTarget = $project->getDefaultTarget();
+
+ if ($defaultTarget !== null && $defaultTarget !== "") {
+ $defaultName = array();
+ $defaultDesc = array();
+ $defaultName[] = $defaultTarget;
+
+ $indexOfDefDesc = array_search($defaultTarget, $topNames, true);
+ if ($indexOfDefDesc !== false && $indexOfDefDesc >= 0) {
+ $defaultDesc = array();
+ $defaultDesc[] = $topDescriptions[$indexOfDefDesc];
+ }
+
+ $this->_printTargets($defaultName, $defaultDesc, "Default target:", $maxLength);
+
+ }
+ $this->_printTargets($topNames, $topDescriptions, "Main targets:", $maxLength);
+ $this->_printTargets($subNames, null, "Subtargets:", 0);
+ }
+
+ /**
+ * Writes a formatted list of target names with an optional description.
+ *
+ * @param array $names The names to be printed.
+ * Must not be <code>null</code>.
+ * @param array $descriptions The associated target descriptions.
+ * May be <code>null</code>, in which case
+ * no descriptions are displayed.
+ * If non-<code>null</code>, this should have
+ * as many elements as <code>names</code>.
+ * @param string $heading The heading to display.
+ * Should not be <code>null</code>.
+ * @param int $maxlen The maximum length of the names of the targets.
+ * If descriptions are given, they are padded to this
+ * position so they line up (so long as the names really
+ * <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;
+
+ $total = count($names);
+ for($i=0; $i < $total; $i++) {
+ $msg .= " ";
+ $msg .= $names[$i];
+ if (!empty($descriptions)) {
+ $msg .= substr($spaces, 0, $maxlen - strlen($names[$i]) + 2);
+ $msg .= $descriptions[$i];
+ }
+ $msg .= $lSep;
+ }
+ 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) {
+
+ // 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)) {
+ return $classname;
+ }
+
+ $dotClassname = basename($dotPath);
+ $dotClassnamePos = strlen($dotPath) - strlen($dotClassname);
+ $classFile = strtr($dotClassname, '.', DIRECTORY_SEPARATOR) . ".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) {
+
+ 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.
+ //
+ // 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
+ // include/require class files from within method calls. This means that not all
+ // necessary files will be included in this import() call, and hence we can't
+ // change the include_path back without breaking those apps. While this method could
+ // 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'));
+ $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)));
+ }
+ }
+
+ $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;
+ }
+
+ return;
+ }
+
+ /**
+ * 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");
+ 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;
+ }
+ }
+
+ // 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;
+ }
+ }
+
+ // 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;
+ }
+ }
+
+ return null;
+ }
+
+ // -------------------------------------------------------------------------------------------
+ // 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
+ */
+ private static function setSystemConstants() {
+
+ /*
+ * PHP_OS returns on
+ * WindowsNT4.0sp6 => WINNT
+ * Windows2000 => WINNT
+ * Windows ME => WIN32
+ * Windows 98SE => WIN32
+ * FreeBSD 4.5p7 => FreeBSD
+ * Redhat Linux => Linux
+ * Mac OS X => Darwin
+ */
+ self::setProperty('host.os', PHP_OS);
+
+ // 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
+ // used by Fileself::getFileSystem to instantiate the correct
+ // abstraction layer
+
+ switch (strtoupper(PHP_OS)) {
+ case 'WINNT':
+ self::setProperty('host.fstype', 'WINNT');
+ break;
+ case 'WIN32':
+ self::setProperty('host.fstype', 'WIN32');
+ break;
+ default:
+ self::setProperty('host.fstype', 'UNIX');
+ break;
+ }
+
+ self::setProperty('php.version', PHP_VERSION);
+ self::setProperty('user.home', getenv('HOME'));
+ self::setProperty('application.startdir', getcwd());
+ self::setProperty('line.separator', "\n");
+
+ // try to detect machine dependent information
+ $sysInfo = array();
+ if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN' && function_exists("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');
+ }
+
+
+ self::setProperty("host.name", isset($sysInfo['nodename']) ? $sysInfo['nodename'] : "unknown");
+ self::setProperty("host.arch", isset($sysInfo['machine']) ? $sysInfo['machine'] : "unknown");
+ self::setProperty("host.domain",isset($sysInfo['domain']) ? $sysInfo['domain'] : "unknown");
+ self::setProperty("host.os.release", isset($sysInfo['release']) ? $sysInfo['release'] : "unknown");
+ 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
+ * 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,
+ * 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
+ switch($propName) {
+ case 'user.dir':
+ $val = getcwd();
+ break;
+ }
+
+ return $val;
+ }
+
+ /** Retuns reference to all properties*/
+ public static function &getProperties() {
+ return self::$properties;
+ }
+
+ 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).
+ * @return void
+ */
+ 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;
+ }
+
+ if ($success === false) {
+ print("SYSTEM FAILURE: Could not set PHP include path\n");
+ self::halt(-1);
+ }
+ }
+
+ /**
+ * Sets PHP INI values that Phing needs.
+ * @return void
+ */
+ private static function setIni() {
+ error_reporting(E_ALL);
+ 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) {
+ ini_set('memory_limit', '32M'); // nore: this may need to be higher for many projects
+ }
+ }
+
+ /**
+ * Returns reference to Timer object.
+ * @return Timer
+ */
+ public static function getTimer() {
+ if (self::$timer === null) {
+ include_once 'phing/system/util/Timer.php';
+ self::$timer= new Timer();
+ }
+ return self::$timer;
+ }
+
+ /**
+ * Start up Phing.
+ * Sets up the Phing environment -- does NOT initiate the build process.
+ * @return void
+ */
+ public static function startup() {
+
+ register_shutdown_function(array('Phing', 'shutdown'));
+
+ // some init stuff
+ self::getTimer()->start();
+
+ self::setSystemConstants();
+ self::setIncludePaths();
+ self::setIni();
+ }
+
+ /**
+ * Halts the system.
+ * @see shutdown()
+ */
+ public static function halt($code=0) {
+ self::shutdown($code);
+ }
+
+ /**
+ * Stops timers & exits.
+ * @return void
+ */
+ public static function shutdown($exitcode = 0) {
+ //print("[AUTOMATIC SYSTEM SHUTDOWN]\n");
+ self::getTimer()->stop();
+ exit($exitcode); // final point where everything stops
+ }
+
+}