/** * Get tags pointing to a commit * * @param GitPHP_Commit $commit commit * @return GitPHP_Tag[] array of tags */ public function GetCommitTags($commit) { if (!$commit) { return array(); } $commitHash = $commit->GetHash(); if (!$this->dataLoaded) { $this->LoadData(); } if (!isset($this->invertedRefs[$commitHash])) { return array(); } $tagNames = $this->invertedRefs[$commitHash]; $tags = array(); foreach ($tagNames as $tag) { if (isset($this->commits[$tag])) { if ($this->commits[$tag] == $commitHash) { $tagObj = $this->project->GetObjectManager()->GetTag($tag, $this->refs[$tag]); $tagObj->SetCommitHash($this->commits[$tag]); $tags[] = $tagObj; } } else { $tagObj = $this->project->GetObjectManager()->GetTag($tag, $this->refs[$tag]); $tagCommitHash = $tagObj->GetCommitHash(); if (!empty($tagCommitHash)) { $this->commits[$tag] = $tagCommitHash; } if ($tagCommitHash == $commitHash) { $tags[] = $tagObj; } } } return $tags; }
/** * Gets the containing tag for a commit * * @param GitPHP_Commit $commit commit * @return string containing tag */ public function LoadContainingTag($commit) { if (!$commit) { return; } $args = array(); $args[] = '--tags'; $args[] = $commit->GetHash(); $revs = explode("\n", $this->exe->Execute($commit->GetProject()->GetPath(), GIT_NAME_REV, $args)); foreach ($revs as $revline) { if (preg_match('/^([0-9a-fA-F]{40})\\s+tags\\/(.+)(\\^[0-9]+|\\~[0-9]+)$/', $revline, $regs)) { if ($regs[1] == $commit->GetHash()) { return $regs[2]; } } } }
/** * Gets heads that point to a commit * * @param GitPHP_Commit $commit commit * @return GitPHP_Head[] array of heads */ public function GetCommitHeads($commit) { if (!$commit) { return array(); } $commitHash = $commit->GetHash(); if (!$this->dataLoaded) { $this->LoadData(); } if (!isset($this->invertedRefs[$commitHash])) { return array(); } $headNames = $this->invertedRefs[$commitHash]; $heads = array(); foreach ($headNames as $head) { $heads[] = $this->project->GetObjectManager()->GetHead($head, $commitHash); } return $heads; }
/** * Constructor * * @param GitPHP_Project $project project * @param GitPHP_Commit $commit commit to trace blame from * @param string $path file path to trace blame of * @param GitPHP_GitExe $exe git executable */ public function __construct($project, $commit, $path, $exe) { if (!$project) { throw new Exception('Project is required'); } if (!$commit) { throw new Exception('Commit is required'); } if (empty($path)) { throw new Exception('Path is required'); } if (!$exe) { throw new Exception('Git exe is required'); } $this->project = $project; $this->commitHash = $commit->GetHash(); $this->path = $path; $this->exe = $exe; }
/** * Sets the head this log will walk from * * @param GitPHP_Commit $head head commit */ public function SetHead($head) { if ($head) { $this->SetHeadHash($head->GetHash()); } else { $this->SetHeadHash(null); } }
/** * Sets the commit this object belongs to * * @param GitPHP_Commit $commit commit object */ public function SetCommit($commit) { if (!$commit) { return; } $this->SetCommitHash($commit->GetHash()); }
/** * CompareAge * * Compares two heads by age * * @access public * @static * @param mixed $a first head * @param mixed $b second head * @return integer comparison result */ public static function CompareAge($a, $b) { $aObj = $a->GetCommit(); $bObj = $b->GetCommit(); return GitPHP_Commit::CompareAge($aObj, $bObj); }
/** * Gets the data for a commit * * @param GitPHP_Commit $commit commit * @return array commit data */ public function Load($commit) { if (!$commit) { return; } $abbreviatedHash = null; $tree = null; $parents = array(); $author = null; $authorEpoch = null; $authorTimezone = null; $committer = null; $committerEpoch = null; $committerTimezone = null; $title = null; $comment = array(); $commitHash = $commit->GetHash(); $projectPath = $commit->GetProject()->GetPath(); /* Try to get abbreviated hash first try. Go up to max hash length on collision. */ for ($i = 7; $i <= 40; $i++) { $abbreviatedHash = substr($commitHash, 0, $i); $ret = $this->exe->GetObjectData($projectPath, $abbreviatedHash); if (!$ret) { return false; } if ($ret['hash'] !== $commitHash) { continue; } $lines = explode("\n", $ret['contents']); break; } $linecount = count($lines); $i = 0; $encoding = null; /* Commit header */ for ($i = 0; $i < $linecount; $i++) { $line = $lines[$i]; if (preg_match('/^tree ([0-9a-fA-F]{40})$/', $line, $regs)) { /* Tree */ $tree = $regs[1]; } else { if (preg_match('/^parent ([0-9a-fA-F]{40})$/', $line, $regs)) { /* Parent */ $parents[] = $regs[1]; } else { if (preg_match('/^author (.*) ([0-9]+) (.*)$/', $line, $regs)) { /* author data */ $author = $regs[1]; $authorEpoch = $regs[2]; $authorTimezone = $regs[3]; } else { if (preg_match('/^committer (.*) ([0-9]+) (.*)$/', $line, $regs)) { /* committer data */ $committer = $regs[1]; $committerEpoch = $regs[2]; $committerTimezone = $regs[3]; } else { if (preg_match('/^encoding (.+)$/', $line, $regs)) { $gitEncoding = trim($regs[1]); if (strlen($gitEncoding) > 0 && function_exists('mb_list_encodings')) { $supportedEncodings = mb_list_encodings(); $encIdx = array_search(strtolower($gitEncoding), array_map('strtolower', $supportedEncodings)); if ($encIdx !== false) { $encoding = $supportedEncodings[$encIdx]; } } $encoding = trim($regs[1]); } else { if (strlen($line) == 0) { break; } } } } } } } /* Commit body */ for ($i += 1; $i < $linecount; $i++) { $trimmed = trim($lines[$i]); if (strlen($trimmed) > 0 && strlen($encoding) > 0 && function_exists('mb_convert_encoding')) { $trimmed = mb_convert_encoding($trimmed, 'UTF-8', $encoding); } if (empty($title) && strlen($trimmed) > 0) { $title = $trimmed; } if (!empty($title)) { if (strlen($trimmed) > 0 || $i < $linecount - 1) { $comment[] = $trimmed; } } } return array($abbreviatedHash, $tree, $parents, $author, $authorEpoch, $authorTimezone, $committer, $committerEpoch, $committerTimezone, $title, $comment); }
/** * Gets the data for a commit * * @param GitPHP_Commit $commit commit * @return array commit data */ public function Load($commit) { if (!$commit) { return; } $abbreviatedHash = null; $tree = null; $parents = array(); $author = null; $authorEpoch = null; $authorTimezone = null; $committer = null; $committerEpoch = null; $committerTimezone = null; $title = null; $comment = array(); $data = $this->objectLoader->GetObject($commit->GetHash()); if (empty($data)) { return; } $lines = explode("\n", $data); $linecount = count($lines); $i = 0; $encoding = null; /* Commit header */ for ($i = 0; $i < $linecount; $i++) { $line = $lines[$i]; if (preg_match('/^tree ([0-9a-fA-F]{40})$/', $line, $regs)) { /* Tree */ $tree = $regs[1]; } else { if (preg_match('/^parent ([0-9a-fA-F]{40})$/', $line, $regs)) { /* Parent */ $parents[] = $regs[1]; } else { if (preg_match('/^author (.*) ([0-9]+) (.*)$/', $line, $regs)) { /* author data */ $author = $regs[1]; $authorEpoch = $regs[2]; $authorTimezone = $regs[3]; } else { if (preg_match('/^committer (.*) ([0-9]+) (.*)$/', $line, $regs)) { /* committer data */ $committer = $regs[1]; $committerEpoch = $regs[2]; $committerTimezone = $regs[3]; } else { if (preg_match('/^encoding (.+)$/', $line, $regs)) { $gitEncoding = trim($regs[1]); if (strlen($gitEncoding) > 0 && function_exists('mb_list_encodings')) { $supportedEncodings = mb_list_encodings(); $encIdx = array_search(strtolower($gitEncoding), array_map('strtolower', $supportedEncodings)); if ($encIdx !== false) { $encoding = $supportedEncodings[$encIdx]; } } $encoding = trim($regs[1]); } else { if (strlen($line) == 0) { break; } } } } } } } /* Commit body */ for ($i += 1; $i < $linecount; $i++) { $trimmed = trim($lines[$i]); if (strlen($trimmed) > 0 && strlen($encoding) > 0 && function_exists('mb_convert_encoding')) { $trimmed = mb_convert_encoding($trimmed, 'UTF-8', $encoding); } if (empty($title) && strlen($trimmed) > 0) { $title = $trimmed; } if (!empty($title)) { if (strlen($trimmed) > 0 || $i < $linecount - 1) { $comment[] = $trimmed; } } } return array($abbreviatedHash, $tree, $parents, $author, $authorEpoch, $authorTimezone, $committer, $committerEpoch, $committerTimezone, $title, $comment); }
/** * Get a commit * * @param string $hash commit hash * @return GitPHP_Commit|null commit objet */ public function GetCommit($hash) { if (empty($hash)) { return null; } if (preg_match('/^[0-9A-Fa-f]{4,39}$/', $hash)) { $fullHash = $this->project->ExpandHash($hash); if ($fullHash == $hash) { throw new GitPHP_InvalidHashException($hash); } $hash = $fullHash; } if (!preg_match('/^[0-9A-Fa-f]{40}$/', $hash)) { return null; } $key = GitPHP_Commit::CacheKey($this->project->GetProject(), $hash); $commit = null; if ($this->memoryCache) { $commit = $this->memoryCache->Get($key); } if (!$commit) { if ($this->cache) { $commit = $this->cache->Get($key); } $strategy = null; if ($this->compat) { $strategy = new GitPHP_CommitLoad_Git($this->exe); } else { $strategy = new GitPHP_CommitLoad_Raw($this->objectLoader, $this->exe); } if ($commit) { $commit->SetProject($this->project); $commit->SetStrategy($strategy); } else { $commit = new GitPHP_Commit($this->project, $hash, $strategy); } $commit->AddObserver($this); if ($this->memoryCache) { $this->memoryCache->Set($key, $commit); } } return $commit; }
/** * CompareAge * * Compares two tags by age * * @access public * @static * @param mixed $a first tag * @param mixed $b second tag * @return integer comparison result */ public static function CompareAge($a, $b) { $aObj = $a->GetObject(); $bObj = $b->GetObject(); if ($aObj instanceof GitPHP_Commit && $bObj instanceof GitPHP_Commit) { return GitPHP_Commit::CompareAge($aObj, $bObj); } if ($aObj instanceof GitPHP_Commit) { return 1; } if ($bObj instanceof GitPHP_Commit) { return -1; } return strcmp($a->GetName(), $b->GetName()); }
/** * Compares two commits by author epoch * * @param GitPHP_Commit $a first commit * @param GitPHP_Commit $b second commit * @return integer comparison result */ public static function CompareAuthorEpoch($a, $b) { if ($a->GetAuthorEpoch() === $b->GetAuthorEpoch()) { return 0; } return $a->GetAuthorEpoch() < $b->GetAuthorEpoch() ? -1 : 1; }
public function testCompareAge() { $commitdata = array(null, null, array(), null, '12345678', null, null, '2', null, null, array()); $loadstrategy = $this->getMock('GitPHP_CommitLoadStrategy_Interface'); $loadstrategy->expects($this->once())->method('Load')->with($this->isInstanceOf('GitPHP_Commit'))->will($this->returnValue($commitdata)); $commit = new GitPHP_Commit($this->getMockBuilder('GitPHP_Project')->disableOriginalConstructor()->getMock(), '1234567890abcdef1234567890ABCDEF12345678', $loadstrategy); $commitdata2 = array(null, null, array(), null, '12345678', null, null, '1', null, null, array()); $loadstrategy2 = $this->getMock('GitPHP_CommitLoadStrategy_Interface'); $loadstrategy2->expects($this->once())->method('Load')->with($this->isInstanceOf('GitPHP_Commit'))->will($this->returnValue($commitdata2)); $commit2 = new GitPHP_Commit($this->getMockBuilder('GitPHP_Project')->disableOriginalConstructor()->getMock(), '1234567890abcdef1234567890ABCDEF12345678', $loadstrategy2); $this->assertLessThan(0, GitPHP_Commit::CompareAge($commit, $commit2)); $this->assertGreaterThan(0, GitPHP_Commit::CompareAge($commit2, $commit)); $commitdata = array(null, null, array(), null, '12345678', null, null, '1', null, null, array()); $loadstrategy = $this->getMock('GitPHP_CommitLoadStrategy_Interface'); $loadstrategy->expects($this->once())->method('Load')->with($this->isInstanceOf('GitPHP_Commit'))->will($this->returnValue($commitdata)); $commit = new GitPHP_Commit($this->getMockBuilder('GitPHP_Project')->disableOriginalConstructor()->getMock(), '1234567890abcdef1234567890ABCDEF12345678', $loadstrategy); $commitdata2 = array(null, null, array(), null, '12345679', null, null, '1', null, null, array()); $loadstrategy2 = $this->getMock('GitPHP_CommitLoadStrategy_Interface'); $loadstrategy2->expects($this->once())->method('Load')->with($this->isInstanceOf('GitPHP_Commit'))->will($this->returnValue($commitdata2)); $commit2 = new GitPHP_Commit($this->getMockBuilder('GitPHP_Project')->disableOriginalConstructor()->getMock(), '1234567890abcdef1234567890ABCDEF12345678', $loadstrategy2); $this->assertGreaterThan(0, GitPHP_Commit::CompareAge($commit, $commit2)); $this->assertLessThan(0, GitPHP_Commit::CompareAge($commit2, $commit)); }
/** * CompareAge * * Compares two commits by age * * @access public * @static * @param mixed $a first commit * @param mixed $b second commit * @return integer comparison result */ public static function CompareAge($a, $b) { if ($a->GetAge() === $b->GetAge()) { // fall back on author epoch return GitPHP_Commit::CompareAuthorEpoch($a, $b); } return $a->GetAge() < $b->GetAge() ? -1 : 1; }
/** * Sets the object for this archive * * @param GitPHP_Commit|GitPHP_Tree|null $object the git object */ public function SetObject($object) { // Archive only works for commits and trees if ($object == null) { $this->objectHash = ''; $this->objectType = ''; return; } if ($object instanceof GitPHP_Commit) { $this->objectType = 'commit'; $this->objectHash = $object->GetHash(); return; } if ($object instanceof GitPHP_Tree) { $this->objectType = 'tree'; $this->objectHash = $object->GetHash(); return; } throw new Exception('Invalid source object for archive'); }