Spaces:
Sleeping
Sleeping
| /* | |
| * $Id: PropertyTask.php 3076 2006-12-18 08:52:12Z fabien $ | |
| * | |
| * 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/TaskPhing.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 TaskPhing { | |
| /** 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)); | |
| } | |
| } | |
| } | |