<?php |
<?php |
|
|
/** |
/** |
* git cat-file constant |
* git cat-file constant |
*/ |
*/ |
define('GIT_CAT_FILE','cat-file'); |
define('GIT_CAT_FILE','cat-file'); |
|
|
/** |
/** |
* git diff-tree constant |
* git diff-tree constant |
*/ |
*/ |
define('GIT_DIFF_TREE','diff-tree'); |
define('GIT_DIFF_TREE','diff-tree'); |
|
|
/** |
/** |
* git ls-tree constant |
* git ls-tree constant |
*/ |
*/ |
define('GIT_LS_TREE','ls-tree'); |
define('GIT_LS_TREE','ls-tree'); |
|
|
/** |
/** |
* git rev-list constant |
* git rev-list constant |
*/ |
*/ |
define('GIT_REV_LIST','rev-list'); |
define('GIT_REV_LIST','rev-list'); |
|
|
/** |
/** |
* git rev-parse constant |
* git rev-parse constant |
*/ |
*/ |
define('GIT_REV_PARSE','rev-parse'); |
define('GIT_REV_PARSE','rev-parse'); |
|
|
/** |
/** |
* git show-ref constant |
* git show-ref constant |
*/ |
*/ |
define('GIT_SHOW_REF','show-ref'); |
define('GIT_SHOW_REF','show-ref'); |
|
|
/** |
/** |
* git archive constant |
* git archive constant |
*/ |
*/ |
define('GIT_ARCHIVE','archive'); |
define('GIT_ARCHIVE','archive'); |
|
|
/** |
/** |
* git grep constant |
* git grep constant |
*/ |
*/ |
define('GIT_GREP','grep'); |
define('GIT_GREP','grep'); |
|
|
/** |
/** |
* git blame constant |
* git blame constant |
*/ |
*/ |
define('GIT_BLAME','blame'); |
define('GIT_BLAME','blame'); |
|
|
/** |
/** |
* git name-rev constant |
* git name-rev constant |
*/ |
*/ |
define('GIT_NAME_REV','name-rev'); |
define('GIT_NAME_REV','name-rev'); |
|
|
/** |
/** |
* git for-each-ref constant |
* git for-each-ref constant |
*/ |
*/ |
define('GIT_FOR_EACH_REF','for-each-ref'); |
define('GIT_FOR_EACH_REF','for-each-ref'); |
|
|
/** |
/** |
* Class to wrap git executable |
* Class to wrap git executable |
* |
* |
* @author Christopher Han <xiphux@gmail.com> |
* @author Christopher Han <xiphux@gmail.com> |
* @copyright Copyright (c) 2010 Christopher Han |
* @copyright Copyright (c) 2010 Christopher Han |
* @package GitPHP |
* @package GitPHP |
* @subpackage Git |
* @subpackage Git |
*/ |
*/ |
class GitPHP_GitExe implements GitPHP_Observable_Interface |
class GitPHP_GitExe implements GitPHP_Observable_Interface |
{ |
{ |
|
|
/** |
/** |
* The binary path |
* The binary path |
* |
* |
* @var string |
* @var string |
*/ |
*/ |
protected $binary; |
protected $binary; |
|
|
/** |
/** |
* The binary version |
* The binary version |
* |
* |
* @var string |
* @var string |
*/ |
*/ |
protected $version; |
protected $version; |
|
|
/** |
/** |
* Whether the version has been read |
* Whether the version has been read |
* |
* |
* @var boolean |
* @var boolean |
*/ |
*/ |
protected $versionRead = false; |
protected $versionRead = false; |
|
|
/** |
/** |
* Observers |
* Observers |
* |
* |
* @var GitPHP_Observer_Interface[] |
* @var GitPHP_Observer_Interface[] |
*/ |
*/ |
protected $observers = array(); |
protected $observers = array(); |
|
|
/** |
/** |
|
* Whether the exec function is allowed by the install |
|
* |
|
* @var null|boolean |
|
*/ |
|
protected $execAllowed = null; |
|
|
|
/** |
|
* Whether the shell_exec function is allowed by the install |
|
* |
|
* @var null|boolean |
|
*/ |
|
protected $shellExecAllowed = null; |
|
|
|
/** |
|
* Whether the popen function is allowed by the install |
|
* |
|
* @var null|boolean |
|
*/ |
|
protected $popenAllowed = null; |
|
|
|
/** |
* Constructor |
* Constructor |
* |
* |
* @param string $binary path to git binary |
* @param string $binary path to git binary |
*/ |
*/ |
public function __construct($binary = '') |
public function __construct($binary = '') |
{ |
{ |
if (empty($binary)) { |
if (empty($binary)) { |
$binary = GitPHP_GitExe::DefaultBinary(); |
$binary = GitPHP_GitExe::DefaultBinary(); |
} |
} |
$this->binary = $binary; |
$this->binary = $binary; |
} |
} |
|
|
/** |
/** |
* Executes a command |
* Executes a command |
* |
* |
* @param string $projectPath path to project |
* @param string $projectPath path to project |
* @param string $command the command to execute |
* @param string $command the command to execute |
* @param string[] $args arguments |
* @param string[] $args arguments |
* @return string result of command |
* @return string result of command |
*/ |
*/ |
public function Execute($projectPath, $command, $args) |
public function Execute($projectPath, $command, $args) |
{ |
{ |
|
if ($this->shellExecAllowed === null) { |
|
$this->shellExecAllowed = GitPHP_Util::FunctionAllowed('shell_exec'); |
|
if (!$this->shellExecAllowed) { |
|
throw new GitPHP_DisabledFunctionException('shell_exec'); |
|
} |
|
} |
|
|
$fullCommand = $this->CreateCommand($projectPath, $command, $args); |
$fullCommand = $this->CreateCommand($projectPath, $command, $args); |
|
|
$this->Log('Begin executing "' . $fullCommand . '"'); |
$this->Log('Begin executing "' . $fullCommand . '"'); |
|
|
$ret = shell_exec($fullCommand); |
$ret = shell_exec($fullCommand); |
|
|
$this->Log('Finish executing "' . $fullCommand . '"' . |
$this->Log('Finish executing "' . $fullCommand . '"' . |
"\nwith result: " . $ret); |
"\nwith result: " . $ret); |
|
|
return $ret; |
return $ret; |
} |
} |
|
|
/** |
/** |
* Opens a resource to a command |
* Opens a resource to a command |
* |
* |
* @param string $projectPath path to project |
* @param string $projectPath path to project |
* @param string $command the command to execute |
* @param string $command the command to execute |
* @param string[] $args arguments |
* @param string[] $args arguments |
* @param string $mode process open mode |
* @param string $mode process open mode |
* @return resource process handle |
* @return resource process handle |
*/ |
*/ |
public function Open($projectPath, $command, $args, $mode = 'r') |
public function Open($projectPath, $command, $args, $mode = 'r') |
{ |
{ |
|
if ($this->popenAllowed === null) { |
|
$this->popenAllowed = GitPHP_Util::FunctionAllowed('popen'); |
|
if (!$this->popenAllowed) { |
|
throw new GitPHP_DisabledFunctionException('popen'); |
|
} |
|
} |
|
|
$fullCommand = $this->CreateCommand($projectPath, $command, $args); |
$fullCommand = $this->CreateCommand($projectPath, $command, $args); |
|
|
return popen($fullCommand, $mode); |
return popen($fullCommand, $mode); |
} |
} |
|
|
/** |
/** |
* Creates a command |
* Creates a command |
* |
* |
* @param string $projectPath path to project |
* @param string $projectPath path to project |
* @param string $command the command to execute |
* @param string $command the command to execute |
* @param string[] $args arguments |
* @param string[] $args arguments |
* @return string full executable string |
* @return string full executable string |
*/ |
*/ |
protected function CreateCommand($projectPath, $command, $args) |
protected function CreateCommand($projectPath, $command, $args) |
{ |
{ |
$gitDir = ''; |
$gitDir = ''; |
if (!empty($projectPath)) { |
if (!empty($projectPath)) { |
$gitDir = '--git-dir=' . $projectPath; |
$gitDir = '--git-dir=' . escapeshellarg($projectPath); |
} |
} |
|
|
return $this->binary . ' ' . $gitDir . ' ' . $command . ' ' . implode(' ', $args); |
return $this->binary . ' ' . $gitDir . ' ' . $command . ' ' . implode(' ', $args); |
} |
} |
|
|
/** |
/** |
* Gets the binary for this executable |
* Gets the binary for this executable |
* |
* |
* @return string binary |
* @return string binary |
*/ |
*/ |
public function GetBinary() |
public function GetBinary() |
{ |
{ |
return $this->binary; |
return $this->binary; |
} |
} |
|
|
/** |
/** |
* Gets the version of the git binary |
* Gets the version of the git binary |
* |
* |
* @return string version |
* @return string version |
*/ |
*/ |
public function GetVersion() |
public function GetVersion() |
{ |
{ |
if (!$this->versionRead) |
if (!$this->versionRead) |
$this->ReadVersion(); |
$this->ReadVersion(); |
|
|
return $this->version; |
return $this->version; |
} |
} |
|
|
/** |
/** |
* Reads the git version |
* Reads the git version |
*/ |
*/ |
protected function ReadVersion() |
protected function ReadVersion() |
{ |
{ |
|
if ($this->shellExecAllowed === null) { |
|
$this->shellExecAllowed = GitPHP_Util::FunctionAllowed('shell_exec'); |
|
if (!$this->shellExecAllowed) { |
|
throw new GitPHP_DisabledFunctionException('shell_exec'); |
|
} |
|
} |
|
|
$this->versionRead = true; |
$this->versionRead = true; |
|
|
$this->version = ''; |
$this->version = ''; |
|
|
$versionCommand = $this->binary . ' --version'; |
$versionCommand = $this->binary . ' --version'; |
$ret = trim(shell_exec($versionCommand)); |
$ret = trim(shell_exec($versionCommand)); |
if (preg_match('/^git version ([0-9\.]+)$/i', $ret, $regs)) { |
if (preg_match('/^git version ([0-9\.]+)$/i', $ret, $regs)) { |
$this->version = $regs[1]; |
$this->version = $regs[1]; |
} |
} |
} |
} |
|
|
/** |
/** |
* Tests if this version of git can skip through the revision list |
* Tests if this version of git can skip through the revision list |
* |
* |
* @return boolean true if we can skip |
* @return boolean true if we can skip |
*/ |
*/ |
public function CanSkip() |
public function CanSkip() |
{ |
{ |
$version = $this->GetVersion(); |
$version = $this->GetVersion(); |
if (!empty($version)) { |
if (!empty($version)) { |
$splitver = explode('.', $version); |
$splitver = explode('.', $version); |
|
|
/* Skip only appears in git >= 1.5.0 */ |
/* Skip only appears in git >= 1.5.0 */ |
if (($splitver[0] < 1) || (($splitver[0] == 1) && ($splitver[1] < 5))) { |
if (($splitver[0] < 1) || (($splitver[0] == 1) && ($splitver[1] < 5))) { |
return false; |
return false; |
} |
} |
} |
} |
|
|
return true; |
return true; |
} |
} |
|
|
/** |
/** |
* Tests if this version of git can show the size of a blob when listing a tree |
* Tests if this version of git can show the size of a blob when listing a tree |
* |
* |
* @return true if we can show sizes |
* @return true if we can show sizes |
*/ |
*/ |
public function CanShowSizeInTree() |
public function CanShowSizeInTree() |
{ |
{ |
$version = $this->GetVersion(); |
$version = $this->GetVersion(); |
if (!empty($version)) { |
if (!empty($version)) { |
$splitver = explode('.', $version); |
$splitver = explode('.', $version); |
|
|
/* |
/* |
* ls-tree -l only appears in git 1.5.3 |
* ls-tree -l only appears in git 1.5.3 |
* (technically 1.5.3-rc0 but i'm not getting that fancy) |
* (technically 1.5.3-rc0 but i'm not getting that fancy) |
*/ |
*/ |
if (($splitver[0] < 1) || (($splitver[0] == 1) && ($splitver[1] < 5)) || (($splitver[0] == 1) && ($splitver[1] == 5) && ($splitver[2] < 3))) { |
if (($splitver[0] < 1) || (($splitver[0] == 1) && ($splitver[1] < 5)) || (($splitver[0] == 1) && ($splitver[1] == 5) && ($splitver[2] < 3))) { |
return false; |
return false; |
} |
} |
} |
} |
|
|
return true; |
return true; |
|
|
} |
} |
|
|
/** |
/** |
* Tests if this version of git has the regexp tuning option to ignore regexp case |
* Tests if this version of git has the regexp tuning option to ignore regexp case |
* |
* |
* @return true if we can ignore regexp case |
* @return true if we can ignore regexp case |
*/ |
*/ |
public function CanIgnoreRegexpCase() |
public function CanIgnoreRegexpCase() |
{ |
{ |
$version = $this->GetVersion(); |
$version = $this->GetVersion(); |
if (!empty($version)) { |
if (!empty($version)) { |
$splitver = explode('.', $version); |
$splitver = explode('.', $version); |
|
|
/* |
/* |
* regexp-ignore-case only appears in git 1.5.3 |
* regexp-ignore-case only appears in git 1.5.3 |
*/ |
*/ |
if (($splitver[0] < 1) || (($splitver[0] == 1) && ($splitver[1] < 5)) || (($splitver[0] == 1) && ($splitver[1] == 5) && ($splitver[2] < 3))) { |
if (($splitver[0] < 1) || (($splitver[0] == 1) && ($splitver[1] < 5)) || (($splitver[0] == 1) && ($splitver[1] == 5) && ($splitver[2] < 3))) { |
return false; |
return false; |
} |
} |
} |
} |
|
|
return true; |
return true; |
} |
} |
|
|
/** |
/** |
* Tests if this executable is valid |
* Tests if this executable is valid |
* |
* |
* @return boolean true if valid |
* @return boolean true if valid |
*/ |
*/ |
public function Valid() |
public function Valid() |
{ |
{ |
|
if ($this->execAllowed === null) { |
|
$this->execAllowed = GitPHP_Util::FunctionAllowed('exec'); |
|
if (!$this->execAllowed) { |
|
throw new GitPHP_DisabledFunctionException('exec'); |
|
} |
|
} |
|
|
if (empty($this->binary)) |
if (empty($this->binary)) |
return false; |
return false; |
|
|
$code = 0; |
$code = 0; |
$out = exec($this->binary . ' --version', $tmp, $code); |
$out = exec($this->binary . ' --version', $tmp, $code); |
|
|
return $code == 0; |
return $code == 0; |
} |
} |
|
|
/** |
/** |
* Add a new observer |
* Add a new observer |
* |
* |
* @param GitPHP_Observer_Interface $observer observer |
* @param GitPHP_Observer_Interface $observer observer |
*/ |
*/ |
public function AddObserver($observer) |
public function AddObserver($observer) |
{ |
{ |
if (!$observer) |
if (!$observer) |
return; |
return; |
|
|
if (array_search($observer, $this->observers) !== false) |
if (array_search($observer, $this->observers) !== false) |
return; |
return; |
|
|
$this->observers[] = $observer; |
$this->observers[] = $observer; |
} |
} |
|
|
/** |
/** |
* Remove an observer |
* Remove an observer |
* |
* |
* @param GitPHP_Observer_Interface $observer observer |
* @param GitPHP_Observer_Interface $observer observer |
*/ |
*/ |
public function RemoveObserver($observer) |
public function RemoveObserver($observer) |
{ |
{ |
if (!$observer) |
if (!$observer) |
return; |
return; |
|
|
$key = array_search($observer, $this->observers); |
$key = array_search($observer, $this->observers); |
|
|
if ($key === false) |
if ($key === false) |
return; |
return; |
|
|
unset($this->observers[$key]); |
unset($this->observers[$key]); |
} |
} |
|
|
/** |
/** |
* Log an execution |
* Log an execution |
* |
* |
* @param string $message message |
* @param string $message message |
*/ |
*/ |
private function Log($message) |
private function Log($message) |
{ |
{ |
if (empty($message)) |
if (empty($message)) |
return; |
return; |
|
|
foreach ($this->observers as $observer) { |
foreach ($this->observers as $observer) { |
$observer->ObjectChanged($this, GitPHP_Observer_Interface::LoggableChange, array($message)); |
$observer->ObjectChanged($this, GitPHP_Observer_Interface::LoggableChange, array($message)); |
} |
} |
} |
} |
|
|
/** |
/** |
* Gets the default binary for the platform |
* Gets the default binary for the platform |
* |
* |
* @return string binary |
* @return string binary |
*/ |
*/ |
public static function DefaultBinary() |
public static function DefaultBinary() |
{ |
{ |
if (GitPHP_Util::IsWindows()) { |
if (GitPHP_Util::IsWindows()) { |
// windows |
// windows |
|
|
if (GitPHP_Util::Is64Bit()) { |
if (GitPHP_Util::Is64Bit()) { |
// match x86_64 and x64 (64 bit) |
// match x86_64 and x64 (64 bit) |
// C:\Program Files (x86)\Git\bin\git.exe |
// C:\Program Files (x86)\Git\bin\git.exe |
return 'C:\\Progra~2\\Git\\bin\\git.exe'; |
return 'C:\\Progra~2\\Git\\bin\\git.exe'; |
} else { |
} else { |
// 32 bit |
// 32 bit |
// C:\Program Files\Git\bin\git.exe |
// C:\Program Files\Git\bin\git.exe |
return 'C:\\Progra~1\\Git\\bin\\git.exe'; |
return 'C:\\Progra~1\\Git\\bin\\git.exe'; |
} |
} |
} else { |
} else { |
// *nix, just use PATH |
// *nix, just use PATH |
return 'git'; |
return 'git'; |
} |
} |
} |
} |
|
|
} |
} |
|
|