diff options
Diffstat (limited to 'buildscripts/phing/classes/phing/tasks/ext/CapsuleTask.php')
-rw-r--r-- | buildscripts/phing/classes/phing/tasks/ext/CapsuleTask.php | 480 |
1 files changed, 480 insertions, 0 deletions
diff --git a/buildscripts/phing/classes/phing/tasks/ext/CapsuleTask.php b/buildscripts/phing/classes/phing/tasks/ext/CapsuleTask.php new file mode 100644 index 00000000..13ccd73d --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/CapsuleTask.php @@ -0,0 +1,480 @@ +<?php + +/* + * $Id: 205bc55fd1f7f36783d105ff2d0e27357282bbed $ + * + * 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 $Id: 205bc55fd1f7f36783d105ff2d0e27357282bbed $ + * @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($this->project->resolveFile($value)->getCanonicalPath()); + if ($f->exists()) { + $fr = new FileReader($f); + $fr->readInto($value); + } + + } // if ends with file.contents + + if (StringHelper::isBoolean($value)) { + $value = StringHelper::booleanValue($value); + } + + $c->put($property, $value); + + } // foreach property + + } // if contextProperties !== null + + try { + $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. + * + * @package phing.tasks.ext + */ +class AssignedVar { + + private $name; + private $value; + + public function setName($v) { + $this->name = $v; + } + + public function setValue($v) { + $this->value = $v; + } + + public function getName() { + return $this->name; + } + + public function getValue() { + return $this->value; + } + +}
\ No newline at end of file |