123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439 |
- <?php
- /*
- * $Id: PropertyTask.php 905 2010-10-05 16:28:03Z 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: 905 $
- * @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));
- }
- }
- }
|