regexp-ignore-case only appears in git 1.5.3
regexp-ignore-case only appears in git 1.5.3

<?php <?php
/** /**
* GitPHP GitExe * GitPHP GitExe
* *
* 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
*/ */
   
define('GIT_CAT_FILE','cat-file'); define('GIT_CAT_FILE','cat-file');
define('GIT_DIFF_TREE','diff-tree'); define('GIT_DIFF_TREE','diff-tree');
define('GIT_LS_TREE','ls-tree'); define('GIT_LS_TREE','ls-tree');
define('GIT_REV_LIST','rev-list'); define('GIT_REV_LIST','rev-list');
define('GIT_REV_PARSE','rev-parse'); define('GIT_REV_PARSE','rev-parse');
define('GIT_SHOW_REF','show-ref'); define('GIT_SHOW_REF','show-ref');
define('GIT_ARCHIVE','archive'); define('GIT_ARCHIVE','archive');
define('GIT_GREP','grep'); define('GIT_GREP','grep');
define('GIT_BLAME','blame'); define('GIT_BLAME','blame');
define('GIT_NAME_REV','name-rev'); define('GIT_NAME_REV','name-rev');
   
/** /**
* Git Executable class * Git Executable class
* *
* @package GitPHP * @package GitPHP
* @subpackage Git * @subpackage Git
*/ */
class GitPHP_GitExe class GitPHP_GitExe
{ {
/** /**
* project * project
* *
* Stores the project internally * Stores the project internally
* *
* @access protected * @access protected
*/ */
protected $project; protected $project;
   
/** /**
* bin * bin
* *
* Stores the binary path internally * Stores the binary path internally
* *
* @access protected * @access protected
*/ */
protected $binary; protected $binary;
   
/** /**
* __construct * __construct
* *
* Constructor * Constructor
* *
* @param string $binary path to git binary * @param string $binary path to git binary
* @param mixed $project project to operate on * @param mixed $project project to operate on
* @return mixed git executable class * @return mixed git executable class
*/ */
public function __construct($project = null) public function __construct($project = null)
{ {
$binary = GitPHP_Config::GetInstance()->GetValue('gitbin'); $binary = GitPHP_Config::GetInstance()->GetValue('gitbin');
if (empty($binary)) { if (empty($binary)) {
// try to pick a reasonable default // try to pick a reasonable default
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
$this->binary = 'C:\\Progra~1\\Git\\bin\\git.exe'; $this->binary = 'C:\\Progra~1\\Git\\bin\\git.exe';
} else { } else {
$this->binary = 'git'; $this->binary = 'git';
} }
} else { } else {
$this->binary = $binary; $this->binary = $binary;
} }
   
$this->SetProject($project); $this->SetProject($project);
} }
   
/** /**
* SetProject * SetProject
* *
* Sets the project for this executable * Sets the project for this executable
* *
* @param mixed $project project to set * @param mixed $project project to set
*/ */
public function SetProject($project = null) public function SetProject($project = null)
{ {
$this->project = $project; $this->project = $project;
} }
   
/** /**
* Execute * Execute
* *
* Executes a command * Executes a command
* *
* @param string $command the command to execute * @param string $command the command to execute
* @param array $args arguments * @param array $args arguments
* @return string result of command * @return string result of command
*/ */
public function Execute($command, $args) public function Execute($command, $args)
{ {
$gitDir = ''; $gitDir = '';
if ($this->project) { if ($this->project) {
$gitDir = '--git-dir=' . $this->project->GetPath(); $gitDir = '--git-dir=' . $this->project->GetPath();
} }
$fullCommand = $this->binary . ' ' . $gitDir . ' ' . $command . ' ' . implode(' ', $args); $fullCommand = $this->binary . ' ' . $gitDir . ' ' . $command . ' ' . implode(' ', $args);
   
GitPHP_Log::GetInstance()->Log('Begin executing "' . $fullCommand . '"'); GitPHP_Log::GetInstance()->Log('Begin executing "' . $fullCommand . '"');
   
$ret = shell_exec($fullCommand); $ret = shell_exec($fullCommand);
   
GitPHP_Log::GetInstance()->Log('Finish executing "' . $fullCommand . '"'); GitPHP_Log::GetInstance()->Log('Finish executing "' . $fullCommand . '"');
   
return $ret; return $ret;
} }
   
/** /**
* GetBinary * GetBinary
* *
* Gets the binary for this executable * Gets the binary for this executable
* *
* @return string binary * @return string binary
* @access public * @access public
*/ */
public function GetBinary() public function GetBinary()
{ {
return $this->binary; return $this->binary;
} }
   
/** /**
* GetVersion * GetVersion
* *
* Gets the version of the git binary * Gets the version of the git binary
* *
* @return string version * @return string version
* @access public * @access public
*/ */
public function GetVersion() public function GetVersion()
{ {
$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)) {
return $regs[1]; return $regs[1];
} }
return ''; return '';
} }
   
