Blame | Letzte Änderung | Log anzeigen | RSS feed
<?php/** $Id: CapsuleTask.php 144 2007-02-05 15:19:00Z hans $** 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>.*/include_once 'phing/Task.php';include_once 'phing/BuildException.php';include_once 'phing/lib/Capsule.php';include_once 'phing/util/StringHelper.php';/*** A phing task for generating output by using Capsule.** This is based on the interface to TexenTask from Apache's Velocity engine.** @author Hans Lellelid <hans@xmpl.org>* @version $Revision: 1.17 $* @package phing.tasks.ext*/class CapsuleTask extends Task {/*** Capsule "template" engine.* @var Capsule*/protected $context;/*** Any vars assigned via the build file.* @var array AssignedVar[]*/protected $assignedVars = array();/*** This is the control template that governs the output.* It may or may not invoke the services of worker* templates.* @var string*/protected $controlTemplate;/*** This is where Velocity will look for templates* using the file template loader.* @var string*/protected $templatePath;/*** This is where texen will place all the output* that is a product of the generation process.* @var string*/protected $outputDirectory;/*** This is the file where the generated text* will be placed.* @var string*/protected $outputFile;/*** <p>* These are properties that are fed into the* initial context from a properties file. This* is simply a convenient way to set some values* that you wish to make available in the context.* </p>* <p>* These values are not critical, like the template path* or output path, but allow a convenient way to* set a value that may be specific to a particular* generation task.* </p>* <p>* For example, if you are generating scripts to allow* user to automatically create a database, then* you might want the <code>$databaseName</code>* to be placed* in the initial context so that it is available* in a script that might look something like the* following:* <code><pre>* #!bin/sh** echo y | mysqladmin create $databaseName* </pre></code>* The value of <code>$databaseName</code> isn't critical to* output, and you obviously don't want to change* the ant task to simply take a database name.* So initial context values can be set with* properties file.** @var array*/protected $contextProperties;// -----------------------------------------------------------------------// The following getters & setters are used by phing to set properties// specified in the XML for the capsule task.// -----------------------------------------------------------------------/*** [REQUIRED] Set the control template for the* generating process.* @param string $controlTemplate* @return void*/public function setControlTemplate ($controlTemplate) {$this->controlTemplate = $controlTemplate;}/*** Get the control template for the* generating process.* @return string*/public function getControlTemplate() {return $this->controlTemplate;}/*** [REQUIRED] Set the path where Velocity will look* for templates using the file template* loader.* @return void* @throws Exception*/public function setTemplatePath($templatePath) {$resolvedPath = "";$tok = strtok($templatePath, ",");while ( $tok ) {// resolve relative path from basedir and leave// absolute path untouched.$fullPath = $this->project->resolveFile($tok);$cpath = $fullPath->getCanonicalPath();if ($cpath === false) {$this->log("Template directory does not exist: " . $fullPath->getAbsolutePath());} else {$resolvedPath .= $cpath;}$tok = strtok(",");if ( $tok ) {$resolvedPath .= ",";}}$this->templatePath = $resolvedPath;}/*** Get the path where Velocity will look* for templates using the file template* loader.* @return string*/public function getTemplatePath() {return $this->templatePath;}/*** [REQUIRED] Set the output directory. It will be* created if it doesn't exist.* @param PhingFile $outputDirectory* @return void* @throws Exception*/public function setOutputDirectory(PhingFile $outputDirectory) {try {if (!$outputDirectory->exists()) {$this->log("Output directory does not exist, creating: " . $outputDirectory->getPath(),Project::MSG_VERBOSE);if (!$outputDirectory->mkdirs()) {throw new IOException("Unable to create Ouptut directory: " . $outputDirectory->getAbsolutePath());}}$this->outputDirectory = $outputDirectory->getCanonicalPath();} catch (IOException $ioe) {throw new BuildException($ioe);}}/*** Get the output directory.* @return string*/public function getOutputDirectory() {return $this->outputDirectory;}/*** [REQUIRED] Set the output file for the* generation process.* @param string $outputFile (TODO: change this to File)* @return void*/public function setOutputFile($outputFile) {$this->outputFile = $outputFile;}/*** Get the output file for the* generation process.* @return string*/public function getOutputFile() {return $this->outputFile;}/*** Set the context properties that will be* fed into the initial context be the* generating process starts.* @param string $file* @return void*/public function setContextProperties($file) {$sources = explode(",", $file);$this->contextProperties = new Properties();// Always try to get the context properties resource// from a file first. Templates may be taken from a JAR// file but the context properties resource may be a// resource in the filesystem. If this fails than attempt// to get the context properties resource from the// classpath.for ($i=0, $sourcesLength=count($sources); $i < $sourcesLength; $i++) {$source = new Properties();try {// resolve relative path from basedir and leave// absolute path untouched.$fullPath = $this->project->resolveFile($sources[$i]);$this->log("Using contextProperties file: " . $fullPath->toString());$source->load($fullPath);} catch (Exception $e) {throw new BuildException("Context properties file " . $sources[$i] ." could not be found in the file system!");}$keys = $source->keys();foreach ($keys as $key) {$name = $key;$value = $this->project->replaceProperties($source->getProperty($name));$this->contextProperties->setProperty($name, $value);}}}/*** Get the context properties that will be* fed into the initial context be the* generating process starts.* @return Properties*/public function getContextProperties() {return $this->contextProperties;}/*** Creates an "AssignedVar" class.*/public function createAssign() {$a = new AssignedVar();$this->assignedVars[] = $a;return $a;}// ---------------------------------------------------------------// End of XML setters & getters// ---------------------------------------------------------------/*** Creates a Smarty object.** @return Smarty initialized (cleared) Smarty context.* @throws Exception the execute method will catch* and rethrow as a <code>BuildException</code>*/public function initControlContext() {$this->context->clear();foreach($this->assignedVars as $var) {$this->context->put($var->getName(), $var->getValue());}return $this->context;}/*** Execute the input script with Velocity** @throws BuildException* BuildExceptions are thrown when required attributes are missing.* Exceptions thrown by Velocity are rethrown as BuildExceptions.*/public function main() {// Make sure the template path is set.if (empty($this->templatePath)) {throw new BuildException("The template path needs to be defined!");}// Make sure the control template is set.if ($this->controlTemplate === null) {throw new BuildException("The control template needs to be defined!");}// Make sure the output directory is set.if ($this->outputDirectory === null) {throw new BuildException("The output directory needs to be defined!");}// Make sure there is an output file.if ($this->outputFile === null) {throw new BuildException("The output file needs to be defined!");}// Setup Smarty runtime.// Smarty uses one object to store properties and to store// the context for the template (unlike Velocity). We setup this object, calling it// $this->context, and then initControlContext simply zeros out// any assigned variables.$this->context = new Capsule();if ($this->templatePath !== null) {$this->log("Using templatePath: " . $this->templatePath);$this->context->setTemplatePath($this->templatePath);}// Make sure the output directory exists, if it doesn't// then create it.$outputDir = new PhingFile($this->outputDirectory);if (!$outputDir->exists()) {$this->log("Output directory does not exist, creating: " . $outputDir->getAbsolutePath());$outputDir->mkdirs();}$this->context->setOutputDirectory($outputDir->getAbsolutePath());$path = $this->outputDirectory . DIRECTORY_SEPARATOR . $this->outputFile;$this->log("Generating to file " . $path);//$writer = new FileWriter($path);// The generator and the output path should// be placed in the init context here and// not in the generator class itself.$c = $this->initControlContext();// Set any variables that need to always// be loaded$this->populateInitialContext($c);// Feed all the options into the initial// control context so they are available// in the control/worker templates.if ($this->contextProperties !== null) {foreach($this->contextProperties->keys() as $property) {$value = $this->contextProperties->getProperty($property);// Special exception (from Texen)// for properties ending in file.contents:// in that case we dump the contents of the file// as the "value" for the Property.if (preg_match('/file\.contents$/', $property)) {// pull in contents of file specified$property = substr($property, 0, strpos($property, "file.contents") - 1);// reset value, and then// read in teh contents of the file into that var$value = "";$f = new PhingFile($project->resolveFile($value)->getCanonicalPath());if ($f->exists()) {$fr = new FileReader($f);$fr->readInto($value);}} // if ends with file.contentsif (StringHelper::isBoolean($value)) {$value = StringHelper::booleanValue($value);}$c->put($property, $value);} // foreach property} // if contextProperties !== nulltry {$this->log("Parsing control template: " . $this->controlTemplate);$c->parse($this->controlTemplate, $path);} catch (Exception $ioe) {throw new BuildException("Cannot write parsed template: ". $ioe->getMessage());}$this->cleanup();}/*** Place useful objects into the initial context.*** @param Capsule $context The context to populate, as retrieved from* {@link #initControlContext()}.* @return void* @throws Exception Error while populating context. The {@link* #main()} method will catch and rethrow as a* <code>BuildException</code>.*/protected function populateInitialContext(Capsule $context) {$this->context->put("now", strftime("%c", time()));$this->context->put("task", $this);}/*** A hook method called at the end of {@link #execute()} which can* be overridden to perform any necessary cleanup activities (such* as the release of database connections, etc.). By default,* does nothing.* @return void* @throws Exception Problem cleaning up.*/protected function cleanup() {}}/*** An "inner" class for holding assigned var values.* May be need to expand beyond name/value in the future.*/class AssignedVar {private $name;private $value;function setName($v) {$this->name = $v;}function setValue($v) {$this->value = $v;}function getName() {return $this->name;}function getValue() {return $this->value;}}