home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Servidores / xampp-win32-1.6.7-installer.exe / php / PEAR / phing / tasks / system / PropertyTask.php < prev    next >
Encoding:
PHP Script  |  2007-02-05  |  14.5 KB  |  439 lines

  1. <?php
  2.  
  3. /*
  4.  *  $Id: PropertyTask.php 144 2007-02-05 15:19:00Z hans $
  5.  *
  6.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  7.  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  8.  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  9.  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  10.  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  11.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  12.  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  13.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  14.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  15.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  16.  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  17.  *
  18.  * This software consists of voluntary contributions made by many individuals
  19.  * and is licensed under the LGPL. For more information please see
  20.  * <http://phing.info>.
  21.  */
  22.  
  23. include_once 'phing/Task.php';
  24. include_once 'phing/system/util/Properties.php';
  25.  
  26. /**
  27.  * Task for setting properties in buildfiles.
  28.  *
  29.  * @author    Andreas Aderhold <andi@binarycloud.com>
  30.  * @author    Hans Lellelid <hans@xmpl.org>
  31.  * @version   $Revision$
  32.  * @package   phing.tasks.system
  33.  */
  34. class PropertyTask extends Task {
  35.  
  36.     /** name of the property */
  37.     protected $name; 
  38.     
  39.     /** value of the property */
  40.     protected $value;
  41.     
  42.     protected $reference;
  43.     protected $env;     // Environment
  44.     protected $file;
  45.     protected $ref;
  46.     protected $prefix;
  47.     protected $fallback;
  48.     
  49.     /** Whether to force overwrite of existing property. */
  50.     protected $override = false;
  51.     
  52.     /** Whether property should be treated as "user" property. */
  53.     protected $userProperty = false;
  54.  
  55.     /**
  56.      * Sets a the name of current property component
  57.      */
  58.     function setName($name) {
  59.         $this->name = (string) $name;
  60.     }
  61.     
  62.     /** Get property component name. */
  63.     function getName() {
  64.         return $this->name;
  65.     }
  66.  
  67.     /**
  68.      * Sets a the value of current property component.
  69.      * @param    mixed      Value of name, all scalars allowed
  70.      */
  71.     function setValue($value) {
  72.         $this->value = (string) $value;
  73.     }
  74.     
  75.     /**
  76.      * Sets value of property to CDATA tag contents.
  77.      * @param string $values
  78.      * @since 2.2.0
  79.      */
  80.     public function addText($value) {
  81.         $this->setValue($value);
  82.     }
  83.     
  84.     /** Get the value of current property component. */
  85.     function getValue() {
  86.         return $this->value;
  87.     }
  88.     
  89.     /** Set a file to use as the source for properties. */
  90.     function setFile($file) {
  91.         if (is_string($file)) {
  92.             $file = new PhingFile($file);
  93.         }
  94.         $this->file = $file;
  95.     }
  96.     
  97.     /** Get the PhingFile that is being used as property source. */
  98.     function getFile() {
  99.         return $this->file;
  100.     }
  101.  
  102.     function setRefid(Reference $ref) {
  103.         $this->reference = $ref;
  104.     }
  105.     
  106.     function getRefid() {
  107.         return $this->reference;
  108.     }
  109.  
  110.     /**
  111.      * Prefix to apply to properties loaded using <code>file</code>.
  112.      * A "." is appended to the prefix if not specified.
  113.      * @param string $prefix prefix string
  114.      * @return void
  115.      * @since 2.0
  116.      */
  117.     public function setPrefix($prefix) {
  118.         $this->prefix = $prefix;
  119.         if (!StringHelper::endsWith(".", $prefix)) {
  120.             $this->prefix .= ".";
  121.         }
  122.     }
  123.  
  124.     /**
  125.      * @return string
  126.      * @since 2.0
  127.      */
  128.     public function getPrefix() {
  129.         return $this->prefix;
  130.     }
  131.  
  132.     /**
  133.     * the prefix to use when retrieving environment variables.
  134.     * Thus if you specify environment="myenv"
  135.     * you will be able to access OS-specific
  136.     * environment variables via property names "myenv.PATH" or
  137.     * "myenv.TERM".
  138.     * <p>
  139.     * Note that if you supply a property name with a final
  140.     * "." it will not be doubled. ie environment="myenv." will still
  141.     * allow access of environment variables through "myenv.PATH" and
  142.     * "myenv.TERM". This functionality is currently only implemented
  143.     * on select platforms. Feel free to send patches to increase the number of platforms
  144.     * this functionality is supported on ;).<br>
  145.     * Note also that properties are case sensitive, even if the
  146.     * environment variables on your operating system are not, e.g. it
  147.     * will be ${env.Path} not ${env.PATH} on Windows 2000.
  148.     * @param env prefix
  149.     */
  150.     function setEnvironment($env) {
  151.         $this->env = (string) $env;
  152.     }
  153.  
  154.     function getEnvironment() {
  155.         return $this->env;
  156.     }
  157.     
  158.     /**
  159.      * Set whether this is a user property (ro).
  160.      * This is deprecated in Ant 1.5, but the userProperty attribute
  161.      * of the class is still being set via constructor, so Phing will
  162.      * allow this method to function.
  163.      * @param boolean $v
  164.      */
  165.     function setUserProperty($v) {
  166.         $this->userProperty = (boolean) $v;
  167.     }
  168.     
  169.     function getUserProperty() {
  170.         return $this->userProperty;
  171.     }
  172.     
  173.     function setOverride($v) {
  174.         $this->override = (boolean) $v;
  175.     }
  176.     
  177.     function getOverride() {
  178.         return $this->override;
  179.     }
  180.     
  181.     function toString() {
  182.         return (string) $this->value;
  183.     }
  184.  
  185.     /**
  186.      * @param Project $p
  187.      */
  188.     function setFallback($p) {
  189.         $this->fallback = $p;
  190.     }
  191.     
  192.     function getFallback() {
  193.         return $this->fallback;
  194.     }
  195.     /**
  196.      * set the property in the project to the value.
  197.      * if the task was give a file or env attribute
  198.      * here is where it is loaded
  199.      */
  200.     function main() {
  201.         if ($this->name !== null) {
  202.             if ($this->value === null && $this->ref === null) {
  203.                 throw new BuildException("You must specify value or refid with the name attribute", $this->getLocation());
  204.             }
  205.         } else {
  206.             if ($this->file === null && $this->env === null ) {
  207.                 throw new BuildException("You must specify file or environment when not using the name attribute", $this->getLocation());
  208.             }
  209.         }
  210.  
  211.         if ($this->file === null && $this->prefix !== null) {
  212.             throw new BuildException("Prefix is only valid when loading from a file.", $this->getLocation());
  213.         }
  214.         
  215.         if (($this->name !== null) && ($this->value !== null)) {
  216.             $this->addProperty($this->name, $this->value);
  217.         }
  218.  
  219.         if ($this->file !== null) {
  220.             $this->loadFile($this->file);
  221.         }
  222.  
  223.         if ( $this->env !== null ) {
  224.             $this->loadEnvironment($this->env);
  225.         }
  226.  
  227.         if (($this->name !== null) && ($this->ref !== null)) {
  228.             // get the refereced property
  229.             try {
  230.             $this->addProperty($this->name, $this->reference->getReferencedObject($this->project)->toString());
  231.             } catch (BuildException $be) {
  232.                 if ($this->fallback !== null) {
  233.                      $this->addProperty($this->name, $this->reference->getReferencedObject($this->fallback)->toString());
  234.                 } else {
  235.                     throw $be;
  236.                 }
  237.             }
  238.         }
  239.     }
  240.     
  241.     /**
  242.      * load the environment values
  243.      * @param string $prefix prefix to place before them
  244.      */
  245.     protected function loadEnvironment($prefix) {
  246.  
  247.         $props = new Properties();
  248.         if ( substr($prefix, strlen($prefix)-1) == '.' ) {
  249.             $prefix .= ".";
  250.         }
  251.         $this->log("Loading Environment $prefix", Project::MSG_VERBOSE);
  252.         foreach($_ENV as $key => $value) {
  253.             $props->setProperty($prefix . '.' . $key, $value);
  254.         }
  255.         $this->addProperties($props);
  256.     }
  257.  
  258.     /**
  259.      * iterate through a set of properties,
  260.      * resolve them then assign them
  261.      */
  262.     protected function addProperties($props) {
  263.         $this->resolveAllProperties($props);
  264.         foreach($props->keys() as $name) {        
  265.             $value = $props->getProperty($name);
  266.             $v = $this->project->replaceProperties($value);            
  267.             if ($this->prefix !== null) {
  268.                 $name = $this->prefix . $name;
  269.             }
  270.             $this->addProperty($name, $v);
  271.         }
  272.     }
  273.  
  274.     /**
  275.      * add a name value pair to the project property set
  276.      * @param string $name name of property
  277.      * @param string $value value to set
  278.      */
  279.     protected function addProperty($name, $value) {
  280.         if ($this->userProperty) {
  281.             if ($this->project->getUserProperty($name) === null || $this->override) {
  282.                 $this->project->setInheritedProperty($name, $value);
  283.             } else {
  284.                 $this->log("Override ignored for " . $name, Project::MSG_VERBOSE);
  285.             }
  286.         } else {
  287.             if ($this->override) {
  288.                 $this->project->setProperty($name, $value);
  289.             } else {
  290.                 $this->project->setNewProperty($name, $value);
  291.             }
  292.         }
  293.     }
  294.  
  295.     /**
  296.      * load properties from a file.
  297.      * @param PhingFile $file
  298.      */
  299.     protected function loadFile(PhingFile $file) {
  300.         $props = new Properties();
  301.         $this->log("Loading ". $file->getAbsolutePath(), Project::MSG_INFO);
  302.         try { // try to load file
  303.             if ($file->exists()) {
  304.                 $props->load($file);
  305.                 $this->addProperties($props);
  306.             } else {
  307.                 $this->log("Unable to find property file: ". $file->getAbsolutePath() ."... skipped", Project::MSG_WARN);
  308.             }
  309.         } catch (IOException $ioe) {
  310.             throw new BuildException("Could not load properties from file.", $ioe);
  311.         }
  312.     }
  313.     
  314.     /**
  315.      * Given a Properties object, this method goes through and resolves
  316.      * any references to properties within the object.
  317.      * 
  318.      * @param Properties $props The collection of Properties that need to be resolved.
  319.      * @return void
  320.      */
  321.     protected function resolveAllProperties(Properties $props) {
  322.         
  323.         $keys = $props->keys();
  324.  
  325.         while(count($keys)) {
  326.  
  327.             // There may be a nice regex/callback way to handle this
  328.             // replacement, but at the moment it is pretty complex, and
  329.             // would probably be a lot uglier to work into a preg_replace_callback()
  330.             // system.  The biggest problem is the fact that a resolution may require
  331.             // multiple passes.
  332.             
  333.             $name     = array_shift($keys);
  334.             $value    = $props->getProperty($name);
  335.             $resolved = false;
  336.             
  337.             while(!$resolved) {
  338.             
  339.                 $fragments = array();
  340.                 $propertyRefs = array();
  341.  
  342.                 // [HL] this was ::parsePropertyString($this->value ...) ... this seems wrong
  343.                 self::parsePropertyString($value, $fragments, $propertyRefs);
  344.  
  345.                 $resolved = true;
  346.                 if (count($propertyRefs) !== 0) {
  347.  
  348.                     $sb = "";
  349.  
  350.                     $i = $fragments;
  351.                     $j = $propertyRefs;
  352.                     while(count($i)) {
  353.                         $fragment = array_shift($i);
  354.                         if ($fragment === null) {
  355.                             $propertyName = array_shift($j);
  356.  
  357.                             if ($propertyName === $name) {
  358.                                 // Should we maybe just log this as an error & move on?
  359.                                 // $this->log("Property ".$name." was circularly defined.", Project::MSG_ERR);
  360.                                 throw new BuildException("Property ".$name." was circularly defined.");
  361.                             }
  362.  
  363.                             $fragment = $this->getProject()->getProperty($propertyName);
  364.                             if ($fragment === null) {
  365.                                 if ($props->containsKey($propertyName)) {
  366.                                     $fragment = $props->getProperty($propertyName);
  367.                                     $resolved = false; // parse again (could have been replaced w/ another var)
  368.                                 } else {
  369.                                     $fragment = "\${".$propertyName."}";
  370.                                 }
  371.                             }
  372.                         }
  373.                         $sb .= $fragment;
  374.                     }
  375.                     
  376.                     $this->log("Resolved Property \"$value\" to \"$sb\"", Project::MSG_DEBUG);
  377.                     $value = $sb;                    
  378.                     $props->setProperty($name, $value);
  379.                                  
  380.                 } // if (count($propertyRefs))
  381.                 
  382.             } // while (!$resolved)
  383.             
  384.         } // while (count($keys)
  385.     }
  386.  
  387.  
  388.      /**
  389.      * This method will parse a string containing ${value} style
  390.      * property values into two lists. The first list is a collection
  391.      * of text fragments, while the other is a set of string property names
  392.      * null entries in the first list indicate a property reference from the
  393.      * second list.
  394.      *
  395.      * This is slower than regex, but useful for this class, which has to handle
  396.      * multiple parsing passes for properties.
  397.      *
  398.      * @param string $value The string to be scanned for property references
  399.      * @param array &$fragments The found fragments
  400.      * @param  array &$propertyRefs The found refs
  401.      */
  402.     protected function parsePropertyString($value, &$fragments, &$propertyRefs) {
  403.     
  404.         $prev = 0;
  405.         $pos  = 0;
  406.  
  407.         while (($pos = strpos($value, '$', $prev)) !== false) {
  408.             
  409.             if ($pos > $prev) {
  410.                 array_push($fragments, StringHelper::substring($value, $prev, $pos-1));
  411.             }
  412.             if ($pos === (strlen($value) - 1)) {
  413.                 array_push($fragments, '$');
  414.                 $prev = $pos + 1;
  415.             } elseif ($value{$pos+1} !== '{' ) {
  416.  
  417.                 // the string positions were changed to value-1 to correct
  418.                 // a fatal error coming from function substring()
  419.                 array_push($fragments, StringHelper::substring($value, $pos, $pos + 1));
  420.                 $prev = $pos + 2;
  421.             } else {
  422.                 $endName = strpos($value, '}', $pos);
  423.                 if ($endName === false) {
  424.                     throw new BuildException("Syntax error in property: $value");
  425.                 }
  426.                 $propertyName = StringHelper::substring($value, $pos + 2, $endName-1);
  427.                 array_push($fragments, null);
  428.                 array_push($propertyRefs, $propertyName);
  429.                 $prev = $endName + 1;
  430.             }
  431.         }
  432.  
  433.         if ($prev < strlen($value)) {
  434.             array_push($fragments, StringHelper::substring($value, $prev));
  435.         }
  436.     }
  437.  
  438. }
  439.