/** /**
* CanSkip * CanSkip
* *
* Tests if this version of git can skip through the revision list * Tests if this version of git can skip through the revision list
* *
* @access public * @access public
* @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;
} }
   
/** /**
* CanShowSizeInTree * CanShowSizeInTree
* *
* 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
* *
* @access public * @access public
* @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;
   
} }
   
  /**
  * CanIgnoreRegexpCase
  *
  * Tests if this version of git has the regexp tuning option to ignore regexp case
  *
  * @access public
  * @return true if we can ignore regexp case
  */
  public function CanIgnoreRegexpCase()
  {
  $version = $this->GetVersion();
  if (!empty($version)) {
  $splitver = explode('.', $version);
   
  /*
  * 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))) {
  return false;
  }
  }
   
  return true;
  }
   
} }
   
<?php <?php
/** /**
* GitPHP Project * GitPHP Project
* *
* Represents a single git project * Represents a single git project
* *
* @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
*/ */
   
require_once(GITPHP_GITOBJECTDIR . 'GitExe.class.php'); require_once(GITPHP_GITOBJECTDIR . 'GitExe.class.php');
require_once(GITPHP_GITOBJECTDIR . 'Commit.class.php'); require_once(GITPHP_GITOBJECTDIR . 'Commit.class.php');
require_once(GITPHP_GITOBJECTDIR . 'Head.class.php'); require_once(GITPHP_GITOBJECTDIR . 'Head.class.php');
require_once(GITPHP_GITOBJECTDIR . 'Tag.class.php'); require_once(GITPHP_GITOBJECTDIR . 'Tag.class.php');
   
/** /**
* Project class * Project class
* *
* @package GitPHP * @package GitPHP
* @subpackage Git * @subpackage Git
*/ */
class GitPHP_Project class GitPHP_Project
{ {
   
/** /**
* project * project
* *
* Stores the project internally * Stores the project internally
* *
* @access protected * @access protected
*/ */
protected $project; protected $project;
   
/** /**
* owner * owner
* *
* Stores the owner internally * Stores the owner internally
* *
* @access protected * @access protected
*/ */
protected $owner = ""; protected $owner = "";
   
/** /**
* readOwner * readOwner
* *
* Stores whether the file owner has been read * Stores whether the file owner has been read
* *
* @access protected * @access protected
*/ */
protected $readOwner = false; protected $readOwner = false;
   
/** /**
* description * description
* *
* Stores the description internally * Stores the description internally
* *
* @access protected * @access protected
*/ */
protected $description; protected $description;
   
/** /**
* readDescription * readDescription
* *
* Stores whether the description has been * Stores whether the description has been
* read from the file yet * read from the file yet
* *
* @access protected * @access protected
*/ */
protected $readDescription = false; protected $readDescription = false;
   
/** /**
* category * category
* *
* Stores the category internally * Stores the category internally
* *
* @access protected * @access protected
*/ */
protected $category = ''; protected $category = '';
   
/** /**
* head * head
* *
* Stores the head hash internally * Stores the head hash internally
* *
* @access protected * @access protected
*/ */
protected $head; protected $head;
   
/** /**
* readHeadRef * readHeadRef
* *
* Stores whether the head ref has been read yet * Stores whether the head ref has been read yet
* *
* @access protected * @access protected
*/ */
protected $readHeadRef = false; protected $readHeadRef = false;
   
/** /**
* heads * heads
* *
* Stores the heads for the project * Stores the heads for the project
* *
* @access protected * @access protected
*/ */
protected $heads = array(); protected $heads = array();
   
/** /**
* readHeads * readHeads
* *
* Stores whether heads have been read yet * Stores whether heads have been read yet
* *
* @access protected * @access protected
*/ */
protected $readHeads = false; protected $readHeads = false;
   
/** /**
* tags * tags
* *
* Stores the tags for the project * Stores the tags for the project
* *
* @access protected * @access protected
*/ */
protected $tags = array(); protected $tags = array();
   
/** /**
* readTags * readTags
* *
* Stores whether tags have been read yet * Stores whether tags have been read yet
* *
* @access protected * @access protected
*/ */
protected $readTags = false; protected $readTags = false;
   
/** /**
* cloneUrl * cloneUrl
* *
* Stores the clone url internally * Stores the clone url internally
* *
* @access protected * @access protected
*/ */
protected $cloneUrl = null; protected $cloneUrl = null;
   
/** /**
* pushUrl * pushUrl
* *
* Stores the push url internally * Stores the push url internally
* *
* @access protected * @access protected
*/ */
protected $pushUrl = null; protected $pushUrl = null;
   
/** /**
* commitCache * commitCache
* *
* Caches fetched commit objects in case of * Caches fetched commit objects in case of
* repeated requests for the same object * repeated requests for the same object
* *
* @access protected * @access protected
*/ */
protected $commitCache = array(); protected $commitCache = array();
   
/** /**
* blobCache * blobCache
* *
* Caches blob objects in case of * Caches blob objects in case of
* repeated requests * repeated requests
* *
* @access protected * @access protected
*/ */
protected $blobCache = array(); protected $blobCache = array();
   
/** /**
* treeCache * treeCache
* *
* Caches tree objects in case of repeated requests * Caches tree objects in case of repeated requests
* *
* @access protected * @access protected
*/ */
protected $treeCache = array(); protected $treeCache = array();
   
/** /**
* __construct * __construct
* *
* Class constructor * Class constructor
* *
* @access public * @access public
* @throws Exception if project is invalid or outside of projectroot * @throws Exception if project is invalid or outside of projectroot
*/ */
public function __construct($project) public function __construct($project)
{ {
$this->SetProject($project); $this->SetProject($project);
} }
   
/** /**
* SetProject * SetProject
* *
* Attempts to set the project * Attempts to set the project
* *
* @access private * @access private
* @throws Exception if project is invalid or outside of projectroot * @throws Exception if project is invalid or outside of projectroot
*/ */
private function SetProject($project) private function SetProject($project)
{ {
$projectRoot = GitPHP_Config::GetInstance()->GetValue('projectroot'); $projectRoot = GitPHP_Config::GetInstance()->GetValue('projectroot');
$realProjectRoot = realpath($projectRoot); $realProjectRoot = realpath($projectRoot);
$path = $projectRoot . $project; $path = $projectRoot . $project;
$fullPath = realpath($path); $fullPath = realpath($path);
   
if (!is_dir($fullPath)) { if (!is_dir($fullPath)) {
throw new Exception(sprintf(GitPHP_Resource::GetInstance()->translate('%1$s is not a directory'), $project)); throw new Exception(sprintf(GitPHP_Resource::GetInstance()->translate('%1$s is not a directory'), $project));
} }
   
if (!is_file($fullPath . '/HEAD')) { if (!is_file($fullPath . '/HEAD')) {
throw new Exception(sprintf(GitPHP_Resource::GetInstance()->translate('%1$s is not a git repository'), $project)); throw new Exception(sprintf(GitPHP_Resource::GetInstance()->translate('%1$s is not a git repository'), $project));
} }
   
if (preg_match('/(^|\/)\.{0,2}(\/|$)/', $project)) { if (preg_match('/(^|\/)\.{0,2}(\/|$)/', $project)) {
throw new Exception(sprintf(GitPHP_Resource::GetInstance()->translate('%1$s is attempting directory traversal'), $project)); throw new Exception(sprintf(GitPHP_Resource::GetInstance()->translate('%1$s is attempting directory traversal'), $project));
} }
   
$pathPiece = substr($fullPath, 0, strlen($realProjectRoot)); $pathPiece = substr($fullPath, 0, strlen($realProjectRoot));
   
if ((!is_link($path)) && (strcmp($pathPiece, $realProjectRoot) !== 0)) { if ((!is_link($path)) && (strcmp($pathPiece, $realProjectRoot) !== 0)) {
throw new Exception(sprintf(GitPHP_Resource::GetInstance()->translate('%1$s is outside of the projectroot'), $project)); throw new Exception(sprintf(GitPHP_Resource::GetInstance()->translate('%1$s is outside of the projectroot'), $project));
} }
   
$this->project = $project; $this->project = $project;
   
} }
   
/** /**
* GetOwner * GetOwner
* *
* Gets the project's owner * Gets the project's owner
* *
* @access public * @access public
* @return string project owner * @return string project owner
*/ */
public function GetOwner() public function GetOwner()
{ {
if (empty($this->owner) && !$this->readOwner) { if (empty($this->owner) && !$this->readOwner) {
$uid = fileowner($this->GetPath()); $uid = fileowner($this->GetPath());
if ($uid > 0) { if ($uid > 0) {
$data = posix_getpwuid($uid); $data = posix_getpwuid($uid);
if (isset($data['gecos']) && !empty($data['gecos'])) { if (isset($data['gecos']) && !empty($data['gecos'])) {
$this->owner = $data['gecos']; $this->owner = $data['gecos'];
} elseif (isset($data['name']) && !empty($data['name'])) { } elseif (isset($data['name']) && !empty($data['name'])) {
$this->owner = $data['name']; $this->owner = $data['name'];
} }
} }
$this->readOwner = true; $this->readOwner = true;
} }
return $this->owner; return $this->owner;
} }
   
/** /**
* SetOwner * SetOwner
* *
* Sets the project's owner (from an external source) * Sets the project's owner (from an external source)
* *
* @access public * @access public
* @param string $owner the owner * @param string $owner the owner
*/ */
public function SetOwner($owner) public function SetOwner($owner)
{ {
$this->owner = $owner; $this->owner = $owner;
} }
   
/** /**
* GetProject * GetProject
* *
* Gets the project * Gets the project
* *
* @access public * @access public
* @return string the project * @return string the project
*/ */
public function GetProject() public function GetProject()
{ {
return $this->project; return $this->project;
} }
   
/** /**
* GetSlug * GetSlug
* *
* Gets the project as a filename/url friendly slug * Gets the project as a filename/url friendly slug
* *
* @access public * @access public
* @return string the slug * @return string the slug
*/ */
public function GetSlug() public function GetSlug()
{ {
$from = array( $from = array(
'/', '/',
'.git' '.git'
); );
$to = array( $to = array(
'-', '-',
'' ''
); );
return str_replace($from, $to, $this->project); return str_replace($from, $to, $this->project);
} }
   
/** /**
* GetPath * GetPath
* *
* Gets the full project path * Gets the full project path
* *
* @access public * @access public
* @return string project path * @return string project path
*/ */
public function GetPath() public function GetPath()
{ {
return GitPHP_Config::GetInstance()->GetValue('projectroot') . $this->project; return GitPHP_Config::GetInstance()->GetValue('projectroot') . $this->project;
} }
   
/** /**
* GetDescription * GetDescription
* *
* Gets the project description * Gets the project description
* *
* @access public * @access public
* @param $trim length to trim description to (0 for no trim) * @param $trim length to trim description to (0 for no trim)
* @return string project description * @return string project description
*/ */
public function GetDescription($trim = 0) public function GetDescription($trim = 0)
{ {
if (!$this->readDescription) { if (!$this->readDescription) {
$this->description = file_get_contents($this->GetPath() . '/description'); $this->description = file_get_contents($this->GetPath() . '/description');
} }
if (($trim > 0) && (strlen($this->description) > $trim)) { if (($trim > 0) && (strlen($this->description) > $trim)) {
return substr($this->description, 0, $trim) . '…'; return substr($this->description, 0, $trim) . '…';
} }
   
return $this->description; return $this->description;
} }
   
/** /**
* SetDescription * SetDescription
* *
* Overrides the project description * Overrides the project description
* *
* @access public * @access public
* @param string $descr description * @param string $descr description
*/ */
public function SetDescription($descr) public function SetDescription($descr)
{ {
$this->description = $descr; $this->description = $descr;
$this->readDescription = true; $this->readDescription = true;
} }
   
/** /**
* GetDaemonEnabled * GetDaemonEnabled
* *
* Returns whether gitdaemon is allowed for this project * Returns whether gitdaemon is allowed for this project
* *
* @access public * @access public
* @return boolean git-daemon-export-ok? * @return boolean git-daemon-export-ok?
*/ */
public function GetDaemonEnabled() public function GetDaemonEnabled()
{ {
return file_exists($this->GetPath() . '/git-daemon-export-ok'); return file_exists($this->GetPath() . '/git-daemon-export-ok');
} }
   
/** /**
* GetCategory * GetCategory
* *
* Gets the project's category * Gets the project's category
* *
* @access public * @access public
* @return string category * @return string category
*/ */
public function GetCategory() public function GetCategory()
{ {
return $this->category; return $this->category;
} }
   
/** /**
* SetCategory * SetCategory
* *
* Sets the project's category * Sets the project's category
* *
* @access public * @access public
* @param string $category category * @param string $category category
*/ */
public function SetCategory($category) public function SetCategory($category)
{ {
$this->category = $category; $this->category = $category;
} }
   
/** /**
* GetCloneUrl * GetCloneUrl
* *
* Gets the clone URL for this repository, if specified * Gets the clone URL for this repository, if specified
* *
* @access public * @access public
* @return string clone url * @return string clone url
*/ */
public function GetCloneUrl() public function GetCloneUrl()
{ {
if ($this->cloneUrl !== null) if ($this->cloneUrl !== null)
return $this->cloneUrl; return $this->cloneUrl;
   
$cloneurl = GitPHP_Config::GetInstance()->GetValue('cloneurl', ''); $cloneurl = GitPHP_Config::GetInstance()->GetValue('cloneurl', '');
if (!empty($cloneurl)) if (!empty($cloneurl))
$cloneurl .= $this->project; $cloneurl .= $this->project;
return $cloneurl; return $cloneurl;
} }
   
/** /**
* SetCloneUrl * SetCloneUrl
* *
* Overrides the clone URL for this repository * Overrides the clone URL for this repository
* *
* @access public * @access public
* @param string $cUrl clone url * @param string $cUrl clone url
*/ */
public function SetCloneUrl($cUrl) public function SetCloneUrl($cUrl)
{ {
$this->cloneUrl = $cUrl; $this->cloneUrl = $cUrl;
} }
   
/** /**
* GetPushUrl * GetPushUrl
* *
* Gets the push URL for this repository, if specified * Gets the push URL for this repository, if specified
* *
* @access public * @access public
* @return string push url * @return string push url
*/ */
public function GetPushUrl() public function GetPushUrl()
{ {
if ($this->pushUrl !== null) if ($this->pushUrl !== null)
return $this->pushUrl; return $this->pushUrl;
   
$pushurl = GitPHP_Config::GetInstance()->GetValue('pushurl', ''); $pushurl = GitPHP_Config::GetInstance()->GetValue('pushurl', '');
if (!empty($pushurl)) if (!empty($pushurl))
$pushurl .= $this->project; $pushurl .= $this->project;
return $pushurl; return $pushurl;
} }
   
/** /**
* SetPushUrl * SetPushUrl
* *
* Overrides the push URL for this repository * Overrides the push URL for this repository
* *
* @access public * @access public
* @param string $pUrl push url * @param string $pUrl push url
*/ */
public function SetPushUrl($pUrl) public function SetPushUrl($pUrl)
{ {
$this->pushUrl = $pUrl; $this->pushUrl = $pUrl;
} }
   
/** /**
* GetHeadCommit * GetHeadCommit
* *
* Gets the head commit for this project * Gets the head commit for this project
* Shortcut for getting the tip commit of the HEAD branch * Shortcut for getting the tip commit of the HEAD branch
* *
* @access public * @access public
* @return mixed head commit * @return mixed head commit
*/ */
public function GetHeadCommit() public function GetHeadCommit()
{ {
if (!$this->readHeadRef) if (!$this->readHeadRef)
$this->ReadHeadCommit(); $this->ReadHeadCommit();
   
return $this->GetCommit($this->head); return $this->GetCommit($this->head);
} }
   
/** /**
* ReadHeadCommit * ReadHeadCommit
* *
* Reads the head commit hash * Reads the head commit hash
* *
* @access protected * @access protected
*/ */
public function ReadHeadCommit() public function ReadHeadCommit()
{ {
$this->readHeadRef = true; $this->readHeadRef = true;
   
$exe = new GitPHP_GitExe($this); $exe = new GitPHP_GitExe($this);
$args = array(); $args = array();
$args[] = '--verify'; $args[] = '--verify';
$args[] = 'HEAD'; $args[] = 'HEAD';
$this->head = trim($exe->Execute(GIT_REV_PARSE, $args)); $this->head = trim($exe->Execute(GIT_REV_PARSE, $args));
} }
   
/** /**
* GetCommit * GetCommit
* *
* Get a commit for this project * Get a commit for this project
* *
* @access public * @access public
*/ */
public function GetCommit($hash) public function GetCommit($hash)
{ {
if (empty($hash)) if (empty($hash))
return null; return null;
   
if ($hash === 'HEAD') if ($hash === 'HEAD')
return $this->GetHeadCommit(); return $this->GetHeadCommit();
   
if (substr_compare($hash, 'refs/heads/', 0, 11) === 0) { if (substr_compare($hash, 'refs/heads/', 0, 11) === 0) {
$head = $this->GetHead(substr($hash, 11)); $head = $this->GetHead(substr($hash, 11));
if ($head != null) if ($head != null)
return $head->GetCommit(); return $head->GetCommit();
} else if (substr_compare($hash, 'refs/tags/', 0, 10) === 0) { } else if (substr_compare($hash, 'refs/tags/', 0, 10) === 0) {
$tag = $this->GetTag(substr($hash, 10)); $tag = $this->GetTag(substr($hash, 10));
if ($tag != null) { if ($tag != null) {
$obj = $tag->GetObject(); $obj = $tag->GetObject();
if ($obj != null) { if ($obj != null) {
return $obj; return $obj;
} }
} }
} }
   
if (!isset($this->commitCache[$hash])) if (!isset($this->commitCache[$hash]))
$this->commitCache[$hash] = new GitPHP_Commit($this, $hash); $this->commitCache[$hash] = new GitPHP_Commit($this, $hash);
   
return $this->commitCache[$hash]; return $this->commitCache[$hash];
} }
   
/** /**
* CompareProject * CompareProject
* *
* Compares two projects by project name * Compares two projects by project name
* *
* @access public * @access public
* @static * @static
* @param mixed $a first project * @param mixed $a first project
* @param mixed $b second project * @param mixed $b second project
* @return integer comparison result * @return integer comparison result
*/ */
public static function CompareProject($a, $b) public static function CompareProject($a, $b)
{ {
$catCmp = strcmp($a->GetCategory(), $b->GetCategory()); $catCmp = strcmp($a->GetCategory(), $b->GetCategory());
if ($catCmp !== 0) if ($catCmp !== 0)
return $catCmp; return $catCmp;
   
return strcmp($a->GetProject(), $b->GetProject()); return strcmp($a->GetProject(), $b->GetProject());
} }
   
/** /**
* CompareDescription * CompareDescription
* *
* Compares two projects by description * Compares two projects by description
* *
* @access public * @access public
* @static * @static
* @param mixed $a first project * @param mixed $a first project
* @param mixed $b second project * @param mixed $b second project
* @return integer comparison result * @return integer comparison result
*/ */
public static function CompareDescription($a, $b) public static function CompareDescription($a, $b)
{ {
$catCmp = strcmp($a->GetCategory(), $b->GetCategory()); $catCmp = strcmp($a->GetCategory(), $b->GetCategory());
if ($catCmp !== 0) if ($catCmp !== 0)
return $catCmp; return $catCmp;
   
return strcmp($a->GetDescription(), $b->GetDescription()); return strcmp($a->GetDescription(), $b->GetDescription());
} }
   
/** /**
* CompareOwner * CompareOwner
* *
* Compares two projects by owner * Compares two projects by owner
* *
* @access public * @access public
* @static * @static
* @param mixed $a first project * @param mixed $a first project
* @param mixed $b second project * @param mixed $b second project
* @return integer comparison result * @return integer comparison result
*/ */
public static function CompareOwner($a, $b) public static function CompareOwner($a, $b)
{ {
$catCmp = strcmp($a->GetCategory(), $b->GetCategory()); $catCmp = strcmp($a->GetCategory(), $b->GetCategory());
if ($catCmp !== 0) if ($catCmp !== 0)
return $catCmp; return $catCmp;
   
return strcmp($a->GetOwner(), $b->GetOwner()); return strcmp($a->GetOwner(), $b->GetOwner());
} }
   
/** /**
* CompareAge * CompareAge
* *
* Compares two projects by age * Compares two projects by age
* *
* @access public * @access public
* @static * @static
* @param mixed $a first project * @param mixed $a first project
* @param mixed $b second project * @param mixed $b second project
* @return integer comparison result * @return integer comparison result
*/ */
public static function CompareAge($a, $b) public static function CompareAge($a, $b)
{ {
$catCmp = strcmp($a->GetCategory(), $b->GetCategory()); $catCmp = strcmp($a->GetCategory(), $b->GetCategory());
if ($catCmp !== 0) if ($catCmp !== 0)
return $catCmp; return $catCmp;
   
$aCommit = $a->GetHeadCommit(); $aCommit = $a->GetHeadCommit();
$bCommit = $b->GetHeadCommit(); $bCommit = $b->GetHeadCommit();
   
if (($aCommit == null) && ($bCommit == null)) if (($aCommit == null) && ($bCommit == null))
return 0; return 0;
else if ($aCommit == null) else if ($aCommit == null)
return 1; return 1;
else if ($bCommit == null) else if ($bCommit == null)
return -1; return -1;
   
if ($aCommit->GetAge() === $bCommit->GetAge()) if ($aCommit->GetAge() === $bCommit->GetAge())
return 0; return 0;
return ($aCommit->GetAge() < $bCommit->GetAge() ? -1 : 1); return ($aCommit->GetAge() < $bCommit->GetAge() ? -1 : 1);
} }
   
/** /**
* GetTags * GetTags
* *
* Gets list of tags for this project * Gets list of tags for this project
* *
* @access public * @access public
* @return array array of tags * @return array array of tags
*/ */
public function GetTags() public function GetTags()
{ {
if (!$this->readTags) if (!$this->readTags)
$this->ReadTagList(); $this->ReadTagList();
   
return $this->tags; return $this->tags;
} }
   
/** /**
* GetTag * GetTag
* *
* Gets a single tag * Gets a single tag
* *
* @access public * @access public
* @param string $tag tag to find * @param string $tag tag to find
* @return mixed tag object * @return mixed tag object
*/ */
public function GetTag($tag) public function GetTag($tag)
{ {
if (empty($tag)) if (empty($tag))
return null; return null;
   
if (!$this->readTags) if (!$this->readTags)
$this->ReadTagList(); $this->ReadTagList();
   
if (isset($this->tags[$tag])) if (isset($this->tags[$tag]))
return $this->tags[$tag]; return $this->tags[$tag];
   
return null; return null;
} }
   
/** /**
* ReadTagList * ReadTagList
* *
* Reads tag list * Reads tag list
* *
* @access protected * @access protected
*/ */
protected function ReadTagList() protected function ReadTagList()
{ {
$this->readTags = true; $this->readTags = true;
   
$exe = new GitPHP_GitExe($this); $exe = new GitPHP_GitExe($this);
$args = array(); $args = array();
$args[] = '--tags'; $args[] = '--tags';
$args[] = '--dereference'; $args[] = '--dereference';
$ret = $exe->Execute(GIT_SHOW_REF, $args); $ret = $exe->Execute(GIT_SHOW_REF, $args);
unset($exe); unset($exe);
   
$lines = explode("\n", $ret); $lines = explode("\n", $ret);
   
foreach ($lines as $line) { foreach ($lines as $line) {
if (preg_match('/^([0-9a-fA-F]{40}) refs\/tags\/([^^]+)(\^{})?$/', $line, $regs)) { if (preg_match('/^([0-9a-fA-F]{40}) refs\/tags\/([^^]+)(\^{})?$/', $line, $regs)) {
try { try {
if ((!empty($regs[3])) && ($regs[3] == '^{}')) { if ((!empty($regs[3])) && ($regs[3] == '^{}')) {
$derefCommit = $this->GetCommit($regs[1]); $derefCommit = $this->GetCommit($regs[1]);
if ($derefCommit && isset($this->tags[$regs[2]])) { if ($derefCommit && isset($this->tags[$regs[2]])) {
$this->tags[$regs[2]]->SetCommit($derefCommit); $this->tags[$regs[2]]->SetCommit($derefCommit);
} }
} else { } else {
$this->tags[$regs[2]] = new GitPHP_Tag($this, $regs[2], $regs[1]); $this->tags[$regs[2]] = new GitPHP_Tag($this, $regs[2], $regs[1]);
} }
} catch (Exception $e) { } catch (Exception $e) {
} }
} }
} }
   
uasort($this->tags, array('GitPHP_Tag', 'CompareAge')); uasort($this->tags, array('GitPHP_Tag', 'CompareAge'));
} }
   
/** /**
* GetHeads * GetHeads
* *
* Gets list of heads for this project * Gets list of heads for this project
* *
* @access public * @access public
* @return array array of heads * @return array array of heads
*/ */
public function GetHeads() public function GetHeads()
{ {
if (!$this->readHeads) if (!$this->readHeads)
$this->ReadHeadList(); $this->ReadHeadList();
   
return $this->heads; return $this->heads;
} }
   
/** /**
* GetHead * GetHead
* *
* Gets a single head * Gets a single head
* *
* @access public * @access public
* @param string $head head to find * @param string $head head to find
* @return mixed head object * @return mixed head object
*/ */
public function GetHead($head) public function GetHead($head)
{ {
if (empty($head)) if (empty($head))
return null; return null;
   
if (!$this->readHeads) if (!$this->readHeads)
$this->ReadHeadList(); $this->ReadHeadList();
   
foreach ($this->heads as $h) { foreach ($this->heads as $h) {
if ($h->GetName() === $head) { if ($h->GetName() === $head) {
return $h; return $h;
} }
} }
return null; return null;
} }
   
/** /**
* ReadHeadList * ReadHeadList
* *
* Reads head list * Reads head list
* *
* @access protected * @access protected
*/ */
protected function ReadHeadList() protected function ReadHeadList()
{ {
$this->readHeads = true; $this->readHeads = true;
   
$exe = new GitPHP_GitExe($this); $exe = new GitPHP_GitExe($this);
$args = array(); $args = array();
$args[] = '--heads'; $args[] = '--heads';
$ret = $exe->Execute(GIT_SHOW_REF, $args); $ret = $exe->Execute(GIT_SHOW_REF, $args);
unset($exe); unset($exe);
   
$lines = explode("\n", $ret); $lines = explode("\n", $ret);
   
foreach ($lines as $line) { foreach ($lines as $line) {
if (preg_match('/^([0-9a-fA-F]{40}) refs\/heads\/(.+)$/', $line, $regs)) { if (preg_match('/^([0-9a-fA-F]{40}) refs\/heads\/(.+)$/', $line, $regs)) {
try { try {
$this->heads[] = new GitPHP_Head($this, $regs[2], $regs[1]); $this->heads[] = new GitPHP_Head($this, $regs[2], $regs[1]);
} catch (Exception $e) { } catch (Exception $e) {
} }
} }
} }
   
usort($this->heads, array('GitPHP_Head', 'CompareAge')); usort($this->heads, array('GitPHP_Head', 'CompareAge'));
   
} }
   
/** /**
* GetLogHash * GetLogHash
* *
* Gets log entries as an array of hashes * Gets log entries as an array of hashes
* *
* @access public * @access public
* @param string $hash hash to start the log at * @param string $hash hash to start the log at
* @param integer $count number of entries to get * @param integer $count number of entries to get
* @param integer $skip number of entries to skip * @param integer $skip number of entries to skip
* @return array array of hashes * @return array array of hashes
*/ */
public function GetLogHash($hash, $count = 50, $skip = 0) public function GetLogHash($hash, $count = 50, $skip = 0)
{ {
return $this->RevList($hash, $count, $skip); return $this->RevList($hash, $count, $skip);
} }
   
/** /**
* GetLog * GetLog
* *
* Gets log entries as an array of commit objects * Gets log entries as an array of commit objects
* *
* @access public * @access public
* @param string $hash hash to start the log at * @param string $hash hash to start the log at
* @param integer $count number of entries to get * @param integer $count number of entries to get
* @param integer $skip number of entries to skip * @param integer $skip number of entries to skip
* @return array array of commit objects * @return array array of commit objects
*/ */
public function GetLog($hash, $count = 50, $skip = 0) public function GetLog($hash, $count = 50, $skip = 0)
{ {
$log = $this->GetLogHash($hash, $count, $skip); $log = $this->GetLogHash($hash, $count, $skip);
$len = count($log); $len = count($log);
for ($i = 0; $i < $len; ++$i) { for ($i = 0; $i < $len; ++$i) {
$log[$i] = $this->GetCommit($log[$i]); $log[$i] = $this->GetCommit($log[$i]);
} }
return $log; return $log;
} }
   
/** /**
* GetBlob * GetBlob
* *
* Gets a blob from this project * Gets a blob from this project
* *
* @access public * @access public
* @param string $hash blob hash * @param string $hash blob hash
*/ */
public function GetBlob($hash) public function GetBlob($hash)
{ {
if (empty($hash)) if (empty($hash))
return null; return null;
   
if (!isset($this->blobCache[$hash])) if (!isset($this->blobCache[$hash]))
$this->blobCache[$hash] = new GitPHP_Blob($this, $hash); $this->blobCache[$hash] = new GitPHP_Blob($this, $hash);
   
return $this->blobCache[$hash]; return $this->blobCache[$hash];
} }
   
/** /**
* GetTree * GetTree
* *
* Gets a tree from this project * Gets a tree from this project
* *
* @access public * @access public
* @param string $hash tree hash * @param string $hash tree hash
*/ */
public function GetTree($hash) public function GetTree($hash)
{ {
if (empty($hash)) if (empty($hash))
return null; return null;
   
if (!isset($this->treeCache[$hash])) if (!isset($this->treeCache[$hash]))
$this->treeCache[$hash] = new GitPHP_Tree($this, $hash); $this->treeCache[$hash] = new GitPHP_Tree($this, $hash);
   
return $this->treeCache[$hash]; return $this->treeCache[$hash];
} }
   
/** /**
* SearchCommit * SearchCommit
* *
* Gets a list of commits with commit messages matching the given pattern * Gets a list of commits with commit messages matching the given pattern
* *
* @access public * @access public
* @param string $pattern search pattern * @param string $pattern search pattern
* @param string $hash hash to start searching from * @param string $hash hash to start searching from
* @param integer $count number of results to get * @param integer $count number of results to get
* @param integer $skip number of results to skip * @param integer $skip number of results to skip
* @return array array of matching commits * @return array array of matching commits
*/ */
public function SearchCommit($pattern, $hash = 'HEAD', $count = 50, $skip = 0) public function SearchCommit($pattern, $hash = 'HEAD', $count = 50, $skip = 0)
{ {
if (empty($pattern)) if (empty($pattern))
return; return;
   
$args = array(); $args = array();
$args[] = '--regexp-ignore-case';  
  $exe = new GitPHP_GitExe($this);
  if ($exe->CanIgnoreRegexpCase())
  $args[] = '--regexp-ignore-case';
  unset($exe);
   
$args[] = '--grep=\'' . $pattern . '\''; $args[] = '--grep=\'' . $pattern . '\'';
   
$ret = $this->RevList($hash, $count, $skip, $args); $ret = $this->RevList($hash, $count, $skip, $args);
$len = count($ret); $len = count($ret);
   
for ($i = 0; $i < $len; ++$i) { for ($i = 0; $i < $len; ++$i) {
$ret[$i] = $this->GetCommit($ret[$i]); $ret[$i] = $this->GetCommit($ret[$i]);
} }
return $ret; return $ret;
} }
   
/** /**
* SearchAuthor * SearchAuthor
* *
* Gets a list of commits with authors matching the given pattern * Gets a list of commits with authors matching the given pattern
* *
* @access public * @access public
* @param string $pattern search pattern * @param string $pattern search pattern
* @param string $hash hash to start searching from * @param string $hash hash to start searching from
* @param integer $count number of results to get * @param integer $count number of results to get
* @param integer $skip number of results to skip * @param integer $skip number of results to skip
* @return array array of matching commits * @return array array of matching commits
*/ */
public function SearchAuthor($pattern, $hash = 'HEAD', $count = 50, $skip = 0) public function SearchAuthor($pattern, $hash = 'HEAD', $count = 50, $skip = 0)
{ {
if (empty($pattern)) if (empty($pattern))
return; return;
   
$args = array(); $args = array();
$args[] = '--regexp-ignore-case';  
  $exe = new GitPHP_GitExe($this);
  if ($exe->CanIgnoreRegexpCase())
  $args[] = '--regexp-ignore-case';
  unset($exe);
   
$args[] = '--author=\'' . $pattern . '\''; $args[] = '--author=\'' . $pattern . '\'';
   
$ret = $this->RevList($hash, $count, $skip, $args); $ret = $this->RevList($hash, $count, $skip, $args);
$len = count($ret); $len = count($ret);
   
for ($i = 0; $i < $len; ++$i) { for ($i = 0; $i < $len; ++$i) {
$ret[$i] = $this->GetCommit($ret[$i]); $ret[$i] = $this->GetCommit($ret[$i]);
} }
return $ret; return $ret;
} }
   
/** /**
* SearchCommitter * SearchCommitter
* *
* Gets a list of commits with committers matching the given pattern * Gets a list of commits with committers matching the given pattern
* *
* @access public * @access public
* @param string $pattern search pattern * @param string $pattern search pattern
* @param string $hash hash to start searching from * @param string $hash hash to start searching from
* @param integer $count number of results to get * @param integer $count number of results to get
* @param integer $skip number of results to skip * @param integer $skip number of results to skip
* @return array array of matching commits * @return array array of matching commits
*/ */
public function SearchCommitter($pattern, $hash = 'HEAD', $count = 50, $skip = 0) public function SearchCommitter($pattern, $hash = 'HEAD', $count = 50, $skip = 0)
{ {
if (empty($pattern)) if (empty($pattern))
return; return;
   
$args = array(); $args = array();
$args[] = '--regexp-ignore-case';  
  $exe = new GitPHP_GitExe($this);
  if ($exe->CanIgnoreRegexpCase())
  $args[] = '--regexp-ignore-case';
  unset($exe);
   
$args[] = '--committer=\'' . $pattern . '\''; $args[] = '--committer=\'' . $pattern . '\'';
   
$ret = $this->RevList($hash, $count, $skip, $args); $ret = $this->RevList($hash, $count, $skip, $args);
$len = count($ret); $len = count($ret);
   
for ($i = 0; $i < $len; ++$i) { for ($i = 0; $i < $len; ++$i) {
$ret[$i] = $this->GetCommit($ret[$i]); $ret[$i] = $this->GetCommit($ret[$i]);
} }
return $ret; return $ret;
} }
   
/** /**
* RevList * RevList
* *
* Common code for using rev-list command * Common code for using rev-list command
* *
* @access private * @access private
* @param string $hash hash to list from * @param string $hash hash to list from
* @param integer $count number of results to get * @param integer $count number of results to get
* @param integer $skip number of results to skip * @param integer $skip number of results to skip
* @param array $args args to give to rev-list * @param array $args args to give to rev-list
* @return array array of hashes * @return array array of hashes
*/ */
private function RevList($hash, $count = 50, $skip = 0, $args = array()) private function RevList($hash, $count = 50, $skip = 0, $args = array())
{ {
if ($count < 1) if ($count < 1)
return; return;
   
$exe = new GitPHP_GitExe($this); $exe = new GitPHP_GitExe($this);
   
$canSkip = true; $canSkip = true;
if ($skip > 0) if ($skip > 0)
$canSkip = $exe->CanSkip(); $canSkip = $exe->CanSkip();
   
if ($canSkip) { if ($canSkip) {
$args[] = '--max-count=' . $count; $args[] = '--max-count=' . $count;
if ($skip > 0) { if ($skip > 0) {
$args[] = '--skip=' . $skip; $args[] = '--skip=' . $skip;
} }
} else { } else {
$args[] = '--max-count=' . ($count + $skip); $args[] = '--max-count=' . ($count + $skip);
} }
   
$args[] = $hash; $args[] = $hash;
   
$revlist = explode("\n", $exe->Execute(GIT_REV_LIST, $args)); $revlist = explode("\n", $exe->Execute(GIT_REV_LIST, $args));
   
if (!$revlist[count($revlist)-1]) { if (!$revlist[count($revlist)-1]) {
/* the last newline creates a null entry */ /* the last newline creates a null entry */
array_splice($revlist, -1, 1); array_splice($revlist, -1, 1);
} }
   
if (($skip > 0) && (!$exe->CanSkip())) { if (($skip > 0) && (!$exe->CanSkip())) {
return array_slice($revlist, $skip, $count); return array_slice($revlist, $skip, $count);
} }
   
return $revlist; return $revlist;
} }
   
} }
   
comments