VersionControl_SVN
[ class tree: VersionControl_SVN ] [ index: VersionControl_SVN ] [ all elements ]

Source for file Command.php

Documentation is available at Command.php

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. /**
  4.  * VersionControl_SVN_Info allows for XML formatted output. XML_Parser is used to
  5.  * manipulate that output.
  6.  *
  7.  * +----------------------------------------------------------------------+
  8.  * | This LICENSE is in the BSD license style.                            |
  9.  * | http://www.opensource.org/licenses/bsd-license.php                   |
  10.  * |                                                                      |
  11.  * | Redistribution and use in source and binary forms, with or without   |
  12.  * | modification, are permitted provided that the following conditions   |
  13.  * | are met:                                                             |
  14.  * |                                                                      |
  15.  * |  * Redistributions of source code must retain the above copyright    |
  16.  * |    notice, this list of conditions and the following disclaimer.     |
  17.  * |                                                                      |
  18.  * |  * Redistributions in binary form must reproduce the above           |
  19.  * |    copyright notice, this list of conditions and the following       |
  20.  * |    disclaimer in the documentation and/or other materials provided   |
  21.  * |    with the distribution.                                            |
  22.  * |                                                                      |
  23.  * |  * Neither the name of Clay Loveless nor the names of contributors   |
  24.  * |    may be used to endorse or promote products derived from this      |
  25.  * |    software without specific prior written permission.               |
  26.  * |                                                                      |
  27.  * | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS  |
  28.  * | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT    |
  29.  * | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS    |
  30.  * | FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE      |
  31.  * | COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,  |
  32.  * | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
  33.  * | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;     |
  34.  * | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER     |
  35.  * | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT   |
  36.  * | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN    |
  37.  * | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE      |
  38.  * | POSSIBILITY OF SUCH DAMAGE.                                          |
  39.  * +----------------------------------------------------------------------+
  40.  *
  41.  * PHP version 5
  42.  *
  43.  * @category  VersionControl
  44.  * @package   VersionControl_SVN
  45.  * @author    Clay Loveless <clay@killersoft.com>
  46.  * @author    Michiel Rook <mrook@php.net>
  47.  * @author    Alexander Opitz <opitz.alexander@gmail.com>
  48.  * @copyright 2004-2007 Clay Loveless
  49.  * @license   http://www.opensource.org/licenses/bsd-license.php BSD License
  50.  * @link      http://pear.php.net/package/VersionControl_SVN
  51.  */
  52.  
  53. require_once 'VersionControl/SVN/Exception.php';
  54. require_once 'System.php';
  55.  
  56. /**
  57.  * Ground class for a SVN command.
  58.  *
  59.  * @category  VersionControl
  60.  * @package   VersionControl_SVN
  61.  * @author    Clay Loveless <clay@killersoft.com>
  62.  * @author    Michiel Rook <mrook@php.net>
  63.  * @author    Alexander Opitz <opitz.alexander@gmail.com>
  64.  * @copyright 2004-2007 Clay Loveless
  65.  * @license   http://www.opensource.org/licenses/bsd-license.php BSD License
  66.  * @version   0.5.1
  67.  * @link      http://pear.php.net/package/VersionControl_SVN
  68.  */
  69. {
  70.     /**
  71.      * Indicates whether commands passed to the
  72.      * {@link http://www.php.net/exec exec()} function in the
  73.      * {@link run} method should be passed through
  74.      * {@link http://www.php.net/escapeshellcmd escapeshellcmd()}.
  75.      * NOTE: this variable is ignored on Windows machines!
  76.      *
  77.      * @var boolean $useEscapeshellcmd 
  78.      */
  79.     public $useEscapeshellcmd = true;
  80.  
  81.     /**
  82.      * Use exec or passthru to get results from command.
  83.      *
  84.      * @var bool $passthru 
  85.      */
  86.     public $passthru = false;
  87.  
  88.     /**
  89.      * Location of the svn client binary installed as part of Subversion
  90.      *
  91.      * @var string $binaryPath 
  92.      */
  93.     public $binaryPath = '/usr/local/bin/svn';
  94.     
  95.     /**
  96.      * Legacy / compatibility location of the svn client binary
  97.      *
  98.      * @var string $svn_path 
  99.      */
  100.     public $svn_path = '';
  101.  
  102.     /**
  103.      * String to prepend to command string. Helpful for setting exec()
  104.      * environment variables, such as:
  105.      *    export LANG=en_US.utf8 &&
  106.      * ... to support non-ASCII file and directory names.
  107.      * 
  108.      * @var string $prependCmd 
  109.      */
  110.     public $prependCmd = '';
  111.  
  112.     /**
  113.      * Array of switches to use in building svn command
  114.      *
  115.      * @var array $switches 
  116.      */
  117.     public $switches = array();
  118.  
  119.     /**
  120.      * Switches required by this subcommand.
  121.      * See {@link http://svnbook.red-bean.com/svnbook/ Version Control with Subversion},
  122.      * Subversion Complete Reference for details on arguments for this subcommand.
  123.      *
  124.      * @var array $requiredSwitches 
  125.      */
  126.     public $requiredSwitches = array();
  127.  
  128.     /**
  129.      * Runtime options being used.
  130.      *
  131.      * @var array $options 
  132.      */
  133.     public $options = array();
  134.  
  135.     /**
  136.      * Command-line arguments that should be passed
  137.      * <b>outside</b> of those specified in {@link switches}.
  138.      *
  139.      * @var array $args 
  140.      */
  141.     public $args = array();
  142.  
  143.     /**
  144.      * Minimum number of args required by this subcommand.
  145.      * See {@link http://svnbook.red-bean.com/svnbook/ Version Control with Subversion},
  146.      * Subversion Complete Reference for details on arguments for this subcommand.
  147.      *
  148.      * @var int $minArgs 
  149.      */
  150.     public $minArgs = 0;
  151.  
  152.     /**
  153.      * Preferred fetchmode. Note that not all subcommands have output available for
  154.      * each preferred fetchmode. The default cascade is:
  155.      *
  156.      * VERSIONCONTROL_SVN_FETCHMODE_ASSOC
  157.      *  VERSIONCONTROL_SVN_FETCHMODE_RAW
  158.      *
  159.      * If the specified fetchmode isn't available, raw output will be returned.
  160.      * 
  161.      * @var int $fetchmode 
  162.      */
  163.     public $fetchmode = VERSIONCONTROL_SVN_FETCHMODE_ASSOC;
  164.  
  165.     /**
  166.      * Default username to use for connections.
  167.      *
  168.      * @var string $username 
  169.      */
  170.     public $username = '';
  171.  
  172.     /**
  173.      * Default password to use for connections.
  174.      *
  175.      * @var string $password 
  176.      */
  177.     public $password = '';
  178.  
  179.     /**
  180.      * Default config-dir to use for connections.
  181.      *
  182.      * @var string $configDir 
  183.      */
  184.     public $configDir = '';
  185.  
  186.     /**
  187.      * Default config-option to use for connections.
  188.      *
  189.      * @var string $configOption 
  190.      */
  191.     public $configOption = '';
  192.  
  193.     /**
  194.      * SVN subcommand to run.
  195.      * 
  196.      * @var string $commandName 
  197.      */
  198.     protected $commandName = '';
  199.  
  200.     /**
  201.      * Fully prepared command string.
  202.      * 
  203.      * @var string $preparedCmd 
  204.      */
  205.     protected $preparedCmd = '';
  206.  
  207.     /**
  208.      * Keep track of whether XML output is available for a command
  209.      *
  210.      * @var boolean $xmlAvail 
  211.      */
  212.     protected $xmlAvail = false;
  213.  
  214.     /**
  215.      * Useable switches for command with parameters.
  216.      */
  217.     protected $validSwitchesValue = array(
  218.         'username',
  219.         'password',
  220.         'config-dir',
  221.         'config-option',
  222.     );
  223.  
  224.     /**
  225.      * Useable switches for command without parameters.
  226.      */
  227.     protected $validSwitches = array(
  228.         'no-auth-cache',
  229.         'non-interactive',
  230.         'trust-server-cert',
  231.     );
  232.  
  233.     /**
  234.      * Constructor. Can't be called directly as class is abstract.
  235.      */
  236.     public function __construct()
  237.     {
  238.         $className get_class($this);
  239.         $this->commandName = strtolower(
  240.             substr(
  241.                 $className,
  242.                 strrpos($className'_'+ 1
  243.             )
  244.         );
  245.     }
  246.  
  247.     /**
  248.      * Allow for overriding of previously declared options.
  249.      *
  250.      * @param array $options An associative array of option names and
  251.      *                        their values
  252.      *
  253.      * @return VersionControl_SVN_Command Themself.
  254.      * @throws VersionControl_SVN_Exception If option isn't available.
  255.      */
  256.     public function setOptions($options = array())
  257.     {
  258.         $class = new ReflectionClass($this);
  259.  
  260.         foreach ($options as $option => $value{
  261.             try {
  262.                 $property $class->getProperty($option);
  263.             catch (ReflectionException $e{
  264.                 $property = null;
  265.             }
  266.             if (null !== $property && $property->isPublic()) {
  267.                 $this->$option $value;
  268.             else {
  269.                 throw new VersionControl_SVN_Exception(
  270.                     '"' $option '" is not a valid option',
  271.                     VersionControl_SVN_Exception::INVALID_OPTION
  272.                 );
  273.             }
  274.         }
  275.  
  276.         return $this;
  277.     }
  278.  
  279.     /**
  280.      * Prepare the command switches.
  281.      *
  282.      * This function should be overloaded by the command class.
  283.      *
  284.      * @return void 
  285.      * @throws VersionControl_SVN_Exception If preparing failed.
  286.      */
  287.     public function prepare()
  288.     {
  289.         $this->checkCommandRequirements();
  290.         $this->preProcessSwitches();
  291.  
  292.         $invalidSwitches = array();
  293.         $cmdParts = array(
  294.             $this->binaryPath,
  295.             $this->commandName
  296.         );
  297.  
  298.         foreach ($this->switches as $switch => $val{
  299.             if (1 === strlen($switch)) {
  300.                 $switchPrefix '-';
  301.             else {
  302.                 $switchPrefix '--';
  303.             }
  304.             if (in_array($switch$this->validSwitchesValue)) {
  305.                 $cmdParts[$switchPrefix $switch ' ' escapeshellarg($val);
  306.             elseif (in_array($switch$this->validSwitches)) {
  307.                 if (true === $val{
  308.                     $cmdParts[$switchPrefix $switch;
  309.                 }
  310.             else {
  311.                 $invalidSwitches[$switch;
  312.             }
  313.         }
  314.  
  315.         $this->postProcessSwitches($invalidSwitches);
  316.  
  317.         $this->preparedCmd = implode(
  318.             ' 'array_merge($cmdParts$this->args)
  319.         );
  320.     }
  321.  
  322.     /**
  323.      * Called after handling switches.
  324.      *
  325.      * @param array $invalidSwitches Invalid switches found while processing.
  326.      *
  327.      * @return void 
  328.      * @throws VersionControl_SVN_Exception If switch(s) is/are invalid.
  329.      */
  330.     protected function postProcessSwitches($invalidSwitches)
  331.     {
  332.         $invalid count($invalidSwitches);
  333.         if ($invalid > 0{
  334.             $invalides implode(','$invalidSwitches);
  335.             if ($invalid > 1{
  336.                 $error '"' $invalides '" are invalid switches';
  337.             else {
  338.                 $error '"' $invalides '" is a invalid switch';
  339.             }
  340.             $error .= ' for class "' get_class($this'".';
  341.             throw new VersionControl_SVN_Exception(
  342.                 $error,
  343.                 VersionControl_SVN_Exception::INVALID_SWITCH
  344.             );
  345.         }
  346.     }
  347.  
  348.  
  349.     /**
  350.      * Called before handling switches.
  351.      *
  352.      * @return void 
  353.      */
  354.     protected function preProcessSwitches()
  355.     {
  356.         if ($this->xmlAvail
  357.             && ($this->fetchmode == VERSIONCONTROL_SVN_FETCHMODE_ARRAY
  358.             || $this->fetchmode == VERSIONCONTROL_SVN_FETCHMODE_ASSOC
  359.             || $this->fetchmode == VERSIONCONTROL_SVN_FETCHMODE_OBJECT
  360.             || $this->fetchmode == VERSIONCONTROL_SVN_FETCHMODE_XML)
  361.         {
  362.             $this->switches['xml'= true;
  363.         }
  364.         $this->switches['non-interactive'= true;
  365.  
  366.         $this->fillSwitch('username'$this->username);
  367.         $this->fillSwitch('password'$this->password);
  368.         $this->fillSwitch('config-dir'$this->configDir);
  369.         $this->fillSwitch('config-option'$this->configOption);
  370.     }
  371.  
  372.     protected function fillSwitch($switchName$value)
  373.     {
  374.         if (!isset($this->switches[$switchName])
  375.             && '' !== $value
  376.         {
  377.             $this->switches[$switchName$value;
  378.         }
  379.     }
  380.  
  381.  
  382.     /**
  383.      * Standardized validation of requirements for a command class.
  384.      *
  385.      * @return void 
  386.      * @throws VersionControl_SVN_Exception If command requirements not resolved.
  387.      */
  388.     public function checkCommandRequirements()
  389.     {
  390.         // Set up error push parameters to avoid any notices about undefined indexes
  391.         $params['options']     $this->options;
  392.         $params['switches']    $this->switches;
  393.         $params['args']        $this->args;
  394.         $params['commandName'$this->commandName;
  395.         $params['cmd']         '';
  396.         
  397.         // Check for minimum arguments
  398.         if (sizeof($this->args$this->minArgs{
  399.             throw new VersionControl_SVN_Exception(
  400.                 'svn command requires at least ' $this->minArgs . ' argument(s)',
  401.                 VersionControl_SVN_Exception::MIN_ARGS
  402.             );
  403.         }
  404.         
  405.         // Check for presence of required switches
  406.         if (sizeof($this->requiredSwitches> 0{
  407.             $missing    = array();
  408.             $switches   $this->switches;
  409.             $reqsw      $this->requiredSwitches;
  410.             foreach ($reqsw as $req{
  411.                 $found = false;
  412.                 $good_switches explode('|'$req);
  413.                 foreach ($good_switches as $gsw{
  414.                     if (isset($switches[$gsw])) {
  415.                         $found = true;
  416.                     }
  417.                 }
  418.                 if (!$found{
  419.                     $missing['('.$req.')';
  420.                 }
  421.             }
  422.             $num_missing count($missing);
  423.             if ($num_missing > 0{
  424.                 throw new VersionControl_SVN_Exception(
  425.                     'svn command requires the following switch(es): ' $missing,
  426.                     VersionControl_SVN_Exception::SWITCH_MISSING
  427.                 );
  428.             }
  429.         }
  430.     }
  431.  
  432.     /**
  433.      * Run the command with the defined switches.
  434.      *
  435.      * @param array $args     Arguments to pass to Subversion
  436.      * @param array $switches Switches to pass to Subversion
  437.      *
  438.      * @return  mixed   $fetchmode specified output on success.
  439.      * @throws VersionControl_SVN_Exception If command failed.
  440.      */
  441.     public function run($args = array()$switches = array())
  442.     {
  443.         if ($this->svn_path != ''{
  444.             $this->binaryPath = $this->svn_path;
  445.         }
  446.         
  447.         if (!file_exists($this->binaryPath)) {
  448.             $system = new System();
  449.             $this->binaryPath = $system->which('svn');
  450.         }
  451.  
  452.         if (sizeof($switches> 0{
  453.             $this->switches = $switches;
  454.         }
  455.         if (sizeof($args> 0{
  456.             foreach (array_keys($argsas $k{
  457.                 $this->args[$kescapeshellarg($args[$k]);
  458.             }
  459.         }
  460.  
  461.         // Always prepare, allows for obj re-use. (Request #5021)
  462.         $this->prepare();
  463.  
  464.         $out       = array();
  465.         // @var integer $returnVar Return number from shell execution.
  466.         $returnVar = null;
  467.  
  468.         $cmd $this->preparedCmd;
  469.  
  470.         // On Windows, don't use escapeshellcmd, and double-quote $cmd
  471.         // so it's executed as 
  472.         // cmd /c ""C:\Program Files\SVN\bin\svn.exe" info "C:\Program Files\dev\trunk""
  473.         if (strtoupper(substr(PHP_OS03)) === 'WIN'{
  474.             $cmd str_replace(
  475.                 $this->binaryPath,
  476.                 escapeshellarg(str_replace('/''\\'$this->binaryPath)),
  477.                 $cmd
  478.             );
  479.  
  480.             if (!$this->passthru{
  481.                 exec("cmd /c \"$cmd 2>&1\""$out$returnVar);
  482.             else {
  483.                 passthru("cmd /c \"$cmd 2>&1\""$returnVar);
  484.             }
  485.         else {
  486.             if ($this->useEscapeshellcmd{
  487.                 $cmd escapeshellcmd($cmd);
  488.             }
  489.             if (!$this->passthru{
  490.                 exec("{$this->prependCmd}$cmd 2>&1", $out, $returnVar);
  491.             } else {
  492.                 passthru("{$this->prependCmd}$cmd 2>&1", $returnVar);
  493.             }
  494.         }
  495.  
  496.         if ($returnVar > 0) {
  497.             throw new VersionControl_SVN_Exception(
  498.                 'Execution of command failed returning: ' . $returnVar
  499.                 . "\n" . implode("\n", $out),
  500.                 VersionControl_SVN_Exception::EXEC
  501.             );
  502.         }
  503.  
  504.         return $this->parseOutput($out);
  505.     }
  506.  
  507.     /**
  508.      * Handles output parsing of standard and verbose output of command.
  509.      *
  510.      * @param array $out Array of output captured by exec command in {@link run}
  511.      *
  512.      * @return  mixed   Returns output requested by fetchmode (if available), or 
  513.      *                  raw output if desired fetchmode is not available.
  514.      */
  515.     public function parseOutput($out)
  516.     {
  517.         $dir = realpath(dirname(__FILE__)) . '/Parser/XML';
  518.         switch($this->fetchmode{
  519.         case VERSIONCONTROL_SVN_FETCHMODE_ARRAY:
  520.         case VERSIONCONTROL_SVN_FETCHMODE_ASSOC:
  521.         case VERSIONCONTROL_SVN_FETCHMODE_OBJECT:
  522.             $file = $dir . '/' . ucfirst($this->commandName'.php';
  523.             if (file_exists($file)) {
  524.                 $class = 'VersionControl_SVN_Parser_XML_'
  525.                     . ucfirst($this->commandName);
  526.  
  527.                 include_once $file;
  528.                 $parser = new $class;
  529.                 $contentVar $this->commandName;
  530.  
  531.                 $parsedData $parser->getParsed(join("\n"$out));
  532.                 if ($this->fetchmode == VERSIONCONTROL_SVN_FETCHMODE_OBJECT{
  533.                     return (object) $parsedData;
  534.                 }
  535.                 return $parsedData;
  536.                 break;
  537.             }
  538.         case VERSIONCONTROL_SVN_FETCHMODE_RAW:
  539.         case VERSIONCONTROL_SVN_FETCHMODE_XML:
  540.         default:
  541.             // What you get with VERSIONCONTROL_SVN_FETCHMODE_DEFAULT
  542.             return join("\n", $out);
  543.             break;
  544.         }
  545.     }
  546. }

Documentation generated on Sat, 09 Feb 2013 12:30:09 +0000 by phpDocumentor 1.4.3. PEAR Logo Copyright © PHP Group 2004.