summaryrefslogtreecommitdiff
path: root/buildscripts/phing/classes/phing/tasks/system/PropertyTask.php
diff options
context:
space:
mode:
Diffstat (limited to 'buildscripts/phing/classes/phing/tasks/system/PropertyTask.php')
-rw-r--r--buildscripts/phing/classes/phing/tasks/system/PropertyTask.php438
1 files changed, 438 insertions, 0 deletions
diff --git a/buildscripts/phing/classes/phing/tasks/system/PropertyTask.php b/buildscripts/phing/classes/phing/tasks/system/PropertyTask.php
new file mode 100644
index 00000000..d6168e44
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/PropertyTask.php
@@ -0,0 +1,438 @@
+<?php
+
+/*
+ * $Id: PropertyTask.php 59 2006-04-28 14:49:47Z mrook $
+ *
+ * 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/system/util/Properties.php';
+
+/**
+ * Task for setting properties in buildfiles.
+ *
+ * @author Andreas Aderhold <andi@binarycloud.com>
+ * @author Hans Lellelid <hans@xmpl.org>
+ * @version $Revision$
+ * @package phing.tasks.system
+ */
+class PropertyTask extends Task {
+
+ /** name of the property */
+ protected $name;
+
+ /** value of the property */
+ protected $value;
+
+ protected $reference;
+ protected $env; // Environment
+ protected $file;
+ protected $ref;
+ protected $prefix;
+ protected $fallback;
+
+ /** Whether to force overwrite of existing property. */
+ protected $override = false;
+
+ /** Whether property should be treated as "user" property. */
+ protected $userProperty = false;
+
+ /**
+ * Sets a the name of current property component
+ */
+ function setName($name) {
+ $this->name = (string) $name;
+ }
+
+ /** Get property component name. */
+ function getName() {
+ return $this->name;
+ }
+
+ /**
+ * Sets a the value of current property component.
+ * @param mixed Value of name, all scalars allowed
+ */
+ function setValue($value) {
+ $this->value = (string) $value;
+ }
+
+ /**
+ * Sets value of property to CDATA tag contents.
+ * @param string $values
+ * @since 2.2.0
+ */
+ public function addText($value) {
+ $this->setValue($value);
+ }
+
+ /** Get the value of current property component. */
+ function getValue() {
+ return $this->value;
+ }
+
+ /** Set a file to use as the source for properties. */
+ function setFile($file) {
+ if (is_string($file)) {
+ $file = new PhingFile($file);
+ }
+ $this->file = $file;
+ }
+
+ /** Get the PhingFile that is being used as property source. */
+ function getFile() {
+ return $this->file;
+ }
+
+ function setRefid(Reference $ref) {
+ $this->reference = $ref;
+ }
+
+ function getRefid() {
+ return $this->reference;
+ }
+
+ /**
+ * Prefix to apply to properties loaded using <code>file</code>.
+ * A "." is appended to the prefix if not specified.
+ * @param string $prefix prefix string
+ * @return void
+ * @since 2.0
+ */
+ public function setPrefix($prefix) {
+ $this->prefix = $prefix;
+ if (!StringHelper::endsWith(".", $prefix)) {
+ $this->prefix .= ".";
+ }
+ }
+
+ /**
+ * @return string
+ * @since 2.0
+ */
+ public function getPrefix() {
+ return $this->prefix;
+ }
+
+ /**
+ * the prefix to use when retrieving environment variables.
+ * Thus if you specify environment="myenv"
+ * you will be able to access OS-specific
+ * environment variables via property names "myenv.PATH" or
+ * "myenv.TERM".
+ * <p>
+ * Note that if you supply a property name with a final
+ * "." it will not be doubled. ie environment="myenv." will still
+ * allow access of environment variables through "myenv.PATH" and
+ * "myenv.TERM". This functionality is currently only implemented
+ * on select platforms. Feel free to send patches to increase the number of platforms
+ * this functionality is supported on ;).<br>
+ * Note also that properties are case sensitive, even if the
+ * environment variables on your operating system are not, e.g. it
+ * will be ${env.Path} not ${env.PATH} on Windows 2000.
+ * @param env prefix
+ */
+ function setEnvironment($env) {
+ $this->env = (string) $env;
+ }
+
+ function getEnvironment() {
+ return $this->env;
+ }
+
+ /**
+ * Set whether this is a user property (ro).
+ * This is deprecated in Ant 1.5, but the userProperty attribute
+ * of the class is still being set via constructor, so Phing will
+ * allow this method to function.
+ * @param boolean $v
+ */
+ function setUserProperty($v) {
+ $this->userProperty = (boolean) $v;
+ }
+
+ function getUserProperty() {
+ return $this->userProperty;
+ }
+
+ function setOverride($v) {
+ $this->override = (boolean) $v;
+ }
+
+ function getOverride() {
+ return $this->override;
+ }
+
+ function toString() {
+ return (string) $this->value;
+ }
+
+ /**
+ * @param Project $p
+ */
+ function setFallback($p) {
+ $this->fallback = $p;
+ }
+
+ function getFallback() {
+ return $this->fallback;
+ }
+ /**
+ * set the property in the project to the value.
+ * if the task was give a file or env attribute
+ * here is where it is loaded
+ */
+ function main() {
+ if ($this->name !== null) {
+ if ($this->value === null && $this->ref === null) {
+ throw new BuildException("You must specify value or refid with the name attribute", $this->getLocation());
+ }
+ } else {
+ if ($this->file === null && $this->env === null ) {
+ throw new BuildException("You must specify file or environment when not using the name attribute", $this->getLocation());
+ }
+ }
+
+ if ($this->file === null && $this->prefix !== null) {
+ throw new BuildException("Prefix is only valid when loading from a file.", $this->getLocation());
+ }
+
+ if (($this->name !== null) && ($this->value !== null)) {
+ $this->addProperty($this->name, $this->value);
+ }
+
+ if ($this->file !== null) {
+ $this->loadFile($this->file);
+ }
+
+ if ( $this->env !== null ) {
+ $this->loadEnvironment($this->env);
+ }
+
+ if (($this->name !== null) && ($this->ref !== null)) {
+ // get the refereced property
+ try {
+ $this->addProperty($this->name, $this->reference->getReferencedObject($this->project)->toString());
+ } catch (BuildException $be) {
+ if ($this->fallback !== null) {
+ $this->addProperty($this->name, $this->reference->getReferencedObject($this->fallback)->toString());
+ } else {
+ throw $be;
+ }
+ }
+ }
+ }
+
+ /**
+ * load the environment values
+ * @param string $prefix prefix to place before them
+ */
+ protected function loadEnvironment($prefix) {
+
+ $props = new Properties();
+ if ( substr($prefix, strlen($prefix)-1) == '.' ) {
+ $prefix .= ".";
+ }
+ $this->log("Loading Environment $prefix", PROJECT_MSG_VERBOSE);
+ foreach($_ENV as $key => $value) {
+ $props->setProperty($prefix . '.' . $key, $value);
+ }
+ $this->addProperties($props);
+ }
+
+ /**
+ * iterate through a set of properties,
+ * resolve them then assign them
+ */
+ protected function addProperties($props) {
+ $this->resolveAllProperties($props);
+ foreach($props->keys() as $name) {
+ $value = $props->getProperty($name);
+ $v = $this->project->replaceProperties($value);
+ if ($this->prefix !== null) {
+ $name = $this->prefix . $name;
+ }
+ $this->addProperty($name, $v);
+ }
+ }
+
+ /**
+ * add a name value pair to the project property set
+ * @param string $name name of property
+ * @param string $value value to set
+ */
+ protected function addProperty($name, $value) {
+ if ($this->userProperty) {
+ if ($this->project->getUserProperty($name) === null || $this->override) {
+ $this->project->setInheritedProperty($name, $value);
+ } else {
+ $this->log("Override ignored for " . $name, PROJECT_MSG_VERBOSE);
+ }
+ } else {
+ if ($this->override) {
+ $this->project->setProperty($name, $value);
+ } else {
+ $this->project->setNewProperty($name, $value);
+ }
+ }
+ }
+
+ /**
+ * load properties from a file.
+ * @param PhingFile $file
+ */
+ protected function loadFile(PhingFile $file) {
+ $props = new Properties();
+ $this->log("Loading ". $file->getAbsolutePath(), PROJECT_MSG_INFO);
+ try { // try to load file
+ if ($file->exists()) {
+ $props->load($file);
+ $this->addProperties($props);
+ } else {
+ $this->log("Unable to find property file: ". $file->getAbsolutePath() ."... skipped", PROJECT_MSG_WARN);
+ }
+ } catch (IOException $ioe) {
+ throw new BuildException("Could not load properties from file.", $ioe);
+ }
+ }
+
+ /**
+ * Given a Properties object, this method goes through and resolves
+ * any references to properties within the object.
+ *
+ * @param Properties $props The collection of Properties that need to be resolved.
+ * @return void
+ */
+ protected function resolveAllProperties(Properties $props) {
+
+ $keys = $props->keys();
+
+ while(count($keys)) {
+
+ // There may be a nice regex/callback way to handle this
+ // replacement, but at the moment it is pretty complex, and
+ // would probably be a lot uglier to work into a preg_replace_callback()
+ // system. The biggest problem is the fact that a resolution may require
+ // multiple passes.
+
+ $name = array_shift($keys);
+ $value = $props->getProperty($name);
+ $resolved = false;
+
+ while(!$resolved) {
+
+ $fragments = array();
+ $propertyRefs = array();
+
+ // [HL] this was ::parsePropertyString($this->value ...) ... this seems wrong
+ self::parsePropertyString($value, $fragments, $propertyRefs);
+
+ $resolved = true;
+ if (count($propertyRefs) !== 0) {
+
+ $sb = "";
+
+ $i = $fragments;
+ $j = $propertyRefs;
+ while(count($i)) {
+ $fragment = array_shift($i);
+ if ($fragment === null) {
+ $propertyName = array_shift($j);
+
+ if ($propertyName === $name) {
+ // Should we maybe just log this as an error & move on?
+ // $this->log("Property ".$name." was circularly defined.", PROJECT_MSG_ERR);
+ throw new BuildException("Property ".$name." was circularly defined.");
+ }
+
+ $fragment = $this->getProject()->getProperty($propertyName);
+ if ($fragment === null) {
+ if ($props->containsKey($propertyName)) {
+ $fragment = $props->getProperty($propertyName);
+ $resolved = false; // parse again (could have been replaced w/ another var)
+ } else {
+ $fragment = "\${".$propertyName."}";
+ }
+ }
+ }
+ $sb .= $fragment;
+ }
+
+ $this->log("Resolved Property \"$value\" to \"$sb\"", PROJECT_MSG_DEBUG);
+ $value = $sb;
+ $props->setProperty($name, $value);
+
+ } // if (count($propertyRefs))
+
+ } // while (!$resolved)
+
+ } // while (count($keys)
+ }
+
+
+ /**
+ * This method will parse a string containing ${value} style
+ * property values into two lists. The first list is a collection
+ * of text fragments, while the other is a set of string property names
+ * null entries in the first list indicate a property reference from the
+ * second list.
+ *
+ * This is slower than regex, but useful for this class, which has to handle
+ * multiple parsing passes for properties.
+ *
+ * @param string $value The string to be scanned for property references
+ * @param array &$fragments The found fragments
+ * @param array &$propertyRefs The found refs
+ */
+ protected function parsePropertyString($value, &$fragments, &$propertyRefs) {
+
+ $prev = 0;
+ $pos = 0;
+
+ while (($pos = strpos($value, '$', $prev)) !== false) {
+
+ if ($pos > $prev) {
+ array_push($fragments, StringHelper::substring($value, $prev, $pos-1));
+ }
+ if ($pos === (strlen($value) - 1)) {
+ array_push($fragments, '$');
+ $prev = $pos + 1;
+ } elseif ($value{$pos+1} !== '{' ) {
+
+ // the string positions were changed to value-1 to correct
+ // a fatal error coming from function substring()
+ array_push($fragments, StringHelper::substring($value, $pos, $pos + 1));
+ $prev = $pos + 2;
+ } else {
+ $endName = strpos($value, '}', $pos);
+ if ($endName === false) {
+ throw new BuildException("Syntax error in property: $value");
+ }
+ $propertyName = StringHelper::substring($value, $pos + 2, $endName-1);
+ array_push($fragments, null);
+ array_push($propertyRefs, $propertyName);
+ $prev = $endName + 1;
+ }
+ }
+
+ if ($prev < strlen($value)) {
+ array_push($fragments, StringHelper::substring($value, $prev));
+ }
+ }
+
+}