src/Command/AbstractCommand.php
<?php
/**
* VersionControl_HG
* Simple OO implementation for Mercurial.
*
* PHP Version 5.4
*
* @copyright 2014 Siad Ardroumli
* @license http://www.opensource.org/licenses/mit-license.php MIT
* @link http://siad007.github.io/versioncontrol_hg
*/
namespace Siad007\VersionControl\HG\Command;
/**
* Abstract class for VersionControl_HG.
*
* This class maintains all global options and take care about getters and
* setters.
*
* @method boolean getVerbose()
* @method void setVerbose(boolean $flag)
* @method boolean getQuiet()
* @method void setQuiet(boolean $flag)
* @method boolean getNoninteractive()
* @method void setNoninteractive(boolean $flag)
* @method boolean getCwd()
* @method void setCwd(string $directory)
* @method boolean getDebug()
* @method void setDebug(boolean $flag)
* @method boolean getDebugger()
* @method void setDebugger(boolean $flag)
* @method string getEncoding()
* @method void setEncoding(string $encoding)
* @method string getEncodingmode()
* @method void setEncodingmode(string $mode)
* @method boolean getTraceback()
* @method void setTraceback(boolean $flag)
* @method boolean getTime()
* @method void setTime(boolean $flag)
* @method boolean getProfile()
* @method void setProfile(boolean $flag)
* @method boolean getVersion()
* @method void setVersion(boolean $flag)
* @method boolean getHelp()
* @method void setHelp(boolean $flag)
* @method boolean getHidden()
* @method void setHidden(boolean $flag)
* @method array getConfig()
* @method void addConfig(string $config)
*/
abstract class AbstractCommand
{
/** @var string $name */
protected $name = '';
/** @var string $hgPath */
protected $hgPath = 'hg';
/** @var string $command */
protected $command = '%s %s';
/**
* Command specific options.
*
* @var array $options
*/
protected $options = [];
/** @var array $globalOptions */
protected $globalOptions = [
'--repository' => '',
'--cwd' => '',
'--noninteractive' => false,
'--quiet' => false,
'--verbose' => false,
'--config' => [],
'--debug' => false,
'--debugger' => false,
'--encoding' => '',
'--encodingmode' => '',
'--traceback' => false,
'--time' => false,
'--profile' => false,
'--version' => false,
'--help' => false,
'--hidden' => false,
];
/**
* Get hg path.
*
* @return string
*/
public function getHgPath()
{
return $this->hgPath;
}
/**
* Set path to hg executable.
*
* @param string $path
*
* @return $this
*/
public function setHgPath($path)
{
$this->hgPath = $path;
return $this;
}
/**
* Returns a string representation for the mercurial shell command.
*
* @return string
*/
public function __toString()
{
return sprintf($this->command, $this->hgPath, $this);
}
/**
* Standard constructor.
*
* - sets the concrete commands name
* - merges the global options with the concrete commands options
*
* @param mixed $options
*/
public function __construct($options = [])
{
$this->name = $this->getCommandName();
$this->options = array_merge($this->options, $options);
}
/**
* Execute mercurial command.
*
* @return string
*
* @throws \RuntimeException
*/
public function execute()
{
$output = [];
$code = 0;
exec(sprintf($this->command, $this->hgPath, $this) . " 2>&1", $output, $code);
if ($code != 0) {
throw new \RuntimeException(
'An error occurred while using VersionControl_HG; hg returned: '
. implode(PHP_EOL, $output),
$code
);
}
return implode(PHP_EOL, $output);
}
/**
* Returns the string representation of the command.
*
* @return string
*/
public function asString()
{
return self::__toString();
}
/**
* Magic method to get option entries with a getter/setter method.
*
* @param string $name
* @param array $arguments
*
* @return boolean|array|string|self
*
* @throws \InvalidArgumentException
*/
public function __call($name, $arguments)
{
if (preg_match('~^(set|get|add)([A-Z])([a-z]*)([A-Z]?)(.*)$~', $name, $matches)) {
$match = !empty($matches[4]) ? sprintf('-%s%s', strtolower($matches[4]), $matches[5]) : '';
$property = strtolower($matches[2]) . $matches[3] . $match;
$this->options = array_merge($this->globalOptions, $this->options);
$this->doesPropertyExist($property);
$result = false;
switch ($matches[1]) {
case 'set':
$this->options["--{$property}"] = $arguments[0];
$result = $this;
break;
case 'add':
$this->options["--{$property}"][] = $arguments[0];
$result = $this;
break;
case 'get':
$result = $this->options["--{$property}"];
break;
}
return $result;
}
throw new \InvalidArgumentException('Method ' . $name . ' not exists');
}
/**
* Does property exist check.
*
* @param string $property
*
* @throws \InvalidArgumentException
*/
private function doesPropertyExist($property)
{
if (! isset($this->options["--{$property}"])) {
throw new \InvalidArgumentException('Property ' . $property . ' not exists');
}
}
/**
* Concatinates string options.
*
* @return string
*/
protected function assembleOptionString()
{
$optionString = '';
foreach ($this->options as $name => $option) {
if ($option === true) {
$optionString .= " {$name}";
} elseif (is_string($option) && $option !== '') {
$optionString .= " {$name} " . escapeshellarg($option);
} elseif (is_array($option) && !empty($option)) {
$optionString .= " {$name} " . implode(' ', $option);
}
}
return $optionString !== '' ? $optionString . '' : ' ';
}
/**
* Returns the concrete commands name.
*
* @return string
*/
private function getCommandName()
{
$className = implode('', array_slice(explode('\\', get_class($this)), -1));
$commandName = str_replace('command', '', strtolower($className));
return $commandName;
}
}