[ Index ] |
|
Code source de Symfony 1.0.0 |
1 <?php 2 /* 3 * $Id: Phing.php 3076 2006-12-18 08:52:12Z fabien $ 4 * 5 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 6 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 7 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 8 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 9 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 10 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 11 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 12 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 13 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 14 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 15 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 16 * 17 * This software consists of voluntary contributions made by many individuals 18 * and is licensed under the LGPL. For more information please see 19 * <http://phing.info>. 20 */ 21 22 require_once 'phing/Project.php'; 23 require_once 'phing/ProjectComponent.php'; 24 require_once 'phing/Target.php'; 25 require_once 'phing/Task.php'; 26 27 include_once 'phing/BuildException.php'; 28 include_once 'phing/BuildEvent.php'; 29 30 include_once 'phing/parser/Location.php'; 31 include_once 'phing/parser/ExpatParser.php'; 32 include_once 'phing/parser/AbstractHandler.php'; 33 include_once 'phing/parser/ProjectConfigurator.php'; 34 include_once 'phing/parser/RootHandler.php'; 35 include_once 'phing/parser/ProjectHandler.php'; 36 include_once 'phing/parser/TaskHandler.php'; 37 include_once 'phing/parser/TargetHandler.php'; 38 include_once 'phing/parser/DataTypeHandler.php'; 39 include_once 'phing/parser/NestedElementHandler.php'; 40 41 include_once 'phing/system/util/Properties.php'; 42 include_once 'phing/util/StringHelper.php'; 43 include_once 'phing/system/io/PhingFile.php'; 44 include_once 'phing/system/io/FileReader.php'; 45 include_once 'phing/system/util/Register.php'; 46 47 /** 48 * Entry point into Phing. This class handles the full lifecycle of a build -- from 49 * parsing & handling commandline arguments to assembling the project to shutting down 50 * and cleaning up in the end. 51 * 52 * If you are invoking Phing from an external application, this is still 53 * the class to use. Your applicaiton can invoke the start() method, passing 54 * any commandline arguments or additional properties. 55 * 56 * @author Andreas Aderhold <andi@binarycloud.com> 57 * @author Hans Lellelid <hans@xmpl.org> 58 * @version $Revision: 1.51 $ 59 * @package phing 60 */ 61 class Phing { 62 63 /** The default build file name */ 64 const DEFAULT_BUILD_FILENAME = "build.xml"; 65 66 /** Our current message output status. Follows PROJECT_MSG_XXX */ 67 private static $msgOutputLevel = PROJECT_MSG_INFO; 68 69 /** PhingFile that we are using for configuration */ 70 private $buildFile = null; 71 72 /** The build targets */ 73 private $targets = array(); 74 75 /** 76 * Set of properties that are passed in from commandline or invoking code. 77 * @var Properties 78 */ 79 private static $definedProps; 80 81 /** Names of classes to add as listeners to project */ 82 private $listeners = array(); 83 84 private $loggerClassname = null; 85 86 /** The class to handle input (can be only one). */ 87 private $inputHandlerClassname; 88 89 /** Indicates if this phing should be run */ 90 private $readyToRun = false; 91 92 /** Indicates we should only parse and display the project help information */ 93 private $projectHelp = false; 94 95 /** Used by utility function getResourcePath() */ 96 private static $importPaths; 97 98 /** System-wide static properties (moved from System) */ 99 private static $properties = array(); 100 101 /** Static system timer. */ 102 private static $timer; 103 104 /** The current Project */ 105 private static $currentProject; 106 107 /** Whether to capture PHP errors to buffer. */ 108 private static $phpErrorCapture = false; 109 110 /** Array of captured PHP errors */ 111 private static $capturedPhpErrors = array(); 112 113 /** 114 * Prints the message of the Exception if it's not null. 115 */ 116 function printMessage(Exception $t) { 117 print($t->getMessage() . "\n"); 118 if (self::getMsgOutputLevel() === PROJECT_MSG_DEBUG) { 119 print($t->getTraceAsString()."\n"); 120 if ($t instanceof Exception) { 121 $c = $t->getCause(); 122 if ($c !== null) { 123 print("Wrapped exception trace:\n"); 124 print($c->getTraceAsString() . "\n"); 125 } 126 } 127 } // if output level is DEBUG 128 } 129 130 /** 131 * Entry point allowing for more options from other front ends. 132 * 133 * This method encapsulates the complete build lifecycle. 134 * 135 * @param array &$args The commandline args passed to phing shell script. 136 * @param array $additionalUserProperties Any additional properties to be passed to Phing (alternative front-end might implement this). 137 * These additional properties will be available using the getDefinedProperty() method and will 138 * be added to the project's "user" properties. 139 * @return void 140 * @see execute() 141 * @see runBuild() 142 */ 143 public static function start(&$args, $additionalUserProperties = null) { 144 145 try { 146 $m = new Phing(); 147 $m->execute($args); 148 } catch (Exception $exc) { 149 $m->printMessage($exc); 150 self::halt(-1); // Parameter error 151 } 152 153 if ($additionalUserProperties !== null) { 154 $keys = $m->additionalUserProperties->keys(); 155 while(count($keys)) { 156 $key = array_shift($keys); 157 $property = $m->additionalUserProperties->getProperty($key); 158 $m->setDefinedProperty($key, $property); 159 } 160 } 161 162 try { 163 $m->runBuild(); 164 } catch(Exception $exc) { 165 self::halt(1); // Errors occured 166 } 167 168 // everything fine, shutdown 169 self::halt(0); // no errors, everything is cake 170 } 171 172 /** 173 * Making output level a static property so that this property 174 * can be accessed by other parts of the system, enabling 175 * us to display more information -- e.g. backtraces -- for "debug" level. 176 * @return int 177 */ 178 public static function getMsgOutputLevel() { 179 return self::$msgOutputLevel; 180 } 181 182 /** 183 * Command line entry point. This method kicks off the building 184 * of a project object and executes a build using either a given 185 * target or the default target. 186 * 187 * @param array $args Command line args. 188 * @return void 189 */ 190 public static function fire($args) { 191 self::start($args, null); 192 } 193 194 /** 195 * Setup/initialize Phing environment from commandline args. 196 * @param array $args commandline args passed to phing shell. 197 * @return void 198 */ 199 public function execute($args) { 200 201 self::$definedProps = new Properties(); 202 $this->searchForThis = null; 203 204 // cycle through given args 205 for ($i = 0, $argcount = count($args); $i < $argcount; ++$i) { 206 // ++$i intentional here, as first param is script name 207 $arg = $args[$i]; 208 209 if ($arg == "-help" || $arg == "-h") { 210 $this->printUsage(); 211 return; 212 } elseif ($arg == "-version" || $arg == "-v") { 213 $this->printVersion(); 214 return; 215 } elseif ($arg == "-quiet" || $arg == "-q") { 216 self::$msgOutputLevel = PROJECT_MSG_WARN; 217 } elseif ($arg == "-verbose") { 218 $this->printVersion(); 219 self::$msgOutputLevel = PROJECT_MSG_VERBOSE; 220 } elseif ($arg == "-debug") { 221 $this->printVersion(); 222 self::$msgOutputLevel = PROJECT_MSG_DEBUG; 223 } elseif ($arg == "-logfile") { 224 try { // try to set logfile 225 if (!isset($args[$i+1])) { 226 print("You must specify a log file when using the -logfile argument\n"); 227 return; 228 } else { 229 $logFile = new PhingFile($args[++$i]); 230 $this->loggerClassname = 'phing.listener.PearLogger'; 231 $this->setDefinedProperty('pear.log.name', $logFile->getAbsolutePath()); 232 } 233 } catch (IOException $ioe) { 234 print("Cannot write on the specified log file. Make sure the path exists and you have write permissions.\n"); 235 throw $ioe; 236 } 237 } elseif ($arg == "-buildfile" || $arg == "-file" || $arg == "-f") { 238 if (!isset($args[$i+1])) { 239 print("You must specify a buildfile when using the -buildfile argument\n"); 240 return; 241 } else { 242 $this->buildFile = new PhingFile($args[++$i]); 243 } 244 } elseif ($arg == "-listener") { 245 if (!isset($args[$i+1])) { 246 print("You must specify a listener class when using the -listener argument\n"); 247 return; 248 } else { 249 $this->listeners[] = $args[++$i]; 250 } 251 252 } elseif (StringHelper::startsWith("-D", $arg)) { 253 $name = substr($arg, 2); 254 $value = null; 255 $posEq = strpos($name, "="); 256 if ($posEq !== false) { 257 $value = substr($name, $posEq+1); 258 $name = substr($name, 0, $posEq); 259 } elseif ($i < count($args)-1) { 260 $value = $args[++$i]; 261 } 262 self::$definedProps->setProperty($name, $value); 263 } elseif ($arg == "-logger") { 264 if (!isset($args[$i+1])) { 265 print("You must specify a classname when using the -logger argument\n"); 266 return; 267 } else { 268 $this->loggerClassname = $args[++$i]; 269 } 270 } elseif ($arg == "-inputhandler") { 271 if ($this->inputHandlerClassname !== null) { 272 throw new BuildException("Only one input handler class may be specified."); 273 } 274 if (!isset($args[$i+1])) { 275 print("You must specify a classname when using the -inputhandler argument\n"); 276 return; 277 } else { 278 $this->inputHandlerClassname = $args[++$i]; 279 } 280 } elseif ($arg == "-projecthelp" || $arg == "-targets" || $arg == "-list" || $arg == "-l") { 281 // set the flag to display the targets and quit 282 $this->projectHelp = true; 283 } elseif ($arg == "-find") { 284 // eat up next arg if present, default to build.xml 285 if ($i < count($args)-1) { 286 $this->searchForThis = $args[++$i]; 287 } else { 288 $this->searchForThis = self::DEFAULT_BUILD_FILENAME; 289 } 290 } elseif (substr($arg,0,1) == "-") { 291 // we don't have any more args 292 print("Unknown argument: $arg\n"); 293 $this->printUsage(); 294 return; 295 } else { 296 // if it's no other arg, it may be the target 297 array_push($this->targets, $arg); 298 } 299 } 300 301 // if buildFile was not specified on the command line, 302 if ($this->buildFile === null) { 303 // but -find then search for it 304 if ($this->searchForThis !== null) { 305 $this->buildFile = $this->_findBuildFile(self::getProperty("user.dir"), $this->searchForThis); 306 } else { 307 $this->buildFile = new PhingFile(self::DEFAULT_BUILD_FILENAME); 308 } 309 } 310 // make sure buildfile exists 311 if (!$this->buildFile->exists()) { 312 throw new BuildException("Buildfile: " . $this->buildFile->__toString() . " does not exist!"); 313 } 314 315 // make sure it's not a directory 316 if ($this->buildFile->isDirectory()) { 317 throw new BuildException("Buildfile: " . $this->buildFile->__toString() . " is a dir!"); 318 } 319 320 $this->readyToRun = true; 321 } 322 323 /** 324 * Helper to get the parent file for a given file. 325 * 326 * @param PhingFile $file 327 * @return PhingFile Parent file or null if none 328 */ 329 function _getParentFile(PhingFile $file) { 330 $filename = $file->getAbsolutePath(); 331 $file = new PhingFile($filename); 332 $filename = $file->getParent(); 333 334 if ($filename !== null && self::$msgOutputLevel >= PROJECT_MSG_VERBOSE) { 335 print("Searching in $filename\n"); 336 } 337 338 return ($filename === null) ? null : new PhingFile($filename); 339 } 340 341 /** 342 * Search parent directories for the build file. 343 * 344 * Takes the given target as a suffix to append to each 345 * parent directory in search of a build file. Once the 346 * root of the file-system has been reached an exception 347 * is thrown. 348 * 349 * @param string $start Start file path. 350 * @param string $suffix Suffix filename to look for in parents. 351 * @return PhingFile A handle to the build file 352 * 353 * @throws BuildException Failed to locate a build file 354 */ 355 function _findBuildFile($start, $suffix) { 356 if (self::$msgOutputLevel >= PROJECT_MSG_INFO) { 357 print("Searching for $suffix ...\n"); 358 } 359 $startf = new PhingFile($start); 360 $parent = new PhingFile($startf->getAbsolutePath()); 361 $file = new PhingFile($parent, $suffix); 362 363 // check if the target file exists in the current directory 364 while (!$file->exists()) { 365 // change to parent directory 366 $parent = $this->_getParentFile($parent); 367 368 // if parent is null, then we are at the root of the fs, 369 // complain that we can't find the build file. 370 if ($parent === null) { 371 throw new BuildException("Could not locate a build file!"); 372 } 373 // refresh our file handle 374 $file = new PhingFile($parent, $suffix); 375 } 376 return $file; 377 } 378 379 /** 380 * Executes the build. 381 * @return void 382 */ 383 function runBuild() { 384 385 if (!$this->readyToRun) { 386 return; 387 } 388 389 $project = new Project(); 390 391 self::setCurrentProject($project); 392 set_error_handler(array('Phing', 'handlePhpError')); 393 394 $error = null; 395 396 $this->addBuildListeners($project); 397 $this->addInputHandler($project); 398 399 // set this right away, so that it can be used in logging. 400 $project->setUserProperty("phing.file", $this->buildFile->getAbsolutePath()); 401 402 try { 403 $project->fireBuildStarted(); 404 $project->init(); 405 } catch (Exception $exc) { 406 $project->fireBuildFinished($exc); 407 throw $exc; 408 } 409 410 $project->setUserProperty("phing.version", $this->getPhingVersion()); 411 412 $e = self::$definedProps->keys(); 413 while (count($e)) { 414 $arg = (string) array_shift($e); 415 $value = (string) self::$definedProps->getProperty($arg); 416 $project->setUserProperty($arg, $value); 417 } 418 unset($e); 419 420 $project->setUserProperty("phing.file", $this->buildFile->getAbsolutePath()); 421 422 // first use the Configurator to create the project object 423 // from the given build file. 424 425 try { 426 ProjectConfigurator::configureProject($project, $this->buildFile); 427 } catch (Exception $exc) { 428 $project->fireBuildFinished($exc); 429 restore_error_handler(); 430 self::unsetCurrentProject(); 431 throw $exc; 432 } 433 434 // make sure that we have a target to execute 435 if (count($this->targets) === 0) { 436 $this->targets[] = $project->getDefaultTarget(); 437 } 438 439 // execute targets if help param was not given 440 if (!$this->projectHelp) { 441 442 try { 443 $project->executeTargets($this->targets); 444 } catch (Exception $exc) { 445 $project->fireBuildFinished($exc); 446 restore_error_handler(); 447 self::unsetCurrentProject(); 448 throw $exc; 449 } 450 } 451 // if help is requested print it 452 if ($this->projectHelp) { 453 try { 454 $this->printDescription($project); 455 $this->printTargets($project); 456 } catch (Exception $exc) { 457 $project->fireBuildFinished($exc); 458 restore_error_handler(); 459 self::unsetCurrentProject(); 460 throw $exc; 461 } 462 } 463 464 // finally { 465 if (!$this->projectHelp) { 466 $project->fireBuildFinished(null); 467 } 468 469 restore_error_handler(); 470 self::unsetCurrentProject(); 471 } 472 473 /** 474 * Bind any default build listeners to this project. 475 * Currently this means adding the logger. 476 * @param Project $project 477 * @return void 478 */ 479 private function addBuildListeners(Project $project) { 480 // Add the default listener 481 $project->addBuildListener($this->createLogger()); 482 } 483 484 /** 485 * Creates the InputHandler and adds it to the project. 486 * 487 * @param Project $project the project instance. 488 * 489 * @throws BuildException if a specified InputHandler 490 * class could not be loaded. 491 */ 492 private function addInputHandler(Project $project) { 493 if ($this->inputHandlerClassname === null) { 494 $handler = new DefaultInputHandler(); 495 } else { 496 try { 497 $clz = Phing::import($this->inputHandlerClassname); 498 $handler = new $clz(); 499 if ($project !== null && method_exists($handler, 'setProject')) { 500 $handler->setProject($project); 501 } 502 } catch (Exception $e) { 503 $msg = "Unable to instantiate specified input handler " 504 . "class " . $this->inputHandlerClassname . " : " 505 . $e->getMessage(); 506 throw new BuildException($msg); 507 } 508 } 509 $project->setInputHandler($handler); 510 } 511 512 /** 513 * Creates the default build logger for sending build events to the log. 514 * @return BuildListener The created Logger 515 */ 516 private function createLogger() { 517 if ($this->loggerClassname !== null) { 518 self::import($this->loggerClassname); 519 // get class name part 520 $classname = self::import($this->loggerClassname); 521 $logger = new $classname; 522 } else { 523 require_once 'phing/listener/DefaultLogger.php'; 524 $logger = new DefaultLogger(); 525 } 526 $logger->setMessageOutputLevel(self::$msgOutputLevel); 527 return $logger; 528 } 529 530 /** 531 * Sets the current Project 532 * @param Project $p 533 */ 534 public static function setCurrentProject($p) { 535 self::$currentProject = $p; 536 } 537 538 /** 539 * Unsets the current Project 540 */ 541 public static function unsetCurrentProject() { 542 self::$currentProject = null; 543 } 544 545 /** 546 * Gets the current Project. 547 * @return Project Current Project or NULL if none is set yet/still. 548 */ 549 public static function getCurrentProject() { 550 return self::$currentProject; 551 } 552 553 /** 554 * A static convenience method to send a log to the current (last-setup) Project. 555 * If there is no currently-configured Project, then this will do nothing. 556 * @param string $message 557 * @param int $priority PROJECT_MSG_INFO, etc. 558 */ 559 public static function log($message, $priority = PROJECT_MSG_INFO) { 560 $p = self::getCurrentProject(); 561 if ($p) { 562 $p->log($message, $priority); 563 } 564 } 565 566 /** 567 * Error handler for PHP errors encountered during the build. 568 * This uses the logging for the currently configured project. 569 */ 570 public static function handlePhpError($level, $message, $file, $line) { 571 572 // don't want to print supressed errors 573 if (error_reporting() > 0) { 574 575 if (self::$phpErrorCapture) { 576 577 self::$capturedPhpErrors[] = array('message' => $message, 'level' => $level, 'line' => $line, 'file' => $file); 578 579 } else { 580 581 $message = '[PHP Error] ' . $message; 582 $message .= ' [line ' . $line . ' of ' . $file . ']'; 583 584 switch ($level) { 585 586 case E_STRICT: 587 case E_NOTICE: 588 case E_USER_NOTICE: 589 self::log($message, PROJECT_MSG_VERBOSE); 590 break; 591 case E_WARNING: 592 case E_USER_WARNING: 593 self::log($message, PROJECT_MSG_WARN); 594 break; 595 case E_ERROR: 596 case E_USER_ERROR: 597 default: 598 self::log($message, PROJECT_MSG_ERR); 599 600 } // switch 601 602 } // if phpErrorCapture 603 604 } // if not @ 605 606 } 607 608 /** 609 * Begins capturing PHP errors to a buffer. 610 * While errors are being captured, they are not logged. 611 */ 612 public static function startPhpErrorCapture() { 613 self::$phpErrorCapture = true; 614 self::$capturedPhpErrors = array(); 615 } 616 617 /** 618 * Stops capturing PHP errors to a buffer. 619 * The errors will once again be logged after calling this method. 620 */ 621 public static function stopPhpErrorCapture() { 622 self::$phpErrorCapture = false; 623 } 624 625 /** 626 * Clears the captured errors without affecting the starting/stopping of the capture. 627 */ 628 public static function clearCapturedPhpErrors() { 629 self::$capturedPhpErrors = array(); 630 } 631 632 /** 633 * Gets any PHP errors that were captured to buffer. 634 * @return array array('message' => message, 'line' => line number, 'file' => file name, 'level' => error level) 635 */ 636 public static function getCapturedPhpErrors() { 637 return self::$capturedPhpErrors; 638 } 639 640 /** Prints the usage of how to use this class */ 641 function printUsage() { 642 $lSep = self::getProperty("line.separator"); 643 $msg = ""; 644 $msg .= "phing [options] [target [target2 [target3] ...]]" . $lSep; 645 $msg .= "Options: " . $lSep; 646 $msg .= " -h -help print this message" . $lSep; 647 $msg .= " -l -list list available targets in this project" . $lSep; 648 $msg .= " -v -version print the version information and exit" . $lSep; 649 $msg .= " -q -quiet be extra quiet" . $lSep; 650 $msg .= " -verbose be extra verbose" . $lSep; 651 $msg .= " -debug print debugging information" . $lSep; 652 $msg .= " -logfile <file> use given file for log" . $lSep; 653 $msg .= " -logger <classname> the class which is to perform logging" . $lSep; 654 $msg .= " -f -buildfile <file> use given buildfile" . $lSep; 655 $msg .= " -D<property>=<value> use value for given property" . $lSep; 656 $msg .= " -find <file> search for buildfile towards the root of the" . $lSep; 657 $msg .= " filesystem and use it" . $lSep; 658 //$msg .= " -recursive <file> search for buildfile downwards and use it" . $lSep; 659 $msg .= $lSep; 660 $msg .= "Report bugs to <dev@phing.tigris.org>".$lSep; 661 print($msg); 662 } 663 664 function printVersion() { 665 print(self::getPhingVersion()."\n"); 666 } 667 668 function getPhingVersion() { 669 $versionPath = self::getResourcePath("phing/etc/VERSION.TXT"); 670 if ($versionPath === null) { 671 $versionPath = self::getResourcePath("etc/VERSION.TXT"); 672 } 673 try { // try to read file 674 $buffer = null; 675 $file = new PhingFile($versionPath); 676 $reader = new FileReader($file); 677 $reader->readInto($buffer); 678 $buffer = trim($buffer); 679 //$buffer = "PHING version 1.0, Released 2002-??-??"; 680 $phingVersion = $buffer; 681 } catch (IOException $iox) { 682 print("Can't read version information file\n"); 683 throw new BuildException("Build failed"); 684 } 685 return $phingVersion; 686 } 687 688 /** Print the project description, if any */ 689 function printDescription(Project $project) { 690 if ($project->getDescription() !== null) { 691 print($project->getDescription()."\n"); 692 } 693 } 694 695 /** Print out a list of all targets in the current buildfile */ 696 function printTargets($project) { 697 // find the target with the longest name 698 $maxLength = 0; 699 $targets = $project->getTargets(); 700 $targetNames = array_keys($targets); 701 $targetName = null; 702 $targetDescription = null; 703 $currentTarget = null; 704 705 // split the targets in top-level and sub-targets depending 706 // on the presence of a description 707 708 $subNames = array(); 709 $topNameDescMap = array(); 710 711 foreach($targets as $currentTarget) { 712 $targetName = $currentTarget->getName(); 713 $targetDescription = $currentTarget->getDescription(); 714 715 // subtargets are targets w/o descriptions 716 if ($targetDescription === null) { 717 $subNames[] = $targetName; 718 } else { 719 // topNames and topDescriptions are handled later 720 // here we store in hash map (for sorting purposes) 721 $topNameDescMap[$targetName] = $targetDescription; 722 if (strlen($targetName) > $maxLength) { 723 $maxLength = strlen($targetName); 724 } 725 } 726 } 727 728 // Sort the arrays 729 sort($subNames); // sort array values, resetting keys (which are numeric) 730 ksort($topNameDescMap); // sort the keys (targetName) keeping key=>val associations 731 732 $topNames = array_keys($topNameDescMap); 733 $topDescriptions = array_values($topNameDescMap); 734 735 $defaultTarget = $project->getDefaultTarget(); 736 737 if ($defaultTarget !== null && $defaultTarget !== "") { 738 $defaultName = array(); 739 $defaultDesc = array(); 740 $defaultName[] = $defaultTarget; 741 742 $indexOfDefDesc = array_search($defaultTarget, $topNames, true); 743 if ($indexOfDefDesc !== false && $indexOfDefDesc >= 0) { 744 $defaultDesc = array(); 745 $defaultDesc[] = $topDescriptions[$indexOfDefDesc]; 746 } 747 748 $this->_printTargets($defaultName, $defaultDesc, "Default target:", $maxLength); 749 750 } 751 $this->_printTargets($topNames, $topDescriptions, "Main targets:", $maxLength); 752 $this->_printTargets($subNames, null, "Subtargets:", 0); 753 } 754 755 /** 756 * Writes a formatted list of target names with an optional description. 757 * 758 * @param array $names The names to be printed. 759 * Must not be <code>null</code>. 760 * @param array $descriptions The associated target descriptions. 761 * May be <code>null</code>, in which case 762 * no descriptions are displayed. 763 * If non-<code>null</code>, this should have 764 * as many elements as <code>names</code>. 765 * @param string $heading The heading to display. 766 * Should not be <code>null</code>. 767 * @param int $maxlen The maximum length of the names of the targets. 768 * If descriptions are given, they are padded to this 769 * position so they line up (so long as the names really 770 * <i>are</i> shorter than this). 771 */ 772 private function _printTargets($names, $descriptions, $heading, $maxlen) { 773 $lSep = self::getProperty("line.separator"); 774 $spaces = ' '; 775 while (strlen($spaces) < $maxlen) { 776 $spaces .= $spaces; 777 } 778 $msg = ""; 779 $msg .= $heading . $lSep; 780 $msg .= str_repeat("-",79) . $lSep; 781 782 $total = count($names); 783 for($i=0; $i < $total; $i++) { 784 $msg .= " "; 785 $msg .= $names[$i]; 786 if (!empty($descriptions)) { 787 $msg .= substr($spaces, 0, $maxlen - strlen($names[$i]) + 2); 788 $msg .= $descriptions[$i]; 789 } 790 $msg .= $lSep; 791 } 792 if ($total > 0) { 793 print $msg . $lSep; 794 } 795 } 796 797 /** 798 * Import a dot-path notation class path. 799 * @param string $dotPath 800 * @param mixed $classpath String or object supporting __toString() 801 * @return string The unqualified classname (which can be instantiated). 802 * @throws BuildException - if cannot find the specified file 803 */ 804 public static function import($dotPath, $classpath = null) { 805 806 // first check to see that the class specified hasn't already been included. 807 // (this also handles case where this method is called w/ a classname rather than dotpath) 808 $classname = StringHelper::unqualify($dotPath); 809 if (class_exists($classname, false)) { 810 return $classname; 811 } 812 813 $dotClassname = basename($dotPath); 814 $dotClassnamePos = strlen($dotPath) - strlen($dotClassname); 815 $classFile = strtr($dotClassname, '.', DIRECTORY_SEPARATOR) . ".php"; 816 $path = substr_replace($dotPath, $classFile, $dotClassnamePos); 817 818 Phing::__import($path, $classpath); 819 820 return $classname; 821 } 822 823 /** 824 * Import a PHP file 825 * @param string $path Path to the PHP file 826 * @param mixed $classpath String or object supporting __toString() 827 * @throws BuildException - if cannot find the specified file 828 */ 829 public static function __import($path, $classpath = null) { 830 831 if ($classpath) { 832 833 // Apparently casting to (string) no longer invokes __toString() automatically. 834 if (is_object($classpath)) { 835 $classpath = $classpath->__toString(); 836 } 837 838 // classpaths are currently additive, but we also don't want to just 839 // indiscriminantly prepand/append stuff to the include_path. This means 840 // we need to parse current incldue_path, and prepend any 841 // specified classpath locations that are not already in the include_path. 842 // 843 // NOTE: the reason why we do it this way instead of just changing include_path 844 // and then changing it back, is that in many cases applications (e.g. Propel) will 845 // include/require class files from within method calls. This means that not all 846 // necessary files will be included in this import() call, and hence we can't 847 // change the include_path back without breaking those apps. While this method could 848 // be more expensive than switching & switching back (not sure, but maybe), it makes it 849 // possible to write far less expensive run-time applications (e.g. using Propel), which is 850 // really where speed matters more. 851 852 $curr_parts = explode(PATH_SEPARATOR, ini_get('include_path')); 853 $add_parts = explode(PATH_SEPARATOR, $classpath); 854 $new_parts = array_diff($add_parts, $curr_parts); 855 if ($new_parts) { 856 if (self::getMsgOutputLevel() === PROJECT_MSG_DEBUG) { 857 print("Phing::import() prepending new include_path components: " . implode(PATH_SEPARATOR, $new_parts) . "\n"); 858 } 859 ini_set('include_path', implode(PATH_SEPARATOR, array_merge($new_parts, $curr_parts))); 860 } 861 } 862 863 $ret = include_once($path); 864 865 if ($ret === false) { 866 $e = new BuildException("Error importing $path"); 867 if (self::getMsgOutputLevel() === PROJECT_MSG_DEBUG) { 868 // We can't log this because listeners belong 869 // to projects. We'll just print it -- of course 870 // that isn't very compatible w/ other frontends (but 871 // there aren't any right now, so I'm not stressing) 872 print("Error importing $path\n"); 873 print($e->getTraceAsString()."\n"); 874 } 875 throw $e; 876 } 877 878 return; 879 } 880 881 /** 882 * Looks on include path for specified file. 883 * @return string File found (null if no file found). 884 */ 885 public static function getResourcePath($path) { 886 887 if (self::$importPaths === null) { 888 $paths = ini_get("include_path"); 889 self::$importPaths = explode(PATH_SEPARATOR, ini_get("include_path")); 890 } 891 892 $path = str_replace('\\', DIRECTORY_SEPARATOR, $path); 893 $path = str_replace('/', DIRECTORY_SEPARATOR, $path); 894 895 foreach (self::$importPaths as $prefix) { 896 $foo_path = $prefix . DIRECTORY_SEPARATOR . $path; 897 if (file_exists($foo_path)) { 898 return $foo_path; 899 } 900 } 901 902 // Check for the property phing.home 903 $home_dir = self::getProperty('phing.home'); 904 905 if ($home_dir) 906 { 907 $home_path = $home_dir . DIRECTORY_SEPARATOR . $path; 908 909 if (file_exists($home_path)) 910 { 911 return $home_path; 912 } 913 } 914 915 // If we are using this via PEAR then check for the file in the data dir 916 // This is a bit of a hack, but works better than previous solution of assuming 917 // data_dir is on the include_path. 918 $data_dir = '@DATA-DIR@'; 919 if ($data_dir{0} != '@') { // if we're using PEAR then the @ DATA-DIR @ token will have been substituted. 920 $data_path = $data_dir . DIRECTORY_SEPARATOR . $path; 921 if (file_exists($data_path)) { 922 return $data_path; 923 } 924 } 925 926 return null; 927 } 928 929 // ------------------------------------------------------------------------------------------- 930 // System-wide methods (moved from System class, which had namespace conflicts w/ PEAR System) 931 // ------------------------------------------------------------------------------------------- 932 933 /** 934 * Set System constants which can be retrieved by calling Phing::getProperty($propName). 935 * @return void 936 */ 937 private static function setSystemConstants() { 938 939 /* 940 * PHP_OS returns on 941 * WindowsNT4.0sp6 => WINNT 942 * Windows2000 => WINNT 943 * Windows ME => WIN32 944 * Windows 98SE => WIN32 945 * FreeBSD 4.5p7 => FreeBSD 946 * Redhat Linux => Linux 947 * Mac OS X => Darwin 948 */ 949 self::setProperty('host.os', PHP_OS); 950 951 // this is used by some tasks too 952 self::setProperty('os.name', PHP_OS); 953 954 // it's still possible this won't be defined, 955 // e.g. if Phing is being included in another app w/o 956 // using the phing.php script. 957 if (!defined('PHP_CLASSPATH')) { 958 define('PHP_CLASSPATH', get_include_path()); 959 } 960 961 self::setProperty('php.classpath', PHP_CLASSPATH); 962 963 // try to determine the host filesystem and set system property 964 // used by Fileself::getFileSystem to instantiate the correct 965 // abstraction layer 966 967 switch (strtoupper(PHP_OS)) { 968 case 'WINNT': 969 self::setProperty('host.fstype', 'WINNT'); 970 break; 971 case 'WIN32': 972 self::setProperty('host.fstype', 'WIN32'); 973 break; 974 default: 975 self::setProperty('host.fstype', 'UNIX'); 976 break; 977 } 978 979 self::setProperty('php.version', PHP_VERSION); 980 self::setProperty('user.home', getenv('HOME')); 981 self::setProperty('application.startdir', getcwd()); 982 self::setProperty('line.separator', "\n"); 983 984 // try to detect machine dependent information 985 $sysInfo = array(); 986 if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN' && function_exists("posix_uname")) { 987 $sysInfo = posix_uname(); 988 } else { 989 $sysInfo['nodename'] = php_uname('n'); 990 $sysInfo['machine']= php_uname('m') ; 991 //this is a not so ideal substition, but maybe better than nothing 992 $sysInfo['domain'] = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : "unknown"; 993 $sysInfo['release'] = php_uname('r'); 994 $sysInfo['version'] = php_uname('v'); 995 } 996 997 998 self::setProperty("host.name", isset($sysInfo['nodename']) ? $sysInfo['nodename'] : "unknown"); 999 self::setProperty("host.arch", isset($sysInfo['machine']) ? $sysInfo['machine'] : "unknown"); 1000 self::setProperty("host.domain",isset($sysInfo['domain']) ? $sysInfo['domain'] : "unknown"); 1001 self::setProperty("host.os.release", isset($sysInfo['release']) ? $sysInfo['release'] : "unknown"); 1002 self::setProperty("host.os.version", isset($sysInfo['version']) ? $sysInfo['version'] : "unknown"); 1003 unset($sysInfo); 1004 } 1005 1006 /** 1007 * This gets a property that was set via command line or otherwise passed into Phing. 1008 * "Defined" in this case means "externally defined". The reason this method exists is to 1009 * provide a public means of accessing commandline properties for (e.g.) logger or listener 1010 * scripts. E.g. to specify which logfile to use, PearLogger needs to be able to access 1011 * the pear.log.name property. 1012 * 1013 * @param string $name 1014 * @return string value of found property (or null, if none found). 1015 */ 1016 public static function getDefinedProperty($name) { 1017 return self::$definedProps->getProperty($name); 1018 } 1019 1020 /** 1021 * This sets a property that was set via command line or otherwise passed into Phing. 1022 * 1023 * @param string $name 1024 * @return string value of found property (or null, if none found). 1025 */ 1026 public static function setDefinedProperty($name, $value) { 1027 return self::$definedProps->setProperty($name, $value); 1028 } 1029 1030 /** 1031 * Returns property value for a System property. 1032 * System properties are "global" properties like line.separator, 1033 * and user.dir. Many of these correspond to similar properties in Java 1034 * or Ant. 1035 * 1036 * @param string $paramName 1037 * @return string Value of found property (or null, if none found). 1038 */ 1039 public static function getProperty($propName) { 1040 1041 // some properties are detemined on each access 1042 // some are cached, see below 1043 1044 // default is the cached value: 1045 $val = isset(self::$properties[$propName]) ? self::$properties[$propName] : null; 1046 1047 // special exceptions 1048 switch($propName) { 1049 case 'user.dir': 1050 $val = getcwd(); 1051 break; 1052 } 1053 1054 return $val; 1055 } 1056 1057 /** Retuns reference to all properties*/ 1058 public static function &getProperties() { 1059 return self::$properties; 1060 } 1061 1062 public static function setProperty($propName, $propValue) { 1063 $propName = (string) $propName; 1064 $oldValue = self::getProperty($propName); 1065 self::$properties[$propName] = $propValue; 1066 return $oldValue; 1067 } 1068 1069 public static function currentTimeMillis() { 1070 list($usec, $sec) = explode(" ",microtime()); 1071 return ((float)$usec + (float)$sec); 1072 } 1073 1074 /** 1075 * Sets the include path based on PHP_CLASSPATH constant (set in phing.php). 1076 * @return void 1077 */ 1078 private static function setIncludePaths() { 1079 $success = false; 1080 1081 if (defined('PHP_CLASSPATH')) { 1082 $success = ini_set('include_path', PHP_CLASSPATH); 1083 } else { 1084 // don't do anything, just assume that include_path has been properly set. 1085 $success = true; 1086 } 1087 1088 if ($success === false) { 1089 print("SYSTEM FAILURE: Could not set PHP include path\n"); 1090 self::halt(-1); 1091 } 1092 } 1093 1094 /** 1095 * Sets PHP INI values that Phing needs. 1096 * @return void 1097 */ 1098 private static function setIni() { 1099 error_reporting(E_ALL); 1100 set_time_limit(0); 1101 ini_set('magic_quotes_gpc', 'off'); 1102 ini_set('short_open_tag', 'off'); 1103 ini_set('default_charset', 'iso-8859-1'); 1104 ini_set('register_globals', 'off'); 1105 ini_set('allow_call_time_pass_reference', 'on'); 1106 1107 // should return memory limit in MB 1108 $mem_limit = (int) ini_get('memory_limit'); 1109 if ($mem_limit < 32) { 1110 ini_set('memory_limit', '32M'); // nore: this may need to be higher for many projects 1111 } 1112 } 1113 1114 /** 1115 * Returns reference to Timer object. 1116 * @return Timer 1117 */ 1118 public static function getTimer() { 1119 if (self::$timer === null) { 1120 include_once 'phing/system/util/Timer.php'; 1121 self::$timer= new Timer(); 1122 } 1123 return self::$timer; 1124 } 1125 1126 /** 1127 * Start up Phing. 1128 * Sets up the Phing environment -- does NOT initiate the build process. 1129 * @return void 1130 */ 1131 public static function startup() { 1132 1133 register_shutdown_function(array('Phing', 'shutdown')); 1134 1135 // some init stuff 1136 self::getTimer()->start(); 1137 1138 self::setSystemConstants(); 1139 self::setIncludePaths(); 1140 self::setIni(); 1141 } 1142 1143 /** 1144 * Halts the system. 1145 * @see shutdown() 1146 */ 1147 public static function halt($code=0) { 1148 self::shutdown($code); 1149 } 1150 1151 /** 1152 * Stops timers & exits. 1153 * @return void 1154 */ 1155 public static function shutdown($exitcode = 0) { 1156 //print("[AUTOMATIC SYSTEM SHUTDOWN]\n"); 1157 self::getTimer()->stop(); 1158 exit($exitcode); // final point where everything stops 1159 } 1160 1161 }
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Fri Mar 16 22:42:14 2007 | par Balluche grâce à PHPXref 0.7 |